去年有个朋友想转行做机器人开发上来就问我“ROS2 现在这么火我是不是应该直接学最新的版本网上教程那么多从哪个开始看效率最高” 我当时没直接回答而是反问他“你学 ROS2 的最终目标是什么是想自己做个会动的小车玩玩还是想进公司做产品级的机器人应用”这个问题很关键。因为 ROS2 的学习路径很大程度上取决于你的目标。如果只是想体验一下网上任何一个“一小时入门”的教程都能让你动起来但如果你想真正掌握它用它来解决实际问题甚至作为职业发展的跳板那需要的就远不止是“安装-运行-hello world”这三板斧了。我见过太多人兴致勃勃地跟着教程装好了 ROS2跑通了几个 Demo然后就卡住了。面对一个真实的项目需求比如“让机器人从 A 点走到 B 点并避开障碍”却不知道从何下手。问题出在哪不是教程不好而是大多数教程只解决了“从 0 到 0.5”的问题——让你知道这个东西存在并且能跑起来。而真正的挑战是从“知道能跑”到“知道为什么能跑”再到“知道怎么让它按照我的想法跑”最后到“知道怎么让它稳定、可靠、高效地跑”。这中间的每一步都需要跨越不同的认知和实践门槛。所以这篇文章不会只是另一个 ROS2 功能列表或命令手册。我想和你聊的是如何为“用 ROS2 进行机器人开发”这件事搭建一个可持续、可扩展的认知和实践框架。我们会从最根本的“为什么是 ROS2”开始一步步拆解到环境、核心概念、项目实践再到工程化思维。目标是让你在看完之后不仅能复现几个例子更能建立起一套属于自己的问题分析和解决路径。1. 为什么是 ROS2它解决的远不止“通信”问题几乎所有教程的开头都会说ROS (Robot Operating System) 是一个机器人领域的开源中间件框架。这句话没错但太抽象了。对于初学者一个更直观的理解是ROS2 是一套“乐高积木”式的开发规范和工具集它定义了机器人软件各个部分感知、决策、控制之间如何“对话”和“协作”。但它的价值远不止于此。我们对比一下 ROS1 和 ROS2 就能看出端倪。很多人知道 ROS2 解决了 ROS1 的实时性、跨平台和安全问题但这背后的深层需求是什么从“实验室原型”到“产品级系统”ROS1 诞生于实验室其核心通信机制基于 TCPROS/UDPROS在单一网络、可控环境下表现良好。但到了工厂、仓库、户外等复杂网络环境其稳定性和实时性就成了短板。ROS2 采用 DDS (Data Distribution Service) 作为底层通信中间件天生支持分布式、强实时、高可靠的通信这是产品化的基石。从“单机思维”到“系统思维”ROS1 严重依赖一个中心节点Master一旦它挂了整个系统就瘫痪了。ROS2 采用了去中心化的发现机制没有单点故障更符合现代分布式系统的设计理念。这意味着你的机器人软件架构可以更健壮容错能力更强。从“功能实现”到“生命周期管理”在 ROS1 里启动、关闭、监控节点更多靠脚本和人工。ROS2 引入了生命周期节点的概念一个节点可以有“未配置”、“非活跃”、“活跃”、“最终化”等状态并能被系统统一管理。这对于需要安全启动、有序关闭、状态监控的复杂机器人如自动驾驶汽车、工业机械臂至关重要。所以当你决定学习 ROS2 时你不仅仅是在学一个新工具更是在接触一套面向未来、面向产品的机器人软件开发范式。这解释了为什么很多新的机器人公司和项目都直接基于 ROS2 启动。那么对于初学者最应该关注 ROS2 的哪些部分我认为是以下三个核心它们构成了理解 ROS2 的骨架计算图Computation Graph这是 ROS2 的运行时逻辑架构。它由节点Node、话题Topic、服务Service、动作Action等实体构成。你必须能在脑子里画出一张图清晰地知道数据从哪里来经过哪些处理到哪里去。通信模型Communication Models重点是理解四种通信方式的区别和选用场景话题Topic单向、异步、一对多/多对多的数据流。适用于持续发布的传感器数据如激光雷达点云、摄像头图像或状态信息。服务Service双向、同步、一对一的请求-响应模型。适用于偶尔触发、需要明确结果的操作如查询传感器参数、计算一个路径。动作Action双向、异步、一对一的长时间任务模型。它本质上是“服务话题”的复合体适合需要反馈、可取消的长时间任务如导航到目标点需要持续反馈位置并可中途取消。参数Parameter动态配置节点行为可在运行时调整。工具链ToolingROS2 的强大一半在于其丰富的命令行和图形化工具。ros2 node list,ros2 topic echo,rqt_graph,rviz2等是你调试和洞察系统的“眼睛”。熟练使用它们比写很多行代码更能快速定位问题。理解了这三点你就拿到了进入 ROS2 世界的钥匙。接下来我们不再空谈概念直接进入实战环境。2. 搭建环境避开第一个“劝退坑”建立可复现的工作空间环境搭建是新手遇到的第一个也是最大的“劝退点”。网上教程很多但往往因为系统版本、网络环境、依赖冲突等问题导致“别人的电脑行我的电脑就不行”。这里的关键不是记住命令而是理解原理并建立一套可复现、可管理的方法。2.1 操作系统与 ROS2 发行版选择ROS2 官方主要支持 Ubuntu。选择一个长期支持LTS版本和与之匹配的 ROS2 发行版是最稳妥的。操作系统推荐 ROS2 发行版特点适合人群Ubuntu 22.04 LTSHumble Hawksbill当前最新的 LTS 发行版支持到 2027 年。软件包丰富社区活跃。绝大多数新学者和项目开发者的首选。Ubuntu 20.04 LTSFoxy Fitzroy上一个 LTS支持到 2025 年。非常稳定生态成熟。维护旧项目或追求极致稳定性的用户。Ubuntu 24.04 LTSJazzy Jalisco未来的 LTS发布时目前是滚动开发版。喜欢尝试最新特性愿意承担一定不稳定风险的开发者。建议无特殊需求一律选择Ubuntu 22.04 ROS2 Humble。这是当前生态和长期支持的最佳平衡点。2.2 安装不止于“复制粘贴命令”官方文档的安装指南很详细但我想强调几个容易被忽略却影响深远的关键点设置软件源除了添加 ROS2 源务必确保 Ubuntu 本身的源main,universe,restricted,multiverse是启用且可用的。很多依赖包来自这些源。安装完整版使用ros-humble-desktop-full进行安装。它包含了 ROS、RQT、RViz、仿真器等几乎所有常用工具和库。虽然体积大但避免了后续因缺少某个功能包而反复查找安装的麻烦。环境变量固化安装后source /opt/ros/humble/setup.bash命令只是临时生效。你必须将其写入~/.bashrc文件末尾这样每次打开新终端都会自动配置好环境。echo source /opt/ros/humble/setup.bash ~/.bashrc source ~/.bashrc验证安装不要只运行ros2 --help。运行一个简单的 Demo如小海龟仿真器来验证整个图形界面和通信链路是否正常。# 终端1启动仿真器 ros2 run turtlesim turtlesim_node # 终端2启动控制节点 ros2 run turtlesim turtle_teleop_key如果能用方向键控制乌龟移动说明基础安装成功。2.3 工作空间Workspace管理项目独立的基石这是区分“随便玩玩”和“正经开发”的重要一步。永远不要在系统目录或家目录下直接写代码。必须使用工作空间。ROS2 使用Colcon作为构建工具。一个标准的工作空间结构如下my_robot_ws/ # 工作空间根目录 src/ # 源代码目录存放你的功能包 my_package/ # 你的功能包 package.xml setup.py # 或 CMakeLists.txt (Python/C) ... build/ # 编译中间文件Colcon 自动生成 install/ # 安装目录Colcon 自动生成 log/ # 编译日志Colcon 自动生成创建和编译工作空间的标准化流程# 1. 创建工作空间目录 mkdir -p ~/my_robot_ws/src cd ~/my_robot_ws # 2. 拉取已有的功能包源码到 src (示例拉取官方教程包) git clone -b humble https://github.com/ros/ros_tutorials.git src/ros_tutorials # 3. 解决依赖非常重要 sudo apt update rosdep update rosdep install -i --from-path src --rosdistro humble -y # 4. 编译整个工作空间 colcon build # 或者使用 symlink 安装模式便于开发调试 # colcon build --symlink-install # 5. 激活当前工作空间的环境 source install/setup.bash # 同样可以将此命令写入 ~/.bashrc但注意顺序工作空间的 source 要在系统 ROS 的 source 之后。为什么必须这么做隔离性每个项目独立的工作空间避免了包版本和依赖的冲突。可复现性你可以将src/目录下的代码用 Git 管理其他人拉取后执行rosdep install和colcon build就能复现完全相同的环境。工程化这是迈向团队协作和持续集成CI的第一步。环境搭建好工作空间建起来你就有了一个稳固的“作战基地”。接下来我们在这个基地里创建第一个真正属于自己的机器人软件模块。3. 从“Hello World”到“会说话的节点”理解通信的本质很多教程的第一个例子是写一个发布“Hello World”的节点。这没错但我想带你走得更深一点我们不止要实现功能更要理解在这个功能背后ROS2 是如何工作的。3.1 创建你的第一个功能包Package功能包是 ROS2 中代码组织的基本单元。我们创建一个 Python 的功能包。cd ~/my_robot_ws/src ros2 pkg create my_first_robot_pkg --build-type ament_python --dependencies rclpy std_msgs--build-type ament_python指定使用 Python 和ament构建系统。--dependencies rclpy std_msgs声明依赖。rclpy是 ROS2 的 Python 客户端库std_msgs包含了标准消息类型如 String。创建后目录结构如下my_first_robot_pkg/ package.xml # 包的定义和依赖声明 setup.py # Python 包的安装脚本 setup.cfg my_first_robot_pkg/ __init__.py test/3.2 编写一个“发布-订阅”对话我们不满足于单向的“Hello World”。我们来创建两个节点一个“说话者”Publisher和一个“倾听者”Subscriber让它们通过一个话题Topic进行对话。1. 编写说话者节点 (talker.py)在my_first_robot_pkg/my_first_robot_pkg/目录下创建talker.py。#!/usr/bin/env python3 import rclpy from rclpy.node import Node from std_msgs.msg import String import time class TalkerNode(Node): def __init__(self): super().__init__(talker_node) # 节点名 # 创建一个发布者发布到 conversation 话题消息类型为 String队列长度10 self.publisher_ self.create_publisher(String, conversation, 10) # 创建一个定时器每1秒触发一次 timer_callback self.timer self.create_timer(1.0, self.timer_callback) self.counter 0 self.get_logger().info(说话者节点已启动正在等待倾听者...) def timer_callback(self): msg String() msg.data f你好这是第 {self.counter} 条消息。时间: {time.strftime(%H:%M:%S)} self.publisher_.publish(msg) self.get_logger().info(f发送: {msg.data}) self.counter 1 def main(argsNone): rclpy.init(argsargs) # 初始化 ROS2 Python 客户端库 node TalkerNode() # 创建节点实例 try: rclpy.spin(node) # 保持节点运行等待回调 except KeyboardInterrupt: node.get_logger().info(收到中断信号关闭节点。) finally: node.destroy_node() # 销毁节点 rclpy.shutdown() # 关闭 ROS2 Python 客户端库 if __name__ __main__: main()2. 编写倾听者节点 (listener.py)在同一目录下创建listener.py。#!/usr/bin/env python3 import rclpy from rclpy.node import Node from std_msgs.msg import String class ListenerNode(Node): def __init__(self): super().__init__(listener_node) # 创建一个订阅者订阅 conversation 话题收到消息后调用 listener_callback self.subscription self.create_subscription( String, conversation, self.listener_callback, 10) # 队列长度 self.get_logger().info(倾听者节点已启动正在等待消息...) def listener_callback(self, msg): # 当收到消息时此函数被调用 self.get_logger().info(f收到: {msg.data}) def main(argsNone): rclpy.init(argsargs) node ListenerNode() rclpy.spin(node) node.destroy_node() rclpy.shutdown() if __name__ __main__: main()3. 修改setup.py以注册可执行脚本找到setup.py文件中的entry_points部分修改如下entry_points{ console_scripts: [ talker my_first_robot_pkg.talker:main, listener my_first_robot_pkg.listener:main, ], },4. 编译并运行cd ~/my_robot_ws colcon build --packages-select my_first_robot_pkg source install/setup.bash现在打开两个终端终端1ros2 run my_first_robot_pkg talker终端2ros2 run my_first_robot_pkg listener你将看到说话者每秒发布一条消息倾听者实时接收并打印出来。3.3 用工具“看见”通信理解计算图程序跑起来了但它是怎么工作的我们使用 ROS2 的工具来“可视化”这个过程。查看节点和话题# 查看所有活跃节点 ros2 node list # 查看所有活跃话题 ros2 topic list # 查看某个话题上的实时数据流 ros2 topic echo /conversation可视化计算图rqt_graph你会看到一个图形界面清晰地显示talker_node和listener_node通过/conversation这个话题连接在一起。这就是 ROS2 计算图的直观体现。到这里你完成了什么你不仅仅写了一个简单的发布订阅程序。你实践了 ROS2 开发的核心循环定义接口我们使用了标准的String消息类型。在复杂项目中你需要自定义.msg文件来定义数据结构。实现节点创建了独立的、功能单一的节点。配置构建系统通过setup.py告诉系统如何安装和运行你的节点。使用工具调试用命令行和rqt_graph验证了通信链路。这个简单的“对话”模型是机器人所有复杂功能的基础。传感器数据发布、控制指令订阅、算法中间结果传递本质上都是这种模式的延伸和组合。4. 迈向真实机器人仿真、感知与控制的初级实践掌握了基本的通信我们就可以尝试一些更接近真实机器人的任务了。直接从实体机器人开始成本高、风险大仿真是最佳的学习和验证平台。我们将使用Gazebo强大的物理仿真器和RViz2ROS 可视化工具来构建一个简单的移动机器人仿真环境并实现基础的控制。4.1 搭建一个差分驱动机器人仿真模型我们不会从零建模而是利用 ROS 社区丰富的资源。一个常用的机器人模型是TurtleBot3它有详细的文档和仿真包。安装 TurtleBot3 仿真包cd ~/my_robot_ws/src git clone -b humble https://github.com/ROBOTIS-GIT/turtlebot3_simulations.git cd ~/my_robot_ws rosdep install -i --from-path src --rosdistro humble -y colcon build --packages-select turtlebot3_gazebo source install/setup.bash启动空世界和机器人export TURTLEBOT3_MODELburger # 设置机器人型号为 burger ros2 launch turtlebot3_gazebo empty_world.launch.py这会启动 Gazebo加载一个空世界并在中间放置一个 TurtleBot3 Burger 机器人。用键盘控制机器人移动 新开一个终端source install/setup.bash export TURTLEBOT3_MODELburger ros2 run turtlebot3_teleop teleop_keyboard按照终端提示通常是WASD或方向键你就可以控制仿真机器人前后左右移动了。观察 Gazebo 中的机器人如何响应。4.2 理解机器人背后的数据流控制指令是如何变成轮子转动的我们用rqt_graph再看一下。rqt_graph你会看到一张复杂的图。聚焦几个关键节点和话题/teleop_turtle键盘控制节点发布geometry_msgs/msg/Twist消息到/cmd_vel话题。这个消息包含线速度和角速度。/turtlebot3_diff_drive差分驱动控制器节点订阅/cmd_vel将其转换为左右轮子的目标速度并通过 Gazebo 插件控制仿真模型中的关节。/gazeboGazebo 主节点提供物理仿真。/robot_state_publisher发布机器人各个连杆link和关节joint之间的变换关系TF这是 RViz 正确显示机器人的关键。关键认知在 ROS 中/cmd_vel是一个标准话题几乎所有移动机器人无论是仿真还是实体都通过订阅这个消息来控制运动。你写的任何导航、避障算法最终输出通常都是一个Twist消息发布到/cmd_vel。4.3 用 RViz2 “看见”机器人的世界Gazebo 是“世界本身”而 RViz2 是“机器人的眼睛和大脑的可视化界面”。它订阅各种话题如传感器数据、TF、地图并以图形方式呈现。启动 RViz2source install/setup.bash export TURTLEBOT3_MODELburger ros2 launch turtlebot3_bringup rviz2.launch.py添加显示项在 RViz2 左侧的Displays面板点击Add。添加TF你会看到机器人坐标系的层级结构。添加RobotModel你会看到机器人的 3D 模型需要正确的 TF 数据。如果仿真中机器人有激光雷达如 TurtleBot3 Burger你可以添加LaserScan话题看到周围的障碍物信息。此时你有了一个完整的闭环Gazebo 模拟物理世界和传感器你的控制指令通过 ROS2 话题传递驱动仿真机器人而 RViz2 则让你能以机器人的视角或上帝视角观察这个过程。4.4 尝试一个简单的自主行为随机漫步让我们写一个简单的 Python 节点让机器人自己“随机漫步”避开前方的障碍物假设它有激光雷达。创建一个新的功能包cd ~/my_robot_ws/src ros2 pkg create my_random_walk --build-type ament_python --dependencies rclpy geometry_msgs sensor_msgs编写随机漫步节点(random_walk.py)#!/usr/bin/env python3 import rclpy from rclpy.node import Node from geometry_msgs.msg import Twist from sensor_msgs.msg import LaserScan import random class RandomWalkNode(Node): def __init__(self): super().__init__(random_walk_node) # 发布速度指令 self.cmd_vel_pub self.create_publisher(Twist, /cmd_vel, 10) # 订阅激光雷达数据 self.scan_sub self.create_subscription( LaserScan, /scan, # TurtleBot3 激光雷达话题 self.scan_callback, 10) self.twist_msg Twist() self.obstacle_detected False self.get_logger().info(随机漫步节点启动) def scan_callback(self, msg): # 简单逻辑检查正前方一定范围内的测距值 front_range msg.ranges[len(msg.ranges)//2] # 如果距离小于 0.5 米认为有障碍物 if front_range 0.5: self.obstacle_detected True self.get_logger().warn(f前方障碍物距离: {front_range:.2f}米) else: self.obstacle_detected False def run(self): # 创建一个定时器来持续发布控制指令 self.timer self.create_timer(0.1, self.timer_callback) def timer_callback(self): if self.obstacle_detected: # 有障碍物转向 self.twist_msg.linear.x 0.0 self.twist_msg.angular.z 0.5 # 顺时针旋转 else: # 无障碍物直行或轻微随机转向 self.twist_msg.linear.x 0.2 self.twist_msg.angular.z random.uniform(-0.2, 0.2) self.cmd_vel_pub.publish(self.twist_msg) def main(argsNone): rclpy.init(argsargs) node RandomWalkNode() node.run() try: rclpy.spin(node) except KeyboardInterrupt: node.get_logger().info(节点关闭。) finally: node.destroy_node() rclpy.shutdown() if __name__ __main__: main()编译运行确保setup.py中注册了random_walk入口点。编译包colcon build --packages-select my_random_walk启动仿真环境如前所述。新终端运行节点ros2 run my_random_walk random_walk你会看到机器人在 Gazebo 的空世界中移动当靠近墙壁时它会自动转向。虽然逻辑极其简单但它完整演示了“感知激光雷达-决策Python 节点-控制发布 /cmd_vel”的经典机器人控制回路。通过这个实践你已将 ROS2 的知识用于解决一个具体的机器人行为问题。接下来我们需要思考如何让这样的代码变得更健壮、更易维护也就是走向工程化。5. 从脚本到工程ROS2 开发中的进阶模式与最佳实践当你能够实现基本功能后下一个瓶颈往往不是 ROS2 本身而是如何组织代码、管理配置、处理异常、调试复杂系统。这一章我们探讨如何让 ROS2 项目更像一个“工程”而不仅仅是一堆脚本。5.1 使用 Launch 文件组织复杂系统之前我们启动节点都是开多个终端手动ros2 run。对于包含多个节点的系统这非常低效。Launch 文件用于描述和启动一组节点及其配置。创建一个launch/目录和my_robot.launch.py文件from launch import LaunchDescription from launch_ros.actions import Node def generate_launch_description(): return LaunchDescription([ Node( packagemy_random_walk, executablerandom_walk, namerandom_walk_node, outputscreen, # 将日志输出到屏幕 parameters[{some_parameter: 0.5}] # 可以传递参数 ), # 可以在这里添加更多节点如传感器驱动、地图服务器等 # Node( # packageturtlebot3_gazebo, # executableturtlebot3_gazebo, # namegazebo, # arguments[-world, empty.world] # ), ])运行ros2 launch my_random_walk my_robot.launch.py。Launch 文件可以嵌套、包含、传递参数、设置命名空间是管理复杂应用的核心。5.2 参数管理与配置硬编码在代码里的常量如障碍物距离阈值0.5是坏味道。ROS2 提供了强大的参数机制。在节点中声明参数# 在节点的 __init__ 方法中 self.declare_parameter(obstacle_threshold, 0.5) # 声明参数默认值0.5 self.threshold self.get_parameter(obstacle_threshold).value # 获取参数值通过 Launch 文件或命令行传递参数ros2 run my_random_walk random_walk --ros-args -p obstacle_threshold:0.3或者在 launch 文件中使用parameters字典。动态重配置对于某些参数ROS2 支持在节点运行时通过rqt_reconfigure图形界面动态修改这对于调试和调优非常方便。5.3 日志与诊断self.get_logger().info(‘…’)是最基本的日志。在生产中你需要更细致的日志等级DEBUG, INFO, WARN, ERROR, FATAL和记录到文件的能力。同时了解并使用ROS2 的诊断框架来监控节点状态如发布频率、处理延迟是构建可靠系统的关键。5.4 自定义消息与服务当标准消息类型不够用时你需要自定义。创建msg和srv目录在功能包下创建msg/和srv/目录。定义消息/服务文件例如msg/MyCustom.msg(内容如string nameint32 idfloat32[] data)。修改package.xml和CMakeLists.txt/setup.py添加对rosidl_default_generators的依赖和构建配置。在代码中使用from my_package.msg import MyCustom。5.5 测试单元测试与集成测试ROS2 基于ament构建系统天然支持测试。编写 Python 单元测试使用unittest框架测试你的核心算法函数。编写 ROS2 节点测试使用launch_testing框架可以启动节点发送模拟消息并断言节点的响应和行为。将测试纳入开发流程是保证代码质量、防止回归错误的最有效手段。5.6 性能考量与工具ros2 topic hz /topic_name测量话题发布频率。ros2 topic delay /topic_name测量消息延迟。ros2 run system_metrics_collector ...收集系统资源使用情况。选择合适的 QoS服务质量策略ROS2 的 DDS 支持丰富的 QoS 策略如可靠性Reliable vs Best Effort、持久性Transient Local、历史深度等。对于传感器数据可能用Best Effort追求低延迟对于关键指令必须用Reliable。遵循这些实践你的 ROS2 项目将从一个脆弱的原型进化为一个结构清晰、配置灵活、可测试、可监控的软件系统。这为你接手或发起真实的机器人项目打下了坚实的基础。6. 下一步如何规划你的 ROS2 学习与实践路径学完以上内容你已经跨越了从“完全陌生”到“能够使用 ROS2 搭建和运行动态仿真机器人系统”的门槛。但这只是开始。要真正精通你需要一个有方向的持续学习路径。深化核心概念重新精读 ROS2 官方概念文档 理解节点、生命周期、执行器Executor、中间件RMW等底层机制。掌握关键中间件与工具导航2 (Nav2)这是 ROS2 中实现机器人自主移动定位、建图、路径规划的“瑞士军刀”。尝试用 Nav2 让 TurtleBot3 在 Gazebo 的迷宫世界里自主导航。MoveIt 2如果你对机械臂感兴趣MoveIt 2 是运动规划和操控的事实标准。学习用它控制一个仿真机械臂完成抓取任务。TF2深刻理解坐标系变换。这是机器人感知、定位、控制的基础也是新手最容易混淆的地方之一。URDF/SDF学习如何用 XML 文件描述你的机器人模型连杆、关节、传感器、外观。参与真实项目或竞赛开源项目在 GitHub 上寻找基于 ROS2 的开源机器人项目如 Autoware.Auto, ROS2 Navigation, 各种机器人仿真环境阅读代码尝试贡献。竞赛平台参加像RoboMaster、DJI RoboMaster或各类学术机器人竞赛在高压下解决实际问题。个人项目买一个树莓派和一台 TurtleBot3 或类似的小车实体将仿真环境中的算法部署到真机上。真机上的传感器噪声、通信延迟、电机控制是完全不同的挑战。学习相关的机器人学理论ROS2 是工具机器人学是内功。并行学习运动学与动力学机器人如何运动。感知计算机视觉、激光 SLAM、多传感器融合。规划与控制路径规划、轨迹优化、反馈控制。状态估计卡尔曼滤波、粒子滤波。关注社区与生态关注 ROS Discourse 论坛、ROS Answers、GitHub 上的核心仓库。了解 ROS 2 的路线图和新特性如ros2 launch的改进、新客户端库等。学习 ROS2 和机器人开发是一个典型的“实践-理论-再实践”的螺旋上升过程。不要指望看完一个教程就能成为专家。真正的能力来源于你用它解决了多少个具体的问题调试通过了多少个令人抓狂的 Bug以及成功地将多少个仿真算法部署到了真实的、充满不确定性的物理世界中。从这个角度看你今天的起点不是安装好了 ROS2而是你拥有了一个可以无限次试错、低成本探索的仿真世界和一套将想法转化为机器人行为的强大工具链。接下来要做的就是带着明确的问题和目标走进去开始建造。