ROS入门学习6-0:理解服务中Server与Client(C++)

  本例程节点放在ros_learning功能包src文件夹下,新建ros_learning功能包(如果已创建则跳过):

$ cs
$ catkin_create_pkg ros_learning std_msgs rospy roscpp
$ cm

动作程序编写

创建服务端(Server)

add_two_ints_server.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include "ros/ros.h"
#include "ros_learning/AddTwoInts.h"
// beginner_tutorials/AddTwoInts.h是由编译系统自动根据我们先前创建的srv文件生成的对应该srv文件的头文件。

// 这个函数提供两个int值求和的服务,int值从request里面获取,而返回数据装入response内,这些数据类型都定义在srv文件内部,函数返回一个boolean值。
bool add(ros_learning::AddTwoInts::Request &req,
ros_learning::AddTwoInts::Response &res)
{
// 现在,两个int值已经相加,并存入了response。
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);
// service完成计算后返回true值
return true;
}

int main(int argc, char **argv)
{
// 创建并初始化节点add_two_ints_server
ros::init(argc, argv, "add_two_ints_server");
// 为这个进程的节点创建一个句柄n
ros::NodeHandle n;
// 这里,service已经建立起来,并在ROS内发布出来
ros::ServiceServer service = n.advertiseService("add_two_ints_c", add);
ROS_INFO("Ready to add two ints.");
ros::spin();

return 0;
}

创建客户端(Client)

add_two_ints_client.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include "ros/ros.h"
#include "ros_learning/AddTwoInts.h"
#include <cstdlib>

int main(int argc, char **argv)
{
// 创建并初始化节点add_two_ints_client
ros::init(argc, argv, "add_two_ints_client");
// 输入参数异常提醒
if (argc != 3)
{
ROS_INFO("usage: add_two_ints_client X Y");
return 1;
}
// 为这个进程的节点创建一个句柄n
ros::NodeHandle n;

// 为add_two_ints service创建一个client;ros::ServiceClient对象待会用来调用service
ros::ServiceClient client = n.serviceClient<ros_learning::AddTwoInts>("add_two_ints_c");
// 实例化一个由ROS编译系统自动生成的service类,并给其request成员赋值
// 一个service类包含两个成员request和response
ros_learning::AddTwoInts srv;
srv.request.a = atoll(argv[1]);
srv.request.b = atoll(argv[2]);

/***
调用service;由于service的调用是模态过程(调用的时候占用进程阻止其他代码的执行),一旦调用完成,将返回调用结果
如果service调用成功,call()函数将返回true,srv.response里面的值将是合法的值
如果调用失败,call()函数将返回false,srv.response里面的值将是非法的
***/
if (client.call(srv))
{
ROS_INFO("Sum: %ld", (long int)srv.response.sum);
}
else
{
ROS_ERROR("Failed to call service add_two_ints_c");
return 1;
}

return 0;
}

新建自定义服务

  • 创建AddTwoInts.srv文件

自定义服务消息数据格式一般为srv文件,如此次需要创建AddTwoInts.srv文件,一般放在功能包目录下srv文件夹下。

路径:catkin_ws/src/ros_learning/srv/AddTwoInts.srv

AddTwoInts.srv
1
2
3
4
int64 a
int64 b
---
int64 sum

注:数据域中的内容,请求与应答数据格式之间需要使用---分割。

  • 修改package.xml文件,添加以下内容
package.xml
1
2
3
<build_depend>message_generation</build_depend>
<build_export_depend>message_generation</build_export_depend>
<exec_depend>message_runtime</exec_depend>
  • 修改CMakeLists.txt文件,添加以下内容
CMakeLists.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)

## Generate services in the 'srv' folder
add_service_files(
FILES
AddTwoInts.srv
)

## Generate added messages and services with any dependencies listed here
generate_messages(
DEPENDENCIES
std_msgs
)

catkin_package(
# INCLUDE_DIRS include
# LIBRARIES ros_learning
CATKIN_DEPENDS roscpp rospy std_msgs message_generation
# DEPENDS system_lib
)

添加配置

方法一:可执行文件添加到CMakeLists.txt末尾位置

CMakeLists.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
add_executable(add_two_ints_server
src/add_two_ints_server.cpp
)
add_dependencies(add_two_ints_server ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(add_two_ints_server
${catkin_LIBRARIES}
)

add_executable(add_two_ints_client
src/add_two_ints_client.cpp
)
add_dependencies(add_two_ints_client ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(add_two_ints_client
${catkin_LIBRARIES}
)

方法二:使用Roboware软件自动创建

   右键src文件夹选择新建cpp源文件,然后输入文件名(如add_two_ints_server.cpp),再选择加入新的可执行文件中。可到CMakeLists.txt文件中查看创建结果。

程序运行

  • 打开新终端,编译功能包,启动ROS:
$ cm
$ roscore
  • 打开新终端,运行服务器,可以看出服务在等待客户端请求:
$ rosrun ros_learning add_two_ints_server
(图)服务器等待客户端请求
  • 打开新终端,运行客户端,可以看出,当发出两个整数相加请求后,服务器计算并返回所求的和:
$ rosrun ros_learning add_two_ints_client 5 8
(图)客户端(Client)
+