文章目录

  • 简述
  • 特点
  • 相关常用命令
  • 通信模型
  • 核心元素
  • 通信过程
  • 代码示例(发布者和订阅者)
    • 发布者(talker.cpp)
    • 订阅者(listener.cpp)
    • 配置 CMakeLists.txt
    • 编译和运行
    • 问题扩展
  • 自定义消息
    • 自定义msg文件
    • 编辑配置文件
    • 执行编译
    • 修改订阅者和发布者代码
    • 编译和运行

简述

话题消息通信是指发送信息的发布者和接收信息的订阅者以话题消息的形式发送和接收信息。希望接收话题的订阅者节点接收的是与在主节点中注册的话题名称对应的发布者节点的信息。基于这个信息,订阅者节点直接连接到发布者节点来发送和接收消息。

特点

话题是单向的,适用于需要连续发送消息的传感器数据,因为它们通过一次的连接连续发送和接收消息。另外,单个发布者可以与多个订阅者进行通信,相反,一个订阅者可以在单个话题上与多个发布者进行通信。

相关常用命令

命令 详细说明
rostopic list 显示活动的话题目录
rostopic echo [话题名称] 实时显示指定话题的消息内容
rostopic find [类型名称] 显示使用指定类型的消息的话题
rostopic type [话题名称] 显示指定话题的消息类型
rostopic bw [话题名称] 显示指定话题的消息带宽(bandwidth)
rostopic hz [话题名称] 显示指定话题的消息数据发布周期
rostopic info [话题名称] 显示指定话题的信息
rostopic pub [话题名称] [消息类型] [参数] 用指定的话题名称发布消息

通信模型


PS:参考原文

核心元素

  1. ROS Master(管理者)
    必须首先被运行,并使用XMLRPC服务器,负责管理节点之间的消息通信中的连接信息。
  2. Talker (发布者)
    生成指定的话题,将TCPROS消息发布给所有的订阅者。
  3. Listener (订阅者)
    订阅指定的话题,从发布者那里接收指定的TCPROS的消息。

PS: XMLRPC(XML-Remote Procedure Call)是一种RPC协议,其编码形式采用XML编码格式,而传输方式采用既不保持连接状态、也不检查连接状态的请求和响应方式的HTTP协议。XMLRPC是一个非常简单的约定,仅用于定义小数据类型或命令,所以它比较简单。有了这个特点,XMLRPC非常轻便,支持多种编程语言,因此非常适合支持各种硬件和语言的ROS。

通信过程

  1. 运行主节点
    主节点(master)负责节点到节点的连接和消息通信,类似于名称服务器(Name Server)。roscore是它的运行命令,当运行主节点时,可以注册每个节点的名字,并根据需要获取信息。没有主节点,就不能在节点之间建立访问和消息交流(如话题和服务)。主节点使用XML远程过程调用(XMLRPC,XML-Remote Procedure Call)与节点进行通信。
  2. 运行发布者节点
    发布者节点向主节点注册发布者节点名称、话题名称、消息类型、URI地址和端口。
  3. 运行订阅者节点
    订阅者节点在运行时向主节点注册其订阅者节点名称、话题名称、消息类型、URI地址和端口。
  4. 主节点向订阅者节点发送发布者节点信息
    主节点向订阅者节点发送此订阅者希望访问的发布者的名称、话题名称、消息类型、URI地址和端口等信息。
  5. 订阅者节点向发布者节点发送连接请求
    订阅者节点根据从主节点接收的发布者信息,向发布者节点请求直接连接。在这种情况下,要发送的信息包括订阅者节点名称、话题名称和消息类型。
  6. 发布者节点进行连接响应
    发布者节点将TCP服务器的URI地址和端口作为连接响应发送给订阅者节点。
  7. 发布者节点和订阅者节点建立连接
    订阅者节点使用TCPROS创建一个与发布者节点对应的客户端,并直接与发布者节点连接。发布者和订阅者建立连接后,可以直接发送消息,不再通过ROS Master,所以,此时即使关闭掉ROS Master也不影响两者的通信。
  8. 发送消息
    发布者节点向订阅者节点发送消息。节点间通信使用一种称为TCPROS的TCP/IP方式。

代码示例(发布者和订阅者)

需求描述:编写发布者和订阅者文件,发布者以10HZ(每秒10次)的频率发布文本消息,订阅者订阅到消息后打印出来。

