4. 代价地图参数深度解析:全局代价地图与局部代价地图的配置、膨胀层、静态层、障碍物层

代价地图,说白了就是机器人对环境的「风险认知图」。

我刚开始接触Nav2时,总觉得代价地图就是个简单的黑白图。后来踩了不少坑才明白——它其实是导航系统里最核心的决策依据。全局代价地图负责「看全局」,局部代价地图负责「看眼前」。两者配合不好,机器人要么撞墙,要么原地转圈。

4.1 全局代价地图 vs 局部代价地图

先搞清楚这两个家伙的分工。

  • 全局代价地图:从静态地图出发,叠加已知障碍物。它不关心动态变化,只做宏观路径规划。我习惯把它的更新频率设低一些,比如1Hz,省CPU。
  • 局部代价地图:实时感知周围环境,处理动态障碍物。更新频率要高,我一般设10Hz。你想想看,如果局部地图更新慢了,机器人可能直接怼到突然出现的人身上。

嗯,这里要注意:全局地图的尺寸可以很大,但局部地图一般只覆盖机器人周围几米。我见过有人把局部地图设得跟全局一样大,结果性能直接崩了。

核心配置对比

参数全局代价地图局部代价地图
update_frequency1.0 Hz5.0 - 10.0 Hz
publish_frequency1.0 Hz5.0 - 10.0 Hz
width / height地图尺寸(如 20m x 20m)3m - 5m 见方
resolution0.05 m0.05 m
pluginsstatic_layer, inflation_layerobstacle_layer, inflation_layer

4.2 膨胀层(Inflation Layer)

膨胀层是代价地图的「安全缓冲带」。它把障碍物周围的区域标记为高代价,让机器人不敢靠近。

我曾经在项目中把膨胀半径设得太小,结果机器人贴着墙走,稍微有点定位误差就撞上了。后来我学乖了——膨胀半径至少要比机器人半径大20%。

inflation_layer:
  enabled: true
  inflation_radius: 0.55  # 膨胀半径,单位米
  cost_scaling_factor: 10.0  # 代价衰减系数

关键参数解读:

  • inflation_radius:膨胀半径。越大,机器人离障碍物越远。我建议设成机器人半径的1.2倍。
  • cost_scaling_factor:代价衰减速度。值越大,代价从障碍物边缘向外衰减得越快。我习惯用10.0,效果比较平滑。

我的经验:如果机器人经常在狭窄通道里卡住,试试把cost_scaling_factor调小到5.0。代价衰减变慢,机器人会更愿意走窄路。

4.3 静态层(Static Layer)

静态层负责加载预先建好的地图。说白了,就是告诉机器人「这堵墙是固定的,你别想穿过去」。

我记得第一次用Nav2时,忘了配静态层,结果机器人直接无视地图里的墙,规划出一条穿墙的路径。嗯,那场面挺尴尬的。

static_layer:
  enabled: true
  map_topic: /map
  first_map_only: false
  subscribe_to_updates: true

参数说明:

  • map_topic:地图话题。默认是/map,如果你用map_server发布地图,这个不用改。
  • first_map_only:是否只接受第一张地图。我建议设成false,这样地图更新时能自动刷新。
  • subscribe_to_updates:是否订阅地图更新。如果你在动态建图,这个必须开。

避坑指南:我曾经把first_map_only设成true,结果地图更新后机器人还在用旧地图规划路径,直接撞上了新摆放的货架。从那以后,我只要不是特别确定地图不变,都会把这个参数设成false。

4.4 障碍物层(Obstacle Layer)

障碍物层是动态障碍物的「实时感知器」。它从激光雷达、深度相机等传感器获取数据,实时标记障碍物。

这个层最容易出问题。我见过有人把障碍物层的最大范围设得比局部地图还大,结果传感器数据被截断,机器人对远处的障碍物完全没反应。

obstacle_layer:
  enabled: true
  observation_sources: laser_scan_sensor
  laser_scan_sensor:
    topic: /scan
    sensor_frame: laser_frame
    data_type: LaserScan
    clearing: true
    marking: true
    obstacle_range: 2.5
    raytrace_range: 3.0

核心参数:

  • obstacle_range:障碍物检测范围。超过这个距离的障碍物会被忽略。我一般设成局部地图尺寸的一半。
  • raytrace_range:射线追踪范围。用于清除障碍物(比如障碍物移走后,清除它留下的代价)。这个值要比obstacle_range大一点。
  • clearing / marking:是否清除/标记障碍物。两个都开,不然障碍物移走了代价还在。

多传感器融合配置:

obstacle_layer:
  observation_sources: laser_scan_sensor point_cloud_sensor
  laser_scan_sensor:
    topic: /scan
    data_type: LaserScan
    obstacle_range: 2.5
    raytrace_range: 3.0
  point_cloud_sensor:
    topic: /camera/depth/points
    data_type: PointCloud2
    obstacle_range: 2.0
    raytrace_range: 2.5

我建议激光雷达和深度相机同时用。激光雷达精度高,深度相机能检测低矮障碍物。两者互补,效果最好。

4.5 三层协同工作流程

这三层不是各自为战的。它们按顺序叠加:

  1. 静态层先加载地图,标记固定障碍物。
  2. 障碍物层实时更新动态障碍物。
  3. 膨胀层最后对所有障碍物做膨胀处理。

你想想看,如果顺序搞反了,膨胀层先处理,障碍物层后更新,那膨胀效果就被覆盖了。嗯,Nav2的插件机制保证了顺序,但你自己写插件时一定要注意。

代价地图三层协同工作流程 静态层 加载预建地图 固定障碍物标记 障碍物层 实时传感器数据 动态障碍物标记/清除 膨胀层 安全缓冲带 代价衰减处理 最终代价地图 静态 + 动态 + 膨胀 = 完整风险认知 三层按顺序叠加,最终生成带安全缓冲的代价地图 全局地图使用静态层 + 膨胀层 | 局部地图使用障碍物层 + 膨胀层

4.6 实战配置建议

说了这么多,我直接给一套我常用的配置模板吧。

# 全局代价地图配置
global_costmap:
  global_frame: map
  robot_base_frame: base_footprint
  update_frequency: 1.0
  publish_frequency: 1.0
  width: 20.0
  height: 20.0
  resolution: 0.05
  plugins:
    - {name: static_layer, type: "nav2_costmap_2d::StaticLayer"}
    - {name: inflation_layer, type: "nav2_costmap_2d::InflationLayer"}

# 局部代价地图配置
local_costmap:
  global_frame: odom
  robot_base_frame: base_footprint
  update_frequency: 10.0
  publish_frequency: 10.0
  width: 4.0
  height: 4.0
  resolution: 0.05
  plugins:
    - {name: obstacle_layer, type: "nav2_costmap_2d::ObstacleLayer"}
    - {name: inflation_layer, type: "nav2_costmap_2d::InflationLayer"}

我的习惯:全局地图的global_frame用map,局部地图用odom。这样全局地图固定不动,局部地图跟着机器人走。如果你把局部地图的global_frame也设成map,那每次定位漂移时局部地图都会抖动,规划出来的路径会很不稳定。

嗯,代价地图的配置就这些。说白了,三层各司其职:静态层管固定障碍,障碍物层管动态变化,膨胀层管安全距离。配好了,机器人跑起来就稳了。

可可精品资料库