ROS中的服务。
通俗理解,ros中的topic适用于节点间的多对多通信,而service主要适用于一对一通信。
1 Writing a Service Node
Here we’ll create the service (“add_two_ints_server”) node which will receive two ints and return the sum.
此处我们创建一个服务节点,该节点将接受两个整数并返回他们的和。
Change directories to your beginner_tutorials package you created in your catkin workspace previous tutorials:
roscd beginner_tutorials
Please make sure you have followed the directions in the previous tutorial for creating the service needed in this tutorial, creating the AddTwoInts.srv (be sure to choose the right version of build tool you’re using at the top of wiki page in the link).
此处需要根据之前的教程先建立.srv文件。
1.1The Code
Create the src/add_two_ints_server.cpp file within the beginner_tutorials package and paste the following inside it:
#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
bool add(beginner_tutorials::AddTwoInts::Request &req,
beginner_tutorials::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;
}
1.2 The Code Explained
Now, let’s break the code down.
#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
beginner_tutorials/AddTwoInts.h is the header file generated from the srv file that we created earlier.
beginner_tutorials/AddTwoInts.h 来自于我们之前建立的srv文件中。
bool add(beginner_tutorials::AddTwoInts::Request &req,
beginner_tutorials::AddTwoInts::Response &res)
This function provides the service for adding two ints, it takes in the request and response type defined in the srv file and returns a boolean.
该函数为服务提供了两整数相加的功能,它将接受srv文件中定义的请求和响应类型,并返回布尔值。
{
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;
}
Here the two ints are added and stored in the response. Then some information about the request and response are logged. Finally the service returns true when it is complete.
此处,两个整数相加并且结果储存于response(响应)。然后,一些关于请求和响应的信息将被记录。最后,当服务完成后,返回true。
ros::ServiceServer service = n.advertiseService("add_two_ints", add);
Here the service is created and advertised over ROS.
2.Writing the Client Node
2.1 The Code
Create the src/add_two_ints_client.cpp file within the beginner_tutorials package and paste the following inside it:
#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.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::AddTwoInts>("add_two_ints");
beginner_tutorials::AddTwoInts 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;
}
2.2 The Code Explained
Now, let’s break the code down.
ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");
This creates a client for the add_two_ints service. The ros::ServiceClient object is used to call the service later on.
这为add_two_ints服务创建了一个客户端。ros::ServiceClient对象用于稍后调用服务。
beginner_tutorials::AddTwoInts srv;
srv.request.a = atoll(argv[1]);
srv.request.b = atoll(argv[2]);
Here we instantiate an autogenerated service class, and assign values into its request member. A service class contains two members, request and response. It also contains two class definitions, Request and Response.
此处,我们实例化一个自动生成的服务类,并将值赋予它的请求成员。一个服务类包含两部分,请求和响应。它还包含两个类定义,Request和Response。
if (client.call(srv))
This actually calls the service. Since service calls are blocking, it will return once the call is done. If the service call succeeded, call() will return true and the value in srv.response will be valid. If the call did not succeed, call() will return false and the value in srv.response will be invalid.
这实际上调用了服务。由于服务调用是阻塞的,一旦调用完成,它将返回。如果服务调用成功,call()将返回true,并且srv.response中的值将有效。如果调用失败,
call()将返回false,并且srv.response中的值将无效。
3.Building your nodes
Again edit the beginner_tutorials CMakeLists.txt located at ~/catkin_ws/src/beginner_tutorials/CMakeLists.txt and add the following at the end:
add_executable(add_two_ints_server src/add_two_ints_server.cpp)
target_link_libraries(add_two_ints_server ${catkin_LIBRARIES})
add_dependencies(add_two_ints_server beginner_tutorials_gencpp)
add_executable(add_two_ints_client src/add_two_ints_client.cpp)
target_link_libraries(add_two_ints_client ${catkin_LIBRARIES})
add_dependencies(add_two_ints_client beginner_tutorials_gencpp)
This will create two executables, add_two_ints_server and add_two_ints_client, which by default will go into package directory of your devel space, located by default at ~/catkin_ws/devel/lib/. You can invoke executables directly or you can use rosrun to invoke them. They are not placed in ‘/bin’ because that would pollute the PATH when installing your package to the system. If you wish for your executable to be on the PATH at installation time, you can setup an install target, see: catkin/CMakeLists.txt
Now run catkin_make:
# In your catkin workspace
cd ~/catkin_ws
catkin_make
If your build fails for some reason:
make sure you have followed the directions in the previous tutorial: creating the AddTwoInts.srv.
4.Running the nodes
Running nodes requires you have a ROS core started. Open a new shell, and type:
roscore
If all goes well, you should see an output that looks something like this:
... logging to /u/takayama/.ros/logs/83871c9c-934b-11de-a451-
001d927076eb/roslaunch-ads-31831.log
... loading XML file
[/wg/stor1a/rosbuild/shared_installation/ros/tools/roslaunch/roscore.xml]
Added core node of type [rosout/rosout] in namespace [/]
started roslaunch server http://ads:54367/
SUMMARY
======
NODES
changing ROS_MASTER_URI to [http://ads:11311/] for starting master locally
starting new master (master configured for auto start)
process[master]: started with pid [31874]
ROS_MASTER_URI=http://ads:11311/
setting /run_id to 83871c9c-934b-11de-a451-001d927076eb
+PARAM [/run_id] by /roslaunch
+PARAM [/roslaunch/uris/ads:54367] by /roslaunch
process[rosout-1]: started with pid [31889]
started core service [/rosout]
+SUB [/time] /rosout http://ads:33744/
+SERVICE [/rosout/get_loggers] /rosout http://ads:33744/
+SERVICE [/rosout/set_logger_level] /rosout http://ads:33744/
+PUB [/rosout_agg] /rosout http://ads:33744/
+SUB [/rosout] /rosout http://ads:33744/
Now everything is set to run server and client.
4.1Running the Server
Start by running the server. Open a new shell and type:
rosrun beginner_tutorials add_two_ints_server
You should see something similar to:
Ready to add two ints.
4.2 Running the Client
Now let’s run the client with the necessary arguments, in another shell:
$ rosrun beginner_tutorials add_two_ints_client 1 3
In the client’s shell, you should see something similar to:
Sum: 4
In the server’s shell, instead, you should see something similar to:
request: x=1, y=3
sending back response: [4]
Now that you have written a simple service and client, let’s examine the simple service and client.