ROS 2 → ros-z API Mapping¶
If you know rclcpp or rclpy, this table maps familiar concepts to their ros-z equivalents.
Core Concepts¶
| rclcpp / rclpy | ros-z (Rust) | Notes |
|---|---|---|
rclcpp::Node |
ZNode |
Created via ctx.create_node("name").build()? |
rclcpp::Publisher<T> |
ZPub<T> |
node.create_pub::<T>("topic").build()? |
rclcpp::Subscription<T> |
ZSub<T> |
Three patterns: blocking recv(), async async_recv(), or callback via build_with_callback() |
rclcpp::Service<T> |
ZServer<T> |
Pull model — call take_request() when ready to handle |
rclcpp::Client<T> |
ZClient<T> |
call(&req).await or call_with_timeout(&req, duration).await |
rclcpp_action::Server<T> |
ZActionServer<T> |
Uses with_handler closure receiving ExecutingGoal<A> |
rclcpp_action::Client<T> |
ZActionClient<T> |
send_goal() returns a GoalHandle |
rclcpp::ParameterServer |
ZParameterServer |
Auto-creates ros2 param compatible services |
rclcpp_lifecycle::LifecycleNode |
ZLifecycleNode |
Same 4-state machine (Unconfigured → Inactive → Active → Finalized) |
No Spin Loop¶
ros-z has no equivalent to rclcpp::spin(). ros-z is fully reactive: subscribers are either
callback-based or backed by an internal queue, and services use a pull model. Your entry point
is a standard #[tokio::main] async function — no spin thread required.
rclcpp:
rclcpp::init(argc, argv);
auto node = std::make_shared<MyNode>();
rclcpp::spin(node);
rclcpp::shutdown();
ros-z:
#[tokio::main]
async fn main() -> Result<()> {
let ctx = ZContextBuilder::default()
.with_connect_endpoints(["tcp/127.0.0.1:7447"])
.build()?;
let node = ctx.create_node("my_node").build()?;
// ... set up pubs, subs, services ...
tokio::signal::ctrl_c().await?;
Ok(())
}
Initialization¶
| Step | rclcpp | ros-z |
|---|---|---|
| Initialize runtime | rclcpp::init(argc, argv) |
ZContextBuilder::default() |
| Connect to network | automatic (DDS multicast) | .with_connect_endpoints(["tcp/127.0.0.1:7447"]) |
| Set domain ID | --ros-args -p use_sim_time:=... / env |
.with_domain_id(42) |
| Build context | implicit | .build()? |
| Create node | std::make_shared<rclcpp::Node>("name") |
ctx.create_node("name").build()? |
QoS Presets¶
| rclcpp | ros-z | Notes |
|---|---|---|
rclcpp::SensorDataQoS() |
QosProfile::sensor_data() |
Best-effort, keep last 5 |
rclcpp::SystemDefaultsQoS() |
QosProfile::default() |
Reliable, keep last 10 |
rclcpp::ServicesQoS() |
QosProfile::services_default() |
Reliable, volatile |
rclcpp::QoS(10).reliable() |
QosProfile { history: KeepLast(10), reliability: Reliable, .. Default::default() } |
Custom profile |
Key Differences¶
- No spin loop — ros-z is fully async and reactive. Use
#[tokio::main]andawait; no executor management needed. - Rust ownership replaces shared_ptr — no
Node::SharedPtr, no reference counting in user code. The borrow checker enforces correct lifetime without manual memory management. - Type hashes required for ROS 2 interop — when communicating with native ROS 2 nodes, message types must carry RIHS01 type hashes. Use schema-generated types from
ros-z-codegenrather than hand-rolled structs. - Pull model for services — there is no callback registration for service servers. Call
take_request()when your application is ready to handle an incoming request. - Router required — ros-z does not use DDS multicast discovery. A Zenoh router must be running and reachable at the configured endpoint (default:
tcp/127.0.0.1:7447).