使用arduino和pyserial绘制串行数据

时间:2014-07-19 08:22:40

标签: python numpy matplotlib arduino pyserial

我试图使用arduino和pyserial,numpy和matplotlib绘制加速度计的串行数据。问题是当GUI打开时,输入数据速率变得非常慢并且绘图也非常慢,如果我不打开GUI并且只是在命令窗口上打印数据,则接收的数据很快。 Plz帮忙!

这是我的python代码:

import serial
import matplotlib.pyplot as plt
import numpy as np
import time


ser = serial.Serial('COM3', 9600, timeout=0) #sets up serial connection (make sure baud          rate is correct - matches Arduino)

ser.flushInput()
ser.flushOutput()

plt.ion()                    #sets plot to animation mode

length = 500       #determines length of data taking session (in data points)
x = [0]*length               #create empty variable of length of test
y = 0
z = 0
fig, ax = plt.subplots()
line, = ax.plot(np.random.randn(100))
plt.show(block=False)
xline, = plt.plot(x)         #sets up future lines to be modified
plt.ylim(30,120)        #sets the y axis limits

#for i in range(length):     #while you are taking data
tstart = time.time()
n = 0
while time.time()-tstart < 5:
   y = (ser.readline().decode('utf-8')[:-2])
   if not (len(y)==0):
       z = float(y)
       x.append(float(z))   #add new value as int to current list

       del x[0]

       xline.set_xdata(np.arange(len(x))) #sets xdata to new list length

       xline.set_ydata(x)                 #sets ydata to new list

       #  ax.draw_artist(ax.patch)
       #  ax.draw_artist(line)
       #  fig.canvas.update()
       fig.canvas.draw()
       fig.canvas.flush_events()   
       #plt.pause(0.0001)                   #in seconds                                      #draws new plot
       #plt.show()
       n +=1
       print (z)
       print(n)




 ser.close() #closes serial connection (very important to do this! if you have an error   partway through the code, type this into the cmd line to close the connection)

4 个答案:

答案 0 :(得分:0)

有几件事可以加快这个过程。当我们尝试使用arduino读出地震检波器时,我们遇到了同样的问题。

主要技巧是在绘图前缓冲十个或更多值,而不是为每个新事件绘制。

使用动画包而不是手动绘图也可能加快这个过程。

查看我们的github代码: https://gist.github.com/ibab/10011590

为什么要将z 2次投射浮动:

z = float(y)
x.append(float(z))

答案 1 :(得分:0)

根据我的经验,用10 000点重绘一行可能需要5毫秒,但这取决于后端和计算机。如果你想要更快地做到这一点,那么你就麻烦了。另一方面,由于感知延迟,不需要或者每秒更新图表超过50次。

因此,正如MaxNoe所说,如果数据是快速数据,则应缓冲数据。您可以使用固定缓冲区,也可以使用超时缓冲区。 (似乎您仍然收到稳定的数据流,否则您会在ser.readline没有超时的情况下遇到问题。)

您还可以采取其他一些措施来加快代码速度。在不知道数据量的情况下,我无法说明这些是否会对性能产生任何影响。分析是关键(如James Mills所述)。

首先,您应该将xy作为ndarray(NumPy数组),以避免将列表转换为数组的开销。基本上是:

# initializing the array
x = np.zeros(length)

# adding one item to the array:
# shift the existing items and add an item to the end
x[:-1] = x[1:]
x[-1] = float(z)

另请注意,由于set_xdata保持不变,因此无需每轮xdatadatabuf = [] # collect data until you have something and at least 20 ms has gone t0 = time.time() while time.time() - t0 < 0.02 or len(databuf) == 0: ln = ser.readline() try: databuf.append(float(ln[:-2])) except: # something went wrong, but now we don't care pass n_newpoints = len(databuf) x[:-n_newpoints] = x[n_newpoints:] x[-n_newpoints:] = databuf # draw etc ... 。在循环之前做一次。

如果你最后使用缓冲,那么基于时间的缓冲在每个刷新周期大致采用这种方式:

databuf

此处{{1}}是一个列表,但由于它是一个简短的列表,转换开销无关紧要。

通过这些改进,您应该能够流畅地更新10000点的图形,而不会使计算机停止运转。如果你在性能非常适中的机器上进行此操作(RaspberryPi等),那么配方就是降低更新频率。

答案 2 :(得分:0)

当从arduino的串行端口绘制数据时,我遇到了类似的速度问题。解决方案在以下地址中描述:http://asaf.pm/wordpress/?p=113#comment-273 在这种情况下,我实现大约700fps绘制一个包含50个数据点的数组。

答案 3 :(得分:0)

我认为您面临这些性能问题的主要原因是matplotlib并非主要用于实时数据。通过脚本创建出色的数据图表确实很有用,但是添加单个样本并重绘可能不是matplotlib的亮点。

请考虑其他用于实时查看数据的选项,例如(无耻的插头)lognplot:https://github.com/windelbouwman/lognplot

可以在以下位置找到另一个有用的实时数据查看程序列表:https://arduino.stackexchange.com/questions/1180/serial-data-plotting-programs