業(yè)務(wù)與數(shù)據(jù)
在Service通訊模型中,我們通常都是Client將數(shù)據(jù)發(fā)送給Server,Server經(jīng)過(guò)業(yè)務(wù)邏輯處理,將結(jié)果返回給client。如下圖:

在此處,我們需要特別關(guān)注的就是傳輸過(guò)程中的Request和Response,這兩個(gè)都是數(shù)據(jù),一個(gè)是請(qǐng)求的數(shù)據(jù),一個(gè)是響應(yīng)的數(shù)據(jù)。從數(shù)據(jù)的角度來(lái)說(shuō),數(shù)據(jù)由業(yè)務(wù)所產(chǎn)生,但不應(yīng)該與業(yè)務(wù)無(wú)關(guān),應(yīng)該與規(guī)范相關(guān),其實(shí)就是定義規(guī)范來(lái)限制數(shù)據(jù)類(lèi)型,來(lái)規(guī)范業(yè)務(wù)間的通訊。
在此,ROS提供的是srv數(shù)據(jù)來(lái)做此操作,如下圖:

在數(shù)據(jù)交互過(guò)程中的請(qǐng)求階段,我們將整個(gè)包當(dāng)成一個(gè)srv,包含了request和response,這個(gè)階段交給client端去填充request的數(shù)據(jù)。
在數(shù)據(jù)交互過(guò)程中的server處理階段,server拿到client發(fā)送的srv包,從中獲得request數(shù)據(jù),根據(jù)業(yè)務(wù)邏輯來(lái)去處理操作數(shù)據(jù)。
在數(shù)據(jù)交互過(guò)程中的響應(yīng)階段,將server操作的結(jié)果填充到srv的response,將srv返回。
在這三個(gè)階段中,srv自始至終就是一個(gè)數(shù)據(jù)包,規(guī)范了client的數(shù)據(jù)填充,也規(guī)范了server的數(shù)據(jù)填充。
在ROS中對(duì)于Service通訊模式的數(shù)據(jù)類(lèi)型,系統(tǒng)提供了一些現(xiàn)成的類(lèi)型供我們參考和使用。
查詢(xún)所有的消息類(lèi)型
rossrv list
可以查詢(xún)出當(dāng)前支持的所有消息類(lèi)型。例如我們用到過(guò)的roscpp_tutorials/TwoInts
查詢(xún)消息類(lèi)型的數(shù)據(jù)結(jié)構(gòu)
我們還可以對(duì)一個(gè)消息的數(shù)據(jù)結(jié)構(gòu)進(jìn)行查詢(xún)。
rossrv show roscpp_tutorials/TwoInts
顯示的結(jié)果為:
int64 a
int64 b
---
int64 sum
結(jié)果顯示分為兩個(gè)部分,中間用---分隔。
上面部分是request的數(shù)據(jù)規(guī)范。
下面部分是response的數(shù)據(jù)規(guī)范。
發(fā)散與探討
我們?cè)谇懊婵梢园l(fā)現(xiàn),ros系統(tǒng)還是提供了大量的數(shù)據(jù)類(lèi)型供我們使用。但是數(shù)據(jù)類(lèi)型再多,很有可能也滿(mǎn)足不了我的實(shí)際業(yè)務(wù)場(chǎng)景,這個(gè)時(shí)候,我們就需要定制自己的數(shù)據(jù)類(lèi)型了。
在Ros中,如果沒(méi)有現(xiàn)成的消息類(lèi)型來(lái)描述要去傳遞的消息時(shí),我們會(huì)自定義消息。
我們會(huì)新建一個(gè)Package來(lái)去自定義消息,通常這個(gè)Package寫(xiě)任何的業(yè)務(wù)邏輯,只是用來(lái)聲明自定義的消息類(lèi)型,可以只定義一種消息類(lèi)型,也可以定義多種消息類(lèi)型,根據(jù)業(yè)務(wù)需求來(lái)定。
所以,首先我們單獨(dú)的創(chuàng)建一個(gè)package,我們?nèi)∶麨?code>demo_srvs,一定要要添加roscpp,rospy,rosmsg的依賴(lài)。
這個(gè)包名取名也是有講究的,業(yè)務(wù)名_srvs。
自定義消息流程
1 . 創(chuàng)建srv目錄,移除不需要的目錄
在pakage目錄下新建srv目錄,刪除掉include和src目錄
2. 新建.srv文件
創(chuàng)建的這個(gè)NumOption.srv文件就是自定義消息文件,需要去描述消息的格式。
我們可以編輯代碼如下
float64 a
float64 b
string option
---
float64 result
這個(gè).srv文件以---分隔為兩部分,上面一部分包含a,b,option,下面一部分包含一個(gè)result.
在這里,上面部分是request的數(shù)據(jù),下面部分是response的數(shù)據(jù)。
此案例中,我們要去做的就是,發(fā)送request,例如,a=3,b=3,option=*,那么server端接收到數(shù)據(jù)后,做a option b 的操作,即3 * 3,結(jié)果放到response中。
這個(gè)srv文件遵循一定規(guī)范的,每一行表示一種數(shù)據(jù)。前面是類(lèi)型,后面是名稱(chēng)。和msg的規(guī)范一致
ros不只是提供了int64和string兩種基本類(lèi)型供我們描述,其實(shí)還有很多:
| msg類(lèi)型 | C++對(duì)應(yīng)類(lèi)型 | Python對(duì)應(yīng)類(lèi)型 |
|---|---|---|
bool |
uint8_t |
bool |
int8 |
int8_t |
int |
int16 |
int16_t |
int |
int32 |
int32_t |
int |
int64 |
int64_t |
int,long
|
uint8 |
uint8_t |
int |
uint16 |
uint16_t |
int |
uint32 |
uint32_t |
int |
uint64 |
uint64_t |
int,long
|
float32 |
float |
float |
float64 |
float |
float |
string |
std:string |
str,bytes
|
time |
ros:Time |
rospy.Time |
duration |
ros::Duration |
rospy.Duration |
3. 配置package.xml文件
在package.xml種添加如下配置:
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
message_generation是消息生成工具,在打包編譯時(shí)會(huì)用到
message_runtime運(yùn)行時(shí)消息處理工具
4. 配置CMakeLists.txt
在find_package添加message_generation,結(jié)果如下:
find_package(catkin REQUIRED COMPONENTS
roscpp
rosmsg
rospy
message_generation
)
添加add_message_file,結(jié)果如下:
add_service_files(
FILES
NumOption.srv
)
這里的NumOption.srv要和你創(chuàng)建的srv文件名稱(chēng)一致,且必須時(shí)在srv目錄下,否則編譯會(huì)出現(xiàn)問(wèn)題
添加generation_msg,結(jié)果如下:
generate_messages(
DEPENDENCIES
std_msgs
)
這個(gè)配置的作用是添加生成消息的依賴(lài),默認(rèn)的時(shí)候要添加std_msgs
修改catkin_package,結(jié)果如下:
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES demo_msg
# CATKIN_DEPENDS roscpp rosmsg rospy
# DEPENDS system_lib
CATKIN_DEPENDS message_runtime
)
為catkin編譯提供了依賴(lài)message_runtime
檢驗(yàn)自定義消息
1. 編譯項(xiàng)目
來(lái)到工作空間目錄下,運(yùn)行編譯
catkin_make
2. 查看生成的頭文件
來(lái)到devel的include目錄下,如果生成了頭文件說(shuō)明,自定義消息創(chuàng)建成功。
3. 通過(guò)rossrv工具校驗(yàn)
rossrv show demo_srvs/NumOption
查看運(yùn)行結(jié)果,運(yùn)行結(jié)果和自己定義的相一致,說(shuō)明成功。