LTE-Controlled Quadcopter
active2026-07 · drone · ardupilot · lte · mavlink · raspberry-pi · telemetry
Commands and monitors a quadcopter over a 4G LTE cellular link, not a short-range radio.




What it is
A normal drone flies on a short-range radio link — line of sight, a few kilometers at best, and it needs a dedicated ground antenna. This project replaces that link with a 4G LTE (Long-Term Evolution) cellular modem, so the same quadcopter can be commanded and watched from anywhere with cell coverage. A Raspberry Pi 5 riding on the aircraft carries flight commands, telemetry, and video across the cellular network to a laptop ground station.
Why it exists
The itch was to fly beyond radio range using infrastructure that already blankets the country, instead of building a specialized long-range ground station. The open question underneath it: is a consumer cellular link good enough to command a flying vehicle safely?
The honest answer so far is mostly, and it tells you when it isn’t.
What it does today
- Routes MAVLink2 — the standard drone command-and-telemetry protocol — between the flight controller and a laptop ground control station (GCS) over the LTE link and a ZeroTier peer-to-peer overlay network. Heartbeats and mode changes round-trip end to end.
- Streams onboard H.264 video to the laptop over SRT (Secure Reliable Transport) at 640×480 / 30 fps at roughly 300 ms of latency — down from the 2 seconds it started at, tuned live over several flights.
- A phone running QGroundControl joins as a second ground station; its joystick command path to the flight controller is confirmed working.
- A floating macOS dashboard polls the aircraft about once per second and draws six colour-coded health tiles — cellular signal, both GPS receivers, flight-controller heartbeat, command path, link freshness — plus a live camera thumbnail.
- Records every flight to the aircraft’s own SD card — video in one-minute chunks, plus cellular signal strength and the serving cell tower every five seconds. This is the black box: the ground station can only record what survives the link, so the outages worth diagnosing are exactly the ones it cannot capture.
- Self-heals a dead cellular link without a human in the loop. A watchdog on the aircraft pings the data path and, if it stays dead, climbs an escalating ladder of remedies — redial, restart the modem manager, reset the modem’s USB connection, and finally reboot the companion computer. It has recovered the link in flight, unprompted.
- 327 automated tests cover the routing, telemetry, video, and provisioning logic; hardware-only paths sit behind a separate test marker so the suite runs without the aircraft attached.
On the aircraft
- Flight controller — Sequre H743 G2 running ArduCopter 4.6.3.
- Companion computer — Raspberry Pi 5 on a 3D-printed mounting plate, running the routing, telemetry, and video stack.
- Cellular link — Quectel EG25-G modem on a Sixfab Raspberry Pi HAT, with two paddle-style LTE antennas (main + diversity) standing off the stack. A second aircraft carries a SIM7600G-H modem instead — deliberately different, see below.
- Camera — Arducam IMX291 USB low-light camera, H.264-encoded on board before it touches the cellular uplink.
- GNSS — BZ-251 GNSS-and-compass puck as the primary receiver; the LTE modem’s built-in GNSS rides along as a logged standby second source.
- Radio control — RadioMaster XR4 ExpressLRS (ELRS) 2.4 GHz receiver in MAVLink mode, the visual-line-of-sight backup to the cellular link.
- Battery — 6-cell lithium-ion pack built on Amprius cells (not LiPo), which is why the low-voltage failsafe waits on measured thresholds.
Under the hood
Python on a Raspberry Pi 5: ModemManager drives the cellular modem, mavlink-router fans one MAVLink stream out to several clients, ZeroTier provides a NAT-punching overlay so the laptop and the aircraft share a private network over the public cellular carrier, and a thin PyQt6 dashboard sits on top of pure, unit-tested threshold logic. Wiring is encoded by function rather than by board pin numbers, so the same code targets more than one H743-class flight-controller board.
There are now two aircraft, deliberately not identical — one carries a Quectel EG25-G modem, the other a SIM7600G-H — which has turned out to be useful: when something breaks, the difference between the two birds is often the fastest way to find out whether it’s the hardware or the code.
State & direction
- Flying. The full chain — cellular command, telemetry, video, and a dashboard that tells you the truth about the link — works in the air.
- The current work is no longer “make it fly” but “find out why the link drops and make it recover itself.” Three genuinely different failure modes have now been separated, and only one of them is a bug we can fix in software.
- The battery low-voltage failsafe is deliberately off until the lithium-ion pack’s real thresholds are measured — a known safety gap, left explicit rather than set wrong.
- The props-off failsafe matrix is a project rule that still has not been run. It is the honest next task.
- All work is local; nothing has been pushed to a public repository.
Flight log
2026-07-14 — A long field day, and the instruments to stop guessing
Second flying day, and mostly a lesson in how easy it is to be confident and wrong.
Started with a dead link that wasn’t the code. Moving one aircraft’s companion computer onto the other’s flight controller produced total silence on the telemetry wire. Same cable, same Pi, same settings — nothing. Six different theories (wiring, board revision, stream rates, a competing device on the same pins) each got tested and each was wrong. Moving to a different serial port on the flight controller worked instantly, first try. The port itself is dead hardware. Nothing in software was ever going to fix it, and no amount of reasoning would have found it faster than swapping the wire.
Video latency went from 2 seconds to 300 ms. The 2-second figure turned out to be hardcoded in a ground-station config file that had been quietly overriding every attempt to lower it. Worth knowing: this video protocol negotiates latency as the larger of what the two ends ask for, so the aircraft’s setting is only a floor — the real control lives on the ground. That’s now true by design, which means tuning it never requires restarting anything on a flying aircraft.
Then the link died in flight. Twice. The aircraft was already heading home on a previously-issued Return-to-Launch when the picture and telemetry went away, which is the only reason this is a log entry and not a recovery story. The backup control radio never wavered.
So the day’s real work became a watchdog. It pings the cellular data path — deliberately not the ground station, or closing a laptop lid would trigger it — and if the path stays dead it escalates: redial, restart the modem manager, reset the modem’s USB connection, reboot the companion. It rebooted the aircraft twice, mid-flight, on its own, and got the link back both times in about 25 seconds.
It also found a bug in itself. The rung built for the exact fault we’d seen never fired. It located the modem by reading the network interface — which disappears when the modem faults. It was looking up the thing that had just died, using the thing that had just died. That one now learns the modem’s address while the link is healthy and remembers it.
Three separate failure modes, previously all blamed on one cause:
- A genuine electrical fault on the modem’s USB connection — real, hard evidence in the kernel log, and physical tape on a connector is the fix.
- Plain bad coverage. Half the samples on one flight were below −95 dBm, with a median of −98. No amount of software fixes being far from a tower.
- The peer-to-peer overlay network dropping while the modem stayed perfectly healthy — invisible to the watchdog by design, since the modem’s own path was fine the whole time.
The most useful thing built all day was instruments, not fixes. The aircraft was measuring its cellular signal every five seconds and throwing the numbers away. So when the link failed, the signal history had to be scraped from the ground — over the very link that was failing, which meant the scrape died exactly when the data got interesting. Two confident conclusions were drawn from that partial data, and both were wrong. Now the aircraft writes it down itself.
Within an hour, that log paid for itself twice:
- It showed that one poll in four was coming back empty — the cause of a dashboard that “permanently reads nothing”. One configuration number was doing two jobs: telling the modem how often to refresh and telling the software how often to ask. Same number, so they beat against each other and a quarter of the asks landed when there was nothing new. The modem was never the problem. Blank rate went from 26% to zero.
- It caught the aircraft switching cell towers between flights — which changed received signal by more than 20 dB at the same physical spot. That single fact invalidates the obvious conclusion (“we fixed the connector and it got better”), because a modem landing on a nearer tower produces exactly the same improvement for free. That question is still open, and now it’s measurable instead of arguable.
Also recalibrated the dashboard’s signal gauge, which had been scored against a textbook range this radio has never come close to reaching — the best signal it ever produced scored 70%, so “Excellent” was literally unreachable. A strong link read worse than a nearly-dead one.
Ended the day with a clean test: power the aircraft up cold, fly, and see whether it logs itself with no help at all. It did.
2026-07-13 — Video transport: SRT vs RTSP over cellular
Compared two ways to carry the live H.264 feed down the LTE link:
- SRT (current setup). The Pi encodes 480p/30 at a few hundred kbps and streams it over SRT with a ~300 ms buffer; a small relay on the ground station hands it to QGroundControl. SRT retransmits lost packets, so even with a flaky cellular signal — and one visibly damaged antenna — the picture stayed remarkably steady, almost no dropped frames. The cost is a little latency (~half a second glass-to-glass).
- RTSP/RTP (the experiment). A native RTSP (Real-Time Streaming Protocol) server on the Pi streams straight to QGroundControl with no relay in between, over plain RTP (Real-time Transport Protocol). Latency was clearly lower — noticeably snappier — but RTP doesn’t retransmit, so every burst of cellular packet loss became a dropout. On today’s degraded signal (swinging 75% down to 10–20% on a damaged antenna) it stuttered about once a second.
Takeaway: over a real cellular link, retransmission matters more than raw latency. SRT stays the daily driver for consistency; RTSP is the low-latency option worth revisiting once the antennas are repaired and the link is healthy. Encoder lessons from the day: on a bandwidth-limited link, fewer and more widely-spaced keyframes plus a lower bitrate beat frequent keyframes (which just add loss-inducing bursts); and intra-refresh — the textbook fix for lossy links — wasn’t usable because QGroundControl’s decoder can’t lock onto a stream without periodic keyframes.
2026-07-13 — First flight
- First flight, at a site with decent cellular coverage. The aircraft flies well; Position Hold sat steady around 150 ft.
- The remarkable part: a second operator flew it from several hundred miles away, over the internet, through the same LTE link — commands out one cellular connection, down another, to a drone he couldn’t see.
- Video bitrate got a significant bump at 480p — roughly 1.5 Mb/s against a 2.0 Mb/s cap — and held solid through the flight. Observed end-to-end latency was about 400–500 ms, which felt comfortable for supervised flying.
- One LTE paddle antenna picked up some damage, so the link readings (RSRP −69 dBm, SNR 6 dB, “fair”) likely under-report what the site — and an intact antenna — actually offer.