VINS-Mono学习与程序解读(5):estimator.processIMU

VINS-Mono学习与程序解读(5):estimator.processIMU

image

附赠自动驾驶学习资料和量产经验:链接

estimator.processIMU函数实现了IMU的预积分,它在vins_estimator文件夹下的estimator.cpp文件中。

//processIMU()实现了IMU的预积分,通过中值积分得到当前PQV作为优化初值
void Estimator::processIMU(double dt, const Vector3d &linear_acceleration, const Vector3d &angular_velocity)
{//利用imu数据进行预积分
    if (!first_imu)
    {//最初first_imu = 0所以会进到这个里面
        first_imu = true;//只有第一次才会进入
        acc_0 = linear_acceleration;//第一次要给acc_0,gyr_0把值赋上
        gyr_0 = angular_velocity;
    }

    if (!pre_integrations[frame_count])//同样第一次要初始化该数组.
    {//第一次frame_count从0开始
        pre_integrations[frame_count] = new IntegrationBase{acc_0, gyr_0, Bas[frame_count], Bgs[frame_count]};
    }
    if (frame_count != 0)//如果已经开始计数的话
    {
        //调用IntegrationBase类中的函数push_back
        /*执行
        dt_buf.push_back(dt);
        acc_buf.push_back(acc);
        gyr_buf.push_back(gyr);
        并完成预积分
        */
        pre_integrations[frame_count]->push_back(dt, linear_acceleration, angular_velocity);
        //if(solver_flag != NON_LINEAR)
            tmp_pre_integration->push_back(dt, linear_acceleration, angular_velocity);

        /*
        这里要说明一下,dt_buf是一个vector<double>类型的数组,也就是说dt_buf[frame_count]是一个
        vector<double>数组,因为一帧图像对应一串imu数据!
        linear_acceleration_buf是一个vector<Vector3d>类型的数组,也就说
        linear_acceleration_buf[frame_count]是一个vector<Vector3d>类型的数组,因为一帧图像对应一串imu数据!
        angular_velocity_buf是一个vector<Vector3d>类型的数组,也就说
        angular_velocity_buf[frame_count]是一个vector<Vector3d>类型的数组
        */
        dt_buf[frame_count].push_back(dt);
        linear_acceleration_buf[frame_count].push_back(linear_acceleration);
        angular_velocity_buf[frame_count].push_back(angular_velocity);

        int j = frame_count;//涉及到的公式我们下面推导!         
        Vector3d un_acc_0 = Rs[j] * (acc_0 - Bas[j]) - g;
        Vector3d un_gyr = 0.5 * (gyr_0 + angular_velocity) - Bgs[j];
        Rs[j] *= Utility::deltaQ(un_gyr * dt).toRotationMatrix();
        Vector3d un_acc_1 = Rs[j] * (linear_acceleration - Bas[j]) - g;
        Vector3d un_acc = 0.5 * (un_acc_0 + un_acc_1);
        Ps[j] += dt * Vs[j] + 0.5 * dt * dt * un_acc;//更新位置与速度
        Vs[j] += dt * un_acc;
    }
    acc_0 = linear_acceleration;//更新acc_0与gyr_0
    gyr_0 = angular_velocity;
}

1.IntegrationBase中的push_back函数

该函数在vins_estimator文件夹下的factor文件夹下的integration_base.h文件中。

void push_back(double dt, const Eigen::Vector3d &acc, const Eigen::Vector3d &gyr)
{
    dt_buf.push_back(dt);
    acc_buf.push_back(acc);
    gyr_buf.push_back(gyr);
    propagate(dt, acc, gyr);
}

该函数首先将dt,acc,gyr保存至对应的容器中,然后执行函数propagate

