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论文解读---完整篇
|
XML 存储 网络安全
ROS入门(二):launch文件解析
该文章是关于ROS入门的第二篇教程,详细解析了ROS中的launch文件,包括其运行方式、XML格式规范、标签使用、参数替代、条件属性以及通过简单和复杂案例来演示launch文件的使用,最后介绍了如何在参数服务器上设置参数。
ROS入门(二):launch文件解析
|
传感器 自动驾驶 机器人
大疆Livox Mid360 使用指南
本文是大疆Livox Mid-360激光雷达的使用指南,包括Livox Viewer 2的安装与使用、Livox SDK2的安装与演示、Livox ROS的配置与启动,以及一些使用时的注意事项。文章还提供了关于Livox Mid-360的详细特点、接线信息、尺寸信息、主控端IP设置、修改Livox Mid 360的IP方法、坐标系定义和IMU内参的介绍。此外,还提供了官方资料和软件下载的链接。
5812 2
|
JSON 算法 数据可视化
Open3d-Point cloud (点云)
Open3d-Point cloud (点云)
1195 6
|
传感器 编解码 算法
LeGO-LOAM算法详解
LeGO-LOAM算法详解
797 0
LeGO-LOAM算法详解
|
安全 定位技术
ENVI软件App Store插件工具的下载、安装与使用方法
ENVI软件App Store插件工具的下载、安装与使用方法
817 1
|
传感器 存储 前端开发
视觉SLAM 关键技术与发展概述
最近看了北京理工大学的课程《智能车辆概述与应用》,感觉入门角度讲的还不错的,于是通过本文记录关键内容。
760 0
|
算法 安全 物联网
【BLE】 BLE安全管理 - SM层剖析(2)
上一章介绍了配对流程的第一阶段,剖析了配对第一阶段的配对请求包和配对响应包的各个字段的含义和使用。接下来就进入了ble配对的阶段二,在该阶段双方会根据阶段一中的配对信息选择合适的配对和认证方式,并且生成会后续链接加密的密钥。
516 1
【BLE】 BLE安全管理 - SM层剖析(2)
解决 ERROR: cannot launch node of type [xxx]: can‘t locate node [xxx] in package [xxx]
解决 ERROR: cannot launch node of type [xxx]: can‘t locate node [xxx] in package [xxx]
1591 0
|
传感器 存储 编解码
Loam算法详解(配合开源代码aloam)
Loam算法详解(配合开源代码aloam)
1358 0
Loam算法详解(配合开源代码aloam)