python机器人编程——无人机python联动控制实现(VREP仿真)1——手搓一个类ROS机器人消息订阅发布模块

2023-10-26

一、前言

我们知道ROS是一个开源的机器人系统,有人叫他是操作系统,里面有丰富的生态,如导航等,很多大学搞研究都利用它。但是,使用ROS很多是基于linux系统,并且需要按照,学习,同时,很多用ROS可能只是为了使用它的消息发布订阅机制,由于其基于的是进程间的通信,可能对通信的实时性也有一些影响。本章,我们来手搓一个纯python构建的类似ROS系统的消息订阅发布系统,非常轻量级,可以在开发机器人时候,想轻量化不想装ROS系统的朋友们。并且我们把这个消息模块用在了无人机仿真控制环境如下:
在这里插入图片描述

接下来开搞…

二、总体设想

开发这个分布订阅系统的目的,我们想是作为一个机器人系统的“中枢神经”系统,用于跟硬件打交道,并为上层运动控制软件提供消息输入输出的服务,并且需要保持一定的实时性,满足实时控制,整个框架设想如下:
在这里插入图片描述

三、系统的组成

如上图所示,我们的一个消息订阅发布系统可以负责跟硬件打交道,通过如串口、以太网口通信的方式去和采集硬件如网关进行通信,这个我们在这里命名为“第一级原始信号通讯”,然后我们会进入一个预处理模块,对原始信号进行一些预处理,这个预处理模块根据需要我们可以自定义修改,预处理的型号变成了上层模块想要的格式和频率的TOPIC(主题)后,可以将这个TOCPIC发布出来,供多个用户订阅后使用,这个过程我们命名为“第二级信号预处理”。经过这个两级处理,从底层传感或者部件采集的不同频率、不同格式数据就变成了可以供上层应用的有固定周期和格式的TOPIC。接下来就可以做各种应用模块了。

四、python代码构建

构建一个MessageBroker消息代理类

python实现的消息代理类其实也非常常见了,网上到处都是,这里我们结合了一下协程的概念,对普通的消息代理类进行了一些优化,利用协程的高性能特性,势必可以在大量的消息来源服务下保持一个好的性能,这部分有待压力测试,发布本博文前并未经过性能测试。源代码如下:

以下这个是常规的MessageBroker类:

class MessageBroker:
    #同步消息订阅分发处理
    def __init__(self):
        self.message_queue = queue.Queue()
        self.subscribers = {}
        self.running=True

    def publish(self, topic, message):
        if self.running:
            self.message_queue.put((topic, message))
        else:
            print("MessageBroker is already stopped")
            

    def subscribe(self, topic, callback):
        if self.running:
            if topic not in self.subscribers:
                self.subscribers[topic] = []
            self.subscribers[topic].append(callback)
        else:
            print("MessageBroker is already stopped")
  
    def unsubscribe(self, topic, callback):
        if topic in self.subscribers:
            if callback in self.subscribers[topic]:
                self.subscribers[topic].remove(callback)

    def start(self):
        self.running=True
        def worker():
            while True:                
                topic, message = self.message_queue.get()
                #print("worker..")
                if message=="close":
                    print("MessageBroker thread stoped")
                    break
                if topic in self.subscribers:
                    for callback in self.subscribers[topic]:
                        callback(message)
                self.message_queue.task_done()
        thread = threading.Thread(target=worker)
        thread.daemon = True
        thread.start()
        print("broker started at:",thread)
    def close(self):
        self.running = False
        self.subscribers.clear()
        self.message_queue.put(('stop', "close"))
        del self.message_queue
        self.message_queue=queue.Queue()

以下这个是引入协程的MessageBroker类:

