iT邦幫忙

2024 iThome 鐵人賽

DAY 11
0
自我挑戰組

ROS 筆記:要怎麼叫無人機自己飛系列 第 11

【ROS 筆記:要怎麼叫無人機自己飛】Day 11:使用 Python 撰寫話題的發布者(Publisher)和訂閱者(Subscriber)

  • 分享至 

  • xImage
  •  

這一篇想介紹如何用 Python 來讓節點發布和訂閱訊息,做到上一篇介紹的 rostopic echorostopic pub 這兩個指令相同的效果。

建立發布者(Publisher)

這裡寫了一個 turtle_pub.py 來示範發布者的程式結構。這支程式會建立一個發布者節點,發布速度 Twist 的訊息到話題 cmd_vel,讓烏龜會原地繞圈。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import rospy
# 訊息: geometry_msgs/Twist 表示直線速度和角速度
from geometry_msgs.msg import Twist 

def turtle_pub():
    # 建立發布者, 指定話題'/turtle1/cmd_vel'
    publisher = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size = 10)
    rate = rospy.Rate(10)
    
    # 發布訊息
    while not rospy.is_shutdown():
        # 定義訊息類型
        msg = Twist()

        # 定義訊息類容
        msg.linear.x = 2.0
        msg.angular.z = -1.8

        rospy.loginfo(msg)
        
        # 讓發布者發布訊息
        publisher.publish(msg)
        rate.sleep()

if __name__ == '__main__':
    # 節點初始化
    rospy.init_node('turtle_publisher', anonymous=True) 
    try:
        turtle_pub()
    except rospy.ROSInterruptException:
        pass

下面來解釋這段腳本的每個部份在做什麼。

匯入必要的模組

import rospy
from geometry_msgs.msg import Twist
  • geometry_msgs.msg 模組的 Twist 類別:

    上一篇文章提到 geometry_msgs/Twist 是一個 ROS 內建的訊息類型,用於表示直線速度和角速度。這個訊息是定義在 geometry_msgs.msg 模組的 Twist 類別,於是在程式開頭匯入。

定義 turtle_pub() 函式

def turtle_pub():
    publisher = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size = 10)
    rate = rospy.Rate(10)
    
    while not rospy.is_shutdown():
        msg = Twist()
        
        msg.linear.x = 2.0
        msg.angular.z = -1.8

        rospy.loginfo(msg)
        
        publisher.publish(msg)
        rate.sleep()

在這段函式中包含了幾個功能:

  • 建立發布者

    使用 rospy.Publisher() 建立一個發布者,指定將訊息發佈到 /turtle/cmd_vel 上,並用一個變數 publisher 儲存。

    格式:

    pub = rospy.Publisher(topic_name, msg_class, queue_size)
    
    • topic_name:指定要發布的話題名稱。

    • msg_class:指定訊息類型。

    • queue_size:設定佇列大小,當訊息被發布到一個 topic 時,如果有訂閱者暫時無法接收訊息,那麼這些訊息會被保留最近幾個並存放在一個佇列中,只能設定整數。

  • 發布訊息

    在 while 迴圈內,首先利用 Twist() 建立了一個訊息變數 msg ,並且設定其直線速度 linear.x 和角速度 angular.z 的向量大小(前進和右轉),單位是 m/s 和 rad/s。定義完訊息後,再利用 publish() 方法讓 publisher 執行發布。

建立訂閱者(Subscriber)

接著再寫一個 turtle_sub.py 用來示範訂閱者的程式結構。它會建立一個訂閱者節點,訂閱話題 cmd_vel 的訊息,並且在終端機持續輸出所有該話題的訊息。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import rospy
# 訊息: geometry_msgs/Twist 表示直線速度和角速度
from geometry_msgs.msg import Twist

# 回呼函式
def callback(data):
    print(data.linear)
    print("------------------------------")
    print(data.angular)
    print("------------------------------")

def turtle_sub():
    # 建立訂閱者, 指定話題'/turtle1/cmd_vel'
    rospy.Subscriber('/turtle1/cmd_vel', Twist, callback)
    rospy.spin()

if __name__ == '__main__':
    # 節點初始化
    rospy.init_node('turtle_subscriber', anonymous=True)
    turtle_sub()

這段腳本最主要的部份是定義 callback()turtle_sub() 這兩個函式。

定義 callback() 函式

def callback(data):
    print(data.linear)
    print("------------------------------")
    print(data.angular)
    print("------------------------------")

這是一個典型的回呼函式(Callback function),也就是在特定條件或事件發生時,才會被做為參數呼叫的函式。函式裡面定義了接收到丟進來參數後,便會輸出四行文字內容。

定義 turtle_sub() 函式

def turtle_sub():
    rospy.Subscriber('/turtle1/cmd_vel', Twist, callback)
    rospy.spin()

這段函式和前一個腳本的 turtle_pub() 概念類似:

  • 建立訂閱者

    使用 rospy.Subsriber() 建立一個訂閱者,指定接收發佈到 /turtle/cmd_vel 上的訊息,因為訂閱者基本上是被動接收,不用建立一個變數儲存。

    格式:

    rospy.Subsriber(topic_name, msg_class, callback)
    
    • callback:指定收到新訊息時呼叫的回呼函式名稱(可以改名稱,但記得要和前面的回呼函式名稱一致)。當執行到這行程式碼時,ROS 便會開始監聽 /turtle/cmd_vel' 話題是否出現 Twist 類型的訊息,並在接收到的訊息時,呼叫並將該訊息傳入 callback() 函式。

    後面 rospy.spin() 這行是設定使節點保持運作直到被手動停止或意外終止。


以上兩支程式是發布者和訂閱者比較經典的程式結構,透過程式我們就能更精細地設計指令及做出更複雜的動作,比用指令會更方變得多。下一篇會繼續介紹服務代理的 Python 程式結構。


上一篇
【ROS 筆記:要怎麼叫無人機自己飛】Day 10:利用話題(Topic)和服務(Service)來讓節點通訊(二)
下一篇
【ROS 筆記:要怎麼叫無人機自己飛】Day 12:使用 Python 撰寫服務代理(Service Proxy)
系列文
ROS 筆記:要怎麼叫無人機自己飛14
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言