Ask Your Question
0

How to correctly deserialize a message with variable length array?

asked 2020-06-13 10:53:16 -0500

Ekaradon gravatar image

updated 2020-06-15 03:03:03 -0500

I'm receiving some data from serial port and want to deserialize the byte stream I received to a ROS message.

The serial port data contains variable number of elements (elements with same type). So I use variable length array in my ROS message.

For example I have received these bytes in memory:

uint8_t buffer[] = { 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 };

Here,

  • 0x02 means 2 elements in the variable length array,
  • (0x01010101, 0x02020202, 0x03030303) is the first element, this is actually a 3-dimensional point with float type,
  • (0x11111111, 0x12121212, 0x13131313) is the second element.

And I'm going to use this message:

uint8 array_size    # will be 0x02
geometry_msgs/Point32[] points    # will be a array with length 2, the first Point32 is (0x01010101, 0x02020202, 0x03030303), and the second one is (0x11111111, 0x12121212, 0x13131313)

It seems the tutorial does not work with variable length array. I checked the code, and there is a serializer for std::vector.

But the deserialization process goes wrong in this function:

// (line 348 of serialization.h)
template<typename Stream>
inline static void read(Stream& stream, VecType& v)
{
    uint32_t len;
    stream.next(len);
    v.resize(len);    // <----
    IteratorType it = v.begin();
    IteratorType end = v.end();
    for (; it != end; ++it)
    {
        stream.next(*it);
    }   
}

It seems the deserializer will change the length of the vector first. But the value of variable len gets very huge and v.resize(len) fails.

edit retag flag offensive close merge delete

Comments

You could try union. Why not use a vector instead of the dynamic array?

Dragonslayer gravatar image Dragonslayer  ( 2020-06-13 11:49:30 -0500 )edit

Note: the link (ie: "the code") points to the DiamondBack version of this. As this is really low-level functionality, it most likely hasn't changed in the important parts, but I would recommend you use either the repository that hosts the code, or at least use a more up-to-date set of documentation.

gvdhoorn gravatar image gvdhoorn  ( 2020-06-14 06:01:37 -0500 )edit

1 Answer

Sort by ยป oldest newest most voted
2

answered 2020-06-14 05:57:44 -0500

gvdhoorn gravatar image

updated 2020-06-15 03:20:13 -0500

This could be an xy-problem, but ignoring that for now:

It seems the tutorial does not work with variable length array.

the code shown in the tutorial is most likely fine, the problem is likely in the buffer you present to deserialize(..):

  • len is of type uint32_t
  • buffer is an array of uint8_t

this will most likely lead stream.next(len) to read 4 bytes from buffer and consider them all part of len.

This makes len equal to 0x01010102 (little endian), which is 16843010 decimal.

The correct byte sequence for 2 would be 0x02 0x00 0x00 0x00.

Finally: please describe what you are attempting to do, as unless you're implementing your own client library (and implement TCPROS from scratch) it seems unlikely that normal use of ROS would require you to deal with any of this.

edit flag offensive delete link more

Comments

The correct byte sequence for 2 would be 0x02 0x00 0x00 0x00 at the first 4 bytes of buffer, and uint8 array_size should be deleted from msg file.

Ekaradon gravatar image Ekaradon  ( 2020-06-15 03:25:51 -0500 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

2 followers

Stats

Asked: 2020-06-13 10:53:16 -0500

Seen: 31 times

Last updated: Jun 15