话题通的模型中涉及三类角色:
-
ROS Master
-
Talker
-
Listener
ROS Master负责Talker和Listener的注册信息,并匹配话题(topic)相同的Talker和Listener建立连接,连接建立后,Talker发布的消息可以被Listener接收。建立连接后,可以不再需要ROS Master。

1、理论流程
- Talker注册
Talker会通过RPC在ROS Master中注册信息,包括自身发布消息的话题名称、自己的RPC地址
- Listener注册
同上,Listener会注册自身需要订阅的话题名和自己的RPC地址
- ROS Master实现信息匹配
ROS Master会根据注册表中的信息匹配Talker和Listener,并通过RPC先Listener发送Talker的RPC地址
- Listener先Talker发送请求
Listener 根据接收到的 RPC 地址,通过 RPC 向 Talker 发送连接请求,传输订阅的话题名称、消息类型以及通信协议(TCP/UDP)
- Talker确认请求
Talker接受到请求后,通过RPC先Listener确认连接信息,并发送自己的TCP地址
- Listener与Talker建立连接
Listener根据返回到的TCP地址与Talker建立网络连接
- Talker向Listener发送消息
连接建立后,Talker可以开始向Listener发布消息
2、通俗理解
-
女方(打电话)找媒婆
-
男方(打电话)找媒婆
-
媒婆匹配信息,把女方信息(打电话)给男方
-
男方给女方打电话
-
女方确认男方信息,并把自己的微信给男方
-
男方通过微信联系女方
-
男方和女方的后续沟通使用微信继续,而不再用媒婆传话
在通俗理解中,打电话即RCP通信协议,微信即TCP通信协议
3、注意事项
-
使用的通信协议有RPC和TCP,前期与ROS Master相关的通信是RCP协议,后面Talker与Listener的直接通信使用TCP协议
-
步骤0和步骤1的顺序先后无所谓
-
talker和listener可以同时存在多个
4、话题通信应用时的关注点
- 大部分实现已被封装
- 话题的设置
- 发布者和订阅放的实现
- 信息载体
5、代码实现
上面介绍的流程中的大部分工作都有ROS系统抽象封装好了,我们只需要简单调用即可。
- 实例化ROS句柄:
ros::NodeHandle nh;
- 发布方的注册:
ros::Publisher pub = nh.advertise<std_msgs::String>("chatter", 10);
- 订阅方的注册:
ros::Subscriber sub = nh.subscribe<std_msgs::String>("chatter", 10, doMsg);
我们可以发现,双方的匹配是根据注册函数中的第一个参数(chatter
)决定的,即话题名称。
双方注册自身的信息后,接下来的工作由ROS系统完成。
发布方发布信息:
pub.publish(msg);
订阅方注册好信息后,就一直处于待接收状态,我们需要将订阅方阻塞即可:ros::spin();
循环读取接收的数据,并调用回调函数处理
6、自定义msg
std_msgs包括:
- int8, int16, int32, int64 (或者无符号类型: uint*)
- float32, float64
- string
- time, duration
- other msg files
- variable-length array[] and fixed-length array[C]
我们可以自定义复合类型的msg类型,比如创建一个自定义消息,该消息包含人的信息:姓名、身高、年龄。
自定义msg流程:
- 定义msg文件
在package新建目录msg,添加Person.msg
内容为:
string name
uint16 age
float64 height
- 修改配置文件
package.xml中添加编译依赖与执行依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
CMakeLists.txt编辑 msg 相关配置
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
# 需要加入 message_generation,必须有 std_msgs
## 配置 msg 源文件
add_message_files(
FILES
Person.msg
)
# 生成消息时依赖于 std_msgs
generate_messages(
DEPENDENCIES
std_msgs
)
#执行时依赖
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES demo02_talker_listener
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
# DEPENDS system_lib
)
需要注意的是,上述语句的顺序不能搞错,否则会报错
- 编译
执行命令cmake_make
C++ 需要调用的中间文件(.../工作空间/devel/include/包名/xxx.h)
Python 需要调用的中间文件(.../工作空间/devel/lib/python3/dist-packages/包名/msg)
- 调用的注意事项
为了方便代码提示以及避免误抛异常,需要先配置 vscode,将前面生成的 头文件和python文件路径配置进vscode的json配置文件
cpp:c_cpp_properties.json 的 includepath
python:settings.json的python.autoComplete.extraPaths
- 调用
发布者调用:
ros::Publisher pub=nh.advertise<current_msgs::Person>("chatter_person", 1000);
订阅者调用:
ros::Subscriber sub = nh.subscribe<current_msgs::Person>("chatter_person", 10, doMsg);
可以发现,函数后面的尖括号包含了我们自定义的信息类型,这个是C++的语法知识,叫做模板,后面会详细补充相关知识。
其他与发布订阅标准信息类型一样。