天天看點

2.1ROS通信機制1.話題通信2.服務通信3.參數伺服器4.通信機制比較

這裡寫自定義目錄标題

  • 1.話題通信
    • 概述
    • 自定義msg
    • 話題通信實作(python)
  • 2.服務通信
    • 概述
    • 自定義srv
    • 服務通信自定義srv調用B(python)
    • 注意事項
  • 3.參數伺服器
    • 概述
    • 參數操作(python)
  • 4.通信機制比較

在ros中每一個功能點是一個單獨的程序,每一個程序都是獨立運作的,ros是程序(也稱為nodes)的分布式架構

ros中的基本通信機制主要有如下三種實作政策:

  • 話題通信-釋出訂閱模式

    控制turtle路徑;擷取位姿

  • 服務通信-請求響應模式

    在指定位置生成turtle

  • 參數伺服器-參數共享模式

    修改turtle背景顔色

1.話題通信

概述

一個節點釋出消息,另外一個節點訂閱該消息,即一個釋出方Talker,訂閱方Listener,傳輸是資料就是話題topic

2.1ROS通信機制1.話題通信2.服務通信3.參數伺服器4.通信機制比較

目标:使用自定義資料類型實作資料互動

自定義msg

關于自定義資料msg

#  <package>/msg/<class_name>
string name
uint32 age
float64 height

# 然後要配置檔案<package>/CMakeLists.txt, package.xml,再編譯
           

2.配置CMakeLists.txt檔案

# <package>/package.xml
# 添加到對應位置
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
           

3.配置package.xml檔案

# <package>/CMakeList.txt
find_package(catkin REQUIRED COMPONENTS
	-snap-
	message_generation
)

# 編譯需要
add_message_files(
	FILES
	Person.msg
)

generate_message(
	DEPENDENCIES
	std_msgs
)

# find_package所依賴 
catkin_package(
	CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
)
           

話題通信實作(python)

1.配置vscode settings.json,将編譯生成的中間檔案dist-packages目錄添加

2.關于Talker部分代碼

#! /usr/bin/env python
# scripts/demo03_pub_person_p.py
import rospy
from plumbing_pub_sub.msg import Person

if __name__=="__main__":
    rospy.init_node("China")
    pub=rospy.Publisher("person",Person,queue_size=10)

    p=Person()
    p.name="Lihua"
    p.age=18
    p.height=171.3

    rate=rospy.Rate(0.5)

    while not rospy.is_shutdown():
        pub.publish(p)
        rospy.loginfo("the published messages is: {0}, {1}, {2}".format(p.name, p.age, p.height))
        rate.sleep()

# 添權重限、配置檔案、編譯
           

3.關于Listener實作

#! scripts/usr/bin/env python
# scripts/demo04_sub_person_p.py
import rospy
from plumbing_pub_sub.msg import Person

def doPerson(p):
    rospy.loginfo("the subscribed message is: {}, {}, {}".format(p.name, p.age, p.height))

if __name__=="__main__":
    rospy.init_node("Listener1")
    sub=rospy.Subscriber("person",Person, doPerson)
    rospy.spin()
 
# 添權重限、配置檔案、編譯
           

2.服務通信

概述

概念:服務通信基于請求響應模式,是一種應答機制,寄:A節點向B節點發送請求,B節點接收請求并響應結果傳回給A

作用:用于偶然的、對時效性要求、對一定邏輯處理需求的資料傳輸場景

案例:實作兩個數字的求和,用戶端節點發送兩個數字,伺服器端點接收數字後求和并傳回給用戶端

2.1ROS通信機制1.話題通信2.服務通信3.參數伺服器4.通信機制比較

自定義srv

srv檔案内可用資料類型與msg檔案一緻,且定義srv實作流程與自動逸msg實作流程類似:按照固定格式建立srv檔案;編輯配置檔案;生成

1.建立plumbing_server_client --><package_>

# <package>/srv/<xx.srv>-->AddInts

int32 num1
int32 num2
---
int32 num3

# srv中請求和響應的資料用---分割
           

2.配置CMakeLists.txt、package.xml檔案

# <package>/package.xml
# 添加到對應位置
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
           
# <package>/CMakeList.txt
find_package(catkin REQUIRED COMPONENTS
	-snap-
	message_generation
)

add_service_files(
	FILES
	<xx>.srv
)

generate_message(
	DEPENDENCIES
	std_msgs
)

# find_package所依賴 
catkin_package(
	CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
)

# 配置完兩個檔案按後進行編譯生成中間檔案
           

服務通信自定義srv調用B(python)

1.配置vscode settings.json,将編譯生成的中間檔案dist-packages目錄添加

2.Server實作

# <package>/<scripts>/<xx.py>-->demo01_server_p.py
#! usr/bin/env python

import rospy
from plumbing_server_client.srv import AddInts,AddIntsRequest,AddIntsResponse

def doNum(request):
	# 封裝并處理請求的資料
	num1 = request.num1
	num2 = request.num2
	s = num1+num2
	response = AddIntsResponse()
	response.num3 = s
	# 此處響應response的屬性名必須是srv定義的變量名
	rospy.loginfo("the collected data are: {}, {}".format(num1, num2))
	return response


if __name__=="__main__":
	rospy.init_node("server")
	rospy.loginfo("the server has been started")
	# 建立server對象
	server=rospy.Service('Sum', AddInts, doNum)
	rospy.spin() 

# 添權重限,配置檔案,編譯
# rosservice call sum "num1:10 num2:20"
           

3.Client實作

# <package>/<scripts>/<xx.py>-->demo02_server_p.py

#! usr/bin/env python

import rospy
from plumbing_server_client.srv import AddInts, AddIntsRequest, AddIntsResponse

