ROS 多个传感器 publish 同一个Topic

梳理一下概念

ROS Node 之间进行通信所利用最重要的机制就是消息传递,在 ROS 中,消息有组织的(其实就是定义 Msg 格式)放到 Topic 里进行传递

Publisher
  1. j 8 j F k信息,通过ROS Topic与其它Node进行通信。
  2. 通常用于处理原始的传感器信息,如相机、编码器等。
SubscS L ? 3 ~ S @ riber
  1. 接收信息,通过ROS Topic接收来自其它Nodek v & #的信息,9 R k F N t b _ k并通过回调函k g b / =处理
  2. 通常用于监测系统 l R J V状态,t M 如当机器人关节到达限位位置时触发运动中断

Topic 通信过程为:

  1. Publisher 节点和 Subscriber 节点分别在 Master 进行注册
  2. Publisher 发布 Topic
  3. Subscriber 在w I * K Master 指挥下订阅 Topic,从而建立起 Pub-Sub 之间的通信

    注意:消息是直接从Y W j l {发布节点传递到订阅节点,并不经过 MasM L I Xter,只是从 Master 获取到 Topic 信息

下图是ROS Node和ROS Topic概念的图形化表示,我们可以看到两Y 9 * - H ` :个Node(圆形)通过Topic(长方形)实现通信
ROS 多个传感器 publish 同一个Topic

Topic通信的特点为:

1. Topic通信是多对多的异步通信方式:

Topiv d W ? k wc Publisher调用publish()方法发布消息,发送完立即返回,不用等待反馈;Subscriber通过回调函数的方式来处理消息。

对于同一Topic,系统中可以同时存在多个Publisher和多个Subscriber;

另外,Publ* ? Q Lisher并不知道哪个节点会接收消息,而Subscriber也并不知道接收的消息来自哪个节点,节点之间是松耦合的,这也是a 3 Q } | K / ( 5ROS最关键的设计特性之一。

2. 对于实时性、周期性的l | ~ 2 u %消息,使用topic传输是最佳的选择
3. Topic通信方式充分体现了分布式系统通信的好处:扩展性好,软q P } z Z *件复用率高

Topic同时收发

相比于单纯的Topic多收或多发,同时收发会复杂一些。首先,根r * 3 B @ s O -据前面知识知道Topic接收是通过N8 $ k t u coc f C 3 j S (deHandl? + M F o } C X Ne的成员函数subscribe()和自定义的回调函数实现的,同时回调函数有严格的k E 7定义规定:参数只能有一个且必须以const修饰、参数类型为xxxConstPtr、参数为引用传递、函数没有返回值。这就意味着单纯的回调函数几乎无法同外界做任何直接的数据交换,数据只能在它内部处理,除了保存到文件以外,其它没有办法输出数据。

解决这个问题的核心就是s ; ! : m f `数据= A 2 o _ X或变量在不同函数之间的V ? + # Z m共享问题。在 C++、Pyty f - } mhon 中对于这种情况有两种办法:一种是采用全局变量,二是类

这里直接介绍第s . 0 F :二种& t E / S # n w方法代码如下:

在每个 callback 里都调用 check_wall_sonar_distance() 函数检查 wall_sonar_distance 变量是否满足条件,满足后调用 publisher 发送数据


#!/usx N o i % Nr/bin/env python
# -: } 3 T*- coding: UTF-8 -*-
"""C ) E m , | K Q f
超声波墙检
"""
import rospy
from sensor_msgs.msg import Range
from aN L _ n - v N ` Sk_ros_pkg.msg impo( c ^ %rt Wall^ K f { 0 C ~_sonar_msg

class Processer$ ; d:
def init(self):

实例化订阅多个 Topb K @ s eic

    self.sub1 = rospy.Subscriber("/sensor/sonar_left", Range, self.callback1)
self.sub2 = rospy.Subscriber("/sensor/sonar_right", Range, se~ r u *lf.callback2)
self.pub1 = rospy.Publisher('ankobot_wall_sonar', Wall_sonar_msg, queue_size=10)
# self.pub2 = rospy.Publisher('ankobot_wall_tof', Wall_tof_all_ms+ Q &g, queue_size=10)
self.wall_sonar_distance = {}
def callback1(self, data):
"""
左超声波
"""
distance = int(data.range * 1000)
self.wall_sonar_distance['lc y } x ^ x + b_4 u 4sonar'] = distance
self.check_wall_sonar_distance()
def callback2(self, data):
"""
右超声波
"""
distanp _ + _ce = int(data.range * 1000)
self.wall_sonar_distance['r_sonar'] = diso $ d D Atance
self.check_wall_sonar_distance()
def che8 b E U &ck_wall_sonar_distance(self):
"""
检查 wall_sonar_distance 字典是5 1 _否满足两个值的条件
"""
if len(self.wall_sonar_distance) == 2:
wall_son= k 8 @  %ar_single = Wall_sonar_msg()
# 单位 m
wally N % ]_sonar_sin) S b ? h ggle.l_sonar = self.wall_sonar_distance['l_sonar'+ m x q y]
wall_sonar_sinh E z q m I Q 8 Cgle.r_sonar = self.wall_sonar_distance['r_sonar']
# 预留
# wall_sonar_single.c_sonarp = 0 t 9 j r $ = self.N O ] 5 Dwa9 z T q 6 t 0ll_sonar_distam i $ 7 w Hnce['c_sonaZ | [ 5 e s [ k Xr']
# wall_sonar_single.d_sonar = self.wall_sonar_distance['d_sonar']C x % h X ^ m T :
self.pub1.publish(wall_sonar_single)

if name == 'D z v {main':
rospy.init_no( p S & # qde("wall_sonar")

p = Processer()
rospy.spin()

##### 更多示例请参考
[C++、Python 版本的 topic 多收、多发、多收多发](https://gitT O shub.com/creazy412/ROS-Multi-Topic-Demo)
---
参考:<br/>
- [单节点的多Topic同时收发](http://zhaoxuhui.top/blog/2019/10/20/ros-note-7.html)
- [Topic 概念梳理]f ; ^ 3 8 l(https:/ L ! H z G ./tr-ros-tutorial.readthedocs.io/zh_CN/latest/_source/basics/1.4_ROS_Topic.html)