1. 导航系统概览:ROS Navigation Stack 架构与核心组件
做机器人导航,说白了就是让机器人知道「我在哪、要去哪、怎么走」。ROS 的 Navigation Stack 把这套逻辑打包成了一个可复用的框架。我最早接触它是在 2016 年,当时被一堆参数搞得头大,后来才慢慢摸清门道。
这一节我们先搭个全局视图。你理解了整体架构,后面调参才不会迷路。
1.1 整体架构:三层分工
ROS Navigation Stack 可以拆成三层,每层干自己的活:
- 感知层:处理传感器数据。激光雷达、里程计、IMU 的数据从这里进来,经过滤波和坐标变换,变成可用的信息。
- 决策层:核心是
move_base。它接收目标点,调用全局和局部规划器,输出速度指令。 - 执行层:把速度指令发给底盘驱动,让电机转起来。
嗯,这里要注意:这三层之间靠 ROS 话题通信,不是硬耦合。你可以换掉任何一层,只要接口对得上。
核心原则:Navigation Stack 是一个「插件化」框架。全局规划器、局部规划器、代价地图都可以替换。我见过有人把全局规划器换成 A* 的变体,也有人把局部规划器换成纯纯的 DWA。灵活,但前提是你得理解默认配置。
1.2 核心组件详解
1.2.1 move_base:导航的大脑
move_base 是 Navigation Stack 的总控节点。它接收 geometry_msgs/PoseStamped 类型的目标点,然后协调全局规划、局部规划、代价地图更新,最终输出 geometry_msgs/Twist 速度指令。
我个人习惯把 move_base 看作一个状态机:
- 空闲态:等待目标点
- 规划态:调用全局规划器生成路径
- 执行态:局部规划器跟踪路径,同时避障
- 恢复态:遇到不可恢复的障碍时,执行旋转、后退等恢复行为
我在项目中遇到过一个问题:机器人卡在门框里,反复尝试恢复行为就是出不来。后来发现是恢复行为的参数太保守,旋转速度设得太低。调高之后就好了。
1.2.2 amcl:定位的基石
AMCL(Adaptive Monte Carlo Localization)是自适应蒙特卡洛定位。它用粒子滤波来估计机器人在已知地图中的位姿。
说白了,就是撒一把粒子在地图上,每个粒子代表一个可能的位姿。然后根据激光雷达的观测数据,给粒子打分,权重高的留下,权重低的淘汰。不断迭代,粒子会收敛到真实位姿附近。
AMCL 有几个关键参数,我后面会专门讲:
- 粒子数量:多了精度高但计算慢,少了容易发散
- 激光模型:决定观测似然的计算方式
- 里程计模型:决定运动更新的噪声模型
避坑指南:我曾经在实验室里跑得好好的,换到走廊就定位漂移。查了半天发现是 AMCL 的 laser_max_range 设得太小,走廊的长距离激光被截断了。记住:激光参数一定要和实际传感器匹配。
1.2.3 costmap:代价地图
代价地图是 Navigation Stack 的「环境模型」。它把地图栅格化,每个格子赋予一个代价值,表示该位置的可通行程度。
ROS 里有两层代价地图:
| 类型 | 作用 | 更新频率 | 典型分辨率 |
|---|---|---|---|
| 全局代价地图 | 用于全局路径规划,考虑静态障碍物 | 低(几秒一次) | 0.05m - 0.1m |
| 局部代价地图 | 用于局部避障,考虑动态障碍物 | 高(10Hz 以上) | 0.02m - 0.05m |
代价地图的核心是「膨胀层」。它把障碍物向外膨胀,让机器人保持安全距离。膨胀半径设得太小,机器人容易擦墙;设得太大,窄通道就过不去了。这个平衡点,我调了不下 50 次才找到手感。
1.3 数据流与坐标系关系
导航系统里,数据流和坐标系是绑在一起的。你想想看,如果坐标系对不上,规划出来的路径就是错的。
ROS 里常用的坐标系有:
- map:世界坐标系,固定不变
- odom:里程计坐标系,以机器人启动位置为原点,会漂移
- base_link:机器人本体坐标系,通常位于底盘中心
- laser:激光雷达坐标系
数据流大致是这样的:
- 激光雷达发布
sensor_msgs/LaserScan到/scan话题 - AMCL 接收激光数据和里程计数据,通过
tf发布map -> odom的变换 move_base订阅tf,知道机器人在 map 下的位姿- 全局规划器在 map 坐标系下规划路径
- 局部规划器在 odom 坐标系下跟踪路径并避障
- 最终输出速度指令到
/cmd_vel话题
这里有个容易踩的坑:odom 和 map 之间的变换必须由 AMCL 发布,不能自己瞎写。我见过有人手动写死这个变换,结果机器人一跑就偏。
调试技巧:用 rviz 查看 tf 树,确认所有坐标系都正确连接。如果看到 map 和 odom 之间没有变换,那就是 AMCL 没启动或者参数配错了。
1.4 整体架构图
下面这张图展示了 Navigation Stack 的核心组件和数据流关系。我建议你把它存下来,后面调参时对照着看。
1.5 坐标系变换关系
坐标系变换是导航系统的「隐形骨架」。ROS 用 tf 包来管理这些变换。你可以在终端里用 tf_echo 工具查看任意两个坐标系之间的变换。
典型的变换树长这样:
map
└── odom
└── base_link
├── laser
└── base_footprint
注意:map 到 odom 的变换由 AMCL 发布,odom 到 base_link 的变换由里程计发布,base_link 到 laser 的变换是固定的,由机器人 URDF 模型定义。
我刚开始做导航时,经常遇到「机器人在地图上乱跳」的问题。后来发现是 base_link 到 laser 的变换写错了,激光数据被投影到了错误的位置。嗯,这个坑踩过一次就记住了。
关键检查点:启动导航系统后,先用 rviz 查看 tf 树。如果看到任何红色的坐标系,说明变换缺失。这是最常见的启动失败原因,没有之一。
1.6 本章小结
这一节我们覆盖了 Navigation Stack 的骨架:
- 三层架构:感知层、决策层、执行层,各司其职
- 三个核心组件:
move_base负责规划与执行,amcl负责定位,costmap负责环境建模 - 数据流:从激光数据到速度指令,经过规划、定位、代价地图的协同处理
- 坐标系:map、odom、base_link、laser 之间的变换关系