python - 从 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
解决方案
我认为您需要查看 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_vals
和y_vals
列表中。这样,您唯一需要调用的animate()
是ln.set_data(x_vals , y_vals )
.
推荐阅读
- scala - 如何从 foreach 循环中获取数据框?
- kubernetes - 如何找出nodePort的ip地址
- hibernate - JpaRepository 抛出 NullPointerException
- validation - Flutter FormBuilder下拉验证不起作用
- android - 无法启动活动:Android 9 中的 java.util.ConcurrentModificationException
- python - 使用来自 pi 相机的 python 解码并显示 H.264 卡住的视频序列
- excel - Excel公式分割文本
- ruby-on-rails - Skyscanner Flight search API 与 Ruby on rails6
- python - 根据列值组合行和列名(python)
- asp.net-mvc-5 - 注销重定向到 MVC5 中的登录页面