ROS的主要通讯方式:Topic话题与Message消息
- 话题Topic是节点间进行持续通讯(qq群聊刷屏)的一种形式。
- 话题通讯的两个节点通过话题的名称(群聊名称)建立起话题通讯连接。
- 话题中通讯的数据,叫做消息Message。
- 消息Message通常会按照一定的频率持续不断的发送,以保证消息数据的实时性。
- 消息发送方 - Publisher。
- 消息接受方 - Subsciber。
如果有多个消息发布者,可以建立多个Topic。让一个Topic连接一个Pulisher和一个Subsciber。
Subsciber和谁通讯就订阅谁的话题Topic。
但是也可以在一个话题里有多个发布者,但需要一些必要机制,控制发言顺序,同一时刻只能有一个发言的节点。
外延补充: - 一个ROS节点网络中,可以同时存在多个话题。
- 一个话题可以有多个发布者,也可以有多个订阅者。
- 一个节点可以对多个话题进行订阅,也可以发布多个话题。
- 不同的传感器消息通常会拥有各自独立话题名称,每个话题只有一个发布者。
- 机器人速度指令话题通常会有多个发布者,但是同一时刻只能有一个发言人。
消息Message
不同的消息可能携带不同的数据类型。所以发布消息时要指定消息的类型。
标准消息类型包 - std_msgs
.里面包含常用的消息类型。
C++创建Publisher发布者节点
- 确定话题名称和消息类型。
std_msgs
.里面包含常用的消息类型。 - 在代码文件中
include
消息类型对应的头文件,如String
类型。
#include <std_msgs/String.h>
- 在main函数中通过NodeHandle大管家(节点句柄)发布一个话题并得到消息发送对象。
ros::NodeHandle nh;
ros::Publisher pub = nh.advertise<std_msgs::String>("kuai_shang_che_kai_hei_qun",10); //发布话题
std_msgs::String
- 确定消息类型
10
- 缓存长度
4. 生成要发送的消息包并进行发送数据的赋值。
std_msgs::String msg;//生成要发送的消息包
msg.data = "国服马超,带飞";//给要发送的消息赋值
- 调用消息发送对象的
publish()
函数将消息包发送到话题当中。
pub.publish(msg);//发布消息
终端常用指令:
rostopic list 查看活跃话题的列表
rostopic hz /主题名称
查看话题的消息发布评论
rostopic echo /主题名称
统计指定话题中的消息包发送频率
###C++创建订阅者节点
- include 两个需要的头文件
#include <ros/ros.h>
#include <std_msgs/String.h>
- main函数中初始化节点
int main(int argc, char *argv[])
{
ros::init(argc, argv, "ma_node")
return 0;
}
3.获取节点句柄NodeHandle,命名为nh
。
ros::NodeHandle nh;
4.创建一个消息接受者,并通过节点句柄订阅一个话题。
ros::Subscriber sub = nh.subscribe("话题名称(用英文)",缓存长度,回调函数)
当消息包队列超过缓存长度时,最前面的消息包就会被丢弃。给多大的数值就表示缓存里可以容纳多少个消息包排队。
因此,在某些情况下需要根据订阅者的处理周期以及发布者的消息发布频率来计算。
订阅者消息队列用来缓存节点内所有订阅的消息,并在消息处理函数ros::spinOnce()
被调用时串行调用对应的回调函数。
回调函数,用来接受消息包,可以理解为对消息包到来的一个响应。类似于单片机里的中断函数。
5. 创建一个回调函数来接受消息
void chao_callback(std_msgs::String msg)
{
ROS_INFO(msg.data.c_str());
}
相对于printf,ROS_INFO函数可以打印出来更多的信息,比如时间戳等。
当要注意的是,ROS_INFO函数的参数是const char*,而msg.data是std::string类型,所以需要用c_str()函数将std::string类型转换为const char*类型。
ROS_INFO()的编码方式会受程序Locale的环境设置影响,一般C语言程序默认是一个叫C的Locale设置,使一些输出函数只支持英文字符的显示。因此如果程序的Locale不是中文的(默认和系统的语言环境保持一致),需要设置为中文。
在main函数中调用setlocale()
函数。
setlocale(LC_ALL,"zh_CN.UTF-8")
// LC_ALL表示把所有的环境参数都设置成新的模式。第二个参数如果输出函数和系统语言环境一致,则直接“”,如果不一致,是英文版的系统,则填入 “zh_CN.UTF-8”
- 在main函数中写一个while循环,来保证订阅节点一直运行。
while(ros::ok)
{
ros::spinOnce();
}
ros::spinOnce()的作用是不断查看回调函数是否有新的消息包传进来。
在启动发布节点和订阅节点后,如果有多个发布和订阅节点,他们之间的关系很乱,可以通过终端输入
rqt_graph
来查看节点之间错综复杂的关系。
如图
问题:话题是谁的话题
话题并不属于发布者也不属于订阅者,而是由ROS系统创建管理的。
只要节点向NodeHandle提出了话题发布需求或订阅需求,话题就会自动被创建。
“该特性有助于帮助我们阅读别人的ROS源码包,通过系统中活跃的话题和其他ROS工具可以清楚各个节点之间的关系”
学海无涯,学习过程中应该明白,不是掌握多少知识,而是通过少量的知识如何实现目标,Fighting!