# rosidl type support and new language

Context: trying to implement support for Ada.

I'm trying to understand how should I bridge the gap from .msg files to Ada data types. I've read this: http://docs.ros2.org/ardent/developer... (unfortunately the rosidl API is not available it seems) and checked relevant rosidl, typesupport packages, but the separation between source templates, generated files and installed headers is causing me some headaches.

Binding the C rcl is easy from Ada, and I already have that. I am able to retrieve an untyped message from a subscription, using the C rcl API and using the rosidl_message_type_support_t as an opaque type. My main concern right now is if I'm barking the wrong tree, in regard to how data is serialized/deserialized. In the docs I read:

type support means: meta data or functions that are specific to a given type and that are used by the system to perform particular tasks for the given type. The type support for a given message might include things like a list of the names and types for each field in the message. It might also contain a reference to code that can perform particular tasks for that type, e.g. publish a message.

However, I'm failing at finding these functions, and am unsure if they're intended for client lib writers or for the RMW implementations. The *__functions.h and *__type_support.h seem obvious candidates but if I'm not mistaken they're more or less boilerplater-y for creation/destruction, and calling the appropriate typesupport macro.

So, in essence, I'm currently hitting a wall at the point of the macros that return a type support struct. I see that each rosidl_message_type_support_t contains a void pointer, and a handler function rosidl_message_typesupport_handle_function whose purpose I cannot ascertain.

Besides any general advice on this, one concrete question I have is: am I already at the point at which I have to interpret the raw bytes using the ROS-to-DDS equivalences of message fields, or should I use some C functions that I'm failing to understand to make things simpler? The former seems doable but quite some work that I'm not sure the other client libraries are doing, so I suspect I'm missing something.

Anyway, thanks for the patience and thanks for any help.

edit retag close merge delete

After spinning a bit more on all this, I think I might use the <type>__struct.h files in my own Ada generated files, and indeed the __functions.h for allocations of dynamic sizes... But I'm unsure if this is the expected path. The C++ struct headers don't seem to rely on the C ones, for example.

( 2018-05-24 10:13:37 -0600 )edit

But the python ones do seem to follow this path

( 2018-05-24 10:16:00 -0600 )edit

And after digging some more in the rclcpp I see that there are indeed the calls I was missing to rcl/rmw, so I guess the answer to my question is the second path of leveraging all the rosidl C generated header files. Would be nice if someone in the know could confirm though.

( 2018-05-25 03:32:34 -0600 )edit

I'd recommend looking at the Python implementation. It's in a similar situation to you where it is using the C data structures but still generates Python objects for each msg type: https://github.com/ros2/rosidl/blob/m...

( 2018-05-25 03:51:52 -0600 )edit

C++ indeed does not use the C data structures. Instead it generates its own structures and therefore its own typesupport for those structures. So those are the two ways you can approach it, Python reuses the C structs but wraps them in a new structure, but C++ defines both types and typesupport.

( 2018-05-25 03:53:24 -0600 )edit

Thanks, @William. I have now seen the wrappers in Python and I'll try to do the same. I do not understand though how C++ can generate its own typesupport. Is this not bypassing rcl/rmw somehow? Are there any advantages in doing it that way? Ada is closer to C++ than Python and I'd like to understand

( 2018-05-25 10:24:15 -0600 )edit

Sort by » oldest newest most voted

You can either use existing data structures and associated type support or you can create new data structures and associated type support objects. Python, for example, just reuses the C data structures, so it doesn't need its own type support as well. However, the Python implementation could have, instead, generate its own version of data structures (maybe as PyObject's), but then every rmw implementation that doesn't use the introspection type support would need to generate code to handle these PyObject's.

At the core, three is a function that most type support objects have, which is to convert the user's data structure into something the middleware handle. So as an example, consider std_msgs/String. It generates a C data structure called std_msgs__msg__string but for Connext (as an example, because it has it's own type support) needed to publish this, we'd first need to convert it to a compatible type Connext could consume. That might be either a CDR buffer (uint8_t[]) or a DDS type generated from IDL like dds::std_msgs::msg::string (something like that). So a pair of functions to convert to and from these types would be stored in the opaque part of the type support. If you wanted to create yet different data structures you'd need matching type support for all supported rmw implementations.

The type supports are paired between the data structure type (C or C++ is all we have right now) and the implementation that needs to operate on those types. So for example, you can see here how Connext supports both C and C++ type supports:

In the future, once some technical details have been sorted out, it might be possible to simplify this interface so that we don't need rmw implementation specific type supports. This might be possible by instead making the interface only send/receive CDR serialization buffers which are untyped (uint8_t[]'s). But for now, we still need to convert directly to/from the user's in memory representation (whether that be a C, C++, or Ada data structure) to the equivalent DDS data structure for a given vendor.

There's also the "introspection" type support, which can be used by any rmw implementation that chooses to do so, and it works by operating on meta data about the message rather than having explicit conversion functions. It can be pairs with DDS's X-Types or used directly. This is what FastRTPS does right now. You can see it here for both C and C++:

more

Very thorough explanation. The missing piece that was throwing me off is the common intermediate representation that you say don't yet exists. I don't like the idea of doing something that is not totally abstract for the transports like a new typesupport, so I'll rely on the C typesupport. Thanks!

( 2018-05-26 05:46:01 -0600 )edit

Another though: could one use the introspection typesupport from the client side (instead of the rmw implementation side, as you explained) to retrieve and set message contents? It seems so from the headers I see there.

( 2018-05-26 06:37:44 -0600 )edit

Answering to myself: yes, it is doable.

( 2018-05-28 16:30:17 -0600 )edit

For completeness I'll address my experience with the introspection typesupport that's suggested in the accepted answer.

Indeed, I was able to create/edit messages using the functions generated by rosidl_generator_c and rosidl_typesuppport_introspection_c. Furthermore, by using dlopen/dlsym to retrieve the symbols corresponding to messages by their name, I entirely avoid generating files from templates. At the cost of some runtime penalty, of course.

more