【Ros2学习】话题的发布与请求
文章目录
- 前言
- 一、订阅发布完整流程
- 二、 工作区结构准备
- 步骤 1:创建工作区目录结构
- 步骤 2:创建功能包
- 三、 创建发布者流程
- 步骤 1:创建发布者节点
- 步骤 2:创建发布者源文件
- 步骤 3:创建订阅者节点
- 步骤 4:创建订阅者源文件
- 步骤 5:创建main
- 四、 修改编译文件
- 步骤 1:修改 CMakeLists.txt
- 步骤 2:修改 package.xml
- 五、 编译工作区
- 步骤1:编译功能包
- 步骤2:加载工作区环境
- 步骤3:运行节点
前言
学习记录Ros2中订阅发布主题的操作步骤
一、订阅发布完整流程
以下图是大致的流程图:

二、 工作区结构准备
步骤 1:创建工作区目录结构
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
步骤 2:创建功能包
ros2 pkg create pub_sub_demo --build-type ament_cmake --dependencies rclcpp std_msgs
三、 创建发布者流程
步骤 1:创建发布者节点
# 创建头文件目录和源文件
mkdir -p ~/ros2_ws/src/pub_sub_demo/include/pub_sub_demo
mkdir -p ~/ros2_ws/src/pub_sub_demo/src# 创建发布者头文件
nano ~/ros2_ws/src/pub_sub_demo/include/pub_sub_demo/publisher_node.hpp
publisher_node.hpp
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"class PublisherNode : public rclcpp::Node {
public:PublisherNode() : Node("publisher_node"), count_(0) {// 1. 创建发布者publisher_ = this->create_publisher<std_msgs::msg::String>("chatter", 10);// 2. 创建定时器定期发布消息timer_ = this->create_wall_timer(std::chrono::seconds(1),[this]() {// 3. 创建消息auto message = std_msgs::msg::String();message.data = "Hello ROS 2: " + std::to_string(count_++);// 4. 发布消息publisher_->publish(message);RCLCPP_INFO(this->get_logger(), "发布: '%s'", message.data.c_str());});}private:rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;rclcpp::TimerBase::SharedPtr timer_;size_t count_;
};
步骤 2:创建发布者源文件
nano ~/ros2_ws/src/pub_sub_demo/src/publisher_node.cpp
publisher_node.cpp:
#include "pub_sub_demo/publisher_node.hpp"PublisherNode::PublisherNode()
: Node("publisher_node"), count_(0)
{// 创建发布者,主题名为 "chatter",队列大小为10publisher_ = this->create_publisher<std_msgs::msg::String>("chatter", 10);// 创建定时器,每秒发布一次消息timer_ = this->create_wall_timer(std::chrono::seconds(1),std::bind(&PublisherNode::timer_callback, this));RCLCPP_INFO(this->get_logger(), "发布者节点已启动");
}void PublisherNode::timer_callback()
{// 创建消息auto message = std_msgs::msg::String();message.data = "Hello ROS 2 - 消息编号: " + std::to_string(count_++);// 发布消息publisher_->publish(message);// 打印日志RCLCPP_INFO(this->get_logger(), "发布消息: '%s'", message.data.c_str());
}
步骤 3:创建订阅者节点
nano ~/ros2_ws/src/pub_sub_demo/include/pub_sub_demo/subscriber_node.hpp
subscriber_node.hpp:
#ifndef PUB_SUB_DEMO__SUBSCRIBER_NODE_HPP_
#define PUB_SUB_DEMO__SUBSCRIBER_NODE_HPP_#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"class SubscriberNode : public rclcpp::Node
{
public:SubscriberNode();private:void message_callback(const std_msgs::msg::String::SharedPtr msg) const;rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};#endif // PUB_SUB_DEMO__SUBSCRIBER_NODE_HPP_
步骤 4:创建订阅者源文件
nano ~/ros2_ws/src/pub_sub_demo/src/subscriber_node.cpp
subscriber_node.cpp:
#include "pub_sub_demo/subscriber_node.hpp"SubscriberNode::SubscriberNode()
: Node("subscriber_node")
{// 创建订阅者subscription_ = this->create_subscription<std_msgs::msg::String>("chatter", // 主题名10, // 队列大小// Lambda 回调函数[this](const std_msgs::msg::String::SharedPtr msg) {this->message_callback(msg);});RCLCPP_INFO(this->get_logger(), "订阅者节点已启动,等待消息...");
}void SubscriberNode::message_callback(const std_msgs::msg::String::SharedPtr msg) const
{RCLCPP_INFO(this->get_logger(), "收到消息: '%s'", msg->data.c_str());
}
步骤 5:创建main
nano ~/ros2_ws/src/pub_sub_demo/src/main.cpp
main.cpp:
#include "rclcpp/rclcpp.hpp"
#include "pub_sub_demo/publisher_node.hpp"
#include "pub_sub_demo/subscriber_node.hpp"int main(int argc, char * argv[])
{// 初始化 ROS 2rclcpp::init(argc, argv);// 创建节点auto publisher_node = std::make_shared<PublisherNode>();auto subscriber_node = std::make_shared<SubscriberNode>();// 创建执行器(单线程)auto executor = std::make_shared<rclcpp::executors::SingleThreadedExecutor>();// 添加节点到执行器executor->add_node(publisher_node);executor->add_node(subscriber_node);RCLCPP_INFO(publisher_node->get_logger(), "开始执行...");try {// 运行执行器(阻塞调用)executor->spin();} catch (const std::exception& e) {RCLCPP_ERROR(rclcpp::get_logger("main"), "执行器异常: %s", e.what());}// 清理资源executor->remove_node(publisher_node);executor->remove_node(subscriber_node);rclcpp::shutdown();return 0;
}
四、 修改编译文件
步骤 1:修改 CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(pub_sub_demo)# 设置 C++ 标准
if(NOT CMAKE_CXX_STANDARD)set(CMAKE_CXX_STANDARD 17)
endif()# 查找依赖
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)# 包含头文件目录
include_directories(include)# 创建可执行文件
add_executable(pub_sub_demo_nodesrc/publisher_node.cppsrc/subscriber_node.cppsrc/main.cpp
)# 添加依赖
ament_target_dependencies(pub_sub_demo_noderclcppstd_msgs
)# 安装
install(TARGETSpub_sub_demo_nodeDESTINATION lib/${PROJECT_NAME}
)install(DIRECTORY include/DESTINATION include/
)# 导出
ament_export_include_directories(include)
ament_export_dependencies(rclcpp std_msgs)# 必须在最后
ament_package()
步骤 2:修改 package.xml
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypelayout="1.0"?>
<package format="3"><name>pub_sub_demo</name><version>0.0.0</version><description>ROS 2 发布订阅示例</description><maintainer email="you@example.com">Your Name</maintainer><license>Apache-2.0</license><buildtool_depend>ament_cmake</buildtool_depend><depend>rclcpp</depend><depend>std_msgs</depend><test_depend>ament_lint_auto</test_depend><test_depend>ament_lint_common</test_depend><export><build_type>ament_cmake</build_type></export>
</package>
五、 编译工作区
步骤1:编译功能包
# 进入工作区根目录
cd ~/ros2_ws# 编译工作区
colcon build --packages-select pub_sub_demo# 或者使用符号链接安装(推荐用于开发)
colcon build --packages-select pub_sub_demo --symlink-install
步骤2:加载工作区环境
# 加载工作区设置
source ~/ros2_ws/install/setup.bash# 验证包是否可找到
ros2 pkg list | grep pub_sub_demo
步骤3:运行节点
# 运行包含两个节点的可执行文件
ros2 run pub_sub_demo pub_sub_demo_node
运行结果如下:

