3D激光slam:LeGO-LOAM---地面点提取方法及代码分析

简介: **地面点提取方法**LeGO-LOAM中前端改进中很重要的一点就是充分利用地面点,本片博客主要讲解 如何进行地面点提取如下图所示,相邻的两个scan的同一列,打在地面上,形成两个点A和B。

前言

地面点提取方法

LeGO-LOAM中前端改进中很重要的一点就是充分利用地面点,本片博客主要讲解 如何进行地面点提取

如下图所示,相邻的两个scan的同一列,打在地面上,形成两个点A和B。
在这里插入图片描述

它们的垂直高度差为h,这个值在理想情况(雷达水平安装,地面是水平的)接近于0
在这里插入图片描述
水平距离差d
在这里插入图片描述
和水平面的夹角为
在这里插入图片描述
如果为地面点,在理想情况下,这个角点接近0.

但是雷达的安装不会完全水平,并且地面也不是平的,因此这个角度会大于0,LeGO-LOAM设置的是10°。
即小于10°被判断为地面点

这种地面点的提取算法有些过于简单,还可以结合激光雷达安装高度,等其它信息进行判断。例如下面这种情况,也会被判断为地面点:
在这里插入图片描述

代码分析

LeGO-LOAM的地面提取的代码在 imageProjection.cppgroundRemoval 函数

    void groundRemoval(){
        size_t lowerInd, upperInd;
        float diffX, diffY, diffZ, angle;

lowerInd, upperInd 是相邻scan上点的索引值
diffX, diffY, diffZ, angle 是 dx dy dz 水平角

        for (size_t j = 0; j < Horizon_SCAN; ++j){//遍历水平方向的点 360/0.2 1800个点
            for (size_t i = 0; i < groundScanInd; ++i){//groundScanInd 为8  地面点不能在上面

嵌套两个for循环, 列要在前面,因为要计算同一列的值

第一行,遍历水平方向的点 360/0.2 1800个点
第二行,groundScanInd 为8 地面点不能在上面

                lowerInd = j + ( i )*Horizon_SCAN;//下面的点
                upperInd = j + (i+1)*Horizon_SCAN;//上面的点

计算的两个点的索引
Horizon_SCAN为1800,

                if (fullCloud->points[lowerInd].intensity == -1 ||
                    fullCloud->points[upperInd].intensity == -1){
                    // no info to check, invalid points
                    groundMat.at<int8_t>(i,j) = -1;//标志位 至-1
                    continue;
                }              

判断两个点是否有效,点无效的话intensity为-1
有一个点无效的话 标志位 至-1

                diffX = fullCloud->points[upperInd].x - fullCloud->points[lowerInd].x;//dx
                diffY = fullCloud->points[upperInd].y - fullCloud->points[lowerInd].y;//dy
                diffZ = fullCloud->points[upperInd].z - fullCloud->points[lowerInd].z;//dz

                angle = atan2(diffZ, sqrt(diffX*diffX + diffY*diffY) ) * 180 / M_PI;//计算水平角度

计算 dx dy dz 和水平角,就是这个公式
在这里插入图片描述

                if (abs(angle - sensorMountAngle) <= 10){
                    groundMat.at<int8_t>(i,j) = 1;
                    groundMat.at<int8_t>(i+1,j) = 1;
                }
            }
        }

sensorMountAngle 是 liadr 是和水平面的倾斜角
这里就是把那两个点的水平角,和10°做比较,判断是不是地面点
如何使把标志位 至 1

        for (size_t i = 0; i < N_SCAN; ++i){
            for (size_t j = 0; j < Horizon_SCAN; ++j){
                if (groundMat.at<int8_t>(i,j) == 1 || rangeMat.at<float>(i,j) == FLT_MAX){
                    labelMat.at<int>(i,j) = -1;//labelMat 至为 -1 ,不参与后续线特征和面特征的提取
                }
            }
        }

判断完地面点后,再遍历每个点,
如过该点是 地面点或者无效点,则把 labelMat 上的该点标志位至-1 .
labelMat 至为 -1 ,不参与后续线特征和面特征的提取

        //地面点可视化 
        if (pubGroundCloud.getNumSubscribers() != 0){//如果有节点要订阅这个地面点的topic 再进行发布
            for (size_t i = 0; i <= groundScanInd; ++i){
                for (size_t j = 0; j < Horizon_SCAN; ++j){
                    if (groundMat.at<int8_t>(i,j) == 1)
                        groundCloud->push_back(fullCloud->points[j + i*Horizon_SCAN]);//把点加在 地面点点云中  之后会发布出去
                }
            }
        }
    }

最后进行地面点得可视化
如果有节点要订阅这个地面点的topic 再进行发布
遍历0-groundScanInd 上得每个点,判断如果是地面点,则添加该点到 groundCloud 中

