ROS 多个传感器 publish 同一个Topic

Stella981
• 阅读 1189

梳理一下概念

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

Publisher
  1. 生成信息,通过ROS Topic与其它Node进行通信。
  2. 通常用于处理原始的传感器信息,如相机、编码器等。
Subscriber
  1. 接收信息,通过ROS Topic接收来自其它Node的信息,并通过回调函数处理
  2. 通常用于监测系统状态,如当机器人关节到达限位位置时触发运动中断

Topic 通信过程为:

  1. Publisher 节点和 Subscriber 节点分别在 Master 进行注册

  2. Publisher 发布 Topic

  3. Subscriber 在 Master 指挥下订阅 Topic,从而建立起 Pub-Sub 之间的通信

    注意:消息是直接从发布节点传递到订阅节点,并不经过 Master,只是从 Master 获取到 Topic 信息

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

Topic通信的特点为:

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

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

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

另外,Publisher并不知道哪个节点会接收消息,而Subscriber也并不知道接收的消息来自哪个节点,节点之间是松耦合的,这也是ROS最关键的设计特性之一。

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

Topic同时收发

相比于单纯的Topic多收或多发,同时收发会复杂一些。首先,根据前面知识知道Topic接收是通过NodeHandle的成员函数subscribe()和自定义的回调函数实现的,同时回调函数有严格的定义规定:参数只能有一个且必须以const修饰、参数类型为xxxConstPtr、参数为引用传递、函数没有返回值。这就意味着单纯的回调函数几乎无法同外界做任何直接的数据交换,数据只能在它内部处理,除了保存到文件以外,其它没有办法输出数据。

解决这个问题的核心就是数据或变量在不同函数之间的共享问题。在 C++、Python 中对于这种情况有两种办法:一种是采用全局变量,二是类

这里直接介绍第二种方法代码如下:

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

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
超声波墙检
"""
import rospy
from sensor_msgs.msg import Range
from ak_ros_pkg.msg import Wall_sonar_msg

class Processer:
def init(self):

实例化订阅多个 Topic

    self.sub1 = rospy.Subscriber("/sensor/sonar_left", Range, self.callback1)
    self.sub2 = rospy.Subscriber("/sensor/sonar_right", Range, self.callback2)

    self.pub1 = rospy.Publisher('ankobot_wall_sonar', Wall_sonar_msg, queue_size=10)
    # self.pub2 = rospy.Publisher('ankobot_wall_tof', Wall_tof_all_msg, queue_size=10)

    self.wall_sonar_distance = {}

def callback1(self, data):
    """
    左超声波
    """
    distance = int(data.range * 1000)

    self.wall_sonar_distance['l_sonar'] = distance
    self.check_wall_sonar_distance()

def callback2(self, data):
    """
    右超声波
    """
    distance = int(data.range * 1000)

    self.wall_sonar_distance['r_sonar'] = distance
    self.check_wall_sonar_distance()

def check_wall_sonar_distance(self):
    """
    检查 wall_sonar_distance 字典是否满足两个值的条件
    """
    if len(self.wall_sonar_distance) == 2:
        wall_sonar_single = Wall_sonar_msg()
        # 单位 m
        wall_sonar_single.l_sonar = self.wall_sonar_distance['l_sonar']
        wall_sonar_single.r_sonar = self.wall_sonar_distance['r_sonar']
        # 预留
        # wall_sonar_single.c_sonar = self.wall_sonar_distance['c_sonar']
        # wall_sonar_single.d_sonar = self.wall_sonar_distance['d_sonar']
        self.pub1.publish(wall_sonar_single)

if name == 'main':
rospy.init_node("wall_sonar")

p = Processer()

rospy.spin()


##### 更多示例请参考 
[C++、Python 版本的 topic 多收、多发、多收多发](https://github.com/creazy412/ROS-Multi-Topic-Demo)
---

参考:<br/>
- [单节点的多Topic同时收发](http://zhaoxuhui.top/blog/2019/10/20/ros-note-7.html)
- [Topic 概念梳理](https://tr-ros-tutorial.readthedocs.io/zh_CN/latest/_source/basics/1.4_ROS_Topic.html)
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Easter79 Easter79
2年前
swap空间的增减方法
(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这