二、VIO
VIO中IMU的状态向量为:
x I = ( G I q T b g T G v I T b a T G p I T C I q T I p C T ) T \textbf x_I=\begin{pmatrix} {}_G^I\textbf q^T & \textbf b_g^T & {}^G\textbf v_I^T & \textbf b_a^T & {}^G\textbf p_I^T & {}_C^I\textbf q^T & {}^I\textbf p_C^T \end{pmatrix}^T xI=(GIqTbgTGvITbaTGpITCIqTIpCT)T
误差状态为:
x ~ I = ( G I θ ~ T b ~ g T G v ~ T b ~ a T G p ~ I T C I θ ~ T I p ~ C T ) T \tilde{\textbf x}_I=\begin{pmatrix} {}_G^I\tilde\boldsymbol{\theta}^T & \tilde\boldsymbol{b}_g^T & {}^G\tilde\textbf{v}^T & \tilde\textbf{b}_a^T & {}^G\tilde\textbf{p}_I^T & {}_C^I\tilde\boldsymbol{\theta}^T & {}^I\tilde\textbf p_C^T \end{pmatrix}^T x~I=(GIθ~Tb~gTGv~Tb~aTGp~ITCIθ~TIp~CT)T
对于普通的变量,如 b g , v I \textbf b_g,\textbf v_I bg,vI等,满足通用的加减关系,比如 G p ~ I = G p I − G p ^ I {}^G\tilde\textbf p_I={}^G\textbf p_I-{}^G\hat\textbf p_I Gp~I=GpI−Gp^I。对于四元数,误差四元数为:
δ q = q ⊗ q ^ − 1 ≈ ( 1 2 I G θ ~ T 1 ) T \delta\textbf q=\textbf q\otimes\hat\textbf q^{-1}\\ \approx\begin{pmatrix} \frac{1}{2}{}^G_I\tilde\boldsymbol \theta^T & 1 \end{pmatrix}^T δq=q⊗q^−1≈(21IGθ~T1)T
其中 I G θ ~ T ∈ R 3 {}^G_I\tilde\boldsymbol\theta^T\in\mathbb R^3 IGθ~T∈R3表示一个微小的旋转,通过这种方式将旋转误差降到了三维。考虑最终的误差状态向量,设有N个相机状态,则最终的误差状态向量为:
x ~ = ( x ~ I T x ~ C 1 … x ~ C N ) T \tilde\textbf x=\begin{pmatrix} \tilde\textbf x_I^T & \tilde\textbf x_{C_1} & \dots & \tilde\textbf x_{C_N} \end{pmatrix}^T x~=(x~ITx~C1…x~CN)T
x ~ C i = ( G C i θ ~ T G p ~ C i T ) T \tilde\textbf x_{C_i}=\begin{pmatrix} {}_G^{C_i}\tilde\boldsymbol\theta^T & {}^G\tilde\textbf p_{C_i}^T \end{pmatrix}^T x~Ci=(GCiθ~TGp~CiT)T
3 VIO初始化
(1) 初始化imu各噪声项,存在state_server.continuous_noise_cov中;
double IMUState::gyro_noise = 0.001;
double IMUState::acc_noise = 0.01;
double IMUState::gyro_bias_noise = 0.001;
double IMUState::acc_bias_noise = 0.01;
continuous_noise_cov为12x12的对角矩阵
(2) 初始化卡方检验表,置信度为0.95(不知道做什么用),存在chi_squared_test_table中。
(3) 创建ROS IO接口,订阅imu、features、mocap_odom,发布reset、gt_odom。
imuCallback
接收到的imu数据放在缓存imu_msg_buffer中,如果数据个数大于200,初始化重力和偏置。由于s-msckf默认从静止状态初始化,所以用加速度平均值初始化重力,角速度平均值初始化角速度偏置。把is_gravity_set设置为true。
得到重力向量后构建世界坐标系,令重力方向为z轴负方向。然后定义惯性系相对于世界坐标系的朝向,这里我看的有点懵,他先求解了一个旋转 R \textbf R R,使得:
R g I = − g w \textbf R\textbf g^I=-\textbf g^w RgI=−gw
然后把初始时刻的旋转 q i w \textbf q_{iw} qiw定义为:
q i w = q u a t e r n i o n ( R T ) \textbf q_{iw}=quaternion(R^T) qiw=quaternion(RT)
这一步目前还不是很懂
double gravity_norm = gravity_imu.norm();
IMUState::gravity = Vector3d(0.0, 0.0, -gravity_norm);
Quaterniond q0_i_w = Quaterniond::FromTwoVectors(
gravity_imu, -IMUState::gravity);
state_server.imu_state.orientation =
rotationToQuaternion(q0_i_w.toRotationMatrix().transpose());
4 featureCallback
4.1 一些预设置
首先判断重力是否已经设置,即判断is_gravity_set是否为true;再判断是否为第一张图像,如果是,把is_first_img置为false,把state_server.imu_state.time置为该图像时间。
4.2 batchImuProcessing
该函数主要用于积分上一次积分时间到当前图像时间的imu数据,也就是积分相邻两个图像时间内的imu数据,并且构建协方差矩阵。
4.2.1 processModel
该函数用于构建 F \textbf F F矩阵、 G \textbf G G矩阵和 Φ \boldsymbol\Phi Φ矩阵,更新状态协方差 P \textbf P P和状态变量 X \textbf X X,其中 P \textbf P P存放在state_server.state_cov里。
4.2.1.1 构建 F \textbf F F、 G \textbf G G和 Φ \boldsymbol\Phi Φ
F 21 × 21 = ( − ω ^ × − I 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 − C ( G I q ^ ) T a ^ × 0 3 × 3 0 3 × 3 − C ( G I q ^ ) T 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 I 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 ) \textbf F_{21\times 21}= \begin{pmatrix} -\hat{\boldsymbol\omega}_{\times} & -\textbf I_3 & \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3}\\ \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3}\\ -C({}_G^I\hat{\textbf{q}})^T\hat{\textbf a}_{\times} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & -C({}_G^I\hat{\textbf{q}})^T & \textbf 0_{3\times 3}\\ \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3}\\ \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf I_3 & \textbf 0_{3\times 3} & \textbf 0_{3\times 3}\\ \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3}\\ \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3} \end{pmatrix} F21×21=⎝⎜⎜⎜⎜⎜⎜⎜⎜⎛−ω^×03×3−C(GIq^)Ta^×03×303×303×303×3−I303×303×303×303×303×303×303×303×303×303×3I303×303×303×303×3−C(GIq^)T03×303×303×303×303×303×303×303×303×303×303×3⎠⎟⎟⎟⎟⎟⎟⎟⎟⎞
G 21 × 12 = ( − I 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 − I 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 − C ( G I q ^ ) T 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 I 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 0 3 × 3 ) \textbf G_{21\times 12}= \begin{pmatrix} -\textbf I_3 & \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3}\\ \textbf 0_{3\times 3} & -\textbf I_3 & \textbf 0_{3\times 3} & \textbf 0_{3\times 3}\\ \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & -C({}_G^I\hat{\textbf{q}})^T & \textbf 0_{3\times 3}\\ \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf I_3\\ \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3} &\textbf 0_{3\times 3}\\ \textbf 0_{3\times 3} & \textbf 0_{3\times 3} & \textbf 0_{3\times 3} &\textbf 0_{3\times 3} \end{pmatrix} G21×12=⎝⎜⎜⎜⎜⎜⎜⎛−I303×303×303×303×303×303×3−I303×303×303×303×303×303×3−C(GIq^)T03×303×303×303×303×303×3I303×303×3⎠⎟⎟⎟⎟⎟⎟⎞
其中
Φ = exp ( ∫ t k t k + 1 F ( τ ) d τ ) \boldsymbol\Phi = \exp(\int_{t_k}^{t_{k+1}}\textbf F(\tau)d\tau) Φ=exp(∫tk