3. 代价地图参数与路径规划故障

Nav2 的路径规划并不是直接在静态地图上画线,而是在两张“代价地图”上做搜索:global_costmap 服务于全局规划器(如 NavFn、Smac Planner),决定从起点到目标点的宏观可通行走廊;local_costmap 服务于局部规划器与控制器(如 DWB、MPPI),决定机器人眼前几米内如何避障、贴边与通过窄口。两张地图共用一套代价地图插件体系,但分辨率、尺寸、更新频率和插件组合往往不同。参数配错时,典型表现不是“程序崩溃”,而是路径贴着墙走、规划失败报 “Failed to create plan”、机器人原地打转或频繁触发恢复行为。理解参数到路径可行性的因果链,是排障的核心。

分辨率:栅格粒度决定“能不能看见缝”

resolution 是每个栅格代表的实际边长(米/格)。全局地图常用 0.05 m,局部地图常用 0.05 m 或更细的 0.03 m。分辨率的影响体现在两个方向:过粗时,宽度小于 2~3 个栅格的通道会被膨胀层“吃掉”,规划器认为不可通行;过细时,栅格数量按面积平方增长,全局地图 40 m×40 m 在 0.05 m 下是 800×800=64 万格,降到 0.02 m 则变成 2000×2000=400 万格,规划搜索与代价更新开销显著上升,且传感器噪声更容易形成孤立致命格。

一个可操作的判断方法是:机器人外接圆直径 D、安全余量 m,则通道最小可通行宽度约为 D+2m;若该宽度除以 resolution 小于 3,就应怀疑分辨率或膨胀参数过激。例如差速机器人宽 0.6 m、要求两侧各留 0.1 m,则需 0.8 m 通道;0.05 m 分辨率下约 16 格,尚可;若误设为 0.2 m,则只有 4 格,膨胀后极易闭合。

膨胀层:inflation_radius 与 cost_scaling_factor 的耦合

膨胀层(inflation_layer)把障碍物的致命代价向外扩散,形成“软代价梯度”,让规划器倾向于走中间而不是贴墙。inflation_radius 决定软代价扩散的最大距离,cost_scaling_factor 决定代价随距离衰减的快慢:值越大衰减越快,梯度越陡,路径越容易贴近膨胀边界;值越小梯度越平缓,路径越居中但可能绕远。

常见故障是 inflation_radius 小于机器人内切圆半径,导致规划出的路径几何上穿过机器人无法通过的区域,表现为全局路径“看起来能走”,局部控制器却反复报碰撞或无法跟踪。经验起点是 inflation_radius ≥ 机器人外接圆半径 + 0.05~0.1 m。另一个隐蔽问题是全局与局部膨胀参数不一致:全局地图膨胀过大导致窄门被判死,局部地图膨胀过小又让机器人贴墙,二者叠加会出现“全局规划失败但局部明明能过”的矛盾现象。

障碍层与体素层:观测如何变成代价

obstacle_layer 基于激光/点云的 2D 投影标记障碍,关键参数包括 observation_sources、max_obstacle_height、raytrace_max_range/raytrace_min_range 与 marking/clearing。若 max_obstacle_height 设得过低,桌面、货架横梁等高于阈值的障碍不会被标记,路径会从下方“穿过”;设得过高,又把悬挂物、天花板结构误判为地面障碍,造成虚假封锁。

voxel_layer 用于三维点云,通过 z_resolution、z_voxels 构建体素柱,再按 origin_z、z_hit、z_max 等参数决定哪些体素投影为 2D 致命格。典型故障是 z_voxels × z_resolution 覆盖的高度范围不足:机器人前方斜坡或低矮台阶落在范围之外,局部地图看不到,直到碰撞才触发。另一个高频问题是清除(clearing)失效——raytrace_max_range 小于传感器实际量程,动态障碍离开后残留的致命格长期不消失,局部规划器持续绕行甚至卡死。

