Week 4, skill booster 3
Protocol Pro.
A drone designed from parts you can buy today, wired pin by pin, and proven compatible by code: a design rule checker, every protocol on it implemented from its specification, and the flight controller's parameters loaded into the real ArduCopter 4.7.1 firmware.
- check
- 0 errors, 17 warnings, 61 checks passed on 9 links and 8 protocols
- firmware
- 72 of 75 generated parameters accepted by ArduCopter 4.7.1 in simulation
- protocols
- 299 MAVLink messages byte identical to pymavlink; DroneCAN, RTCM, CAN, CRSF, SBUS and DShot from scratch; 2,908 C++ parity cases
- airframe
- 1.99 kg, thrust to weight 2.61, 11.0 minutes of hover
Every wire, explained.
The diagram is drawn from the design file, not by hand. Click a wire for its pin by pin cable and what the checker found on it; click a part for its specs, price, source and anything that had to be estimated.
The lecture, in four answers.
Focus topic 3 asked four questions about flight controllers. Short answers, each tied to this drone. Full notes: docs/week04/NOTES.md.
-
Question 1
What does a flight controller do, and how is it different from a Jetson?
- The flight controller keeps the drone in the air. It fuses IMU, GPS, barometer and compass into an attitude and position, and runs the control loops hundreds of times a second, whatever else is happening.
- The onboard computer decides what to do: detection, planning, mission logic. On this drone the Jetson Orin Nano talks to the Cube over DDS for ROS 2 and over MAVLink on USB, and never touches a motor.
-
Question 2
What sensors connect to a flight controller?
- Inside the Cube: three IMUs (two on a heated, vibration isolated board), barometers and a compass.
- Outside, on this design: a Here4 RTK GPS with its own compass and barometer on CAN, a TFmini-S rangefinder on I2C, an ExpressLRS receiver, the ADS-B receiver on the carrier board, and the power module's voltage and current.
-
Question 3
Which protocols connect it to its peripherals?
- UART for point to point links: telemetry, the companion, the gimbal and the receiver (CRSF). I2C for slow sensors on a shared bus. CAN for a robust bus, here DroneCAN to the Here4.
- MAVLink is a message format on top of them, carrying telemetry, commands, parameters and RTK corrections. Every one is implemented here and checked against reference libraries.
-
Question 4
How does firmware shape what it can do?
- The same board is a different machine under each firmware. On this drone ArduPilot supports 14 of 15 features as designed, PX4 9 of 15 with 6 more needing changes, and Betaflight cannot run on the Cube at all.
- Betaflight trades autonomy for a faster inner loop, built for a pilot's hands. Every feature, with sources.
The brief, and what shipped.
The Week 4 skill booster: design your own drone, pick a flight controller and sensors off the internet, draw the wiring, and think about communication protocols and compatibility.
-
Design
Pick the parts
Design your own drone! Pick out a flight controller and some sensors off the internet.
- The club's Cube Orange+ with a Here4 RTK GPS, Jetson Orin Nano, SIYI gimbal, ExpressLRS, RFD900x and a TFmini-S, on a Holybro X500 V2.
- A researched catalog: every figure has a source, and everything a vendor does not publish is marked as an estimate with the reasoning.
- A propulsion model calibrated to Holybro's own flight time and payload claims.
-
Wiring
Draw the model
Draw a model of what the wiring setup looks like to connect everything together!
- A generated diagram and a pin by pin harness: TX crossed to RX, flow control, who powers what.
- It catches the TFmini-S cable: the sensor's pin order is the reverse of the Cube's.
-
Protocols
Ensure compatibility
Think about communication protocols and ensure compatibility.
- 30 rules: logic levels, baud rates, receive DMA, I2C addresses, CAN load and termination, 5 V budgets, regulator loads, bandwidth, firmware features, ESC and connector ratings.
- An ArduPilot parameter file generated from the wiring and validated against 4.7.1's own metadata.
- MAVLink, DroneCAN, CAN, RTCM, CRSF, SBUS, DShot, UART and I2C implemented from the specifications and checked against reference libraries.
-
Beyond
Prove it on real firmware
Documentation is key.
- ArduCopter 4.7.1 built from source and flown in simulation with this airframe's mass and inertia, driven only by this repo's MAVLink code.
- The link budget predicted, then measured on the firmware; MAVLink signing set up and verified.
- The PID slides as a simulator you can tune, next to ArduPilot's real response.
Parts, weight and flight time.
Airborne parts only; the ground side is a laptop, a second RFD900x, a RadioMaster Boxer and a Here4 as the RTK base. Masses marked "est." are not published by the vendor.
| Part | Role | Qty | Price | Mass |
|---|---|---|---|---|
| CubePilot Cube Orange+ Standard Set (ADS-B IN carrier board) | flight controller | 1 | $451.00 | 75 g est. |
| Holybro X500 V2 ARF kit (frame) | frame | 1 | $329.00 | 610 g est. |
| Holybro 2216 KV920 motor | motor | 4 | in the frame kit | 60 g est. |
| Holybro X500 V2 BLHeli S ESC 20A | esc | 4 | in the frame kit | 10 g est. |
| Holybro 1045 propeller (X500 V2) | propeller | 4 | in the frame kit | 13 g est. |
| OVONIC 14.8V 5000mAh 4S 50C LiPo (XT60 & TRX plug) | battery | 1 | $45.99 | 448 g |
| Holybro PM02 V3 (12S) analog power module | power module | 1 | $18.99 | 20 g |
| Mateksys BEC12S-PRO, set to 12 V | regulator | 1 | $31.74 | 5 g |
| Mateksys BEC12S-PRO, set to 5.2 V | regulator | 1 | $31.74 | 5 g |
| CubePilot Here4 Multiband RTK GNSS | gnss | 1 | $255.00 | 60 g |
| NVIDIA Jetson Orin Nano Super Developer Kit (8GB) | companion | 1 | $399.00 | 175 g |
| SIYI A8 mini gimbal camera | camera | 1 | $257.40 | 95 g |
| RadioMaster RP3 V2 ExpressLRS 2.4GHz Nano receiver | rc receiver | 1 | $22.99 | 4.6 g |
| RFDesign RFD900x-US telemetry modem | telemetry radio | 1 | $120.90 | 14 g |
| Benewake TFmini-S LiDAR (I2C mode) | rangefinder | 1 | not found | 5 g |
| Total | $1,963.75 | 1.99 kg |
- 1.99 kg all up
- 2.61 thrust to weight; 60 percent throttle to hover.
- 11.0 minutes of hover
- To 20 percent charge, 21.7 A at hover, avionics included.
- Calibrated, not guessed
- The propeller and resistance terms are fitted so the stock X500 V2 kit gives Holybro's own 18 minutes and 1 kg at 70 percent throttle.
Would it fly on PX4 or Betaflight?
Every feature this design relies on, on ArduPilot 4.7.1, PX4 v1.16.2 and Betaflight 2026.6.2, with the parameter or driver involved and a link to the firmware's own docs or source. ArduPilot: 14 of 15 as designed. PX4: 9 of 15, 6 with changes, none lost. Betaflight: 5 of 15, 6 lost, starting with the board.
| Feature | ArduPilot | PX4 | Betaflight |
|---|---|---|---|
| Cube Orange+ build target | yes Official CubeOrangePlus hwdef (STM32H757, with the IOMCU on USART6) built for every release. source | yes Official target cubepilot_cubeorangeplus, shipped since v1.14 and not interchangeable with Cube Orange firmware. source | no No Cube Orange or Cube Orange+ board config exists; 2026.6 only adds a generic STM32H757 MCU, and there is no driver for the IOMCU that drives the 8 MAIN outputs, so a custom board config would be needed. source |
| MAVLink 2 telemetry, parameters, missions and signing | yes SERIALn_PROTOCOL = 2 at SERIALn_BAUD = 57 with the full parameter and mission protocols, and MAVLink 2 signing on MAVLink 2 ports. source | partly MAVLink 2 to the ground station with parameters and missions on TELEM1, but message signing exists only in the main branch, not in v1.16.2 or v1.17.0. source | partly The MAVLink serial function streams telemetry and 2026.6 adds mission upload, but there is no MAVLink parameter protocol and no signing. source |
| ROS 2 over micro XRCE-DDS to the Jetson | partly AP_DDS is left out of the standard Cube Orange+ build, so it needs a custom build with DDS, then SERIALn_PROTOCOL = 45 and DDS_ENABLE = 1. source | yes The uXRCE-DDS client is in the default Cube Orange+ build; free TELEM2 with MAV_1_CONFIG = 0 and set UXRCE_DDS_CFG = TELEM2. source | no No DDS or XRCE client exists in the source tree. source |
| Guided or offboard control from the companion over MAVLink | yes Guided mode accepts SET_POSITION_TARGET_LOCAL_NED, SET_POSITION_TARGET_GLOBAL_INT and SET_ATTITUDE_TARGET from the companion on USB (SERIAL0). source | yes Offboard mode accepts the same setpoint messages and needs a stream of at least 2 Hz. source | no There is no guided or offboard mode; MAVLink input only accepts RC_CHANNELS_OVERRIDE and RADIO_STATUS, and USB speaks MSP. source |
| DroneCAN GPS, compass, barometer, LED and buzzer (Here4) | yes CAN_P1_DRIVER = 1, CAN_D1_PROTOCOL = 1 and GPS1_TYPE = 9; every Here4 sensor and the LED and buzzer are found automatically. source | partly UAVCAN_ENABLE = 2 with GPS and compass on by default and UAVCAN_SUB_BARO = 1 for the barometer, but the docs name only the Here3, not the Here4. source | partly 2026.6 adds initial DroneCAN with GNSS, compass and ESCs but no barometer, LED or buzzer; 2025.12 has no CAN at all. source |
| RTK corrections from GPS_RTCM_DATA forwarded to the CAN GPS | yes GPS_RTCM_DATA is reassembled and sent on as uavcan.equipment.gnss.RTCMStream, to every GPS by default (GPS_INJECT_TO = 127). source | yes QGroundControl sends GPS_RTCM_DATA and UAVCAN_PUB_RTCM = 1 publishes it on the CAN bus. source | no No GPS_RTCM_DATA handler, and the DroneCAN GNSS code only reads fixes. source |
| SIYI A8 mini gimbal over its serial protocol | yes Native driver: MNT1_TYPE = 8, SERIALn_PROTOCOL = 8 at SERIALn_BAUD = 115; the A8 is listed as supported. source | partly No SIYI driver; it works only if the A8 mini speaks MAVLink Gimbal Protocol v2 (MNT_MODE_IN = 4, MNT_MODE_OUT = 2), which SIYI does not document, or through the companion. source | no The only serial gimbal support is a head tracker protocol for FPV gimbals, not SIYI's. source |
| ExpressLRS over CRSF at 420000 baud with telemetry | yes SERIALn_PROTOCOL = 23 with RC_OPTIONS bit 13 for the 420k ELRS rate; CRSF telemetry is built in. source | partly The crsf_rc driver (RC_CRSF_PRT_CFG) is not in the Cube Orange+ build, so a custom build that enables it is needed. source | yes serialrx_provider = CRSF, the default, with CRSF telemetry. source |
| Benewake TFmini-S rangefinder on I2C at 0x10 | yes RNGFND1_TYPE = 25 (BenewakeTFmini-I2C) and RNGFND1_ADDR = 16. source | partly The tfmini driver supports the TFmini-S only over UART (SENS_TFMINI_CFG); the only Benewake I2C driver is tf02pro, and whether it works with a TFmini-S is unconfirmed. source | partly rangefinder_hardware = TFMINI is serial only, so the sensor would have to move to a UART. source |
| DShot300 to BLHeli_S ESCs on the AUX outputs | yes MOT_PWM_TYPE = 5; AUX outputs support DShot, and bidirectional DShot is listed for BLHeli32 and AM32 ESCs only. source | yes DShot works only on FMU outputs, which on the Cube are the AUX pins: select DShot300 for them in Actuator Configuration. source | yes motor_pwm_protocol = DSHOT300, and dshot_bidir = ON for RPM filtering on Bluejay or JESC firmware (given a custom board config for the AUX timers). source |
| ADS-B receiver built into the carrier board | yes The Cube Orange+ defaults already set ADSB_TYPE = 1 and SERIAL5_PROTOCOL = 1 at 57600 baud; AVD_ENABLE = 1 turns on avoidance. source | yes The receiver is configured automatically in default firmware, and NAV_TRAFF_AVOID chooses warn, return or land. source | no No ADS-B or traffic avoidance support, and ADSB_VEHICLE is not handled. source |
| Missions, geofence, return to launch and terrain following | yes Auto missions, fence and RTL are standard, and terrain following uses the terrain database (TERRAIN_ENABLE = 1) or a rangefinder (WP_RFND_USE = 1). source | partly Missions, geofences and Return mode are standard, but terrain following is not available in missions, only in Position and Altitude modes (MPC_ALT_MODE = 1). source | partly GPS Rescue and position hold are standard; the 2026.6 waypoint autopilot is experimental and tested only in simulation, and there is no terrain following. source |
| Analog power module (PM02 V3) on POWER1 | yes BATT_MONITOR = 4, calibrated in Mission Planner. source | yes BAT1_N_CELLS, then calibrate BAT1_V_DIV and BAT1_A_PER_V in QGroundControl, since the board defaults do not match a PM02. source | yes battery_meter = ADC with vbat_scale and ibata_scale (pins from the missing board config). source |
| Attitude control loop | yes An angle P loop feeds a rate PID loop at SCHED_LOOP_RATE, 400 Hz by default for Copter. source | yes A quaternion attitude P loop feeds a rate PID loop at IMU_GYRO_RATEMAX, 400 Hz by default and up to 2000 Hz. source | yes The PID loop runs on every gyro sample by default (pid_process_denom = 1), typically 4 to 8 kHz, which is why it feels so sharp in manual flight. source |
| How it is configured | yes Flat named parameters (BATT_MONITOR, SERIALn_PROTOCOL) in Mission Planner or QGroundControl; this repo generates them in protocol_pro.param. source | yes Named parameters through QGroundControl setup screens, with optional modules chosen at build time in the board's Kconfig. source | yes CLI set commands or the Configurator app, with optional features chosen when the firmware is built in the cloud. source |
What each protocol puts on the wire.
Real captures from this week's encoders. UART frames every byte with a start and stop bit; SBUS inverts it; DShot encodes each bit as a pulse width; CAN inserts a stuff bit after five equal bits (highlighted) so every node stays in step.
299 of 299MAVLink messages in the ArduPilot dialect encode byte for byte like pymavlink, from the XML definitions, signing included.
15 DroneCAN typesparsed from the DSDL files, with signatures and multi frame transfers identical to pydronecan.
2,908 caseswhere the C++17 port and the Python agree exactly: CRCs, SBUS, CRSF, DShot, CAN and MAVLink framing.
One RTK correction, five protocols.
An RTK base station's corrections reach the drone's GPS through RTCM, MAVLink, a 915 MHz radio, UART, DroneCAN and CAN. Each hop is encoded with this week's code and decoded again.
Checked on the real firmware.
ArduCopter 4.7.1, built from the release tag and run in software in the loop. This repo's own MAVLink code loads the parameter file, measures the telemetry link, sets up signing and flies this airframe.
72 of 75parameters accepted. The three it refuses are the ones simulation cannot have: two flow control switches and DDS, which the stable build leaves out.
2,140 of 2,375 B/smeasured against predicted on TELEM1. The prediction is an upper bound: MAVLink 2 trims trailing zeros.
36 signedpackets from the autopilot verified with this repo's SHA-256 signing; unsigned requests on TELEM1 are then refused.
| Stream | Message | Planned Hz | Measured Hz | Measured B/s |
|---|---|---|---|---|
| HEARTBEAT | HEARTBEAT | 1 | 1.00 | 21 |
| RAW_SENS | RAW_IMU | 1 | 1.00 | 41 |
| RAW_SENS | SCALED_IMU2 | 1 | 1.00 | 36 |
| RAW_SENS | SCALED_IMU3 | 1 | 1.00 | 34 |
| RAW_SENS | SCALED_PRESSURE | 1 | 1.00 | 26 |
| RAW_SENS | SCALED_PRESSURE2 | 1 | 1.00 | 26 |
| EXT_STAT | SYS_STATUS | 2 | 2.00 | 86 |
| EXT_STAT | POWER_STATUS | 2 | 2.00 | 28 |
| EXT_STAT | MEMINFO | 2 | 2.00 | 38 |
| EXT_STAT | MISSION_CURRENT | 2 | 2.00 | 34 |
| EXT_STAT | GPS_RAW_INT | 2 | 2.00 | 104 |
| EXT_STAT | NAV_CONTROLLER_OUTPUT | 2 | 2.00 | 66 |
| RC_CHAN | SERVO_OUTPUT_RAW | 1 | 1.00 | 24 |
| RC_CHAN | RC_CHANNELS | 1 | 1.00 | 54 |
| POSITION | GLOBAL_POSITION_INT | 3 | 3.00 | 118 |
| POSITION | LOCAL_POSITION_NED | 3 | 3.00 | 120 |
| EXTRA1 | ATTITUDE | 4 | 4.00 | 160 |
| EXTRA1 | SIMSTATE | 4 | 4.00 | 224 |
| EXTRA1 | AHRS2 | 4 | 4.00 | 144 |
| EXTRA1 | ESC_TELEMETRY_1_TO_4 | 4 | 4.00 | 224 |
| EXTRA2 | VFR_HUD | 2 | 2.00 | 58 |
| EXTRA3 | AHRS | 2 | 2.00 | 80 |
| EXTRA3 | WIND | 2 | 2.00 | 32 |
| EXTRA3 | SYSTEM_TIME | 2 | 2.00 | 44 |
| EXTRA3 | TERRAIN_REPORT | 2 | 2.00 | 64 |
| EXTRA3 | TERRAIN_REQUEST | 2 | 0.50 | 14 |
| EXTRA3 | BATTERY_STATUS | 2 | 2.00 | 106 |
| EXTRA3 | EKF_STATUS_REPORT | 2 | 2.00 | 68 |
| EXTRA3 | VIBRATION | 2 | 2.00 | 64 |
In 4.7 the stream rates are MAVn_*, where n counts MAVLink ports in serial order: USB is MAV1 and TELEM1 is MAV2. The experiment confirms it: 4.0 Hz of ATTITUDE on TELEM1 from MAV2_EXTRA1 = 4. The rates are also only read at boot.
Isabelle, Preeti and Darren.
The PID slides as a simulator: one pitch axis with motor lag, a 10 degree step, then a gust at 1.5 s that only the integral term can cancel. The same code runs in Python and in this page. Notice that no single loop gains give both a clean step and zero gust offset: the integral winds up during the climb.
- Rise
- Overshoot
- Settles (2%)
- Gust offset
Unstable: the oscillation grows until the motors saturate.
And the real thing.
ArduCopter's cascaded controller with its default gains, in the simulator above on this airframe's inertia and torque (orange), against ArduCopter 4.7.1 SITL flying the same airframe (white). Rise time 0.33 s against 0.32 s.
The compatibility report.
What python -m week04 check says about this design. Warnings are actions, not failures: order this cable, flash that setting, mind this margin. Each rule is also tested by breaking the design on purpose.
| Level | Rule | Where | Finding |
|---|
Run it.
Everything on this page comes out of python -m week04, and the protocol codecs also ship as a dependency free C++17 tool.
check,harness,params,diagram,performance,budget: the design.journey,frame,decode: the protocols.sitl: the firmware experiments, given an ArduPilot build.
$ python -m week04 check
$ python -m week04 params --out protocol_pro.param
$ python -m week04 journey
$ python -m week04 frame can --message 0x1004260A --extended
$ python -m week04 decode docs/week04/sitl_flight.tlog
$ cmake -S week04/cpp -B build/cpp4 && cmake --build build/cpp4 -j
$ echo "crc x25 313233343536373839" | ./build/cpp4/protocol_tool