系列文章目录

·【ROS】中级操作学习整理-gazebo机器人仿真

·【ROS】中级操作学习整理-TF坐标变换

·【ROS】中级操作学习整理-传感器建模

·【ROS】中级操作学习整理-激光SLAM

文章目录

系列文章目录

文章目录

前言

一、地图描述格式

二、gmapping

三、hector

四、cartograph

五、karto

总结


前言

前面介绍了如何在gazebo中建立自己的移动机器人模型,并且我们为机器人建模了传感器,使得我们的机器人在仿真环境中也可以感知周围的环境,那么这篇文章就可以根据之前的工作,利用激光雷达来感知周围的环境,构建环境地图。

这篇文章要讲的SLAM(Simultaneous localization and mapping)-同步定位与建图是我感兴趣的方向,SLAM的问题可以描述为:将一个机器人放入未知环境中的未知位置,是否有办法让机器人一边移动一边逐步描绘出此环境完全的地图,在这个过程中机器人可以实现自身的定位和周围环境的感知,并为下一步的导航和路径规划做好准备。

SLAM分为激光SLAM(主要传感器是激光雷达)和视觉SLAM(主要传感器是相机),SLAM是1988年才提出的概念,现在理论发展基本饱和,SLAM的框架已经大概搭建完毕,现在正处于应用的巅峰期,SLAM领域门槛较高,亟需顶尖人才。

关于更多SLAM的知识可以参考高翔博士的《视觉SLAM十四讲》或者更多网络上的资源,这篇文章我们还是以ROS为主,讲解ROS中集成的一些激光SLAM算法,以及他们如何在我们的机器人上应用起来。

一、地图描述格式

在介绍激光SLAM算法之前,我们先介绍一下在ROS中地图是怎么存储和传递的。

在ROS中地图(map)其实也是一个话题,可以由建图算法发布,由路径规划节点订阅,或者由rviz节点订阅进行可视化显示,map的数据结构如下:

std_msgs/Header header          // 数据的消息头uint32 seq                    // 数据的序号time stamp                    // 数据的时间戳string frame_id               // 地图的坐标系
nav_msgs/MapMetaData info       // 地图的一些信息time map_load_time            // 加载地图的时间float32 resolution            // 地图的分辨率,一个格子代表着多少米,一般为0.05,[m/cell]uint32 width                  // 地图的宽度,像素的个数, [cells]uint32 height                 // 地图的高度,像素的个数, [cells]geometry_msgs/Pose origin     // 地图左下角的格子对应的物理世界的坐标,[m, m, rad]geometry_msgs/Point positionfloat64 xfloat64 yfloat64 zgeometry_msgs/Quaternion orientationfloat64 xfloat64 yfloat64 zfloat64 w
// 地图数据,优先累加行,从(0,0)开始。占用值的范围为[0,100],未知为-1。
int8[] data 

比较重要的有frame_id用来描述地图的坐标系,width和height用来描述地图的高度和宽度,data这是一个变长度数组用来记录地图栅格的占用情况,ROS中地图的栅格占用情况是通过概率表示的,表示这个栅格有多大的概率被占用。

二、gmapping

Gmapping是一个基于2D激光雷达使用RBPF(Rao-Blackwellized Particle Filters)算法完成二维栅格地图构建的SLAM算法,算是性能较好且最常用的激光SLAM算法了,我们这里只谈gmapping的应用,而不具体深究它的算法实现。

优点:gmapping可以实时构建室内环境地图,在小场景中计算量少,且地图精度较高,对激光雷达扫描频率要求较低。

缺点:随着环境的增大,构建地图所需的内存和计算量就会变得巨大,所以gmapping不适合大场景构图。一个直观的感受是,对于200x200米的范围,如果栅格分辨率是5cm,每个栅格占用一个字节内存,那么每个粒子携带的地图都要16M的内存,如果是100粒子就是1.6G内存。

可以通过以下的命令安装gmapping算法

sudo apt-get install ros-noetic-gmapping

gmapping订阅和发布的话题

gmapping算法订阅tf话题和雷达数据话题scan,雷达数据不用说,由激光雷达发布,这里的tf需要注意,一定要包含机器人底盘坐标系(base_frame)和里程计坐标系(odom_frame)之间的坐标变换关系,因为SLAM解决的是定位问题,需要由这个tf经过算法,计算得出机器人(base_frame)与环境(map_frame)之间的相对位置,这个过程就是定位的过程。