void propagate(double _dt, const Eigen::Vector3d &_acc_1, const Eigen::Vector3d &_gyr_1)
{//其作用是积分计算两个关键帧之间IMU测量的变化量:
    dt = _dt;//时间间隔
    acc_1 = _acc_1;//线加速度
    gyr_1 = _gyr_1;//角速度
    //保存计算的结果!
    Vector3d result_delta_p;
    Quaterniond result_delta_q;
    Vector3d result_delta_v;
    Vector3d result_linearized_ba;
    Vector3d result_linearized_bg;
    //中值法积分!
    midPointIntegration(_dt, acc_0, gyr_0, _acc_1, _gyr_1, delta_p, delta_q, delta_v,
                        linearized_ba, linearized_bg,
                        result_delta_p, result_delta_q, result_delta_v,
                        result_linearized_ba, result_linearized_bg, 1);

    //checkJacobian(_dt, acc_0, gyr_0, acc_1, gyr_1, delta_p, delta_q, delta_v,
    //                    linearized_ba, linearized_bg);
    //更新状态信息!
    delta_p = result_delta_p;
    delta_q = result_delta_q;
    delta_v = result_delta_v;
    linearized_ba = result_linearized_ba;
    linearized_bg = result_linearized_bg;
    delta_q.normalize();
    sum_dt += dt;//sum_dt是一段时间
    acc_0 = acc_1;
    gyr_0 = gyr_1;  
     
}

从程序中可以看出propagate的核心是midPointIntegration函数。下面就来看该函数,它同样也在文件integration_base.h中。

