🎉 rmw_zenoh binaries for Rolling, Jazzy and Humble

Hi everyone,

New year, new RMW!

We’ve released rmw_zenoh binaries for ROS 2 Rolling, Jazzy and Humble on respective Ubuntu (amd64, arm64) and RHEL (amd64) platforms.

Install rmw_zenoh binaries

The package can be installed with the command sudo apt install ros-<DISTRO>-rmw-zenoh-cpp. (Replace <DISTRO> with either rolling, jazzy or humble).

The binaries will be available after the next package sync for the respective distributions but in the meanwhile, you can get the pre-release binaries from the testing repository by following this guide.

Note: We strongly recommend using rmw_zenoh on Jazzy and Rolling as these versions are feature complete and have been extensively tested. We have not tested the Humble version ourselves and are expecting the community to help maintain it.

Once installed, you’ll be able to switch to rmw_zenoh by setting the RMW_IMPLEMENTATION environment variable to rmw_zenoh_cpp as seen below.

export RMW_IMPLEMENTATION=rmw_zenoh_cpp

Don’t forget to run the Zenoh router in a separate terminal prior!

ros2 run rmw_zenoh_cpp rmw_zenohd

For more information on usage, configuration, and known issues please see the README. An overview of rmw_zenoh along with its capabilities was presented at ROSCon 2024 Odense and the recording is available here.

Finally, a reminder that rmw_zenoh is not yet an official Tier-1 middleware in ROS 2 but our goal is to get there for the Kilted release in May. We hope these binaries will make it easier for the community to switch to rmw_zenoh and provide feedback!

62 Likes

Finally :raised_hands: , this makes it easy for Zenoh integration.

Great to know this, I was wondering if there are any concrete dates for the next package sync [Jazzy and Humble] ?

They’ll be out next week!

2 Likes

I was curious if there were resources around Zenoh configs or examples around. For example:

  • A configuration for using the router to avoid peer-to-peer discovery
  • A configuration for setting to use local host only to not leave the machine (does it respect ROS_LOCALHOST_ONLY?)
  • What the default config looks like for reference
  • A configuration doing some of the more advanced settings like setting TCP/UDP transport, configuring buffer sizes, shared memory, etc.

I think these are valuable starting-point recipes for folks :slight_smile:

4 Likes

Here is a good overview: https://www.youtube.com/watch?v=fS0_rbQ6KKA

  • A configuration for using the router to avoid peer-to-peer discovery

I’ve got a very very minimal config working, between a docker container on a RPi3 controlling an old Neato botvac: neato_ros2/docker/robot/zenoh.json5 at zenoh · LoyVanBeek/neato_ros2 · GitHub which talks to my laptop, also running a docker: neato_ros2/docker/operator/zenoh.json5 at zenoh · LoyVanBeek/neato_ros2 · GitHub

A couple of years ago I saw this interview with Julien Enoch, a Senior Solutions Architect at ZettaScale Technology: Zenoh for ROS2 (ROS Developers Podcast). At the end, there is also a demo with Zenoh. I found this interesting, and maybe it can help to understand the idea behind it.

Hi @smac,

A configuration for using the router to avoid peer-to-peer discovery

This is actually the out-of-the-box configuration in rmw_zenoh. All discovery traffic is limited to peers in the same host but routers between hosts can be bridged to extend discovery (and transport) across multiple hosts. There’s a little bit of information here and the ROSCon talk/slides is a useful reference to understand the topology in rmw_zenoh.

A configuration for setting to use local host only to not leave the machine (does it respect ROS_LOCALHOST_ONLY?)

Again, this is the default configuration in rmw_zenoh. We do not respect dynamic discovery envars yet but there is a ticket to address this .

What the default config looks like for reference

The default configs for the router and session (every ROS context) is found here. These are adapted from the upstream Zenoh config for the topology we’ve adopted in rmw_zenoh.

A configuration doing some of the more advanced settings like setting TCP/UDP transport, configuring buffer sizes, shared memory, etc.

This draft PR aims to add documentation that goes over different ways rmw_zenoh/zenoh can be configured.
In the meanwhile, this repo which was used for a workshop in ROSCon 2024 can serve as a useful reference!
Feel free to add suggestion to that ticket!

Thanks for the info, that’s all really helpful! I think what I’m meaning is config files that a user can copy+paste to work with from example of preconfigured setups of common needs. The docs are a resource, thanks! As part of that, may I suggest adding a few configs for those that like to work from example / recipes?

I think that’s a similar thing as github.com/ros2/demos to see how to use it in a brass-ticks-heres-the-code way to accompany the configuration and explanation docs. Starting with something in the ballpark of what you need and adjusting it over time from a library of example configs has alot less friction IMO. Then the configuration docs of all the params and explanations dovetail in it well for modifying instead of starting from scratch.