因此gmapping发布了新的tf变换,并且发布三个话题,map就是创建的二维栅格地图,map_metadata主要包含地图的数据,还有机器人位姿估计的熵entropy(平时用不到,我认为是用来评估算法性能的)

虽然ROS中集成了gmapping算法,但是我们也需要创建一个launch文件来调整gmapping的一些参数,以获得我们需要的性能,具体的参数含义可以参考ros的官方说明,这里只对一些需要注意的参数进行说明。

<launch><arg name="scan_topic" default="/scan" />                  <!-- 根据自己发布scan名称进行修改 --><node pkg="gmapping" type="slam_gmapping" name="slam_gmapping" output="screen" clear_params="true"><param name="base_frame" value="/base_footprint"/>     <!-- 根据自己的基座标系名称进行修改 --><param name="odom_frame" value="/odom"/>               <!-- 根据自己的里程计坐标系名称进行修改 --><param name="map_update_interval" value="4.0"/><!-- Set maxUrange < actual maximum range of the Laser --><param name="maxRange" value="5.0"/><param name="maxUrange" value="4.5"/><param name="sigma" value="0.05"/><param name="kernelSize" value="1"/><param name="lstep" value="0.05"/><param name="astep" value="0.05"/><param name="iterations" value="5"/><param name="lsigma" value="0.075"/><param name="ogain" value="3.0"/><param name="lskip" value="0"/><param name="srr" value="0.01"/><param name="srt" value="0.02"/><param name="str" value="0.01"/><param name="stt" value="0.02"/><param name="linearUpdate" value="0.5"/><param name="angularUpdate" value="0.436"/><param name="temporalUpdate" value="-1.0"/><param name="resampleThreshold" value="0.5"/><param name="particles" value="80"/><param name="xmin" value="-1.0"/><param name="ymin" value="-1.0"/><param name="xmax" value="1.0"/><param name="ymax" value="1.0"/><param name="delta" value="0.05"/><param name="llsamplerange" value="0.01"/><param name="llsamplestep" value="0.01"/><param name="lasamplerange" value="0.005"/><param name="lasamplestep" value="0.005"/><remap from="scan" to="$(arg scan_topic)"/></node>
</launch>

代码段中通过注释,标注了三个一定需要我们根据自己机器人信息修改的参数,这几个参数需要通过rostopic list具体查看到底是哪个话题在发布,修改成对应的话题,构建了这个launch文件,我们就可以愉快的启动gmapping算法进行建图了,可以把gmapping与启动gazebo仿真环境的代码放在一个一个launch文件中启动。

<launch><include file="$(find mbot_gazebo)/launch/view_mbot_with_laser_gazebo.launch"/><include file="$(find my_mapping)/launch/my_gmapping.launch"/><include file="$(find my_mapping)/launch/mbot_movebase.launch"/><node pkg="rviz" type="rviz" name="rviz" args="-d $(find my_mapping)/config/my_gmapping.rviz"/>
</launch>

当然,这个文件中我还包含了movebase路径规划的配置文件,目前是我们不需要的;还包含了rviz的配置文件,当然你也可以打开一个rviz界面进行手动设置。

运行gmapping算法后,机器人的tf树上会出现图中红框的部分,这部分就是由gmapping算法发布的新tf变换,另外,使用rostopic工具也可以看到gmapping发布的话题。

我们在gazebo仿真环境中添加一些能被雷达检测到的障碍物,然后启动机器人键盘控制器节点,让机器人在环境中走一圈,看看构建出的地图是什么样子。

这里就大概完成了一张地图的创建,我们可以使用一下这行命令将地图保存到当前目录下。

rosrun map_server map_saver [-f filename]

保存的地图有两个文件,pgm格式的文件像是一张图像,yaml文件中记录了地图的信息,将地图保存下来后,在今后的仿真环境导航工作中就可以直接使用map_server节点直接加载地图了。

加载地图的命令:

rosrun map_server map_server filename.yaml

下面是yaml文件中记录的信息

三、hector

hector_slam算法与gmapping一样都是建图算法,但是hector的特点是不需要里程计的信息即可完成建图,他只需要接收雷达的信息,使用高斯牛顿方法进行建图,下面来看一下hector订阅和发布的信息

