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                                                                 planner

base_local_planner: "dwa_local_planner/DWAPlannerROS" # Sets the dwa local planner

base_local_planner: "eband_local_planner/EBandPlannerROS" # Sets the eband local planner

base_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.5
  acc_lim_y: 0
  acc_lim_th: 3.2

  max_vel_x: 0.5
  min_vel_x: 0.0
  max_vel_y: 0
  min_vel_y: 0

  max_vel_trans: 0.5
  min_vel_trans: 0.1
  max_vel_theta: 1.0
  min_vel_theta: 0.2

  # Goal Tolerance Parameters
  yaw_goal_tolerance: 0.1
  xy_goal_tolerance: 0.2
  latch_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: true

plugins:
  - {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 layer
    observation_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
update_frequency: 4.0
publish_frequency: 3.0
transform_tolerance: 0.5

resolution: 0.05

#layer definitions
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。现在您将能够看到红色箭头所示的目标姿势。它可用于了解机器人的最终位置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/875951.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

比较stl库的ostringstream与Qt的QString::arg(),QString::number()

需求&#xff1a; 显示一个float或者double类型的数&#xff0c;要求小数点后的数字位数为定值。 考虑STL库的ostringstream或者Qt的QString::arg(), number 对于stringstream,使用比较繁琐&#xff0c;要联合使用std::fixed和std::setprecision才能实现固定小数位数显示&am…

UE5-俯视角色移动(蓝图)01

效果如下&#xff1a; 蓝图节点如下&#xff1a; 使用示例自带的移动蓝图&#xff0c;发现角色只能平移&#xff0c;不会转向。必须勾选以下选项&#xff1a; 点击蓝图-》组件-》SpringArm节点。在细节中找到摄像机设置&#xff0c;勾选以下&#xff1a; 在 点击蓝图-》组件-…

PowerShell install 一键部署Oracle21c-xe

Oracle21c-xe前言 无论您是开发人员、DBA、数据科学家、教育工作者,还是仅仅对数据库感兴趣,Oracle Database Express Edition (XE) 都是理想的入门方式。它是全球企业可依赖的强大的 Oracle Database,提供简单的下载、易于使用和功能齐全的体验。您可以在任何环境中使用该…

Qt多语言/多语种详细开发教程

Qt作为跨平台的开发工具&#xff0c;早已应用到各行各业的软件开发中。 今天讲讲&#xff0c;Qt开发的正序怎么做多语言开发。就是说&#xff0c;你设置中文&#xff0c;就中文显示&#xff1b;设置英语就英文显示&#xff0c;设置繁体就繁体显示&#xff0c;设置发育就显示法语…

Vue3+TS项目给el-button统一封装一个点击后转圈效果的钩子函数按钮防抖

前言 每个按钮都要单独定义一个loading变量&#xff0c;并且在接口请求前修改为true&#xff0c;接口响应后再修改为false&#xff0c;封装后这段重复的逻辑就可以统一管理不用每次都写一遍了。 效果 新建一个公共的src\common.ts import { ref } from "vue"expor…

Azure web app has no access to openai private endpoint in virtual network

题意&#xff1a;"Azure Web 应用无法访问虚拟网络中的 OpenAI 私有端点。" 问题背景&#xff1a; I am trying to host a web application similar to a private ChatGPT instance within a secluded virtual network, ensuring that theres no external internet …

服务器环境搭建-5 Nexus搭建与使用介绍

背景 本文介绍nexus的安装、配置和使用&#xff0c;之后通过案例的方式演示使用过程。 1.下载和安装 本文使用Nexus 3.x版本进行演示 下载地址&#xff1a;Download Nexus Repository OSS | Sonatype 国外网站下载速度较慢&#xff0c;也可以通过百度网盘下载(提取码:9999): …

形态学算法(连通分量提取,区域最大值提取)

文章目录 二值图像形态学算法连通分量提取 灰度图形态学算法灰度重建区域最大值查找 本文先列举一些近期用到的形态学算法&#xff0c;以后可能会再进行补充。 二值图像形态学算法 连通分量提取 在上一篇文章中已经提到连通分量的概念&#xff0c;这里再进行回顾&#xff1a;…

Leetcode 寻找重复数

可以使用 位运算 来解决这道题目。使用位运算的一个核心思想是基于数字的二进制表示&#xff0c;统计每一位上 1 的出现次数&#xff0c;并与期望的出现次数做比较。通过这种方法&#xff0c;可以推断出哪个数字重复。 class Solution { public:int findDuplicate(vector<i…

abVIEW 可以同时支持脚本编程和图形编程

LabVIEW 可以同时支持脚本编程和图形编程&#xff0c;但主要依赖其独特的 图形编程 环境&#xff08;G语言&#xff09;&#xff0c;其中程序通过连线与节点来表示数据流和功能模块。不过&#xff0c;LabVIEW 也支持通过以下方式实现脚本编程的能力&#xff1a; 1. 调用外部脚本…

使用 PyCharm 新建 Python 项目详解

使用 PyCharm 新建 Python 项目详解 文章目录 使用 PyCharm 新建 Python 项目详解一 新建 Python 项目二 配置环境1 项目存放目录2 Python Interpreter 选择3 创建隔离环境4 选择你的 Python 版本5 选择 Conda executable 三 New Window 打开项目四 目录结构五 程序编写运行六 …

【资料分析】平均倍数类

平均 观察选项&#xff0c;差距较大&#xff0c;大胆约分即可 很少的情况下&#xff0c;选项相差很近不能随便约分 倍数 第N次注意增长率是否为下降&#xff01; 问的是基期倍数比哦 平均增长量 十三五这种明确问法&#xff0c;一定是五年 属于有往前推的A和不往前推的…

【QT】常用控件-下

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 &#x1f3e0;个人专栏&#xff1a;QT 目录 &#x1f449;&#x1f3fb;QComboBox&#x1f449;&#x1f3fb; QSpinBox&#x1f449;&#x1f3fb;QDateTimeEdit&#x1f449;&#x1f3fb;QD…

第四届长城杯部分wp

还是太菜了&#xff0c;要经常练了 1.BrickGame 读源码可以看到时间的值是由js设定的&#xff0c;所以控制台将timeleft的时间改成999999 通过游戏就可以得到flag 2.SQLUP 一道文件上传的题目&#xff0c;在登陆页面我用admin和1登陆成功了&#xff0c;但是按照正常的应该是…

实战千问2大模型第三天——Qwen2-VL-7B(多模态)视频检测和批处理代码测试

画面描述:这个视频中,一位穿着蓝色西装的女性站在室内,背景中可以看到一些装饰品和植物。她双手交叉放在身前,面带微笑,似乎在进行一场演讲或主持活动。她的服装整洁,显得非常专业和自信。 一、简介 阿里通义千问开源新一代视觉语言模型Qwen2-VL。其中,Qwen2-VL-72B在大…

Spring Boot 集成 Redisson 实现消息队列

包含组件内容 RedisQueue&#xff1a;消息队列监听标识RedisQueueInit&#xff1a;Redis队列监听器RedisQueueListener&#xff1a;Redis消息队列监听实现RedisQueueService&#xff1a;Redis消息队列服务工具 代码实现 RedisQueue import java.lang.annotation.ElementTyp…

清理C盘缓存的垃圾,专业清理C盘缓存垃圾的步骤与策略

在维护计算机系统的过程中&#xff0c;定期清理C盘&#xff08;通常是系统盘&#xff09;中的缓存和垃圾文件是一项至关重要的任务。这不仅能有效释放磁盘空间&#xff0c;提升系统性能&#xff0c;还能减少因磁盘空间不足导致的程序运行缓慢或错误。以下是一系列专业且安全的步…

请求响应-02.请求-postman工具

一.前后端分离开发 当前主流的开发模式是前后端分离开发&#xff0c;每开发一个功能&#xff0c;就需要对该功能接口进行测试&#xff0c;当前我们的测试方法是直接将url地址输入到浏览器中&#xff0c;查看web页面是否满足我们的要求。但是浏览器发起的请求全部都是GET请求&am…

架构设计 - 常用日志收集方案选型对比与推荐

目录 1. 常用组合1.1 ELK Stack -> Elastic Stack1.2 EFK Stack1.3 Graylog1.4 PLG 日志系统1.5 Splunk1.6 Filebeat ELK1.7 AWS CloudWatch Logs1.8 阿里云日志服务1.9 腾讯云 CLS&#xff08;日志服务&#xff09; 2. 推荐 日志收集是系统监控和调试中的关键环节。常见的…

[ RK3566-Android11 ] 关于 RK628F 驱动移植以及调试说明

问题描述 我这个项目的SDK比较老&#xff0c;移植RK628F最新驱动的调试过程&#xff0c;踩了很多坑&#xff0c;希望大家别踩坑。 解决方案&#xff1a; 首先在FTP上下载最新的RK628的驱动 rk628-for-all-v27-240730 版本。 下载完后 不要直接替换&#xff0c;不要直接替换&a…