Expand description
§ados-sensorhub
Sensor hub wire protocol: COBS framing, CRC-16/CCITT-FALSE and fixed-layout IMU, barometer, magnetometer, trigger, PPS and GNSS packets. no_std, no allocation.
A sensor hub is a small microcontroller that timestamps IMU samples, camera triggers and PPS edges on one clock and streams them to a companion computer over USB or a UART. This crate is the wire format both ends share: the same code encodes on the microcontroller and decodes on the host. Reach for it when you build either side of such a link and want byte-exact packets, framing that resynchronises after line noise, and no heap.
use ados_sensorhub::{
decode_frame, encode_frame, Deframer, ImuBatch, ImuSample, ImuSamples, Packet, Push,
MAX_FRAME, MAX_RAW,
};
// Encode two IMU samples taken 1 ms apart as one wire frame.
let samples = [
ImuSample { gyro: [1, -2, 3], accel: [0, 0, 2048], temp: 3150 },
ImuSample { gyro: [2, -1, 4], accel: [1, 0, 2049], temp: 3151 },
];
let pkt = Packet::ImuBatch(ImuBatch {
t0_ns: 5_000_000,
dt_ns: 1_000_000,
imu_id: 0,
flags: 0,
seq0: 100,
samples: ImuSamples::Typed(&samples),
});
let mut scratch = [0u8; MAX_RAW];
let mut wire = [0u8; MAX_FRAME];
let n = encode_frame(&pkt, &mut scratch, &mut wire).unwrap();
// The receiver splits the byte stream on 0x00 and decodes each block.
let mut deframer = Deframer::<MAX_FRAME>::new();
let mut buf = [0u8; MAX_RAW];
let mut decoded = 0;
for &b in &wire[..n] {
if let Push::Block(block) = deframer.push(b) {
let Packet::ImuBatch(batch) = decode_frame(block, &mut buf).unwrap() else {
panic!("expected an IMU batch");
};
assert_eq!(batch.samples.get(1), Some(samples[1]));
assert_eq!(batch.sample_t_ns(1), 6_000_000);
decoded += 1;
}
}
assert_eq!(decoded, 1);§Highlights
#![no_std], no allocation: every buffer is caller-owned, sized by theMAX_RAWandMAX_FRAMEconstants.- Zero required dependencies;
serdederives on the owned packet structs are opt-in. #![forbid(unsafe_code)].- Decoding borrows variable-length payloads (IMU samples, GNSS and RTCM bytes) straight from the decode buffer, with no copy.
- Unknown packet types decode to
Packet::Unknowninstead of failing, so a newer hub does not break an older host. - Round-trip, framing and malformed-input tests, including proptest round trips.
§How it works
Every packet travels as one frame:
wire := COBS(raw) 0x00
raw := type:u8 len:u16le payload[len] crc:u16le
crc := CRC-16/CCITT-FALSE over type, len and payloadCOBS (Consistent Overhead Byte Stuffing) removes every 0x00 from the raw frame, so 0x00 can only appear as the delimiter. A receiver that starts mid-stream, or loses bytes, recovers at the next delimiter. Payloads are at most MAX_PAYLOAD (1024) bytes; multi-byte fields are little-endian, reserved fields are written as zero and ignored on receive, and every t_ns is hub time.
encode_framewrites one delimited wire frame;encode_rawwrites only the raw frame.Deframersplits a byte stream on0x00into COBS blocks, one byte at a time. A block longer than its buffer is dropped up to the next delimiter and reported asPush::Overflow.decode_frameunstuffs one block and parses it;decode_rawparses a raw frame. Both check the length and the CRC before touching the payload.cobsandcrcare usable on their own.
Packet types:
| Type | Packet | Payload |
|---|---|---|
0x01 | Hello | 40 bytes: protocol and firmware version, board ID, capability bits, MCU UID, board name |
0x10 | ImuBatch | 20-byte header plus 1 to 64 samples of 14 bytes (raw gyro, accel, temperature) |
0x11 | Baro | 20 bytes: pressure and temperature |
0x12 | Mag | 24 bytes: field in microtesla |
0x20 | Trigger | 28 bytes: camera trigger sequence, exposure start, mid-exposure time and length |
0x30 | Pps | 24 bytes: PPS edge time, lock state, phase error, frequency correction |
0x40 | GnssRaw | 10-byte header plus up to 1014 receiver bytes |
0x41 | RtcmIn | 2-byte header plus up to 1022 correction bytes |
0x50 | Config | 16 bytes: trigger rate and mode, IMU rate and batch size, outputs, heater target |
0x60 | Health | 40 bytes: uptime, temperatures, input voltage, drop and error counters |
Raw IMU counts convert with GYRO_LSB_RAD_S (±2000 dps full scale) and ACCEL_LSB_M_S2 (±16 g full scale).
§Cargo features
| Feature | Default | What it enables |
|---|---|---|
serde | no | Serialize/Deserialize on the owned packet structs |
§Part of ADOS
Used in production by the ADOS Drone Agent, the onboard software of the ADOS software-defined drone platform. All ADOS crates · Docs · Discord
§Other ADOS crates
Platform (versioned with the ADOS Drone Agent)
| Crate | What it does | Docs |
|---|---|---|
ados-protocol | Wire contracts of the ADOS Drone Agent: IPC framing, plugin RPC envelope, capability tokens and the vision frame bus. | docs.rs |
ados-sdk | Write Rust plugins for the ADOS Drone Agent: IPC client, plugin context, driver traits and lifecycle runner. | docs.rs |
ados-vision | Single-object visual tracker: Kalman motion model, appearance re-identification and YOLOv8 head decoding. | docs.rs |
ados-gpio | Drive status buzzers and LEDs on Linux GPIO lines, with bounded software-PWM beep patterns. | docs.rs |
ados-hal-probe | Find out what a board’s hardware can really do by probing it, plus bundled board profiles. | docs.rs |
Standalone
| Crate | What it does | Docs |
|---|---|---|
ados-offload | Choose where perception runs (onboard, offloaded or hybrid) and hold the vehicle when results go stale. | docs.rs |
ados-macpin | Stable MAC addresses for Linux network adapters that randomize theirs every boot. | docs.rs |
ados-lora | LoRa transmit governor with cited regional band plans, duty cycle, dwell time and airtime accounting. | docs.rs |
ados-crsf-codec | no_std CRSF / ExpressLRS codec for RC channels, telemetry and parameter frames. | docs.rs |
ados-positioning | Split mixed UBX, NMEA and RTCM3 GNSS streams, configure u-blox receivers and run an RTK base survey-in. | docs.rs |
ados-rtcm | RTCM3 framing, CRC-24Q and MAVLink GPS_RTCM_DATA fragmentation for RTK corrections. | docs.rs |
ados-clock | Map remote clocks onto the host clock: least-squares and envelope fits, TIMESYNC and a chrony sink. | docs.rs |
ados-swarm | Swarm control laws: separation, flocking, formations, CBBA task allocation and a point-mass simulator. | docs.rs |
ados-mavlink-tunnel | Send large messages over MAVLink TUNNEL frames with chunking and bounded reassembly. | docs.rs |
ados-display-driver | Small-display output on Linux: SSD1306/SH1106 OLED over I2C, pixel packers and a framebuffer writer. | docs.rs |
ados-hmi | Front-panel input: touchscreen calibration and gestures, button presses and rotary encoders. | docs.rs |
§ADOS repositories
| Repo | Runs on | What it does | Link |
|---|---|---|---|
| ADOS Mission Control | Browser, desktop (Electron) | Ground control station: FC setup, mission planning, flight, 3D simulation, fleet | ADOSMissionControl |
| ADOS Drone Agent | Companion computer on the drone, or a ground node | Onboard agent: MAVLink routing, HD video, long-range radio link, plugins, remote control | ADOSDroneAgent |
| ADOS Android GCS | Android phones and tablets | Native ground control app for agents on the LAN, direct flight controllers and the cloud | ADOSAndroidGCS |
| ADOS Extensions | Drone Agent and Mission Control | First-party signed plugins, each with an agent half and a GCS half | ADOSExtensions |
| ADOS MCP | Your machine | Model Context Protocol server that lets AI clients operate ADOS drones under scopes and a safety gate | ADOS-MCP |
| Documentation | docs.altnautica.com | Public docs for every ADOS product | Documentation |
§License
Licensed under the MIT license. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you shall be licensed as above, without any additional terms or conditions.
Re-exports§
pub use packet::*;
Modules§
- cobs
- Consistent Overhead Byte Stuffing (Cheshire & Baker), without the
trailing
0x00delimiter (the frame layer appends it). - crc
- CRC-16/CCITT-FALSE: poly 0x1021, init 0xFFFF, no reflection, xorout 0.
- packet
- Packet payload structs, byte-exact per protocol v1. Every
t_nsis hub time. Reserved fields are written as zero and ignored on receive.
Structs§
- Deframer
- Splits a byte stream into COBS blocks on
0x00. A block longer thanNis discarded up to the next delimiter (resync).
Enums§
Constants§
- MAX_
FRAME - Largest wire frame including the
0x00delimiter. - MAX_
PAYLOAD - Largest payload (
len) the protocol allows. - MAX_RAW
- Largest raw (pre-COBS) frame.
- RAW_
OVERHEAD - Raw frame overhead: type (1) + len (2) + crc (2).
Functions§
- decode_
frame - Decode one COBS block (delimiter stripped) into
bufand parse it. - decode_
raw - Parse a raw frame (type, len, payload, crc).
- encode_
frame - Encode
pktas one wire frame (COBS +0x00) intoout, usingscratch(≥ the raw length,MAX_RAWalways suffices) for the raw frame. Returns the wire length including the delimiter. - encode_
raw - Write the raw frame (type, len, payload, crc) of
pktintoout; returns its length.