3. 日志数据结构:时间戳与同步、消息类型与定义、数据流与采样率

日志这东西,说白了就是无人机飞行时的「黑匣子」。但如果你看不懂它的数据结构,那它就是一串乱码。我刚开始接触无人机日志时,面对满屏的十六进制数据,说实话,头都是大的。后来慢慢摸清了门道,才发现日志结构其实很有规律。

这一章,我们就来拆解日志数据的三个核心要素:时间戳、消息类型和数据流。搞懂这些,你就能读懂无人机在「想什么」。

3.1 时间戳:日志的「时间轴」

时间戳是日志的灵魂。没有它,所有数据都是孤立的快照,连不成故事。

3.1.1 时间戳的来源

无人机上的时间戳通常来自两个地方:

  • GPS 时间:精度高,全球统一,但受信号遮挡影响。
  • 系统时钟(RTC):飞控板上的本地时钟,掉电会跑偏。

我见过不少新手,拿到日志后发现时间轴是乱的。为什么?因为飞控在启动时先用 RTC,等 GPS 锁定后才切换到 GPS 时间。这个切换过程如果没处理好,时间戳就会「跳变」。

避坑指南:我曾经排查过一个案例,日志里电机转速和姿态数据对不上。折腾了两天,最后发现是时间戳源不一致——姿态数据用的是 GPS 时间,电机数据用的是 RTC 时间,两者差了 0.3 秒。在高速飞行中,0.3 秒足以让飞机偏航好几米。

3.1.2 时间同步机制

现代飞控(如 PX4、ArduPilot)通常采用 uORB 消息总线 或 DDS 来同步时间。每个消息发布时,都会被打上一个硬件时间戳。

这里有个关键概念:时间基准。所有传感器数据,必须统一到同一个时间基准上。否则,你分析出来的因果关系全是错的。

时间源 精度 典型误差 适用场景
GPS PPS ±1 μs 极低 高精度同步
系统 RTC ±10 ppm 每天漂移约 0.86 秒 无 GPS 时兜底
软件时间戳 ±1 ms 受 CPU 负载影响 普通日志记录

我个人习惯,在分析日志时,第一件事就是检查时间戳的连续性。如果发现时间戳突然跳了 1 秒以上,那这段数据基本就不能用了。

3.2 消息类型与定义:日志的「词汇表」

日志里的每一条数据,都对应一个消息类型。就像字典里的词条,你得知道每个词是什么意思,才能读懂句子。

3.2.1 常见的消息类型

以 PX4 的 .ulog 文件为例,消息类型大致分这几类:

  • 传感器数据:IMU(加速度计、陀螺仪)、磁力计、气压计、GPS
  • 状态估计:姿态(四元数/欧拉角)、位置、速度
  • 控制输出:电机 PWM 值、舵机角度
  • 系统状态:电池电压、CPU 负载、内存使用
  • 事件/错误:解锁失败、GPS 丢失、EKF 警告
重点:每个消息类型都有一个唯一的 ID 和定义。比如 IMU 数据,通常包含 timestamp、gyro_rad[3]、accelerometer_m_s2[3] 三个字段。你想想看,如果不知道这些字段的含义,你连数据是啥都看不懂。

3.2.2 消息定义的解析

日志文件里,消息定义通常以 键值对 或 结构体 的形式存储。解析时,你需要一个「字典文件」来对照。

举个例子,PX4 的日志定义文件(.msg)长这样:

# 传感器加速度计数据
uint64 timestamp        # 时间戳(微秒)
float[3] x              # X 轴加速度(m/s^2)
float[3] y              # Y 轴加速度(m/s^2)
float[3] z              # Z 轴加速度(m/s^2)
uint8 id                # 传感器 ID

嗯,这里要注意:不同飞控厂商的消息定义可能完全不同。ArduPilot 用的是 .bin 格式,消息类型靠 FMT 消息来定义。所以,分析日志前,先搞清楚你用的是哪种格式。

3.3 数据流与采样率:日志的「节奏感」

数据流就像音乐的节拍,采样率就是节拍的速度。节奏乱了,整首曲子就毁了。

3.3.1 采样率的差异

无人机上不同传感器的采样率天差地别:

  • IMU:通常 200 Hz ~ 1000 Hz(高动态,需要快速响应)
  • GPS:5 Hz ~ 20 Hz(更新慢,但精度高)
  • 磁力计:10 Hz ~ 100 Hz(受干扰大,采样率不宜过高)
  • 气压计:25 Hz ~ 100 Hz(响应慢,适合高度估计)

我在项目中遇到过一个问题:IMU 采样率是 400 Hz,但日志记录频率只有 100 Hz。这意味着每 4 个 IMU 数据里,有 3 个被丢弃了。分析高频振动时,这种降采样会导致信息丢失,误判为「正常」。

我的建议:分析高频问题(如电机振动、姿态震荡)时,尽量使用原始采样率的数据,不要用降采样后的日志。如果日志本身已经降采样了,那就得小心结论的可靠性。

3.3.2 数据流的对齐

不同采样率的数据,怎么对齐到同一个时间轴上?

常用的方法有两种:

  1. 最近邻插值:用时间上最接近的数据点代替。简单,但会引入误差。
  2. 线性插值:在两个数据点之间线性拟合。精度更高,但计算量大。

我个人习惯,在分析姿态和位置关系时,用线性插值。分析故障触发瞬间时,用最近邻插值——因为故障往往是「瞬间」发生的,插值反而会模糊掉边界。

3.4 知识体系总览

下面这张图,帮你把本章的核心逻辑串起来:

日志数据结构核心要素 时间戳与同步 消息类型与定义 数据流与采样率 时间源 GPS 时间 / 系统 RTC 硬件时间戳 vs 软件时间戳 消息分类 传感器 / 状态 / 控制 / 事件 键值对 / 结构体 / FMT 定义 采样率差异 IMU 200-1000Hz / GPS 5-20Hz 降采样 vs 原始采样 日志分析基础 应用场景 故障定位 → 性能评估 → 参数调优 → 事故复盘

3.5 实践中的常见陷阱

说了这么多理论,来点实际的。我总结了几条日志数据结构的「坑」,你遇到了可以少走弯路。

陷阱一:时间戳溢出
32 位微秒时间戳,大约 71 分钟就会溢出一次。如果飞行时间超过 1 小时,日志里的时间戳会归零重计。我曾经因为没处理溢出,把一段 2 小时的日志分析成了两段独立的飞行,结论完全错了。
陷阱二:消息类型不匹配
不同固件版本的消息定义可能不一样。比如 PX4 v1.12 和 v1.13 的 IMU 消息字段顺序就变了。用旧版解析工具读新版日志,数据全是乱的。我的习惯是:解析日志前,先确认固件版本和消息定义文件是否匹配。
陷阱三:采样率混叠
当 IMU 采样率是 400 Hz,而日志记录频率是 50 Hz 时,高频振动信号会被「折叠」到低频段,看起来像是低频震荡。这就是采样定理里的混叠效应。分析振动问题时,一定要确认日志的采样率是否足够高。