跳到主要内容

在本章中,我们将学习如何使用 Python 编写最小化的发布者和订阅者节点。相比于C++,Python的语法更加简洁,能让初学者快速体会 ROS2 的运行机制。

编写python发布者节点

首先,打开一个新的终端窗口,并加载 ROS2 环境变量(如果没有将加载命令写入到 ~/.bashrc中)。

source /opt/ros/jazzy/setup.bash

导航到之前创建的工作空间 ros2_ws 目录中的 src 文件夹,执行以下命令创建功能包:

ros2 pkg create --build-type ament_python --license Apache-2.0 py_pubsub

执行成功后,终端将确认功能包 py_pubsub 已经创建,并生成必要的文件和目录。

1 编写发布者节点

导航至功能包内的Python代码目录:

cd ros2_ws/src/py_pubsub/py_pubsub

在此目录下创建 publisher_member_function.py 文件,并使用文本编辑器打开,输入以下代码:

import rclpy
from rclpy.node import Node
from std_msgs.msg import String

class MinimalPublisher(Node):
def __init__(self):
super().__init__('minimal_publisher')
self.publisher_ = self.create_publisher(String, 'topic', 10)
timer_period = 0.5 # 秒
self.timer = self.create_timer(timer_period, self.timer_callback)
self.i = 0

def timer_callback(self):
msg = String()
msg.data = 'Hello World: %d' % self.i
self.publisher_.publish(msg)
self.get_logger().info('Publishing: "%s"' % msg.data)
self.i += 1

def main(args=None):
rclpy.init(args=args)
minimal_publisher = MinimalPublisher()
rclpy.spin(minimal_publisher)
# 显式销毁节点
# (可选 - 否则当垃圾收集器销毁节点对象时会自动完成)
minimal_publisher.destroy_node()
rclpy.shutdown()

if __name__ == '__main__':
main()

发布者节点代码解释

发布者节点的Python代码分为以下几个部分:

1. 导入库和模块

import rclpy 
from rclpy.node import Node
from std_msgs.msg import String
  • rclpy 是 ROS2 提供的 Python 客户端库,允许你使用 Python 编写 ROS2 节点。
  • rclpy.node 导入的 Node 类用于创建节点,这个类是所有 ROS2 节点的基类。
  • std_msgs.msg 导入的 String 是 ROS2 内置的标准消息类型之一,用于发布或订阅字符串数据。

2. 创建发布者节点类

class MinimalPublisher(Node):

  • 定义了一个名为MinimalPublisher的类,继承自Node类,意味着它将具备 ROS2 节点的全部功能。

3. 节点构造函数__init__

def __init__(self):
super().__init__('minimal_publisher')
self.publisher_ = self.create_publisher(String, 'topic', 10)
timer_period = 0.5 # 秒
self.timer = self.create_timer(timer_period, self.timer_callback)
self.i = 0
  • super().__init__('minimal_publisher')

    • 调用父类 Node 的构造函数,并将节点命名为 minimal_publisher
  • self.create_publisher(String, 'topic', 10)

    • 创建一个发布者,用于在名为 topic 的话题上发布类型为 String 的消息。

    • 数字 10 表示消息队列大小,当消息发布速度快于订阅者处理速度时,最多可保留10条消息。

  • self.create_timer(timer_period, self.timer_callback)

    • 创建一个定时器,每隔0.5秒调用一次 timer_callback 函数,这样节点就能以固定的频率发布消息。
  • self.i = 0

    • 初始化一个计数器,用于记录消息的序号。

4. 定时器回调函数 timer_callback

    def timer_callback(self):
