Skip to content

Latest commit

 

History

History

README.md

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)
just fw

# Build and flash release (optimized, no text logs)
just fwr

# Build and flash debug profile
just fwd

Log Reader (host tool)

# Extract CopperLists from log file
just logreader log=logs/embedded.copper

# Check log file integrity
just fsck log=logs/embedded.copper

# Extract text logs (requires log index)
just textlogs log=logs/embedded.copper

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
just py-build

# Print GNSS latitude/longitude from the flight-controller sim log
just py-gnss log=logs/flight_controller_sim.copper

The script is at python/print_gnss_from_log.py and can also be run directly:

python3 python/print_gnss_from_log.py logs/flight_controller_sim.copper

Implementation notes:

  • src/python_module.rs exposes 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
just rc

Simulator (Bevy + Copper)

# Run the normal full-window simulator
just

# Run the split BevyMon simulator
just bevy

# Run the split BevyMon simulator in the browser
just web

# Build a deployable browser bundle into dist/flight-controller with hashed asset filenames
just web-dist

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" just sim

# Allow generic/non-radio joystick devices as RC input
CU_SIM_ALLOW_GENERIC_JOYSTICK=1 just sim

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)
  • 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

just attach

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
just logreader

# Extract text logs (when compiled with textlogs feature)
just textlogs

Dependencies

Key Copper components used:

  • cu29 - Core runtime
  • cu-ahrs - Attitude estimation
  • cu-bdshot - Bidirectional DShot ESC protocol
  • cu-crsf - CRSF RC protocol (ExpressLRS)
  • cu-msp-bridge - MSP protocol for VTX/OSD
  • cu-pid - PID controller
  • cu-micoairh743 - MicoAir H743 HAL bundle
  • cu-logmon - Log monitoring