3D激光SLAM:LeGO-LOAM---两步优化的帧间里程计及代码分析

简介: **LeGO-LOAM**的全称是 Lightweight and Ground-Optimized Lidar Odometry and Mapping on Variable Terrain其中LeGO就是轻量级和利用地面优化,轻量级的实现就是通过两步的优化方式,利用地面优化的部分也在两步优化的第一步中。和原始LOAM一样,通过前后两帧点云来估计两帧之间的运动,从而累加得到前端里程计的输出,和上述方法使用线面约束同时优化六自由度帧间位姿不同,LeGO-LOAM的前端分成两个步骤,每个步骤估计三自由度的变量。通过这种方式进行帧间里程计的运算,可以提供运算效率,使得可以在嵌入式平台

前言

LeGO-LOAM的全称是 Lightweight and Ground-Optimized Lidar Odometry and Mapping on Variable Terrain

其中LeGO就是轻量级和利用地面优化,轻量级的实现就是通过两步的优化方式,利用地面优化的部分也在两步优化的第一步中。

和原始LOAM一样,通过前后两帧点云来估计两帧之间的运动,从而累加得到前端里程计的输出,和上述方法使用线面约束同时优化六自由度帧间位姿不同,LeGO-LOAM的前端分成两个步骤,每个步骤估计三自由度的变量。

通过这种方式进行帧间里程计的运算,可以提供运算效率,使得可以在嵌入式平台中运行

在里程计部分,LeGO-LOAM充分利用了前面存储的标签信息,在原本LOAM的里程计部分,其使用的思路更像是ICP,单纯寻找距离最近的点,而并没有考虑其合理性。在这里,LeGO-LOAM通过标签增加了一次筛选,标签相同的点才会用于优化,通过这种方法,能够大幅提高匹配的准确率。

此外,在优化部分,LOAM使用的是直接将所有参数放在一起,进行LM优化,而在LeGO-LOAM中,作者将LM优化分两步进行,每次优化三个参数,在确保准确性的前提下,减小了35%的计算开销。

利用地面点优化

地面点更符合面特征的性质,因此地面点的优化问题就使用点到面的约束来构建

地面点的约束对x,y,yaw这三个自由度是不能估测的。当这个三个自由度的值发生变化,点到面的残差不会发生显著变化,
地面点的优化,只对pitch、roll及z进行约束和优化

在这里插入图片描述
在这里插入图片描述
白色的为当前帧,绿色的为上一帧,可以看到当前帧发生yaw的旋转,和发生x、y的平移的时候,当前帧的面点到上一帧的距离都没有变,所有不能把这三个自由度的优化放到面点特征上来。

当z轴发生移动,或者发生pitch和roll角的变化,当前帧的面特征点,到上一帧的面特征点的距离即发生变化。

利用角点优化

第一步优化完pitch、roll和z之后,剩下还有三个自由度的变量需要进行估计,
需要提取角点进行优化,由于多线激光雷达提取的角点通常是垂直的边缘特征,因此对,x、y及yaw有着比较好的能观性,通过角点的优化结合上地面点的结果可以得到六自由度的帧间优化结果。

将上一步分优化的z、pitch和roll的三自由度量,和剩下没有估计的三个自由度进行角点的约束优化。

代码部分

LeGO-LOAM的帧间里程计部分在FeatureAssociation.cpp中 。
可以直接找到runFeatureAssociation的函数

        adjustDistortion();//去除畸变

        calculateSmoothness();//计算曲率

        markOccludedPoints();//剔除离散点

        extractFeatures();//提取特征

        publishCloud(); // cloud for visualization
    
        /**
        2. Feature Association
        */
        if (!systemInitedLM) {
            checkSystemInitialization();
            return;
        }

        updateInitialGuess();

        updateTransformation();//帧间里程计核心部分

        integrateTransformation();

        publishOdometry();

        publishCloudsLast(); // cloud to mapOptimization

在这个函数中进行了

  • 去除畸变
  • 计算曲率
  • 剔除离散点
  • 提取特征
  • 帧间里程计核心部分
  • 发布里程计
  • 发布点云

