在 ROS 2 中,话题(Topic) 是节点之间异步通信的核心机制。它采用 发布/订阅(Publish/Subscribe)模型:
.msg
文件定义。举例说明:
想象一个电台广播,发布者相当于电台节目主持人,订阅者相当于收听节目的听众,而“话题”就是广播的频道频率。
flowchart LR
A[Publisher 节点] -->|发布消息| B[(Topic 话题)]
B -->|订阅消息| C[Subscriber 节点1]
B -->|订阅消息| D[Subscriber 节点2]
解释:
ROS 2 提供一系列命令用于查看、调试话题:
ros2 topic list
ros2 topic type /话题名
ros2 topic echo /话题名
ros2 topic pub /话题名 消息类型 "{字段: 值}"
示例:
ros2 topic pub /chatter std_msgs/msg/String "{data: 'Hello ROS2'}"
此节点会每隔 0.5 秒发布一条消息到 chatter
话题。
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class MinimalPublisher(Node):
def __init__(self):
super().__init__('minimal_publisher')
# 创建发布者,话题名为 "chatter",消息类型为 String
self.publisher_ = self.create_publisher(String, 'chatter', 10)
# 定时器:每 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 (Python): {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)
node = MinimalPublisher()
rclpy.spin(node) # 循环运行节点
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
此节点会订阅 chatter
话题并打印接收到的消息。
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class MinimalSubscriber(Node):
def __init__(self):
super().__init__('minimal_subscriber')
self.subscription = self.create_subscription(
String,
'chatter',
self.listener_callback,
10)
def listener_callback(self, msg):
self.get_logger().info(f'I heard: "{msg.data}"')
def main(args=None):
rclpy.init(args=args)
node = MinimalSubscriber()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
#include
#include
#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("chatter", 10);
// 每 500 毫秒触发一次回调
timer_ = this->create_wall_timer(
500ms, std::bind(&MinimalPublisher::timer_callback, this));
}
private:
void timer_callback()
{
auto message = std_msgs::msg::String();
message.data = "Hello ROS2 (C++): " + std::to_string(count_++);
RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
publisher_->publish(message);
}
rclcpp::Publisher::SharedPtr publisher_;
rclcpp::TimerBase::SharedPtr timer_;
size_t count_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared());
rclcpp::shutdown();
return 0;
}
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
class MinimalSubscriber : public rclcpp::Node
{
public:
MinimalSubscriber() : Node("minimal_subscriber")
{
subscription_ = this->create_subscription(
"chatter", 10, std::bind(&MinimalSubscriber::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::SharedPtr subscription_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared());
rclcpp::shutdown();
return 0;
}
ros2_ws/
└── src/
└── topic_demo/
├── CMakeLists.txt
├── package.xml
├── src/
│ ├── publisher.cpp
│ └── subscriber.cpp
└── topic_demo/
├── __init__.py
├── publisher.py
└── subscriber.py
topic_demo
0.0.0
ROS2 Topic Demo
Your Name
Apache-2.0
ament_cmake
rclcpp
rclpy
std_msgs
cmake_minimum_required(VERSION 3.5)
project(topic_demo)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
add_executable(publisher src/publisher.cpp)
ament_target_dependencies(publisher rclcpp std_msgs)
add_executable(subscriber src/subscriber.cpp)
ament_target_dependencies(subscriber rclcpp std_msgs)
install(TARGETS
publisher
subscriber
DESTINATION lib/${PROJECT_NAME})
ament_package()
cd ~/ros2_ws
colcon build
source install/setup.bash
ros2 run topic_demo publisher.py
ros2 run topic_demo subscriber.py
ros2 run topic_demo publisher
ros2 run topic_demo subscriber
查看话题是否存在:
ros2 topic list
查看话题消息:
ros2 topic echo /chatter
确认消息类型:
ros2 topic type /chatter
手动发布调试:
ros2 topic pub /chatter std_msgs/msg/String "{data: 'test'}"