iT邦幫忙

2021 iThome 鐵人賽

DAY 10
0
Arm Platforms

ROS with Deep learning 開發與實戰系列 第 10

Day 10 ROS Cpp Service

今天要來講 Cpp Service 的部分,Service 是一種一問一答的通訊方式,請求的一方是客戶端,提供資料的叫做伺服器,在這邊幫大家複習一下 Service 跟 Topic 的差異在於:

  • 訊息的傳輸是雙向的,是會回傳資訊回來的。
  • 訊息通常不會連續傳輸,而是在客戶端請求時才傳送。

Demo

今天要做的是去模擬一個客戶端跟伺服器互相聊天的過程。而創建的過程跟昨天類似,不熟悉的人可以去看一下昨天的,下面是待會的順序。

  • package
  • srv
  • server.cpp
  • client.cpp
  • CMakeList.txt & package.xml

Package

首先我們需要建立一個套件包

cd ~/catkin_ws/src
catkin_create_pkg service_demo roscpp rospy std_msgs

srv

接下來要創建資料夾跟 srv檔案

cd service_demo
mkdir srv
cd srv
nano Greeeting.srv

接下來一樣去定義他的資料結構

string name
int32 age
---
string feedback

這邊先提一下,在編譯以後,他一樣會自動生成幾個 .hg 檔, 但是因為他是 service , 所以會有全部的 Greeeting.h 、 請求的 GreeetingRequest.h 和 發送回復的 GreeetingResponse.h 。它的位置在 ~/catkin_ws/devel/include/service_demo/ 裡面,我們以後要用的時候就是去 include 他。

server.cpp

在定義好通訊方式的結構後,我們要開始寫伺服器的部分。

//引用套件
# include <ros/ros.h>
# include <service_demo/Greeting.h>

// 定義請求處理的 function,我們定義的是 bool function ,如果正確回全 true,錯誤則相反
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);
	
	// 處理請求,並將結果寫到 回應 裡面 ,跟客戶端說 嗨~
	res.feedback = "Hi " + req.name + ". I'm server!";
    // 回復正確,表示正確的完成了請求
	return true;
}

int main(int argc, char **argv)
{
	// 初始化參數,第三個參數位置是節點名稱
	ros::init(argc, argv, "greetings_server");
	


    // 創建一個把手,讓我們可以在後面輕鬆地來處理節點
	ros::NodeHandle nh;
    
    	// 定義 service 的 伺服器 ,service 名稱為 “greetings” ,收到請求之後把值傳給handle_function 進行處理
	ros::ServiceServer service = nh.advertiseService("greetings", handle_function);
	
	// 重複查詢是否要跑
	ros::spin();

	return 0;
}


client.cpp

在定義好 伺服器,開始定義客戶端啦

//引用套件
# include "ros/ros.h"
# include "service_demo/Greeting.h"

int main(int argc, char **argv)
{
	// 初始化參數,第三個參數位置是節點名稱
	ros::init(argc, argv, "greetings_client");
	
	ros::NodeHandle nh;
    
    // 定義 伺服器的 客戶端,service 名字為 “greetings”,service 類型為 Service_demo
	ros::ServiceClient client = nh.serviceClient<service_demo::Greeting>("greetings");
	
//  設置 srv 請求消息的內容,這裡 request 包含兩個變數,name 和 age。
	srv.request.name = "HAN";
	srv.request.age = 20;
 
	if (client.call(srv))
	{
		// 注意我們請求的內容只包含一個變數 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;
}

我們可以去把 srv 裡面的檔案想成這樣:

struct Greeting
{
    struct Request
    {
        string name;
        int age;
    }request;
    struct Response
    {
        string feedback;
    }response;
}

它裡面有兩個結構,一個是 Request 一個是 Response ,然後裡面又各自是各自的東西。

client.call 是去跟我們的伺服器去聊天,如果伺服器有回他,沒有以讀不回,就代表成功了~

CMakeList.txt & package.xml

修改 CMakeList.txt & package.xml 的部分跟昨天是一樣的,所以這邊就不講啦! 忘記的話可以去看一下昨天的部分來複習。

結語

今天就到這邊了~ 明天繼續看 Ros Cpp ~


上一篇
Day9 Topic in Cpp
下一篇
Day 11 ROS Cpp Parameter Server
系列文
ROS with Deep learning 開發與實戰11

尚未有邦友留言

立即登入留言