其中帧间里程计核心部分在 updateTransformation() 函数中

    void updateTransformation(){

        if (laserCloudCornerLastNum < 10 || laserCloudSurfLastNum < 100)
            return;

        //地面点帧间里程计估计优化
        for (int iterCount1 = 0; iterCount1 < 25; iterCount1++) {
            laserCloudOri->clear();
            coeffSel->clear();

            findCorrespondingSurfFeatures(iterCount1);//通过kdtree 寻找对应的点

            if (laserCloudOri->points.size() < 10)
                continue;
            if (calculateTransformationSurf(iterCount1) == false)//进行优化估计
                break;
        }

        //角点帧间里程计估计优化
        for (int iterCount2 = 0; iterCount2 < 25; iterCount2++) {

            laserCloudOri->clear();
            coeffSel->clear();

            findCorrespondingCornerFeatures(iterCount2);//通过kdtree 寻找对应的点

            if (laserCloudOri->points.size() < 10)
                continue;
            if (calculateTransformationCorner(iterCount2) == false)//进行优化估计
                break;
        }
    }

从这个函数中可以明显看出分成了两部分

  • 第一个for循环是 地面点帧间里程计估计优化
  • 第二个for循环是 角点帧间里程计估计优化

在这里插入图片描述
从这里可以看出surfPointsFlat中的点都是地面点

然后在findCorrespondingSurfFeatures的函数中,进行当前帧的地面点与上一帧中的地面点进行匹配。
其过程和ALOAM中的原理一致。

findCorrespondingCornerFeatures的函数中,进行当前帧的角点与上一帧中的角点进行匹配。
其过程和ALOAM中的原理一致。

当前帧角点i,映射到上一帧点云中,并找到距离最近的点j,在与j相同的scan中,寻找次近邻点m。
利用映射后的点i到j和m的距离,进行约束

通过两步优化的位姿变换通过里程计数据的方式发送出来可以进行可视化的操作
具体代码在 publishOdometry() 函数中

当前帧角点i,映射到上一帧点云中,并找到距离最近的点j,并在相同scan中找到次近邻点l,在相邻的scan中再找到近邻点m。
利用映射后的点i到j、l、m平面的距离,进行约束。

//发布前端里程计
    void publishOdometry(){
        geometry_msgs::Quaternion geoQuat = tf::createQuaternionMsgFromRollPitchYaw(transformSum[2], -transformSum[0], -transformSum[1]);

        laserOdometry.header.stamp = cloudHeader.stamp;
        laserOdometry.pose.pose.orientation.x = -geoQuat.y;
        laserOdometry.pose.pose.orientation.y = -geoQuat.z;
        laserOdometry.pose.pose.orientation.z = geoQuat.x;
        laserOdometry.pose.pose.orientation.w = geoQuat.w;
        laserOdometry.pose.pose.position.x = transformSum[3];
        laserOdometry.pose.pose.position.y = transformSum[4];
        laserOdometry.pose.pose.position.z = transformSum[5];
        pubLaserOdometry.publish(laserOdometry);

        laserOdometryTrans.stamp_ = cloudHeader.stamp;
        laserOdometryTrans.setRotation(tf::Quaternion(-geoQuat.y, -geoQuat.z, geoQuat.x, geoQuat.w));
        laserOdometryTrans.setOrigin(tf::Vector3(transformSum[3], transformSum[4], transformSum[5]));
        tfBroadcaster.sendTransform(laserOdometryTrans);
    }

其topic的名称为:
在这里插入图片描述

gazebo测试

在这里插入图片描述
前端的里程计在Z轴方向已经发生了漂移。
但是地图没有飘,这个是后端进行优化的结果,将前端漂移的部分优化了回来

