Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
17abc71
Move rclrs_examples to examples/minimal_pub_sub (#163)
nnmm May 16, 2022
6d58b6c
Add Nikolai and Jacob to authors in Cargo.toml and maintainers in pac…
nnmm May 23, 2022
21c75ee
Add function to demonstrate serde integration (#179)
nnmm May 29, 2022
337ad4a
feat: add example launch (#187)
wep21 Jun 4, 2022
b54446b
Move create_node and create_node_builder back to the rclrs module (#200)
esteve Jun 22, 2022
098c07d
Added support for clients and services (#146)
esteve Jul 8, 2022
7f148b8
Fix build errors in examples_rclrs_minimal_client_service (#220)
nnmm Jul 9, 2022
127668b
Add support for loaned messages (#212)
nnmm Aug 16, 2022
f603a55
Extend SubscriptionCallback trait to ReadOnlyLoanedMessage (#266)
nnmm Sep 28, 2022
c99c70d
Bump package versions to 0.3 (#274)
nnmm Oct 3, 2022
8bdaf35
Format all code with group_imports = StdExternalCrate (#272)
nnmm Oct 3, 2022
cfc7f57
Version 0.3.1 (#285)
nnmm Oct 17, 2022
96e4ad3
Return Arc from the create_node function to match other create_X func…
esteve Jul 25, 2023
8b8b5c4
Refactor spin and spin_once to mimic rclcpp's Executor API (#324)
esteve Aug 7, 2023
01a961a
Add service_is_ready() (#339)
Carter12s Oct 26, 2023
fa67ce0
Version 0.4.0 (#343)
esteve Nov 7, 2023
3c9f0ff
Revert "Version 0.4.0 (#343)" (#344)
esteve Nov 7, 2023
9ba4f85
Version 0.4.0 (#346)
esteve Nov 7, 2023
8e99416
Version 0.4.1 (#353)
esteve Nov 28, 2023
7a2289c
Add wchar support (#349)
maspe36 Jan 9, 2024
db24114
Moved the `rclrs_example_msgs` package to the examples folder. This p…
maspe36 Mar 31, 2024
72568bd
Use nightly for style check (#396)
mxgrey May 13, 2024
572c16c
Add simple talk/listener tutorial, matching the official ROS 2 docume…
Guelakais Jun 28, 2024
88ed5ae
Fix buffer overflow for bounded sequence example (#444)
mxgrey Dec 9, 2024
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
25 changes: 25 additions & 0 deletions examples/message_demo/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "examples_rclrs_message_demo"
version = "0.4.1"
authors = ["Nikolai Morin <[email protected]>"]
edition = "2021"

[[bin]]
name = "message_demo"
path = "src/message_demo.rs"

[dependencies]
anyhow = {version = "1", features = ["backtrace"]}

[dependencies.rclrs]
version = "0.4"

[dependencies.rosidl_runtime_rs]
version = "0.4"

[dependencies.rclrs_example_msgs]
version = "0.4"
features = ["serde"]

[dependencies.serde_json]
version = "1.0"
23 changes: 23 additions & 0 deletions examples/message_demo/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0"?>
<?xml-model
href="http://download.ros.org/schema/package_format3.xsd"
schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>examples_rclrs_message_demo</name>
<version>0.4.1</version>
<description>Package containing an example of message-related functionality in rclrs.</description>
<maintainer email="[email protected]">Nikolai Morin</maintainer>
<license>Apache License 2.0</license>

<build_depend>rclrs</build_depend>
<build_depend>rosidl_runtime_rs</build_depend>
<build_depend>rclrs_example_msgs</build_depend>

<exec_depend>rclrs</exec_depend>
<exec_depend>rosidl_runtime_rs</exec_depend>
<exec_depend>rclrs_example_msgs</exec_depend>

<export>
<build_type>ament_cargo</build_type>
</export>
</package>
185 changes: 185 additions & 0 deletions examples/message_demo/src/message_demo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
use std::{convert::TryInto, env, sync::Arc};

use anyhow::{Error, Result};
use rosidl_runtime_rs::{seq, BoundedSequence, Message, Sequence};

fn check_default_values() {
let msg = rclrs_example_msgs::msg::rmw::VariousTypes::default();
assert!(msg.bool_member);
assert_eq!(msg.int8_member, 1i8);
assert_eq!(msg.uint8_member, 2u8);
assert_eq!(msg.byte_member, 3u8);
assert_eq!(msg.float32_member, 1e-2f32);
assert_eq!(msg.float_array, [1.0, 2.0, 3.0]);
assert_eq!(msg.float_seq_bounded, seq![3 # 4.0, 5.0]);
assert_eq!(msg.float_seq_unbounded, seq![6.0]);
assert_eq!(msg.string_member.to_string(), "Χαίρετε 你好");
assert_eq!(msg.wstring_member.to_string(), "αντίο σου 再见");
assert_eq!(msg.bounded_string_member.to_string(), "aou");
assert_eq!(msg.bounded_wstring_member.to_string(), "äöü");
assert_eq!(
msg.string_array.clone().map(|s| s.to_string()),
["R", "O", "S", "2"].map(String::from)
);
assert_eq!(
msg.string_seq_bounded,
seq![4 # "R".into(), "O".into(), "S".into(), "2".into()]
);
assert_eq!(
msg.string_seq_unbounded,
seq!["R".into(), "O".into(), "S".into(), "2".into()]
);
assert_eq!(
msg.bounded_string_array.clone().map(|s| s.to_string()),
["R", "O", "S", "2"].map(String::from)
);
assert_eq!(
msg.bounded_string_seq_bounded,
["R", "O", "S", "2"]
.into_iter()
.map(|s| s.try_into().unwrap())
.collect()
);
assert_eq!(
msg.bounded_string_seq_unbounded,
["R", "O", "S", "2"]
.into_iter()
.map(|s| s.try_into().unwrap())
.collect()
);
assert_eq!(msg.nested_member.effect.to_string(), "discombobulate");
assert_eq!(
msg.nested_array,
[msg.nested_member.clone(), msg.nested_member.clone()]
);
assert_eq!(msg.nested_seq_bounded, seq![3 #]);
assert_eq!(msg.nested_seq_unbounded, seq![]);

// The default instance for the idiomatic type also has the defaults set
let idiomatic_msg = rclrs_example_msgs::msg::VariousTypes::default();
assert_eq!(
rclrs_example_msgs::msg::VariousTypes::into_rmw_message(std::borrow::Cow::Owned(
idiomatic_msg
))
.into_owned(),
msg
);
}

fn check_default_idl_values() {
let idiomatic_msg = rclrs_example_msgs::msg::MyMessage::default();
let rmw_msg = rclrs_example_msgs::msg::rmw::MyMessage::default();

assert_eq!(idiomatic_msg.wchar_value, 0u16);
assert_eq!(rmw_msg.wchar_value, 0u16);
}

fn demonstrate_printing() {
let default_msg = rclrs_example_msgs::msg::VariousTypes::default();
println!("================== Compact debug representation ==================");
println!("{:?}", default_msg);
println!("================== Pretty debug representation ===================");
println!("{:#?}", default_msg);
// The RMW-native message type has the same output
let default_rmw_msg = rclrs_example_msgs::msg::rmw::VariousTypes::default();
assert_eq!(
format!("{:?}", default_msg),
format!("{:?}", default_rmw_msg)
);
assert_eq!(
format!("{:#?}", default_msg),
format!("{:#?}", default_rmw_msg)
);
}

fn demonstrate_serde() -> Result<(), Error> {
// When the serde feature is turned on, messages are able to be serialized
// to and deserialized from a variety of formats. Here JSON is used as an
// example.
// Works with RMW-native and idiomatic messages.
let idiomatic_msg = rclrs_example_msgs::msg::VariousTypes::default();
let rmw_msg = rclrs_example_msgs::msg::rmw::VariousTypes::default();
println!("================= JSON serialization with Serde ==================");
let idiomatic_serialized = serde_json::to_string_pretty(&idiomatic_msg)?;
let rmw_serialized = serde_json::to_string_pretty(&rmw_msg)?;
assert_eq!(idiomatic_serialized, rmw_serialized);
println!("{}", rmw_serialized);
let idiomatic_deserialized = serde_json::from_str(&idiomatic_serialized)?;
let rmw_deserialized = serde_json::from_str(&rmw_serialized)?;
assert_eq!(idiomatic_msg, idiomatic_deserialized);
assert_eq!(rmw_msg, rmw_deserialized);
Ok(())
}

fn demonstrate_sequences() {
// Convenient creation of (bounded) sequences with the seq! macro
// This one has three items and a length bound of 5
let mut float_seq_bounded = seq![5 # 1.0, 2.0, 3.0];
// Sequences and bounded sequences have iter(), iter_mut(), and into_iter()
float_seq_bounded
.iter_mut()
.for_each(|n: &mut f32| *n += 1.0);
let float_vec_1: Vec<_> = float_seq_bounded.iter().copied().collect();
let float_vec_2: Vec<_> = float_seq_bounded.into_iter().collect();
assert_eq!(float_vec_1, float_vec_2);
// Sequences also implement FromIterator.
let mut int_seq_unbounded: Sequence<i32> = [42; 4].into_iter().collect();
// Bounded sequences will ignore remaining items once the length bound is reached
let mut int_seq_bounded: BoundedSequence<i32, 3> = [42; 4].into_iter().collect();
// Sequences deref to slices
int_seq_bounded[2] = 24;
assert_eq!(int_seq_bounded.last(), Some(&24));
int_seq_unbounded[2..].copy_from_slice(&int_seq_bounded[1..]);
// New sequences will contain default values – and 0 for primitive types
let seq_with_default_values = Sequence::<rclrs_example_msgs::msg::rmw::NestedType>::new(1);
assert_eq!(seq_with_default_values[0].effect, "discombobulate".into());
}

fn demonstrate_pubsub() -> Result<(), Error> {
println!("================== Interoperability demo ==================");
// Demonstrate interoperability between idiomatic and RMW-native message types
let context = rclrs::Context::new(env::args())?;
let node = rclrs::create_node(&context, "message_demo")?;

let idiomatic_publisher = node.create_publisher::<rclrs_example_msgs::msg::VariousTypes>(
"topic",
rclrs::QOS_PROFILE_DEFAULT,
)?;
let direct_publisher = node.create_publisher::<rclrs_example_msgs::msg::rmw::VariousTypes>(
"topic",
rclrs::QOS_PROFILE_DEFAULT,
)?;

let _idiomatic_subscription = node
.create_subscription::<rclrs_example_msgs::msg::VariousTypes, _>(
"topic",
rclrs::QOS_PROFILE_DEFAULT,
move |_msg: rclrs_example_msgs::msg::VariousTypes| println!("Got idiomatic message!"),
)?;
let _direct_subscription = node
.create_subscription::<rclrs_example_msgs::msg::rmw::VariousTypes, _>(
"topic",
rclrs::QOS_PROFILE_DEFAULT,
move |_msg: rclrs_example_msgs::msg::rmw::VariousTypes| {
println!("Got RMW-native message!")
},
)?;
println!("Sending idiomatic message.");
idiomatic_publisher.publish(rclrs_example_msgs::msg::VariousTypes::default())?;
rclrs::spin_once(Arc::clone(&node), None)?;
println!("Sending RMW-native message.");
direct_publisher.publish(rclrs_example_msgs::msg::rmw::VariousTypes::default())?;
rclrs::spin_once(Arc::clone(&node), None)?;

Ok(())
}

fn main() -> Result<(), Error> {
check_default_values();
check_default_idl_values();
demonstrate_printing();
demonstrate_serde()?;
demonstrate_sequences();
demonstrate_pubsub()?;
Ok(())
}
30 changes: 30 additions & 0 deletions examples/minimal_client_service/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
name = "examples_rclrs_minimal_client_service"
version = "0.4.1"
authors = ["Esteve Fernandez <[email protected]>"]
edition = "2021"

[[bin]]
name = "minimal_client"
path = "src/minimal_client.rs"

[[bin]]
name = "minimal_client_async"
path = "src/minimal_client_async.rs"

[[bin]]
name = "minimal_service"
path = "src/minimal_service.rs"

[dependencies]
anyhow = {version = "1", features = ["backtrace"]}
tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread", "time"] }

[dependencies.rclrs]
version = "0.4"

[dependencies.rosidl_runtime_rs]
version = "0.4"

[dependencies.example_interfaces]
version = "*"
23 changes: 23 additions & 0 deletions examples/minimal_client_service/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0"?>
<?xml-model
href="http://download.ros.org/schema/package_format3.xsd"
schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>examples_rclrs_minimal_client_service</name>
<version>0.4.1</version>
<description>Package containing an example of the client-service mechanism in rclrs.</description>
<maintainer email="[email protected]">Esteve Fernandez</maintainer>
<license>Apache License 2.0</license>

<build_depend>example_interfaces</build_depend>
<build_depend>rclrs</build_depend>
<build_depend>rosidl_runtime_rs</build_depend>

<exec_depend>example_interfaces</exec_depend>
<exec_depend>rclrs</exec_depend>
<exec_depend>rosidl_runtime_rs</exec_depend>

<export>
<build_type>ament_cargo</build_type>
</export>
</package>
34 changes: 34 additions & 0 deletions examples/minimal_client_service/src/minimal_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use std::env;

use anyhow::{Error, Result};

fn main() -> Result<(), Error> {
let context = rclrs::Context::new(env::args())?;

let node = rclrs::create_node(&context, "minimal_client")?;

let client = node.create_client::<example_interfaces::srv::AddTwoInts>("add_two_ints")?;

let request = example_interfaces::srv::AddTwoInts_Request { a: 41, b: 1 };

println!("Starting client");

while !client.service_is_ready()? {
std::thread::sleep(std::time::Duration::from_millis(10));
}

client.async_send_request_with_callback(
&request,
move |response: example_interfaces::srv::AddTwoInts_Response| {
println!(
"Result of {} + {} is: {}",
request.a, request.b, response.sum
);
},
)?;

std::thread::sleep(std::time::Duration::from_millis(500));

println!("Waiting for response");
rclrs::spin(node).map_err(|err| err.into())
}
35 changes: 35 additions & 0 deletions examples/minimal_client_service/src/minimal_client_async.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use std::env;

use anyhow::{Error, Result};

#[tokio::main]
async fn main() -> Result<(), Error> {
let context = rclrs::Context::new(env::args())?;

let node = rclrs::create_node(&context, "minimal_client")?;

let client = node.create_client::<example_interfaces::srv::AddTwoInts>("add_two_ints")?;

println!("Starting client");

while !client.service_is_ready()? {
std::thread::sleep(std::time::Duration::from_millis(10));
}

let request = example_interfaces::srv::AddTwoInts_Request { a: 41, b: 1 };

let future = client.call_async(&request);

println!("Waiting for response");

let rclrs_spin = tokio::task::spawn_blocking(move || rclrs::spin(node));

let response = future.await?;
println!(
"Result of {} + {} is: {}",
request.a, request.b, response.sum
);

rclrs_spin.await.ok();
Ok(())
}
25 changes: 25 additions & 0 deletions examples/minimal_client_service/src/minimal_service.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use std::env;

use anyhow::{Error, Result};

fn handle_service(
_request_header: &rclrs::rmw_request_id_t,
request: example_interfaces::srv::AddTwoInts_Request,
) -> example_interfaces::srv::AddTwoInts_Response {
println!("request: {} + {}", request.a, request.b);
example_interfaces::srv::AddTwoInts_Response {
sum: request.a + request.b,
}
}

fn main() -> Result<(), Error> {
let context = rclrs::Context::new(env::args())?;

let node = rclrs::create_node(&context, "minimal_service")?;

let _server = node
.create_service::<example_interfaces::srv::AddTwoInts, _>("add_two_ints", handle_service)?;

println!("Starting server");
rclrs::spin(node).map_err(|err| err.into())
}
Loading