当前位置: 首页 > news >正文

ros学习笔记.4 Path Planning Part 2 (避障)

  • 避障是如何工作的
  • 什么是局部规划器?
  • 什么是局部成本图?
  • 路径规划回顾
  • 如何使用动态重新配置和其他 Rviz 工具

局部规划器

一旦全局规划器计算出要遵循的路径,该路径就会发送给局部规划器。然后,局部规划器将执行全局规划的每个部分(让我们将局部规划想象为全局规划的一小部分)。因此,给定要遵循的规划(由全局规划器提供)和地图,局部规划器将提供速度命令以移动机器人。

与全局规划器不同,局部规划器监视里程表和激光数据,并为机器人选择无碰撞的局部规划(让我们将局部规划想象为全局规划的一小部分)。因此,局部规划器可以动态重新计算机器人的路径,以防止机器人撞到物体,但仍允许它到达目的地。

一旦计算出局部规划,它将发布到名为 /local_plan 的主题中。局部规划器还会将其尝试遵循的全局规划部分发布到主题 /global_plan 中。让我们做一个练习,以便你更好地理解这一点。

练习

a) 打开 Rviz 并添加显示,以便能够可视化局部规划器的 /global_plan 和 /local_plan 主题。

b) 向机器人发送目标姿势并可视化两个主题。

和全局规划器一样,还有不同类型的局部规划器。根据您的设置(您使用的机器人、它导航的环境等)和您想要的性能类型,您将使用其中一种或另一种。让我们来看看最重要的几种。

base_local_planner

base_local_planner提供了轨迹展开(Trajectory Rollout)和动态窗口方法(Dynamic Window Approach, DWA)算法的实现,用于计算和执行机器人的全局路径规划。

总结一下,这些算法的基本工作原理如下:

  1. 从机器人的控制空间中离散地采样。
  2. 对于每个采样的速度,从机器人的当前状态开始执行前向模拟,以预测应用该速度后的情况。
  3. 评估每条前向模拟得到的轨迹。
  4. 丢弃不合法的轨迹。
  5. 选择得分最高的轨迹,并将相关的速度发送到移动底盘。
  6. 重复以上步骤。

DWA 轨迹展开的不同之处在于机器人的空间采样方式。轨迹展开从整个前向模拟期间内可实现的速度集合中进行采样,考虑了机器人的加速度限制;而 DWA 则仅在一个模拟步骤中从可实现的速度集合中进行采样,考虑了机器人的加速度限制。

由于 DWA 采样的空间较小,因此它是一种更高效的算法,但对于加速度限制较低的机器人,DWA 可能不如轨迹展开表现得好,因为 DWA 不会对恒定加速度进行前向模拟。在实际应用中,DWA 和轨迹展开的性能类似,因此推荐使用 DWA 以获得效率上的优势。

base_local_planner的 DWA 算法在一个新的局部规划器中得到了改进,这就是我们接下来要介绍的 DWA local planner。

dwa_local_planner

DWA local planner 提供了动态窗口方法(Dynamic Window Approach, DWA)算法的实现。它基本上是对基础局部规划器的 DWA 选项的重写,但代码更简洁、更易于理解,特别是在轨迹模拟方面。

因此,对于使用 DWA 方法进行局部规划的应用,dwa_local_planner 可能是最佳选择。这是最常用的选项。

eband_local_planner

eband_local_planner实现了弹性带(Elastic Band)方法,以计算要跟随的局部路径。

teb_local_planner

teb 局部规划器实现了有时间弹性带(Timed Elastic Band)方法,以计算要跟随的局部路径。

修改Local Planner

move_base 节点使用的局部规划器在 base_local_planner 参数中指定。可以在参数文件中设置,如下例所示:

base_local_planner: "base_local_planner/TrajectoryPlannerROS" # Sets the Trajectory Rollout algorithm from base local                                                                 plannerbase_local_planner: "dwa_local_planner/DWAPlannerROS" # Sets the dwa local plannerbase_local_planner: "eband_local_planner/EBandPlannerROS" # Sets the eband local plannerbase_local_planner: "teb_local_planner/TebLocalPlannerROS" # Sets the teb local planner

或者可以直接在启动文件中设置,就像我们的例子一样:

<arg name="base_local_planner" default="dwa_local_planner/DWAPlannerROS"/>

正如您所期望的,每个局部规划器也有自己的参数。这些参数将根据您使用的局部规划器而有所不同。在本课程中,我们将重点介绍 DWA 局部规划器参数,因为它是最常见的选择。无论如何,如果您想检查其他局部规划器的具体参数,您可以在此处查看:

base_local_planner: base_local_planner - ROS Wiki

