Python多线程事件计时器

Python多线程事件计时器,python,Python,我有一个带压力传感器的水泵。一个在输入端(低),一个在输出端(高)。我的问题是我的低压传感器。有时,低压刚好在截止点,导致电机快速启动和停止-这是不可取的。该系统运行在自制的PLS上 我是一个编程新手,3个月,但系统大部分都在工作。我需要帮助在低压报警事件之间创建计时器。我认为系统可以在30秒内发生3个事件,但如果任何一个事件在5秒内发生,系统应该关闭 因此,如果第一个事件和第二个事件之间的间隔小于5秒,电机将永久关闭。第二至第三和第三至第四个项目也是如此。在第四个事件中,如果在第一个事件和第四

我有一个带压力传感器的水泵。一个在输入端(低),一个在输出端(高)。我的问题是我的低压传感器。有时,低压刚好在截止点,导致电机快速启动和停止-这是不可取的。该系统运行在自制的PLS上

我是一个编程新手,3个月,但系统大部分都在工作。我需要帮助在低压报警事件之间创建计时器。我认为系统可以在30秒内发生3个事件,但如果任何一个事件在5秒内发生,系统应该关闭

因此,如果第一个事件和第二个事件之间的间隔小于5秒,电机将永久关闭。第二至第三和第三至第四个项目也是如此。在第四个事件中,如果在第一个事件和第四个事件之间发生的时间少于30秒,系统也将永久关闭。请记住,这是一个更大循环的一部分。以下是我能够创建的代码:

def Systemofftimer():
    EventCounter = (0)
    OneTimeLoopVarable = (0)
    While True
        if (is_low_pressure_alarm_on() and (OneTimeLoopVarable ==0)):
            Timer = time.time()
            EventCounter = EventCounter + (1)
            OneTimeLoopVarable = 1


            if EventCounter == (2) and (time.time() - Timer >= (10))
                EventCounter = EventCounter + (1)
                stop_motor()


            if EventCounter == (3) and (time.time() - Timer >= (20))
                EventCounter = EventCounter + (1)
                stop_motor()

            if EventCounter == (4) and (time.time() - Timer >= (30))
                EventCounter = EventCounter + (1)
                stop_motor()
        else:
            start_motor()

实际上,我会使用一种不同的方法来实现这一点:只需将打开的阈值设置为大于打开的阈值。例如:

这样,您就不需要处理它的时间安排,并且仍然可以消除状态转换过程中的紧张情绪。您还可以对此进行调整,以考虑传感器的噪音

编辑:

下面我已经模拟了你所问的系统。这可能比您最初想要的要多,但我想在发布之前测试一下,确保所有功能都正常工作,所以欢迎您全部或部分使用它。至于你问的计时器,它是基于Hans Then的帖子。要触发报警,只需在
PumpSystem
类上调用
Triggeralam()
。它将记录报警已触发,然后检查您在问题中提到的两种情况(5秒和30秒错误)。
self.alarms
的每个元素都包含特定秒内发生的报警数,每秒钟计时器都会触发从列表中删除最早的一秒并创建新的一秒。如果运行该程序,您可以通过按空格键触发报警,并查看列表如何更新。
MockUp
类只是用来测试和演示它是如何工作的。我想如果你决定把它的一部分插入到你正在做的工作中,你会把它移除。不管怎样,这是代码

from threading import Timer, Thread, Event

class PumpSystem():
    def __init__(self):
        self.alarms = [0 for x in range(30)]
        self.Start()
        return None

    def SetUpdateFlag(self, flag):
        self.update_flag = flag
        return True

    def Start(self):
        self.stop_flag = Event()
        self.thread = ClockTimer(self.OnTimerExpired, self.stop_flag)
        self.thread.start()
        return True

    def Stop(self):
        self.stop_flag.set()
        return True

    def TriggerAlarmEvent(self):
        self.alarms[-1] += 1
        self.CheckConditions()
        self.update_flag.set()
        return True

    def OnTimerExpired(self):
        self.UpdateRunningAverage()

    def CheckConditions(self):
        # Check if another error has triggered in the past 5 seconds
        if sum(self.alarms[-5:]) > 1:
            print('5 second error')

        # Check if more than 3 errors have triggered in the past 30 seconds
        if sum(self.alarms) > 3:
            print('30 second error')

        return True

    def UpdateRunningAverage(self):
        self.alarms.append(0)
        self.alarms.pop(0)
        self.update_flag.set()
        return True

