Introduction
The ROS 2 communication middleware is a critical component that enables seamless interaction between different nodes in a robotic system.
ROS 2 radically improves on ROS 1 by embracing a pluggable middleware layer, enabling real-time communication, better reliability, and deployment at scale.
Understanding the ROS 2 middleware is crucial for building efficient and scalable robotic applications, and sometimes it’s the most difficult part to grasp.
This tutorial dives deep into the ROS 2 communication middleware, compares the main DDS-based implementations, and ends with a detailed look at Zenoh as an emerging alternative.
ROS 2 Communication Stack in a Nutshell
ROS 2 follows a layered architecture where the middleware is a replaceable component hidden behind the RMW (ROS Middleware) abstraction.
Core concepts
- Nodes, topics, services, actions, and parameters are the application-level communication primitives ROS 2 developers interact with every day.
- The RMW layer defines a common interface that each supported middleware must implement (publish/subscribe, request/reply, discovery, QoS, etc.).
- Below RMW, the concrete middleware implementation is chosen at build or runtime (e.g., Fast DDS, Cyclone DDS, Connext, GurumDDS, or Zenoh).
In practice, you select the middleware through the RMW_IMPLEMENTATION environment variable, and ROS 2 uses the associated shared library to handle all wire-level communication.
DDS and RTPS: The Foundation of ROS 2
Most ROS 2 distributions ship with multiple DDS or RTPS-based vendors. DDS (Data Distribution Service) is a standardized publish–subscribe middleware designed for distributed, real-time, and safety-critical systems.
DDS key properties
- Data-centric pub/sub with strongly-typed topics and rich QoS (Quality of Service) policies (reliability, durability, deadline, latency budget, liveliness, etc.).
- Peer-to-peer discovery based on RTPS, avoiding a single central broker, which improves scalability and robustness.
- Built-in support for multicast, content filtering, and security (DDS Security standard).
ROS 2 maps its concepts almost directly to DDS entities (participants, publishers, subscribers, data writers/readers), so most behavior is defined by the chosen DDS vendor and QoS settings.
Supported DDS Implementations in ROS 2
ROS 2 currently supports multiple DDS/RTPS vendors through different RMW implementations. The “core” ones you encounter in practice are: Fast DDS, Cyclone DDS, Connext DDS, and GurumDDS.
Overview table
| Feature / Vendor | Fast DDS (eProsima) | Cyclone DDS (Eclipse) | Connext DDS (RTI) | GurumDDS (GurumNetworks) |
|---|---|---|---|---|
| License | Apache 2.0 | EPL/EDL mix | Commercial | Commercial |
| ROS 2 status | Default in many distros | Tier-1 in several distros | Supported, but not always bundled | Supported, less common |
| Focus | Performance, features, security | Determinism, low latency, embedded | Industrial-grade, tooling | Embedded and low-resource systems |
| QoS support | Full DDS QoS set | Full DDS QoS set | Full DDS QoS set | Full DDS QoS set |
| Inter-vendor interop | Generally good, with some service limitations | Known issues with services to others | Works with Fast DDS for topics/services | DDS standard-level interop |
Fast DDS - rmw_fastrtps_cpp
Fast DDS (formerly Fast RTPS) is a popular default ROS 2 middleware, especially in Ubuntu-based desktop/server deployments. It’s the default DDS middleware in Foxy, Humble, Iron, Jazzy, and Kilted.
Strengths
- Widely deployed, battle-tested in many ROS 2 tutorials and community projects, including typical
RMW_IMPLEMENTATION=rmw_fastrtps_cppsetups. - Good performance for large numbers of topics and nodes, with extensive QoS support and security features.
- Broad interoperability with other DDS vendors at the topic level, and mostly working services with Connext.
Weak points
- Configuration can be complex, especially around discovery, multicast, and fine-grained QoS in large heterogeneous networks.
- Historically, some issues have appeared with reliability and discovery on Wi‑Fi or NATed networks, requiring tuning or XML profiles.
Use Fast DDS when you want a solid default, good tooling and community knowledge, and you are mostly in LAN or controlled network environments.
Cyclone DDS - rmw_cyclonedds_cpp
Cyclone DDS is a modern, open-source DDS implementation with a strong focus on determinism and resource efficiency. It’s the default DDS middleware in Galactic.
Strengths
- Designed for embedded and real-time systems, offering predictable latency and good memory behavior.
- Can be easier to tune for deterministic behavior, and integrates well with mixed CPU/RTOS environments.
- Fully open-source and actively developed under the Eclipse Foundation umbrella.
Weak points
- While topics interoperate with other vendors, services and actions have known interoperability limitations with Fast DDS and Connext, especially in older distros.
- Community documentation is still less extensive than Fast DDS in the ROS 2 ecosystem.
Cyclone DDS is a strong choice when you care about real-time performance and deterministic behavior, and your system is dominated by a single vendor (all nodes using Cyclone) to avoid cross-vendor service issues.
Connext DDS - rmw_connextdds
Connext DDS by RTI targets industrial and safety-critical domains, and ROS 2 supports it through a dedicated RMW.
Strengths
- Rich set of enterprise tools: monitoring, recording, visualization, and debugging.
- Proven track record in aerospace, defense, and medical fields, useful if your ROS 2 system must integrate with existing Connext deployments.
- Good interoperability with Fast DDS at the topic and (tested) service level.
Weak points
- Commercial licensing, which may not fit all open-source or academic projects.
- Installation and integration with ROS 2 are more involved than the default open-source vendors.
Connext DDS fits best in projects that already use RTI tooling or require safety-certified middleware.
GurumDDS - rmw_gurumdds
GurumDDS is another DDS implementation supported in ROS 2, especially in some embedded and commercial contexts.
Strengths
- Designed with embedded systems in mind, offering a small footprint and low latency.
- Fully supports the DDS specification and QoS suite.
Weak points
- Less visible in the open ROS 2 community; fewer public examples and benchmarks available.
- Commercial licensing similar to Connext.
You typically consider GurumDDS when working with vendors or platforms that already include it as part of their stack.
Interoperability Between DDS Vendors
One promise of DDS is vendor interoperability, and ROS 2 does leverage that, but there are caveats.
What generally works
- Topics with compatible types and QoS settings typically interoperate across Fast DDS, Connext, and Cyclone, allowing mixed-vendor deployments.
- In-system tests confirm that topics publish/subscribe consistently among core vendors for supported distributions.
Known limitations
- Services and actions are more fragile: for example, Cyclone DDS has known issues with services when interacting with Fast DDS or Connext in some distributions, sometimes even leading to crashes on deserialization.
- Some features (security configurations, content filtering, discovery tuning) are vendor-specific, so advanced setups may not be fully portable.
In a production system, try to standardize on a single DDS vendor whenever possible, and treat cross-vendor communication as a constrained interface that you test explicitly.
Zenoh and rmw_zenoh: A Different Approach
Zenoh is not a DDS implementation; it is a data-centric communication protocol and architecture that unifies pub/sub, queries, and storage, targeting constrained, fog, and cloud environments. ROS 2 integrates Zenoh through rmw_zenoh, an RMW that uses Zenoh as its underlying transport instead of DDS.
Why Zenoh?
- Aims to simplify some of the pain points seen with DDS in ROS 2, especially around configuration complexity and non-LAN deployments.
- Designed from the ground up for heterogeneous networks (LAN, WAN, cellular, intermittent connectivity) and constrained devices.
- Supports routing, bridging, and data persistence in a unified stack, which is attractive for multi-robot and cloud-robotics scenarios.
rmw_zenoh in ROS 2
rmw_zenoh_cpp maps ROS 2 entities directly to Zenoh constructs.
- Publishers and subscribers become Zenoh publishers/subscribers, with “liveliness tokens” to track presence and availability.
- Services and actions are implemented using Zenoh queryables and queries, mapping request–response semantics to Zenoh’s API.
- The implementation was introduced alongside newer ROS 2 distributions (e.g., Humble) and is evolving as a first-class alternative to DDS-based RMWs.
The main design goal is to preserve ROS 2 semantics while leveraging Zenoh’s capabilities to improve performance and operability across challenging networks.
DDS vs Zenoh: Conceptual Differences
From a ROS 2 developer perspective, switching from DDS to Zenoh is “just” changing the RMW, but under the hood the paradigms differ.
Conceptual comparison
| Aspect | DDS vendors | Zenoh |
|---|---|---|
| Standardization | OMG DDS and RTPS standards | Zenoh-specific protocol and APIs |
| Discovery | Peer-to-peer, multicast-centric | Flexible, supports routed/federated topologies |
| Network model | Mostly LAN, VPN-friendly, WAN possible with tuning | Designed for LAN, WAN, and constrained links |
| Features beyond pub/sub | DDS RPC, some recording tools | Integrated queries, storage, routing |
| Configuration complexity | XML profiles, vendor-specific parameters | Configuration tends to be simpler; focus on routing, sessions |
| ROS 2 maturity | Long-standing, production use today | Newer, rapidly evolving RMW |
In high-level terms, DDS focuses on standardized peer-to-peer pub/sub, while Zenoh targets a broader “data plane” across diverse networks with built-in routing and persistence.
Choosing the Right Middleware for Your Robot
Given this landscape, the “best” middleware depends on your use case.
When to prefer DDS
- You need strict DDS standard compliance or must integrate with existing DDS-based systems.
- Your deployment is mostly within a LAN or a controlled industrial network where DDS discovery works well.
- You rely on vendor-specific tooling (RTI Monitor, Fast DDS Monitor, etc.) or certification roadmaps.
When to consider Zenoh
- You are building multi-robot systems where robots span different networks, 4G/5G links, or cloud endpoints.
- You want a single technology to handle pub/sub, queries, and data persistence across edge–fog–cloud.
- You struggle with DDS discovery across NATs or complex network topologies and prefer an explicit routed architecture.
Because ROS 2 uses the RMW abstraction, you can prototype with one middleware and later benchmark another using the same nodes, just by switching RMW_IMPLEMENTATION and installing the corresponding packages.
How to Install and Use Different RMWs
You switch RMW by (1) installing the desired RMW, (2) exporting RMW_IMPLEMENTATION, and (3) restarting the ROS 2 daemon if needed.
1. Check what RMWs you have
Open a terminal console and enter:
env | grep RMW_IMPLEMENTATION # often empty → default Fast DDS
# or
ros2 doctor --report | grep middleware
ros2 doctor will show the active middleware, e.g., rmw_fastrtps_cpp or rmw_cyclonedds_cpp. For example:
$ ros2 doctor --report | grep middleware
middleware name : rmw_fastrtps_cpp
2. Install the RMW implementation
Examples:
-
Fast DDS RMW (usually already installed by default):
sudo apt install ros-$ROS_DISTRO-rmw-fastrtps-cpp -
Cyclone DDS RMW:
sudo apt install ros-$ROS_DISTRO-rmw-cyclonedds-cpp -
Connext (requires separate RTI install, then):
sudo apt install ros-$ROS_DISTRO-rmw-connextdds -
GurumDDS (after installing GurumDDS):
sudo apt install ros-$ROS_DISTRO-rmw-gurumdds-cpp -
Zenoh:
sudo apt install ros-$ROS_DISTRO-rmw-zenoh-cpp
3. Switch RMW per-shell
Use the RMW_IMPLEMENTATION environment variable when running nodes.
Examples:
# Fast DDS
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
# Cyclone DDS
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
# Connext
export RMW_IMPLEMENTATION=rmw_connextdds
# GurumDDS
export RMW_IMPLEMENTATION=rmw_gurumdds_cpp
# Zenoh
export RMW_IMPLEMENTATION=rmw_zenoh_cpp
Then run your nodes as usual:
ros2 run demo_nodes_cpp talker
ros2 run demo_nodes_cpp listener
This works the same in every ROS 2 distribution.
4. Make a default RMW for your user
To make the choice persistent, enter one of the following according to the selected RMW:
# Fast DDS
echo 'export RMW_IMPLEMENTATION=rmw_fastrtps_cpp' >> ~/.bashrc
# Cyclone DDS
echo 'export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp' >> ~/.bashrc
# Connext
echo 'export RMW_IMPLEMENTATION=rmw_connextdds' >> ~/.bashrc
# GurumDDS
echo 'export RMW_IMPLEMENTATION=rmw_gurumdds_cpp' >> ~/.bashrc
# Zenoh
echo 'export RMW_IMPLEMENTATION=rmw_zenoh_cpp' >> ~/.bashrc
Open a new terminal (or source ~/.bashrc), then verify with:
ros2 doctor --report | grep middleware
You should see your chosen implementation.
5. Important detail: ROS 2 daemon
If you switch RMW while the ROS 2 daemon is running, CLI tools can get confused.
Before testing a new RMW:
ros2 daemon stop
ros2 daemon start
This forces CLI tools (ros2 node, ros2 topic, etc.) to use the new RMW implementation.
ROS 2 daemon? What’s that?
This is the first time I’ve introduced the concept of the ROS 2 daemon. Let’s try to understand what it is and why it’s useful.
The ROS 2 daemon is a background process that caches information about the ROS graph to make command-line introspection fast and responsive. It is an optimization for tooling, not a core part of the runtime like the ROS 1 master.
What the ROS 2 daemon is
- It is a long-running helper node started automatically the first time you use certain
ros2CLI commands (e.g.,ros2 node list,ros2 topic list). - It listens to discovery traffic and maintains an internal cache of nodes, topics, services, and other graph entities currently present in the system.
- It communicates with the CLI tools over localhost (e.g., using XML-RPC) to answer “what exists in the graph?” queries quickly.
What the ROS 2 daemon is needed for
1. Speeding up CLI introspection
Without the daemon, every CLI call must directly perform discovery via the underlying middleware, which can take noticeable time as the system grows. The daemon amortizes this cost by continuously tracking the graph so that commands like:
ros2 node listros2 topic listros2 service list
can return almost immediately from the cached state.
2. Avoiding repeated discovery work
Each new CLI call would otherwise have to “re-discover” the network to answer the same questions (which nodes/topics exist), duplicating work that the running daemon has already done. By centralizing this discovery for the workstation, it reduces overhead and improves responsiveness, especially in larger systems.
3. Optional helper, not mandatory infrastructure
- ROS 2 nodes communicate purely via distributed discovery in the middleware; they do not depend on the daemon to run, unlike ROS 1 nodes that depended on the master.
- If the daemon is not running, CLI tools still work; they just perform discovery themselves and are slower.
- You can explicitly start/stop and query it using commands like
ros2 daemon start,ros2 daemon stop, andros2 daemon status, or bypass it with--no-daemonwhen you want to force direct discovery.
In short, the daemon is there to accelerate and stabilize ROS 2 introspection from the command line by caching the ROS graph, but it is not required for the core pub/sub/service communication between nodes.
Conclusions
Choosing the right RMW implementation is crucial for the performance and compatibility of your ROS 2 applications. By understanding the strengths and weaknesses of each middleware option, you can make informed decisions that align with your project’s requirements. Remember to test your setup thoroughly and consult the documentation for any specific configuration details.
A final note: I cited QoS (Quality of Service) settings throughout this guide, but I consciously avoided deep diving into them. QoS settings are essential for fine-tuning the behavior of your ROS 2 nodes and ensuring reliable communication, especially in complex systems. I will dedicate a special section to QoS settings in a future tutorial.