VINS中陀螺仪零偏的估计

时间:2023-04-04 17:15:18

VINS中关于陀螺仪零偏的初始化估计

对于窗口中得连续两帧 b k b_{k} bk b k + 1 b_{k+1} bk+1 ,已经从视觉SFM中得到了旋转 q b k c 0 q_{b_{k}}^{c_{0}} qbkc0 q b k + 1 c 0 q_{b_{k+1}}^{c_{0}} qbk+1c0 ,从IMU预积分中得到了相邻帧旋转 γ ^ b k + 1 b k \hat{\gamma}^{b_{k}}_{b_{k+1}} γ^bk+1bk 。 根据约束方程,联立所有相邻帧,最小化代价函数(论文式(7)):
min ⁡ δ b w ∑ k ∈ B ∥ q b k + 1 c 0 − 1 ⊗ q b k c 0 ⊗ γ b k + 1 b k ∥ 2 \min _{\delta b_{w}} \sum_{k \in \mathcal{B}}\left\|q_{b_{k+1}}^{c_{0}}{ }^{-1} \otimes q_{b_{k}}^{c_{0}} \otimes \gamma_{b_{k+1}}^{b_{k}}\right\|^{2} δbwminkB qbk+1c01qbkc0γbk+1bk 2
其中对陀螺仪偏置求IMU预积分项线性化,有:
γ b k + 1 b k ≈ γ ^ b k + 1 b k ⊗ [ 1 1 2 J b w γ δ b w ] \gamma_{b_{k+1}}^{b_{k}} \approx \hat{\gamma}_{b_{k+1}}^{b_{k}} \otimes\left[\begin{array}{c} 1 \\ \frac{1}{2} J_{b_{w}}^{\gamma} \delta b_{w} \end{array}\right] γbk+1bkγ^bk+1bk[121Jbwγδbw]
在具体实现的时候,因为上述约束方程为:

q b k + 1 c 0 − 1 ⊗ q b k c 0 ⊗ γ b k + 1 b k = [ 1 0 ] q_{b_{k+1}}^{c_{0}}{ }^{-1} \otimes q_{b_{k}}^{c_{0}} \otimes \gamma_{b_{k+1}}^{b_{k}}=\left[\begin{array}{l} 1 \\ 0 \end{array}\right] qbk+1c01qbkc0γbk+1bk=[10]
有:

γ b k + 1 b k = q b k c 0 − 1 ⊗ q b k + 1 c 0 ⊗ [ 1 0 ] \gamma_{b_{k+1}}^{b_{k}}=q_{b_{k}}^{c_{0}-1} \otimes q_{b_{k+1}}^{c_{0}} \otimes\left[\begin{array}{l} 1 \\ 0 \end{array}\right] γbk+1bk=qbkc01qbk+1c0[10]
代入 δ b w \delta b_{w} δbw 得 :

γ ^ b k + 1 b k ⊗ [ 1 1 2 J b w γ δ b w ] = q b k c 0 − 1 ⊗ q b k + 1 c 0 ⊗ [ 1 0 ] \hat{\gamma}_{b_{k+1}}^{b_{k}} \otimes\left[\begin{array}{c} 1 \\ \frac{1}{2} J_{b_{w}}^{\gamma} \delta b_{w} \end{array}\right]=q_{b_{k}}^{c 0-1} \otimes q_{b_{k+1}}^{c 0} \otimes\left[\begin{array}{l} 1 \\ 0 \end{array}\right] γ^bk+1bk[121Jbwγδbw]=qbkc01qbk+1c0[10]

只考虑虚部,有 :

J b w γ δ b w = 2 ( γ ^ b k + 1 b k − 1 ⊗ q b k c 0 − 1 ⊗ q b k + 1 c 0 ) v e c J_{b_{w}}^{\gamma} \delta b_{w}=2\left(\hat{\gamma}_{b_{k+1}}^{b_{k}}{ }^{-1} \otimes q_{b_{k}}^{c_{0}-1} \otimes q_{b_{k+1}}^{c_{0}}\right)_{v e c} Jbwγδbw=2(γ^bk+1bk1qbkc01qbk+1c0)vec

两侧乘以 J b w γ T \mathbf{J_{b_{w}}^{\gamma}}^{T} JbwγT ,用LDLT分解求得 δ b w \delta b_{w} δbw
在代码中, q i , j \mathrm{q}_\mathrm{i,j} qi,j q b k + 1 b k = q b k c 0 − 1 ⊗ q b k + 1 c 0 q_{b_{k+1}}^{b_{k}}=q_{b_{k}}^{c_{0}-1} \otimes q_{b_{k+1}}^{c_{0}} qbk+1bk=qbkc01qbk+1c0
t m p − A \mathrm{tmp}_{-} \mathrm{A} tmpA J b w γ J_{b_{w}}^{\gamma} Jbwγ