首先,这里创建了一个topic_test的包,然后分别创建talker.cpp(发布者)和listener(订阅者)两个文件。

发布者(talker.cpp)

#include "ros/ros.h"
#include "std_msgs/UInt32.h"int main(int argc, char **argv)
{// 设置编码setlocale(LC_ALL, "");// 1.初始化ROS节点// 参数3为节点名称,全局唯一ros::init(argc, argv, "talker");// 2.实例化ROS句柄ros::NodeHandle nh;// 3.实例化发布者对象// 参数1为数据要发布到的话题名称,参数2为缓冲区大小ros::Publisher pub = nh.advertise<std_msgs::UInt32>("chatter", 1000);// 4.定义要发布的数据int count = 0;std_msgs::UInt32 msg;// 5.定义数据发布的频率为每秒10次ros::Rate loop_rate(10);// ros::ok()表示只要节点还在运行即满足循环条件while (ros::ok()){msg.data = count;// 6.发布消息pub.publish(msg);// 打印发送的信息ROS_INFO("发送的消息是:%d", msg.data);// 处理ROS消息回调,只循环一次// 这里并没有接收到任何回调,所以这一句可以不写ros::spinOnce();count++;loop_rate.sleep();}return 0;
}

订阅者(listener.cpp)

#include "ros/ros.h"
#include "std_msgs/UInt32.h"void chatterCallback(const std_msgs::UInt32::ConstPtr& msg)
{// 4.处理订阅的消息ROS_INFO("订阅到了消息: [%d]", msg->data);
}int main(int argc, char **argv)
{// 设置编码setlocale(LC_ALL, "");// 1.初始化ROS节点// 参数3为节点名称,全局唯一ros::init(argc, argv, "listener");// 2.实例化ROS句柄ros::NodeHandle nh;// 3.实例化订阅者者对象// 参数1为要订阅的话题名称,参数2为缓冲区大小,参数3为处理订阅消息的回调函数ros::Subscriber sub = nh.subscribe<std_msgs::UInt32>("chatter", 1000, chatterCallback);// 处理ROS消息回调,一直循环,直到ROS节点退出(执行了Ctrl+C或者ros::shutdown()被调用)ros::spin();return 0;
}

配置 CMakeLists.txt

注意:这里的CMakeLists.txt指的是topic_test包下面的,而非整个工程下面的那个,在CMakeLists.txt文件中添加下面的内容。

# 节点构建选项,配置可执行文件
add_executable(talker src/talker.cpp)
add_executable(listener src/listener.cpp)# 节点构建选项,配置目标链接库
target_link_libraries(talker${catkin_LIBRARIES}
)
target_link_libraries(listener${catkin_LIBRARIES}
)

编译和运行

使用Ctrl+Shift+B进行编译,然后使用roscore命令启动主节点,然后source下环境变量,分别运行发布者和订阅者节点即可看到通信数据的打印输出。

问题扩展

上面先运行了发布者节点,从0开始打印信息,然后运行订阅者节点,信息直接从196开始打印了,订阅者运行之前发布者发布的信息就接收不到了。

尝试先运行订阅者节点,然后运行发布者节点,仍然存在信息丢失的情况。原因是在发布者开始发布消息时,其还未在主节点注册完成。

可以在talker.cpp中添加延时来延迟第一条数据的发送时间。

ros::Duration(1.0).sleep();

在延时等待注册完成后再发送消息,就可以收到完整的消息了。


自定义消息

ROS节点通过消息相互通信,ROS提供了一些标准的数据类型,也提供了一种基于标准消息类型开发自定义消息类型的机制。上面的示例中我们使用的是ROS标准的消息,实际使用中常常需要自定义消息来满足需求。

ROS的消息类型可以在这里查看。

需求描述:创建一个关于学生信息的msg文件,其中包含姓名、年龄和成绩,发布者发送学生信息,订阅者打印学生信息。

自定义msg文件

首先,在topic_test包中创建msg文件夹,然后,在文件夹中创建消息文件(Student.msg)。

string name
uint8 age
float32 score

编辑配置文件

  • 在package.xml中添加编译依赖与执行依赖
<!-- 编译时依赖 -->
<build_depend>message_generation</build_depend>
<!-- 运行时依赖 -->
<exec_depend>message_runtime</exec_depend>
  • 在CMakeLists.txt编辑 msg 相关配置
