ROS2 发布/订阅Topic

发布/订阅Topic是ROS2中用于节点间通信的一种机制。在ROS2中,一个节点可以作为发布者(Publisher)发布消息到某个话题(Topic),而其他节点可以作为订阅者(Subscriber)订阅这个话题以接收消息。这种发布/订阅模型允许解耦的通信方式,使得不同节点之间可以灵活地进行数据交换。
这里把发布者和订阅者的简单示例介绍一下,这里会用到rclcpp和std_msgs。

发布者(Publisher)

在我们的工作空间目录下(~/ROSWorkspace),先创建一个topic包,这里先把发布者节点也创建出来,省得自己创建cpp文件,package的创建可参考另一篇文章”ROS2 HelloWorld“。

ros2 pkg create pkg_topic_cpp --build-type ament_cmake --dependencies rclcpp std_msgs --node-name publisher_node_cpp

在publisher_node_cpp.cpp中实现如下代码:

#include <cstdio>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

int main(int argc, char ** argv)
{
 rclcpp::init(argc, argv);//初始化rclcpp
 rclcpp::Node::SharedPtr node = rclcpp::Node::make_shared("my_publisher");//创建节点
 rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher = node->create_publisher<std_msgs::
 msg::String>("my_topic", 10);//创建发布者,发布类型为std_msgs::msg::String,发布topic为my_topic,队列长度为10
 rclcpp::WallRate loop_rate(1);//创建时钟,1Hz
 while (rclcpp::ok()) {
 std_msgs::msg::String msg;
 msg.data = "Hello, world!";//设置消息内容
 publisher->publish(msg);//发布消息  
 RCLCPP_INFO(node->get_logger(), "%s: '%s'", publisher->get_topic_name(), msg.data.c_str());//打印消息
 loop_rate.sleep();//休眠到1s,确保1Hz
 }

 printf("hello world pkg_topic_cpp package end\n");
 return 0;
}

编译指定pkg_topic_cpp:

colcon build --packages-select pkg_topic_cpp

编译完之后先配置一下环境:

. install/setup.sh 

然后运行:

ros2 run pkg_topic_cpp publisher_node_cpp

可以看到每秒打印一次
在这里插入图片描述
这个是我们自己使用RCLCPP_INFO打印出来的,如果想看是不是真的发布出去了可以创建新的node订阅该topic,这个后文再介绍,我们可以用ros2命令行订阅my_topic测试一下,在新的终端一下命令:

ros2 topic echo /my_topic

在这里插入图片描述
看到上面的这个打印就说my_topic明确实发布出来了,这也说明我们写的Publisher代码是有效的。
接下来实现我们自己的Subscriber。

订阅者(Subscriber)

在<工作空间>/pkg_topic_cpp/src/目录下创建subscriber_node_cpp.cpp,然后实现如下代码:

#include <cstdio>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

// Subscription回调函数
void mySubCallback(const std_msgs::msg::String::SharedPtr msg) {
 RCLCPP_INFO(rclcpp::get_logger("my_subscriber"), "/my_topic: I heard: %s", msg->data.c_str());
}

int main(int argc, char const *argv[])
{
 rclcpp::init(argc, argv);//初始化rclcpp
 rclcpp::Node::SharedPtr node = rclcpp::Node::make_shared("my_subscriber");//创建节点
 rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription = node->create_subscription<std_msgs::
 msg::String>("my_topic", 10, mySubCallback);//创建订阅者,第一个参数为topic名称,第二个参数为队列大小,第三个参数为回调函数
 
 rclcpp::spin(node);//进入消息循环
 rclcpp::shutdown();//关闭节点

 printf("hello world pkg_topic_cpp subsriber_node_cpp end\n");
 return 0;
}

在编译前,我们需要先将subscriber_node_cpp节点添加到CMakeLists里面去,在CMakeLists中添加如下内容:

add_executable(subscriber_node_cpp src/subscriber_node_cpp.cpp)
target_include_directories(subscriber_node_cpp PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)
ament_target_dependencies(
  subscriber_node_cpp
 "rclcpp"
)

install(TARGETS subscriber_node_cpp
  DESTINATION lib/${PROJECT_NAME})

我们在新的终端打开工作空间(~/ROSWorkspace),重新编译pkg_topic_cpp:

colcon build --packages-select pkg_topic_cpp

编译完之后先配置一下环境:

. install/setup.sh 

然后运行:

ros2 run pkg_topic_cpp subscriber_node_cpp

在这里插入图片描述
看到上面的这个打印就说明我们成功的订阅了my_topic,这也就说明我们的Subscriber正确的实现了。

### ROS2 中消息发布的实现 在 ROS2 的架构下,消息的发布订阅是一个核心功能。通过定义 `Publisher` 和 `Subscriber` 节点,可以实现在不同节点之间传递数据的功能。 以下是基于 Python 实现的一个简单示例代码: #### 示例代码:发布者 (Publisher) ```python import rclpy from rclpy.node import Node from std_msgs.msg import String class MinimalPublisher(Node): def __init__(self): super().__init__('minimal_publisher') self.publisher_ = self.create_publisher(String, 'topic', 10) timer_period = 0.5 # seconds self.timer = self.create_timer(timer_period, self.timer_callback) self.i = 0 def timer_callback(self): msg = String() msg.data = f'Hello World: {self.i}' self.publisher_.publish(msg) self.get_logger().info(f'Publishing: "{msg.data}"') self.i += 1 def main(args=None): rclpy.init(args=args) minimal_publisher = MinimalPublisher() rclpy.spin(minimal_publisher) minimal_publisher.destroy_node() rclpy.shutdown() if __name__ == '__main__': main() ``` 这段代码创建了一个名为 `minimal_publisher` 的节点,并向主题 `topic` 发布字符串消息[^1]。 --- ### 订阅者的实现 下面是一段用于接收上述发布者所发送消息的订阅者代码: #### 示例代码:订阅者 (Subscriber) ```python 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, 'topic', self.listener_callback, 10) self.subscription # prevent unused variable warning def listener_callback(self, msg): self.get_logger().info('I heard: "%s"' % msg.data) def main(args=None): rclpy.init(args=args) minimal_subscriber = MinimalSubscriber() rclpy.spin(minimal_subscriber) minimal_subscriber.destroy_node() rclpy.shutdown() if __name__ == '__main__': main() ``` 此代码片段实现了对主题 `topic` 上的消息监听并打印接收到的内容[^2]。 --- ### 关键概念解析 - **发布者 (`Publisher`)** - 定义了要发布到的主题名称以及该主题的数据类型。 - 使用 `create_publisher()` 方法来初始化发布器对象。 - **订阅者 (`Subscriber`)** - 需要知道它希望订阅哪个主题及其对应的数据类型。 - 利用回调函数处理来自指定主题的新消息。 - **话题名称与类型** - 主题名应唯一标识通信通道;而其关联的消息类型则决定了传输的具体结构化数据形式。 --- ### 运行说明 为了测试以上两个脚本,请按照如下顺序操作: 1. 启动第一个终端运行 Publisher 程序; 2. 打开第二个终端执行 Subscriber 应用程序; 3. 查看日志输出确认双方交互正常工作。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值