msg = String()
msg.data = 'Hello World: %d' % self.i
self.publisher_.publish(msg)
self.get_logger().info('Publishing: "%s"' % msg.data)
self.i += 1
  • msg = String()

    • 创建一个新的字符串消息实例。
  • msg.data = f'Hello World: {self.i}'

    • 给消息的数据部分赋值,消息中包含当前计数器的值。
  • self.publisher_.publish(msg)

    • 使用发布者将消息发布到指定的话题 topic 上。
  • self.get_logger().info(f'Publishing: "{msg.data}"')

    • 通过 ROS2 的日志系统将发布的消息内容打印到控制台,以便实时监控节点的运行情况。
  • self.i += 1

    • 每发布一次消息后,计数器递增一次,确保每条消息都具有唯一编号。

5. 主函数(main)

def main(args=None):
rclpy.init(args=args)
minimal_publisher = MinimalPublisher()
rclpy.spin(minimal_publisher)
# 显式销毁节点
# (可选 - 否则当垃圾收集器销毁节点对象时会自动完成)
minimal_publisher.destroy_node()
rclpy.shutdown()
  • rclpy.init(args=args)
    • 初始化 ROS2 通信环境,这是 ROS2 节点启动前必须调用的函数。
  • minimal_publisher = MinimalPublisher()
    • 创建 MinimalPublisher 类的一个实例(节点对象)。
  • rclpy.spin(minimal_publisher)
    • 启动节点,并持续运行,调用节点内部定义的回调函数(如timer_callback)。
  • minimal_publisher.destroy_node()
    • 明确销毁节点对象,释放资源。这是一个推荐的做法。
  • rclpy.shutdown()
    • 关闭ROS 2通信环境,确保ROS 2环境正常关闭并释放所有相关资源。

6. 程序入口

if __name__ == '__main__':
main()
  • 检测Python脚本是否作为主程序运行,如果是,则执行main()函数启动ROS 2节点。

3 添加依赖和入口点

添加依赖

使用编辑器打开功能包根目录ros2_ws/src/py_pubsub中的package.xml文件,编辑以下标签:

  • <description>:功能包的简单描述

  • <maintainer>:维护者的姓名和联系方式(电子邮件)

  • <license>:代码的许可方式,这里使用Apache License 2.0

填写示例如下:

<description>Examples of minimal publisher/subscriber using rclpy</description>
<maintainer email="you@email.com">name</maintainer>
<license>Apache License 2.0</license>

上述标签不是必须的。在上述标签之后,添加程序运行时所需的ROS 2依赖项:

<exec_depend>rclpy</exec_depend>
<exec_depend>std_msgs</exec_depend>
  • <exec_depend> 标签表示功能包在运行节点时需要的依赖库:

    • rclpy:ROS 2的Python客户端库,提供ROS节点的基本功能。

    • std_msgs:标准消息类型库,这里用于发送字符串类型的消息。

完成后保存文件。

添加入口点

编辑 setup.py 文件,确保以下字段与之前 package.xml 文件中的信息保持一致:

maintainer='name',
maintainer_email='you@email.com',
description='Examples of minimal publisher/subscriber using rclpy',
license='Apache License 2.0',

找到 entry_points 字段,修改为以下内容,告诉 ROS2 如何启动Python节点程序:

entry_points={
'console_scripts': [
'talker = py_pubsub.publisher_member_function:main',
],
},
  • talker:命令行中用于启动节点的名称。

  • py_pubsub.publisher_member_function:main:运行publisher_member_function.py文件中的main函数。

完成修改后保存文件。

检查 setup.cfg 文件

打开 setup.cfg 文件,一般创建功能包时该文件会自动正确生成,其默认内容如下:

[develop]
script_dir=$base/lib/py_pubsub

[install]
install_scripts=$base/lib/py_pubsub

这部分定义了 Python 可执行脚本安装后的存放路径,ROS2 默认在 lib 目录中查找并执行这些脚本,因此一般无需改动。

  • [develop] → 开发模式下脚本路径
  • [install] → 安装模式下脚本路径

这两个路径指向 lib/py_pubsub,是 ROS2 约定的节点可执行文件目录,确保 ros2 run 可以找到并执行 Python 节点。完成确认后保存文件。