# catkin构建时依赖的组件包,前3个创建ROS包时已经自动生成了,这里添加了message_generation
find_package(catkin REQUIRED COMPONENTSroscpprospystd_msgsmessage_generation
)# 配置msg源文件,FILES将引用当前功能包目录的msg目录中的*.msg文件,自动生成一个头文件(*.h)
add_message_files(FILESStudent.msg
)# 生成消息时依赖于std_msgs
generate_messages(DEPENDENCIESstd_msgs
)# 运行时依赖,描述了库、catkin构建依赖项和系统依赖的功能包
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES topic_testCATKIN_DEPENDS roscpp rospy std_msgs message_runtime
#  DEPENDS system_lib
)

执行编译

使用Ctrl+Shift+B进行编译,然后可以在/devel/topic_test目录下看到自动生成的头文件Student.h,此时便可以代后面的代码中进行引用了。

PS: 在修改代码之前,先在c_cpp_properties.json文件中添加下头文件路径,否则在代码中引用头文件时会出现找不到的情况。

修改订阅者和发布者代码

下面我们在代码中使用自定义的消息来进行通信。

  • 发布者(talker.cpp)
#include "ros/ros.h"
#include "topic_test/Student.h"int main(int argc, char **argv)
{// 设置编码setlocale(LC_ALL, "");// 1.初始化ROS节点// 参数3为节点名称,全局唯一ros::init(argc, argv, "talker");// 2.实例化ROS句柄ros::NodeHandle nh;// 3.实例化发布者对象// 参数1为数据要发布到的话题名称,参数2为缓冲区大小ros::Publisher pub = nh.advertise<topic_test::Student>("chatter", 1000);// 4.定义要发布的数据topic_test::Student msg;msg.name = "张三";msg.age = 18;msg.score = 85.6;// 5.定义数据发布的频率为每秒1次ros::Rate loop_rate(1);// ros::ok()表示只要节点还在运行即满足循环条件while (ros::ok()){// 6.发布消息pub.publish(msg);// 打印发送的信息ROS_INFO("发送的消息是:姓名-%s, 年龄-%d, 成绩-%.2f", msg.name.c_str(), msg.age, msg.score);// 处理ROS消息回调,只循环一次// 这里并没有接收到任何回调,所以这一句可以不写ros::spinOnce();loop_rate.sleep();}return 0;
}
  • 订阅者(listener.cpp)
#include "ros/ros.h"
#include "topic_test/Student.h"void chatterCallback(const topic_test::Student::ConstPtr& msg)
{// 4.处理订阅的消息ROS_INFO("订阅到了消息: 姓名【%s】, 年龄【%d】, 成绩【%.2f】", msg->name.c_str(), msg->age, msg->score);
}int main(int argc, char **argv)
{// 设置编码setlocale(LC_ALL, "");// 1.初始化ROS节点// 参数3为节点名称,全局唯一ros::init(argc, argv, "listener");// 2.实例化ROS句柄ros::NodeHandle nh;// 3.实例化订阅者者对象// 参数1为要订阅的话题名称,参数2为缓冲区大小,参数3为处理订阅消息的回调函数ros::Subscriber sub = nh.subscribe<topic_test::Student>("chatter", 1000, chatterCallback);// 处理ROS消息回调,一直循环,直到ROS节点退出(执行了Ctrl+C或者ros::shutdown()被调用)ros::spin();return 0;
}

编译和运行

使用Ctrl+Shift+B进行编译,然后使用roscore命令启动主节点,然后source下环境变量,分别运行发布者和订阅者节点即可看到通信数据的打印输出。

☝ ★★★ — 返回 《ROS机器人开发笔记汇总》总目录 — ★★★ ☝

