企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# 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`修改方法类似,不再赘述。