eband_local_planner: eband_local_planner - ROS Wiki

teb_local_planner: teb_local_planner - ROS Wiki

DWAPlannerROS 参数

如果您检查包 my_move_base_launcher 中的文件 my_move_base_params.yaml,您将看到 DWAPlannerROS 规划器的参数:

DWAPlannerROS:# Robot configuration parameters  acc_lim_x: 2.5acc_lim_y: 0acc_lim_th: 3.2max_vel_x: 0.5min_vel_x: 0.0max_vel_y: 0min_vel_y: 0max_vel_trans: 0.5min_vel_trans: 0.1max_vel_theta: 1.0min_vel_theta: 0.2# Goal Tolerance Parametersyaw_goal_tolerance: 0.1xy_goal_tolerance: 0.2latch_xy_goal_tolerance: false

DWA 局部规划器最重要的参数如下:

机器人配置参数

  • /acc_lim_x(默认值:2.5):机器人在 x 方向上的加速度限制,单位是米/秒²。
  • /acc_lim_th(默认值:3.2):机器人在旋转方向上的加速度限制,单位是弧度/秒²。
  • /max_vel_trans(默认值:0.55):机器人最大平移速度的绝对值,单位是米/秒。
  • /min_vel_trans(默认值:0.1):机器人最小平移速度的绝对值,单位是米/秒。
  • /max_vel_x(默认值:0.55):机器人最大 x 方向速度,单位是米/秒。
  • /min_vel_x(默认值:0.0):机器人最小 x 方向速度,单位是米/秒,负值表示向后运动。
  • /max_vel_theta(默认值:1.0):机器人最大旋转速度的绝对值,单位是弧度/秒。
  • /min_vel_theta(默认值:0.4):机器人最小旋转速度的绝对值,单位是弧度/秒。

目标容差参数

  • /yaw_goal_tolerance(双精度,默认值:0.05):控制器在达到目标时在偏航/旋转方向上的容差,单位是弧度。
  • /xy_goal_tolerance(双精度,默认值:0.10):控制器在达到目标时在 x 和 y 方向上的容差,单位是米。
  • /latch_xy_goal_tolerance(布尔值,默认值:false):如果目标容差被锁定,当机器人达到目标 xy 位置时,它会原地旋转,即使在旋转过程中最终位置超出了目标容差范围。

练习

a) 打开上一章中创建的 my_move_base_params.yaml 文件进行编辑。

b) 修改 DWAPlannerROS 的 xy_goal_tolerance 参数并将其设置为更高的值。

c) 检查是否注意到性能有任何差异。

High XY tolerance:

 Low XY tolerance:

正如您在练习中看到的,您在参数文件中设置的目标容差越高,机器人设定的目标就越不准确。

正如您在参数文件中看到的,还有其他参数被注释(因此规划器采用它们的默认值):

# 前向模拟参数
# sim_time: 2.0  # 模拟时间(秒)
# sim_granularity: 0.02  # 模拟粒度(秒)
# vx_samples: 6  # x方向速度样本数
# vy_samples: 0  # y方向速度样本数
# vtheta_samples: 20  # 旋转速度样本数
# penalize_negative_x: true  # 是否惩罚负x方向速度# 轨迹评分参数
# path_distance_bias: 32.0  # 控制器保持接近给定路径的权重
# goal_distance_bias: 24.0  # 控制器试图到达局部目标的权重,也控制速度
# occdist_scale: 0.01  # 控制器尝试避免障碍物的权重
# forward_point_distance: 0.325  # 从机器人中心点到额外评分点的距离(米)
# stop_time_buffer: 0.2  # 为了使轨迹被认为有效,机器人在碰撞前必须停止的时间(秒)
# scaling_speed: 0.25  # 机器人足迹开始缩放的速度绝对值(米/秒)
# max_scaling_factor: 0.2  # 机器人足迹的最大缩放因子# 振荡防止参数
# oscillation_reset_dist: 0.25  # 机器人在振荡标志重置之前必须行驶的距离(米)(默认值: 0.05)

练习:

a) 修改局部规划器参数文件中的 sim_time 参数并将其设置为 4.0。

b) 检查是否注意到局部规划器的性能或可视化方面有任何差异。

Regular sim_time (local plan in blue):

 High sim_time (local plan in blue):

从上面的练习中可以看出,sim_time 参数越高,计算出的局部规划就越长。但是,请记住,这也会增加使用的计算资源。

轨迹评分参数

  • /path_distance_bias(默认值:32.0):控制器应保持接近给定路径的权重
  • /goal_distance_bias(默认值:24.0):控制器应尝试达到其局部目标的权重;还控制速度
  • /occdist_scale(默认值:0.01):控制器应尝试避开障碍物的权重

