Under active development. Breaking changes expected. APIs, installers, and UI may shift between releases.
One drone. Multiple ground nodes. One stream.
Plant a relay on a ridge. Drop a receiver in the vehicle. Let the mesh handle the rest. Fragments combine, drops self-heal, and any node with a working uplink becomes the cloud gateway.
The Problem
One node has one line of sight.
A single ground station covers the RF bubble its antennas see. A ridge, a building, a treeline, and that coverage ends. Distributed receive is the answer.
Three Roles
One codebase. One config key.
Set ground_station.role to direct, relay, or receiver. The agent enables the right services and disables the wrong ones. No separate firmware.
Default
direct
ados-wfb-rx.service
- ✓Single node catches the drone on its own RTL8812EU.
- ✓Serves all pilot-facing clients (HDMI, WiFi AP, USB, Android).
- ✓Cloud relay bridge runs here too. No mesh traffic.
Field placed
relay
ados-wfb-relay.service
- ✓Catches the drone on its own RTL8812EU.
- ✓Forwards raw WFB-ng fragments over the mesh to the receiver.
- ✓Headless. No client services. No HDMI kiosk.
Hub
receiver
ados-wfb-receiver.service
- ✓Collects fragments from every relay over batman-adv UDP.
- ✓Runs WFB-ng Reed-Solomon FEC on the combined stream.
- ✓Serves the clean stream to all clients. Advertises mDNS.
Self-Healing Mesh
batman-adv does the routing.
Every relay and receiver carries a second RTL8812EU USB adapter that runs the batman-adv 802.11s mesh on 5 GHz. Same chip as the primary, matched 29 dBm TX power on both radios. The first adapter catches the drone. The second carries the fragments between nodes.
batman-adv is a Linux kernel mesh routing protocol. It advertises OGMv2 packets every second, detects a dead neighbor in three to five seconds, and re-routes around the failure with no operator action. Mesh IDs are scoped per deployment so two sites on the same channel do not cross-contaminate.
The same agent binary runs the mesh carrier. No separate daemon, no custom routing code, no second service to keep in sync. When the role manager sets ground_station.role to relay or receiver, it enables ados-batman.service. When the role flips back to direct, it disables it. Clean.
Cloud Gateway Election
Any node with an uplink becomes the gateway.
batman-adv has a built-in gateway election protocol. Nodes with Ethernet, WiFi client, or 4G advertise themselves. The receiver picks the best path by measured TQ and re-picks on failure.
A relay on the roof of a building might have 4G. A relay in a valley might not. Both advertise themselves as possible gateways. The receiver watches the batman-adv TQ metric and picks the strongest gateway. If the rooftop relay loses its 4G signal mid-flight, the receiver switches to the backup gateway in seconds. The cloud bridge stays up.
This is how a distributed deployment stays connected to the Altnautica cloud relay or a self-hosted MQTT broker without requiring every node to have its own cellular modem.
Receiver Promotion
If the hub dies, promote a relay.
Any relay can be promoted to receiver with one click in the Mission Control Hardware tab. The new receiver advertises mDNS, the other relays find it, the stream resumes.
The Hardware tab shows a Distributed RX sub-view with one card per mesh node. Each card lists RSSI, fragment count, FEC-repair count, and role. If the receiver disappears, click Promote on any surviving relay. The agent writes the new role to config, restarts the right systemd units, and publishes the new mDNS record on bat0. Other relays re-resolve and resume fragment egress to the new hub. Target time from click to restored stream is under 10 seconds.
The CLI equivalent is ados gs role set receiver. Either path works. The ground node does not need a reboot to change role.
Coverage Math
How many nodes do you need.
Coverage depends on antenna gain, terrain, and flight altitude. These numbers are planning guides, not contracts.
| Setup | Nominal range | Obstructed |
|---|---|---|
| 1 node, rubber duck (2 dBi) | 1 to 3 km | 0.5 to 1.5 km |
| 1 node, 5 dBi omni | 3 to 8 km | 1.5 to 4 km |
| 1 node, 8 to 12 dBi panel | 10 to 20 km | 5 to 10 km |
| 2 nodes overlapped (5 dBi each) | 12 to 18 km corridor | 6 to 10 km corridor |
| 3 nodes (5 dBi each) | 20 to 26 km corridor | 10 to 15 km corridor |
Field Tap-to-Pair
No laptop in the field.
A second node joins the mesh using only the OLED and four buttons. Curve25519 ECDH key exchange, ChaCha20-Poly1305 invite bundle, scoped to the mesh ID.
┌──────────────────────────┐ │ [receiver] │ │ │ │ Accepting relay │ │ 60s remaining │ │ │ │ Pending: 1 │ │ Accepted: 0 │ │ │ │ B1 accept B4 deny │ └──────────────────────────┘
┌──────────────────────────┐ │ [relay joining] │ │ │ │ Scanning for mesh.. │ │ │ │ Found: │ │ ados-gs-a4b2 -52 │ │ ados-gs-1f0c -78 │ │ │ │ B1 join B4 cancel │ └──────────────────────────┘
On the receiver, long-press B3 to open a 60 second pairing window. On the incoming relay, enter the menu, pick Join mesh, and wait. The relay discovers the receiver through mDNS broadcast on bat0. The OLED lists found receivers with link quality. Tap B1 to join. ECDH runs over the air, the receiver seals an invite bundle, the relay decrypts, batman-adv comes up, mesh live.
The whole flow targets under 120 seconds from power-on to live mesh, with zero computer in the field.
Validated Scenarios
Twelve test scenarios. Bench-pending.
Distributed receive is code-complete on main. Every scenario below has a reproducible test procedure. Field validation is in flight on a two-node Pi 4B mesh rig.
Single-hop relay and receiver over batman-adv
Two-relay FEC repair through obstruction
Two-hop mesh relay routing
Receiver promotion in under ten seconds
Self-healing on relay drop
Cloud gateway on a relay with 4G
Gateway failover to backup node
Partition tolerance, clean re-merge
Field tap-to-pair with OLED, no laptop
Three-node field deployment with auto-accept
Decommission and re-pair to new deployment
Multi-site RF coexistence
One mesh. Many nodes. One clean stream.
Full setup walkthroughs, CLI reference, and mesh troubleshooting in public docs.
Distributed RX docs