ROS组合导航笔记2:使用外部定位系统

在上一单元中,我们了解了如何合并不同传感器的数据以生成机器人的姿势估计。因此,基本上,我们介绍了图表的以下部分,其中向 robot_localization 节点提供了不同的传感器,以便通过卡尔曼滤波器进行合并。

但是...图表的其他部分怎么样?如果除了传感器数据之外,我们还有另一个外部定位系统作为输入,会发生什么?

好吧,这就是我们将在接下来的章节中发现的!不过,在本章中,我们将重点介绍如何处理外部 SLAM 系统。所以,让我们开始吧!

AMCL

在 ROS 中有多种定位系统存在,但最为知名和广泛使用的无疑是 AMCL。AMCL 是一个用于 2D 环境中移动机器人的概率定位系统。它实现了自适应蒙特卡洛定位(AMCL)方法,使用粒子滤波器来跟踪机器人相对于已知地图的位置。

 

在本章节中,我们将专注于运行一个 AMCL 节点,以便稍后我们可以将其与 robot_localization 节点结合使用。那么,让我们开始吧!

创建一个地图

要使用 AMCL,您需要做的第一件事就是创建机器人所在环境的地图。为此,您将需要导航堆栈提供的 slam_gmapping 节点。要了解如何执行此操作,请按照下一个练习进行操作:

Exercise 2.1

a) 首先,让我们创建一个新包,将所有与导航相关的文件放在里面。

roscd; cd src;
catkin_create_pkg my_sumit_xl_tools

b) 在这个新包中,让我们创建 2 个新目录:一个名为 launch,另一个名为 param。

c) 现在,让我们创建一个 launch 文件以启动我们的 slam_gmapping 节点!

start_mapping.launch

<launch><node pkg="gmapping" type="slam_gmapping" name="slam_gmapping" output="screen"><remap from="scan" to ="/hokuyo_base/scan"/> <!-- 重映射激光扫描数据源到 /hokuyo_base/scan --><param name="base_frame" value="summit_xl_a_base_footprint"/> <!-- 机器人底盘坐标系名称 --><param name="odom_frame" value="summit_xl_a_odom"/> <!-- 里程计坐标系名称 --><!-- 处理每多少个扫描数据中的 1 个(设置为更高的数字以跳过更多扫描) --><param name="throttle_scans" value="1"/><param name="map_update_interval" value="5.0"/> <!-- 地图更新间隔时间(秒),默认值:5.0 --><!-- 激光的最大有效范围。一个光束被裁剪到这个值。 --><param name="maxUrange" value="5.0"/><!-- 传感器的最大范围。如果没有障碍物的区域在传感器范围内应被视为地图中的自由空间,请设置 maxUrange < 真实传感器的最大范围 <= maxRange --><param name="maxRange" value="10.0"/><param name="sigma" value="0.05"/> <!-- 高斯滤波器的标准差 --><param name="kernelSize" value="1"/> <!-- 高斯滤波器的内核大小 --><param name="lstep" value="0.05"/> <!-- 激光扫描数据的步长 --><param name="astep" value="0.05"/> <!-- 角度步长 --><param name="iterations" value="5"/> <!-- 最大迭代次数 --><param name="lsigma" value="0.075"/> <!-- 线性分布的标准差 --><param name="ogain" value="3.0"/> <!-- 增益系数 --><param name="lskip" value="0"/> <!-- 跳过的激光扫描数量 --><param name="srr" value="0.1"/> <!-- 运动模型的旋转误差 --><param name="srt" value="0.2"/> <!-- 运动模型的旋转误差 --><param name="str" value="0.1"/> <!-- 运动模型的平移误差 --><param name="stt" value="0.2"/> <!-- 运动模型的平移误差 --><param name="linearUpdate" value="0.2"/> <!-- 线性更新阈值 --><param name="angularUpdate" value="0.1"/> <!-- 角度更新阈值 --><param name="temporalUpdate" value="3.0"/> <!-- 时间更新阈值 --><param name="resampleThreshold" value="0.5"/> <!-- 重采样阈值 --><param name="particles" value="100"/> <!-- 粒子数量 --><param name="xmin" value="-50.0"/> <!-- 地图的最小 x 坐标 --><param name="ymin" value="-50.0"/> <!-- 地图的最小 y 坐标 --><param name="xmax" value="50.0"/> <!-- 地图的最大 x 坐标 --><param name="ymax" value="50.0"/> <!-- 地图的最大 y 坐标 --><param name="delta" value="0.05"/> <!-- 网格分辨率 --><param name="llsamplerange" value="0.01"/> <!-- 线性样本范围 --><param name="llsamplestep" value="0.01"/> <!-- 线性样本步长 --><param name="lasamplerange" value="0.005"/> <!-- 角度样本范围 --><param name="lasamplestep" value="0.005"/> <!-- 角度样本步长 --></node>
</launch>

这些文件中最重要的参数是:

