Skip to content

feat(ros2-bridge): port to ros2-client 0.10.0 and RustDDS 0.13.1 - #2854

Open
bobdingAI wants to merge 1 commit into
mainfrom
worktree-ros2-client-0.10-port
Open

feat(ros2-bridge): port to ros2-client 0.10.0 and RustDDS 0.13.1#2854
bobdingAI wants to merge 1 commit into
mainfrom
worktree-ros2-client-0.10-port

Conversation

@bobdingAI

Copy link
Copy Markdown
Contributor

What

Ports dora-ros2-bridge from ros2-client 0.8.0 / rustdds =0.11.4 to
ros2-client 0.10.0 / rustdds 0.13.1, removing the = pin on RustDDS.

These are one upgrade, not two: ros2-client 0.10 declares rustdds = "0.13", so
resolving RustDDS to >= 0.13.1 follows from the ros2-client bump.

No source changes were required. Every ros2-client symbol the bridge uses
(~60 items) survives 0.8 → 0.10 — the public-surface diff is additions only
(distributions, pub use rustdds, Node::stop_spinner). The APIs that were
removed, QosPolicyBuilder::property() and the rustdds::CdrEncodingSize
re-export, were never referenced here.

ros2-client and cdr-encoding move into [workspace.dependencies] so the
bridge and its arrow helper cannot drift apart on the ROS distro.
cdr-encoding goes 0.10.2 → 0.11 to match what RustDDS 0.13 depends on, leaving
a single copy in the lockfile; its only API change tightens from_bytes to
&'de [u8], and every call site here yields owned types.

Two things that need reviewer attention

1. ROS distro is now explicit, and this picks humble — a wire change

0.10 gained distro Cargo features (default = [jazzy], plus
galactic/humble/iron/kilted/lyrical); 0.8 only had a pre-iron-gid
opt-out. These select Gid width in ros2-client's src/gid.rs:

Build GID_LENGTH
0.8 as we shipped it (pre-iron-gid off) 16
0.10 with default = [jazzy] (jazzy ⊃ iron) 16
0.10 with humble (this PR) 24

This aligns the build with the distro our own harness runs
(scripts/ros2dev.sh:57, scripts/ros2-zenoh-interop.sh). Previously we emitted
iron-era 16-byte Gids while testing against a 24-byte-Gid distro.

It is a deliberate wire-format change. It affects rmw_dds_common graph
discovery only — topic, service, and action payloads are ordinary CDR and
interoperate across distros either way. Anyone currently doing graph
introspection against an iron-or-newer stack is affected. Flagging it plainly
because it is a behavior change riding along with a version bump; happy to split
it out or switch to a feature passthrough (ros-humble / ros-jazzy / …) if
you'd rather.

2. Windows is excluded, not fixed

The =0.11.4 pin was load-bearing. RustDDS 0.11.5+ depends unconditionally
on pnet, whose pnet_datalink declares #[link(name = "Packet")] under
#[cfg(windows)] (src/bindings/winpcap.rs:357), so Windows linking needs
Packet.lib from the Npcap SDK. That is
Atostek/RustDDS#375, and it is
still open — 0.13.1 still has the dependency.

This PR excludes the affected crates from the Windows build/test steps in
nightly.yml rather than forking RustDDS or requiring the SDK of every Windows
developer. The exclusion set is exactly the crates that transitively pull
RustDDS, verified with cargo tree -e normal:

Crate Pulls RustDDS Action
dora-ros2-bridge yes excluded (test targets link)
dora-ros2-bridge-arrow yes excluded (test targets link)
dora-ros2-bridge-node yes excluded (bin links)
rust-ros2-example-node yes excluded (bin links)
dora-ros2-bridge-msg-gen no kept — Windows still covers it
dora-cli, dora-daemon no kept

Packet.lib is required at link time only, so deliberately unchanged: the
cargo check --all / cargo check --examples steps in the same job, and the
cross-check job's x86_64-pc-windows-gnu target (which only runs
cargo check). macOS keeps full bridge coverage via a per-platform matrix
variable.

The excludes are carried in matrix.ros2_excludes rather than duplicated, and
macOS gets an empty string.

The durable fix is upstream: RustDDS needs pnet for a single
pnet::datalink::interfaces() call (src/network/util.rs:61). An
optional-pnet feature would close #375 and restore Windows for everyone. Noted
as a follow-up rather than expanding this PR's scope.

Verification

Run on Linux against a real ROS 2 Humble install.

  • cargo fmt --all -- --check — clean
  • cargo clippy --lib --bins --tests -- -D warnings on all five bridge crates — clean
  • cargo check --examples — clean
  • bridge tests — 110 passed, 0 failed (18 + 15 + 77)
  • full workspace cargo test --all (CLAUDE.md exclude list) — 1543 passed, 0 failed, 126 binaries
  • cargo deny check licenses advisories bans sources — all ok
  • cargo build --example links against RustDDS 0.13.1, so the port is proven to
    link, not merely typecheck

Live interop against ros2 run demo_nodes_cpp talker, using a throwaway
probe node on the bridge's ros2-client stack subscribed to
/chatter (std_msgs/String). A counterfactual run with the jazzy default
isolates what the distro feature actually buys:

Build ros2 node list sees the dora node Payload interop
humble (24-byte Gid) yes/dora_interop_probe listed 3/3 messages
jazzy (16-byte Gid) no — only /talker listed 3/3 messages

