彻底弄懂IMU预积分原理及代码实现

彻底弄懂IMU预积分原理及代码实现

image

附赠自动驾驶学习资料和量产经验:链接

1. IMU测量模型

image

IMU测量模型

2.相邻两个IMU数据之间的积分递推,时间间隔 image 恒定

image

相邻两个imu数据之间的递推

image

IMU 预积分示意图

3. 从i时刻积分到j时刻的递推公式,中间包含很多个IMU数据,每个IMU数据之间的时间间隔都是 image

image

动力学积分递推公式

4. 写成预积分形式,使得预积分量不和i时刻和j时刻的状态量相关,这样每次更新i时刻和j时刻的状态量时就不需要重新计算预积分量

image

预积分原始公式

image

于是将预积分项 Δ� 写成递推形式有:

image

image

image

5. 真实值和估计值之间,由于白噪声的存在,会有一定的误差,假设白噪声服从高斯分布,那么状态向量的估计值的协方差矩阵可以递推,即不确定度的递推,先分离出误差形式。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

image

image

image

6. 白噪声的高斯分布证明及协方差递推

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

image

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

image

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

image

image

状态量的协方差递推

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

image

7. 当状态向量的bias发生更新的时候,预积分项需要重新进行积分,通常bias的增量都非常小,直接采用一阶近似来进行更新,而不用重新计算整个预积分过程,此时Jacobian可以利用递推进行计算。

image

bias的一阶线性展开

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

image

image

image

image

image

预积分量对bias的jacobian

8. 完整积分过程

image

增量式预积分迭代计算

9. 在和视觉或者其他传感器融合的时候,我们可以利用IMU的估计值,和其他传感器的真实值的差值来作为残差项,从而迭代的求解出最优解,此时估计量为以下形式,需要计算出每一个残差项对待求解变量的jacobian。

image

和其他传感器融合时的残差项

定义每个变量的增量

image

“lift-solve-retract” method

image

image

image

image

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

image

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