maxUrange:此参数设置您的激光将被视为创建地图的距离。更大的范围将更快地创建地图,并且机器人迷路的可能性更小。缺点是它会消耗更多资源。
throttle_scans:对于降低资源消耗非常有用。

d) 现在,您可以继续启动此启动文件。

roslaunch my_sumit_xl_tools start_mapping.launch

e) 现在让我们启动 RViz,以便能够可视化映射过程。执行以下操作:

将以下显示添加到 RViz:RobotModel、LaserScan 和 Map。

  • 将 LaserScan 主题设置为 /hokuyo/base/scan
  • 将 Map 主题设置为 /map。

最后,您应该会看到类似以下内容:

f) 现在,您可以开始在环境中移动机器人,以生成环境的完整地图。

您可以使用以下命令移动机器人:

roslaunch summit_xl_gazebo keyboard_teleop.launch

太棒了!所以,您已经创建了环境的完整地图。现在该做什么呢?现在是时候保存这张地图了,这样您就可以使用它来定位您的机器人!

保存地图

ROS 导航堆栈中的另一个可用包是 map_server 包。此包提供 map_saver 节点,允许我们从 ROS 服务访问地图数据并将其保存到文件中。

您可以随时使用以下命令保存构建的地图:

rosrun map_server map_saver -f name_of_map

该命令将从地图主题中获取地图数据,并将其写入2个文件,name_of_map.pgm和name_of_map.yaml。

Exercise 2.2

a) 将上一个练习中创建的地图保存到文件中。

roscd my_summit_xl_tools;
mkdir maps;
cd maps;
rosrun map_server map_saver -f my_map;

End of Exercise 2.2

您最终应该会得到 2 个新文件:my_map.yaml 和 my_map.pgm。

PGM 文件包含地图的占用数据(真正重要的数据),而 YAML 文件包含有关地图的一些元数据,例如地图尺寸和分辨率,或 PGM 文件的路径。

my_map.yaml

image: my_map.pgm
resolution: 0.050000
origin: [-10.000000, -10.000000, 0.000000]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.196

my_map.pgm

定位机器人

生成地图后,我们需要做的下一件事就是将机器人定位到该地图中。

为此,我们将使用导航堆栈中的 amcl 节点。因此,正如您在映射过程中所做的那样,让我们​​创建一个启动文件以启动此节点。

Exercise 2.3

a) 在您的包中,创建一个新的启动文件以启动定位节点。

start_amcl_localization.launch

<launch><!-- 运行地图服务器 --><arg name="map_file" default="$(find my_sumit_xl_tools)/maps/my_map.yaml"/> <!-- 指定地图文件路径 --><node name="map_server" pkg="map_server" type="map_server" args="$(arg map_file)" /> <!-- 启动地图服务器节点 --><node pkg="amcl" type="amcl" name="amcl" output="screen"><remap from="scan" to="/hokuyo_base/scan" /> <!-- 将扫描数据重映射到 /hokuyo_base/scan --><remap from="cmd_vel" to="/summit_xl_control/cmd_vel"/> <!-- 将速度命令重映射到 /summit_xl_control/cmd_vel --><!-- 从最佳姿态发布扫描,最大频率为 10 Hz --><param name="odom_model_type" value="diff"/> <!-- 里程计模型类型为差分 --><param name="odom_alpha5" value="0.1"/> <!-- 里程计模型的 alpha5 参数 --><param name="transform_tolerance" value="0.2" /> <!-- 变换容忍度 --><param name="gui_publish_rate" value="10.0"/> <!-- GUI 发布速率 --><param name="laser_max_beams" value="30"/> <!-- 激光最大光束数 --><param name="min_particles" value="500"/> <!-- 最小粒子数 --><param name="max_particles" value="5000"/> <!-- 最大粒子数 --><param name="kld_err" value="0.05"/> <!-- KLD 错误阈值 --><param name="kld_z" value="0.99"/> <!-- KLD Z 值 --><param name="odom_alpha1" value="0.2"/> <!-- 里程计模型的 alpha1 参数 --><param name="odom_alpha2" value="0.2"/> <!-- 里程计模型的 alpha2 参数 --><param name="odom_alpha3" value="0.8"/> <!-- 里程计模型的 alpha3 参数 --><param name="odom_alpha4" value="0.2"/> <!-- 里程计模型的 alpha4 参数 --><param name="laser_z_hit" value="0.5"/> <!-- 激光测量的命中概率 --><param name="laser_z_short" value="0.05"/> <!-- 激光短距离测量概率 --><param name="laser_z_max" value="0.05"/> <!-- 激光最大距离测量概率 --><param name="laser_z_rand" value="0.5"/> <!-- 激光随机测量概率 --><param name="laser_sigma_hit" value="0.2"/> <!-- 激光命中模型的标准差 --><param name="laser_lambda_short" value="0.1"/> <!-- 激光短距离模型的参数 --><param name="laser_model_type" value="likelihood_field"/> <!-- 激光模型类型为 likelihood field --><param name="laser_likelihood_max_dist" value="2.0"/> <!-- 激光最大可能距离 --><param name="update_min_d" value="0.2"/> <!-- 最小距离更新阈值 --><param name="update_min_a" value="0.5"/> <!-- 最小角度更新阈值 --><param name="odom_frame_id" value="summit_xl_a_odom"/> <!-- 里程计坐标系ID --><param name="base_frame_id" value="summit_xl_a_base_link"/> <!-- 机器人底盘坐标系ID --><param name="global_frame_id" value="map"/> <!-- 全局坐标系ID --><!--<param name="odom_frame_id" value="odom"/><param name="base_frame_id" value="base_footprint"/><param name="global_frame_id" value="map"/>--><param name="resample_interval" value="1"/> <!-- 重采样间隔 --><param name="transform_tolerance" value="0.1"/> <!-- 变换容忍度 --><param name="recovery_alpha_slow" value="0.0"/> <!-- 慢速恢复的 alpha 参数 --><param name="recovery_alpha_fast" value="0.0"/> <!-- 快速恢复的 alpha 参数 --><param name="initial_pose_x" value ="0.0"/> <!-- 初始位置 x 坐标 --><param name="initial_pose_y" value ="0.0"/> <!-- 初始位置 y 坐标 --><param name="initial_pose_a" value ="0.0"/> <!-- 初始姿态角度 --></node></launch>

