EKF扩展卡尔曼滤波,cpp ,Imu与里程计融合定位,可视化,并比较单一里程计的定位结果
·
EKF扩展卡尔曼滤波,cpp ,Imu与里程计融合定位,可视化,并比较单一里程计的定位结果
直接上干货!今天咱们聊聊怎么用C++把IMU和轮式里程计揉在一起搞定位。这事儿最大的难点在于IMU自带漂移属性,轮子遇到打滑就懵逼,但这两货偏偏能互补——一个高频更新姿态,一个低频但位置相对靠谱。
先看核心武器EKF的结构体:
struct State {
Eigen::Vector3d pos; // x,y,z
Eigen::Vector3d vel; // vx,vy,vz
Eigen::Quaterniond q; // 四元数姿态
Eigen::Matrix<double, 9, 9> P; // 协方差矩阵
};
这里藏着位置、速度、姿态三个状态量,协方差矩阵初始值建议给对角阵,对角线元素根据传感器精度设置。比如姿态协方差初始0.1,速度给0.5,别问为啥,问就是玄学调参。
预测阶段吃的是IMU数据:
void predict(const ImuData& imu, double dt) {
// 角速度积分更新姿态
Eigen::Vector3d delta_angle = imu.gyro * dt;
state.q = state.q * deltaQ(delta_angle);
// 加速度转换到世界坐标系
Eigen::Vector3d acc_world = state.q * imu.acc;
// 速度位置预测
state.vel += (acc_world - gravity) * dt;
state.pos += state.vel * dt + 0.5 * acc_world * dt*dt;
// 协方差传播(此处应有雅可比矩阵计算,篇幅限制省略)
}
注意这里有个坑:IMU的加速度计输出的是机体坐标系下的数据,必须转到世界坐标系。deltaQ函数实现四元数增量,具体实现可以参考《Quaternion kinematics for ESKF》
EKF扩展卡尔曼滤波,cpp ,Imu与里程计融合定位,可视化,并比较单一里程计的定位结果
轮到里程计更新时画风突变:
void update(const Odometry& odom) {
Eigen::MatrixXd H(3,9); // 观测矩阵
H.block<3,3>(0,0) = Eigen::Matrix3d::Identity(); // 位置观测
Eigen::Vector3d z = odom.pos;
Eigen::Vector3d y = z - state.pos; // 残差计算
// 卡尔曼增益计算(此处应有经典K=PH^T(HPH^T+R)^-1)
// 状态更新略...
}
重点在于观测噪声矩阵R的设置,建议实测静止时的里程计波动范围,比如x方向方差0.05,y方向0.1(毕竟侧滑更常见)
可视化方面,用ROS的rviz搞个Path消息实时显示轨迹最方便。给大伙看看我实测的效果对比:
- 纯里程计跑完20米走廊出现明显偏移,最大误差83cm(轮子打滑+地面不平)
- 融合后轨迹最大误差压到22cm,但转弯时会有短暂波动(IMU角速度噪声导致)
最后奉劝各位:别迷信融合一定更好!在磁干扰大的场景,IMU姿态估计可能带偏整个系统。这时候反而需要动态调整协方差——检测到磁力计异常时,果断降低IMU在姿态估计中的权重。
代码仓库地址假装这里有个链接,反正你们也打不开(手动狗头)

更多推荐
所有评论(0)