这里有一个 dwa_local_planner_params.yaml 的示例:

# 轨迹评分参数
# path_distance_bias: 32.0  # 控制器保持接近给定路径的权重
# goal_distance_bias: 24.0  # 控制器试图到达局部目标的权重,也控制速度
# occdist_scale: 0.01  # 控制器尝试避免障碍物的权重
# forward_point_distance: 0.325  # 从机器人中心点到额外评分点的距离(米)
# stop_time_buffer: 0.2  # 机器人在碰撞前必须停止的时间,以使轨迹被认为有效(秒)
# scaling_speed: 0.25  # 机器人足迹开始缩放的速度绝对值(米/秒)
# max_scaling_factor: 0.2  # 机器人足迹的最大缩放因子

尝试自己修改这些参数,看看它们如何影响规划过程。例如,您可以尝试更改局部规划器参数文件中的 path_distance_bias 参数。

path_distance_bias 参数用于控制机器人在轨迹追踪时保持接近给定路径的权重。修改这个参数会对机器人行为产生以下影响:

  1. 增加 path_distance_bias 的值:

    • 机器人会更紧密地跟随路径。 增大的权重使得控制器更加重视保持机器人在给定路径上的位置,导致机器人更努力地纠正偏离路径的情况。
    • 可能导致路径跟随过度。 如果 path_distance_bias 设得过高,机器人可能会变得过于固执,紧紧依赖路径,可能会导致在复杂或狭窄环境中的表现变差,甚至导致在障碍物附近出现困难。
  2. 减少 path_distance_bias 的值:

    • 机器人会更灵活。 较低的权重使得控制器对路径的依赖性降低,机器人可能会有更多的自由度来进行调整和优化其他目标,例如到达目标点或避开障碍物。
    • 可能导致路径偏离。 如果这个权重设置得过低,机器人可能不会很好地遵循给定路径,从而导致偏离预定路径,尤其是在路径弯曲或变化较大的情况下。

在全局规划器部分,我们已经向您介绍了代价地图,重点介绍了全局代价地图。现在是时候谈谈局部代价地图了。

Local Costmap

您需要知道的第一件事是,局部规划器使用局部代价地图来计算局部规划。

与全局代价地图不同,局部代价地图直接根据机器人的传感器读数创建。给定代价地图的宽度和高度(由用户定义),它会在机器人在整个环境中移动时将机器人保持在代价地图的中心,并在机器人移动时从地图中删除障碍物信息。

让我们做一个练习,以便您更好地了解局部代价地图的外观,以及如何区分局部代价地图和全局代价地图。

练习

a) 打开 Rviz 并添加适当的显示,以便可视化全局和局部成本地图。

b) 执行以下命令以在房间中生成障碍物。

检查您的工作区中是否已经有 object.urdf 文件。如果您还没有,您需要执行以下命令将其移动到您的工作区。

cp /home/simulations/public_sim_ws/src/all/turtlebot/turtlebot_navigation_gazebo/urdf/object.urdf /home/user/catkin_ws/src

 创建对象

rosrun gazebo_ros spawn_model -file /home/user/catkin_ws/src/object.urdf -urdf -x 0 -y 0 -z 1 -model my_object

c) 启动键盘操作并靠近生成的物体。

roslaunch husky_launch keyboard_teleop.launch

d) 检查全局和局部Costmaps之间的差异。

Husky 面对生成的障碍物:

 全局成本地图(未出现障碍物):

 局部成本地图(障碍物出现):

因此,正如您在上一个练习中看到的,局部代价地图确实会检测模拟中出现的新对象,而全局代价地图则不会。

您可能已经推断出这种情况,因为全局代价地图是从静态地图文件创建的。这意味着即使环境发生变化,代价地图也不会改变。相反,局部代价地图是根据机器人的传感器读数创建的,因此它将始终使用来自传感器的新读数进行更新。

由于全局代价地图和局部代价地图的行为不同,因此参数文件也必须不同。让我们来看看我们需要为局部代价地图设置的最重要的参数。

Local Costmap 参数

你需要了解的参数如下:

  • global_frame: 成本地图操作的全局坐标系。在局部成本地图中,此参数必须设置为 "/odom"。
  • robot_base_frame: 机器人基座链接的坐标系名称。
  • rolling_window: 是否使用滚动窗口版本的成本地图。如果 static_map 参数设置为 true,则此参数必须设置为 false。在局部成本地图中,此参数必须设置为 true
  • update_frequency(默认值: 5.0): 更新地图的频率,以赫兹(Hz)为单位。
  • width(默认值: 10): 成本地图的宽度。
  • height(默认值: 10): 成本地图的高度。
  • plugins: 插件规范的序列,每个层一个。每个规范是一个包含 nametype 字段的字典。name 用于定义插件的参数命名空间。

