用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/MIUAV/vibe-coding-ros2 --skill ros2-topic-communication命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | ros2-topic-communication |
| description | ROS2 Topic 通讯技能 - 发布者/订阅者实现、QoS 策略、数据同步与过滤 |
| user-invocable | true |
| argument-hint | 创建 topic OR ros2 topic OR 发布订阅 OR publisher subscriber |
ROS2 Topic 发布/订阅通讯完整指南
当需要以下帮助时使用此技能:
Publisher (发布者) ──[Topic]──> Subscriber (订阅者)
│ │
└──> msg type └──> msg type
└──> QoS policy └──> QoS policy
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/string.hpp>
class PublisherNode : public rclcpp::Node {
public:
PublisherNode() : Node("publisher_node") {
// 创建发布者
publisher_ = this->create_publisher<std_msgs::msg::String>("chatter", 10);
// 定时发布
timer_ = this->create_wall_timer(1s, [this]() {
auto msg = std_msgs::msg::String();
msg.data = "Hello, ROS2!";
publisher_->publish(msg);
});
}
private:
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
rclcpp::TimerBase::SharedPtr timer_;
};
class SubscriberNode : public rclcpp::Node {
public:
SubscriberNode() : Node("subscriber_node") {
subscription_ = this->create_subscription<std_msgs::msg::String>(
"chatter",
10,
[this](const std_msgs::msg::String::SharedPtr msg) {
RCLCPP_INFO(this->get_logger(), "Received: %s", msg->data.c_str());
});
}
private:
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class PublisherNode(Node):
def __init__(self):
super().__init__('publisher_node')
self.publisher = self.create_publisher(String, 'chatter', 10)
self.timer = self.create_timer(1.0, self.timer_callback)
def timer_callback(self):
msg = String()
msg.data = 'Hello, ROS2!'
self.publisher.publish(msg)
class SubscriberNode(Node):
def __init__(self):
super().__init__('subscriber_node')
self.subscription = self.create_subscription(
String, 'chatter', self.listener_callback, 10)
def listener_callback(self, msg):
self.get_logger().info(f'Received: {msg.data}')
| 策略 | 选项 | 说明 |
|---|---|---|
| History | KEEP_LAST, KEEP_ALL | 保留历史消息数量 |
| Depth | 队列大小 | 配合 KEEP_LAST 使用 |
| Reliability | RELIABLE, BEST_EFFORT | 可靠传输 vs 尽力而为 |
| Durability | TRANSIENT_LOCAL, VOLATILE | 持久性 |
| Deadline | 时间间隔 | 预期发布频率 |
| Liveliness | AUTOMATIC, MANUAL | 节点存活检测 |
| Priority | 优先级 | 消息优先级 |
rclcpp::QoS sensor_qos(10);
sensor_qos.best_effort()
.durability_volatile()
.deadline(rclcpp::Duration(0.1));
rclcpp::QoS cmd_qos(10);
cmd_qos.reliable()
.durability_volatile();
rclcpp::QoS state_qos(10);
state_qos.reliable()
.transient_local()
.keep_last(5);
// 创建独立回调组
auto callback_group = this->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
// 在回调组中创建订阅
auto sub_options = rclcpp::SubscriptionOptions();
sub_options.callback_group = callback_group;
subscription_ = this->create_subscription<...>(
"topic", qos, callback, sub_options);
class TimestampFilter : public rclcpp::Node {
public:
TimestampFilter() : Node("timestamp_filter") {
sub_ = this->create_subscription<sensor_msgs::msg::Image>(
"/camera/image_raw", 10,
[this](const sensor_msgs::msg::Image::SharedPtr msg) {
auto now = this->now();
auto msg_time = rclcpp::Time(msg->header.stamp);
if ((now - msg_time).seconds() < 1.0) {
// 消息足够新
process_image(msg);
}
});
}
};
// 订阅多个主题,使用同一个回调
std::vector<std::string> topics = {"/camera/left", "/camera/right"};
for (const auto& topic : topics) {
subs_.push_back(this->create_subscription<sensor_msgs::msg::Image>(
topic, 10,
[this](const sensor_msgs::msg::Image::SharedPtr msg) {
process_image(msg);
}));
}
#include <message_filters/subscriber.h>
#include <message_filters/synchronizer.h>
#include <message_filters近似时间同步器.h>
using namespace message_filters;
class SyncedNode : public rclcpp::Node {
public:
SyncedNode() : Node("synced_node") {
sub1_.subscribe(this, "/camera/image");
sub2_.subscribe(this, "/depth/image");
sync_ = std::make_shared<Synchronizer<SyncPolicy>>(
SyncPolicy(10), sub1_, sub2_);
sync_->registerCallback(&SyncedNode::sync_callback, this);
}
void sync_callback(const sensor_msgs::msg::Image::SharedPtr img,
const sensor_msgs::msg::Image::SharedPtr depth) {
// 同时处理两个话题的数据
}
private:
Subscriber<sensor_msgs::msg::Image> sub1_, sub2_;
std::shared_ptr<Synchronizer<SyncPolicy>> sync_;
};
from message_filters import Subscriber, ApproximateTimeSynchronizer
class SyncedNode(Node):
def __init__(self):
super().__init__('synced_node')
self.img_sub = Subscriber(self, Image, '/camera/image')
self.depth_sub = Subscriber(self, Image, '/depth/image')
self.sync = ApproximateTimeSynchronizer(
[self.img_sub, self.depth_sub], queue_size=10, slop=0.1)
self.sync.registerCallback(self.sync_callback)
def sync_callback(self, img, depth):
self.get_logger().info('Synced!')
# 列出所有话题
ros2 topic list
# 查看话题类型
ros2 topic type /scan
# 查看发布/订阅信息
ros2 topic info /scan
# 查看实时频率
ros2 topic hz /scan
# 查看带宽
ros2 topic bw /scan
# 查看数据
ros2 topic echo /scan
# 查看消息定义
ros2 interface show sensor_msgs/msg/LaserScan
# 发布字符串
ros2 topic pub /chatter std_msgs/msg/String "data: 'test'" -1
# 发布激光扫描
ros2 topic pub /scan sensor_msgs/msg/LaserScan "{header: {stamp: {sec: 0}, frame_id: 'laser'}, angle_min: -3.14, angle_max: 3.14, angle_increment: 0.01, time_increment: 0.0, scan_time: 0.1, range_min: 0.1, range_max: 30.0, ranges: [1.0, 2.0]}"
# 持续发布
ros2 topic pub /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.5}}" -r 10
# 检查节点连接
ros2 node info /node_name
# 启动 rqt_graph 可视化
ros2 run rqt_graph rqt_graph
# 查看详细信息
ros2 run rqt_graph rqt_graph --args -t
/robot/arm/joint_states