ULog File Format

Ulog是一种用来记录系统数据的日志格式。这种格式是自解释的,比如,他包含了日志的格式和消息类型。

他可以用来记录设备的输入(传感器等),内部状态(CPU负载,姿态等)以及打印日志信息。

采用小端格式。(译注:低字节存储在低地址)

数据类型

下面列举了使用的数据类型,他们都与C语言的类型相对应。

此外所有类型都可以使用数组,比如。一般而言所有的字符串(char[length])结尾都不包含 '\0'。字符串大小写敏感。

文件包含三个部分:

头部大小固定,格式如下(16 bytes):

  1. ----------------------------------------------------------------------
  2. | 0x55 0x4c 0x6f 0x67 0x01 0x12 0x35 | 0x00 | uint64_t |
  3. | File magic (7B) | Version (1B) | Timestamp (8B) |
  4. ----------------------------------------------------------------------

Version是文件格式的版本,当前是0。时间戳是uint64_t类型,用微秒表示记录开始的时间。

长度可变,包含版本信息,格式定义以及(初始) 参数值。

定义部分和数据部分由消息流组成,消息流以下面这样的头部开始:

  1. struct message_header_s {
  2. uint16_t msg_size;
  3. uint8_t msg_type
  4. };
  • ‘F’: format definition for a single (composite) type that can be logged or
    used in another definition as a nested type.

  • ‘F’: 单一(混合)类型的格式定义,用于日志记录或者作为嵌套类型用在其他的定义中。

  1. struct message_format_s {
  2. struct message_header_s header;
  3. char format[header.msg_size-hdr_size];
  4. };

format: 纯文本字符串,格式如下: message_name:field0;field1;可以有任意数量的field
(至少 1), 用 ;隔开。
field 的格式: type field_name 或者数组形式 type[array_length] field_name(只支持固定尺寸的数组).
type 可以是基本的数据类型,也可以是另一种格式定义的message_name (嵌套用法).
type可以在定义前使用。可以任意地嵌套,但是不要循环依赖。

有一些特殊的field:

  • timestamp: 每个日志消息 (message_add_logged_s) 必须包含一个
    timestamp field (不必是第一个). 他的type可以是:

  • ‘I’: information message.

  1. struct message_info_s {
  2. uint8_t key_len;
  3. char key[key_len];
  4. char value[header.msg_size-hdr_size-1-key_len]
  5. };

key 是一个纯文本字符串, 只包含一个field,没有;结尾,例如
float[3] myvalues. value 含有用key描述的数据。

预定义的 information messages :

This message can also be used in the Data section (this is however the preferred section).

  • ‘P’: 参数消息. 和message_info_s格式一样.
    如果一个参数在运行时实时改变, 那这个消息也可以用在数据部分(Data section).
    1. 数据类型限制为: `int32_t`, `float`.

This section ends before the start of the first message_add_logged_s or message_logging_s message, whichever comes first.

下列消息属于这一部分:

  • ‘A’: 订阅一个message,并且赋予它一个用于message_data_s的id.
    This must come before the first corresponding
    message_data_s.
  1. struct message_add_logged_s {
  2. struct message_header_s header;
  3. uint8_t multi_id;
  4. uint16_t msg_id;
  5. char message_name[header.msg_size-hdr_size-3];
  6. };

: 相同的消息格式可以通过multi_id赋予多个实例。默认的第一个实例为0。
msg_id: 唯一的 id 用来匹配 message_data_s 数据.第一次用必须置0,然后增加(The first use must set
this to 0, then increase it.) 不同的订阅必须使用不同的id,甚至在取消订阅之后也不能使用相同的id
message_name: 要订阅的消息名称. 必须与message_format_s 中的一个定义相匹配.

  • ‘R’: 取消订阅一个message,标记这个消息不再被记录 (当前没有使用).
  • ‘D’: 包含记录的数据.
  1. struct message_data_s {
  2. struct message_header_s header;
  3. uint16_t msg_id;
  4. uint8_t data[header.msg_size-hdr_size];
  5. };

msg_id: 被message_add_logged_s定义的 message. data 包含被 message_format_s定义的
二进制消息. 关于padding特殊的处理机制查看上面.

  • ‘L’: 记录的字符串消息, i.e. printf output.
  1. struct message_logging_s {
  2. uint8_t log_level;
  3. uint64_t timestamp;
  4. char message[header.msg_size-hdr_size-9]
  5. };

timestamp:微秒为单位, log_level: 与 Linux kernel 一样:

  • synchronization message so that a reader can recover from a corrupt
    message by search for the next sync message (not used currently).
    ‘S’: 同步消息,消息阅读器通过搜索下一个同步消息的方式从一个损坏的消息恢复。(当前未使用)
    1. struct message_sync_s {
    2. struct message_header_s header;
    3. uint8_t sync_magic[8];
    4. };

sync_magic: 待定义(to be defined).

  • ‘O’: 标记一个在以ms给定的时间段内的数据丢失 (丢失日志消息)。
    比如设备不够快的时候就会发生消息丢失.
  • ‘I’: information message. See above.
  • ‘P’: parameter message. See above.

Requirements for Parsers

A valid ULog parser must fulfill the following requirements:

  • Must ignore unknown messages (but it can print a warning).
  • Parse future/unknown file format versions as well (but it can print a warning).
  • Must refuse to parse a log which contains unknown incompatibility bits set
    (incompat_flags of ulog_message_flag_bits_s message), meaning the log
    contains breaking changes that the parser cannot handle.
  • A parser must be able to correctly handle logs that end abruptly, in the
    middle of a message. The unfinished message should just be discarged.
  • For appended data: a parser can assume the Data section exists, i.e. the
    offset points to a place after the Definitions section.

    Appended data must be treated as if it was part of the regular Data section.

  • PX4 Firmware: C++
  • : python, ULog parser library with CLI
    scripts.
  • FlightPlot: Java, log plotter.
  • : Messages for ULog streaming via
    MAVLink (note that appending data is not supported, at least not for cut off
    messages).
  • QGroundControl: C++, ULog
    streaming via MAVLink and minimal parsing for GeoTagging.
  • : Java, ULog streaming via
    MAVLink and parser for plotting and analysis.

File Format Version History