适合场景:ROS2 Nav2 局部规划 / DWB / MPPI 调参,尤其是想搞清楚 inflation_radiuscost_scaling_factor 到底怎么影响避障行为。


1. Costmap 里的 254、253、0 分别是什么?

Nav2 costmap 内部使用 0 ~ 255 的 unsigned char 数值表示栅格代价:

内部 cost 值 名称 含义
0 FREE_SPACE 完全自由空间
1 ~ 252 inflated cost 膨胀层产生的渐变代价
253 INSCRIBED_INFLATED_OBSTACLE 距离障碍物小于等于机器人内切半径的区域,极危险
254 LETHAL_OBSTACLE 致命障碍物,也就是障碍物所在格子
255 NO_INFORMATION 未知区域

可以简单理解为:

254:障碍物本体所在格子,不能碰
253:离障碍物非常近,机器人中心如果进入这个区域,footprint 很可能已经撞到或擦到障碍物
1~252:膨胀代价区,越靠近障碍物 cost 越高
0:自由空间

注意:253 不是一个独立插件,也不是传感器直接打出来的障碍物,而是 Inflation Layer 根据机器人 footprint / robot_radius 算出来的高危险区。


2. Inflation Layer 的核心公式

Nav2 Inflation Layer 的核心计算逻辑可以简化为:

if (distance == 0) {
  cost = LETHAL_OBSTACLE;  // 254
} else if (distance * resolution <= inscribed_radius) {
  cost = INSCRIBED_INFLATED_OBSTACLE;  // 253
} else {
  cost = (INSCRIBED_INFLATED_OBSTACLE - 1)
       * exp(-cost_scaling_factor * (distance * resolution - inscribed_radius));
}

换成数学公式就是:

如果 d = 0:
  cost = 254

如果 0 < d <= r_inscribed:
  cost = 253

如果 r_inscribed < d <= inflation_radius:
  cost = 252 × exp(-k × (d - r_inscribed))

如果 d > inflation_radius:
  cost = 0

其中:

符号 含义
d 当前栅格到最近 lethal obstacle 栅格的距离,单位是米
distance 源码里的距离,单位是 costmap cell,不是米
resolution costmap 分辨率,单位是 m/cell,例如 0.05 表示每格 5cm
distance * resolution 把 cell 距离转换成米
r_inscribed 机器人内切半径,Nav2 根据 footprintrobot_radius 自动计算
k cost_scaling_factor,控制代价衰减速度
inflation_radius 膨胀影响的最大半径

3. distance 到底是谁到谁的距离?

这是最容易误解的地方。

源码里的 distance 不是

障碍物到 base_footprint 的距离
障碍物到机器人 footprint 边框的距离
雷达到障碍物的距离

它实际是:

当前 costmap 栅格中心
到
最近 lethal obstacle 栅格中心
之间的欧氏距离

并且源码里这个 distance 一开始是以 cell 为单位的。

例如 costmap 分辨率是:

resolution: 0.05  # 5cm/cell

如果某个栅格离障碍物格子 10 个 cell:

distance = 10
resolution = 0.05 m/cell
实际距离 d = distance × resolution = 10 × 0.05 = 0.5m

所以源码里才会写:

distance * resolution <= inscribed_radius

意思是:

当前栅格到障碍物格子的实际距离 <= 机器人内切半径

如果成立,就把这个格子标成 253


4. inscribed_radius 内切半径从哪里来?

inscribed_radius 不是你直接在 Inflation Layer 里手动设置的。

Nav2 会根据 costmap 的机器人形状自动算:

footprint: "[[0.45, 0.35], [0.45, -0.35], [-0.45, -0.35], [-0.45, 0.35]]"

或者:

robot_radius: 0.35

如果你配置的是 footprint,Nav2 会计算:

inscribed_radius = base_footprint 原点到 footprint 边或顶点的最小距离
circumscribed_radius = base_footprint 原点到 footprint 边或顶点的最大距离

对一个中心在 base_footprint 的矩形车体:

footprint: "[[L/2, W/2], [L/2, -W/2], [-L/2, -W/2], [-L/2, W/2]]"

那么:

inscribed_radius = min(L/2, W/2)
circumscribed_radius = sqrt((L/2)^2 + (W/2)^2)

举例:

车长 L = 0.90m
车宽 W = 0.70m

inscribed_radius = min(0.45, 0.35) = 0.35m
circumscribed_radius = sqrt(0.45² + 0.35²) ≈ 0.57m

工程含义:

inscribed_radius 内的区域是非常危险区域;
如果机器人中心进入距离障碍物小于内切半径的位置,机器人 footprint 很可能已经碰到障碍物。

注意:如果你的 base_footprint 原点不在车体几何中心,或者 footprint 点写错,Nav2 算出来的内切/外接半径也会跟着错。


5. inflation_radius 和 cost_scaling_factor 分别控制什么?

这两个参数作用不同:

参数 控制什么 直观理解
inflation_radius 膨胀影响范围最大到多远 影响范围
cost_scaling_factor 这个范围内 cost 衰减多快 衰减速度