这些文件中最重要的参数是:

min_particles、max_particles:此参数设置过滤器将使用的粒子数量,以便定位机器人。使用的粒子越多,定位就越精确,但消耗的资源也越多。
laser_max_range:激光束的最大范围。
 

d) 现在,您可以继续启动此启动文件。

roslaunch my_sumit_xl_tools start_amcl_localization.launch

e) 现在让我们启动 RViz,以便能够可视化定位过程。您可以使用与映射过程相同的设置,再添加 1 个显示:位姿数组。

您应该看到类似以下内容:

f) 您可以开始在环境中移动机器人,以便定位机器人。随着机器人的移动,您将在 RViz 中看到粒子如何不断靠近,这意味着机器人的估计姿势越来越接近真实位置。这是对您的定位系统运行情况的测试。

您可以使用以下命令移动机器人:

roslaunch summit_xl_gazebo keyboard_teleop.launch

End of Exercise 2.3

太棒了!现在,您已经构建了环境地图,并且能够在地图上定位 Summit XL 机器人

合并amcl与robot_localization

所以,既然我们的 AMCL 系统已经运行,让我们将它与 robot_localization 包合并!

Exercise 2.4

在您的包中,创建一个新的启动文件以启动 robot_localization 包。

start_ekf_localization.launch

<launch> <!-- Run the EKF Localization node --><node pkg="robot_localization" type="ekf_localization_node" name="ekf_localization"><rosparam command="load" file="$(find my_sumit_xl_tools)/config/ekf_localization.yaml"/></node></launch>

现在,让我们创建配置文件,就像您在上一单元中所做的那样。

ekf_localization.yaml

#Configuation for robot odometry EKF
#
frequency: 50two_d_mode: truepublish_tf: falseodom_frame: summit_xl_a_odom
base_link_frame: summit_xl_a_base_link
world_frame: map
map_frame: mapodom0: /robotnik_base_control/odom
odom0_config: [false, false, false,false, false, true,true, true, false,false, false, true,false, false, false]
odom0_differential: falseimu0: /imu/data
imu0_config: [false, false, false,false, false, true,false, false, false,false, false, true,true, false, false]
imu0_differential: falseprocess_noise_covariance": [0.05, 0,    0,    0,    0,    0,    0,     0,     0,    0,    0,    0,    0,    0,    0,0,    0.05, 0,    0,    0,    0,    0,     0,     0,    0,    0,    0,    0,    0,    0,0,    0,    0.06, 0,    0,    0,    0,     0,     0,    0,    0,    0,    0,    0,    0,0,    0,    0,    0.03, 0,    0,    0,     0,     0,    0,    0,    0,    0,    0,    0,0,    0,    0,    0,    0.03, 0,    0,     0,     0,    0,    0,    0,    0,    0,    0,0,    0,    0,    0,    0,    0.06, 0,     0,     0,    0,    0,    0,    0,    0,    0,0,    0,    0,    0,    0,    0,    0.025, 0,     0,    0,    0,    0,    0,    0,    0,0,    0,    0,    0,    0,    0,    0,     0.025, 0,    0,    0,    0,    0,    0,    0,0,    0,    0,    0,    0,    0,    0,     0,     0.04, 0,    0,    0,    0,    0,    0,0,    0,    0,    0,    0,    0,    0,     0,     0,    0.01, 0,    0,    0,    0,    0,0,    0,    0,    0,    0,    0,    0,     0,     0,    0,    0.01, 0,    0,    0,    0,0,    0,    0,    0,    0,    0,    0,     0,     0,    0,    0,    0.02, 0,    0,    0,0,    0,    0,    0,    0,    0,    0,     0,     0,    0,    0,    0,    0.01, 0,    0,0,    0,    0,    0,    0,    0,    0,     0,     0,    0,    0,    0,    0,    0.01, 0,0,    0,    0,    0,    0,    0,    0,     0,     0,    0,    0,    0,    0,    0,    0.015]initial_estimate_covariance: [1e-9, 0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     0,     0,    0,    0,0,    1e-9, 0,    0,    0,    0,    0,    0,    0,    0,     0,     0,     0,    0,    0,0,    0,    1e-9, 0,    0,    0,    0,    0,    0,    0,     0,     0,     0,    0,    0,0,    0,    0,    1e-9, 0,    0,    0,    0,    0,    0,     0,     0,     0,    0,    0,0,    0,    0,    0,    1e-9, 0,    0,    0,    0,    0,     0,     0,     0,    0,    0,0,    0,    0,    0,    0,    1e-9, 0,    0,    0,    0,     0,     0,     0,    0,    0,0,    0,    0,    0,    0,    0,    1e-9, 0,    0,    0,     0,     0,     0,    0,    0,0,    0,    0,    0,    0,    0,    0,    1e-9, 0,    0,     0,     0,     0,    0,    0,0,    0,    0,    0,    0,    0,    0,    0,    1e-9, 0,     0,     0,     0,    0,    0,0,    0,    0,    0,    0,    0,    0,    0,    0,    1e-9,  0,     0,     0,    0,    0,0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     1e-9,  0,     0,    0,    0,0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     1e-9,  0,    0,    0,0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     0,     1e-9, 0,    0,0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     0,     0,    1e-9, 0,0,    0,    0,    0,    0,    0,    0,    0,    0,    0,     0,     0,     0,    0,    1e-9]

