Search this site
Embedded Files
No Boredom
  • Home
    • Computer Geek
    • Learning
    • Math Geek
    • Projects
No Boredom
  • Home
    • Computer Geek
    • Learning
    • Math Geek
    • Projects
  • More
    • Home
      • Computer Geek
      • Learning
      • Math Geek
      • Projects

Messages and Services

< Back to ROS Beginner tutorials
Messages
What's a message ?
Defining a message
Prerequisites
Code
Building
Services
What's a service ?
Defining a service
Prerequisites
Code
Building
Coding a Server
Using C++
Building the C++ Nodes
Executing the node
Using Python
Running the node
Coding a Client
Using C++
Building the C++ Node
Executing the node
Using Python
Running the Node
Additional
Official tutorials

Messages

What's a message ?

A message is essentially a datatype that is defined to be used in communication. ROS has a programming language that is used to define messages. It's called Message Description Language (more info here) and it's very simple. All the messages go into a folder named "msg" in your package.

Let us define our own message with the following features:

  • A string named info
  • A floating point number named value

We'll used the info to send a description and value to send actual floating point value. We'll name it "Equ.msg".

Defining a message

Prerequisites

Before defining a message, the following is required:

  • A folder named "msg" in your package folder. Create a file named "Equ.msg" inside this folder. We'll write contents into this later.
  • Your package must depend upon 'message_generation' and 'message_runtime'. These are basically dependencies that need to be present in the package manifesto (package.xml) and CMakeLists.txt file. You can find everything here but here's a short summary of what to do:
    • Open package.xml file of the package and write these two lines in it:
      • <build_depend>message_generation</build_depend>
        • This is so that the package can generate messages. This is required only to generate the header files and source files for the message, hence it's a build dependency.
      • <run_depend>message_runtime</run_depend>
        • This is so that the package can use the defined message during run-time.
        • You could also use exec_depend instead of run_depend, they both do the same thing.
    • Open CMakeLists.txt file of the package and make the following amendments:
      • Find the function find_package and add "message_generation" to the list inside.
        • This is a catkin specific configuration. This is to pass the dependency to the projects that will be using this package (so they won't have to add message_generation as a dependency).
        • We need to add message_generation as a dependency.
        • This is required because the header files and libraries need to be generated for the messages defined, so you need to tell ROS that you 'have a message' and give more specifics.
      • Find the function catkin_package and add "CATKIN_DEPENDS message_runtime" to the list inside.
        • This is for the catkin tool. It's a macro that needs to be there for the runtime dependency on the message.
      • Find the function add_message_files and add "FILES" and (newline) "Equ.msg" to the list inside (name has to match the message file that we created).
        • This is to tell the name of the message file.
      • Find the function generate_messages and add "DEPENDENCIES" and (newline) "std_msgs" to the list inside.
        • This is where you tell the dependencies of the message file. If you have used messages from other packages, you need to mention those here as well.
        • Most of the messages are made using the std_msgs package (if derived from primitive types) but there could be others depending upon your need.
          • You can get the entire list of messages available, execute rosmsg list command and you'll get a list of messages and packages they're in (package_name/message_name), check it out.

This is also the procedure to add dependencies after you've created the package. Here's the CMakeLists.txt file and package.xml file of the package on GitHub. Note that you might not have the lines for Publisher1 and Subscriber1 files (we'll create them later in this tutorial).

Code

Code here

Here's the code that we must write in a file named "Equ.msg" in the msg folder of our package intro_pkg1. Write the following into it:

  • string info
    • Information string
  • float32 value
    • Floating point value

Note that the name of our message here is "Equ.msg". It can virtually be any valid name, just don't name them after keywords like "float" or "char", because even though they might build, they'll give you tremendous problems ahead.

Code here

Building

Now that we've written and saved the files, do the following (open a terminal and run catkin_make on the workspace):

  • Open a terminal and write and execute the following commands
    • cd ~/ROS_workspaces/ros_ws/
      • Navigate to the workspace directory
    • catkin_make
      • Build the workspace, you could alternatively use catkin_make --pkg intro_pkg1 to build the intro_pkg1 package only.

You could navigate to the devel folder of the workspace (ros_ws here) and check the following directories:

  • ros_ws/devel/include/
    • Equ.h: This is header file for the message. Made for C++ nodes.
  • ros_ws/devel/lib/python2.7/dist-packages/intro_pkg1/msg/
    • _Equ.py: This is for python nodes.

ros_ws folder on GitHub.

You could also see the output of rosmsg list command and search for intro_pkg1/Equ in the list. Try other commands to know more about the message using rosmsg.

Equ.msg file

This finishes the task of creating a message using message description language. You could check the following out as well:

  • Publisher1.cpp for seeing how to publish a custom made message using C++
  • Subscriber1.cpp for seeing how to subscribe and receive a custom made message using C++
  • Publisher1.py for seeing how to publish a custom made message using Python
  • Subscriber1.py for seeing how to subscribe and receive a custom made message using Python

These files show you how to use these custom made messages

Services

What's a service ?

A service is a pair of messages, one for request and one for reply. A topic is where some nodes publish data and some nodes read data through subscription. Such a communication form is not apt for a request and response type of communication, thus services. Just like message description language, we have service description language for definition of services (more info here). All services go in a folder named "srv" in your package.

Let's define our own service with the following features:

  • Request
    • A floating point number, named input
  • Response
    • A floating point number, named output

We'll name the service as FloatIO.srv.

Defining a service

Prerequisites

Since a service incorporates the concepts of messages as well, we have to follow similar steps to the prerequisites for messages. You would've already done most of it already, you won't need to change those. You'll need to have the following fone:

  • A folder named "srv" in your package folder.
  • Your package must depend upon 'message_generation' and 'message_runtime'. These are basically dependencies that need to be present in the package manifesto (package.xml) and CMakeLists.txt file. You can find everything here but here's a short summary of what to do:
    • Open package.xml file of the package and write these two lines in it:
      • <build_depend>message_generation</build_depend>
        • This is so that the package can generate messages
      • <run_depend>message_runtime</run_depend>
        • This is so that the package can use the defined message during run-time.
    • Open CMakeLists.txt file of the package and make the following amendments:
      • Find the function find_package and add "message_generation" to the list inside.
        • We need to add message_generation as a dependency.
        • This is required because the header files and libraries need to be generated for the messages defined, so you need to tell ROS that you 'have a message' and give more specifics.
      • Find the function catkin_package and add "CATKIN_DEPENDS message_runtime" to the list inside.
        • This is for the catkin tool. It's a macro that needs to be there for the runtime dependency on the message.
      • Find the function add_service_files and add "FILES" and (newline) "FloatIO.srv"
      • Find the function generate_messages and add "DEPENDENCIES" and (newline) "std_msgs" to the list inside.
        • This is where you tell the dependencies of the message file. If you have used messages from other packages, you need to mention those here as well.

Here's the CMakeLists.txt and package.xml file on GitHub. It might have more things than what's given above.

Code

Code here

Here's what we must write in the file "FloatIO.srv" in the srv folder of the package intro_pkg1. Write the following into it:

  • float64 input
    • This is the request part
  • ---
    • This is to divide the request part from response part
  • float64 output
    • This is the response part
Code here

Building

  • Open a terminal and run the following commands:
    • cd ~/ROS_workspaces/ros_ws/
      • Navigate to the workspace
    • catkin_make
      • Make the workspace

You could navigate to the devel folder and check out the following directories (with respect to the workspace directory):

  • ros_ws/devel/include/intro_pkg1/: Header file for nodes made using C++
    • FloatIO.h: Complete service, main header file
    • FloatIORequest.h: Contains request part (input)
    • FloatIOResponse.h: Contains response part (output)
  • ros_ws/devel/lib/python2.7/dist-packages/intro_pkg1/srv/: Files for nodes made using python
    • _FloatIO.py: Contains all code for the service
    • __init__.py: File required for initializing node

ros_ws folder on GitHub.

You could also see the output of rossrv list command and search for intro_pkg1/FloatIO in the list. Try other commands to know more about the service using rossrv.

Coding a Server

A service server is a node that is hosting (or providing) a service. Till now we only defined the structure of the service, not the relation between request and response. A service server does exactly that, defines the service. This is obviously written through C++ or Python code, let's observe how to do that.

We'll take the relation as response (output) is equal to request (input) times 2 plus 1.

Using C++

Code here

Follow this procedure to create a service server (we've named it "ServiceServer1.cpp"):

  1. Include the header files for ROS and the main service
  2. Define a function that returns a boolean value (if the server executed successfully, return true, else false)
    • It must have two arguments (passed by reference), one of data type Request of the service and other of data type Response of the service.
    • Write the entire relation between request and response here
  3. In the main function
    • Initialize the node
    • Create a node handler
    • Create an object of class ros::ServiceServer and use the member function advertiseService of the node handler. Pass it
      • The name under which you'll provide the service during runtime
      • Function that's handling the service
  4. Call the ros::spin function or ros::spinOnce function if you have to use the node for something else.
    • The spin function allows the node to get into listening mode. Whenever it receives a request it executes the function and the response message is assigned.
Code here

Building the C++ Nodes

  1. Make the following amendments to the CMakeLists.txt file of the package:
    • Add the following at appropriate places and save the file
      • add_executable(EquationServer src/ServiceServer1.cpp)
      • target_link_libraries(EquationServer ${catkin_LIBRARIES})
  2. Open a terminal and execute the following commands
    • cd ROS_workspaces/ros_ws/
    • catkin_make
CMakeLists.txt file

Executing the node

Now you can run the node using rosrun intro_pkg1 EquationServer. You can check out the service using the rosservice command. Try out the following:

  • rosservice info /equation_service
  • rosservice call /equation_service "input: 2.5"

Using Python

Code here

Follow this procedure to create a service server:

  1. Import the library rospy and the file created for the service
  2. Create a function that takes in one argument (Request) and returns the Response.
    • Write the relation code here
  3. In the main core (place where the program starts execution from)
    • Initialize the node
    • Set up the service using rospy.Service.
      • Pass it the name under which the service will be provided
      • The service class
      • The function that handles the service
    • Set the node into spin using rospy.spin function
Code here

Running the node

Run the following commands on a terminal:

  • roscd intro_pkg1/scripts/
  • chmod +x *.py
  • rosrun intro_pkg1 ServiceServer1.py
    • If you see an error, check the output of echo $PYTHONPATH and source the workspace if the output doesn't have the workspace python source folder.

You can check out the service using the rosservice command. Try out the following:

  • rosservice info /equation_service
  • rosservice call /equation_service "input: 2.5"

Service server made using C++

Service server made using Python

Coding a Client

A service client is a node that sends requests to a service server. It sends a request and receives a response. Let's program this using C++ and Python. It'll take a number as an argument and print the response received. We can code it using C++ or Python.

Using C++

Code here

Follow the following procedure to create a service client:

  • Include the header files for ROS and the service.
  • Create the main function. Write the following in it
    • Initialize the node
    • Create a NodeHandle
    • Create a ServiceClient and assign it a service client using the node handler's member function serviceClient.
    • Create a service object. At this stage it has both request and response.
    • Assign value to request of the service object
    • Call the service client using the service object and inspect if the service call returns true (indicates that the service was found and successfully executed).
    • Now, the service object's response has value that you can use.
Code here

Building the C++ Node

  1. Make the following amendments to the CMakeLists.txt file of the package:
    • Add the following lines at appropriate places
      • add_executable(EquationClient src/ServiceClient1.cpp)
      • target_link_libraries(EquationClient ${catkin_LIBRARIES})
  2. Build the package. Open a terminal and execute the following commands:
    • cd ~/ROS_workspaces/ros_ws/
    • catkin_make
CMakeLists.txt file

Executing the node

Now you can run the node using "rosrun intro_pkg1 EquationClient <Number>". Try out the following:

  • rosrun intro_pkg1 EquationClient 2
  • rosrun intro_pkg1 EquationClient 5.5

Make sure the roscore and the service server is running before calling the client. Try using the service client after killing the service server, you must get an error message

Using Python

Code here

Follow the following procedure to create a service client:

  1. Import the library rospy and service files.
  2. Initialize the node.
  3. Wait for the service to be available using wait_for_service.
  4. Create a ServiceProxy. This will return a function that takes in the request and returns the response.
  5. Call the service proxy with a request and receive a response
Code here

Running the Node

Open a terminal and execute the following commands:

  • roscd intro_pkg1/scripts/
  • chmod +x *.py
  • rosrun intro_pkg1 ServiceClient1.py 5.3
  • rosrun intro_pkg1 ServiceClient1.py 2.5

Make sure the roscore and the service server is running before calling the client. Try using the service client after killing the service server, you must get an error message.

Service client made using C++

Service client made using Python

Additional

Official tutorials

  • C++ documentation
  • Python documentation
< Back to ROS Beginner tutorials
Google Sites
Report abuse
Page details
Page updated
Google Sites
Report abuse