2. 基础回顾:ROS2导航栈架构详解(Nav2)
聊到导航调参,咱们得先把地基打牢。ROS2的导航栈,也就是Nav2,说白了就是一套帮你把机器人从A点送到B点的工具集。我刚开始接触Nav2的时候,觉得它就是个黑盒子——给个目标点,机器人就自己走了。后来踩的坑多了,才明白这里面每一层都有讲究。
今天我就带你拆开这个盒子,看看里面到底装了些什么。
2.1 Nav2的整体架构
Nav2不是单个节点,而是一堆节点协同工作的结果。它的核心思路是:感知 → 规划 → 控制 → 执行。嗯,这个链条你想想看,跟人类找路其实差不多——你先看路况,再想怎么走,然后迈腿,最后调整步伐。
核心要点:Nav2基于行为树(Behavior Tree)来编排整个导航流程。我个人习惯把行为树理解成一张「决策流程图」,它决定了什么时候做全局规划、什么时候做局部规划、什么时候该停下来避障。
下面这张图展示了Nav2的主要模块和它们之间的关系:
2.2 行为树——导航的「大脑」
Nav2用行为树来编排任务,而不是传统的状态机。为什么?因为行为树更灵活。你想想看,状态机里加一个新状态,往往要改一堆逻辑。行为树呢?加个节点就行了。
我记得第一次用Nav2的时候,默认的行为树是navigate_to_pose。它的大致流程是:
- 计算全局路径——从起点到终点画一条大路线
- 计算局部路径——边走边调整,避开动态障碍
- 控制执行——把路径转成速度指令
- 监控与恢复——卡住了怎么办?转个身或者倒车
小技巧:如果你想自定义导航行为,比如「先走到A点,再走到B点,中间必须经过一个充电桩」,那就得改行为树。Nav2提供了nav2_behavior_tree包,里面有很多现成的节点可以直接用。
2.3 全局规划器——画大路线
全局规划器的任务,是在已知地图上找一条从起点到终点的路径。它不考虑动态障碍物,只看静态地图。
Nav2里常用的全局规划器有:
| 规划器 | 算法 | 特点 | 适用场景 |
|---|---|---|---|
| NavFn | Dijkstra / A* | 稳定、成熟、计算快 | 大多数室内场景 |
| Smac Planner | Hybrid-A* / Lattice | 支持非完整约束、更平滑 | 阿克曼底盘、狭窄通道 |
| Theta* | Any-angle 路径 | 路径更短、更自然 | 开阔环境、追求路径质量 |
我个人习惯在调参初期先用NavFn,因为它参数少、不容易出幺蛾子。等基础功能跑通了,再换Smac Planner去优化路径平滑度。
2.4 局部规划器——边走边调
全局路径画好了,但实际走的时候,路上突然冒出个人怎么办?这就是局部规划器的工作了——它负责实时调整路径,避开动态障碍。
Nav2里主流的局部规划器有三个:
- DWB(Dynamic Window Approach)——经典算法,参数多但可控性强。我在项目里遇到过一个坑:DWB的
max_vel_x设得太高,机器人过弯时直接甩出去了。嗯,后来我学乖了,先设个0.3 m/s慢慢试。 - MPPI(Model Predictive Path Integral)——基于采样的方法,效果很顺滑,但计算量大。如果你用的是Jetson Orin或者更高级的板子,可以试试。
- TEB(Timed Elastic Band)——把路径看成一条「橡皮筋」,优化它的形状和时间。适合动态环境,但参数调起来有点玄学。
注意:局部规划器依赖代价地图的实时更新。如果你发现机器人明明看到障碍了却不躲,先检查一下代价地图的更新频率,别急着调规划器参数。我曾经花了两天调DWB参数,最后发现是激光雷达的帧率设得太低了——教训啊。
2.5 代价地图——机器人的「眼睛」
代价地图说白了就是一张带「危险等级」的栅格图。每个格子都有一个代价值,值越高表示越危险。规划器看到高代价的格子就会绕开。
Nav2里有两层代价地图:
- 全局代价地图(Global Costmap)——用于全局规划,通常分辨率低一些(比如0.05m/格),范围大一些。
- 局部代价地图(Local Costmap)——用于局部规划,分辨率高一些(比如0.025m/格),范围小一些(比如3m×3m)。
代价地图的更新来源包括:
- 激光雷达(LaserScan)——最常用,精度高
- 深度相机(PointCloud2)——能检测悬空障碍,比如桌子边缘
- 静态地图(Static Map)——预先建好的地图,作为基础层
- 膨胀层(Inflation Layer)——把障碍物「吹大」一圈,给机器人留安全距离
调参重点:膨胀层的inflation_radius参数直接影响路径的「保守程度」。设大了,机器人离墙远远的,但可能钻不过窄门;设小了,能钻窄门,但容易蹭墙。我一般从0.3m开始试,根据实际效果微调。
2.6 恢复行为——出错了怎么办
导航不可能永远一帆风顺。机器人卡在角落里、被障碍困住、或者局部规划找不到路径——这些情况都需要恢复行为来处理。
Nav2默认的恢复行为有三种:
| 恢复行为 | 动作 | 适用场景 |
|---|---|---|
| Spin | 原地旋转一定角度 | 被障碍包围、需要重新扫描环境 |
| Backup | 后退一段距离 | 卡在狭窄通道、前进方向被堵 |
| Wait | 等待一段时间 | 动态障碍暂时挡住、稍后会移开 |
我曾经在一个仓库项目里遇到过这种情况:机器人每次经过一个货架通道就触发恢复行为,原地转一圈再走。后来发现是激光雷达的扫描角度刚好被货架腿挡住了,代价地图上出现了一个「幽灵障碍」。解决办法是把激光雷达的安装高度调高了一点,问题就解决了。
2.7 各模块之间的通信
Nav2的模块之间通过ROS2的Topic和Service通信。我整理了一张常用的Topic表:
| Topic名称 | 消息类型 | 发布者 | 订阅者 |
|---|---|---|---|
| /cmd_vel | Twist | 局部规划器 | 底盘驱动 |
| /odom | Odometry | 里程计 | 代价地图、规划器 |
| /scan | LaserScan | 激光雷达 | 代价地图 |
| /map | OccupancyGrid | SLAM或静态地图 | 全局代价地图 |
| /goal_pose | PoseStamped | 导航请求 | 行为树 |
嗯,这里要注意:如果你发现机器人接收不到速度指令,先别急着查规划器参数。用ros2 topic echo /cmd_vel看一眼,说不定是Topic没对上。
2.8 小结
Nav2的架构说白了就是:行为树管流程,全局规划管大方向,局部规划管细节,代价地图管感知,恢复行为管兜底。这五个部分配合好了,导航才能跑得稳。
我个人觉得,理解Nav2架构最好的方式不是看书,而是动手改参数、看效果。下一轮调参的时候,你可以试着改一个参数,然后观察机器人的行为变化——这样学得最快。