void midPointIntegration(double _dt, 
                        const Eigen::Vector3d &_acc_0, const Eigen::Vector3d &_gyr_0,
                        const Eigen::Vector3d &_acc_1, const Eigen::Vector3d &_gyr_1,
                        const Eigen::Vector3d &delta_p, const Eigen::Quaterniond &delta_q, const Eigen::Vector3d &delta_v,
                        const Eigen::Vector3d &linearized_ba, const Eigen::Vector3d &linearized_bg,
                        Eigen::Vector3d &result_delta_p, Eigen::Quaterniond &result_delta_q, Eigen::Vector3d &result_delta_v,
                        Eigen::Vector3d &result_linearized_ba, Eigen::Vector3d &result_linearized_bg, bool update_jacobian)
{
    /*
    double _dt //时间间隔
    const Eigen::Vector3d &_acc_0 //上次测量加速度
    const Eigen::Vector3d &_gyr_0 //上次测量角速度
    const Eigen::Vector3d &_acc_1 //本次测量加速度
    const Eigen::Vector3d &_gyr_1 //本次测量角速度
    const Eigen::Vector3d &delta_p //相对初始参考系的位移
    const Eigen::Quaterniond &delta_q //相对初始参考系的姿态
    const Eigen::Vector3d &delta_v //相对初始参考系的速度
    const Eigen::Vector3d &linearized_ba //相对初始参考系的加速度偏差
    const Eigen::Vector3d &linearized_bg //相对初始参考系的角速度偏差
    Eigen::Vector3d &result_delta_p //位置变化量计算结果
    Eigen::Quaterniond &result_delta_q  //姿态变化量计算结果
    Eigen::Vector3d &result_delta_v //速度变化量计算结果
    Eigen::Vector3d &result_linearized_ba //加速度偏差计算结果
    Eigen::Vector3d &result_linearized_bg //角速度偏差计算结果

    */
    //ROS_INFO("midpoint integration");
    Vector3d un_acc_0 = delta_q * (_acc_0 - linearized_ba);
    Vector3d un_gyr = 0.5 * (_gyr_0 + _gyr_1) - linearized_bg;
    result_delta_q = delta_q * Quaterniond(1, un_gyr(0) * _dt / 2, un_gyr(1) * _dt / 2, un_gyr(2) * _dt / 2);
    Vector3d un_acc_1 = result_delta_q * (_acc_1 - linearized_ba);
    Vector3d un_acc = 0.5 * (un_acc_0 + un_acc_1);
    result_delta_p = delta_p + delta_v * _dt + 0.5 * un_acc * _dt * _dt;//累积位移
    result_delta_v = delta_v + un_acc * _dt;//累积速度
    result_linearized_ba = linearized_ba; //加速度偏差不变
    result_linearized_bg = linearized_bg; //角速度偏差不变

    if(update_jacobian)
    {
        Vector3d w_x = 0.5 * (_gyr_0 + _gyr_1) - linearized_bg;//两帧IMU数据间的平均角速度!
        Vector3d a_0_x = _acc_0 - linearized_ba;//本次计算初始时刻的加速度
        Vector3d a_1_x = _acc_1 - linearized_ba;//本次计算末尾时刻的加速度
        Matrix3d R_w_x, R_a_0_x, R_a_1_x;

        R_w_x<<0, -w_x(2), w_x(1),
            w_x(2), 0, -w_x(0),
            -w_x(1), w_x(0), 0;         //w_x 对应的斜对称矩阵
        R_a_0_x<<0, -a_0_x(2), a_0_x(1),
            a_0_x(2), 0, -a_0_x(0),
            -a_0_x(1), a_0_x(0), 0;     //a_0_x 对应的斜对称矩阵
        R_a_1_x<<0, -a_1_x(2), a_1_x(1),
            a_1_x(2), 0, -a_1_x(0),
            -a_1_x(1), a_1_x(0), 0;     //a_1_x 对应的斜对称矩阵

        MatrixXd F = MatrixXd::Zero(15, 15);
        F.block<3, 3>(0, 0) = Matrix3d::Identity();
        F.block<3, 3>(0, 3) = -0.25 * delta_q.toRotationMatrix() * R_a_0_x * _dt * _dt + 
                              -0.25 * result_delta_q.toRotationMatrix() * R_a_1_x * (Matrix3d::Identity() - R_w_x * _dt) * _dt * _dt;
        F.block<3, 3>(0, 6) = MatrixXd::Identity(3,3) * _dt;
        F.block<3, 3>(0, 9) = -0.25 * (delta_q.toRotationMatrix() + result_delta_q.toRotationMatrix()) * _dt * _dt;
        F.block<3, 3>(0, 12) = -0.25 * result_delta_q.toRotationMatrix() * R_a_1_x * _dt * _dt * -_dt;
        F.block<3, 3>(3, 3) = Matrix3d::Identity() - R_w_x * _dt;
        F.block<3, 3>(3, 12) = -1.0 * MatrixXd::Identity(3,3) * _dt;
        F.block<3, 3>(6, 3) = -0.5 * delta_q.toRotationMatrix() * R_a_0_x * _dt + 
                              -0.5 * result_delta_q.toRotationMatrix() * R_a_1_x * (Matrix3d::Identity() - R_w_x * _dt) * _dt;
        F.block<3, 3>(6, 6) = Matrix3d::Identity();
        F.block<3, 3>(6, 9) = -0.5 * (delta_q.toRotationMatrix() + result_delta_q.toRotationMatrix()) * _dt;
        F.block<3, 3>(6, 12) = -0.5 * result_delta_q.toRotationMatrix() * R_a_1_x * _dt * -_dt;
        F.block<3, 3>(9, 9) = Matrix3d::Identity();
        F.block<3, 3>(12, 12) = Matrix3d::Identity();
        //cout<<"A"<<endl<<A<<endl;

        MatrixXd V = MatrixXd::Zero(15,18);
        V.block<3, 3>(0, 0) =  0.25 * delta_q.toRotationMatrix() * _dt * _dt;
        V.block<3, 3>(0, 3) =  0.25 * -result_delta_q.toRotationMatrix() * R_a_1_x  * _dt * _dt * 0.5 * _dt;//检查下是否多了个负号!
        V.block<3, 3>(0, 6) =  0.25 * result_delta_q.toRotationMatrix() * _dt * _dt;
        V.block<3, 3>(0, 9) =  V.block<3, 3>(0, 3);
        V.block<3, 3>(3, 3) =  0.5 * MatrixXd::Identity(3,3) * _dt;//检查下是否少了一个负号!
        V.block<3, 3>(3, 9) =  0.5 * MatrixXd::Identity(3,3) * _dt;//检查下是否少了一个负号!
        V.block<3, 3>(6, 0) =  0.5 * delta_q.toRotationMatrix() * _dt;//检查符号是否反了
        V.block<3, 3>(6, 3) =  0.5 * -result_delta_q.toRotationMatrix() * R_a_1_x  * _dt * 0.5 * _dt;//检查符号是否反了
        V.block<3, 3>(6, 6) =  0.5 * result_delta_q.toRotationMatrix() * _dt;//检查符号是否反了
        V.block<3, 3>(6, 9) =  V.block<3, 3>(6, 3);//检查符号是否反了
        V.block<3, 3>(9, 12) = MatrixXd::Identity(3,3) * _dt;
        V.block<3, 3>(12, 15) = MatrixXd::Identity(3,3) * _dt;

        //step_jacobian = F;
        //step_V = V;
        jacobian = F * jacobian;//更新雅克比矩阵
        covariance = F * covariance * F.transpose() + V * noise * V.transpose();//更新协方差矩阵
    }

}

