ROS Service 入门到应用
使用ros有一段时间了,但是一般topic类型的通信方式使用的最多,很少使用service,所以对service也就是简单的了解,并没有真正的使用过,最近要用到service通信模式,所以自己就要去学,但是看了官网的教程之后,还不是特别明确到底怎么去做。官网教程链接:http://wiki.ros.org/ROS/Tutorials/WritingServiceClient%28c%2B%2B%29
在这里,对于没用过service或者刚开始学习ros的朋友来说,一般都有如下疑问?
(1)service与topic有什么区别,一般什么时候需要用到service?
个人理解:topic与service最大的区别在于topic发送数据时,对方是否成功接收是没有反馈的,而service是有一个对方的反馈的,而且返回值不一定是bool类型,也可以是int,string等类型。所以当你需要接收方有反馈给你时,这时需要用到service。而且据官网讲(http://wiki.ros.org/ROS/Technical%20Overview)service的通信开销是很大的,所以对于频率比较高的通信最好用topic。
另外,在这里也提出自己的一点疑惑,topic跟service分别是TCP/IP通信中UDP与TCP通信协议的封装吗?我本来一位topic就是UDP的封装,而service就是TCP的封装,但是也不确定,ros官网上也没找到明显的解释,所以懂的麻“烦指教下。
(2)service像topic一样有很多自带的标准类型吗?
个人理解:topic使用的msg有很多自带的类型,如std_msgs、sensor_msgs、geometry_msgs等,所以我在使用service时也在想,service是不是也有很多这种标准类型,遗憾的是我找到很少,就找到了std_srvs中的几个类型,所以你想要用service的话,需要自己定义service类型。(如果有知道很多service标准类型的话,请指教下,我找了好几遍没找到)
下面我们开始使用service吧
(1) 首先打开你的工作空间至src目录下,例如我的工作空间为catkin_ws,那么:
这里写代码片
cd ~/catkin_ws/src
(2)在你的工作空间下创建我们我们service用的package:
catkin_creat_pkg learn_srvs roscpp rospy std_srvs std_msgs message_generation
(3) 接下来我们自己定义一个service, 名字为learn.srv
打开包所在的目录
cd catkin_ws/src/learn_srvs
新建srv文件夹
mkdir srv
创建learn.srv文件
cd srv/
gedit learn.srv
假设客户端发送的request为两个浮点型的数,x,y。服务端返回的response为bool类型的received, 当然变量的名字x,y,received是由我们自己定义的,
learn.srv内容如下:
float64 x
float64 y
---
bool received
保存,这样我们就创建了一个自己的service文件,
下面修改CMakeLists.txt使新生成的srv生效,CMakeLists.txt内容如下:
cmake_minimum_required(VERSION 2.8.3)
project(learn_srvs)
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_srvs
std_msgs
message_generation
)
add_service_files(
FILES
learn.srv
)
generate_messages(
DEPENDENCIES
std_msgs
)
catkin_package(
INCLUDE_DIRS include
)
include_directories(
${catkin_INCLUDE_DIRS}
)
保存,去工作空间下catkin_make编译,即可生成与service相应的头文件
进到devel文件夹下会看到新生成的include目录,这里面便有我们新建的srv的头文件,现在就可以开始按照官网的教程写客户端与服务端了
cd ~/catkin_ws/devel/include/learn_srvs/
我在learn_srvs/src下边写了两个node测试,如下:
客户端:learn_srv_client.cpp
#include "ros/ros.h"
#include "learn_srvs/learn.h"
#include <cstdlib>
int main(int argc, char **argv)
{
ros::init(argc, argv, "learn_srv_client");
if (argc != 3)
{
ROS_INFO("need x,y");
return 1;
}
ros::NodeHandle n;
ros::ServiceClient client = n.serviceClient<learn_srvs::learn>("learn_srvs");
learn_srvs::learn srv;
srv.request.x = atoll(argv[1]);
srv.request.y = atoll(argv[2]);
if (client.call(srv))
{
ROS_INFO("Sum: %ld", (long int)srv.response.received);
}
else
{
ROS_ERROR("Failed to call service add_two_ints");
return 1;
}
return 0;
}
服务端:learn_srv_server.cpp
#include "ros/ros.h"
#include "learn_srvs/learn.h"
bool add(learn_srvs::learn::Request &req,
learn_srvs::learn::Response &res)
{
res.received = 1;
ROS_INFO("request: x=%ld, y=%ld", (long int)req.x, (long int)req.y);
ROS_INFO("sending back response: [%ld]", (long int)res.received);
return true;
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "learn_srv_server");
ros::NodeHandle n;
ros::ServiceServer service = n.advertiseService("learn_srvs", add);
ROS_INFO("Ready to learn srvs.");
ros::spin();
return 0;
}
当然CMakeLists.txt也相应修改如下:
cmake_minimum_required(VERSION 2.8.3)
project(learn_srvs)
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_srvs
std_msgs
message_generation
)
add_service_files(
FILES
learn.srv
)
generate_messages(
DEPENDENCIES
std_msgs
)
catkin_package(
INCLUDE_DIRS include
)
include_directories(
${catkin_INCLUDE_DIRS}
)
add_executable(learn_srv_client_node src/learn_srv_client.cpp)
add_executable(learn_srv_server_node src/learn_srv_server.cpp)
target_link_libraries(learn_srv_client_node
${catkin_LIBRARIES}
)
target_link_libraries(learn_srv_server_node
${catkin_LIBRARIES}
)
catkin_make 编译工作空间,然后,在终端运行即可看到结果:
rosrun learn_srvs learn_srv_server_node
rosrun learn_srvs learn_srv_client_node 1 2
需要注意的是:
(1)这个例子要先启动服务端再启动客户端才行
(2)在实际应用中发送端为客户端,相当于topic里面的发布者。接收端为服务端,相当于topic里面的订阅者。
其实没啥难的,多写就好了,有问题欢迎交流讨论。
本文介绍 ROS 中 Service 的基本概念及应用场景,对比 Topic 模型,详细讲解如何自定义 Service 类型并实现客户端和服务端交互。
2191

被折叠的 条评论
为什么被折叠?



