robotics data flow
The robotics modality is topic pub/sub for a robot fleet, built on the same QUIC relay mesh ClutchCall uses for voice, streams, and games. One client speaks for one (tenant, robot) pair. Two namespaces are baked in — telemetry from the robot and commands to the robot — so the two directions never collide and a controller can never accidentally subscribe to the robot’s own announce.
robot/<id>          telemetry topics   (robot → cloud)
robot/<id>/ctl      command topics     (cloud → robot)
Payloads are opaque bytes — typically ROS 2 CDR — with the message type name prefixed on the wire so a cross-language subscriber can pick the right deserializer without any out-of-band schema exchange.

When to use it

Fleet telemetry

Stream odometry, LIDAR, battery, and pose from hundreds of robots to a cloud dashboard or a recorder, each on its own robot/<id> namespace.

Teleoperation

Drive a robot from the cloud — cmd_vel and goal commands flow down robot/<id>/ctl on a low-latency lane, telemetry flows back up the same session.

Cross-language demux

A TypeScript dashboard and a Python analytics worker subscribe to the same CDR track; the type-name prefix lets each pick its own decoder.

Drop-in ROS 2 transport

Swap the local middleware for a ClutchCall-backed transport so a ROS 2 node reaches the fleet over WAN-grade QUIC with zero code change.

Three transports onto the mesh

A robot can reach the relay mesh three different ways. All three land on the same namespaces and the same type-name-prefixed wire frame, so producers and consumers interoperate regardless of how each one connected.
The native path. A ROS 2 node serializes its messages to CDR (the DDS Common Data Representation) and the raw CDR bytes ride the track unchanged. The type name (nav_msgs/msg/Odometry) is what the SDK prefixes, so a subscriber anywhere can hand the payload straight to a CDR decoder.
However a device connects, the on-the-wire frame is identical. The transport is a property of how a peer reached the mesh, not of the data — so a CDR publisher, a Zenoh node, and an MQTT sensor can all feed one subscriber.

Wire model & track conventions

Each robot maps to a pair of MoQT namespaces. A topic becomes a track name under the relevant namespace; one MoQT track carries one topic.
DirectionNamespaceExample track
Telemetry (up)robot/<id>robot/spot-12 · odom
Commands (down)robot/<id>/ctlrobot/spot-12/ctl · cmd_vel
Each published message opens its own MoQT group (one discrete ROS message per group), and the relay holds a small recent-group window so a late subscriber catches the latest frames — the closest analog to a ROS 2 history depth.

Type-name-prefixed CDR frame

Every object on the wire is a self-describing envelope:
┌────────────────────┬──────────────────────┬─────────────────────┐
│ u16 BE type_len    │ type_name (UTF-8)    │ CDR payload         │
│ (2 bytes)          │ e.g. nav_msgs/msg/…  │ opaque bytes        │
└────────────────────┴──────────────────────┴─────────────────────┘
  • The 2-byte big-endian length bounds type names at 65 535 bytes; real ROS 2 names fit in ~64.
  • The CDR payload is opaque to the SDK — you hand it the bytes your DDS, Zenoh, or serialize_message already produced.
  • The prefix is what makes the stream cross-language: a subscriber gets (cdr, typeName) and routes to the matching decoder with no schema registry.
The frame is byte-identical across the TypeScript, Python, Go, and native bridges. A frame published by a Python robot decodes unchanged in a browser dashboard.

QoS → lanes

ROS 2 QoS hints map onto MoQT lanes at the relay. You pass a qos profile when you create a publication; the relay routes and admits the track by the resulting capability.
QoS hintLaneCapability
reliability: "reliable"subgroup stream (ordered)ros.reliable
reliability: "best_effort"QUIC datagram (lossy)ros.best_effort
durability: "transient_local"adds late-join retainros.tl_*
depth: Nper-track group window
  • Reliable rides subgroup streams — guaranteed, in order per-publisher. Use it for commands and for telemetry you can’t drop (a map update, a goal).
  • Best-effort rides QUIC datagrams — lowest latency, lossy. Use it for high-rate sensor streams (pose, LIDAR) where the freshest sample wins.
  • transient_local makes the relay retain the last group(s) so a subscriber that joins late immediately receives the most recent value — the analog of a latched MQTT retained message.
  • depth caps the per-track group window the relay holds for late subscribers, mirroring ROS 2 keep-last history.
Reliable publications also default to a higher send priority (lower priority number) than best-effort; you can override priority per message on write.

Drop-in ROS 2 transport

A robot doesn’t have to know the relay exists. A small native bridge runs beside the ROS 2 graph and presents itself as an ordinary middleware transport — the same role a vendor RMW (ROS Middleware) plugin fills. Local nodes publish and subscribe their topics exactly as before; the bridge mirrors those topics into and out of MoQT:
1

Local nodes stay local

Nodes talk to the bridge over the standard middleware interface — DDS or Zenoh on the robot’s loopback. No application code changes.
2

Bridge mirrors topics

For each configured topic, the bridge subscribes locally and republishes the raw CDR onto a robot/<id> telemetry track, and subscribes a robot/<id>/ctl command track and republishes onto the local graph.
3

Mesh fan-out

The relay fans each telemetry frame out to every cloud subscriber and routes each command down to the addressed robot — over WAN-grade QUIC, across NAT, with one auth token.
The bridge is described here by role, not by file. From the robot’s point of view it is “the transport that carries my topics off-box”; from the cloud’s it is “the fleet ingress”. The SDK in SDK Methods gives you the same pub/sub surface programmatically when you want to bridge selected topics yourself.

Architecture

The data plane is one QUIC connection per robot multiplexing every track via MoQT; the relay mesh fans tracks out to subscribers across hosts. Underneath, the engine is shard-per-core with an AF_XDP kernel-bypass NIC fast path, lock-free mcache / dcache rings between shards, and io_uring for async I/O — so a single host fans a high-rate fleet out at line rate without copying through the kernel network stack.
  • One connection, many tracks. Telemetry and commands for a robot share one QUIC session; MoQT multiplexes the tracks.
  • One token. The tenant token that authorizes voice / streams / games authorizes the fleet — no separate broker credentials.
  • No broker to run. The relay mesh is the fan-out. There’s no MQTT broker or DDS discovery domain to operate in the cloud.