3. 全局代价地图参数:三层核心配置详解
全局代价地图,说白了就是机器人对环境的「全局认知」。它由三层叠加而成:静态层、障碍物层、膨胀层。每一层都有自己的职责,配置不好,导航就会出各种怪问题。
我个人习惯,调参之前先搞清楚每层到底在干什么。不然你改了一个数字,根本不知道它会怎么影响机器人的行为。
核心观点:全局代价地图 = 静态层(地图数据)+ 障碍物层(传感器数据)+ 膨胀层(安全边界)。三层叠加,最终决定机器人能不能走某条路径。
3.1 静态层(Static Layer)—— 地图的「底图」
静态层是最基础的一层。它加载我们预先构建好的地图文件(通常是 pgm/yaml)。说白了,就是告诉机器人:「这堵墙是固定的,你别想穿过去。」
我在项目中遇到过一个问题:换了新地图后,机器人老是往墙上撞。查了半天,发现是静态层的 map_topic 没更新,还在用旧地图。嗯,这种低级错误,犯过一次就记住了。
| 参数名 | 默认值 | 说明 |
|---|---|---|
map_topic |
"map" | 订阅的地图话题名称 |
first_map_only |
false | 是否只使用第一帧地图 |
subscribe_to_updates |
false | 是否订阅地图更新 |
track_unknown_space |
false | 是否追踪未知区域 |
use_maximum_map |
false | 是否使用最大代价地图 |
小技巧:如果你在动态环境中工作,建议把 subscribe_to_updates 设为 true。这样地图更新时,代价地图会自动刷新,不用重启导航栈。
3.2 障碍物层(Obstacle Layer)—— 实时「眼睛」
障碍物层负责处理传感器数据。激光雷达、深度相机、声呐……这些传感器检测到的障碍物,都会在这一层标记出来。
你想想看,如果静态层是地图,那障碍物层就是机器人的「实时眼睛」。它告诉机器人:「前面有个箱子,刚才还没有,现在有了,绕过去。」
我曾经调试一个项目,机器人总是忽略低矮的障碍物。后来发现是 obstacle_range 设得太大了,传感器远处的数据被当成了噪声过滤掉。调小之后,问题就解决了。
核心参数一览
| 参数名 | 默认值 | 说明 |
|---|---|---|
obstacle_range |
2.5 | 障碍物检测最大距离(米) |
raytrace_range |
3.0 | 射线追踪最大距离(米) |
observation_sources |
"" | 传感器数据源列表 |
footprint_clearing_enabled |
true | 是否清除机器人足迹下的障碍物 |
max_obstacle_height |
2.0 | 障碍物最大高度(米) |
min_obstacle_height |
0.0 | 障碍物最小高度(米) |
注意:obstacle_range 和 raytrace_range 不要设得太大。设大了,远处的噪声会被当成障碍物,导致机器人不敢走。我一般设 2.5~3.5 米,够用就好。
多传感器配置示例
如果你有多个传感器,比如一个激光雷达加一个深度相机,可以这样配:
observation_sources: laser_front depth_camera
laser_front:
sensor_frame: laser_frame
data_type: LaserScan
topic: /scan
marking: true
clearing: true
expected_update_rate: 10.0
depth_camera:
sensor_frame: camera_depth_frame
data_type: PointCloud2
topic: /camera/depth/points
marking: true
clearing: true
expected_update_rate: 5.0
这里要注意 marking 和 clearing 的区别。marking 是在代价地图上标记障碍物,clearing 是清除障碍物。说白了,marking 是「画障碍」,clearing 是「擦障碍」。两个都设为 true,才能保证障碍物实时更新。
3.3 膨胀层(Inflation Layer)—— 安全「缓冲区」
膨胀层是我觉得最需要细调的一层。它给障碍物周围添加一个「安全缓冲区」,让机器人不会贴着障碍物走。
为什么需要膨胀?你想想看,机器人是有体积的。如果路径规划只考虑障碍物的边缘,那机器人很可能擦着墙过去,稍微偏一点就撞上了。膨胀层就是给障碍物「加一圈肉」,让路径规划器知道:「这里不能走太近。」
我记得有一次,客户说机器人老是卡在走廊里。我一看,膨胀半径设了 0.8 米,走廊才 1.2 米宽。机器人觉得整个走廊都是禁区,当然过不去。调小到 0.3 米,问题就解决了。
膨胀层核心参数
| 参数名 | 默认值 | 说明 |
|---|---|---|
inflation_radius |
0.55 | 膨胀半径(米) |
cost_scaling_factor |
10.0 | 代价衰减因子 |
inflation_layer_namespace |
"" | 膨胀层命名空间 |
关键理解:inflation_radius 决定膨胀范围,cost_scaling_factor 决定代价衰减速度。两者配合,决定了机器人离障碍物多远开始「害怕」。
代价衰减曲线
膨胀层的代价不是一刀切的。离障碍物越近,代价越高;越远,代价越低。这个衰减速度由 cost_scaling_factor 控制。
- cost_scaling_factor 大:代价衰减快,只有紧贴障碍物的地方代价高。适合狭窄通道。
- cost_scaling_factor 小:代价衰减慢,障碍物周围一大片区域代价都高。适合需要大安全距离的场景。
我个人习惯,先设 inflation_radius 为机器人宽度的一半,再调 cost_scaling_factor。比如机器人宽 0.5 米,我就先设 0.25 米,然后看效果再微调。
避坑指南:我曾经把 cost_scaling_factor 设成 100,结果代价衰减太快,膨胀层几乎没效果。后来改成 10,效果就好多了。记住,这个值不是越大越好。
3.4 三层协同工作
三层不是各自为政的。它们叠加在一起,最终形成一个完整的代价地图。
举个例子:
- 静态层加载地图,标记出墙壁的位置。
- 障碍物层检测到临时摆放的箱子,在箱子位置标记障碍物。
- 膨胀层在墙壁和箱子周围添加安全缓冲区。
- 路径规划器看到最终代价地图,选择一条代价最低的路径。
如果某一层配置不对,整个导航就会出问题。比如膨胀层设太大,机器人可能找不到路;障碍物层更新太慢,机器人可能撞上突然出现的障碍物。
重要提醒:全局代价地图和局部代价地图的参数是分开配置的。不要以为改了全局的,局部的也会跟着变。我见过有人改了半天全局参数,发现局部导航没变化,就是因为没改局部配置。
3.5 实战配置模板
下面是我常用的全局代价地图配置模板,你可以直接拿来用:
global_costmap:
global_frame: map
robot_base_frame: base_footprint
update_frequency: 1.0
publish_frequency: 0.5
transform_tolerance: 0.5
resolution: 0.05
static_map: true
rolling_window: false
plugins:
- {name: static_layer, type: "costmap_2d::StaticLayer"}
- {name: obstacle_layer, type: "costmap_2d::ObstacleLayer"}
- {name: inflation_layer, type: "costmap_2d::InflationLayer"}
static_layer:
map_topic: map
first_map_only: false
subscribe_to_updates: true
track_unknown_space: true
obstacle_layer:
observation_sources: laser_scan
laser_scan:
sensor_frame: laser_frame
data_type: LaserScan
topic: /scan
marking: true
clearing: true
expected_update_rate: 10.0
obstacle_range: 2.5
raytrace_range: 3.0
footprint_clearing_enabled: true
max_obstacle_height: 2.0
min_obstacle_height: 0.0
inflation_layer:
inflation_radius: 0.55
cost_scaling_factor: 10.0
这个模板我用了很多项目,基本都能跑。当然,具体参数要根据你的机器人尺寸、传感器类型、工作环境来微调。
嗯,全局代价地图的三层参数就讲到这里。记住,调参不是一蹴而就的,多试几次,找到最适合你机器人的组合。