Skip to content

ros2dds plugin Zenoh publications not delivered to remote_api WebSocket subscribers (v1.9.0) #697

@robertvandervoort

Description

@robertvandervoort

Summary

When zenoh-plugin-ros2dds and zenoh-plugin-remote-api are loaded in the same zenohd v1.9.0 router, DDS-originated publications bridged into the Zenoh key-space by the ros2dds plugin never reach subscribers declared via the remote_api WebSocket interface. The reverse direction (WS → Zenoh → ros2dds → DDS) works correctly.

Environment

Component Version
zenohd 1.9.0 (rustc 1.93.0)
zenoh-plugin-ros2dds bundled .so from eclipse/zenoh:1.9.0 image
zenoh-plugin-remote-api bundled .so from same image
@eclipse-zenoh/zenoh-ts 1.9.0 (npm)
ROS 2 distro Jazzy
RMW rmw_cyclonedds_cpp
Platform NVIDIA Jetson AGX Thor, Linux 6.8 aarch64
Deployment Docker Compose (zenohd, audio/ROS2 node, web/Node.js containers)

zenohd configuration (zenohd.json5)

{
  mode: "router",
  listen: { endpoints: ["tcp/0.0.0.0:7447"] },
  scouting: { multicast: { enabled: false }, gossip: { enabled: false } },
  plugins: {
    ros2dds: {
      __path__: "/libzenoh_plugin_ros2dds.so",
      domain: 0,
      namespace: "/",
      allow: {
        publishers:      ["/chip/.*"],
        subscribers:     ["/chip/.*"],
        service_servers: ["/chip/.*"],
        service_clients: ["/chip/.*"],
        action_servers:  ["/chip/.*"],
        action_clients:  ["/chip/.*"],
      },
    },
    remote_api: {
      __path__: "/libzenoh_plugin_remote_api.so",
      websocket_port: "0.0.0.0:10000",
    },
  },
}

What works

Path Direction Status
WS client A publishes → WS client A subscriber same-session works
WS client B publishes → WS client A subscriber cross-session works
WS client publishes chip/audio/config → ros2dds Route Subscriber → ROS2 node receives Zenoh → DDS works

What does NOT work

Path Direction Status
ROS2 node publishes /chip/audio/utterance → ros2dds Route Publisher → Zenoh key chip/audio/utterance → remote_api WS subscriber DDS → Zenoh → WS broken — handler never fires

This applies to all topics bridged by ros2dds, not just one. A wildcard subscriber on chip/audio/** receives zero DDS-bridged samples while receiving self-published and cross-session WS-published samples correctly.

zenohd logs confirm routes are created

INFO zenoh_plugin_ros2dds: Node /audio_node declares Publisher /chip/audio/utterance: std_msgs/msg/String - Allowed
INFO zenoh_plugin_ros2dds::routes_mgr: Route Publisher (ROS:/chip/audio/utterance -> Zenoh:chip/audio/utterance) created

The ROS2 node is actively publishing (confirmed via application logs showing wake-word fires and utterance storage), but zero samples reach any WS subscriber.

Minimal reproduction script (zenoh-ts, runs inside the web container)

import { Config, Session } from '@eclipse-zenoh/zenoh-ts';

// Session A: subscriber
const sessionA = await Session.open(new Config('ws/zenohd:10000'));
let fromDDS = 0, fromWS = 0;

await sessionA.declareSubscriber('chip/audio/**', {
  handler: (sample) => {
    fromDDS++; // should increment when ROS2 node publishes
    console.log('GOT SAMPLE, payload size:', sample.payload().toBytes().length);
  }
});

// Session B: publish via WS (simulates non-DDS traffic)
const sessionB = await Session.open(new Config('ws/zenohd:10000'));
const pub = await sessionB.declarePublisher('chip/audio/utterance');
await pub.put(new TextEncoder().encode('{"test":"from_ws"}'));
fromWS++; // will be received by Session A

await new Promise(r => setTimeout(r, 15000));
// During this 15s window, the ROS2 node published multiple messages on
// /chip/audio/utterance (confirmed in its logs).

console.log('From WS:', fromWS, 'From DDS bridge:', fromDDS);
// Output: From WS: 1  From DDS bridge: 0
// Expected: From DDS bridge: >0

Result: fromDDS stays 0 despite active ROS2 publishers. fromWS correctly increments from the cross-session WS publish.

Hypothesis

The ros2dds plugin's internal Zenoh publisher (created for each Route Publisher) either:

  1. Does not propagate its publications through the router to remote_api plugin subscribers, or
  2. The remote_api plugin's subscription declarations don't register as "matching" with the ros2dds plugin's publishers, so the plugin never forwards DDS data into the Zenoh key-space

The asymmetry (Zenoh→DDS works but DDS→Zenoh→WS doesn't) suggests the issue is in how the ros2dds plugin's publications interact with the router's forwarding to the remote_api plugin, rather than a DDS discovery or QoS problem.

Workaround

Direct HTTP POST from the ROS2 container to the WebSocket client's HTTP backend, bypassing the Zenoh data plane for this message type.

Cross-reference

The remote_api plugin lives in eclipse-zenoh/zenoh-ts. The bug may originate there rather than in ros2dds — filing here since the ros2dds plugin is the publication source.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions