Skip to content

Commit 8e8300f

Browse files
author
GueLaKais
committed
Added descriptions for the subscriber
1 parent 5f2896f commit 8e8300f

File tree

1 file changed

+87
-4
lines changed

1 file changed

+87
-4
lines changed

docs/writing_a_simple_publisher_and_subscriber.md

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,6 @@ Of course, you can use any capable editor or even your file explorer to do this.
9090

9191
<details><summary>Write the publisher node</summary>
9292

93-
94-
9593
To construct a node, replace the code in your main.rs with the [following](https://gitlab.com/ros21923912/simple_ros2_node/-/raw/more_simple_nodes/src/simple_publisher.rs?ref_type=heads):
9694
```
9795
/// Creates a SimplePublisherNode, initializes a node and publisher, and provides
@@ -328,8 +326,93 @@ As you can see, you are now calling your node by the name declared in `[[bin]]`
328326
Of course, you can implement a new ros2 rust package for this node. You can find out how to do this in the section called 'Create a package'.
329327
Or you can add a new binary target to your package. Then just add a new `<file>.rs` to your source directory - for simplicity I'll call this file `simple_subscriber.rs` - and add a corresponding binary target to your `Cargo.toml`:
330328
```
331-
329+
[[bin]]
330+
name="simple_subscriber"
331+
path="src/simple_subscriber.rs"
332332
```
333-
333+
To construct the subscriber node, put the [following](https://gitlab.com/ros21923912/simple_ros2_node/-/raw/more_simple_nodes/src/simple_subscriber.rs?ref_type=heads) code into a file.rs - in my case its the `src/simple_subscriber.rs`:
334+
```
335+
use rclrs::{create_node, Context, Node, RclrsError, Subscription, QOS_PROFILE_DEFAULT};
336+
use std::{
337+
env,
338+
iter,thread,
339+
sync::{Arc, Mutex},
340+
time::Duration,
341+
};
342+
use std_msgs::msg::String as StringMsg;
343+
/// A simple ROS2 subscriber node that receives and prints "hello" messages.
344+
///
345+
/// This node creates a subscription to the "publish_hello" topic and prints the
346+
/// received messages to the console. It runs the subscription in a separate
347+
/// thread, while the main thread calls `rclrs::spin()` to keep the node running.
348+
pub struct SimpleSubscriptionNode {
349+
node: Arc<Node>,
350+
_subscriber: Arc<Subscription<StringMsg>>,
351+
data: Arc<Mutex<Option<StringMsg>>>,
352+
}
353+
/// Implements a simple ROS2 subscriber node that receives and prints "hello" messages.
354+
///
355+
/// The `SimpleSubscriptionNode` creates a subscription to the "publish_hello" topic and
356+
/// prints the received messages to the console. It runs the subscription in a separate
357+
/// thread, while the main thread calls `rclrs::spin()` to keep the node running.
358+
///
359+
/// The `new` function creates the node and the subscription, and returns a `SimpleSubscriptionNode`
360+
/// instance. The `data_callback` function can be used to access the latest received message.
361+
impl SimpleSubscriptionNode {
362+
fn new(context: &Context) -> Result<Self, RclrsError> {
363+
let node = create_node(context, "simple_subscription").unwrap();
364+
let data: Arc<Mutex<Option<StringMsg>>> = Arc::new(Mutex::new(None));
365+
let data_mut: Arc<Mutex<Option<StringMsg>>> = Arc::clone(&data);
366+
let _subscriber = node
367+
.create_subscription::<StringMsg, _>(
368+
"publish_hello",
369+
QOS_PROFILE_DEFAULT,
370+
move |msg: StringMsg| {
371+
*data_mut.lock().unwrap() = Some(msg);
372+
},
373+
)
374+
.unwrap();
375+
Ok(Self {
376+
node,
377+
_subscriber,
378+
data,
379+
})
380+
}
381+
fn data_callback(&self) -> Result<(), RclrsError> {
382+
if let Some(data) = self.data.lock().unwrap().as_ref() {
383+
println!("{}", data.data);
384+
} else {
385+
println!("No message available yet.");
386+
}
387+
Ok(())
388+
}
389+
}
390+
/// The `main` function creates a new ROS2 context, a `SimpleSubscriptionNode` instance, and starts a separate thread to periodically call the `data_callback` method on the subscription. The main thread then calls `rclrs::spin()` to keep the node running and receive messages.
391+
///
392+
/// The separate thread is used to ensure that the `data_callback` method is called regularly, even if the main thread is blocked in `rclrs::spin()`. This allows the subscriber to continuously process and print the received "hello" messages.
393+
fn main() -> Result<(), RclrsError> {
394+
let context = Context::new(env::args()).unwrap();
395+
let subscription = Arc::new(SimpleSubscriptionNode::new(&context).unwrap());
396+
let subscription_other_thread = Arc::clone(&subscription);
397+
thread::spawn(move || -> () {
398+
iter::repeat(()).for_each(|()| {
399+
thread::sleep(Duration::from_millis(1000));
400+
subscription_other_thread.data_callback().unwrap()
401+
});
402+
});
403+
rclrs::spin(subscription.node.clone())
404+
}
405+
```
406+
Once you've implemented the code, you're ready to make it runnable:
407+
```
408+
cd ${MainFolderOfWorkspace}
409+
colcon build
410+
source install/setub.bash
411+
```
412+
And finally run with:
413+
```
414+
ros2 run your_project_name your_node_name
415+
```
416+
(Please give your package a better name than me ;) )
334417
</details>
335418
</details></div>

0 commit comments

Comments
 (0)