Skip to content

Commit c8caca3

Browse files
committed
Move examples to separate repo
1 parent b7cb830 commit c8caca3

18 files changed

+615
-0
lines changed

message_demo/Cargo.toml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[package]
2+
name = "examples_rclrs_message_demo"
3+
version = "0.3.0"
4+
authors = ["Nikolai Morin <[email protected]>"]
5+
edition = "2021"
6+
7+
[[bin]]
8+
name = "message_demo"
9+
path = "src/message_demo.rs"
10+
11+
[dependencies]
12+
anyhow = {version = "1", features = ["backtrace"]}
13+
14+
[dependencies.rclrs]
15+
version = "0.3"
16+
17+
[dependencies.rosidl_runtime_rs]
18+
version = "0.3"
19+
20+
[dependencies.rclrs_example_msgs]
21+
version = "0.3"
22+
features = ["serde"]
23+
24+
[dependencies.serde_json]
25+
version = "1.0"

message_demo/package.xml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0"?>
2+
<?xml-model
3+
href="http://download.ros.org/schema/package_format3.xsd"
4+
schematypens="http://www.w3.org/2001/XMLSchema"?>
5+
<package format="3">
6+
<name>examples_rclrs_message_demo</name>
7+
<version>0.3.0</version>
8+
<description>Package containing an example of message-related functionality in rclrs.</description>
9+
<maintainer email="[email protected]">Nikolai Morin</maintainer>
10+
<license>Apache License 2.0</license>
11+
12+
<build_depend>rclrs</build_depend>
13+
<build_depend>rosidl_runtime_rs</build_depend>
14+
<build_depend>rclrs_example_msgs</build_depend>
15+
16+
<exec_depend>rclrs</exec_depend>
17+
<exec_depend>rosidl_runtime_rs</exec_depend>
18+
<exec_depend>rclrs_example_msgs</exec_depend>
19+
20+
<export>
21+
<build_type>ament_cargo</build_type>
22+
</export>
23+
</package>

message_demo/src/message_demo.rs

