一、SLAM是什么

SLAM的全称是Simultaneous Localization And Mapping,翻译过来就是即时定位与地图构建。这里有两个关键词:定位和地图构建,也就是说机器人会在未知的环境中,一边确定自己的位置,一边去构建地图,最后输出类似这样的地图。

简而言之,SLAM地图构建的过程就是用深度传感器测量机器人和周围环境的距离信息,从而完成对周边环境的地图构建,同时,机器人会对环境进行一致性检查,检测是否运动到已经构建过地图的地方,最终完成地图闭环,完成整个地图。

ROS中最为常用的SLAM算法就是Gmapping,这是一种基于滤波SLAM框架的常用开源SLAM算法,基于RBpf粒子滤波算法,即将定位和建图过程分离,先进行定位再进行建图。如果大家对Gmapping算法感兴趣,可以阅读该算法的论文:https://openslam-org.github.io/gmapping.html

二、LIMO移动机器人运动控制

2.1 LIMO多模态机器人

我们常见的移动机器人运动类型一般有四轮差速、阿克曼转向、履带差速、全向移动等,但是俗话说的好,成年人不做选择,LIMO一款满足你所有需求,四种运动类型随心任意切换。

关于多模态运动类型的测试,我们未来再专门讲解,今天的重点是在LIMO机器人四轮差速的运动状态下,实现SLAM应用功能。

2.2 远程连接LIMO

LIMO开机后,通过虚拟键盘onboard连接上自己的WiFi,然后在电脑上下载与之相应的远程桌面软件NoMachine。可以直接在官网下载NoMachine - Free Remote Desktop For Everybodyhttps://www.nomachine.com/

安装好软件之后,电脑和小车连接同一个WiFi,这样就可以和小车进行远程连接了。

2.3 下载并编译代码

LIMO机器人的代码还处于持续更新中,我们可以在Github主页中看到,为保证使用的是最新的代码,这里我们使用如下命令将代码包下载到LIMO机载系统中的工作空间里,替换掉原有代码:

$ git clone https://github.com/agilexrobotics/limo_ros

然后使用catkin_make命令编译空间,这个是ROS的常规操作,不熟悉的同学可以去看下古月君的《ROS入门21讲》。

2.4 让小车跑起来

为了确保机器人的底层功能已经可以正常工作,我们先尝试一下最基本的键盘控制,让小车动起来。

启动一个终端,将小车的底盘和传感器启动起来:

$ roslaunch limo_bringup limo_start.launch

底盘成功启动后,会订阅cmd_vel话题,就像控制小海龟一样,启动如下键盘控制节点,就可以通过键盘控制LIMO流畅运动了。

$ roslaunch limo_bringup limo_teletop_keyboard.launch

三、Gmapping SLAM功能配置解析

3.1 Gmapping功能包

在ROS中使用Gmapping功能包前,需要使用如下命令安装,这里使用的是Melodic版本,如果使用的是其他版本的ROS,替换命令中的版本名称即可:

$ sudo apt-get install ros-melodic-gmapping 

ROS中的各种功能包就类似于积木块,我们只需要了解其接口的使用方式,就可以拼装出一系列复杂的功能。SLAM算法不简单,但是Gmapping这个“积木块”已经把算法封装的很好了,我们在ROS wiki上可以找到其接口说明,如下图所示:

可以看出,Gmapping需要订阅机器人关节变换话题/tf和激光雷达扫描数据话题/scan,然后发布栅格地图话题/map。

关于/tf又分为两个部分,Gmapping功能包中的TF变换如下图所示:

所以我们可以确定,Gmapping算法的必备条件:/tf、/odom、/scan,就可以通过算法发布/map了。

在前边LIMO机器人底盘启动后,这些基本条件都已经在底层节点中正常发布或者更新,所以我们的重点就是通过一个launch文件,配置Gmapping功能节点。

3.2 SLAM功能配置

在工作空间中的src文件下创建一个名为limo_slam的功能包,其中再创建一个launch文件夹,关于Gmapping启动配置的launch文件就放到这里。

启动文件gmapping.launch的详细内容如下,如果使用其他机器人,需要根据各自的情况,对下面文件中注释的部分进行更改。

<launch>
	<arg name="scan_topic" default="scan" />
	
	<node pkg="gmapping" type="slam_gmapping" name="slam_gmapping" output="screen" clear_params="true">
	<param name="output_frame" value="odom"/> #根据limo_start.launch文件更改
	<param name="base_footprint_frame" value="base_link"/> #根据limo_start.launch文件更改
	<remap from="imu_data" to="imu" /> #根据limo_start.launch文件更改
	<param name="base_link_to_imu" value="tf"/> #根据limo_start.launch文件更改
	<param name="map_update_interval" value="5.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>

如果你熟悉SLAM算法,这些参数可能对你并不陌生,但是若你不了解SLAM算法,也不用担心,这些参数独有默认值,大部分时候使用默认值或使用ROS中相似机器人的配置即可。
由于Gmapping算法的框架如下图所示,我们需要更改的主要参数有odom(里程计坐标系,必须)、scan(激光雷达话题,必须)、base_footprint_frame(机器人基坐标系,必须)、imu_data(IMU话题,可选),这些参数的名字与值需要跟机器人底盘驱动limo_start中发布的话题名和值相对应,不然Gmapping接收不到这些参数,就无法进行SALM。

四、Gmapping SLAM运行效果

做好相关的准备工作之后,我们就可以利用激光雷达来进行SLAM了。

首先在工作空间下使用catkin_make对代码进行编译,然后分别启动终端运行如下命令:

$ roslaunch limo_bringup limo_start.launch
$ roslaunch limo_bringup limo_teletop_keyboard.launch
$ roslaunch limo_slam gmapping.launch  

为了看到动态SLAM的效果,我们还需要使用Rviz可视化显示,打开一个终端,输入以下指令

$ rviz

然后点击ADD按钮添加需要的设置,如Map,LaserScan,TF等等,订阅对应的话题数据,例如添加Map时,我们需要更改Map下面的Topic为/map。

然后我们就可以通过键盘控制小车缓慢运动进行SLAM了。若开始SLAM后搬动小车,则需要重新进行SLAM,因为小车的TF很有可能会出错。

注意控制小车的运动速度,如果转弯时候速度过快,很容易出现地图偏移的现象:

配置好Rviz之后,我们也可以保存当前的配置到功能包中,然后在Gmapping的启动Launch文件中添加如下Rviz节点与参数的配置,避免每次都需要新建一个终端输入rviz指令并重新添加Rviz中的显示。

<node name="rviz" pkg="rviz" type="rviz" required="true" args="-d $(find limo_slam)/rivz/gampping.rviz" /> #根据相关的rviz设置自行配置

我们也可以使用rqt_graph命令来查看各个节点之间的关系

SLAM结束后,需要使用以下指令来保存地图。

$ rosrun map_server map_save -f map_file # -f 后面的的地址和文件名可自行更改

由于空间有限,我们构建的地图如下图所示。