Create a Custom Message
In order to create a new message, you will need to do the following steps:
- Create a directory named
msg
inside your package - Inside this directory, create a file named
Name_of_your_message.msg
. - Modify
CMakeLists.txt
file. - Modify
package.xml
file. - Compile and source your workspace
- Use in code
Let's create a message that indicates age, with years, months, and days.
Create message file
Create a directory msg in your package.
cd ~/ros2_ws/src/my_package
mkdir msg
Inside the msg folder, create a new file named Age.msg, which contains the following:
float32 years
float32 months
float32 days
Modify CMakeLists.txt
You will have to edit two functions inside CMakeLists.txt:
find_package()
This is where all the packages required to COMPILE the messages of the topics, services, and actions go. In package.xml, you have to state them as build_depend and exec_depend.
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
find_package(builtin_interfaces REQUIRED)
find_package(rosidl_default_generators REQUIRED)
II. rosidl_generate_interfaces()
This function includes all of the messages of this package (in the msg folder) to be compiled. The file should look like this.
rosidl_generate_interfaces(my_package
"msg/Age.msg"
DEPENDENCIES builtin_interfaces
)
Summarizing, this is the minimum expression of what is needed for the CMakaelist.txt to work:
cmake_minimum_required(VERSION 3.5)
project(my_package)
# 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(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
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(my_package
"msg/Age.msg"
DEPENDENCIES builtin_interfaces
)
ament_package()
Modify package.xml
First, you will need to set the package format to 3. Note that, by default, this will be set to 2, so you will need to manually modify it.
<package format="3">
This has to be done because the member_of_group command requires format 3. Now, just add the following lines to the package.xml file.
<build_depend>builtin_interfaces</build_depend>
<build_depend>rosidl_default_generators</build_depend>
<exec_depend>builtin_interfaces</exec_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>
This is the minimum expression of the package.xml
<?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>my_package</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>rclcpp</depend>
<depend>std_msgs</depend>
<build_depend>builtin_interfaces</build_depend>
<build_depend>rosidl_default_generators</build_depend>
<exec_depend>builtin_interfaces</exec_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
Build the new message
Now, you have to compile the new message.
cd ~/ros2_ws
colcon build --symlink-install --packages-select new_msg
source install/setup.bash
To verify that your message has been created successfully, type the below command. If the structure of the Age message appears, it will mean that your message has been created successfully and it's ready to be used in your ROS programs.
ros2 msg show new_msg/Age
You should get an output like this one:
float32 years
float32 months
float32 days
Use the new Messages in a program
You will have to add to your CMakeLists.txt the following extra lines to compile and link your executable (in this example, it's called publish_age.cpp):
find_package(my_package REQUIRED)
add_executable(age_publisher_node src/publish_age.cpp)
ament_target_dependencies(age_publisher_node rclcpp std_msgs my_package)
install(TARGETS
age_publisher_node
DESTINATION lib/${PROJECT_NAME}
)
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.