预备知识
move_base的基本框架
- ROS中用于导航避障的功能包为move_base,代码链接为 https://github.com/ros-planning/navigation.git。
- 关于导航与避障的总体配置可以参考: http://wiki.ros.org/navigation/Tutorials/RobotSetup
- 导航核心的介绍可以参考: https://wiki.ros.org/nav_core
- move_base的核心代码为 nav_core,代码链接为 https://wiki.ros.org/nav_core, 利用nav_core::BaseGlobalPlanner接口可以指定全局路径规划器, 利用nav_core::BaseLocalPlanner 接口可以指定局部路径规划器。在move_base的节点中, 维护着两张代价地图, 一张是全局代价地图, 一张是局部代价地图,以此来完成需要的导航任务。
- move_base的总体框架图如下所示:
白色节点为move_base提供的, 灰色节点为可选的, 比如map_server, 这样我们就可以实现在未知环境进行建图, 蓝色节点为必须指定的节点。 - move_base 导航栈中可以在不需要构建的地图情况下便可进行相应的导航操作。
- move_base功能包中默认的自恢复行为过程如下:
首先,用户指定区域的障碍物地图将会被清除, 其次, 如果可行的话, 机器人将会旋转来清除外部空间,如果这也失败的话, 机器人将会积极地旋转运动来清除方形区域外的障碍物区域, 如果这都失败的话, 机器人将会通知move_base放弃该导航任务。自恢复行为可以通过recovery_behaviors
参数来进行配置, 或者使用recovery_behavior_enabled
参数来开启和关闭自恢复行为。 - move_base功能包的主体配置参数,包含如下:
~base_global_planner (string, default: "navfn/NavfnROS" For 1.1+ series)
用于指定全局路径规划的插件名,默认值为 "NavfnROS"
~base_local_planner (string, default: "base_local_planner/TrajectoryPlannerROS" For 1.1+ series)
用于指定局部路径规划的插件名, 默认值为 "TrajectoryPlannerROS"
~recovery_behaviors (list,
default: [{name: conservative_reset, type: clear_costmap_recovery/ClearCostmapRecovery},
{name: rotate_recovery, type: rotate_recovery/RotateRecovery},
{name: aggressive_reset, type: clear_costmap_recovery/ClearCostmapRecovery}],
用于指定机器人在无法避障情况下的恢复行为, 其自恢复的整体流程参考上图。
~/local_costmap/circumscribed_radius
用于指定代价地图的机器人外切半径
~controller_frequency (double, default: 20.0)
发送速度控制命令的频率。
~planner_patience (double, default: 5.0)
规划器尝试查找有效行进路径的最大容忍时长。
~controller_patience (double, default: 15.0)
如果没有收到有效的控制的命令,那么在进行空间清除的操作前,机器人会会等待的最长时间秒数。
~conservative_reset_dist (double, default: 3.0)
距离机器人的距离,以米为单位,当试图清除地图中的空间时,超过该距离的障碍物将从成本地图中清除. 注意: 该参数只在默认自恢复行为被使用的时候有效。
~recovery_behavior_enabled (bool, default: true)
是否使能机器人的自恢复行为。
~clearing_rotation_allowed (bool, default: true)
机器人是否允许通过原地旋转来进行清除地图的动作。 注意: 该参数只在默认自恢复行为被使用的时候有效。
~shutdown_costmaps (bool, default: false)
当move_base的节点未启动的情况下, 机器人是否能够关闭节点的代价地图。
~oscillation_timeout (double, default: 0.0)
在执行自恢复行为之前允许振荡运动多长时间(秒)。 0.0的值对应着无限长的超时时间在在最新的navigation 1.3.1中。
~oscillation_distance (double, default: 0.5)
来回运动在多大距离以上不会被认为是振荡运动。 超出这个距离将会重置oscillation_timeout的值在最新的navigation 1.3.1中。
~planner_frequency (double, default: 0.0)
全局路径规划的频率值, 如果这个值被设置为0.0, 那么全局规划器将会在只收到新的目标的情况下运行或者局部规划器报告改路径已经存在阻塞, 发布于最新的版本navigation 1.6.0中。
~max_planning_retries (int32_t, default: -1)
在执行自恢复行为之前, 允许尝试多少次路径规划, -1.0的值表示允许无穷次的尝试。
- move_base通过
action_lib
库与用户进行联动开发。 - move_base的配置主要包含两部分, 一部分是代价地图的配置, 一部分是路径规划的配置。
路径规划的配置
nav_core的功能包包含了导航栈的关键接口, 所有的规划器和自恢复行为的功能将会以插件的形式应用在move_base节点中。
在ROS中开发并使用插件
- 在ROS中开发插件可以参考链接: https://wiki.ros.org/pluginlib
- 首先在move_base中通过两个参数
base_global_planner
,base_local_planner
来制定全局路径规划器以及局部路径规划器, 如下, 指定了navfn功能包的NavfnROS节点。
base_global_planner: "navfn/NavfnROS"
#base_global_planner: "global_planner/GlobalPlanner"
#base_local_planner: "base_local_planner/TrajectoryPlannerROS"
base_local_planner: "teb_local_planner/TebLocalPlannerROS"
- 该插件库会通过
PLUGINLIB_EXPORT_CLASS(global_planner::GlobalPlanner, nav_core::BaseGlobalPlanner)
来注册一个规划器,比如本例子会将global_planner::GlobalPlanner
注册为nav_core::BaseGlobalPlanner
的插件,然后,通过nav_core
功能包中的服务器参数base_global_planner赋值为global_planner/GlobalPlanner
, 即可选择该插件作为全局规划器的插件, - 那么如何配置并加载全局规划器的参数呢? 如move_base中参数base_global_palanner的设置,即通过
base_global_planner: "navfn/NavfnROS"
语句,该语句, 我们可以理解为,我们在move_base中指定了navfn功能包中的**NavfnROS**节点来作为move_base的全局路径规划器
,因此在yaml文件中配置该节点的私有参数时, 必须在配置文件中指出NavfnROS命名空间,将后续的参数归属于该命名空间,才能正确传入节点, 并生效。 如下配置:
NavfnROS:
allow_unknown: true
default_tolerance: 0.05
visualize_potential: true
publish_potential: true
use_quadratic: true
use_dijkstra: true
allow_unknown: true
cost_factor: 3
outline_map: false
- 那么如何配置局部路径规划器,局部规划器的指定是由
~base_local_planner (string, default: "base_local_planner/TrajectoryPlannerROS")
的配置得来的,比如指定base_local_planner: “base_local_planner/TrajectoryPlannerROS”。 其中, 设置base_local_planner
参数的值将会传入到move_base中,传入的字符串将会以/
被切割, 代码中会取出最后一个字符串TrajectoryPlannerROS
, 然后通过该字符串来初始化规划器节点的namespace,然后我们再在yaml中以该字符串为namespace配置相对应的规划器的所有参数。 因此,我们在yaml文件中选择TrajectoryPlannerROS
作为参数的namespace, 如下配置:
TrajectoryPlannerROS:
max_vel_x: 0.45
min_vel_x: 0.1
max_vel_theta: 1.0
min_in_place_vel_theta: 0.4
acc_lim_theta: 3.2
acc_lim_x: 2.5
acc_lim_y: 2.5
holonomic_robot: true
与此类似的,base_global_planner
规划器也是如此形式,以下代码可以作为加深了解。
template<class T>
std::string ClassLoader<T>::getName(const std::string & lookup_name)
{
// remove the package name to get the raw plugin name
std::vector<std::string> split;
boost::split(split, lookup_name, boost::is_any_of("/:"));
return split.back();
}
try {
tc_ = blp_loader_.createInstance(config.base_local_planner);
// Clean up before initializing the new planner
planner_plan_->clear();
latest_plan_->clear();
controller_plan_->clear();
resetState();
tc_->initialize(blp_loader_.getName(config.base_local_planner), &tf_, controller_costmap_ros_);
}
全局路径规划器
nav_core::BaseGlobalPlanner的规划器接口包含如下, 通过以下的插件名设定给base_global_planner
参数可以实现全局规划器的选择。
global_planner
- 快速,内插式,可更灵活地用于替换navfn的规划器。插件名为: "global_planner/GlobalPlanner"
, 可以参考该链接: https://wiki.ros.org/global_plannernavfn
- 基于格点地图计算机器人全局路径的导航方案。插件名为: "navfn/NavfnROS"
。carrot_planner
- 一种简单的用于用户自定义目标的全局规划器, 可最大限度地尝试和逼近目标点,即使目标点旁边存在障碍物。插件名为: "carrot_planner/CarrotPlanner"
。
局部路径规划器
nav_core::BaseLocalPlanner的规划器接口包含如下5种:
base_local_planner
- 该控制器提供一种基于DWA(动态窗口)以及 Trajectory Rollout (轨迹滑动)算法的实现方案。关于该规划器,可以参考以下链接: http://wiki.ros.org/base_local_plannerdwa_local_planner
- 模块化的DWA实现,界面更清晰、更容易理解,与base_local_planner的DWA方案相比,该方案在全向机器人的y轴上的控制更为灵活。 http://wiki.ros.org/dwa_local_plannereband_local_planner
- 在SE2流形上实现弹性方法的控制器。teb_local_planner
-实现了TEB(实时弹性带)的轨迹优化方法的控制器mpc_local_planner
- 基于SE2流形提供了大部分模型预测控制方案的控制器。
其中, 目前常用的局部规划器为 dwa_local_planner ,teb_local_planner。
导航自恢复
通过nav_core::RecoveryBehavior的接口,我们可以指定导航在异常情况下的自恢复手段,常见的接口如下:
- clear_costmap_recovery - 用于重置超出用户定义的范围之外的代价地图的自恢复行为。
- rotate_recovery - 机器人通过360度旋转来清空代价地图的自恢复行为。