ROS 话题Topic

  • Post author:
  • Post category:其他




1 背景知识



1.1 话题是什么

ROS程序由多个功能组成;一个功能由多个节点完成;各节点的功能独立,节点与节点间通过不同的通信方式,实现数据的传输,完成功能。即总功能由分功能组成,各分功能由节点的子功能及节点间的通信完成。

话题是一种节点与节点间进行

一对多、单向传输

的数据通信方式,数据通过话题的发布与订阅实现传送。



1.2 话题的通信机制

参与节点及节点功能:

1. 发布者节点Talker: 发布话题。

2. 订阅者节点Listener: 订阅话题。

3. 节点管理器ROS Master:保管节点注册信息,匹配话题的订阅者和发布者,并帮助订阅者和发布者的建立连接。


通信过程如下:


在这里插入图片描述

七步骤如下:

步骤 步骤内容 类比
1.发布者注册 向节点管理器ROS Master注册相关信息,包括:节点信息、发布的话题 在婚姻介绍所登记信息
2.订阅者注册 向节点管理器ROS Master注册相关信息,包括:节点信息、订阅的话题 在婚姻介绍所登记信息
3.节点管理器进行话题匹配 保管注册信息,匹配话题相同的Talker和Listener,通过RPC向Listener发送Talker的RPC地址 婚姻介绍所举办相亲会
4.订阅者向发送连接请求 Listener通过RPC向Talker发送连接请求,传输话题名、消息类型、通信协议 相亲会上选择中意对象
5.发布者确认连接请求 Talker接收连接请求,通过RPC向Listener确认连接 也看上了,坐下
6.发布者尝试与订阅者建立网络连接 Listener接收到确认信息后,通过TCP与Talker建立网络连接。 聊得不错,加微信
7.发布者向订阅者发布消息 成功建立连接后,Talker开始向Listener发送话题消息数据 同意好友请求,火热聊天



1.3 话题的特点

  • 一个话题可以有多个订阅者;一个订阅者可以订阅多个话题,一个发布者也可以发布多个话题。实现一对一、一对多、多对多的通信网络 。
  • 话题是一种异步通信方式。话题的发布者只发布话题,发布完成立马返回;话题订阅者收到话题后,通过回调函数处理话题发送的消息。



1.4 验证

打开一终端

$ roscore

打开另一终端

$ rosrun turtlesim turtlesim_node
[ INFO] [1679577658.273288946]: Starting turtlesim with node name /turtlesim
[ INFO] [1679577658.283734154]: Spawning turtle [turtle1] at x=[5.544445], y=[5.544445], theta=[0.000000]

再启另一终端

$ rosrun turtlesim turtle_teleop_key
Reading from keyboard
---------------------------
Use arrow keys to move the turtle. 'q' to quit.

在这里插入图片描述

此时,通过输入四个方向键可以使乌龟动起来。

再启另一终端:

$ rosrun rqt_graph rqt_graph

在这里插入图片描述

rqt_graph:图形化的工具,画出正在发布主题和订阅的关系图

再启另一终端:

$ rostopic info /turtle1/cmd_vel 
Type: geometry_msgs/Twist

