micro-ROS中对消息的内存管理

文章目录

  • 1.背景
  • 2.答案
    • 2.1.基本类型及其数组,不需要
    • 2.1.序列类型(复合类型、复合序列类型),需要
  • 3.内存申请方法
    • 3.1.手动申请(Manual allocation)
    • 3.1.工具辅助(micro-ROS utilities)
      • 3.1.1.规则的定义
      • 3.1.2.规则的使用

1.背景

我在之前的一篇文章【在VSCode下利用PlateFormIO开发Arduino的MicroROS遇到的一些问题】中的第10点中,提到一个问题:为啥在使用自定义消息类型时,有时候需要调用 micro_ros_utilities_create_message_memory 函数来对消息对象进行内存申请,而有时候不用呢?

2.答案

其实答案就在这篇官方的指导/说明文章中:【Handling messages memory in micro-ROS】

是否需要对消息类型进行内存申请,取决于消息的成员类型。

2.1.基本类型及其数组,不需要

假如你的消息的成员类型是基本类型(Basic type)及其数组类型(Array type),比如bool、byte、char、float32,bool[n]、byte[n]、char[n]、float32[n]等等,那就不用额外进行内存申请的操作,因为这些基本类型在实例化时就已经明确了空间大小,系统直接帮忙分配好了内存。

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

2.1.序列类型(复合类型、复合序列类型),需要

但是,假如消息的成员类型为:序列类型(Sequence type)、包含序列的复合类型(Compound type)、复合序列类型(Sequences of compound types),那就需要手动申请内存空间了。当然,假如复合类型中的成员全是基本类型,那也不用手动申请。
上面提到的这些类型,之所以需要人为去申请内存,原因很简单:系统不知道你要多大的空间。
就拿int32的序列int32[](注意,这个不是数组类型,中括号中间没有具体的数值)来说,在micro-ROS中,该类型经过解析后,得到的是这样一个结构体:

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 */
} rosidl_runtime_c__int32__Sequence;

由于size、capacity都是未知的,那么系统如何知道要申请多大的内存空间并把指针值赋予data呢?
因此需要程序员自己手动申请并赋值一下。(这里解释一下上述结构体中的size、capacity的区别,类比电池的话,size表示剩余电量/可用电量,capacity表示电池总容量。这样设计,估计是为了在实例化一次这个对象后,能够对这个对象反复利用)

3.内存申请方法

在这个【Handling messages memory in micro-ROS】文章中提到,在micro-ROS中处理消息的内存有两种方式:手动申请(Manual allocation)、辅助申请(micro-ROS utilities)。

3.1.手动申请(Manual allocation)

这个就是要求对数据结构的各个成员进行数据填充、内存分配。比如对上面的rosidl_runtime_c__int32__Sequence类型,可以这样子初始化:

rosidl_runtime_c__int32__Sequence values;

values.capacity = 100;
values.data = (int32_t*) malloc(mymsg.values.capacity * sizeof(int32_t));
values.size = 0;

这样子操作比较繁琐,更好的是下面的方法。

3.1.工具辅助(micro-ROS utilities)

在micro-ROS中,官方提供了一些函数及结构,可以让我们相对便捷地对消息类型进行内存管理。
这里看一下例子:

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
);

其中,mypackage__msg__MyComplexType类型是这样子的:

typedef struct mypackage__msg__MyComplexType
{
  std_msgs__msg__Header__Sequence multiheaders;
  rosidl_runtime_c__int32__Sequence values;
  double duration;
  int8 coefficients[10];
  rosidl_runtime_c__String name;  // equal to rosidl_runtime_c__char__Sequence
} mypackage__msg__MyComplexType;

header的类型是这样的:

typedef struct std_msgs__msg__Header
{
  builtin_interfaces__msg__Time stamp;
  rosidl_runtime_c__String frame_id;
} std_msgs__msg__Header;

3.1.1.规则的定义

可以看到,针对mypackage__msg__MyComplexType的成员multiheaders,指定下面的内存申请规则:

...
micro_ros_utilities_memory_rule_t rules[] = {
  {"multiheaders", 4}, // 对序列进行长度(capacity)的申请
  {"multiheaders.frame_id", 60}, // frame_id是字符串,进行60字节的申请
  ...
};
...

rule的具体的写法应该是

 {"对象成员名称",  Sequence的capacity大小}

micro-ROS中对消息的内存管理_第1张图片

需要注意的是,序列成员的成员可以直接写,而不用序列号,比如上面的"multiheaders.frame_id"就不用写成"multiheaders.data[0].frame_id"之类的。

另外,对于未在rules中指定的序列类型成员,会按照micro_ros_utilities_memory_conf_t的max_string_capacity、max_ros2_type_sequence_capacity、max_basic_type_sequence_capacity来进行申请,假如需要覆盖默认值micro_ros_utilities_memory_conf_default,可以这样操作:

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;

3.1.2.规则的使用

定义好规则之后,当调用 micro_ros_utilities_create_message_memory 函数时,应该是对Sequence类型的capacity进行赋值,然后再根据此capacity进行实际内存的计算+申请。(可能会涉及递归过程?)
大概看一下源码,应该是的。具体实现过程有空再分析分析。
micro-ROS中对消息的内存管理_第2张图片


参考:
【Handling messages memory in micro-ROS】

你可能感兴趣的:(ros,micro-ROS)