+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
use std::convert::TryInto;
2+
use std::env;
3+
4+
use anyhow::{Error, Result};
5+
use rosidl_runtime_rs::{seq, BoundedSequence, Message, Sequence};
6+
7+
fn check_default_values() {
8+
let msg = rclrs_example_msgs::msg::rmw::VariousTypes::default();
9+
assert!(msg.bool_member);
10+
assert_eq!(msg.int8_member, 1i8);
11+
assert_eq!(msg.uint8_member, 2u8);
12+
assert_eq!(msg.byte_member, 3u8);
13+
assert_eq!(msg.float32_member, 1e-2f32);
14+
assert_eq!(msg.float_array, [1.0, 2.0, 3.0]);
15+
assert_eq!(msg.float_seq_bounded, seq![3 # 4.0, 5.0]);
16+
assert_eq!(msg.float_seq_unbounded, seq![6.0]);
17+
assert_eq!(msg.string_member.to_string(), "Χαίρετε 你好");
18+
assert_eq!(msg.wstring_member.to_string(), "αντίο σου 再见");
19+
assert_eq!(msg.bounded_string_member.to_string(), "äöü");
20+
assert_eq!(msg.bounded_wstring_member.to_string(), "äöü");
21+
assert_eq!(
22+
msg.string_array.clone().map(|s| s.to_string()),
23+
["R", "O", "S", "2"].map(String::from)
24+
);
25+
assert_eq!(
26+
msg.string_seq_bounded,
27+
seq![4 # "R".into(), "O".into(), "S".into(), "2".into()]
28+
);
29+
assert_eq!(
30+
msg.string_seq_unbounded,
31+
seq!["R".into(), "O".into(), "S".into(), "2".into()]
32+
);
33+
assert_eq!(
34+
msg.bounded_string_array.clone().map(|s| s.to_string()),
35+
["R", "O", "S", "2"].map(String::from)
36+
);
37+
assert_eq!(
38+
msg.bounded_string_seq_bounded,
39+
["R", "O", "S", "2"]
40+
.into_iter()
41+
.map(|s| s.try_into().unwrap())
42+
.collect()
43+
);
44+
assert_eq!(
45+
msg.bounded_string_seq_unbounded,
46+
["R", "O", "S", "2"]
47+
.into_iter()
48+
.map(|s| s.try_into().unwrap())
49+
.collect()
50+
);
51+
assert_eq!(msg.nested_member.effect.to_string(), "discombobulate");
52+
assert_eq!(
53+
msg.nested_array,
54+
[msg.nested_member.clone(), msg.nested_member.clone()]
55+
);
56+
assert_eq!(msg.nested_seq_bounded, seq![3 #]);
57+
assert_eq!(msg.nested_seq_unbounded, seq![]);
58+
59+
// The default instance for the idiomatic type also has the defaults set
60+
let idiomatic_msg = rclrs_example_msgs::msg::VariousTypes::default();
61+
assert_eq!(
62+
rclrs_example_msgs::msg::VariousTypes::into_rmw_message(std::borrow::Cow::Owned(
63+
idiomatic_msg
64+
))
65+
.into_owned(),
66+
msg
67+
);
68+
}
69+
70+
fn demonstrate_printing() {
71+
let default_msg = rclrs_example_msgs::msg::VariousTypes::default();
72+
println!("================== Compact debug representation ==================");
73+
println!("{:?}", default_msg);
74+
println!("================== Pretty debug representation ===================");
75+
println!("{:#?}", default_msg);
76+
// The RMW-native message type has the same output
77+
let default_rmw_msg = rclrs_example_msgs::msg::rmw::VariousTypes::default();
78+
assert_eq!(
79+
format!("{:?}", default_msg),
80+
format!("{:?}", default_rmw_msg)
81+
);
82+
assert_eq!(
83+
format!("{:#?}", default_msg),
84+
format!("{:#?}", default_rmw_msg)
85+
);
86+
}
87+
88+
fn demonstrate_serde() -> Result<(), Error> {
89+
// When the serde feature is turned on, messages are able to be serialized
90+
// to and deserialized from a variety of formats. Here JSON is used as an
91+
// example.
92+
// Works with RMW-native and idiomatic messages.
93+
let idiomatic_msg = rclrs_example_msgs::msg::VariousTypes::default();
94+
let rmw_msg = rclrs_example_msgs::msg::rmw::VariousTypes::default();
95+
println!("================= JSON serialization with Serde ==================");
96+
let idiomatic_serialized = serde_json::to_string_pretty(&idiomatic_msg)?;
97+
let rmw_serialized = serde_json::to_string_pretty(&rmw_msg)?;
98+
assert_eq!(idiomatic_serialized, rmw_serialized);
99+
println!("{}", rmw_serialized);
100+
let idiomatic_deserialized = serde_json::from_str(&idiomatic_serialized)?;
101+
let rmw_deserialized = serde_json::from_str(&rmw_serialized)?;
102+
assert_eq!(idiomatic_msg, idiomatic_deserialized);
103+
assert_eq!(rmw_msg, rmw_deserialized);
104+
Ok(())
105+
}
106+
107+
fn demonstrate_sequences() {
108+
// Convenient creation of (bounded) sequences with the seq! macro
109+
// This one has three items and a length bound of 5
110+
let mut float_seq_bounded = seq![5 # 1.0, 2.0, 3.0];
111+
// Sequences and bounded sequences have iter(), iter_mut(), and into_iter()
112+
float_seq_bounded
113+
.iter_mut()
114+
.for_each(|n: &mut f32| *n += 1.0);
115+
let float_vec_1: Vec<_> = float_seq_bounded.iter().copied().collect();
116+
let float_vec_2: Vec<_> = float_seq_bounded.into_iter().collect();
117+
assert_eq!(float_vec_1, float_vec_2);
118+
// Sequences also implement FromIterator.
119+
let mut int_seq_unbounded: Sequence<i32> = [42; 4].into_iter().collect();
120+
// Bounded sequences will ignore remaining items once the length bound is reached
121+
let mut int_seq_bounded: BoundedSequence<i32, 3> = [42; 4].into_iter().collect();
122+
// Sequences deref to slices
123+
int_seq_bounded[2] = 24;
124+
assert_eq!(int_seq_bounded.last(), Some(&24));
125+
int_seq_unbounded[2..].copy_from_slice(&int_seq_bounded[1..]);
126+
// New sequences will contain default values – and 0 for primitive types
127+
let seq_with_default_values = Sequence::<rclrs_example_msgs::msg::rmw::NestedType>::new(1);
128+
assert_eq!(seq_with_default_values[0].effect, "discombobulate".into());
129+
}
130+
131+
fn demonstrate_pubsub() -> Result<(), Error> {
132+
println!("================== Interoperability demo ==================");
133+
// Demonstrate interoperability between idiomatic and RMW-native message types
134+
let context = rclrs::Context::new(env::args())?;
135+
let mut node = rclrs::create_node(&context, "message_demo")?;
136+
137+
let idiomatic_publisher = node.create_publisher::<rclrs_example_msgs::msg::VariousTypes>(
138+
"topic",
139+
rclrs::QOS_PROFILE_DEFAULT,
140+
)?;
141+
let direct_publisher = node.create_publisher::<rclrs_example_msgs::msg::rmw::VariousTypes>(
142+
"topic",
143+
rclrs::QOS_PROFILE_DEFAULT,
144+
)?;
145+
146+
let _idiomatic_subscription = node
147+
.create_subscription::<rclrs_example_msgs::msg::VariousTypes, _>(
148+
"topic",
149+
rclrs::QOS_PROFILE_DEFAULT,
150+
move |_msg: rclrs_example_msgs::msg::VariousTypes| println!("Got idiomatic message!"),
151+
)?;
152+
let _direct_subscription = node
153+
.create_subscription::<rclrs_example_msgs::msg::rmw::VariousTypes, _>(
154+
"topic",
155+
rclrs::QOS_PROFILE_DEFAULT,
156+
move |_msg: rclrs_example_msgs::msg::rmw::VariousTypes| {
157+
println!("Got RMW-native message!")
158+
},
159+
)?;
160+
println!("Sending idiomatic message.");
161+
idiomatic_publisher.publish(rclrs_example_msgs::msg::VariousTypes::default())?;
162+
rclrs::spin_once(&node, None)?;
163+
println!("Sending RMW-native message.");
164+
direct_publisher.publish(rclrs_example_msgs::msg::rmw::VariousTypes::default())?;
165+
rclrs::spin_once(&node, None)?;
166+
167+
Ok(())
168+
}
169+
170+
fn main() -> Result<(), Error> {
171+
check_default_values();
172+
demonstrate_printing();
173+
demonstrate_serde()?;
174+
demonstrate_sequences();
175+
demonstrate_pubsub()?;
176+
Ok(())
177+
}

minimal_client_service/Cargo.toml

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
[package]
2+
name = "examples_rclrs_minimal_client_service"
3+
version = "0.3.0"
4+
authors = ["Esteve Fernandez <[email protected]>"]
5+
edition = "2021"
6+
7+
[[bin]]
8+
name = "minimal_client"
9+
path = "src/minimal_client.rs"
10+
11+
[[bin]]
12+
name = "minimal_client_async"
13+
path = "src/minimal_client_async.rs"
14+
15+
[[bin]]
16+
name = "minimal_service"
17+
path = "src/minimal_service.rs"
18+
19+
[dependencies]
20+
anyhow = {version = "1", features = ["backtrace"]}
21+
tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread", "time"] }
22+
23+
[dependencies.rclrs]
24+
version = "0.3"
25+
26+
[dependencies.rosidl_runtime_rs]
27+
version = "0.3"
28+
29+
[dependencies.example_interfaces]
30+
version = "*"

minimal_client_service/package.xml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0"?>
2+
<?xml-model
3+
href="http://download.ros.org/schema/package_format3.xsd"
4+
schematypens="http://www.w3.org/2001/XMLSchema"?>
5+
<package format="3">
6+
<name>examples_rclrs_minimal_client_service</name>
7+
<version>0.3.0</version>
8+
<description>Package containing an example of the client-service mechanism in rclrs.</description>
9+
<maintainer email="[email protected]">Esteve Fernandez</maintainer>
10+
<license>Apache License 2.0</license>
11+
12+
<build_depend>example_interfaces</build_depend>
13+
<build_depend>rclrs</build_depend>
14+
<build_depend>rosidl_runtime_rs</build_depend>
15+
16+
<exec_depend>example_interfaces</exec_depend>
17+
<exec_depend>rclrs</exec_depend>
18+
<exec_depend>rosidl_runtime_rs</exec_depend>
19+
20+
<export>
21+
<build_type>ament_cargo</build_type>
22+
</export>
23+
</package>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use std::env;
2+
3+
use anyhow::{Error, Result};
4+
5+
fn main() -> Result<(), Error> {
6+
let context = rclrs::Context::new(env::args())?;
7+
8+
let mut node = rclrs::create_node(&context, "minimal_client")?;
9+
10+
let client = node.create_client::<example_interfaces::srv::AddTwoInts>("add_two_ints")?;
11+
12+
let request = example_interfaces::srv::AddTwoInts_Request { a: 41, b: 1 };
13+
14+
println!("Starting client");
15+
16+
std::thread::sleep(std::time::Duration::from_millis(500));
17+
18+
client.async_send_request_with_callback(
19+
&request,
20+
move |response: example_interfaces::srv::AddTwoInts_Response| {
21+
println!(
22+
"Result of {} + {} is: {}",
23+
request.a, request.b, response.sum
24+
);
25+
},
26+
)?;
27+
28+
std::thread::sleep(std::time::Duration::from_millis(500));
29+
30+
println!("Waiting for response");
31+
rclrs::spin(&node).map_err(|err| err.into())
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use std::env;
2+
3+
use anyhow::{Error, Result};
4+
5+
#[tokio::main]
6+
async fn main() -> Result<(), Error> {
7+
let context = rclrs::Context::new(env::args())?;
8+
9+
let mut node = rclrs::create_node(&context, "minimal_client")?;
10+
11+
let client = node.create_client::<example_interfaces::srv::AddTwoInts>("add_two_ints")?;
12+
13+
println!("Starting client");
14+
15+
std::thread::sleep(std::time::Duration::from_millis(500));
16+
17+
let request = example_interfaces::srv::AddTwoInts_Request { a: 41, b: 1 };
18+
19+
let future = client.call_async(&request);
20+
21+
println!("Waiting for response");
22+
23+
let rclrs_spin = tokio::task::spawn_blocking(move || rclrs::spin(&node));
24+
25+
let response = future.await?;
26+
println!(
27+
"Result of {} + {} is: {}",
28+
request.a, request.b, response.sum
29+
);
30+
31+
rclrs_spin.await.ok();
32+
Ok(())
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use std::env;
2+
3+
use anyhow::{Error, Result};
4+
5+
fn handle_service(
6+
_request_header: &rclrs::rmw_request_id_t,
7+
request: example_interfaces::srv::AddTwoInts_Request,
8+
) -> example_interfaces::srv::AddTwoInts_Response {
9+
println!("request: {} + {}", request.a, request.b);
10+
example_interfaces::srv::AddTwoInts_Response {
11+
sum: request.a + request.b,
12+
}
13+
}
14+
15+
fn main() -> Result<(), Error> {
16+
let context = rclrs::Context::new(env::args())?;
17+
18+
let mut node = rclrs::create_node(&context, "minimal_service")?;
19+
20+
let _server = node
21+
.create_service::<example_interfaces::srv::AddTwoInts, _>("add_two_ints", handle_service)?;
22+
23+
println!("Starting server");
24+
rclrs::spin(&node).map_err(|err| err.into())
25+
}

0 commit comments

Comments
 (0)