1、service通信简介
topic是ROS中的一种单向的异步通信方式。Service是一种请求-反馈的通信机制。请求的一方通常被称为客户端,提供服务的一方叫做服 务器端。
Service机制相比于Topic的不同之处在于:
- 消息的传输是双向的,有反馈的,而不是单一的流向。
- 消息往往不会以固定频率传输,不连续,而是在需要时才会向服务器发起请求。
service包括两部分,一部分是请求方(Clinet),另 一部分是应答方/服务提供方(Server)。这时请求方(Client)就会发送一个request,要等 待server处理,反馈回一个reply,这样通过类似“请求-应答”的机制完成整个服务通信。
这种通信方式的示意图如下:
Node B是server(应答方),提供了一个服务的接口,叫做 /Service ,我们一般都会用 string类型来指定service的名称,类似于topic。Node A向Node B发起了请求,经过处理后得 到了反馈。
过程
Service是同步通信方式,所谓同步就是说,此时Node A发布请求后会在原地等待reply,直到 Node B处理完了请求并且完成了reply,Node A才会继续执行。Node A等待过程中,是处于 阻塞状态的成通信。这样的通信模型没有频繁的消息传递,没有冲突与高系统资源的占用, 只有接受请求才执行服务,简单而且高效。
2、service demo 实例
(1)创建service_demo package
进入工作空间的src文件夹
$ catkin_create_pkg service_demo_jone roscpp rospy std_msgs
# catkin_create_pkg 是创建package的命令
#service_demo_jone 是package的名称
#roscpp rospy std_msgs 依赖项
AI 代码解读
此时会在src文件夹下生成service_demo_jone文件夹
下面会有自动生成的相应文件
(2)创建.srv文件
在service_demo_jone文件夹下创建srv文件夹,用于存放.srv文件。
创建一个文件Greeting.srv文件。
里面写入
string name #短横线上边部分是服务请求的数据 即客户端发给服务器的数据
int32 age
--- #短横线下面是服务回传的内容。 即服务器回传给客户端的数据
string feedback
AI 代码解读
然后编译生成cpp可以include的.h文件
在 CMakeLissts.txt 中加入
find_package(catkin REQUIRED COMPONENTS #需要找个整个函数添加相应的依赖
roscpp
rospy
std_msgs
message_generation # 需要添加的地方
)
add_service_files(
FILES
Greeting.srv #自己定义的.srv文件
)
generate_messages(
DEPENDENCIES
std_msgs #由于定义的文件中用到了string、int32 关节字 所以必须要引入该依赖项
)
AI 代码解读
在package.xml文件中加入
<build_depend>message_generation</build_depend> <!-- #generate new msg must add-->
<exec_depend>message_runtime</exec_depend> <!-- #generate new msg must add-->
AI 代码解读
然后回到工作空间 进行 编译
$ catkin_make
AI 代码解读
编译完成后
会在在图片路径下生成如下文件
新生成的Greeting类型的服务,其结构体的风格更为明显,可以这么理解,一个Greeting服务 结构体中嵌套了两个结构体,分别是请求和响应:
struct Greeting
{
struct Request
{
string name;
int age;
}request;
struct Response
{
string feedback;
}response;
}
AI 代码解读
(3)创建服务 提供节点 server.cpp
#include <ros/ros.h>
#include <service_demo_jone/Greeting.h>
//服务的处理函数
bool handle_function(service_demo_jone::Greeting::Request &req,service_demo_jone::Greeting::Response &res){ //用到service的参数的固定写法
//从中可以拿到请求的数据 ,req.name req.age
ROS_INFO("Request from %s with age %d",req.name.c_str(),req.age ); //显示请求信息
//赋值返回 变量
res.feedback = "Hi!"+req.name+". I'm server!";//处理请求,结果写入response
return true; //返回true,正确处理了请求
}
int main(int argc, char** argv){ //主函数
ros::init(argc, argv, "greeting_server"); //声明节点名称 greeting_server
ros::NodeHandle nd; //创建句柄,实例化node
ros::ServiceServer service=nd.advertiseService("greeting",handle_function); //写明服务的处理函数 handle_function greeting是service的名称
ros::spin(); //轮询 查询请求 有请求时 调用 服务的处理函数 handle_function
return 0;
}
AI 代码解读
在以上代码中,服务的处理操作都写在 handle_function() 中,它的输入参数就是Greeting的 Request和Response两部分,而非整个Greeting对象。通常在处理函数中,我们对Requst数 据进行需要的操作,将结果写入到Response中。在roscpp中,处理函数返回值是bool型,也 就是服务是否成功执行。
(4)创建服务请求节点(client.cpp)
#include "ros/ros.h"
#include "service_demo_jone/Greeting.h"
int main(int argc, char **argv)
{
ros::init(argc, argv, "greeting_client");//声明节点名称 greeting_client
ros::NodeHandle nh;//创建句柄,实例化node
ros::ServiceClient client = nh.serviceClient<service_demo_jone::Greeting>("greeting"); // 定义service客户端,service名字为“greeting”
// 实例化srv,设置其request消息的内容,这里request包含两个变量,name和age,见Greeting.srv
service_demo_jone::Greeting srv;
srv.request.name="jone";
srv.request.age=27;
if(client.call(srv))//调用服务。
{
// 注意我们的response部分中的内容只包含一个变量feedback,另,注意将其转变成字符串
ROS_INFO("Response from server : %s",srv.response.feedback.c_str());
}
else
{
ROS_INFO("Failed to call service Service_demo_jone");
return 1;
}
return 0;
}
AI 代码解读
(5)修改CMakeList.txt
add_executable(greeting_server src/server.cpp )
#必须添加add_dependencies,否则找不到自定义的msg产生的头文件
add_dependencies(greeting_server ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(greeting_server ${catkin_LIBRARIES})
add_executable(greeting_client src/client.cpp )
add_dependencies(greeting_client ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(greeting_client ${catkin_LIBRARIES})
AI 代码解读
(6)编译
回到工作空间
$ catkin_make
AI 代码解读
3、测试
启动ros
$ roscore
AI 代码解读
检测是否生成package
$ rospack list
AI 代码解读
在列表里有刚做的package
运行greeting_server节点
$ rosrun service_demo_jone greeting_server
AI 代码解读
运行greeting_client节点
$ rosrun service_demo_jone greeting_client
AI 代码解读
当运行greeting_client节点时
收到并打印服务器反馈的信息
同时greeting_server节点打印 服务器此时的信息
此时说明在ros中创建service服务成功。
查看此时服务列表
$ rosservice list
AI 代码解读
有在代码中创建的服务
查看该服务信息
$ rosservice info /greeting
AI 代码解读