4.2. Creating custom types

Table of Contents

This tutorial aims at providing step-by-step guidance for those users interested in adding custom message definition to the micro-ROS build. Those instructions can be used to extend the type definition for topics, services and actions provided by ROS 2 and micro-ROS.

Further information can be found in Implementing custom interfaces.

Note

This tutorial starts from a previously created micro-ROS environment. Check the first steps of Getting started micro-ROS for instructions on how to create a micro-ROS environment for embedded platforms.

For creating custom types in a Build System Component, check the instructions in each component repository. For example Renesas e2 Studio Readme or ST Micro ST Cube IDE/MX.

4.2.1. Simple types

Once the micro-ROS workspace is created, navigate to firmware/mcu_ws and create a new package for the custom messages:

cd firmware/mcu_ws
ros2 pkg create --build-type ament_cmake my_custom_message
cd my_custom_message
mkdir msg
touch msg/MyCustomMessage.msg

In the generated CMakeLists.txt file the following lines shall be added just before ament_package() line:

...
find_package(rosidl_default_generators REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/MyCustomMessage.msg"
 )
...

In the generated package.xml file the following lines shall be added:

...
<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>
...

The content of the msg/MyCustomMessage.msg file contains the message definition. For example:

bool bool_test
byte byte_test
char char_test
float32 float32_test
float64 double_test
int8 int8_test
uint8 uint8_test
int16 int16_test
uint16 uint16_test
int32 int32_test
uint32 uint32_test
int64 int64_test
uint64 uint64_test

Note

Same approach can be taken with .srv and .action files for creating types for micro-ROS services and actions.

Now, the micro-ROS workspace workspace can be built as usual. As explained in Getting started micro-ROS, the ros2 run micro_ros_setup build_firmware.sh command will build all packages located inside mcu_ws. In the micro-ROS application code the new message type can be used as usual:

#include <my_custom_message/msg/my_custom_message.h>

...

my_custom_message__msg__MyCustomMessage msg = {0};

msg.byte_test = 3;
msg.uint32_test = 42;

...

rclc_publisher_init_default(&publisher, &node, ROSIDL_GET_MSG_TYPE_SUPPORT(my_custom_message, msg, MyCustomMessage), "my_custom_publisher");
rcl_publish(&publisher, &msg, NULL);

...

4.2.2. Type composition

It is possible to create custom types that compose members from another ROS 2 message type packages. For example a member with type Point32 from the ROS 2 package geometry_msgs.

First of all, the dependency shall also be included in in the CMakeLists.txt:

...
find_package(rosidl_default_generators REQUIRED)
find_package(geometry_msgs REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/MyCustomMessage.msg"
  DEPENDENCIES geometry_msgs
 )
...

The dependency shall be included in package.xml:

...
<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>
<depend>geometry_msgs</depend>
...

At this point, message definition in msg/MyCustomMessage.msg can now include types from the geometry_msgs package:

...
int64 int64_test
uint64 uint64_test
geometry_msgs/Point32 point32_test

And finally, the new member can be accessed in the custom type:

#include <my_custom_message/msg/my_custom_message.h>

...

my_custom_message__msg__MyCustomMessage msg;

msg.byte_test = 3;
msg.uint32_test = 42;

msg.point32_test.x = 1.23;
msg.point32_test.y = 2.31;
msg.point32_test.z = 3.12;

...

Note

More details on how to handle micro-ROS types memory can be found on Handling messages memory tutorial.