cu-flight-controller
A bare-metal quadcopter flight controller implemented end-to-end using Copper components.
Overview
This example demonstrates a complete flight controller running on the MicoAir H743 board (STM32H743). It showcases Copper's ability to run deterministic, real-time control loops on embedded hardware with zero dynamic allocation during runtime.
Hardware
- MCU: STM32H743VIT @ 400MHz
- IMU: BMI088 (accelerometer + gyroscope)
- RC Input: CRSF protocol (ExpressLRS compatible)
- ESC Output: BDShot (bidirectional DShot with telemetry)
- VTX/OSD: MSP DisplayPort protocol
- Storage: MicroSD card for logging
- Battery: ADC voltage monitoring
See doc/PINOUT.md for the complete pinout reference.
Architecture
The flight controller uses a cascaded control architecture:
RC Input (CRSF) -> RC Mapper -> Attitude Controller -> Rate Controller -> Mixer -> ESCs (BDShot)
^ ^
| |
IMU -> Calibrator -> AHRS ---------+
Task Graph
| Task | Description |
|---|---|
bmi088 |
BMI088 IMU driver (accelerometer + gyroscope) |
imu_cal |
Gyroscope bias calibration on arm |
ahrs |
Attitude and Heading Reference System |
mapper |
RC channel mapping and arm/mode logic |
attitude |
Outer loop PID (angle to rate setpoint) |
rate |
Inner loop PID (rate to motor commands) |
mixer0-3 |
QuadX motor mixing |
battery_adc |
Battery voltage monitoring |
vtx_osd |
MSP DisplayPort OSD rendering |
led_blink |
Status LED heartbeat |
Flight Modes
- Angle: Self-leveling mode with attitude hold
- Acro: Rate mode for aerobatic flight
- Position Hold: (placeholder for GPS integration)
Features
- Airmode: Maintains control authority at zero throttle for aerobatic maneuvers
- Expo curves: Configurable stick expo for smoother control
- Gyro calibration: Automatic bias calibration on arm
- Zero-copy logging: Binary logs to SD card via unified logger
Building
Firmware (for flashing to hardware)
# Build and flash with text logging (debug)
# Build and flash release (optimized, no text logs)
# Build and flash debug profile
Log Reader (host tool)
# Extract CopperLists from log file
# Check log file integrity
# Extract text logs (requires log index)
Replay Debug Server
To replay a recorded simulation log through the remote debug API:
# or, for parity with other examples:
The replay target uses the standardized replay contract:
--debug-baseselects the remote debug namespace--log-baseselects the recorded Copper log to inspect--replay-log-baseselects the per-session replay log template
If you are building another replay target, follow the same pattern with
cu29::replay::{ReplayCli, ReplayDefaults, per_session_replay_log_base, serve_remote_debug}.
Python GNSS Extraction
You can use the PyO3 bindings to iterate CopperLists directly from Python and extract GNSS fields without going through JSON.
This is an offline log-analysis workflow, not a runtime Python task. Python only touches data that Copper has already recorded, so this does not affect the realtime behavior of the flight controller itself.
# Build the Python extension module
# Print GNSS latitude/longitude from the flight-controller sim log
The script is at python/print_gnss_from_log.py and can also be run directly:
Implementation notes:
src/python_module.rsexposes an app-specific#[pymodule]- it uses
gen_cumsgs!("copperconfig.ron")so the CopperList type matches this app - the Python script imports that module and iterates typed CopperLists plus runtime lifecycle records
This pattern is the recommended Python story in Copper: post-process logs in Python after the run, keep Python off the control path during the run.
RC Tester (simulation)
# Test RC input via joystick
Simulator (Bevy + Copper)
# Run the normal full-window simulator
# Run the split BevyMon simulator
# Run the split BevyMon simulator in the browser
# Build a deployable browser bundle into dist/flight-controller with hashed asset filenames
The split BevyMon path reuses the same cu_bevymon::spawn_split_layout(...) shell as
cu_rp_balancebot and cu_bevymon_demo, but the left panel still runs the real flight-controller
sim world, OSD, and help overlays.
RC Input In Simulation
The simulator reads RC input from a host joystick device (evdev). By default it only auto-connects to
radio-style joystick profiles, to avoid false positives from keyboards/mice/gamepads that also expose joystick interfaces.
Environment variables:
# Prefer a specific device name substring (case-insensitive)
CU_SIM_JOYSTICK="radiomaster"
# Allow generic/non-radio joystick devices as RC input
CU_SIM_ALLOW_GENERIC_JOYSTICK=1
Notes:
- If no compatible RC joystick is found, the sim falls back to keyboard controls.
- When connected, the bottom-right help panel shows the selected device name and technical axis bindings (
ABS_X,ABS_RY, etc.). - USB and Bluetooth radios both work if they appear as a joystick device on the host.
Compatible TX/RX Notes
- Simulation path: no receiver is used directly; input is read from the host joystick interface.
- Auto-detected TX joystick profiles:
- ExpressLRS-style USB joystick names (
expresslrs,radiomaster) - OpenTX / EdgeTX USB joystick names (
opentx,edgetx)
- ExpressLRS-style USB joystick names (
- Firmware path (real hardware): RC input is CRSF on UART, so use a CRSF-compatible RX link (for example ExpressLRS/Crossfire-class receivers and compatible transmitters).
Configuration
The task graph is defined in copperconfig.ron. Key configurable parameters:
Rate Controller
config: {
"kp": 0.04,
"ki": 0.0,
"kd": 0.0005,
"airmode": true,
"airmode_start_throttle_percent": 20.0,
}
Attitude Controller
config: {
"angle_limit_deg": 60.0,
"acro_rate_dps": 180.0,
"acro_expo": 0.3,
"kp": 1.0,
}
RC Mapper
config: {
"arm_channel": 4,
"arm_min": 1700,
"arm_max": 1811,
"mode_channel": 5,
}
Motor Layout
QuadX configuration (props out):
Front
3 1
\ /
X
/ \
2 0
Rear
| Motor | Position | Rotation |
|---|---|---|
| 0 | Rear Right | CCW |
| 1 | Front Right | CW |
| 2 | Rear Left | CW |
| 3 | Front Left | CCW |
Development
Attaching to Running Target
Viewing Logs
The firmware logs to the SD card in Copper's binary format. Use the log reader tools to extract and analyze:
# Extract structured data
# Extract text logs (when compiled with textlogs feature)
Dependencies
Key Copper components used:
cu29- Core runtimecu-ahrs- Attitude estimationcu-bdshot- Bidirectional DShot ESC protocolcu-crsf- CRSF RC protocol (ExpressLRS)cu-msp-bridge- MSP protocol for VTX/OSDcu-pid- PID controllercu-micoairh743- MicoAir H743 HAL bundlecu-logmon- Log monitoring