ROS话题中的发布和订阅

1.创建Publisher

Publisher的主要作用是针对制定话题发布特定数据类型的消息。我们用代码实现一个节点,并且在节点中创建一个Publisher并发布字符串“Hello World”,代码如下:

#include <sstream>
#include "ros/ros.h"
#include "std_msgs/String.h"

int main(int argc, char **argv)
{
     //ROS节点初始化
ros::init(argc,argv,"talker");

     //创建节点句柄
ros::NodeHandle n;

     //创建一个Publisher,发布名为chatter的topic,消息类型为std_msgs::String
ros::Publisher chatter_pub =n.advertise<std_msgs::String>("chatter",1000);

      //设置循环的频率
ros::Rate loop_rate(10);

int count = 0;

while (ros::ok())
{
     // 初始化std_msgs::String类型的消息
      std_msgs::String msg;
      std::stringstream ss;
      ss <<"hello world" << count;
      msg.data = ss.str();
  
    //发布消息
      ROS_INFO("%s",msg.data.c_str());
      chatter_pub.publish(msg);
      

      //循环等待回调函数
      ros::spinOnce();

      //按照循环频率延时
       loop_rate.sleep();
       ++count;
}
return 0;
}

2.创建Subscriber

下面创建一个Subscriber以订阅Publisher节点发布的“Hello World”字符串,实现代码如下:

#include "ros/ros.h"
#include "std_msgs/String.h"

 //接收到订阅的消息后,会进入消息回调函数

void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
         //将接收到的信息打印出来
        ROS_INFO("I heard: [%s]",msg->data.c_str());
}

int main (int argc, char **argv)
{
        //初始化ROS节点

       ros::init(argc,argv,"listener");
     
       //创建节点句柄
       ros::NodeHandle n;

   //创建一个Subscriber,订阅名为chatter的话题,注册回调函数chatterCallback

    ros::Subscriber sub=n.subscribe("chatter",1000,chatterCallback);
    
     //循环等待回调函数
   
     ros::spin();

      return 0;
}

3.编译功能包

我们使用C++语言来编写,所以需要使用CMaker编译器进行编译,编译规则通过功能包中的CMakerLists.txt文件设置,使用catkin命令创建,我们需要对部分内容进行更改;

打开功能包中的CMakerLists.txt文件,找到以下配置项,去掉注释并稍作修改:

## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
# include
  ${catkin_INCLUDE_DIRS}
)
##add_executable(hello ~/Alltest/catkin_ws/src/learning_communication/src/hello.cpp)

add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker ${PROJECT_NAME}_generate_messages_cpp)

add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener ${PROJECT_NAME}_generate_messages_cpp)

4.运行PublisherSubscriber

在工作空间根目录设置环境变量并编译:

source devel/setup.bash
catkin_make

a.启动ROS Master

roscore

b.启动Publisher

source devel/setup.bash
rosrun learning_communication talker

c.启动Subscriber

source devel/setup.bash
rosrun learning_communication listener

这样就运行起来了,效果如下:

 

