一、参考资料
编写一个简单的发布者和订阅者(C++) --- ROS 2 Documentation: Humble 文档
SLAM之ROS通信:发布者与话题(C++)(三) - 知乎
SLAM之ROS通信:订阅者与回调函数(C++)(四) - 知乎
二、发布者-订阅者模式
1. 创建ros2_ws工作空间
bash
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
2. 创建功能包
bash
ros2 pkg create --build-type ament_cmake cpp_pubsub
输出示例:
bash
forlinx@okrk3588:/mnt/ros2_ws/src$ ros2 pkg create --build-type ament_cmake cpp_pubsub
going to create a new package
package name: cpp_pubsub
destination directory: /mnt/ros2_ws/src
package format: 3
version: 0.0.0
description: TODO: Package description
maintainer: ['forlinx <forlinx@todo.todo>']
licenses: ['TODO: License declaration']
build type: ament_cmake
dependencies: []
creating folder ./cpp_pubsub
creating ./cpp_pubsub/package.xml
creating source and include folder
creating folder ./cpp_pubsub/src
creating folder ./cpp_pubsub/include/cpp_pubsub
creating ./cpp_pubsub/CMakeLists.txt
[WARNING]: Unknown license 'TODO: License declaration'. This has been set in the package.xml, but no LICENSE file has been created.
It is recommended to use one of the ament license identifiers:
Apache-2.0
BSL-1.0
BSD-2.0
BSD-2-Clause
BSD-3-Clause
GPL-3.0-only
LGPL-3.0-only
MIT
MIT-0
功能包创建成功后,构建信息会收集在两个文件中:package.xml 和 CMakeLists.txt,它们必须位于同一目录中。
功能包构建完成的目录结构:
bash
.
├── build
├── install
├── log
└── src
3. 发布者
bash
#include <memory>
#include <string>
#include <functional>
#include <chrono>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using namespace std::chrono_literals;
class MinimalPublisher : public rclcpp::Node
{
public:
MinimalPublisher()
: Node("minimal_publisher"), count_(0)
{
publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);
timer_ = this->create_wall_timer(
std::chrono::milliseconds(500), std::bind(&MinimalPublisher::timer_callback, this)
);
}
private:
void timer_callback()
{
auto message = std_msgs::msg::String();
message.data = "Hello, world! " + std::to_string(count_++);
RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
publisher_->publish(message);
}
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
size_t count_;
};
int main(int argc, char *argv[]) {
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalPublisher>());
rclcpp::shutdown();
return 0;
}
4. 订阅者
bash
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
class MinimalSubscriber : public rclcpp::Node
{
public:
MinimalSubscriber()
: Node("minimal_subscriber")
{
subscription_ = this->create_subscription<std_msgs::msg::String>(
"topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, std::placeholders::_1)
);
}
private:
void topic_callback(const std_msgs::msg::String &msg) const
{
RCLCPP_INFO(this->get_logger(), "I head: '%s'", msg.data.c_str());
}
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};
int main(int argc, char *argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalSubscriber>());
rclcpp::shutdown();
return 0;
}
5. 修改 package.xml
xml
<build_depend>rclcpp</build_depend>
<build_depend>std_msgs</build_depend>
<exec_depend>rclcpp</exec_depend>
<exec_depend>std_msgs</exec_depend>
6. 修改 CMakeLists.txt
在 CMakeLists.txt 中添加以下内容:
cmake
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
add_executable(talker src/publisher_member_function.cpp)
ament_target_dependencies(talker rclcpp std_msgs)
add_executable(listener src/subscriber_member_function.cpp)
ament_target_dependencies(listener rclcpp std_msgs)
install(TARGETS
talker
listener
DESTINATION lib/${PROJECT_NAME}
)
7. 构建功能包
在构建之前,最好在工作空间的根目录ros2_ws 中运行 rosdep 检查是否缺少依赖项:
bash
rosdep install -i --from-path src --rosdistro jazzy -y
构建功能包:
bash
colcon build --packages-select cpp_pubsub
设置环境变量:
bash
source install/setup.bash
发布sub订阅者节点:
bash
ros2 run cpp_pubsub listener
启动pub发布者节点:
bash
ros2 run cpp_pubsub talker
sub订阅者输出示例:
bash
forlinx@okrk3588:/mnt/ros2_ws$ ros2 run cpp_pubsub listener
[INFO] [1765851862.727183300] [minimal_subscriber]: I head: 'Hello, world! 0'
[INFO] [1765851863.226124301] [minimal_subscriber]: I head: 'Hello, world! 1'
[INFO] [1765851863.726138208] [minimal_subscriber]: I head: 'Hello, world! 2'
[INFO] [1765851864.226031365] [minimal_subscriber]: I head: 'Hello, world! 3'
[INFO] [1765851864.726637431] [minimal_subscriber]: I head: 'Hello, world! 4'
[INFO] [1765851865.227187706] [minimal_subscriber]: I head: 'Hello, world! 5'
[INFO] [1765851865.726502618] [minimal_subscriber]: I head: 'Hello, world! 6'
[INFO] [1765851866.230778562] [minimal_subscriber]: I head: 'Hello, world! 7'
[INFO] [1765851866.727568708] [minimal_subscriber]: I head: 'Hello, world! 8'
[INFO] [1765851867.226840453] [minimal_subscriber]: I head: 'Hello, world! 9'
pub发布者输出示例:
bash
forlinx@okrk3588:/mnt/ros2_ws$ ros2 run cpp_pubsub talker
[INFO] [1765851862.725834064] [minimal_publisher]: Publishing: 'Hello, world! 0'
[INFO] [1765851863.225641306] [minimal_publisher]: Publishing: 'Hello, world! 1'
[INFO] [1765851863.725631588] [minimal_publisher]: Publishing: 'Hello, world! 2'
[INFO] [1765851864.225584245] [minimal_publisher]: Publishing: 'Hello, world! 3'
[INFO] [1765851864.725695524] [minimal_publisher]: Publishing: 'Hello, world! 4'
[INFO] [1765851865.225820679] [minimal_publisher]: Publishing: 'Hello, world! 5'
[INFO] [1765851865.725987540] [minimal_publisher]: Publishing: 'Hello, world! 6'
[INFO] [1765851866.225913029] [minimal_publisher]: Publishing: 'Hello, world! 7'
[INFO] [1765851866.725899517] [minimal_publisher]: Publishing: 'Hello, world! 8'
[INFO] [1765851867.225956129] [minimal_publisher]: Publishing: 'Hello, world! 9'