2 releases

0.10.1-rc.2 Jan 23, 2024
0.10.1-rc Dec 21, 2023

#6 in Robotics

28 downloads per month

EPL-2.0 OR Apache-2.0

400KB
9K SLoC

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:

  • A better integration of the ROS graph (all ROS topics/services/actions can be seen across bridges)
  • A better support of ROS toolings (ros2, rviz2...)
  • Configuration of a ROS namespace on the bridge, instead of on each ROS Nodes
  • Easier integration with Zenoh native applications (services and actions are mapped to Zenoh Queryables)
  • More compact exchanges of discovery information between the bridges

Plugin or bridge ?

This software is built in 2 ways to choose from:

  • zenoh-plugin-ros2dds: a Zenoh plugin - a dynamic library that can be loaded by a Zenoh router
  • zenoh-bridge-ros2dds: a standalone executable

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

How to install it

No version has been released yet. Therefore only nightly built packages are available.

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, 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

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

  • docker pull eclipse/zenoh-bridge-ros2dds:nightly for the main branch version (nightly build)

How to build it

⚠️ 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 mantaining compatibility between the various git repositories in the Zenoh project.

⚠️ 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:

  • Rust. If you already have the Rust toolchain installed, make sure it is up-to-date with:

    $ rustup update
    
  • On Linux, make sure the llvm and clang development packages are installed:

    • on Debians do: sudo apt install llvm-dev libclang-dev
    • on CentOS or RHEL do: sudo yum install llvm-devel clang-devel
    • on Alpine do: apk install llvm11-dev clang-dev
  • CMake (to build CycloneDDS which is a native dependency)

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

⚠️ WARNING ⚠️ : On Linux, don't use cargo build command without specifying a package with -p. Building both zenoh-plugin-ros2dds (plugin library) and zenoh-bridge-ros2dds (standalone executable) together will lead to a multiple definition of load_plugin'` error at link time. See #117 for explanations.

You can then choose between building the zenoh bridge for DDS:

  • as a plugin library that can be dynamically loaded by the zenoh router (zenohd):
$ cargo build --release -p zenoh-plugin-ros2dds

The plugin shared library (*.so on Linux, *.dylib on Mac OS, *.dll on Windows) will be generated in the target/release subdirectory.

  • or as a standalone executable binary:
$ cargo build --release -p zenoh-bridge-ros2dds

The zenoh-bridge-ros2dds binary will be generated in the target/release sub-directory.

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 architechture 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.

⚠️ 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:

  • define ROS_LOCALHOST_ONLY=1.
    Preferably, enable MULTICAST on the loopback interface with this command (on Linux): sudo ip l set lo multicast on
  • use different ROS_DOMAIN_ID on each hosts
  • use a CYCLONEDDS_URI that configures CycloneDDS to only use internal interfaces to the robot. This configuration has to be used for all ROS Nodes as well as for the bridge.
    For instance for Turtlebot4 which embeds 2 hosts interconnected via USB:
    <CycloneDDS>
     <Domain>
         <General>
             <Interfaces>
                 <NetworkInterface name="usb0"/>
                 <!-- For less traffic, force multicast usage on loopback even if not configured.         -->
                 <!-- All ROS Nodes and bridges must have this same config, otherwise they won't discover -->
                 <NetworkInterface address="127.0.0.1" multicast="true"/> 
             </Interfaces>
             <DontRoute>true</DontRoute>
         </General>
     </Domain>
    
```

On the robot, run:

  • zenoh-bridge-ros2dds -l tcp/0.0.0.0:7447

On the operating host run:

  • zenoh-bridge-ros2dds -e tcp/<robot-ip>:7447
  • check if the robot's ROS interfaces are accessible via:
    • ros2 topic list
    • ros2 service list
    • ros2 action list

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 possibile 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:

  • zenoh-bridge-ros2dds -h

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

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 @ros2/<id>/**, where <id> is the unique 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, those URLs can be queried:

Dependencies

~40–55MB
~1M SLoC