我一直在研究一个项目,该项目更新标签并将其绘制在来自Arduino的实时图形中。它输出温度和湿度。我的arduino串行输出看起来像这样:
29,50,44
我使用以下代码行在python中分离串行数据:
ser = serial.Serial('COM3',9600)
pullData = ser.readline().decode('utf-8')
get_data = pullData.split(',')
我可以分开这些值,并在各自的标签中对其进行更新。但是,我无法使用这些相同的串行值来动态更新图形时,却无法正常工作。我想同时更新它们。我收到类似
的错误28,90,43 Exception in thread Thread-3: Traceback (most recent call last): File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\threading.py", line 916, in _bootstrap_inner self.run() File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\threading.py", line 864, in run self._target(*self._args, **self._kwargs) File "c:\Users\Deanne\OneDrive\Documents\Example#1\example#7.py", line 68, in animate humid = int(data_1[0]) ValueError: invalid literal for int() with base 10: '\x005\n' Exception in thread Thread-1: Traceback (most recent call last): File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\threading.py", line 916, in _bootstrap_inner self.run() File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\threading.py", line 864, in run self._target(*self._args, **self._kwargs) File "c:\Users\Deanne\OneDrive\Documents\Example#1\example#7.py", line 69, in animate temp = int(data_1[1]) ValueError: invalid literal for int() with base 10: '\x00\x00\n' Exception in Tkinter callback Traceback (most recent call last): File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py", line 1699, in __call__ return self.func(*args) File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py", line 745, in callit func(*args) File "c:\Users\Deanne\OneDrive\Documents\Example#1\example#7.py", line 86, in GetSerialData data_array2 = int(get_data[2]) IndexError: list index out of range
这个错误还在继续,我知道也许我的代码不是实现此目标或实现我想要的目标的最合适方法,但这是我从研究中得出的结果。我尝试了这种方法Trying to plot real time serial port data from Arduino in Python,但由于问题没有得到答案,因此毫无用处。我也读过很多相关的问题,但还是没有运气。我不知道如何掌握队列和线程的主题。我希望有人能指出我做错了什么。任何帮助将不胜感激。
这是我的完整代码:
from tkinter import *
import serial
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import style
import threading
my_window = Tk()
my_window.title("Graphical User Interface Demo#1")
my_window.geometry("720x720")
#For raising frames
def raise_frame(frame):
frame.tkraise()
F1 = Frame(my_window, relief = RAISED)
F2 = Frame(my_window, relief = RAISED)
F3 = Frame(my_window, relief = RAISED)
F4 = Frame(my_window, relief = RAISED)
for frame in(F1, F2, F3, F4):
frame.grid(row = 0, column = 0, sticky = "NSEW")
raise_frame(F1)
List_1 = []
List_2 = []
List_3 = []
#Initialization of Serial Comm
ser = serial.Serial('COM3', 9600)
style.use("ggplot")
a = Figure(figsize = (7,6))
plot_a = a.add_subplot(111)
plot_a.set_title('Temperature Graph')
plot_a.set_ylabel('Temperature')
plot_a.set_xlabel('Time')
plot_a.plot(List_1, 'c', marker = 'o',label = 'Degrees C')
plot_a.legend(loc= 'upper left')
b = Figure(figsize = (7,6))
plot_b = b.add_subplot(111)
plot_b.set_title('Humidity Graph')
plot_b.set_ylabel('Humidity')
plot_b.plot(List_2,'g', marker = 'o', label = 'Percentage %')
plot_c.legend(loc = 'upper right')
c = Figure(figsize = (7,6))
plot_c = c.add_subplot(111)
plot_c.set_title('Solved Water Graph')
plot_c.set_ylabel('Water Volume')
plot_c.plot(List_3,'b', marker = 'o', label = 'mL')
plot_c.legend(loc = 'upper right')
def animate_thread(i):
threading.Thread(target=animate, args=(i,)).start()
def animate(i):
pulldata = ser.readline().decode('ascii')
data_1 = pulldata.split(',')
humid = int(data_1[0])
temp = int(data_1[1])
solved_water = int(data_1[2])
List_1.append(humid)
List_2.append(temp)
List_3.append(solved_water)
plot_a.set_ylim(0,40)
plot_a.plot(List_1, 'c', marker = 'o',label = 'Degrees C')
plot_b.set_ylim(0,100)
plot_b.plot(List_2, 'g', marker = 'o',label = 'Percentage %')
plot_c.set_ylim(0,55)
plot_c.plot(List_3, 'b', marker = 'o',label = 'mL')
def GetSerialData():
pulldata = ser.readline().decode('ascii')
get_data = pulldata.split(',')
data_array = int(get_data[0])
data_array1 = int(get_data[1])
data_array2 = int(get_data[2])
label_2data.config(text = str(data_array))
label_3data.config(text = str(data_array1))
label_4data.config(text = str(data_array2))
print(pulldata)
my_window.after(10000, GetSerialData)
#For Frame One
label_1 = Label(F1, text = "Homepage of GUI", relief = "solid", font = "Times 22 bold")
label_1.grid(row = 0, column = 3)
button_1 = Button(F1, text = "Page of Humidity", relief = GROOVE, bd = 8, command = lambda:raise_frame(F2))
button_1.grid(row = 1, column = 2)
button_2 = Button(F1, text = "Page of Temperature", relief = GROOVE, bd = 8, command = lambda:raise_frame(F3))
button_2.grid(row = 1, column = 3)
button_3 = Button(F1, text = "Page of Water", relief = GROOVE, bd = 8, command = lambda:raise_frame(F4))
button_3.grid(row = 1, column = 4)
#For Frame Two
label_2 = Label(F2, text = "Temperature", relief = "solid", font = "Times 22 bold")
label_2.grid(row = 0, column = 3)
button_1 = Button(F2, text = "Back To Homepage", command = lambda:raise_frame(F1))
button_1.grid(row = 1, column = 2)
label_2_1 = Label(F2, text = "Current Value: ", relief = "solid", font = "Verdana 10 bold")
label_2_1.grid(row = 2, column = 2)
label_2data = Label(F2, font = "Verdana 10")
label_2data.grid(row = 2, column = 3)
canvas1 = FigureCanvasTkAgg(a, F2)
canvas1.get_tk_widget().grid(row = 3, column = 3)
F2.canvas = canvas1
#For Frame Three
label_3 = Label(F3, text = "Humidity", relief = "solid", font = "Times 22 bold")
label_3.grid(row = 0, column = 3)
button_1 = Button(F3, text = "Back To Homepage", command = lambda:raise_frame(F1))
button_1.grid(row = 1, column = 2)
label_3_1 = Label(F3, text = "Current Value: ", relief = "solid", font = "Verdana 10 bold")
label_3_1.grid(row = 2, column = 2)
label_3data = Label(F3, font = "Verdana 10")
label_3data.grid(row = 2, column = 3)
canvas2 = FigureCanvasTkAgg(b, F3)
canvas2.get_tk_widget().grid(row = 3, column = 3)
F3.canvas = canvas2
#For Frame Four
label_4 = Label(F4, text = "Solved Water Value", relief = "solid", font = "Times 22 bold")
label_4.grid(row = 0, column = 3)
button_1 = Button(F4, text = "Back To Homepage", command = lambda:raise_frame(F1))
button_1.grid(row = 1, column = 2)
label_4_1 = Label(F4, text = "Current Value: ", relief = "solid", font = "Verdana 10 bold")
label_4_1.grid(row = 2, column = 2)
label_4data = Label(F4,font = "Verdana 10")
label_4data.grid(row = 2, column = 3)
canvas3 = FigureCanvasTkAgg(b, F4)
canvas3.get_tk_widget().grid(row = 3, column = 3)
F4.canvas = canvas3
aniA = animation.FuncAnimation(a, animate_thread, interval = 20000, blit = False)
aniB = animation.FuncAnimation(b, animate_thread, interval = 20000, blit = False)
aniC = animation.FuncAnimation(c, animate_thread, interval = 20000, blit = False)
GetSerialData()
my_window.mainloop()
更新:我尝试使用@Novel的整洁代码。这是代码:
#from tkinter import *
import tkinter as tk # proper way to import tkinter
import serial
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import style
style.use("ggplot")
import threading
class Dee(tk.Frame):
def __init__(self, master=None, title='', ylabel='', label='', color='c', ylim=1, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.data = []
fig = Figure(figsize = (7,6))
self.plot = fig.add_subplot(111)
self.plot.set_title(title)
self.plot.set_ylabel(ylabel)
self.plot.set_ylim(0, ylim)
self.line, = self.plot.plot([], [], color, marker = 'o',label = label)
self.plot.legend(loc='upper left')
label = tk.Label(self, text = ylabel, font = "Times 22 bold")
label.grid(row = 0, column = 3)
button_1 = tk.Button(self, text = "Back To Homepage", command = F1.tkraise)
button_1.grid(row = 1, column = 2)
label_1 = tk.Label(self, text = "Current Value: ", font = "Verdana 10 bold")
label_1.grid(row = 2, column = 2)
self.label_data = tk.Label(self, font = "Verdana 10")
self.label_data.grid(row = 2, column = 3)
canvas = FigureCanvasTkAgg(fig, master=self)
canvas.get_tk_widget().grid(row = 3, column = 3)
ani = animation.FuncAnimation(fig, self.update_graph, interval = 1000, blit = False)
canvas.draw()
def update_graph(self, i):
if self.data:
self.line.set_data(range(len(self.data)), self.data)
self.plot.set_xlim(0, len(self.data))
def set(self, value):
self.data.append(value)
self.label_data.config(text=value)
my_window = tk.Tk()
my_window.title("Graphical User Interface Demo#1")
my_window.geometry("720x720")
F1 = tk.Frame(my_window)
F2 = Dee(my_window, title='Temperature Graph', ylabel='Temperature', color='c', label='Degrees C', ylim=40)
F3 = Dee(my_window, title='Humidity Graph', ylabel='Humidity', color='g', label='Percentage %', ylim=100)
F4 = Dee(my_window, title='Solved Water Graph', ylabel='Water Volume', color='b', label='mL', ylim=55)
#For Frame One
label_1 = tk.Label(F1, text = "Homepage of GUI", font = "Times 22 bold")
label_1.grid(row = 0, column = 3)
button_1 = tk.Button(F1, text = "Page of Humidity", bd = 8, command = F2.tkraise)
button_1.grid(row = 1, column = 2)
button_2 = tk.Button(F1, text = "Page of Temperature", bd = 8, command = F3.tkraise)
button_2.grid(row = 1, column = 3)
button_3 = tk.Button(F1, text = "Page of Water", bd = 8, command = F4.tkraise)
button_3.grid(row = 1, column = 4)
for frame in(F1, F2, F3, F4):
frame.grid(row = 0, column = 0, sticky = "NSEW")
F1.tkraise()
def get_data():
#Initialization of Serial Comm
ser = serial.Serial('COM3', 9600)
while True:
pulldata = ser.readline().decode('ascii')
get_data = pulldata.split(',')
F2.set(int(get_data[0]))
F3.set(int(get_data[1]))
F4.set(int(get_data[2]))
print(pulldata)
# start the thread that will poll the arduino
t = threading.Thread(target=get_data)
t.daemon = True
t.start()
my_window.mainloop()
图形和标签正在更新,但是现在出现的问题是冻结。这也给我这个错误:
Exception in Tkinter callback Traceback (most recent call last): File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py", line 1699, in __call__ return self.func(*args) File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py", line 745, in callit func(*args) File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\backends\_backend_tk.py", line 310, in idle_draw self.draw() File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\backends\backend_tkagg.py", line 12, in draw super(FigureCanvasTkAgg, self).draw() File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\backends\backend_agg.py", line 433, in draw self.figure.draw(self.renderer) File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\artist.py", line 55, in draw_wrapper return draw(artist, renderer, *args, **kwargs) File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\figure.py", line 1475, in draw renderer, self, artists, self.suppressComposite) File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\image.py", line 141, in _draw_list_compositing_images a.draw(renderer) File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\artist.py", line 55, in draw_wrapper return draw(artist, renderer, *args, **kwargs) File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\axes\_base.py", line 2607, in draw mimage._draw_list_compositing_images(renderer, self, artists) File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\image.py", line 141, in _draw_list_compositing_images a.draw(renderer) File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\artist.py", line 55, in draw_wrapper return draw(artist, renderer, *args, **kwargs) File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\lines.py", line 738, in draw self.recache() File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\lines.py", line 661, in recache self._xy = np.column_stack(np.broadcast_arrays(x, y)).astype(float) File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\numpy\lib\stride_tricks.py", line 249, in broadcast_arrays shape = _broadcast_shape(*args) File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\numpy\lib\stride_tricks.py", line 184, in _broadcast_shape b = np.broadcast(*args[:32]) ValueError: shape mismatch: objects cannot be broadcast to a single shape
我可以说它仍在工作,因为它仍在输出数据。任何帮助再次将不胜感激。谢谢。
答案 0 :(得分:0)
这是一个疯狂的猜测,它显示了如何使单个线程轮询arduino,以及如何通过使用类而不是复制/粘贴使代码更整洁:
from tkinter import *
import tkinter as tk # proper way to import tkinter
import serial
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import style
style.use("ggplot")
import threading
class Dee(tk.Frame):
def __init__(self, master=None, title='', ylabel='', label='', color='c', ylim=1, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.data = []
fig = Figure(figsize = (7,6))
self.plot = fig.add_subplot(111)
self.plot.set_title(title)
self.plot.set_ylabel(ylabel)
self.plot.set_ylim(0, ylim)
self.line, = self.plot.plot([], [], color, marker = 'o',label = label)
self.plot.legend(loc='upper left')
label = Label(self, text = ylabel, relief = "solid", font = "Times 22 bold")
label.grid(row = 0, column = 3)
button_1 = Button(self, text = "Back To Homepage", command = F1.tkraise)
button_1.grid(row = 1, column = 2)
label_1 = Label(self, text = "Current Value: ", relief = "solid", font = "Verdana 10 bold")
label_1.grid(row = 2, column = 2)
self.label_data = Label(self, font = "Verdana 10")
self.label_data.grid(row = 2, column = 3)
canvas = FigureCanvasTkAgg(fig, master=self)
canvas.get_tk_widget().grid(row = 3, column = 3)
ani = animation.FuncAnimation(fig, self.update_graph, interval = 1000, blit = False)
canvas.draw()
def update_graph(self, i):
if self.data:
self.line.set_data(range(len(self.data)), self.data)
self.plot.set_xlim(0, len(self.data))
def set(self, value):
self.data.append(value)
self.label_data.config(text=value)
my_window = Tk()
my_window.title("Graphical User Interface Demo#1")
my_window.geometry("720x720")
F1 = Frame(my_window, relief = RAISED)
F2 = Dee(my_window, title='Temperature Graph', ylabel='Temperature', color='c', label='Degrees C', ylim=40, relief = RAISED)
F3 = Dee(my_window, title='Humidity Graph', ylabel='Humidity', color='g', label='Percentage %', ylim=100, relief = RAISED)
F4 = Dee(my_window, title='Solved Water Graph', ylabel='Water Volume', color='b', label='mL', ylim=55, relief = RAISED)
#For Frame One
label_1 = Label(F1, text = "Homepage of GUI", relief = "solid", font = "Times 22 bold")
label_1.grid(row = 0, column = 3)
button_1 = Button(F1, text = "Page of Humidity", relief = GROOVE, bd = 8, command = F2.tkraise)
button_1.grid(row = 1, column = 2)
button_2 = Button(F1, text = "Page of Temperature", relief = GROOVE, bd = 8, command = F3.tkraise)
button_2.grid(row = 1, column = 3)
button_3 = Button(F1, text = "Page of Water", relief = GROOVE, bd = 8, command = F4.tkraise)
button_3.grid(row = 1, column = 4)
for frame in(F1, F2, F3, F4):
frame.grid(row = 0, column = 0, sticky = "NSEW")
F1.tkraise()
def get_data():
#Initialization of Serial Comm
ser = serial.Serial('COM3', 9600)
while True:
pulldata = ser.readline().decode('ascii')
get_data = pulldata.split(',')
F2.set(int(get_data[0]))
F3.set(int(get_data[1]))
F4.set(int(get_data[3]))
# start the thread that will poll the arduino
t = threading.Thread(target=get_data)
t.daemon = True
t.start()
my_window.mainloop()