1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
//! Rust client library for ROS 2.
//!
//! Since this library depends on the ROS ecosystem, see the [README][1] for
//! setup instructions.
//!
//! [1]: https://github.com/ros2-rust/ros2_rust/blob/main/README.md
//!
//! This client library is made to be familiar for ROS users who are used to
//! the conventional client libraries `rcl`, `rclcpp`, and `rclpy`, while taking
//! full advantage of the unique strengths of the Rust programming language.
//!
//! The library provides structs that will be familiar to ROS users:
//! - [`Context`]
//! - [`Executor`]
//! - [`Node`]
//! - [`Subscription`]
//! - [`Publisher`]
//! - [`Service`]
//! - [`Client`]
//!
//! It also provides some unique utilities to help leverage Rust language features,
//! such as `async` programming:
//! - [`Worker`]
//! - [`ExecutorCommands`]
//!
//! # Basic Usage
//!
//! To build a typical ROS application, create a [`Context`], followed by an
//! [`Executor`], and then a [`Node`]. Create whatever primitives you need, and
//! then tell the [`Executor`] to spin:
//!
//! ```no_run
//! use rclrs::*;
//! # use crate::rclrs::vendor::example_interfaces;
//!
//! let context = Context::default_from_env()?;
//! let mut executor = context.create_basic_executor();
//! let node = executor.create_node("example_node")?;
//!
//! let subscription = node.create_subscription(
//! "topic_name",
//! |msg: example_interfaces::msg::String| {
//! println!("Received message: {}", msg.data);
//! }
//! )?;
//!
//! executor.spin(SpinOptions::default()).first_error()?;
//! # Ok::<(), RclrsError>(())
//! ```
//!
//! If your callback needs to interact with some state data, consider using a
//! [`Worker`], especially if that state data needs to be shared with other
//! callbacks:
//!
//! ```no_run
//! # use rclrs::*;
//! #
//! # let context = Context::default_from_env()?;
//! # let mut executor = context.create_basic_executor();
//! # let node = executor.create_node("example_node")?;
//! # use crate::rclrs::vendor::example_interfaces;
//! #
//! // This worker will manage the data for us.
//! // The worker's data is called its payload.
//! let worker = node.create_worker::<Option<String>>(None);
//!
//! // We use the worker to create a subscription.
//! // This subscription's callback can borrow the worker's
//! // payload with its first function argument.
//! let subscription = worker.create_subscription(
//! "topic_name",
//! |data: &mut Option<String>, msg: example_interfaces::msg::String| {
//! // Print out the previous message, if one exists.
//! if let Some(previous) = data {
//! println!("Previous message: {}", *previous)
//! }
//!
//! // Save the latest message, to be printed out the
//! // next time this callback is triggered.
//! *data = Some(msg.data);
//! }
//! )?;
//!
//! # executor.spin(SpinOptions::default()).first_error()?;
//! # Ok::<(), RclrsError>(())
//! ```
//!
//! # Parameters
//!
//! `rclrs` provides an ergonomic way to declare and use node parameters. A
//! parameter can be declared as [mandatory][crate::MandatoryParameter],
//! [optional][crate::OptionalParameter], or [read-only][crate::ReadOnlyParameter].
//! The API of each reflects their respective constraints.
//! - Mandatory and read-only parameters always have a value that you can [get][MandatoryParameter::get]
//! - Optional parameters will return an [`Option`] when you [get][OptionalParameter::get] from them.
//! - Read-only parameters do not allow you to modify them after they have been declared.
//!
//! The following is a simple example of using a mandatory parameter:
//! ```no_run
//! use rclrs::*;
//! # use crate::rclrs::vendor::example_interfaces;
//! use std::sync::Arc;
//!
//! let mut executor = Context::default_from_env()?.create_basic_executor();
//! let node = executor.create_node("parameter_demo")?;
//!
//! let greeting: MandatoryParameter<Arc<str>> = node
//! .declare_parameter("greeting")
//! .default("Hello".into())
//! .mandatory()?;
//!
//! let _subscription = node.create_subscription(
//! "greet",
//! move |msg: example_interfaces::msg::String| {
//! println!("{}, {}", greeting.get(), msg.data);
//! }
//! )?;
//!
//! executor.spin(SpinOptions::default()).first_error()?;
//! # Ok::<(), RclrsError>(())
//! ```
//!
//! # Logging
//!
//! `rclrs` provides the same logging utilites as `rclcpp` and `rclpy` with an
//! ergonomic Rust API. [`ToLogParams`] can be used to dictate how logging is
//! performed.
//!
//! ```no_run
//! use rclrs::*;
//! # use crate::rclrs::vendor::example_interfaces;
//! use std::time::Duration;
//!
//! let mut executor = Context::default_from_env()?.create_basic_executor();
//! let node = executor.create_node("logging_demo")?;
//!
//! let _subscription = node.clone().create_subscription(
//! "logging_demo",
//! move |msg: example_interfaces::msg::String| {
//! let data = msg.data;
//!
//! // You can apply modifiers such as .once() to node.logger()
//! // to dictate how the logging behaves.
//! log!(
//! node.logger().once(),
//! "First message: {data}",
//! );
//!
//! log!(
//! node.logger().skip_first(),
//! "Subsequent message: {data}",
//! );
//!
//! // You can chain multiple modifiers together.
//! log_warn!(
//! node
//! .logger()
//! .skip_first()
//! .throttle(Duration::from_secs(5)),
//! "Throttled message: {data}",
//! );
//! }
//! )?;
//!
//! // Any &str can be used as the logger name and have
//! // logging modifiers applied to it.
//! log_info!(
//! "notice".once(),
//! "Ready to begin logging example_interfaces/msg/String messages published to 'logging_demo'.",
//! );
//! log_warn!(
//! "help",
//! "Try running\n \
//! $ ros2 topic pub logging_demo example_interfaces/msg/String \"data: message\"",
//! );
//! executor.spin(SpinOptions::default()).first_error()?;
//! # Ok::<(), RclrsError>(())
//! ```
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
use DropGuard;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use rmw_request_id_t;
pub use *;
pub use *;
pub use *;
use *;
pub use *;
pub use *;
pub use *;
pub use ;