Move PX4 Guide source into /docs (#24490)

* Add vitepress tree

* Update existing workflows so they dont trigger on changes in the docs path

* Add nojekyll, package.json, LICENCE etc

* Add crowdin docs upload/download scripts

* Add docs flaw checker workflows

* Used docs prefix for docs workflows

* Crowdin obvious fixes

* ci: docs move to self hosted runner

runs on a beefy server for faster builds

Signed-off-by: Ramon Roche <mrpollo@gmail.com>

* ci: don't run build action for docs or ci changes

Signed-off-by: Ramon Roche <mrpollo@gmail.com>

* ci: update runners

Signed-off-by: Ramon Roche <mrpollo@gmail.com>

* Add docs/en

* Add docs assets and scripts

* Fix up editlinks to point to PX4 sources

* Download just the translations that are supported

* Add translation sources for zh, uk, ko

* Update latest tranlsation and uorb graphs

* update vitepress to latest

---------

Signed-off-by: Ramon Roche <mrpollo@gmail.com>
Co-authored-by: Ramon Roche <mrpollo@gmail.com>
This commit is contained in:
Hamish Willee
2025-03-13 16:08:27 +11:00
committed by GitHub
co-authored by Ramon Roche
parent 8e6d2ebe4a
commit 88d623bedb
5176 changed files with 558771 additions and 2 deletions
+8
View File
@@ -0,0 +1,8 @@
# 飞行日志分析
关于飞行日志分析的资料包含在 PX4 用户指南中:
- [Flight Reporting](../getting_started/flight_reporting.md) - How to download a log and report/discuss issues about a flight.
- [Log Analysis using Flight Review](../log/flight_review.md) - How to analyse many common vehicle problems using the [Flight Review](https://logs.px4.io/) online tool.
- [Flight Log Analysis](../log/flight_log_analysis.md) - Introduction to flight analysis and links to a number of analysis tools.
- [Statistical Analysis](flight_log_analysis_statistical.md) - Information & resources for statistical analysis (including Flight Review logs).
@@ -0,0 +1,23 @@
# Statistical Flight Log Analysis
This topic contains information and resources related to statistical flight log analysis.
## Flight Review Public Logs
[Flight Review](../log/flight_log_analysis.md#flight-review-online-tool) hosts a large set of publicly available log files that can be used for statistical analysis, machine learning, or other purposes.
The dataset contains a set of different:
- vehicle types
- PX4 versions (including development versions)
- boards
- flight modes
The logs are accessible on [logs.px4.io/browse](https://logs.px4.io/browse) and are licensed under [CC-BY PX4](https://creativecommons.org/licenses/by/4.0/).
Log files can also be downloaded in bulk with the [download_logs.py](https://github.com/PX4/flight_review/blob/main/app/download_logs.py) script.
The script allows to filter by different attributes (like flight modes, airframe name or type).
Use the `--help` flag for a full list.
The newest logs will be downloaded first, and downloads can be interrupted and resumed later on.
There are different parsing libraries, for example [pyulog](../log/flight_log_analysis.md#pyulog) can be used to read logs with Python.
+256
View File
@@ -0,0 +1,256 @@
# Log Encryption
<Badge type="tip" text="PX4 v1.13" />
The [System Logger](../modules/modules_system.md#logger) can be used to create encrypted logs, which may then be decrypted manually before analysis.
The default encryption algorithm is XChaCha20, and the default wrapping algorithm is RSA2048-OAEP.
:::warning
Log encryption is not enabled by default in PX4 firmware builds.
To use it you will need to build firmware with this feature enabled and then upload it to the flight controller (see instructions below).
:::
:::tip
Log encryption was has been improved in PX4 main (v1.16+) to generate a single encrypted log file that contains both encrypted log data, and an encrypted symmetric key that you can use to decrypt it (provided you can decrypt the symmetric key).
In earlier versions the encrypted symmetric key was stored in a separate file.
For more information see the [Log Encryption (PX4 v1.15)](https://docs.px4.io/v1.15/en/dev_log/log_encryption.html).
:::
## How ULog Encryption Works
:::info
The encryption algorithm used is set in [SDLOG_ALGORITHM](../advanced_config/parameter_reference.md#SDLOG_ALGORITHM).
At time of writing, only `XChaCha20` is supported (AES can be selected, but there is no implementation).
If another algorithm is supported in future, the process is _likely_ to remain the same as documented here.
:::
The encryption process for each new ULog is:
1. A XChaCha20 symmetric key is generated and encrypted using an RSA2048 public key.
This wrapped (encrypted) key is stored on the SD card in the beginning of a file that has the suffix `.ulge` ("ulog encrypted").
2. When a log is captured, the ULog data is encrypted with the unwrapped symmetric key and the resulting data is appended into the end of the `.ulge` file immediately after the wrapped key data.
After the flight, the `.ulge` file containing both the wrapped symmetric key and the encrypted log data can be found on the SD card.
In order to extract the log file, a user must first decrypt the wrapped symmetric key, which can then be used to decrypt the log.
Decrypting the wrapped symmetric key file is only possible if the user has the corresponding RSA private key for the public key that was used to wrap it.
This process is covered in more detail in [Download & Decrypt Log Files](#download-decrypt-log-files) below.
## File Structure
Encrypted `.ulge` file contains following sections:
```plain
-------------------------
| Header |
-------------------------
| Wrapped symmetric key |
-------------------------
| Encrypted ulog data |
-------------------------
```
Header section (22 bytes) contains following fields:
| Bytes | Field |
| -------------------------------------- | --------------------- |
| 0..6 | File magic identifier |
| 7 | Header version |
| 8..15 | Timestamp |
| 16 | exchange algorithm |
| 17 | exchange key index |
| 18..19 | key size |
| 20..21 | nonce size |
The header part begins with magic string: `"ULogEnc"`, which identifies this is encrypted ulog file.
The file offset of the symmetric key section is `22` and the file offset of the log data section is `22 + key_size + nonce_size` (`key_size` and `nonce_size` are taken from the header section).
## Custom PX4 Firmware with Log Encryption
You will need to build custom firmware that contains your own public RSA key and the required Crypto API modules to support log encryption.
This section shows how to do this using the `px4-fmu-v5` board as an example.
:::tip
We show you how to generate your own keys in the [Generate RSA Public & Private Keys](#generate-rsa-public-private-keys) section below.
:::
:::info
The modules in a PX4 build are defined in configuration files, which may be modified either manually or using the `menuconfig` tool.
For more information see: [PX4 Board Configuration (Kconfig)](../hardware/porting_guide_config.md).
:::
### Cryptotest Make Target
Crypto uses large amounts of flash memory, and is therefore not included in the default PX4 make targets for each board (such as `make px4-fmu-v5`).
The easiest way to add support for encrypted logs is to define a custom `make` target that includes the required modules and your public RSA keys.
:::warning
Many builds are close to their maximum capacity.
If you run into a build error telling you that you have gone above the maximum flash memory, you will need to disable other features in the `.px4board` file you are working on, or in the `default.px4board` file.
Be careful not to disable something you need.
For example, if you found you were running out of memory on FMUv4 boards you could disable SIH mode by setting `CONFIG_MODULES_SIMULATION_SIMULATOR_SIH=n` in [boards/px4/fmu-v4/default.px4board](https://github.com/PX4/PX4-Autopilot/blob/main/boards/px4/fmu-v4/default.px4board#L76), which may free up enough flash memory to allow crypto to be added.
:::
#### Pixhawk FMUv5 boards
The FMUv5 board already has a custom make target `px4-fmu-v5_cryptotest` that you can use to build custom firmware with the required modules and "test" RSA keys.
The configuration file that enables the above make target is [`cryptotest.px4board`](https://github.com/PX4/PX4-Autopilot/blob/main/boards/px4/fmu-v5/cryptotest.px4board) file in `boards/px4/fmu-v5`.
The relevant keys in that file are reproduced below:
```plain
CONFIG_BOARD_CRYPTO=y
CONFIG_DRIVERS_STUB_KEYSTORE=y
CONFIG_DRIVERS_SW_CRYPTO=y
CONFIG_PUBLIC_KEY1="../../../Tools/test_keys/rsa2048.pub"
```
:::info
The file also sets `CONFIG_PUBLIC_KEY0` to a key named `key0.pub`.
This is not used in the current PX4 implementation and can be ignored.
:::
:::details
Overview of crypto-relevant keys
| Argument | 描述 |
| ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| CONFIG_BOARD_CRYPTO | Include crypto module in firmware.<br>= `y`: Enable log encryption.<br>= `n`: Disable log encryption. |
| CONFIG_DRIVERS_SW_CRYPTO | Include the PX4 crypto backend library (used by above library).<br>= `y`: Enable<br>= `n`: Disable |
| CONFIG_DRIVERS_STUB_KEYSTORE | Includes the PX4 stub keystore driver.<br>= `y`: Enable<br>= `n`: Disable |
| CONFIG_PUBLIC_KEY0 | Location of public key for keystore index 0. |
| CONFIG_PUBLIC_KEY1 | Location of public key for keystore index 1.<br>= `{path to key1}` |
| CONFIG_PUBLIC_KEY2 | Location of public key for keystore index 2.<br>= `{path to key2}` |
| CONFIG_PUBLIC_KEY3 | Location of public key for keystore index 3.<br>= `{path to key3}` |
The stub keystore is a keystore implementation that can store up to four keys.
The initial values of these keys are set in the locations defined by `CONFIG_PUBLIC_KEY0` to `CONFIG_PUBLIC_KEY3`.
The keys can be used for different cryptographic purposes, which are determined by parameters.
The _exchange key_, which is the public key used for encrypting the symmetric key stored in the beginning of the `.ulge` file, is specified using [SDLOG_EXCH_KEY](../advanced_config/parameter_reference.md#SDLOG_EXCH_KEY) as an index value into the key store.
The value is `1` by default, which maps to the key defined in `CONFIG_PUBLIC_KEY1`.
The _logging key_ is the unencrypted symmetric key.
This is specified using [SDLOG_KEY](../advanced_config/parameter_reference.md#SDLOG_KEY) as an index value into the key store, and default to `2`.
Note that the value is generated fresh for each log, and any value specified in `CONFIG_PUBLIC_KEY2` would be overwritten.
You can use choose different locations for your keys as long as they aren't used by anything else.
:::
The key in `CONFIG_PUBLIC_KEY1` is the public key used to wrap the symmetric key in the the beginning of `.ulge` file (by default: see [SDLOG_EXCH_KEY](../advanced_config/parameter_reference.md#SDLOG_EXCH_KEY)).
You can use the `rsa2048.pub` key for testing, or replace it with the path to your own public key in the file (see [Generate RSA Public & Private Keys](#generate-rsa-public-private-keys)).
Build the firmware like this:
```sh
make px4-fmu-v5_cryptotest
```
#### 其他飞控板
For other boards you will need to first copy `cryptotest.px4board` into the root of the target board directory.
For example, for FMUv6 you would copy the board to [/boards/px4/fmu-v6x](https://github.com/PX4/PX4-Autopilot/tree/main/boards/px4/fmu-v6x).
Then you will need to add a few more configuration settings that are present in FMUv5 default configuration but not in the other boards.
We do add these using the `menuconfig` tool.
To use `menuconfig` you will need to add these dependencies:
```sh
sudo apt-get install libncurses-dev flex bison openssl libssl-dev dkms libelf-dev libudev-dev libpci-dev libiberty-dev autoconf
```
Now, in PX4, run the normal `make` command you would use to build the board you are targeting, but add "menuconfig" at the end of it.
Here we use `px4_fmu-v5_cryptotest` as an example, because that already has the settings that we want to copy:
```sh
make px4_fmu-v5_cryptotest menuconfig
```
Navigate to `Crypto API` and use the **Y** key to select it.
![Menuconfig Crypto API Main Menu Option](../../assets/hardware/kconfig-crypto-1.png)
This will open the menu below.
Enable the settings: `Blake2s hash algorithm`, `Entropy pool and strong random number generator`, and `Use interrupts to feed timing randomness to entropy pool`.
![Menuconfig Crypto Options Set](../../assets/hardware/kconfig-crypto-2.png)
:::tip
Some of these options can be tweaked if desired.
:::
After enabling encryption settings, exit `menuconfig`.
You can now build and test.
## Download & Decrypt Log Files
Encrypted log files are downloaded using the QGroundControl [Log Download](https://docs.qgroundcontrol.com/master/en/qgc-user-guide/analyze_view/log_download.html) view (**Analyze Tools > Log Download**) just like ordinary log files.
Note that the encrypted files will be downloaded with the `.ulg` suffix, instead of `.ulge`.
### Decrypt ULogs
Before you can analyze your encrypted logs, you will need to decrypt them.
There is a Python script that can be used to decrypt logs in `Tools/decrypt_ulog.py`.
When decrypting a `.ulge` file the script takes 3 arguments:
1. The encrypted log file.
2. An empty string `''`.
3. The decryption key (the RSA2048 `.pem` private key which is used to unwrap the symmetric key).
例如:
```sh
python3 decrypt_ulog.py \
/home/john/Downloads/log_24_2024-10-6-23-39-50.ulg '' \
new_keys/private_key.pem
```
On success the decrypted log file is created with the `.ulog` suffix.
:::info
The script can be used with both `.ulge` logs and the `.ulgc`/`.ulgk` files used in [PX4 v1.15 Log Encryption](https://docs.px4.io/v1.15/en/dev_log/log_encryption.html).
The full command line syntax is given below:
```sh
usage: decrypt_ulog.py [-h] [ulog_file] [ulog_key] [rsa_key]
CLI tool to decrypt an ulog file
positional arguments:
ulog_file .ulge/.ulgc, encrypted log file
ulog_key .ulgk, legacy encrypted key (give empty string '' to ignore for .ulge)
rsa_key .pem format key for decrypting the ulog key
optional arguments:
-h, --help show this help message and exit
```
:::
## Generate RSA Public & Private Keys
To generate a RSA2048 private and public key, you can use OpenSSL:
```sh
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
```
Then you can create a public key from this private key:
```sh
# Convert private_key.pem to a DER file
openssl rsa -pubout -in private_key.pem -outform DER -out public_key.der
# From the DER file, generate a public key in hex format, separated by commas
xxd -p public_key.der | tr -d '\n' | sed 's/\(..\)/0x\1, /g' > public_key.pub
```
To use this key you would modify your `.px4board` file to point `CONFIG_PUBLIC_KEY1` to the file location of `public_key.pub`.
The private key generated should be stored safely and used when you need to decrypt log files.
+190
View File
@@ -0,0 +1,190 @@
# 日志
The [system logger](../modules/modules_system.md#logger) is able to log any ORB topic with all included fields.
Everything necessary is generated from the `.msg` file, so that only the topic name needs to be specified.
An optional interval parameter specifies the maximum logging rate of a certain topic.
所有主题的实例将会被记录。
The output log format is [ULog](../dev_log/ulog_file_format.md).
[Encrypted logging](../dev_log/log_encryption.md) is also supported.
## 用法
By default, logging is automatically started when arming, and stopped when disarming.
每次解锁后的飞行对话将会在 SD 卡上生成一个新的日志文件。
To display the current state, use `logger status` on the console.
If you want to start logging immediately, use `logger on`.
This overrides the arming state, as if the system was armed.
`logger off` undoes this.
If logging stops due to a write error, or reaching the [maximum file size](#file-size-limitations), PX4 will automatically restart logging in a new file.
对于所有支持的记录器命令和参数的列表,使用:
```
logger help
```
## 配置
The logging system is configured by default to collect sensible logs for [flight reporting](../getting_started/flight_reporting.md) with [Flight Review](http://logs.px4.io).
Logging may further be configured using the [SD Logging](../advanced_config/parameter_reference.md#sd-logging) parameters.
The parameters you are most likely to change are listed below.
| 参数 | 描述 |
| --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [SDLOG_MODE](../advanced_config/parameter_reference.md#SDLOG_MODE) | 日志模式 Defines when logging starts and stops.<br />- `-1`: Logging disabled.<br />- `0`: Log when armed until disarm (default).<br />- `1`: Log from boot until disarm.<br />- `2`: Log from boot until shutdown.<br />- `3`: Log based on the [AUX1 RC channel](../advanced_config/parameter_reference.md#RC_MAP_AUX1).<br />- `4`: Log from first armed until shutdown. |
| [SDLOG_PROFILE](../advanced_config/parameter_reference.md#SDLOG_PROFILE) | Logging profile. Use this to enable less common logging/analysis (e.g. for EKF2 replay, high rate logging for PID & filter tuning, thermal temperature calibration). |
| [SDLOG_MISSION](../advanced_config/parameter_reference.md#SDLOG_MISSION) | Create very small additional "Mission Log".<br>This log can _not_ be used with [Flight Review](../log/flight_log_analysis.md#flight-review-online-tool), but is useful when you need a small log for geotagging or regulatory compliance. |
Useful settings for specific cases:
- Raw sensor data for comparison: [SDLOG_MODE=1](../advanced_config/parameter_reference.md#SDLOG_MODE) and [SDLOG_PROFILE=64](../advanced_config/parameter_reference.md#SDLOG_PROFILE).
- Disabling logging altogether: [SDLOG_MODE=`-1`](../advanced_config/parameter_reference.md#SDLOG_MODE)
### Logger module
_Developers_ can further configure what information is logged via the [logger](../modules/modules_system.md#logger) module.
This allows, for example, logging of your own uORB topics.
### 诊断
Separately, the list of logged topics can also be customized with a file on the SD card.
Create a file `etc/logging/logger_topics.txt` on the card with a list of topics (For SITL, it's `build/px4_sitl_default/rootfs/fs/microsd/etc/logging/logger_topics.txt`):
```plain
<topic_name> <interval> <instance>
```
The `<interval>` is optional, and if specified, defines the minimum interval in ms between two logged messages of this topic.
If not specified, the topic is logged at full rate.
The `<instance>` is optional, and if specified, defines the instance to log.
If not specified, all instances of the topic are logged.
To specify `<instance>`, `<interval>` must be specified. It can be set to 0 to log at full rate
The topics in this file replace all of the default logged topics.
By far the best card we know so far is the <strong x-id="1">SanDisk Extreme U3 32GB</strong>. This card is recommended, because it does not exhibit write time spikes (and thus virtually no dropouts). Different card sizes might work equally well, but the performance is usually different.
```plain
sensor_accel 0 0
sensor_accel 100 1
sensor_gyro 200
sensor_mag 200 1
```
This configuration will log sensor_accel 0 at full rate, sensor_accel 1 at 10Hz, all sensor_gyro instances at 5Hz and sensor_mag 1 at 5Hz.
## 脚本
There are several scripts to analyze and convert logging files in the [pyulog](https://github.com/PX4/pyulog) repository.
## File size limitations
The maximum file size depends on the file system and OS.
The size limit on NuttX is currently around 2GB.
## 丢帧
Logging dropouts are undesired and there are a few factors that influence the
amount of dropouts:
- Most SD cards we tested exhibit multiple pauses per minute. This shows itself as a several 100 ms delay during a write command. It causes a dropout if the write buffer fills up during this time. This effect depends on the SD card (see below).
This shows itself as a several 100 ms delay during a write command.
It causes a dropout if the write buffer fills up during this time.
This effect depends on the SD card (see below).
- 格式化 SD 卡有助于避免丢帧。
- 增大日志缓存也有效。
- Decrease the logging rate of selected topics or remove unneeded topics from being logged (`info.py <file>` is useful for this).
## SD 卡
The maximum supported SD card size for NuttX is 32GB (SD Memory Card Specifications Version 2.0).
The **SanDisk Extreme U3 32GB** and **Samsung EVO Plus 32** are known to be reliable cards (do not exhibit write-time spikes, and thus virtually no dropouts).
The table below shows the **mean sequential write speed [KB/s]** / **maximum write time per block (average) [ms]** for F4- (Pixracer), F7-, and H7-based flight controllers.
| SD Card | F4 | F7 | H7 |
| -------------------------------------------------------------------------------- | ------------- | ---------- | --------- |
| SanDisk Extreme U3 32GB | 1500 / **15** | 1800/10 | 2900/8 |
| Samsung EVO Plus 32GB | 1700/10-60 | 1800/10-60 | 1900/9-60 |
| Sandisk Ultra Class 10 8GB | 348 / 40 | ?/? | ?/? |
| Sandisk Class 4 8GB | 212 / 60 | ?/? | ?/? |
| SanDisk Class 10 32 GB (High Endurance Video Monitoring Card) | 331 / 220 | ?/? | ?/? |
| Lexar U1 (Class 10), 16GB High-Performance | 209 / 150 | ?/? | ?/? |
| Sandisk Ultra PLUS Class 10 16GB | 196 /500 | ?/? | ?/? |
| Sandisk Pixtor Class 10 16GB | 334 / 250 | ?/? | ?/? |
| Sandisk Extreme PLUS Class 10 32GB | 332 / 150 | ?/? | ?/? |
Logging bandwidth with the default topics is around 50 KB/s, which almost all SD cards satisfy in terms of their mean sequential write speed.
More important than the mean write speed is spikes (or generally high values) in the maximum write time per block (of 4 KB) or `fsync` times, as a long write time means a larger log buffer is needed to avoid dropouts.
PX4 uses bigger buffers on F7/H7 and read caching, which is enough to compensate for spikes in many poor cards.
That said, if your card has an `fsync` or write duration of several 100ms it is should not be preferred for use with PX4.
You can check the value by running [sd_bench](../modules/modules_command.md#sd-bench) should be run with more iterations (around 100 should do).
```sh
sd_bench -r 100
```
并且同一时刻只能有一个客户机可以请求日志流。
PX4 uses bigger buffers on F7/H7 and read caching to make up for some of these issues.
:::info
If you have concerns about a particular card you can run the above test and report the results to https://github.com/PX4/PX4-Autopilot/issues/4634.
:::
## 日志流
The traditional and still fully supported way to do logging is using an SD card on the FMU.
However there is an alternative, log streaming, which sends the same logging data via MAVLink.
This method can be used for example in cases where the FMU does not have an SD card slot (e.g. Intel® Aero Ready to Fly Drone) or simply to avoid having to deal with SD cards.
Both methods can be used independently and at the same time.
The requirement is that the link provides at least ~50KB/s, so for example a WiFi link.
And only one client can request log streaming at the same time.
The connection does not need to be reliable, the protocol is designed to handle drops.
There are different clients that support ulog streaming:
- `mavlink_ulog_streaming.py` script in PX4-Autopilot/Tools.
- QGroundControl:
![QGC Log Streaming](../../assets/gcs/qgc-log-streaming.png)
- [MAVGCL](https://github.com/ecmnet/MAVGCL)
### Diagnostics
- If log streaming does not start, make sure the `logger` is running (see above), and inspect the console output while starting.
- If it still does not work, make sure that Mavlink 2 is used. Enforce it by setting <code>MAV_PROTO_VER</code> to 2.
Enforce it by setting `MAV_PROTO_VER` to 2.
- Log streaming uses a maximum of 70% of the configured MAVLink rate (`-r` parameter).
如果需要更大的速率,数据会丢失。
The currently used percentage can be inspected with `mavlink status` (1.8% is used in this example):
```sh
instance #0:
GCS heartbeat: 160955 us ago
mavlink chan: #0
type: GENERIC LINK OR RADIO
flow control: OFF
rates:
tx: 95.781 kB/s
txerr: 0.000 kB/s
rx: 0.021 kB/s
rate mult: 1.000
ULog rate: 1.8% of max 70.0%
accepting commands: YES
MAVLink version: 2
transport protocol: UDP (14556)
```
Also make sure `txerr` stays at 0.
Also make sure <code>txerr</code> stays at 0. If this goes up, either the NuttX sending buffer is too small, the physical link is saturated or the hardware is too slow to handle the data.
## See Also
- [Encrypted logging](../dev_log/log_encryption.md)
+512
View File
@@ -0,0 +1,512 @@
# ULog 文件格式
ULog is the file format used for logging messages. The format is self-describing, i.e. it contains the format and [uORB](../middleware/uorb.md) message types that are logged.
This document is meant to be the ULog File Format Spec Documentation.
It is intended especially for anyone who is interested in writing a ULog parser / serializer and needs to decode / encode files.
PX4 uses ULog to log uORB topics as messages related to (but not limited to) the following sources:
- **Device inputs:** Sensors, RC input, etc.
- **Internal states:** CPU load, attitude, EKF state, etc.
- **String messages:** `printf` statements, including `PX4_INFO()` and `PX4_ERR()`.
The format uses [little endian](https://en.wikipedia.org/wiki/Endianness) memory layout for all binary types (the least significant byte (LSB) of data type is placed at the lowest memory address).
## 数据类型
The following binary types are used for logging. They all correspond to the types in C.
| 类型 | 大小(以字节为单位) |
| ----------------------------------------------------------- | ---------- |
| int8_t, uint8_t | 1 |
| int16_t, uint16_t | 2 |
| int32_t, uint32_t | 4 |
| int64_t, uint64_t | 8 |
| float | 4 |
| double | 8 |
| bool, char | 1 |
Additionally the types can be used as a fixed-size array: e.g. `float[5]`.
Strings (`char[length]`) do not contain the termination NULL character `'\0'` at the end.
:::info
String comparisons are case sensitive, which should be taken into account when comparing message names when [adding subscriptions](#a-subscription-message).
:::
## ULog File Structure
ULog files have the following three sections:
```
----------------------
| 头 |
----------------------
| 定义 |
----------------------
| 数据 |
----------------------
```
A description of each section is provided below.
### 头部分
头是一个固定大小的部分,具有以下格式(16个字节):
```plain
----------------------------------------------------------------------
| 0x55 0x4c 0x6f 0x67 0x01 0x12 0x35 | 0x01 | uint64_t |
| File magic(7B) | Version (1B) | Timestamp (8B) |
----------------------------------------------------------------------
```
- **File Magic (7 Bytes):** File type indicator that reads "ULogXYZ where XYZ is the magic bytes sequence `0x01 0x12 0x35`"
- **Version (1 Byte):** File format version (currently 1)
- **Timestamp (8 Bytes):** `uint64_t` integer that denotes when the logging started in microseconds.
### Definition & Data Section Message Header
The _Definitions and Data_ sections contain a number of **messages**. Each message is preceded by this header:
```c
struct message_header_s {
uint16_t msg_size;
uint8_t msg_type;
};
```
- `msg_size` is the size of the message in bytes without the header.
- `msg_type` defines the content, and is a single byte.
:::info
Message sections below are prefixed with the character that corresponds to it's `msg_type`.
:::
### 定义部分
The definitions section contains basic information such as software version, message format, initial parameter values, and so on.
The message types in this section are:
1. [Flag Bits](#b-flag-bits-message)
2. [Format Definition](#f-format-message)
3. [Information](#i-information-message)
4. [Multi Information](#m-multi-information-message)
5. [Parameter](#p-parameter-message)
6. [Default Parameter](#q-default-parameter-message)
#### 'B': Flag Bits Message
:::info
This message must be the **first message** right after the header section, so that it has a fixed constant offset from the start of the file!
:::
This message provides information to the log parser whether the log is parsable or not.
```c
struct ulog_message_flag_bits_s {
struct message_header_s header; // msg_type = 'B'
uint8_t compat_flags[8];
uint8_t incompat_flags[8];
uint64_t appended_offsets[3]; // file offset(s) for appended data if appending bit is set
};
```
- `compat_flags`: compatible flag bits
- These flags indicate the presence of features in the log file that are compatible with any ULog parser.
- `compat_flags[0]`: _DEFAULT_PARAMETERS_ (Bit 0): if set, the log contains [default parameters message](#q-default-parameter-message)
The rest of the bits are currently not defined and must be set to 0.
These bits can be used for future ULog changes that are compatible with existing parsers.
For example, adding a new message type can be indicated by defining a new bit in the standard, and existing parsers will ignore the new message type.
It means parsers can just ignore the bits if one of the unknown bits is set.
- `incompat_flags`: incompatible flag bits.
- `incompat_flags[0]`: _DATA_APPENDED_ (Bit 0): if set, the log contains appended data and at least one of the `appended_offsets` is non-zero.
The rest of the bits are currently not defined and must be set to 0.
这可用于引入现有解析器无法处理的重大更改。 For example, when an old ULog parser that didn't have the concept of _DATA_APPENDED_ reads the newer ULog, it would stop parsing the log as the log will contain out-of-spec messages / concepts.
If a parser finds any of these bits set that isn't specified, it must refuse to parse the log.
- `appended_offsets`: File offset (0-based) for appended data.
如果没有附加数据,则所有偏移量必须为零。
这可以用于消息中途暂停的情况下可靠的添加数据。
For example, crash dumps.
附加数据的过程应该做到:
- set the relevant `incompat_flags` bit
- set the first `appended_offsets` that is currently 0 to the length of the log file without the appended data, as that is where the new data will start
- append any type of messages that are valid for the Data section.
It is possible that there are more fields appended at the end of this message in future ULog specifications. This means a parser must not assume a fixed length of this message. If the message is longer than expected (currently 40 bytes), the exceeding bytes must just be ignored.
这意味着解析器必须不能假定此消息的长度是固定的。
If the `msg_size` is bigger than expected (currently 40), any additional bytes must be ignored/discarded.
#### 'F': Format Message
Format message defines a single message name and its inner fields in a single string.
```c
struct message_format_s {
struct message_header_s header; // msg_type = 'F'
char format[header.msg_size];
};
```
- `format` is a plain-text string with the following format: `message_name:field0;field1;`
- There can be an arbitrary amount of fields (minimum 1), separated by `;`.
- `message_name`: an arbitrary non-empty string with these allowed characters: `a-zA-Z0-9_-/` (and different from any of the [basic types](#data-types)).
A `field` has the format: `type field_name`, or for an array: `type[array_length] field_name` is used (only fixed size arrays are supported).
`field_name` must consist of the characters in the set `a-zA-Z0-9_`.
A `type` is one of the [basic binary types](#data-types) or a `message_name` of another format definition (nested usage).
- 一个类型可以在定义之前使用。
- e.g. The message `MessageA:MessageB[2] msg_b` can come before the `MessageB:uint_8[3] data`
- There can be arbitrary nesting but **no circular dependencies**
- e.g. `MessageA:MessageB[2] msg_b` & `MessageB:MessageA[4] msg_a`
有些字段名是特殊的:
- `timestamp`: every message format with a [Subscription Message](#a-subscription-message) must include a timestamp field (for example a message format only used as part of a nested definition by another format may not include a timestamp field)
- Its type must be `uint64_t`.
- The unit is microseconds.
- The timestamp must always be monotonic increasing for a message series with the same `msg_id` (same subscription).
- `_padding{}`: field names that start with `_padding` (e.g. `_padding[3]`) should not be displayed and their data must be ignored by a reader.
- 写入器可以通过插入这个字段确保正确对齐。
- If the padding field is the last field, then this field may not be logged, to avoid writing unnecessary data.
- This means the `message_data_s.data` will be shorter by the size of the padding.
- 但是当报文在嵌套定义中使用时任然需要填充。
- In general, message fields are not necessarily aligned (i.e. the field offset within the message is not necessarily a multiple of its data size), so a reader must always use appropriate memory copy methods to access individual fields.
#### 'I': Information Message
The Information message defines a dictionary type definition `key` : `value` pair for any information, including but not limited to Hardware version, Software version, Build toolchain for the software, etc.
```c
struct ulog_message_info_header_s {
struct message_header_s header; // msg_type = 'I'
uint8_t key_len;
char key[key_len];
char value[header.msg_size-1-key_len]
};
```
- `key_len`: Length of the key value
- `key`: Contains the key string in the form`type name`, e.g. `char[value_len] sys_toolchain_ver`. Valid characters for the name: `a-zA-Z0-9_-/`. The type may be one of the [basic types including arrays](#data-types).
- `value`: Contains the data (with the length `value_len`) corresponding to the `key` e.g. `9.4.0`.
:::info
A key defined in the Information message must be unique. Meaning there must not be more than one definition with the same key value.
:::
解析器可以将报文信息存储为字典。
预定义的信息报文有:
| 键 | 描述 | 示例值 |
| ----------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `char[value_len] sys_name` | 系统名称 | "PX4" |
| `char[value_len] ver_hw` | 硬件版本 (主板) | "PX4FMU_V4" |
| `char[value_len] ver_hw_subtype` | 主办子版本 (变化的) | "V2" |
| `char[value_len] ver_sw` | 软件版本 (git 标签) | "7f65e01" |
| `char[value_len] ver_sw_branch` | git branch | "master" |
| `uint32_t ver_sw_release` | 软件版本 (见下文) | 0x010401ff |
| `char[value_len] sys_os_name` | 操作系统名称 | "Linux" |
| `char[value_len] sys_os_ve`r | 操作系统版本 (git 标签) | "9f82919" |
| `uint32_t ver_os_release` | 操作系统版本 (见下文) | 0x010401ff |
| `char[value_len] sys_toolchain` | 工具链名称 | "GNU GCC" |
| `char[value_len] sys_toolchain_ver` | 工具链版本 | "6.2.1" |
| `char[value_len] sys_mcu` | 芯片名称和修订 | "STM32F42x, rev A" |
| `char[value_len] sys_uuid` | Unique identifier for vehicle (eg. MCU ID) | "392a93e32fa3"... |
| `char[value_len] log_type` | Type of the log (full log if not specified) | "mission" |
| `char[value_len] replay` | 重播日志的文件名如果处于重播模式 | "log001.ulg" |
| `int32_t time_ref_utc` | UTC 时间的秒偏移量 | -3600 |
:::info
`value_len` represents the data size of the `value`. This is described in the `key`.
:::
- The format of `ver_sw_release` and `ver_os_release` is: 0xAABBCCTT, where AA is **major**, BB is **minor**, CC is patch and TT is the **type**.
- **Type** is defined as following: `>= 0`: development, `>= 64`: alpha version, `>= 128`: beta version, `>= 192`: RC version, `== 255`: release version.
- For example, `0x010402FF` translates into the release version v1.4.2.
This message can also be used in the Data section (this is however the preferred section).
#### 'M': Multi Information Message
Multi information message serves the same purpose as the information message, but for long messages or multiple messages with the same key.
```c
struct ulog_message_info_multiple_header_s {
struct message_header_s header; // msg_type = 'M'
uint8_t is_continued; // can be used for arrays
uint8_t key_len;
char key[key_len];
char value[header.msg_size-2-key_len]
};
```
- `is_continued` can be used for split-up messages: if set to 1, it is part of the previous message with the same key.
解析器可以将所有多报文信息存储为一个 2D 列表,使用与日志中报文相同的顺序。
Valid names and types are the same as for the Information message.
#### 'P': Parameter Message
Parameter message in the _Definitions_ section defines the parameter values of the vehicle when logging is started. It uses the same format as the [Information Message](#i-information-message).
```c
struct message_info_s {
struct message_header_s header; // msg_type = 'P'
uint8_t key_len;
char key[key_len];
char value[header.msg_size-1-key_len]
};
```
If a parameter dynamically changes during runtime, this message can also be [used in the Data section](#messages-shared-with-the-definitions-section) as well.
The data type is restricted to `int32_t` and `float`. Valid characters for the name: `a-zA-Z0-9_-/`.
#### 'Q': Default Parameter Message
The default parameter message defines the default value of a parameter for a given vehicle and setup.
```c
struct ulog_message_parameter_default_header_s {
struct message_header_s header; // msg_type = 'Q'
uint8_t default_types;
uint8_t key_len;
char key[key_len];
char value[header.msg_size-2-key_len]
};
```
- `default_types` is a bitfield and defines to which group(s) the value belongs to.
- At least one bit must be set:
- `1<<0`: system wide default
- `1<<1`: default for the current configuration (e.g. an airframe)
A log may not contain default values for all parameters.
In those cases the default is equal to the parameter value, and different default types are treated independently.
This message can also be used in the Data section, and the same data type and naming applies as for the Parameter message.
This section ends before the start of the first [Subscription Message](#a-subscription-message) or [Logging](#l-logged-string-message) message, whichever comes first.
### 数据部分
The message types in the _Data_ section are:
1. [Subscription](#a-subscription-message)
2. [Unsubscription](#r-unsubscription-message)
3. [Logged Data](#d-logged-data-message)
4. [Logged String](#l-logged-string-message)
5. [Tagged Logged String](#c-tagged-logged-string-message)
6. [Synchronization](#s-synchronization-message)
7. [Dropout Mark](#o-dropout-message)
8. [Information](#i-information-message)
9. [Multi Information](#m-multi-information-message)
10. [Parameter](#p-parameter-message)
11. [Default Parameter](#q-default-parameter-message)
#### `A`: Subscription Message
Subscribe a message by name and give it an id that is used in [Logged data Message](#d-logged-data-message).
This must come before the first corresponding [Logged data Message](#d-logged-data-message).
```c
struct message_add_logged_s {
struct message_header_s header; // msg_type = 'A'
uint8_t multi_id;
uint16_t msg_id;
char message_name[header.msg_size-3];
};
```
- `multi_id`: the same message format can have multiple instances, for example if the system has two sensors of the same type. 默认值以及第一个实例一定是0.
- `msg_id`: unique id to match [Logged data Message](#d-logged-data-message) data. 第一次使用一定要设置为 0,然后递增。
- The same `msg_id` must not be used twice for different subscriptions.
- `message_name`: message name to subscribe to.
Must match one of the [Format Message](#f-format-message) definitions.
#### `R`: Unsubscription Message
Unsubscribe a message, to mark that it will not be logged anymore (not used currently).
```c
struct message_remove_logged_s {
struct message_header_s header; // msg_type = 'R'
uint16_t msg_id;
};
```
#### 'D': Logged Data Message
```c
struct message_data_s {
struct message_header_s header; // msg_type = 'D'
uint16_t msg_id;
uint8_t data[header.msg_size-2];
};
```
- `msg_id`: as defined by a [Subscription Message](#a-subscription-message)
- `data` contains the logged binary message as defined by [Format Message](#f-format-message)
有关填充字段的特殊处理,请参见上文。
#### 'L': Logged String Message
Logged string message, i.e. `printf()` output.
```c
struct message_logging_s {
struct message_header_s header; // msg_type = 'L'
uint8_t log_level;
uint64_t timestamp;
char message[header.msg_size-9]
};
```
- `timestamp`: in microseconds
- `log_level`: same as in the Linux kernel:
| 参数名 | 对应值 | 含义 |
| ------- | --- | -------- |
| EMERG | '0' | 系统无法使用 |
| ALERT | '1' | 操作必须立即执行 |
| CRIT | '2' | 紧急情况 |
| ERR | '3' | 错误情况 |
| WARNING | '4' | 警告情况 |
| NOTICE | '5' | 正常但重要的情况 |
| INFO | '6' | 信息 |
| DEBUG | '7' | 调试级别的消息 |
#### 'C': Tagged Logged String Message
```c
struct message_logging_tagged_s {
struct message_header_s header; // msg_type = 'C'
uint8_t log_level;
uint16_t tag;
uint64_t timestamp;
char message[header.msg_size-11]
};
```
- `tag`: id representing source of logged message string. It could represent a process, thread or a class depending upon the system architecture.
- For example, a reference implementation for an onboard computer running multiple processes to control different payloads, external disks, serial devices etc can encode these process identifiers using a `uint16_t enum` into the `tag` attribute of struct as follows:
```c
enum class ulog_tag : uint16_t {
unassigned,
mavlink_handler,
ppk_handler,
camera_handler,
ptp_handler,
serial_handler,
watchdog,
io_service,
cbuf,
ulg
};
```
- `timestamp`: in microseconds
- `log_level`: same as in the Linux kernel:
| 参数名 | 对应值 | 含义 |
| ------- | --- | -------- |
| EMERG | '0' | 系统无法使用 |
| ALERT | '1' | 操作必须立即执行 |
| CRIT | '2' | 紧急情况 |
| ERR | '3' | 错误情况 |
| WARNING | '4' | 警告情况 |
| NOTICE | '5' | 正常但重要的情况 |
| INFO | '6' | 信息 |
| DEBUG | '7' | 调试级别的消息 |
#### 'S': Synchronization message
Synchronization message so that a reader can recover from a corrupt message by searching for the next sync message.
```c
struct message_sync_s {
struct message_header_s header; // msg_type = 'S'
uint8_t sync_magic[8];
};
```
- `sync_magic`: [0x2F, 0x73, 0x13, 0x20, 0x25, 0x0C, 0xBB, 0x12]
#### 'O': Dropout message
Mark a dropout (lost logging messages) of a given duration in ms.
例如当设备不够快的情况下会出现丢包。
```c
struct message_dropout_s {
struct message_header_s header; // msg_type = 'O'
uint16_t duration;
};
```
#### Messages shared with the Definitions Section
Since the Definitions and Data Sections use the same message header format, they also share the same messages listed below:
- [Information Message](#i-information-message).
- [Multi Information Message](#m-multi-information-message)
- [Parameter Message](#p-parameter-message)
- For the _Data_ section, the Parameter Message is used when the parameter value changes
- [Default Parameter Message](#q-default-parameter-message)
## 解析器的要求
一个有效的 ULog 解析器必须满足以下要求:
- Must ignore unknown messages (but it can print a warning)
- 解析未来/未知的文件格式版本 (但可以打印警告) 。
- Must refuse to parse a log which contains unknown incompatibility bits set (`incompat_flags` of [Flag Bits Message](#b-flag-bits-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.
未完成的报文应该丢弃。
- 对于附加数据:解析器可以假设数据部分存在,即在定义部分之后的位置有一个偏移点。
- 必须将附加数据视为常规数据部分的一部分。
## Known Parser Implementations
- PX4 Firmware: C++
- [logger module](https://github.com/PX4/PX4-Autopilot/tree/main/src/modules/logger)
- [replay module](https://github.com/PX4/PX4-Autopilot/tree/main/src/modules/replay)
- [hardfault_log module](https://github.com/PX4/PX4-Autopilot/tree/main/src/systemcmds/hardfault_log): append hardfault crash data.
- [pyulog](https://github.com/PX4/pyulog): python, ULog reader and writer library with CLI scripts.
- [ulog_cpp](https://github.com/PX4/ulog_cpp): C++, ULog reader and writer library.
- [FlightPlot](https://github.com/PX4/FlightPlot): Java, log plotter.
- [MAVLink](https://github.com/mavlink/mavlink): Messages for ULog streaming via MAVLink (note that appending data is not supported, at least not for cut off messages).
- [QGroundControl](https://github.com/mavlink/qgroundcontrol): C++, ULog streaming via MAVLink and minimal parsing for GeoTagging.
- [mavlink-router](https://github.com/01org/mavlink-router): C++, ULog streaming via MAVLink.
- [MAVGAnalysis](https://github.com/ecmnet/MAVGCL): Java, ULog streaming via MAVLink and parser for plotting and analysis.
- [PlotJuggler](https://github.com/facontidavide/PlotJuggler): C++/Qt application to plot logs and time series. 自版本2.1.3支持 ULog。
- [ulogreader](https://github.com/maxsun/ulogreader): Javascript, ULog reader and parser outputs log in JSON object format.
- [Foxglove Studio](https://github.com/foxglove/studio): an integrated visualization and diagnosis tool for robotics
(Typescript ULog parser: https://github.com/foxglove/ulog).
## 文件格式版本历史
### 版本 2 中的改变
- Addition of [Multi Information Message](#m-multi-information-message) and [Flag Bits Message](#b-flag-bits-message) and the ability to append data to a log.
- 这被用来给现有的日志添加损坏的数据。
- 如果从中间切开的报文数据被附加到日志中,这不能被版本 1 解析器解析。
- 除此之外,如果解析器忽略未知消息,则提供向前和向后的兼容性。