1 Like

That’s a great suggestion! I’ll get a ticket going but we’ll likely need help from the community on this!

This is a great idea. In our company we mostly don’t use ROS but are transitioning our custom IPC over to Zenoh and have been trying to define our different use cases, understand the examples, and come up with standard configs so keen to see what others have / contribute where we can.

Ooh, this might be helpful…<clicks>

Every so often I’ll be online and find a link that I hope will teach me something, and it turns out to just be me - the worst part is sometimes it’s something I’ve forgotten and I find it very helpful!!

3 Likes

I tested the binaries (ros-jazzy-rmw-zenoh-cpp) and wanted to leave a comment for others struggling with the same default RMW issues. The following is just a quick & dirty test, and I guess there are much better and more extensive evaluations out there.

I tested the realsense2_camera_node with rgb_camera.color_profile and depth_module.depth_profile set to 640x480x60 (60 Hz) and visualised the images in rqt as well as check the frequency with ros2 topic hz.

tl;dr: In the jazzy default settings, the frequency with ros2 topic hz was far away from my 60 Hz target and the visualisation in rqt was very choppy. With RMW_IMPLEMENTATION=rmw_zenoh_cpp everything was super smooth and I got the expected target frequency. However, the logging with ros2 bag record seemed to be unaffected by this; I got 60 Hz on the image topics with any RMW.

RMW_IMPLEMENTATION rqt ros2 topic hz comment
rmw_fastrtps_cpp “choppy” ~33 default RMW
rmw_cyclonedds_cpp “smooth” 57 some connection issues
rmw_zenoh_cpp “super smooth” 59.5 had to start Zenoh router manually

I can’t wait for rmw_zenoh_cpp to become the default RMW. Having to start the Zenoh router manually is the only drawback at the moment. I really don’t understand why rmw_fastrtps_cpp was the default RMW for so long. Even rmw_cyclonedds_cpp would have been a better choice.

9 Likes

the frequency with ros2 topic hz was far away from my 60 Hz target

logging with ros2 bag record seemed to be unaffected by this

That’s interesting, I wonder if it has something to do with roscli using python and rosbag2 recording being done with cpp? Rclpy is notoriously high in overhead which causes problems all over the place constantly.

If Zenoh genuinely manages to somehow magically fix the broad rclpy problems then that’s huge in itself.

ros2 bag record relies on rclpy too. The slight performance improvement observed by @christian is likely attributed to the fact that the subscription in rosbag2_transport gets the data from the RMW as as serialized message and writes to disk (in a separate thread) without any deserialization whereas the subscriptions in ros2 topic hz or rqt processes handle data which has been deserialized into ROS msg objects. This deserialization incurs additional overhead.

Why does topic hz deserialize the messages?

Are you sure that’s the only factor? Wouldn’t deserialization have the same impact regardless of rmw type, which is not what’s observed?

ros2 bag record relies on rclpy too

I’m not sure that’s entirely accurate, the rosbag2 repo is 85% cpp in github stats and the 11% that’s python seems to be pybind, not rclpy. I haven’t taken a deep dive into it though.

1 Like

@MoffKalast

the rosbag2 repo is 85% cpp in github stats and the 11% that’s python seems to be pybind, not rclpy. I haven’t taken a deep dive into it though.

you are right.
the implementation details such as Recorder is written in cpp, rosbag2_py provides the type-hinting information for binary Python modules.

but ros2bag package still depends on rclpy, for example QoS configuration. (maybe that is not important for this context.)

@peci1

Why does topic hz deserialize the messages?

i think this is very good question.

the reason ros2 topic hz deserializes the message is that --filter option support, that only measures messages matching the specified Python expression.

but if that option is not specified, i do not think we need to deserialize the message every time when the message comes in.

instead, we can just calculate the frequency without checking what is inside the message. (the same enhancement can be done for ros2 topic bw)

for doing that, we 1st need to have GenericSubscription and create_generic_subscription in rclpy.

10 Likes

Generations of future ROS2 users will thank you for fixing ros2 topic hz. I stopped counting how often I have explained 1st time ROS2 users that for high bandwidth message streams (or messages using compound types), they cannot rely on ros2 topic hz.

8 Likes

I see the UDP transport cargo feature is disabled. In addition, I don’t see the Z_RELIABILITY_BEST_EFFORT flag used anywhere.

In my application, I would like to make best_effort topics use UDP, and reliable topic use TCP. This seems possible in “vanilla” zenoh if I believe this piece of documentation.

Is it planned to enable the UDP transport and enable best effort topics?