如您所见,主要的区别在于,现在我们使用 map_frame 变量。

world_frame: map
map_frame: map

正如我们在上一章中已经告诉过您的,此 map_frame 变量用于报告来自知道机器人所在位置的系统的全局位置,在本例中,该系统是我们在上一个练习中创建的 AMCL 系统。

那么这个地图坐标系来自哪里?这个坐标系由 AMCL 节点提供。您可以通过可视化坐标系树来看到这一点,就像您在上一单元中所做的那样。请注意,您需要运行 AMCL 系统才能可视化此地图坐标系。

让我们启动 EKF 定位节点,并验证它是否生成一个名为 odometry/filtered 的新主题。

roslaunch my_sumit_xl_tools start_ekf_localization.launch
rostopic list | grep odom

你应该得到如下结果:

/robotnik_base_control/odom
/odometry/filtered

太棒了!现在我们知道我们的 EKF 定位节点正在工作……什么?好吧,现在我们使用它!

默认情况下,我们在上一个练习中创建的 AMCL 系统使用 /odom 主题来获取里程表数据。但是现在,多亏了我们的 EKF 定位节点,我们拥有了更可靠的里程表数据,这些数据发布在 /odometry/filtered 主题上。那么……如何使用这个新的里程表代替旧的里程表呢?

为此,我们需要做的就是重新映射 start_amcl_localization.launch 文件中的主题。在文件的开头,您将看到一些主题正在重新映射,因此让我们也重新映射里程表主题:

<node pkg="amcl" type="amcl" name="amcl" output="screen"><remap from="scan" to="/hokuyo_base/scan" /><remap from="cmd_vel" to="/summit_xl_control/cmd_vel"/><remap from="odom" to="/odometry/filtered" />

太棒了!现在让我们创建一个结合两种定位的新启动文件。我们将其命名为 global_localization.launch。

<launch><!--- Start AMCL Localization --><include file="$(find my_sumit_xl_tools)/launch/start_amcl_localization.launch" /><!-- Start EKF Localization --><include file="$(find my_sumit_xl_tools)/launch/start_ekf_localization.launch" /></launch>

启动这个新文件,并使用 PoseArray 显示器在 RViz 中检查现在的定位效果。您应该得到如下结果:

你看到有什么不同吗?如果我们比较添加 EKF 定位节点之前和之后的同一张图像,我们可以看到我们的定位有了很大的改善。

如您所见,在第二张图片中,箭头更加集中,分散性更低,这意味着定位效果更好。

太棒了!现在,为了完成本章,让我们添加一个路径规划系统,以便我们能够使用我们新改进的定位来导航我们的机器人!

让我们导航我们的机器人! 

为了进行路径规划,我们将使用导航堆栈中的 move_base 节点,它将为您管理整个路径规划系统。因此,正如您在前面的练习中所做的那样,让我们​​创建启动文件以启动路径规划系统。不过,这一次,您将需要做一些额外的工作,因为您需要设置很多参数。但别担心,您可以按照下一个练习来指导您完成整个过程!

Exercise 2.5

a) 首先,让我们创建一个新的启动文件来启动move_base节点。

move_base_map.launch

