VINS-Mono代码分析与总结 系统初始化

Posted buxiaoyi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VINS-Mono代码分析与总结 系统初始化相关的知识,希望对你有一定的参考价值。

VINS-Mono代码注释:https://github.com/gaochq/VINS-Mono/tree/comment
注释不完整,可以一起交流。

参考文献

1 VINS-Mono: A Robust and Versatile Monocular Visual-Inertial State Estimator, Tong Qin, Peiliang Li, Zhenfei Yang, Shaojie Shen (techincal report)
2 Solà J. Quaternion kinematics for the error-state KF[M]// Surface and Interface Analysis. 2015.
3 Solà J. Yang Z, Shen S. Monocular Visual–Inertial State Estimation With Online Initialization and Camera–IMU Extrinsic Calibration[J]. IEEE Transactions on Automation Science & Engineering, 2017, 14(1):39-51.
4 Engel J, Sch?ps T, Cremers D. LSD-SLAM: Large-scale direct monocular SLAM[C]//European Conference on Computer Vision. Springer, Cham, 2014:834-849.
5 Shen S, Michael N, Kumar V. Tightly-coupled monocular visual-inertial fusion for autonomous flight of rotorcraft MAVs[C]// IEEE International Conference on Robotics and Automation. IEEE, 2015:5303-5310.
6 Shen S, Mulgaonkar Y, Michael N, et al. Initialization-Free Monocular Visual-Inertial State Estimation with Application to Autonomous MAVs[M]// Experimental Robotics. Springer International Publishing, 2016.
7 Sibley G. A Sliding Window Filter for SLAM[J]. University of Southern California, 2006.
8 CamOdoCal: https://github.com/hengli/camodocal
****

3 系统初始化

??在提取的图像的Features和做完IMU的预积分之后,进入了系统的初始化环节,那么系统为什么要进行初始化呢,主要的目的有以下两个:

  • 系统使用单目相机,需要恢复尺度;
  • 要对IMU进行初始化,IMU会受到bias的影响,所以要得到IMU的bias(只估计了陀螺仪的Bias);
  • VIO的一些初始状态量未知。

所以我们要从初始化中恢复出尺度、重力、速度以及IMU的bias,因为视觉(SFM)在初始化的过程中有着较好的表现,所以在初始化的过程中主要以SFM为主,然后将IMU的预积分结果与其对齐,即可得到较好的初始化结果。
??系统的初始化主要包括三个环节:求取相机与IMU之间的相对旋转、相机初始化(局部滑窗内的SFM,包括没有尺度的BA)、IMU与视觉的对齐(IMU预积分中的 \(\alpha\)等和相机的translation)。

3.1 相机与IMU之间的相对旋转

??这个地方相当于求取相机与IMU的一部分外参。相机与IMU之间的旋转标定非常重要,偏差1-2°系统的精度就会变的极低。这部分的内容参考文献[3]中Ⅴ-A部分,这里做简单的总结。
??设相机利用对极关系得到的旋转矩阵为 \(R^{c_{k}}_{c_{k+1}}\),IMU经过预积分得到的旋转矩阵为\(R^{b_{k}}_{b_{k+1}}\),相机与IMU之间的相对旋转为 \(R^{b}_{c}\),则对于任一帧满足,
\[ R^{b_{k}}_{b_{k+1}}R^{b}_{c}=R^{b}_{c}R^{c_{k}}_{c_{k+1}} \tag{3.1} \]
对式(3.1)可以做简单的证明,在其两边同乘 \(^{c}x_{k+1}\)
\[ \begin{align}\nonumber R^{b_{k}}_{b_{k+1}}R^{b}_{c}{^{c}x_{k+1}}&=R^{b}_{c}R^{c_{k}}_{c_{k+1}}{^{c}x_{k+1}} \\\nonumber R^{b_{k}}_{b_{k+1}}{^{b}x_{k+1}}&=R^{b}_{c}{^{c}x_{k}} \\\nonumber ^{b}x_{k}&=^{b}x_{k} \end{align} \]
将旋转矩阵写为四元数,则式(3.1)可以写为
\[ q^{b_{k}}_{b{k+1}}\otimes q^{b}_{c}=q^{b}_{c}\otimes q^{c_{k}}_{c{k+1}} \]
将其写为左乘和右乘的形式,综合为
\[ [Q_{1}(q^{b_{k}}_{b{k+1}})-Q_{2}(q^{c_{k}}_{c{k+1}})]q^{b}_{c}=Q^{k}_{k+1}q^{b}_{c}=0 \tag{3.2} \]
其中 \(Q_{1}(q^{b_{k}}_{b{k+1}})\)\(Q_{2}(q^{c_{k}}_{c{k+1}})\) 分别表示四元数的左乘和右乘形式,
\[ \begin{align}\nonumber Q_{1}(q)&=\begin{bmatrix} q_{w}I_{3}+[q_{xyz }]_{\times} & q_{xyz}\\\nonumber -q_{xyz} & q_{w} \end{bmatrix} \Q_{2}(q)&=\begin{bmatrix} q_{w}I_{3}-[q_{xyz }]_{\times} & q_{xyz}\\\nonumber -q_{xyz} & q_{w} \end{bmatrix} \end{align} \tag{3.3} \]
这个地方因为四元数的实部在前在后的表达不一样,而左右乘的形式也不一样,所以文献[2]和文献[3]存在区别。Vins-Mono使用的是Eigen实部在后的表达方式。
那么对于 \(n\)对测量值,则有
\[ \begin{bmatrix} w^{0}_{1}Q^{0}_{1}\w^{1}_{2}Q^{1}_{2}\\vdots \w^{N-1}_{N}Q^{N-1}_{N} \end{bmatrix}q^{b}_{c}=Q_{N}q^{b}_{c}=0 \tag{3.4} \]
其中 \(w^{N-1}_{N}\) 为外点剔除权重,其与相对旋转求取得残差有关,\(N\)为最新的视觉帧的index,其由最终的终止条件决定。残差可以写为,
\[ r^{k}_{k+1}=acos((tr(\hat{R}^{b^{-1}}_{c}R^{b_{k}^{-1}}_{b_{k+1}}\hat{R}^{b}_{c}R^{c_{k}}_{c_{k+1}} )-1)/2) \tag{3.5} \]
残差还是很好理解的,在具体的代码中可以计算公式(3.1)两边两个旋转的得角度差。在得到残差之后就可以进一步得到公式(3.4)中的权重,
\[ w^{k}_{k+1}=\left\{\begin{matrix} 1,\qquad r^{k}_{k+1}<threshold\\frac{threshold}{r^{k}_{k+1}},\qquad otherwise \end{matrix}\right. \tag{3.6} \]
一般会将阈值 \(threshold\) 取做 \(5°\)。至此,就可以通过求解方程(3.4)得到相对旋转,式(3.4)的解为 \(Q_{N}\) 的左奇异向量中最小奇异值对应的特征向量。
??但是,在这里还要注意 求解的终止条件(校准完成的终止条件) 。在足够多的旋转运动中,我们可以很好的估计出相对旋转 \(R^{b}_{c}\),这时 \(Q_{N}\) 对应一个准确解,且其零空间的秩为1。但是在校准的过程中,某些轴向上可能存在退化运动(如匀速运动),这时 \(Q_{N}\) 的零空间的秩会大于1。判断条件就是 \(Q_{N}\) 的第二小的奇异值是否大于某个阈值,若大于则其零空间的秩为1,反之秩大于1,相对旋转\(R^{b}_{c}\) 的精度不够,校准不成功。

3.2 相机初始化

??这一阶段的思路就是单目相机的初始化过程,先求取本质矩阵求解位姿,进而三角化特征点,然后PnP求解位姿,不断重复的过程,直到恢复出滑窗内的Features和相机位姿,代码比较清晰。要注意的就是坐标系的和位姿的变换,容易混乱。如以下几个函数:
triangulateTwoFrames :输入是相机外参(世界到相机),求解出的3D点是在世界坐标系下。
cv::solvePnP:该API输入是世界坐标系的点,求解出的是世界坐标系到相机坐标系的变换,所以一般需要将结果转置。

3.3 视觉与IMU对齐

??视觉与IMU的对齐主要解决三个问题:
??(1) 修正陀螺仪的bias;
??(2) 初始化速度、重力向量 \(g\)和尺度因子(Metric scale);
??(3) 改进重力向量 \(g\)的量值;

3.3.1 陀螺仪Bias修正

??发现校正部分使用的都是一系列的约束条件,思路很重要啊。陀螺仪Bias校正的时候也是使用了一个简单的约束条件:
\[ \underset{\delta b_{w}}{min}\sum_{k\in B}^{ }\left \| q^{c_{0}^{-1}}_{b_{k+1}}\otimes q^{c_{0}}_{b_{k}}\otimes\gamma _{b_{k+1}}^{b_{k}} \right \|^{2} \tag{3.7} \]
其中
\[ \gamma _{b_{k+1}}^{b_{k}}\approx \hat{\gamma}_{b_{k+1}}^{b_{k}}\otimes \begin{bmatrix} 1\\frac{1}{2}J^{\gamma }_{b_{w}}\delta b_{w} \end{bmatrix} \tag{3.8} \]
公式(3.7)的最小值为单位四元数 \([1,0_{v}]^{T}\) ,所以将式(3.7)进一步写为,
\[ \begin{align}\nonumber q^{c_{0}^{-1}}_{b_{k+1}}\otimes q^{c_{0}}_{b_{k}}\otimes\gamma _{b_{k+1}}^{b_{k}}&=\begin{bmatrix} 1\0 \end{bmatrix} \\\nonumber \hat{\gamma}_{b_{k+1}}^{b_{k}}\otimes \begin{bmatrix} 1\\frac{1}{2}J^{\gamma }_{b_{w}}\delta b_{w} \end{bmatrix}&=q^{c_{0}^{-1}}_{b_{k}}\otimes q^{c_{0}}_{b_{k+1}} \\end{align} \]
\[ \begin{bmatrix} 1\\frac{1}{2}J^{\gamma }_{b_{w}}\delta b_{w} \end{bmatrix}=\hat{\gamma}_{b_{k+1}}^{b_{k}^{-1}}\otimes q^{c_{0}^{-1}}_{b_{k}}\otimes q^{c_{0}}_{b_{k+1}} \tag{3.9} \]
只取式(3.9)式虚部,在进行最小二乘求解
\[ J^{\gamma^{T}}_{b_{w}}J^{\gamma }_{b_{w}}\delta b_{w}=2*J^{\gamma^{T}}_{b_{w}}(\hat{\gamma}_{b_{k+1}}^{b_{k}^{-1}}\otimes q^{c_{0}^{-1}}_{b_{k}}\otimes q^{c_{0}}_{b_{k+1}}).vec \tag{3.10} \]
求解式(3.10)的最小二乘解,即可得到 \(\delta b_{w}\),注意这个地方得到的只是Bias的变化量,需要在滑窗内累加得到Bias的准确值。

3.3.2 初始化速度、重力向量 \(g\)和尺度因子

??在这个步骤中,要估计系统的速度、重力向量以及尺度因子。所以系统的状态量可以写为,
\[ X_{I}=[v^{c_{0}}_{b_{0}},v^{c_{0}}_{b_{1}},\cdots ,g^{c_{0}},s] \tag{3.11} \]
上面的状态量都是在 \(c_{0}\) 相机坐标系下。接着,有前面的由预积分部分,IMU的测量模型可知
\[ \begin{align}\nonumber \alpha^{b_{k}}_{b_{k+1}}&=q^{b_{k}}_{c_{0}}(s(\bar{p}^{c_{0}}_{b_{k+1}}-\bar{p}^{c_{0}}_{b_{k}})+\frac{1}{2}g^{c_{0}}\triangle t_{k}^{2}-v^{c_{0}}_{b_{k}}\triangle t_{k}^{2}) \\\nonumber \beta ^{b_{k}}_{b_{k+1}}&=q^{b_{k}}_{c_{0}}(v^{c_{0}}_{b_{k+1}}+g^{c_{0}}\triangle t_{k}-v^{c_{0}}_{b_{k}}) \end{align} \tag{3.12} \]
在3.1小节,我们已经得到了IMU相对于相机的旋转 \(q_{b}^{c}\),假设IMU到相机的平移量\(p_{b}^{c}\) 那么可以很容易地将相机坐标系下的位姿转换到IMU坐标系下,
\[ \begin{align}\nonumber q_{b_{k}}^{c_{0}} &= q^{c_{0}}_{c_{k}}\otimes q_{b}^{c} \\\nonumber s\bar{p}^{c_{0}}_{b_{k}}&=s\bar{p}^{c_{0}}_{c_{k}}+q^{c_{0}}_{c_{k}}p_{b}^{c} \end{align} \tag{3.13} \]
综合式(3.12)和式(3.13)可得,
\[ \begin{align}\nonumber \hat{z}^{b_{k}}_{b_{k+1}}&=\begin{bmatrix} \alpha^{b_{k}}_{b_{k+1}}-q^{c_{0}}_{c_{k+1}}p^{c}_{b}+q^{c_{0}}_{c_{k}}p^{c}_{b}&\\\nonumber \beta ^{b_{k}}_{b_{k+1}} \end{bmatrix}=H^{b_{k}}_{b_{k+1}}X_{I}+n^{b_{k}}_{b_{k+1}} \\\nonumber &\approx \begin{bmatrix} -q^{b_{k}}_{c_{0}}\triangle t_{k} &0& 1/2q^{b_{k}}_{c_{0}}\triangle t_{k}^{2} &q^{b_{k}}_{c_{0}}(\bar{p}^{c_{0}}_{b_{k+1}}-\bar{p}^{c_{0}}_{b_{k}}) \ -q^{b_{k}}_{c_{0}}& q^{b_{k}}_{c_{0}} &q^{b_{k}}_{c_{0}}\triangle t_{k} & 0 \end{bmatrix}\begin{bmatrix} v^{c_{0}}_{b_{k}}\v^{c_{0}}_{b_{k+!}}\g^{c_{0}}\s \end{bmatrix} \end{align} \tag{3.14} \]
这一步的推导也比较简单,以\(H\)矩阵的第一行,将式(3.13)的(2)式带入(3.12)的(1)式可得
\[ \begin{align} \nonumber \alpha^{b_{k}}_{b_{k+1}}&=q^{b_{k}}_{c_{0}}(s(\bar{p}^{c_{0}}_{c_{k+1}}-\bar{p}^{c_{0}}_{c_{k}}+(q_{c_{k+1}}^{c_{0}}-q_{c_{k}}^{c_{0}})p^{b}_{c}+\frac{1}{2}g^{c_{0}}\triangle t_{k}^{2}-v^{c_{0}}_{b_{k}}\triangle t_{k}^{2}) \\ \nonumber \alpha^{b_{k}}_{b_{k+1}}&-q^{b_{k}}_{c_{0}}(q_{c_{k+1}}^{c_{0}}-q_{c_{k}}^{c_{0}})p^{b}_{c}=q^{b_{k}}_{c_{0}}(s(\bar{p}^{c_{0}}_{c_{k+1}}-\bar{p}^{c_{0}}_{c_{k}}p^{b}_{c})+\frac{1}{2}g^{c_{0}}\triangle t_{k}^{2}-v^{c_{0}}_{b_{k}}\triangle t_{k}^{2}) \end{align} \]
但是不知道为什么论文,在做了近似之后漏了上式等式左边的\(q^{b_{k}}_{c_{0}}\)
最后求解最小二乘问题
\[ \underset{\delta b_{w}}{min}\sum_{k\in B}^{ }\left \| \hat{z}^{b_{k}}_{b_{k+1}}-H^{b_{k}}_{b_{k+1}}X_{I} \right \|^{2} \]
至此即可求解出所有状态量,但是对于重力向量 \(g^{c_{0}}\) 还要做进一步的纠正。在纠正\(g^{c_{0}}\) 的过程中,会对速度也做进一步的优化。

3.3.3 纠正重力向量

??这部分和上一小节的内容差不多,就是迭代不断更新重力向量的过程,要注意重力向量被表达为:
\[ \hat{g} = g\cdot \hat{\bar{g}} + \omega_{1}b_{1}+\omega_{2}b_{2} \]

以上是关于VINS-Mono代码分析与总结 系统初始化的主要内容,如果未能解决你的问题,请参考以下文章

VINS简介与代码结构

Linux内核设计第二周学习总结 完成一个简单的时间片轮转多道程序内核代码

Linux内核分析—完成一个简单的时间片轮转多道程序内核代码

linux内核分析作业:操作系统是如何工作的进行:完成一个简单的时间片轮转多道程序内核代码

嵌入式开发裸机引导操作系统和ARM 内存操作 ( DRAM SRAM 类型 简介 | Logical Bank | 内存地址空间介绍 | 内存芯片连接方式 | 内存初始化 | 汇编代码示例 )(代码片

SD卡在SPI模式下的初始化和详细的代码分析