PX4 EKF2 RingBuffer 环形缓冲区详解
一、延迟融合的核心问题
EKF2 的延迟时间融合架构要求:当 GPS 数据(延迟 ~110 ms)到达时,需要找到 110 ms 前对应时刻的 IMU 预测状态进行融合,而不是与当前时刻的 IMU 状态对齐。
解决方案是 RingBuffer<T>——一个固定大小的环形缓冲区,持续保存一段历史时间窗口内的传感器数据。
二、RingBuffer 结构
1 | template <typename data_type> |
三、关键操作详解
3.1 push(sample) — 写入
1 | 写入前: [oldest] → ... → [head] |
实现逻辑(伪代码):
1 | _head = (_head + 1) % _size; |
每次 IMU 降采样(~250 Hz)后的 imuSample 都会被 push 进 IMU RingBuffer,缓冲区深度通常为 maxDelay / dtImu,保证足够覆盖最大传感器延迟(通常设 0.5 s)。
3.2 pop_first_older_than(time_us, sample) — 延迟对齐查询
这是延迟补偿的核心操作:
1 | bool pop_first_older_than(uint64_t time_us, data_type *sample) { |
调用时机:control.cpp 中,当 GPS 数据到达时:
1 | gnssSample gps_sample; |
3.3 get_oldest() — 获取历史最旧 IMU
ekf.cpp 主循环中:
1 | // 从 IMU RingBuffer 取出最旧(即最大延迟时刻)的 IMU 数据 |
四、各传感器缓冲区配置
| 缓冲区 | 类型 | 深度(典型) | 最大延迟 |
|---|---|---|---|
| IMU | imuSample |
~20 | 由最大传感器延迟决定 |
| GNSS | gnssSample |
10 | EKF2_GPS_DELAY = 110 ms |
| 磁力计 | magSample |
5 | EKF2_MAG_DELAY = 0 ms |
| 气压计 | baroSample |
10 | EKF2_BARO_DELAY = 0 ms |
| 光流 | flowSample |
15 | EKF2_OF_DELAY = 5 ms |
| 测距仪 | rangeSample |
10 | EKF2_RNG_DELAY = 5 ms |
| 外部视觉 | extVisionSample |
15 | EKF2_EV_DELAY = 175 ms |
延迟参数通过 EKF2_*_DELAY PX4 参数设定,需与实际传感器延迟匹配,否则会造成状态跳变。
五、与 IMU 降采样器的配合
1 | sequenceDiagram |
六、关键约束与注意事项
- 缓冲区大小必须足够覆盖最大传感器延迟:
size >= delay_ms / dt_imu_ms。estimator_interface.cpp在初始化时根据参数动态计算并分配。 - RingBuffer 不是线程安全的。EKF2 整体运行在单个 WorkQueue 回调中,无并发问题。
- 若
pop_first_older_than返回false(缓冲区中没有足够旧的数据),表示当前延迟时刻还没有对应传感器数据,本周期跳过该传感器融合。 - 缓冲区满时 push 会自动覆盖最旧条目,因此实时性较差的传感器(EV 延迟 175 ms)需要更大的缓冲区。
上一篇:common.h 数据结构
下一篇:State.h 状态向量
系列总目录:PX4 v1.16 源码解读总目录