ROS通信机制(一) —— 话题(topic)与msg文件相关推荐

  1. ROS通信机制:话题、服务、参数

    目录 话题通信 理论模型 流程 通信样例 自定义消息的通信 服务通信 理论模型 服务通信自定义srv 参数服务器 理论模型 参数操作 话题通信 话题通信是ROS中使用频率最高的一种通信模式,话题通信是 ...

  2. ROS通信机制一---话题通信

    文章目录 总述 1. 话题通信模型 2. 话题通信基本实现示例 2.1 发布者 2.1.1 创建发布者topic_pub.cpp文件 2.1.2 修改CMakeLists.txt文件 2.1.3 编译 ...

  3. ROS通信机制(二) —— 服务(service)与srv文件

    文章目录 简述 特点 相关常用命令 通信模型 核心元素 通信过程 代码示例(服务端和客户端) 服务端(server.cpp) 客户端(client.cpp) 配置 CMakeLists.txt 编译和 ...

  4. ROS 通信机制(已整理)

    文章目录 节点与节点管理器 ROS通信机制 1. 话题通信 1.1 基本话题通信 1.1.1 C++实现 发布方 demo01_pub.cpp 订阅方 demo01_sub.cpp 1.1.2 Pyt ...

  5. ROS自主导航学习———ROS通信机制

    前言 前面ROS很多都忘记了 ,现在来重新回顾一下内容 ROS 中的基本通信机制主要有如下三种实现策略: 话题通信(发布订阅模式) 服务通信(请求响应模式) 参数服务器(参数共享模式) Action通 ...

  6. ROS通信机制——发布/订阅者模型

    目录 发布/订阅者模型 (一)发布者 (二)订阅者 (三)综合 参考资料 ROS (Robot Operating System),即机器人操作系统,是为了加快机器人的开发效率,提高机器人软件代码的复 ...

  7. 【ROS理论与实践-赵虚左老师】Chap2 ROS通信机制

    第二章 ROS通信机制 通信是ROS中的核心 Core 机器人是一种高度复杂的系统性实现,在机器人上可能集成各种传感器(雷达.摄像头.GPS-)以及运动控制实现,为了解耦合,在ROS中每一个功能点都是 ...

  8. Chapter2 ROS通信机制----基础篇(Ⅰ)vs配置及通信基础

    目录 一.复习及launch 1.1 深入理解配置信息(非常重要) 1.2 launch文件演示 二.ROS通信机制-----基础 2.1 本节导论 2.2 话题通信 2.2.1 话题通信概述 2.2 ...

  9. ROS通信机制--键盘控制乌龟运动线速度角速度XYZ值的解释

    目录 前言 案例实现 线速度角速度X.Y.Z值的取值和作用 (END) 前言 在学习ros之初,想必大家运行的第一个案例就是键盘控制乌龟运动.这是ros内置的小案例,采用的通信机制为话题通信.本文介绍 ...

最新文章

  1. CentOS 7 安装 GlusterFS
  2. repmat--矩阵的复制和平铺
  3. C/S和B/S的区别
  4. Java内存泄漏介绍
  5. 【今日CV 视觉论文速览】Fri, 8 Feb 2019
  6. 如何在ppt下面加入讲解内容_如何批量查找并修改替换 Word、PPT、Excel、PDF、TXT等文件的内容——我的ABC...
  7. 吴恩达机器学习 逻辑回归 作业3(手写数字分类) Python实现 代码详细解释
  8. 微软vs2008快捷键
  9. 嘿嘿,俺做长辈了!!!
  10. 面向项目(二)—— visual studio 的使用
  11. java初学者笔记总结day7
  12. 《进击的虫师》百度文库下载器
  13. 教务管理系统数据字典mysql_学校教务管理系统--数据库课程设计
  14. 最新最全的微信小程序入门学习教程,微信小程序零基础入门到精通
  15. MATLAB频谱图绘制
  16. 1:500城镇地形图测绘已正式启动
  17. 数字化住宅小区对计算机网络有需求,浅谈智能小区宽带接入及其技术发展趋势...
  18. Windows 10家庭版也能共享打印机(中)解除Guest账户网络登录限制,实现局域网共享...
  19. 从一个app里面 跳转到另一个 app
  20. 芋头哥:从码农到农民,靠微博3个月卖出20万斤

热门文章

  1. 纯css修改图标颜色的五种方式
  2. 学计算机动漫设计软件,动漫设计需要学习哪些软件?
  3. 学生成绩计算的c语言,学生成绩标准管理系统C语言.doc
  4. 单片机软件延时的时间计算
  5. Log日志(Linux C)
  6. 在html中怎么格式化输出json字符串
  7. 【shell 脚本编程】一键搭建 LAMP,Web 应用程序平台,你值得拥有
  8. vectorvn1610报价_VECTOR VN1610 +CANOE+CANALYZER
  9. variable argument parameter的区别
  10. leetcode 575. 分糖果