crabpilot.dev
BlogPricing
← All posts

Why we built a UAV autopilot stack in Rust

May 12, 2026 · Crabpilot team

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.