首页 > 解决方案 > 从 Arduino 绘制实时串行数据,除非手动关闭,否则绘图不会更新?

问题描述

我正在使用带有温度传感器的 Arduino,并使用 python 将数据保存为 csv。具体来说,arduino 正在打印出两组值,一组用作时间度量(数字每 10 秒增加 1),一组详细说明温度读数。我设置了 arduino 打印 10 个值然后等待 10 秒。然后,python 代码取 10 个读数的平均值。我想绘制这两个实时更新的值。我将在下面添加代码。它原则上有效,但是,它不会在每次测量后更新图形。我必须手动关闭图形窗口,然后它才会显示下一个图的图形。测量似乎一直在后台运行,例如,如果我等待 60 秒,我将在它“赶上”之前打开/关闭 6 个图表

import serial
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

x_vals = []
y_vals= []
plt.style.use('fivethirtyeight')
num_averages=10

filename = "E:/Python/Data/TemperatureReadPlotreadings.csv"

port = "COM3"
baudrate = 9600
arduino = serial.Serial(port, baudrate)

arduino.flush()

def readdata():
    dataline = arduino.readline()
    try:
        y = dataline.decode("ascii").strip().split(",")
        for i in range(len(y)):
            y[i] = float(y[i])    
        return y
    except ValueError:
        arduino.flush()
        y = [0,0]
        return y

def save_data(filename, mean, stddev):
    print("Saving data")
    
    datafile = open(filename, 'a')
    
    datafile.write("{0:6.2f}".format(mean[0])+ "," + "{0:6.3f}".format(stddev[0])+ "," + "{0:9.2f}".format(mean[1])+ "," + "{0:9.3f}".format(stddev[1])+ "\n")
   
    datafile.close()
def animate(i):
            x_vals.append(mean[0])
            y_vals.append(mean[1])
            
            plt.cla()
            plt.plot(x_vals, y_vals, label = "LM35")
            
run = True
while run:
    try:  
        data = np.zeros((2,num_averages))
        mean = np.zeros(2)
        stddev = np.zeros(2)
        for i in range(num_averages):
            data_new = readdata()
            data[0,i] = data_new[0]
            data[1,i] = data_new[1] 

        for i in range(2):
            mean[i] = np.mean(data[i,:])
            stddev[i] = np.std(data[i,:])

        save_data(filename, mean, stddev)
        
        
        ani = FuncAnimation(plt.gcf(), animate, interval=10000)
    
        plt.tight_layout()
        plt.draw()
        plt.show()

                                     
        
    except KeyboardInterrupt:
         print('\nExiting')
         run = False




    
        



标签: pythonmatplotlibarduino

解决方案


我认为您需要查看 Animation 类的工作原理。FuncAnimation()只调用一次。它会animate()定期调用。

请参阅此处的示例和说明:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], 'ro')

def init():
    ax.set_xlim(0, 2*np.pi)
    ax.set_ylim(-1, 1)
    return ln,

def update(frame):
    xdata.append(frame)
    ydata.append(np.sin(frame))
    ln.set_data(xdata, ydata)
    return ln,

ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
                    init_func=init, blit=True)
plt.show()

此外,您不需要在animate(). 你只需要更新线(Line2D)就好了ln.set_data(xdata, ydata)plt.plot()只调用一次并返回Line2D对象。

我看到你需要readdata()定期打电话来获取你的数据。你可以这样做,animation()但我建议你在一个单独的线程中运行它:

#import threading
.
.
.
yourDataReadingThread = threading.Thread(target=readdata)
yourDataReadingThread.start()

更多关于线程在这里

这将运行readdata()一次。所以在里面readdata()你需要一个循环,就像你在主线程中有一个循环一样,但这次它不会阻塞你的主线程。在这个循环中,您还可以将新数据附加到您的x_valsy_vals列表中。这样,您唯一需要调用的animate()ln.set_data(x_vals , y_vals ).


推荐阅读