
1. 先搞清楚运行第一个机器人这一步在跑什么第一次把 ROS 2 环境装好敲下那条启动命令屏幕上蹦出一只小海龟然后你用键盘方向键让它满屏幕爬尾巴拖出一条白线——这个过程对很多人来说就是入门 ROS 2的仪式感。但如果你只把它当成一个演示程序按几下键盘就关掉那这一步的价值基本浪费了九成。运行你的第一个机器人这句话里的关键词其实是机器人三个字turtlesim 只是把一台真实机器人身上最核心的几层东西——节点、话题、服务、参数、坐标系、控制指令——压缩进了一个窗口里。你先在这个窗口里把通信链路摸熟后面换到真机、换到机械臂、换到移动底盘动作方式几乎一模一样。我在带新人的时候有个固定流程装完环境不急着讲代码先让对方用小海龟把ros2 node、ros2 topic、ros2 service、ros2 param这四组命令各敲一遍边敲边解释屏幕上发生了什么。原因很直接ROS 2 是一套分布式通信框架它的学习曲线陡峭的地方从来不是语法而是我现在敲的这条命令到底在跟谁说话说的是什么内容。小海龟把这几个问题可视化得非常友好你echo一个话题能看到海龟位置的实时数据你call一个服务能立刻看到海龟重置或瞬移。这种即时反馈是纯看文档替代不了的。这一节的定位是给刚装完系统、还没写过任何 ROS 2 节点的人一条完整的动手路径同时也会讲到刚从 ROS 1 迁移过来的老手容易踩的坑——两者的命令行工具、构建系统、通信中间件都不是一回事用 ROS 1 的肌肉记忆去敲 ROS 2 的命令报错能让你怀疑人生。至于已经有基础、想直接上真机的读者我建议也先把这一节过一遍尤其是后面讲ROS_DOMAIN_ID和 DDS 通信那块很多两台机器互相看不见的问题根子就在这里。提示小海龟不是玩具它是 ROS 2 官方维护的教学示例包源码结构、话题命名、服务定义都遵循标准规范是可以拿来当模板读的。1.1 为什么官方入门示例选的是小海龟而不是一套真机这个问题的答案其实涉及教学成本和风险控制两个层面。真实机器人最大的问题是它不可复现电池电量、地面摩擦力、传感器噪声、编码器误差任何一个变量都会让你的调试结果飘。你昨天晚上调好的一段控制代码今天早上跑出来轨迹偏了二十厘米你根本分不清是代码问题还是轮子打滑。而 turtlesim 是一个理想化的二维仿真速度指令进去位置按固定模型更新输入输出完全确定。你调试的是通信逻辑不是物理世界。从架构上拆turtlesim 这个包内部只干三件事订阅/turtle1/cmd_vel这个话题接收速度指令按运动学模型更新海龟位姿把位姿发布到/turtle1/pose同时把画面刷出来。它的结构跟一台真实差分驱动机器人的最小闭环几乎一致——上位机发速度底盘执行并反馈里程计。你在这里学会的发布一个 Twist 消息让对象动起来换成真机就是把 Twist 换成发给底盘的串口或者 CAN 指令消息类型和发布方式不变。另一个考虑是依赖。真机跑起来需要驱动、需要标定、需要处理通信丢包随便一个环节卡住都可能让你一整天停在那里。turtlesim 只依赖桌面版 ROS 2 的基础组件装完就有零配置。对于刚入门的阶段能跑起来这件事带来的正反馈极其重要先让人体会到成就感再去啃那些硬的骨头这个顺序不能反。1.2 一个 ROS 2 系统的最小组成节点、话题、服务、参数ROS 2 里所有东西都挂在节点上。节点是一个进程干一件具体的事情。turtlesim 启动后会有一个叫/turtlesim的节点键盘遥控启动后会有另一个叫/teleop_turtle的节点。系统就是由若干个节点通过通信机制拼起来的。话题是最常用的通信方式特点是单向、异步、多对多。发布者往话题里写消息订阅者从话题里读双方互相不知道对方是谁也不需要同时在线。/turtle1/cmd_vel就是这样一个话题遥控节点往里发速度turtlesim 节点从里面读速度。服务是请求—应答模式同步、一对一。客户端发一个请求服务端处理完返回一个结果中间客户端会阻塞等待。清屏、重置、生成新海龟这类我需要立刻知道结果的操作用服务比话题合适。参数是挂在节点上的键值配置。turtlesim 的背景色就是三个参数background_r、background_g、background_b控制的你运行时改一下画面立刻变色。理解这四个概念的分工比背命令重要得多──你后面写业务代码时判断一段交互该用话题还是服务靠的就是这个判断。1.3 版本选择Humble 为什么值得作为入门首选ROS 2 的发行版按字母顺序命名目前被提到最多的是 Humble 和 Jazzy。对入门的人来说Humble 的适配面最广它对应 Ubuntu 22.04 LTS这个系统版本稳定、社区文档厚、第三方包覆盖全micro-ROS 对它的支持也最成熟。你搜到的大多数教程、问答、示例代码时间线都集中在 Humble 上遇到问题容易找到答案。Jazzy 对应 Ubuntu 24.04更新但生态还在追赶部分硬件厂商的驱动和仿真工具包还没完全跟上。铁律是入门阶段不要追新选文档最多的那个版本。等你能独立解决依赖问题、能读源码打补丁了再考虑新版。ROS 2 的发行版支持周期一般是五年Humble 到 2027 年足够你把基础打穿。2. 环境准备地基没打好后面全是玄学问题环境这块我见过太多翻车现场最常见的不是命令敲错而是版本错配和源没配好。Ubuntu 20.04 硬装 Humble、装完不 source 直接敲ros2、用 conda 的 python 去跑系统 python 装的东西——这三类问题能占新手报错的一半以上。这一章把安装和环境变量的逻辑讲透。2.1 系统版本与 ROS 2 发行版的对应关系这张表建议截图存着装之前先对一遍Ubuntu 版本推荐 ROS 2 版本状态备注22.04 LTSHumble HawksbillLTS2027 年停支持入门首选文档最全24.04 LTSJazzy JaliscoLTS新生态在补齐20.04 LTSFoxy Fitzroy已停止维护不建议新项目使用18.04 LTSDashing已停止维护只用于维护老旧设备Ubuntu 版本和 ROS 2 版本不是随便搭的二进制包针对特定系统的库版本编译混搭的结果就是依赖地狱。如果你手上只有 Ubuntu 20.04 的机器要么升系统要么用 Docker 起一个 22.04 的容器别硬装。2.2 装系统的两条路APT 安装和源码编译绝大多数人走 APT 路线我也推荐这条。源码编译适合需要改 ROS 2 源码本身、或者要针对特定架构做裁剪的场景普通人没必要折腾。APT 安装的核心是先把 ROS 2 的软件源和密钥加进去再装 meta 包。# 1. 配置本地化避免中文环境下包信息乱码 sudo apt update sudo apt install locales sudo locale-gen en_US en_US.UTF-8 sudo update-locale LC_ALLen_US.UTF-8 LANGen_US.UTF-8 export LANGen_US.UTF-8 # 2. 启用 universe 仓库ROS 2 的依赖大量来自这里 sudo apt install software-properties-common sudo add-apt-repository universe # 3. 添加 ROS 2 的 GPG 密钥 sudo apt update sudo apt install curl -y sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key \ -o /usr/share/keyrings/ros-archive-keyring.gpg # 4. 写入软件源 echo deb [arch$(dpkg --print-architecture) signed-by/usr/share/keyrings/ros-archive-keyring.gpg] \ http://packages.ros.org/ros2/ubuntu $(. /etc/os-release echo $UBUNTU_CODENAME) main | \ sudo tee /etc/apt/sources.list.d/ros2.list /dev/null # 5. 安装桌面版 sudo apt update sudo apt upgrade -y sudo apt install ros-humble-desktop -y sudo apt install ros-dev-tools -y这里有三个细节值得说清楚。第一ros-humble-desktop包含了 RViz2、rqt、demo 节点和仿真工具ros-humble-ros-base只有通信框架和命令行工具没有图形界面。入门阶段装 desktop省得后面一个个补包。第二ros-dev-tools是编译工具链包含colcon、rosdep这些写自己的包必须用。第三第 4 步里的$(. /etc/os-release echo $UBUNTU_CODENAME)会自动取当前系统代号Ubuntu 22.04 得到的是jammy写死成别的代号会直接装不上。2.3 环境变量 source 的那些坑装完不 source敲ros2会提示找不到命令这是新手第一道坎。ROS 2 的所有可执行文件、库路径、Python 模块都靠环境变量拼出来只有 source 了 setup 脚本这套变量才会被注入当前 shell。source /opt/ros/humble/setup.bash临时这么敲一次只对当前这个终端窗口生效。关掉重开就没了。要让它持久生效得写进~/.bashrcecho source /opt/ros/humble/setup.bash ~/.bashrc source ~/.bashrc我个人的习惯是不写进.bashrc而是给每个项目单独写一个setup.sh需要的时候手动 source。理由有两个一是多版本共存时比如你同时装了 Humble 和 Jazzy.bashrc里写死一个版本会让另一个没法用二是显式 source 能让你清楚地知道当前终端处于什么环境排查问题时这个信息很关键。注意如果你之前 source 过工作空间的install/setup.bash再 source 系统的是没用的因为 shell 的环境变量是有先后的后面的会追加而不是覆盖。要彻底重置得关掉终端重开或者用env -i bash --norc起一个干净 shell。2.4 装完怎么验证三条命令判断环境是否可用不要一上来就跑小海龟先用三条命令做体检# 1. 看版本对不对 ros2 --version # 2. 看有哪些命令行工具 ros2 --help # 3. 跑官方的最小示例两个终端 ros2 run demo_nodes_cpp talker ros2 run demo_nodes_cpp listener第三条命令会看到一个终端不断打印Hello World: 数字另一个终端打印I heard: [Hello World: 数字]。这个例子比小海龟更能说明问题两个独立进程通过话题通信发布和订阅完全解耦。如果你只看到 talker 在刷数据、listener 没反应那说明环境装好了但通信有问题八成是 DDS 层面的配置这个我们放到排查章节细讲。3. 跑起小海龟把每条命令背后的通信机制拆开看前面铺垫够多了现在正式进入实操。这一章我按启动—观察—干预—理解的顺序来每个终端开在哪、敲什么、会看到什么、为什么是这个结果我尽量都写清楚。3.1 第一个终端启动 turtlesim 节点ros2 run turtlesim turtlesim_node命令拆开看ros2 run是做启动动作turtlesim是包名turtlesim_node是这个包里的可执行文件准确说是可执行目标C 编译出来是二进制Python 是脚本。执行后弹出蓝色背景的窗口中间一只默认朝向右侧的海龟。这个节点启动后注册进了 ROS 2 的图graph节点名是/turtlesim。窗口标题栏可能会显示它的话题命名空间是/turtle1。命名空间这个概念后面讲多机器人时会反复用到现在先记住一个 turtlesim 节点默认管一只海龟海龟的所有话题和服务都挂在/turtle1/下面。如果你想指定这个节点的名字可以用重映射ros2 run turtlesim turtlesim_node --ros-args -r __node:my_turtle--ros-args是 ROS 2 参数系统的入口-r是 remap 的缩写__node是节点名的保留关键字。这个语法在启动真实机器人节点时用得非常频繁现在混个眼熟。3.2 第二个终端键盘遥控与它的话题真相新开一个终端source 环境后启动遥控source /opt/ros/humble/setup.bash ros2 run turtlesim turtle_teleop_key关键点来了光标必须停在这个终端里方向键才有效。原因很直白键盘事件是被这个终端捕获的你点回小海龟窗口按键就发给窗口管理器了。这个坑几乎每个人都踩过我见过有人把键盘按烂了都没反应最后发现是焦点问题。遥控节点在后台做的事是每按一次方向键构造一条geometry_msgs/msg/Twist消息发布到/turtle1/cmd_vel话题上。Twist 是 ROS 2 里描述速度的标准消息包含两个三维向量linear线速度 x/y/z和angular角速度 x/y/z。对平面运动的差分底盘来说真正起作用的是linear.x前进方向线速度和angular.z绕竖直轴旋转的角速度其余四个分量都是 0。3.3 节点视角用 ros2 node 看清系统里有谁再开一个终端敲ros2 node list你会看到/turtlesim和/teleop_turtle两个名字。ros2 node list列出的是当前 ROS 2 域里所有活跃节点。接着看单个节点的详情ros2 node info /turtlesim输出会分成四块Subscribers订阅的话题、Publishers发布的话题、Service Servers提供的服务、Service Clients调用的服务、Action Servers、Action Clients。这时候你会发现/turtlesim订阅了/turtle1/cmd_vel发布了/turtle1/pose同时提供了一堆服务。这就是这个节点的身份档案——你搞清楚了一个节点的输入输出就等于摸清了这个模块的接口看任何陌生的 ROS 2 机器人系统都是这个套路先node list再node info比读文档快。3.4 话题视角echo、pub、hz 三板斧ros2 topic list -t-t参数会额外显示每条话题的消息类型输出类似/turtle1/cmd_vel [geometry_msgs/msg/Twist]。记住这个类型手工发消息的时候要用。# 实时查看海龟位姿每秒刷新若干次 ros2 topic echo /turtle1/pose # 查看话题的发布频率 ros2 topic hz /turtle1/pose # 查看带宽占用 ros2 topic bw /turtle1/poseros2 topic echo在调试传感器数据时是神器但要注意它输出量大看完记得CtrlC停掉不然刷屏刷到终端卡死。ros2 topic hz用来验证发布频率是否正常比如你要确认一个 10Hz 的激光雷达是不是真的按 10Hz 在发这条命令最直接。现在换个玩法不用键盘手动往话题里灌速度指令ros2 topic pub --rate 1 /turtle1/cmd_vel geometry_msgs/msg/Twist \ {linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}--rate 1表示每秒发一次。这里linear.x 2.0是前进线速度angular.z 1.8是旋转角速度两者同时给海龟会走出一个圆形轨迹。这个组合不是随便写的当线速度 v 和角速度 ω 同时恒定运动轨迹的半径就是 r v/ω 2.0/1.8 ≈ 1.11。你可以自己改这两个数验证这个公式改完立刻能看到圆的半径变化。这就是我说的参数有据可循——每个数字背后都有物理意义别当成玄学在填。注意ros2 topic pub的默认 QoS 是可靠传输而部分传感器话题用的是 Best Effort。如果话题类型对但收不到数据去查ros2 topic info /话题名 --verbose里的 QoS 配置。3.5 服务视角清屏、瞬移、生成新海龟ros2 service list ros2 service type /clear/clear的服务类型是std_srvs/srv/Empty请求和应答都是空纯副作用操作ros2 service call /clear std_srvs/srv/Empty执行后海龟走过的轨迹被清掉海龟留在原地。再看生成新海龟的服务ros2 service call /spawn turtlesim/srv/Spawn \ {x: 2.0, y: 2.0, theta: 0.2, name: turtle2}返回结果里会带出新海龟的名字。生成后你会发现两个有意思的现象第一ros2 topic list里多了/turtle2/cmd_vel和/turtle2/pose第二遥控节点的速度指令只发给turtle1turtle2 不动。这正好演示了命名空间隔离——每只海龟活在自己的命名空间里互不干扰。你要让 turtle2 动得用重映射把遥控的输出指过去ros2 run turtlesim turtle_teleop_key --ros-args \ -r /turtle1/cmd_vel:/turtle2/cmd_vel这条命令的意思是把遥控原本发布到/turtle1/cmd_vel的话题名替换成/turtle2/cmd_vel。多机器人系统的核心技巧就是这个现在掌握了后面控制三台、五台机器人无非是命名空间规划得更细致。还有个服务值得试/turtle1/teleport_absolute它能把海龟瞬间挪到指定坐标不产生轨迹。原理上就是直接改位姿状态跳过运动学积分。3.6 参数视角运行时改背景色ros2 param list ros2 param get /turtlesim background_r ros2 param set /turtlesim background_r 150get拿到的是当前值set改完之后画面不会立刻变色这是因为背景色只在节点初始化时读取一次。要让它生效得重启节点时带上参数文件ros2 param dump /turtlesim turtlesim.yaml ros2 run turtlesim turtlesim_node --ros-args --params-file ./turtlesim.yamlparam dump把当前所有参数导出成 YAML重启时用--params-file加载。这个流程在真实项目里非常常用——你在图形界面上把 PID 参数调到满意然后 dump 出来存进版本管理下次部署直接加载避免每次手敲。3.7 rqt把命令行看到的东西图形化命令行敲多了会累rqt 是把这些信息可视化的工具箱ros2 run rqt_graph rqt_graph # 看节点和话题的连接拓扑 ros2 run rqt_console rqt_console # 看日志聚合 ros2 run rqt_plot rqt_plot # 把话题里的数值画成曲线rqt_graph我强烈建议在每次搭好一个新系统后看一眼节点之间的连线一目了然谁发给谁、有没有孤立的发布者图上一清二楚。有次我调一个话题一直没数据rqt_graph一看订阅者根本没连上发布者原因是两边 QoS 不兼容图里那条线是断的。这个信息用命令查要翻好几个输出看图三秒就定位了。4. 从虚拟到真实同一套逻辑怎么搬到硬件上小海龟跑通之后下一步自然是想上硬件。这一章讲两件事一是 micro-ROS 这条低门槛的硬件路线二是把 turtlesim 的理解映射到真机架构上。4.1 micro-ROS ESP32把 ROS 2 节点塞进单片机ESP32 这类 MCU 资源有限跑不动完整的 ROS 2 中间件。micro-ROS 的思路是在单片机上跑一个轻量客户端库通过串口或 WiFi 跟主机上的 micro-ROS Agent 通信Agent 相当于一个翻译层把单片机的数据转发进 ROS 2 图里。对上层来说这个 ESP32 就是一个正常的 ROS 2 节点话题、服务一样能用。大致流程是这样主机上编译运行 micro-ROS Agent可以装在桌面版 ROS 2 上ESP32 端用 micro-ROS 提供的工具生成固件框架你在里面写发布者、订阅者烧录进去两边连上之后ros2 node list就能看到 MCU 上报的节点。这条路子的价值在于可以直接拿现成的开发板做传感器采集、舵机控制成本低、上手快是很多爱好者做第一台自研机器人时的选择。4.2 turtlesim 与真机的分层对应关系把 turtlesim 拆成层你就能明白上真机时每一层要换什么层级turtlesim真实机器人是否需要改动上层代码速度指令话题/turtle1/cmd_vel/cmd_vel或底盘专属话题话题名重映射消息类型geometry_msgs/msg/Twist同为Twist标准基本不变运动执行内置运动学模型电机驱动 编码器闭环换成驱动节点位姿反馈/turtle1/pose里程计话题 IMU 融合需要坐标系变换可视化窗口画面RViz2 实际传感器数据换显示工具你会发现最关键的那一层——速度指令话题——消息类型是统一的Twist。这正是 ROS 2 生态的价值只要大家都遵守标准消息控制层代码几乎不用改换个话题名就能从仿真切到真机。所以我在仿真里练的东西不是白练的。4.3 写一个最小发布者验证你真的懂了光敲命令不算会写一个节点才能把概念焊死。下面这段 Python 代码用最少的行数复刻遥控节点的核心行为import rclpy from rclpy.node import Node from geometry_msgs.msg import Twist class CircleDriver(Node): def __init__(self): super().__init__(circle_driver) # 创建发布者话题名、消息类型、队列长度 self.pub self.create_publisher(Twist, /turtle1/cmd_vel, 10) # 每秒触发 10 次 self.timer self.create_timer(0.1, self.tick) self.get_logger().info(circle driver started) def tick(self): msg Twist() msg.linear.x 2.0 msg.angular.z 1.8 self.pub.publish(msg) def main(): rclpy.init() node CircleDriver() try: rclpy.spin(node) except KeyboardInterrupt: pass finally: node.destroy_node() rclpy.shutdown() if __name__ __main__: main()几个要点。create_publisher的第三个参数 10 是 QoS 队列深度意思是消息发出去后最多缓冲 10 条等订阅者取超过就丢最旧的这个值太小会导致突发数据丢包太大占内存。create_timer的回调周期 0.1 秒对应 10Hz和海龟的位姿发布频率接近比较合适。rclpy.spin是事件循环负责把接收到的消息派发到对应的回调不 spin 的话定时器不触发、订阅者收不到数据这是新手代码看着没错但不工作的最高频原因。代码存成circle_driver.pychmod x之后直接python3 circle_driver.py就能跑前提是 source 过 ROS 2 环境。想做成正规的包用ros2 pkg create --build-type ament_python my_first_pkg生成骨架把文件放进my_first_pkg/my_first_pkg/目录在setup.py里注册入口点再colcon build。这套流程走一遍你就正式跨过了只会敲命令的门槛。提示运行前先关掉键盘遥控节点两个发布者同时往/turtle1/cmd_vel发速度会打架海龟的动作会变得不可预测。多发布者共存是 ROS 2 允许的行为但业务上要避免。5. 常见问题与排查速查表这一章是纯经验打包都是我或者身边人真实踩过的坑。5.1 环境和版本类问题ros2: command not found出现频率最高99% 是没 source。别急着怀疑安装失败先echo $ROS_DISTRO看变量在不在空的就是没 source。装包时提示依赖冲突或者rosdep install反复失败先检查是不是混装了 conda 环境。conda 的 Python 会覆盖系统 Python导致 ROS 2 的 Python 包找不到。命令which python3应该指向/usr/bin/python3如果指向 conda 目录退出 conda 环境再试。ros2 run时提示Package xxx not found大概率是没 source 工作空间。ROS 2 的包查找靠AMENT_PREFIX_PATH环境变量工作空间 source 后里面的包才会被找到。注意 source 顺序工作空间必须在系统之后 source否则会被系统环境覆盖。5.2 通信类问题节点都在但互相看不见多机通信的问题集中在 DDS 层。ROS 2 默认用 DDS 做发现同网段内节点会自动相互发现。如果两台机器互相看不见按这个顺序排查现象可能原因排查命令处理方式本机都看不到自己环境未 sourceecho $ROS_DISTROsource setup.bash同机节点互相看不见域 ID 不一致echo $ROS_DOMAIN_ID两端设成同一个值跨机发现不了不在同一网段 / 组播被限制ping对端 IP用同一交换机或设置发现服务器能看到节点看不到话题QoS 不匹配ros2 topic info /话题 --verbose调整可靠性策略话题有数据但延迟大网络拥塞或频率过高ros2 topic hz降频或改用大消息压缩ROS_DOMAIN_ID是隔离用的默认都是 0所以正常情况下能互通。但如果你在实验室或者办公室里同一网段有一堆人都在跑 ROS 2默认域会互相干扰你会看到一堆陌生节点。这时候给每个人分配一个不同的域 ID问题立刻消失。这是个非常实用的小技巧多人共用网络环境时必备。5.3 命令和操作类问题ros2 topic pub报消息格式错误多半是 YAML 少了大括号或者字段名拼错。我的做法是先用 Tab 补全把消息类型敲出来然后照着消息定义文件里的字段名填。字段名大小写敏感linear写成Linear直接失败。键盘遥控没反应先确认终端焦点再确认遥控节点进程还活着。有的终端在按下方向键时会触发终端自身的快捷键把输入吞掉换个终端模拟器试试。rqt_graph打开是空白检查是不是DISPLAY变量没设置远程终端场景常见。纯 SSH 连接没有图形界面图形工具跑不起来得用-X或-Y做 X11 转发或者直接用命令行替代。6. 几个让我少走弯路的实操心得写到这里基础流程已经完整了。最后分享几个不太出现在文档里、但实际用起来很省事的东西。6.1 终端管理别用三个标签页硬撑小海龟这个例子只要两个终端但真机调试动辄需要七八个窗口。我早期一直靠标签页切来切去经常搞混哪个终端在哪台机器上。后来改用 tmux一个会话里开多个窗格布局固定重启终端后会话还在。命令不复杂tmux new -s ros建会话CtrlB加方向键切窗格tmux attach -t ros重新接入。花半小时学一遍往后每天都省时间。另外一个习惯是给每个终端加上醒目的提示符比如把 source 过的版本和域 ID 显示在提示符里一眼就知道这个终端当前是什么环境。这个配置不复杂写进.bashrc的PS1里就行效果立竿见影。6.2 把重复命令脚本化我一开始也是每次手敲那串长的ros2 topic pub敲错一个字符就得重来。后来把这些命令整理成脚本起名起得有规律需要的时候./pub_speed.sh一把梭。更进一步用ros2 launch把多个节点组合成一次启动这是从会用命令到会用工具的分界线。launch 文件本身是 Python 或者 XML/YAML 写的里面描述要启动哪些节点、各自的参数是什么。小海龟这个场景写一个 launch 文件同时起节点和遥控虽然简单但把模板立起来了后面搭复杂系统就是往里面加节点的事。6.3 一个容易被忽略的细节时间和坐标系小海龟这个例子简单到不涉及时间戳和坐标变换但这是真实机器人里最容易出问题的地方。仿真里你看到的时间是连续的真机上时间戳可能回跳、可能停滞直接导致依赖时间的算法崩掉。我在真机上第一次遇到 TF 报错时完全懵后来才知道是时间同步没做好。建议的做法是每次接触新机器人系统第一件事是ros2 topic echo /tf和/tf_static看坐标系树的根在哪里、有没有断链。再ros2 topic echo /clock确认时间源是仿真时钟还是系统时钟。这两个检查加起来不超过两分钟能省掉后面几个小时的排查。养成习惯之后面对任何陌生的机器人平台你都能快速摸清它的骨架然后再往细节里钻。