if (jacobians) {
            if (jacobians[0]) {
                Eigen::Map<Eigen::Matrix<double, 15, 4, Eigen::RowMajor>> dr_dq_i(jacobians[0]);
                dr_dq_i.setZero();
                dr_dq_i.block<3, 3>(ES_Q, 0) = -right_jacobian(r.segment<3>(ES_Q)).inverse() * q_j.conjugate().matrix() * q_center_i.matrix();
                dr_dq_i.block<3, 3>(ES_P, 0) = imu_i.q_cs.conjugate().matrix() * hat(q_center_i.conjugate() * (p_j - p_center_i - dt * v_i - 0.5 * dt * dt * gravity));
                dr_dq_i.block<3, 3>(ES_V, 0) = imu_i.q_cs.conjugate().matrix() * hat(q_center_i.conjugate() * (v_j - v_i - dt * gravity));
                dr_dq_i = pre.delta.sqrt_inv_cov * dr_dq_i;
            }
            if (jacobians[1]) {
                Eigen::Map<Eigen::Matrix<double, 15, 3, Eigen::RowMajor>> dr_dp_i(jacobians[1]);
                dr_dp_i.setZero();
                dr_dp_i.block<3, 3>(ES_P, 0) = -q_i.conjugate().matrix();
                dr_dp_i = pre.delta.sqrt_inv_cov * dr_dp_i;
            }
            if (jacobians[2]) {
                Eigen::Map<Eigen::Matrix<double, 15, 3, Eigen::RowMajor>> dr_dv_i(jacobians[2]);
                dr_dv_i.setZero();
                dr_dv_i.block<3, 3>(ES_P, 0) = -dt * q_i.conjugate().matrix();
                dr_dv_i.block<3, 3>(ES_V, 0) = -q_i.conjugate().matrix();
                dr_dv_i = pre.delta.sqrt_inv_cov * dr_dv_i;
            }
            if (jacobians[3]) {
                Eigen::Map<Eigen::Matrix<double, 15, 3, Eigen::RowMajor>> dr_dbg_i(jacobians[3]);
                dr_dbg_i.setZero();
                dr_dbg_i.block<3, 3>(ES_Q, 0) = -right_jacobian(r.segment<3>(ES_Q)).inverse() * expmap(r.segment<3>(ES_Q)).conjugate().matrix() * right_jacobian(dq_dbg * dbg) * dq_dbg;
                dr_dbg_i.block<3, 3>(ES_P, 0) = -dp_dbg;
                dr_dbg_i.block<3, 3>(ES_V, 0) = -dv_dbg;
                dr_dbg_i.block<3, 3>(ES_BG, 0) = -Eigen::Matrix3d::Identity();
                dr_dbg_i = pre.delta.sqrt_inv_cov * dr_dbg_i;
            }
            if (jacobians[4]) {
                Eigen::Map<Eigen::Matrix<double, 15, 3, Eigen::RowMajor>> dr_dba_i(jacobians[4]);
                dr_dba_i.setZero();
                dr_dba_i.block<3, 3>(ES_P, 0) = -dp_dba;
                dr_dba_i.block<3, 3>(ES_V, 0) = -dv_dba;
                dr_dba_i.block<3, 3>(ES_BA, 0) = -Eigen::Matrix3d::Identity();
                dr_dba_i = pre.delta.sqrt_inv_cov * dr_dba_i;
            }
            if (jacobians[5]) {
                Eigen::Map<Eigen::Matrix<double, 15, 4, Eigen::RowMajor>> dr_dq_j(jacobians[5]);
                dr_dq_j.setZero();
                dr_dq_j.block<3, 3>(ES_Q, 0) = right_jacobian(r.segment<3>(ES_Q)).inverse() * imu_j.q_cs.conjugate().matrix();
                dr_dq_j.block<3, 3>(ES_P, 0) = -q_i.conjugate().matrix() * q_center_j.matrix() * hat(imu_j.p_cs);
                dr_dq_j = pre.delta.sqrt_inv_cov * dr_dq_j;
            }
            if (jacobians[6]) {
                Eigen::Map<Eigen::Matrix<double, 15, 3, Eigen::RowMajor>> dr_dp_j(jacobians[6]);
                dr_dp_j.setZero();
                dr_dp_j.block<3, 3>(ES_P, 0) = q_i.conjugate().matrix();
                dr_dp_j = pre.delta.sqrt_inv_cov * dr_dp_j;
            }
            if (jacobians[7]) {
                Eigen::Map<Eigen::Matrix<double, 15, 3, Eigen::RowMajor>> dr_dv_j(jacobians[7]);
                dr_dv_j.setZero();
                dr_dv_j.block<3, 3>(ES_V, 0) = q_i.conjugate().matrix();
                dr_dv_j = pre.delta.sqrt_inv_cov * dr_dv_j;
            }
            if (jacobians[8]) {
                Eigen::Map<Eigen::Matrix<double, 15, 3, Eigen::RowMajor>> dr_dbg_j(jacobians[8]);
                dr_dbg_j.setZero();
                dr_dbg_j.block<3, 3>(ES_BG, 0).setIdentity();
                dr_dbg_j = pre.delta.sqrt_inv_cov * dr_dbg_j;
            }
            if (jacobians[9]) {
                Eigen::Map<Eigen::Matrix<double, 15, 3, Eigen::RowMajor>> dr_dba_j(jacobians[9]);
                dr_dba_j.setZero();
                dr_dba_j.block<3, 3>(ES_BA, 0).setIdentity();
                dr_dba_j = pre.delta.sqrt_inv_cov * dr_dba_j;
            }
        }

参考文献

  1. Forster C, Carlone L, Dellaert F, et al. On-Manifold Preintegration for Real-Time Visual–Inertial Odometry[J]. IEEE Transactions on Robotics, 2016, 33(1): 1-21.

  2. Li J, Yang B, Huang K, et al. Robust and Efficient Visual-Inertial Odometry with Multi-plane Priors[C]//Chinese Conference on Pattern Recognition and Computer Vision (PRCV). Springer, Cham, 2019: 283-295.

  3. itsuhane/slamtools

  4. https://github.com/zju3dv/PVIO

  • 13
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值