<?xml version="1.0"?>
<!-- NEW SUMIT XL NAVIGATION -->
<launch><arg name="base_global_planner" default="navfn/NavfnROS"/> <!-- 全局规划器,默认使用 NavfnROS --><arg name="base_local_planner" default="dwa_local_planner/DWAPlannerROS"/> <!-- 局部规划器,默认使用 DWAPlannerROS --><!-- <arg name="base_local_planner" default="base_local_planner/TrajectoryPlannerROS"/> --> <!-- 可选的局部规划器,TrajectoryPlannerROS --><node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen"><remap from="scan" to="/hokuyo_base/scan" /> <!-- 将扫描数据重映射到 /hokuyo_base/scan --><remap from="cmd_vel" to="/summit_xl_control/cmd_vel"/> <!-- 将速度命令重映射到 /summit_xl_control/cmd_vel --><remap from="odom" to="/odometry/filtered" /> <!-- 将里程计数据重映射到 /odometry/filtered --><param name="base_global_planner" value="$(arg base_global_planner)"/> <!-- 设置全局规划器 --><param name="base_local_planner" value="$(arg base_local_planner)"/>  <!-- 设置局部规划器 --><!-- 加载全局和局部代价地图的通用配置 --><rosparam file="$(find my_sumit_xl_tools)/config/planner.yaml" command="load"/> <!-- 加载规划器相关的参数配置 --><!-- 代价地图源配置,位于 costmap_common.yaml --><rosparam file="$(find my_sumit_xl_tools)/config/costmap_common.yaml" command="load" ns="global_costmap" /> <!-- 加载全局代价地图的通用配置 --><rosparam file="$(find my_sumit_xl_tools)/config/costmap_common.yaml" command="load" ns="local_costmap" /> <!-- 加载局部代价地图的通用配置 --><!-- 局部代价地图,需要设置尺寸 --><rosparam file="$(find my_sumit_xl_tools)/config/costmap_local.yaml" command="load" ns="local_costmap" /> <!-- 加载局部代价地图的特定配置 --><param name="local_costmap/width" value="5.0"/> <!-- 局部代价地图的宽度 --><param name="local_costmap/height" value="5.0"/> <!-- 局部代价地图的高度 --><!-- 静态全局代价地图,静态地图提供尺寸 --><rosparam file="$(find my_sumit_xl_tools)/config/costmap_global_static.yaml" command="load" ns="global_costmap" /> <!-- 加载静态全局代价地图的配置 --></node></launch>

如您所见,有许多参数文件正在加载,所以让我们创建它们!您必须将所有这些参数文件放在 my_sumit_xl_tools 包内名为 config 的文件夹中。

costmap_common.yaml

# 机器人足迹定义,定义了机器人的占用空间
footprint: [[0.35, -0.3], [0.35, 0.3], [-0.35, 0.3], [-0.35, -0.3]]
footprint_padding: 0.01  # 足迹的额外填充,用于增加安全边距# 机器人基础坐标系
robot_base_frame: summit_xl_a_base_link
update_frequency: 4.0  # 代价地图的更新频率(Hz)
publish_frequency: 3.0  # 代价地图的发布频率(Hz)
transform_tolerance: 0.5  # 变换容忍度,用于处理坐标变换的延迟resolution: 0.05  # 地图分辨率,每个栅格的大小为 0.05 米obstacle_range: 5.5  # 检测障碍物的最大范围(米)
raytrace_range: 6.0  # 激光射线追踪的最大范围(米)# 图层定义
static:map_topic: /map  # 静态地图的话题subscribe_to_updates: true  # 是否订阅地图更新obstacles_laser:observation_sources: hokuyo_laser  # 观测源的名称hokuyo_laser: sensor_frame: summit_xl_a_front_laser_link  # 激光传感器坐标系data_type: LaserScan  # 数据类型clearing: true  # 是否用于清除障碍物marking: true  # 是否用于标记障碍物topic: hokuyo_base/scan  # 激光扫描数据的话题inf_is_valid: true  # 是否将无限距离视为有效数据inflation:inflation_radius: 1.0  # 膨胀半径,用于在代价地图中创建障碍物周围的安全区域

评论一下涉及到 Summit XL 的一些元素:

  • footprint 和 footprint_padding:这些参数定义了机器人的简化模型,即一个包围机器人的简单框。如果你希望机器人能够非常接近物体,可以将填充值(padding)设得更小。在这种情况下,值为 0.1,因为这个型号的 Summit 配备普通轮子,在转向时容易产生某些误差,因此其机动性不如其兄弟型号 Summit XL(配备全向轮)。

  • obstacles_laser:这里定义了用于导航的激光数据传感器。在这个例子中,话题是 /hokuyo_base/scan

另外,提到这个文件 costmap_common.yaml 被加载到两个命名空间中:global_costmaplocal_costmap。这意味着它将在全局和局部规划以及两个代价地图的生成中被使用。这只是一种代码重用的方法。

costmap_local.yaml

