欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【从零开始手写 VIO】习题

程序员文章站 2022-07-12 10:35:04
...

第1节概述与课程介绍

1. VIO 文献阅读

视觉与IMU进行融合之后有何优势?
答:视觉提供丰富的场景信息,可以用来建立3D模型,定位和重定位;IMU提供自我运动的信息,可以用来恢复尺度信息,估计重力方向和速度信息等。

有哪些常见的视觉 + IMU 融合方案?有没有工业界应用的例子?
答:MSCKF,ROVIO,Okvis,VI-ORB,VINS-Mono等;谷歌tango里面的算法据说用的是MSCKF,还有AR/VR设备和无人机里面会用VIO。

在学术界, VIO 研究有哪些新进展?有没有将学习方法用到 VIO 中的例子?
答:2020最新的应该是ORB-SLAM3,还有多基元的VIO;个人觉得语义定位的VIO运用了学习方法。

2. 四元数和李代数更新

课件提到了可以使用四元数或旋转矩阵存储旋转变量。当我们用计算出来的 ω\omega 对某旋转更新时,有两种不同方式:
RRexp(ω)R \leftarrow R exp(\omega^{\wedge})
 qq[1,12ω]T或 \ q \leftarrow q \otimes [1, \frac{1}{2}\omega]^T
请编程验证对于小量 ω=[0.01,0.02,0.03]T\omega = [0.01, 0.02, 0.03]^T,两种方法得到的结果非常接近,实践当中可视为等同。因此,在后文提到旋转时,我们并不刻意区分旋转本身是 q 还是 R,也不区分其更新方式为上式的哪一种。

答:

方法一:使用李群计算旋转矩阵

#include <iostream>

#include <Eigen/Core>
#include <Eigen/Geometry>
#include <sophus/se3.hpp>

int main(int argc, char **argv) {
    Eigen::Vector3d vec(1, 2, 3);
    Eigen::Matrix3d R = Eigen::AngleAxisd(M_PI / 4, vec / vec.norm()).toRotationMatrix();
    Eigen::Quaterniond q(R);
    Sophus::SO3d SO3_R(R);
    std::cout << "R is" << std::endl<< R << std::endl << std::endl;

    Eigen::Vector3d w(0.01, 0.02, 0.03);
    Sophus::SO3d R_updated = SO3_R * Sophus::SO3d::exp(w);
    std::cout << "Rotation updated = \n" << R_updated.matrix() << std::endl << std::endl;

    Eigen::Quaterniond q_updated = q * Eigen::Quaterniond(1, w.x() / 2, w.y() / 2, w.z() / 2);
    Eigen::Matrix3d R_q_updated = Eigen::Matrix3d(q_updated.normalized());
    std::cout << "Quaternion updated = \n" << R_q_updated << std::endl << std::endl;

    std::cout << "Difference = \n" << R_updated.matrix() - R_q_updated << std::endl << std::endl;

    return 0;
}

方法二:使用罗德里格斯公式计算旋转矩阵

#include <iostream>

#include <Eigen/Core>
#include <Eigen/Geometry>

int main(int argc, char **argv) {
    Eigen::Vector3d vec(1, 2, 3);
    Eigen::Matrix3d R = Eigen::AngleAxisd(M_PI / 4, vec / vec.norm()).toRotationMatrix();
    Eigen::Quaterniond q(R);
    std::cout << "Before updating, R = " << std::endl<< R << std::endl << std::endl;

    Eigen::Vector3d w(0.01, 0.02, 0.03);
    double theta = w.norm();
    Eigen::Vector3d u_w = w / theta;
    Eigen::Matrix3d u_w_skew;
    u_w_skew << 0,          -u_w(2),    u_w(1),
                u_w(2),     0,          -u_w(0),
                -u_w(1),    u_w(0),     0;
    Eigen::Matrix3d R_w = cos(theta) * Eigen::Matrix3d::Identity() + (1 - cos(theta)) * u_w * u_w.transpose() + sin(theta) * u_w_skew;
    Eigen::Matrix3d R_updated = R * R_w;
    std::cout << "After rotation updating, R = " << std::endl << R_updated.matrix() << std::endl << std::endl;

    Eigen::Quaterniond q_updated = q * Eigen::Quaterniond(1, w.x() / 2, w.y() / 2, w.z() / 2);
    q_updated = q_updated.normalized();
    Eigen::Matrix3d R_q_updated = q_updated.toRotationMatrix();
    std::cout << "After quaternion updating, R = " << std::endl << R_q_updated << std::endl << std::endl;

    std::cout << "Difference = \n" << R_updated - R_q_updated << std::endl << std::endl;

    return 0;
}

