Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 131 additions & 3 deletions _docs/tutorials/advanced/handling_type_memory/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ This page aims to explain how to handle messages and types memory in micro-ROS.

First of all, since the micro-ROS user is in an embedded C99 environment, it is important to be aware of what messages and ROS 2 types are being used in order to handle memory correctly.

The micro-ROS type memory handling has changed in the latest micro-ROS Galactic distribution, two approaches are presented in this tutorial: micro-ROS Foxy and micro-ROS Galactic and beyond:

- [micro-ROS Foxy](#micro-ros-foxy)
- [Sequence types in micro-ROS](#sequence-types-in-micro-ros)
- [Compound types in micro-ROS](#compound-types-in-micro-ros)
- [Sequences of compound types](#sequences-of-compound-types)
- [micro-ROS Galactic](#micro-ros-galactic)

# micro-ROS Foxy

By watching the `.msg` or `.srv` of the types used in a micro-ROS application, you can determine the type of each member. Currently, the following types are supported:
- Basic type
- Array type
Expand Down Expand Up @@ -58,7 +68,7 @@ In the case of `MyType.msg`, the `values` sequence member is represented in C99

```c
typedef struct rosidl_runtime_c__int32__Sequence
{
{
int32_t* data; /* The pointer to an array of int32 */
size_t size; /* The number of valid items in data */
size_t capacity; /* The number of allocated items in data */
Expand Down Expand Up @@ -94,7 +104,7 @@ for(int32_t i = 0; i < 3; i++){

## Compound types in micro-ROS

When dealing with a compound type, the user should recursively inspect the types in order to determine how to handle each internal member.
When dealing with a compound type, the user should recursively inspect the types in order to determine how to handle each internal member.

For example in the `MyType.msg` example, the `header` member has the following structure:

Expand Down Expand Up @@ -148,7 +158,7 @@ int8[10] coefficients
string name
```

In this case, the generated typesupport will be:
In this case, the generated typesupport will be:

```c
typedef struct mypackage__msg__MyComplexType
Expand Down Expand Up @@ -191,3 +201,121 @@ for(int32_t i = 0; i < 3; i++){
mymsg.multiheaders.size++;
}
```

# micro-ROS Galactic

Due to the inclusion of [`rosidl_typesupport_introspection_c`](https://github.com/ros2/rosidl/tree/master/rosidl_typesupport_introspection_c) in micro-ROS Galactic distribution, an automated memory handling for micro-ROS types is available. The tools related to this feature are available in the package [`micro_ros_utilities`](https://github.com/micro-ROS/micro_ros_utilities).

The documentation of the package [`micro_ros_utilities`](https://github.com/micro-ROS/micro_ros_utilities) is available [here](https://micro.ros.org/docs/api/utils/).

This package is able to auto-assign memory to a certain message struct using default dynamic memory allocators, for example, using the previouly declated type:

```c
mypackage__msg__MyType mymsg;

static micro_ros_utilities_memory_conf_t conf = {0};

bool success = micro_ros_utilities_create_message_memory(
ROSIDL_GET_MSG_TYPE_SUPPORT(mypackage, msg, MyType),
&mymsg,
conf
);
```

This code will init all the string and sequences recursively in `MyType` type. The size of this memory slots will be by default the ones in [`micro_ros_utilities_memory_conf_default`](https://github.com/micro-ROS/micro_ros_utilities/blob/c829971bd33ac1f14a94aa722476110b4b59eaf9/include/micro_ros_utilities/type_utilities.h#L51), that is:
- String will have 20 characters
- ROS 2 types sequences will have a length of 5
- Basic types sequences will have a length of 5

This defaults can be overriden using:

```c
mypackage__msg__MyType mymsg;

static micro_ros_utilities_memory_conf_t conf = {0};

conf.max_string_capacity = 50;
conf.max_ros2_type_sequence_capacity = 5;
conf.max_basic_type_sequence_capacity = 5;

bool success = micro_ros_utilities_create_message_memory(
ROSIDL_GET_MSG_TYPE_SUPPORT(mypackage, msg, MyType),
&mymsg,
conf
);
```

To customize the length of each member of the struct, a complex rules approach can be used as in the following example:

```c
mypackage__msg__MyComplexType mymsg;

static micro_ros_utilities_memory_conf_t conf = {0};

micro_ros_utilities_memory_rule_t rules[] = {
{"multiheaders", 4},
{"multiheaders.frame_id", 60},
{"name", 10}
};
conf.rules = rules;
conf.n_rules = sizeof(rules) / sizeof(rules[0]);

// member named "values" of MyComplexType will have the default max_basic_type_sequence_capacity

bool success = micro_ros_utilities_create_message_memory(
ROSIDL_GET_MSG_TYPE_SUPPORT(mypackage, msg, MyComplexType),
&mymsg,
conf
);
```

Is also possible to use a user-provided buffer to allocate memory:

```c
mypackage__msg__MyComplexType mymsg;

static micro_ros_utilities_memory_conf_t conf = {0};

static uint8_t my_buffer[1000];

bool success = micro_ros_utilities_create_static_message_memory(
ROSIDL_GET_MSG_TYPE_SUPPORT(mypackage, msg, MyComplexType),
&mymsg,
conf,
my_buffer,
sizeof(my_buffer)
);
```

The library provides utilies for calculating the size that both approaches will use with a certain configuration. Notice that this amount of memory is only the dynamic usage or the usage in the user provided buffer, `sizeof(mypackage__msg__MyComplexType)` is not taken into account.

```c
mypackage__msg__MyComplexType mymsg;

static micro_ros_utilities_memory_conf_t conf = {0};

size_t dynamic_size = micro_ros_utilities_get_dynamic_size(
ROSIDL_GET_MSG_TYPE_SUPPORT(mypackage, msg, MyComplexType),
conf
);

size_t static_size = micro_ros_utilities_get_static_size(
ROSIDL_GET_MSG_TYPE_SUPPORT(mypackage, msg, MyComplexType),
conf
);
```

Finally, a destruction function is also provided for messages allocated in dynamic memory:


```c
mypackage__msg__MyComplexType mymsg;

// Release memory previously allocated with micro_ros_utilities_create_message_memory

bool success = micro_ros_utilities_destroy_message_memory(
ROSIDL_GET_MSG_TYPE_SUPPORT(mypackage, msg, MyComplexType),
&mymsg,
conf
);
```