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.

Protocol Pro wiring diagram A 500 mm RTK survey quad: Cube Orange+ flight controller, Here4 RTK GNSS on DroneCAN, Jetson Orin Nano companion on DDS and MAVLink, SIYI gimbal camera, ExpressLRS control and a 900 MHz telemetry link. Cube Orange+ ArduCopter 4.7.1, ADS-B carrier ADS-B IN on SERIAL5 4 x ESC 20A Holybro 4S 5000 mAh OVONIC PM02 V3 Holybro BEC 12 V Mateksys BEC 5.2 V Mateksys Here4 RTK CubePilot Jetson Orin Nano NVIDIA SIYI A8 mini SIYI ELRS RP3 RadioMaster RFD900x RFDesign TFmini-S Benewake I2C2 GPS2 TELEM1 GPS1 TELEM2 USB_GH CAN1 AUX1-4 POWER1 I2C 0x10 CRSF 420000 MAVLink 2 57600 SIYI 115200 DDS 921600 MAVLink 2 USB DroneCAN 1000k DShot300 Ethernet RTSP 5.2 V + sensing battery 13.2 to 16.8 V 915 MHz to ground 2.4 GHz from the Boxer GNSS L1 and L5 MAVLink DDS CRSF SIYI DroneCAN I2C DShot Ethernet Battery 5 V

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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.

PartRoleQtyPriceMass
CubePilot Cube Orange+ Standard Set (ADS-B IN carrier board)flight controller1$451.0075 g est.
Holybro X500 V2 ARF kit (frame)frame1$329.00610 g est.
Holybro 2216 KV920 motormotor4in the frame kit60 g est.
Holybro X500 V2 BLHeli S ESC 20Aesc4in the frame kit10 g est.
Holybro 1045 propeller (X500 V2)propeller4in the frame kit13 g est.
OVONIC 14.8V 5000mAh 4S 50C LiPo (XT60 & TRX plug)battery1$45.99448 g
Holybro PM02 V3 (12S) analog power modulepower module1$18.9920 g
Mateksys BEC12S-PRO, set to 12 Vregulator1$31.745 g
Mateksys BEC12S-PRO, set to 5.2 Vregulator1$31.745 g
CubePilot Here4 Multiband RTK GNSSgnss1$255.0060 g
NVIDIA Jetson Orin Nano Super Developer Kit (8GB)companion1$399.00175 g
SIYI A8 mini gimbal cameracamera1$257.4095 g
RadioMaster RP3 V2 ExpressLRS 2.4GHz Nano receiverrc receiver1$22.994.6 g
RFDesign RFD900x-US telemetry modemtelemetry radio1$120.9014 g
Benewake TFmini-S LiDAR (I2C mode)rangefinder1not found5 g
Total$1,963.751.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.