3. 其他导数

使用右乘 so(3),推导以下导数:
d(R1p)dR\frac{d(R^{-1}p)}{dR}
d ln(R1R21)dR2\frac{d \ ln(R_1 R_2^{-1})^{\vee}}{dR_2}

答:

d(R1p)dR=(R1p)ψ=limψ0[Rexp(ψ)]1pR1pψ=limψ0exp(ψ)1R1pR1pψ=limψ0exp(ψ)R1pR1pψlimψ0[Iψ]R1pR1pψ=limψ0R1pψR1pR1pψ=limψ0ψR1pψ=limψ0(R1p)ψψ=(R1p)\begin{aligned} \frac{d(R^{-1}p)}{dR} &= \frac{\partial(R^{-1}p)}{\partial \psi} \\ &= \lim \limits_{\psi \to 0} \frac{[Rexp(\psi^{\wedge})]^{-1} p - R^{-1} p}{\psi} \\ &= \lim \limits_{\psi \to 0} \frac{exp(\psi^{\wedge})^{-1} R^{-1} p - R^{-1} p}{\psi} \\ &= \lim \limits_{\psi \to 0} \frac{exp(-\psi^{\wedge}) R^{-1} p - R^{-1} p}{\psi} \\ &\approx \lim \limits_{\psi \to 0} \frac{[I - \psi^{\wedge}] R^{-1} p - R^{-1} p}{\psi} \\ &= \lim \limits_{\psi \to 0} \frac{R^{-1} p - \psi^{\wedge} R^{-1} p - R^{-1} p}{\psi} \\ &= \lim \limits_{\psi \to 0} \frac{- \psi^{\wedge} R^{-1} p}{\psi} \\ &= \lim \limits_{\psi \to 0} \frac{(R^{-1} p)^{\wedge} \psi}{\psi} \\ &= (R^{-1} p)^{\wedge} \end{aligned}

d ln(R1R21)dR2=limψ0ln[R1(R2exp(ψ))1]ln(R1R21)ψ=limψ0ln[R1exp(ψ)R21]ln(R1R21)ψ=limψ0ln[R1exp(ψ)R2T]ln(R1R2T)ψ=limψ0ln[R1R2TR2exp(ψ)R2T]ln(R1R2T)ψ=limψ0ln[R1R2Texp((R2ψ))]ln(R1R2T)ψlimψ0ln(R1R2T)+Jr1(ln(R1R2T))[(R2ψ)]ln(R1R2T)ψ=limψ0Jr1(ln(R1R2T))R2ψψ=Jr1(ln(R1R2T))R2=Jr1(ln(R1R21))R2\begin{aligned} \frac{d \ ln(R_1 R_2^{-1})^{\vee}}{dR_2} &= \lim \limits_{\psi \to 0} \frac{ln[R_1(R_2 exp(\psi^{\wedge}))^{-1}]^{\vee} - ln(R_1 R_2^{-1})^{\vee}}{\psi} \\ &= \lim \limits_{\psi \to 0} \frac{ln[R_1exp(-\psi^{\wedge})R_2^{-1}]^{\vee} - ln(R_1 R_2^{-1})^{\vee}}{\psi} \\ &= \lim \limits_{\psi \to 0} \frac{ln[R_1exp(-\psi^{\wedge})R_2^T]^{\vee} - ln(R_1 R_2^T)^{\vee}}{\psi} \\ &= \lim \limits_{\psi \to 0} \frac{ln[R_1 R_2^T R_2exp(-\psi^{\wedge})R_2^T]^{\vee} - ln(R_1 R_2^T)^{\vee}}{\psi} \\ &= \lim \limits_{\psi \to 0} \frac{ln[R_1 R_2^Texp(-(R_2 \psi)^{\wedge})]^{\vee} - ln(R_1 R_2^T)^{\vee}}{\psi} \\ &\approx \lim \limits_{\psi \to 0} \frac{ln(R_1 R_2^T)^{\vee} + J_r^{-1}(ln(R_1 R_2^T)^{\vee})[-(R_2 \psi)] - ln(R_1 R_2^T)^{\vee}}{\psi} \\ &= \lim \limits_{\psi \to 0} \frac{-J_r^{-1}(ln(R_1 R_2^T)^{\vee})R_2 \psi}{\psi} \\ &= -J_r^{-1}(ln(R_1 R_2^T)^{\vee})R_2 \\ &= -J_r^{-1}(ln(R_1 R_2^{-1})^{\vee})R_2 \end{aligned}

相关标签: VIO SLAM slam