|
1 | 1 | #![warn(missing_docs)] |
2 | 2 | //! Rust client library for ROS 2. |
3 | 3 | //! |
4 | | -//! For getting started, see the [README][1]. |
| 4 | +//! Since this library depends on the ROS ecosystem, see the [README][1] for |
| 5 | +//! setup instructions. |
5 | 6 | //! |
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 | +//! |
| 36 | +//! let context = Context::default_from_env()?; |
| 37 | +//! let mut executor = context.create_basic_executor(); |
| 38 | +//! let node = executor.create_node("example_node")?; |
| 39 | +//! |
| 40 | +//! let subscription = node.create_subscription( |
| 41 | +//! "topic_name", |
| 42 | +//! |msg: example_interfaces::msg::String| { |
| 43 | +//! println!("Received message: {}", msg.data); |
| 44 | +//! } |
| 45 | +//! )?; |
| 46 | +//! |
| 47 | +//! executor.spin(SpinOptions::default()).first_error()?; |
| 48 | +//! # Ok::<(), RclrsError>(()) |
| 49 | +//! ``` |
| 50 | +//! |
| 51 | +//! If your callback needs to interact with some state data, consider using a |
| 52 | +//! [`Worker`], especially if that state data needs to be shared with other |
| 53 | +//! callbacks: |
| 54 | +//! |
| 55 | +//! ```no_run |
| 56 | +//! # use rclrs::*; |
| 57 | +//! # |
| 58 | +//! # let context = Context::default_from_env()?; |
| 59 | +//! # let mut executor = context.create_basic_executor(); |
| 60 | +//! # let node = executor.create_node("example_node")?; |
| 61 | +//! # |
| 62 | +//! // This worker will manage the data for us. |
| 63 | +//! // The worker's data is called its payload. |
| 64 | +//! let worker = node.create_worker::<Option<String>>(None); |
| 65 | +//! |
| 66 | +//! // We use the worker to create a subscription. |
| 67 | +//! // This subscription's callback can borrow the worker's |
| 68 | +//! // payload with its first function argument. |
| 69 | +//! let subscription = worker.create_subscription( |
| 70 | +//! "topic_name", |
| 71 | +//! |data: &mut Option<String>, msg: example_interfaces::msg::String| { |
| 72 | +//! // Print out the previous message, if one exists. |
| 73 | +//! if let Some(previous) = data { |
| 74 | +//! println!("Previous message: {}", *previous) |
| 75 | +//! } |
| 76 | +//! |
| 77 | +//! // Save the latest message, to be printed out the |
| 78 | +//! // next time this callback is triggered. |
| 79 | +//! *data = Some(msg.data); |
| 80 | +//! } |
| 81 | +//! )?; |
| 82 | +//! |
| 83 | +//! # executor.spin(SpinOptions::default()).first_error()?; |
| 84 | +//! # Ok::<(), RclrsError>(()) |
| 85 | +//! ``` |
| 86 | +//! |
| 87 | +//! # Parameters |
| 88 | +//! |
| 89 | +//! `rclrs` provides an ergonomic way to declare and use node parameters. A |
| 90 | +//! parameter can be declared as [mandatory][crate::MandatoryParameter], |
| 91 | +//! [optional][crate::OptionalParameter], or [read-only][crate::ReadOnlyParameter]. |
| 92 | +//! The API of each reflects their respective constraints. |
| 93 | +//! - Mandatory and read-only parameters always have a value that you can [get][MandatoryParameter::get] |
| 94 | +//! - Optional parameters will return an [`Option`] when you [get][OptionalParameter::get] from them. |
| 95 | +//! - Read-only parameters do not allow you to modify them after they have been declared. |
| 96 | +//! |
| 97 | +//! The following is a simple example of using a mandatory parameter: |
| 98 | +//! ```no_run |
| 99 | +//! use rclrs::*; |
| 100 | +//! use std::sync::Arc; |
| 101 | +//! |
| 102 | +//! let mut executor = Context::default_from_env()?.create_basic_executor(); |
| 103 | +//! let node = executor.create_node("parameter_demo")?; |
| 104 | +//! |
| 105 | +//! let greeting: MandatoryParameter<Arc<str>> = node |
| 106 | +//! .declare_parameter("greeting") |
| 107 | +//! .default("Hello".into()) |
| 108 | +//! .mandatory()?; |
| 109 | +//! |
| 110 | +//! let _subscription = node.create_subscription( |
| 111 | +//! "greet", |
| 112 | +//! move |msg: example_interfaces::msg::String| { |
| 113 | +//! println!("{}, {}", greeting.get(), msg.data); |
| 114 | +//! } |
| 115 | +//! )?; |
| 116 | +//! |
| 117 | +//! executor.spin(SpinOptions::default()).first_error()?; |
| 118 | +//! # Ok::<(), RclrsError>(()) |
| 119 | +//! ``` |
7 | 120 |
|
8 | 121 | mod arguments; |
9 | 122 | mod client; |
|
0 commit comments