代价地图参数 → 栅格代价 → 路径可行性 因果链 分辨率 resolution 0.05 m / 格 过粗→窄道闭合 过细→计算膨胀 膨胀层 inflation inflation_radius cost_scaling_factor 过小→贴墙/穿模 障碍层 obstacle max_obstacle_height raytrace_max_range 漏标 / 残影 体素层 voxel z_resolution × z_voxels global_costmap 静态层 + 膨胀层 尺寸大、更新慢 决定宏观走廊 窄门被判死 → 规划失败 local_costmap 障碍层 + 体素层 + 膨胀层 滚动窗口、更新快 决定眼前避障 残影/漏标 → 绕行卡死 路径可行 走廊居中、窄口可过 局部跟踪平滑 无频繁恢复行为 典型故障模式 ① 全局规划失败(窄道闭合) ② 路径贴墙 / 穿模 ③ 动态障碍残影绕行 ④ 低矮/高处障碍漏标 ⑤ 全局/局部膨胀不一致 排障顺序:先看 global 是否规划成功 → 再看 local 是否跟踪 → 最后核对两层膨胀参数是否一致 可视化工具:RViz 中分别订阅 /global_costmap/costmap 与 /local_costmap/costmap

典型故障模式与排查路径

故障一:全局规划持续失败。日志出现 “Failed to create plan” 或 “Start/goal in collision”。先确认起点/终点是否落在致命格上(机器人自身足迹被静态层误标也会导致),再检查 inflation_radius 是否把唯一通道封死。可在 RViz 中订阅 /global_costmap/costmap,把颜色方案切到 costmap,观察窄口处是否整片变为 100 号致命色。

故障二:路径贴墙、控制器反复报碰撞。多为膨胀半径小于机器人外接圆,或 cost_scaling_factor 过大导致软代价梯度太陡。把 inflation_radius 提到外接圆半径以上,并适当降低 cost_scaling_factor(例如从 5.0 调到 3.0),路径会明显向通道中心靠拢。

故障三:动态障碍离开后仍绕行。检查 raytrace_max_range 是否覆盖传感器量程、clearing 是否开启、局部地图 update_frequency 是否过低。若残影只在局部地图出现,通常是清除射线未覆盖到该距离。

故障四:低矮台阶或悬空横梁处理异常。前者是 max_obstacle_height 或体素高度范围不足,后者是阈值过高把高处结构误判为地面障碍。需要结合机器人实际高度与场景几何重新标定 z_max、origin_z 与 max_obstacle_height。

一份可对照的参数核查表

参数所在层示例值失配时的典型现象
resolution两层0.05 m过粗:窄道闭合;过细:CPU 升高、孤立致命格增多
inflation_radius两层0.45 m小于外接圆:路径穿模、控制器报碰撞
cost_scaling_factor两层3.0过大:贴墙;过小:过度绕远
max_obstacle_height障碍层2.0 m过低:高处障碍漏标;过高:悬挂物误封
raytrace_max_range障碍层3.5 m小于量程:动态障碍残影不消失
z_resolution × z_voxels体素层0.05 × 16覆盖高度不足:斜坡、台阶漏检
调参时建议一次只改一个参数,并在 RViz 中同时打开 global 与 local 两张代价地图对比观察。全局地图看“走廊是否连通”,局部地图看“眼前障碍是否被正确标记与清除”,两者分开判断能显著缩短排障时间。
不要把全局地图的膨胀参数直接照搬到局部地图。全局地图追求走廊连通性,膨胀可略保守;局部地图追求实时避障,膨胀过大会让机器人在窄口前犹豫甚至触发恢复行为。两层参数应在同一机器人几何模型下分别标定。

归根结底,代价地图参数不是孤立的数值,而是一条从“传感器观测”到“栅格代价”再到“搜索可行性”的链条。分辨率决定空间粒度,膨胀层决定安全边界与路径偏好,障碍层与体素层决定观测如何被信任和清除。排障时沿着这条链从全局到局部逐段核对,比盲目试参更可靠。