【ROS学习8(Service)】服务数据service的定义与使用

服务数据的定义与使用:

在这里插入图片描述
由于先前的话题通讯机制适合在通讯频率高的场景下使用,因此我们对Person话题消息的发布与接收也是不断执行的,
但在某些场景下这种高频的通讯方式或许不太合适,我们希望每请求一次,服务才被执行一次。

因此本次我们使用Service通讯机制:
Client请求一个服务,服务内容为某人信息,Server实现这个服务并给予显示(执行一次),并将执行成功与否Response给Client

自定义服务数据Person:

➢定义srv文件:Person.srv

string name
uint8 age
uint8 sex
uint8 unknown =0
uint8 male= 1
uint8 female = 2
“- - -”
string result

msg的区别在于srv分两部分,
“- - -”之上为Request,
“- - -”之下为“Response”

➢ 在package.xml中添加功能包依赖(和msg的操作相似)
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>  
➢ 在CMakeLists.txt添加编译选项(和msg的操作相似)
find_package( ...... message_generation)

add_service_files(FILESPerson.srv)
generate_messages(DEPENDENCIES std_msgs)

catkin_package(...... message_runtime)
➢ 编译:
catkin_make

编译成功后进入devel/include/learning_service,动态产生三个.h文件
在这里插入图片描述
和msg的不同,其中还包括Request和Response部分:

PersonRequest.h中的请求数据:
在这里插入图片描述
PersonResponse.h中的回应数据:

在这里插入图片描述
Person.h中包括了y以上两个头文件Response和Request,因此调用时只需包括Person.h
在这里插入图片描述

创建Client端代码

person_client.cpp
代码实现:

/** * 该例程将请求/show_person服务,服务数据类型learning_service::Person */ 
#include <ros/ros.h>
#include "learning_service/Person.h"
//包含头文件 

int main(int argc, char** argv)
{
    
        
    // 初始化ROS节点	
    ros::init(argc, argv, "person_client");     
    // 创建节点句柄	
    ros::NodeHandle node; 	 
    ros::service::waitForService("/show_person");
    
    //等待服务该服务的服务端出现    
    // 发现/show_person服务后,创建客户端person_client ,连接名为/show_person的service	
    ros::ServiceClient person_client = node.serviceClient<learning_service::Person>("/show_person");
         
    // 初始化learning_service::Person的请求数据	
    learning_service::Person srv;	
    srv.request.name = "Tom";	
    srv.request.age  = 20;	
    srv.request.sex  = learning_service::Person::Request::male;     
    
    // 打印请求服务调用信息
    ROS_INFO("Call service to show person[name:%s, age:%d, sex:%d]",srv.request.name.c_str(), srv.request.age, srv.request.sex);
    person_client.call(srv);//等待Response 	
    
    // 显示服务调用结果	
    ROS_INFO("Show person result : %s", srv.response.result.c_str());
    
    return 0;
}

创建Server端代码

person_server.cpp:
代码实现:

/** * 该例程将执行/show_person服务,服务数据类型learning_service::Person */ 
#include <ros/ros.h>
#include "learning_service/Person.h" 

// service回调函数,输入参数req,输出参数res
bool personCallback(learning_service::Person::Request  &req,         			learning_service::Person::Response &res)
{
    
        
    // 显示请求数据    
    ROS_INFO("Person: name:%s  age:%d  sex:%d", req.name.c_str(), req.age, req.sex); 	
    // 设置反馈数据	
    res.result = "OK";     
    return true;
} 

int main(int argc, char **argv)
{
    
        
    // ROS节点初始化    
    ros::init(argc, argv, "person_server");     
    // 创建节点句柄    
    ros::NodeHandle n;
         
    // 创建一个名为/show_person的server,注册回调函数personCallback
    ros::ServiceServer person_service = n.advertiseService("/show_person", personCallback);     
    
    // 循环等待回调函数    
    ROS_INFO("Ready to show person information.");    
    ros::spin();  //不断等待Request,接收到请求便进入回调函数,循环。     
    return 0;
}

CMakeLists:

add_executable(person_serversrc/person_server.cpp)
target_link_libraries(person_server${catkin_LIBRARIES})
add_dependencies(person_server ${PROJECT_NAME}_gencpp) 

add_executable(person_clientsrc/person_client.cpp)
target_link_libraries(person_client${catkin_LIBRARIES})
add_dependencies(person_client ${PROJECT_NAME}_gencpp)

编译

运行:

roscore
rosrun learning_service person_server
rosrun learning_service person_client

Client端:
在这里插入图片描述
Server端:在这里插入图片描述
如果我们先执行Client端,发送服务请求,由于没有服务端接收该服务,程序便一直停留在waitForService函数中等待:
在这里插入图片描述
直到Server端注册了相同服务的回调函数(因此服务名要相同!!),且注册一次就不用重复注册:在这里插入图片描述

总结

最后,我们再比较一下Topic和Service的不同作为总结:

ROS node 之间的通讯形式主要包括两种:TopicService

Topic通讯时,不同的 node 可以向同一个 topic 上发送、接收数据,发送数据的 node 不知道数据是从哪个 node 发送过来的,同样地,发送数据的 node 也不知道是哪个 node 接收了数据。因此,每个 node 都是相对独立的,只需要负责自己的功能实现以及外部接口,不需要关心其他 node 的行为。这是一种开放式的收、发数据的方式,也是 node 之间通讯的主要形式,有利于构造分布式大系统。

service 则是一种请求+反馈的通信机制。消息的传输只涉及两个 节点:发送请求的一方称为 client,提供服务的一方叫做 server。在通过 service 形式进行通讯时,client 首先向 server 请求服务, 收到消息之后 server 运行事先设置好的服务功能,并返回Response给 client。
service 通讯一般用在事件触发情景中,例如满足某个条件就令 node 开启某项功能,并希望确认功能确实顺利开启。

在这里插入图片描述

参考博客:
ROS Service vs Topic
ros–topic和service区别
ROS学习笔记6~Topic(话题) 和Service(服务)的区别

学习记录blog,若存在理解有误的地方,还请各位大佬指正 :–)

おすすめ

転載: blog.csdn.net/SESESssss/article/details/105614553