Skip to main content

Crate ados_sensorhub

Crate ados_sensorhub 

Source
Expand description

§ados-sensorhub

crates.io docs.rs license MSRV

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 the MAX_RAW and MAX_FRAME constants.
  • Zero required dependencies; serde derives 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::Unknown instead 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 payload

COBS (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_frame writes one delimited wire frame; encode_raw writes only the raw frame.
  • Deframer splits a byte stream on 0x00 into COBS blocks, one byte at a time. A block longer than its buffer is dropped up to the next delimiter and reported as Push::Overflow.
  • decode_frame unstuffs one block and parses it; decode_raw parses a raw frame. Both check the length and the CRC before touching the payload.
  • cobs and crc are usable on their own.

Packet types:

TypePacketPayload
0x01Hello40 bytes: protocol and firmware version, board ID, capability bits, MCU UID, board name
0x10ImuBatch20-byte header plus 1 to 64 samples of 14 bytes (raw gyro, accel, temperature)
0x11Baro20 bytes: pressure and temperature
0x12Mag24 bytes: field in microtesla
0x20Trigger28 bytes: camera trigger sequence, exposure start, mid-exposure time and length
0x30Pps24 bytes: PPS edge time, lock state, phase error, frequency correction
0x40GnssRaw10-byte header plus up to 1014 receiver bytes
0x41RtcmIn2-byte header plus up to 1022 correction bytes
0x50Config16 bytes: trigger rate and mode, IMU rate and batch size, outputs, heater target
0x60Health40 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

FeatureDefaultWhat it enables
serdenoSerialize/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)

CrateWhat it doesDocs
ados-protocolWire contracts of the ADOS Drone Agent: IPC framing, plugin RPC envelope, capability tokens and the vision frame bus.docs.rs
ados-sdkWrite Rust plugins for the ADOS Drone Agent: IPC client, plugin context, driver traits and lifecycle runner.docs.rs
ados-visionSingle-object visual tracker: Kalman motion model, appearance re-identification and YOLOv8 head decoding.docs.rs
ados-gpioDrive status buzzers and LEDs on Linux GPIO lines, with bounded software-PWM beep patterns.docs.rs
ados-hal-probeFind out what a board’s hardware can really do by probing it, plus bundled board profiles.docs.rs

Standalone

CrateWhat it doesDocs
ados-offloadChoose where perception runs (onboard, offloaded or hybrid) and hold the vehicle when results go stale.docs.rs
ados-macpinStable MAC addresses for Linux network adapters that randomize theirs every boot.docs.rs
ados-loraLoRa transmit governor with cited regional band plans, duty cycle, dwell time and airtime accounting.docs.rs
ados-crsf-codecno_std CRSF / ExpressLRS codec for RC channels, telemetry and parameter frames.docs.rs
ados-positioningSplit mixed UBX, NMEA and RTCM3 GNSS streams, configure u-blox receivers and run an RTK base survey-in.docs.rs
ados-rtcmRTCM3 framing, CRC-24Q and MAVLink GPS_RTCM_DATA fragmentation for RTK corrections.docs.rs
ados-clockMap remote clocks onto the host clock: least-squares and envelope fits, TIMESYNC and a chrony sink.docs.rs
ados-swarmSwarm control laws: separation, flocking, formations, CBBA task allocation and a point-mass simulator.docs.rs
ados-mavlink-tunnelSend large messages over MAVLink TUNNEL frames with chunking and bounded reassembly.docs.rs
ados-display-driverSmall-display output on Linux: SSD1306/SH1106 OLED over I2C, pixel packers and a framebuffer writer.docs.rs
ados-hmiFront-panel input: touchscreen calibration and gestures, button presses and rotary encoders.docs.rs

§ADOS repositories

RepoRuns onWhat it doesLink
ADOS Mission ControlBrowser, desktop (Electron)Ground control station: FC setup, mission planning, flight, 3D simulation, fleetADOSMissionControl
ADOS Drone AgentCompanion computer on the drone, or a ground nodeOnboard agent: MAVLink routing, HD video, long-range radio link, plugins, remote controlADOSDroneAgent
ADOS Android GCSAndroid phones and tabletsNative ground control app for agents on the LAN, direct flight controllers and the cloudADOSAndroidGCS
ADOS ExtensionsDrone Agent and Mission ControlFirst-party signed plugins, each with an agent half and a GCS halfADOSExtensions
ADOS MCPYour machineModel Context Protocol server that lets AI clients operate ADOS drones under scopes and a safety gateADOS-MCP
Documentationdocs.altnautica.comPublic docs for every ADOS productDocumentation

§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 0x00 delimiter (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_ns is 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 than N is discarded up to the next delimiter (resync).

Enums§

Error
Framing and parsing errors.
Push
Outcome of pushing one byte into a Deframer.

Constants§

MAX_FRAME
Largest wire frame including the 0x00 delimiter.
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 buf and parse it.
decode_raw
Parse a raw frame (type, len, payload, crc).
encode_frame
Encode pkt as one wire frame (COBS + 0x00) into out, using scratch (≥ the raw length, MAX_RAW always suffices) for the raw frame. Returns the wire length including the delimiter.
encode_raw
Write the raw frame (type, len, payload, crc) of pkt into out; returns its length.