ROS 服务Server

1背景知识

1.1 服务是什么

  ROS程序由多个功能组成;一个功能由多个节点完成;各节点的功能独立,节点与节点间通过不同的通信方式,实现数据的传输,完成功能。即总功能由分功能组成,各分功能由节点的子功能及节点间的通信完成。
  服务是一种节点与节点间进行一对一双向传输的数据通信方式,数据通过服务的请求与响应实现传送。

1.2 服务的通信机制

  参与节点及节点功能:

  1. 服务端节点Server:提供服务。
  2. 客户端节点Client: 请求服务。
  3. 节点管理器ROS Master:保管节点注册信息,匹配话题的订阅者和发布者,并帮助服务端和客户端的建立连接。
    在这里插入图片描述

  五步骤如下:

步骤步骤内容类比
1.服务端Server注册向节点管理器ROS Master注册相关信息,包括:节点信息、提供的服务在婚姻介绍所登记信息
2.客户端Client注册向节点管理器ROS Master注册相关信息,包括:节点信息、请求的服务在婚姻介绍所登记信息
3.节点管理器进行话题匹配保管注册信息,匹配服务相同的Server和Client,通过RPC向Client发送Server的TCP地址婚姻介绍所匹配信息,推荐相亲对象
4.客户端请求服务Client通过TCP,与Server建立网络连接,发送请求数据看对眼了,加微信
5.服务端提供服务Server 接收、解析请求的数据,并产生响应结果返回给 Client通过好友请求,开始聊天

1.3 服务通信的特点

  服务实现一对一,双向的通信,客户端请求服务,服务端响应服务,处理得到的反馈,并将反馈返回给请求服务的客户端。通信通过反馈实现数据的双向流通。
  服务是一种同步通信方式,客户端请求服务,服务端立即响应服务,在服务端未处理完请求前,客户端将等待,直到服务端反馈请求的数据,客户端才会继续执行程序。

1.4 验证

打开一终端,运行roscore

$ roscore

打开另一终端,运行turtlesim_node节点

$ rosrun turtlesim turtlesim_node 
[ INFO] [1681894353.864916325]: Starting turtlesim with node name /turtlesim
[ INFO] [1681894353.871969072]: Spawning turtle [turtle1] at x=[5.544445], y=[5.544445], theta=[0.000000]

再启另一终端,查看/turtlesim 节点提供的服务,并请求/spawn服务

$ rosnode info /turtlesim 
--------------------------------------------------------------------------------
Node [/turtlesim]
Publications: 
 * /rosout [rosgraph_msgs/Log]
 * /turtle1/color_sensor [turtlesim/Color]
 * /turtle1/pose [turtlesim/Pose]

Subscriptions: 
 * /turtle1/cmd_vel [unknown type]

Services: 
 * /clear
 * /kill
 * /reset
 * /spawn
 * /turtle1/set_pen
 * /turtle1/teleport_absolute
 * /turtle1/teleport_relative
 * /turtlesim/get_loggers
 * /turtlesim/set_logger_level


contacting node http://ubuntu:39225/ ...
Pid: 20104
Connections:
 * topic: /rosout
    * to: /rosout
    * direction: outbound (41501 - 127.0.0.1:34348) [24]
    * transport: TCPROS

$ rosservice info /spawn 
Node: /turtlesim
URI: rosrpc://ubuntu:37257
Type: turtlesim/Spawn
Args: x y theta name

$ rosservice call /spawn 3 6 7.8 "hello"
name: "hello"

在这里插入图片描述
  上述过程中, /turtlesim 节点提供了服务/spawn,服务/spawn能够生成新的乌龟,并返回新乌龟的名字,表明请求服务成功。

  服务通过请求与响应实现数据传递,例如:查看服务/spawn传递的数据:

$ rossrv show turtlesim/Spawn 
float32 x
float32 y
float32 theta
string name
---
string name




前提ROS 创建工作空间和软件包
  当前所处软件包为beginner_tutorials,该软件包的文件系统结构如下图:
在这里插入图片描述

2 自定义服务Server

  服务消息的数据结构:由两组数据构成 ; 两组由仅包含三个破折号的一行为界, - - -上为请求,- - -下为响应。例如:请求"两数相加的和"服务中,其AddTwoNumber.srv文件如下:

int32 a
int32 b
- - -
int32 sum

  自定义服务的文件的后缀为.srv。

