Skip to content
Docs
foxborne.comRequest a pilot

MAVLink ground receiver

Record what range control hears from each vehicle, stamped with the receiver's own clock. The receive log is what the telemetry_gap rule reads, and it shows when the ground heard a message, not when the vehicle sent it.

How-toEvery deploymentAdminMarkdown
On this page9

The flight log shows what PX4 believed about its link. The receive log shows what actually reached the ground, and when. The MAVLink receiver source records it: it Listens to telemetry on the ground and records every receipt with its own clock.

Before you start#

  • You need the Admin role.
  • The receiver must hear your vehicles' MAVLink telemetry at the address you give it.
  • Keep the receiver's clock on NTP. In the example dataset it reads NTP, synchronised, good to ±15 ms.
  • Know the MAVLink system IDs of the vehicles to record. Each vehicle page shows its system ID.

Add the receiver#

  1. Choose MAVLink receiver

    In Sources, select Add source. Under Vehicles, pick MAVLink receiver and select Continue.

  2. Fill in the fields

    FieldExample in the consoleWhat it sets
    NameFor example: Fleet log archive, west rangeA name the team will recognize, such as the range it serves.
    Listen onudp://0.0.0.0:14560Where the receiver listens. The example listens for UDP on port 14560, on every interface.
    System IDs1 to 16The MAVLink system IDs to record.
    RecordEvery HEARTBEAT and SYSTEM_TIME receiptWhich messages to keep.
  3. Test and add

    Select Test connection and wait for the fourth check. Then select Add source. The toast names the source and says The first sync is running.

If range control already writes receive logs to a server, connect that directory instead. The example dataset's Range control receive logs source reads *.jsonl over SFTP from /var/log/mav-receive/ and polls every 5 minutes. See SFTP, SMB and NFS.

What a receive record holds#

A receive log is receiver JSONL: one JSON object per receipt, one receipt per line. Foxborne recognizes the file by the key "recv_utc". This is the last heartbeat from UAS-04 before the telemetry gap in INC-0142:

rc1-receive.jsonlExample dataset, line 1,118, spread over several lines to readJSON
{
  "recv_utc": "2026-09-24T14:32:03.912Z",
  "mono_ns": 12805145901122,
  "link": "mesh0",
  "sysid": 4,
  "compid": 1,
  "msgid": 0,
  "msg": "HEARTBEAT",
  "seq": 204,
  "len": 9
}
FieldWhat it holds
recv_utcThe arrival time in UTC, on the receiver's clock
mono_nsThe arrival time on the receiver's monotonic clock, in nanoseconds
linkThe link the message arrived on
sysid, compidThe sender's MAVLink system and component IDs
msgid, msgThe message ID and name, here 0 and HEARTBEAT
seqThe MAVLink packet sequence number, 0 to 255
lenThe payload length in bytes, 9 for a HEARTBEAT

Receiver JSONL records gives the full schema.

Receive time is not send time#

A receipt always comes after the transmission. The record gives the arrival, and the departure was earlier by the link latency. Latency widens the bound on one side only, toward earlier times, because it can never move a transmission after its receipt.

For an event at time t with clock error err and link latency lat, the interval is [t − err − lat, t + err]. The heartbeat above arrived at 14:32:03.912, with ±15 ms on the receiver clock and up to 412 ms of latency. It left UAS-04 between 14:32:03.485 and 14:32:03.927.

Example data−400 ms−300 ms−200 ms−100 ms0+100 ms+200 msthe moment it happenedFlight logPX4 boot time, anchored by GPS±40 msCompanion journalWall clock, disciplined by chrony±6 msGround receive logReceive time at range controlsent up to 412 ms before it arrived±15 ms + latency−400 ms−200 ms0+200 msthe momentFlight log±40 msCompanion journal±6 msGround receive log±15 ms + latencysent up to 412 ms before it arrived
The same moment on three clocks, with INC-0142's bounds. The ground receipt lands 96 ms after the moment, the run's median latency, and may have been sent up to 412 ms before it arrived.

Latency per run#

Foxborne measures link latency for each run and reports its median and 95th percentile. Bounds carry the 95th percentile.

RunIncidentMedian95th percentile
R-0931INC-014296 ms412 ms
R-0934INC-014388 ms380 ms

The latency follows the receive log wherever it appears. Source files gives its bound as ±15 ms + latency, and Ordering bounds between sources adds a line such as plus 412 ms latency. On the event page, the Clock card's Receive latency row reads Up to 412 ms, 95th percentile.

Foxborne 1.4.1 added receive log latency estimates from SYSTEM_TIME. That MAVLink message, msgid 2, carries the sender's own clock: time_unix_usec, in microseconds since the UNIX epoch, and time_boot_ms, in milliseconds since boot.

How telemetry_gap reads the log#

The telemetry_gap rule reads HEARTBEAT receipts (msgid 0) from each vehicle's system ID. It measures the time between consecutive heartbeats and fires when two are more than 3 s apart.

The finding sits where the next heartbeat was due: one expected interval, 1 s at 1 Hz, after the last receipt. In INC-0142 the receiver heard UAS-04 at 14:32:03.912 and then not until 14:32:10.874.

The finding reads Heartbeat due and not received. Nothing for 6.96 s, with the wording Observed: telemetry receive gap, not necessarily radio failure.

On the timeline, the Ground receive lane draws each receipt as a tick and hatches the gap, labeled No telemetry received for 6.96 s.

Check the result#

  • The source appears in Connections with Healthy under Status.
  • Runs gain a Ground receive log under Source files. Its clock reads Range control receiver clock, its anchor NTP, synchronised and its parser receive 0.4.1.
  • The audit log records Added source with a detail such as MAVLink receiver, read-only test passed.

Troubleshoot#

  • Runs show Partial with No ground receive log for this run. The receiver did not record that run, or its log never reached Foxborne. Check the source's Last sync, and import the log by hand if you have it.
  • A gap appears, and the radio seems fine. A receive gap is not a radio failure. Compare the vehicle's own view in telemetry_status before you conclude anything, as telemetry_gap explains.

Next#