A flight controller has no room for undefined behaviour. A buffer overrun in a MAVLink parser, a use-after-free in a sensor driver, an integer overflow in the mixer — on a desk these are crashes, in the air they are a vehicle falling out of the sky. The existing open-source autopilots are excellent, decades-deep projects written in C and C++. We did not set out to replace them lightly. We set out because we wanted a stack where an entire class of those failures is gone before the code ever runs.
One language, motor to map
The Crab stack is Rust end to end:
- Crabpilot —
#![no_std]firmware for STM32H7 flight controllers. - CrabLink — the async MAVLink library shared by every host-side tool.
- CrabStation — the cross-platform ground control station.
- CrabCompanion, CrabSim, and the rest of the ecosystem.
One language means a type can be defined once and used everywhere. A MAVLink message, a mission item, a parameter descriptor — the firmware and the ground station agree on its shape because they share, or generate from, the same definition. There is no hand-maintained C struct on one side and a Python class on the other drifting quietly out of sync.
What the borrow checker buys on embedded
no_std Rust on a microcontroller is not a watered-down dialect. You still get:
- No data races. The borrow checker rejects shared mutable state across tasks at compile time. On an RTIC-scheduled flight controller with interrupt-driven sensors, that is the difference between a provable design and a hopeful one.
- No null, no use-after-free.
Option<T>makes "this sensor may not be initialised" a value the compiler forces you to handle. - Panic-freedom you can audit. Overflow and divide-by-zero are explicit. We can point a tool at the firmware and ask: can this hot path panic?
The goal was never "Rust because it is fashionable." It was: make the dangerous states unrepresentable, then spend the saved review effort on the control loops that actually need a human thinking hard.
Generated, not hand-written, board support
Every board in the stack is described by a TOML file. crab-board-defs reads
it at build time and generates the peripheral init and the RTIC task wiring.
Adding an ADC battery monitor or an SD card slot is a few lines of TOML, not a
weekend of driver plumbing. The generated code is still ordinary Rust the
compiler checks like any other.
Try it without hardware
You do not need a flight controller to see any of this. Crabpilot runs in SITL against Gazebo with real simulated sensors and the real EKF — the next post walks through getting airborne in five minutes.
The whole stack is open source on GitLab. If memory-safe avionics is the kind of problem you want to work on, the contribution guide is waiting.