正如你所看到的,这些参数与全局成本地图的参数相同。然而,我们增加了一些在处理局部成本地图时很有用的参数:widthheight。我们还增加了 update_frequency,稍后将在本单元中讨论。

现在,让我们做一个简单的练习来测试 widthheight 参数。

练习

a) 将一个名为 my_local_costmap_params.yaml 的文件添加到您在练习my_move_base_launcher中创建的包的 params目录中。

b) 将 husky_navigation 包的 costmap_local.yaml 文件的内容复制到此文件中。

global_frame: odom
rolling_window: trueplugins:- {name: obstacles_laser,           type: "costmap_2d::ObstacleLayer"}- {name: inflation,                 type: "costmap_2d::InflationLayer"}

c) 修改您在练习my_move_base_launcher中创建的 my_move_base.launch 文件,以便它加载您刚刚创建的局部 costmap 参数文件。

<?xml version="1.0"?>
<launch><!-- Run the map server --><arg name="map_file" default="$(find husky_navigation)/maps/my_map.yaml"/><node name="map_server" pkg="map_server" type="map_server" args="$(arg map_file)" /><!--- Run AMCL --><include file="$(find husky_navigation)/launch/amcl.launch" /><arg name="no_static_map" default="false"/><arg name="base_global_planner" default="navfn/NavfnROS"/><arg name="base_local_planner" default="dwa_local_planner/DWAPlannerROS"/><!-- <arg name="base_local_planner" default="base_local_planner/TrajectoryPlannerROS"/> --><node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen"><param name="base_global_planner" value="$(arg base_global_planner)"/><param name="base_local_planner" value="$(arg base_local_planner)"/>  <rosparam file="$(find my_move_base_launcher)/params/my_move_base_params.yaml" command="load"/><!-- observation sources located in costmap_common.yaml --><rosparam file="$(find husky_navigation)/config/costmap_common.yaml" command="load" ns="global_costmap" /><rosparam file="$(find husky_navigation)/config/costmap_common.yaml" command="load" ns="local_costmap" /><!-- local costmap, needs size --><rosparam file="$(find my_move_base_launcher)/params/my_local_costmap_params.yaml" command="load" ns="local_costmap" /><param name="local_costmap/width" value="10.0"/> # Change to 5 for the Exercise<param name="local_costmap/height" value="10.0"/> # Change to 5 for the Exercise<!-- static global costmap, static map provides size --><rosparam file="$(find my_move_base_launcher)/params/my_global_costmap_params.yaml" command="load" ns="global_costmap" unless="$(arg no_static_map)"/><!-- global costmap with laser, for odom_navigation_demo --><rosparam file="$(find husky_navigation)/config/costmap_global_laser.yaml" command="load" ns="global_costmap" if="$(arg no_static_map)"/><param name="global_costmap/width" value="100.0" if="$(arg no_static_map)"/><param name="global_costmap/height" value="100.0" if="$(arg no_static_map)"/></node></launch>

d) 启动 Rviz 并再次可视化局部costmap。可视化地图和 costmap 模式。

e) 修改宽度和高度参数并将其设置为 5。再次可视化 costmap。

10x10 costmap (map view):

 10x10 costmap (costmap view):

5x5 costmap (map view):

5x5 costmap (costmap view):

正如您在上一个练习中所看到的,为代价地图设置正确的宽度和高度非常重要。根据您想要导航的环境,您将设置一个或另一个值以正确显示障碍物。

让我们继续使用局部代价地图参数。尽管参数与全局代价地图相同,但它们的设置值并不相同。

例如,对于局部代价地图,rolling_window 参数将设置为 true。这样,我们表明我们不希望代价地图从静态地图初始化(就像我们对全局代价地图所做的那样),而是从机器人的传感器读数构建。

此外,由于我们没有任何静态地图,因此需要将 global_frame 参数设置为 odom。

您可以在上一个练习中创建的 my_local_costmap_params.yaml 文件中看到这一点:

global_frame: odom
rolling_window: true

正如我们在全局成本地图中看到的,局部成本地图也可以添加层。在局部成本地图的情况下,通常会添加以下两层:

  • costmap_2d::ObstacleLayer: 用于避障。
  • costmap_2d::InflationLayer: 用于对障碍物进行膨胀处理。

因此,你最终会得到如下结果:

plugins:- {name: obstacle_layer,      type: "costmap_2d::ObstacleLayer"}- {name: inflation_layer,     type: "costmap_2d::InflationLayer"}