global_frame: summit_xl_a_odom  # 全局坐标系的名称,这里设置为 summit_xl_a_odom
rolling_window: true  # 是否使用滚动窗口模式plugins:- {name: obstacles_laser, type: "costmap_2d::ObstacleLayer"}  - {name: inflation, type: "costmap_2d::InflationLayer"}  

在此处注释:

  • global_frame:对于 Local Costmaps,通常将其设置为 odom。
  • plugins:此处加载并执行障碍物检测和膨胀的插件。

costmap_global_static.yaml

global_frame: map  # 全局坐标系的名称,这里设置为 'map'
rolling_window: false  # 是否使用滚动窗口模式,这里设置为 false,表示不使用滚动窗口模式
track_unknown_space: true  # 是否跟踪未知空间,将未知空间标记为代价地图中的障碍物plugins:- {name: static, type: "costmap_2d::StaticLayer"}  - {name: inflation, type: "costmap_2d::InflationLayer"}  

因此,如您所见,它与前一个非常相似。

  • global_frame:对于 Global Costmaps,通常将其设置为 map(使用地图导航时)。
  • plugins:此处加载并执行静态地图和 Inflation 的插件。

planner.yaml

controller_frequency: 5.0  # 控制器的频率(Hz),表示控制器每秒更新的次数
recovery_behaviour_enabled: true  # 是否启用恢复行为,用于处理机器人遇到的障碍物或困境NavfnROS:allow_unknown: true  # 是否允许导航规划器生成穿越未知空间的路径default_tolerance: 0.1  # 规划器目标点的容忍度TrajectoryPlannerROS:# 机器人配置参数acc_lim_x: 2.5  # 机器人在 X 轴方向的加速度限制acc_lim_theta: 3.2  # 机器人在旋转方向的加速度限制max_vel_x: 1.0  # 机器人在 X 轴方向的最大速度min_vel_x: 0.0  # 机器人在 X 轴方向的最小速度max_vel_theta: 1.0  # 机器人在旋转方向的最大速度min_vel_theta: -1.0  # 机器人在旋转方向的最小速度min_in_place_vel_theta: 0.2  # 机器人在原地旋转时的最小速度holonomic_robot: false  # 机器人是否为全向的,这里设置为 false 表示不是全向机器人escape_vel: -0.1  # 逃逸速度,机器人在遇到障碍物时的反向速度# 目标容忍度参数yaw_goal_tolerance: 0.1  # 目标方向的容忍度(弧度)xy_goal_tolerance: 0.2  # 目标位置的容忍度(米)latch_xy_goal_tolerance: false  # 是否锁定目标位置的容忍度,设置为 false 表示不锁定# 前向模拟参数sim_time: 2.0  # 模拟时间(秒)sim_granularity: 0.02  # 模拟粒度,时间步长(秒)angular_sim_granularity: 0.02  # 角度模拟粒度(弧度)vx_samples: 6  # 前向速度样本数量vtheta_samples: 20  # 旋转速度样本数量controller_frequency: 20.0  # 控制器的频率(Hz)# 轨迹评分参数meter_scoring: true  # 是否将距离单位假设为米,而不是默认的栅格单元occdist_scale: 0.1  # 避免障碍物的权重pdist_scale: 0.75  # 保持靠近路径的权重gdist_scale: 1.0  # 尝试达到局部目标的权重,同时控制速度heading_lookahead: 0.325  # 在评分不同的旋转轨迹时,前瞻的距离(米)heading_scoring: false  # 是否基于机器人朝向路径还是距离路径进行评分heading_scoring_timestep: 0.8  # 使用朝向评分时,模拟轨迹的前瞻时间(秒)dwa: true  # 是否使用动态窗口方法(DWA),否则使用轨迹展开simple_attractor: false  # 是否使用简单的吸引子模型publish_cost_grid_pc: true  # 是否发布代价网格点云# 振荡防止参数oscillation_reset_dist: 0.25  # 机器人必须移动的距离(米),以便重置振荡标志escape_reset_dist: 0.1  # 逃逸模式重置距离escape_reset_theta: 0.1  # 逃逸模式重置角度(弧度)DWAPlannerROS:# 机器人配置参数acc_lim_x: 2.5  # 机器人在 X 轴方向的加速度限制acc_lim_y: 0  # 机器人在 Y 轴方向的加速度限制acc_lim_th: 3.2  # 机器人在旋转方向的加速度限制max_vel_x: 0.5  # 机器人在 X 轴方向的最大速度min_vel_x: 0.0  # 机器人在 X 轴方向的最小速度max_vel_y: 0  # 机器人在 Y 轴方向的最大速度min_vel_y: 0  # 机器人在 Y 轴方向的最小速度max_trans_vel: 0.5  # 最大线速度min_trans_vel: 0.1  # 最小线速度max_rot_vel: 1.0  # 最大旋转速度min_rot_vel: 0.2  # 最小旋转速度# 目标容忍度参数yaw_goal_tolerance: 0.1  # 目标方向的容忍度(弧度)xy_goal_tolerance: 0.2  # 目标位置的容忍度(米)latch_xy_goal_tolerance: false  # 是否锁定目标位置的容忍度# 轨迹评分参数(已注释掉)# 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  # 机器人轮廓缩放的速度(m/s)# max_scaling_factor: 0.2  # 机器人轮廓的最大缩放因子# 振荡防止参数(已注释掉)# oscillation_reset_dist: 0.25  # 机器人必须移动的距离(米),以便重置振荡标志