hector不需要odom与base之间的坐标系变换,但是需要知道laser坐标系和base坐标系之间的坐标变换,这一部分的坐标变换关系我们可以通过robot_state_publisher发布的机器人坐标变换关系获取,然后hector会发布map与odom之间的坐标变换,以确定机器人在环境中的位置。

也可以通过以下的代码安装hector_slam

sudo apt-get install ros-noetic-hector-slam

然后也可以像启动gmapping一样,通过配置hector的launch文件,配置它的参数

<launch><include file="$(find mbot_gazebo)/launch/view_mbot_with_laser_gazebo.launch"/><node pkg="hector_mapping" type="hector_mapping" name="hector_height_mapping" output="screen"><!--Frame names--><param name="pub_map_odom_transform" value="true"/><param name ="map_frame" value ="map"/><param name="base_frame" value="base_link" /><param name="odom_frame" value="odom" /><!--TF use--><param name="use_tf_scan_transformation" value="true"/><param name="use_tf_pose_start_estimate" value="false"/><!--mapsize /start point--><param name="map_resolution" value="0.05"/><param name="map_size" value="1024"/><param name="map_start_x" value="0.5"/><param name="map_start_y" value="0.5"/><param name="laser_z_min_value" value="-1.0"/><param name="laser_z_max_value" value="1.0"/><param name="map_multi_res_levels" value="2"/><param name="map_pub_period" value="1"/><param name="laser_min_dist" value="0.4"/><param name="laser_max_dist" value="5.5"/><param name="output_timing" value="false"/><param name="pub_map_scanmatch_transform"  value="true"/><!--map update parameter--><param name="update_factor_free" value="0.45"/><param name="update_factor_occupied" value="0.7"/><param name="map_update_distance_thresh" value="0.1"/><param name="map_update_angle_thresh" value="0.05"/><!--Advertising  config--><param name="scan_topic" value="scan" /><param name="advertise_map_service" value="true"/><param name="map_with_known_poses" value="false"/><param name="scan_subscriber_queue_size" value="5"/></node><!-- Move base --><include file="$(find my_mapping)/launch/mbot_movebase.launch"/></launch>

其中需要注意的地方也是frame的名字,需要与你的机器人坐标系匹配,更多关于参数的含义可以参考官网的说明。

hector可以代替gmapping算法进行建图,在上面的launch文件中,我也添加了机器人仿真环境的启动和movebase框架的启动,下面就运行一下launch文件一起看一下它的效果。

然后也可以使用tf工具,可视化其中的坐标变换关系

当然也可以使用map_server节点将地图保存下来

另外,hector提供了另一个节点也可以用来保存地图及机器人的地理位置信息-geotiff_node,可以通过这行代码,将地图保存为一个包含图像数据的 .tif 文件和一个包含地理参考信息的 .tfw 文件。

rostopic pub syscommand std_msgs/String "savegeotiff"

最后,这个包提供了一个节点hector_trajectory_server,可以在给定目标和源框架的情况下保存基于tf的轨迹数据,轨迹在内部保存为nav_msgs/Path,可以使用服务或主题获取。在内部,一个 tf::Transformlistener 监听tf,执行必要的转换并将生成的姿势推送到保存的轨迹。更新和发布速率可以通过参数进行修改。

优缺点:不需要里程计,但对于雷达帧率要求很高40Hz,估计6自由度位姿,可以适应空中或者地面不平坦的情况。初值的选择对结果影响很大,所以要求雷达帧率较高

四、cartograph

cartographer是google开发的实时室内SLAM项目,cartographer采用基于google自家开发的ceres非线性优化的方法,cartographer的亮点在于代码规范与工程化,非常适合于商业应用和再开发。并且cartographer基于submap子图构建全局地图的思想,能有效的避免建图过程中环境中移动物体的干扰。并且cartographer支持多传感器数据(odometry、IMU、LaserScan等)建图,支持2D_SLAM和3D_SLAM建图。

这部分使用的是google的开源库,具体我没用过,可以参考这篇博客。

五、karto

karto是基于图优化的SLAM算法,用高度优化和非迭代cholesky矩阵进行稀疏系统解耦作为解。图优化方法利用图的均值表示地图,每个节点表示机器人轨迹的一个位置点和传感器测量数据集,箭头的指向的连接表示连续机器人位置点的运动,每个新节点加入,地图就会依据空间中的节点箭头的约束进行计算更新。路标landmark越多,内存需求越大,然而图优化方式相比其他方法在大环境下制图优势更大

