diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 69e3a217e..b0d8a98b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -152,7 +152,7 @@ jobs: ros2-bridge-examples: name: "ROS2 Bridge Examples" runs-on: ubuntu-latest - timeout-minutes: 30 + timeout-minutes: 45 steps: - uses: actions/checkout@v3 - uses: r7kamura/rust-problem-matchers@v1.1.0 diff --git a/Cargo.lock b/Cargo.lock index b7728668d..4e1d22f98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -377,10 +377,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", - "event-listener", + "event-listener 2.5.3", "futures-core", ] +[[package]] +name = "async-channel" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c" +dependencies = [ + "concurrent-queue", + "event-listener 4.0.0", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + [[package]] name = "async-executor" version = "1.5.4" @@ -401,7 +414,7 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" dependencies = [ - "async-channel", + "async-channel 1.9.0", "async-executor", "async-io", "async-lock", @@ -437,7 +450,7 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ - "event-listener", + "event-listener 2.5.3", ] [[package]] @@ -451,7 +464,7 @@ dependencies = [ "autocfg", "blocking", "cfg-if 1.0.0", - "event-listener", + "event-listener 2.5.3", "futures-lite", "rustix 0.37.25", "signal-hook", @@ -476,7 +489,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" dependencies = [ "async-attributes", - "async-channel", + "async-channel 1.9.0", "async-global-executor", "async-io", "async-lock", @@ -729,7 +742,7 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94c4ef1f913d78636d78d538eec1f18de81e481f44b1be0a81060090530846e1" dependencies = [ - "async-channel", + "async-channel 1.9.0", "async-lock", "async-task", "fastrand 2.0.1", @@ -1950,6 +1963,27 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "event-listener" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "770d968249b5d99410d61f5bf89057f3199a077a04d087092f58e7d10692baae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener 4.0.0", + "pin-project-lite", +] + [[package]] name = "ext-trait" version = "1.0.1" @@ -2758,6 +2792,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -3467,13 +3510,13 @@ dependencies = [ [[package]] name = "num-derive" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.38", ] [[package]] @@ -4191,7 +4234,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", - "itertools", + "itertools 0.10.5", "proc-macro2", "quote", "syn 1.0.109", @@ -4564,22 +4607,28 @@ dependencies = [ [[package]] name = "ros2-client" -version = "0.5.2" -source = "git+https://github.com/dora-rs/ros2-client.git?branch=deserialize-seed#3cab61b9d877322bd9da5779764b8a8e7d3f4030" +version = "0.6.1" +source = "git+https://github.com/dora-rs/ros2-client.git?branch=deserialize-seed-2#23cbcc8557011cf3e89f95bab4fe02a40c5dac74" dependencies = [ + "async-channel 2.1.1", + "bstr", "bytes", "cdr-encoding-size", "chrono", + "clap 4.4.6", "futures", + "itertools 0.11.0", "lazy_static", "log", "mio 0.6.23", "mio-extras", + "nom", "pin-utils", "rustdds", "serde", "serde_repr", "uuid", + "widestring", ] [[package]] @@ -4665,8 +4714,8 @@ dependencies = [ [[package]] name = "rustdds" -version = "0.8.4" -source = "git+https://github.com/dora-rs/RustDDS.git?branch=deserialize-seed#f49cafcf6448767a26f0b8788856cb1857a254fc" +version = "0.9.0" +source = "git+https://github.com/dora-rs/RustDDS.git?branch=deserialize-seed-2#fae9fcfb582c4842b849268b3466875daf62fb7f" dependencies = [ "bit-vec", "byteorder", @@ -5240,7 +5289,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af91f480ee899ab2d9f8435bfdfc14d08a5754bd9d3fef1f1a1c23336aad6c8b" dependencies = [ - "async-channel", + "async-channel 1.9.0", "cfg-if 1.0.0", "futures-core", "pin-project-lite", @@ -6412,7 +6461,7 @@ dependencies = [ "async-trait", "base64 0.13.1", "env_logger", - "event-listener", + "event-listener 2.5.3", "flume", "form_urlencoded", "futures", @@ -6711,7 +6760,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdf3eaea2095d2c13fefdae25aca813b3644fc15e1441e16a4398b5113033753" dependencies = [ "hex", - "itertools", + "itertools 0.10.5", "lazy_static", "rand", "serde", @@ -6727,7 +6776,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "821070b62a55d4c8a22e1e06c939c1f2d94767e660df9fcbea377781f72f59bf" dependencies = [ "async-std", - "event-listener", + "event-listener 2.5.3", "flume", "futures", "tokio", diff --git a/examples/python-ros2-dataflow/random_turtle.py b/examples/python-ros2-dataflow/random_turtle.py index d466ab1e5..3e97228b5 100755 --- a/examples/python-ros2-dataflow/random_turtle.py +++ b/examples/python-ros2-dataflow/random_turtle.py @@ -39,6 +39,12 @@ print("looping", flush=True) +# take track of minimum and maximum coordinates of turtle +min_x = 1000 +max_x = 0 +min_y = 1000 +max_y = 0 + for i in range(500): event = dora_node.next() if event is None: @@ -55,8 +61,10 @@ # ROS2 Event elif event_kind == "external": pose = event.inner()[0].as_py() - if i == CHECK_TICK: - assert ( - pose["x"] != 5.544444561004639 - ), "turtle should not be at initial x axis" + min_x = min([min_x, pose["x"]]) + max_x = max([max_x, pose["x"]]) + min_y = min([min_y, pose["y"]]) + max_y = max([max_y, pose["y"]]) dora_node.send_output("turtle_pose", event.inner()) + +assert max_x - min_x > 1 or max_y - min_y > 1, "no turtle movement" diff --git a/examples/rust-ros2-dataflow/node/src/main.rs b/examples/rust-ros2-dataflow/node/src/main.rs index 313cc47d9..15c360b62 100644 --- a/examples/rust-ros2-dataflow/node/src/main.rs +++ b/examples/rust-ros2-dataflow/node/src/main.rs @@ -10,7 +10,7 @@ use dora_ros2_bridge::{ rustdds::{self, policy}, turtlesim::msg::Pose, }; -use eyre::Context; +use eyre::{eyre, Context}; fn main() -> eyre::Result<()> { let mut ros_node = init_ros_node()?; @@ -79,8 +79,8 @@ fn init_ros_node() -> eyre::Result { ros_context .new_node( - "turtle_teleop", // name - "/ros2_demo", // namespace + ros2_client::NodeName::new("/ros2_demo", "turtle_teleop") + .map_err(|e| eyre!("failed to create ROS2 node name: {e}"))?, NodeOptions::new().enable_rosout(true), ) .context("failed to create ros2 node") @@ -93,7 +93,7 @@ fn create_vel_publisher( rustdds::QosPolicyBuilder::new() .durability(policy::Durability::Volatile) .liveliness(policy::Liveliness::Automatic { - lease_duration: ros2::Duration::DURATION_INFINITE, + lease_duration: ros2::Duration::INFINITE, }) .reliability(policy::Reliability::Reliable { max_blocking_time: ros2::Duration::from_millis(100), @@ -104,8 +104,9 @@ fn create_vel_publisher( let turtle_cmd_vel_topic = ros_node .create_topic( - "/turtle1/cmd_vel", - String::from("geometry_msgs::msg::dds_::Twist_"), + &ros2_client::Name::new("/turtle1", "cmd_vel") + .map_err(|e| eyre!("failed to create ROS2 name: {e}"))?, + ros2_client::MessageTypeName::new("geometry_msgs", "Twist"), &topic_qos, ) .context("failed to create topic")?; @@ -122,8 +123,9 @@ fn create_pose_reader( ) -> eyre::Result> { let turtle_pose_topic = ros_node .create_topic( - "/turtle1/pose", - String::from("turtlesim::msg::dds_::Pose_"), + &ros2_client::Name::new("/turtle1", "pose") + .map_err(|e| eyre!("failed to create ROS2 name: {e}"))?, + ros2_client::MessageTypeName::new("turtlesim", "Pose"), &Default::default(), ) .context("failed to create topic")?; diff --git a/libraries/extensions/ros2-bridge/Cargo.toml b/libraries/extensions/ros2-bridge/Cargo.toml index dce23fe20..7c55a1cb1 100644 --- a/libraries/extensions/ros2-bridge/Cargo.toml +++ b/libraries/extensions/ros2-bridge/Cargo.toml @@ -17,8 +17,8 @@ dora-ros2-bridge-msg-gen-macro = { path = "msg-gen-macro", optional = true } serde = { version = "1.0.164", features = ["derive"] } serde-big-array = "0.5.1" widestring = "1.0.2" -ros2-client = { git = "https://github.com/dora-rs/ros2-client.git", branch = "deserialize-seed" } -rustdds = { git = "https://github.com/dora-rs/RustDDS.git", branch = "deserialize-seed" } +ros2-client = { git = "https://github.com/dora-rs/ros2-client.git", branch = "deserialize-seed-2" } +rustdds = { git = "https://github.com/dora-rs/RustDDS.git", branch = "deserialize-seed-2" } eyre = { version = "0.6.8", optional = true } tokio = { version = "1.29.1", features = ["full"], optional = true } dora-daemon = { path = "../../../binaries/daemon", optional = true } diff --git a/libraries/extensions/ros2-bridge/python/src/lib.rs b/libraries/extensions/ros2-bridge/python/src/lib.rs index ac2e4d544..8b3abb11e 100644 --- a/libraries/extensions/ros2-bridge/python/src/lib.rs +++ b/libraries/extensions/ros2-bridge/python/src/lib.rs @@ -76,8 +76,10 @@ impl Ros2Context { namespace: &str, options: Ros2NodeOptions, ) -> eyre::Result { + let name = ros2_client::NodeName::new(namespace, name) + .map_err(|err| eyre!("invalid node name: {err}"))?; Ok(Ros2Node { - node: self.context.new_node(name, namespace, options.into())?, + node: self.context.new_node(name, options.into())?, messages: self.messages.clone(), }) } @@ -103,12 +105,16 @@ impl Ros2Node { message_type ) })?; - let encoded_type_name = format!("{namespace_name}::msg::dds_::{message_name}_"); + let message_type_name = ros2_client::MessageTypeName::new(namespace_name, message_name); + let topic_name = ros2_client::Name::parse(name) + .map_err(|err| eyre!("failed to parse ROS2 topic name: {err}"))?; let topic = self .node - .create_topic(name, encoded_type_name, &qos.into())?; - let type_info = for_message(&self.messages, namespace_name, message_name) - .context("failed to determine type info for message")?; + .create_topic(&topic_name, message_type_name, &qos.into())?; + let type_info = + for_message(&self.messages, namespace_name, message_name).with_context(|| { + format!("failed to determine type info for message {namespace_name}/{message_name}") + })?; Ok(Ros2Topic { topic, type_info }) } diff --git a/libraries/extensions/ros2-bridge/python/src/qos.rs b/libraries/extensions/ros2-bridge/python/src/qos.rs index b56e2cf2a..398cfe5f3 100644 --- a/libraries/extensions/ros2-bridge/python/src/qos.rs +++ b/libraries/extensions/ros2-bridge/python/src/qos.rs @@ -96,7 +96,7 @@ pub enum Ros2Liveliness { impl Ros2Liveliness { fn convert(self, lease_duration: f64) -> policy::Liveliness { let lease_duration = if lease_duration.is_infinite() { - rustdds::Duration::DURATION_INFINITE + rustdds::Duration::INFINITE } else { rustdds::Duration::from_frac_seconds(lease_duration) };