ROS导航包的应用
接触ROS系统已经很久了,前段时间终于排除万难,利用ROS Navigation功能包集跑通了基于rplidar 的slam,把自己的一些相关经验可以搬到这里来,记录分享加交流。
开发环境
Ubuntu14.04+ROS indigo
Navigation stack:amcl | base_local_planner | carrot_planner | clear_costmap_recovery | costmap_2d | dwa_local_planner | fake_localization | global_planner | map_server | move_base | move_base_msgs | move_slow_and_clear | nav_core | navfn | robot_pose_ekf | rotate_recovery | voxel_grid
Navigation功能包集概述
这是2D的导航功能包集,通过接收里程计数据、tf坐标变换树以及传感器数据,为移动机器人输出目标位置以及安全速度。概念层面上讲,导航功能包集是相当简单的。 它从里程计和传感器数据流获取信息,并将速度命令发送给移动基站(比如你的机器人)。但是,想要在任意机器人上使用导航功能包集可能有点复杂。使用导航功能包集的先决条件是,机器人必须运行ROS,有一个tf变换树,使用正确的ROS Message types发布传感器数据。而且,我们需要在高层为一个具有一定形状和动力学特点的机器人配置导航功能包集。
acml:是一个针对在二维移动的机器人的基于概率定位系统。它实现了自适应蒙特卡罗滤波的定位方法,并使用粒子滤波器去跟踪在已知地图中机器人的位置。
base_local_planner:这个包提供了Trajectory Rollout以及Dynamic Window两种在2D平面局部导航的方法。通过提供一个跟随的规划路径和一个代价地图,控制器生成速度指令并发送至机器人。它支持全向和非全向机器人,以及任何可以用多边形或圆描述的机器人轮廓,并且可以在launch文件中设置这些参数。这个包已经被封装好,可以通过nav_core包的BaseLocolPlanner接口来调用。
carrot_planner:这个规划器是一个简单的全局规划器,可以通过nav_core::BaseGlobalPlanner 来进行调用,并且被move_base节点用作一个全局规划的插件。这个规划器从用户处采集到一个目标点,之后检查用户指定的目标点是否是障碍物,如果是的话沿着robot与目标点构成的向量向后退,直到找到一点没有障碍物位置。之后它会将此目标点作为目标发送给局部规划器和控制器。这个规划器允许机器人尽可能到达离用户指定的目标点最近的位置。
clear_costmap_recovery:为导航包提供了一种自救行为,试图通过将代价地图还原成已知区域外的静态地图从而清除出空间。
costmap_2d:通过激光或点云的数据,投影到2D平面上,创建代价地图,并可以设置膨胀半径。
dwa_local_planner:局部规划器,提供动态窗口方法( Dynamic Window Approach)在平面上局部导航。与base_local_planner类似。
fake_localization:提供了一个简单节点fake_localization node,可以代替一个定位系统,并提供了acml包的ROS API的子集。由于较低的计算量,这个节点非常频繁的用于在仿真环境中提供完美的定位。这个节点将里程计数据转换为位置、粒子云,并以acml发布的数据格式发布。
global_planner:全局路径规划节点。
map_server:将代价地图作为ROS Service发布,提供了map_saver节点,可以通过命令行存储地图。
move_base:提供了action动作的实现(actionlib包),即给定一个世界系下的目标位置,机器人会试图移动到该位置。另外,move_base节点中包含了两个代价地图(全局、局部),以及一个全局规划器和一个局部规划器,以便实现导航任务。
move_base_msgs: 通过MoveBase.action文件定义产生的消息文件,用于actionlib与move_base的通信。
move_slow_and_clear:为robot提供一种自救行为,即清除代价地图的信息并限制机器人速度,但这不绝对安全,robot可能会撞到某些障碍。但这是唯一一种可以与允许最大速度动态设置的局部规划器兼容的自救行为。
nav_core:为robot实现导航任务提供了通用的接口,包括BaseGlobalPlanner,BaseLocalPlanner,, RecoveryBehavior interfaces等,这有利于方便的更新规划器或者自救行为的版本。
navfn:全局规划器,提供了一个快速插值的函数,可以在起始点到目标点之间快速插值,并找到代价最小的一条路径。
robot_pose_ekf:这个包用于估计robot的三维位置,利用扩展卡尔曼滤波的方法,建立了一个六维模型,联合了轮子里程计、IMU、视觉里程计的数据。
rotate_recovery:提供了一种自救行为,通过旋转360度来清除空间。
voxel_grid:提供一个有效的三维体素网格的实现。
导航框架
这幅图描述了使用Navigation导航包的一个整体框架,其核心是move_base节点,包含了global_planner、local_planner、global_costmap、local_costmap、recovery_behaviors五个模块,move_base节点订阅tf(坐标系转换)、odom(里程计数据)、map(地图)、sensor datas(激光数据或点云)以及goal等话题,之后发布cmd_vel话题。
tf:利用ROS的tf工具发布坐标系之间的转换关系,包括:/map->/odom,/odom->/base_link,/base_link->/sensor等
odom:导航包需要用到里程计的数据,故需将其用tf工具和nav_msgs/Odometry消息发布出来
map:在导航前,最好可以提供一张全局的地图,因此需要我们提前创建(但这不是必须的)
sensor data:用于避障,建图等等,可以是激光雷达的平面数据或者是点云数据(sensor_msgs/LaserScan or sensor_msgs/PointCloud )
goal:目标在全局地图中的坐标,用geometry_msgs/PoseStamped消息格式发布
此外,move_base节点还提供了action动作的接口(即SimpleActionServer的实现,详细可见actionlib包),包括订阅了move_base/goal (move_base_msgs/MoveBaseActionGoal),move_base/cancel (actionlib_msgs/GoalID)两个话题,并发布了move_base/feedback (move_base_msgs/MoveBaseActionFeedback)、move_base/status (actionlib_msgs/GoalStatusArray)、move_base/result (move_base_msgs/MoveBaseActionResult)等三个话题。因此用户可以自己写一个利用actionlib库写一个发布目标位置的节点。
在熟悉完整个导航框架后,我们就可以开始依次做好相应的准备工作了。需要的步骤如下:
1、搭建一个移动平台,使其订阅/cmd_vel话题,并发布odom里程计数据以及/odom->/base_link的tf数据??
2、将传感器数据(激光数据或RGB-D点云数据)发布出来
3、创建地图,利用slam_gmapping或hector_slam的方法
4、配置Navigation包,进行导航
由于我采用的是西工大HandsFree团队开发的Stone2机器人,移动平台已经完全搭建好了,我需要考虑的也就是从第三步开始,如何创建地图,详细内容可以参照我下一篇博文。