在这里我们可以注释很多参数。只是指出几个真正重要的:

  • yaw_goal_tolerance:这个参数表示你希望机器人在给定姿态下的精度。在这种情况下,指的是 XY 平面上的方向精度。

  • xy_goal_tolerance:这个参数与前一个类似,但指的是 XY 平面上的位置精度。

  • holonomic_robot:这个参数很重要,因为 Summit XL 配备全向轮时可以被视为全向机器人。而你当前使用的 Summit 型号则不是全向的。

DWAPlannerROS 是用于局部规划器的规划器。您也可以使用 TrajectoryPlannerROS。主要区别在于速度的采样方式。但它们在一般情况下的表现或多或少处于同一水平。

b) 现在,让我们创建一个启动文件,它将我们迄今为止所做的一切结合起来:

start_navigation.launch

<launch><!--- Start AMCL Localization --><include file="$(find my_sumit_xl_tools)/launch/start_amcl_localization.launch" /><!-- Start EKF Localization --><include file="$(find my_sumit_xl_tools)/launch/start_ekf_localization.launch" /><!-- Start Move Base --><include file="$(find my_sumit_xl_tools)/launch/move_base_map.launch" /></launch>

c) 执行您的启动文件以启动导航系统。

roslaunch my_sumit_xl_tools start_navigation.launch

d) 现在让我们启动 RViz,以便能够可视化路径规划过程。您需要添加以下内容:

  • 固定坐标必须是地图。
  • 请注意两个路径显示:一个用于局部,另一个用于全局规划。
  • 还请注意两个地图:一个用于 LocalCostmap,另一个用于 GlobalCostmap。

最后,你应该看到类似这样的内容:

 

e) 使用 Rviz 中的 2D 位姿估计工具在地图中定位机器人。

f) 使用 Rviz 中的 2D 导航目标工具向机器人发送目标(所需位姿)。

现在您应该看到 Summit XL 机器人在模拟中到达该位置。在 Rviz 中,您还可以可视化它所遵循的规划路径。

End of Exercise 2.5

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

背包问题 总结详解

就是感觉之前 dp 的 blog 太乱了整理一下。 0-1 背包 例题:P1048 朴素算法 思路 对于一个物品&#xff0c;我们可以选&#xff0c;也可以不选。 我们用表示第 i 件物品的重量&#xff0c;表示第 i 件物品的价值。 考虑表示前 i 件物品放入容量为j的背包中的最大价值。 如…

【图像匹配】基于Harris算法的图像匹配,matlab实现

博主简介&#xff1a;matlab图像代码项目合作&#xff08;扣扣&#xff1a;3249726188&#xff09; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于基于Harris算法的图像匹配&#xff0c;用matlab实现。 一、案例背景和算法介绍 …

Observability:日志管理的最佳实践 - 利用日志更快地解决问题

作者&#xff1a;来自 Elastic Luca Wintergerst•David Hope•Bahubali Shetti 在当今快速发展的软件开发环境中&#xff0c;高效的日志管理对于维护系统可靠性和性能至关重要。随着基础架构和应用程序组件的不断扩展和复杂化&#xff0c;运营和开发团队的职责也不断增加且越来…

yolov8区域入侵检测警报系统-pyside6可视化界面

yolov8区域入侵检测警报系统&#xff0c;是微智启软件工作室基于yolov8目标追踪和pyside6开发&#xff0c;在window的pycharm或者vscode里运行&#xff0c;可以应用于多个领域&#xff0c;检测统计物体个数以及入侵语音警报。 功能介绍 可以应用于 江河流域危险区域禁止游泳警…

利用AI技术提升ISP处理:图像质量的四大关键模块

随着智能手机和数码相机的飞速发展&#xff0c;图像质量成为了影响用户体验的关键因素之一。图像信号处理&#xff08;ISP&#xff0c;Image Signal Processing&#xff09;管道是将图像传感器捕捉到的原始数据转化为高质量输出的核心技术。然而&#xff0c;传统的ISP处理方法在…

螺丝、螺母、垫片等紧固件常用类型详细介绍

螺钉、螺母、垫片等紧固件介绍 螺钉 杯头内六角 首先介绍一下杯头内六角&#xff0c;杯头内六角是我们用的最常见的一种螺钉&#xff0c;如果你对选择螺钉没有什么想法&#xff0c;可以直接无脑选杯头内六角去使用。 比如说我们有一个零件加工了通孔&#xff0c;另一个零件加…

vmware,centos8(虚拟机) 的安装