karto采取的是spa(karto_slam)或g2o(nav2d), karto的前端与后端采取的是单线程进行

先运行下面的代码,安装karto_slam:

sudo apt-get install ros-kinetic-slam-karto

下面我们还是从应用的角度看看hector_slam需要那些话题的输入和输出

hector_slam的输入是激光雷达的数据scan和系统命令,另外还有一个必须要求的tf变换,就是odom与base之间的坐标变换(hector_slam需要里程计信息),然后它发布地图map、地图信息map_metadata、估计的机器人位姿slam_out_pose,然后像gmapping一样发布odom与map之间的坐标变换,另外他也提供了一个用来获取地图数据的服务。

然后我们将hector_slam的参数配置单独放置在一个yaml文件中,然后通过launch文件将参数加载到参数服务器上,下面是yaml文件

# General Parameters
use_scan_matching: true
use_scan_barycenter: true
minimum_travel_distance: 0.2
minimum_travel_heading: 0.174                  #in radians
scan_buffer_size: 70
scan_buffer_maximum_scan_distance: 20.0
link_match_minimum_response_fine: 0.8
link_scan_maximum_distance: 10.0
loop_search_maximum_distance: 4.0
do_loop_closing: true
loop_match_minimum_chain_size: 10
loop_match_maximum_variance_coarse: 0.4     # gets squared later
loop_match_minimum_response_coarse: 0.8
loop_match_minimum_response_fine: 0.8# Correlation Parameters - Correlation Parameters
correlation_search_space_dimension: 0.3
correlation_search_space_resolution: 0.01
correlation_search_space_smear_deviation: 0.03# Correlation Parameters - Loop Closure Parameters
loop_search_space_dimension: 8.0
loop_search_space_resolution: 0.05
loop_search_space_smear_deviation: 0.03# Scan Matcher Parameters
distance_variance_penalty: 0.3              # gets squared later
angle_variance_penalty: 0.349                # in degrees (gets converted to radians then squared)
fine_search_angle_offset: 0.00349               # in degrees (gets converted to radians)
coarse_search_angle_offset: 0.349            # in degrees (gets converted to radians)
coarse_angle_resolution: 0.0349                # in degrees (gets converted to radians)
minimum_angle_penalty: 0.9
minimum_distance_penalty: 0.5
use_response_expansion: false

具体的参数含义也可以参考官网说明,下面是启动的launch文件。

<launch><node pkg="slam_karto" type="slam_karto" name="slam_karto" output="screen"><rosparam command="load" file="$(find slam_sim_demo)/param/karto_params.yaml" /><param name="map_update_interval" value="1"/><param name="resolution" value="0.05"/></node><!-- Move base --><include file="$(find navigation_sim_demo)/launch/include/move_base.launch.xml"/></launch>

这是启动后的情况,我在launch文件中一并启动了movebase节点,因此我们可以通过rviz的插件2D Nav Goal设定目标点,来控制机器人移动,建立一张完整的地图。

创建完地图后,也可以使用map_server节点将地图保存下来,以便下次使用。

另外我们还可以在建图过程中启动rosbag,记录我们建图的过程,方便以后我们进行复盘

rosbag record -a

总结

本文介绍了5中ROS中常见的激光SLAM建图方法,其中最为常用的是gmapping_slam,另外,我们在激光SLAM使用讲解过程中,一并对如何保存地图、加载地图、地图数据格式进行了简要说明,这涉及到一个重要节点map_server。

另外,虽然我们对这些算法的原理和参数没有进行详尽的说明,但我们在每个建图算法中都附上了相关的官网和参考链接,以便读者进行查阅。

最后,我们对于每个激光slam算法都进行了仿真,通过图片向读者展现了他们的效果。

下一篇,我们将对视觉slam中的代表-orbslam进行说明