**障碍层**对**局部代价地图**和**全局代价地图**使用不同的插件。对于局部代价地图,它使用**costmap_2d::ObstacleLayer**,而对于全局代价地图,它使用**costmap_2d::VoxelLayer**。这非常重要,因为在导航中,对障碍层使用错误的插件是一个常见错误。

让我们添加最后一个参数!正如您通过练习已经看到的,局部成本地图会不断更新自身。这些更新周期以 update_frequency 参数指定的速率进行。每个周期的工作方式如下:

  1. 传感器数据进入。
  2. 执行标记和清除操作。
  3. 为每个单元格分配适当的成本值。
  4. 对每个有障碍物的单元格执行障碍物膨胀。这包括将成本值从每个占用的单元格向外传播到指定的膨胀半径。

练习

a) 在 local costmap  参数文件中,将地图的 update_frequency 参数改得更慢。

b) 再次重复上面练习,看看现在会发生什么。

代价地图中的对象的生成稍有延迟。

现在,您可能想知道……上面提到的标记和清除操作是什么?

正如您已经知道的,代价地图会自动订阅传感器主题,并根据从传感器收到的数据进行自我更新。每个传感器都用于标记(将障碍物信息插入代价地图)、清除(从代价地图中删除障碍物信息)或两者兼而有之。

标记操作只是数组中的索引,用于更改单元格的成本。

但是,清除操作包括从传感器原点向外通过网格进行光线追踪,以报告每个观察结果。

标记和清除操作可以在障碍层中定义。

此时,我们几乎可以说您已经知道如何配置全局和本地代价地图。但如果您还记得的话,还有一个我们尚未讨论的参数文件。那就是通用代价地图参数文件。这些参数将影响全局和本地代价地图。

Common Costmap Parameters

基本上,您需要在这个文件中设置的最重要参数如下:

  • footprint: 足迹是移动底盘的轮廓。在 ROS 中,它表示为一个二维数组,例如 [x0, y0], [x1, y1], [x2, y2], ...。这个足迹将用于计算内接圆和外接圆的半径,这些圆用于以适合该机器人的方式膨胀障碍物。通常,为了安全起见,我们希望足迹略大于机器人的实际轮廓。
  • robot_radius: 如果机器人是圆形的,我们将指定此参数而不是足迹。
  • layers parameters: 在这里我们将定义每一层的参数。每一层都有其自己的参数。

障碍层

障碍层负责标记和清除操作。

如您所知,成本地图会自动订阅传感器主题,并根据接收到的数据进行更新。每个传感器用于标记(将障碍物信息插入成本地图)、清除(从成本地图中移除障碍物信息),或两者兼具。

  • 标记操作:只是通过数组索引来改变一个单元格的成本。
  • 清除操作:则是通过从传感器原点向外进行网格射线追踪,处理每个报告的观察数据。

标记和清除操作可以在障碍层中定义。

为了配置障碍层,我们首先需要为层设置名称,然后设置 observation_sources 参数。

  • observation_sourcesdefault: ""):由空格分隔的观察源名称列表。这定义了以下各个 source_name 命名空间。

您可以在 husky_navigation 包中的 costmap_common.yaml 文件中查看其操作方式:

obstacles_laser: # Name of the layerobservation_sources: laser # We define 1 observation_source named laser

现在我们可以为这个 observation_source 定义具体的参数。observation_sources 中的每个 source_name 定义了一个命名空间,其中可以设置参数:

  • /source_name/topic(默认值: source_name):传感器数据接收的主题。默认为源名称。
  • /source_name/data_type(默认值: "PointCloud"):与主题相关联的数据类型,目前只支持 "PointCloud"、"PointCloud2" 和 "LaserScan"。
  • /source_name/clearing(默认值: false):是否使用该观察源来清除空闲空间。
  • /source_name/marking(默认值: true):是否使用该观察源来标记障碍物。
  • /source_name/inf_is_valid(默认值: false):允许在 "LaserScan" 观察消息中存在 Inf 值。Inf 值将被转换为激光的最大范围。
  • /source_name/max_obstacle_height(默认值: 2.0):要插入到成本地图中的障碍物的最大高度(米)。该参数应设置为比机器人的实际高度稍高。
  • /source_name/obstacle_range(默认值: 2.5):障碍物将在成本地图中插入的默认最大距离(米)。此设置可以按传感器进行覆盖。
  • /source_name/raytrace_range(默认值: 3.0):使用传感器数据从地图中射线追踪障碍物的默认范围(米)。此设置可以按传感器进行覆盖。

您可以在 husky_navigation 包中的 costmap_common.yaml 文件中查看其完成方式:

