Alpha

Under active development. Breaking changes expected. APIs, installers, and UI may shift between releases.

Distributed RX · v0.7.1

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.

Single node
drone
obstruction
dropout
groundno signal
The obstruction blocks the only line of sight. The stream drops.
Two nodes overlapped
drone
obstruction
relayside A
relayside B
receiverFEC combine
clients
Two relays cover both sides. Receiver combines the fragments.

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.

Node drop, mesh reconvergence
t = 0srelay A + relay B advertising OGMv2
receiver routes to both
t = 1srelay A loses power
t = 3sreceiver misses 3 OGMs from relay A
t = 4sreceiver drops route A
relay B takes full share
t = 5sstream clean again
Five seconds from a dead relay to a clean stream, with no operator action.

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.

Gateway paths
relay AEthernet uplink
gw server TQ = 245
relay B4G LTE uplink
gw server TQ = 180
receivergw client
picks relay A (higher TQ)
Altnautica cloudMQTT, Convex
Receiver picks the strongest TQ. Failover is automatic when the top path degrades.

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.

Promotion timeline
t = 0sreceiver drops offline
pilot sees stall
t = 2soperator clicks Promote
on a surviving relay
t = 3srole manager rewrites config
restarts services
t = 5snew mDNS record on bat0
t = 7sother relays re-resolve
fragment egress resumes
t = 9sstream clean
Click to clean stream in under ten seconds. 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.

SetupNominal rangeObstructed
1 node, rubber duck (2 dBi)1 to 3 km0.5 to 1.5 km
1 node, 5 dBi omni3 to 8 km1.5 to 4 km
1 node, 8 to 12 dBi panel10 to 20 km5 to 10 km
2 nodes overlapped (5 dBi each)12 to 18 km corridor6 to 10 km corridor
3 nodes (5 dBi each)20 to 26 km corridor10 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 screen — simulation
┌──────────────────────────┐
│ [receiver]               │
│                          │
│ Accepting relay          │
│ 60s remaining            │
│                          │
│ Pending: 1               │
│ Accepted: 0              │
│                          │
│ B1 accept  B4 deny       │
└──────────────────────────┘
Long-press B3 opens a 60 second pairing window. The OLED shows Accepting relay with pending and accepted counts.
Relay screen — simulation
┌──────────────────────────┐
│ [relay joining]          │
│                          │
│ Scanning for mesh..      │
│                          │
│ Found:                   │
│  ados-gs-a4b2  -52       │
│  ados-gs-1f0c  -78       │
│                          │
│ B1 join  B4 cancel       │
└──────────────────────────┘
The relay listens for mDNS broadcasts on bat0 (UDP 5801), lists receivers with link quality, and joins on B1.

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.

Physical UI walkthrough

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
Get Early Access