# 6.4 service in roscpp
## 6.4.1 Service通信
Service是一種請求-反饋的通信機制。請求的一方通常被稱為客戶端,提供服務的一方叫做服務器端。Service機制相比于Topic的不同之處在于:
1. 消息的傳輸是雙向的,有反饋的,而不是單一的流向。
2. 消息往往不會以固定頻率傳輸,不連續,而是在需要時才會向服務器發起請求。
在ROS中如何請求或者提供一個服務,我們來看`service_demo`的代碼:**一個節點發出服務請求(姓名,年齡),另一個節點進行服務響應,答復請求。**
## 6.4.2 創建Greeting服務
創建`service_demo/Greeting.srv`文件,內容包括:
```
string name #短橫線上邊部分是服務請求的數據
int32 age
--- #短橫線下面是服務回傳的內容。
string feedback
```
srv格式的文件創建后,也需要修改`CMakeLissts.txt`,在其中加入
```cmake
add_service_files(FILES Greeting.srv)
```
其余與添加msg的改動一樣。然后進行`catkin_make`,系統就會生成在代碼中可用的Greeting類型。在代碼中使用,只需要`#include <service_demo/Greeting.h>`,然后即可創建該類型的srv。
```cpp
service_demo::Greeting grt; //grt分為grt.request和grt.response兩部分
grt.request.name = "HAN"; //不能用grt.name或者grt.age來訪問
grt.request.age = "20";
...
```
新生成的Greeting類型的服務,其結構體的風格更為明顯,可以這么理解,一個Greeting服務結構體中嵌套了兩個結構體,分別是請求和響應:
```cpp
struct Greeting
{
struct Request
{
string name;
int age;
}request;
struct Response
{
string feedback;
}response;
}
```
## 6.4.3 創建提供服務節點(server)
`service_demo/srv/server.cpp`內容如下:
```cpp
#include <ros/ros.h>
#include <service_demo/Greeting.h>
bool handle_function(service_demo::Greeting::Request &req, service_demo::Greeting::Response &res){
//顯示請求信息
ROS_INFO(“Request from %s with age %d”, req.name.c_str(), req.age);
//處理請求,結果寫入response
res.feedback = “Hi ” + req.name + “. I’m server!”;
//返回true,正確處理了請求
return true;
}
int main(int argc, char** argv){
ros::init(argc, argv, “greetings_server”); //解析參數,命名節點
ros::NodeHandle nh; //創建句柄,實例化node
ros::ServiceServer service = nh.advertiseService(“greetings”, handle_function); //寫明服務的處理函數
ros::spin();
return 0;
}
```
在以上代碼中,服務的處理操作都寫在`handle_function()`中,它的輸入參數就是Greeting的Request和Response兩部分,而非整個Greeting對象。通常在處理函數中,我們對Requst數據進行需要的操作,將結果寫入到Response中。在roscpp中,處理函數返回值是bool型,也就是服務是否成功執行。不要理解成輸入Request,返回Response,在rospy中是這樣的。
## 6.4.4 創建服務請求節點(client)
`service_demo/srv/client.cpp`內容如下:
```cpp
# include "ros/ros.h"
# include "service_demo/Greeting.h"
int main(int argc, char **argv)
{
ros::init(argc, argv, "greetings_client");// 初始化,節點命名為"greetings_client"
ros::NodeHandle nh;
ros::ServiceClient client = nh.serviceClient<service_demo::Greeting>("greetings");
// 定義service客戶端,service名字為“greetings”,service類型為Service_demo
// 實例化srv,設置其request消息的內容,這里request包含兩個變量,name和age,見Greeting.srv
service_demo::Greeting srv;
srv.request.name = "HAN";
srv.request.age = 20;
if (client.call(srv))
{
// 注意我們的response部分中的內容只包含一個變量response,另,注意將其轉變成字符串
ROS_INFO("Response from server: %s", srv.response.feedback.c_str());
}
else
{
ROS_ERROR("Failed to call service Service_demo");
return 1;
}
return 0;
}
```
以上代碼比較關鍵的地方有兩處,一個是建立一個ServiceClient,另一個是開始調用服務。建立client需要用`nh.serviceClient<service_demo::Greeting>("greetings")`,指明服務的類型和服務的名稱。而調用時可以直接用`client.call(srv)`,返回結果不是response,而是是否成功調用遠程服務。
`CMakeLists.txt`和`pacakge.xml`修改方法和`topic_demo`修改方法類似,不再贅述。
- 前言
- 第一章 ROS簡介
- 機器人時代的到來
- ROS發展歷程
- 什么是ROS
- 安裝ROS
- 安裝ROS-Academy-for-Beginners教學包
- 二進制與源碼包
- 安裝RoboWare Studio
- 單元測試一
- 第二章 ROS文件系統
- Catkin編譯系統
- Catkin工作空間
- Package軟件包
- CMakeLists.txt
- package.xml
- Metapacakge軟件元包
- 其他常見文件類型
- 單元測試二
- 第三章 ROS通信架構(一)
- Node & Master
- Launch文件
- Topic
- Msg
- 常見msg類型
- 單元測試三
- 第四章 ROS通信架構(二)
- Service
- Srv
- Parameter server
- Action
- 常見srv類型
- 常見action類型
- 單元測試四
- 第五章 常用工具
- Gazebo
- RViz
- Rqt
- Rosbag
- Rosbridge
- moveit!
- 單元測試五
- 第六章 roscpp
- Client Library與roscpp
- 節點初始、關閉與NodeHandle
- Topic in roscpp
- Service in roscpp
- Param in roscpp
- 時鐘
- 日志與異常
- 第七章 rospy
- Rospy與主要接口
- Topic in rospy
- Service in rospy
- Param與Time
- 第八章 TF與URDF
- 認識TF
- TF消息
- tf in c++
- tf in python
- 統一機器人描述格式
- 附錄:TF數學基礎
- 三維空間剛體運動---旋轉矩陣
- 三維空間剛體運動---歐拉角
- 三維空間剛體運動---四元數
- 第九章 SLAM
- 地圖
- Gmapping
- Karto
- Hector
- 第十章 Navigation
- Navigation Stack
- move_base
- costmap
- Map_server & Amcl
- 附錄:Navigation工具包說明
- amcl
- local_base_planner
- carrot_planner
- clear_costmap_recovery
- costmap_2d
- dwa_local_planner
- fake_localization
- global_planner
- map_server
- move_base_msg
- move_base
- move_slow_and_clear
- navfn
- nav_core
- robot_pose_ekf
- rotate_recovery