laser: {data_type: LaserScan, clearing: true, marking: true, topic: scan, inf_is_valid: true, obstacle_range: 5.5}

正如您在示例中看到的,我们仅声明 1 个 observer_source,用于激光。这意味着我们的 Husky 机器人将根据从其激光接收到的数据构建其本地成本地图。

练习:

a) 将名为 my_common_costmap_params.yaml 的文件添加到您在练习my_move_base_launcher中创建的包的 params 目录中。

b) 将 husky_navigation 包的 costmap_common.yaml 文件的内容复制到这个新文件中。

# 机器人足迹定义,表示机器人在代价图上的占用区域
footprint: [[-0.5, -0.33], [-0.5, 0.33], [0.5, 0.33], [0.5, -0.33]]# 足迹填充值,用于确保代价图上机器人的边缘有一定的缓冲
footprint_padding: 0.01# 机器人基础坐标系
robot_base_frame: base_link# 更新代价图的频率(Hz)
update_frequency: 4.0# 发布代价图的频率(Hz)
publish_frequency: 3.0# 坐标变换的容忍度(秒),用于处理传感器数据和代价图之间的坐标变换
transform_tolerance: 0.5# 代价图的分辨率(米/像素),定义每个像素在实际世界中的大小
resolution: 0.05# 层定义部分
# 静态地图层
static:# 静态地图的主题名称map_topic: /map# 是否订阅地图更新subscribe_to_updates: true# 障碍物激光层
obstacles_laser:# 观测源,表示激光数据的来源observation_sources: laser# 激光数据的配置laser: {data_type: LaserScan,          # 数据类型clearing: true,                # 是否清除已探测到的障碍物marking: true,                 # 是否标记障碍物topic: scan,                   # 激光数据的主题inf_is_valid: true,            # 是否将无穷大距离视为有效obstacle_range: 5.5            # 识别障碍物的最大范围(米)}# 膨胀层
inflation:# 膨胀半径(米),用于扩展障碍物区域以考虑机器人周围的安全距离inflation_radius: 1.0

a) 现在,修改 obstacle_range 参数并将其设置为 1。

b) 将机器人移近障碍物并观察会发生什么。

Inflation Layer

Inflation Layer负责对每个包含障碍物的单元格进行膨胀处理。

  • inflation_radius(默认值: 0.55):用于膨胀障碍物成本值的半径(米)。
  • cost_scaling_factor(默认值: 10.0):在膨胀过程中应用于成本值的缩放因子。

练习

a) 现在,修改 costmap 的 inflation_radius 参数,使其速度更慢。

b) 靠近某个物体,检查差异。

inflation_radius 参数用于控制障碍物周围的膨胀区域的大小,这有助于为机器人提供一个更加保守的避障区域。

Low inflation:

High inflation:

Static Layer

静态层负责向需要它的代价地图(全局代价地图)提供静态地图。

map_topic(string,默认值:“map”):代价地图为静态地图订阅的主题。

Rotate Recovery

基本上,旋转恢复行为是一种简单的恢复行为,通过将机器人旋转 360 度来尝试清理空间。这样,机器人可能能够找到一条没有障碍物的路径继续导航。

它有一些可以自定义的参数,以便改变或改善其行为:

旋转恢复参数
  • /sim_granularity (默认值: 0.017): 在检查是否可以安全地进行原地旋转时,检查障碍物的距离,单位是弧度。默认为 1 度。
  • /frequency (默认值: 20.0): 向移动底盘发送速度命令的频率,单位是赫兹 (HZ)。
其他参数
  • /yaw_goal_tolerance (double, 默认值: 0.05): 控制器在实现目标时在偏航/旋转方向上的容差,单位是弧度。
  • /acc_lim_th (double, 默认值: 3.2): 机器人的旋转加速度限制,单位是弧度/秒²。
  • /max_rotational_vel (double, 默认值: 1.0): 底盘允许的最大旋转速度,单位是弧度/秒。
  • /min_in_place_rotational_vel (double, 默认值: 0.4): 执行原地旋转时底盘允许的最小旋转速度,单位是弧度/秒。

这些参数也可以在 move_base 参数文件中设置。

Clear Costmap

清除成本图恢复是一种简单的恢复行为,通过清除机器人地图中指定区域之外的障碍物来清理空间。基本上,局部成本图会恢复到与全局成本图相同的状态。

让我们来进行一个简短的练习,以测试这些恢复行为。

练习

向无法到达的机器人发送导航目标,并检查是否触发恢复行为。

例如,您可以在模拟世界的厨房内设置一个目标。查看下图:

move base节点的输出:

旋转恢复行为:

