这段代码实现了一个ROS的临时Subscriber,主要功能是:
初始化时传入topic名称、消息类型、队列大小等参数
提供get_data()接口获取最新消息数据
调用get_data()时才会创建Subscriber,并开始接收数据
一定时间内如果没有调用,则会自动销毁Subscriber
可以重用,再次调用get_data()会重新创建Subscriber
主要涉及的功能点包括:
init_subscriber() 创建Subscriber
destroy() 销毁Subscriber
callback() 接收到消息的回调函数
createTimer() 创建定时器,用于判断超时关闭
timer_callback() 定时器回调,判断是否需要关闭
subscriber_flag 标志是否已经创建了Subscriber
last_call_time 记录最后调用时间
这样就实现了一个按需创建,自动关闭的Subscriber,可以根据需要启用和关闭,减少不必要的资源占用。
如果需要我可以进一步详细解释其中的功能逻辑。请指出您需要我着重解释的部分。
#!/usr/bin/env python
# coding=utf-8
import rospy
import time
import os
import threading
from threading import Lock,Thread
# 导入相关的Python库
class TemporarySubscriber(object):
# 自定义的临时Subscriber类
DEFAULT_TIME_OUT = 15
# 默认的超时时间,单位秒
def __init__(self, name, data_class, queue_size=None, tcp_nodelay=False, timeout=DEFAULT_TIME_OUT):
# 构造函数,初始化对象属性
self.name = name
# Subscriber的topic名称
self.data_class = data_class
# Subscriber的消息类型
self.queue_size = queue_size
# Subscriber的队列大小
self.tcp_nodelay = tcp_nodelay
# TCP参数,禁用延迟发送
self.timeout = timeout
# 自定义的超时时间,单位秒
self.last_call_time = 0
# 记录最后一次调用get_data()的时间
self.subscriber = None
# Subscriber对象,初始化为None
self.data = data_class()
# 接收到的消息数据,初始化为空消息
self.subscriber_flag = False
# 标志是否已经创建了Subscriber
def __del__(self):
# 析构函数,在对象被删除时调用
self.destroy()
# 关闭并销毁Subscriber
def destroy(self):
# 关闭Subscriber
if self.subscriber is not None:
self.subscriber.unregister()
# 如果Subscriber存在,注销注册
self.subscriber = None
# 置空
self.data = self.data_class()
# 消息数据重新初始化
self.subscriber_flag = False
# 标志置为False
def init_subscriber(self):
# 创建并初始化Subscriber
self.subscriber = rospy.Subscriber(self.name, self.data_class, self.callback, queue_size=self.queue_size)
# 创建Subscriber,订阅指定topic
self.createTimer()
# 创建定时器,用于判断超时关闭
def get_data(self):
# 获取订阅的数据
# 如果需要会首先创建Subscriber
self.last_call_time = time.time()
# 更新最后调用时间
if not self.subscriber_flag:
self.subscriber_flag = True
# 将标志置为True
self.init_subscriber()
# 创建并初始化Subscriber
return self.data
else:
return self.data
def callback(self, data):
# 接收到订阅消息的回调函数
self.data = data
# 保存接收到的消息数据
def createTimer(self):
# 创建定时器,用于判断是否需要关闭Subscriber
timer = threading.Timer(3 ,self.timer_callback)
timer.setDaemon(True)
timer.start()
def timer_callback(self):
# 定时器回调函数
if time.time() - self.last_call_time >= self.timeout:
self.destroy()
# 如果超过指定时间没有调用,关闭Subscriber
else:
self.createTimer()
# 否则重新创建定时器
这个临时Subscriber的使用方法如下:
from temporary_subscriber import TemporarySubscriber
sub = TemporarySubscriber("/scan", LaserScan)
需要传入topic名称和消息类型。
scan_data = sub.get_data()
第一次调用会创建Subscriber,开始接收数据。
scan_data会包含接收到的最新消息。
ranges = scan_data.ranges
print(min(ranges))
一段时间后Subscriber会自动关闭。
再次获取数据会重新创建:
scan_data = sub.get_data()
这样就可以实现按需获取数据,不需要长时间运行Subscriber。
在使用上就是导入这个类,创建实例,然后调用get_data()获取数据即可,比较简单方便。
需要注意超时时间设置合理,不要太短,保证有足够时间来接收到数据。
如果有别的问题可以继续讨论。