if __name__=="__main__":
	rospy.init_node("client")
	client=rospy.ServiceProxy('Sum', AddInts)
	response = client.call(num1=10, num2=20)
	rospy.loginfo("the response data is {}".format(response.num3))

# 添權重限,配置檔案,編譯
           

3+.Client優化實作——可在執行節點時,動态傳入參數

在cmd中調用節點指令時,可附加上輸入的參數

#! usr/bin/env python

import rospy
from plumbing_server_client.srv import AddInts, AddIntsRequest, AddIntsResponse

if __name__=="__main__":
	if len(sys.argv) != 3:
		# argv為數組,需先判斷數組的長度;[0]是檔案名,[1],[2]對應着num1,num2
		rospy.logerr("Incoming data is incorrect")
		sys.exit(1)
	rospy.init_node("client")
	client=rospy.ServiceProxy('Sum', AddInts)
	num1=int(sys.argv[1])
	num2=int(sys.argv[2])
	#client.wait_for_service()
	#rospy.wait_for_service('Sum')
	# 等待伺服器啟動
	response=client.call(num1, num2)
	rospy.loginfo("the response data is {}".format(response.num3))		

# 添權重限,配置檔案,編譯
# rosrun plumbing_server_client demo02_client_py x y
           

注意事項

存在問題:若client先于server啟動,會抛出異常;若想令client先于server啟動時不要抛出異常而是挂起,等待伺服器

實作:ros中内置了相關函數,這些函數可以判斷伺服器的狀态,如果伺服器沒有啟動,那麼就讓用戶端挂起

1.使用client用戶端對象方法

client.wait_for_service()

2.使用rospy方法

rospy.wait_for_service('topic')

3.參數伺服器

概述

參數伺服器主要用于不同節點之間的資料共享,參數伺服器相當于時獨立于所有節點的一個公共容器,可以将資料存儲容器中,可以被不同節點所調用,不同節點也可以往裡存儲伺服器

應用場景:導航實作時,會進行路徑規劃;全局路徑規劃,設計一個從出發點到目标點的大緻路徑;本地路徑規劃,會根據目前路況實時生成行進的路徑

參數伺服器,一般用于存在資料共享的一些應用場景

概念:已共享的方式實作不同節點之間資料互動的通信模式

作用:存儲一些多節點共享的資料,類似于全局變量

案例:實作參數 增删改查操作

2.1ROS通信機制1.話題通信2.服務通信3.參數伺服器4.通信機制比較

參數可以使用資料類型

32-bit integers #4位元組整型資料
booleans #布爾值
strings #文本
doubles #浮點數
iso8601 dates #iso8601時間表示方法
lists #清單
dic #字典
base64-encoded binary data #以base64編碼的二進制資料
           

注意:參數伺服器不是為高性能而設計的,是以最好用于存儲靜态的非二進制的簡單資料

參數操作(python)

1.增&改

rospy.set_param(<key>, <value>)

# plumbing_param_server/scripts/demo01_param_set_p.py
#! usr/bin/env python

import rospy

if __name__=="__main__":
	rospy.init_node('param_set_p')
	rospy.set_param('type_p', 'common')
	rospy.set_param('radius_p', 0.15)
	# 新增兩組參數
	
# 添權重限,配置檔案,編譯
# rosrun
# rosparam list #列出目前參數-鍵
# rosparam get <key> #得到對應key的value
           

2.查詢參數

rospy.get_param(<key>, defaults)

rospy.get_param_cached(<key>, defaults)

rospy.get_param_names()

rospy.has_param(<key>)

# plumbing_param_server/scripts/demo02_param_get_p.py
#! /usr/bin/env python

import rospy

if __name__=="__main__":
	rospy.init_node("get_param_p")
	r=rospy.get_param('radius_p', 0.5)
	# 擷取key=radius_p的value,并且設定預設值為0.5
	p=rospy.get_param('radius', 0.5)
	r1=rospy.get_param_cached('radius_p', 0.5)
	# 從緩存裡查詢資料
	keys=rospy.get_param_names()
	# 擷取鍵,傳回清單?元組?
	bool1=rospy.has_param('radius_p')
	# 判斷key=radius_p是否存在傳回bool
	rospy.loginfo('radius_p = {}'.format(r))
	rospy.loginfo('radius = {}'.format(p))
	rospy.loginfo('radius_p1 = {}'.format(r1))
	
	for n in keys:
		rospy.loginfo('key = {}'.format(n))
	
	if bool1:
		rospy.loginfo('radius_p exist')
	else:
		rosypy.loginfo('radius_p doesn\'t exist ')

           

3.删除

rospy.delete_param(<key>)

# plumbing_param_server/scriptsdemo03_param_del_p.py
#! /usr/bin/env python

import rospy

if __name__=='__main__':
	rospy.init_node('del_param_p')
	try:
		rospy.delete_param('radius_p')	
	except Exception as e:
		rospy.loginfo('the data doesns\'t exist')
           

4.通信機制比較

三種通信機制中,參數伺服器是一種資料共享機制,可以在不同節點之間共享資料;話題通信和服務通信時在不同節點之間傳遞資料,三者時ROS中最基礎的通信機制

二者的實作流程設計四個要素

  • 消息的釋出方,客戶方publisher,client
  • 消息的訂閱方,伺服器subscriber,server
  • 話題名稱topic、service
  • 資料載體msg,src
topic service
通信模式 釋出/訂閱 請求/響應
同步性 異步 同步
底層協定 ROSTCP/ROSUDP ROSTCP/ROSUDP
緩沖區
時時性
節點關系 多對多 一對多
通信資料 msg srv
使用場景 連續高頻的資料釋出和接收 偶爾調用或執行的某一項功能