相关文章
|
存储 传感器 编解码
3D激光SLAM:LeGO-LOAM论文解读---完整篇
![在这里插入图片描述](https://img-blog.csdnimg.cn/348d0b4467a24296a22413207566c67e.png) 论文的标题是:**LeGO-LOAM: Lightweight and Ground-Optimized Lidar Odometry and Mapping on Variable Terrain** - 标题给出的应用场景是 **可变地形** - 重点是 **轻量级** 并 利用 **地面优化** - 本质依然是一个 **激光雷达里程计和建图**
3D激光SLAM:LeGO-LOAM论文解读---完整篇
|
5月前
|
编解码 并行计算 算法
MPI分形图像高精度绘制程序和PC端Mandelbrot-Julia分形集预览程序
这篇文章描述了一个使用2010年技术的集群程序,该程序基于Linux + MPI + C++或Windows + .NET + C#,用于并行计算生成高分辨率BMP图像,特别是Mandelbrot和Julia集。在8台节点上,程序实现了7.31的稳定加速比,并在更大规模任务中有望提升。它支持MPI并行计算、任务日志、不同阶数的分形集生成、批处理、多线程以及优化的颜色处理等功能。创新点包括颜色表的正弦控制、动态调整运算精度、复杂颜色生成、优化的颜色更新和并发机制等。程序产生的图像样本显示了其多样性和质量。作者提供源代码,并提到设计思路可应用于类似图像生成任务。
|
6月前
|
传感器 定位技术
Ardupilot — EKF3使用光流室内定位代码梳理
Ardupilot — EKF3使用光流室内定位代码梳理
161 0
|
计算机视觉
【状态估计】基于卡尔曼滤波器和扩展卡尔曼滤波器用于 INS/GNSS 导航、目标跟踪和地形参考导航研究(Matlab代码实现)
【状态估计】基于卡尔曼滤波器和扩展卡尔曼滤波器用于 INS/GNSS 导航、目标跟踪和地形参考导航研究(Matlab代码实现)
|
传感器 机器学习/深度学习 算法
【滤波跟踪】基于卡尔曼滤波实现ins与gps松组合导航附matlab代码
【滤波跟踪】基于卡尔曼滤波实现ins与gps松组合导航附matlab代码
|
前端开发 定位技术 C++
3D激光SLAM:A-LOAM :前端lidar点预处理部分代码解读
A-LOAM的cpp有四个,其中 kittiHelper.cpp 的作用是将kitti数据集转为rosbag 剩下的三个是作为 slam 的 部分,分别是: - laserMappin.cpp ++++ 当前帧到地图的优化 - laserOdometry.cpp ++++ 帧间里程计 - scanRegistration.cpp ++++ 前端lidar点预处理及特征提取 本片主要解读 前端lidar点预处理部分的代码
3D激光SLAM:A-LOAM :前端lidar点预处理部分代码解读
|
Ubuntu 定位技术
A-LOAM配置过程
A-LOAM配置过程
359 0
|
机器学习/深度学习 算法 计算机视觉
【滤波跟踪】基于自适应UKF和UKF算法实现运动刚体的位姿估计附matlab代码
【滤波跟踪】基于自适应UKF和UKF算法实现运动刚体的位姿估计附matlab代码
|
编解码 算法 数据可视化
3D激光slam:LeGO-LOAM---基于广度优先遍历的点云聚类算法及代码分析
## 广度优先遍历(BFS)算计介绍 广度优先遍历(BFS)和深度优先遍历(DFS)同属于两种经典的图遍历算法 **广度优先遍历算法**:首先从某个节点出发,一层一层的遍历,下一层必须等到上一层节点全部遍历完之后才会开始遍历 **基本思想**:尽最大程度辐射能够覆盖的节点,并对其进行访问。
3D激光slam:LeGO-LOAM---基于广度优先遍历的点云聚类算法及代码分析
|
前端开发 算法 数据可视化
3D激光slam:LeGO-LOAM---地面点提取方法及代码分析
**地面点提取方法** LeGO-LOAM中前端改进中很重要的一点就是充分利用地面点,本片博客主要讲解 如何进行地面点提取 如下图所示,相邻的两个scan的同一列,打在地面上,形成两个点A和B。
3D激光slam:LeGO-LOAM---地面点提取方法及代码分析