ROS service入门到应用

来源:互联网 发布:mac 怎么使用语音朗读 编辑:程序博客网 时间:2024/06/05 11:50

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 xfloat64 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里面的订阅者。

其实没啥难的,多写就好了,有问题欢迎交流讨论。

0 0