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:激光雷达坐标系

数据流大致是这样的:

  1. 激光雷达发布 sensor_msgs/LaserScan 到 /scan 话题
  2. AMCL 接收激光数据和里程计数据,通过 tf 发布 map -> odom 的变换
  3. move_base 订阅 tf,知道机器人在 map 下的位姿
  4. 全局规划器在 map 坐标系下规划路径
  5. 局部规划器在 odom 坐标系下跟踪路径并避障
  6. 最终输出速度指令到 /cmd_vel 话题

这里有个容易踩的坑:odom 和 map 之间的变换必须由 AMCL 发布,不能自己瞎写。我见过有人手动写死这个变换,结果机器人一跑就偏。

调试技巧:用 rviz 查看 tf 树,确认所有坐标系都正确连接。如果看到 map 和 odom 之间没有变换,那就是 AMCL 没启动或者参数配错了。

1.4 整体架构图

下面这张图展示了 Navigation Stack 的核心组件和数据流关系。我建议你把它存下来,后面调参时对照着看。

ROS Navigation Stack 架构与数据流 感知层 激光雷达 → /scan 里程计 → /odom IMU → /imu_data 决策层 move_base 全局规划器 (navfn / global_planner) 局部规划器 (dwa_local_planner / teb) 恢复行为 (clear_costmap / rotate) 执行层 /cmd_vel → 底盘驱动 电机控制 → 轮子转动 里程计反馈 → /odom /scan, /odom, tf /cmd_vel 里程计反馈 说明:实线箭头表示数据流方向,虚线箭头表示反馈回路。AMCL 位于感知层与决策层之间,负责发布 map→odom 变换。

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 之间的变换关系