ROS2 Topics和Services

本文主要介紹ROS的Topics概念,如何創建Publisher和Subscriber,通過Topic在ROS程序間通信;介紹ROS的Services概念,如何創建Client和Server并建立通信。
更多內容,訪問專欄目錄獲取實時更新。

ROS Topics

Topics可以被視為一種具名的總線,用于節點間交換數據,通過Topics可以發布和訂閱消息,實現單向的流式通信。需要注意的重點包括:

  • 單向流式通信(發布/訂閱模式)
  • 匿名通信
  • 每個Topic都有特定的消息格式
  • 可以在ROS節點中通過Python, C++等多種語言實現
  • 一個節點可以擁有多個Topic

Publisher in Python

在ROS2基礎編程一文中,我們已經創建了工作空間和工作包,在此基礎上,來通過Python實現一個Topic的發布者。
my_py_pkg工作包下創建一個新的文件robot_news_station.py
在這里插入圖片描述
robot_news_station.py

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from example_interfaces.msg import String  # do not forget to add package dependencyclass RobotNewsPublisherNode(Node):def __init__(self):super().__init__("robot_news_publisher")self.robot_name = "HiRobot"self.publisher = self.create_publisher(String, "robot_news", 10)self.timer = self.create_timer(1, self.publish_news)self.get_logger().info("Robot News Publisher has been started")def publish_news(self):msg = String()msg.data = "Hi, this is " + str(self.robot_name) + " from the robot news publisher"self.publisher.publish(msg)def main(args=None):rclpy.init(args=args)node = RobotNewsPublisherNode()rclpy.spin(node)rclpy.shutdown()if __name__ == "__main__":main()

還需要添加依賴包引用,修改package.xml文件:
在這里插入圖片描述

然后裝載我們的新節點,修改setup.py:
在這里插入圖片描述

之后執行下面的指令就可以啟動我們的publisher了:

colcon build --packages-select my_py_pkg --symlink-install
source ~/.bashrc
ros2 run my_py_pkg robot_news_station
ros2 topic echo /robot_news

Subscriber in Python

創建訂閱者的方式與創建發布者類似,這里我們添加了一個名為robot_news_subscriber.py的文件:

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from example_interfaces.msg import String  # do not forget to add package dependencyclass RobotNewsSubscriberNode(Node):def __init__(self):super().__init__("robot_news_subscriber")self.subscriber = self.create_subscription(String, "robot_news", self.subscribe_news_callback, 10)self.get_logger().info("Robot News Subscriber has been started")def subscribe_news_callback(self, msg):self.get_logger().info(msg.data)def main(args=None):rclpy.init(args=args)node = RobotNewsSubscriberNode()rclpy.spin(node)rclpy.shutdown()if __name__ == "__main__":main()

不要忘記修改setup.pycolcon build編譯。之后同時運行publisher和subscriber就可以看到右側命令行里的subscriber每1s收到一條來自publisher的信息,并打印:
在這里插入圖片描述

使用命令行工具調試Topics

ros2 topic list
ros2 topic info <topic_name>  # 查看所有激活的topic
ros2 topic echo <topic_name>   # 創建一個訂閱者監聽發布的消息
ros2 interface show <msg_type>  # 顯示話題消息的類型
ros2 topic hz <topic_name>  # 獲取發布頻率
ros2 topic bw <topic_name>  # 獲取消息的長度,byte width
ros2 topic pub <topic_name>  <msg_type> <msg_data>  # 發布一個topic
ros2 topic pub -r 10 /robot_news example_interfaces/msg/String "{data: 'hello from robot'}"
ros2 node list
ros2 info <node_name>
ros2 run <pkg_name> <node_name> --ros-args -r __node:=<new_node_name>
ros2 run <pkg_name> <node_name> --ros-args -r __node:=<new_node_name> -r <topic_name>:=<new_topic_name>

Ros Services

前文提到Topics實現的是單向的傳輸,通過發布/訂閱模式建立連接,但用在一些需要請求/回復的分布式系統中就不太合適了。
Services可以幫助我們實現請求/回復的通信模式,一條消息用于請求,一條用于回復,ROS節點以字符串名稱提供服務,客戶端通過發送請求消息并等待回復來調用服務,從而建立持久性的連接。

Service Server in Python

ros2 interface show example_interfaces/srv

