Projects

Drone Telemetry Engine

Keeping track of a drone when the connection gets unreliable, with a C++20 telemetry engine and a flight black box for when things go wrong.Creator · Complete · September 23, 2026
C++20
POSIX / Linux
Python
MAVLink
ArduPilot SITL
The optional web dashboard during a jammed flight: altitude, battery, speed and GPS cards, an attitude indicator, the ground track, a per-message data-freshness table, and link-quality counters showing corrupted frames, lost frames and 6% loss over the last 10 seconds.
A drone needs reliable information about where it is and how much battery it has left. But the radio link carrying that information can drop messages, deliver them out of order, or corrupt them along the way. Drone Telemetry Engine keeps track of the aircraft through those interruptions. It gives a Python autonomy layer the latest flight data, makes clear when that data is too old to trust, and keeps a black-box recording to help explain a crash. Everything runs against ArduPilot's flight simulator or a recorded flight, with a local dashboard for watching position, attitude, battery, and connection quality. A single C++20 thread receives MAVLink v2 telemetry over UDP, checks each message, and updates the aircraft's state. That state is shared with Python, which checks whether the drone has left its allowed area or is running low on battery, then sends a return-to-launch command if needed. The important part is knowing when to wait. If position or battery readings are stale, the autonomy layer holds off on making a decision. It also waits for a valid GPS fix before setting the home position. For testing, a proxy can deliberately damage the connection, so the same flight can be replayed with missing, late, and corrupted messages.
  • Recovering after a bad message — the parser scans forward one byte at a time after a failed checksum, so a damaged message cannot hide the valid one behind it. Loss tracking also accounts for messages arriving late: a gap in the stream does not always mean something was lost. In the recorded test, the engine's count matched all 1,164 lost frames, and it rejected all 179 corrupted frames.
  • Sharing data without slowing reception — C++ and Python communicate through shared memory using a seqlock. Python checks that a snapshot stayed consistent while it was being read and retries if necessary, while the receive loop keeps running. Stress testing found no partially updated snapshots, though readers can run out of retries under heavy load.
  • Leaving something useful after a crash — a preallocated ring buffer keeps the last 1,024 incoming frames, including damaged ones. The crash handler saves them without allocating memory or taking locks, and a Python tool decodes the recording and checks its CRCs. All 20 recorded crash tests produced complete dumps.
The engine processed about 4 million frames per second on one thread in recorded loopback benchmarks on an Intel Core Ultra 9 185H under WSL2. Saving the black box usually took less than a millisecond, with a 2.2 ms maximum. These measurements come from a laptop running simulated traffic; real flight hardware remains untested. The current version runs on Linux and handles one vehicle and five message types. Long outages can make the loss count incomplete, and a vehicle reboot requires restarting the engine; stale readings still cause the autonomy layer to wait. MAVLink signing is not supported, and the recording can survive a process crash but not a power failure. The code is open source (MIT) on GitHub. The replay demo runs a recorded flight through an unreliable connection on Ubuntu 24.04 or WSL2, without needing the simulator, Docker, or Python packages:
Sh
cmake --preset release && cmake --build --preset release -j
ctest --preset release
bash scripts/demo.sh --replay