class MessageBrokerAsy:
    #高性能异步步消息订阅分发处理
    def __init__(self):
        self.message_queue = queue.Queue()
        self.subscribers = {}        
        self.thread=None
        self.running=True
        #self.condition = asyncio.Condition()

    def publish(self, topic, message):
        if self.running:
            self.message_queue.put((topic, message))
            return True
        else:
            print("MessageBroker is already stopped")
            return 

    def subscribe(self, topic, callback):
        if self.running:
            if topic not in self.subscribers:
                self.subscribers[topic] = []
            #asy_callback=self.make_async(callback)
            self.subscribers[topic].append(callback)
            return True
        else:
            print("MessageBroker is already stopped")
            return 
         
    def unsubscribe(self, topic, callback):
        if topic in self.subscribers:
            if callback in self.subscribers[topic]:
                self.subscribers[topic].remove(callback)
   
    async def main(self):        
        while True:  
            if self.running==False:
                print("MessageBroker thread stoped")
                break
            topic, message = self.message_queue.get()
            if topic in self.subscribers:
                callbacks = self.subscribers[topic]
                for callback in callbacks:
                    if inspect.iscoroutinefunction(callback):
                        await callback(message) 
                    else:
                        callback(message)                         
                    #asyncio.run(dotasks())                    
            self.message_queue.task_done() 
    def start(self):            
        def worker():
            self.running=True
            asyncio.run(self.main())             
 
        thread = threading.Thread(target=worker)
        thread.daemon = True
        thread.start()
        self.thread=thread
        print("broker started at:",thread)
    def close(self):
        self.running = False
        time.sleep(1)
        self.subscribers.clear()       
        del self.message_queue
        self.message_queue=queue.Queue()

如上所述,我们可以实例化这个类之后,通过start()启动这个消息服务,并且是在新线程中运行,不会影响主线程,也保持了一定的实时性,然后在main()这个消息分发处理方法中,采用了协程处理,这样理论上会提高处理时间。
此外,可以通过subscribeunsubscribe 来订阅相关的主题,用publish 发布主题:

下面是使用MessageBroker消息代理类

if __name__ == '__main__':	
	MB=MessageBrokerAsy()#创建一个消息系统
	MB.start()#启动一个消息系统
	 # 订阅者1的回调处理函数
    async def subscriber1(message):
        print("Subscriber 1 received:", message,time.perf_counter())        
   # 订阅者2的回调函数
    def subscriber2(message):
        print("Subscriber 2 received:", message)	
	# 订阅主题为"topic1"的消息,可以支持多个处理函数(用户)
    broker.subscribe("topic1", subscriber1)
    broker.subscribe("topic1", subscriber2)
	for i in range(20):
        # 模拟采集数据,发布消息到主题"topic1"
        MB.publish("topic1", np.array([11,1.5]))        
        time.sleep(0.5)
    MB.close()   

运行如下:
在这里插入图片描述

构建一个DataProcessor消息预处理类

根据我们的设想,是要建设一个消息预处理系统,也就是对原始数据进行加工处理,将原始数据按照一定的频率发布出去供上层订阅使用。这个DataProcessor是这么构建的:

class DataProcessor:
    def __init__(self, interval,broker=None,topic=None,processer=None):
        self.interval = interval        
        self.data_queue1 = []
        self.data_queue2 = []
        self.queue_shift=1
        if processer==None:#默认为均值过滤器
            self.processer=self.Everage_Filter
        else:
            self.processer=processer
        #输出逻辑
        if broker==None:
            self.broker=self
        else:
            self.broker=broker
        #发布的主题
        if topic==None:
            self.topic="Notopic"
        else:
            self.topic=topic
        
    def publish(self, topic, message):
        print(topic, message)        

    def Everage_Filter(self,data_queue):
        # 均值过滤,处理队列内的数据的逻辑,数据指定为np格式        
        if len(data_queue)>0:
            average = sum(data_queue) / len(data_queue)
            data_queue.clear()      
            #print("done:",average)
        else:
            print("empty done:",average,time.perf_counter())
        return average

    async def process_data(self):
        while True:
            processed_data=None
            if self.queue_shift==1:
                data_queue=self.data_queue1
                if len(data_queue) > 0:
                    self.queue_shift=2
                    # 处理队列内的数据
                    processed_data = self.processer(data_queue)
                    print("Processed data1:")
                    self.broker.publish(self.topic,processed_data)
            if self.queue_shift==2:
                data_queue=self.data_queue2                
                if len(data_queue) > 0:
                    self.queue_shift=1
                    # 处理队列内的数据
                    processed_data = self.processer(data_queue)
                    print("Processed data2:")            
                    self.broker.publish(self.topic,processed_data)
            await asyncio.sleep(self.interval)   

    def add_data(self, data):
        # 向队列中添加数据,多个容器,避免冲突
        if self.queue_shift==1:
            self.data_queue1.append(data)
        if self.queue_shift==2:
            self.data_queue2.append(data)
    async def start(self):
        # 启动主循环
        #loop = asyncio.get_event_loop()
        #loop.create_task(self.process_data())
        #loop.run_forever()       
        return asyncio.create_task(self.process_data())