ros2 topic info -v /chatter on the humble build attributes the dora
subscription to node dora_interop_probe with a 24-octet GID matching the
talker's format. This confirms the Gid width governs graph discovery and nothing
else. The probe was temporary scaffolding and is not part of the diff.

New lockfile entries — six crates: pnet, pnet_macros, pnet_macros_support,
pnet_packet, pnet_transport, pastey. (pnet_datalink, pnet_sys,
ipnetwork, winapi were already present.)

Not verified here

The Windows link failure and the exclusion that avoids it. No Windows host
was available, and cargo check cannot reproduce a link error. This needs a
nightly run to confirm. The reasoning is spelled out above and in the
nightly.yml comment, but it is reasoning, not a green run.

Also noted, not fixed: cargo clippy --all-targets on the bridge trips a
pre-existing single_component_path_imports error on use tokio; at
examples/ros2-bridge/rust/service-server/run.rs:4. It is unrelated to this
change and invisible to CI (which doesn't pass --all-targets), so per
CONTRIBUTING/CLAUDE.md guidance on unrelated warnings I left it alone.

Design doc

docs/superpowers/specs/2026-07-26-ros2-client-0.10-port-design.md records the
investigation, the alternatives considered for the Windows problem (Npcap SDK in
CI / exclusion / RustDDS fork), and the follow-ups.

🤖 Generated with Claude Code

Bumps `dora-ros2-bridge` from ros2-client 0.8.0 / rustdds =0.11.4 to
ros2-client 0.10.0 / rustdds 0.13.1, and lifts the `=` pin on RustDDS.
The two are one upgrade: ros2-client 0.10 declares `rustdds = "0.13"`.

No source changes were required. Every ros2-client symbol the bridge uses
survives 0.8 -> 0.10 (the public-surface diff is additions only), and the
removed APIs — `QosPolicyBuilder::property()` and the
`rustdds::CdrEncodingSize` re-export — were never referenced here.

`ros2-client` and `cdr-encoding` move to `[workspace.dependencies]` so the
bridge and its arrow helper cannot drift apart on the ROS distro.
`cdr-encoding` goes 0.10.2 -> 0.11 to match what RustDDS 0.13 depends on,
leaving a single copy in the lockfile; its only API change tightens
`from_bytes` to `&'de [u8]`, and every call site here yields owned types.

Two consequences worth review attention:

ROS distro is now explicit. 0.10 gained distro features (0.8 only had a
`pre-iron-gid` opt-out), and they select `Gid` width. This builds with
`humble`, giving a 24-byte `Gid` where the previous build had 16 — a
deliberate wire change that aligns the build with the distro our harness
actually runs (`scripts/ros2dev.sh`). It affects `rmw_dds_common` graph
discovery only; topic/service/action payloads are untouched.

Windows is excluded rather than fixed. RustDDS 0.11.5+ depends
unconditionally on `pnet`, whose `pnet_datalink` declares
`#[link(name = "Packet")]` on Windows, so linking needs the Npcap SDK
(Atostek/RustDDS#375, still open — this was the reason for the pin). The
four crates that transitively pull RustDDS are excluded from the Windows
build/test steps in nightly.yml. `Packet.lib` is link-time only, so the
`cargo check` steps and the `cross-check` job's windows-gnu target are
unaffected and stay as they were. The durable fix is upstreaming an
optional-`pnet` feature — RustDDS needs it for one
`pnet::datalink::interfaces()` call.

Verified on Linux against a real ROS 2 Humble install: fmt, clippy
-D warnings, `cargo check --examples`, 110 bridge tests, 1543 workspace
tests, and `cargo deny check licenses advisories bans sources` all pass.
Live interop against `demo_nodes_cpp talker` receives messages and shows
the dora node in `ros2 node list` with a 24-octet GID; the same probe
built with the `jazzy` default is absent from `ros2 node list` while still
receiving payloads, confirming the Gid width governs graph discovery only.

The Windows link failure and the exclusion that avoids it are NOT verified
here — no Windows host was available. That needs a nightly run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@trunk-io

trunk-io Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

Copy link
Copy Markdown
Collaborator

🤖 Fully automated review by Claude — this review was generated end-to-end by an automated agent with no human vetting. Treat it accordingly.

No issues found. This is a manifest + CI + docs change with no source edits.

Points I verified from the diff:

  • The nightly.yml matrix conversion from platform: [...] to an include:-only list with a per-platform ros2_excludes is valid (one job per include entry; fail-fast: false preserved), and macOS keeps full bridge coverage with an empty excludes string.
  • The Windows exclusion set (dora-ros2-bridge, -arrow, -node, rust-ros2-example-node) is the RustDDS-linking set; msg-gen, dora-cli, dora-daemon stay covered, and the cargo check steps are correctly left unexcluded since Packet.lib is link-time only.
  • Moving ros2-client / cdr-encoding to [workspace.dependencies] removes the drift risk between the bridge and arrow crates, and Cargo.lock resolves a single cdr-encoding 0.11.

The two riding behavior changes — selecting humble (24-byte Gid, affecting rmw_dds_common graph discovery only) and dropping Windows bridge coverage — are deliberate and clearly flagged. My only caveat is the one you already called out: the Windows link failure and the exclusion that avoids it are reasoned, not verified by a green Windows run, so they need a nightly to confirm.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants