
如果你准备学 ROS2并想从零打通机器人自主移动这条链路最容易被卡住的通常不是某个命令记不住而是仿真、SLAM、Nav2 这几段之间的衔接一直串不起来。你可能会先在一个二维 Stage 场景里看到小车能跑接着又听说 Ignition 仿真更接近真实环境于是一换仿真器话题、TF、传感器参数全变了SLAM 建图和 Nav2 导航自然就跟不上。这篇内容更像是陪你一起动手的记录我会把 ROS2 仿真 - SLAM 建图 - Nav2 导航这条完整链路拆开用 Stage 和 Ignition 两种仿真器分别过一遍并把每一步该看什么、怎么判断成功、失败先从哪查都写出来。适合刚学 ROS2、想理解自主移动全流程、又不想一开始就买实体车的读者。需要先说清楚的是ROS2 生态版本变化快不同发行版对应的仿真器、Nav2、SLAM 工具版本都不一样。我这里以 Ubuntu 22.04 ROS2 Humble 这套比较常见的组合为例但核心思路可以迁移到其他发行版。1. 先搞清楚这条链路到底要打通什么1.1 仿真、SLAM、Nav2 不是三件事是一条数据流水线很多新手把这几个概念当成并列模块去学结果越学越乱。实际上它们是一条完整的数据流水线。仿真器负责提供“环境”和“身体”。环境是机器人周围的地图、障碍物、墙壁身体是机器人模型、雷达、轮子、里程计。仿真器会源源不断发布传感器数据最常见的是 2D 激光雷达数据sensor_msgs/LaserScan也会发布里程计nav_msgs/Odometry。如果你用键盘控制机器人仿真器还会接收/cmd_vel速度指令让机器人移动。SLAM 负责回答两个问题机器人现在在哪里周围环境长什么样它会接收雷达、里程计和 TF 这些输入一边估计机器人位姿一边更新地图。最终输出的是一张二维占用栅格地图以及机器人在地图中的定位结果。Nav2 负责回答另一个问题给定地图和目标点机器人该怎么走过去它会加载 SLAM 保存的地图结合当前定位结果做全局路径规划、局部避障最终输出速度指令给仿真器。三者串起来的顺序就是仿真器给数据 - SLAM 建图并保存地图 - Nav2 加载地图并导航。你如果只学单个模块每一步看起来都简单但串起来以后会暴露大量问题比如话题对不上、坐标系缺失、时间戳不同步。所以打通全链路的意义在于培养排错能力。1.2 为什么把 Stage 和 Ignition 放在一起学Stage 是一个轻量级二维仿真器。它的优点是启动快、资源占用低、参数简单适合快速验证算法逻辑。在 Stage 里跑通 SLAM 和 Nav2能让你把注意力放在行为和参数上而不是被环境渲染、物理引擎、传感器噪声折磨。Ignition 是更贴近真实机器人的三维物理仿真器现在也常被归入 Gazebo 系列生态。它的环境更丰富传感器更复杂能模拟碰撞、摩擦、光线和更多传感器数据。代价是配置更多、资源占用更高、排查链路更长。两个仿真器放在一起实战是为了让你体会同一个 ROS2 算法栈在不同环境下的差异。你会发现SLAM 和 Nav2 的算法逻辑不用大改但话题名、坐标名、传感器配置、启动参数都要跟着环境调整。这种能力恰恰是真实机器人开发最需要的。1.3 学习路径怎么拆最不容易中途放弃我建议把整个目标拆成三步每一步都有明确的验收标准。第一步在仿真器里启动一台机器人用键盘控制它移动。验收标准是键盘按键后机器人能动终端能看到/cmd_vel话题有输出仿真器同时发布/scan和/odom。这一步的主要目标是确认“仿真器到 ROS2 的话题链路”是通的。第二步打开 SLAM 节点手动控制机器人绕环境走一圈生成一张地图并保存。验收标准是地图随着机器人移动逐步扩展墙体轮廓清晰没有严重重影最后能保存成.pgm和.yaml文件。第三步启动 Nav2加载刚才保存的地图在 RViz 里给机器人一个目标点观察它能不能规划路径并自己走过去。验收标准是RViz 里出现全局路径机器人收到速度指令开始移动最终到达目标点。不要急着把 SLAM 和 Nav2 同时开。分开跑能让你在每一步都清楚问题出在哪一层。2. 环境准备把 ROS2 工作台搭到能跑为止2.1 系统版本和 ROS2 发行版怎么选ROS2 的功能包和系统版本强相关。最常见的选择是 Ubuntu 22.04 搭配 ROS2 Humble这也是当前入门教程数量最多、遇到问题最容易搜到答案的组合。如果你的系统版本不同不要直接照抄安装命令一定要先去确认对应的 ROS2 发行版。版本不匹配会带来一系列依赖问题比如某些功能包找不到、编译报错、Nav2 参数格式不一致等。更麻烦的是ROS2 发行版更新后部分 API 会有变化旧教程里的启动命令可能直接失效。有一个比较稳妥的做法查 ROS2 官方安装文档按你的系统版本选择对应发行版再安装ros-发行版-desktop。比如 Humble 就是ros-humble-desktop。不要在源没配好的情况下强行安装否则很容易出现E: Unable to locate package ros-humble-desktop这类错误。2.2 安装后先做五个检查安装完成后先不要急着建工作空间也不要急着跑仿真先确认基础环境是正常的。第一步打开终端配置环境变量source /opt/ros/humble/setup.bash第二步看当前 ROS2 发行版echo $ROS_DISTRO如果输出humble说明环境变量没问题。如果输出为空说明没有 source 或者安装路径不对。第三步看能否直接列出节点ros2 node list刚启动时没有任何节点输出一般是空列表这算正常。如果提示找不到命令说明 ROS2 没有正确安装。第四步跑一个最简单的发布订阅测试ros2 run demo_nodes_cpp talker再开一个终端ros2 run demo_nodes_cpp listener如果 listener 能不断收到消息说明 DDS 通信链路是通的。第五步运行 RViz2rviz2能正常启动图形界面说明图形相关依赖也没问题。不要一上来就折腾机器人模型和仿真先把基础环境确认好。2.3 创建工作空间和第一个功能包后续的仿真、SLAM、Nav2 配置会很多最好集中放在一个工作空间里。mkdir -p ~/ros2_ws/src cd ~/ros2_ws/src ros2 pkg create --build-type ament_python my_robot_demo cd ~/ros2_ws colcon build --symlink-install source install/setup.bash这里有个细节--symlink-install对 Python 功能包比较友好改完代码后不用反复重新编译。如果你以后写 C 节点就需要按正常流程重新 build。工作空间建好以后可以先创建一个空的功能包后面把仿真启动文件、SLAM 参数、Nav2 配置统一放进去。这样比直接把命令散在终端里更容易维护。2.4 安装后续要用的仿真和导航组件不同 ROS2 发行版的包名不一样官方源和第三方源也可能有差异。我这里给一个常见组合示例但你在实际安装前最好先用apt-cache search查一下当前环境里可用的包名。sudo apt install ros-humble-navigation2 ros-humble-nav2-bringup ros-humble-slam-toolbox ros-humble-turtlebot3-gazebo ros-humble-turtlebot3-cartographer ros-humble-teleop-twist-keyboard ros-humble-tf2-tools注意这只是示例。如果你的源里没有某个包不要硬装先用搜索命令确认apt-cache search ros-humble | grep nav2确定包名后再安装。安装完成后建议把环境变量写进~/.bashrc避免每次开终端都要手动 sourceecho source /opt/ros/humble/setup.bash ~/.bashrc但要注意如果你同时装过多个 ROS2 发行版不要重复 source 多个版本否则环境变量会互相覆盖。3. 仿真模型让仿真器里先出现一台能动的小车3.1 先跑通一个最简 Stage 场景Stage 的优势是简单。你可以先不纠结三维模型直接启动一个包含小车、雷达和里程计的 Stage 场景。启动之后先不要急着开 SLAM用下面的命令确认仿真器正常工作ros2 topic list看看有没有/scan、/odom、/cmd_vel这些话题。然后单独看话题数据ros2 topic echo /scan ros2 topic hz /odom/scan有数据说明雷达在工作/odom有固定频率说明里程计在工作。如果这些话题不存在不要直接去调 SLAM问题大概率出在 Stage 的模型配置或者启动参数上。比如传感器插件没写对、frame_id 没有设置、机器人模型没有加载成功。这个阶段最容易忽略的是速度和视角在 Stage 里地图小、环境简单很多问题不会立刻暴露。但你要记住这一步的重点不是“跑得多好”而是确认数据链路是通的。3.2 Ignition 作为更接近真机的仿真环境Ignition 启动起来会比 Stage 慢很多加载一个三维 world 可能需要几十秒甚至更久。这是正常现象不要以为卡住了。在 Ignition 里你通常会加载一个 URDF 或 SDF 格式的机器人模型模型里配置了轮子、激光雷达、IMU 等传感器插件。ROS2 节点要拿到仿真器里的数据一般需要通过桥接包把 Ignition 话题转换成 ROS2 话题。首次在 Ignition 里跑通一个小车比在 Stage 里要多做三件事第一确认 world 文件路径正确。很多启动失败不是模型问题而是文件路径找不到。第二确认桥接话题正确。不同版本的桥接包话题类型和命名规范有差异。第三确认机器人模型里的 link 和 joint 名称与 SLAM、Nav2 里期望的 frame_id 对齐。在 Ignition 里你会发现一些 Stage 里完全没有的问题比如雷达安装位置偏低导致数据被车身遮挡或者仿真物理引擎导致小车原地打滑。这些都是接近真实机器人才会遇到的问题所以把 Ignition 作为进阶仿真环境很有价值。3.3 两个仿真器共通的一条主线传感器、里程计和 TF无论你用 Stage 还是 IgnitionSLAM 和 Nav2 真正依赖的输入是三个传感器数据、里程计数据、TF 树。传感器数据通常来自激光雷达话题类型一般为sensor_msgs/LaserScan。里程计数据来自轮式编码器模型话题类型为nav_msgs/Odometry。TF 树里至少要有odom、base_link、laser这些坐标系之间的变换。换仿真器之后第一件事不是调算法参数而是用下面的命令确认三个输入ros2 topic hz /scan ros2 topic hz /odom ros2 topic hz /tf如果某个话题频率为 0说明数据没发布或者话题名不对。如果频率很低比如正常情况下 10Hz现在只有 1Hz那就要看是不是仿真器配置重了或者桥接节点在丢消息。还有一个经常被忽略的参数use_sim_time。如果你用仿真器里的模拟时钟就要把相关节点的use_sim_time设置为 true否则各个节点拿到的时间戳不一致TF 和话题会一直报“等待数据”之类的错误。可以先检查时钟话题ros2 topic list | grep clock如果存在/clock说明仿真器启用了模拟时间那后面启动 SLAM 和 Nav2 时就要注意use_sim_time参数。4. SLAM 建图先让机器人知道自己在哪4.1 SLAM 不是一键出图是边移动边更新SLAM 看起来很高端但入门阶段完全可以把它理解成一个“边移动边画地图”的过程。机器人通过雷达扫描周围环境同时估计自己在地图中的位置然后把每一帧测量数据叠加到地图上。如果你启动 SLAM 之后机器人不动地图几乎不会自动扩展。所以你必须手动控制机器人行走让雷达扫到更多区域。常用的键盘控制工具ros2 run teleop_twist_keyboard teleop_twist_keyboard如果这个工具找不到先确认对应功能包是否安装。如果你的仿真器发布的话题不是/cmd_vel需要做话题重映射。建图时不要走得很快。先把机器人放在一个相对开阔的位置让它原地旋转一圈让雷达建立初步环境轮廓然后缓慢向前移动。遇到走廊时先直行再分段转向。不要频繁急转弯也不要一会儿前进一会儿后退这样很容易让里程计累计误差变大地图出现重影。4.2 常用建图算法怎么选ROS2 里常见的 2D 激光建图方案有几种我这里给一张对比表算法传感器类型适合阶段常见麻烦gmapping2D 激光雷达经典入门ROS2 下维护不积极依赖较老slam_toolbox2D 激光雷达现代推荐参数配置需要看文档Cartographer2D / 3D 激光雷达更大场景、更高精度配置复杂资源占用更高视觉 SLAM相机 / 相机 IMU无激光雷达时标定、光照、特征依赖更多我的建议是如果只是为了打通 Stage 到 Nav2 的链路选一个文档相对多、安装相对容易的算法先跑通不要同时配多套 SLAM。SLAM 节点之间会互相抢话题和资源排错时根本分不清是哪个算法的问题。如果你用的是 2D 激光雷达slam_toolbox是一个比较现代的选项配置比 Cartographer 简单功能也够用。Cartographer 出来后就是坑但如果你后面要做更大的地图或者更复杂的场景再回来研究它也来得及。4.3 建图质量的判断和保存判断地图是否合格不要只看屏幕上有轮廓就算成功。我一般会看四个地方第一地图边界是否清晰。墙体应该是实线不能是散点或者断断续续的虚影。第二有没有明显重影。如果同一面墙在地图上出现两条错开的线说明机器人位姿估计有偏差运动太快或者里程计不准。第三回到起点时机器人在 RViz 里的位置和地图原点是否还能对得上。如果对不上说明累计漂移已经比较明显。第四TF 是否持续报错。如果终端里不停刷 transform 相关警告说明坐标系链路有问题地图质量也不会稳定。还有一个很常见的 RViz 操作问题如果你在地图上看不到完整地图或者一移动视角整个地图就跟着跑通常是 Fixed Frame 没有设置好。把 RViz 左侧的Fixed Frame设置为map或odom而不是base_link。建图完成后保存地图ros2 run nav2_map_server map_saver_cli -f ~/my_map这个命令会在当前目录或指定路径下生成my_map.pgm和my_map.yaml。如果你的环境里包名不一样可以先试试ros2 pkg list | grep map_server然后选择对应工具。保存地图这一步非常关键因为后面的 Nav2 导航加载的是这份静态地图而不是 SLAM 实时建图的结果。4.4 定位和地图坐标系不能混很多新手在导航时会遇到一个奇怪现象SLAM 建图时明明正常但一加载地图启动 Nav2机器人就不知道自己在哪。这是因为 Nav2 启动后定位模块需要知道自己在地图中的初始位置。你可以在 RViz 里手动设置初始位姿也可以通过配置指定。这个动作不是可选项而是定位是否收敛的前提。设置初始位姿时要选一个和你当前实际环境对应的位置并且朝向也要设置对。如果朝向反了后面导航会一直绕圈甚至直接穿过障碍物。5. Nav2 导航让机器人在已知地图里自己走5.1 Nav2 不是单一节点是一整套导航框架Nav2 不是一个单独的节点而是一组功能包的集合。它至少包含定位、代价地图、全局路径规划、局部路径规划、行为树控制等模块。所以你在启动 Nav2 时可能会看到很多节点一起启动不要慌这是正常现象。正因为模块多参数也多才有那么多看起来奇奇怪怪的问题。在入门阶段你不必理解每一个插件但至少要清楚每个模块的大概职责定位模块负责告诉机器人“你现在在地图的哪个位置”。全局代价地图负责在整张地图上评估哪些区域可走哪些区域是障碍物。全局路径规划器负责从起点到目标点找一条宏观路径。局部代价地图负责机器人周围的短距离环境建模。局部路径规划器负责在行驶过程中避开临时出现的障碍物并输出速度指令。5.2 建图完切导航为什么经常起不来很多人建图完成后直接启动 Nav2结果机器人原地不动或者 RViz 里没有路径。最常见的原因不是 Nav2 坏了而是定位没有收敛。正确流程应该是先把刚才保存的静态地图加载起来。启动 Nav2 相关节点。在 RViz 里给机器人设置一个正确的初始位姿。再给目标点。定位没有收敛时机器人脑中的“自己位置”是错的。你给一个目标点全局规划器可能会从错误位置规划路径或者因为路径被障碍物挡住而一直失败。一个比较笨但好用的验证方法是设置完初始位姿后先不要急着给目标点观察 RViz 里的激光点云和地图墙体重合得怎么样。如果激光点和地图边界基本对齐说明定位已经稳定。5.3 参数要点别照搬默认值Nav2 的配置项非常多但入门阶段不用全部理解重点关注几个和“能不能走”直接相关的参数。第一个是机器人半径或 footprint。它表示机器人在地图上占多大面积。如果你用差速小车通常用robot_radius就能表达。半径设得太大机器人会认为窄路不可通行半径设得太小实际行驶时可能会撞到障碍物。第二个是代价地图的分辨率和尺寸。分辨率越高地图越精细但计算量也越大。低配置机器上可以先降低分辨率让导航先跑起来。第三个是全局规划器的选型。Nav2 默认配置在很多简单场景下能跑但如果你发现路径贴着墙壁走或者转弯特别大就说明规划器参数需要调整尤其是规划器的启发函数和轨迹优化相关参数。第四个是局部规划器的速度限制。机器人不是速度越快越好的速度上限太高碰到障碍物时可能刹不住导致局部规划器反复尝试失败。参数这个东西没有一套万能的推荐值。最好的方法是在仿真器里先用小地图、低速度测试一点一点调。5.4 别急着上 3D 雷达和复杂传感器热词里有人问 Nav2 使用 3D 雷达的问题。我的建议是入门阶段先用 2D 激光雷达把链路跑通。Nav2 的很多默认配置和教程示例都围绕 2D 激光雷达设计问题更容易定位。如果项目里只有 3D 激光雷达或深度相机通常需要先把 3D 点云转换成 2D 激光数据常见方式是使用pointcloud_to_laserscan这类节点。这样可以把问题隔离在“传感器数据转换”和“导航算法”两个阶段分别排查。一上来就让 Nav2 直接处理 3D 点云不是不行但你会同时面对点云降采样、障碍物膨胀、坐标变换、性能优化等多重问题对新手非常不友好。6. Stage / Ignition 双实战的流程差异和坑6.1 两个仿真器各自适合做什么项目StageIgnition仿真维度2D 平面3D 物理环境资源占用较低较高传感器模型简单更丰富配置复杂度低高启动速度快慢适合场景快速验证算法链路接近真实机器人验证出错排查难度低高我的建议是先 Stage 后 Ignition。在 Stage 里跑通建图和导航能建立基本信心再切换到 Ignition你会有意识地区分哪些是算法问题哪些是仿真环境问题。6.2 从 Stage 切到 Ignition 最容易出现的三件事第一话题名对不上。Stage 的驱动和 Ignition 的桥接包发布的话题不一定同名。不要靠记忆直接启动后看ros2 topic list然后把/scan、/odom、/cmd_vel等话题查清楚。第二TF 树不完整。Ignition 的机器人模型可能包含很多 link 和 joint如果某个传感器插件的 frame_id 和 base_link 之间没有正确的变换发布SLAM 或 Nav2 会一直等待变换。建议使用ros2 run tf2_tools view_frames生成frames.pdf或类似文件检查 odom、base_link、laser 之间的关系是否完整。第三模拟时间问题。Ignition 通常会启用/clock你需要确保 SLAM 和 Nav2 的参数文件里use_sim_time为 true。否则节点拿到的系统时间戳和仿真时间戳不一致会出现“Waiting on transform”或“Message dropped”等错误。6.3 低配置机器上的降载建议如果你的电脑配置一般在使用 Ignition 时要注意控制资源占用。常见做法包括降低 world 复杂度不要在场景里放太多高精度模型。关闭摄像头渲染或者降低图像分辨率。降低激光雷达采样率。减小机器人速度上限避免仿真物理引擎计算量过大。低配置机器能跑通 Stage不代表能顺畅跑 Ignition。这不算工具问题而是环境能力边界。6.4 双实战的黄金顺序我见过不少新手一上来就装 Ignition结果启动失败连是不是仿真器问题都分不清。更稳妥的顺序是Stage 里启动最小场景跑通键盘控制。Stage 里跑通 SLAM保存地图。Stage 里启动 Nav2跑通目标点导航。切到 Ignition重新做一遍重点排查话题和 TF 差异。这个顺序看起来多花一点时间但能帮你少走很多弯路。7. 卡住时怎么排查按顺序来不要瞎改参数7.1 把故障分层看遇到问题先不要急着改参数先把问题定位到某一层。仿真层仿真器有没有启动成功机器人模型有没有加载驱动层话题有没有数据频率是否稳定感知层SLAM 有没有输出地图定位层Nav2 的定位是否收敛激光点云和地图边界是否对齐规划层有没有生成路径机器人有没有收到/cmd_vel每一层都有对应的验证方式不要跳过。7.2 高频问题排查表现象优先检查apt 找不到 ros-humble 包ROS2 源、系统版本、apt update启动后没有 /scan仿真器和桥接包是否启动话题是否被 remap一直 Waiting on transform检查 TF 树frame_id 是否一致use_sim_time 是否开启地图是空的机器人没有移动、SLAM 没有收到雷达、scan 是空数据地图重影或漂移里程计不准、雷达数据异常、运动太快Nav2 收不到目标RViz 固定坐标系、地图话题、定位没有收敛有路径但机器人不动检查 /cmd_vel 话题、局部规划器、速度上下限路径绕远代价地图膨胀半径、全局规划器设置7.3 日志、话题、坐标是三条命脉排查时不要只盯着 RViz 的彩色画面节点终端里的日志往往比图像更直接。推荐一个固定排查顺序ros2 topic list ros2 topic hz /scan /odom /cmd_vel ros2 run tf2_tools view_frames ros2 node list先看节点有没有启动再看话题有没有数据然后看 TF 树完整不完整。如果这些都正常最后再怀疑参数问题。日志里如果出现Waiting for transform那就先去查 TF。如果日志里出现Message dropped那就去查时间戳和use_sim_time。如果日志里没有任何提示但机器人不动那就去查/cmd_vel有没有输出以及目标点是否发送成功。很多问题看着像 SLAM 或 Nav2 坏了实际上只是启动顺序、话题重映射或者坐标系命名的问题。8. 全链路跑通后下一步建议8.1 把启动流程收敛成一键启动当你手动跑通 Stage 或 Ignition 全流程后不要停在“能手动启动”的阶段。建议把所有节点整理成一个 launch 文件启动仿真器启动传感器和状态发布节点启动 SLAM 或地图服务启动 Nav2启动 RViz这样下次运行就不再需要在多个终端里按顺序手动敲命令。整理 launch 文件本身也是很好的 ROS2 学习方式你会更清楚每个节点之间的依赖关系。一个比较实用的经验是先按顺序拆成多个 launch 文件再写一个总 launch 文件把它们串起来。不要一开始就写一个巨大无比的 launch 文件那样出错时很难定位。8.2 换传感器和真实机器人时要重新验证什么跑通仿真之后如果后面要换真实机器人或不同传感器就不要抱着“仿真里能跑真机一定也能跑”的想法。至少重新验证这几项传感器话题名字和类型是否和算法节点期望一致。机器人实际尺寸和代价地图参数是否匹配。里程计话题的频率和噪声情况。机器人坐标系和传感器坐标系的安装关系。Nav2 的速度限制是否适合真实电机和控制板。仿真器最大的价值是让你在没有真实机器人硬件的情况下先把算法和流程理解透。真正落地时硬件差异一定会带来新的问题。到那时候你再回来查这篇内容里的排查顺序思路会清楚很多。整套流程跑通之后建议你再做一次“完整重启”。关掉所有终端重新启动只运行你整理好的一键启动命令看能不能顺利走到目标点。能自动化完成这一步才算真正把 ROS2 仿真、SLAM 建图和 Nav2 导航这条链路打稳了。