一、measurementUpdate() — 卡尔曼更新核心
measurementUpdate() 是所有传感器融合的最终执行函数,实现标准 EKF 的测量更新步骤:
标准卡尔曼更新公式
给定观测矩阵 H(1×24)、新息 y(标量)、新息方差 S = HPH’ + R:
EKF2 使用 Joseph 稳定形式(而非简化的 P = (I-KH)P),保证数值正定性。
代码实现(简化)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| void Ekf::measurementUpdate( VectorState &H, const float innovation, const float innov_var) { VectorState K; for (int i = 0; i < _k_num_states; i++) { K(i) = 0.0f; for (int j = 0; j < _k_num_states; j++) { K(i) += P(i,j) * H(j); } K(i) /= innov_var; }
fuse(K, innovation);
SquareMatrix24f KH; for (int i = 0; i < _k_num_states; i++) { for (int j = 0; j < _k_num_states; j++) { KH(i,j) = K(i) * H(j); } } SquareMatrix24f ImKH = SquareMatrix24f::identity() - KH; P = ImKH * P * ImKH.T() + K.outerProduct(K) * (innov_var - P_contribution); }
|
fuse() 函数 — 状态修正
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| void Ekf::fuse(const VectorState &K, const float innovation) { _state.vel += K.slice<3,1>(3,0) * innovation; _state.pos += K.slice<3,1>(6,0) * innovation; _state.gyro_bias += K.slice<3,1>(9,0) * innovation; _state.accel_bias += K.slice<3,1>(12,0) * innovation; _state.mag_I += K.slice<3,1>(15,0) * innovation; _state.mag_B += K.slice<3,1>(18,0) * innovation; _state.wind_vel += K.slice<2,1>(21,0) * innovation;
const Vector3f dq = K.slice<3,1>(0,0) * innovation; _state.quat_nominal = Quatf(_state.quat_nominal * AxisAnglef(dq)).normalized();
_state.gyro_bias = matrix::constrain(_state.gyro_bias, -_params.gyro_bias_lim, _params.gyro_bias_lim); _state.accel_bias = matrix::constrain(_state.accel_bias, -_params.accel_bias_lim, _params.accel_bias_lim); }
|
二、fuseDirectStateMeasurement() — 直接状态测量
对于直接测量某个状态量的传感器(如直接测量速度的 GPS),提供简化接口:
1 2 3 4 5 6 7 8 9 10 11
| void Ekf::fuseDirectStateMeasurement( const float innov, const float innov_var, const int state_index) { VectorState H{}; H(state_index) = 1.0f; measurementUpdate(H, innov, innov_var); }
|
三、精度报告函数
3.1 位置精度 get_ekf_lpos_accuracy()
1 2 3 4 5 6 7 8
| void Ekf::get_ekf_lpos_accuracy(float *ekf_eph, float *ekf_epv) const { *ekf_eph = sqrtf(P(6,6) + P(7,7));
*ekf_epv = sqrtf(P(8,8)); }
|
这些值通过 estimator_status 话题发布,供 vehicle_local_position.eph/epv 使用,Navigator 和安全模块据此判断定位是否可信。
3.2 新息测试比率
1 2 3 4 5 6 7 8 9 10
| float Ekf::getHeadingInnovationTestRatio() const { return _aid_src_yaw.test_ratio; }
float Ekf::getHorizontalVelocityInnovationTestRatio() const { return math::max(_aid_src_gnss_vel.test_ratio[0], _aid_src_gnss_vel.test_ratio[1]); }
|
这些比率通过 estimator_innovations 话题发布,是调试传感器融合质量的关键指标。
四、零偏管理
4.1 resetGyroBias() / resetAccelBias()
1 2 3 4 5 6 7 8 9 10 11
| void Ekf::resetGyroBias() { _state.gyro_bias.setZero(); for (int i = 9; i < 12; i++) { P(i,i) = sq(_params.switch_on_gyro_bias); for (int j = 0; j < _k_num_states; j++) { if (j != i) P(i,j) = P(j,i) = 0.0f; } } }
|
4.2 updateIMUBiasInhibit() — 零偏估计抑制
当飞机处于某些特殊状态时,应停止更新零偏估计(避免动态机动被错误解释为零偏):
1 2 3 4 5 6 7 8 9 10
| void Ekf::updateIMUBiasInhibit() { const bool inhibit = _control_status.flags.vehicle_at_rest || _fault_status.flags.bad_acc_vertical;
if (inhibit) { } }
|
五、航迹推算(Dead Reckoning)状态
当所有外部定位传感器(GPS/EV/光流)失效后,EKF 进入航迹推算模式,仅靠 IMU 积分维持位置估计:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| void Ekf::updateDeadReckoningStatus() { const bool pos_aiding = _control_status.flags.gps || _control_status.flags.ev_pos || _control_status.flags.opt_flow;
const bool vel_aiding = _control_status.flags.gps || _control_status.flags.ev_vel;
if (!pos_aiding && !vel_aiding) { _time_last_hor_pos_aiding = 0;
_control_status.flags.dead_reckoning = true; } }
|
航迹推算期间,vehicle_local_position.dead_reckoning = true,高层模块(如 mc_pos_control)应降低对位置精度的要求,可能触发悬停或降落。
六、辅助源状态管理 updateAidSourceStatus()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| template<int N> void Ekf::updateAidSourceStatus( AidSourceStatus<N>& status, const matrix::Vector<float, N>& observation, const matrix::Vector<float, N>& observation_variance, const matrix::Vector<float, N>& innovation, const matrix::Vector<float, N>& innovation_variance, const float gate_size) { status.observation = observation; status.observation_variance = observation_variance; status.innovation = innovation; status.innovation_variance = innovation_variance;
float test_ratio_sum = 0.0f; for (int i = 0; i < N; i++) { test_ratio_sum += sq(innovation[i]) / innovation_variance[i]; } status.test_ratio = test_ratio_sum / N; status.innovation_rejected = (status.test_ratio > sq(gate_size)); }
|
这一函数统一了所有传感器在融合前的状态更新,是连接 control.cpp 调度逻辑和具体融合实现的桥梁。
七、小结
ekf_helper.cpp 提供了 EKF2 的底层通用操作:
measurementUpdate() 是卡尔曼更新的唯一实现点,所有融合最终汇聚于此
fuse() 负责将数学修正量正确注入各类状态(特别是姿态的四元数旋转处理)
- 精度报告函数将协方差矩阵转换为可供高层模块使用的置信度指标
- 零偏管理和航迹推算状态更新保证了 EKF 在复杂飞行场景中的鲁棒性
上一篇:高度融合与多源仲裁
系列总目录:PX4 v1.16 源码解读总目录
下一章:Navigator 导航模块