rclrs/
lib.rs

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