4. 全局规划器初探:Nav2默认全局规划器NavFn原理,参数文件结构解析
全局规划器,说白了就是给机器人画一条从起点到终点的“大路”。你告诉它“我要去那里”,它就在全局代价地图上找出一条能走的路。Nav2 默认用的是 NavFn,一个基于 Dijkstra 和 A* 混合思想的规划器。我最早接触它的时候,觉得不就是个寻路嘛,后来才发现里面的门道真不少。
这一章,咱们就把它拆开看看。不搞花架子,直接聊原理、参数、还有我踩过的坑。
4.1 NavFn 到底怎么工作的?
NavFn 本质上是一个 势场规划器。它把地图看成一张网格,每个格子都有一个“代价”值。然后从目标点开始,像水波一样往外扩散,计算每个格子到目标点的最小代价路径。最后机器人沿着“梯度下降”的方向走,就能到目标。
我个人习惯把它理解成“水往低处流”。目标点就是最低点,机器人顺着坡往下滑。嗯,当然这个坡是数学上的势场。
核心步骤:
- 初始化势场:目标点势能为 0,其他点设为无穷大。
- 波前传播:从目标点开始,用 Dijkstra 思想更新相邻格子的势能,直到覆盖整个地图或到达机器人位置。
- 路径生成:从机器人当前位置出发,沿着势能下降最快的方向回溯,直到目标点。
我在项目中遇到过一个问题:当障碍物把路堵死的时候,NavFn 会绕很远的路,甚至找不到路径。后来发现是 allow_unknown 参数没开,导致未知区域直接被当成障碍。你想想看,机器人还没探索的地方就被堵死了,那肯定绕路啊。
4.2 参数文件结构解析
Nav2 的参数文件通常叫 nav2_params.yaml。全局规划器的配置放在 global_costmap 和 planner_server 下面。我习惯把参数分成三块:规划器核心参数、代价地图参数、以及插件选择。
下面是一个典型的 NavFn 参数片段,我加了注释,方便你理解。
planner_server:
ros__parameters:
planner_plugins: ["GridBased"]
GridBased:
plugin: "nav2_navfn_planner/NavfnPlanner"
tolerance: 0.5 # 到达目标点的容忍距离 (米)
use_astar: false # 是否使用 A* 加速 (默认 Dijkstra)
allow_unknown: true # 是否允许通过未知区域
max_iterations: 100000 # 最大迭代次数,防止死循环
| 参数名 | 默认值 | 说明 | 我的建议 |
|---|---|---|---|
| tolerance | 0.5 | 终点判定半径,机器人进入这个范围就算到达 | 室内设 0.3~0.5,室外可适当放大 |
| use_astar | false | 是否启用 A* 启发式搜索 | 地图大时建议 true,小地图 Dijkstra 更稳 |
| allow_unknown | true | 是否把未知区域当作可通行 | 探索阶段建议 true,已知环境设 false 更安全 |
| max_iterations | 100000 | 规划器最大迭代次数 | 一般不用改,地图超大时可增大 |
我曾经因为 use_astar 设为 true 但启发函数权重没调好,导致路径有时会贴着障碍物走。后来我干脆在复杂环境中用纯 Dijkstra,虽然慢一点,但路径更安全。看你的场景取舍吧。
4.3 全局代价地图的联动
全局规划器不是孤立的。它依赖全局代价地图提供的“障碍物膨胀层”。你想想看,如果膨胀半径设得太大,机器人可能找不到路;设得太小,又容易刮蹭。我一般先设 0.3m 的膨胀半径,然后根据机器人实际尺寸微调。
下面这个例子展示了全局代价地图中与规划器相关的参数:
global_costmap:
global_costmap:
ros__parameters:
robot_radius: 0.22
inflation_layer:
inflation_radius: 0.55
cost_scaling_factor: 10.0
plugins: ["static_layer", "obstacle_layer", "inflation_layer"]
注意 inflation_radius 和 cost_scaling_factor 直接影响规划器生成的路径离障碍物有多远。数值越大,路径越保守。
千万不要把 inflation_radius 设得比机器人转弯半径还小!否则规划出来的路径,机器人实际根本拐不过去。我吃过这个亏,机器人卡在走廊里一直原地转圈……
4.4 调试小技巧:如何观察规划器行为
调参的时候,光看机器人跑是不够的。我习惯用 RViz 打开 Path 和 Potential 显示。NavFn 可以发布势场图(如果你开启了 publish_potential 参数)。
另外,你可以在终端用 ros2 param get /planner_server GridBased.tolerance 来实时查看参数值。嗯,热加载参数也是可以的,不过那是后面章节的内容了。
我个人习惯在调试时把 max_iterations 临时设小一点(比如 10000),这样如果规划失败能快速报错,不用等半天。
4.5 避坑指南
- 路径频繁重规划? 检查
tolerance是否太小,或者代价地图更新太快。 - 规划失败但地图明明有路? 看看
allow_unknown是不是 false,以及膨胀层是否把通道堵死了。 - 规划时间过长? 试试
use_astar: true,或者减小地图分辨率(但别低于 0.05m)。
我曾经在一个仓库项目里,机器人总是规划出奇怪的“Z”字形路径。查了两天,最后发现是全局代价地图的 static_layer 加载了过期的地图,导致障碍物位置不对。所以,有时候问题不在规划器本身,而在上游数据。
本章小结: NavFn 是一个基于势场的全局规划器,通过 Dijkstra/A* 计算梯度路径。参数文件集中在 planner_server 命名空间下,核心参数包括 tolerance、use_astar、allow_unknown。调参时一定要结合全局代价地图的膨胀层,别孤立地看规划器。