[ROS] Topic话题与Message消息
简介
ros的主要通讯方式
Topic, Message, Publisher 与 Subscriber的关系
小结
- 话题Topic是节点间进行持续通讯的一种形式。
- 话题通讯的两个节点通过话题的名称建立起话题通讯连接。
- 话题中通讯的数据,叫做消息Message。
- 消息Message通常会按照一定的频率持续不断地发送,以保证消息数据的实时性。
- 消息的发送方叫做话题的发布者Publisher。
- 消息的接收方叫做话题的订阅者Subscriber。
- 一个ROS节点网络中,可以同时存在多个话题。
- 一个话题可以有多个发布者,也可以有多个订阅者。
- 一个节点可以对多个话题进行订阅,也可以发布多个话题。
- 不同的传感器消息通常会拥有各自独立话题名称,每个话题只有一个发布者。
- 机器人速度指令话题通常会有多个发布者,但是同一个时间只能有一个发言人。
基本的消息类型
std_msgs
一些复杂的数据类型可以类比为c++中的结构体,本质是由基本的数据类型组合而成。
Publisher的实现
代码实现
#include <ros/ros.h>
#include <std_msgs/String.h>
int main(int argc, char *argv[])//去除const
{
ros::init(argc,argv,"chao_node");//初始化
ros::NodeHandle nh;
ros::Publisher pub = nh.advertise<std_msgs::String>("TpName",10);
//定义一个发送消息的工具pub,advertise<填入消息类型>(“话题名称”,消息的缓存长度)
while(ros::ok())
{
printf("好好好好好!\n");
std_msgs::String msg;
msg.data = "哈哈哈哈";
//生成消息包
pub.publish(msg);
}
return 0;
}
- 运行节点
rostopic list
可以查看当前话题rostopic echo /话题名称
可以查看话题内容(message)
由于中文显示为Unicode,使用echo -e "unicode代码"
可以查看中文消息
控制消息发送频率
#include <ros/ros.h>
#include <std_msgs/String.h>
int main(int argc, char *argv[])//去除const
{
ros::init(argc,argv,"chao_node");//初始化
ros::NodeHandle nh;
ros::Publisher pub = nh.advertise<std_msgs::String>("TpName",10);
//定义一个发送消息的工具pub,advertise<填入消息类型>(“话题名称”,消息的缓存长度)
ros::Rate loop_rate(10);//参数单位为“次/秒”
while(ros::ok())
{
printf("好好好好好!\n");
std_msgs::String msg;
msg.data = "哈哈哈哈";
//生成消息包
pub.publish(msg);
loop_rate.sleep();//进行阻塞
}
return 0;
}
使用rostopic hz
命令 即可查看发送频率 如图Rate:10
小结
- 常用指令
rostopic list
列出当前系统中所有活跃着的话题rostopic echo 主题名称
显示制定话题中发送的消息包内容rostopic hz 主题名称
统计指定话题中消息包发送频率
Subscriber的实现
创建订阅者节点
- 创建一个新包,名为"atr_pkg"
- 创建一个新节点,名为"ma_node"
#include <ros/ros.h>
#include <std_msgs/String.h>
void chao_callback(std_msgs::String msg)
{
printf(msg.data.c_str());//printf参数为char*,需要将string转化为字符数组(c_str())
printf("\n");
}// 定义一个回调函数
int main(int argc, char *argv[])
{
ros::init(argc,argv,"ma_node");
ros::NodeHandle nh;
ros::Subscriber sub = nh.subscribe("TpName",10,chao_callback);//(话题名称,缓存长度,回调函数)
while (ros::ok())
{
ros::spinOnce();
}
return 0;
}
运行测试
- 分别运行chao_node与ma_node
调整与优化
#include <ros/ros.h>
#include <std_msgs/String.h>
void chao_callback(std_msgs::String msg)
{
ROS_INFO(msg.data.c_str());//可以显示时间
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"zh_CN.UTF-8");//设置locale为中文
ros::init(argc,argv,"ma_node");
ros::NodeHandle nh;
ros::Subscriber sub = nh.subscribe("TpName",10,chao_callback);
while (ros::ok())
{
ros::spinOnce();
}
return 0;
}
- 通过
rqt_graph
直观展示当前节点关系
注意:ROS话题不单独属于Publisher或者Subscriber,话题由ROS系统统一管理。只要节点向NodeHandle提出话题发布或者订阅需求,话题就会被创建
小结
使用launch文件启动节点
launch文件是一种遵循xml语法的描述文件,批量启动ROS节点是它的功能之一。<标记名称 属性名1="属性值"...>内容</标记名称>
launch文件放在哪都可以
例:
<launch>
<node pkg="ssr_pkg" type="chao_node" name="chao_node"/>
//包名 节点 节点名
<node pkg="atr_pkg" type="ma_node" name="ma_node" output="screen"/>
//输出于屏幕
</launch>
运行launch文件roslaunch atr_pkg qidong.launch
使用新的终端程序运行节点,添加属性launch-prefix="gnome-terminal -e"
即可
小结
我的理解
这是小乌龟的rqt_graph,展示了/teleop_turtle节点与/turtlesim节点之间的通讯关系。两个节点之间的共同话题为/turtle1/cmd_vel
其中/teleop_turte节点将会检测键盘的输入,并将其以信息通过/turtle1/cmd_vel话题发送给/turtlesim,turtlesim将会改变运动轨迹,最终呈现键盘控制小乌龟运动的效果。
附加:使用launch文件启动小乌龟以及键盘控制程序
由于打开单个节点过于繁琐,需要分别执行如下命令roscore
rosrun turtlesim turtlesim_node
rosrun turtlesim turtle_teleop_key
此处在turtleism包中创建launch文件,为避免与原作者文件混淆,此处命名带上了自己的名字
代码实现如下
<launch>
<node pkg="turtlesim" type="turtlesim_node" name="turtlesim_node"/>
<node pkg="turtlesim" type="turtle_teleop_key" name="urtle_teleop_key"/>
</launch>
运行launch文件roslaunch turtlesim turtlesim_key_Elaina.launch
实现效果