Zenoh support - #73
Open
victorpaleologue wants to merge 33 commits into
Open
Conversation
…hop use cases) Background research collected as ground-truth references for the Zenoh backend study: rmw_zenoh key-expression/liveliness/attachment/service model, the Zenoh 1.x Rust API surface, and the RosCon 2025 workshop use cases. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
- docs/zenoh_study/{README,feature_map,refactoring_plan,test_plan}.md
- docs/decisions/0001..0009 ADRs (feature architecture, CDR reuse,
owned public types, liveliness discovery, queryable services,
type-hash interop, GID/attachment parity, router/config)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
Captured because the session has read-only GitHub access (issue/PR/push writes are policy-denied); create from this file once access is granted. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
Introduce the mutually-exclusive middleware backend features per ADR-0002: - Cargo: add `dds` (default) and `zenoh` features; make `rustdds` optional and gated behind `dds`; add optional `zenoh`/`zenoh-ext` deps (resolve to zenoh 1.9); `security` now implies `dds`; default = ["dds", "jazzy"]. - lib.rs: compile_error! guard requiring exactly one backend; gate the crate root `rustdds` re-exports and `ros2::` DDS types behind `dds`. - Add `src/zenoh_backend/` module home (cfg `zenoh`) for E2-E6. The default DDS build is unchanged and green (9 lib tests pass, fmt clean); the Zenoh backend compile lands with E1-E3. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
Backend-neutral 'spec' modules under src/zenoh_backend/, compiled on every build so they are unit-testable without the zenoh crate or a network: - keyexpr: data-plane topic/service keys <domain>/<name>/<type>/<hash> and @ros2_lv liveliness keys (NN/MP/MS/SS/SC) with %-mangling; tests reproduce the exact key strings from the rmw_zenoh design examples. - type_hash: REP-2016 known-types table + wildcard-receive strategy (ADR-0007). - gid: 16-byte entity GID = XXH3-128(liveliness key) as low64||high64 LE (ADR-0008); byte-layout and determinism tests. Adds xxhash-rust dep. 22 lib tests pass (11 new); fmt + clippy clean; default DDS build unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
CI formats with nightly rustfmt honoring wrap_comments/imports_granularity; reflow comments to match so the format check passes.
…tvgj Zenoh backend: study, plan, decisions + E0/E2 foundations
Introduce ros2_client::qos::QosProfile — a backend-neutral ROS 2 QoS profile (reliability/durability/history/deadline/lifespan/liveliness/lease) that does not name any rustdds type, per ADR-0004. On the dds backend it converts to/from rustdds::QosPolicies (round-trip tested); on zenoh it will drive pub/sub options and the liveliness QoS encoding. Additive: existing APIs still take rustdds QoS; migration is incremental. Re-exported as ros2_client::QosProfile and ros2::QosProfile. 3 unit tests (incl. rustdds round-trip); fmt/clippy/doc clean. Refs #4 (E1), #2. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
The publisher unwrapped its first async_publish, which a Reliable writer can legitimately fail with WouldBlock before a matching subscription is discovered (a race exposed on fast loopback CI runners; surfaced now that this fork runs CI for the first time). Tolerate the transient error and keep publishing; the subscriber only needs one message within its timeout. Refs #2.
…4tvgj E1: owned QosProfile type (decouple public API from RustDDS)
Make the crate compile under `--no-default-features --features zenoh` and add the first real Zenoh backend module: - lib.rs: gate all RustDDS-coupled modules/re-exports (context, node, pubsub, service, action, message_info, parameters, rcl_interfaces, rosout, builtin_topics, entities_info, gid, interfaces, lazy_static) behind `dds`; gate the RustDDS Timestamp conversions in ros_time and the `Log` struct in log (keeping `LogLevel`); allow dead_code on the zenoh build for neutral helpers not yet wired to the zenoh side. - zenoh_backend::context: `Context`/`ContextOptions` opening one `zenoh::Session` per context (E3). Default peer config listens on IPv4 loopback with multicast off (rmw_zenoh shape; also works where IPv6 is unavailable, e.g. CI). Full JSON5/env config is a follow-up TODO. - CI: new tests-zenoh.yml (check + clippy -D warnings + lib tests for the zenoh feature; guards dds/zenoh exclusivity). DDS build unchanged (23 lib tests). Zenoh: 18 lib tests pass incl. opening a real session. Refs #6 (E3), #5 (E2), #2. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
…4tvgj E3: Zenoh Context/session + compile the `zenoh` feature + CI
zenoh_backend::attachment::AttachmentData carries (i64 sequence, i64 source_timestamp_ns, [u8;16] source_gid) via the zenoh-ext serializer, matching rmw_zenoh's exact wire layout: 8B LE seq | 8B LE ts | 0x10 | 16B gid (33 bytes). Unit tests pin the byte layout, round-trip, and truncation rejection (ADR-0008). Refs #5 (E2), #2. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
…4tvgj E2: message attachment (rmw_zenoh byte-compatible)
zenoh_backend::cdr provides to_cdr/from_cdr: message body via cdr-encoding (same author as RustDDS) plus the 4-byte encapsulation header prepended ourselves (cdr-encoding emits the body only). to_cdr writes CDR_LE; from_cdr honours the representation identifier's endianness (LE/BE incl. PL variants). Tests cover round-trip (String + struct), header-present-once, big-endian decode, and header validation (ADR-0003). Adds cdr-encoding + byteorder deps under the zenoh feature. Unblocks E4 pub/sub. Refs #5 (E2), #7 (E4), #2. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
cargo-audit flagged RUSTSEC-2026-0041 (lz4_flex <0.11.6, pulled by zenoh's compression; zenoh pins 0.10.x) and RUSTSEC-2023-0071 (rsa 0.9 Marvin timing side-channel, via zenoh's TLS stack; no upstream patch exists). Both are transitive, only affect the optional zenoh feature, and are unresolvable without an upstream zenoh bump. Ignore them with justification in .cargo/audit.toml and re-trigger the audit workflow on changes to it. Refs #2.
Minimal Zenoh node surface + data plane: - Context::new_node -> Node; Node::create_topic/create_publisher/ create_subscription. Topic resolves the fully-qualified ROS name. - Publisher<M>: put(CDR payload + attachment(seq,ts,gid)); concrete key with real-or-placeholder type hash. Subscription<M>: declare_subscriber with a wildcard type hash (liberal receive), decodes CDR + attachment into MessageInfo. Per-publisher sequence numbers; entity GID from liveliness key. - type_hash::sender_hash now returns a concrete PLACEHOLDER_HASH (a put can't target a wildcard key); receivers keep using WILDCARD. - Re-export Node/NodeOptions/Topic/Publisher/Subscription/MessageInfo under zenoh. Tier B in-process test: two contexts connected over loopback exchange a std_msgs/String round-trip. 27 zenoh lib tests pass; dds unchanged (23); fmt + clippy (both backends) clean. Refs #7 (E4), #2. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
zenoh_backend::qos_encoding encodes/decodes the <qos> component of liveliness tokens (rmw_zenoh format, 6 colon-groups). Every field except depth is delta-encoded vs the RMW default profile; depth is always emitted. Reproduces the documented examples exactly (reliable/volatile/keep-last depth 7 -> '::,7:,:,:,,') and round-trips. Pure module, tested on both backends. Refs #8 (E5), #2. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
- keyexpr::parse_liveliness_key: inverse of the token builders (ParsedEntity; names demangled), with round-trip + rejection tests. - Node declares a node (NN) liveliness token on creation; create_publisher/ create_subscription declare MP/MS tokens carrying the compact QoS encoding (E5a); the entity GID is derived from that liveliness key. Tokens are held by the Node/Publisher/Subscription (dropped => undeclared). Declaration is best-effort (warns, still functional). Tier-B test: a publisher created on one context is discovered by another via a liveliness get, its NN + MP tokens parsed back correctly. 35 zenoh lib tests pass; dds unchanged (30); fmt + clippy (both) clean. Refs #8 (E5), #2. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
zenoh_backend::graph_cache::GraphCache maintains the live entity set parsed from liveliness tokens. Context declares a liveliness subscriber over @ros2_lv/<domain>/** with history(true) and a callback that applies PUT/DELETE to the cache. New Context queries: publisher_count/subscription_count/node_names. Tier-B test: a second context discovers a remote publisher + node via the cache (publisher_count == 1, node_names contains /talker). Pure cache logic also unit tested. 37 zenoh lib tests pass; dds unchanged (31); fmt + clippy (both) clean. Refs #8 (E5), #2. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
zenoh_backend::service: Client<Req,Resp> and Server<Req,Resp> implementing ROS 2
services over Zenoh (ADR-0006).
- Server: complete queryable; per-query reads CDR request + attachment
(seq,ts,client_gid), stores the Query keyed by (client_gid,seq), and replies
with the CDR response echoing seq+gid. try_receive_request/async_receive_request
+ send_response; RmwRequestId {writer_gid,sequence_number}.
- Client: get on the concrete service key (real hash if known, else placeholder)
carrying request payload + attachment; decodes the first OK reply. call/async_call.
- Node::create_client/create_server; SC/SS liveliness tokens; names::ServiceTypeName
gains dds_service_type() (zenoh-only) for the service key type component.
Tier-B test: example_interfaces/AddTwoInts round-trip across two contexts returns
42. 38 zenoh lib tests pass; dds unchanged (31); clippy -D warnings (both) + fmt clean.
Refs #9 (E6), #2.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
zenoh_backend::action: ActionClient/ActionServer composing the ROS 2 action sub-entities on the Zenoh service + pub/sub layers (ADR / rmw_zenoh §8): - send_goal + get_result services, feedback topic; goals correlated by an application-level GoalId (random UUID). - Client: send_goal (returns id+accepted), get_result (long timeout, mirroring rmw's _action/get_result heuristic; bounded to 60s), take_feedback. - Server: try_receive_goal/respond_goal, publish_feedback, try_receive_result_request/respond_result. - Node::create_action_client/create_action_server build the sub-entities; service.Client gains an optional get timeout. cancel_goal + status topic are documented follow-ups. Tier-B test: action_tutorials_interfaces/Fibonacci order 5 -> [0,1,1,2,3] via send_goal + feedback + get_result across two contexts. 39 zenoh lib tests pass; dds unchanged (31); clippy -D warnings (both) + fmt clean. Refs #11 (E7), #2. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
Implement ROS 2 parameters on the Zenoh backend as a composition of six `rcl_interfaces` services and the `parameter_events` topic, mirroring how rmw_zenoh / rclcpp expose parameters (there is no middleware-level parameter concept). - `ParameterServer`: parameter store + get_parameters, get_parameter_types, set_parameters, set_parameters_atomically, list_parameters, describe_parameters queryables, plus a `/parameter_events` publisher. Application-driven via `spin_once()`/`spin()`, matching the primitives idiom of the Zenoh services/actions layers. `set_parameters_atomically` is not implemented (fails per entry, as in the DDS backend). - `ParameterClient`: get/set/list/types/describe against a remote node's parameter services. - `Node::create_parameter_server` / `create_parameter_client`. - `ParameterEvent` carries an owned `builtin_interfaces::Time` stamp, keeping the Zenoh backend independent of RustDDS (ADR-0004); its CDR field layout matches `rcl_interfaces/msg/ParameterEvent`. To reuse the ROS 2 parameter message types across both backends, make the `parameters` and `rcl_interfaces` modules backend-neutral: only the DDS-specific pieces (`raw::ParameterEvent`'s `rustdds::Timestamp` and the `AService` type aliases) stay gated behind the `dds` feature; the value enums, conversions, and request/response structs now compile on both. Verified in-process (Tier B) over IPv4 loopback: a client gets the initial value, sets a changed value and a new parameter, reads them back, queries types, and lists names (including the built-in `use_sim_time`) with prefix filtering. 40 zenoh lib tests pass; DDS tests, clippy (both backends), and nightly rustfmt are clean. Closes #12 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
Add rosout logging on the Zenoh backend: a `Logger` that publishes `rcl_interfaces/msg/Log` records to the global `/rosout` topic, plus an inbound subscription for reading `/rosout` (the `read_rosout` capability). - `zenoh_backend::rosout::Log`: an owned-timestamp (`builtin_interfaces::Time`) log record whose CDR field layout matches `rcl_interfaces/msg/Log`, keeping the Zenoh backend independent of RustDDS (ADR-0004; the DDS backend's `log::Log` uses `rustdds::Timestamp`). - `Logger` with `log_at` + level helpers (debug/info/warn/error/fatal), stamping the node's base name into each record. - A `zenoh`-gated `rosout!` macro mirroring the DDS one, capturing the call site's file/line (the DDS macro lives in the dds-gated `node` module, so the two never collide). - `Node::create_logger` / `Node::read_rosout`. Verified in-process (Tier B) over IPv4 loopback: a node logs via `rosout!` and a second node reads the record back, checking level, name, message, and source location. 41 zenoh lib tests pass; DDS tests, clippy (both backends), and nightly rustfmt are clean. Closes #10 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
Wrap up the Zenoh backend MVP with docs and an example. - Add a self-contained `zenoh_demo` example: an in-process talker + listener over IPv4 loopback (peer mode, no router) that exercises topic pub/sub and `/rosout` logging, runnable with `cargo run --no-default-features --features zenoh --example zenoh_demo`. - Declare all examples explicitly in Cargo.toml with `autoexamples = false`. The DDS examples are gated `required-features = ["dds"]`, so a `--no-default-features --features zenoh --examples` build skips them instead of failing; `zenoh_demo` is gated on `zenoh`. - README: new "Middleware backends: DDS and Zenoh" section documenting the mutually-exclusive `dds`/`zenoh` features, the Zenoh router requirement, a per-capability interop matrix, the type-hash limitation, and pointers to docs/zenoh_study and docs/decisions. Add a 0.10 changelog line. - CI: the zenoh job now lints the zenoh example (`cargo clippy --no-default-features --features zenoh --examples -D warnings`), guarding both the example and the DDS-example gating. Verified locally: `zenoh_demo` runs (sends and receives on /chatter, logs to /rosout); DDS examples still build under the default features; clippy clean on both backends; nightly rustfmt clean. Closes #13 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
Round out the Zenoh Context configuration by honouring the two environment variables `rmw_zenoh` uses, when no explicit `ContextOptions::zenoh_config` is provided: - `ZENOH_SESSION_CONFIG_URI`: path to a JSON5 Zenoh config file used as the base config (via `zenoh::Config::from_file`); otherwise the built-in peer default is the base. - `ZENOH_CONFIG_OVERRIDE`: a `;`-separated list of `key=value` JSON5 assignments applied on top (e.g. `mode="client";connect/endpoints=["tcp/localhost:7447"]`). Malformed overrides and unreadable config files are surfaced as errors rather than silently ignored. This replaces the E3 `TODO` in `default_config` and lets a `ros2-client` node join a `zenohd`-based `rmw_zenoh` deployment purely through the standard env vars. A unit test covers the override parser (valid list applies and sets the mode; empty entries ignored; an entry without `=` is rejected). 42 zenoh lib tests pass; clippy (both backends) and nightly rustfmt are clean. Closes #6 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
…iption Complete the remaining E1 item (#4): a backend-neutral view of the ROS graph on the Zenoh backend, replacing the RustDDS-specific `NodeEvent::DDS` for graph observation. - `GraphEvent` (EntityDeclared / EntityUndeclared) + `GraphEntity` (kind, node_name, name, type_name) — owned, backend-neutral types (ADR-0004). `EntityKind` is now re-exported at the crate root. - `GraphCache` fans out these events to any number of subscribers (one unbounded channel each), mirroring the DDS backend's status senders, on every liveliness PUT/DELETE. - `Context::graph_event_stream()` returns an event stream; `Context` and `Node` gain `wait_for_publisher(topic)` / `wait_for_subscription(topic)` futures that resolve on discovery (immediately if already present, and race-free: they subscribe before checking the current count). Tests (Tier B): `emits_declared_and_undeclared_events` (cache-level, incl. non-token keys producing no event) and `wait_for_publisher_resolves_on_ discovery` (end-to-end over loopback — a waiter on one context resolves when a publisher appears on another). 44 zenoh lib tests pass; clippy (both backends) and nightly rustfmt clean. Refs #4 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
Complete the ROS 2 action surface on the Zenoh backend by adding the two
remaining sub-entities, mirroring rmw_zenoh / the DDS backend:
- `cancel_goal` service — `action_msgs/srv/CancelGoal` on
`<action>/_action/cancel_goal` (the shared, non-action-namespaced type).
Client: `cancel_goal(goal_id)` / `cancel_all_goals()`. Server:
`try_receive_cancel()` / `respond_cancel(id, return_code, goals_canceling)`.
- `status` topic — `action_msgs/msg/GoalStatusArray` on
`<action>/_action/status`. Client: `take_status()`. Server:
`publish_status(status_list)`.
The `action_msgs` message types are backend-neutral and reused directly.
`ActionClient`/`ActionServer` and `Node::create_action_{client,server}` are
extended to wire the extra client/server + sub/pub.
Tier-B test `cancel_and_status_roundtrip`: the client sends a goal, observes
it reach `Executing` on `/status`, cancels it (asserting `return_code=None`
and the goal present in `goals_canceling`), then observes `Canceled` on
`/status`. 45 zenoh lib tests pass; clippy (both backends) and nightly
rustfmt clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
Implement the core of ADR-0007 item (c): a backend-neutral, from-scratch
port of rosidl's `calculate_type_hash`, so a ros2-client can compute the
same `RIHS01_…` hash a C++ peer embeds in its Zenoh keys.
- New `zenoh_backend::type_description`: `FieldType` (with the base id table
+ array/bounded-seq/unbounded-seq offset scheme), `Field`,
`IndividualTypeDescription`, `TypeDescription`, and:
- `hashable_json()` — the exact canonical JSON (struct-order keys, `", "`
/ `": "` separators, `default_value` stripped, referenced types sorted
by name, `ensure_ascii` escaping);
- `rihs01()` — `RIHS01_` + lowercase-hex SHA-256 of that JSON;
- `service_type_description()` — the synthetic service composition
(`request_message`/`response_message`/`event_message` + closure).
- Reproduces the published hashes of `std_msgs/msg/String` and
`example_interfaces/srv/AddTwoInts` byte-exactly, and cross-checks them
against the known-types table so the two cannot silently diverge.
- `sha2` added as an unconditional (pure-Rust) dependency, matching the
`xxhash-rust` precedent of keeping wire-format spec modules testable on
any build. Verified on both the dds and zenoh builds.
What remains for ADR-0007 (c) is the msggen *pipeline* — resolving each
generated type's transitive nested-type closure across packages and
emitting the computed hash as a constant — documented in ADR-0007 and the
`type_hash` module. Until then the send direction still uses the (now
verified) known-types table for un-generated types.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
Address the interop follow-up in two honest parts, since a real ROS 2 + rmw_zenoh stack can't run in this repo's CI: - `pub_sub_through_router`: an end-to-end test that stands up a real in-process Zenoh *router* and connects two client-mode `Context`s to it, exchanging a message on /chatter. This exercises the client→router→client topology (ADR-0009 / the rmw_zenoh deployment model) that the peer-mode loopback tests never touch. - `docs/zenoh_study/interop_runbook.md`: a concrete Tier-C procedure for validating the Zenoh backend against real ROS 2 + rmw_zenoh + zenohd — topics (both directions), services, actions (incl. cancel/status), parameters, rosout, and discovery — each mapped to its C# acceptance criterion, with the env-var config (`ZENOH_CONFIG_OVERRIDE` / `ZENOH_SESSION_CONFIG_URI`) and the type-hash/distro caveats. README links it from the interop section. 49 zenoh lib tests pass; clippy (both backends) and nightly rustfmt clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DP3yDMFQ3h1mDPAty2g5ZK
Native std_msgs scalar topics (Float64, Float32, Int32/64, UInt32/64, Bool) now advertise a correct RIHS01 type hash on the send direction, computed from their one-field descriptions via `type_description` (byte-exact, exactly as for String), so C++ rmw_zenoh subscribers match them. Previously only String and AddTwoInts were in the hash table; other scalars fell back to the all-zero placeholder and did not match a C++ subscriber. Closes the common-scalar gap ahead of full msggen (ADR-0007). Adds a drift-guard test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Introduced flags to select
zenohorddsas the RMW.DDS route mainly unchanged.
Zenoh route tested with official ROS 2 tools.
Closes #71
Supersedes #72 (was coming from
semio-ai:master, but it was a moving branch)