Note: This tutorial assumes that you have completed the previous tutorials: examining the simple publisher and subscriber. |
Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags. |
Writing a Simple Service and Client
Description: This tutorial covers how to write a service and client node in python.Tutorial Level: BEGINNER
Next Tutorial: Using Parameters in rospy
Contents
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 directory into the beginner_tutorials package, you created in the earlier tutorial, creating a package:
Change directory into the beginner_tutorials package, you created in the earlier tutorial, creating a package:
$ 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).
The Code
Create the scripts/add_two_ints_server.py file within the beginner_tutorials package and paste the following inside it:
1 #!/usr/bin/env python
2 import roslib; roslib.load_manifest('beginner_tutorials')
3 from beginner_tutorials.srv import *
4 import rospy
5
6 def handle_add_two_ints(req):
7 print "Returning [%s + %s = %s]"%(req.a, req.b, (req.a + req.b))
8 return AddTwoIntsResponse(req.a + req.b)
9
10 def add_two_ints_server():
11 rospy.init_node('add_two_ints_server')
12 s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)
13 print "Ready to add two ints."
14 rospy.spin()
15
16 if __name__ == "__main__":
17 add_two_ints_server()
1 #!/usr/bin/env python
2
3 from __future__ import print_function
4
5 from beginner_tutorials.srv import AddTwoInts,AddTwoIntsResponse
6 import rospy
7
8 def handle_add_two_ints(req):
9 print("Returning [%s + %s = %s]"%(req.a, req.b, (req.a + req.b)))
10 return AddTwoIntsResponse(req.a + req.b)
11
12 def add_two_ints_server():
13 rospy.init_node('add_two_ints_server')
14 s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)
15 print("Ready to add two ints.")
16 rospy.spin()
17
18 if __name__ == "__main__":
19 add_two_ints_server()
Don't forget to make the node executable:
chmod +x scripts/add_two_ints_server.py
Add the following to your CMakeLists.txt. This makes sure the python script gets installed properly, and uses the right python interpreter.
catkin_install_python(PROGRAMS scripts/add_two_ints_server.py DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} )
The Code Explained
Now, let's break the code down.
There's very little to writing a service using rospy. We declare our node using init_node() and then declare our service:
12 s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)
This declares a new service named add_two_ints with the AddTwoInts service type. All requests are passed to handle_add_two_ints function. handle_add_two_ints is called with instances of AddTwoIntsRequest and returns instances of AddTwoIntsResponse.
Just like with the subscriber example, rospy.spin() keeps your code from exiting until the service is shutdown.
Writing the Client Node
The Code
Create the scripts/add_two_ints_client.py file within the beginner_tutorials package and paste the following inside it:
1 #!/usr/bin/env python
2
3 from __future__ import print_function
4
5 import sys
6 import rospy
7 from beginner_tutorials.srv import *
8
9 def add_two_ints_client(x, y):
10 rospy.wait_for_service('add_two_ints')
11 try:
12 add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)
13 resp1 = add_two_ints(x, y)
14 return resp1.sum
15 except rospy.ServiceException as e:
16 print("Service call failed: %s"%e)
17
18 def usage():
19 return "%s [x y]"%sys.argv[0]
20
21 if __name__ == "__main__":
22 if len(sys.argv) == 3:
23 x = int(sys.argv[1])
24 y = int(sys.argv[2])
25 else:
26 print(usage())
27 sys.exit(1)
28 print("Requesting %s+%s"%(x, y))
29 print("%s + %s = %s"%(x, y, add_two_ints_client(x, y)))
Don't forget to make the node executable:
$ chmod +x scripts/add_two_ints_client.py
Then, edit the catkin_install_python() call in your CMakeLists.txt so it looks like the following:
catkin_install_python(PROGRAMS scripts/add_two_ints_server.py scripts/add_two_ints_client.py DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} )
The Code Explained
Now, let's break the code down.
The client code for calling services is also simple. For clients you don't have to call init_node(). We first call:
10 rospy.wait_for_service('add_two_ints')
This is a convenience method that blocks until the service named add_two_ints is available.
Next we create a handle for calling the service:
12 add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)
We can use this handle just like a normal function and call it:
Because we've declared the type of the service to be AddTwoInts, it does the work of generating the AddTwoIntsRequest object for you (you're free to pass in your own instead). The return value is an AddTwoIntsResponse object. If the call fails, a rospy.ServiceException may be thrown, so you should setup the appropriate try/except block.
Building your nodes
We use CMake as our build system and, yes, you have to use it even for Python nodes. This is to make sure that the autogenerated Python code for messages and services is created.
We also use a Makefile for a bit of convenience. roscreate-pkg automatically created a Makefile, so you don't have to edit it.
Now run make:
$ make
Go to your catkin workspace and run catkin_make.
# In your catkin workspace $ cd ~/catkin_ws $ catkin_make
Try it out!
In a new terminal, run
$ cd ~/catkin_ws $ . devel/setup.bash $ rosrun beginner_tutorials add_two_ints_server.py
In a new terminal, run
$ cd ~/catkin_ws $ . devel/setup.bash $ rosrun beginner_tutorials add_two_ints_client.py
- And you will see the usage information printed, similar to
/home/user/catkin_ws/src/beginner_tutorials/scripts/add_two_ints_client.py [x y]
Then run
$ rosrun beginner_tutorials add_two_ints_client.py 4 5
- And you will get
Requesting 4+5 4 + 5 = 9
- And the server will print out
Returning [4 + 5 = 9]
Next tutorial: rospy_tutorials/Tutorials/Parameters.