t m p − B \mathrm{tmp}_{-} \mathrm{B} tmpB
2 ( r ^ b k + 1 b k − 1 ⊗ q b k + 1 b k ) v e c = 2 ( r ^ b k + 1 b k − 1 ⊗ q b k c 0 − 1 ⊗ q b k + 1 c 0 ) v e c 2\left(\hat{r}_{b_{k+1}}^{b_{k}}{ }^{-1} \otimes q_{b_{k+1}}^{b_{k}}\right)_{v e c}=2\left(\hat{r}_{b_{k+1}}^{b_{k}}{ }^{-1} \otimes q_{b_{k}}^{c_{0}-1} \otimes q_{b_{k+1}}^{c_{0}}\right)_{v e c} 2(r^bk+1bk1qbk+1bk)vec=2(r^bk+1bk1qbkc01qbk+1c0)vec
根据上面的代价函数构造 A x = B \mathrm{Ax}=\mathrm{B} Ax=B
J b w γ T J b w γ δ b w = 2 J b w γ T ( r ^ b k + 1 b k − 1 ⊗ q b k c 0 − 1 ⊗ q b k + 1 c 0 ) vec  J_{b_{w}}^{\gamma T} J_{b_{w}}^{\gamma} \delta b_{w}=2 J_{b_{w}}^{\gamma T}\left(\hat{r}_{b_{k+1}}^{b_{k}}{ }^{-1} \otimes q_{b_{k}}^{c_{0}-1} \otimes q_{b_{k+1}}^{c_{0}}\right)_{\text {vec }} JbwγTJbwγδbw=2JbwγT(r^bk+1bk1qbkc01qbk+1c0)vec 
然后采用LDLT分解求得 δ b w \delta b_{w} δbw

  • VINS中的代码
/**
 * @brief   陀螺仪偏置校正
 * @optional    根据视觉SFM的结果来校正陀螺仪Bias -> Paper V-B-1
 *              主要是将相邻帧之间SFM求解出来的旋转矩阵与IMU预积分的旋转量对齐
 *              注意得到了新的Bias后对应的预积分需要repropagate
 * @param[in]   all_image_frame所有图像帧构成的map,图像帧保存了位姿、预积分量和关于角点的信息
 * @param[out]  Bgs 陀螺仪偏置
 * @return      void
*/
void solveGyroscopeBias(map<double, ImageFrame> &all_image_frame, Vector3d* Bgs)
{
    Matrix3d A;
    Vector3d b;
    Vector3d delta_bg;
    A.setZero();
    b.setZero();
    map<double, ImageFrame>::iterator frame_i;
    map<double, ImageFrame>::iterator frame_j;
    for (frame_i = all_image_frame.begin(); next(frame_i) != all_image_frame.end(); frame_i++)
    {
        frame_j = next(frame_i);
        MatrixXd tmp_A(3, 3);
        tmp_A.setZero();
        VectorXd tmp_b(3);
        tmp_b.setZero();
 
        //R_ij = (R^c0_bk)^-1 * (R^c0_bk+1) 转换为四元数 q_ij = (q^c0_bk)^-1 * (q^c0_bk+1)
        Eigen::Quaterniond q_ij(frame_i->second.R.transpose() * frame_j->second.R);
        //tmp_A = J_j_bw
        tmp_A = frame_j->second.pre_integration->jacobian.template block<3, 3>(O_R, O_BG);
        //tmp_b = 2 * (r^bk_bk+1)^-1 * (q^c0_bk)^-1 * (q^c0_bk+1)
        //      = 2 * (r^bk_bk+1)^-1 * q_ij
        tmp_b = 2 * (frame_j->second.pre_integration->delta_q.inverse() * q_ij).vec();
        //tmp_A * delta_bg = tmp_b
        A += tmp_A.transpose() * tmp_A;
        b += tmp_A.transpose() * tmp_b;
 
    }
    // LDLT方法
    delta_bg = A.ldlt().solve(b);
    ROS_WARN_STREAM("gyroscope bias initial calibration " << delta_bg.transpose());
 
    for (int i = 0; i <= WINDOW_SIZE; i++)
        Bgs[i] += delta_bg;
    // 得到了新的Bias后对应的预积分需要repropagate
    for (frame_i = all_image_frame.begin(); next(frame_i) != all_image_frame.end( ); frame_i++)
    {
        frame_j = next(frame_i);
        frame_j->second.pre_integration->repropagate(Vector3d::Zero(), Bgs[0]);
    }
}

之所以 A +=tmp_A.transpose() * tmp_A,其实就是 A T A x = A T b A^T Ax=A^Tb ATAx=ATb。在求解 A x = b Ax=b Ax=b 的最小二乘解时,两边同乘以A矩阵的转置得到的 A T A A^TA ATA 一定是可逆的。

  • TIPS

    这里为什么是可以连加的呢,直接构造该正定方程呢,简单来说就是VINS中认为滑窗中陀螺仪的Bags都是一样的。所以把所有的方程写在一起就构成了同一个变量的连加形式。

Reference