如上所述,我们在DataProcessor初始化时定义了interval 消息更新的周期,broker 指定的分发模块,topic 预处理完后的消息名称如“机械臂末端坐标”,processer 预处理的自定义函数,预处理默认我们内置了一个在周期内取平均的过滤器。这样就可以把各路原始数据来自一级系统进行预处理后在二级系统broker中进行发布了。
此外,我们知道原始数据路数非常多,如果使用串行进行预处理肯定是不合理的,特别是用到某些耗时的预处理函数时,那么我们还是引入了协程处理的方式,通过再开启一个线程,并集中创建预处理任务的方式,让各路预处理函数平行运行,这样就提高了效率。于是我们再要构建一个类DataProcessors

构建一个DataProcessors平行协程处理类

这个类的代码如下:

class DataProcessors:
    def __init__(self):
        self.DataPros=[]
        self.tasks=[]
        self.stop=False
        self.T=None
        self.main_queue= queue.Queue()
    def add(self,DataPro):
        self.DataPros.append(DataPro)       
    
    def close(self):
        self.stop=True
        self.DataPros.clear()
        
    def start(self):
        #创建新线程,启动所有周期处理
        async def main():
            # 启动主循环
            # 在主线程中创建并行的协程定时任务
            """
            async def datasource(processor):
                while True:
                    #print("Running task 2...")
                    # 在这里编写您的定时任务逻辑
                    processor.add_data(101)
                    processor.add_data(111)
                    processor.add_data(130)
                    await asyncio.sleep(0.5)  # 设置定时任务的时间间隔为10秒
            """    
            #task2=datasource            
            for DataPro in self.DataPros:
                self.tasks.append(await DataPro.start()) 
                #await asyncio.gather(task1(), task2(processor))        
                #task2_obj = asyncio.create_task(task2(DataPro))
            
            while True:
                print("DataProcessors main runing")
                await asyncio.sleep(5) 
                if self.stop:
                    break
            #task1_obj.cancel()            
            #task2_obj.cancel()
            print("DataProcessors  stoped")
        
        def run():
            print("Starting main program...")
            asyncio.run(main())
        thread = threading.Thread(target=run)
        thread.daemon = True
        thread.start()
        print("DataProcessors started at:",thread)
        self.T=thread
        return thread

综合应用示例

结合以上三个模块,我们就完成了本标题的一个类ROS机器人消息订阅发布模块,以下是简易使用:

if __name__ == '__main__':
    # 示例用法
    broker = MessageBrokerAsy()
    # 启动消息分发系统
    broker.start()
    
    # 创建一个DataProcessor对象
    processor = DataProcessor(interval=1,broker=broker,topic="topic2")  # 设置时间周期为5秒
    DataProcessors1=DataProcessors()
    DataProcessors1.add(processor)
    T=DataProcessors1.start() 
    
    # 订阅者1的回调函数
    async def subscriber1(message):
        #print("Subscriber 1 received:", message,time.perf_counter())
        processor.add_data(message)
        
    # 订阅者1的回调函数
    async def subscriber3(message):
        print("Subscriber 3 received:", message,time.perf_counter())
        
        
    # 订阅者2的回调函数
    def subscriber2(message):
        print("Subscriber 2 received:", message)
    # 订阅者2的回调函数
    def subscriber4(message):
        print("Subscriber 4 received:", message)
 
    # 订阅主题为"topic1"的消息
    broker.subscribe("topic1", subscriber1)
    #broker.subscribe("topic1", subscriber3)
    
    broker.subscribe("topic1", subscriber2)
    broker.subscribe("topic2", subscriber4)

    # 取消订阅主题"topic1"的消息
    #broker.unsubscribe("topic1", subscriber2)
    
    for i in range(20):
        # 发布消息到主题"topic1"
        broker.publish("topic1", np.array([11,1.5]))
        broker.publish("topic1", np.array([1.1,1.5]))
        broker.publish("topic1", np.array([12,1.5]))
        broker.publish("topic1", np.array([1.1,1.5]))
        time.sleep(0.5)
    
    DataProcessors1.close()
    time.sleep(6)
    broker.close()

