Skip to content
Docs
foxborne.comRequest a pilot

MAVLink telemetry logs and receive records

Two ground-side records of MAVLink traffic: the ground station's .tlog and the Foxborne receiver's JSONL. Both stamp each message when it reached the ground, so both give receive time, never send time.

ReferenceMarkdown
On this page10

MAVLink traffic from a vehicle can land in two records on the ground. Ground station software writes a telemetry log, the .tlog, and the Foxborne MAVLink receiver at range control writes receiver JSONL. Both are written on the ground as each message arrives, and both say when the ground heard it.

The two records#

PropertyGround station telemetry logReceiver JSONL
File.tlog.jsonl
Written byGround station softwareThe Foxborne MAVLink receiver
What it holdsEvery MAVLink packet the ground station logged, wholeOne JSON object per message received: its name, its sender and its arrival
Time stamp8 bytes before each packet: microseconds since the Unix epochrecv_utc in UTC to the millisecond, and mono_ns on the receiver's monotonic clock
ClockThe ground station computer's clockThe receiver's clock, kept on UTC by NTP
How it reaches FoxborneListed in the File import catalogThe MAVLink receiver source, a storage source or Import files

Ground station telemetry logs#

Ground stations record .tlog files of the MAVLink traffic they handle. Mission Planner starts one when it connects, and QGroundControl writes one after each flight when that setting is on.

Structure#

A .tlog has no header of its own. It is a run of records to the end of the file, each an 8-byte timestamp followed by one MAVLink packet as it arrived.

Bytes in the recordFieldContent
0 to 7TimestampA uint64, big endian: microseconds since the Unix epoch, on the ground station's clock
8 to endPacketThe MAVLink packet as received, from its start marker to its checksum

The packet's start marker says which MAVLink version follows, and with it where each field sits:

Packet fieldMAVLink 1MAVLink 2
Start marker, byte 00xFE0xFD
Payload lengthByte 1Byte 1
Message IDByte 5, one byteBytes 7 to 9, three bytes
Header before the payload6 bytes10 bytes
After the payloadA 2-byte checksumA 2-byte checksum, then a signature block when the packet is signed

The timestamp is receive time#

pymavlink, the MAVLink library for Python, shows where the timestamp comes from. It writes each record right after it parses a packet from the link, with the computer's clock at that moment:

pymavlink/mavutil.pypymavlink, mavfile.recv_msg(), abridgedPython
msg = self.mav.parse_char(s)
if msg:
    if self.logfile and  msg.get_type() != 'BAD_DATA' :
        usec = int(time.time() * 1.0e6) & ~3
        self.logfile.write(struct.pack('>Q', usec) + msg.get_msgbuf())

The stamp is therefore the time the ground station logged the packet, on the ground station's clock. It is a receive time, as good as that computer's time synchronization.

pymavlink clears the timestamp's two lowest bits when it writes, and its reader takes those two bits back as a link number. Its stamps land on multiples of 4 µs.

pymavlink/mavutil.pypymavlink, mavlogfile.pre_message(), abridgedPython
tbuf = self.f.read(8)
(tusec,) = struct.unpack('>Q', tbuf)
t = tusec * 1.0e-6
...
self._link = tusec & 0x3

Importing .tlog files#

The console's File import entry, under Integrations and Ingest, lists .tlog among the formats it takes by upload, drop folder or removable media. Each file arrives under a user login with the sender's SHA-256 manifest, and it is checked against that manifest before it is parsed.

Settings, under Import, lists the formats your deployment reads. In the example deployment, File import reads On, 4 formats, and .tlog is not among them. Its Formats on row names PX4 ULog, journalctl JSON, collector JSONL and receiver JSONL.

The Telemetry gap alert, R2 under Alerts, names its signals as vehicle HEARTBEAT arrivals in the ground-station .tlog and the ground receiver log. In the example deployment it reads the range control receive logs. Sortie closeout triage, automation A1, counts a ground-station .tlog among the sources a test card can list.

Receiver JSONL#

The Foxborne MAVLink receiver listens for telemetry on the ground and writes one JSON object per receipt, one receipt per line. Foxborne recognizes the file by the key "recv_utc" in its first 4,096 bytes, and the example dataset's parser is receive 0.4.1.

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, such as 0 and HEARTBEAT
seqThe MAVLink packet sequence number, 0 to 255
lenThe payload length in bytes, 9 for a HEARTBEAT

In the example dataset, the receiver clock is good to ±15 ms, and the run page gives the bound as ±15 ms + latency. Receiver JSONL records has the full schema and an example record. MAVLink ground receiver sets the receiver up.

Why both are receive time#

A receipt always comes after the transmission, later by the link latency. Both records stamp the arrival, and neither carries the moment the vehicle sent the message.

A HEARTBEAT has no time field. The vehicle's own clock reaches the ground only in messages that carry it, such as SYSTEM_TIME, msgid 2. Its time_unix_usec counts microseconds since the Unix epoch, and time_boot_ms milliseconds since boot.

Foxborne 1.4.1 added receive log latency estimates from SYSTEM_TIME. Foxborne gives each receipt an interval that reaches back by the clock error plus the latency, and forward by the clock error alone:

Send window of a receiptExample dataset, INC-0142: ±15 ms clock error, 412 ms latency at the 95th percentileText
interval      = [ t - error - latency , t + error ]
earliest send = 14:32:03.912 - 15 ms - 412 ms = 14:32:03.485
latest send   = 14:32:03.912 + 15 ms          = 14:32:03.927

The same holds for a .tlog stamp: it marks when the ground station logged the packet, on the ground station's clock.

HEARTBEAT at 1 Hz#

Vehicles send HEARTBEAT, msgid 0, on a steady schedule. MAVLink's heartbeat service describes the rate as typically 1 Hz on radio links, and treats a system as lost after four or five missed heartbeats.

In the example dataset, UAS-04's heartbeats reach range control about once a second as system ID 4, and UGV-02's as system ID 22. A gap in those receipts is the first sign on the ground that something stopped.

How telemetry_gap reads receipts#

The telemetry_gap rule reads HEARTBEAT receipts from the ground receive log. It measures the time between consecutive heartbeats from the same system ID and fires when two are more than 3 s apart.

The finding sits where the next heartbeat was due, one expected interval after the last receipt. It reads Observed: telemetry receive gap, not necessarily radio failure.

IncidentLast receivedNext receivedFinding title
INC-014214:32:03.91214:32:10.874Heartbeat due and not received. Nothing for 6.96 s
INC-014315:41:02.71315:41:33.689Heartbeat due and not received. Nothing for 31.0 s

A receive gap proves only that nothing arrived. In INC-0142 the MAVLink router on the companion computer had stopped, and in INC-0143 the radio had dropped off the companion's USB bus.