我们首先给出两帧之间 PVQ 增量的中值法的离散形式。

image

公式与程序的对应关系如下:

image

Vector3d un_acc_0 = delta_q * (_acc_0 - linearized_ba);

image

Vector3d un_gyr = 0.5 * (_gyr_0 + _gyr_1) - linearized_bg;

image

result_delta_q = delta_q * Quaterniond(1, un_gyr(0) * _dt / 2, un_gyr(1) * _dt / 2, un_gyr(2) * _dt / 2);

image

Vector3d un_acc_1 = result_delta_q * (_acc_1 - linearized_ba);

image

Vector3d un_acc = 0.5 * (un_acc_0 + un_acc_1);

image

result_delta_p = delta_p + delta_v * _dt + 0.5 * un_acc * _dt * _dt;//累积位移

image

result_delta_v = delta_v + un_acc * _dt;//累积速度

下面再说状态误差雅克比与噪声雅克比矩阵。

上面我们已经完成了IMU预积分计算的推导,而要将IMU预积分运用到非线性优化中,需要建立线性高斯误差状态递推方程

先给出在t时刻误差项的线性化递推方程:

image

image

image

image

image

以上的推导是在连续情况下的,下面给出离散形式。

image

image

image

image

image

image

以上就是所有公式的推导。具体可以结合源码中矩阵的索引号和每一个公式对应。

processIMU最后这部分原理不用多说,其实就是把我们前面算的在 �� 系下的状态变换到世界坐标系下。

