目录
要求:编写发布订阅实现,要求发布方以10HZ(每秒10次)的频率发布文本消息,订阅方订阅消息并将消息内容打印输出
1.在功能包下的src文件夹下新建文件,分别命名为:hello_pub.cpp及hello_sub.cpp
2.hello_pub.cpp为发布者,循环发布信息:HelloWorld 后缀数字编号
6.编辑配置文件:编辑 ros 包下的 CamkeLists.txt 文件
8.通过实验我们可以观察到,hello_pub成功的发送了信息而hello_sub也成功地接收到了信息。
ROS中基本的通信机制:
1.话题通信(发布订阅模式)
2.服务通信(请求响应模式)
3.参数服务器(参数共享模式)
4.动作通信(话题和服务的配合)
一、话题通信:
1.话题通信定义与基本概念
话题通信是ROS(Robot Operating System,机器人操作系统)中使用频率最高的一种通信模式,话题通信是基于发布与订阅模式的通信方式,其中一个节点(发布者)发布消息,而另一个或多个节点(订阅者)订阅并接收这些消息。发布者和订阅者通过共同的话题(Topic)建立联系,实现数据的传输与交流。话题通信的应用场景也极其广泛,像雷达、摄像头、GPS.... 等等一些传感器数据的采集,也都是使用了话题通信,换言之,话题通信适用于不断更新的数据传输相关的应用场景。
2.核心要素
发布方(Talker):负责发布消息的节点,它将数据发布到特定的话题上。
订阅方(Listener):负责订阅并接收来自特定话题的消息的节点。
话题(Topic):发布方和订阅方之间建立联系的桥梁,是数据传输的通道。
3.工作流程
话题通信的工作流程通常包括以下几个步骤:
-
发布者注册:发布者启动后,会在ROS Master(管理者)中注册自身信息,包括所发布消息的话题名称和远端调用地址(RPC)。ROS Master会将节点的注册信息加入到注册表中。
-
订阅者注册:订阅者也会通过RPC在 ROS Master 中注册自身信息自己的话题。
-
匹配与连接:ROS Master会将订阅者与发布者的话题进行对比,发现有匹配的两者时,会把发布者的RPC地址发送给订阅者。订阅者根据RPC地址远程访问发布者,获取发布者的TCP地址,并建立连接。
-
消息发布与接收:建立连接后,发布者可以发布消息,这些消息会被订阅者接收并处理。
-
Listener向Talker发送请求:Listener 根据接收到的 RPC 地址,通过 RPC 向 Talker 发送连接请求,传输订阅的话题名称、消息类型以及通信协议(TCP/UDP)。
-
Talker确认请求:Talker 接收到 Listener 的请求后,也是通过 RPC 向 Listener 确认连接信息,并发送自身的 TCP 地址信息。
-
Listener与Talker件里连接:Listener 根据步骤6返回的消息使用 TCP 与 Talker 建立网络连接。
-
Talker向Listener发送消息:连接建立后,Talker 开始向 Listener 发布消息。
4.消息接口与数据类型
在ROS中,话题通信的消息接口和数据类型具有多样性。ROS2通过std_msgs包封装了一些原生的数据类型,如String、Int8、Int16等,这些数据类型可以作为话题通信的载体。此外,ROS2还预定义了许多标准话题消息接口,如sensor_msgs包中定义了关于传感器消息的接口,geometry_msgs包中定义了关于几何消息相关的接口。当这些预定义的消息接口无法满足需求时,用户还可以自定义接口消息。
二、vscode实现话题通信
按照之前的教程,直接打开test02_ws的vscode
cd test02_ws
code .
三、C++实现话题通信
要求:编写发布订阅实现,要求发布方以10HZ(每秒10次)的频率发布文本消息,订阅方订阅消息并将消息内容打印输出
1.在功能包下的src文件夹下新建文件,分别命名为:hello_pub.cpp及hello_sub.cpp
2.hello_pub.cpp为发布者,循环发布信息:HelloWorld 后缀数字编号
3. 实现流程:
发布者:
(1)包含头文件
(2)初始化 ROS 节点:命名(唯一)
(3)实例化 ROS 句柄
(4)实例化 发布者 对象
(5)组织被发布的数据,并编写逻辑发布数据
订阅者:
(1)包含头文件
(2)初始化 ROS 节点:命名(唯一)
(3)实例化 ROS 句柄
(4)实例化 订阅者 对象
(5)处理订阅的消息(回调函数)
(6)设置循环调用回调函数
4.发布者代码:
#include "ros/ros.h" // 引入ROS的核心头文件
#include "std_msgs/String.h" // 引入标准消息类型中的字符串消息
#include <sstream> // 引入字符串流库,用于字符串拼接
int main(int argc, char *argv[])
{
// 设置程序的本地化环境,确保能够正确处理各种字符编码
setlocale(LC_ALL,"");
// 初始化ROS节点
// 参数1和参数2通常用于从命令行接收参数,这里暂时未使用
// 参数3是节点的名称,需要保证在ROS网络中唯一
ros::init(argc,argv,"talker");
// 实例化ROS节点句柄,用于与ROS系统通信
ros::NodeHandle nh;
// 创建一个发布者对象
// 泛型参数指定了发布的消息类型(std_msgs::String)
// 第一个参数指定了要发布到的话题名称("chatter")
// 第二个参数指定了消息队列的最大长度(10),超出此长度时,旧的消息会被丢弃
ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",10);
// 准备要发布的消息数据
std_msgs::String msg;
std::string msg_front = "Hello 你好!"; // 消息的前缀部分
int count = 0; // 用于计数,每次发布的消息都会附带一个递增的数字
// 设置发布频率(1Hz,即每秒发布一次)
ros::Rate r(1);
// 主循环,保持节点运行
while (ros::ok())
{
// 使用字符串流拼接前缀和计数器值,生成新的消息内容
std::stringstream ss;
ss << msg_front << count;
msg.data = ss.str(); // 将拼接后的字符串赋值给消息的数据部分
// 发布消息到指定的话题
pub.publish(msg);
// 打印调试信息,显示发送的消息内容
ROS_INFO("发送的消息:%s",msg.data.c_str());
// 根据设置的频率休眠,确保发布频率准确
r.sleep();
// 计数器自增,为下一次发布准备
count++;
// 调用ros::spinOnce()可以在循环中处理回调函数,虽然在这个简单示例中没有用到回调
ros::spinOnce();
}
// 程序结束
return 0;
}
5.订阅者代码:
#include "ros/ros.h"
#include "std_msgs/String.h"
void doMsg(const std_msgs::String::ConstPtr& msg_p){
ROS_INFO("我听见:%s",msg_p->data.c_str());
// ROS_INFO("我听见:%s",(*msg_p).data.c_str());
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
//2.初始化 ROS 节点:命名(唯一)
ros::init(argc,argv,"listener");
//3.实例化 ROS 句柄
ros::NodeHandle nh;
//4.实例化 订阅者 对象
ros::Subscriber sub = nh.subscribe<std_msgs::String>("chatter",10,doMsg);
//5.处理订阅的消息(回调函数)
// 6.设置循环调用回调函数
ros::spin();//循环读取接收的数据,并调用回调函数处理
return 0;
}
6.编辑配置文件:编辑 ros 包下的 CamkeLists.txt 文件
add_executable(hello_pub src/hello_pub.cpp)
add_executable(hello_sub src/hello_sub.cpp)
target_link_libraries(hello_pub
${catkin_LIBRARIES}
)
target_link_libraries(hello_sub
${catkin_LIBRARIES}
)
7.编译并执行
ctrl+shift+B编译,新建终端键入
roscore
新建终端
source ./devel/setup.bash
rosrun helloworld hello_pub
再新建一个终端,输入:
source ./devel/setup.bash
rosrun helloworld hello_sub
8.通过实验我们可以观察到,hello_pub成功的发送了信息而hello_sub也成功地接收到了信息。
通过更多的实验可以验证:
先启动roscore, 然后启动发布节点,然后启动订阅节点
可以发现,发布者正常发布信息,订阅者正常接收信息
先启动roscore, 然后启动订阅节点,然后启动发布节点
根据实验可知,订阅者没有信息,发布者启动后有发布信息,再观察订阅者可以接收到信息
先启动发布节点,然后启动订阅节点,然后启动roscore
根据实验观察,没有启动roscore时,启动发布者和订阅者都报错,最后启动roscore也能正常发送消息和接受消息。
正常启动后,关闭roscore终端,观察程序是否正常执行
可以观察到正常启动后,已经在发布者和订阅者之间建立了通信通道,关闭roscore对已经建立的话题通信没有影响。
另启终端,可以使用 rqt_graph 查看节点关系。
标签:订阅,VScode,话题,C++,消息,发布者,ROS,hello From: https://blog.csdn.net/m0_68608816/article/details/143063500