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
,首先對description
、 maintainer
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
,首先填寫maintainer
、maintainer_email
、 description
、 license
和package.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.xml
。setup.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編寫話題訂閱發佈,基本操作就需要添加依賴和添加程序入口。