We'll create a simple example of a publisher and a subscriber like we did for DDS, but this time using ROS to manage the process communication for us.
By the end of this example, we'll have two nodes running, one of them will be publishing Hello World! and the other will be receiving it.
First we create a new package called hello_pubsub
ros2 pkg create --build-type ament_cmake hello_pubsub
Now, let's create the HelloPublisher class on a file called hello_publisher.cpp
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using namespace std::chrono_literals;
#define MAX_MESSAGES_QUEUE 10
class HelloPublisher : public rclcpp::Node {
private:
size_t count;
rclcpp::TimerBase::SharedPtr timer;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher;
void send_message () {
auto msg = std_msgs::msg::String();
msg.data = "Hello World! " + std::to_string(count);
count++;
publisher->publish(msg);
RCLCPP_INFO(this->get_logger(), "message #%d sent", count);
}
public:
HelloPublisher() : Node("hello_publisher"), count(0) {
publisher = this->create_publisher<std_msgs::msg::String>(
"hello_world_messages_topic", MAX_MESSAGES_QUEUE);
/* A timer will be sending a message each 500ms */
timer = this->create_wall_timer(500ms,
std::bind(&HelloPublisher::send_message, this));
}
};
int main (int argc, char *argv[]) {
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<HelloPublisher>());
rclcpp::shutdown();
return 0;
}
The publisher is very straighforward. ROS handles all the trouble here. All we have to do is to create an object of type rclcpp::Publisher that is typed to msg::String, because it is what we're sending.
After that, we need to periodically send our message (because this is our USE CASE for this testing project)
And that's it.
The holding class, HelloPublisher, must inherits from the Node class, in order to be a "node" in the ROS process tree,
We'll name it hello_subscriber.cpp
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using std::placeholders::_1;
#define MAX_MESSAGES_QUEUE 10
class HelloSubscriber : public rclcpp::Node {
private:
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscriber;
void read_message (const std_msgs::msg::String & msg) {
RCLCPP_INFO(this->get_logger(), "received: '%s'",
msg.data.c_str());
}
public:
HelloSubscriber() : Node("hello_subscriber") {
subscriber = this->create_subscription<std_msgs::msg::String>(
"hello_world_messages_topic", MAX_MESSAGES_QUEUE,
std::bind(&HelloSubscriber::read_message, this, _1));
}
};
int main (int argc, char *argv[]) {
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<HelloSubscriber>());
rclcpp::shutdown();
return 0;
}
The subscriber is also very straighforward. ROS handles all the trouble here too.
All we have to do is to create an object of type rclcpp::Subscription that is typed to msg::String, because it is what we're expecting, set the topic we wish to observe and then define a callback function that get's called whenever something is published on the topic .
And that's it.
To finish our example, we need to set up things to run.
We need to edit the package.xml file to add dependencies and the CMakeList.txt to teach the compiler how to compile our code.
On package.xml, we add the dependecies for the standard message format and the rclcpp:
<export>
<build_type>ament_cmake</build_type>
<depend>rclcpp</depend>
<depend>std_msgs</depend>
</export>
On CMakeLists.txt, we also add dependencies for those packages, and add executable configurations. Another thing that we add is the install( ) method, which is responsible for defining a path to the output of the building.
cmake_minimum_required(VERSION 3.8)
project(hello_pubsub)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
add_executable(publisher src/hello_publisher.cpp)
add_executable(subscriber src/hello_subscriber.cpp)
ament_target_dependencies(publisher rclcpp std_msgs)
ament_target_dependencies(subscriber rclcpp std_msgs)
install(TARGETS
publisher
subscriber
DESTINATION lib/${PROJECT_NAME})
ament_package()
All set. Now, let's download the dependencies by issuing:
rosdep install -i --from-path src --rosdistro galactic -y And then, we compile our new package
colcon build --packages-select hello_pubsub Finally, let's open two separate consoles, one running the publisher and the other running the subscriber
Publisher
. install/setup.bash
ros2 run hello_pubsub publisherSubscriber
. install/setup.bash
ros2 run hello_pubsub subscriber[INFO] [1649219711.222277763] [hello_publisher]: message #86 sent
[INFO] [1649219711.722307938] [hello_publisher]: message #87 sent
[INFO] [1649219712.222268412] [hello_publisher]: message #88 sent
[INFO] [1649219712.722280066] [hello_publisher]: message #89 sent
[INFO] [1649219713.222285281] [hello_publisher]: message #90 sent
(...)
[INFO] [1649219711.722458435] [hello_subscriber]: received: 'Hello World! 86'
[INFO] [1649219712.222437726] [hello_subscriber]: received: 'Hello World! 87'
[INFO] [1649219712.722470352] [hello_subscriber]: received: 'Hello World! 88'
[INFO] [1649219713.222397218] [hello_subscriber]: received: 'Hello World! 89'
(..)

Nenhum comentário:
Postar um comentário