class ClockTimer(Thread):
    def __init__(self, callback, event):
        Thread.__init__(self)
        self.callback = callback
        self.stopped = event
        return None

    def SetInterval(self, time_in_seconds):
        self.delay_period = time_in_seconds
        return True

    def run(self):
        while not self.stopped.wait(1.0):
            self.callback()
        return True


## START MOCKUP CODE ##

import tkinter as tk
class MockUp():
    def __init__(self):
        self.pump_system = PumpSystem()
        self.update_flag = Event()
        self.pump_system.SetUpdateFlag(self.update_flag)
        self.StartSensor()
        return None

    def StartSensor(self):
        self.root = tk.Tk()
        self.root.protocol("WM_DELETE_WINDOW", self.Exit)
        self.alarms = tk.StringVar()
        w = tk.Label(self.root, textvariable=self.alarms, width=100, height=15)
        self.alarms.set(self.pump_system.alarms)
        w.pack()
        self.root.after('idle', self.ManageUpdate)
        self.root.bind_all('<Key>', self.ManageKeypress)
        self.root.mainloop()
        return True

    def ManageUpdate(self):
        if self.update_flag.isSet():
            self.alarms.set(self.pump_system.alarms)
            self.update_flag.clear()
        self.root.after(1, self.ManageUpdate)
        return True

    def ManageKeypress(self, event):
        if event.keysym == 'Escape':
            self.Exit()
        if event.keysym == 'space':
            self.pump_system.TriggerAlarmEvent()
        return True

    def Exit(self):
        self.pump_system.Stop()
        self.root.destroy()


mockup = MockUp()
从线程导入计时器、线程、事件
类PumpSystem():
定义初始化(自):
self.alarms=[0表示范围内的x(30)]
self.Start()
一无所获
def SetUpdateFlag(自身,标志):
self.update_flag=标志
返回真值
def启动(自):
self.stop_标志=事件()
self.thread=时钟计时器(self.OnTimerExpired,self.stop_标志)
self.thread.start()
返回真值
def停止(自):
self.stop_flag.set()
返回真值
def触发报警事件(自身):
自报警[-1]+=1
self.CheckConditions()
self.update_flag.set()
返回真值
def OnTimerExpired(自):
self.UpdateRunningAverage()
def检查条件(自身):
#检查在过去5秒内是否触发了其他错误
如果总和(自报警[-5:])>1:
打印(“5秒错误”)
#检查在过去30秒内是否触发了3个以上的错误
如果总和(自报警)>3:
打印(“30秒错误”)
返回真值
def更新平均值(自身):
self.alarms.append(0)
self.alarms.pop(0)
self.update_flag.set()
返回真值
类时钟计时器(线程):
定义初始化(自、回调、事件):
线程。\uuuu初始化\uuuuu(自)
self.callback=回调
self.stopped=事件
一无所获
def设置间隔(自身,时间单位为秒):
self.delay\u period=以秒为单位的时间
返回真值
def运行(自):
而不是自我。已停止。等待(1.0):
self.callback()
返回真值
##启动模型代码##
将tkinter作为tk导入
类实体模型():
定义初始化(自):
self.pump_system=PumpSystem()
self.update_flag=事件()
self.pump\u system.SetUpdateFlag(self.update\u标志)
self.StartSensor()
一无所获
def起动传感器(自身):
self.root=tk.tk()
self.root.protocol(“WM\u DELETE\u WINDOW”,self.Exit)
self.alarms=tk.StringVar()
w=tk.Label(self.root,textvariable=self.alarms,宽度=100,高度=15)
自报警设置(自泵系统报警)
w、 包()
self.root.after('idle',self.ManageUpdate)
self.root.bind_all(“”,self.ManageKeypress)
self.root.mainloop()
返回真值
def管理器更新(自我):
如果self.update_flag.isSet():
自报警设置(自泵系统报警)
self.update_flag.clear()
self.root.after(1,self.ManageUpdate)
返回真值
def ManageKeypress(自身,事件):
如果event.keysym=='Escape':
self.Exit()
如果event.keysym==“空格”:
自泵系统触发报警事件()
返回真值
def出口(自):
自停泵系统停止()
self.root.destroy()
实体模型

这看起来可能很多,但有一半是你可以忽略的模型类。如果您有什么不明白的地方,请告诉我,我很乐意解释发生了什么。

HI hobenkr是的,我同意我尝试过这种方法,但输入压力会慢慢降低(通过慢慢堵塞的过滤器),因此无论我将截止阀放在哪里,压力迟早都会在那里徘徊。谢谢你的快速回复:)我想我不小心把我的图形弄反了:)如果你在较低的阈值打开泵,这会不会把压力推回到较高的阈值,在那里它会关闭,然后漂移回来