ROS系統學習4---最小服務系統的製作
阿新 • • 發佈:2019-02-17
上一篇文章我們介紹了ros最小話題系統的製作,本篇將進一步介紹ROS的另一種節點間的互動形式---服務
首先,什麼是服務?
它是節點間的另外一種互動方式(這是句廢話。。。),它提供了一種有應答的通訊方式。
其次,為什麼要有它?
這個問題比較深奧,我們得先回頭去看看“話題”的特點。
話題是單向的,按照一定頻率傳送的一種通訊方式。在這種方式下,發出訊息的一方是不知道訊息有沒有人收到的。另一方面,如果只想傳送一次比較重要的訊息,也是辦不到的。
因此,我們可以做出這樣的類比,話題有點像是一種被封裝過了的UDP傳輸機制,而服務則像是一種被封裝過的TCP機制。注意這裡我說的是“像”,這是因為它們的底層其實並沒有想象的這麼簡單,以後本人研究過後會專門做這部分的介紹。
下面,我們將製作一個最小的服務系統,來看看服務該怎麼用起來。
這個系統是這樣的,我們製作一個伺服器,該伺服器接收三個整數,然後輸出三個整數的和(也是一個整數)。
客戶端通過請求服務,將要做加法的三個數給伺服器,然後伺服器返回結果給它。
首先強調一下,本篇文章的工作空間和包沿用第二篇文章的。
在製作的過程中,我們需要定義一個service檔案,該檔案告訴ROS我們這個伺服器的輸入輸出是什麼東西。具體的,在包“printHelloRosPK”中,新建一個叫做“srv”的資料夾,然後在裡面建立一個檔案,名字隨便取,本文取的“add.srv”。因為我們要輸入3個整數,輸出它們的和,因此檔案的內容如下:
int32 A
int32 B
int32 C
---
int32 sum
前三行是我們要輸入的三個整數,第四行是分割,第五行是輸出。
另外,由於我們在第二篇文章建立包的時候沒有包含服務需要的依賴項,因此需要加進去,方法是開啟包下面的“package.xml”,然後將下面一句話新增進去。
<build_depend>message_generation</build_depend>
然後開啟CMakeLists.txt,找到
find_package(catkin REQUIRED COMPONENTS
roscpp
std_msgs
)
新增 message_generation,變成
find_package(catkin REQUIRED COMPONENTS
roscpp
std_msgs
message_generation
)
搜尋"srv"關鍵字,看到如下的程式碼
## Generate services in the 'srv' folder
# add_service_files(
# FILES
# Service1.srv
# Service2.srv
# )
把“#”去掉,然後修改檔名稱,修改後如下:
# Generate services in the 'srv' folder
add_service_files(
FILES
add.srv
)
找到
# generate_messages(
# DEPENDENCIES
# std_msgs
# )
把註釋去掉
generate_messages(
DEPENDENCIES
std_msgs
)
這樣準備工作就做完了,我們可以檢查ROS是否能夠識該服務描述。輸入:
rossrv show add
成功的話輸出如下:
接著編寫伺服器和客戶端:
service.cpp
#include "ros/ros.h"
#include "printHelloRosPK/add.h"
//服務主功能函式,輸入為client給的資料,輸出處理結果
bool add(printHelloRosPK::add::Request &req,
printHelloRosPK::add::Response &res)
{
res.sum = req.A + req.B+ req.C;
ROS_INFO("request: x=%ld, y=%ld, z=%ld", (long int)req.A, (long int)req.B, (long int)req.C);
ROS_INFO("sending back response: [%ld]", (long int)res.sum);
return true;
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "service");
ros::NodeHandle n;
ros::ServiceServer service = n.advertiseService("add", add);//建立service,並在ROS內釋出出來
ROS_INFO("Ready to add three ints.");
ros::spin();
return 0;
}
client.cpp
#include "ros/ros.h"
#include "printHelloRosPK/add.h"//由編譯系統自動根據我們先前建立的srv檔案生成的對應該srv檔案的標頭檔案
#include <cstdlib>
int main(int argc, char **argv)
{
ros::init(argc, argv, "add_three_ints_client");
ros::NodeHandle n;
//為add_three_ints_service建立一個client。ros::ServiceClient物件待會用來呼叫service。
ros::ServiceClient client = n.serviceClient<printHelloRosPK::add>("add");
printHelloRosPK::add srv; //例項化一個由ROS編譯系統自動生成的service類,並給其request成員賦值
srv.request.A = 1;
srv.request.B = 2;
srv.request.C = 3;
//呼叫service。由於service的呼叫是模態過程(呼叫的時候佔用程序阻止其他程式碼的執行),一旦呼叫完成,將返回呼叫結果。
//如果service呼叫成功,call()函式將返回true,srv.response裡面的值將是合法的值。
//如果呼叫失敗,call()函式將返回false,srv.response裡面的值將是非法的
if (client.call(srv))
{
ROS_INFO("Sum: %ld", (long int)srv.response.sum);
return 0;
}
else
{
ROS_ERROR("Failed to call service add_three_ints");
return 1;
}
}
在CMakeLists.txt末尾新增檔案位置及依賴關係:
add_executable(service /home/weixin/HelloRos/src/printHelloRosPK/src/service.cpp)#定義了這個工程會生成一個檔名為"topicSend"的可執行檔案
target_link_libraries(service ${catkin_LIBRARIES})#指定在連結目標檔案的時候需要連結的外部庫
add_dependencies(service beginner_tutorials_generate_messages_cpp)#為可執行檔案新增對生成的訊息檔案的依賴
add_executable(client /home/weixin/HelloRos/src/printHelloRosPK/src/client.cpp)
target_link_libraries(client ${catkin_LIBRARIES})
add_dependencies(client beginner_tutorials_generate_messages_cpp)
接著編譯下就可以了:
catkin_make