PX4 ULog
What Foxborne reads from a PX4 flight log: the file's structure, the topics and parameters it uses, the GPS time anchor, dropouts and why a truncated log is quarantined and an encrypted one rejected.
On this page12
ULog is the format PX4's logger writes to the flight controller's SD card. It is self-describing: the file defines each message format before the data that uses it. Foxborne reads the completed .ulg with parser ulog 0.9.2.
With a valid clock, PX4 names each log for its date and start time. Run R-0931's flight log in the example dataset is log/2026-09-24/14_13_19.ulg. Without a valid clock, the logger numbers its folders and files instead.
File structure#
A ULog has three sections: a fixed 16-byte header, then definitions, then data. All binary values are little endian.
Header#
| Bytes | Field | Content |
|---|---|---|
| 0 to 6 | File magic | 55 4C 6F 67 01 12 35: "ULog", then 0x01 0x12 0x35 |
| 7 | Version | The file format version. PX4 v1.16.0 writes 1. |
| 8 to 15 | Timestamp | A uint64: when logging started, in microseconds on the flight controller's boot clock |
Foxborne checks the magic bytes before anything else. The Import page then shows PX4 ULog, version 1 and Magic bytes verified.
Messages#
After the header, the file is a sequence of messages. Each starts with three bytes: msg_size, a uint16 giving the message's size without those three bytes, and msg_type, one character. The definitions section ends where the first subscription or logged string begins.
| Type | Name | Section | What it carries |
|---|---|---|---|
B | Flag bits | Definitions, first after the header | Compatible and incompatible feature flags, and the offsets of any appended data |
F | Format | Definitions | One message layout, written as name:type field;type field; |
I | Information | Both | One key and its value, such as sys_name, ver_hw, ver_sw or time_ref_utc |
M | Multi information | Both | Long or repeated information values, split across messages |
P | Parameter | Both | One parameter value, int32 or float: at log start in the definitions, and on each change in the data |
Q | Default parameter | Both | A parameter's default, system-wide or for the current configuration such as the airframe |
A | Subscription | Data | A topic name, its multi_id instance and the msg_id its samples carry |
R | Unsubscription | Data | Marks a topic that stops being logged. Not used currently. |
D | Logged data | Data | One sample of a subscribed topic, tagged with its msg_id |
L | Logged string | Data | A console message: a log level, a uint64 timestamp and the text |
C | Tagged logged string | Data | A logged string with a uint16 tag naming its source |
S | Synchronization | Data | Eight fixed bytes, 2F 73 13 20 25 0C BB 12, so a reader can recover after a corrupt message |
O | Dropout | Data | A uint16 duration in milliseconds: how long the logger lost messages |
"Both" means the definitions and the data sections.
Each format with a subscription carries a timestamp field: a uint64 in microseconds that only increases within that subscription. In PX4 it counts from boot, so a sample at 1,132,793,000 µs sits 1,132.793 s after the flight controller started.
PX4 v1.16.0 writes its console messages as L messages. It stores the level as a character, from '0' (EMERG) to '7' (DEBUG), as in the Linux kernel. It writes a synchronization message whenever more than 500 ms have passed since the last one.
How a record is cited#
A flight log event cites its topic and instance, its timestamp, its message number and its byte offset in the file. The evidence inspector shows the original record like this:
topic obstacle_distance (multi_id 0)
timestamp 1,132,793,000 µs boot + 1132.793 s
message 1,146,099 of 1,388,540
offset byte 53,503,302
frame 12 (MAV_FRAME_BODY_FRD)
sensor_type 0 (laser)
min_distance 20 cm
max_distance 2000 cm
increment 5.0 deg
distances[0..7] 412 406 399 401 388 1999 1999 1999Anyone holding the original file can find message 1,146,099 at byte 53,503,302 and check the values against it.
Topics Foxborne reads#
Foxborne expects a set of topics on each platform. In the example dataset each platform expects 13, and each run logged 11 of them.
| Topic | Q4 recon quad | T4 tracked UGV | What it gives the investigation |
|---|---|---|---|
vehicle_status | Logged | Logged | Arming state, navigation state and the failsafe flag, for the state band on the timeline and the failsafe_entered rule |
vehicle_land_detected | Logged | Not expected | Landing, such as Landed in INC-0142 |
sensor_gps | Logged | Logged | The GPS time anchor, eph and satellites_used for gps_quality_drop, and jamming_state and jamming_indicator for gnss_jamming |
vehicle_global_position | Logged | Logged | The track on the map and the ground speed lane |
battery_status | Logged | Logged | The battery lane and the battery_sag rule |
failsafe_flags | Logged | Logged | The cause of a failsafe, such as gcs_connection_lost |
telemetry_status | Logged | Logged | PX4's own view of each link, from heartbeat_type_gcs and heartbeat_type_onboard_controller |
obstacle_distance | Logged | Not expected | Obstacle data from the companion computer. Its stalls are findings in INC-0142 and INC-0139. |
estimator_status | Logged | Logged | The state estimator's status, checked under Flight log topics |
cpuload | Logged | Logged | Processor load and RAM use on the flight controller, each from 0 to 1 |
| logged messages | Logged | Logged | PX4's console messages, such as Failsafe activated and GCS connection regained |
distance_sensor | Not logged | Not logged | Expected on both platforms and logged on neither in the example dataset |
vehicle_imu_status | Not logged | Logged | accel_vibration_metric for the vibration_high rule |
vehicle_command | Not expected | Logged | Commands the vehicle received, such as DO_SET_MODE from system 255 in INC-0143 |
offboard_control_mode | Not expected | Not logged | Which setpoints offboard control uses. Expected on T4 vehicles and not logged in the example dataset. |
The topic_stall rule fires when a logged topic stops updating: no sample for 5 times its median period.
Topics shown as Not logged#
A topic missing from the file shows Not logged under Flight log topics on the run page. The panel's subtitle counts what arrived, for example 11 of 13 expected topics were logged.
A topic can be missing because the logging profile left it out or because nothing on the vehicle published it. A rule that reads a missing topic has nothing to read on that run, so it produces no finding there.
Parameters read from the header#
Foxborne reads parameters from the P messages in the definitions section, which hold the values in force when logging started. It compares them from one run to the next on each vehicle.
| Parameter | Description on the vehicle page | Q4 example | T4 example |
|---|---|---|---|
COM_DL_LOSS_T | Seconds without a ground heartbeat before the data link failsafe | 10 | 10 |
NAV_DLL_ACT | Data link loss action | 2 (Return) | 1 (Hold) |
COM_FAIL_ACT_T | None. PX4 describes it as the delay between failsafe condition triggered and failsafe reaction. | 5 | 5 |
COM_OF_LOSS_T | Seconds without offboard setpoints before the offboard failsafe | 1.0 | 1.0 |
COM_OBL_RC_ACT | Offboard loss action | 5 (Hold) | 5 (Hold) |
COM_POS_FS_EPH | Horizontal accuracy that invalidates position, metres | 5 | Not read |
SYS_HAS_NUM_GNSS | GNSS receivers expected | 1 | 1 |
COM_GNSSLOSS_ACT | GNSS loss action | 0 (Warning) | 0 (Warning) |
The vehicle page lists these values under Failsafe parameters, and any differences in the Changes between runs drawer, opened from that panel's header. On UGV-05 in the example dataset it reads NAV_DLL_ACT 0 (Disabled) to 1 (Hold) in R-0924, 22 Sep. PX4 parameters Foxborne reads gives each parameter's range and default.
The GPS time anchor#
The flight log counts from boot, and sensor_gps ties that count to UTC. Three of its fields do the work:
| Field | Type | Meaning, from SensorGps.msg in PX4 v1.16.0 |
|---|---|---|
timestamp | uint64 | Time since system start, in microseconds |
timestamp_time_relative | int32 | Added to timestamp, the time of the UTC reading on the boot clock, in microseconds |
time_utc_usec | uint64 | UTC from the GPS module, in microseconds. It reads 0 right after a cold start. |
A fix with a nonzero time_utc_usec reads one instant on both clocks and gives the offset from boot to UTC. Foxborne leaves out the zeros and reports how many fixes it used. For run R-0931 the run page reads GPS time from sensor_gps, 1,081 fixes, which puts the flight controller's boot at 14:13:11.286 UTC.
The information key time_ref_utc is no substitute. PX4 writes it from the SDLOG_UTC_OFFSET parameter, so it holds a configured offset in seconds, not a reading of any clock.
GPS time that reaches the flight controller over a serial link carries latency and jitter. That is why the example dataset carries ±40 ms on flight logs.
A run with no fix has no anchor, and the run page shows Elapsed time only. Clocks, anchors and error bounds covers the anchor in full.
Dropouts and the log_dropout rule#
When the logger cannot keep up, it loses messages and records the gap as an O message with its length in milliseconds. The samples in that gap were never written. The ULog specification names a device that is not fast enough as one cause.
The log_dropout rule turns each dropout of 50 ms or longer into a finding worded Observed: flight log has a dropout. In the example dataset's INC-0133, UAS-05 logged three dropouts of 60 to 140 ms once its logging profile included high-rate IMU topics.
The SD card's write rate had saturated, and moving back to the default logging profile fixed it. See log_dropout.
Truncated logs are quarantined#
A log cut off by a power loss ends partway through a message. Foxborne quarantines the file and shows nothing from it as complete, and the run page offers Replace the file. Run R-0933 in the example dataset gives the reason in full:
The flight log ends inside a data message at 41.2 MB. The file was truncated, most likely when power was cut during logging. Nothing from it is shown as complete.
Encrypted logs are rejected#
An encrypted flight log stops at the first step of the import job, Validate type, size and schema. Run R-0932 in the example dataset reads:
The flight log is encrypted. Foxborne does not decrypt logs. Import the decrypted .ulg exported from your key holder.
Ask whoever holds the log's key for the decrypted .ulg, then replace the file from the run page. Import statuses and fixes walks through both cases.
Related#
- Clocks, anchors and error bounds explains the boot clock and its GPS anchor.
- PX4 parameters Foxborne reads lists each parameter's range and default.
- log_dropout and topic_stall describe the rules that read the log's structure.
- Supported file formats compares the ULog with the other formats.