安装vmware 点击下方网址 虚拟机安装地址https://www1.msc23.cn/vm/?bd_vid8829610582362807097选择VMware17 打开文件所在地&#xff0c;双击安装 同意条款 选择安装位置 不将VMware配置到环境变量path 不检查更新,不加入客户体验 创建桌面快捷方式 开始安装 安装完成…

CSP-J/S 考试介绍

CSP-J/S是由中国计算机学会&#xff08;CCF&#xff09;主办的非专业级别的软件能力认证考试。 CSP-J/S全称为CCF CSP-J/S&#xff0c;是CCF计算机软件能力认证&#xff08;简称CCFCSP认证&#xff09;中的一个部分&#xff0c;重点考察软件开发者实际编程能力。该项认证由CCF…

MTC完成右臂抓取放置任务\\放置姿态设置

#include "mtc_tutorial/mtc_glass_bottle.hpp" static const rclcpp::Logger LOGGER rclcpp::get_logger("mtc_glass_right"); // 获取节点基础接口的实现 rclcpp::node_interfaces::NodeBaseInterface::SharedPtr MTCTaskNode_Right::getNodeBaseInterf…

棋盘格角点检测-libcbdetect

libcbdetect libcbdetect 是一个用于自动子像素级别的棋盘格&#xff08;checkerboard&#xff09;、棋盘&#xff08;chessboard&#xff09;以及 Deltille 图案检测的库。它主要由 C 编写&#xff0c;旨在提供高精度、高鲁棒性的角点检测和图案组合功能&#xff0c;是一种基…

使用HTML和CSS制作网页的全面指南

目录 引言 一、理解HTML 1. 什么是HTML&#xff1f; 2. HTML文档的基本结构 3. 常用的HTML标签 4. 示例&#xff1a;创建一个简单的HTML页面 二、理解CSS 1. 什么是CSS&#xff1f; 2. CSS的使用方式 3. CSS选择器和属性 4. 常用的CSS属性 三、创建网页的步骤 1. 规…

【Java数据结构】二叉树

目录 树树的特征树的概念 二叉树两种特殊的二叉树二叉树的性质二叉树的基本操作4 种遍历二叉树的方式判断一棵树是不是完全二叉树获取二叉树总共的节点个数获取叶子节点的个数获取第 k 层的节点个数获取二叉树的高度检测值为 value 的元素是否存在 二叉树基本操作完整代码 树 …

VS code 安装使用配置 Continue

Continue 插件介绍 Continue 是一款高效的 VS Code 插件&#xff0c;提供类似 GitHub Copilot 的功能&#xff0c;旨在提升开发者的编程效率。其配置简单&#xff0c;使用体验流畅&#xff0c;深受开发者喜爱。 主要功能特点 智能代码补全 Continue 能够基于当前代码上下文生…

年化60.7%,最大回撤-16.5%,RSRS标准分择时效果差不多

原创内容第653篇&#xff0c;专注量化投资、个人成长与财富自由。 中秋节&#xff0c;祝大家中秋快乐&#xff01; 人有悲欢离合&#xff0c;月有阴晴圆缺&#xff0c;此事古难全。但愿人长久&#xff0c;千里共婵娟。 今天引入RSRS来择时&#xff0c;看下策略效果。 年化60.7…

Python编码系列—Python代理模式:为对象赋予超能力的魔法

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

C++掉血迷宫

目录 开头程序程序的流程图程序游玩的效果下一篇博客要说的东西 开头 大家好&#xff0c;我叫这是我58。 程序 #include <iostream> #include <string> #include <cstring> using namespace std; enum RBYG {R 1,B 2,Y 4,G 7, }; struct heal {int ix…

【例题】lanqiao549 扫雷

输入 3 4 0 1 0 0 1 0 1 0 0 0 1 0输出 2 9 2 1 9 4 9 2 1 3 9 2解题思路 分类讨论&#xff1a; 如果原来的方格整数为1&#xff0c;输出9如果原来的方格整数为0&#xff0c;输出周围8个&#xff08;最多八个&#xff09;的地雷数量和 代码 如何遍历一个方格mp[i][j]周围…

c++中引用是通过指针的方式实现

其实在汇编层面上&#xff0c;引用的代码和指针的代码是一致的。 先看指针情况下的代码分析&#xff0c;如下所示&#xff1a; #include <iostream>using namespace std;void fuzhi(int *x)//引用传参 {*x 10; }int main(int argc, char** argv) {int a 0;int b;a …

架构设计——概念和基础

&#x1f3e0;1 架构基础 想要搞清楚架构到底指什么&#xff0c;架构与框架的区别&#xff0c;就需要了解梳理系统、子系统、模块、组件、框架和架构 1.1系统与子系统 1.1.1系统 wiki:系统泛指由一群有关联的个体组成&#xff0c;根据某种规则运作&#xff0c;能完成个别元…

Python编码系列—Python外观模式:简化复杂系统的快捷方式

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…