目录
Setting Up the Robot’s Footprint
Configuring the Robot’s Footprint
Planner and Controller Servers
Selecting the Algorithm Plugins
First-Time Robot Setup Guide
在本指南中,我们将讨论如何为 Nav2 使用的导航算法配置机器人的足迹。我们还将展示在这一系列设置指南中构建的模拟机器人 sam_bot 上的示例足迹配置。最后,我们还将展示在 RViz 中可视化 sam_bot 足迹,以确保我们已正确设置。
Footprint Introduction
足迹是机器人在地面投影时的二维形状,主要由 Nav2 在规划过程中用于避免碰撞。涉及到这一任务的算法确保机器人在计算路径或规划时不会与代价地图中的障碍物发生碰撞。
足迹是通过全局和局部代价地图中的 footprint 或 robot_radius 参数进行设置,这些参数我们在之前的教程中已经介绍过(设置传感器指南)。在 footprint 参数中定义的值是一个有序的二维点向量,用于定义机器人在 base_link 坐标系中的足迹。向量中的第一个和最后一个点将连接为最后一条线段,以封闭足迹的形状。作为替代方案,您还可以使用 robot_radius 参数,在此情况下将自动生成以 base_link 为中心的圆形足迹。如果在配置中同时定义了 footprint 和 robot_radius 参数,则使用 footprint。
前面的指南《配置 nav2_costmap_2d》 Configuring nav2_costmap_2d 中有一节详细介绍了如何配置基本的代价地图参数。请参考那篇指南以获取更多有关代价地图配置的细节。 |
对于全局代价地图的机器人外形,选择使用 robot_radius(圆形)还是 footprint(多边形)参数取决于机器人本身、其环境以及您将使用的路径规划算法。即使您使用的是非圆形机器人,也可能存在圆形外形是可接受的情况。例如,像 NavFn 这样的路径规划算法假设机器人是圆形,因为它仅对每个网格单元进行碰撞检查,所以不需要为其足迹勾勒出精确的形状。另一方面,像 Smac Planner’s Hybrid-A* 算法会对机器人的多边形足迹进行碰撞检查,如果可能且必要的话。因此,可能有用的是使用多边形足迹。另一个例子是小型 RC 小车在仓库内行驶。这种机器人很小,不需要进行严格的机动操作,因此用最大的横截面半径来近似它是一个节省时间的好优化方案。
对于局部代价地图的机器人外形,非圆形机器人通常设置为使用 footprint(多边形)。不建议使用的一些情况是当您没有足够的计算资源来在多边形足迹上实现碰撞避免算法时。使用局部代价地图的 robot_radius(圆形)的另一个可能原因是,当机器人相对于其环境非常小,以至于不需要精确的碰撞避免时。但一般来说,局部轨迹规划器应该使用机器人的实际足迹多边形。
请注意,可以通过代价地图的 ~/footprint 话题进行动态调整,根据机器人状态的变化,如操纵臂的移动、提取托盘或其他调整机器人形状的操作。然后,这个多边形将自动被规划器和控制器使用。
Configuring the Robot’s Footprint
在本节中,我们将配置 sam_bot 的足迹,使其在局部代价地图中使用 footprint(多边形),在全局代价地图中使用 robot_radius(圆形)。我们将利用 Nav2 的默认配置文件,并针对全局和局部代价地图修改足迹参数。
sam_bot的完整源代码可以在navigation2_tutorials navigation2_tutorials 存储库中找到。 |
在config目录下,创建一个名为nav2_params.yaml的新文件。然后,复制config/nav2_params.yaml的内容并粘贴到新创建的文件中。config/nav2_params.yaml的内容是从Nav2的默认配置文件中复制的,但是对footprint和robot_radius参数进行了更改,以匹配sam_bot的形状。
Nav2的默认配置文件可以在官方Navigation2存储库Navigation2 repository中找到。 |
以下是来自nav2_params.yaml的代码片段,定义了本地costmap的足迹。在这个配置文件中,本地costmap的footprint参数已经设置为一个矩形足迹。这个矩形框以sam_bot的base_link框架为中心。
resolution: 0.05
footprint: "[ [0.21, 0.195], [0.21, -0.195], [-0.21, -0.195], [-0.21, 0.195] ]"
plugins: ["voxel_layer", "inflation_layer"]
对于全局costmap,我们已经设置了robot_radius参数,以创建一个圆形足迹,与sam_bot的尺寸相匹配,并以base_link为中心。下面是已修改的参数代码片段。
use_sim_time: True
robot_radius: 0.3
resolution: 0.05
Build, Run and Verification
现在我们将确认我们已经正确设置了sam_bot的足迹。
首先,我们启动 launch/display.launch.py 来启动机器人状态发布者,将sam_bot加载到Gazebo中,并在Rviz中可视化sam_bot及其足迹。机器人状态发布者发布了在sam_bot的URDF中定义的 base_link => sensors 的变换,而Gazebo的差分驱动插件发布了 odom => base_link 的变换。打开一个新的终端并执行以下命令。
colcon build
. install/setup.bash
ros2 launch sam_bot_description display.launch.py
启动display.launch.py后,RViz 和 Gazebo 应该打开。在 RViz 中,你应该能够看到 sam_bot、sam_bot 部件的坐标系,并且 odom 坐标系没有错误。在 Gazebo 中,你应该能够看到 sam_bot,它有一个球体和一个立方体,可以被 sambot 的激光雷达传感器检测到。
接下来,我们将使用static_transform_publisher发布map => odom的变换。在本指南中,我们将map => odom的变换发布为静态变换,作为一种简单的方式来发布变换和可视化足迹。打开一个新的终端并执行以下命令。
ros2 run tf2_ros static_transform_publisher 0 0 0 0 0 0 map odom
map => odom的变换现在应该已经被发布了,并且在RViz中添加了map坐标系而没有出现错误。
最后,我们将使用刚刚创建的nav2_params.yaml配置文件和navigation_launch.py,即nav2_bringup中的内置启动文件,来启动Nav2。打开一个新的终端并执行以下命令:
ros2 launch nav2_bringup navigation_launch.py params_file:=<full/path/to/config/nav2_params.yaml>
现在我们应该能够在RViz中可视化轮廓,接下来会讨论这个内容。
Visualizing Footprint in RViz
要可视化局部costmap的轮廓,在RViz窗口的左下角点击添加按钮。在“By topic”选项卡下,在/local_costmap/published_footprint主题下选择Polygon,如下图所示。
将RViz中的固定帧设置为odom,您应该能够看到sam_bot的矩形轮廓:
另一方面,对于全局代价地图,在RViz窗口的左下部分点击添加按钮。转到“按主题”选项卡,然后在/global_costmap/published_footprint主题下选择Polygon,如下所示。
设置RViz中的固定坐标系为map,你应该可以看到sam_bot的圆形足迹。
Conclusion
在本指南中,我们展示了如何为机器人配置圆形和多边形足迹。这个足迹非常重要,因为它在Nav2的路径规划算法中发挥着重要作用。
作为演示,我们配置了sam_bot的成本地图足迹参数。我们设置了局部成本地图使用了符合sam_bot形状的多边形足迹,同时将全局成本地图设置为使用圆形足迹。最后,在RViz中可视化并确认了局部和全局成本地图的足迹。
在本指南的这一部分,我们将讨论您的机器人如何利用不同的规划器和控制器算法来完成导航任务。我们将讨论一些可用的算法插件,您可以根据机器人类型和环境选择使用的算法。
Planner and Controller Servers
导航算法通过在 ROS 动作服务器上运行的插件来实现,在 Nav2 中实现。这些服务器包括规划器、控制器和行为服务器(等等)。在本节中,我们将讨论规划器和控制器服务器,它们是导航堆栈的核心部分。这些服务器可以实现一个或多个算法插件,每个插件都有自己的配置,专门为特定的操作或机器人状态进行了定制。本指南将根据机器人的类型和环境突出显示不同的算法。本指南不涵盖行为、平滑器等,因为这些取决于应用程序而不是硬件/环境,提供的是泛化的建议。
规划器服务器负责实现计算机器人路径的算法。例如,一个插件可以配置为计算两个相对较近位置之间的简单最短路径,而另一个插件可以计算覆盖整个机器人环境的路径。
控制器服务器生成机器人在其本地环境中完成任务所需的适当控制力。这些任务包括但不限于:遵循规划器服务器生成的路径,避免沿途的动态障碍物,甚至在充电站进行充电。
正如之前提到的,规划器和控制器服务器托管一个或多个插件的地图,其中特定的插件将用于特定的环境、场景或任务。例如,控制器服务器可以有一个用于在长廊中沿中间行走的路径的插件,然后在拥挤的地方避免动态障碍物的另一个插件。根据机器人的任务选择执行哪种规划算法可以通过导航系统或应用程序服务器的行为树来完成。
更深入地讨论导航服务器,建议查看“导航概念”类别下的“导航服务器” Navigation Servers 部分。 |
Selecting the Algorithm Plugins
在本节中,我们将讨论规划器和控制器服务器的一些可用算法插件。我们还会讨论每个算法的目的,以及推荐用于哪种类型的机器人。最后,我们展示一些示例 YAML 配置,指定了每个服务器要使用的插件。
你可以使用的算法插件不限于本节中提到的内容。你也可以创建自定义插件,而且 Nav2 定期会添加新的插件。有关如何编写自己的插件的教程,请参阅《编写新的规划器插件》 Writing a New Planner Plugin 和《编写新的控制器插件》 Writing a New Controller Plugin 。你可以在导航插件部分找到所有可用 Nav2 插件 Navigation Plugins Section 及其描述的列表。 |
Planner Server
用于规划服务器的算法插件利用机器人不同传感器捕获的环境表示来找到机器人的路径。其中一些算法是通过搜索环境的网格空间,而其他算法则是通过扩展机器人的可能状态来考虑路径的可行性。
正如前面提到的,规划服务器可以利用在网格空间上运行的插件,比如 NavFn 规划器、Smac 2D 规划器和 Theta Star 规划器。NavFn 规划器是一个使用 Dijkstra 或 A* 算法的导航函数规划器。接下来,Smac 2D 规划器使用 4 或 8 连通邻域的 2D A* 算法,具有更加平滑和多分辨率查询的特性。最后,Theta Star 规划器是 Theta* 的一种实现,使用视线来创建非离散定向的路径段。
当使用在网格空间工作的算法时可能会遇到的一个问题是,并不能保证为任何类型的机器人生成可行的路径。例如,NavFn 规划器并不能保证为在狭窄空间中的非圆形机器人规划出可行路径,因为它使用机器人的圆形足迹(通过近似机器人的最大横截面半径)并检查每个代价地图网格单元的碰撞。此外,这些算法也不适用于 Ackermann 和腿式机器人,因为它们有转弯限制。尽管如此,这些插件最适合于可以向任何方向行驶或安全地就地旋转的机器人,比如圆形差动和圆形全向机器人。
另一个规划器插件是 Smac Hybrid-A* 规划器,它支持任意形状的 Ackermann 和腿式机器人。它是一个高度优化和完全可重新配置的 Hybrid-A* 实现,支持 Dubin 和 Reeds-Shepp 运动模型。该算法在考虑机器人的最小转弯半径约束和机器人的完整足迹进行避碰时扩展机器人的候选路径。因此,这个插件适用于需要全足迹碰撞检测的任意形状机器人。它也可以用于需要小心导航以避免翻车、打滑或在高速时倾倒货物的高速机器人。
还有 Smac Lattice 规划器插件,它基于状态格规划器。该插件通过扩展机器人的状态空间来确保路径符合机器人的运动约束。该算法提供最小控制集,使其能够支持最小重新配置即可适应任何形状和大小的差动、全向和 Ackermann 类型的车辆。
Summary
Plugin Name | Supported Robot Types |
---|---|
NavFn Planner | Circular Differential, Circular Omnidirectional 圆形差动、圆形全向 |
Smac Planner 2D | |
Theta Star Planner | |
Smac Hybrid-A* Planner | Non-circular or Circular Ackermann, Non-circular or Circular Legged 非圆形或圆形 Ackermann、非圆形或圆形腿式 |
Smac Lattice Planner | Non-circular Differential, Non-circular Omnidirectional 非圆形差动、非圆形全向 |
Example Configuration
planner_server:
ros__parameters:
planner_plugins: ['GridBased']
GridBased:
plugin: 'nav2_navfn_planner/NavfnPlanner'
在这里,定义了一个名为 planner_server
的 ROS 参数,其中包含了规划器插件的配置信息。
-
planner_plugins: ['GridBased']
:指定了要加载的规划器插件的名称列表。在这个例子中,只加载了一个名为GridBased
的规划器插件。 -
GridBased:
:这个名称空间对应于上面指定的规划器插件名称。在这里,定义了该插件的配置。 -
plugin: 'nav2_navfn_planner/NavfnPlanner'
:指定了要使用的规划器插件的类型和名称。在这个示例中,加载了名为NavfnPlanner
的插件,它属于nav2_navfn_planner
软件包。
上面展示了规划器服务器的示例配置。planner_plugins 参数接受一个映射到规划器插件名称列表的参数。对于每个在 planner_plugins 中定义的插件命名空间(在我们的示例中是 GridBased),我们在 plugin 参数中指定要加载的插件类型。然后,必须根据要使用的算法在此命名空间中指定其他配置。请参阅配置指南 Configuration Guide 获取更多详情。
Controller Server
默认的控制器插件是 DWB 控制器。它实现了一种改进的动态窗口方法(DWA)算法,具有可配置的插件来计算机器人的控制指令。该控制器利用轨迹生成器插件生成可能的轨迹集。然后,这些轨迹将由一个或多个评论者插件进行评估,每个评论者插件根据配置可能会给出不同的分数。这些评论者插件的分数之和确定了轨迹的总体分数。得分最高的轨迹确定了输出的命令速度。
(
这些轨迹生成器会创建多个可能的路径,然后每个路径会被评估以获取一个总体分数。这个分数基于路径的多个方面,可能包括距离、速度、安全性等,这取决于配置的评估标准。最后,根据这些分数,选择最优路径来确定机器人的输出指令速度。
)
DWB 控制器可用于圆形或非圆形差分机器人、圆形或非圆形全向轮机器人。如果给定一个能够考虑机器人最小曲率约束的轨迹生成插件,它也可以配置用于阿克曼和多足机器人。
另一个控制器服务器插件的例子是 TEB 控制器,它是一种 MPC 时间最优控制器。它实现了基于执行时间、与障碍物的距离以及机器人运动学约束的可行性来优化机器人轨迹的 Timed Elastic Band(TEB)方法。该控制器可用于差分、全向轮、阿克曼和多足机器人。
(
Timed Elastic Band (TEB) 方法的目标之一是优化机器人的轨迹以最小化执行时间。它考虑了机器人运动的时间性质,希望在满足各种约束条件的前提下,找到一个最佳轨迹,既可以保持时间最短,又能安全、有效地避开障碍物。这个方法并不仅仅关注时间,还考虑了机器人遵循其运动学约束的能力和与环境的安全距离。
)
本节最后一个示例是 RPP(Regulated Pure Pursuit)控制器。该控制器实现了纯追踪算法的一种变体,并添加了管理碰撞和速度约束的调节启发函数。这种变体的设计是为了满足服务或工业机器人的需求,并适用于差分、阿克曼和多足机器人。
(
这种调节启发函数是一种额外的处理机制,用于控制纯追踪算法。它对标准的追踪行为进行调整,以确保机器人在执行追踪运动时能够遵守特定的速度约束和避免碰撞。这种调节功能通过添加额外的逻辑来管理速度和避障行为,使得纯追踪算法更适合于服务或工业机器人等特定应用场景。
)
Summary
Plugin Name | Supported Robot Types | Task |
---|---|---|
DWB controller | Differential, Omnidirectional 差分式、全向式 | Dynamic obstacle avoidance 动态障碍物避让 |
TEB Controller | Differential, Omnidirectional, Ackermann, Legged 差分式、全向式、Ackermann、腿式 | |
RPP controller | Differential, Ackermann, Legged 差分式、Ackermann、腿式 | Exact path following 精确路径跟踪 |
所有这些算法都适用于圆形和非圆形机器人。
Example Configuration
controller_server:
ros__parameters:
controller_plugins: ["FollowPath"]
FollowPath:
plugin: "dwb_core::DWBLocalPlanner"
上面显示的是控制器服务器的一个简单示例配置。控制器插件的映射名称列表定义在 controller_plugins 参数中。与规划器服务器类似,控制器_plugins 中定义的每个命名空间(在我们的示例中是 FollowPath)必须在 plugin 参数中定义它将使用的插件类型。还必须为命名空间中选择的算法进行其他配置。请参阅配置指南 Configuration Guide 以获取更多详细信息。
规划器和控制器服务器以及 Nav2 的其他服务器在 ROS 2 中通过生命周期节点启动。生命周期节点允许更轻松地启动和停止服务器。生命周期节点管理将在下一个教程中讨论。 |
Conclusion
在本教程中,我们讨论了 Nav2 的规划器和控制器服务器的角色和配置。总结一下,这些服务器承载了一个或多个算法插件的地图,根据你的机器人结构和环境选择相应的插件。我们还描述了一些规划器和控制器服务器可用的插件,以帮助你确定哪些插件适合你的机器人。最后,我们还提供了一些简单的配置示例,展示了这些插件如何在服务器上实例化。你可以参考所选择的算法插件的配置指南,了解更多有关其配置参数的详细信息。
设置生命周期和组合节点
在本指南中,我们将讨论 ROS 2 中的两个新概念,即生命周期和组合。在本指南的第一个部分,我们讨论了NAV2中生命线的概念以及如何添加生命周期节点以利用它。在第二部分中,我们讨论了组成的目的以及如何在NAV2中手动和动态实施它。
生命周期
ROS 2 中引入了生命周期,以系统地管理机器人操作中涉及的不同节点的启动和关闭。 Lifecycle 节点的使用可确保所有节点在开始执行之前成功实例化,并且如果有任何无响应的节点,Nav2 会关闭这些节点。
生命周期节点包含状态机转换,可在ROS 2服务器中实现确定性行为。生命周期节点转换Nav2由 Lifecycle Manager
处理 。生命周期管理器转换生命周期节点的状态,并更好的控制系统状态。
(
-
生命周期节点(Lifecycle Nodes):这些节点具有不同的状态(例如配置、活动、未配置等),它们的行为和功能在不同状态下可能会有所变化。Lifecycle Nodes 是 ROS 2 中的节点,具有能够在不同状态之间转换的能力。
-
状态机转换:Lifecycle Nodes 实现了状态机的概念,它们可以从一个状态转换到另一个状态。这些转换代表节点在其生命周期中可能经历的状态变化。
-
Lifecycle Manager(生命周期管理器):这是一个用于管理 Lifecycle Nodes 状态的工具或服务。Lifecycle Manager 负责跟踪节点的状态变化,确保节点在适当的时间以正确的顺序进行状态转换。它提供了一种集中式的方式来管理节点状态,使系统状态更加可控。
在 Nav2 中,Lifecycle Manager 负责监视和管理 planner、controller 和其他节点的状态,以确保它们在正确的时间和条件下启动、运行和关闭。Lifecycle Nodes 具有定义的状态,Lifecycle Manager 可以根据定义好的转换规则来管理节点的状态变化。这种状态管理方式有助于确保系统以一致和可预测的方式运行。
)
生命周期节点的主要状态是``Unconfigured`` 、 Inactive
、 Active
和 Finalized
。生命周期节点在实例化后以“未配置”状态开始。生命周期管理器通过实施``Configurating``转换将节点从``Unconfigured`` 转换为 Inactive
。 Configurating
转换设置所有配置参数并准备任何所需的设置,例如内存分配以及静态发布和订阅主题的设置。处于`Inactive``状态的节点可以重新配置其参数,但不能执行任何处理。从`Inactive``状态,生命周期管理器执行``Activating`` 转换状态,将节点从``Inactive`` 过渡到 Active
,这是主要状态。处于 Active
状态的节点被允许执行任何处理操作。如果节点崩溃,生命周期管理器会关闭系统以防止任何严重故障。在关闭时,执行必要的清理操作,节点通过 ``Deactivating ``、 ``CleaningUp ``和 ``ShuttingDown ``转换状态转换到 ``Finalized ``状态。
Configurating:未配置→不活跃
Activating:不活跃→活跃
Deactivating 、CleaningUp 和ShuttingDown:活跃→关闭
有关生命周期管理的更多信息,请参阅 Managed Nodes 的文章。 |
生命周期节点框架由NAV2服务器大量使用,例如在上一个教程中讨论的规划器和控制器服务器。
您可能希望将自己的节点集成到 Nav2 框架中,或者将新的生命周期节点添加到您的系统中。 例如,我们将添加一个新的名义生命周期节点“sensor_driver”,并通过 Nav2 生命周期管理器对其进行控制,以确保在激活导航之前传感器馈送可用。 您可以通过在启动文件中添加一个 sensor_driver
节点并将其添加到导航前由 lifecycle_manager
激活的节点列表中来实现,如下面的示例所示。
lifecycle_nodes = ['sensor_driver',
'controller_server',
'smoother_server',
'planner_server',
'recoveries_server',
'bt_navigator',
'waypoint_follower']
...
Node(
package='nav2_sensor_driver',
executable='sensor_driver',
name='sensor_driver',
output='screen',
parameters=[configured_params],
remappings=remappings),
Node(
package='nav2_lifecycle_manager',
executable='lifecycle_manager',
name='lifecycle_manager_navigation',
output='screen',
parameters=[{'autostart': autostart},
{'node_names': lifecycle_nodes}]),
在上面的代码片段中,生命周期管理器要处理的节点是使用 node_names
参数设置的。 node_names
参数接受一个有序的节点列表,以通过生命周期转换来启动。 如代码片段所示
Lifecycle Manager 的另外两个参数是 autostart
和 bond_timeout `` 。 如果您想在启动时将转换节点设置为 ``Active
状态,请将``autostart`` 设置为``true``。 否则,您将需要手动触发 Lifecycle Manager 以升级系统。 bond_timeout
设置等待时间,以决定如果节点没有响应,何时向下转换所有节点。
关于 Lifecycle Manager 参数的更多信息可以在 Lifecycle Manager 的配置指南 中找到 |
组成
组合是 ROS 2 中的另一个新概念,它通过将多个节点放在一个进程中来减少内存和 CPU 资源。 在 Nav2 中,Composition 可用于在单个进程中组合所有 Nav2 节点,而不是单独启动它们。 这对于部署在开发人员需要优化资源使用的嵌入式系统上很有用。
有关合成的更多信息,请参见 此处。 |
在以下小节中,我们将举例说明如何将新的 Nav2 服务器(我们在概念上称为``route_server`` )添加到我们的系统。 这可以通过手动合成或动态合成来完成。
手动合成
对于手动合成,有一个现有的手动合成启动文件,composed_bringup.cpp 在``nav2_bringup``。 您可以通过执行以下步骤将``route_server``添加到此现有手动组合中:
1、将以下内容添加到 composed_bringup.cpp:
添加 route_server
头文件。
#include "nav2_route_server/route_server.hpp"
创建共享指针 route_node
,并将其添加到 navigation_node_names
,以便通过生命周期管理器 (如果是生命周期节点) 转换。
auto route_node = std::make_shared<nav2_route_server::RouteServer>();
navigation_node_names.push_back(route_node->get_name());
添加 route_node
到 threads
以创建 route_node
的单线程执行器
threads.push_back(create_spin_thread(route_node));
2、将包含服务器的包作为依赖项添加到您的“package.xml”文件中。
<exec_depend>nav2_route_server</exec_depend>
3、将包包含在``CMakeLists.txt``文件中。
find_package(nav2_route_server REQUIRED)
set(dependencies nav2_route_server)
动态组合
在动态组合中,我们利用启动文件将不同的服务器组合成一个进程。 该过程由“ComposableNodeContainer”容器建立,该容器通过“ComposableNode”填充了组合节点。 然后可以像任何其他 Nav2 节点一样启动和使用该容器。
1、在您的启动文件中添加一个新的 ComposableNode() 实例,指向您选择的组件容器。
container = ComposableNodeContainer(
name='my_container',
namespace='',
package='rclcpp_components',
executable='component_container',
composable_node_descriptions=[
ComposableNode(
package='nav2_route_server',
plugin='nav2_route_server::RouteServer',
name='nav2_route_server'),
],
output='screen',
)
请参阅组合演示的 composition_demo.launch.py 中的示例。 |
2、将包含服务器的包添加到您的 package.xml
文件中。
<exec_depend>nav2_route_server</exec_depend>
小结
在本指南的这一部分中,我们讨论了生命周期和组合节点,它们是 ROS 2 中新的重要概念。我们还展示了如何使用 Nav2 为新创建的节点/服务器实现生命周期和组合。 这两个概念有助于有效地运行您的系统,因此鼓励在整个 Nav2 中使用。