VINS 優化

VINS 優化

@(VINS)[VINS]

IMU優化

已知條件:
(1){Rwbkpbk+1w=Rwbk(pbkw+vbkwΔtk12gwΔtk2)+αbk+1bkRwbkvbk+1w=Rwbk(vbkwgwΔtk)+βbk+1bkqwbkqbk+1w=γbk+1bk\begin{cases} R_w^{b_k} p_{b_{k+1}}^w = R_w^{b_k} \left(p_{b_k}^w + v_{b_k}^w {\Delta t}_k - \frac{1}{2}g^w {\Delta t}_k^2\right) + {\alpha}_{b_{k+1}}^{b_k} \\ R_w^{b_k} v_{b_{k+1}}^w = R_w^{b_k} \left(v_{b_k}^w - g^w {\Delta t}_k\right) + {\beta}_{b_{k+1}}^{b_k} \\ q_w^{b_k} \otimes q_{b_{k+1}}^w = {\gamma}_{b_{k+1}}^{b_k} \end{cases} \tag{$1$}
以及雅各比矩陣和協方差矩陣:(具體計算見 “VINS 預積分 雅各比矩陣和協方差矩陣推導過程”
{Jk=[JαJβJγJbaJbg]=[If01δt14(qk+qk+1)δt2f040I[ωk+1+ωk2bwk]×δt00δt0f21I12(qk+qk+1)δtf24000I00000I]Pbk\begin{cases} J_{k} = \begin{bmatrix} J^{\alpha} \\ J^{\beta} \\ J^{\gamma} \\ J^{b_a} \\ J^{b_g} \end{bmatrix} = \begin{bmatrix} I & f_{01} & \delta t & -\frac{1}{4}\left(q_k + q_{k+1}\right){\delta t}^2 & f_{04} \\ 0 & I - \left[\frac{\omega_{k+1} + \omega_k}{2} - b_{w_k}\right]_{\times}\delta t & 0 & 0 & -\delta t \\ 0 & f_{21} & I & -\frac{1}{2}\left(q_k + q_{k+1}\right)\delta t & f_{24} \\ 0 & 0 & 0 & I & 0 \\ 0 & 0 & 0 & 0 & I \end{bmatrix} \\ P_{b_k} \end{cases}

關於偏差一階近似可以寫成:
(2){αbk+1bkα^bk+1bk+Jbaαδbak+Jbωαδbωkβbk+1bkβ^bk+1bk+Jbaβδbak+Jbωβδbωkγbk+1bkγ^bk+1bk[112Jbωγδbωk]\begin{cases} {\alpha}_{b_{k+1}}^{b_k} \approx {\hat{\alpha}}_{b_{k+1}}^{b_k} + J_{b_a}^{\alpha} \delta b_{a_k} + J_{b_{\omega}}^{\alpha} \delta b_{{\omega}_k} \\ {\beta}_{b_{k+1}}^{b_k} \approx {\hat{\beta}}_{b_{k+1}}^{b_k} + J_{b_a}^{\beta} \delta b_{a_k} + J_{b_{\omega}}^{\beta} \delta b_{{\omega}_k} \\ {\gamma}_{b_{k+1}}^{b_k} \approx {\hat{\gamma}}_{b_{k+1}}^{b_k} \otimes \begin{bmatrix} 1 \\ \frac{1}{2}J_{b_{\omega}}^{\gamma} \delta b_{{\omega}_k} \end{bmatrix} \end{cases} \tag{$2$}
根據 (1)\left(1\right) 式我們同樣可以得到 αbk+1bk, βbk+1bk, γbk+1bk{\alpha}_{b_{k+1}}^{b_k}, \ {\beta}_{b_{k+1}}^{b_k}, \ {\gamma}_{b_{k+1}}^{b_k}
(3){αbk+1bk=Rwbk(pbk+1wpbkw+12gwΔtk2vbkwΔtk)βbk+1bk=Rwbk(vbk+1w+gwΔtkvbkw)γbk+1bk=qbkw1qbk+1w\begin{cases} {\alpha}_{b_{k+1}}^{b_k} = R_{w}^{b_k}\left(p_{b_{k+1}}^w - p_{b_k}^w + \frac{1}{2}g^w{{\Delta t}_k}^2 - v_{b_k}^w {\Delta t}_k\right) \\ {\beta}_{b_{k+1}}^{b_k} = R_w^{b_k}\left(v_{b_{k+1}}^w + g^w \Delta t_k - v_{b_k}^w\right) \\ {\gamma}_{b_{k+1}}^{b_k} = {q_{b_k}^w}^{-1} \otimes q_{b_{k+1}}^w \end{cases} \tag{$3$}
通過 (3)(2)\left(3\right) - \left(2\right) 式計算殘差:
residual15×1=[δαbk+1bkδθbk+1bkδβbk+1bkδbaδbg]=[Rwbk(pbk+1wpbkw+12gwΔtk2vbkwΔtk)(α^bk+1bk+Jbaαδbak+Jbωαδbωk)2 [(γ^bk+1bk[112Jbωγδbωk])1(qbkw1qbk+1w)]xyzRwbk(vbk+1w+gwΔtkvbkw)(β^bk+1bk+Jbaβδbak+Jbωβδbωk)babk+1babkbωbk+1bωbk]residual_{15 \times 1} = \begin{bmatrix} {\delta {\alpha}}_{b_{k+1}}^{b_k} \\ {\delta {\theta}}_{b_{k+1}}^{b_k} \\ {\delta {\beta}}_{b_{k+1}}^{b_k} \\ \delta b_a \\ \delta b_g \end{bmatrix} = \begin{bmatrix} R_{w}^{b_k}\left(p_{b_{k+1}}^w - p_{b_k}^w + \frac{1}{2}g^w{{\Delta t}_k}^2 - v_{b_k}^w {\Delta t}_k\right) - \left({\hat{\alpha}}_{b_{k+1}}^{b_k} + J_{b_a}^{\alpha} \delta b_{a_k} + J_{b_{\omega}}^{\alpha} \delta b_{{\omega}_k}\right)\\ 2 \ \begin{bmatrix} \left({\hat{\gamma}}_{b_{k+1}}^{b_k} \otimes \begin{bmatrix} 1 \\ \frac{1}{2}J_{b_{\omega}}^{\gamma} \delta b_{{\omega}_k} \end{bmatrix}\right)^{-1} \otimes \left({q_{b_k}^w}^{-1} \otimes q_{b_{k+1}}^w \right) \end{bmatrix}_{xyz} \\ R_w^{b_k}\left(v_{b_{k+1}}^w + g^w \Delta t_k - v_{b_k}^w\right) - \left({\hat{\beta}}_{b_{k+1}}^{b_k} + J_{b_a}^{\beta} \delta b_{a_k} + J_{b_{\omega}}^{\beta} \delta b_{{\omega}_k}\right)\\ {b_a}_{b_{k+1}} - {b_a}_{b_k} \\ {b_{\omega}}_{b_{k+1}} - {b_{\omega}}_{b_k} \end{bmatrix}
根據 residualresidual 公式計算對應的雅各比矩陣
注:R˙=ϕR, [q]L=qwI+[0qvTqv[qv]×], [q]R=qwI+[0qvTqv[qv]×]\dot{R}=\phi^{\wedge}R, \ \left[q\right]_L = q_w I + \begin{bmatrix} 0 & -{q_v}^T \\ q_v & \left[q_v\right]_{\times} \end{bmatrix}, \ \left[q\right]_R = q_w I + \begin{bmatrix} 0 & -{q_v}^T \\ q_v & -\left[q_v\right]_{\times} \end{bmatrix}

  1. 求第 ii(j=i+1)(j = i + 1) 的位姿的雅各比矩陣
    Jposei=[Ri1[Ri1(0.5GΔt2+PjPiViΔt)]×03×103×3[[Qj1Qi]L[δq]R]br3×303×103×3[Qi1(GΔt+VjVi)]×03×103×303×303×103×303×303×1]J_{pose_i} = \begin{bmatrix} -{R_i}^{-1} & \left[R_i^{-1} * \left(0.5G {\Delta t}^2 + P_j - P_i - V_i \Delta t\right)\right]_{\times} & 0_{3 \times 1} \\ 0_{3 \times 3} & \left[-\left[{Q_j}^{-1} Q_i\right]_L \left[\delta q\right]_R\right]_{{br}_{3 \times 3}} & 0_{3 \times 1} \\ 0_{3 \times 3} & \left[{Q_i}^{-1} \left(G \Delta t + V_j - V_i\right)\right]_{\times} & 0_{3 \times 1} \\ 0_{3 \times 3} & 0_{3 \times 3} & 0_{3 \times 1} \\ 0_{3 \times 3} & 0_{3 \times 3} & 0_{3 \times 1} \end{bmatrix}
    其中:
    δbω=BωiBωj\delta b_{\omega} = B_{\omega_i} - B_{\omega_j}
    δq=γ^ji12Jbωγδbω\delta q = \hat{\gamma}_j^i\frac{1}{2}J_{b_{\omega}}^{\gamma} \delta b_{\omega}
  2. 求第 ii(j=i+1)(j = i + 1)v  ba  bωv \ \ b_{a} \ \ b_{\omega} 的雅各比矩陣
    Jspeedi=[Ri1ΔtJbaαJbωα00[[Qj1Qi δq]L]br3×3JbωαRi1JbaβJbωβ0I000I] J_{speed_i} = \begin{bmatrix} -{R_i}^{-1} \Delta t & -J_{b_a}^{\alpha} & -J_{b_{\omega}}^{\alpha} \\ 0 & 0 & \left[-\left[{Q_j}^{-1}Q_i \ \delta q\right]_L\right]_{br_{3 \times 3}}J_{b_{\omega}}^{\alpha} \\ R_i^{-1} & -J_{b_a}^{\beta} & -J_{b_{\omega}}^{\beta} \\ 0 & -I & 0 \\ 0 & 0 & -I \end{bmatrix}
  3. 求第 jj(j=i+1)(j = i + 1) 的位姿的雅各比矩陣
    Jposej=[Ri103×303×103×3[[δq1Qi1Qj]L]br3×303×103×303×303×103×303×303×103×303×303×1]J_{pose_j} = \begin{bmatrix} {R_i}^{-1} & 0_{3 \times 3} & 0_{3 \times 1} \\ 0_{3 \times 3} & \left[\left[{\delta q}^{-1} {Q_i}^{-1} Q_j\right]_L\right]_{br_{3 \times 3}} & 0_{3 \times 1} \\ 0_{3 \times 3} & 0_{3 \times 3} & 0_{3 \times 1} \\ 0_{3 \times 3} & 0_{3 \times 3} & 0_{3 \times 1} \\ 0_{3 \times 3} & 0_{3 \times 3} & 0_{3 \times 1} \end{bmatrix}
  4. 求第 jj(j=i+1)(j = i + 1)v  ba  bωv \ \ b_{a} \ \ b_{\omega} 的雅各比矩陣
    Jspeedj=[000000Ri000I000I] J_{speed_j} = \begin{bmatrix} 0 & 0 & 0 \\ 0 & 0 & 0 \\ R_i & 0 & 0 \\ 0 & I & 0 \\ 0 & 0 & I \end{bmatrix}
    使用最小二乘並加入殘差矩陣,優化:
    JTP1J=JTP1  residual15×1J^TP^{-1}J = J^TP^{-1} \ \ residual_{15 \times 1}
    由於ceres庫的限制,只能使用J,   residual15×1J ,\ \ \ residual_{15 \times 1}優化,爲了能夠使用協方差,因此,我們重新定義雅各比矩陣和殘差J  residual15×1J' \ \ {residual_{15 \times 1}}'
    J=P1J,  residual15×1=P1  residual15×1J' = \sqrt{P^{-1}} J, \ \ {residual_{15 \times 1}}' = \sqrt{P^{-1}} \ \ residual_{15 \times 1}
    這樣就可以通過最小二乘的方式就可以使用殘差:
    JTJ=JTP1J,  JT  residual15×1=JTP1  residual15×1J'^T J' = J^T P^{-1} J, \ \ J'^T \ \ {residual_{15 \times 1}}' = J^T P^{-1} \ \ residual_{15 \times 1}
    其中:
    P1=Pj1matrixLT\sqrt{P^{-1}} = {{{P_j}^{-1}}_{matrixL}}^T通過調用Eigen::LLT函數

特徵點重投影優化

已知條件有:

  1. 匹配點對(有像素座標作用了相機內參矩陣後的點座標) (u,v)\left(u, v\right)爲像素座標,經過相機內參作用得到座標(uPXFOCUS,vPYFOCUS)\left(\frac{u-PX}{FOCUS}, \frac{v-PY}{FOCUS}\right) (匹配點對不需要優化)
  2. 兩幀的位姿 (重投影誤差,需要優化)
  3. IMU座標系到相機座標系的變換矩陣 (此參數固定,不會進行優化)
  4. 匹配點對的深度信息的倒數(重投影誤差,需要優化)
    即:
    {ptsi=(xi,yi,1),  ptsj=(xj,yj,1)Qi,Pi,Qj,PjQic,TicDepi \begin{cases} pts_i = \left(x_i, y_i, 1\right), \ \ pts_j = \left(x_j, y_j, 1 \right) \\ Q_i, P_i, Q_j, P_j \\ Q_{ic}, T_{ic} \\ Dep_i \end{cases}
    根據 ptsi, Qi, Pi, Qj, Pj, Depipts_i, \ Q_i, \ P_i, \ Q_j, \ P_j, \ Dep_iptsj{pts_j}'
    ptsj=Qic1(Qj1(Qi(QicptsiDepi+Tic)+PiPj)Tic){pts_j}' ={Q_{ic}}^{-1}\left({Q_j}^{-1}\left(Q_i\left(Q_{ic}\frac{pts_i}{Dep_i} + T_{ic}\right)+P_i - P_j\right) - T_{ic}\right)
    令:
    pts_camerai=ptsiDepipts\_camera_i = \frac{pts_i}{Dep_i}
    ptsimui=Qic  pts_camerai+Ticptsimu_i = Q_{ic} \ \ pts\_camera_i + T_{ic}
    ptsimuj=Qj1(Qi  ptsimui+PiPj)ptsimu_j = {Q_j}^{-1}\left(Q_i \ \ ptsimu_i +P_i - P_j\right)
    然後把 ptsj{pts_j}' 歸一化到 z=1z = 1平面 ptsj=ptsjptsj.z{pts_j}' = \frac{{pts_j}'}{{pts_j}'.z}
    構建優化方程:
    minptsjxyptsjxy2\min || {pts_j}'_{xy} - {pts_j}_{xy}||^2
    殘差爲:
    residual2×1=FOCUS1.5I2×2(ptsjxyptsjxy)residual_{2 \times 1} = \frac{FOCUS}{1.5} I_{2 \times 2} * \left({pts_j}'_{xy} - {pts_j}_{xy}\right)
    注:FOCUS1.5I2×2\frac{FOCUS}{1.5} I_{2 \times 2} 的作用是把殘差轉化到像素單位

根據最小二乘優化,需要求取雅各比矩陣:

  • ii 幀位姿的雅各比矩陣
  • jj 幀位姿的雅各比矩陣
  • Qic,TicQ_{ic}, T_{ic} 的雅各比矩陣(即使不優化也需要求取)
  • 特徵點深度信息的雅各比矩陣

先求出 ptsj=ptsjptsj.z{pts_j}' = \frac{{pts_j}'}{{pts_j}'.z}方程關於ptsjx, ptsjy{pts_j}_x, \ {pts_j}_y的導數:
reduce2×3=FOCUS1.5I2×2[1ptsjz0ptsjxptsjzptsjz01ptsjzptsjyptsjzptsjz]reduce_{2 \times 3} = \frac{FOCUS}{1.5} I_{2 \times 2} * \begin{bmatrix} \frac{1}{{pts_j}_z} & 0 & -\frac{{pts_j}_x}{{pts_j}_z * {pts_j}_z} \\ 0 & \frac{1}{{pts_j}_z} & -\frac{{pts_j}_y}{{pts_j}_z * {pts_j}_z} \end{bmatrix}

ii 幀位姿的雅各比矩陣
jacoi2×7=[reduce2×3[Ric1Rj1Ric1Rj1Ri[ptsimui]×]02×1]{jaco_i}_{2 \times 7} = \begin{bmatrix} reduce_{2 \times 3} * \begin{bmatrix} {R_{ic}}^{-1}{R_j}^{-1} & -{R_{ic}}^{-1}{R_j}^{-1}R_i\left[ptsimu_i\right]_{\times} \end{bmatrix} & 0_{2 \times 1} \end{bmatrix}

jj 幀位姿的雅各比矩陣
jacoj2×7=[reduce2×3[Ric1Rj1Ric1[ptsimuj]×]02×1]{jaco_j}_{2 \times 7} = \begin{bmatrix} reduce_{2 \times 3} * \begin{bmatrix} -{R_{ic}}^{-1}{R_j}^{-1} & {R_{ic}}^{-1}\left[ptsimu_j\right]_{\times} \end{bmatrix} & 0_{2 \times 1} \end{bmatrix}

Qic,TicQ_{ic}, T_{ic} 的雅各比矩陣
令:
tmpr=Ric1Rj1RiRictmp_r = {R_{ic}}^{-1} {R_j}^{-1}R_i R_{ic}
jacoic2×7=[reduce2×3[Ric1(Rj1RiI3×3)tmpr [pts_camerai]×+[tmprpts_camerai]×+[Ric1(Rj1(RiTic+PiPj)Tic)]×]02×1]{jaco_{ic}}_{2 \times 7} = \begin{bmatrix} reduce_{2 \times 3} * \begin{bmatrix} {R_{ic}}^{-1} \left({R_j}^{-1} R_i - I_{3 \times 3}\right) & -tmp_r \ \left[pts\_camera_i\right]_{\times} + \left[tmp_r * pts\_camera_i \right]_{\times} + \left[R_{ic}^{-1}\left(R_j^{-1}\left(R_i T_{ic} + P_i - P_j \right) - T_{ic}\right)\right]_{\times} \end{bmatrix} & 0_{2 \times 1} \end{bmatrix}

特徵點深度信息的雅各比矩陣
jacofeature2×1=reduce2×3Ric1Rj1RiRic ptsiDepi2{jaco_{feature}}_{2 \times 1} = -\frac{reduce_{2 \times 3} {R_{ic}}^{-1}R_j^{-1}R_iR_{ic} \ pts_i}{Dep_i^2}
根據以上求得的殘差矩陣和雅各比矩陣,就可以通過ceres 庫對位姿和特徵點信息進行最小二乘的優化,在優化過程中有使用損失函數ceres::CauchyLoss(1.0),該函數的是
ρ(x)={log(x+1)1x+11(x+1)2 \rho\left(x\right) = \begin{cases} \log \left(x + 1\right) \\ \frac{1}{x + 1} \\ -\frac{1}{\left(x + 1\right)^2} \end{cases}
即,log(x+1), log(x+1), log(x+1)\log\left(x + 1\right), \ \log\left(x + 1\right)', \ \log\left(x + 1\right)'' 原型,一階導,二階導。
最終的優化函數爲minρ(ptsjxyptsjxy2)\min \rho \left(|| {pts_j}'_{xy} - {pts_j}_{xy}||^2\right)

邊緣化優化

邊緣化優化中的重投影優化
相比單純的重投影優化,添加了係數。
已知重投影優化計算出了 residual,  Jresidual, \ \ J 在邊緣化優化中的重投影優化中sq_norm=ptsjxyptsjxy22,  residual=residual1sq_norm+1,  J=1sq_norm+1Jsq\_norm = || {pts_j}'_{xy} - {pts_j}_{xy}||^2_2, \ \ residual = residual * \frac{1}{\sqrt{sq\_norm }+ 1}, \ \ J = \frac{1}{\sqrt{sq\_norm }+ 1} * J
此操作主要是爲了當重投影誤差特別大時,我們認爲該點不準確,使其權重減小。能夠一定程度上減小錯誤點對優化的影響。

邊緣化優化時,添加的優化信息有:
1. 劃窗內的第0幀與第1幀之間的IMU優化信息
2. 劃窗內與第0幀有關的特徵點重投影優化信息

邊緣化掉劃窗內第0幀相關的信息,需要用到舒爾補,用舒爾補之前我們需要先把包含第0幀相關信息的矩陣構建出來,由於優化使用的最小二乘,因此構建的矩陣如下:
A=JTJ,  b=JTrA = J^T J, \ \ b = J^T r, rr表示的殘差矩陣。AX=bAX = b
代碼如下:

void* ThreadsConstructA(void* threadsstruct)
{
    ThreadsStruct* p = ((ThreadsStruct*)threadsstruct);
    for (auto it : p->sub_factors)
    {
        for (int i = 0; i < static_cast<int>(it->parameter_blocks.size()); i++)
        {
            int idx_i = p->parameter_block_idx[reinterpret_cast<long>(it->parameter_blocks[i])];
            int size_i = p->parameter_block_size[reinterpret_cast<long>(it->parameter_blocks[i])];
            if (size_i == 7)
                size_i = 6;
            Eigen::MatrixXd jacobian_i = it->jacobians[i].leftCols(size_i);
            for (int j = i; j < static_cast<int>(it->parameter_blocks.size()); j++)
            {
                int idx_j = p->parameter_block_idx[reinterpret_cast<long>(it->parameter_blocks[j])];
                int size_j = p->parameter_block_size[reinterpret_cast<long>(it->parameter_blocks[j])];
                if (size_j == 7)
                    size_j = 6;
                Eigen::MatrixXd jacobian_j = it->jacobians[j].leftCols(size_j);
                if (i == j)
                    p->A.block(idx_i, idx_j, size_i, size_j) += jacobian_i.transpose() * jacobian_j;
                else
                {
                    p->A.block(idx_i, idx_j, size_i, size_j) += jacobian_i.transpose() * jacobian_j;
                    p->A.block(idx_j, idx_i, size_j, size_i) = p->A.block(idx_i, idx_j, size_i, size_j).transpose();
                }
            }
            p->b.segment(idx_i, size_i) += jacobian_i.transpose() * it->residuals;
        }
    }
    return threadsstruct;
}

以上信息可以構成一個矩陣,我們分爲4部分:

AA矩陣:
A=[AmmAmrArmArr]A = \begin{bmatrix} A_{mm} &amp; A_{mr} \\ A_{rm} &amp; A_{rr} \end{bmatrix}
其中AmmA_{mm}中包含 劃窗內第0幀位姿,speed 和特徵點相關信息。
  ArrA_{rr}中包含劃窗內第1幀的speed相關信息和第1幀到第10幀的位姿相關信息,同時包含IMU到Camera座標系的轉換Angleic,TicAngle_{ic}, T_{ic}信息。
通過舒爾補重新構建矩陣AA
A=ArrArmAmminvAmrA = A_{rr} - A_{rm} * {A_{mm}}_{inv} * A_{mr}
代碼:

Eigen::MatrixXd Amm = 0.5 * (A.block(0, 0, m, m) + A.block(0, 0, m, m).transpose());
Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> saes(Amm);
Eigen::MatrixXd Amm_inv = saes.eigenvectors() * Eigen::VectorXd((saes.eigenvalues().array() > eps).select(saes.eigenvalues().array().inverse(), 0)).asDiagonal() * saes.eigenvectors().transpose();
// 此部分爲舒爾補 邊緣化優化狀態量
Eigen::MatrixXd Amr = A.block(0, m, m, n);
Eigen::MatrixXd Arm = A.block(m, 0, n, m);
Eigen::MatrixXd Arr = A.block(m, m, n, n);
A = Arr - Arm * Amm_inv * Amr;

bb矩陣:
b=[bmmbrr]b = \begin{bmatrix} b_{mm} \\ b_{rr} \end{bmatrix}
通過舒爾補重新構建矩陣bb
b=brrArmAmminvbmmb=b_{rr} - A_{rm} * {A_{mm}}_{inv} * b_{mm}
代碼:

Eigen::VectorXd bmm = b.segment(0, m);
Eigen::VectorXd brr = b.segment(m, n);
b = brr - Arm * Amm_inv * bmm;

這樣我們就保留了關於第0幀的約束到了通過舒爾補重新構建的矩陣A,  bA, \ \ b 中。
因爲現在的矩陣A,  bA, \ \ bA=JTJ,  b=JTrA = J^T J, \ \ b = J^T r 這樣的形式,又因爲ceres庫只能使用最小二乘優化,因此我們需要根據 AA 重新分解出 JJ 形式的矩陣。即類似 linearized_jacobians=A,,linearized_residuals=1Ablinearized\_jacobians = \sqrt{A}, , linearized\_residuals = \frac{1}{\sqrt{A}} blinearized_jacobians, linearized_residualslinearized\_jacobians, \ linearized\_residuals 爲優化時使用的矩陣。

現在linearized_jacobians, linearized_residualslinearized\_jacobians, \ linearized\_residuals 包含的信息爲linearized_jacobians[110]0,linearized_residuals[110]0linearized\_jacobians_{[1-10] | 0}, linearized\_residuals_{[1-10] | 0}

代碼:

Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> saes2(A);
Eigen::VectorXd S = Eigen::VectorXd((saes2.eigenvalues().array() > eps).select(saes2.eigenvalues().array(), 0));
Eigen::VectorXd S_inv = Eigen::VectorXd((saes2.eigenvalues().array() > eps).select(saes2.eigenvalues().array().inverse(), 0));

Eigen::VectorXd S_sqrt = S.cwiseSqrt();
Eigen::VectorXd S_inv_sqrt = S_inv.cwiseSqrt();

linearized_jacobians = S_sqrt.asDiagonal() * saes2.eigenvectors().transpose();
linearized_residuals = S_inv_sqrt.asDiagonal() * saes2.eigenvectors().transpose() * b;

以上是構建邊緣化優化需要的信息。構建完以上信息,劃窗內把第0幀信息移除掉,然後進行優化,邊緣化優化的信息爲:
第1幀到第10幀的位姿。即 PoseRT[110]{Pose_{RT}}_{[1-10]}
已知條件:

  • keep_Pose 第1幀到第10幀的位姿和第1幀的speed (速度v , 陀螺儀偏置bgs , 加速度偏置 bas)信息 。(該信息不進行優化)
  • 劃窗內的位姿Pose 第1幀到第10幀的位姿和第1幀的speed。(該變量需要進行優化)

優化的方式使用的最小二乘優化,雅各比矩陣和殘差矩陣使用linearized_jacobians, linearized_residualslinearized\_jacobians, \ linearized\_residuals

優化過程中更新雅各比矩陣和殘差矩陣的方法爲:
δx=Posekeep_Pose\delta x = Pose - keep\_Pose
linearized_residuals=linearized_residuals+linearized_jacobiansδxlinearized\_residuals = linearized\_residuals + linearized\_jacobians * \delta x
linearized_jacobians=linearized_jacobianslinearized\_jacobians = linearized\_jacobians

代碼:

bool MarginalizationFactor::Evaluate(double const *const *parameters, double *residuals, double **jacobians) const
{
    int n = marginalization_info->n;
    int m = marginalization_info->m;
    Eigen::VectorXd dx(n);
    for (int i = 0; i < static_cast<int>(marginalization_info->keep_block_size.size()); i++)
    {
        int size = marginalization_info->keep_block_size[i];
        int idx = marginalization_info->keep_block_idx[i] - m;
        Eigen::VectorXd x = Eigen::Map<const Eigen::VectorXd>(parameters[i], size);
        
        Eigen::VectorXd x0 = Eigen::Map<const Eigen::VectorXd>(marginalization_info->keep_block_data[i], size);
        if (size != 7)
            dx.segment(idx, size) = x - x0;
        else
        {
            // \delta t
            dx.segment<3>(idx + 0) = x.head<3>() - x0.head<3>();
            // \delta \theta
            dx.segment<3>(idx + 3) = 2.0 * Utility::positify(Eigen::Quaterniond(x0(6), x0(3), x0(4), x0(5)).inverse() * Eigen::Quaterniond(x(6), x(3), x(4), x(5))).vec();
            if (!((Eigen::Quaterniond(x0(6), x0(3), x0(4), x0(5)).inverse() * Eigen::Quaterniond(x(6), x(3), x(4), x(5))).w() >= 0))
            {
                dx.segment<3>(idx + 3) = 2.0 * -Utility::positify(Eigen::Quaterniond(x0(6), x0(3), x0(4), x0(5)).inverse() * Eigen::Quaterniond(x(6), x(3), x(4), x(5))).vec();
            }
        }
    }
    Eigen::Map<Eigen::VectorXd>(residuals, n) = marginalization_info->linearized_residuals + marginalization_info->linearized_jacobians * dx;
    if (jacobians)
    {
        for (int i = 0; i < static_cast<int>(marginalization_info->keep_block_size.size()); i++)
        {
            if (jacobians[i])
            {
                int size = marginalization_info->keep_block_size[i], local_size = marginalization_info->localSize(size);
                int idx = marginalization_info->keep_block_idx[i] - m;
                Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> jacobian(jacobians[i], n, size);
                jacobian.setZero();
                jacobian.leftCols(local_size) = marginalization_info->linearized_jacobians.middleCols(idx, local_size);
            }
        }
    }
    return true;
}

添加新的一幀數據 後,按照同樣的方式構建linearized_jacobians, linearized_residualslinearized\_jacobians, \ linearized\_residuals
但是keep_Pose有原來的 keep_Pose[211]=keep_Pose[210]+keep_Pose[11]keep\_Pose_{[2-11]} = keep\_Pose_{[2-10]} + keep\_Pose_{[11]} 即,前9個位姿使用的還是上一次構建邊緣化優化信息,然後再添加新的一幀的位姿。
Pose則是使用的優化過後的劃窗內的位姿。
流程如下圖:
在這裏插入圖片描述

迴環檢測優化

  1. 已經在當前劃窗內通過詞袋找到與之前關鍵幀迴環的關鍵幀分別記爲cur_KeyFrame, old_KeyFrame。

  2. 記錄相關信息。包括:

    • old_KeyFrame的位姿,的關鍵幀序號
    • 匹配點對
    • cur_KeyFrame的關鍵幀序號,時間戳,並標記爲迴環
  3. 優化
    通過重投影,計算cur_KeyFrame位姿移動到old_KeyFrame位姿的變化量
    因爲光流跟蹤的原因,可以得到劃窗內與cur_KeyFrame匹配的點對,然後把cur_KeyFrame位姿當做old_keyFrame位姿,把cur_KeyFrame匹配點的座標用old_KeyFrame對應點代替,通過重投影計算ΔR  ΔT\Delta R \ \ \Delta T,即:window_FramesPose,  Pointswindow_Frames,  loop_Pose=cur_KeyFramepose,  Pointsold_KeyFrame{window\_Frames}_{Pose}, \ \ Points_{window\_Frames}, \ \ loop\_Pose = {cur\_KeyFrame}_{pose}, \ \ Points_{old\_KeyFrame}
    其中window_FramesPose{window\_Frames}_{Pose}也包含cur幀的位姿,優化的意義不同。loop_Posewindow_FramesPoseloop\_Pose、{window\_Frames}_{Pose}、匹配點的深度信息 爲優化對象。
    根據優化後的 loop_Pose{loop\_Pose}&#x27;window_FramesPosecur{{{window\_Frames}_{Pose}}_{cur}}&#x27; 計算出relative_t,  relative_q,  relative_yawrelative\_t, \ \ relative\_q, \ \ relative\_yaw此3個參數會用在四自由度的全局優化中
    {relative_t=Rs_loop1(PscurPs_loop)relative_q=Rs_loop1Rscurrelative_yaw=Rscur.Angle.zRs_loop.Angle.z\begin{cases} relative\_t = {Rs\_loop}^{-1} \left(Ps_{cur} - Ps\_loop \right) \\ relative\_q = {Rs\_loop}^{-1} Rs_{cur} \\ relative\_yaw = Rs_{cur}.Angle.z - Rs\_loop.Angle.z \end{cases}
    其中Rs_loop  Ps_loopRs\_loop \ \ Ps\_looploop_Pose{loop\_Pose}&#x27;得到
    Rscur  PscurRs_{cur} \ \ Ps_{cur}window_FramesPosecur{{{window\_Frames}_{Pose}}_{cur}}&#x27;得到

代碼:

for (int i = 0; i< WINDOW_SIZE; i++)
{
    if (front_pose.header == Headers[i])
    {
        Matrix3d Rs_i = Quaterniond(para_Pose[i][6], para_Pose[i][3], para_Pose[i][4], para_Pose[i][5]).normalized().toRotationMatrix();
        Vector3d Ps_i = Vector3d(para_Pose[i][0], para_Pose[i][1], para_Pose[i][2]);
        Matrix3d Rs_loop = Quaterniond(front_pose.loop_pose[6], front_pose.loop_pose[3], front_pose.loop_pose[4], front_pose.loop_pose[5]).normalized().toRotationMatrix();
         Vector3d Ps_loop = Vector3d(front_pose.loop_pose[0], front_pose.loop_pose[1], front_pose.loop_pose[2]);
        // relative_t  relative_q = delta位姿
        // relative_yaw  z軸轉動的角度
        front_pose.relative_t = Rs_loop.transpose() * (Ps_i - Ps_loop);
        front_pose.relative_q = Rs_loop.transpose() * Rs_i;
        front_pose.relative_yaw = Utility::normalizeAngle(Utility::R2ypr(Rs_i).x() - Utility::R2ypr(Rs_loop).x());
    }
}

優化後位姿的更新

  1. 已知條件
  • 優化之前的劃窗內的位姿 Rs  Ps  SpeedBiasRs \ \ Ps \ \ SpeedBias
  • 優化後的位姿 para_PoseQ  para_PoseT  para_SpeedBiasv,bas,bgs{para\_Pose}_Q \ \ {para\_Pose}_T \ \ {para\_SpeedBias}_{v, bas, bgs}
  • 迴環優化後的位姿 Rs_loop  Ps_loopRs\_loop \ \ Ps\_loop
  • 迴環old_KeyFrame的位姿 Qold  PoldQ_{old} \ \ P_{old}
  1. 以上的四中優化會同時進行,因此會把約束條件羅列到一起,我們知道現在需要優化的變量有:
    para_PoseQ,  para_PoseT,  para_SpeedBias,  Rs_loop,  Ps_loop,  Dep{para\_Pose}_Q, \ \ {para\_Pose}_T, \ \ {para\_SpeedBias}, \ \ Rs\_loop, \ \ Ps\_loop, \ \ Dep 分別爲劃窗內的位姿,劃窗內的速度、加速度偏置、角速度偏置,迴環位姿,特徵點深度信息。
    優化的內容爲:
    [JPose[010]JSpeedBias[010]JDep[010]JMarginalization[110]JLoop[010]][para_PoseQpara_PoseTpara_SpeedBiasRs_loopPs_loopDep]=[rPose[010]rSpeedBias[010]rDep[010]rMarginalization[110]rLoop[010]]\begin{bmatrix} J_{Pose[0 - 10]} \\ J_{SpeedBias[0-10]} \\ J_{Dep[0 - 10]} \\ J_{Marginalization[1 - 10]} \\ J_{Loop[0-10]} \end{bmatrix} \begin{bmatrix} {para\_Pose}_Q \\ {para\_Pose}_T \\ {para\_SpeedBias} \\ Rs\_loop \\ Ps\_loop \\ Dep \end{bmatrix} = \begin{bmatrix} r_{Pose[0 - 10]} \\ r_{SpeedBias[0 - 10]} \\ r_{Dep[0 - 10]} r_{Marginalization[1 - 10]} \\ r_{Loop[0 - 10]} \end{bmatrix}
    上式公式,矩陣大小默認自動對齊。這樣邊緣化優化就會體現出。邊緣化優化經過舒爾補的雅各比矩陣就會和其它優化計算出的雅各比矩陣一起約束優化。上式同樣是使用最小二乘優化,最終展現是:
    JTJ  X=JTr\sum {J^TJ} \ \ X = J^T r

  2. 本來優化完的位姿,可以直接使用,考慮到後續的四自由度的全局優化(z軸的轉動和位姿),在此我們把z軸的轉動消除,消除z軸的轉動需要保持消除的值保持一致,因此我們以劃窗內的第0幀爲標準來消除。
    ΔzAngle=Rs[0].Angle.zpara_PoseQ.Angle.z\Delta zAngle = Rs_{[0]}.Angle.z - {para\_Pose}_Q.Angle.z
    計算第0幀z軸的轉動量,用3x3矩陣表示:
    rot_diff=(ΔzAngle,0,0).Matrix3x3rot\_diff = \left(\Delta zAngle, 0, 0\right).Matrix_{3x3}
    origin_P0=Ps[0]origin\_P0 = Ps[0]
    對優化後的位姿以第0幀爲標準消除z軸的轉動:
    Rs=rot_diffpara_PoseRRs = rot\_diff * {para\_Pose}_R
    Ps=rot_diff(para_PoseTpara_Pose[0]T)+origin_P0Ps = rot\_diff * \left({para\_Pose}_T - para\_Pose[0]_T\right) + origin\_P0
    SpeedBias=rot_diffpara_SpeedBiasSpeedBias = rot\_diff * para\_SpeedBias
    同理迴環也需要如此做:
    Rs_loop=rot_diffRs_loopRs\_loop = rot\_diff * Rs\_loop
    Ps_loop=rot_diff(Ps_looppara_Pose[0]T)+origin_P0Ps\_loop = rot\_diff * \left(Ps\_loop - para\_Pose[0]_T\right) + origin\_P0
    現在需要根據迴環信息計算優化後的位姿(只是劃窗內優化)轉到迴環 old_KeyFrame 的漂移:

先求z軸的漂移:
drift_yaw=Qold.Angle.xRs_loop.Angle.xdrift\_yaw = Q_{old}.Angle.x - Rs\_loop.Angle.x
轉換爲旋轉矩陣:
r_drift=(drift_yaw,0,0).Matrix3x3r\_drift = \left(drift\_yaw, 0, 0\right).Matrix_{3 x 3}
位移的漂移:
t_drift=Poldr_driftPs_loopt\_drift = P_{old} - r\_drift * Ps\_loop

r_drift  t_driftr\_drift \ \ t\_drift爲漂移量

深度信息直接使用優化後的深度信息。

代碼:

void VINS::new2old()
{
    Vector3d origin_R0 = Utility::R2ypr(Rs[0]);
    Vector3d origin_P0 = Ps[0];
    if (failure_occur)
    {
        origin_R0 = Utility::R2ypr(last_R_old);
        origin_P0 = last_P_old;
    }
    // 優化後的第0幀的相機位姿
    Vector3d origin_R00 = Utility::R2ypr(Quaterniond(para_Pose[0][6],
                                                     para_Pose[0][3],
                                                     para_Pose[0][4],
                                     para_Pose[0][5]).toRotationMatrix());

    // z軸轉動的角度
    double y_diff = origin_R0.x() - origin_R00.x();
    //TODO
    Matrix3d rot_diff = Utility::ypr2R(Vector3d(y_diff, 0, 0));

    for (int i = 0; i <= WINDOW_SIZE; i++)
    {
        Rs[i] = rot_diff * Quaterniond(para_Pose[i][6], para_Pose[i][3], para_Pose[i][4], para_Pose[i][5]).normalized().toRotationMatrix();
        Ps[i] = rot_diff * Vector3d(para_Pose[i][0] - para_Pose[0][0],
                                    para_Pose[i][1] - para_Pose[0][1],
                                    para_Pose[i][2] - para_Pose[0][2]) + origin_P0;
        Vs[i] = rot_diff * Vector3d(para_SpeedBias[i][0],
                                    para_SpeedBias[i][1],
                                    para_SpeedBias[i][2]);
        Bas[i] = Vector3d(para_SpeedBias[i][3],
                          para_SpeedBias[i][4],
                          para_SpeedBias[i][5]);

        Bgs[i] = Vector3d(para_SpeedBias[i][6],
                          para_SpeedBias[i][7],
                          para_SpeedBias[i][8]);
    }

    Vector3d cur_P0 = Ps[0];

    if (LOOP_CLOSURE && loop_enable)
    {       
        loop_enable = false;
        for (int i = 0; i< WINDOW_SIZE; i++)
        {
            if (front_pose.header == Headers[i])
            {
                Matrix3d Rs_loop = Quaterniond(front_pose.loop_pose[6], front_pose.loop_pose[3], front_pose.loop_pose[4], front_pose.loop_pose[5]).normalized().toRotationMatrix();
                Vector3d Ps_loop = Vector3d(front_pose.loop_pose[0], front_pose.loop_pose[1], front_pose.loop_pose[2]);

                Rs_loop = rot_diff * Rs_loop;
                Ps_loop = rot_diff * (Ps_loop - Vector3d(para_Pose[0][0], para_Pose[0][1], para_Pose[0][2])) + origin_P0;

                double drift_yaw = Utility::R2ypr(front_pose.Q_old.toRotationMatrix()).x() - Utility::R2ypr(Rs_loop).x();

                r_drift = Utility::ypr2R(Vector3d(drift_yaw, 0, 0));
            //r_drift = front_pose.Q_old.toRotationMatrix() * Rs_loop.transpose();
                t_drift = front_pose.P_old - r_drift * Ps_loop;
            }
        }
    }
    
    for (int i = 0; i < NUM_OF_CAM; i++)
    {
        tic = Vector3d(para_Ex_Pose[i][0],
                       para_Ex_Pose[i][1],
                       para_Ex_Pose[i][2]);
        ric = Quaterniond(para_Ex_Pose[i][6],
                          para_Ex_Pose[i][3],
                          para_Ex_Pose[i][4],
                          para_Ex_Pose[i][5]).toRotationMatrix();
    }

    VectorXd dep = f_manager.getDepthVector();
    for (int i = 0; i < f_manager.getFeatureCount(); i++)
    {
        dep(i) = para_Feature[i][0];
    }
    f_manager.setDepth(dep);
}

##四自由度優化

  • 四自由度優化必須在有迴環的條件下進行
  • 該優化不會使用到特徵點信息,只用到關鍵幀的位姿信息
  • 該優化的殘差主要是由迴環信息計算出
  • 該優化使用的關鍵幀位姿爲IMU積分通過劃窗優化得到的位姿
  • 該優化最終會重新給出一個漂移量 r_drift  t_driftr\_drift \ \ t\_drift
  • 該優化只會優化迴環內關鍵幀的位姿
  • old_KeyFrame的位姿固定

推理公式

該幀沒有迴環:
已知關鍵幀的位姿 Ri,  TiR_i, \ \ T_i 和與該關鍵幀相差5幀以內, 並在該關鍵幀之前 的某一關鍵幀位姿 Rij,  TijR_{i-j}, \ \ T_{i - j}

ConsAngleij=AngleijConsAngle_{i - j} = Angle_{i - j}
ΔT=Rij1(TiTij)\Delta T = {R_{i - j}}^{-1}\left(T_{i} - T_{i-j}\right)
ΔzAngle=Anglei.zAngleij.z\Delta zAngle = Angle_{i}.z - Angle_{i - j}.z
優化迭代過程: 默認只有z軸轉動
Rijw=(Angleij.z,ConsAngleij.y,ConsAngleij.z)R_{i - j}^w = \left(Angle_{i - j}.z, ConsAngle_{i - j}.y, ConsAngle_{i - j}.z\right)
ΔT=Rijw1(TijTi){\Delta T}&#x27; = {R_{i - j}^w}^{-1}\left(T_{i - j} - T_{i}\right)

最終計算出的殘差爲:
residuals4×1=[ΔTΔTAnglei.zAngleij.zΔzAngle]residuals_{4 \times 1} = \begin{bmatrix} {\Delta T}&#x27; - \Delta T \\ Angle_{i}.z - Angle_{i - j}.z - \Delta zAngle \end{bmatrix}

雅各比矩陣使用的自動求導方式獲得,ceres有自動求導的函數。
該過程中用到損失函數ceres::HuberLoss(1.0)
ρ(s)={ss&lt;=12s1s&gt;=1\rho\left(s\right) = \begin{cases} s \qquad \qquad s &lt;= 1 \\ 2\sqrt{s} - 1 \quad s &gt;= 1 \end{cases}
殘差經過損失函數作用 residuals4×1=ρ(residuals4×122)residuals4×1residuals_{4 \times 1} = \rho\left(\|residuals_{4 \times 1}\|_2^2\right)residuals_{4 \times 1}
以上j = {1, 2, 3, 4, 5}


該幀有迴環:
已知有 Rold,  Told,  Ri,  Ti,  relative_t,  relative_q,  relative_yawR_{old}, \ \ T_{old}, \ \ R_i, \ \ T_i, \ \ relative\_t, \ \ relative\_q, \ \ relative\_yaw
其中ΔT=relative_t,  ΔzAngle=relative_yaw\Delta T = relative\_t, \ \ \Delta zAngle = relative\_yaw
ConsAngleold=AngleoldConsAngle_{old} = Angle_{old}
使用同樣的方式計算出殘差,不同的是,計算出的殘差在位移上的殘差添加了一個係數10, 此做法應該是,優化的過程中,我們更應該關注迴環的殘差。
residuals4×1=[(ΔTΔT)10Anglei.zAngleij.zΔzAngle]residuals_{4 \times 1} = \begin{bmatrix} \left({\Delta T}&#x27; - \Delta T\right) * 10 \\ Angle_{i}.z - Angle_{i - j}.z - \Delta zAngle \end{bmatrix}

雅各比矩陣同樣使用的ceres的自動求導。

以上優化完之後,需要根據cur_KeyFrame, old_KeyFrame重新跟新漂移量 r_drift  t_driftr\_drift \ \ t\_drift

已知Rcur,  Tcur,  OriginRcur,  OriginTcurR_{cur}, \ \ T_{cur}, \ \ OriginR_{cur}, \ \ OriginT_{cur}, 其中Rcur,  TcurR_{cur}, \ \ T_{cur}爲優化後的位姿,OriginRcur,  OriginTcurOriginR_{cur}, \ \ OriginT_{cur}爲積分得到並經過劃窗優化的位姿
yaw_drift=Anglecur.zOriginAnglecur.zyaw\_drift = Angle_{cur}.z - OriginAngle_{cur}.z
r_drift=(yaw_drift,0,0).Matrix3x3r\_drift = \left(yaw\_drift, 0, 0\right).Matrix_{3 x 3}
t_drift=Tcurr_driftOriginTcurt\_drift = T_{cur} - r\_drift * OriginT_{cur}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章