R3LIVE源码解析(9) — R3LIVE中r3live_lio.cpp文件

目录

1 r3live_lio.cpp文件简介

2 r3live_lio.cpp源码解析


1 r3live_lio.cpp文件简介

在r3live.cpp文件中创建LIO线程后,R3LIVE中的LIO线程本质上整体流程和FAST-LIO2基本一致。

2 r3live_lio.cpp源码解析

函数最开始会进行一系列的声明和定义,发布的lidar路径,协方差矩阵,kalman增益矩阵和4个重要的点云容器,IMU前向/后向传播处理器等

    /**
     * ===================================================================================================
     * @note (1) 定义用到的变量 : 发布的lidar路径,协方差矩阵,kalman增益矩阵和4个重要的点云容器,IMU前向/后向传播处理器等.
     * ===================================================================================================
     */
    nav_msgs::Path path;    // Lidar的路径 : 主要有两个成员变量: header和pose
    path.header.stamp = ros::Time::now();   // header的时间
    path.header.frame_id = "/world";        // header的id
    /*** variables definition ***/
    // DIM_OF_STATES=29. G:, H_T_H, I_STATE:
    // G : 用于传递协方差用的矩阵, H_T_H : 用于计算kalman增益用的, I_STATE : 单位阵
    Eigen::Matrix< double, DIM_OF_STATES, DIM_OF_STATES > G, H_T_H, I_STATE;
    G.setZero();
    H_T_H.setZero();
    I_STATE.setIdentity();

    cv::Mat matA1( 3, 3, CV_32F, cv::Scalar::all( 0 ) );    // 后面没用到
    cv::Mat matD1( 1, 3, CV_32F, cv::Scalar::all( 0 ) );    // 后面没用到
    cv::Mat matV1( 3, 3, CV_32F, cv::Scalar::all( 0 ) );    // 后面没用到
    cv::Mat matP( 6, 6, CV_32F, cv::Scalar::all( 0 ) );    // 后面没用到

    PointCloudXYZINormal::Ptr feats_undistort( new PointCloudXYZINormal() );//去除畸变后的点云
    PointCloudXYZINormal::Ptr feats_down( new PointCloudXYZINormal() );     // 保存下采样后的点云
    // 有M个特征点找到了M个对应的最近平面Si,则coeffSel存储Si的平面方程系数,和点到平面的残差
    PointCloudXYZINormal::Ptr coeffSel( new PointCloudXYZINormal() );// 存放M个最近平面信息的容器: 平面方程,点-面残差
    PointCloudXYZINormal::Ptr laserCloudOri( new PointCloudXYZINormal() );// 存放找到了最近平面的M个点的容器

    /*** variables initialize ***/
    FOV_DEG = fov_deg + 10; // fov_deg=360
    HALF_FOV_COS = std::cos( ( fov_deg + 10.0 ) * 0.5 * PI_M / 180.0 );// cos(185)

    for ( int i = 0; i < laserCloudNum; i++ )   // laserCloudNum = 48x48x48
    {
        // featsArray[48x48x48]
        featsArray[ i ].reset( new PointCloudXYZINormal() );
    }

    std::shared_ptr< ImuProcess > p_imu( new ImuProcess() );    // 定义用于前向/后向传播的IMU处理器
    m_imu_process = p_imu;
    //------------------------------------------------------------------------------------------------------
    ros::Rate rate( 5000 );
    bool      status = ros::ok();
    g_camera_lidar_queue.m_liar_frame_buf = &lidar_buffer;//取出lidar数据
    set_initial_state_cov( g_lio_state );   //初始化g_lio_state的状态协方差矩阵

然后开始LIO线程的主循环。首先会对比相机和lidar队列头的时间戳,如果camera的时间戳更早则等待vio线程把更早的图像处理完。

  • td::this_thread::yield()函数的作用是让出当前线程的执行权,让其他线程有机会执行。它可以用来提高多线程程序的效率,避免某个线程长时间占用CPU资源。
  • std::this_thread::sleep_for()函数的作用是让当前线程暂停执行一段时间。它接受一个时间间隔作为参数,参数类型为std::chrono::milliseconds,表示以毫秒为单位的时间间隔。在代码中,THREAD_SLEEP_TIM是一个时间间隔的变量,它的值可以根据需要进行设置,代码中设置为1s。
while ( g_camera_lidar_queue.if_lidar_can_process() == false )
{   // 考虑camera和lidar在频率上的时间对齐关系
    // 判断当前时间是否可以处理lidar数据, 不可以则sleep一会
    ros::spinOnce();
    std::this_thread::yield();
    std::this_thread::sleep_for( std::chrono::milliseconds( THREAD_SLEEP_TIM ) );
}

从lidar_buffer和imu_buffer_lio中分别获取雷达和imu数据,存放至Measures中,如果没有读取到数据则退出。

/**
* @note (2-2) 从lidar_buffer和imu_buffer_lio中分别获取雷达和imu数据,存放至Measures中
*              MeasureGroup Measures; // 存放雷达数据和IMU数据的结构体全局变量
*/             
if ( sync_packages( Measures ) == 0 )
{
    continue;   // 提取数据失败
}

然后下一步就是调用Process 函数补偿点云畸变,并用imu数据进行系统状态预测。

  • 如果没有成功去除点云运动畸变,则重置当前处理lidar帧的起始时间。
  • 接着进行时间判断, 当前帧中lidar的开始时间,必须<=记录的帧开始时间,如果时间满足关系,开始EKF过程
