更新log实训

This commit is contained in:
yewuya 2021-01-22 17:53:54 +08:00
parent 7e17efd0ac
commit d7cdf6f651
2 changed files with 80 additions and 301 deletions

View File

@ -2,37 +2,77 @@
## log简介 ## log简介
## log使用 **log的定义**:日志是将软件运行的状态、过程等信息,输出到不同的介质中(例如:文件、控制台、显示屏等),并进行显示和保存。为软件调试、维护过程中的问题追溯、性能分析、系统监控、故障预警等功能,提供参考依据。可以说,日志的使用,几乎占用的软件生命周期的至少 80% 的时间。
**log的重要性**:对于操作系统而言,由于其软件的复杂度非常大,单步调试在一些场景下并不适合,所以日志组件在操作系统上几乎都是标配。完善的日志系统也能让操作系统的调试事半功倍.
**log的作用**
在进行debug调试中可以使用以下代码进行调试根据不同的错误级别在相应的部分插入相应的信息。不同的信息代表不同的情况info一般用来表示重要功能完成了。warn表示发生异常但不影响系统使用err代表使用已经影响到了系统的工作必须马上解决问题 * *** 确定程序的运行路径 *** 一个函数有没有被调用,一个 if 块有没有被执行,一个 while 循环执行了几次,到了哪一步中断了,都可以通过 输出出相关信息来查看
PX4_INFO("输出需要的数据"); * *** 查看变量的状态 *** 程序自身的报错会告诉你发生了什么错误,但你还需要找出为什么会发生错误。**通过 log输出出错语句涉及到的相关变量的值和类型**,可以帮助分析出错原因。
PX4_WARN(" 输出警告信息"); * *** 找出出错位置 *** 往往错误的原因并不在报错的位置,所以多输出一些标记,多 输出不同位置的变量值,**查看变量在运行过程中值的变化情况**,可以观察是在哪里发生了问题。
PX4_ERR("输出错误信息" ); ## px4 log使用
https://zhuanlan.zhihu.com/p/45298171 ### 代码添加log输出
日志文件结构 在飞控开发过程中可以使用以下代码进行log调试根据不同的错误级别在相应的部分插入相应的信息。不同的信息代表不同的情况info一般用来表示重要功能完成了。warn表示发生异常但不影响系统使用err代表使用已经影响到了系统的工作必须马上解决问题。
ulog 功能 ```c++
PX4_INFO("输出需要的数据");
PX4_WARN(" 输出警告信息");
PX4_ERR("输出错误信息" );
log作用 ```
在代码的需要的位置插入这三种log输出代码原则如下
**多输出一些辅助信息**,方便自己查看,不然一堆数据看花眼。一般输出时会标注上**变量名,再输出变量类型,以及变量的值**
**在出错行之前输出**。报错行涉及的一些变量,把他们的数值和类型,全都输出出来,看看和预期是否一致。
**一行做一件事 **。如果你出错的一行里连续调用了多个函数或运算,要分开写,分开输出。
Px4还有一个logger功能可以使用logger 记录 uorb消息,将记录的消息转成ulog文件存储默认记录的消息主要是飞行日志相关的内容。记录的文件为sample.ulg文件可以通过安装pyulog查看相应的信息 ### nsh调试
debug方式主要分仿真器调试和真机调试一般都是先进行软件仿真调试再进行真机调试。二者调试时的终端都会输出log信息。根据输出的log信息可以快速定位问题所在。也可以在把编译生成的固件写入飞控之后飞控连接[QGC地面站][http://qgroundcontrol.com/ ]之后打开mavlink console也可以运行自己所写的module.仿真器和QGC地面站都可以输入help来查看有效的命令和语法.这里以px4_simple_app为例,下图是在jmavsim仿真器运行px4_simple_app时所输出的log信息。
![image-20210122161137944](C:\Users\ASUS\Desktop\mymarkdown\images\image-20210122161137944.png)
![image-20210122154447764](C:\Users\ASUS\Desktop\mymarkdown\images\image-20210122154447764.png)
### 日志分析
px4 的logger会把订阅的uorb消息记录成.ulg文件存在SD卡中
px4还有一个logger功能,默认情况下飞机解锁之后就会开始记录日志,飞机锁定之后停止记录日志.也可以在终端使用logger on手动开启.logger off停止记录.日志记录的主要内容为飞行数据和debug信息记录的日志文件可以用于对飞机的系统和飞行性能的评估、调整和事故分析.日志的格式是ulog.记录的日志文件会存储成.ulg文件存在SD卡中.可以安装使用pyulog查看日志信息.
pyulog安装方法 pyulog安装方法
```shell
git clone https://github.com/PX4/pyulog.git
cd pyulog
python setup.py build install
```
pyulog常用命令
```shell
ulog2csv sample.ulg //将sample.ulg文件转成.csv文件这些文件可以使用excel打开
ulog_messgaes sample.ulg //查看ulog中的uorb的消息
ulog_info sample.ulg //显示sample.ulg记录的信息
ulog_params sample.ulg //查看sample.ulg文件的参数
```
下方是ulg文件转成csv后的几个比较重要的文件和所记录的信息。
airspeed_0.csv 存放了飞行的指示空速和滤波前后的真空速 airspeed_0.csv 存放了飞行的指示空速和滤波前后的真空速
vehicle_attitude_0.csv 存放了四元数及pqr或者是姿态角速度? vehicle_attitude_0.csv 存放了四元数及pqr
vehicle_attitude_setpoint_0.csv 存放了期望的姿态角及四元数、油门信息 vehicle_attitude_setpoint_0.csv 存放了期望的姿态角及四元数、油门信息
@ -46,6 +86,35 @@ ekf2 两个文件中存放着互补滤波的数据更新
home_position_0.csv 存放着地面站所在位置 home_position_0.csv 存放着地面站所在位置
日志记录的消息主题也可以自己定义的,通过创建SD卡中的etc/logging/logger_topics.txt文件可以自定义记录需要的日志消息主题.一旦使用这个文件就会自动替换全部的默认主题.文件内容格式如下.
```text
<topic_name> <interval> <instance>
```
topic_name 就是所要订阅的消息主题的名称
interval 是消息之间的间隔.如果指定了则定义该主题的两条日志消息之间的最小间隔单位为ms。如果不指定则以全速率记录该主题.
instance是消息的实例,如果不指定就记录该消息主题的所有实例,指定就记录相应的实例.如果不指定就记录该消息主题的所有实例.
例子如下
```text
sensor_accel 0 0
sensor_accel 100 1
sensor_gyro 200
sensor_mag 200 1
```
使用前的记录的数据
![image-20210122174608467](C:\Users\ASUS\Desktop\mymarkdown\images\image-20210122174608467.png)
替换后的数据
![image-20210122174633579](C:\Users\ASUS\Desktop\mymarkdown\images\image-20210122174633579.png)

View File

@ -1,290 +0,0 @@
# log实训
## log简介
## log的作用
**log的定义**:日志是将软件运行的状态、过程等信息,输出到不同的介质中(例如:文件、控制台、显示屏等),并进行显示和保存。为软件调试、维护过程中的问题追溯、性能分析、系统监控、故障预警等功能,提供参考依据。可以说,日志的使用,几乎占用的软件生命周期的至少 80% 的时间。
**log的重要性**:对于操作系统而言,由于其软件的复杂度非常大,单步调试在一些场景下并不适合,所以日志组件在操作系统上几乎都是标配。完善的日志系统也能让操作系统的调试事半功倍
px4所使用的log为ulog.
## ulog的功能
**ULog File Format**
- Ulog是一种用来记录系统数据的日志格式。这种格式是自解释的比如他包含了日志的格式和消息类型。
- 他可以用来记录设备的输入传感器等内部状态CPU负载姿态等以及打印日志信息。
- 采用小端格式。(注:低字节存储在低地址)
**数据类型**
- 下面列举了使用的数据类型他们都与C语言的类型相对应。
![请输入图片描述](http://images.ncnynl.com/ros/2017/PX4-13.21-01.png)
- 此外所有类型都可以使用数组,比如`float[5]`。一般而言所有的字符串(`char[length]`)结尾都不包含 `'\0'`。字符串大小写敏感。
**文件结构**
- 文件包含三个部分:
```
----------------------
| Header |
----------------------
| Definitions |
----------------------
| Data |
----------------------
```
- **头部**
- 头部大小固定,格式如下(16 bytes):
```
----------------------------------------------------------------------
| 0x55 0x4c 0x6f 0x67 0x01 0x12 0x35 | 0x00 | uint64_t |
| File magic (7B) | Version (1B) | Timestamp (8B) |
----------------------------------------------------------------------
```
- Version是文件格式的版本当前是0。时间戳是uint64_t类型用微秒表示记录开始的时间。
- **定义部分Definitions Section**
- 长度可变,包含版本信息,格式定义以及(初始) 参数值。
- 定义部分和数据部分由消息流组成,消息流以下面这样的头部开始:
```
struct message_header_s {
uint16_t msg_size;
uint8_t msg_type
};
```
- `msg_size` 消息去掉头部的字节数 (`hdr_size`= 3 bytes). `msg_type`定义了内容,是下面可能的情况之一:
- 'F': format definition for a single (composite) type that can be logged or used in another definition as a nested type.
- 'F': 单一(混合)类型的格式定义,用于日志记录或者作为嵌套类型用在其他的定义中。
```
struct message_format_s {
struct message_header_s header;
char format[header.msg_size-hdr_size];
};
```
- `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可以是:
```
`uint64_t` \(当前唯一被用到的\), `uint32_t`, `uint16_t` or
`uint8_t`. 除了 `uint8_t` 的单位是毫秒,其他单位都是微秒 。
日志写入器必须确保记录日志消息足够频繁,能够检测环绕,一个日志读取器必须处理环绕
\(并且考虑到数据丢失\. 拥有相同`msg_id`的消息序列的timestamp必须单调增加.
```
- Padding: 以`_padding` 开头的field名称不应该被显示并且读取器应该忽略他们的数据should not be displayed and
their data must be ignored by a reader. 写入器插入这些 fields 用来确保正确的对齐。
如果 padding field 是最后一个field, 那么这个field不会被记录,这样就避免了写入不必要的数据 这使`message_data_s.data` 得以缩短 。然而当消息用于嵌套定义的时候依然需要padding
- 'I': information message.
```
struct message_info_s {
struct message_header_s header;
uint8_t key_len;
char key[key_len];
char value[header.msg_size-hdr_size-1-key_len]
};
```
- `key` 是一个纯文本字符串, 只包含一个field没有;结尾,例如
`float[3] myvalues`. `value` 含有用`key`描述的数据。
- 预定义的 information messages :
![请输入图片描述](http://images.ncnynl.com/ros/2017/PX4-13.21-02.png)
- `ver_sw_release``ver_os_release`的格式是: `0xAABBCCTT`, AA 是 major主版本号, BB 是 minor次版本号, CC 是 patch补丁版本 and TT 是类型. 类型 定义如下: `>= 0`: development, `>= 64`: alpha version, `>= 128`: beta version, `>= 192`: RC version, `== 255`: release version. 例如 0x010402ff 转换成版本为 v1.4.2.
- This message can also be used in the Data section (this is however the preferred section).
- 'P': 参数消息. 和message_info_s格式一样. 如果一个参数在运行时实时改变, 那这个消息也可以用在数据部分(Data section).
```
数据类型限制为: `int32_t`, `float`.
```
- This section ends before the start of the first message_add_logged_s or message_logging_s message, whichever comes first.
**数据部分Data Section**
- **下列消息属于这一部分:**
- 'A': 订阅一个message并且赋予它一个用于message_data_s的id. This must come before the first corresponding message_data_s.
```
struct message_add_logged_s {
struct message_header_s header;
uint8_t multi_id;
uint16_t msg_id;
char message_name[header.msg_size-hdr_size-3];
};
```
- `multi_id`: 相同的消息格式可以通过`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,标记这个消息不再被记录 (当前没有使用).
```
struct message_remove_logged_s {
struct message_header_s header;
uint16_t msg_id;
};
```
- 'D': 包含记录的数据.
```
struct message_data_s {
struct message_header_s header;
uint16_t msg_id;
uint8_t data[header.msg_size-hdr_size];
};
```
- `msg_id`: 被`message_add_logged_s`定义的 message。 `data` 包含被 `message_format_s`定义的 二进制消息. 关于padding特殊的处理机制查看上面.
- 'L': 记录的字符串消息, i.e. printf output.
```
struct message_logging_s {
struct message_header_s header;
uint8_t log_level;
uint64_t timestamp;
char message[header.msg_size-hdr_size-9]
};
```
- `timestamp`:微秒为单位, `log_level`: 与 Linux kernel 一样:
![请输入图片描述](http://images.ncnynl.com/ros/2017/PX4-13.21-03.png)
- synchronization message so that a reader can recover from a corrupt message by search for the next sync message (not used currently). 'S': 同步消息,消息阅读器通过搜索下一个同步消息的方式从一个损坏的消息恢复。(当前未使用)
```
struct message_sync_s {
struct message_header_s header;
uint8_t sync_magic[8];
};
```
- `sync_magic`: 待定义(to be defined).
- 'O': 标记一个在以ms给定的时间段内的数据丢失 (丢失日志消息)。 比如设备不够快的时候就会发生消息丢失.
```
struct message_dropout_s {
struct message_header_s header;
uint16_t duration;
};
```
- '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.
**Known Implementations**
- PX4 Firmware: C++
- [logger module](https://github.com/PX4/Firmware/tree/master/src/modules/logger)
- [replay module](https://github.com/PX4/Firmware/tree/master/src/modules/replay)
- [hardfault_log module](https://github.com/PX4/Firmware/tree/master/src/systemcmds/hardfault_log): append hardfault crash data.
- [pyulog](https://github.com/PX4/pyulog): python, ULog parser library with CLI scripts.
- [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.
**File Format Version History**
- **Changes in version 2**
- Addition of `ulog_message_info_multiple_header_s` and `ulog_message_flag_bits_s` messages and the ability to append data to a log. This is used to add crash data to an existing log. If data is appended to a log that is cut in the middle of a message, it cannot be parsed with version 1 parsers. Other than that forward and backward compatibility is given if parsers ignore unknown messages.
该记录器能够记录任何包含所有字段的ORB主题。所有必要的内容都从.msg文件中生成因此只需要指定主题名称。一个可选的间隔参数指定了某个主题的最大记录速率。一个主题的所有现有实例都会被记录。默认情况ulog会在飞机解锁之后开始记录,飞机锁定之后停止记录..
## logger
源代码: [modules/logger](https://github.com/PX4/Firmware/tree/master/src/modules/logger)
### 说明
系统日志记录一组可配置的uORB主题和系统打印消息`PX4_WARN``PX4_ERR`到ULog文件。这些可用于系统和飞行性能评估调整再现和意外分析。
它支持2个后端
- 文件将ULog文件写入文件系统SD卡
- MAVLink通过MAVLink向客户端传输ULog数据客户端必须支持此功能
两个后端可以同时启用和使用。
### 实现
实现使用两个线程:
- 主线程以固定速率运行(如果以-p参数启动的话则轮询主题并检查数据更新
- 写入线程,将数据写入文件
两个线程之间有一个可配置大小的写入缓存区。写入缓存应该足够大,以避免数据丢失。
### 示例
立即启动日志的典型用法
```
logger start -e -t
```
如果已经在运行状态:
```
logger on
```
### 用法
```
logger <命令> [参数...]
命令:
start
[-m <val>] 后端模式
可选: file|mavlink|all, 缺省: all
[-e] 启动后立即开始记录,直到上锁(否则只在解锁后开始记录)
[-f] 记录直到关闭为止(包含 -e)
[-t] 使用日期/时间命名日志目录和文件
[-r <val>] 记录速率单位Hz值为0则不限速
缺省: 280
[-b <val>] 记录缓存大小单位KiB
缺省: 12
[-q <val>] mavlink模式下uORB队列大小
缺省: 14
[-p <val>] 轮询主题而不是以固定速率运行(记录速率和主题间隔将被忽略)
可选: <topic_name>
on 立即开始记录,覆盖解锁(日志系统必须在运行中)
off 立即停止记录,覆盖锁定(日志系统必须在运行中)
stop
status 打印状态信息
```