2.1 创建srv文件夹 ,并编辑.srv文件**

  创建srv文件夹和两数相加之和的.srv文件

$ roscd beginner_tutorials          //进入软件包
$ mkdir srv                        //新建msg 目录  放置消息
$ touch AddTwoNumber.srv

  编辑AddTwoNum.srv文件,内容如下:

int32 a
int32 b
---
int32 sum
2.2 添加srv的依赖

  编辑package.xml文件(修改后部分)

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

  编辑CMakeLists.txt 文件(修改后部分)

//需添加部分1
find_package(catkin REQUIRED COMPONENTS
   roscpp
   rospy
   std_msgs
   message_generation
)

//需添加部分2:添加运行时的依赖关系
catkin_package(
  ...
  CATKIN_DEPENDS message_runtime ...
  ...)
  
//需修改部分3:     
			 1)删除前面的# 符号 
			 2)替换Service1.srv为AddTwoNumber.srv
add_message_files(
	FILES
 	AddTwoNumber.srv
)

  查看服务是否创建成功

$ rossrv show beginner_tutorials/AddTwoNumber 
int64 a
int64 b
---
int64 sum  

$ rossrv show AddTwoNumber
[beginner_tutorials/AddTwoNumber:
int64 a
int64 b
---
int64 sum
2.3 编译,使.srv文件能被转换为C++、Python和其他语言的使用的源代码

  要使用自定义服务,需将.srv文件编译为 .h 文件,再引入到程序中 。

$ roscd beginner_tutorials
$ cd ~/.catkin_ws
$ catkin_make

  编译后,将在/devel/include/beginner_tutorials/下出现三个与srv相关的头文件。

  1. AddTwoNumberRequest.h :请求头文件
  2. AddTwoNumberResponse.h:响应头文件
  3. AddTwoNumber.h :#include 响应和请求头文件的头文件


3 服务的客户端

  1. 初始化节点
  2. 创建句柄
  3. 创建客户端对象,请求的服务,请求服务的数据
  4. 请求服务,接收服务的响应
3.1 编辑add_two_number_client.cpp
$ touch add_two_number_client.cpp

  编辑add_two_number_client.cpp文件

#include "ros/ros.h"
#include "beginner_tutorials/AddTwoNumber.h"
#include <cstdlib>

int main(int argc, char **argv)
{
        ros::init(argc, argv, "add_two_ints_client");
        if (argc != 3)
        {
                ROS_INFO("usage: add_two_ints_client X Y");
                return 1;
        }

        ros::NodeHandle n;
        ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoNumber>("add_two_ints");
        beginner_tutorials::AddTwoNumber srv;
        srv.request.a = atoll(argv[1]);
        srv.request.b = atoll(argv[2]);
        if (client.call(srv))
        {
                ROS_INFO("Sum: %ld", (long int)srv.response.sum);
        }
        else
        {
                ROS_ERROR("Failed to call service add_two_ints");
                return 1;
        }

        return 0;
 }
3.2 编译,生成可执行文件
add_executable(add_two_ints_client src/add_two_number_client.cpp.cpp)
target_link_libraries(add_two_ints_client ${catkin_LIBRARIES})
add_dependencies(add_two_ints_client beginner_tutorials_gencpp)

  在工作空间下编译,生成可执行文件。

$ cd catkin_ws
$ catkin_make
$ source ./devel/setup.bash

  可执行文件放置于:devel/lib/beginner_tutorials


4 服务的服务器

  1. 初始化节点
  2. 创建句柄
  3. 创建服务对象,处理服务的回调函数
  4. 回调函数处理请求,并产生响应
4.1 编辑add_two_number_server.cpp
touch add_two_number_server.cpp

  编辑add_two_number_server.cpp

#include "ros/ros.h"
#include "beginner_tutorials/AddTwoNumber.h"

//服务的回调函数
bool add(beginner_tutorials::AddTwoNumber::Request  &req,
         beginner_tutorials::AddTwoNumber::Response &res)
{
        res.sum = req.a + req.b;
        ROS_INFO("request: the x number =%ld, the y number =%ld", (long int)req.a, (long int)req.b);
        ROS_INFO("sending back response: [%ld]", (long int)res.sum);
        return true;
}

int main(int argc, char **argv)
{
        ros::init(argc, argv, "add_two_ints_server");
        //初始化节点
        ros::NodeHandle n;
        //初始化句柄

        ros::ServiceServer service = n.advertiseService("add_two_ints", add);
        //服务对象,处理的服务,服务的回调函数
        
        ROS_INFO("Ready to add two ints.");
        ros::spin();

        return 0;
}
4.2 编译,生成可执行文件
add_executable(add_two_ints_server src/add_two_number_server.cpp)
target_link_libraries(add_two_ints_server ${catkin_LIBRARIES})
add_dependencies(add_two_ints_server beginner_tutorials_gencpp)

  在工作空间下编译, 生成可执行文件。

$ cd catkin_ws
$ catkin_make
$ source ./devel/setup.bash

  可执行文件放置于:devel/lib/beginner_tutorials。


5 验证

  打开终端,运行roscore

$ roscore

  另起终端,先运行服务器节点add_two_ints_server节点

$ rosrun beginner_tutorials add_two_ints_server

  再另起终端,运行add_two_ints_client节点

$ rosrun beginner_tutorials add_two_ints_client 23 67

  结果:

在这里插入图片描述

当前软件包的文件系统结构:(红框为当前教程新增)
在这里插入图片描述

6 总结

  ros指令:

rosserver show <package_name> :查看当前活跃的服务

rossrv show <package_name>/ :查看服务的消息格式

  核心函数:
在这里插入图片描述

### 回答1: ROS中创建服务server和client的步骤如下: 1. 创建服务文件:在ROS包中创建一个srv文件,定义服务的请求和响应类型。 2. 编写服务server:在ROS节点中编写服务server的代码,实现服务的功能。 3. 编写服务client:在ROS节点中编写服务client的代码,调用服务server提供的功能。 4. 编译ROS包:使用catkin_make命令编译ROS包,生成可执行文件。 5. 运行ROS节点:使用rosrun命令运行ROS节点,启动服务server和client。 6. 测试服务:使用rostopic命令发布服务请求,查看服务响应结果。 以上是ROS创建服务server和client的基本步骤,具体实现可以参考ROS官方文档和相关教程。 ### 回答2: 首先,ROS是一个流行的机器人操作系统,具有强大的工具集来创建和管理机器人应用程序。其中,服务Service)是ROS中实现通信的另一个重要机制。services允许节点之间进行同步通信,一个节点可以请求一个service,另一个节点会响应请求。在ROS中,service分别有server端和client端两个组成部分,下面我们来介绍一下ROS创建service的具体步骤: 1. 编写srv文件 在ROS中,服务是由srv文件定义的,类似于msg文件。srv文件定义服务的请求和响应格式。我们可以通过文本编辑器在ROS工作空间中创建srv文件,例如在package中创建test_srv.srv文件: ``` int64 A int64 B --- int64 C ``` 其中,`A`、`B`和`C`均为服务变量的名称,`int64`代表对应变量类型。这里定义了A和B两个变量作为服务请求的输入,C变量作为服务的响应结果。 2. 编写server端代码 在ROS中,一个节点往往同时充当server和client。因此在编写server端代码之前,需要创建一个node。可以使用`rospy.init_node()`初始化一个节点。然后,在Python中,可以使用`rospy.Service()`函数来定义server服务和回调函数: ``` #!/usr/bin/env python import rospy from test_srv.srv import TestSrvResponse, TestSrvRequest def srv_callback(req): res = TestSrvResponse() res.out = req.A + req.B return res if __name__ == '__main__': rospy.init_node('test_server') srv = rospy.Service('test_service', TestSrv, srv_callback) rospy.spin() ``` 上面代码中,`srv_callback()`函数就是用于处理服务请求的服务回调函数,用户需要根据自身服务逻辑来编写。再将`srv_callback()`绑定到`rospy.Service()`中完成服务的定义和注册。 `rospy.spin()`函数保证了服务一直处于等待请求的状态直到stop节点。 3. 编写client端代码 在ROS中,client可以使用C++或Python编写,这里以Python为例。首先需要导入所用的srv定义。 在Python中使用服务,可以利用rospy.ServiceProxy()函数来创建一个service的proxy,并且传递必要的参数来调用该service: ``` #!/usr/bin/env python import rospy from test_srv.srv import TestSrvResponse, TestSrvRequest if __name__ == '__main__': rospy.init_node('test_client') rospy.wait_for_service('test_service') test_srv = rospy.ServiceProxy('test_service', TestSrv) req = TestSrvRequest() req.A = 3 req.B = 4 res = test_srv(req) rospy.loginfo("server response:{0}".format(res.out)) ``` 在Python脚本中,使用`rospy.wait_for_service()`函数等待一个服务,然后,创建TestSrvRequest类型的请求,发送给已定义的服务,并等待服务响应。 最后,本文仅给出了ROS服务server和client的关键部分代码,完整代码详见ROS官网。服务的安全性和错误处理也是极重要的,使用时需要谨慎,精心编写容错处理,以保证服务相互安全。 ### 回答3: ROS是一个流行的机器人操作系统,它提供了构建机器人应用程序所需的工具和库。ROS中的服务提供了一种在不同节点之间共享数据的方法。服务以client-server模式工作,客户端节点可以向服务节点请求数据,服务节点会响应这些请求。这篇文章将介绍如何在ROS中创建服务server和client。 首先,在ROS中创建服务必须要在package中创建srv文件,这些srv文件定义了服务消息的类型。服务消息定义了服务节点可以接受和返回的数据类型。在srv文件中,必须指定请求和响应数据类型的详细信息。在本文中,我们将创建一个服务节点来处理两个整数之间的加法操作。 例如,在我们的my_service_pkg包中创建一个名称为add_two_ints.srv的srv文件。该srv文件的格式如下所示: int64 a int64 b --- int64 sum 在上面的srv文件中,我们定义了两个整数"a"和"b"作为请求消息的参数,并定义了一个名为"sum"的相应参数。 创建完srv文件后,我们需要在CMakeLists.txt文件中添加相关内容以进行编译和构建。我们需要将"add_two_ints.srv"添加到package.xml中,以便在构建期间自动生成相关文件。 接下来,我们需要在服务节点中编写代码。在服务节点中,我们需要调用ros::ServiceServer服务类以添加服务。该类允许我们注册一个回调函数,当请求消息到达时执行该回调函数。 在ROS中,服务节点和客户端节点通常运行于不同的进程中。因此,我们需要使用rosrun命令启动两个不同的节点。一个节点将作为服务节点,另一个节点将作为客户端节点。 在客户端节点中,我们需要在代码中调用serviceClient类,以便连接到服务节点。serviceClient类允许我们使用类似函数调用的语法从服务节点请求数据。 在代码中使用ROS服务client和server非常简单,下面是一个基本的示例: **服务server** ``` #include "ros/ros.h" #include "my_service_pkg/addTwoInts.h" bool add(my_service_pkg::addTwoInts::Request& req, my_service_pkg::addTwoInts::Response& res) { res.sum = req.a + req.b; ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b); ROS_INFO("sending back response: [%ld]", (long int)res.sum); return true; } int main(int argc, char **argv) { ros::init(argc, argv, "add_two_ints_server"); ros::NodeHandle n; ros::ServiceServer service = n.advertiseService("add_two_ints", add); ROS_INFO("Ready to add two ints."); ros::spin(); return 0; } ``` 在上述示例中,我们创建了一个名为"add"的回调函数,当请求到达时执行该函数。该回调函数从请求参数中读取两个整数"a"和"b",并将它们相加,然后将结果存储在响应参数中。最后,该函数将响应发送回客户端节点。 **服务client** ``` #include "ros/ros.h" #include "my_service_pkg/addTwoInts.h" int main(int argc, char **argv) { ros::init(argc, argv, "add_two_ints_client"); ros::NodeHandle n; ros::ServiceClient client = n.serviceClient<my_service_pkg::addTwoInts>("add_two_ints"); my_service_pkg::addTwoInts srv; srv.request.a = 100; srv.request.b = 500; if (client.call(srv)) { ROS_INFO("Sum: %ld", (long int)srv.response.sum); } else { ROS_ERROR("Failed to call service add_two_ints"); return 1; } return 0; } ``` 在上述示例中,我们创建了一个服务client,连接到服务节点上的"add_two_ints"服务。我们填充了一个my_service_pkg::addTwoInts类型的请求参数,并使用call函数调用服务。如果服务成功响应,则我们将打印出响应结果。 总结:在ROS中,创建服务server和client非常简单。我们定义一个srv文件,编写服务节点代码和客户端节点代码,然后启动两个不同节点,客户端节点调用服务节点并获得服务响应。服务ROS中非常有用的机制之一,可以帮助组织和解决各种机器人应用程序中的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值