/**
* @note (2-3) 通过测量数据Measures(IMU数据和Lidar数据)计算LIO的状态和去畸变后的Lidar点云数据
*             前向传播 + 后向传播
*      LIO状态结果保存在g_lio_state,去运动畸变后的点保存在feats_undistort中
*/
p_imu->Process( Measures, g_lio_state, feats_undistort );
g_camera_lidar_queue.g_noise_cov_acc = p_imu->cov_acc;  // 获取加速度误差状态传递的协方差
g_camera_lidar_queue.g_noise_cov_gyro = p_imu->cov_gyr; // 获取角速度误差状态传递的协方差
StatesGroup state_propagate( g_lio_state ); // 状态传播值(先验):通过计算得到的状态实例化一个StatesGroup变量

// 输出lio上一帧更新的时间 : 上一帧更新记录时间 - lidar开始时间
// cout << "G_lio_state.last_update_time =  " << std::setprecision(10) << g_lio_state.last_update_time -g_lidar_star_tim  << endl;
if ( feats_undistort->empty() || ( feats_undistort == NULL ) )  // 没有成功去除点云运动畸变
{
    // 重置当前处理lidar帧的起始时间 : 比如当前处理t1-t2间的lidar但失败了
    // 因此后面处理时间为t1-t3,所以需要把t1保存进frame_first_pt_time
    frame_first_pt_time = Measures.lidar_beg_time;
    std::cout << "not ready for odometry" << std::endl;
    continue;
}

// 当前帧中lidar的开始时间,必须<=记录的帧开始时间
// 按理应该相等,这里的判断估计是实际使用中发生的问题(从理解的角度-不一定正确:如果lidar中损失了初始点,那么
// 当前最开始的lidar点的时间就<记录下来的帧开始时间)
if ( ( Measures.lidar_beg_time - frame_first_pt_time ) < INIT_TIME ) // INIT_TIME=0
{
    flg_EKF_inited = false;
    std::cout << "||||||||||Initiallizing LiDAR||||||||||" << std::endl;
}
else    // 时间满足关系,开始EKF过程
{
    flg_EKF_inited = true;
}

p_imu->Process() 函数的主要作用是通过测量数据meas(IMU数据和Lidar数据)计算LIO的状态和去畸变后的Lidar点云数据。

/**
 * @note 通过测量数据meas(IMU数据和Lidar数据)计算LIO的状态和去畸变后的Lidar点云数据
 * @param meas : 输入的Lidar和IMU数据
 * @param stat : Lidar状态
 * @param cur_pcl_un_ : 去畸变后的点云
 */ 
void ImuProcess::Process( const MeasureGroup &meas, StatesGroup &stat, PointCloudXYZINormal::Ptr cur_pcl_un_ )
{
    // double t1, t2, t3;
    // t1 = omp_get_wtime();

    if ( meas.imu.empty() ) // 判断IMU数据
    {
        // std::cout << "no imu data" << std::endl;
        return;
    };
    ROS_ASSERT( meas.lidar != nullptr );    // 判断Lidar数据

    if ( imu_need_init_ )   // 初始化IMU数据
    {
        /// The very first lidar frame 初始化第一帧雷达数据帧
        // 初始化重力,陀螺仪bias,加速度和陀螺仪协方差
        // 归一化加速度测量值到单位重力下
        IMU_Initial( meas, stat, init_iter_num );

        imu_need_init_ = true;

        last_imu_ = meas.imu.back();    // 获取当前处理的最后一个imu数据

        if ( init_iter_num > MAX_INI_COUNT ) // (1 > 20) : 默认不进入if
        {
            imu_need_init_ = false;
            // std::cout<<"mean acc: "<<mean_acc<<" acc measures in word frame:"<<state.rot_end.transpose()*mean_acc<<std::endl;
            ROS_INFO(
                "IMU Initials: Gravity: %.4f %.4f %.4f; state.bias_g: %.4f %.4f %.4f; acc covarience: %.8f %.8f %.8f; gry covarience: %.8f %.8f %.8f",
                stat.gravity[ 0 ], stat.gravity[ 1 ], stat.gravity[ 2 ], stat.bias_g[ 0 ], stat.bias_g[ 1 ], stat.bias_g[ 2 ], cov_acc[ 0 ],
                cov_acc[ 1 ], cov_acc[ 2 ], cov_gyr[ 
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
R3LIVE是一种激光-惯性-视觉结合的SLAM算法,被认为是非常经典的文章\[1\]。该算法使用了IMU、相机和激光雷达三个传感器,每个传感器都有不同的作用。R3LIVE的代码流程可以概括为以下几个部分。 首先是前言部分,其介绍了R3LIVE算法的结构和各个传感器的作用\[1\]。 接下来是节点与话题的绘图部分,通过绘制节点和话题的图形,可以清晰地看到R3LIVE的两个节点:/r3live_LiDAR_front_end和/r3live_mapping\[2\]。 然后是主函数部分,该部分在FAST-LIO2已经详细介绍过,所以在R3LIVE不再过多介绍\[3\]。 最后是重点部分,即VIO部分。在这部分,R3LIVE算法进行了详细的操作,但由于篇幅限制,无法在这里进行详细介绍。建议参考相关文献或代码来深入了解R3LIVE的VIO部分\[3\]。 总之,R3LIVE是一种激光-惯性-视觉结合的SLAM算法,其代码包括前言部分、节点与话题的绘图部分、主函数部分和VIO部分。详细的代码解析可以参考相关文献或代码资。 #### 引用[.reference_title] - *1* *2* [R3LIVE代码详解(一)](https://blog.csdn.net/lovely_yoshino/article/details/126572997)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [R3LIVE代码详解(三)](https://blog.csdn.net/lovely_yoshino/article/details/126676059)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

几度春风里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值