FeatureArduPilotPX4Betaflight
Cube Orange+ build targetyes Official CubeOrangePlus hwdef (STM32H757, with the IOMCU on USART6) built for every release. sourceyes Official target cubepilot_cubeorangeplus, shipped since v1.14 and not interchangeable with Cube Orange firmware. sourceno 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 signingyes SERIALn_PROTOCOL = 2 at SERIALn_BAUD = 57 with the full parameter and mission protocols, and MAVLink 2 signing on MAVLink 2 ports. sourcepartly 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. sourcepartly 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 Jetsonpartly 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. sourceyes The uXRCE-DDS client is in the default Cube Orange+ build; free TELEM2 with MAV_1_CONFIG = 0 and set UXRCE_DDS_CFG = TELEM2. sourceno No DDS or XRCE client exists in the source tree. source
Guided or offboard control from the companion over MAVLinkyes Guided mode accepts SET_POSITION_TARGET_LOCAL_NED, SET_POSITION_TARGET_GLOBAL_INT and SET_ATTITUDE_TARGET from the companion on USB (SERIAL0). sourceyes Offboard mode accepts the same setpoint messages and needs a stream of at least 2 Hz. sourceno 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. sourcepartly 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. sourcepartly 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 GPSyes GPS_RTCM_DATA is reassembled and sent on as uavcan.equipment.gnss.RTCMStream, to every GPS by default (GPS_INJECT_TO = 127). sourceyes QGroundControl sends GPS_RTCM_DATA and UAVCAN_PUB_RTCM = 1 publishes it on the CAN bus. sourceno No GPS_RTCM_DATA handler, and the DroneCAN GNSS code only reads fixes. source
SIYI A8 mini gimbal over its serial protocolyes Native driver: MNT1_TYPE = 8, SERIALn_PROTOCOL = 8 at SERIALn_BAUD = 115; the A8 is listed as supported. sourcepartly 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. sourceno The only serial gimbal support is a head tracker protocol for FPV gimbals, not SIYI's. source
ExpressLRS over CRSF at 420000 baud with telemetryyes SERIALn_PROTOCOL = 23 with RC_OPTIONS bit 13 for the 420k ELRS rate; CRSF telemetry is built in. sourcepartly The crsf_rc driver (RC_CRSF_PRT_CFG) is not in the Cube Orange+ build, so a custom build that enables it is needed. sourceyes serialrx_provider = CRSF, the default, with CRSF telemetry. source
Benewake TFmini-S rangefinder on I2C at 0x10yes RNGFND1_TYPE = 25 (BenewakeTFmini-I2C) and RNGFND1_ADDR = 16. sourcepartly 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. sourcepartly 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 outputsyes MOT_PWM_TYPE = 5; AUX outputs support DShot, and bidirectional DShot is listed for BLHeli32 and AM32 ESCs only. sourceyes DShot works only on FMU outputs, which on the Cube are the AUX pins: select DShot300 for them in Actuator Configuration. sourceyes 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 boardyes The Cube Orange+ defaults already set ADSB_TYPE = 1 and SERIAL5_PROTOCOL = 1 at 57600 baud; AVD_ENABLE = 1 turns on avoidance. sourceyes The receiver is configured automatically in default firmware, and NAV_TRAFF_AVOID chooses warn, return or land. sourceno No ADS-B or traffic avoidance support, and ADSB_VEHICLE is not handled. source
Missions, geofence, return to launch and terrain followingyes Auto missions, fence and RTL are standard, and terrain following uses the terrain database (TERRAIN_ENABLE = 1) or a rangefinder (WP_RFND_USE = 1). sourcepartly 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). sourcepartly 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 POWER1yes BATT_MONITOR = 4, calibrated in Mission Planner. sourceyes BAT1_N_CELLS, then calibrate BAT1_V_DIV and BAT1_A_PER_V in QGroundControl, since the board defaults do not match a PM02. sourceyes battery_meter = ADC with vbat_scale and ibata_scale (pins from the missing board config). source
Attitude control loopyes An angle P loop feeds a rate PID loop at SCHED_LOOP_RATE, 400 Hz by default for Copter. sourceyes A quaternion attitude P loop feeds a rate PID loop at IMU_GYRO_RATEMAX, 400 Hz by default and up to 2000 Hz. sourceyes 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 configuredyes Flat named parameters (BATT_MONITOR, SERIALn_PROTOCOL) in Mission Planner or QGroundControl; this repo generates them in protocol_pro.param. sourceyes Named parameters through QGroundControl setup screens, with optional modules chosen at build time in the board's Kconfig. sourceyes 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.

    TELEM1 stream plan: predicted rate against what ArduCopter sent in 20 seconds.
    StreamMessagePlanned HzMeasured HzMeasured B/s
    HEARTBEATHEARTBEAT11.0021
    RAW_SENSRAW_IMU11.0041
    RAW_SENSSCALED_IMU211.0036
    RAW_SENSSCALED_IMU311.0034
    RAW_SENSSCALED_PRESSURE11.0026
    RAW_SENSSCALED_PRESSURE211.0026
    EXT_STATSYS_STATUS22.0086
    EXT_STATPOWER_STATUS22.0028
    EXT_STATMEMINFO22.0038
    EXT_STATMISSION_CURRENT22.0034
    EXT_STATGPS_RAW_INT22.00104
    EXT_STATNAV_CONTROLLER_OUTPUT22.0066
    RC_CHANSERVO_OUTPUT_RAW11.0024
    RC_CHANRC_CHANNELS11.0054
    POSITIONGLOBAL_POSITION_INT33.00118
    POSITIONLOCAL_POSITION_NED33.00120
    EXTRA1ATTITUDE44.00160
    EXTRA1SIMSTATE44.00224
    EXTRA1AHRS244.00144
    EXTRA1ESC_TELEMETRY_1_TO_444.00224
    EXTRA2VFR_HUD22.0058
    EXTRA3AHRS22.0080
    EXTRA3WIND22.0032
    EXTRA3SYSTEM_TIME22.0044
    EXTRA3TERRAIN_REPORT22.0064
    EXTRA3TERRAIN_REQUEST20.5014
    EXTRA3BATTERY_STATUS22.00106
    EXTRA3EKF_STATUS_REPORT22.0068
    EXTRA3VIBRATION22.0064

    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.

    LevelRuleWhereFinding

    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.
    Pythonpython -m week04
    $ 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
    C++17week04/cpp
    $ cmake -S week04/cpp -B build/cpp4 && cmake --build build/cpp4 -j
    $ echo "crc x25 313233343536373839" | ./build/cpp4/protocol_tool