Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion crates/hiroz/examples/demo_nodes/talker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ pub async fn run_talker(
) -> Result<()> {
// --8<-- [start:node_setup]
// Create a node named "talker"
let node = ctx.create_node("talker").build()?;
let node = ctx
.create_node("talker")
.with_type_description_service()
.build()?;
// --8<-- [end:node_setup]

// --8<-- [start:publisher_setup]
Expand Down
5 changes: 4 additions & 1 deletion crates/hiroz/examples/laser_scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ fn main() -> Result<()> {

fn run_publisher() -> Result<()> {
let ctx = ZContextBuilder::default().build()?;
let node = ctx.create_node("laser_scan_publisher").build()?;
let node = ctx
.create_node("laser_scan_publisher")
.with_type_description_service()
.build()?;
let zpub = node.create_pub::<LaserScan>("scan").build()?;

println!("Publishing LaserScan messages on /scan...");
Expand Down
5 changes: 4 additions & 1 deletion crates/hiroz/examples/lifecycle/talker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ fn main() -> Result<()> {
// Build a Zenoh context and create a lifecycle node.
// The node starts in the Unconfigured state.
let ctx = ZContextBuilder::default().build()?;
let mut node = ctx.create_lifecycle_node("lifecycle_talker").build()?;
let mut node = ctx
.create_lifecycle_node("lifecycle_talker")
.with_type_description_service()
.build()?;

// Register callbacks for each lifecycle transition.
// Each callback receives the previous state and must return
Expand Down
15 changes: 12 additions & 3 deletions crates/hiroz/examples/shm_pointcloud2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ fn demo_user_managed_shm() -> zenoh::Result<()> {

// Step 3: Create node and publisher
let ctx = ZContextBuilder::default().build()?;
let node = ctx.create_node("pointcloud_publisher").build()?;
let node = ctx
.create_node("pointcloud_publisher")
.with_type_description_service()
.build()?;
let publisher = node
.create_pub::<PointCloud2>("cloud/user_managed")
.build()?;
Expand All @@ -95,7 +98,10 @@ fn demo_automatic_shm() -> zenoh::Result<()> {
.build()?;
println!(" ✓ Context configured with automatic SHM (threshold: 10KB)");

let node = ctx.create_node("pointcloud_publisher").build()?;
let node = ctx
.create_node("pointcloud_publisher")
.with_type_description_service()
.build()?;
let publisher = node.create_pub::<PointCloud2>("cloud/automatic").build()?;

// Generate point cloud normally (using Vec<u8>)
Expand Down Expand Up @@ -126,7 +132,10 @@ fn demo_automatic_shm() -> zenoh::Result<()> {
fn demo_publisher_shm_override() -> zenoh::Result<()> {
// Context has no SHM, but publisher has its own config
let ctx = ZContextBuilder::default().build()?;
let node = ctx.create_node("pointcloud_publisher").build()?;
let node = ctx
.create_node("pointcloud_publisher")
.with_type_description_service()
.build()?;

// Create SHM provider for this publisher only
let provider = Arc::new(ShmProviderBuilder::new(30 * 1024 * 1024).build()?);
Expand Down
5 changes: 4 additions & 1 deletion crates/hiroz/examples/twist_pub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use hiroz_msgs::geometry_msgs::{Twist, Vector3};

fn main() -> Result<()> {
let ctx = ZContextBuilder::default().build()?;
let node = ctx.create_node("twist_publisher").build()?;
let node = ctx
.create_node("twist_publisher")
.with_type_description_service()
.build()?;
let zpub = node.create_pub::<Twist>("cmd_vel").build()?;

println!("Publishing Twist messages on /cmd_vel...");
Expand Down
5 changes: 4 additions & 1 deletion crates/hiroz/examples/z_cache/talker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ use hiroz::{Builder, Result, context::ZContextBuilder};
use hiroz_msgs::std_msgs::String as RosString;

pub async fn run(ctx: hiroz::context::ZContext, topic: String, count: usize) -> Result<()> {
let node = ctx.create_node("cache_talker").build()?;
let node = ctx
.create_node("cache_talker")
.with_type_description_service()
.build()?;
let publisher = node.create_pub::<RosString>(&topic).build()?;

println!("[talker] publishing on '{}' every 100 ms", topic);
Expand Down
5 changes: 4 additions & 1 deletion crates/hiroz/examples/z_custom_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,10 @@ async fn run_status_subscriber() -> Result<()> {
pub fn run_navigation_server(ctx: hiroz::context::ZContext) -> Result<()> {
println!("Starting navigation service server...");

let node = ctx.create_node("navigation_server").build()?;
let node = ctx
.create_node("navigation_server")
.with_type_description_service()
.build()?;
let mut zsrv = node.create_service::<NavigateTo>("/navigate_to").build()?;

println!("Navigation server ready, waiting for requests...");
Expand Down
7 changes: 5 additions & 2 deletions crates/hiroz/examples/z_pubsub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use hiroz_msgs::std_msgs::String as RosString;
async fn run_subscriber(ctx: ZContext, topic: String) -> Result<()> {
// Create a ROS 2 node - the fundamental unit of computation
// Nodes are logical groupings of publishers, subscribers, services, etc.
let node = ctx.create_node("Sub").build()?;
let node = ctx.create_node("listener").build()?;

// Create a subscriber for the specified topic
// The type parameter RosString determines what message type we'll receive
Expand All @@ -33,7 +33,10 @@ async fn run_publisher(
payload: String,
) -> Result<()> {
// Create a ROS 2 node for publishing
let node = ctx.create_node("Pub").build()?;
let node = ctx
.create_node("talker")
.with_type_description_service()
.build()?;

// Create a publisher for the specified topic
// The type parameter RosString determines what message type we'll send
Expand Down
1 change: 1 addition & 0 deletions crates/hiroz/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,7 @@ impl ZContext {
Some(self.namespace.clone())
},
enable_communication_interface: true,
type_description_service: false,
}
}

Expand Down
3 changes: 3 additions & 0 deletions crates/hiroz/src/dynamic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ pub use message::{DynamicMessage, DynamicMessageBuilder};
#[cfg(feature = "dynamic-schema-loader")]
pub use registry::load_schema;
pub use registry::{SchemaRegistry, get_schema, has_schema, register_schema};
// Exported next to `load_schema`: the two are used as a pair -- demangle a
// graph-reported type name, then load its schema.
pub use schema::{FieldSchema, FieldType, MessageSchema, MessageSchemaBuilder};
pub use serdes::DynamicSerdeCdrSerdes;
pub use serialization::SerializationFormat;
Expand All @@ -88,6 +90,7 @@ pub use type_description_service::{
WireKeyValue, WireTypeDescription, WireTypeSource, schema_to_wire_type_description,
wire_to_schema_type_description,
};
pub use type_info::ros_type_name_from_dds;
pub use value::{DynamicValue, FromDynamic, IntoDynamic};

pub(crate) use discovery::{SchemaDiscovery, discovered_schema_type_info};
Expand Down
8 changes: 7 additions & 1 deletion crates/hiroz/src/dynamic/type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ pub(crate) fn dds_type_name_from_schema(schema: &MessageSchema) -> String {
+ "_"
}

pub(crate) fn ros_type_name_from_dds(dds_name: &str) -> String {
/// Convert a DDS-mangled type name as it appears in liveliness tokens and the
/// graph (`std_msgs::msg::dds_::String_`) into the canonical ROS form the schema
/// registry and `.msg` loader expect (`std_msgs/msg/String`). Public because
/// out-of-crate consumers (e.g. `hu`'s WASM host) resolve graph-reported types
/// against `load_schema` and must use this exact normalisation rather than
/// re-deriving one -- see issue #172.
pub fn ros_type_name_from_dds(dds_name: &str) -> String {
dds_name
.replace("::msg::dds_::", "/msg/")
.replace("::srv::dds_::", "/srv/")
Expand Down
14 changes: 14 additions & 0 deletions crates/hiroz/src/lifecycle/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ pub struct ZLifecycleNodeBuilder {
pub(crate) name: String,
pub(crate) namespace: Option<String>,
pub enable_communication_interface: bool,
pub(crate) type_description_service: bool,
}

impl ZLifecycleNodeBuilder {
Expand All @@ -284,6 +285,16 @@ impl ZLifecycleNodeBuilder {
self
}

/// Pass-through to [`ZNodeBuilder::with_type_description_service`] on the
/// inner node, so publishers created via [`ZLifecycleNode::create_publisher`]
/// register their schemas and runtime-typed consumers can decode them.
///
/// [`ZNodeBuilder::with_type_description_service`]: crate::node::ZNodeBuilder::with_type_description_service
pub fn with_type_description_service(mut self) -> Self {
self.type_description_service = true;
self
}

pub fn disable_communication_interface(mut self) -> Self {
self.enable_communication_interface = false;
self
Expand All @@ -298,6 +309,9 @@ impl Builder for ZLifecycleNodeBuilder {
if let Some(ns) = self.namespace {
node_builder = node_builder.with_namespace(ns);
}
if self.type_description_service {
node_builder = node_builder.with_type_description_service();
}
let inner = node_builder.build()?;

// Shared state machine for service closures
Expand Down
9 changes: 9 additions & 0 deletions crates/hiroz/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,15 @@ impl ZNodeBuilder {
/// // Static publishers also auto-register when their message type provides
/// // MessageTypeInfo::message_schema() (e.g. generated hiroz messages).
/// ```
///
/// # Why this is opt-in, and why you probably want it
///
/// ROS 2 (rclcpp/rclpy) serves the equivalent service by default, and
/// hiroz's own RMW layer forces it on for every node it creates. A plain
/// hiroz node does not: it must opt in here. Without it, runtime-typed
/// consumers that have no compiled knowledge of the message — `hu meter
/// echo`, dynamic subscribers, bridges — cannot obtain the schema and
/// therefore cannot decode this node's messages.
pub fn with_type_description_service(mut self) -> Self {
self.enable_type_desc_service = true;
self
Expand Down
Loading