ROS2零基础入门:从环境搭建到三种通信机制实战

ROS2零基础入门:从环境搭建到三种通信机制实战 在机器人开发领域ROS 早已不是新鲜词。过去几年ROS1 在学术研究和原型验证中占据绝对主流但到了真实产品落地阶段它的通信实时性、多机协同、安全机制等短板越来越明显。ROS2 正是在这种背景下开始逐步取代 ROS1成为新项目、新课程、新工具链的首选。不过对于零基础读者来说ROS2 的上手门槛并不低环境安装涉及大量系统依赖工作空间和功能包概念又和传统软件开发不一样话题、服务、动作三种通信方式也容易混淆。这篇文章会围绕 ROS2 零基础入门最常见的几个环节展开从环境搭建开始到创建工作空间和功能包再通过可运行的代码案例把话题通信、服务通信、动作通信全部串起来。无论你是刚接触机器人的学生还是准备转行机器人开发的工程师都可以按照本文步骤从零跑通。最终你会理解 ROS2 的节点如何组织、消息如何在节点之间传递并且能独立创建自己的功能包。1. 为什么选择 ROS21.1 ROS2 与 ROS1 的本质区别ROS1 的通信架构依赖一个 Master 节点来管理所有节点之间的连接。如果 Master 挂了整个系统就会失去协调能力。这一点在实验室单机场景下问题不大但一旦进入多机器人协作、车间部署、车机环境稳定性就会成为致命伤。ROS2 则去掉了中心化 Master底层通信改为 DDSData Distribution Service标准。DDS 是一种工业级的数据分发中间件支持实时通信、自动发现、QoS 控制节点之间可以直接发现对方不需要中心节点转达。简单说ROS2 把“通信可靠性”从上层应用下沉到了通信中间件层这让整个系统更适合真实机器人项目。另一个重要变化是 ROS2 支持 Python、C 双语言平等开发。ROS1 对 Python 的支持虽然也存在但很多核心工具链和通信接口对 C 更友好。ROS2 中 Python 节点和 C 节点可以混用通信完全透明这对新手非常友好。1.2 本文学习目标与适合人群本文适合以下三类读者没有 ROS 基础但会一点 Python想快速入门 ROS2 的初学者。用过 ROS1想看 ROS2 环境、工作空间、功能包和通信方式有哪些变化的老开发者。已经安装过 ROS2但对话题、服务、动作三种通信机制理解不深想通过代码加深理解的同学。读完这篇文章后你应该能独立完成以下事情在 Ubuntu 上安装 ROS2 Humble。创建自己的工作空间和功能包。用 Python 写出话题发布者、订阅者。用 Python 写出服务端、客户端。用 Python 实现动作通信的 server 与 client。掌握 ROS2 常用调试命令。文章示例基于 Python因为 Python 的代码结构更适合讲清楚通信原理。掌握概念后转写 C 会容易很多。2. ROS2 环境搭建2.1 版本选择ROS2 Humble 还是别的ROS2 的发行版本很多常见的有 Foxy、Galactic、Humble、Iron、Jazzy。对零基础学习者最推荐的是ROS2 Humble Hawksbill因为 Humble 是长期支持版本支持周期较长社区资料多网上遇到的坑基本都能搜到解决方案。需要特别注意ROS2 每个版本对应的 Ubuntu 版本是固定的。Humble 官方推荐 Ubuntu 22.04Jammy。如果你的系统是 Ubuntu 20.04则需要安装 Foxy如果是 Ubuntu 24.04则对应 Jazzy。版本不匹配会出现大量依赖冲突这是新手最容易踩的坑。本文以 Ubuntu 22.04 ROS2 Humble 为例。如果你的环境不同安装步骤中的 apt 源、包名需要对应调整。2.2 Ubuntu 22.04 下安装 ROS2 Humble在安装开始之前建议先更新系统软件源和软件包索引sudo apt update sudo apt upgrade -yROS2 官方安装方式是把安装源添加到 apt 中然后通过 apt 安装。首先安装基础工具sudo apt install curl gnupg lsb-release -y接着导入 ROS2 的 GPG 公钥sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg然后添加 ROS2 apt 源。这里使用系统自动识别的 Ubuntu 版本代号不需要手动填echo deb [arch$(dpkg --print-architecture) signed-by/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(source /etc/os-release echo $UBUNTU_CODENAME) main | sudo tee /etc/apt/sources.list.d/ros2.list /dev/null再次更新 apt 索引sudo apt update接下来安装桌面版 ROS2。桌面版包含了常用的 rviz2、demo 程序、示例等功能学习和调试非常方便sudo apt install ros-humble-desktop python3-argcomplete -y安装过程比较长取决于网络速度。安装完成后可以安装 colcon 构建工具。colcon 是 ROS2 官方推荐的编译工具相当于 ROS1 中的 catkinsudo apt install python3-colcon-common-extensions -y这里解释一下为什么要用 colcon工作空间中有多个功能包时colcon 可以批量编译并且会生成build、install、log目录方便管理。2.3 配置环境变量与验证安装ROS2 安装完成后还需要在每次打开终端时加载环境变量。你可以手动输入source /opt/ros/humble/setup.bash为了避免每个新终端都要手动 source建议写入~/.bashrcecho source /opt/ros/humble/setup.bash ~/.bashrc source ~/.bashrc验证是否安装成功ros2 --help如果能看到命令帮助说明 ROS2 已经安装成功。更直观的验证方式是运行小海龟程序sudo apt install ros-humble-turtlesim -y打开第一个终端启动海龟仿真器ros2 run turtlesim turtlesim_node打开第二个终端启动键盘控制节点ros2 run turtlesim turtle_teleop_key此时应该能看到一只小海龟出现在窗口里按方向键可以控制它移动。这是一个非常经典的 ROS2 运行验证方式虽然简单但它已经用到了“节点”和“话题”的概念后面会详细解释。如果你的终端提示找不到ros2命令优先检查环境变量是否加载成功执行echo $ROS_DISTRO如果输出为空或错误则说明 source 没有生效。2.4 Windows 用户WSL2 环境说明如果你使用的是 Windows 系统最稳妥的方法不是原生安装 ROS2而是通过 WSL2 安装 Ubuntu 22.04。在 Windows 中安装 WSL2 后在 Ubuntu 子系统内部按照上面的步骤安装 ROS2 Humble。WSL2 下 ROS2 的图形界面工具如 rviz2、turtlesim需要 WSLg 支持较新的 Windows 10/11 版本默认自带。如果你在使用过程中看不到图形窗口可以先更新 WSL 内核或者检查 Windows 版本是否满足要求。另外在 WSL2 中运行硬件相关的机器人驱动可能会遇到 USB 设备透传问题这一点在实际项目阶段需要单独处理。对于学习通信机制和写功能包来说WSL2 已经足够。3. 工作空间与功能包3.1 工作空间目录结构在 ROS2 中工作空间是一个存放所有功能包的顶层目录。通常命名为ros2_ws。一个标准工作空间包含 4 个子目录src存放功能包源码。build编译过程中生成的中间文件。install编译完成后的安装文件和环境变量。log编译和运行日志。创建标准工作空间mkdir -p ~/ros2_ws/src cd ~/ros2_ws colcon build编译完成后工作空间中会自动生成build、install、log目录。记住一个原则不要把源码直接放在build或install中所有功能包都放在src下源码和编译产物分离便于管理和清理。3.2 创建第一个功能包功能包是 ROS2 代码复用和发布的基本单元。一个功能包可以包含节点源码、配置文件、launch 文件、消息接口等。创建功能包时需要先进入工作空间的src目录cd ~/ros2_ws/src ros2 pkg create my_pkg --build-type ament_python --dependencies rclpy std_msgs解释一下参数my_pkg功能包名称。--build-type ament_python指定 Python 构建类型。--dependencies rclpy std_msgs声明依赖的库。rclpy是 ROS2 的 Python 客户端库std_msgs包含常见的标准消息类型。创建完成后my_pkg目录结构大致如下my_pkg ├── package.xml ├── resource ├── setup.cfg ├── setup.py ├── test └── my_pkg └── __init__.py其中my_pkg/my_pkg是实际的 Python 包目录后续编写的节点代码都放在这里。setup.py负责声明可执行程序的入口package.xml负责声明依赖信息。3.3 编译与 source功能包代码写完后需要回到工作空间根目录编译cd ~/ros2_ws colcon build编译成功后需要 source 当前工作空间的 setup 文件这样才能让终端找到新功能包里的可执行程序source install/setup.bash建议把这条命令也写入~/.bashrc这样每次打开新终端都能自动加载echo source ~/ros2_ws/install/setup.bash ~/.bashrc这里需要提醒新手每次修改功能包代码后都要重新执行colcon build才能让改动生效否则ros2 run运行的还是旧版本代码。4. 通信机制节点、话题、服务、动作4.1 核心概念速览在 ROS2 中一个独立运行的程序被称为“节点”。节点之间通过不同的通信机制交换数据。最常用的有三种话题通信节点持续发布或订阅数据适合传感器数据、状态信息等高频单向数据流。服务通信客户端发起请求服务端返回响应适合一次性调用比如请求某个位置的坐标。动作通信客户端发起目标服务端持续返回反馈最终返回结果适合执行时间长、需要取消的任务。简单理解话题是“广播”服务是“问答”动作是“交办任务并持续汇报进度”。4.2 通信机制怎么选实际项目里三种通信方式经常会混用。话题用于高频、单向、无需应答的数据。例如激光雷达扫描数据、摄像头图像、机器人当前速度都会用话题发布。服务用于一次性的请求-响应。例如打开机械臂的夹爪、校准陀螺仪、查询当前地图名称这类操作不需要持续反馈服务就够用了。动作用于需要多次反馈的长时间任务。例如让机器人导航到某个目标点、让机械臂执行一段复杂轨迹这类任务可能执行几十秒甚至几分钟需要实时反馈进度并且允许中途取消这时候就必须使用动作通信。4.3 rqt_graph 可视化理解可以用一个可视化工具 rqt_graph 查看节点和话题的连接关系。安装sudo apt install ros-humble-rqt-graph -y启动 turtlesim 并让小海龟运动后打开新终端运行rqt_graph你会看到两个节点和一个话题连接线。话题的名字和连接方向都一目了然这对排查通信问题非常有帮助。以后如果发现节点之间收不到数据第一步就应该打开 rqt_graph 看连接是否存在。5. 话题通信实战5.1 发布者节点实现话题通信中发布者负责把数据发送到指定话题订阅者负责从同一话题接收数据。现在我们在my_pkg中创建一个发布者节点。文件路径为~/ros2_ws/src/my_pkg/my_pkg/publisher_node.py代码如下# 文件路径~/ros2_ws/src/my_pkg/my_pkg/publisher_node.py import rclpy from rclpy.node import Node from std_msgs.msg import String class SimplePublisher(Node): def __init__(self): super().__init__(simple_publisher) self.publisher_ self.create_publisher(String, chatter, 10) self.timer self.create_timer(0.5, self.timer_callback) self.count 0 def timer_callback(self): msg String() msg.data fHello ROS2: {self.count} self.publisher_.publish(msg) self.get_logger().info(fPublishing: {msg.data}) self.count 1 def main(argsNone): rclpy.init(argsargs) node SimplePublisher() rclpy.spin(node) node.destroy_node() rclpy.shutdown() if __name__ __main__: main()这段代码的核心逻辑是继承Node并将节点命名为simple_publisher。通过create_publisher创建发布者消息类型为String话题名为chatter队列长度为 10。通过create_timer创建一个 0.5 秒触发一次的定时器。每次定时器触发就发布一条字符串消息并打印日志。最后那个if __name__ __main__:是为了让这个文件也能被命令行直接执行。不过 ROS2 的推荐方式是使用setup.py配置入口然后通过ros2 run启动。5.2 订阅者节点实现发布者写完再写一个订阅者节点文件路径为~/ros2_ws/src/my_pkg/my_pkg/subscriber_node.py代码如下# 文件路径~/ros2_ws/src/my_pkg/my_pkg/subscriber_node.py import rclpy from rclpy.node import Node from std_msgs.msg import String class SimpleSubscriber(Node): def __init__(self): super().__init__(simple_subscriber) self.subscription self.create_subscription( String, chatter, self.listener_callback, 10 ) def listener_callback(self, msg): self.get_logger().info(fI heard: {msg.data}) def main(argsNone): rclpy.init(argsargs) node SimpleSubscriber() rclpy.spin(node) node.destroy_node() rclpy.shutdown() if __name__ __main__: main()订阅者的关键点是回调函数listener_callback只要话题上来了新消息这个回调函数就会被自动执行。注意create_subscription需要指定消息类型、话题名、回调函数和 QoS 队列长度。这里有一个新手容易搞混的地方不要在主线程里反复手动读取话题数据ROS2 是事件驱动模型收到消息后回调函数会先执行所以只需要等待rclpy.spin(node)把程序阻塞住不断处理回调即可。5.3 配置入口并编译运行为了让ros2 run能找到这两个节点需要在setup.py中配置入口。编辑文件~/ros2_ws/src/my_pkg/setup.py在entry_points中添加entry_points{ console_scripts: [ simple_publisher my_pkg.publisher_node:main, simple_subscriber my_pkg.subscriber_node:main, ], },回到工作空间根目录编译cd ~/ros2_ws colcon build source install/setup.bash打开两个终端。终端 1 运行订阅者终端 2 运行发布者ros2 run my_pkg simple_subscriberros2 run my_pkg simple_publisher终端 1 中应该能看到发布者发来的每一条消息例如[INFO] I heard: Hello ROS2: 0 [INFO] I heard: Hello ROS2: 1话题通信已经跑通了。5.4 使用 CLI 工具验证话题除了写代码ROS2 提供了一系列命令行工具排查问题非常方便。查看当前话题列表ros2 topic list查看某个话题的消息类型ros2 topic info /chatter实时监听话题中的数据ros2 topic echo /chatter手动向话题发布数据ros2 topic pub /chatter std_msgs/msg/String {data: Hello CLI} --once这些命令是话题调试的利器。尤其当你写了一个复杂系统却收不到数据时先用 CLI 工具确认话题是否存在、消息是否真正发布可以快速缩小问题范围。6. 服务通信实战6.1 服务通信接口介绍服务通信使用客户端-服务端模式。客户端发送请求服务端处理请求并返回响应。ROS2 中服务的接口文件后缀为.srv格式分成上下两部分中间用---分隔上半部分是请求下半部分是响应。本文使用example_interfaces/srv/AddTwoInts.srv这是一个内置的示例服务接口内容等价于int64 a int64 b --- int64 sum也就是说客户端传入两个整数a和b服务端返回它们的和sum。6.2 服务端节点实现在my_pkg中创建服务端节点文件路径为~/ros2_ws/src/my_pkg/my_pkg/service_server_node.py代码如下# 文件路径~/ros2_ws/src/my_pkg/my_pkg/service_server_node.py import rclpy from rclpy.node import Node from example_interfaces.srv import AddTwoInts class AddTwoIntsService(Node): def __init__(self): super().__init__(add_two_ints_service) self.srv self.create_service(AddTwoInts, add_two_ints, self.add_two_ints_callback) def add_two_ints_callback(self, request, response): response.sum request.a request.b self.get_logger().info( fReceived: {request.a} {request.b} {response.sum} ) return response def main(argsNone): rclpy.init(argsargs) node AddTwoIntsService() rclpy.spin(node) node.destroy_node() rclpy.shutdown() if __name__ __main__: main()这里最需要注意的是回调函数的写法request和response都由框架自动创建回调返回的是填充后的response。这个返回值会被自动发送给客户端不需要手动处理网络传输。6.3 客户端节点实现客户端节点比服务端稍复杂一点因为它需要等待服务上线并通过异步方式发送请求。文件路径为~/ros2_ws/src/my_pkg/my_pkg/service_client_node.py代码如下# 文件路径~/ros2_ws/src/my_pkg/my_pkg/service_client_node.py import rclpy from rclpy.node import Node from example_interfaces.srv import AddTwoInts class AddTwoIntsClient(Node): def __init__(self): super().__init__(add_two_ints_client) self.cli self.create_client(AddTwoInts, add_two_ints) while not self.cli.wait_for_service(timeout_sec1.0): self.get_logger().info(Service not available, waiting...) self.req AddTwoInts.Request() def send_request(self, a, b): self.req.a a self.req.b b future self.cli.call_async(self.req) rclpy.spin_until_future_complete(self, future) return future.result() def main(argsNone): rclpy.init(argsargs) node AddTwoIntsClient() response node.send_request(5, 3) node.get_logger().info(fService result: {response.sum}) node.destroy_node() rclpy.shutdown() if __name__ __main__: main()服务端启动后客户端会先循环等待服务可用避免出现“服务没起来请求直接失败”的情况。call_async是异步调用它会立即返回一个 future后续通过rclpy.spin_until_future_complete阻塞直到拿到结果。6.4 运行验证在setup.py的entry_points中加入服务端和客户端入口add_two_ints_server my_pkg.service_server_node:main, add_two_ints_client my_pkg.service_client_node:main,重新编译cd ~/ros2_ws colcon build source install/setup.bash先启动服务端ros2 run my_pkg add_two_ints_server然后启动客户端ros2 run my_pkg add_two_ints_client客户端会打印结果[INFO] Service result: 8服务端终端中也会收到一条日志。这说明服务通信成功。也可以用命令行直接请求服务不需要写客户端代码。新开终端执行ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts {a: 10, b: 20}这个命令非常适合测试服务端是否正常。7. 动作通信实战7.1 动作通信接口与适用场景动作通信是最接近真实机器人任务的一种交互方式。它包含目标、反馈、结果三部分客户端下发目标服务端在执行过程中不断发布反馈最后返回结果。整个过程还支持取消任务。本文使用example_interfaces/action/Fibonacci.action。这个接口内容等价于int32 order --- int32[] sequence --- int32[] partial_sequence目标是计算斐波那契数列的前order项服务端在计算过程中不断反馈已经算出的部分序列最后返回完整结果。在实际项目中动作通信常用于导航、机械臂规划这类长时间任务。7.2 动作服务端节点实现在my_pkg中创建动作服务端节点文件路径为~/ros2_ws/src/my_pkg/my_pkg/action_server_node.py代码如下# 文件路径~/ros2_ws/src/my_pkg/my_pkg/action_server_node.py import rclpy import rclpy.action from rclpy.node import Node from example_interfaces.action import Fibonacci class FibonacciActionServer(Node): def __init__(self): super().__init__(fibonacci_action_server) self._action_server rclpy.action.create_server( self, Fibonacci, fibonacci, self.execute_callback ) def execute_callback(self, goal_handle): self.get_logger().info(Executing goal...) feedback_msg Fibonacci.Feedback() feedback_msg.partial_sequence [0, 1] for i in range(1, goal_handle.request.order): feedback_msg.partial_sequence.append( feedback_msg.partial_sequence[i] feedback_msg.partial_sequence[i - 1] ) goal_handle.publish_feedback(feedback_msg) goal_handle.succeed() result Fibonacci.Result() result.sequence feedback_msg.partial_sequence return result def main(argsNone): rclpy.init(argsargs) node FibonacciActionServer() rclpy.spin(node) node.destroy_node() rclpy.shutdown() if __name__ __main__: main()动作服务端的核心是execute_callback。这个回调函数接收一个goal_handle通过它可以发布反馈、标记目标成功或失败。在长时间任务中建议在循环里周期性调用publish_feedback这样客户端才能实时看到进度。7.3 动作客户端节点实现动作客户端在发送目标之后需要等待服务端接受目标同时接收反馈最后等待最终结果。文件路径为~/ros2_ws/src/my_pkg/my_pkg/action_client_node.py代码如下# 文件路径~/ros2_ws/src/my_pkg/my_pkg/action_client_node.py import rclpy import rclpy.action from rclpy.node import Node from example_interfaces.action import Fibonacci class FibonacciActionClient(Node): def __init__(self): super().__init__(fibonacci_action_client) self._action_client rclpy.action.create_client( self, Fibonacci, fibonacci ) def send_goal(self, order): goal_msg Fibonacci.Goal() goal_msg.order order self._action_client.wait_for_server() future self._action_client.send_goal_async( goal_msg, feedback_callbackself.feedback_callback ) future.add_done_callback(self.goal_response_callback) def goal_response_callback(self, future): goal_handle future.result() if not goal_handle.accepted: self.get_logger().info(Goal rejected.) return self.get_logger().info(Goal accepted.) result_future goal_handle.get_result_async() result_future.add_done_callback(self.get_result_callback) def feedback_callback(self, feedback_msg): self.get_logger().info( fReceived feedback: {feedback_msg.feedback.partial_sequence} ) def get_result_callback(self, future): result future.result().result self.get_logger().info(fResult: {result.sequence}) rclpy.shutdown() def main(argsNone): rclpy.init(argsargs) node FibonacciActionClient() node.send_goal(10) rclpy.spin(node) if __name__ __main__: main()动作客户端的回调比较多理解起来比话题复杂。可以这样记忆发送目标后先触发“目标响应回调”判断服务端是否接受目标接受后后续每一次服务端发布反馈都会触发“反馈回调”最终任务完成触发“结果回调”。整个过程是一个完整的异步状态机。7.4 运行验证在setup.py的entry_points中添加fibonacci_action_server my_pkg.action_server_node:main, fibonacci_action_client my_pkg.action_client_node:main,编译并 sourcecd ~/ros2_ws colcon build source install/setup.bash先启动动作服务端ros2 run my_pkg fibonacci_action_server再启动动作客户端ros2 run my_pkg fibonacci_action_client客户端会依次打印反馈序列最终打印结果[INFO] Received feedback: [0, 1, 1] [INFO] Received feedback: [0, 1, 1, 2] [INFO] Received feedback: [0, 1, 1, 2, 3] ... [INFO] Result: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]也可以用命令行发送动作目标ros2 action send_goal /fibonacci example_interfaces/action/Fibonacci {order: 5} --feedback加--feedback参数可以实时显示反馈这对调试动作通信非常方便。8. 常见问题与排查思路8.1 高频报错与解决方式新手在 ROS2 环境搭建和通信代码编写中最常遇到下面这些问题问题现象常见原因解决思路找不到命令ros2环境变量没有加载执行source /opt/ros/humble/setup.bash并检查~/.bashrcros2 pkg create报 Package not found功能包名冲突或语法错误确认包名符合命名规范不要使用已存在的相同包名编译时报模块找不到依赖没有安装或未 source 工作空间安装对应依赖并重新执行source install/setup.bash话题收不到消息话题名不一致、节点没有运行、QoS 不匹配用ros2 topic list和rqt_graph检查连接关系服务调用超时服务端没有启动或服务名错误先启动服务端用ros2 service list查询服务名动作目标一直不被接受动作服务端没有运行或 action 类型不匹配检查动作服务名称和类型使用ros2 action list查看在 WSL2 中看不到图形窗口WSLg 异常更新 WSL 内核或检查 Windows 系统版本8.2 调试工具与排查思路遇到通信问题不要盲目改代码建议按顺序排查第一步确认节点都在运行ros2 node list如果节点不在列表中检查是否 source 了工作空间是否编译成功。第二步确认话题、服务、动作都在列表中ros2 topic list ros2 service list ros2 action list第三步查看消息类型是否匹配ros2 topic info /chatter ros2 service type /add_two_ints ros2 action type /fibonacci第四步直接使用 CLI 工具发布或请求判断问题在发送端还是接收端。这套流程基本可以解决 90% 的通信问题。9. 工程实践与开发建议9.1 命名与目录规划功能包名称建议使用小写字母和下划线例如my_pkg、robot_navigation不要使用大写字母或中划线。节点名称一般和功能包名区分开表达功能含义比如camera_node、lidar_node。与 ROS1 相比ROS2 的命名空间和话题重映射能力更强。同一个功能包可以启动多个节点实例通过不同命名空间区分数据流这在多机器人场景中非常实用。目录规划上一个功能包内部可以按作用拆分my_pkg/ ├── my_pkg/ │ ├── publisher_node.py │ ├── subscriber_node.py │ ├── service_server_node.py │ ├── service_client_node.py │ └── action_server_node.py ├── launch/ ├── config/ ├── package.xml └── setup.py节点文件多以后把 launch 和 config 单独放在目录中是工程化的重要一步。9.2 尽量使用 launch 文件实际项目中通常有多个节点需要同时启动。如果每个节点都开一个终端既不便于维护也不能保证启动顺序。ROS2 的 launch 文件可以统一管理节点启动。在功能包下新建launch目录创建一个 launch 文件# 文件路径~/ros2_ws/src/my_pkg/launch/talker_listener.launch.py from launch import LaunchDescription from launch_ros.actions import Node def generate_launch_description(): return LaunchDescription([ Node( packagemy_pkg, executablesimple_publisher, namepublisher, outputscreen ), Node( packagemy_pkg, executablesimple_subscriber, namesubscriber, outputscreen ), ])在setup.py的data_files中加入 launch 目录import os from glob import glob data_files[ (share/ament_index/resource_index/packages, [resource/ package_name]), (share/ package_name, [package.xml]), (os.path.join(share, package_name, launch), glob(launch/*.launch.py)), ],之后只需要一条命令启动多个节点ros2 launch my_pkg talker_listener.launch.pylaunch 文件支持参数传递、条件判断、命名空间设置是 ROS2 大型项目不可缺少的一部分。9.3 QoS 与日志规范ROS2 的 QoSQuality of Service策略决定了消息传输的可靠性。默认情况下话题使用keep_last(10)策略这条策略表示发送端缓冲区最多保留 10 条历史消息。在传感器数据传输或命令控制中需要根据实际场景调整 QoS。新手最容易遇到的问题就是发布者和订阅者的 QoS 不匹配导致消息传输失败或降级。如果通信不稳优先检查双方的 QoS 设置例如self.publisher_ self.create_publisher(String, chatter, 10)这里的10就是 QoS 队列深度。在关键控制场景中建议使用reliable传输在高频传感器场景中建议使用best_effort否则会引入不必要的延迟。日志方面ROS2 提供了统一的日志系统节点中打印日志应该使用self.get_logger()而不是直接print。这样日志可以集成到 ROS2 的日志框架中便于按级别过滤和控制。10. 总结与后续学习路线到这里你已经完成了 ROS2 的第一个完整闭环安装环境、创建工作空间、创建功能包并分别实现了话题、服务、动作三种通信方式的节点代码。这四件事是 ROS2 开发的基本功无论以后做什么机器人项目都离不开这些基础能力。下一步可以继续学习三个方向第一个方向是硬件接入。把单片机、激光雷达、摄像头接入 ROS2需要掌握传感器驱动包的使用方法以及消息类型如何转换。建议从摄像头和雷达开始因为这些传感器的 ROS2 驱动比较成熟。第二个方向是机器人建模与仿真。学习 URDF 文件格式、Gazebo 仿真环境、rviz2 可视化在仿真中验证算法再迁移到真机可以大幅降低开发风险。第三个方向是导航和运动控制。学习 Nav2 导航框架理解地图、定位、路径规划、代价地图等概念这些都是机器人项目落地时最常用的模块。如果你现在还在犹豫要不要继续学不妨先不要看太多理论。安装好 Humble 后跑一次小海龟再动手把 publisher 和 subscriber 这两段代码改成你想要的数据类型。等你亲手把一个自定义话题跑通ROS2 的大门就已经打开了。