int j = frame_count;//         
Vector3d un_acc_0 = Rs[j] * (acc_0 - Bas[j]) - g;
Vector3d un_gyr = 0.5 * (gyr_0 + angular_velocity) - Bgs[j];
Rs[j] *= Utility::deltaQ(un_gyr * dt).toRotationMatrix();
Vector3d un_acc_1 = Rs[j] * (linear_acceleration - Bas[j]) - g;
Vector3d un_acc = 0.5 * (un_acc_0 + un_acc_1);
Ps[j] += dt * Vs[j] + 0.5 * dt * dt * un_acc;//更新位置与速度
Vs[j] += dt * un_acc;
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 很高兴听到您想要在Ubuntu 18.04上运行VINS-Mono。以下是一些步骤,希望能帮助您完成这个任务: 1. 安装ROS:在Ubuntu 18.04上安装ROS,可以使用以下命令: ``` sudo apt-get install ros-melodic-desktop-full ``` 2. 安装依赖项:在安装VINS-Mono之前,需要安装一些依赖项。您可以使用以下命令来安装它们: ``` sudo apt-get install cmake libgoogle-glog-dev libatlas-base-dev libsuitesparse-dev libeigen3-dev ``` 3. 克隆VINS-Mono:使用以下命令克隆VINS-Mono: ``` git clone https://github.com/HKUST-Aerial-Robotics/VINS-Mono.git ``` 4. 编译VINS-Mono:进入VINS-Mono目录并编译它: ``` cd VINS-Mono mkdir build cd build cmake .. make -j4 ``` 5. 运行VINS-Mono:在VINS-Mono目录中,使用以下命令运行它: ``` roslaunch vins_estimator euroc.launch ``` 如果您想使用自己的数据,请将数据放入VINS-Mono/data文件夹中,并在euroc.launch文件中更改数据路径。 希望这些步骤能够帮助您在Ubuntu 18.04上成功运行VINS-Mono。如果您有任何问题,请随时问我。 ### 回答2: 首先,如果您尚未安装Ubuntu 18.04,请先完成此步骤。接下来,我们将讲解在Ubuntu 18.04上如何跑通VINS-MonoVINS-Mono是一个面向单目相机的视觉惯性里程计算法,它使用相机和IMU数据来计算三维运动轨迹。要在Ubuntu 18.04上能够跑通VINS-Mono,您需要执行以下步骤: 1.安装必要的依赖项 在终端中输入以下命令以确保所有依赖项都已安装: ``` sudo apt-get update sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev sudo apt-get install libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libdc1394-22-dev ``` 2.获取VINS-Mono 在终端中输入以下命令以从GitHub上获取VINS-Mono源代码: ``` mkdir VINS-Mono cd VINS-Mono git clone https://github.com/HKUST-Aerial-Robotics/VINS-Mono.git ``` 3.安装必要的ROS依赖项 在终端中输入以下命令以安装VINS-Mono的ROS依赖项: ``` cd ../VINS-Mono rosdep install --from-paths src --ignore-src -r -y ``` 4.生成ROS工作区 在终端中输入以下命令以生成ROS工作区: ``` cd ../VINS-Mono catkin_make ``` 5.设置环境变量 在终端中输入以下命令以设置ROS工作区的环境变量: ``` source devel/setup.bash ``` 6.运行VINS-Mono 在终端中输入以下命令以启动VINS-Mono: ``` roslaunch vins_mono euroc.launch ``` 在运行VINS-Mono之前,您需要将存储Euroc数据集的文件夹路径添加到euroc.launch文件中。 现在,您应该已经成功地在Ubuntu 18.04上运行了VINS-Mono。跟随上述步骤,您可以轻松地安装和运行VINS-Mono,从而实现自己的项目和研究。 ### 回答3: VINS-Mono是一种单目视觉SLAM算法,用于机器人或者无人机的位置估计和地图构建。Ubuntu18.04是一种开源的操作系统,因此将这两个工具组合来使用是十分容易的。 首先,需要注意的是VINS-Mono需要安装ROS(机器人操作系统)来支持其运行,因此需要先安装ROS。ROS的安装可以通过官方网站(http://wiki.ros.org/melodic/Installation/Ubuntu)提供的步骤进行。其中,需要选择适当的ROS版本来与Ubuntu18.04兼容。建议选择ROS Melodic Morenia,这是针对Ubuntu18.04版本的ROS版本。 安装完成后,需要安装VINS-Mono包,可以通过以下命令进行安装: ``` $ sudo apt-get install ros-melodic-vins-mono ``` 其中,ros-melodic-vins-monoVINS-Mono的ROS包。 接下来,安装状态估计器(state estimator)。状态估计器是使用VINS-Mono进行位置估计的必要工具。状态估计器常用的是MSCKF(Multi-State Constraint KalmanFilter)。 ``` $ sudo apt-get install ros-melodic-msckf ``` 接着,需要下载VINS-Mono的代码库,通过Git软件进行下载: ``` $ git clone https://github.com/HKUST-Aerial-Robotics/VINS-Mono.git ``` 在下载代码库之后,需要注意一些依赖项,这些依赖项可以通过以下命令进行安装: ``` $ sudo apt-get install libsuitesparse-dev liblapack-dev libblas-dev libopencv-dev ``` 安装完所有依赖项之后,可以运行VINS-Mono,可以通过以下命令使用roslaunch运行: ``` $ roslaunch vins_estimator vins_rviz.launch ``` 这将启动VINS-Mono和RVIZ(一种可视化工具),可用于显示结果。 总之,安装和运行VINS-Mono需要安装ROS、MSCKF、VINS-Mono代码库和VINS-Mono依赖项。如果按照以上步骤操作,则ubuntu18.04就可以跑通VINS-Mono

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值