Home

Awesome

<img src="https://raw.githubusercontent.com/eclipse-zenoh/zenoh/main/zenoh-dragon.png" height="150">

CI Discussion Discord License License

Eclipse Zenoh

The Eclipse Zenoh: Zero Overhead Pub/sub, Store/Query and Compute.

Zenoh (pronounce /zeno/) unifies data in motion, data at rest and computations. It carefully blends traditional pub/sub with geo-distributed storages, queries and computations, while retaining a level of time and space efficiency that is well beyond any of the mainstream stacks.

Check the website zenoh.io and the roadmap for more detailed information.


A Zenoh bridge for ROS 2 over DDS

ROS (the Robot Operating System) is a set of software libraries and tools allowing to build robotic applications. In its version 2, ROS 2 relies mostly on O.M.G. DDS as a middleware for communications. This plugin bridges all ROS 2 communications using DDS over Zenoh.

While a Zenoh bridge for DDS already exists and helped lot of robotic use cases to overcome some wireless connectivity, bandwidth and integration issues, using a bridge dedicated to ROS 2 brings the following advantages:

Plugin or bridge ?

This software is built in 2 ways to choose from:

The features and configurations described in this document applies to both. Meaning the "plugin" and "bridge" words are interchangeables in the rest of this document.

How to install it

To install the latest release of either the DDS plugin for the Zenoh router, either the zenoh-bridge-ros2dds standalone executable, you can do as follows:

Manual installation (all platforms)

All release packages can be downloaded from:

Each subdirectory has the name of the Rust target. See the platforms each target corresponds to on https://doc.rust-lang.org/stable/rustc/platform-support.html

Choose your platform and download:

Linux Debian

Add Eclipse Zenoh private repository to the sources list:

echo "deb [trusted=yes] https://download.eclipse.org/zenoh/debian-repo/ /" | sudo tee -a /etc/apt/sources.list > /dev/null
sudo apt update

Then either:

Docker images

The zenoh-bridge-ros2dds standalone executable is also available as a Docker images for both amd64 and arm64. To get it, do:

Nightly builds

The "Release" action builds packages for most most of OSes. You can download those from the "Artifacts" section in each build.
Just download the package for your OS and unzip it. You'll get 3 zips: 1 for the plugin, 1 for the plugin as debian package and 1 for the bridge. Unzip the zenoh-bridge-ros2dds-<platform>.zip file, and you can run ./zenoh-bridge-ros2dds

How to build it

:warning: WARNING :warning: : Zenoh and its ecosystem are under active development. When you build from git, make sure you also build from git any other Zenoh repository you plan to use (e.g. binding, plugin, backend, etc.). It may happen that some changes in git are not compatible with the most recent packaged Zenoh release (e.g. deb, docker, pip). We put particular effort in maintaining compatibility between the various git repositories in the Zenoh project.

:warning: WARNING :warning: : As Rust doesn't have a stable ABI, the plugins should be built with the exact same Rust version than zenohd, and using for zenoh dependency the same version (or commit number) than 'zenohd'. Otherwise, incompatibilities in memory mapping of shared types between zenohd and the library can lead to a "SIGSEV" crash.

In order to build the zenoh bridge for DDS you need first to install the following dependencies:

Once these dependencies are in place, you may clone the repository on your machine:

git clone https://github.com/eclipse-zenoh/zenoh-plugin-ros2dds.git
cd zenoh-plugin-ros2dds
cargo build --release

The standalone executable binary zenoh-bridge-ros2dds and a plugin shared library (*.so on Linux, *.dylib on Mac OS, *.dll on Windows) to be dynamically loaded by the zenoh router zenohd will be generated in the target/release subdirectory.

DDS Library Symbol Prefixing

DDS support is provided by the cyclors crate. As this crate contains C code, symbol clashes may occur when loading the plugin statically with other plugins which use a different version of the cyclors crate (e.g. the zenoh-plugin-dds plugin).

To allow multiple versions of the cyclors crate to be loaded at the same time the symbols within the crate can be prefixed with the crate version. The optional prefix_symbols feature can be used to build the ROS2 plugin with prefixed DDS library symbols. e.g.

cargo build --features prefix_symbols

Note: The prefix_symbols feature cannot be used at the same time as the dds_shm feature.

ROS 2 package

You can also build zenoh-bridge-ros2dds as a ROS package running:

rosdep install --from-paths . --ignore-src -r -y
colcon build --packages-select zenoh_bridge_ros2dds --cmake-args -DCMAKE_BUILD_TYPE=Release

The rosdep command will automatically install Rust and clang as build dependencies.

If you want to cross-compile the package on x86 device for any target, you can use the following command:

