1 前言
学习了一段时间的基于滤波的slam,其中参考了多位大神的博客,相关的博客链接也会放到文章的最下方,从中学习到很多,为此以larvio为例子总结一下滤波slam,文章较长,还请耐心看完。有些地方可能理解得还不是很到位,如有错误请指出交流。
2 LARVIO算法概述
LARVIO全称为Lightweight Accurate Robust Visual Inertial Odometry,本质上是一个基于Hybrid MSCKF的单目视觉惯性里程计。除了是一个Hybrid MSCKF之外,它还具备以下几个主要的功能:
适用于动态或静态的自动初始化
在线传感器参数标定
零速矫正
Hybrid MSCKF是将观测时间比较长的特征点增广到状态向量中,克服了MSCKF对于跟踪长度超过滑窗长度的地图点长时间约束的浪费问题。在Mingyang Li的最早版本中,都使用了3维(3D逆深度或3D世界坐标)的方式来对增广地图点状态进行参数化。一般也称它为Hybrid VIO或Hybrid EKF,最早是由Mingyang Li大佬提出的。同时,MSCKF是一个基于EKF的经典VIO方案。因此LARVIO本质上就是EKF,需要先弄清楚什么EKF,进而理解MSCKF。
MSCKF全称Multi-State Constraint Kalman Filter(多状态约束下的Kalman滤波器),是一种滤波VIO。其目标是解决EKF-SLAM中维数爆炸问题,传统EKF-SLAM将特征点加入到状态向量中与IMU状态一起估计,当环境很大时,特征点会非常多,状态向量维数会变得非常大。MSCKF不是将特征点加入到状态向量,而是将不同时刻的相机位姿加入到状态向量中,并利用多个时刻相机共视形成的几何约束(Constraint)构建观测模型对状态进行更新。更进一步,为了控制状态规模,纯MSCKF仅维持固定数目的相机位姿,使用滑动窗口的方式来限制后端的计算量。而Hybrid MSCKF方案则还将观测时间较长的特征点加入状态向量,以提高定位精度。
2.1 IMU状态向量与INS
由于MSCKF本质就是一个EKF,所以介绍MSCKF之前,我们先介绍一下INS(Inertial Navigation System)中的IMU状态EKF估计,INS中IMU的状态向量为 X I M U = [ G I q T b g T G v I T b a T G p I T ] X_{IMU}=\begin{bmatrix}_{G}^{I}q^T & b_g^T & _{}^{G}v_I^T & b_a^T & ^{G}p_I^T\end{bmatrix} XIMU=[GIqTbgTGvITbaTGpIT]其中
- G I q T _{G}^{I}q^T GIqT为单位四元数,表示从世界系( G系)到IMU坐标系( I系)的旋转
- b g T b_g^T bgT为加速度计accelerator的bias
- $_{}{G}v_IT $为IMU在G系下的速度
- b a T b_a^T baT为陀螺仪gyroscope的bias
- G p I T ^{G}p_I^T GpIT为IMU在G系下的位置
INS的EKF步骤为:
-
EKF预测:先利用传感器获得的观测加速度和观测角速度,可以对状态进行估计,显然,该步骤会使得估计的不确定度/协方差越来越大
-
EKF更新:然后利用GPS观测构建观测模型,对状态向量的均值和协方差进行更新, 修正预测过程的累积误差,减少不确定度。
2.2 MSCKF中的观测模型
对于MSCKF来说,EKF预测步骤与INS一样,区别在EKF观测更新,需要用视觉信息来构建观测模型,从而对IMU预测的状态进行更新。INS中GPS可以直接给出位置的观测,而视觉通常只能提供多个相机之间相对位姿关系的约束。利用特征点到相机的重投影误差(空间中一个3D特征点根据相机的姿态和位置投影到相机平面,与实际观测的特征点之间的误差)来进行约束:
误差=实际观测到的特征点2D坐标 - 估计的3D点坐标投影到图像上的2D坐标
用这个重投影误差的约束等式来作为观测模型,但前提是需要知道特征点的3D坐标,而实际应用中特征点的3D坐标是未知的。
- EKF-SLAM的做法是将特征点加入到状态向量进行估计,但它的状态向量会随特征点的增多而变得非常大。
- MSCKF的做法是根据历史相机位姿和观测来三角化计算特征点的3D坐标。这又带来了一个问题:如何确保三角化的精度呢?如果三角化误差太大,那么观测模型就会不准,最终会使得VIO精度太差。MSCKF做法是当特征点跟踪丢失后再进行三角化,特征点跟丢表示该特征的观测不会再继续增加了,这时利用所有的历史观测三角化。所以MSCKF中观测更新的时机是特征点跟丢。
2.3 MSCKF算法步骤
MSCKF算法步骤如下:
- IMU积分:先利用IMU加速度和角速度对状态向量中的IMU状态进行预测,一般会处理多帧IMU观测数据。
- 相机状态扩增:每来一张图片后,计算当前相机状态并加入到状态向量中, 同时扩充状态协方差.
- 特征点三角化:然后根据历史相机状态三角化估计3D特征点
- 特征更新:再利用特征点对多个历史相机状态的约束,来更新状态向量。注意:这里不只修正历史相机状态,因为历史相机状态和IMU状态直接也存在关系(相机与IMU的外参),所以也会同时修正IMU状态。
- 历史相机状态移除:如果相机状态个数超过N,则剔除最老或最近的相机状态以及对应的协方差.
MSCKF状态propagation和update的流程如下图所示:
图中X表示状态向量, P表示对应的协方差矩阵,红色表示当前步骤发生改变的量。
- 首先初始化状态向量和协方差
- 然后进行IMU积分,状态向量和协方差都发生改变
- 接着将新的相机状态加入到状态向量中,扩充协方差矩阵(新相机自身的协方差以及对 X I M U X_{IMU} XIMU的协方差)
- 进行观测更新,所有状态和协方差都会发生改变。(注意:第一次因为只有一个相机状态,形成不了重投影约束,所以第一次观测更新并不会做任何事情)
- 当相机状态个数超过限制时,删除最历史的一个相机状态及其对应的协方差项。
- 重复2-5。
2.4 LARVIO算法流程
除了2.3中MSCKF的操作之外LARVIO还有以下几个部分:
- 视觉前端:Good Feature+金字塔光流跟踪+利用ORB描述子对光流跟踪结果进行筛选
- 自动初始化:同时针对静止和动态的情况进行初始化。静止初始化与MSCKF_VIO相似,但可以自动选取静止的数据进行初始化,而不需要保证数据静止。动态初始化则是直接采用了VINS-MONO的方法。
- 传感器参数在线标定:包括相机和IMU相对外参、相机和IMU时间戳误差以及IMU内参标定。外参标定是采用了MSCKF2.0中的方法,时间戳误差标定采用了VINS-MONO的方法。IMU内参标定则参考了kalibr中提供的方法。
- 零速矫正:基于微惯性的行人导航的一个常规操作,其目的是利用脚落地的一瞬间的静止来抑制IMU积分结果的漂移。当载体静止时间太长时,会导致滤波器的漂移。ZUPT采用了一种closed-form的测量更新方式——在检测到静止时停止常规的测量更新,而是采用ZUPT约束进行测量更新。LARVIO采用的ZUPT约束包括三项:a.当前速度为零 b.静止的两帧间相对位置不变 c.静止的两帧间相对姿态不变
具体的算法流程如下图所示:
1.视觉前端光流跟踪:采用Good Feature+金字塔光流跟踪,经过一系列的过滤操作(imu预测、反向光流、ORB描述子过滤、F矩阵RANSAC过滤)筛选出合适的特征。
2.自动初始化:同时针对静止和动态的情况进行初始化。静止初始化与MSCKF_VIO相似,但可以自动选取静止的数据进行初始化,而不需要保证数据静止。动态初始化则是直接采用了VINS-MONO的方法。
3.INS和协方差传播:先利用IMU加速度和角速度对状态向量中的IMU状态进行预测,一般会处理多帧IMU观测数据,估计新的状态向量和对应的协方差矩阵。
4.状态增广:每来一张图片后,计算当前相机状态并加入到状态向量中, 同时扩充状态协方差矩阵。
5.测量更新:根据静态场景的检测结果,在静态场景下采用ZUPT零速矫正进行测量更新,在动态场景下基于特征的测量更新,更新MSCKF特征残差、旧的和新的增广特征残差,其中新的增广特征采用的是一维逆深度参数化的方法。
3 LARVIO算法原理
在传统的EKF-SLAM框架中,特征点的信息会加入到特征向量和协方差矩阵里,其缺点是特征点的信息会给一个初始深度和初始协方差,如果不正确的话,极容易导致后面不收敛,出现inconsistent的情况。MSCKF会通过一个滑动窗口来维护一定数量的pose,如果一个特征点被滑动窗口中几个位姿观察到的话,就会在这几个位姿间建立约束,从而进行KF的更新。如下图所示, 左边代表的是传统EKF SLAM,红色五角星是old feature,这个也是保存在状态向量中的,另外状态向量中只保存最新的相机姿态;中间这张可以表示的是keyframe-based SLAM,它会保存稀疏的关键帧和它们之间相关联的地图点; 最右边这张则可以代表MSCKF的一个基本结构,MSCKF中老的地图点和滑窗之外的相机姿态是被丢弃的,它只存了滑窗内部的相机姿态和它们共享的地图点。
3.1 视觉前端光流跟踪
VIO算法的核心在后端,不管是优化的方法还是滤波的方法,都是靠后端的紧耦合融合获得较高的VIO精度,为了节省计算量一般前端都会做得很简单,基本都是FAST、Harris等角点加LK光流跟踪,而LARVIO则是采用goodFeatureToTrack+LK光流跟踪。
3.1.1 构建金字塔图像
调用opencv中的buildOpticalFlowPyramid创建金字塔图像。
3.1.2 前后帧跟踪
对上一帧图像的特征点,在当前帧图像进行跟踪,获得当前帧图像的跟踪特征点。
1.IMU旋转估计
收集前后两帧之间所有的IMU数据,计算平均角速度 ,通过外参转到相机系,并根据角速度、时间和Rodrigues公式计算出相对旋转。
w
ˉ
i
m
u
=
1
N
∑
j
=
1
N
w
j
\bar{w}_{imu}=\frac{1}{N} {\textstyle \sum_{j=1}^{N}}w_j
wˉimu=N1∑j=1Nwj
w
c
a
m
=
i
m
u
c
a
m
R
w
ˉ
i
m
u
{w}_{cam}= ^{cam}_{imu}R\bar{w}_{imu}
wcam=imucamRwˉimu
δ
R
c
a
m
=
w
c
a
m
δ
t
\delta R_{cam}={w}_{cam}\delta t
δRcam=wcamδt
2.特征点预测
对于前一帧特征点 p p p_p pp,投影到后一帧为 s p c = K ⋅ ( δ R ⋅ d ⋅ K − 1 ⋅ p p + δ t ) sp_c=K\cdot (\delta R\cdot d\cdot K^{-1}\cdot p_p+\delta t) spc=K⋅(δR⋅d⋅K−1⋅pp+δt)其中s为尺度,d为特征点的深度, δ t \delta t δt为时间,这里假设d=1, δ t = 0 \delta t =0 δt=0,这样相当于将所有的特征点都归一化到深度为1的平面,因此可以直接计算Homogrphy,即: H = K ⋅ δ R ⋅ K − 1 H=K\cdot\delta R \cdot K^{-1} H=K⋅δR⋅K−1从而可以得到投影公式简化为: s p c = H p p sp_c=Hp_p spc=Hpp虽然这样假设会存在误差,但这只是对特征点的初始位置的预测,提供一个先验信息,后面还会通过LK光流对位置进行refine。
3.LK光流跟踪
调用opencv中的calcOpticalFlowPyrLK进行跟踪。
3.1.3 筛选过滤
- 将图像区域外的跟踪点剔除
- 使用反向光流跟踪剔除外点
- 利用ORB描述子剔除距离大于58的外点
- 采用F矩阵进行RANSAC过滤外点
3.2 IMU自动初始化
IMU初始化的目的是:
-
有助于提高该紧耦合系统鲁棒性,有助于状态估计更快收敛(由于imu加速度值通常不准,对速度很敏感的应用场景,在系统融合前估计出较准的速度也很重要)
-
为后续预积分(用到 g w g^w gw,需要重力对齐)计算铺垫(重新预积分)
LARVIO中提供了自动的初始化方法,且同时能够针对载体静止和动态的情况。
静止初始化与MSCKF_VIO中的类似,但改进之处在于可以自动选取静止的数据进行初始化,无需像前者那样必须保证初始阶段的数据静止。静止的检测利用了基于图像的方法,但比较偏经验性,还需进一步改进。动态初始化则照搬了VINS-MONO的方法。
两种初始化进行了一个简单的逻辑封装,使得LARVIO能够在任意条件满足时立刻初始化。
3.2.1 imu静态初始化
静态初始化主要是想获取imu在起始阶段的朝向,不希望会由于起始角的偏差与地面不对齐。
1.计算陀螺仪bias:
静止时刻的陀螺仪理想测量值(角速度)应该为0,因此陀螺仪的bias即检测到静止状态下陀螺仪数据的平均值:
b
g
=
1
n
∑
1
n
w
m
b_g=\frac{1}{n} \sum_{1}^{n} w_m
bg=n11∑nwm
2.计算加速度计bias:
静止时的加速度计bias为加速度平均值与实际重力加速度的差:
b
a
=
1
n
∑
1
n
a
m
−
R
g
b_a=\frac{1}{n} \sum_{1}^{n} a_m-Rg
ba=n11∑nam−Rgg为世界系下的重力加速度,R为世界系到imu系的旋转矩阵,将重力矢量从世界系投影到imu坐标系下。
3.2.2 imu动态初始化
主要流程:
- 估计旋转外参
- 利用SfM确定各个pose和特征点的相对于 c 0 c_0 c0帧的位置关系
- 利用相机旋转约束标定IMU角速度bias
- 利用IMU的平移估计重力/各bk帧速度/尺度scaler
- 利用gw的模长已知这个先验条件进一步优化gc0
- 利用gc0和gw确定世界坐标系
1.估计旋转外参
根据IMU和视觉部分的旋转关系,可以得到下面的关系式: R c k + 1 b k = R b k + 1 b k ⋅ R c b = R c b ⋅ R c k + 1 c k R_{c_{k+1}}^{b_k}=R_{b_{k+1}}^{b_k}\cdot R_c^b=R_c^b\cdot R_{c_{k+1}}^{c_k} Rck+1bk=Rbk+1bk⋅Rcb=Rcb⋅Rck+1ck q b k + 1 b k ⋅ q c b = q c b ⋅ q c k + 1 c k q_{b_{k+1}}^{b_k}\cdot q_c^b=q_c^b\cdot q_{c_{k+1}}^{c_k} qbk+1bk⋅qcb=qcb⋅qck+1ck [ Q 1 ( q b k + 1 b k ) − Q 2 ( q c k + 1 c k ) ] ⋅ q c b = Q c b ⋅ q c b = 0 [Q_1(q_{b_{k+1}}^{b_k})-Q_2(q_{c_{k+1}}^{c_k})]\cdot q_c^b=Q_c^b\cdot q_c^b=0 [Q1(qbk+1bk)−Q2(qck+1ck)]⋅qcb=Qcb⋅qcb=0将多个帧之间的等式关系一起构建超定方程Ax=0。对A进行svd分解,其中最小奇异值对应的奇异向量便为需要求解的 q c b q_c^b qcb。虽然这里IMU的旋转部分并没有标定,得到的外参数可能不太准。但由于初始化所占用的总运行时间不长,而更长生命周期的后端会持续的优化这部分的值。
2.利用SfM确定各个pose和特征点的相对于 c 0 c_0 c0帧的位置关系
这一部分和基于图像的三维重建比较像,可以用三角化和PnP所有 c k c_k ck帧的位姿和特征点位置确定下来(特征点是伪深度),再通过外参数 q c b q_c^b qcb和 p c b p_c^b pcb,将 b k b_k bk帧的位姿也确定下来。注意,这里把 c 0 c_0 c0帧作为基础帧,实际上, c 0 c_0 c0帧旋转一下使 g c 0 g_{c_0} gc0和 g w g_w gw方向一致时获得的坐标系就是larvio的世界坐标系,也就是先验。
首先我们先推导论文[1]中式(14),所有帧的位姿
(
R
c
k
c
0
,
p
c
k
c
0
)
(R^{c_0}_{c_k},p^{c_0}_{c_k})
(Rckc0,pckc0)表示相对于第一帧相机坐标系(·)c0。相机到IMU的外参为
(
R
c
b
,
p
c
b
)
(R_c^b, p_c^b)
(Rcb,pcb),得到姿态从相机坐标系转换到IMU坐标系的关系。
T
c
k
c
0
=
T
b
k
c
0
⋅
T
c
b
T^{c_0}_{c_k}=T^{c_0}_{b_k}\cdot T_c^b
Tckc0=Tbkc0⋅Tcb将T展开成R与p有:
[
R
c
k
c
0
s
p
c
k
c
0
0
1
]
=
[
R
b
k
c
0
s
p
b
k
c
0
0
1
]
[
R
c
b
p
c
b
0
1
]
=
[
R
b
k
c
0
R
c
b
R
b
k
c
0
p
c
b
+
s
p
b
k
c
0
0
1
]
\begin{bmatrix} R^{c_0}_{c_k} & sp^{c_0}_{c_k} \\ 0 & 1\end{bmatrix}=\begin{bmatrix} R^{c_0}_{b_k} & sp^{c_0}_{b_k} \\ 0 & 1\end{bmatrix}\begin{bmatrix} R_c^b & p_c^b \\ 0 & 1\end{bmatrix}=\begin{bmatrix} R^{c_0}_{b_k}R_c^b & R^{c_0}_{b_k}p_c^b+sp^{c_0}_{b_k} \\ 0 & 1\end{bmatrix}
[Rckc00spckc01]=[Rbkc00spbkc01][Rcb0pcb1]=[Rbkc0Rcb0Rbkc0pcb+spbkc01]
根据上式可得:
R
c
k
c
0
=
R
b
k
c
0
R
c
b
⇒
R
b
k
c
0
=
R
c
k
c
0
(
R
c
b
)
−
1
R^{c_0}_{c_k}=R^{c_0}_{b_k}R_c^b\Rightarrow R^{c_0}_{b_k}=R^{c_0}_{c_k}(R_c^b)^{-1}
Rckc0=Rbkc0Rcb⇒Rbkc0=Rckc0(Rcb)−1
s
p
c
k
c
0
=
R
b
k
c
0
R
c
b
+
s
p
b
k
c
0
⇒
s
p
b
k
c
0
=
s
p
c
k
c
0
−
R
b
k
c
0
p
c
b
sp^{c_0}_{c_k} =R^{c_0}_{b_k}R_c^b+sp^{c_0}_{b_k}\Rightarrow sp^{c_0}_{b_k} =sp^{c_0}_{c_k}-R^{c_0}_{b_k}p_c^b
spckc0=Rbkc0Rcb+spbkc0⇒spbkc0=spckc0−Rbkc0pcb
3.利用相机旋转约束标定IMU角速度bias
求解的目标函数如下公式所示:
在完成SfM和外参数标定后,
q
b
k
+
1
c
0
−
1
{q_{b_{k+1}}^{c_0}}^{-1}
qbk+1c0−1和
q
b
k
c
0
q_{b_{k}}^{c_0}
qbkc0是已知的了,而且我们假设头两个值是准的。理想状态下,这三个数乘积应该是单位四元数,很可惜,第三个值是IMU预积分得到的,而预积分里面是有bias的。所以,通过最小化这个目标函数的,可以把旋转bias标定出来!
在IMU预积分部分,也就是论文[1]中公式(12),有
γ
b
k
+
1
b
k
=
γ
^
b
k
+
1
b
k
⊗
[
1
1
2
J
b
w
γ
δ
b
w
k
]
\gamma_{b_{k+1}}^{b_k} = \hat{\gamma}_{b_{k+1}}^{b_k} \otimes \begin{bmatrix}1\\\frac{1}{2} J_{b_w}^\gamma \delta b_{w_k}\end{bmatrix}
γbk+1bk=γ^bk+1bk⊗[121Jbwγδbwk]代入到损失函数里,可以得到:
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}=\begin{bmatrix}1\\0\end{bmatrix}
qbk+1c0−1⊗qbkc0⊗γ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 \begin{bmatrix}1\\0\end{bmatrix}
γbk+1bk=qbkc0−1⊗qbk+1c0⊗[10]代入bias的残差后,得到:
γ
^
b
k
+
1
b
k
⊗
[
1
1
2
J
b
w
γ
δ
b
w
k
]
=
q
b
k
c
0
−
1
⊗
q
b
k
+
1
c
0
⊗
[
1
0
]
\hat{\gamma}_{b_{k+1}}^{b_k} \otimes \begin{bmatrix}1\\\frac{1}{2} J_{b_w}^\gamma \delta b_{w_k}\end{bmatrix}={q_{b_{k}}^{c_0}}^{-1} \otimes q_{b_{k+1}}^{c_0} \otimes \begin{bmatrix}1\\0\end{bmatrix}
γ^bk+1bk⊗[121Jbwγδbwk]=qbkc0−1⊗qbk+1c0⊗[10]由于实部没有需要标定的量,所以只用考虑虚部,也就是:
J
b
w
γ
δ
b
w
k
=
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_k}=2({\hat{\gamma}_{b_{k+1}}^{b_k}}^{-1} \otimes {q_{b_{k}}^{c_0}}^{-1} \otimes q_{b_{k+1}}^{c_0})_{vec}
Jbwγδbwk=2(γ^bk+1bk−1⊗qbkc0−1⊗qbk+1c0)vec两侧再乘以
J
b
w
γ
T
{J_{b_w}^\gamma}^{T}
JbwγT,可以构造出Ax=B的形式,再采用LDLT分解,就可以求出状态量
δ
b
w
\delta b_w
δbw:
J
b
w
γ
T
J
b
w
γ
δ
b
w
k
=
2
J
b
g
w
γ
T
(
γ
^
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}^{T}J_{b_w}^\gamma \delta b_{w_k}=2{J_{b_gw}^\gamma}^{T}({\hat{\gamma}_{b_{k+1}}^{b_k}}^{-1} \otimes {q_{b_{k}}^{c_0}}^{-1} \otimes q_{b_{k+1}}^{c_0})_{vec}
JbwγTJbwγδbwk=2JbgwγT(γ^bk+1bk−1⊗qbkc0−1⊗qbk+1c0)vec
4.利用IMU的平移估计重力/各 b k b_k bk帧速度/尺度scale
首先要明确需要优化的状态量是什么,是各帧在
b
k
b_k
bk坐标系下的速度,
c
0
c_0
c0帧下的g和SfM的尺度scale:
在IMU预积分部分,已经有如下的公式:
但是
w
w
w坐标系不知道,只知道
c
0
c_0
c0坐标系,所以需要把上面的公式转到
c
0
c_0
c0坐标系上:
α
b
k
+
1
b
k
=
R
c
0
b
k
(
s
p
b
k
+
1
c
0
−
s
p
b
k
c
0
+
1
2
g
c
0
Δ
t
k
2
−
R
b
k
c
0
v
b
k
b
k
Δ
t
k
)
\alpha_{b_{k+1}}^{b_{k}}=R_{c_{0}}^{b_{k}}(s p_{b_{k+1}}^{c_{0}}-s p_{b_{k}}^{c_{0}}+\frac{1}{2}g^{c_{0}}\Delta t_{k}^{2}-R_{b_{k}}^{c_{0}}v_{b_{k}}^{b_{k}}\Delta t_{k})
αbk+1bk=Rc0bk(spbk+1c0−spbkc0+21gc0Δtk2−Rbkc0vbkbkΔtk)
β
b
k
+
1
b
k
=
R
c
0
b
k
(
R
b
k
+
1
c
0
v
b
k
+
1
b
k
+
1
+
g
c
0
Δ
t
k
−
R
b
k
c
0
v
b
k
b
k
)
\beta_{b k+1}^{b_{k}}=R_{c0}^{b_{k}}(R_{b_{k+1}}^{c_{0}}v_{b_{k+1}}^{b_{k+1}}+g^{c_{0}}\Delta t_{k}-R_{b_{k}}^{c_{0}}v_{b_{k}}^{b_{k}})
βbk+1bk=Rc0bk(Rbk+1c0vbk+1bk+1+gc0Δtk−Rbkc0vbkbk)
上式中,等号左边减去等号右边就是残差,理想状态下,这个残差是0,那么带入上式得:
δ
α
b
k
+
1
b
k
=
α
b
k
+
1
b
k
−
R
c
0
b
k
(
s
p
b
k
+
1
c
0
−
s
p
b
k
c
0
+
1
2
g
c
0
Δ
t
k
2
−
R
b
k
c
0
v
b
k
b
k
Δ
t
k
)
=
α
b
k
+
1
b
k
−
R
c
0
b
k
(
s
p
c
k
+
1
c
0
−
R
b
k
+
1
c
0
p
c
b
−
(
s
p
c
k
c
0
−
R
b
k
c
0
p
c
b
)
+
1
2
g
c
0
Δ
t
k
2
−
R
b
k
c
0
v
b
k
b
k
Δ
t
k
)
=
α
b
k
+
1
b
k
−
R
c
0
b
k
s
(
p
c
k
+
1
c
0
−
p
c
k
c
0
)
+
R
c
0
b
k
R
b
k
+
1
c
0
p
c
b
−
p
c
b
+
v
b
k
b
k
Δ
t
k
−
1
2
R
c
0
b
k
g
c
0
Δ
t
k
2
=
0
3
×
1
\begin{array}{c}\delta \alpha_{b_{k+1}}^{b_{k}}=\alpha_{b_{k+1}}^{b_{k}}-R_{c_{0}}^{b_{k}}\left(s p_{b_{k+1}}^{c_{0}}-s p_{b_{k}}^{c_{0}}+\frac{1}{2} g^{c_{0}} \Delta t_{k}^{2}-R_{b_{k}}^{c_{0}} v_{b_{k}}^{b_{k}} \Delta t_{k}\right) \\ =\alpha_{b_{k+1}}^{b_{k}}-R_{c_{0}}^{b_{k}}\left(s p_{c_{k+1}}^{c_{0}}-R_{b_{k+1}}^{c_{0}} p_{c}^{b}-\left(s p_{c_{k}}^{c_{0}}-R_{b_{k}}^{c_{0}} p_{c}^{b}\right)+\frac{1}{2} g^{c_{0}} \Delta t_{k}^{2}-R_{b_{k}}^{c_{0}} v_{b_{k}}^{b_{k}} \Delta t_{k}\right) \\ =\alpha_{b_{k+1}}^{b_{k}}-R_{c_{0}}^{b_{k}} s\left(p_{c_{k+1}}^{c_{0}}-p_{c_{k}}^{c_{0}}\right)+R_{c_{0}}^{b_{k}} R_{b_{k+1}}^{c_{0}} p_{c}^{b}-p_{c}^{b}+v_{b_{k}}^{b_{k}} \Delta t_{k}-\frac{1}{2} R_{c_{0}}^{b_{k}} g^{c_{0}} \Delta t_{k}^{2}=0_{3 \times 1}\end{array}
δαbk+1bk=αbk+1bk−Rc0bk(spbk+1c0−spbkc0+21gc0Δtk2−Rbkc0vbkbkΔtk)=αbk+1bk−Rc0bk(spck+1c0−Rbk+1c0pcb−(spckc0−Rbkc0pcb)+21gc0Δtk2−Rbkc0vbkbkΔtk)=αbk+1bk−Rc0bks(pck+1c0−pckc0)+Rc0bkRbk+1c0pcb−pcb+vbkbkΔtk−21Rc0bkgc0Δtk2=03×1
把这个 XX = 0的等式也转为 A x = b这种线性方程组的形式,如下式:
R
c
0
b
k
(
p
c
k
+
1
c
0
−
p
c
k
c
0
)
s
−
v
b
k
b
k
Δ
t
k
+
1
2
R
c
0
b
k
Δ
t
k
2
g
c
0
=
α
b
k
+
1
b
k
+
R
c
0
b
k
R
b
k
+
1
c
0
p
c
b
−
p
c
b
R_{c_{0}}^{b_{k}}\left(p_{c k+1}^{c_{0}}-p_{c_{k}}^{c_{0}}\right) s-v_{b_{k}}^{b_{k}} \Delta t_{k}+\frac{1}{2} R_{c_{0}}^{b_{k}} \Delta t_{k}^{2} g^{c_{0}}=\alpha_{b_{k+1}}^{b_{k}}+R_{c_{0}}^{b_{k}} R_{b_{k+1}}^{c_{0}} p_{c}^{b}-p_{c}^{b}
Rc0bk(pck+1c0−pckc0)s−vbkbkΔtk+21Rc0bkΔtk2gc0=αbk+1bk+Rc0bkRbk+1c0pcb−pcb
或者矩阵的形式:
[
−
I
Δ
t
k
0
1
2
R
c
0
b
k
Δ
t
k
2
R
c
0
b
k
(
p
c
k
+
1
c
0
−
p
c
k
c
0
)
]
[
v
b
k
b
k
v
b
k
+
1
b
k
+
1
g
c
0
s
]
=
α
b
k
+
1
b
k
+
R
c
0
b
k
R
b
k
+
1
c
0
p
c
b
−
p
c
b
\begin{bmatrix} -I\Delta t_k & 0 & \frac{1}{2}R_{c_{0}}^{b_{k}}\Delta t_k^2 & R_{c_{0}}^{b_{k}}(p_{c_{k+1}}^{c_{0}} - p_{c_{k}}^{c_{0}}) \end{bmatrix} \begin{bmatrix} v_{b_{k}}^{b_{k}}\\ v_{b_{k+1}}^{b_{k+1}}\\ g^{c_0}\\ s\end{bmatrix} =\alpha_{b_{k+1}}^{b_{k}}+R_{c_{0}}^{b_{k}} R_{b_{k+1}}^{c_{0}} p_{c}^{b}-p_{c}^{b}
[−IΔtk021Rc0bkΔtk2Rc0bk(pck+1c0−pckc0)]
vbkbkvbk+1bk+1gc0s
=αbk+1bk+Rc0bkRbk+1c0pcb−pcb
对于beta而言,也是类似的:
δ
β
b
k
+
1
b
k
=
β
b
k
+
1
b
k
−
R
c
0
b
k
(
R
b
k
+
1
c
0
v
b
k
+
1
b
k
+
1
+
g
c
0
Δ
t
k
−
R
b
k
c
0
v
b
k
b
k
)
=
0
3
×
1
\delta \beta_{b_{k+1}}^{b_{k}}=\beta_{b_{k+1}}^{b_{k}}-R_{c_{0}}^{b_{k}}\left(R_{b_{k+1}}^{c_{0}} v_{b_{k+1}}^{b_{k+1}}+g^{c_{0}} \Delta t_{k}-R_{b_{k}}^{c_{0}} v_{b_{k}}^{b_{k}}\right)=0_{3 \times 1}
δβbk+1bk=βbk+1bk−Rc0bk(Rbk+1c0vbk+1bk+1+gc0Δtk−Rbkc0vbkbk)=03×1
R
c
0
b
k
R
b
k
+
1
c
0
v
b
k
+
1
b
k
+
1
−
R
c
0
b
k
Δ
t
k
g
c
0
+
R
c
0
b
k
R
b
k
c
0
v
b
k
b
k
=
β
b
k
+
1
b
k
R_{c_{0}}^{b_{k}} R_{b_{k+1}}^{c_{0}} v_{b_{k+1}}^{b_{k+1}}-R_{c_{0}}^{b_{k}} \Delta t_{k} g^{c_{0}}+R_{c_{0}}^{b_{k}} R_{b_{k}}^{c_{0}} v_{b_{k}}^{b_{k}}=\beta_{b_{k+1}}^{b_{k}} \\
Rc0bkRbk+1c0vbk+1bk+1−Rc0bkΔtkgc0+Rc0bkRbkc0vbkbk=βbk+1bk
[
−
I
R
c
0
b
k
R
b
k
+
1
c
0
R
c
0
b
k
Δ
t
k
0
]
[
v
b
k
b
k
v
b
k
+
1
b
k
+
1
g
c
0
s
]
=
β
b
k
+
1
b
k
{\left[\begin{array}{llll}-I & R_{c_{0}}^{b_{k}} R_{b_{k+1}}^{c_{0}} & R_{c_{0}}^{b_{k}} \Delta t_{k} & 0\end{array}\right]\left[\begin{array}{c}v_{b_{k}}^{b_{k}} \\ v_{b k+1}^{b_{k+1}} \\ g^{c_{0}} \\ s\end{array}\right]=\beta_{b_{k+1}}^{b_{k}}}
[−IRc0bkRbk+1c0Rc0bkΔtk0]
vbkbkvbk+1bk+1gc0s
=βbk+1bk
那么,把这两个矩阵合体,就能得到论文[1]中的等式(18):
[
−
I
Δ
t
k
0
1
2
R
c
0
b
k
Δ
t
k
2
R
c
0
b
k
(
p
c
k
+
1
c
0
−
p
c
k
c
0
)
−
I
R
c
0
b
k
R
b
k
+
1
c
0
R
c
0
b
k
Δ
t
k
0
]
[
v
b
k
b
k
v
b
k
+
1
b
k
+
1
g
c
0
s
]
=
[
α
b
k
+
1
b
k
+
R
c
0
b
k
R
b
k
+
1
c
0
p
c
b
−
p
c
b
β
b
k
+
1
b
k
]
\left[\begin{array}{cccc}-I \Delta t_{k} & 0 & \frac{1}{2} R_{c_{0}}^{b_{k}} \Delta t_{k}^{2} & R_{c_{0}}^{b_{k}}\left(p_{c_{k+1}}^{c_{0}}-p_{c_{k}}^{c_{0}}\right) \\ -I & R_{c_{0}}^{b_{k}} R_{b_{k+1}}^{c_{0}} & R_{c_{0}}^{b_{k}} \Delta t_{k} & 0\end{array}\right]\left[\begin{array}{c}v_{b_{k}}^{b_{k}} \\ v_{b_{k+1}}^{b_{k+1}} \\ g^{c_{0}} \\ s\end{array}\right]=\left[\begin{array}{c}\alpha_{b_{k+1}}^{b_{k}}+R_{c_{0}}^{b_{k}} R_{b_{k+1}}^{c_{0}} p_{c}^{b}-p_{c}^{b} \\ \beta_{b_{k+1}}^{b_{k}}\end{array}\right]
[−IΔtk−I0Rc0bkRbk+1c021Rc0bkΔtk2Rc0bkΔtkRc0bk(pck+1c0−pckc0)0]
vbkbkvbk+1bk+1gc0s
=[αbk+1bk+Rc0bkRbk+1c0pcb−pcbβbk+1bk]
同样采用LDLT分解,就能求出状态量
χ
I
10
×
1
\chi _I^{10×1}
χI10×1:
H
T
H
χ
I
10
×
1
=
H
T
b
H^TH \chi _I^{10×1}=H^Tb
HTHχI10×1=HTb
5.修正重力矢量 g c 0 g^{c_0} gc0
在上一步的操作中得到的g向量是三维度的,但是优化过程中并没有加入其自身的模长为9.81的约束,根据论文[1]中给的图,如下图所示,其加入约束
g
c
0
=
∣
g
∣
⋅
g
^
+
w
1
b
1
+
w
2
b
2
g_{c_0}=|g|\cdot\hat{g}+w_{1}b_{1}+w_{2}b_{2}
gc0=∣g∣⋅g^+w1b1+w2b2,通过上面求解的
g
^
\hat{g}
g^作为观测值,对应代码中
g
0
g_0
g0。
在这里,采用球面坐标进行参数化,也就是用g的模长作为半径画一个半球,上图蓝色线对应的是
g
c
0
g_{c_0}
gc0的测量值的方向(也就是优化前的方向),在这个交点上找到一个切平面,用
g
c
0
g_{c_0}
gc0,
b
1
b_1
b1,
b
2
b_2
b2构造一个坐标系,那么在轴
b
1
b_1
b1和
b
2
b_2
b2上坐标值
w
1
和
w
2
w_1和w_2
w1和w2就是我们需要求的量。只需要将此模值约束带入论文[1]公式(18)即可得到一个新的等式如下,最后同样的是求解Ax=b的过程。其中假设一个轴为(0,0,1),然后采用的史密斯正交化求解出
b
1
b_1
b1,之后由
g
c
0
g_{c_0}
gc0的测量值的方向与
b
1
b_1
b1作叉乘得到
b
2
b_2
b2。
[
−
I
Δ
t
k
0
1
2
R
c
0
b
k
Δ
t
k
2
b
⃗
R
c
b
b
k
(
p
c
k
+
1
c
0
−
p
c
k
c
0
)
−
I
R
c
0
b
k
R
b
k
+
1
c
0
R
c
0
b
k
Δ
t
k
b
⃗
0
]
[
v
b
k
b
k
v
b
k
+
1
b
k
+
1
w
s
]
=
[
α
b
k
+
1
b
k
+
R
c
0
b
k
R
b
k
+
1
c
0
p
c
b
−
p
c
b
−
1
2
R
c
0
b
k
Δ
t
k
b
k
∣
∣
g
∣
∣
g
^
⃗
β
b
k
+
1
b
k
−
R
c
0
b
k
Δ
t
k
∣
∣
g
∣
∣
g
^
⃗
]
\left.\left[\begin{array}{ccc}-I\Delta t_k&0&\frac{1}{2}R_{c_0}^{b_k}\Delta t_k^2\vec{b}&R_{c_b}^{b_k}(p_{c_{k+1}}^{c_0}-p_{c_k}^{c_0})\\-I&R_{c_0}^{b_k}R_{b_{k+1}}^{c_0}&R_{c_0}^{b_k}\Delta t_k\vec{b}&0\end{array}\right.\right]\left[\begin{array}{c}v_{b_k}^{b_k}\\v_{b_{k+1}}^{b_{k+1}}\\w\\s\end{array}\right]=\left[\begin{array}{c}\alpha_{b_{k+1}}^{b_k}+R_{c_0}^{b_k}R_{b_{k+1}}^{c_0}p_c^b-p_c^b-\frac{1}{2}R_{c_0}^{b_k}\Delta t_k^{b_k}||g||\vec{\hat{g}}\\\beta_{b_{k+1}}^{b_k}-R_{c_0}^{b_k}\Delta t_k||g||\vec{\hat{g}}\end{array}\right]
[−IΔtk−I0Rc0bkRbk+1c021Rc0bkΔtk2bRc0bkΔtkbRcbbk(pck+1c0−pckc0)0]
vbkbkvbk+1bk+1ws
=[αbk+1bk+Rc0bkRbk+1c0pcb−pcb−21Rc0bkΔtkbk∣∣g∣∣g^βbk+1bk−Rc0bkΔtk∣∣g∣∣g^]
同样使用LDLT分解:
H
T
H
X
I
9
×
1
=
H
T
b
H^TH\mathcal{X}_I^{9\times1}=H^Tb
HTHXI9×1=HTb
6 重力方向对齐(将所有变量调整至惯性世界坐标系)
这部分主要是计算相机系到惯性系的旋转矩阵 q c 0 w q_{c_0}^w qc0w,将 C 0 C_0 C0系下的重力向量 g g^{} g旋转至惯性坐标系中的Z轴方向,并把所有变量调整至惯性坐标系。
(1)找到
c
0
c_0
c0到
w
w
w系的旋转矩阵
R
c
0
w
=
e
x
p
(
[
θ
u
]
)
R_{c_0}^w = exp([θu])
Rc0w=exp([θu])
u
=
g
^
c
0
×
g
^
w
∥
g
^
c
0
×
g
^
w
∥
,
θ
=
a
t
a
n
2
(
∥
g
^
c
0
×
g
^
w
∥
,
g
^
c
0
⋅
g
^
w
)
\mathbf{u}=\frac{\hat{\mathbf{g}}^{c_0}\times\hat{\mathbf{g}}^w}{\|\hat{\mathbf{g}}^{c_0}\times\hat{\mathbf{g}}^w\|},\theta=atan2(\|\hat{\mathbf{g}}^{c_0}\times\hat{\mathbf{g}}^w\|,\hat{\mathbf{g}}^{c_0}\cdot\hat{\mathbf{g}}^w)
u=∥g^c0×g^w∥g^c0×g^w,θ=atan2(∥g^c0×g^w∥,g^c0⋅g^w)由于
g
c
0
g^{c_0}
gc0已经求出来了,而
g
w
g^w
gw是一个已知的量,因此它们之间的夹角
θ
θ
θ可以由上式求得,然后用
g
c
0
g^{c_0}
gc0和
g
w
g^w
gw作叉乘得到一个旋转轴u;最后把
c
0
c_0
c0坐标系绕着转轴旋转一个θ,就能找到
c
0
c_0
c0到
w
w
w系的对齐关系,也就是
R
c
0
w
=
e
x
p
(
[
θ
u
]
)
R_{c_0}^w = exp([θu])
Rc0w=exp([θu])。
(2) 把所有 c 0 c_0 c0坐标系下的变量旋转到 w w w系下
所有量都乘上 R c 0 w R_{c_0}^w Rc0w就可以了。定义的 c 0 c_0 c0与 w w w系的原点坐标是重合的。
(3) 把相机平移和特征点尺度恢复到米制单位
以上操作即完成了在动态场景下的初始化!初始化部分的代码虽然生命周期比较短,但是其代码量还是不少,细节操作较多,特别是动态初始化。
由于篇幅太长,后续的章节放在下一篇文章中!
参考资料:
1.https://zhuanlan.zhihu.com/p/76341809
2.https://zhuanlan.zhihu.com/p/412877911
3.https://zhuanlan.zhihu.com/p/113127198