前言
在网上看了几天的ROS文档之后对ROS这个框架有了大致的了解,核心就是ROS的分布式运算以及各个节点之间的通信机制,由于这些都在软件层面做了抽象,使用时完全不需要关心底层是如何实现的,个人感觉学起来比单片机之类的快很多。
主从机配置
使用建图和导航一般需要一个图形化界面方便我们查看地图、激光雷达等信息,ROS提供了一个很好用的叫RVIZ的可视化软件。但显然这个软件不应该由小车来运行,一是因为显示在电脑上方便调试,二是RVIZ比较耗算力,车上的板卡不一定跑得动。
那么问题来了,我的电脑怎么能接收和发送运行在小车上的roscore的数据呢?ROS最突出的特点就是它是一个分布式的框架,即一个框架可以在分布在多个计算平台上运行,所以这种事情肯定是能轻松做到的,只要正确配置即可。
联网
要想两个设备通过ROS进行通信首先需要把最底层的连接建立起来。
- 将两个设备连接至同一个局域网(最好设置成固定IP不然可能会有问题)
分别查询两个设备的IP和hostname
#在终端中输入 ifconfig #查询IP hostname #查询hostname
- 把信息分别添加到两个设备的/etc/hosts中,格式如下:
IP hostname
4.互相ping一下对方的hostname检查连接是否正常
ROS配置
ROS的分布式框架中允许一个主机和多个从机(只有主机能执行roscore),我们需要在两个设备的~/.bashrc中设定主机和从机的信息。
主机
export ROS_MASTER_URI=http://主机IP:11311 export ROS_HOSTNAME=主机IP
- 从机
export ROS_MASTER_URI=http://主机IP:11311
export ROS_HOSTNAME=从机IP
设定完成后,在主机上执行roscore,打开从机的终端,输入rostopic list(或者别的也行),有对应的结果,不报错,证明主从机已经配置成功。
使用gmapping进行建图
gmapping简介
gmapping是一个开源的基于激光雷达的SLAM功能包,通过采集机器人的位置和激光雷达数据可以创建出一个2D的栅格地图。
- gmapping订阅的话题
tf
(tf/tfMessage):为gmapping提供传感器(主要是激光雷达和里程计)和机器人之间的坐标变换信息
scan
(sensor_msgs/LaserScan):为gmapping提供激光雷达的数据
- gmapping发布的话题
map_metadata
(nav_msgs/MapMetaData)、map
(nav_msgs/OccupancyGrid):地图信息
~entropy
(std_msgs/Float64):姿态分布熵(表示机器人位置的不确定性)
建图流程
启动所需节点(激光雷达驱动和底盘驱动等),发布gmapping所需的坐标变换信息
这部分是根据机器人的实际情况做的,只要确保gmapping需要的信息被正确发送即可。
踩坑记录
笔者一开始运行gmapping的时候地图话题没有任何信息被发布,并且gmapping节点出现了如下的警告:
[ WARN] [1346231329.853649941]: MessageFilter [target=/odom ]: Dropped 100.00% of messages so far. Please turn the [ros.gmapping.message_notifier] rosconsole logger to DEBUG for more information.
虽然不知道具体是什么意思,但是信息里有个odom,证明这个问题大概率跟里程计有关,于是笔者使用rqt显示了tf树:
可以发现,odom与base_link之间是缺少了坐标变换的。“少了这个变换给它加上去不就得了”,抱着这样的想法以及想当然的理解,笔者直接发布了一个odom到base_link的静态坐标变换,因为当时觉得里程计和机器人之间的坐标变换就应该是一个静态的,而且是重合的。
加上这个缺失的坐标变换之后,地图确实出来了,但是机器人移动的时候建出来的地图变成了一坨屎.......
这现象看起来就是gmapping觉得车没在动,激光雷达扫出的信息就一直重叠(事实也是这样的)。然后笔者把tf信息显示在RVIZ上,然后发现无论机器人怎么动,base_link始终粘在map的原点一动不动,证实了前面的猜想。
于是笔者开始重新思考这个odom和base_link之间到底是一个什么关系。
首先,gmapping在建图的时候是怎么知道车在动以及车动到哪儿的——显然不可能是激光雷达,那只有里程计了。
笔者一开始的理解是这个关系就是map到odom之间的变换决定的,然而细想就发现了不对劲的地方,这个map到odom之间的坐标变换是gmapping发布的,它怎么可能知道这个变换关系呢?
所以正确的理解是odom是里程计坐标系的原点,gmapping发布的那个坐标变换实际上是结合激光雷达等传感器来修正里程计的漂移的,因此odom到base_link的坐标变换应该是动态的,由底盘驱动节点发布的。
修改了之后建图可以正常进行了。
- 启动gmapping,在从机上启动RVIZ,显示地图等信息
控制机器人进行移动以建图
笔者使用了一个键盘控制节点发布cmd_vel来控制底盘移动,这一步可以根据实际情况更改。
启动mapserver节点保存地图
mapserver订阅的是建图节点发布的map信息,因此建图完成后应该先保存地图再关闭gmapping。
可以写一个launch文件一键完成地图mapserver的启动:
<launch> <arg name="filename" value="$(find 功能包名)/用于存放地图的文件夹/地图文件名" /> <node name="map_save" pkg="map_server" type="map_saver" args="-f $(arg filename)" /> </launch>
启动后,mapserver会在目标文件夹中生成 地图文件名.pgm 与 地图文件名.yaml两个文件,其中包含了地图的信息。
进行导航
建图完成之后就可以进行导航了:ROS有一套完整的导航框架,叫move_base,整个框架的结构是这样的:
该框架主要由几个部分组成:
1、全局代价地图:由建图得到的地图和当前传感器的数据进行一定处理得到一个全局的地图,可以理解为机器人记忆中的地图
2、局部代价地图:由当前的传感器数据进行一定处理得到一个局部的地图,即机器人周围的实际情况
3、全局路径规划器:根据全局地图以及当前位姿和目标位姿计算出一条路径,使用最短路径算法,如BFS,A*,Dijkstra等
4、局部路径规划器:根据机器人周围实际情况(考虑到动态障碍和建图误差等)修正全局路径,使用TEB、DWA等算法
5、恢复行为:机器人无法规划出到达目标点的路径时试图从代价地图中移除障碍的一系列行为
move_base使用时只需要将参数配置好,把它需要的数据喂给他就行。各部分参数的含义和作用可以参考ROS官网的文档。
2 条评论
博主您说“修改了之后建图可以正常进行了”,到底是咋修改的啊??谢谢!!
就是把缺失的坐标变换补上去,在这个项目里面odom到base_link的变换是由底盘驱动节点发布的,实际上就是底盘惯导得到的位姿,具体的发布方法在ROS Wiki教程的tf部分有提到