rosdep install --from-paths . --ignore-src -r -y
colcon build --packages-select zenoh_bridge_ros2dds --cmake-args -DCMAKE_BUILD_TYPE=Release  --cmake-args -DCROSS_ARCH=<target>

where <target> is the target architecture (e.g. aarch64-unknown-linux-gnu). The architecture list can be found here.

The cross-compilation uses zig as a linker. You can install it with instructions in here. Also, the zigbuild package is required to be installed on the target device. You can install it with instructions in here.


Usage

A typical usage is to run 1 bridge in a robot, and 1 bridge in another host monitoring and operating the robot.

:warning: The bridge relies on CycloneDDS and has been tested with RMW_IMPLEMENTATION=rmw_cyclonedds_cpp. While the DDS implementations are interoperable over UDP multicast and unicast, some specific and non-standard features of other DDS implementations (e.g. shared memory) might cause some issues.

It's important to make sure that NO DDS communication can occur between 2 hosts that are bridged by zenoh-bridge-ros2dds. Otherwise, some duplicate or looping traffic can occur.
To make sure of this, you can either:

On the robot, run:

On the operating host run:

Other interconnectivity between the 2 bridges can be configured (e.g. automatic discovery via UDP multicast, interconnection via 1 or more Zenoh routers...). See the Zenoh documentation to learn more about the possible deployments allowed by Zenoh.

Configuration

zenoh-bridge-ros2dds can be configured via a JSON5 file passed via the -c argument. You can see a commented and exhaustive example of such configuration file: DEFAULT_CONFIG.json5.

The "ros2dds" part of this same configuration file can also be used in the configuration file for the zenoh router (within its "plugins" part). The router will automatically try to load the plugin library (zenoh-plugin_dds) at startup and apply its configuration.

zenoh-bridge-ros2dds also allows some of those configuration values to be configured via command line arguments. Run this command to see which ones:

The command line arguments overwrite the equivalent keys configured in a configuration file.

Connectivity configurations

DDS communications

The bridge discovers all ROS 2 Nodes and their topics/services/actions running on the same Domain ID (set via ROS_DOMAIN_ID or 0 by default) via UDP multicast, as per DDS specification.

As the bridge relies on CycloneDDS, it's DDS communications can be configured via a CycloneDDS XML configuration file as explained here.

Zenoh communications

Starting from v0.11.0, the zenoh-bridge-ros2dds is by default started in router mode (See the difference between modes in Zenoh documentation). This means it's listening for incoming TCP connections by remote bridges or any Zenoh application on port 7447 via any network interface. It does perform discovery via scouting over UDP multicast or gossip protocol, but doesn't auto-connect to anything.
As a consequence the connectivity between bridges has to be statically configured in one bridge connecting to the other (or several other bridges) via the -e command line option, or via the connect section in configuration file.

If required, the automatic connection to other discovered bridges (also running in router mode) can be enabled adding such configuration:

scouting: {
  multicast: {
    autoconnect: { router: "router" }
  },
  gossip: {
    autoconnect: { router: "router" }
  }
},

Prior to v0.11.0, the zenoh-bridge-ros2dds was by default started in peer mode.
It was listening for incoming TCP connections on a random port (chosen by the OS), and was automatically connecting to any discovered bridge, router or peer.

Easy multi-robots via Namespace configuration

Deploying a zenoh-bridge-ros2dds in each robot and configuring each with its own namespace brings several benefits:

  1. No need to configure each ROS Node with a namespace. As the DDS traffic between all Nodes of a single robot remains internal to the robot, no namespace needs to be configured
  2. Configuring each zenoh-bridge-ros2dds with namespace: "/botX" (where 'X' is a unique id), each topic/service/action name routed to Zenoh is prefixed with "/botX". Robots messages are not conflicting with each other.
  3. On a monitoring/controlling host, you have 2 options:
    • Run a zenoh-bridge-ros2dds with namespace: "/botX" corresponding to 1 robot. Then to monitor/operate that specific robot, just any ROS Node without namespace.
      E.g.: rviz2
    • Run a zenoh-bridge-ros2dds without namespace. Then you can monitor/operate any robot remapping the namespace to the robot's one, or each topic/service/action name you want to use adding the robot's namespace as a prefix.
      E.g.: rviz2 --ros-args -r /tf:=/botX2/tf -r /tf_static:=/botX/tf_static

NOTE: the bridge prefixes ALL topics/services/actions names with the configured namespace, including /rosout, /parameter_events, /tf and /tf_static.

Admin space

The bridge exposes some internal states via a Zenoh admin space under @/<id>/ros2/**, where <id> is the unique Zenoh ID of the bridge (configurable).
This admin space can be queried via Zenoh get() operation. If the REST plugin is configured for the bridge for instance via --rest-http-port 8000 argument, such URLs can be queried: