Module 8 — Coding the flight controller
The moment the stack stops being a black box: you build the firmware from source, script the autopilot, and speak its protocols.
🟢 Foundations. Three coding "surfaces", from gentle to deep:
- Radio scripting — Lua on EdgeTX: custom telemetry screens, warnings, model logic.
- Autopilot scripting — Lua onboard ArduPilot: react to flight state, drive servos/LEDs, small missions — no toolchain needed.
- Firmware itself — C/C++: Betaflight, INAV, ArduPilot, PX4 are open repositories waiting for your commits.
Set up the universal toolchain once: Git, the ARM GCC cross-compiler, and the project's build system; build an unmodified firmware and flash it. That single loop (edit → build → flash → log) is 80 % of embedded development.
🟡 Practitioner. Learn the two protocols everything speaks. MSP (MultiWii Serial Protocol) is how configurators talk to Betaflight. MAVLink is the lingua franca of ArduPilot/PX4: framed messages with system-ID, component-ID and message-ID (HEARTBEAT, ATTITUDE, COMMAND_LONG…). From Python:
# pip install pymavlink — run against SITL first, never a live quad with props!
from pymavlink import mavutil
link = mavutil.mavlink_connection('udp:127.0.0.1:14550')
link.wait_heartbeat()
print("Connected: sys", link.target_system)
link.arducopter_arm()
link.mav.command_long_send(
link.target_system, link.target_component,
mavutil.mavlink.MAV_CMD_NAV_TAKEOFF, 0,
0, 0, 0, 0, 0, 0, 10) # takeoff to 10 m
And onboard, ArduPilot Lua (drop a .lua file on the SD card):
-- scripts/alt_report.lua : say altitude once per second
function update()
local pos = ahrs:get_relative_position_NED_home()
if pos then
gcs:send_text(6, string.format("Alt: %.1f m", -pos:z()))
end
return update, 1000
end
return update()
SITL (software-in-the-loop) lets you crash a simulated quad a thousand times for free — make it your default target.
🔴 Advanced. Read real firmware architecture: Betaflight's src/main/flight/ (PID, mixer) vs drivers/; ArduPilot's vehicle/libraries/ split and its HAL. Embedded-C literacy: interrupts, DMA, volatile, fixed-point vs float, why printf in an ISR crashes things, unit-testing flight code against recorded logs. Make a first real contribution: reproduce a bug, write the fix, pass CI, survive code review.
⚫ Master. You can write a minimal flight controller from scratch (gyro driver → complementary filter → rate PID → mixer → DShot) as an educational project, bridge ArduPilot to ROS 2 / MAVSDK for companion-computer autonomy, and design your own MAVLink messages for custom payloads — like the head-tracked gimbal from this site's project pages.
Mastery checklist
- Build Betaflight and ArduPilot from source and flash your own binaries.
- Write a Lua script that changes behavior in flight (e.g., auto-tilt gimbal on speed).
- Explain a MAVLink COMMAND_LONG frame byte-by-byte.
🖼️ Image ideas: screenshot of your own SITL session + Mission Planner; terminal build output (your screenshots = your copyright).
📚 Free resources: ArduPilot dev wiki (Lua & building); Betaflight developer docs; MAVLink developer guide; pymavlink examples repo.