为什么要预积分?
- 论文中的说法是: State Estimation其实是想估计任意时刻的全局坐标系下的位置和姿态, 也就是论文中的 pwbk,vwbk,qwbk , 分别对应位置,速度,旋转四元数, 它们满足迭代式
离散形式:
对应代码中integration_base.h中的midPointIntegration()函数, 该函数输入两个时刻的IMU观测_acc_0,_acc_1,_gyr_0,_gyr_1, 根据 t0 时刻的p,q,v,ba,bg, 利用上面公式递推出 t1 时刻的p,q,v,ba,bg. 每次选完关键帧以后p,q,v,ba,bg又reset为零点.
函数中还有另一块是更新jacobian的, 先求F和V矩阵, 然后根据F和V更新jacobian和covariance. 这里暂时还不是太理解!!!
这段代码对应论文中的公式
/* pre-propogation between two successive imu measurements
\param[in] dt: time interval
\param[in] _acc_0: first acc
\param[in] _gyr_0: first gyro
\param[in] _acc_1: second acc
\param[in] _gyr_1: second gyro
\param[in] delta_p: delta position at t0
\param[in] delta_q: delta quaternion at t0
\param[in] delta_v: delta velocity at t0
\param[in] linearized_ba: accelerator bias at t0
\param[in] linearized_bg: gyroscope bias at t0
\param[out] result_delta_p: delta position at t1
\param[out] result_delta_q: delta quaternion at t1
\param[out] result_delta_v: delta velocity at t1
\param[out] result_delta_ba: accelerator bias at t1
\param[out] result_delta_bg: gyroscope bias at t1
\param[in] update_jacobian: whether to update Jacobian and calculate F,V
*/
void midPointIntegration(double _dt,
const Eigen::Vector3d &_acc_0, const Eigen::Vector3d &_gyr_0,
const Eigen::Vector3d &_acc_1, const Eigen::Vector3d &_gyr_1,
const Eigen::Vector3d &delta_p, const Eigen::Quaterniond &delta_q, const Eigen::Vector3d &delta_v,
const Eigen::Vector3d &linearized_ba, const Eigen::Vector3d &linearized_bg,
Eigen::Vector3d &result_delta_p, Eigen::Quaterniond &result_delta_q, Eigen::Vector3d &result_delta_v,
Eigen::Vector3d &result_linearized_ba, Eigen::Vector3d &result_linearized_bg, bool update_jacobian)
{
//ROS_INFO("midpoint integration");
Vector3d un_gyr = 0.5 * (_gyr_0 + _gyr_1) - linearized_bg; // average angular vel in body frame
result_delta_q = delta_q * Quaterniond(1, un_gyr(0) * _dt / 2, un_gyr(1) * _dt / 2, un_gyr(2) * _dt / 2); //q1 = q0 * q(0->1)
Vector3d un_acc_0 = delta_q * (_acc_0 - linearized_ba); // un bias acc0 in global frame
Vector3d un_acc_1 = result_delta_q * (_acc_1 - linearized_ba); // un bias acc1 in global frame
Vector3d un_acc = 0.5 * (un_acc_0 + un_acc_1); // average un bias acc in global frame
/*assume constant acceleration from t0 to t1*/
result_delta_p = delta_p + delta_v * _dt + 0.5 * un_acc * _dt * _dt; // p1 = p0 + v0*t + 0.5*a_avg*t^2
result_delta_v = delta_v + un_acc * _dt; // v1 = v0 + a_avg*t
/*bias not changed*/
result_linearized_ba = linearized_ba;
result_linearized_bg = linearized_bg;
if(update_jacobian)
{
Vector3d w_x = 0.5 * (_gyr_0 + _gyr_1) - linearized_bg;
Vector3d a_0_x = _acc_0 - linearized_ba;
Vector3d a_1_x = _acc_1 - linearized_ba;
Matrix3d R_w_x, R_a_0_x, R_a_1_x;
R_w_x<<0, -w_x(2), w_x(1),
w_x(2), 0, -w_x(0),
-w_x(1), w_x(0), 0;
R_a_0_x<<0, -a_0_x(2), a_0_x(1),
a_0_x(2), 0, -a_0_x(0),
-a_0_x(1), a_0_x(0), 0;
R_a_1_x<<0, -a_1_x(2), a_1_x(1),
a_1_x(2), 0, -a_1_x(0),
-a_1_x(1), a_1_x(0), 0;
MatrixXd F = MatrixXd::Zero(15, 15);
F.block<3, 3>(0, 0) = Matrix3d::Identity();
F.block<3, 3>(0, 3) = -0.25 * delta_q.toRotationMatrix() * R_a_0_x * _dt * _dt +
-0.25 * result_delta_q.toRotationMatrix() * R_a_1_x * (Matrix3d::Identity() - R_w_x * _dt) * _dt * _dt;
F.block<3, 3>(0, 6) = MatrixXd::Identity(3,3) * _dt;
F.block<3, 3>(0, 9) = -0.25 * (delta_q.toRotationMatrix() + result_delta_q.toRotationMatrix()) * _dt * _dt;
F.block<3, 3>(0, 12) = -0.25 * result_delta_q.toRotationMatrix() * R_a_1_x * _dt * _dt * -_dt;
F.block<3, 3>(3, 3) = Matrix3d::Identity() - R_w_x * _dt;
F.block<3, 3>(3, 12) = -1.0 * MatrixXd::Identity(3,3) * _dt;
F.block<3, 3>(6, 3) = -0.5 * delta_q.toRotationMatrix() * R_a_0_x * _dt +
-0.5 * result_delta_q.toRotationMatrix() * R_a_1_x * (Matrix3d::Identity() - R_w_x * _dt) * _dt;
F.block<3, 3>(6, 6) = Matrix3d::Identity();
F.block<3, 3>(6, 9) = -0.5 * (delta_q.toRotationMatrix() + result_delta_q.toRotationMatrix()) * _dt;
F.block<3, 3>(6, 12) = -0.5 * result_delta_q.toRotationMatrix() * R_a_1_x * _dt * -_dt;
F.block<3, 3>(9, 9) = Matrix3d::Identity();
F.block<3, 3>(12, 12) = Matrix3d::Identity();
//cout<<"A"<A<;
MatrixXd V = MatrixXd::Zero(15,18);
V.block<3, 3>(0, 0) = 0.25 * delta_q.toRotationMatrix() * _dt * _dt;
V.block<3, 3>(0, 3) = 0.25 * -result_delta_q.toRotationMatrix() * R_a_1_x * _dt * _dt * 0.5 * _dt;
V.block<3, 3>(0, 6) = 0.25 * result_delta_q.toRotationMatrix() * _dt * _dt;
V.block<3, 3>(0, 9) = V.block<3, 3>(0, 3);
V.block<3, 3>(3, 3) = 0.5 * MatrixXd::Identity(3,3) * _dt;
V.block<3, 3>(3, 9) = 0.5 * MatrixXd::Identity(3,3) * _dt;
V.block<3, 3>(6, 0) = 0.5 * delta_q.toRotationMatrix() * _dt;
V.block<3, 3>(6, 3) = 0.5 * -result_delta_q.toRotationMatrix() * R_a_1_x * _dt * 0.5 * _dt;
V.block<3, 3>(6, 6) = 0.5 * result_delta_q.toRotationMatrix() * _dt;
V.block<3, 3>(6, 9) = V.block<3, 3>(6, 3);
V.block<3, 3>(9, 12) = MatrixXd::Identity(3,3) * _dt;
V.block<3, 3>(12, 15) = MatrixXd::Identity(3,3) * _dt;
//step_jacobian = F;
//step_V = V;
jacobian = F * jacobian;
covariance = F * covariance * F.transpose() + V * noise * V.transpose();
}
}