ROS学习总结十四:机器人SLAM(hector)

1、机器人必备条件:硬件要求
(1)差分轮式机器人,可使用twist速度指令控制

1
2
linear:xyz方向上的线速度,单位是m/s;
angular:xyz方向上的角速度,单位是rad/s。

(2)机器人必须安装激光雷达等测距设备,可以获取环境深度信息。
(3)最好使用正方形和圆形的机器人,其他外形的机器人虽然可以使用但是效果可能不佳。
1、机器人必备条件:深度信息

1
2
3
4
5
6
7
8
angle_min:可检测范围的起始角度;
angle_max:可检测范围的终止角度,与angle_min组成激光雷达的可检测范围;
angle_increment:相邻数据帧之间的角度步长;
time_incremen:采集到相邻数据帧之间的时间步长,当传感器处于相对运动状态时进行补偿使用。
scan_time:采集一帧数据所需要的视觉;
rang_min:最近可检测深度的阈值;
rang_max:最远可检测深度的阈值;
ranges:一帧深度数据的存储数组。

Kinect等GRB-D摄像头,也可以通过红外摄像头获取周围环境的深度信息。
depthimage_to_laserscan功能包:

1
2
3
4
5
6
<node pkg="depthimage_to_laserscan" type="depthimage_to_laserscan" name="depthimage_to_laserscan" output="screen">
    <remap from="image" to="/kinect/depth/image_raw"/>
    <remap from="camera_info" to=/kinect/depth/camera_info"/>
    <remap froam="scan" to="/scan"/>
    <param name="output_frame_id" value="/camera_link"/>
</node>

1、机器人必备条件:里程计信息

1
2
3
4
可以使用:rosmsg show nav_msgs/odometry查看
pose:机器人当前位置坐标,包括机器人的XYZ三轴位置与方向参数,以及用于校正误差的方差矩阵
twist:机器人当前的运动状态,包括XYZ三轴的线速度与角速度,以及用于校正误差的方差矩阵。
注意:ROS中所有的坐标系都是右手坐标系。

在这里插入图片描述

1、机器人必备条件:仿真环境
在shenlan视频中给出了一个仿真环境:

1
roslaunch mbot_gazebo mbot_laser_nav_gazebo.launch

如果不使用这个环境的话也可以自己建立一个仿真环境,在第十章有具体的建立仿真环境的过程。

2、ROS SLAM功能包应用方法:hector_slam

1
2
3
4
5
6
7
hector_slam功能包:
基于激光雷达
高斯牛顿方法
二维栅格地图
不需要里程计数据
输出地图话题:
nav_msgs/OccupancyGrid

在这里插入图片描述
hector_slam安装:

1
sudo apt-pet install ros-kinetic-hector-slam

如果使用这个命令安装不了的话可以采用源码安装,参考下面方式安装:

1
https://blog.csdn.net/YiYeZhiNian/article/details/100084661

这里要注意一点就是按照链接中的方式添加依赖项可能会失败,这个是否成功当你打开hector的时候会提示找不到包的话就是添加没成功,这时候可以打开bashrc文件看一下最下面是否有这个包的source,如果没有的话可以手动添加一下。保存退出后记得resource。
通过下面这个图我们也可以看出来hector中所需要的数据以及发布的数据:
在这里插入图片描述
然后我们启动一个gazebo仿真节点以及hector建图节点:

1
2
roslaunch mbot_gazebo mbot_laser_nav_gazebo.launch
roslaunch mbot_navigation hector_demo.launch

这时候我们可以看到gazebo的仿真图像以及rviz的建图了:
在这里插入图片描述
接下来我们再启动一个键盘控制节点:

1
roslaunch mbot_teleop mbot_teleop.launch

控制机器人在地图中走动就可以得到一张完整的地图了。可以看到在仿真环境中其实建图效果还不错。
在这里插入图片描述

然后我改用了上面源码安装时启动的hector建图方式:

1
roslaunch hector_slam_launch tutorial.launch

同样的可以得到建图的效果,其实来说上面所启动的两个节点应该是相关联而又独立的,第一个节点其实应该只是启动了gazebo仿真,它最后使用仿真的雷达给出了一个scan扫描数据;而后下面的节点订阅了这个数据并进行处理,最后得到一个二维的栅格地图。但是我使用第二种方式建图的时候报了一个错误:

1
[ERROR] [1588595825.830761801, 12216.482000000]: Transform failed during publishing of map_odom transform: "nav" passed to lookupTransform argument target_frame does not exist.

这里显然是存在一个tf变换的问题,这也说明了两个hector程序上其实是有一定区别的,但似乎对于整体的效果来说好像没有太大的影响:
在这里插入图片描述

这里在最后走回起点的时候发生了一点问题,它的自定位似乎发生了跳跃,按照左边仿真环境来说它此时应该是在中间位置而它突然跳向了左上方。其他的整体来说效果还是很好的。我们打开rqt工具查看一下两者的数据流变换关系:
首先是tutorial.launch的rqt变换关系:
在这里插入图片描述
然后是hector_demo.launch的rqt关系:
在这里插入图片描述
还是可以看出两者的程序上其实是有比较大的区别的,前者比后者多了两个节点。其中一个关于轨迹的节点调用了很多参数。但是思路上都是一样的,hector的主要思想也就是订阅一个scan,计算出一张地图以及自身的位置。
但是不可否认hector这个算法有一个很大的问题,就是在于它的自定位,它利用自身的激光雷达数据进行定位,如果上一次的扫描数据与下一次的扫描数据基本一致的话,它就很难确定自己是否在运动,例如当我给一个足够大的空间,这里有一条没有任何特征点的长廊,长度远远超过激光扫描的最大距离时,hector基本就失去了建图的能力。
在这里插入图片描述
如上图所示,当激光位于这样一个低特征的环境中的时候,我让小车绕着环境走一圈,它基本上是完全不能得到真实的地图的。关于激光雷达的扫描距离在第十章中其实已经给出,根据

1
2
3
4
5
6
                    </scan>
                    <range><!-- 扫描距离-->
                      <min>0.10</min>
                      <max>6.0</max>
                      <resolution>0.01</resolution><!-- 精度-->
                    </range>

这一段代码我们可以知道其最大扫描距离是6米,当长廊距离超过6米时其不能正确定位自己以及正常建图。