Publishers: 
 * /teleop_turtle (http://ubuntu:45347/)

Subscribers: 
 * /turtlesim (http://ubuntu:39403/)

上述终端中的信息可以看出, /teleop_turtle节点发布话题 /turtle1/cmd_vel ,/turtlesim节点订阅话题 /turtle1/cmd_vel,但话题名上看不出传递了什么信息。

话题要实现信息传递,实际上是通过话题下的

消息message

,例如:话题/turtle1/cmd_vel的消息是[geometry_msgs/Twist] ,话题和消息的关系可以类比成报纸和报纸上的内容。

话题的消息数据类型是根据需要决定的。查看消息[geometry_msgs/Twist] 传递数据:

$ rosmsg show geometry_msgs/Twist
        geometry_msgs/Vector3 linear
          float64 x
          float64 y
          float64 z
        geometry_msgs/Vector3 angular
          float64 x
          float64 y
          float64 z

上述过程验证了节点Node通过

发布和订阅Topic

实现信息的传递。





前提



ROS 创建工作空间和软件包


当前所处软件包为beginner_tutorials,该软件包的文件系统结构如下图:

在这里插入图片描述



2 自定义消息

话题消息的数据结构:为

单个

数据结构。即由

一组

字段定义,字段间的顺序无关紧要。


一个

字段由类型和名称组成,一个字段的结构:<type>空格<name> = <value>

<type>字段的类型:数据类型 + 数组说明符[](可选)

→数据类型:内置类型 或者 非内置类型

→数组说明符[]:有界[N] 或者 无界[]

<name> 字段的名称: 由小写字母、数字、下划线组成


= <value>字段值:可选, ROS1中表明该字段是常量

#注释

自定义话题消息文件的后缀为.msg,消息名称与软件包名的组合实现唯一标识消息。



2.1 创建msg文件夹(专放消息), 并编辑Example.msg 文件**

$ roscd beginner_tutorials        
$ mkdir msg                       
$ cd msg
$ touch Example.msg   

编辑Example.msg 文件

int64 num              #内置类型
std_msgs/String str2   #ROS其他消息包
char[]  ch             #数组
string str1 = "hello"   #常量,此行的注释在实例时不要添加,会被认为是字符串内容



2.2 添加msg依赖

编辑 ‘

软件包

’ 下的package.xml 文件(修改后)

#下面两行取消注释,不存在,则添加
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

# <build_depend>  编译时的依赖
#  <exec_depend>  运行时的依赖

编辑‘

软件包

’ 下CMakeLists.txt 文件(修改后)

# 需添加部分1:添加消息生成依赖
find_package(catkin REQUIRED COMPONENTS
   .......   
   message_generation
)

# 需添加部分2 :添加运行时依赖关系
catkin_package(
  ...
  CATKIN_DEPENDS message_runtime ...
  ...)
  
# 需修改部分3:     
#            1)删除前面的# 符号  
#            2)替换Message1.msg,Message2.msg 为 Example.msg     
 add_message_files(
  FILES
  Example.msg   
 )

# 需修改部分4: 删除前面的# 符号 ,int64是规定的ros标准消息类型,属于消息包std_msgs
generate_messages(
  DEPENDENCIES
  std_msgs
)

查看消息是否创建成功:

$ rosmsg show beginner_tutorials/Example 
string str1="hello"
int64 num
std_msgs/String str2
  string data
char[] ch

std_msgs/String是ROS的标准数据包。



2.3 编译,使.msg能被转换为C++、Python和其他语言的源代码

要使用自定义消息,需将.msg 文件编译为 .h 文件,再引入到程序中 。

$ cd ~/catkin_ws
$ catkin_make

编译后,生成相应的Example.h。

Example.h头文件位置在:

./devel/include/beginner_tutorials/Example.h




3 编辑发布者

  1. 初始化节点(命名,唯一) 。
  2. 实例化句柄 。
  3. 实例化发布者对象,发布的话题及话题的消息数据。
  4. 组织发布的数据。
  5. 编译。



3.1 编辑talker.cpp

在软件包的src文件中,创建talker.cpp文件。

$ touch talker.cpp

编辑talker.cpp文件:

#include "ros/ros.h" 
#include "beginner_tutorials/Example.h"  //自定义消息包

 int main(int argc, char **argv)
 {

    ros::init(argc, argv, "talker");//初始化节点,标识"listener"的节点名, 需唯一

    ros::NodeHandle n;//初始化句柄

    ros::Publisher chatter_pub = n.advertise<beginner_tutorials::Example>("chatter", 1000);
	//定义发布者,发布话题"chatter"                          
    ros::Rate loop_rate(10);

    beginner_tutorials::Example example; //定义消息对象,以组织发布的数据
    int count = 0;
    while (ros::ok())
    {
		example.str2.data = "talker";
      	example.num = count;
      	example.ch.push_back('A');
		ROS_INFO(" %s say :%s, the %c part is %ld ",   example.str2.data.c_str(),  example.str1.c_str(), example.ch.at(0), example.num);
		++count;
		
		chatter_pub.publish(example); //发布话题
		ros::spinOnce();
		loop_rate.sleep();
    }
    return 0;
  }



3.2 编译,生成可执行文件

编辑CMakeLists.txt,增添内容:

#生成可执行文件
add_executable(listener src/listener_msg.cpp)
#需要连接的库
target_link_libraries(listener ${catkin_LIBRARIES})
#需要的依赖
add_dependencies(listener ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

在工作空间下编译,生成可执行文件。

$ cd catkin_ws
$ catkin_make
$ source ./devel/setup.bash

可执行文件放置于:devel/lib/beginner_tutorials




4 编辑订阅者

  1. 初始化节点(命名,唯一) 。
  2. 实例化句柄 。
  3. 实例化订阅者对象,订阅的话题,处理话题消息的回调函数。
  4. 定义处理订阅的消息(回调函数)。
  5. 设置循环,以调用回调函数。
  6. 编译。



4.1 编辑listener.cpp



软件包

的src文件中,创建listener.cpp

$ touch listener.cpp

编辑 listener.cpp

# include "ros/ros.h"
#include "beginner_tutorials/Example.h"   //自定义消息

//回调函数:处理订阅消息
void chatterCallback(const beginner_tutorials::Example::ConstPtr& msg)
{
        ROS_INFO("listener get the value is : [%ld]", msg->num);
}


int main(int argc, char **argv)
{

        ros::init(argc, argv, "listener");//初始化节点,标识"listener"的节点名, 需唯一

        ros::NodeHandle n; //初始化句柄

        ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
        //定义订阅者,订阅话题"chatter",绑定回调函数

        ros::spin();//设置循环,调用回调函数

        return 0;
}

回调函数的要求:

  1. 参数只能有一个且必须以const修饰
  2. 参数类型为xxxConstPtr
  3. 参数为引用传递
  4. 函数没有返回值



4.2 编译,生成可执行文件

编辑CMakeLists.txt,增添内容:

add_executable(talker src/talker_msg.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

在工作空间下编译, 生成可执行文件。

$ cd catkin_ws
$ catkin_make
$ source ./devel/setup.bash

可执行文件放置于:devel/lib/beginner_tutorials




5 验证

打开终端,运行roscore。

$ roscore 

另起终端,先运行订阅者listener节点。

$ rosrun beginner_tutorials listener

再另起终端,运行发布者talker节点

$ rosrun beginner_tutorials talker

结果:

在这里插入图片描述

当前软件包的文件系统结构:(红框为当前教程新增)

在这里插入图片描述



6 总结


6.1 ros指令总结

roscore 运行节点管理器

rosrun <package_name> <node_Name> : 运行软件包的节点

rospack info <topic_name> :打印有关活动主题的详细信息

rosmsg info <package_name>/<\message_name> : 打印与话题相关的发布者订阅者信息

rosmsg show <package_name>/<\message_name> : 查看话题的消息


6.2 核心函数

在这里插入图片描述



版权声明:本文为TTTTTTTTTSS原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。