執行上面的指令,你能看到example_interface包里提供了哪些服務,這里我們使用AddTwoInts來演示如何創建一個service server
add_two_ints_server.py

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoIntsclass AddTwoIntsServerNode(Node):def __init__(self):super().__init__("add_two_ints_server")self.server = self.create_service(AddTwoInts, "add_two_ints", self.callback_add_two_ints)self.get_logger().info("Add Two Ints Server has started")def callback_add_two_ints(self, request, response):response.sum = request.a + request.bself.get_logger().info(str(request.a) + " + " + str(request.b) + " = " + str(response.sum))return responsedef main(args=None):rclpy.init(args=args)node = AddTwoIntsServerNode()rclpy.spin(node)rclpy.shutdown()if __name__ == "__main__":main()

編譯并運行,通過ros2 service list就能在服務列表里看到我們啟動的服務了。
在這里插入圖片描述

ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 3, b: 4}"

執行上面的指令就可以在命令行里調用我們創建的service。

Service Client in Python

add_two_ints_client.py

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoIntsdef main(args=None):rclpy.init(args=args)node = Node("add_two_ints_no_oop")client = node.create_client(AddTwoInts, "add_two_ints")while not client.wait_for_service(1):node.get_logger().warn("Waiting for server Add Two Ints...")request = AddTwoInts.Request()request.a = 3request.b = 8future = client.call_async(request)rclpy.spin_until_future_complete(node, future)try:response = future.result()node.get_logger().info(str(request.a) + " + " + str(request.b) + " = " + str(response.sum))except Exception as e:node.get_logger().error("Service call failed %r" % (e,))rclpy.shutdown()if __name__ == "__main__":main()

使用命令行工具調試Services

ros2 service list
ros2 service type <service_name>
ros2 interface show <service type>
ros2 service call <service_name> <service_type> <value>
ros2 run <pkg_name> <node_name> --ros-args -r <service_name>:=<new_service_name>

ROS Interface

ROS應用之間有三種通信接口:messages, services和actions,ROS2使用IDL(interface definition language)來描述這些接口,使得在不同應用,不同編程語言間進行交互更加簡單。例如前文提到的Topic和Service:

Topic:

  • Name:話題名
  • 消息定義:Msg,如example_interfaces/msg/Int64

Service:

  • Name: 服務名
  • 服務定義:Srv,如example_interfaces/srv/AddTwoInts (包含request和response)

創建自定義的Msg

創建一個新的工作包my_robot_interfaces,移除目錄下的includesrc文件夾,并新建msg文件夾:
在這里插入圖片描述
msg文件夾下新建msg定義文件: HardwareStatus.msg

int64 temperature
string debug_message

更新package.xml,添加:

<build_depend>rosidl_default_generators</build_depend><exec_depend>rosidl_default_runtime</exec_depend><member_of_group>rosidl_interface_packages</member_of_group>

更新CMakeLists.txt,添加:

find_package(rosidl_default_generators REQUIRED)rosidl_generate_interfaces(${PROJECT_NAME}"msg/HardwareStatus.msg"
)ament_export_dependencies(rosidl_default_runtime)
ament_package()

然后編譯工作包,就可以在其他工程中使用該Msg定義了。

使用自定義的Msg

my_py_pkg工作包下創建一個新的publisher:hw_status_publisher.py

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from my_robot_interfaces.msg import HardwareStatusclass HardwareStatusPublisherNode(Node):def __init__(self):super().__init__("hardware_status_publisher")self.hw_status_publisher = self.create_publisher(HardwareStatus, "hardware_status", 10)self.timer = self.create_timer(1, self.publish_hw_status)self.get_logger().info("Hardware Status Publisher has been started")def publish_hw_status(self):msg = HardwareStatus()msg.temperature = 45msg.debug_message = "No error"self.hw_status_publisher.publish(msg)def main(args=None):rclpy.init(args=args)node = HardwareStatusPublisherNode()rclpy.spin(node)rclpy.shutdown()if __name__ == "__main__":main()

不要忘記在package.xml中添加對my_robot_interface的依賴,并把新的節點加載到setup.py并編譯。運行haredware_status_publisher并監聽,可以看到如下的效果:
在這里插入圖片描述

創建自定義的Srv

my_robot_interfaces工作包目錄下創建srv文件夾,并新建文件ComputerRectangleArea.srv

float64 length
float64 width
---
float64 area

