0 引言
在ROS2中,节点间的信息传输方式主要为以下几种:
- Topic(话题,发布-订阅)
- Service(服务,请求-响应)
- Action(动作,长时间任务)
- Parameter(参数服务)
- Lifecycle(生命周期节点通信)
- DDS(底层通信机制)
本文将针对Topic(话题)进行简要讲解与使用教学
1 Topic 介绍
Topic(话题)即 “发布-订阅” 模型,是ROS2中一个最常用的信息传输方法。运用此方法时,通常会有一个节点进行信息的发布,单个或多个节点进行信息的订阅。
通俗的来讲,Topic方法就是通过“广播”的方式将信息分发出去的。发布节点作为信号塔,订阅节点作为收音机。单向的接收信息。
在实际的使用场景中,通常被运用在连续数据流的传输中。例如:摄像头的帧数据获取、传感器的数据读取......
2 Topic 使用方法
2.1 Python 版本
2.1.1 创建包(pkg)
通过下述代码在工作区内创建节点,
ros2 pkg create --build-type ament_python "your_node_name" --dependencies rclpy
--build-type: 构建类型参数,选择 ament_python 构建Python包--dependencies: 依赖, rclpy、std_msgs等
2.1.2 创建节点(Node)
在包对应文件夹中创建新的.py,如下图中的listener.py。
2.1.3 发布话题(Publisher)
创建 talker.py:
import rclpy # ROS2 Python接口库
from rclpy.node import Node # ROS2节点基类
from std_msgs.msg import String # 导入字符串消息类型
class Talker(Node):
def __init__(self):
super().__init__('talker') # 初始化节点,节点名为 talker
# 创建发布者(Publisher)
self.publisher_ = self.create_publisher(
String, # 消息类型
'chatter', # 话题名称
10 # 队列长度(QoS队列深度)
)
# 创建定时器,每 0.5 秒触发一次回调函数
self.timer = self.create_timer(
0.5, # 时间间隔(秒)
self.timer_callback # 回调函数
)
self.count = 0 # 计数器,用于生成消息内容
def timer_callback(self):
msg = String() # 创建消息对象
msg.data = f'Hello ROS2 {self.count}' # 填充消息内容
self.publisher_.publish(msg) # 发布消息
# 在终端打印日志(调试很重要)
self.get_logger().info(f'Publishing: "{msg.data}"')
self.count += 1 # 计数递增
def main(args=None):
rclpy.init(args=args) # 初始化 ROS2 Python通信
node = Talker() # 创建节点对象
rclpy.spin(node) # 保持节点运行(循环等待回调)
node.destroy_node() # 销毁节点(释放资源)
rclpy.shutdown() # 关闭 ROS2
2.1.4 订阅话题(Subscriber)
创建 listener.py:
import rclpy # ROS2 Python接口
from rclpy.node import Node # 节点基类
from std_msgs.msg import String # 字符串消息类型
class Listener(Node):
def __init__(self, name):
super().__init__(name) # 初始化节点,节点名由外部传入
# 创建订阅者(Subscriber)
self.sub = self.create_subscription(
String, # 消息类型(必须与发布者一致)
"chatter", # 订阅的话题名称
self.listener_callback, # 收到消息时触发的回调函数
10 # 队列长度(QoS)
)
def listener_callback(self, msg):
# msg 是接收到的消息对象
self.get_logger().info(f'I heard: "{msg.data}"')
def main(args=None):
rclpy.init(args=args) # 初始化 ROS2
node = Listener("topic_helloworld_sub") # 创建订阅节点
rclpy.spin(node) # 持续监听话题
node.destroy_node() # 销毁节点
rclpy.shutdown() # 关闭 ROS2
2.1.5 运行
将节点加入setup.py,colcon build 并setup后就可以打开终端运行两个节点了。可以观察到终端中发送和接收的效果。
2.2 C++ 版本
相比 Python,C++ 版本基于 rclcpp 实现,适用于对性能要求更高的场景(如机器人控制、实时系统等)。
2.2.1 创建包(pkg)
使用如下命令创建 C++ 功能包:
ros2 pkg create --build-type ament_cmake your_cpp_pkg --dependencies rclcpp std_msgs
--build-type:选择ament_cmake(C++构建方式)--dependencies:依赖项(rclcpp、std_msgs)
2.2.2 创建节点(Node)
在 src/ 目录下创建 .cpp 文件,例如:
src/talker.cpp
src/listener.cpp
2.2.3 发布话题(Publisher)
创建 talker.cpp:
#include <chrono>
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using namespace std::chrono_literals;
class Talker : public rclcpp::Node
{
public:
Talker() : Node("talker_cpp")
{
// 创建发布者
publisher_ = this->create_publisher<std_msgs::msg::String>("chatter", 10);
// 创建定时器,每0.5秒发送一次
timer_ = this->create_wall_timer(
500ms, std::bind(&Talker::timer_callback, this));
}
private:
void timer_callback()
{
auto msg = std_msgs::msg::String();
msg.data = "Hello ROS2 C++";
// 打印日志
RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", msg.data.c_str());
// 发布消息
publisher_->publish(msg);
}
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv); // 初始化ROS2
rclcpp::spin(std::make_shared<Talker>()); // 运行节点
rclcpp::shutdown(); // 关闭ROS2
return 0;
}
2.2.4 订阅话题(Subscriber)
创建 listener.cpp:
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
class Listener : public rclcpp::Node
{
public:
Listener() : Node("listener_cpp")
{
// 创建订阅者
subscription_ = this->create_subscription<std_msgs::msg::String>(
"chatter",
10,
std::bind(&Listener::topic_callback, this, std::placeholders::_1)
);
}
private:
void topic_callback(const std_msgs::msg::String::SharedPtr msg) const
{
// 接收到消息后打印
RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg->data.c_str());
}
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv); // 初始化ROS2
rclcpp::spin(std::make_shared<Listener>()); // 运行节点
rclcpp::shutdown(); // 关闭ROS2
return 0;
}
2.2.5 修改 CMakeLists.txt
在 CMakeLists.txt 中添加:
add_executable(talker src/talker.cpp)
add_executable(listener src/listener.cpp)
ament_target_dependencies(talker rclcpp std_msgs)
ament_target_dependencies(listener rclcpp std_msgs)
install(TARGETS
talker
listener
DESTINATION lib/${PROJECT_NAME}
)
2.2.6 编译与运行
colcon build
source install/setup.bash
运行:
ros2 run your_cpp_pkg talker
ros2 run your_cpp_pkg listener