ROS2學習筆記之編寫Python發佈訂閱節點篇

學習目標:通過Python實現編寫並運行發佈訂閱節點

背景

在本篇教程當中,我們編寫兩個節點通過話題的方式進行字符串消息的傳遞。在這個例子中我們使用“talker” 和 “listener” 的模式,一個發佈數據一個接收數據,讓他們實現數據的交流。

前期準備

知道如何創建工作空間和節點,瞭解Python基本語法。

學習內容

1. 創建Python功能包

新打開一個終端,進入dev_ws/src,準備創建功能包

cd ~/dev_ws/src

創建一個py_pubsub的功能包

ros2 pkg create --build-type ament_python py_pubsub

終端會顯示創建了一些文件和目錄表示創建成功。

2. 編寫發佈節點

之前的教程我們講過Python腳本一般放在和功能包目錄下面和功能同名的一個文件夾下,首先進入這個文件夾

cd py_pubsub/py_pubsub

通過下面的命令下載實例代碼

wget https://raw.githubusercontent.com/ros2/examples/master/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py

選擇一個編輯器打開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  # seconds
        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)

    # Destroy the node explicitly
    # (optional - otherwise it will be done automatically
    # when the garbage collector destroys the node object)
    minimal_publisher.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

2.1 代碼解釋

引入ros2的相關功能到Python

import rclpy
from rclpy.node import Node

引入消息類型

from std_msgs.msg import String

上面這些代表了依賴,需要在package.xml中添加相關信息,之後會講。
接下來是定義了一個MinimalPublisher類,繼承至Node類

class MinimalPublisher(Node):

接下來是這個類的構造函數,通過super().__init__的方式調用了父類的構造函數,將節點名稱命名爲minimal_publisher

create_publisher聲明瞭話題名稱爲topic,消息類型爲String,消息隊列長度爲10。
定時器timer創建了一個0.5s的回調
self.i作爲一個記錄消息發送數量的計數器

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

timer_callback是定時回調函數,發送消息同時,將消息打印到終端通過get_logger().info的方式

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

最後一部分是main函數的定義

def main(args=None):
    rclpy.init(args=args)

    minimal_publisher = MinimalPublisher()

    rclpy.spin(minimal_publisher)

    # Destroy the node explicitly
    # (optional - otherwise it will be done automatically
    # when the garbage collector destroys the node object)
    minimal_publisher.destroy_node()
    rclpy.shutdown()

首先rclpy進行了初始化,然後創建節點,之後進入回調。

2.2 添加依賴

進入dev_ws/src/py_pubsub目錄,我們可以看到setup.py、setup.cfg和 package.xml 文件都給我們自動創建好了。

打開package.xml,首先對descriptionmaintainer and license進行填寫。

<description>Examples of minimal publisher/subscriber using rclpy</description>
<maintainer email="[email protected]">Your Name</maintainer>
<license>Apache License 2.0</license>

在ament_python構建依賴後面加上執行時需要的依賴。

<exec_depend>rclpy</exec_depend>
<exec_depend>std_msgs</exec_depend>

保存文件

2.3 添加發布者程序入口

打開setup.py,首先填寫maintainermaintainer_emaildescriptionlicensepackage.xml保持一致

maintainer='YourName',
maintainer_email='[email protected]',
description='Examples of minimal publisher/subscriber using rclpy',
license='Apache License 2.0',

然後在console_scripts 下一行括號之內添加程序入口:

entry_points={
        'console_scripts': [
                'talker = py_pubsub.publisher_member_function:main',
        ],
},

保存文件

2.4 檢查setup.cfg

文件內容應該是創建包的時候自動填充的

[develop]
script-dir=$base/lib/py_pubsub
[install]
install-scripts=$base/lib/py_pubsub

這些就是告訴setuptools把可執行文件放到lib中,讓ros2 run可以找到它。

到此爲止發佈者就完全編寫完成了,我們可以編譯過後source一下就可以運行了,但是我們還是等訂閱者也寫好過後在運行,方便看到整體的效果。

3. 編譯訂閱者

我們首先進入文件夾然後下載示例代碼

cd ~/dev_ws/src/py_pubsub/py_pubsub
wget https://raw.githubusercontent.com/ros2/examples/master/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py

3.1 代碼解釋

打開subscriber_member_function.py內容如下:

import rclpy
from rclpy.node import Node

from std_msgs.msg import String


class MinimalSubscriber(Node):

    def __init__(self):
        super().__init__('minimal_subscriber')
        self.subscription = self.create_subscription(
            String,
            'topic',
            self.listener_callback,
            10)
        self.subscription  # prevent unused variable warning

    def listener_callback(self, msg):
        self.get_logger().info('I heard: "%s"' % msg.data)


def main(args=None):
    rclpy.init(args=args)

    minimal_subscriber = MinimalSubscriber()

    rclpy.spin(minimal_subscriber)

    # Destroy the node explicitly
    # (optional - otherwise it will be done automatically
    # when the garbage collector destroys the node object)
    minimal_subscriber.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

前面的大部分代碼都和發佈者相似。在構造函數裏面,用和發佈者相同的消息類型、話題、消息隊列長度定義了一個訂閱者

self.subscription = self.create_subscription(
    String,
    'topic',
    self.listener_callback,
    10)

由於我們只需要處理接收到的消息就沒有了定時器,話題的回調函數裏面將接收到的消息打印到控制檯。

def listener_callback(self, msg):
    self.get_logger().info('I heard: "%s"' % msg.data)

main函數部分和發佈者部分的代碼幾乎一樣,唯一不同的地方就是把相應的地方換爲了訂閱者的內容。

minimal_subscriber = MinimalSubscriber()

rclpy.spin(minimal_subscriber)

訂閱和發佈者節點的依賴相同,所以我們並不需要修改package.xmlsetup.cfg也保持默認。

3.2 添加訂閱者程序入口

打開setup.py文件,在剛剛添加發布者的下面添加訂閱者的程序入口。

entry_points={
        'console_scripts': [
                'talker = py_pubsub.publisher_member_function:main',
                'listener = py_pubsub.subscriber_member_function:main',
        ],
},

保存文件,到此我們發佈和訂閱的節點都準備完成了。

4. 編譯運行節點

我們進入工作空間根目錄開始編譯節點

cd ~/dev_ws
colcon build --packages-select py_pubsub

新打開一個終端運行talker節點

source dev_ws/install/setup.bash
ros2 run py_pubsub talker

節點開始運行在終端不斷打印出發佈的消息內容

[INFO] [minimal_publisher]: Publishing: "Hello World: 0"
[INFO] [minimal_publisher]: Publishing: "Hello World: 1"
[INFO] [minimal_publisher]: Publishing: "Hello World: 2"
[INFO] [minimal_publisher]: Publishing: "Hello World: 3"
[INFO] [minimal_publisher]: Publishing: "Hello World: 4"
...

再新打開一個終端運行listener節點

source dev_ws/install/setup.bash
ros2 run py_pubsub listener

節點開始運行,並且將接收到的消息打印顯示到終端。

[INFO] [minimal_subscriber]: I heard: "Hello World: 10"
[INFO] [minimal_subscriber]: I heard: "Hello World: 11"
[INFO] [minimal_subscriber]: I heard: "Hello World: 12"
[INFO] [minimal_subscriber]: I heard: "Hello World: 13"
[INFO] [minimal_subscriber]: I heard: "Hello World: 14"

總結

這個例程講述了ros2中Python編寫話題訂閱發佈,基本操作就需要添加依賴和添加程序入口。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章