更新CMakeLists.txt
在這里插入圖片描述
成功編譯了工作包后我們就能夠獲得自定義的Srv了
在這里插入圖片描述

如有錯誤,歡迎留言或來信指正:hbin6358@163.com

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/18714.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/18714.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/18714.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

做電商,錯過了2020年的抖音!那2024一定要選擇視頻號小店!

哈嘍~我是電商月月 電商老板們集合了&#xff0c;問大家一個問題: 如果能讓你回到三四年前&#xff0c;抖音才步入大眾視野&#xff0c;這時候讓你去做抖音小店&#xff0c;你愿意嗎&#xff1f; 我敢相信&#xff01;很多&#xff0c;錯過當年抖音紅利的商家&#xff0c;一…

計算機三級 網絡技術

一、邊界網關協議BGP BGP是邊界網關協議&#xff0c;是外部而不是內部網關協議&#xff08;是不同自治系統的路由器之間使用的協議&#xff09;一個BGP發言人使用TCP&#xff08;不是UDP&#xff09;與其自治系統的BGP發言人交換路由信息。BGP協議交換路由由信息的節點數是以自…

Docker HTTPS api V2 Manifest V 2, Schema 2 下的免裝docker下載鏡像的方法

目錄 前言 下載鏡像代碼 使用方法 原代碼中無法適配 Schema 2 的原因淺析 如何解決 相對原代碼改動的東西 前言 本文提供代碼主要是基于 https://github.com/NotGlop/docker-drag 提供的代碼修改的。鏈接中提供的代碼應該是是基于HTTPS api V2 Manifest V 2, Schema 1實…

面試必備:應對 “為什么離職” 的萬能回答

使用PC端的朋友&#xff0c;請將頁面縮小到最小比例&#xff0c;閱讀最佳&#xff01; 面試官問到你為什么從上一家公司離職時&#xff0c;你會怎么回答&#xff1f;這個問題我覺得很有意思&#xff0c;也很有必要去探討一下。 很多專業人士都會建議你&#xff0c;最好不要直接…

C++---迭代器介紹

迭代器的介紹 使用迭代器需要引用頭文件,但一般的容器都引用了這個頭文件。 這五種迭代器的聲明如下: struct output_iterator_tag { };//輸出迭代器 struct input_iterator_tag{ };//輸入迭代器 struct forward_iterator_tag : public input_iterator_tag {};//向前迭代器 …

基于序列深度學習模型的向量海岸線形狀分類方法 2024.05

本文中提出了一個數據驅動的方法來分類的形狀矢量海岸線&#xff0c;該方法利用基于序列的深度學習算法對海岸線矢量分段進行建模和分類。具體而言&#xff0c;首先將復雜的海岸線劃分為一系列彎曲&#xff0c;并進一步提出了一組不同的特征來描述每個彎曲的形態特征。然后&…

強化學習——學習筆記2

在上一篇文章中對強化學習進行了基本的概述&#xff0c;在此篇文章中將繼續深入強化學習的相關知識。 一、什么是DP、MC、TD&#xff1f; 動態規劃法&#xff08;DP&#xff09;&#xff1a;動態規劃法離不開一個關鍵詞&#xff0c;拆分 &#xff0c;就是把求解的問題分解成若…

【JavaScript腳本宇宙】點燃你的Web開發:數據綁定和MV*框架

逐一剖析&#xff1a;JavaScript框架和庫的概述、特點與應用 前言 在當今技術日新月異的時代&#xff0c;JavaScript庫和框架已成為前端開發的重要工具。這篇文章將詳細介紹六種不同的JavaScript庫和框架&#xff0c;幫助讀者了解他們的主要特性、使用示例和適用場景。 歡迎訂…

gif幀數修改怎么操作?一鍵掌握GIF幀數修改技巧!

gif幀數修改怎么操作&#xff1f;在數字化信息爆炸的時代&#xff0c;GIF動圖因其生動有趣的特性而備受廣大網友喜愛。然而&#xff0c;很多時候我們可能會遇到GIF動圖幀數過多或過少&#xff0c;導致動畫效果不盡如人意的情況。那么&#xff0c;如何對GIF動圖的幀數進行修改呢…

探索微軟Edge開發者工具:優化前端開發的藝術與科學