之后会被发布出去

发布得在这个地方

        // original dense ground cloud
        if (pubGroundCloud.getNumSubscribers() != 0){
            pcl::toROSMsg(*groundCloud, laserCloudTemp);
            laserCloudTemp.header.stamp = cloudHeader.stamp;
            laserCloudTemp.header.frame_id = "base_link";
            pubGroundCloud.publish(laserCloudTemp);
        }

topic得名称是/ground_cloud

pubGroundCloud = nh.advertise<sensor_msgs::PointCloud2> ("/ground_cloud", 1);

gazebo测试

在这里插入图片描述
在这里插入图片描述
效果还是挺好得,没有出现异常点

但是由于没有加入高度得判断,在前面里说得这种情况则会出现问题
在这里插入图片描述
在这里插入图片描述

相关文章
|
存储 前端开发 算法
激光SLAM:ALOAM---后端lasermapping地图栅格化处理与提取
不同于前端的scan-to-scan的过程,ALOAM的后端是scan-to-map的算法,具体来说就是把当前帧和地图进行匹配,得到更准确的位姿同时也可以构建更好的地图.由于是scan-to-map的算法,因此计算量会明显高于scan-to-scan的前端,所以后端通常处于一个低频的运行频率,但是由于scan-to-map的精度往往优于scan-to-scan.因此后端也有比前端更高的精度.为了提高后端的处理速度,所以要进行地图的栅格化处理
激光SLAM:ALOAM---后端lasermapping地图栅格化处理与提取
|
存储 前端开发 数据可视化
3D激光SLAM:LeGO-LOAM---两步优化的帧间里程计及代码分析
**LeGO-LOAM**的全称是 Lightweight and Ground-Optimized Lidar Odometry and Mapping on Variable Terrain 其中LeGO就是轻量级和利用地面优化,轻量级的实现就是通过两步的优化方式,利用地面优化的部分也在两步优化的第一步中。 和原始LOAM一样,通过前后两帧点云来估计两帧之间的运动,从而累加得到前端里程计的输出,和上述方法使用线面约束同时优化六自由度帧间位姿不同,LeGO-LOAM的前端分成两个步骤,每个步骤估计三自由度的变量。 通过这种方式进行帧间里程计的运算,可以提供运算效率,使得可以在嵌入式平台
3D激光SLAM:LeGO-LOAM---两步优化的帧间里程计及代码分析
|
存储 传感器 编解码
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论文解读---完整篇
|
计算机视觉
【状态估计】基于卡尔曼滤波器和扩展卡尔曼滤波器用于 INS/GNSS 导航、目标跟踪和地形参考导航研究(Matlab代码实现)
【状态估计】基于卡尔曼滤波器和扩展卡尔曼滤波器用于 INS/GNSS 导航、目标跟踪和地形参考导航研究(Matlab代码实现)
|
传感器 机器学习/深度学习 算法
【滤波跟踪】基于卡尔曼滤波实现ins与gps松组合导航附matlab代码
【滤波跟踪】基于卡尔曼滤波实现ins与gps松组合导航附matlab代码
|
机器学习/深度学习 传感器 存储
2022最新!视觉SLAM综述(多传感器/姿态估计/动态环境/视觉里程计)(下)
论文调查的主要目的是介绍VSLAM系统的最新进展,并讨论现有的挑战和未来趋势。论文对在VSLAM领域发表的45篇有影响力的论文进行了深入的调查,并根据不同的特点对这些方法进行了分类,包括novelty domain、目标、采用的算法和语义水平。最后论文讨论了当前的趋势和未来的方向,有助于研究人员进行研究。
2022最新!视觉SLAM综述(多传感器/姿态估计/动态环境/视觉里程计)(下)
|
传感器 机器学习/深度学习 数据采集
2022最新!视觉SLAM综述(多传感器/姿态估计/动态环境/视觉里程计)(上)
论文调查的主要目的是介绍VSLAM系统的最新进展,并讨论现有的挑战和未来趋势。论文对在VSLAM领域发表的45篇有影响力的论文进行了深入的调查,并根据不同的特点对这些方法进行了分类,包括novelty domain、目标、采用的算法和语义水平。最后论文讨论了当前的趋势和未来的方向,有助于研究人员进行研究。
2022最新!视觉SLAM综述(多传感器/姿态估计/动态环境/视觉里程计)(上)
|
传感器 编解码 算法
LeGO-LOAM算法详解
LeGO-LOAM算法详解
471 0
LeGO-LOAM算法详解
Threejs实现机械臂运动,机械臂dae格式模型,模型下载
Threejs实现机械臂运动,机械臂dae格式模型,模型下载
527 0
Threejs实现机械臂运动,机械臂dae格式模型,模型下载
|
前端开发 定位技术 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点预处理部分代码解读