|
| 1 | +# Backend Selection |
| 2 | + |
| 3 | +**ros-z supports multiple backend protocols for Zenoh key expression generation, enabling interoperability with different ROS 2-to-Zenoh bridges.** The backend determines how topic names are mapped to Zenoh key expressions, allowing seamless communication across different deployment architectures. |
| 4 | + |
| 5 | +```admonish note |
| 6 | +Backend selection is a compile-time or runtime choice that affects how ros-z maps ROS 2 topics to Zenoh key expressions. Choose the backend that matches your bridge infrastructure for proper message routing. |
| 7 | +``` |
| 8 | + |
| 9 | +## Available Backends |
| 10 | + |
| 11 | +ros-z provides two backend implementations: |
| 12 | + |
| 13 | +| Backend | Key Expression Format | Use Case | Bridge Compatibility | |
| 14 | +|---------|----------------------|----------|---------------------| |
| 15 | +| **RmwZenoh** | `<domain_id>/<topic>/**` | Standard ROS 2 integration | `rmw_zenoh_cpp` middleware | |
| 16 | +| **Ros2Dds** | `<topic>/**` | DDS bridge compatibility | `zenoh-bridge-ros2dds` | |
| 17 | + |
| 18 | +### RmwZenoh Backend (Default) |
| 19 | + |
| 20 | +The RmwZenoh backend is designed for compatibility with ROS 2's official Zenoh middleware implementation. |
| 21 | + |
| 22 | +**Key Expression Format:** |
| 23 | + |
| 24 | +```text |
| 25 | +<domain_id>/<topic>/** |
| 26 | +``` |
| 27 | + |
| 28 | +**Example:** |
| 29 | + |
| 30 | +```text |
| 31 | +0/chatter/** # Domain 0, topic /chatter |
| 32 | +5/robot/status/** # Domain 5, topic /robot/status |
| 33 | +``` |
| 34 | + |
| 35 | +**Use this backend when:** |
| 36 | + |
| 37 | +- Using `rmw_zenoh_cpp` as your ROS 2 middleware |
| 38 | +- Running pure ros-z deployments |
| 39 | +- Requiring domain isolation via Zenoh |
| 40 | + |
| 41 | +### Ros2Dds Backend |
| 42 | + |
| 43 | +The Ros2Dds backend is designed for compatibility with `zenoh-bridge-ros2dds`, which bridges standard DDS-based ROS 2 nodes to Zenoh. |
| 44 | + |
| 45 | +**Key Expression Format:** |
| 46 | + |
| 47 | +```text |
| 48 | +<topic>/** |
| 49 | +``` |
| 50 | + |
| 51 | +**Example:** |
| 52 | + |
| 53 | +```text |
| 54 | +chatter/** # Topic /chatter (no domain prefix) |
| 55 | +robot/status/** # Topic /robot/status |
| 56 | +``` |
| 57 | + |
| 58 | +**Use this backend when:** |
| 59 | + |
| 60 | +- Bridging existing DDS-based ROS 2 systems to Zenoh |
| 61 | +- Using `zenoh-bridge-ros2dds` |
| 62 | +- Integrating with CycloneDDS or FastDDS nodes via Zenoh |
| 63 | + |
| 64 | +## Specifying Backend in Code |
| 65 | + |
| 66 | +### Type-Based Selection (Compile-Time) |
| 67 | + |
| 68 | +Use the builder pattern with generic type parameters for compile-time backend selection: |
| 69 | + |
| 70 | +```rust,ignore |
| 71 | +use ros_z::{Builder, backend::{RmwZenohBackend, Ros2DdsBackend}}; |
| 72 | +use ros_z::qos::{QosProfile, QosHistory}; |
| 73 | +use ros_z_msgs::std_msgs::String as RosString; |
| 74 | +use ros_z_msgs::example_interfaces::srv::AddTwoInts; |
| 75 | +use ros_z_msgs::action_tutorials_interfaces::action::Fibonacci; |
| 76 | +
|
| 77 | +// Create context and node |
| 78 | +let ctx = ZContextBuilder::default().build()?; |
| 79 | +let node = ctx.create_node("my_node").build()?; |
| 80 | +
|
| 81 | +// Publisher with RmwZenoh backend (default) |
| 82 | +let pub_rmw = node |
| 83 | + .create_pub::<RosString>("chatter") |
| 84 | + .with_backend::<RmwZenohBackend>() // Explicit backend |
| 85 | + .build()?; |
| 86 | +
|
| 87 | +// Subscriber with Ros2Dds backend |
| 88 | +let sub_dds = node |
| 89 | + .create_sub::<RosString>("chatter") |
| 90 | + .with_backend::<Ros2DdsBackend>() // DDS bridge compatibility |
| 91 | + .build()?; |
| 92 | +
|
| 93 | +// Service client with RmwZenoh backend |
| 94 | +let client = node |
| 95 | + .create_client::<AddTwoInts>("add_two_ints") |
| 96 | + .with_backend::<RmwZenohBackend>() |
| 97 | + .build()?; |
| 98 | +
|
| 99 | +// Service server with Ros2Dds backend |
| 100 | +let mut server = node |
| 101 | + .create_service::<AddTwoInts>("add_two_ints") |
| 102 | + .with_backend::<Ros2DdsBackend>() |
| 103 | + .build()?; |
| 104 | +
|
| 105 | +// Action client with RmwZenoh backend |
| 106 | +let action_client = node |
| 107 | + .create_action_client::<Fibonacci>("fibonacci") |
| 108 | + .with_backend::<RmwZenohBackend>() |
| 109 | + .build()?; |
| 110 | +
|
| 111 | +// Action server with Ros2Dds backend |
| 112 | +let mut action_server = node |
| 113 | + .create_action_server::<Fibonacci>("fibonacci") |
| 114 | + .with_backend::<Ros2DdsBackend>() |
| 115 | + .build()?; |
| 116 | +``` |
| 117 | + |
| 118 | +**Key points:** |
| 119 | + |
| 120 | +- Backend is specified via generic type parameter |
| 121 | +- Default backend is `RmwZenohBackend` if not specified |
| 122 | +- Type-safe selection ensures correct key expression format |
| 123 | +- No runtime overhead - resolved at compile time |
| 124 | + |
| 125 | +### Default Backend Behavior |
| 126 | + |
| 127 | +If no backend is specified, ros-z uses `RmwZenohBackend`: |
| 128 | + |
| 129 | +```rust,ignore |
| 130 | +// These are equivalent: |
| 131 | +let pub1 = node.create_pub::<RosString>("topic").build()?; |
| 132 | +let pub2 = node.create_pub::<RosString>("topic") |
| 133 | + .with_backend::<RmwZenohBackend>() |
| 134 | + .build()?; |
| 135 | +``` |
| 136 | + |
| 137 | +### Multiple Backend Features |
| 138 | + |
| 139 | +When both `rmw-zenoh` and `ros2dds` feature flags are enabled in `Cargo.toml`: |
| 140 | + |
| 141 | +```toml |
| 142 | +[dependencies] |
| 143 | +ros-z = { version = "0.1", features = ["rmw-zenoh", "ros2dds"] } |
| 144 | +``` |
| 145 | + |
| 146 | +**Default behavior**: `RmwZenohBackend` is used by default (more established, backwards compatible). |
| 147 | + |
| 148 | +To use the ros2dds backend, explicitly specify it: |
| 149 | + |
| 150 | +```rust,ignore |
| 151 | +let publisher = node |
| 152 | + .create_pub::<RosString>("chatter") |
| 153 | + .with_backend::<Ros2DdsBackend>() // Explicit opt-in |
| 154 | + .build()?; |
| 155 | +``` |
| 156 | + |
| 157 | +**Rationale**: The `rmw-zenoh` backend is more established and maintains backwards compatibility with existing ros-z deployments. The `ros2dds` backend requires explicit opt-in to ensure users are aware they're using bridge-compatible key expressions. |
| 158 | + |
| 159 | +## Architecture Diagrams |
| 160 | + |
| 161 | +### RmwZenoh Backend Architecture |
| 162 | + |
| 163 | +```mermaid |
| 164 | +graph LR |
| 165 | + A[ros-z Node<br/>RmwZenohBackend] -->|"0/chatter/**"| B[Zenoh Router<br/>rmw_zenoh] |
| 166 | + B -->|"0/chatter/**"| C[ROS 2 Node<br/>rmw_zenoh_cpp] |
| 167 | +``` |
| 168 | + |
| 169 | +**Use case:** Native Zenoh-based ROS 2 deployment |
| 170 | + |
| 171 | +- All nodes use rmw_zenoh or ros-z |
| 172 | +- Direct Zenoh communication |
| 173 | +- Domain isolation via key expression prefix |
| 174 | + |
| 175 | +### Ros2Dds Backend Architecture |
| 176 | + |
| 177 | +```mermaid |
| 178 | +graph LR |
| 179 | + A[ros-z Node<br/>Ros2DdsBackend] -->|"chatter/**"| B[zenoh-bridge-ros2dds<br/>Router + Bridge] |
| 180 | + B -->|DDS| C[ROS 2 Node<br/>CycloneDDS/FastDDS] |
| 181 | +``` |
| 182 | + |
| 183 | +**Use case:** Bridge existing DDS systems to Zenoh |
| 184 | + |
| 185 | +- ROS 2 nodes use standard DDS middleware |
| 186 | +- `zenoh-bridge-ros2dds` translates DDS ↔ Zenoh |
| 187 | +- ros-z communicates via Zenoh side of bridge |
| 188 | + |
| 189 | +## Complete Example: Backend Selection |
| 190 | + |
| 191 | +The `z_pubsub` example demonstrates backend selection for pub/sub communication. The example supports both `RmwZenoh` and `Ros2Dds` backends via command-line arguments: |
| 192 | + |
| 193 | +```rust,ignore |
| 194 | +{{#include ../../../ros-z/examples/z_pubsub.rs}} |
| 195 | +``` |
| 196 | + |
| 197 | +Key features of this example: |
| 198 | + |
| 199 | +- **Generic backend support**: Uses `KeyExprBackend` trait for compile-time backend selection |
| 200 | +- **CLI arguments**: Select backend with `--backend rmw-zenoh` or `--backend ros2-dds` |
| 201 | +- **Conditional compilation**: Ros2Dds backend only available with `--features ros2dds` |
| 202 | +- **Same high-level API**: Publisher and subscriber code identical except for backend type parameter |
| 203 | + |
| 204 | +**Usage Examples:** |
| 205 | + |
| 206 | +### Direct ros-z Communication (RmwZenoh backend - default) |
| 207 | + |
| 208 | +```bash |
| 209 | +# Terminal 1: Run listener with default RmwZenoh backend |
| 210 | +cargo run --example z_pubsub -- --role listener |
| 211 | + |
| 212 | +# Terminal 2: Run talker with default RmwZenoh backend |
| 213 | +cargo run --example z_pubsub -- --role talker |
| 214 | +``` |
| 215 | + |
| 216 | +### Interop with ROS 2 via zenoh-bridge-ros2dds (Ros2Dds backend) |
| 217 | + |
| 218 | +1. **Terminal 1 - Start zenoh-bridge-ros2dds:** |
| 219 | + |
| 220 | + ```bash |
| 221 | + zenoh-bridge-ros2dds |
| 222 | + ``` |
| 223 | + |
| 224 | +2. **Terminal 2 - Start ROS 2 DDS talker:** |
| 225 | + |
| 226 | + ```bash |
| 227 | + ros2 run demo_nodes_cpp talker |
| 228 | + ``` |
| 229 | + |
| 230 | +3. **Terminal 3 - Run ros-z listener with Ros2Dds backend:** |
| 231 | + |
| 232 | + ```bash |
| 233 | + cargo run --example z_pubsub --features ros2dds -- --role listener --backend ros2-dds |
| 234 | + ``` |
| 235 | + |
| 236 | +Or run ros-z talker and ROS 2 listener: |
| 237 | + |
| 238 | +```bash |
| 239 | +# Terminal 2: Run ros-z talker with Ros2Dds backend |
| 240 | +cargo run --example z_pubsub --features ros2dds -- --role talker --backend ros2-dds --topic chatter |
| 241 | + |
| 242 | +# Terminal 3: Run ROS 2 listener |
| 243 | +ros2 run demo_nodes_cpp listener |
| 244 | +``` |
| 245 | + |
| 246 | +## ros-z-console Backend Support |
| 247 | + |
| 248 | +The `ros-z-console` monitoring tool supports backend selection via CLI: |
| 249 | + |
| 250 | +```bash |
| 251 | +# Monitor rmw_zenoh-based systems (default) |
| 252 | +ros-z-console tcp/127.0.0.1:7447 0 |
| 253 | + |
| 254 | +# Monitor zenoh-bridge-ros2dds systems |
| 255 | +ros-z-console tcp/127.0.0.1:7447 0 --backend ros2dds |
| 256 | + |
| 257 | +# Show help |
| 258 | +ros-z-console --help |
| 259 | +``` |
| 260 | + |
| 261 | +**Backend parameter:** |
| 262 | + |
| 263 | +- `--backend rmw-zenoh` - Monitor rmw_zenoh systems (default) |
| 264 | +- `--backend ros2dds` - Monitor zenoh-bridge-ros2dds systems |
| 265 | + |
| 266 | +The backend choice affects: |
| 267 | + |
| 268 | +- Topic discovery key expressions |
| 269 | +- Rate measurement subscriptions |
| 270 | +- Multi-topic monitoring |
| 271 | + |
| 272 | +```admonish tip |
| 273 | +Always match the backend in `ros-z-console` to your deployment architecture. Use `rmw-zenoh` for native Zenoh systems and `ros2dds` when monitoring systems bridged via `zenoh-bridge-ros2dds`. |
| 274 | +``` |
| 275 | + |
| 276 | +## Backend Comparison |
| 277 | + |
| 278 | +### When to Use RmwZenoh Backend |
| 279 | + |
| 280 | +✅ **Use RmwZenoh when:** |
| 281 | + |
| 282 | +- Building pure Zenoh-based ROS 2 systems |
| 283 | +- Using `rmw_zenoh_cpp` middleware |
| 284 | +- Requiring domain isolation |
| 285 | +- Deploying new systems with native Zenoh support |
| 286 | +- Maximizing Zenoh performance benefits |
| 287 | + |
| 288 | +### When to Use Ros2Dds Backend |
| 289 | + |
| 290 | +✅ **Use Ros2Dds when:** |
| 291 | + |
| 292 | +- Bridging existing DDS-based ROS 2 systems |
| 293 | +- Using `zenoh-bridge-ros2dds` |
| 294 | +- Integrating with legacy ROS 2 infrastructure |
| 295 | +- Gradual migration from DDS to Zenoh |
| 296 | +- Heterogeneous deployments (DDS + Zenoh) |
0 commit comments