Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
240 changes: 185 additions & 55 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions docs/hardware/sensors.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ On the Rover, we have a lotta sensors to maintain Autonomous operations.

## GPS

- connection: TCP (through the router. see [`network.md`](../network.md) for more info!)
- connection: USB 2.0 (with a bundled driver that fakes a serial connection)

Our GPS is a Swift Navigation Piksi Multi. It provides a multitude of measurements, some of which only appear when [setting up the Base Station](https://support.swiftnav.com/support/solutions/articles/44001904334-piksi-multi-gnss-rtk-position-with-stationary-base). Having the Base Station can also increase the reliability of data. We're not currently using this enhanced data, but doing so is absolutely possible (and preferable).
We use the [Septentrio mosaic-Go Heading](https://www.digikey.com/en/products/detail/septentrio-inc/410397/18091780) evaluation kit as the GNSS (GPS) receiver in our Rover. The device supports up to 2 antennas, though we only use one at the moment. The antenna we use is the Swift Navigation GPS500. It connects to the GNSS antenna over a regular old TNC connector. There are several of those cables scattered around the Bay; usually, one is connected to the antenna already.

The mosaic-Go plugs into any computer via a micro-USB cable; this both powers it and provides a web interface on a fake network connection. **You do not need any other cable to connect; just that one micro-USB**. To configure the mosaic-Go, just plug it into your computer, open your network settings, and find its IP. For me, it was accessible at [this IP: `192.168.3.1`](https://192.168.3.1/scr). Please back up the configuration before making any changes.

## Color Camera

Expand Down
8 changes: 0 additions & 8 deletions docs/network.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,3 @@ We use an Netgear Nighthawk AX1800 WiFi Router (R6700AX) on firmware version v1.
- 9-DoF sensor package - [ICM-20948](https://www.adafruit.com/product/4554)
- battery: `5007`
- indicates how charged the batteries are

## GPS

The Piksi Multi (GPS controller)

- MAC Addr: `8c:c8:f4:90:03:e5`
- Static IP: `192.168.1.222`
- Port: `55556` (TODO: is this configurable?)
6 changes: 3 additions & 3 deletions lib/soro_gps/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ readme = "README.md"
crate-time = ["staticlib"]

[dependencies]
pisserror = "0.3.0"
libsbf = { version = "0.14.0", features = ["std"] }
serialport = { version = "4.8.1", default-features = false }
tokio = { version = "1.43.0", features = ["time"] }
tracing = "0.1.41"
sbp = "6.2.1"
tokio = { version = "1.43.0", features = ["net", "time"] }

[dev-dependencies]
tracing-subscriber = "0.3.19"
Expand Down
42 changes: 7 additions & 35 deletions lib/soro_gps/README.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,13 @@
<!-- cargo-rdme start -->
# `soro_gps`

# `gps-rs`
Connects to the GPS and provides its data in a readable format.

Bindings to the Swift GPS library ([`gps/`](https://github.com/Sooner-Rover-Team/gps)).
## Testing

This crate exposes the `bindings` module to access the C functions and statics directly.
To test the GPS connection, use the following command:

However, intended usage is through the `Gps` struct, which provides a safe wrapper for the unsafe C items.
`timeout 3s sh -c 'dd if=/dev/serial/by-id/usb-Septentrio_Septentrio_USB_Device_3844945-if02 bs=1 count=64 status=none | xxd -g 1 -u'`

This type exposes safe bindings with respect to the (kinda undocumented) safety constraints of the C code. Previous testing shows that violating these unspoken invariants can result in all kinds of weird behavior!
If that works, great! Otherwise, you'll want to find the device path: `ls /dev/serial/by-id/ | grep Septentrio`. Then, replace the path in the command above with the one you got from that command. If there's multiple, test them all.

## Usage (Rust)

In short, you can use the various methods on `Gps` to interact with the Rover's GPS system.

```rust
use gps_rs::Gps;

// we can make a GPS from a given IP address and port.
//
// on the Rover, this is from the router (hopefully a static IP) and a port
let swift_ip: IpAddr = "192.168.1.222".parse().unwrap();
let swift_port: u16 = 55556;

// here, we make the GPS! this will automatically initialize it.
let gps: Gps = Gps::new(swift_ip, swift_port).unwrap();

// now, you can use its methods:
println!("coord: {:?}", gps.coord());
println!("height: {:?}", gps.height());
println!("error in mm: {:?}", gps.error());

// dropping it (when it falls from scope) automatically runs the required cleanup.
```

## Usage (Python)

Unimplemented. This should use the `pyo3` feature to build, and I'll plan to upload it to PyPi soon.

<!-- cargo-rdme end -->
On the other hand, if none of those work, you should try configuring the streams on the GPS receiver. Ensure it's plugged into a computer with a display (like a laptop), then navigate to [its configuration page](http://192.168.3.1) and select the "NMEA/SBF Out" tab.
Binary file added lib/soro_gps/data_files/inside_bay.sbf
Binary file not shown.
Binary file added lib/soro_gps/data_files/minimal_sbf.sbf
Binary file not shown.
Binary file added lib/soro_gps/data_files/outside_the_bay.sbf
Binary file not shown.
38 changes: 38 additions & 0 deletions lib/soro_gps/examples/laptop.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//! This example should work on a laptop/desktop computer.
//!
Comment thread
onkoe marked this conversation as resolved.
//! I'm using it now to test the GPS connection without any ROS 2 stuff to mess
//! with anything.

use soro_gps::Gps;

fn main() {
// IMPORTANT: change this to the GPS' serial connection file.
//
// on Windows, you might be outta luck, but macOS and Linux should allow
// grabbing this with: `ls /dev/serial/by-id | grep Septentrio`
const DEVICE_PATH: &str = "/dev/ttyACM0";

// then, "make a connection" by reading from that file!
let mut gps: Gps = match Gps::new(DEVICE_PATH.into()) {
Ok(gps) => gps,
Err(e) => {
tracing::error!("GPS connection error: {e}");
panic!();
}
};

// continuously grab GPS information
loop {
match gps.get() {
Some(gps_info) => {
tracing::info!("New GPS message: {gps_info:?}")
}

Option::None => {
tracing::error!("GPS disconnected! Waiting 2s and trying again...");
std::thread::sleep(core::time::Duration::from_millis(2_000));
continue;
}
}
}
}
54 changes: 33 additions & 21 deletions lib/soro_gps/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
use core::error::Error;
use std::time::Duration;
use std::path::PathBuf;

/// An error that can occur when connecting to the GPS.
#[derive(Debug, pisserror::Error)]
#[derive(Clone, Debug)]
pub enum GpsConnectionError {
#[error("Failed to bind to the provided port. port: {port}, err: {err}")]
BindError { port: u16, err: std::io::Error },

#[error("Couldn't connect to the provided address and port. err: {_0}")]
ConnectionError(#[from] std::io::Error),
/// The GPS' serial output file representation was not found at the given
/// location.
FileNotFound(
/// The given location.
PathBuf,
),
/// The GPS path exists, but opening it as a serial source failed.
FailedToOpen(
/// The given location.
PathBuf,
/// Details from the OS/driver stack.
String,
),
}

/// An error that may occur when reading from the GPS.
#[derive(Debug, pisserror::Error)]
pub enum GpsReadError {
#[error("GPS can't update that fast. elapsed: {} ms", elapsed.as_millis())]
HaventHitUpdateTime { elapsed: Duration },

#[error("Failed to read before hitting the timeout. timeout: {} ms", _0.as_millis())]
HitTimeout(Duration),

#[error("Failed to read from the socket.")]
ReadFailed,
impl core::error::Error for GpsConnectionError {}

#[error("Parsing failed.")]
ParseFailed(#[from] sbp::Error),
impl core::fmt::Display for GpsConnectionError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
GpsConnectionError::FileNotFound(serial_path) => write!(
f,
"The GPS' serial output file representation was not found at \
the given location: `{}`",
serial_path.to_string_lossy()
),
GpsConnectionError::FailedToOpen(serial_path, reason) => write!(
f,
"Failed to open GPS source at `{}`: {}",
serial_path.to_string_lossy(),
reason
),
}
}
}
Loading
Loading