函数在后台持续运行以收集实例变量的数据而不会阻塞

时间:2017-07-06 14:00:11

标签: python tkinter subprocess multiprocessing pyserial

问题: 如何从串口读取数据,而不会阻止GUI的其余部分发生操作。

当前问题: 我有一个GUI,无法在我需要它的时候执行所有任务。我需要读取数据 - >存储传入的数据(在文件,列表中,无关紧要) - >显示一些最近的数据点~50个用于4个不同的变量 - >在.05秒内检查GUI中的任何更改。

方法我尝试过:(我可能做错了,也许这就是为什么它没有工作)

使用计时器执行不同的功能:仍然太慢

读取数据块:仍然太慢

每隔一点格斗:仍然太慢

线程读取缓冲区:读取不完整(不确定我是否正确执行此操作,但似乎是一种很好的方法,希望看到如何对readlines进行操作的示例)

多处理:无法开始工作,但似乎是最好的方法

目前正在尝试读取打包的二进制数据以减少读取时间。

我收到的内容包含12个变量长整数值的行

int1.int2.int3 | INT1,INT2,INT3 | INT1,INT2,INT3 | INT1,INT2,INT3

我将此字符串拆分为" |"并绘制每个拆分中的一个整数变量并将所有变量存储在单独的列表中

我通过usb从arduino接收这些数据,这个数据每50ms或20Hz以该格式输出一个字符串。

我遇到的主要问题是读取串口需要很长时间,当它备份时会导致显着的延迟,我需要它是实时的。

这是我正在使用的GUI:

import Tkinter
import serial
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from matplotlib import pyplot as plt
import matplotlib.animation as animation
from collections import deque
import random
import time

class App:
    def __init__(self, master):
        self.arduinoData = serial.Serial('com5', 250000, timeout=None)

        frame = Tkinter.Frame(master)

        self.running = False
        self.ani = None

        self.run = Tkinter.LabelFrame(frame, text="Testing", borderwidth=10, relief=Tkinter.GROOVE, padx=10, pady=10)
        self.run.grid(row=0, column=0, padx=20, pady=20)

        self.run_respiration = Tkinter.Button(self.run, text="RUN",bd=10, height=5, width=10, command=self.getData)
        self.run_respiration.grid(row=0, column=0, padx=5, pady=5)

        self.test_options = Tkinter.LabelFrame(frame, text="Test Options", borderwidth=10, relief=Tkinter.GROOVE, padx=10, pady=10 )
        self.test_options.grid(row=0, column=1, padx=20, pady=20)

        self.stop = Tkinter.Button(self.test_options, text="STOP", bd=10, height=5, width=10, command=self.stopTest)
        self.stop.grid(row=0, column=0, padx=5, pady=5)


        self.fig = plt.Figure()
        self.ax1 = self.fig.add_subplot(111)
        self.line0, = self.ax1.plot([], [], lw=2)
        self.line1, = self.ax1.plot([], [], lw=2)
        self.line2, = self.ax1.plot([], [], lw=2)
        self.line3, = self.ax1.plot([], [], lw=2)
        self.canvas = FigureCanvasTkAgg(self.fig,master=master)
        self.canvas.show()
        self.canvas.get_tk_widget().grid(row=0, column=4, padx=20, pady=20)
        frame.grid(row=0, column=0, padx=20, pady=20)

    def getData(self):
        if self.ani is None:
            self.k = 0
            self.arduinoData.flushInput()
            self.arduinoData.write("<L>")
            return self.start()
        else:
            self.arduinoData.write("<L>")
            self.arduinoData.flushInput()
            self.ani.event_source.start()
        self.running = not self.running

    def stopTest(self):
        self.arduinoData.write("<H>")
        if self.running:
            self.ani.event_source.stop()
        self.running = not self.running

    def start(self):
        self.xdata = []
        self.pressure1 = []
        self.displacement1 = []
        self.cycle1 = []
        self.pressure2 = []
        self.displacement2 = []
        self.cycle2 = []
        self.pressure3 = []
        self.displacement3 = []
        self.cycle3 = []
        self.pressure4 = []
        self.displacement4 = []
        self.cycle4 = []
        self.k = 0
        self.limit = 300
        self.arduinoData.flushInput()
        self.timer()
        self.ani = animation.FuncAnimation(
            self.fig,
            self.setData,
            interval=10,
            repeat=True)
        self.arduinoData.write("<L>")
        self.running = True
        self.ani._start()


    def readData(self):
        if (self.arduinoData.inWaiting()>0):
            self.xdata.append(self.k)
            x = self.arduinoData.readline()
            strip_data = x.strip()
            split_data = x.split("|")
            actuator1 = split_data[0].split(".")
            actuator2 = split_data[1].split(".")
            actuator3 = split_data[2].split(".")
            actuator4 = split_data[3].split(".")
            self.pressure1.append(int(actuator1[0]))
            self.displacement1.append(int(actuator1[1]))
            self.cycle1 = int(actuator1[2])
            self.pressure2.append(int(actuator2[0]))
            self.displacement2.append(int(actuator2[1]))
            self.cycle2 = int(actuator2[2])
            self.pressure3.append(int(actuator3[0]))
            self.displacement3.append(int(actuator3[1]))
            self.cycle3 = int(actuator3[2])
            self.pressure4.append(int(actuator4[0]))
            self.displacement4.append(int(actuator4[1]))
            self.cycle4 = int(actuator4[2])
            if self.k > 0:
                self.line0.set_data(self.xdata, self.pressure1)
                self.line1.set_data(self.xdata, self.pressure2)
                self.line2.set_data(self.xdata, self.pressure3)
                self.line3.set_data(self.xdata, self.pressure4)
                if self.k < 49:
                    self.ax1.set_ylim(min(self.pressure1)-1, max(self.pressure4) + 1)
                    self.ax1.set_xlim(0, self.k+1)
                elif self.k >= 49:
                    self.ax1.set_ylim(min(self.pressure1[self.k-49:self.k])-1, max(self.pressure4[self.k-49:self.k]) + 1)
                    self.ax1.set_xlim(self.xdata[self.k-49], self.xdata[self.k-1])
                if self.cycle1 >= self.limit:
                    self.running = False
                    self.ani = None
                    self.ani.event_source.stop()
                    self.running = not self.running
            self.k += 1


    def setData(self, i):
            return self.line0, self.line1, self.line2, self.line3,



    def timer(self):
        self.readData()
        root.after(1, self.timer)

root = Tkinter.Tk()
app = App(root)
root.mainloop()

所以基本上我需要它,以便readData()函数能够在不阻塞GUI的其余部分的情况下运行,并使数据可以访问gui,或者能够在绘制图形时跟上传入的数据。

任何可行性或一般指导的方法都将受到高度赞赏,并提前感谢您的帮助。

0 个答案:

没有答案