当前位置:   article > 正文

ROS 话题Topic_ros发布话题

ros发布话题

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
  • 1

  打开另一终端

$ 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]
  • 1
  • 2
  • 3

  再启另一终端

$ rosrun turtlesim turtle_teleop_key
Reading from keyboard
---------------------------
Use arrow keys to move the turtle. 'q' to quit.
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述

  此时,通过输入四个方向键可以使乌龟动起来。
  再启另一终端:

$ rosrun rqt_graph rqt_graph
  • 1

在这里插入图片描述

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

  再启另一终端:

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

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

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

  上述终端中的信息可以看出, /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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

  上述过程验证了节点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   
  • 1
  • 2
  • 3
  • 4

  编辑Example.msg 文件

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

  编辑 ‘软件包’ 下的package.xml 文件(修改后)

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

# <build_depend>  编译时的依赖
#  <exec_depend>  运行时的依赖
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

  编辑‘软件包’ 下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
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

  查看消息是否创建成功:

$ rosmsg show beginner_tutorials/Example 
string str1="hello"
int64 num
std_msgs/String str2
  string data
char[] ch
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

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

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

$ cd ~/catkin_ws
$ catkin_make
  • 1
  • 2

  编译后,生成相应的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
  • 1

  编辑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;
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
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})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

$ cd catkin_ws
$ catkin_make
$ source ./devel/setup.bash
  • 1
  • 2
  • 3

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


4 编辑订阅者

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

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

$ touch listener.cpp
  • 1

  编辑 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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

回调函数的要求:

  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})
  • 1
  • 2
  • 3

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

$ cd catkin_ws
$ catkin_make
$ source ./devel/setup.bash
  • 1
  • 2
  • 3

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


5 验证

  打开终端,运行roscore。

$ roscore 
  • 1

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

$ rosrun beginner_tutorials listener
  • 1

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

$ rosrun beginner_tutorials talker
  • 1

  结果:

在这里插入图片描述

当前软件包的文件系统结构:(红框为当前教程新增)
在这里插入图片描述

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 核心函数

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/657157
推荐阅读
相关标签
  

闽ICP备14008679号