ROS 2 type support introspection and conversion of C/C++ messages to/from YAML

This post is a follow-up to this previous post/comment about message introspection and conversion into a YAML representation using this repo: GitHub - osrf/dynamic_message_introspection

I’ve added support for C++ messages to go along support for C messages, made the message<–>YAML conversion symmetrical, and did a bunch of refactoring. The code for this is on a branch on my fork: GitHub - christophebedard/dynamic_message_introspection at add-cpp-support-and-refactor

In short, it allows you to convert a C or C++ message, like this std_msgs/Header message:

std_msgs::msg::Header msg;
msg.frame_id = "my_frame";
builtin_interfaces::msg::Time stamp;
stamp.sec = 4;
stamp.nanosec = 20U;
msg.stamp = stamp;

into a YAML representation, which can be converted to string:

stamp:
  sec: 4
  nanosec: 20
frame_id: my_frame

That string can be parsed as a YAML object and then converted back to a std_msgs/Header message that will be equivalent to the original one!

Note that you could do the first part using std_msgs::msg::to_yaml(const Header & msg). However, that doesn’t use type support introspection, and again it only does the conversion to YAML and not the other way. rosidl_runtime_py can do the conversion from YAML (e.g., for ros2 topic pub), but it’s in Python.

Even starting from the implementation for C messages, writing the introspection code for C++ messages was a nice challenge. I’m sure some things could be improved, and I might have done some things wrong (although it works :tm:). It could nonetheless serve as another example of how to do type support introspection! :robot:

9 Likes

Cool!

Is that a typo (hopefully), should be std_msgs::to_yaml()?

1 Like

Oops yes it’s a typo! It should be std_msgs::msg::to_yaml(); I fixed it, thank you!

This is great!

I just started using asyncapi to document ROS2, and then the converted messages for MQTT also.

Would you be interested in letting me contribute to convert from your yaml representation into asyncapi yaml?

My interest is to make a way to, given a ROS2 .msg, generate the asyncapi yaml specification for the messages.

Asyncapi supports code generation for many other languages, so if this is accomplished, this could allow people to re-use the ROS2 message definitions in many other languages.

Feel free to fork my fork and give it a try!

As for AsyncAPI, unless I misunderstand your goal, I don’t think this project is what you want. This turns a message instance (with values) into YAML at runtime. However, you want to turn the message definition/structure (.idl/.msg file) into an AsyncAPI YAML spec, correct? You might want to look into parsing .idl files directly or trying to rely on some of the existing tools, like rosidl_parser (and the other rosidl* packages).

Got it. Seems to not be the right tool for the job. We are using asyncAPI to generate source code to convert between the messages from ROS2 representations into JSON for MQTT, but supports all our custom messages too.

I’ll check out the rosidl_parser.

The biggest issue I have right now is the conversion that ROS2 does to go from msg files into idl loses all the documentation because documentation is just comments in msg with no official guidelines. I don’t think there is any way to fix that other than flipping the way ROS2 genenerates their messages, by starting from IDL and the IDL is the source of truth; it at least supports @annotations.

Theoretically, we could pass along the comments from the .msg files into the .idl as annotations. There are some design decisions to be made there, but I don’t think the problem is insurmountable.

That feature - to preserve comments - has actually been implemented almost three years ago.

While comments in .msg / .srv / .action are unstructured (due to limitations of that format) the parser in ROS 2 is able to extract them and based on a heuristic described in ros2/rosidl#316 associate comment lines with different parts - either the whole file (or section for services and actions) or individual fields. And this information is then transferred into generated .idl as annotations (from where it should even go into the generated source code in each language).

Very cool thank you both for the information. Being able to propogate ROS2 message definitions + comments into the respective IDL, as well as MQTT message payloads will help us expand the data schemas of our systems into non-ROS2 based systems that support DDS and also to MQTT.

Do you plan to open this C++ support as a PR to the upstream GitHub - osrf/dynamic_message_introspection ?

This is a really useful example - available just in time for a rosbag2 serialization format converter sample I’m trying to put together.

Sure, here it is! Add support for C++ messages, make conversion symmetrical, and refactor by christophebedard · Pull Request #15 · osrf/dynamic_message_introspection · GitHub

1 Like

Thanks for contributing those changes, @christophebedard ! They look pretty awesome, but it will take me a few days to get to a proper review.

1 Like