Skip to content
This repository was archived by the owner on Apr 1, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
target
.idea
Cargo.lock
23 changes: 0 additions & 23 deletions Cargo.lock

This file was deleted.

13 changes: 7 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
[package]
name = "navigation"
description = "Provides basic navigation between GPS waypoints"
version = "0.1.7"
authors = ["Andy Grove <andygrove73@gmail.com>"]
homepage = "https://github.com/andygrove/rust-navigation"
documentation = "https://github.com/andygrove/rust-navigation"
repository = "https://github.com/andygrove/rust-navigation"
version = "0.2.0"
authors = ["Andy Grove <andygrove73@gmail.com>", "Christopher Moran <christophermoran@ucsb.edu>"]
homepage = "https://github.com/ucsb-coast-lab/rust-navigation"
documentation = "https://github.com/ucsb-coast-lab/rust-navigation"
repository = "https://github.com/ucsb-coast-lab/rust-navigation"
license = "MIT/Apache-2.0"
edition = "2018"

[dependencies]
rand = "0.3.13"
rand = "0.8"
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,33 @@ let bearing = boulder.estimate_bearing_to(&dia); // results in 110.44
(40.091311, -105.185128) -> (40.090946, -105.184925): bearing=157.0 estimate=156.9 diff=0.1 [OK]
(40.091150, -105.185586) -> (40.091221, -105.185793): bearing=294.2 estimate=294.1 diff=0.1 [OK]
```

## AlvinXY submodule

The `alvinxy` submodule adds the ability to switch between a local and global coordinate frame according to the
```
Murphy, Chris & Singh, Hanumant. (2010). Rectilinear coordinate frames for Deep sea navigation. 2010 IEEE/OES Autonomous Underwater Vehicles, AUV 2010. 1 - 10. 10.1109/AUV.2010.5779654.`
```

### AlvinXY mission planning example

A mission planned for a vehicle using this coordinate plan might look like the following, where the final GPS coordinates could be exported to a mission file or use directly by a control system. This implementation has been used for mission planning of an autonomous underwater vehicle in a freshwater reservoir.

```
fn main() {
let origin = Location::new(34.589,-119.96472);
// Writing the vehicle coordinate sequence and push them to vector
let mut wt_list: Vec<LocalCoor> = Vec::new();
let mut b = LocalCoor::new(-900.0,0.0);
let mut soff = LocalCoor::new(-900.,-100.);
let mut son = LocalCoor::new(-900.,100.);
wt_list.push(b);
wt_list.push(soff);
wt_list.push(son);

for wpt in &mut wt_list {
wpt.rotate_local(15.0);
println!("List of waypoints after rotation and conversion: {:?}",xy2latlon(*wpt,origin));
}
}
```
81 changes: 81 additions & 0 deletions src/alvinxy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//! This is module converts between GPS coordinates in decimal form to a local coordinate structure per the AlvinXY algorithm as laid out in the paper below.
//!
//! `Murphy, Chris & Singh, Hanumant. (2010). Rectilinear coordinate frames for Deep sea navigation. 2010 IEEE/OES Autonomous Underwater Vehicles, AUV 2010. 1 - 10. 10.1109/AUV.2010.5779654.`
//!
//! This implementation has been used to generate waypoints for an autonomous underwater vehicle mission in a freshwater resevoir

use std::f64;

#[derive(Clone, Copy, Debug)]
pub struct LocalCoor {
pub x: f64,
pub y: f64,
}

use crate::Location;

impl LocalCoor {
/// Create a new coordinate in the local reference frame
pub fn new(x: f64, y: f64) -> Self {
LocalCoor { x, y }
}

/// Rotate a coordinate around the origin by an angle supplied in degrees
pub fn rotate_local(&mut self, theta: f64) {
let theta = theta.to_radians();
self.x = (self.x * theta.cos()) - (self.y * theta.sin());
self.y = (self.x * theta.sin()) + (self.y * theta.cos());
}
}

/// Convert a GPS `Location` coordinate to a local `LocalCoor` coordinate frame
pub fn latlon2xy(coordinate: Location, origin: Location) -> LocalCoor {
let x = (coordinate.lon - origin.lon) * mdeglon(origin.lat);
let y = (coordinate.lat - origin.lat) * mdeglat(origin.lat);
LocalCoor::new(x, y)
}

/// Converts from the local `LocalCoor` xy to global `Location` Coordinate frame
pub fn xy2latlon(coordinate: LocalCoor, origin: Location) -> Location {
let lon = coordinate.x / mdeglon(origin.lat) + origin.lon;
let lat = coordinate.y / mdeglat(origin.lat) + origin.lat;
Location { lat, lon }
}

#[inline]
fn mdeglon(lat0: f64) -> f64 {
let lat0rad = lat0.to_radians();
111415.13 * lat0rad.cos() - (94.55 * (3.0 * lat0rad).cos()) - (0.12 * (5.0 * lat0rad).cos())
}

#[inline]
fn mdeglat(lat0: f64) -> f64 {
let lat0rad = lat0.to_radians();
111132.09 - (566.05 * (2.0 * lat0rad).cos()) + (1.20 * (4.0 * lat0rad).cos())
- (0.002 * (6.0 * lat0rad).cos())
}

// This test was used to verify the coordinate offsets for an AUV mission in a Californian freshwater resevoir
#[test]
fn reservoir_coordinates() {
let origin = Location::new(34.589000, -119.966000);
let o = latlon2xy(Location::new(34.589000, -119.966000), origin); // Making sure the origin in (0.0,0.0)
println!("The origin is at: ({},{})", o.x, o.y);
assert!((o.x == 0.0) && (o.y == 0.0));
// Directly above/North
let n = latlon2xy(Location::new(34.59000, -119.966000), origin);
println!("nx,ny = ({},{})", n.x, n.y);
assert!(n.y > o.y);
// Directly below/South
let s = latlon2xy(Location::new(34.58800, -119.966000), origin);
println!("nx,ny = ({},{})", s.x, s.y);
assert!(s.y < o.y);
// Directly left/West (longitude DECREASES going West)
let w = latlon2xy(Location::new(34.589000, -119.967000), origin);
println!("wx,wy = ({},{})", w.x, w.y);
assert!(w.x < o.x);
// Directly right/East (latitude INCREASES going East)
let e = latlon2xy(Location::new(34.589000, -119.96500), origin);
println!("ex,ey = ({},{})", e.x, e.y);
assert!(e.x > o.x);
}
Loading