<think>首先,用户的问题是:“我想在程序中实现ROS话题发布订阅请问如何在代码中添加ROSTopic发布订阅功能”,需要结合提供的引用来回答。引用来自站内引用,包括引用[1]、[2][3]。引用关键点:-引用[1]是概述ROSTopic的基础重要性。-引用[2]具体展示了订阅方的代码实现:`demo02_sub.cpp`,涉及创建订阅者对象处理数据。-引用[2]也提到了发布方的代码:虽然没有显示完整,但在上下文中提到发布订阅。-引用[3]讨论了pluginlib,但不是直接相关。用户的上一次问题我的回答:在系统指令中,有示例关于快速排序,但现在用户的问题是关于ROSTopic的发布订阅。用户没有历史对话记录,所以我要基于当前引用直接回答。系统级指令:-所有行内数学表达式使用$...$格式。-独立公式用$$...$$单独成段。-LaTeX语法正确。-使用中文回答。-生成相关问题。-回答中引用的段落末尾自然地添加引用标识,如[^1]。-结构清晰,真实可靠。回答结构:1.逐步解释如何在代码中添加ROSTopic发布订阅功能。2.提供代码示例,参考引用[2]。3.在引用的部分添加引用标识。4.最后生成相关问题。从引用[2],我有订阅方的代码:```cpp#include"ros/ros.h"#include"std_msgs/String.h"/*订阅方实现:1、包含头文件ROS中文本类型--->std_msgs/String.h2、初始化ROS节点3、创建节点句柄4、创建订阅者对象5、处理订阅到的数据*/voiddoMsg(conststd_msgs::String::ConstPtr&msg){//通过msg获取并操作订阅到的数据ROS_INFO("翠花订阅到的数据:%s",msg->data.c_str());}intmain(intargc,char*argv[]){setlocale(LC_ALL,"");//初始化ROS节点(节点不能重名,不然把别的节点给干掉了,要具有唯一性)ros::init(argc,argv,"cuiHua");//创建节点句柄ros::NodeHandlenh;//创建订阅者对象ros::Subscribersub=nh.subscribe("fang",10,doMsg);//处理订阅到的数据//循环ros::spin();return0;}```我需要补充发布方的代码。引用中没有直接给出发布方的完整代码,但引用[1]提到了发布订阅。所以我可以基于标准ROS知识添加。标准ROS发布订阅:-发布方:创建一个发布者对象,定期发布消息。-订阅方:创建一个订阅者对象,回调函数处理消息。发布方的典型代码:```cpp#include"ros/ros.h"#include"std_msgs/String.h"intmain(intargc,char**argv){ros::init(argc,argv,"talker");ros::NodeHandlen;ros::Publisherpub=n.advertise<std_msgs::String>("chatter",1000);ros::Rateloop_rate(10);while(ros::ok()){std_msgs::Stringmsg;msg.data="helloworld";pub.publish(msg);ros::spinOnce();loop_rate.sleep();}return0;}```结合引用:-引用[1]强调Topic通信是基础且重要的[^1]。-引用[2]提供订阅方代码[^2]。-引用[3]关于pluginlib,可能不太相关,所以我不直接用。回答步骤:1.解释发布订阅的基本概念。2.展示如何在代码中添加发布功能。3.展示如何在代码中添加订阅功能。4.提供完整的示例代码。5.自然地添加引用标识。6.最后生成相关问题。结构:-开头:解释ROSTopic发布订阅的重要性(引用[1])。-然后:分步骤介绍发布订阅的实现。-代码块:使用单独的代码段展示。-结尾:总结。-生成相关问题。使用中文回答。数学表达式:用户问题中没有数学相关内容,所以可能不需要添加。但指令说所有行内数学表达式必须用$...$,所以如果有变量等,我可以提及但不强制。这里主要是代码,所以可能不涉及数学。生成相关问题:在末尾。最终回答框架:1.介绍ROSTopic发布订阅。2.添加发布功能的步骤代码。3.添加订阅功能的步骤代码。4.完整示例。5.相关问题。</think> ### 如何在程序中添加 ROS Topic 发布订阅功能 在 ROS (Robot Operating System) 中,Topic 是节点间通信的核心机制之一,通过发布/订阅模型实现异步数据传输。掌握如何在代码中添加发布订阅功能对机器人开发至关重要[^1]。下面我将逐步解释实现方法,并基于 ROS1(以 C++ 为例)提供详细代码示例。整个过程包括初始化节点、创建发布订阅者对象、以及处理消息。 --- #### 步骤 1: 理解基本流程 - **发布方 (Publisher)**: 负责向指定 Topic 发送数据。需要创建发布者对象并循环发布消息。 - **订阅方 (Subscriber)**: 负责监听指定 Topic 并处理接收的数据。需创建订阅者对象并定义回调函数。 - **核心元素**: - Topic 名称(如 `"fang"`)用于标识通信通道。 - 消息类型(如 `std_msgs/String`)定义了数据的结构。 - 节点必须唯一,避免冲突。 引用[2] 提供了订阅方的实现基础,我会在此完善发布方的代码[^2]。 --- #### 步骤 2: 添加发布功能 发布方负责生成并发送数据。以下是添加发布功能的步骤代码: 1. **包含头文件**: 引入 ROS 核心库所需消息类型。 2. **初始化节点**: 创建唯一节点名称。 3. **创建发布者对象**: 使用 `NodeHandle::advertise()` 方法指定 Topic 名称队列大小。 4. **循环发布消息**: 在 `ros::ok()` 循环中构造并发送数据。 代码示例 (`publisher_node.cpp`): ```cpp #include "ros/ros.h" #include "std_msgs/String.h" int main(int argc, char **argv) { // 初始化 ROS 节点(节点名称必须唯一) ros::init(argc, argv, "publisher_node"); ros::NodeHandle nh; // 创建发布者对象:Topic 名为 "fang",队列大小 10 ros::Publisher pub = nh.advertise<std_msgs::String>("fang", 10); // 设置发布频率,例如 1 Hz ros::Rate loop_rate(1); int count = 0; while (ros::ok()) { // 构造消息 std_msgs::String msg; msg.data = "Hello, ROS! Count: " + std::to_string(count); // 发布消息 pub.publish(msg); ROS_INFO("发布数据: %s", msg.data.c_str()); count++; loop_rate.sleep(); // 按频率等待 } return 0; } ``` - **关键点**: `pub.publish(msg)` 发送消息,`ros::Rate` 控制发布频率。Topic 名称必须与订阅方一致[^2]。 --- #### 步骤 3: 添加订阅功能 订阅方监听 Topic 并在收到数据时触发回调函数。以下是添加订阅功能的步骤代码: 1. **包含头文件**: 与发布方类似。 2. **定义回调函数**: 处理接收到的消息。 3. **创建订阅者对象**: 使用 `NodeHandle::subscribe()` 方法。 4. **循环监听**: `ros::spin()` 或 `ros::spinOnce()` 启动事件循环。 代码示例 (`subscriber_node.cpp`,基于引用[2]调整): ```cpp #include "ros/ros.h" #include "std_msgs/String.h" // 回调函数:处理收到的消息 void messageCallback(const std_msgs::String::ConstPtr &msg) { ROS_INFO("订阅到的数据: %s", msg->data.c_str()); // 可添加自定义处理逻辑,例如解析数据 } int main(int argc, char **argv) { // 初始化 ROS 节点(节点名称必须唯一) setlocale(LC_ALL, ""); // 支持中文输出 ros::init(argc, argv, "subscriber_node"); ros::NodeHandle nh; // 创建订阅者对象:Topic 名为 "fang",队列大小 10,指定回调函数 ros::Subscriber sub = nh.subscribe("fang", 10, messageCallback); // 开始监听,ros::spin() 阻塞线程直到节点关闭 ros::spin(); return 0; } ``` - **关键点**: 回调函数 `messageCallback` 自动调用,`nh.subscribe()` 绑定 Topic。Topic 名称 `"fang"` 需与发布方匹配[^2]。 --- #### 完整测试流程 1. **编译代码**: - 创建 ROS 包(如 `catkin_create_pkg my_topic roscpp std_msgs`)。 - 将代码放入 `src/` 目录。 - 修改 `CMakeLists.txt` 添加可执行文件并编译:`catkin_make`。 2. **运行节点**: - 启动 ROS Master:`roscore` - 在一个终端运行发布方:`rosrun my_topic publisher_node` - 在另一个终端运行订阅方:`rosrun my_topic subscriber_node` - 订阅方应打印发布的数据,例如: ``` [INFO] [时间戳]: 订阅到的数据: Hello, ROS! Count: 0 ``` 3. **调试提示**: - 使用 `rostopic list` 检查 Topic 是否存在。 - 用 `rostopic echo /fang` 手动查看数据流。 - 确保 Topic 名称一致,节点名称唯一,避免冲突[^1]。 --- #### 注意事项 - **消息类型**: 示例使用 `std_msgs/String`,但你可以自定义消息类型(如创建 `msg/MyMessage.msg` 文件)。 - **线程安全**: `ros::spin()` 用于单线程回调,`ros::MultiThreadedSpinner` 适用高性能场景。 - **性能优化**: 增加队列大小可减少数据丢失,但需平衡资源[^1]。 通过以上步骤,即可在程序中添加 ROS Topic 发布订阅功能。这在 SLAM 导航或传感器数据处理中广泛应用[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值