赞
踩
浏览开源代码LVI-SAM,记录自己的理解。
项目分为7个部分(程序):visual_feature、visual_odometry、visual_loop、imuPreintegration、imageProjection、featureExtraction、mapOptimization。
LIO-SAM中各模块之间的ROS消息收发结构。
LIO-SAM的因子图结构如下:
该项目整体流程如下:
订阅IMU和/lidar/mapping/odometry消息,估计IMU bias,与lidar进行图优化输出实时预积分结果。
IMU处理线程中,将IMU消息放入队列中,积分最新IMU数据,获得最新位置并发布到odometry/imu和/lidar/imu/path。
Lidar odometry处理线程中,将Lidar的odometry作为观测,与IMU预积分factor、bias between factor共同优化后,作为IMU线程的最新状态,继续预积分输出。
疑问:两个线程有公用内容,但是未用mutex保护!!!!
使用 ISAM2 优化器,为了保证运行速度,每加入100个factor就reset一次,reset前手动进行边缘化操作。
参考点:优化完成后,进行失败检测failureDetection,优化出的速度>30m/s,或imu bias >0.1m/ss、rad/s,重设优化器。
利用imuPreintegration中的信息对每帧激光的每一时刻激光点进行运动畸变校正。
订阅IMU消息,存放到imuQueue中。
订阅/vins/odometry/imu_propagate_ros,存放到odomQueue中。
订阅点云数据:
只处理点云数据。
加imu和odo的锁
从imu_propagate_ros发出的消息中,获取timeScanCur之后的一个预积分位姿作为cloudInfo和transBegin的位姿,获取timeScanNext之后的一个预积分位姿作为transEnd,需要保证两个位姿之间未进行优化,即相同的resetID。
根据transBegin和transEnd计算odomIncreX, odomIncreY, odomIncreZ, rollIncre, pitchIncre, yawIncre。
对0~激光雷达线数内的点,滤除1m内的点,将三维距离存放到rangeMat(二维)。
findRotation: 从imuRot中找该点对应的旋转,时间在两个IMU之间时,用前后两帧rot根据时间做插值获取。
findPosition:设置pos为0,为何没有用odom获取?
计算相对第0个雷达点的位姿,然后将该点的坐标转换到第0个点时刻的坐标。不是相对timeScanCur的???
将坐标存放到fullCloud->points一维数组中。
将rageMat中的点按照行的顺序存放到cloudInfo.pointRange中,并记录每行对应的pointRange的起止索引。同时将fullCloud->points存储到extractedCloud中。
publishClouds();
resetParameters();
对经过运动畸变校正之后的当前帧激光点云,计算每个点的曲率,进而提取角点、平面点(用曲率的大小进行判定)。
订阅imageProjection发布的/lidar/deskew/cloud_info。
计算每个点的曲率,存储到cloudSmoothness
曲率计算公式:
dr = di-5+di-4+di-3+di-2+di-1-10*+di+di+1+di+2+di+3+di+4+di+5
curvature = dr * dr
标记遮挡点和平行光束点.
遮挡点:10个水平像素内,距离超过0.3m,认为存在遮挡。
平行光束点:前后点的距离差大于距离的0.02倍。
提取corner和surface点。
publishFeatureCloud();
main中创建3个任务:mapOptimization、loopDetectionthread、visualizeMapThread。
mapOptimization创建后会订阅多个消息,包括雷达点云/lidar/feature/cloud_info、odometry/gps、/vins/loop/match_frame。
输出消息:/lidar/mapping/trajectory、/lidar/mapping/odometry
#pragma omp parallel for num_threads(numberOfCores)
gtSAMgraph.add(BetweenFactor<Pose3>(cloudKeyPoses3D->size()-1, cloudKeyPoses3D->size(), poseFrom.between(poseTo), odometryNoise));
Vector3 << max(noise_x, 1.0f), max(noise_y, 1.0f), max(noise_z, 1.0f);
noiseModel::Diagonal::shared_ptr gps_noise = noiseModel::Diagonal::Variances(Vector3);
gtsam::GPSFactor gps_factor(cloudKeyPoses3D->size(), gtsam::Point3(gps_x, gps_y, gps_z), gps_noise);
将GPS数据放入gpsQueue。
限制本次回环距离上次的时间>=5s。
每0.5s进行一次performLoopClosureDetection。
每0.2s执行一次publishGlobalMap,仅是发布关键帧和点云。
To be continued。。。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。