What you will learn:
How to create custom interfaces using a field type that is a msg from a package, and not just a primitive built-in-type.
Prerequisite:
Basic understanding of the basics of creating custom interfaces with the built-in field types (including best practices such as creating a package dedicated to your interface definitions).
If you want to learn ROS 2 Python in a practical, hands-on way, check out the course ROS 2 Basics in 5 Days: https://app.theconstruct.ai/courses/132
In this course, you’ll cover the foundational concepts needed to start working with ROS 2, as well as more advanced topics, all while engaging in hands-on practice.
Opening the rosject
In order to follow this tutorial, we need to have ROS2 installed in our system, and ideally a ros2_ws (ROS2 Workspace). To make your life easier, we have already prepared a rosject for that: /https://app.theconstruct.ai/l/5f773d8c/
Just by copying the rosject (clicking the link above), you will have a setup already prepared for you.
After the rosject has been successfully copied to your own area, you should see a Run button. Just click that button to launch the rosject ( see this example).
After pressing the Run button, you should have the rosject loaded. Now, let’s head to the next section to get some real practice.
In order to interact with ROS2, we need a terminal.
Let’s open a terminal by clicking the Open a new terminal button.
Recreating the error: Creating the custom srv
Create a new package named custom_interfaces
. This package, however, has to be a CMake
package (default when using ros2 pkg create
). Currently, there is no way to generate custom interfaces in a pure Python package. However, you can create a custom interface in a CMake package and then use it in a Python node.
cd ~/ros2_ws/src/ ros2 pkg create custom_interfaces
Next, remove the include
and src
directories and create a directory named srv
inside your package. Inside this directory, create the srv file TurnCamera.srv
:
cd ~/ros2_ws/src/custom_interfaces rm -rf include rm -rf src mkdir srv touch srv/TurnCamera.srv
Paste this inside TurnCamera.srv
:
float32 deg_turn --- sensor_msgs/Image camera_image
Then add the following lines to the CMakeLists.txt
file:
find_package(rosidl_default_generators REQUIRED) find_package(sensor_msgs REQUIRED) rosidl_generate_interfaces(${PROJECT_NAME} "srv/TurnCamera.srv" )
And also the following lines to the package.xml
file within the <package>
element:
<buildtool_depend>rosidl_default_generators</buildtool_depend> <exec_depend>rosidl_default_runtime</exec_depend> <member_of_group>rosidl_interface_packages</member_of_group>
Finally compile the package by running this in the terminal:
cd ~/ros2_ws colcon build --packages-select custom_interfaces
You should get this error:
Starting >>> custom_interfaces --- stderr: custom_interfaces In file included from /home/user/ros2_ws/build/custom_interfaces/rosidl_typesupport_cpp/custom_interfaces/srv/turn_camera__type_support.cpp:7: /home/user/ros2_ws/build/custom_interfaces/rosidl_generator_cpp/custom_interfaces/srv/detail/turn_camera__struct.hpp:134:10: fatal error: sensor_msgs/msg/detail/image__struct.hpp: No suchfile or directory 134 | #include "sensor_msgs/msg/detail/image__struct.hpp" | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ compilation terminated. gmake[2]: *** [CMakeFiles/custom_interfaces__rosidl_typesupport_cpp.dir/build.make:86: CMakeFiles/custom_interfaces__rosidl_typesupport_cpp.dir/rosidl_typesupport_cpp/custom_interfaces/srv/turn_camera__type_support.cpp.o] Error 1 gmake[1]: *** [CMakeFiles/Makefile2:414: CMakeFiles/custom_interfaces__rosidl_typesupport_cpp.dir/all] Error 2 gmake: *** [Makefile:146: all] Error 2 --- Failed <<< custom_interfaces [20.3s, exited with code 2] Summary: 0 packages finished [20.8s] 1 package failed: custom_interfaces 1 package had stderr output: custom_interfaces
Fixing the error: Adding a dependency
So what was the issue?
Well the OP did not pass the dependencies to rosidl_generate_interfaces
by specifying other packages that their custom interface used. In this case, they did not specify the dependency on sensor_msgs
which their custom srv TurnCamera.srv
used.
They added the find_package
line (in green) but did not add the DEPENDENCIES
line (in red) in the CMakeLists.txt
file. Both lines are necessary when using a msg from another package as a field type:
find_package(rosidl_default_generators REQUIRED) find_package(sensor_msgs REQUIRED) # Add packages that the custom interfaces depend on rosidl_generate_interfaces(${PROJECT_NAME} "srv/TurnCamera.srv" DEPENDENCIES sensor_msgs # Add packages that the custom interfaces depend on )
After adding this line, recompile and source the workspace:
cd ~/ros2_ws colcon build --packages-select custom_interfaces source install/setup.bash
It should work now!
Starting >>> custom_interfaces Finished <<< custom_interfaces [21.1s] Summary: 1 package finished [21.5s]
You can verify that your custom srv has been created successfully by running these two commands:
ros2 interface list | grep custom
ros2 interface show custom_interfaces/srv/TurnCamera
You should get these results respectively:
custom_interfaces/srv/TurnCamera
float32 deg_turn --- sensor_msgs/Image camera_image std_msgs/Header header # builtin_interfaces/Time stamp int32 sec uint32 nanosec string frame_id # Header frame_id should be optical frame of camera # origin of frame should be optical center of cameara # +x should point to the right in the image # +y should point down in the image # +z should point into to plane of the image # If the frame_id here and the frame_id of the CameraInfo # message associated with the image conflict # the behavior is undefined uint32 height # uint32 width # string encoding # # taken from the list of strings in include/sensor_msgs/image_encodings.hpp uint8 is_bigendian # uint32 step # uint8[] data #
The same principles should apply for custom msgs and actions with field types that are msgs from packages rather than simply the primitive built-in-types.
Congratulations. You now know how to create ROS 2 Custom Interface.
To learn more advanced topics about ROS 2, have a look at the course below:
- Intermediate ROS 2: https://app.theconstruct.ai/courses/113
We hope this post was really helpful to you.
This tutorial is created by Robotics Ambassador Ernest.
0 Comments