move_base 节点还提供了一项服务,用于清除 costmap 中的障碍物。这项服务称为 /move_base/clear_cotmaps。

请记住,通过清除 costmap 中的障碍物,您将使这些障碍物对机器人不可见。因此,调用此服务时要小心,因为它可能会导致机器人开始撞到障碍物。

练习

a) 如果还没有,则将一个未出现在全局代价地图中的对象添加到场景中。

b) 移动机器人,使其在局部代价地图中检测到这个新障碍物。

c) 转动机器人,使其不再看到障碍物(激光束检测不到它)。

d) 通过 WebShell 调用 /clear_costmaps 服务,并检查发生了什么。

rosservice call /move_base/clear_costmaps "{}"

被激光检测到的物体,放置到局部Ccostmap中:

Husky转身,激光不再检测到物体,但它仍然出现在本地代价地图中。

调用/move_base/clear_costmaps服务后,对象从局部代价地图中清除:

Recap

恭喜你!到目前为止,你已经了解了本章涵盖的几乎所有重要内容。由于这是课程的最后一章,这意味着你距离完全掌握 ROS 导航系统已经非常接近了!

不过,你可能会对有关路径规划的大量信息感到不知所措。因此,我认为这是一个总结本章内容的好时机。让我们开始吧!

move_base 节点

move_base 节点基本上是协调所有路径规划系统的节点。它接收目标位姿作为输入,并输出必要的速度指令,以便将机器人从初始位姿移动到指定的目标位姿。为实现这一目标,move_base 节点管理一个完整的内部流程,其中包括以下几个部分:

  • 全局规划器
  • 局部规划器
  • 成本图
  • 恢复行为

全局规划器

move_base 节点收到新的目标时,它会立即将其发送给全局规划器。全局规划器随后将计算出一条安全的路径,供机器人到达指定的目标。全局规划器使用全局成本图数据来计算这条路径。

有不同类型的全局规划器。根据你的设置,你将使用不同的全局规划器。

局部规划器

一旦全局规划器为机器人计算出路径,它会将路径发送给局部规划器。局部规划器将执行这条路径,将其拆分为更小的(局部)部分。因此,给定一个要遵循的计划和地图,局部规划器将提供速度指令以移动机器人。局部规划器在局部成本图上操作。

有不同类型的局部规划器。根据你对性能的需求,你将选择不同的局部规划器。

成本图

成本图基本上是表示地图上哪些点对机器人是安全的,哪些点是不安全的地图。有 2 种类型的成本图:

  • 全局成本图
  • 局部成本图

基本上,它们之间的区别在于,全局成本图是使用先前构建的静态地图数据构建的,而局部成本图则是从机器人的传感器读取数据构建的。

恢复行为

恢复行为提供了在机器人卡住时的处理方法。导航栈提供了 2 种不同的恢复行为:

  • 旋转恢复
  • 清除成本图

配置

由于有许多不同的节点协同工作,因此可配置的参数数量也非常高。我认为总结一下需要设置的路径规划相关参数文件是一个好主意。你需要的参数文件如下:

<launch><!-- Load move_base parameters --><param file="$(find your_package)/config/move_base_params.yaml" command="load" /><!-- Load global planner parameters --><param file="$(find your_package)/config/global_planner_params.yaml" command="load" /><!-- Load local planner parameters --><param file="$(find your_package)/config/local_planner_params.yaml" command="load" /><!-- Load common costmap parameters --><param file="$(find your_package)/config/common_costmap_params.yaml" command="load" /><!-- Load global costmap parameters --><param file="$(find your_package)/config/global_costmap_params.yaml" command="load" /><!-- Load local costmap parameters --><param file="$(find your_package)/config/local_costmap_params.yaml" command="load" /><!-- Start the move_base node --><node pkg="move_base" type="move_base" name="move_base" />
</launch>

除了上述参数文件外,我们还需要一个启动文件,以便启动整个系统并加载不同的参数。

总结

总体而言,路径规划的流程如下:

在获取机器人的当前位置后,我们可以将目标位置发送到 move_base 节点。该节点将目标位置发送到全局规划器,全局规划器将计划出一条从当前位置到目标位置的路径。这个计划是基于全局成本图的,而全局成本图由地图服务器提供数据。

全局规划器将此路径发送给本地规划器,本地规划器执行全局计划的每个部分。本地规划器获取里程计和激光数据值,并找到一个没有碰撞的局部计划。局部规划器与本地成本图相关联,本地成本图可以监视机器人周围的障碍物。局部规划器生成速度指令并将其发送到底盘控制器。底盘控制器将这些指令转换为实际的机器人运动。

