Expand description
§ados-hmi
Input state machines for hardware front panels: touchscreen affine calibration and gestures, button press classification, quadrature encoder decoding and a pilot-in-command arbiter.
A small device with a few buttons, a rotary knob and a resistive touchscreen needs the same logic every time: debounce the buttons, tell a short press from a long one, turn noisy encoder edges into clean detents, map raw touch counts onto display pixels and recognise taps and swipes. This crate holds those pieces as pure state machines that take timestamped events, so you wire them to GPIO or evdev yourself and test them without hardware.
use std::collections::HashMap;
use ados_hmi::encoder::{Channel, QuadratureDecoder, Rotation};
use ados_hmi::press::{Edge, PressClassifier, PressKind};
// Four buttons on GPIO 5, 6, 13 and 19 are labelled B1..B4.
let mapping: HashMap<String, String> = [("B1_short", "next"), ("B1_long", "menu")]
.into_iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect();
let mut buttons = PressClassifier::from_mapping(mapping, [5, 6, 13, 19]);
// Press at t=0 ms, a contact bounce 8 ms later, release after 2.5 s: one long press.
assert!(buttons.on_edge(5, Edge::Falling, 0).is_none());
assert!(buttons.on_edge(5, Edge::Falling, 8).is_none());
let event = buttons.on_edge(5, Edge::Rising, 2_500).unwrap();
assert_eq!(event.kind, PressKind::Long);
assert_eq!(event.action.as_deref(), Some("menu"));
// One clockwise detent of a KY-040 style encoder: A leads B.
let mut knob = QuadratureDecoder::new(true, true);
let mut detents = Vec::new();
for (line, high) in [(Channel::A, false), (Channel::B, false), (Channel::A, true), (Channel::B, true)] {
detents.extend(knob.on_edge(line, high));
}
assert_eq!(detents, [Rotation::Cw]);§Highlights
- Every state machine takes caller-supplied timestamps or an injectable clock, so debounce windows, hold thresholds, token TTLs and watchdogs are tested without sleeping.
- Quadrature decoding counts quarter steps, so contact bounce cancels out and a missed edge is rejected instead of producing a wrong detent.
- Touch calibration fits a 2x3 affine matrix by least squares from any number of points and reports the RMS residual.
- Action mappings sit behind a shared
Arc<RwLock<_>>, so a remap takes effect on the next release without rebuilding the classifier. - Event buses are bounded
tokio::sync::broadcastchannels: a slow subscriber lags instead of stalling the publisher. - Builds on any host; nothing touches GPIO, evdev or a display directly.
§How it works
press: active-low buttons. A falling edge records the press unless it lands inside the 20 ms debounce window of the previous press on that pin. The rising edge classifies the hold: under 2 s isshort, 2 s to 6 s islong, 6 s or more is dropped as a cancel. The action is looked up as<label>_<kind>, where the label isB1..B4by role order,BX<pin>for other pins, orENC_SWfor an encoder push switch.encoder: the 2-bit Gray codeA << 1 | Bwalks four states per detent. Each valid single-line transition adds or removes a quarter step; a detent is reported only on the return to rest with a net count of four in one direction. A transition where both lines changed is counted as rejected. Detents can be fed intoPressClassifier::on_rotationand resolve asENC_CW_short/ENC_CCW_short.affine: maps raw 12-bit touch ADC counts to display pixels. Covers the four rotation identities, the normal-equations least-squares fit, a Gaussian-elimination solver with partial pivot and singular guard, round-half-to-even application, and atomic JSON persistence that rejects a stored calibration whose panel size or rotation no longer matches.touch: a per-stroke state machine with a move filter, classifying each stroke as tap, long press, swipe or drag by duration and displacement, with direction taken from the larger axis.pic: a pilot-in-command arbiter. Exactly one client holds control; a takeover needs a confirm token or a force flag, a missed heartbeat auto-releases, and a connected gamepad can auto-claim an unheld seat. Each transition is published oneventbus.
§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-sensorhub | Sensor hub wire protocol: COBS framing, CRC-16 and fixed-layout IMU, baro, mag and GNSS packets. no_std. | docs.rs |
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 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 either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Modules§
- affine
- Touchscreen affine transform: raw ADC -> LCD pixel coordinates.
- encoder
- Rotary encoder (KY-040 class): quadrature decode and the encoder’s labels.
- eventbus
- In-process fanout for PIC state transitions.
- pic
- Pilot-in-command arbiter FSM.
- press
- Button press classification.
- touch
- Touch gestures: calibrated samples in, classified gestures out.