如上所述,我们对一级原始数据通过broker进行发布"topic1"给预处理器processor,processor在processors的线程里周期处理原始数据,处理完后按照周期为1s定时进行发布"topic2","topic2"即为成品数据,给subscriber4使用。
在这里插入图片描述
如上图,红框为原始数据,红线为预处理后的成品数据(这里是平均值)。

五、总结

好了到此,我们构建了一个非常轻量的类ROS机器人消息订阅发布模块,当然跟ROS其实没有半毛钱关系,也没法比较,只是一个说头。源码已经上传至本站资源库点击连接。需要请下载获取或者关注公众号回复获取。
下一篇我们将这个系统用于无人机的控制,尽情期待…
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python机器人编程——无人机python联动控制实现(VREP仿真)1——手搓一个类ROS机器人消息订阅发布模块 的相关文章

  • 在 Mac OS 10.14.2 上的 Python 3.7 中安装 JPype1 时出错

    我在系统中安装 JPype1 时遇到错误 我正在使用Python 3 7 JPype1 是 Jaydebeapi 的依赖项 pip install Jpype1 以下是错误消息 Collecting jpype1 Using cached
  • 如何使用 lstm 执行多类多输出分类

    I have multiclass multioutput classification see https scikit learn org stable modules multiclass html https scikit lear
  • 如何向数据添加填充以使其可以接受 pycrypto 库中的 AES256 加密算法

    有人可以告诉我如何向数据添加填充 使其可以接受 pycrypto 库 Python 中的 AES256 加密算法 提前非常感谢 看着文档 http www dlitz net software pycrypto doc 看来要由图书馆用户自
  • Pandas:根据其他多级列对最里面的列进行分组排序

    考虑下面的 df In 3771 df pd DataFrame A a 11 B b 11 C C1 C1 C2 C1 C3 C3 C2 C3 C3 C2 C2 D D1 D2 D1 D3 D3 D2 D4 D4 D1 D2 D3 E v
  • numpy.linalg.inv() 是否给出了正确的矩阵逆?编辑:为什么 inv() 给出数值错误?

    我有一个矩阵形状 4000 4000 我想取逆矩阵 我对逆矩阵的直觉因如此大的矩阵而崩溃 起始矩阵的值大小为e 10 具有以下值 print matrix给出一个输出 2 19885119e 10 2 16462810e 10 2 1306
  • 检查字符串是否以 XXXX 开头

    我想知道如何在Python中检查字符串是否以 hello 开头 在 Bash 中我通常这样做 if string hello then do something here fi 我如何在Python中实现同样的效果 aString hell
  • 在Python中将距离矩阵转换为成对距离列表[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 假设Python中有以下距离矩阵 0 1 2 3 0 0 1 4 8 1 1 0 3 7 2 4 3 0 3 3 8 7 3 0 我想
  • 在python中浏览ftp目录

    我正在尝试使用 ftplib 使用 Python 3 从 ftp 服务器下载多个文件夹 我有一个文件夹名称列表 它们都位于文件夹 root 中 问题是我不知道如何浏览它们 当我使用cwd我可以进入更深的目录 但是如何再次起来呢 我正在尝试得
  • ctypes.ArgumentError:不知道如何转换参数

    我在C库中定义了一个函数 如下所示 int Test char str1 int id1 char str2 float val float ls 我想在Python中使用它 所以我编写了以下Python代码 str1 a str2 b i
  • seaborn 未在定义的子图中绘制

    我正在尝试用这段代码并排绘制两个图表 fig ax1 ax2 plt subplots 1 2 sns displot x X train Age hue y train ax ax1 sns displot x X train Fare
  • Altair 条形图具有可变宽度的条形?

    我正在尝试在 Python 中使用 Altair 制作条形图 其中条形的宽度根据源数据帧列中的数据而变化 最终目标是获得如下所示的图表 条形的高度对应于每种能源技术的边际成本 在源数据框中以列形式给出 条形宽度对应于每种能源技术的容量 也以
  • 如何将文本文件中的十六进制行转换为数组(Python)?

    我有一个文本文件 每行包含一个十六进制明文 我的文件如下所示 7a8e5dc390781eab8df2c090bf4bebca dbac0fba55d3d4fc177161bfe24dc7fb 82e5a7a021197f6fbe94a86
  • 如何使用 Tkinter 创建等宽网格列?

    如何强制 Tkinter 应用程序窗口中的列宽度相等 tkdocs网站声明如下 每列的宽度 或每行的高度 取决于列或行中包含的小部件的宽度或高度 这意味着当绘制用户界面并将其划分为行和列时 您无需担心每列或行的宽度相等 或高度 大概 TkD
  • 您能否从函数、args 和 kwargs 确定变量将如何分配?

    我有一些样板逻辑 我想包装几个具有相同可选关键字的函数 现在看起来像下面的代码 但是 这仅处理 opt key 作为关键字传递的情况 而不是按位置传递 解决这个问题的一种方法是了解如何解决参数分配 是否有一些元函数接受函数 args 和 k
  • 在 matplotlib 中分割图例

    是否有可能将一个大图例分成多个 通常是 2 个 较小的图例 from pylab import t arange 0 0 2 0 0 01 s sin 2 pi t plot t s linewidth 1 0 label Graph1 g
  • 是否有比 .apply() 更慢或更受控制的替代方案?

    所以这似乎是一个奇怪的问题 但我有一只熊猫DataFrame其中包含地址 我想对其进行地理编码 以便获得纬度和经度 我有可以使用的代码 apply 感谢这个非常有帮助的线程 使用 geopy pandas 的新列坐标 https stack
  • Mac 上的 PythonXY?

    如何在 Mac OS X Lion 上安装 Python 我开始了 它应该能够通过 macports 但无论如何我找不到 mac ports 网站上所述的端口 pythonXY 我对 MAC 和 pythonXY 都不太了解 但在 pyth
  • 从 s3 获取 ogg 轨道的长度而不下载整个文件

    如何在不下载整个文件的情况下获取 ogg 文件的播放长度 我知道这是可能的 因为 HTML5 标签和 VLC 都可以在加载 URL 后立即显示整个播放长度 而无需下载整个文件 有标题或我可以阅读的内容吗 也许甚至是比特率 我可以将其除以文件
  • vtkPythonAlgorithm 控制管道执行

    我正在尝试用 python 编写一个 vtk 过滤器ProjectDepthImage进行投影不是问题 它控制 vtk 管道的执行 基本上 我对 UserEvent 有一个回调 当用户在渲染窗口处于活动状态时按下 u 键时会触发该回调 这将
  • 媒体文件上的 404 - Django

    昨晚我将项目上传到 pythonanywhere com 我想在那里测试我的项目生产设置 在我允许的模型之一中用户上传JPG 团队徽标 上传过程运行良好 文件位于我的 MEDIA ROOT 中 问题是 当我尝试在模板中访问它 以将其显示在页

随机推荐

  • HTML中Table表格的使用与漂亮的表格模板

    1 表格标记 表格是网页中十分重要的组成元素 表格用来存储数据 包含标题 表头 行和单元格 在HTML语言中 表格标记使用符号 table 表示 定义表格光使用 table 是不够的 还需要定义表格中的行 列 标题等内容 标记 说明 表格标
  • Vue2 项目里,使用 Element 的 dialog 里嵌套 tabs,导致关闭 dialog 时浏览器卡死问题

    Vue2 项目里 使用 Element 的 dialog 里嵌套 tabs 导致关闭 dialog 时浏览器卡死问题 解决办法 给 tab 添加 v if 绑定 dialog 的 visible sync
  • 如何查看awr/statspack报表,来定位系统的问题

    author skate time 2010 03 25 如何查看awr statspack报表 来定位系统的问题 数据库的性能指标一般都有什么 只有定好指标才能判定系统的性能 性能参考指标一般有如下几个 1 响应时间 平均每事务的响应时间
  • QT 使用QLibrary加载动态库

    简介 使用QLibraryi可以在程序运行时加载动态链接库 一个QLibrary的实例作用于一个单一的共享库上 QLibrary提 供了一种平台无关的方式访问库中的函数 可以在构建QLibrary的实例时将要加载的库文件传入 也可以在创建
  • python/元组、列表、字典

    Python 的元组与列表类似 不同之处在于元组的元素不能修改 元组使用小括号 列表使用方括号 字典使用 下面用一个实例来体验一下 s list input r 创建一个字典 for i in s r i r get i 0 1 看下文解释
  • 引爆点--读书有感

    有个理念一直在我心里 都说流行都是轮回 如何去让产品抓住流行趋势 究竟是什么造就了流行 如何去学习 看看周围的世界吧 它看上去似乎雷打不动 无法改变 但只要你找准位置 轻轻一触 它就可能倾斜 书籍理念 个别人物法则 附着力因素法则和环境威力
  • 单片机控制直流电机(风扇)电路详解

    单片机引脚为什么无法直接控制电机或风扇 我们在使用单片机去控制 5V的直流电机或者散热风扇时 可能会有一种疑惑 51单片机的引脚电压为 5V 为什么不直接用单片机引脚去驱动电机或者风扇 实际上单片机的控制引脚 不管是51单片机或者stm32
  • Linux安装python显示“软件包python没有可安装候选”

    在Linux中安装python时 调用 sudo apt get install python 命令出现以下问题 sudo apt get install python sudo lyx 的密码 正在读取软件包列表 完成 正在分析软件包的依
  • java中public/private/protected的具体区别

    java中public private protected的具体区别 public public表明该数据成员 成员函数是对所有用户开放的 所有用户都可以直接进行调用 private private表示私有 私有的意思就是除了class自己
  • 深度学习——更深层次的神经网络

    一个深层次的CNN网络结构 这里使用的卷积层全都是3 3的小型滤波器 特点是随着层的加深 通道数变大 卷积层的通道数从前面的层开始按顺序以16 16 32 32 64 64的方式增加 此外 插入了池化层 以逐渐减小中间数据的空间大小 并且
  • C++ 字符串

    C 提供了以下两种类型的字符串表示形式 C 风格字符串 C 引入的 string 类类型 C 风格字符串 C 风格的字符串起源于 C 语言 并在 C 中继续得到支持 字符串实际上是使用 null 字符 0 终止的一维字符数组 因此 一个以
  • OpenMV的单颜色识别讲解

    OpenMV的官方教程 寻找色块 single color rgb565 blob tracking示例讲解 视频讲解 需要提前看的文章 程序烧录 颜色阈值设置 目录 threshold index和thresholds解析 固定代码部分
  • Vue记住滚动条位置 scrollBehavior + debounce

    Vue记住滚动条位置 1 先给占位符加一层缓存 2 在路由上加一个源信息meta 记录滚动条的top值 3 使用 scrollBehavior 4 给页面添加事件监听 使用前端路由 当切换到新路由时 想要页面滚到顶部 或者是保持原先的滚动位
  • 浅谈 js运行机制 、宏观任务、微观任务

    今天我们谈一下我对js 运行机制 和宏观任务 微观任务的理解 js运行机制有同步运行和异步运行 js是单线程运行模式在进入任务当中如果是同步任务 那么就直接被主线程运行 如果是异步任务 那么就进入任务队列中进行等待运行 直到主线程任务执行完
  • 二叉树基础

    文章目录 一 树的基础 1 树的概念 2 非树 3 树的相关概念 image 20220402143804166 https img blog csdnimg cn img convert a8bbb6f8483be3ca9edd9e354
  • 虚假人脸检测实验

    虚假人脸检测实验 虚假人脸识别 数据集链接 链接 https pan baidu com s 1ZY7 PqPGsxCBFerpfRW13Q pwd 0w2r 或者https download csdn net download weixi
  • 关于Windows Mobile手机视听电脑视音频的程序实现(一)

    心情不好 突然想写博客了 嘿嘿 其实这一个程序是差不多一年前实现的 那时正好着手一个项目 同时后来也因为这一个项目买了一款多普达手机 呵呵 这一个项目大概实现这么一个功能 电脑 服务器端 安装一个用于抓取摄像头与麦克风的数据 Windows
  • Qt元对象系统

    元对象系统 Meta Object System 元对象系统是一个基于标准C 的扩展 为Qt提供了信号与槽机制 实时类型信息 动态属性系统 元对象系统的三个基本条件 类必须继承自QObject 类声明Q OBJECT宏 默认私有有 元对象编
  • 如何解决幻读?

    一 什么是幻读 幻读 一个事务按相同的查询条件重新读取以前的检索过的数据 却发现其他事务插入了满足其条件查询的新数据 这种现象被成为幻读 进行了读取 分别读取了不同的数据 重点在于新增 insert 针对多笔数据 举个例子 事务A对数据进行
  • python机器人编程——无人机python联动控制实现(VREP仿真)1——手搓一个类ROS机器人消息订阅发布模块

    目录 一 前言 二 总体设想 三 系统的组成 四 python代码构建 构建一个MessageBroker消息代理类 以下这个是常规的MessageBroker类 以下这个是引入协程的MessageBroker类 下面是使用MessageB