2. 基础回顾:ROS2导航栈架构详解(Nav2)

聊到导航调参,咱们得先把地基打牢。ROS2的导航栈,也就是Nav2,说白了就是一套帮你把机器人从A点送到B点的工具集。我刚开始接触Nav2的时候,觉得它就是个黑盒子——给个目标点,机器人就自己走了。后来踩的坑多了,才明白这里面每一层都有讲究。

今天我就带你拆开这个盒子,看看里面到底装了些什么。

2.1 Nav2的整体架构

Nav2不是单个节点,而是一堆节点协同工作的结果。它的核心思路是:感知 → 规划 → 控制 → 执行。嗯,这个链条你想想看,跟人类找路其实差不多——你先看路况,再想怎么走,然后迈腿,最后调整步伐。

核心要点:Nav2基于行为树(Behavior Tree)来编排整个导航流程。我个人习惯把行为树理解成一张「决策流程图」,它决定了什么时候做全局规划、什么时候做局部规划、什么时候该停下来避障。

下面这张图展示了Nav2的主要模块和它们之间的关系:

Nav2 架构总览图 Nav2 核心模块架构图 输入:目标位姿 / 初始位姿 行为树(Behavior Tree) 全局规划器 NavFn / Smac Planner 局部规划器 DWB / MPPI / TEB 恢复行为 Spin / Backup / Wait 代价地图(Costmap 2D / 3D) 里程计(Odometry) 传感器(Lidar / Depth Camera) 输出:速度指令 / 控制信号 说明:箭头表示数据流方向,各模块通过ROS2的Topic和Service进行通信

2.2 行为树——导航的「大脑」

Nav2用行为树来编排任务,而不是传统的状态机。为什么?因为行为树更灵活。你想想看,状态机里加一个新状态,往往要改一堆逻辑。行为树呢?加个节点就行了。

我记得第一次用Nav2的时候,默认的行为树是navigate_to_pose。它的大致流程是:

  1. 计算全局路径——从起点到终点画一条大路线
  2. 计算局部路径——边走边调整,避开动态障碍
  3. 控制执行——把路径转成速度指令
  4. 监控与恢复——卡住了怎么办?转个身或者倒车

小技巧:如果你想自定义导航行为,比如「先走到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)。

代价地图的更新来源包括:

  1. 激光雷达(LaserScan)——最常用,精度高
  2. 深度相机(PointCloud2)——能检测悬空障碍,比如桌子边缘
  3. 静态地图(Static Map)——预先建好的地图,作为基础层
  4. 膨胀层(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架构最好的方式不是看书,而是动手改参数、看效果。下一轮调参的时候,你可以试着改一个参数,然后观察机器人的行为变化——这样学得最快。