Skip to content

feat(tf): add ros-z-tf crate with TF2 listener, broadcaster, and buffer#178

Closed
YuanYuYuan wants to merge 12 commits into
mainfrom
feat/ros-z-tf
Closed

feat(tf): add ros-z-tf crate with TF2 listener, broadcaster, and buffer#178
YuanYuYuan wants to merge 12 commits into
mainfrom
feat/ros-z-tf

Conversation

@YuanYuYuan
Copy link
Copy Markdown
Collaborator

Summary

  • New crate ros-z-tf — pure-Rust TF2 transform listener and buffer for ros-z
  • Subscribes to /tf (Volatile) and /tf_static (TransientLocal) with automatic replay for late-joining subscribers
  • LCA-based multi-hop frame tree traversal with linear/slerp interpolation
  • TransformBroadcaster and StaticTransformBroadcaster for publishing transforms
  • wait_for_transform async wait with Option<Duration> timeout (defaults to 10 s)
  • lookup_transform_full for tf2 "time travel" lookups through a fixed frame
  • 28 unit tests + 8 integration tests via ros-z-tests --features tf-tests

Key Changes

  • crates/ros-z-tf/ — new crate with Buffer, TransformBroadcaster, StaticTransformBroadcaster, LCA lookup, slerp/lerp math
  • crates/ros-z/src/pubsub.rs — TransientLocal replay via PublicationCache + FetchingSubscriber (zenoh-ext)
  • crates/ros-z-msgs/ — added tf2_msgs feature with TFMessage
  • crates/ros-z-codegen/ — excludes tf2_msgs from protobuf (cross-package array fields unsupported)
  • crates/ros-z-tests/ — integration tests under tf-tests feature flag

API

let buffer = ros_z_tf::Buffer::new(&node)?;

// Lookup (latest available)
let tf = buffer.lookup_transform("map", "base_link", ZTime::zero())?;

// Async wait
let tf = buffer.wait_for_transform("map", "base_link", ZTime::zero(), None).await?;

// Time-travel lookup (tf2 signature order)
let tf = buffer.lookup_transform_full("camera", target_time, "odom", source_time, "map")?;

// Broadcast
let bc = TransformBroadcaster::new(&node)?;
bc.send_transform(tf)?;

let sbc = StaticTransformBroadcaster::new(&node)?;
sbc.send_transform(tf)?;  // timestamp zeroed automatically

Breaking Changes

None — new crate, no changes to existing public APIs.

Introduces `ros-z-tf`, a pure-Rust TF2 listener and transform buffer
that subscribes to `/tf` and `/tf_static`, maintains a frame tree, and
provides `lookup_transform` with multi-hop LCA traversal and
linear/slerp interpolation.

Public API:
- `Buffer::new(node)` — subscribes to /tf (Volatile) and /tf_static (TransientLocal)
- `Buffer::lookup_transform(target, source, time)` — LCA-based chain composition
- `Buffer::can_transform(target, source, time)` — non-panicking availability check
- `Buffer::all_frames()` — enumerate known frame IDs
- `LookupError` — UnknownFrame, NoCommonAncestor, ExtrapolationError

Also adds `tf2_msgs` message definitions to ros-z-codegen assets and
extends `GeneratorConfig` with `protobuf_excluded_packages` to handle
packages whose cross-package array fields cannot be represented in
protobuf (e.g. `geometry_msgs/TransformStamped[]` in TFMessage).
…sform, lookup_transform_full

- ros-z core: declare PublicationCache alongside ZPub for TransientLocal
  publishers; use QueryingSubscriber (FetchingSubscriber) for TransientLocal
  subscribers so late joiners receive previously published data
- ros-z-tf: add TransformBroadcaster (/tf, Volatile) and
  StaticTransformBroadcaster (/tf_static, TransientLocal)
- ros-z-tf: add wait_for_transform (async, notified on each add_message)
  with WaitError::Timeout and WaitError::Lookup variants
- ros-z-tf: add lookup_transform_full for fixed-frame two-time lookups
- remove #[ignore] from tf_static_transient_local_replayed_on_connect
- 8 integration tests pass, 28 unit tests pass
…rder, optional wait timeout

- StaticTransformBroadcaster zeroes all timestamps before publishing
  (tf2 spec requires sec=0, nanosec=0 on /tf_static for ROS 2 interop)
- lookup_transform_full reordered to (target, target_time, source, source_time,
  fixed_frame) matching tf2 C++ and roslibrust APIs
- wait_for_transform now takes Option<Duration>; None falls back to the
  buffer's default duration (10 s)
- Document intentional separation of Buffer and broadcaster types
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 11, 2026

PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://ZettaScaleLabs.github.io/ros-z/pr-preview/pr-178/

Built to branch gh-pages at 2026-05-11 09:07 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 11, 2026

Codecov Report

❌ Patch coverage is 81.81818% with 8 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
crates/ros-z/src/pubsub.rs 83.33% 7 Missing ⚠️
crates/ros-z-codegen/src/bin/export_json.rs 0.00% 1 Missing ⚠️
Files with missing lines Coverage Δ
crates/ros-z-codegen/src/lib.rs 86.91% <100.00%> (+0.02%) ⬆️
crates/ros-z-codegen/src/bin/export_json.rs 0.00% <0.00%> (ø)
crates/ros-z/src/pubsub.rs 53.40% <83.33%> (+1.69%) ⬆️

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…y codegen filter

- QosHistory::KeepAll was mapped to usize::MAX for PublicationCache ring
  buffer capacity, which would OOM on first transient-local publisher;
  cap at 1000 entries to match tf2 buffer convention
- tf-tests feature no longer hardcodes ros-z-tf/jazzy; distro propagation
  uses '?' syntax so it only activates when the optional dep is enabled
- generate_protobuf_types always filters excluded packages via one-liner
  instead of a split-variable conditional
…t_naming

Adds digit→uppercase split so Int8MultiArray→Int8MultiArray and
ensures TFMessage→TfMessage matches what prost_build generates.
@YuanYuYuan YuanYuYuan closed this May 26, 2026
@YuanYuYuan YuanYuYuan deleted the feat/ros-z-tf branch May 26, 2026 08:28
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.

1 participant