Sending ROS 2 Message Types Over the Wire

Dynamically fetch type descriptions for ROS 2 topics at runtime
Emerson KnappEmerson Knapp ·
Esther WeonEsther Weon ·
5 min read
Published
Sending ROS 2 Message Types Over the Wire

Thanks in part to Foxglove’s contributions, the ROS 2 Iron Irwini release allows you to programmatically fetch type descriptions from remote nodes at runtime. Every type description now includes an associated hash, ensuring that you have the correct type descriptions to decode your ROS messages.

ROS 1 already provided md5sum hashes for type checking, and this contribution closes the gap for ROS 2.

Added support

In ROS, publisher nodes advertise a topic by providing a topic name (e.g. /imu) and type name (e.g. sensor_msgs/msg/Imu). If a subscriber node wants to listen to a published topic and start receiving its messages, it first checks that the message type name matches before connecting.

There were two problems with this model. For one, ROS message type definitions can evolve over time. Nodes with an outdated version of a type description could still receive messages of that type, but would fail to correctly deserialize the packets. Secondly, a system that didn't have the necessary type descriptions installed would not be able to parse ROS 2 data files using those message types.

With Foxglove’s latest contribution, ROS 2 makes progress towards tackling these issues by making it possible to identify when type descriptions have evolved and to dynamically fetch the required types at runtime.

Hash checking

Each message type now has a unique compact hash baked into it at build time. Subscribers now receive this hash when requesting topic information from publishers and compare it with their own local understanding of the type description. In this way, they can detect a possible mismatch – even if the type name itself hasn’t changed – before ever connecting to the publisher.

This pre-validation leads to more accurate type tracking and more robust systems. Instead of having to wonder why users can’t parse or playback a particular ROS data file, app developers can now detect if a type has changed and surface this root cause to users.

This new hash lives in the updated topic_endpoint_info, in the new rosidl_type_hash_t field. The ros2 topic info --verbose command will now print the discovered type hash (starts with “RIHS01”, for ROS Interface Hashing Standard, version 01):

$ ros2 topic info /chatter --verbose
Type: std_msgs/msg/String

Publisher count: 1

Node name: talker
Node namespace: /
Topic type: std_msgs/msg/String
Topic type hash: RIHS01_df668c740482bbd48fb39d76a70dfd4bd59db1288021743503259e948f6b1a18
Endpoint type: PUBLISHER
GID: 01.0f.70.b7.38.00.06.74.00.00.00.00.00.00.14.03
QoS profile:
  Reliability: RELIABLE
  History (Depth): UNKNOWN
  Durability: VOLATILE
  Lifespan: Infinite
  Deadline: Infinite
  Liveliness: AUTOMATIC
  Liveliness lease duration: Infinite

Subscription count: 0

Type fetching

Nodes now provide a GetTypeDescription service (~/get_type_description) – similar to the services exposed to manage ROS parameters. Given a request, a publisher node will return the full programmatic type description via a new set of type description messages. It may optionally also send the text contents of the original source used to define the type.

To dynamically fetch the types required to parse a given topic, run a simple publisher node in one Terminal window:

$ ros2 run demo_nodes_cpp talker

List all services in another:

$ ros2 service list
    /talker/describe_parameters
    /talker/get_parameter_types
    /talker/get_parameters
    /talker/get_type_description
    /talker/list_parameters
    /talker/set_parameters
    /talker/set_parameters_atomically

Call the /talker/get_type_description service to dynamically fetch the appropriate type descriptions (in this case, std_msgs/msg/String):

$ ros2 service call \
    /talker/get_type_description \
    type_description_interfaces/srv/GetTypeDescription \
    "{type_name: std_msgs/msg/String, type_hash: RIHS01_df668c740482bbd48fb39d76a70dfd4bd59db1288021743503259e948f6b1a18
    , include_type_sources: true}"

    requester: making request: type_description_interfaces.srv.GetTypeDescription_Request(type_name='std_msgs/msg/String', type_hash='RIHS01_df668c740482bbd48fb39d76a70dfd4bd59db1288021743503259e948f6b1a18', include_type_sources=True)

    response:
    type_description_interfaces.srv.GetTypeDescription_Response(
    successful=True, failure_reason='',
    type_description=type_description_interfaces.msg.TypeDescription(
    type_description=type_description_interfaces.msg.IndividualTypeDescription(
    type_name='std_msgs/msg/String',
    fields=[
    type_description_interfaces.msg.Field(
    name='data',
    type=type_description_interfaces.msg.FieldType(type_id=17, capacity=0, string_capacity=0, nested_type_name=''), default_value='')
    ]),
    referenced_type_descriptions=[]),
    type_sources=[
    type_description_interfaces.msg.TypeSource(
    type_name='std_msgs/msg/String',
    encoding='msg',
    raw_file_contents='# This was originally provided as an example message.\n# It is deprecated as of Foxy\n# It is recommended to create your own semantically meaningful message.\n# However if you would like to continue using this please use the equivalent in example_msgs.\n\nstring data')
    ],
    extra_information=[])

Now that you can dynamically fetch the types you need, you can inspect remote systems – even those that are not known on the local computer – and dynamically fetch the types needed to parse their topics.

Future work

Dynamic subscriptions and publishers

This added support paves the way for future improvements – like allowing dynamic subscriptions to any publisher using just a type name at runtime. Even without prior knowledge of a custom type description, subscribers would always have automatic access to the “source of truth” during data playback – regardless of when and where the original type descriptions were first defined.

This is particularly useful for third party applications and developer tools like Foxglove, as they can now dynamically inspect whatever is coming over the network.

Evolving types

Dynamic subscriptions and publishers also open the door to “evolving types”. Messages change over time as a regular part of ROS development, but ROS 2 currently does not adapt well to these type description iterations.

In the future, applications could handle these type changes more gracefully, by dynamically converting them for forwards- and backwards-compatibility. This would afford developers much more flexibility, as types evolve alongside previously recorded data.

Stay tuned

We’re excited that this new feature is making ROS 2 more robust for production use and enabling easy message inspection in off-host visualization tools like Foxglove Studio and RViz.

This type description feature set was a prerequisite for the features of ROS Enhancement Proposal (REP) 2011 “Evolving Types”, which is a larger project designed to make ROS applications more robust to migrations over time. Check out the new REP 2016 “Type Descriptions” for a full description of this feature set, or the type_description_interfaces package for more information.


Read more:

Improved Topic Discovery and Visualization in Foxglove
article
visualization
Improved Topic Discovery and Visualization in Foxglove

Drag-and-drop topics into select panels for instant visualization

Esther WeonEsther WeonEsther Weon
3 min read
Announcing Foxglove's Improved URDF Support
article
visualization
Announcing Foxglove's Improved URDF Support

Fetch remote meshes, use additional URDF sources, and visualize collision geometries

Hans-Joachim KrauchHans-Joachim KrauchHans-Joachim Krauch
Esther WeonEsther WeonEsther Weon
2 min read

Get blog posts sent directly to your inbox.

Ready to try Foxglove?

Get started for free