【ROS】中级操作学习整理-激光SLAM相关推荐

  1. 【ROS】中级操作学习整理-gazebo机器人仿真

    系列文章目录 ·[ROS]中级操作学习整理-gazebo机器人仿真 ·[ROS]中级操作学习整理-TF坐标变换 ·[ROS]中级操作学习整理-传感器建模 ·[ROS]中级操作学习整理-激光SLAM 目 ...

  2. SLAN学习笔记-激光SLAM和视觉SLAM基础

    问题来源 自动导航技术是机器人的关键技术,机器人要实现自主导航需要解决以下三个问题: 1.我在哪里? 2.到哪里去? 3.怎么去? 其中第一个问题是后面两个的基础,如果都不知道所处的位置,又怎么能确定 ...

  3. 机器人学习--图解激光SLAM

    转自:​​​​​​图解SLAM_「小白学移动机器人」一个专注分享移动机器人相关知识的公众号!-CSDN博客 学习参考使用. 正文 3.说明 本篇图解SLAM配合my_slam_gmapping阅读 4 ...

  4. 激光SLAM入门学习笔记

    激光SLAM入门学习笔记 激光SLAM入门学习笔记 一.推荐阅读书籍 二.推荐公众号.知乎.博客 1.公众号 2.知乎 3.博客 三.推荐阅读论文&代码(参考泡泡机器人) 2D激光SLAM 3 ...

  5. 彻底搞懂基于LOAM框架的3D激光SLAM全套学习资料汇总!

    地图定位算法是自动驾驶模块的核心,而激光SLAM则是地图定位算法的关键技术,其重要性不言而喻,在许多AI产品中应用非常多(包括但不限于自动驾驶.移动机器人.扫地机等).相比于传统的视觉传感器,激光传感 ...

  6. Livox激光MID-360使用与fast-lio2激光SLAM建图

    1.Livox激光MID-360使用 mid-360激光雷达使用前首先需要安装 SDK2和 ROS2驱动.注意,一定要使用 SDK2和 ROS2驱动. 安装 SDK2比较简单,按照README可以顺利 ...

  7. SLAM学习笔记(十九)开源3D激光SLAM总结大全——Cartographer3D,LOAM,Lego-LOAM,LIO-SAM,LVI-SAM,Livox-LOAM的原理解析及区别

    本文为我在浙江省北大信研院-智能计算中心-情感智能机器人实验室-科技委员会所做的一个分享汇报,现在我把它搬运到博客中. 由于参与分享汇报的同事有许多是做其他方向的机器人工程师(包括硬件.控制等各方面并 ...

  8. SLAM学习--2D激光SLAM--入门学习

    一.学习心得记录(不一定对):转载了很多博主的网站,若侵权,告知必删 1. 激光slam 和视觉slam 实际在实现的时候完全是两码事,可能根本思想差不多,特别是非线性优化方面,但是实现方案差距较大, ...

  9. 六.激光SLAM框架学习之A-LOAM框架---项目工程代码介绍---4.laserMapping.cpp--后端建图和帧位姿精估计(优化)

    专栏系列文章如下: 一:Tixiao Shan最新力作LVI-SAM(Lio-SAM+Vins-Mono),基于视觉-激光-惯导里程计的SLAM框架,环境搭建和跑通过程_goldqiu的博客-CSDN ...

最新文章

  1. 百度启动高管退休计划,总裁张亚勤今年十月退休
  2. 给RadioButtonList这些加JS事件
  3. 不是python中用于开发用户界面的第三方库-20个必不可少的Python库也是基本的第三方库...
  4. T400的5100无线网卡在Centos下跑起来了
  5. mysql got signal 11_mysql bug : mysqld got signal 11
  6. mysql时间相关函数和操作
  7. 内核初始化流程start_kernel
  8. django中自定义了manager函数,使用的时候报错AttributeError: 'Manager' object has no attribute 'title_count'...
  9. 机器学习高质量数据集大合辑
  10. [lammps安装教程]lammps串行版安装教程
  11. android之exoplayer
  12. C语言统计1到100素数的个数,统计1到100素数的个数
  13. Navigator对象,获取浏览器类型userAgent,机器类型platform
  14. 双线性插值法图像放缩示例
  15. Python数据处理案例
  16. 算法---DFS和BFS
  17. Java并发编程艺术
  18. day_02-个人博客系统
  19. 自学本科计算机课程要多久,22岁完全0基础自考计算机本科是否现实?
  20. 微软Windows系统发展史

热门文章

  1. 解决win7网速慢的问题
  2. 免费的项目管理及任务管理小程序
  3. 微信多开工具:一键排序多开登录窗口,方便管理与切换多个微信账号
  4. Windows上使用“LogView”打开大文件
  5. g140wc研究总结
  6. 对卷积神经网络中卷积层、激活层、池化层、全连接层的理解
  7. EOS基础全家桶(七)合约表操作
  8. 我们加班熬夜,大步向前跃进
  9. Elasticsearch 定义多个分词器模板
  10. 什么是TCP,什么是UDP,有什么区别?