Nav2 Inflation Layer 膨胀层公式、内切半径与 RViz 颜色理解
适合场景:ROS2 Nav2 局部规划 / DWB / MPPI 调参,尤其是想搞清楚
inflation_radius和cost_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}elseif(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 根据footprint或robot_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.0inscribed_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 topicecho/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.05inflation_layer:plugin:"nav2_costmap_2d::InflationLayer"inflation_radius:1.0cost_scaling_factor:2.0调参顺序建议:
- 先写准
footprint。 - 确认 RViz 里 footprint 和真实车宽一致。
- 设置一个偏保守的
inflation_radius,比如0.8 ~ 1.2m。 - 把
cost_scaling_factor先设在1.5 ~ 3.0。 - 看车是否更愿意远离障碍物。
- 如果窄路过不去,减小
inflation_radius或增大cost_scaling_factor。 - 如果还贴障碍,增大
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
