-
Notifications
You must be signed in to change notification settings - Fork 8
Week 4
You should be able to complete this week's work within the allotted 2-hour lab session.
This week you will learn about another method to transfer data between nodes and invoke actions on a ROS Robot using Services. You will learn how ROS Services can be used, in combination with the standard publisher/subscriber principles that you already know about, to control a robot more effectively for certain actions or operations.
By the end of this week's lab session, you will be able to:
- Recognise how ROS Services differ to the standard the standard publisher-subscriber approach and identify appropriate use-cases for this type of messaging system
- Implement Python node pairs to observe how services work
- Develop Python Service nodes of your own to implement some basic obstacle avoidance using data from the LiDAR sensor as the feedback signal
Once again, launch your WSL-ROS environment by running the WSL-ROS shortcut in the Windows Start Menu, which will build the WSL-ROS environment and launch an Ubuntu terminal instance in the Windows Terminal (TERMINAL 1).
Remember that any work that you do within this WSL/Ubuntu environment will not be preserved between sessions and across different University computers. Follow these steps to restore the work that you have done so far in these lab sessions:
- TODO...
From TERMINAL 1, launch the TurtleBot3 Waffle "Empty World" simulation:
[TERMINAL 1] $ roslaunch turtlebot3_gazebo turtlebot3_empty_world.launch
...and wait for the Gazebo window to open:
In weeks 1 & 2 we learnt about ROS topics and messages, and how individual nodes can access data on a robot by simply subscribing to topics that are being published by any other node on the system. In addition to this, we also learnt how any node can publish messages to any topic, where this essentially broadcasts the data contained in the message to any other node on the system that wants to access it.
Another way to pass data between ROS Nodes is by using Services. These are different to messages in that "Service calls" (that is, the process of requesting a service) occur only between one node and another:
- One node (a Service Client) sends a Request to another node
- Another node (a Service Server) processes that request, performs an action and then sends back a Response
Services are therefore Synchronous: When a ROS node sends a request to a service it can't continue until it receives a response. This can be useful for a range of different scenarios, for example:
- A robot might need to do something before it can move on to something else, i.e. it needs to see something before it can move towards it
- High definition cameras generate large amounts of data and consume battery power, so you may wish to turn a camera on for a specific amount of time, or until an image has been captured, and then turn it off again
- Remember that ROS is network-based so you might want to offload some computations to a remote computer when a certain piece of data is available, and then get the remote computer to send back a result once it's done all the hard work
You will observe how all this works in the next two exercises, where you will create service Server and Client nodes in Python, launch them from the command line and observe the outcomes.
To start with, let's set up a service and learn how to make a call to it from the command line to give you an idea of how this all works and why it might be useful.
-
First open up a new terminal instance (TERMINAL 2) and create a package called
service_exercises
using thecatkin_create_pkg
tool as you have done in previous weeks:-
Navigate to the
catkin_ws/src
directory:[TERMINAL 2] $ cd ~/catkin_ws/src
-
Create the
service_exercises
package and defineropsy
,geometry_msgs
andsrv_examples
as dependencies:[TERMINAL 2] $ catkin_create_pkg service_exercises rospy geometry_msgs srv_examples
-
-
Then, navigate to the package
src
folder that should have just been created:[TERMINAL 2] $ roscd service_exercises/src
-
Create a file called
move_server.py
:[TERMINAL 2] $ touch move_server.py
-
and set this to be executable:
[TERMINAL 2] $ chmod +x move_server.py
-
Open the file in Gedit, copy and paste the code provided here and then save it.
Note: It is important that you understand how the code above works so that you know how to build your own service Servers in Python. For more information have a look at the Explainer below the code.
-
Return to the terminal window and launch the node using
rosrun
:[TERMINAL 2] $ rosrun service_exercises move_server.py
You should see the message:
[INFO] [timestamp]: the move_service server is ready to be called...
-
Then open up a new terminal window (TERMINAL 3)
-
We can use the
rosservice
command to view all of the services that are currently active on our system:[TERMINAL 3] $ rosservice list
You should see the
/move_service
service that we defined in the python code above listed here. -
We can find out more about this using the
rosservice info
command:[TERMINAL 3] $ rosservice info /move_service
Which should provide the following output:
Node: /move_service_server URI: [not important] Type: srv_examples/SetBool Args: boolean_request
You will notice that the node name is as we set in our Python code:
rospy.init_node('move_service_server')
Type tells us the type of message this service uses and we'll look at this in more detail later Args tells us what input arguments we need to supply to the service in order to make a valid service call (or Request)
-
We can now call this service from the command line using the
rosservice
command again. The autocomplete functionality in the terminal can help us format this message correctly. Type the following text followed by a space and two tabs as illustrated:rosservice call /move_service[SPACE][TAB][TAB]
which should autocomplete the rest of the command for us:
rosservice call /move_service "boolean_request: false"
-
Press
[ENTER]
to issue this command and make a call to the service. You should see the following response:boolean_response: False response_message: "Nothing happened, set boolean_request to true next time."
-
Arrange your ROSDS windows so that you can see:
- The terminal where you launched the service (TERMINAL 2)
- The gazebo simulation with your robot in
- The terminal that you just issued the
rosservice call
command (TERMINAL 3)
In TERMINAL 3 enter the
rosservice call
command again, but this time setting the input argument toTrue
. Observe the response to both the simulated robot in Gazebo and TERMINAL 2.**What happens??**
Summary:
You have just created a node in Python to launch a service. This node acted as a Server and waited indefinitely for the service to be called. We then issued the call to the service via the command line, which then prompted our Service Server to carry out the tasks that we had defined within the Python code, namely:
- Start a timer
- Issue a velocity command to the robot to make it move forwards
- Wait for 5 seconds
- Issue a velocity command to make the robot stop
- Prepare a Service Response and issue this to the terminal in which we called the service (TERMINAL 3).
In the previous exercise we used rosservice list
to identify all the services that were currently active on the ROS system. We then used rosservice info
to find out a bit more about the service that we had launched with our Python node (which we called /move_service
).
$ rosservice info /move_service:
Node: /move_service_server
URI: [not important]
Type: srv_examples/SetBool
Args: boolean_request
Type tells us the type of message this service uses. Just like a topic message there are two parts to this definition:
srv_examples/SetBool
- The service message is part of a package called
srv_examples
- The message itself is called
SetBool
We can find out more about this using the rossrv
command, which has the same usage as the rosmsg
command that you have already used previously (for interrogating topic messages). rossrv
gives us information about all the service messages that are installed on our system and that are available for us to use in our ROS programs:
$ rossrv show srv_examples/SetBool:
bool boolean_request
---
bool boolean_response
string response_message
As you can see from above, service messages have two parts to them, separated by three hyphens (---
). Above the separator is the Service Request portion of the message, and below it is the Service Response:
Request bool boolean_request
--- ---
Response bool boolean_response
string response_message
In order to Call a service, we need to provide data to it in the format specified in the Request section of the message. A service Server (like the Python node we created earlier) will then send data back to the caller in the format specified in the Response section of the message. In the case of the srv_examples/SetBool
service, we need to provide a boolean input called boolean_request
in order to call the service, and our Server then needs to provide a response which has two variables: a boolean flag called boolean_response
and a text string called response_message
.
← Week 3: Odometry-Based Navigation and SLAM | Week 5: TODO... →
COM2009/3009 Robotics Lab Course
Updated for the 2021-22 Academic Year
Dr Tom Howard | Multidisciplinary Engineering Education (MEE) | The University of Sheffield
The documentation within this Wiki is licensed under Creative Commons License CC BY-NC:
You are free to distribute, remix, adapt, and build upon this work (for non-commercial purposes only) as long as credit is given to the original author.