一、高度融合的核心挑战 高度估计需要解决以下问题:
多源矛盾 :气压计(长期稳定但受环境影响)、GPS 高度(绝对但精度低)、测距仪(高精度但距离有限)、外部视觉(精确但依赖基础设施)同时工作时,如何仲裁
坐标系差异 :PX4 内部高度(NED 坐标 D 轴,向下为正),外部 API 高度(altitude,向上为正),需要符号统一
地面效应 :近地面时气压计受旋翼下洗流影响,导致高度读数偏低
参考切换 :主高度源失效时,无缝切换至备用源,避免高度跳变
二、高度传感器选择参数 EKF2_HGT_REF 参数控制首选高度源:
参数值
传感器
适用场景
0
气压计(默认)
通用室外场景
1
GPS 高度
需要绝对高度参考
2
测距仪
低空精确悬停
3
外部视觉
室内精确定位
实际工作中,多个高度源可以同时工作 ,只是只有一个是”参考”(reference),其他作为辅助约束。
三、controlHeightFusion() 实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 flowchart TD A["controlHeightFusion"] --> B["checkVerticalAccelerationHealth"] B --> C{"垂直加速度<br/>是否异常?"} C --是--> D["设置 bad_vert_accel 标志<br/>抑制垂直状态更新"] C --否--> E["controlGroundEffect<br/>地面效应补偿"] E --> F["controlBaroHeightFusion<br/>气压计高度"] F --> G["controlGnssHeightFusion<br/>GNSS高度"] G --> H["controlRangeHeightFusion<br/>测距仪高度"] H --> I["controlEvHeightFusion<br/>外部视觉高度"] I --> J["checkHeightSensorRefFallback<br/>主参考健康检查"] J --> K{"主参考是否持续输出?"} K --是--> L("[继续当前参考]") K --否超时--> M["按优先级选择下一个可用源"] M --> N["resetHeightToBaro/GPS/Range/EV<br/>执行高度重置对齐"] N --> L
3.1 垂直加速度健康检查 1 2 3 4 5 6 7 8 9 10 11 12 void Ekf::checkVerticalAccelerationHealth (const imuSample &imu_sample) { if (imu_sample.delta_vel_clipping[2 ]) { _clip_counter++; if (_clip_counter > CLIP_COUNT_THRESHOLD) { _fault_status.flags.bad_acc_vertical = true ; } } else { _clip_counter = math::max (0 , _clip_counter - 1 ); } }
当 bad_acc_vertical 置位时,EKF 停止使用加速度计进行垂直状态预测(防止削波导致高度突变)。
3.2 气压计高度融合 气压计高度单位转换:气压计提供的是气压高度 (相对起飞点 MSL 高度差):
1 2 3 4 float innov = -_state.pos (2 ) - (_baro_hgt_offset + baro_sample.hgt);
_baro_hgt_offset 是气压计高度与 EKF 原点的偏差,在初始化或高度重置时更新。
3.3 GNSS 高度融合 GPS 高度使用 WGS84 椭球高,与气压计 MSL 高度存在大地水准面起伏差 (geoid undulation),需要通过 _gpos.altitude() 接口统一处理。
1 2 3 4 float innov = _gpos.altitude () - gnss_sample.alt;
3.4 测距仪高度融合 测距仪测量地面以上高度(HAGL) ,而非 NED 原点高度:
1 2 3 4 float innov = -(gpos_height - _terrain_vpos) - rng_sample.rng;
四、高度参考自动切换 checkHeightSensorRefFallback() 检测主高度参考是否超时无数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 void Ekf::checkHeightSensorRefFallback () { const uint64_t timeout_us = 2 * _params.hgt_timeout_us; if (_time_last_hgt_fuse + timeout_us < _time_delayed_us) { switch (_params.hgt_sensor_ref) { case HeightSensor::EV: if (isBaroHealthy ()) resetHeightToBaro (); else if (isGnssHgtHealthy ()) resetHeightToGnss (); break ; case HeightSensor::GNSS: if (isBaroHealthy ()) resetHeightToBaro (); break ; } } }
切换时会执行 resetHeight*() ,将 EKF 高度状态直接跳变到新传感器的读数,同时:
更新高度参考偏置(_*_hgt_offset)
清除高度状态的协方差相关性
重置 OutputPredictor 中的高度积分
五、速度融合通用模式 速度融合(velocity_fusion.cpp)统一处理各传感器速度:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 void Ekf::fuseVelocity (AidSourceStatus<3 >& status) { for (int i = 0 ; i < 3 ; i++) { status.innovation[i] = _state.vel[i] - status.observation[i]; status.innovation_variance[i] = P (3 +i, 3 +i) + status.observation_variance[i]; const float test_ratio = sq (status.innovation[i]) / status.innovation_variance[i]; if (test_ratio > sq (_params.vel_innov_gate)) { status.innovation_rejected = true ; continue ; } VectorState K = P.col (3 +i) / status.innovation_variance[i]; applyKalmanGainToState (K, status.innovation[i]); applyKalmanGainToCovariance (K, 3 +i); } }
六、航向融合 fuseYaw() 航向角 ψ 无法由重力观测,必须依赖磁力计或 GPS 双天线或外部视觉:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void Ekf::fuseYaw (AidSourceStatus<1 >& status) { sym::ComputeYawInnovVarAndH (q, R_yaw, &status.innovation_variance[0 ], &H); if (status.innovation_variance[0 ] < status.observation_variance[0 ]) { initialiseCovariance (); return ; } measurementUpdate (status, H, status.innovation, status.innovation_variance); }
航向重置 resetQuatStateYaw() :当航向误差过大时,直接重置四元数而非卡尔曼更新:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void Ekf::resetQuatStateYaw (float yaw, float yaw_var) { const Dcmf R_body_to_earth{_state.quat_nominal}; const Eulerf euler_angles (R_body_to_earth) ; _state.quat_nominal = Quatf (Eulerf (euler_angles.phi (), euler_angles.theta (), yaw)); _output_predictor.resetQuatState (_state.quat_nominal); P (2 ,2 ) = yaw_var; for (int i = 0 ; i < _k_num_states; i++) { if (i != 2 ) { P (2 ,i) = P (i,2 ) = 0.0f ; } } }
七、小结 EKF2 高度融合的关键设计:
多源并行:气压计、GPS、测距仪、EV 可同时工作,各自提供独立约束
参考仲裁:单一主参考 + 自动降级,失效时平滑切换
坐标统一:所有高度源通过偏置对齐到 EKF 内部 NED 坐标原点
故障隔离:垂直加速度健康检查 + 地面效应补偿,防止特殊场景下的错误融合
航向融合的病态检查体现了 EKF2 在数值稳定性方面的防御性编程思路。
上一篇:融合调度 control.cpp 下一篇:辅助函数与卡尔曼更新 ekf_helper.cpp 系列总目录:PX4 v1.16 源码解读总目录