探索微軟Edge開發者工具&#xff1a;優化前端開發的藝術與科學 引言&#xff1a;Edge開發者工具概覽一、基礎操作&#xff1a;步入DevTools的大門1.1 啟動與界面布局1.2 快速導航與定制 二、元素審查與樣式調整2.1 精準元素選取2.2 實時CSS編輯2.3 自動完成與內聯文檔 三、Java…

YOLOv10最詳細全面講解1- 目標檢測-準備自己的數據集(YOLOv5,YOLOv8均適用)

YOLOv10沒想到出來的如此之快&#xff0c;作為一名YOLO的愛好者&#xff0c;以YOLOv5和YOLOv8的經驗&#xff0c;打算出一套從數據集裝備->環境配置->訓練->驗證->目標追蹤全系列教程。請大家多多點贊和收藏&#xff01;&#xff01;&#xff01;YOLOv5和YOLOv8親測…

dubbo復習:(13)把服務劃分為不同的group 和version,只有服務端和客戶端group和version匹配才能通信

一、接口定義 package cn.edu.tju.service;public interface DevelopService {String invoke(String param); }二、兩個版本的實現&#xff1a; package cn.edu.tju.service;import org.apache.dubbo.config.annotation.DubboService;DubboService(group "group1"…

bert模型數據集加載方式

數據集構造 無論是機器學習還是深度學習對于數據集的構造都是十分重要。 現記錄一下PyTorch 的 torch.utils.data.Dataset 類的子類。Dataset 類是PyTorch框架中用于處理數據的基本組件&#xff0c;它允許用戶定義自己的數據集類&#xff0c;以滿足特定任務的需求。 Dataset…

重學英語:輸出的重要性

精通一門外語的四要素&#xff1a;聽&#xff0c;說&#xff0c;讀&#xff0c;寫 輸入&#xff1a;聽&#xff0c;讀 輸出&#xff1a;寫&#xff0c;說 因為輸入是我們可以單獨完成&#xff0c;不需要有人互動&#xff0c;所以我們做得最多 輸出練習做得很少&#xff0c;…

Redis中的數據結構與內部編碼

本篇文章主要是對 Redis 常見的數據結構進行講解&#xff0c;同時還對其所對應的不同的內部編碼進行講解。希望本篇文章會對你有所幫助。 文章目錄 一、五大數據結構 二、數據結構對應的編碼方式 String hash list set zset &#x1f64b;?♂? 作者&#xff1a;Ggggggtm &…

js 面試題學習筆記一

1、什么是防抖和節流&#xff1f;有什么區別&#xff1f;如何實現&#xff1f; 防抖&#xff1a;觸發高頻事件后N秒內函數只會執行一次&#xff0c;如果N秒高頻事件再次被觸發&#xff0c;則重新計算時間。&#xff08;a時間觸發&#xff0c;5秒內執行一次&#xff0c;但是第4…

10G UDP協議棧 (9)UDP模塊

目錄 一、UDP協議簡單介紹 二、UDP功能實現 三、仿真 一、UDP協議簡單介紹 UDP協議和TCP協議同位于傳輸層&#xff0c;介于網絡層&#xff08;IP&#xff09;和應用層之間&#xff1a;UDP數據部分為應用層報文&#xff0c;而UDP報文在IP中承載。 UDP 報文格式相對于簡單&am…

電腦出現:excel詞典(xllex.dll)文件丟失或損壞的錯誤提示怎么辦?有效的將丟失的xllex.dll修復

當遇到 Excel 提示“詞典 (xllex.dll) 文件丟失或損壞”的問題時&#xff0c;通常意味著該動態鏈接庫文件&#xff08;Dynamic Link Library&#xff0c;DLL&#xff09;&#xff0c;它與拼寫檢查功能相關聯的&#xff0c;無法被正確找到或者合適地使用。那么有什么辦法可以解決…

LLVM技術在GaussDB等數據庫中的應用

目錄 LLVM和數據庫 LLVM適用場景 LLVM對所有類型的SQL都會有收益嗎&#xff1f; LLVM在OLTP中就一定沒有收益嗎&#xff1f; GaussDB中的LLVM 1. LLVM在華為應用于數據庫的時間線 2. GaussDB LLVM實現簡析 3. GaussDB LLVM支持加速的場景 支持LLVM的表達式&#xff1a…

vue項目出現多次ElMessage

問題&#xff1a; 解決方法&#xff1a; let message null if (message null) { message ElMessage.error(“登錄過期,請重新登錄”); } 最終效果&#xff1a;只出現一個彈框