不要误解成:

inflation_radius = 1.0m,所以 1m 内都是高代价

正确理解是:

1m 内会产生指数衰减代价;
越靠近障碍物 cost 越高,越远 cost 越低;
cost_scaling_factor 越大,下降越快。

6. 例子:inflation_radius = 1.0m,inscribed_radius = 0.30m

假设:

inflation_radius: 1.0
inscribed_radius: 0.30

不同 cost_scaling_factor 下,距离障碍物不同位置的内部 cost 大概如下:

距离障碍物 k=1 k=2 k=3 k=5 k=10
0.0m 254 254 254 254 254
0.1m 253 253 253 253 253
0.3m 253 253 253 253 253
0.4m 228 206 186 152 92
0.5m 206 168 138 92 34
0.6m 186 138 102 56 12
0.8m 152 92 56 20 1
1.0m 125 62 30 7 0
1.2m 0 0 0 0 0

可以看到:

k 越小,代价下降越慢,远处也还有明显 cost,车更不容易贴障碍;
k 越大,代价下降越快,只有障碍旁边很小一圈有明显 cost。

所以如果你想让车更倾向走通道中间,一般不要把 cost_scaling_factor 设得太大。


7. 如何根据目标 cost 反推 cost_scaling_factor?

公式:

cost = 252 × exp(-k × (d - r_inscribed))

反推:

k = -ln(cost / 252) / (d - r_inscribed)

例如:

inscribed_radius = 0.30m
希望 d = 1.00m 时 cost 约为 80

那么:

k = -ln(80 / 252) / (1.00 - 0.30)
  ≈ 1.64

参考表:

希望 1.0m 处 cost 约为 对应 cost_scaling_factor,假设 inscribed_radius=0.30m
150 0.74
100 1.32
80 1.64
50 2.31
20 3.62

8. RViz 里的颜色代表什么?

RViz 颜色显示的是 costmap 的可视化结果,不同显示模式/主题可能略有差异,但一般可以这样理解:

RViz 颜色 大概含义 内部 cost
黑色 / 透明 free space 0
蓝色 低代价膨胀区 较低的 1~252
红色 / 橙色 高代价膨胀区 较高的 1~252
青色 inscribed inflated obstacle,内切半径危险区 253
紫色 / 粉紫色 lethal obstacle,障碍物本体 254
灰蓝 / 灰绿 unknown 255

调参时不要只看颜色“好不好看”,重点看:

障碍物周围是不是有连续渐变?
通道中间的 cost 是否明显低于贴边位置?
膨胀区有没有把窄通道完全堵死?
253/254 区域是否只在真正危险区域附近?

如果想看原始代价值,可以看 raw costmap:

ros2 topic echo /local_costmap/costmap_raw

或者写一个小脚本订阅 /local_costmap/costmap_raw,取某个格子的 cost 值。


9. 针对园区巡检车的调参思路

如果你的车比较大,且目标是安全优先,可以先从下面的方向试:

local_costmap:
  local_costmap:
    ros__parameters:
      footprint: "[[0.45, 0.35], [0.45, -0.35], [-0.45, -0.35], [-0.45, 0.35]]"
      footprint_padding: 0.05

      inflation_layer:
        plugin: "nav2_costmap_2d::InflationLayer"
        inflation_radius: 1.0
        cost_scaling_factor: 2.0

调参顺序建议:

  1. 先写准 footprint
  2. 确认 RViz 里 footprint 和真实车宽一致。
  3. 设置一个偏保守的 inflation_radius,比如 0.8 ~ 1.2m
  4. cost_scaling_factor 先设在 1.5 ~ 3.0
  5. 看车是否更愿意远离障碍物。
  6. 如果窄路过不去,减小 inflation_radius 或增大 cost_scaling_factor
  7. 如果还贴障碍,增大 inflation_radius 或减小 cost_scaling_factor

经验理解:

太贴障碍:inflation_radius 增大,或 cost_scaling_factor 减小
太保守、窄路过不去:inflation_radius 减小,或 cost_scaling_factor 增大

10. 一句话总结

inflation_radius 决定“影响多远”;
cost_scaling_factor 决定“掉得多快”;
inscribed_radius 由 footprint / robot_radius 自动计算;
distance 是 costmap 栅格到最近障碍物栅格的距离,不是机器人到障碍物的实时距离;
253 是内切半径危险区,254 是障碍物本体。

参考资料

  • Nav2 Inflation Layer Parameters: https://docs.nav2.org/configuration/packages/costmap-plugins/inflation.html
  • Nav2 Inflation Layer 源码:computeCost():https://api.nav2.org/nav2-rolling/html/inflation__layer_8hpp_source.html
  • Nav2 Footprint 源码:calculateMinAndMaxDistances():https://api.nav2.org/nav2-humble/html/footprint_8cpp_source.html
  • Nav2 Costmap 2D 配置文档:https://docs.nav2.org/configuration/packages/configuring-costmaps.html
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