1. Nav2架构总览:从ROS1 Navigation Stack到Nav2的演进
各位同学好,我是你们这门课的老朋友。今天咱们正式开篇,聊聊Nav2的架构。说实话,我从ROS1时代就开始折腾导航了,那时候的Navigation Stack,嗯,怎么说呢,像个大工具箱,但工具之间怎么配合,全靠你自己摸索。到了Nav2,整个思路都变了——它更像一个精密的乐高系统,每个模块都设计好了接口,你只需要按需拼装。
我个人习惯把Nav2的演进看作一次「架构觉醒」。ROS1的导航栈把所有逻辑揉在一个节点里,调试起来像在迷宫里找路。而Nav2引入了行为树,把决策流程变成了可视化的流程图。你想想看,这就像从手写面条代码升级到了状态机,清晰太多了。
1.1 从ROS1 Navigation Stack到Nav2:一次架构的涅槃
先简单回顾一下历史。ROS1的move_base大家应该都熟悉,它把全局规划、局部规划、恢复行为都塞进了一个大节点。我在项目中遇到过一个问题:机器人卡在墙角,全局路径重新规划了三次,但局部规划器还在傻傻地往前冲。为什么?因为所有逻辑都耦合在一起,你很难单独控制某个行为的触发条件。
Nav2彻底改变了这一点。它把导航拆成了多个独立的生命周期节点:
- planner_server:负责全局路径规划
- controller_server:负责局部运动控制
- behavior_server:负责恢复行为(比如倒车、旋转)
- bt_navigator:负责用行为树编排整个流程
每个节点都有自己的生命周期——未配置、未激活、激活。你可以单独重启某个模块,而不影响其他模块。我曾经在调试时,只重启了controller_server就解决了局部震荡问题,这在ROS1时代想都不敢想。
核心变化总结:
- 从单节点到多节点:解耦更彻底
- 从硬编码逻辑到行为树:决策可视化
- 从全局状态到生命周期:控制更精细
- 从ROS1消息到ROS2动作:通信更可靠
1.2 核心组件与数据流
咱们来看看Nav2的核心组件是怎么配合的。我画了一张图,帮你理清数据流:
数据流其实很直观。用户发送一个导航目标,BT Navigator拿到后,根据行为树定义,依次调用Planner Server规划全局路径,然后交给Controller Server去跟踪。如果遇到障碍物卡住了,Behavior Server就会介入,执行倒车或旋转等恢复动作。所有模块都依赖Costmap 2D来感知环境,依赖TF来知道自己在哪。
我的小建议:刚开始接触Nav2时,别急着改代码。先打开行为树的XML文件看看,理解每个节点是干什么的。我见过太多人一上来就调参数,结果越调越乱。行为树就是导航的「剧本」,先把剧本读懂了,再谈表演。
1.3 行为树在导航中的角色
行为树(Behavior Tree,简称BT)是Nav2的灵魂。说白了,它就是用一棵树来描述「什么时候该做什么事」。每个节点代表一个动作或一个条件判断,树的结构决定了执行顺序。
举个例子,一个简单的导航行为树可能是这样的:
Sequence (主任务)
├── ComputePathToPose (规划全局路径)
├── FollowPath (跟踪路径)
└── 如果失败,执行:
└── Spin (原地旋转恢复)
你想想看,这种结构比传统的if-else清晰多了。我在项目中遇到过一个问题:机器人每次遇到障碍物就原地旋转,转完还是过不去,就继续转,陷入死循环。用行为树,我可以轻松加一个「重试次数」节点,转三次还过不去就放弃,或者换一条路。
Nav2默认提供了一套行为树,但你完全可以自己写。我个人习惯把行为树分成三层:
- 控制层:Sequence、Fallback、Parallel这些控制节点,决定执行逻辑
- 动作层:具体的导航动作,比如规划、控制、恢复
- 条件层:判断当前状态,比如是否到达目标、是否卡住
注意:行为树不是万能的。如果你把树写得过于复杂(比如嵌套超过5层),调试起来会非常痛苦。我曾经见过一个同事写了200多个节点的行为树,最后他自己都看不懂了。保持简洁,能用3个节点解决的问题,别用5个。
最后说一句,Nav2的行为树是用XML定义的,你可以用任何文本编辑器修改。但我不建议手写——用Nav2自带的BehaviorTree.CPP库提供的可视化工具,拖拽节点就能生成XML,省时省力。嗯,这个工具我们后面会专门讲。
好了,第一章就到这里。记住:Nav2的核心不是代码,而是架构思维。理解了行为树,你就掌握了Nav2的钥匙。