V-LOAM和LOAM在KITTI上的排名一直是前两名。
LOAM在KITTI上的排名
原始LOAM代码(带中文注释)的地址:https://github.com/cuitaixiang/LOAM_NOTED
作为教学用的A-LOAM代码地址:https://github.com/HKUST-Aerial-Robotics/A-LOAM使用ceres库来做非线性优化。代码里默认一帧激光数据内是匀速运动的,直接使用时间进行线性插值得到去畸变的点云位姿
利用IMU去除激光传感器在运动过程中非匀速(加减速)部分造成的误差(运动畸变)。为什么这样做呢?因为LOAM是基于匀速运动的假设,但实际中激光传感器的运动肯定不是匀速的,因此使用IMU来去除非匀速运动部分造成的误差,以满足匀速运动的假设。
imuHandler()函数接受IMU数据。IMU的数据可以提供给我们IMU坐标系三个轴相对于世界坐标系的欧拉角和三个轴上的加速度。但由于加速度受到重力的影响所以首先得去除重力影响。在去除重力影响后我们想要获得IMU在世界坐标系下的运动,因此在 AccumulateIMUShift()中,根据欧拉角就可以将IMU三轴上的加速度转换到世界坐标系下的加速度。 然后利用匀加速度公式来计算位移。因此我们可以求出每一帧IMU数据在世界坐标系下对应的位移和速度。代码中实际缓存了200帧这样的数据,为后面插值激光点运动畸变打下了基础。
这里使用IMU数据进行插值计算点云的中点的位置,消除由于非匀速运动造成的运动畸变。
void ShiftToStartIMU(float pointTime)函数中主要计算一帧数据中某点相对于一帧的起始点由于加减速造成的运动畸变。因此我们首先要求出世界坐标系下的加减速造成的运动畸变,然后将运动畸变值经过绕y、x、z轴旋转后得到起始点坐标系下的运动畸变。这里的坐标系一定要搞清楚为什么要放的起始点的坐标系下。
接下来就是VeloToStartIMU()函数,这个函数流程和上一个函数大致相同。它的作用就是求当前点的速度相对于点云起始点的速度畸变,先计算全局坐标系下的然后再转换到起始点的坐标系中。
接下来就是TransformToStartIMU(PointType *p)函数作用是将当前点先转换到世界坐标系下然后再由世界坐标转换到点云起始点坐标系下。 然后减去加减速造成的非匀速畸变的值。
这一部分主要引用:https://blog.csdn.net/liuyanpeng12333/article/details/82737181中讲解IMU进行运动畸变的部分
针对前后遮挡的情况,如b所示,是通过计算前后两点间距的平方是否大于该点距离值平方的万分之二来排除的。下面是代码实现。
遍历点云计算好曲率后会对曲率进行从小到大的排序。为了保证特征点的均匀获取,会将点云分成6个部分,每个部分选取一定数量的特征点。
2.点云匹配与误差函数
图片引用于https://huangwang.github.io/2019/01/05/%E5%90%91%E9%87%8F%E7%82%B9%E7%A7%AF%E5%8F%89%E7%A7%AF%E5%8F%8A%E5%85%B6%E5%87%A0%E4%BD%95%E6%84%8F%E4%B9%89/
最终的误差函数是两项误差的和。最后用LM方法迭代(代码中最大迭代25次)求解出前后两帧激光的位姿差。
从Lidar Odometry模块中,我们可以得到一帧已经去除畸变的激光点云数据和相对于前一帧的粗糙位姿变换。Lidar Mapping模块的任务就是用与地图进行匹配得到一个更为精确的帧间位姿变换,然后建图,为下次匹配做好准备。这里使用的匹配方法与Lidar Odometry模块中是一致的。不同的地方在于这里提取的特征点数量是Lidar Odometry模块的10倍。特征点的匹配不是找对应的2个或者3个特征点。而是相对于当前帧,在地图中对应位置附近10m10m10m的Cubic中提取所有的特征点。筛选出最近的5个特征点,然后计算协方差。对协方差进行特征值分解,最大特征值对应的向量就是需要匹配的Edge line方向向量,最小特征值对应的向量就是需要匹配的Planar patch方向向量。分别在Edge line上选取两个点,在Planar patch上选取三个点,按照点到线的距离公式和点到面的距离公式构建误差方程。同样使用LM方法迭代(最多迭代10次)求解,得到一个更为精确的帧间位姿变换。
Transform Integration
Transform Integration模块主要是融合了Lidar Mapping得到的位姿变换和Lidar Odometry得到的位姿变换。最终发布一个频率与Lidar Odometry发布频率一致的位姿变换。
LOAM_velodyne学习该专栏对LOAM代码的的4个模块都做了分析
LOAM 论文及原理分析这篇文章对论文内容做了较为详细的解释
LOAM SLAM代码解析之一:scanRegistration.cpp 点云及IMU数据处理节点这篇文章对IMU数据处理和特征点选取的代码作了分析解释
收集的材料放到自己的github上了:https://github.com/shoufei403/loam_leanring.git
1.LOAM认为一帧激光点云的间隔时间内激光器是匀加减速运动的,并且在点云畸变去除时使用了IMU数据来去除非匀速部分的畸变,然后在Lidar Mapping模块中还利用IMU数据求出平均速度来去除匀速运动引起的畸变。而A-LOAM只认为一帧激光点云的间隔时间内激光器是匀速运动的。然后直接根据时间进行线性插值来进行点云运动畸变去除。很显然LOAM对激光器的运动描述的更为准确,所以效果会更好。
2.A-LOAM使用ceres进行非线性优化求解。而LOAM是作者手写的非线性求解器。这一部分我看不太懂,但猜测代码的工程实现上会有优化,代码执行效率可能更高。