如果你准备学 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 通信链路是通的。
第五步,运行 RViz2:
rviz2能正常启动图形界面,说明图形相关依赖也没问题。不要一上来就折腾机器人模型和仿真,先把基础环境确认好。
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,避免每次开终端都要手动 source:
echo "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 还是 Ignition,SLAM 和 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 激光建图方案有几种,我这里给一张对比表:
| 算法 | 传感器类型 | 适合阶段 | 常见麻烦 |
|---|---|---|---|
| gmapping | 2D 激光雷达 | 经典入门 | ROS2 下维护不积极,依赖较老 |
| slam_toolbox | 2D 激光雷达 | 现代推荐 | 参数配置需要看文档 |
| Cartographer | 2D / 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 两个仿真器各自适合做什么
| 项目 | Stage | Ignition |
|---|---|---|
| 仿真维度 | 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 导航这条链路打稳了。