How to create your own service message

Create a New Package

In ROS2, the custom message topics and services have to be created in a CPP Package. It could be done in the same package we have been using for all the examples. But we are going to create a new package, so we can practice importing from different packages.

So, we will create a new package for the creation of our custom service messages:

cd ~/ros2_ws/src
ros2 pkg create service_custom_msg --dependencies std_msgs rclcpp

Create Custom Service Message

For this example, we are going to create a Custom Service Message that will help us calculate the area of a triangle. The message file will be named TriangleArea.srv and it should be something like this:

float64 base      # The distance of of the base of the triangle
float64 height    # The height of the triangle
---
bool success      # Did it achieve it?

Now, let's create the file in our package

cd ~/ros2_ws/src/service_custom_msg
mkdir srv
touch srv/TriangleArea.srv

Prepare CMakeLists.txt and package.xml for Custom Service Compilation

Set Up CMakeLists.txt

Here you need to add the dependencies that your custom message needs. Add the following packages, which are responsible for the topics and services message generators in ROS2:

find_package(builtin_interfaces REQUIRED)
​find_package(rosidl_default_generators REQUIRED)
​
​rosidl_generate_interfaces(service_custom_msg
​"srv/TriangleArea.srv"
​DEPENDENCIES builtin_interfaces)
​

At the end, you should have something like this:

cmake_minimum_required(VERSION 3.5)
project(service_custom_msg)
​
​​# Default to C99
​​​if(NOT CMAKE_C_STANDARD)
​​​​set(CMAKE_C_STANDARD 99)
​​​​​endif()
​​​​​​​​​​​​​​​​​​​​​
​​​​​​​# Default to C++14
​​​​​​​​if(NOT CMAKE_CXX_STANDARD)
​​​​​​​​​set(CMAKE_CXX_STANDARD 14)
​​​​​​​​​​endif()
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
​​​​​​​​​​​​if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
​​​​​​​​​​​​​add_compile_options(-Wall -Wextra -Wpedantic)
​​​​​​​​​​​​​​endif()
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
​​​​​​​​​​​​​​​​# find dependencies
​​​​​​​​​​​​​​​​​find_package(ament_cmake REQUIRED)
​​​​​​​​​​​​​​​​​​find_package(std_msgs REQUIRED)
​​​​​​​​​​​​​​​​​​​find_package(rclcpp REQUIRED)
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
​​​​​​​​​​​​​​​​​​​​​# For Message Generation
​​​​​​​​​​​​​​​​​​​​​​find_package(builtin_interfaces REQUIRED)
​​​​​​​​​​​​​​​​​​​​​​​find_package(rosidl_default_generators REQUIRED)
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
​​​​​​​​​​​​​​​​​​​​​​​​​if(BUILD_TESTING)
​​​​​​​​​​​​​​​​​​​​​​​​​​find_package(ament_lint_auto REQUIRED)
​​​​​​​​​​​​​​​​​​​​​​​​​​​# the following line skips the linter which checks for copyrights
​​​​​​​​​​​​​​​​​​​​​​​​​​​​# remove the line when a copyright and license is present in all source files
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​set(ament_cmake_copyright_FOUND TRUE)
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​# the following line skips cpplint (only works in a git repo)
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​# remove the line when this package is a git repo
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​set(ament_cmake_cpplint_FOUND TRUE)
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ament_lint_auto_find_test_dependencies()
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​endif()
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​rosidl_generate_interfaces(service_custom_msg
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​"srv/TriangleArea.srv"
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​DEPENDENCIES builtin_interfaces)
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ament_package()
​

Set Up package.xml

Here you needed to add the following dependencies, which are for message generation and for any dependencies added in the custom message:

<depend>builtin_interfaces</depend>
​<depend>rosidl_default_generators</depend>
​
​<member_of_group>rosidl_interface_packages</member_of_group>
​

It's important to add the member_of_group tag to avoid this error:

CMake Error at /opt/ros/bouncy/share/rosidl_cmake/cmake/rosidl_generate_interfaces.cmake:129 (message):
​Packages installing interfaces must include
​'<member_of_group>rosidl_interface_packages</member_of_group>' in their
​package.xml

And we have to change the package version to 3, otherwise we won't be able to use member_group.

<package format="3">

At the end, you should have something like this:

<?xml version="1.0"?>
​​​​<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
​​​​​<package format="3">
​​​​​​<name>service_custom_msg</name>
​​​​​​​<version>0.0.0</version>
​​​​​​​​<description>TODO: Package description</description>
​​​​​​​​​<maintainer email="ubuntu@todo.todo">ubuntu</maintainer>
​​​​​​​​​​<license>TODO: License declaration</license>
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
​​​​​​​​​​​​<buildtool_depend>ament_cmake</buildtool_depend>
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
​​​​​​​​​​​​​​<depend>std_msgs</depend>
​​​​​​​​​​​​​​​<depend>rclcpp</depend>
​​​​​​​​​​​​​​​​<depend>builtin_interfaces</depend>
​​​​​​​​​​​​​​​​​<depend>rosidl_default_generators</depend>
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
​​​​​​​​​​​​​​​​​​​<test_depend>ament_lint_auto</test_depend>
​​​​​​​​​​​​​​​​​​​​<test_depend>ament_lint_common</test_depend>
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
​​​​​​​​​​​​​​​​​​​​​​<member_of_group>rosidl_interface_packages</member_of_group>
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
​​​​​​​​​​​​​​​​​​​​​​​​<export>
​​​​​​​​​​​​​​​​​​​​​​​​​<build_type>ament_cmake</build_type>
​​​​​​​​​​​​​​​​​​​​​​​​​​</export>
​​​​​​​​​​​​​​​​​​​​​​​​​​​</package>
​​​​​​​​​​​​​​​​​​​​​​​​​​​
​​​​​​​​​
​​​​​​​​​

Compile Service Message

Once we have our CMakeLists.txt and package.xml files ready, it's time to compile our custom Service message.

​ cd ~/ros2_ws

​ colcon build --symlink-install --packages-select services_custom_msg

If everything goes OK, you will get something like this:

VERY IMPORTANT: After the message generation, you have to source again your ROS2 workspace. Otherwise, you won't be able to see the messages generated through the ROS2 service commands, and you will think that it didn't work.

​ source ~/ros2_ws/install/setup.bash

Now we can list all the Service messages available and filter by name with the following command:

​ ros2 srv list | grep service_custom_msg/srv/TriangleArea

You should get something like this:

Finally, we can also visualize the contents of the new message generated:

​ ros2 srv show service_custom_msg/TriangleArea

You will get something like this:

If you had this output, the message was generated.

Practice Online

Also, you can test this tutorial in ROSDS, using a ROSject which already contains all the code described in it. You can get the ROSject by clicking on the button below:

Above: Get ROSDS ROSject

The link above will take yo a page like the below one:

Now, you just need to Sign In (or Sign Up if you don't have an account yet) to ROSDS in order to launch the ROSject.