如果机器人卡住了,恢复行为节点(如清除成本图恢复或旋转恢复)将被调用。

现在一切都更有意义了,对吧?

所以,凭借你在本课程中获得的所有知识,你可以再次查看下面的图示,尝试理解其中涉及的所有不同元素。

动态重新配置

到目前为止,我们已经了解了如何通过在参数文件中修改参数来更改参数。但是,猜猜看……这不是更改参数的唯一方法!您还可以使用 rqt_reconfigure 工具更改动态参数。请按照以下步骤操作:

a) 运行下一个命令以打开 rqt_reconfigure 工具。

rosrun rqt_reconfigure rqt_reconfigure
  • 打开 move_base group。
  • 选择 DWAPlannerROS 节点。
  • 稍微调整一下以下 3 个参数:
    • path_distance_bias
    • goal_distance_bias
    • occdist_scale
  • 上述参数用于计算成本函数,用于对每条轨迹进行评分。更详细地说,它们定义了以下内容:
    • path_distance_bias:控制器应保持接近给定路径的权重。
    • goal_distance_bias:控制器应尝试达到其局部目标的权重,也控制速度。
    • occdist_scale:控制器应尝试避开障碍物的权重。
  • 打开 Rviz 并可视化全局和局部计划如何根据设置的值发生变化。

Rviz 中的其他有用可视化

到目前为止,我们已经了解了一些通过 Rviz 可视化 move_base 节点过程不同部分的方法。但是,还有一些可能值得了解:

Robot Footprint

它显示了机器人的足迹。

Current Goal

要显示导航堆栈试图实现的目标姿势,请添加姿势显示并将其主题设置为 /move_base_simple/goal。现在您将能够看到红色箭头所示的目标姿势。它可用于了解机器人的最终位置。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【Linux基础】冯诺依曼体系结构操作系统的理解
  • 1.接口测试基础
  • 测试用例的了解
  • 【设计模式】创建型模式(四):建造者模式
  • Python中的魔法:探索自定义Context Manager的魅力
  • 7天速成前端 ------学习日志 (继苍穹外卖之后)
  • Eclipse折叠if、else、try catch的{}
  • leetcode01——27. 移除元素(双指针)、977. 有序数组的平方(双指针)、209. 长度最小的子数组(双指针/滑动窗口)
  • leetcode刷题day17|二叉树Part05(654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树)
  • MySQL:索引02——使用索引
  • React 嵌套类名样式不生效
  • 基于python+django+vue的家居全屋定制系统
  • Vue3.5+ 响应式 Props 解构
  • PDF扫描版文字识别OCR
  • C/C++实现植物大战僵尸(PVZ)(打地鼠版)
  • 分享的文章《人生如棋》
  • 【399天】跃迁之路——程序员高效学习方法论探索系列(实验阶段156-2018.03.11)...
  • Android 架构优化~MVP 架构改造
  • CAP理论的例子讲解
  • CentOS 7 防火墙操作
  • CentOS从零开始部署Nodejs项目
  • Java编程基础24——递归练习
  • Kibana配置logstash,报表一体化
  • Making An Indicator With Pure CSS
  • MySQL的数据类型
  • Node 版本管理
  • SpiderData 2019年2月16日 DApp数据排行榜
  • underscore源码剖析之整体架构
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 闭包--闭包作用之保存(一)
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 记一次删除Git记录中的大文件的过程
  • 世界上最简单的无等待算法(getAndIncrement)
  • 我与Jetbrains的这些年
  • 06-01 点餐小程序前台界面搭建
  • puppet连载22:define用法
  • ​ 无限可能性的探索:Amazon Lightsail轻量应用服务器引领数字化时代创新发展
  • #QT(串口助手-界面)
  • #QT项目实战(天气预报)
  • #Z0458. 树的中心2
  • $(this) 和 this 关键字在 jQuery 中有何不同?
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (2024,Flag-DiT,文本引导的多模态生成,SR,统一的标记化,RoPE、RMSNorm 和流匹配)Lumina-T2X
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第2节(共同的基类)
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (十八)三元表达式和列表解析
  • (一) storm的集群安装与配置
  • (转)shell中括号的特殊用法 linux if多条件判断
  • (转)我也是一只IT小小鸟
  • ****** 二十三 ******、软设笔记【数据库】-数据操作-常用关系操作、关系运算
  • .NET Core 发展历程和版本迭代
  • .Net IE10 _doPostBack 未定义
  • .netcore 6.0/7.0项目迁移至.netcore 8.0 注意事项
  • .net开源工作流引擎ccflow表单数据返回值Pop分组模式和表格模式对比
  • .net企业级架构实战之7——Spring.net整合Asp.net mvc