【ROS2】从零开始构建你的第一个ROS2节点:基于RCLPY的实战指南

【ROS2】从零开始构建你的第一个ROS2节点:基于RCLPY的实战指南 1. ROS2节点基础概念第一次接触ROS2的朋友可能会被节点这个概念搞懵。简单来说节点就是ROS2系统中的基本功能单元就像人体内的器官一样各司其职。举个例子假设我们要做一个自动巡逻的小车可能需要这些节点一个节点负责读取摄像头数据一个节点处理图像识别一个节点控制电机转动一个节点规划巡逻路线每个节点都专注于做好自己的事情节点之间通过四种方式通信话题(Topics)单向数据流像广播电台服务(Services)双向请求-响应像打电话动作(Actions)长时间执行的任务像点外卖参数(Parameters)配置项像系统设置在终端里我们可以用这些命令管理节点# 查看所有运行中的节点 ros2 node list # 查看某个节点的详细信息 ros2 node info /node_name # 运行一个节点 ros2 run package_name executable_name2. 搭建开发环境2.1 创建工作空间工作空间就像你的项目文件夹建议按这个结构创建mkdir -p ~/ros2_ws/src cd ~/ros2_ws这个结构清晰明了src/存放所有功能包源码build/编译中间文件自动生成install/安装目录自动生成log/日志文件自动生成2.2 安装Colcon构建工具Colcon是ROS2的构建系统相当于ROS1中的catkin。安装很简单sudo apt install python3-colcon-common-extensions验证安装成功colcon --help3. 创建Python功能包3.1 初始化功能包进入src目录创建Python包cd ~/ros2_ws/src ros2 pkg create my_first_pkg --build-type ament_python --dependencies rclpy参数说明--build-type ament_python指定Python包--dependencies rclpy添加ROS2 Python客户端依赖创建完成后会生成如下结构my_first_pkg/ ├── my_first_pkg/ │ ├── __init__.py │ └── (你的Python代码放这里) ├── package.xml ├── resource/ └── setup.py3.2 编写第一个节点在my_first_pkg/my_first_pkg/下创建first_node.py#!/usr/bin/env python3 import rclpy from rclpy.node import Node class MyFirstNode(Node): def __init__(self): super().__init__(my_first_node) # 节点名 self.get_logger().info(Hello ROS2!) def main(argsNone): rclpy.init(argsargs) # 初始化ROS2 node MyFirstNode() # 创建节点 rclpy.spin(node) # 保持节点运行 rclpy.shutdown() # 关闭ROS2 if __name__ __main__: main()代码解析导入rclpy库和Node基类创建继承自Node的自定义节点类在__init__中初始化节点名称main()函数是标准入口初始化ROS2实例化节点保持节点运行最后关闭ROS23.3 配置包信息修改setup.py添加节点入口entry_points{ console_scripts: [ first_node my_first_pkg.first_node:main, ], },这行配置告诉ROS2first_node可执行命令名my_first_pkg.first_node包名.模块名:main入口函数4. 编译与运行4.1 编译功能包回到工作空间根目录cd ~/ros2_ws colcon build --packages-select my_first_pkg常用编译选项--symlink-install创建符号链接修改代码无需重新编译--packages-select只编译指定包--cmake-args传递CMake参数4.2 运行节点先加载环境source install/setup.bash然后运行节点ros2 run my_first_pkg first_node你应该会看到终端输出[INFO] [my_first_node]: Hello ROS2!5. 调试与进阶技巧5.1 常见问题排查问题1找不到包或节点确保正确执行了source install/setup.bash检查setup.py中的entry_points配置是否正确问题2Python脚本没有执行权限chmod x my_first_pkg/my_first_pkg/first_node.py问题3依赖缺失 检查package.xml确保已声明所有依赖dependrclpy/depend5.2 日志输出技巧ROS2节点内置了日志系统self.get_logger().debug(调试信息) # 默认不显示 self.get_logger().info(常规信息) # 绿色 self.get_logger().warn(警告信息) # 黄色 self.get_logger().error(错误信息) # 红色 self.get_logger().fatal(严重错误) # 紫色设置日志级别ros2 run my_first_pkg first_node --ros-args --log-level debug5.3 参数传递启动时传递参数# 在节点类中声明参数 self.declare_parameter(my_param, default_value) # 获取参数值 param_value self.get_parameter(my_param).value命令行传参ros2 run my_first_pkg first_node --ros-args -p my_param:custom_value6. 扩展应用实例6.1 创建一个发布者节点修改first_node.py添加发布者功能from std_msgs.msg import String import time class MyFirstNode(Node): def __init__(self): super().__init__(my_first_node) self.publisher self.create_publisher(String, greeting, 10) self.timer self.create_timer(1.0, self.timer_callback) self.counter 0 def timer_callback(self): msg String() msg.data fHello {self.counter} times! self.publisher.publish(msg) self.get_logger().info(fPublished: {msg.data}) self.counter 1这个节点会创建一个String类型的发布者每秒触发一次定时器回调在回调中发布消息并计数6.2 创建一个订阅者节点新建subscriber_node.pyfrom std_msgs.msg import String class MySubscriber(Node): def __init__(self): super().__init__(my_subscriber) self.subscription self.create_subscription( String, greeting, self.listener_callback, 10) def listener_callback(self, msg): self.get_logger().info(fI heard: {msg.data})别忘了在setup.py中添加新的入口点entry_points{ console_scripts: [ first_node my_first_pkg.first_node:main, subscriber_node my_first_pkg.subscriber_node:main, ], },6.3 测试通信重新编译后开三个终端分别运行# 终端1运行发布者 ros2 run my_first_pkg first_node # 终端2运行订阅者 ros2 run my_first_pkg subscriber_node # 终端3查看话题列表 ros2 topic list你应该能看到订阅者终端不断打印接收到的消息这就是ROS2节点间最基本的通信过程。