2014-07-19 112 views
2

我想繪製使用arduino和pyserial,numpy和matplotlib的加速度計的串行數據。問題是每當GUI打開時,傳入數據速率變得非常慢,並且圖也非常慢,如果我沒有打開GUI並只是在命令窗口上打印數據,則接收到的數據很快。 Plz幫忙!使用arduino和pyserial繪製串行數據

這裏是我的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) 
+0

我希望我可以幫你回答這個問題。我自己也玩過Arduino(*不用Python)*。我無法確定減速/延遲的特定原因。你有沒有試過分析代碼? –

回答

0

有幾件事情,可能加快這一進程。當我們嘗試使用arduino讀取地震檢波器時,我們遇到了同樣的問題。

主要的技巧是在繪圖之前緩衝十個或更多的值,而不是爲每一個新的事件繪圖。

使用動畫包而不是手動繪製也可能會加速該過程。

對我們的GitHub代碼看看: https://gist.github.com/ibab/10011590

的,爲什麼你施放Z 2倍浮動:

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

以我的經驗,重畫一條線,用10萬點需要也許5毫秒,但這取決於後端和計算機。如果你試圖做得更快,那麼你有麻煩了。另一方面,由於知覺延遲,更新圖形超過例如每秒50次是不需要或不合理的。

因此,如MaxNoe所述,如果數據是快速數據,則應緩衝數據。您可以使用固定緩衝區或超時緩衝區。 (看起來你仍然在接收穩定的數據流,否則你會在沒有超時的情況下出現ser.readline問題。)

還有一些其他的事情可以加快你的代碼。在不知道數據量的情況下,我無法確定這些數據是否有任何實際的性能影響。性能分析是關鍵(如James Mills所述)。

的第一件事是,你應該有你的xyndarray(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每一輪,作爲xdata保持不變。在循環之前只做一次。

如果再與緩衝結束,基於時間的緩衝去約這樣每個刷新週期:

databuf = [] 
# 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是一個列表,但因爲它是一個短名單,轉換開銷是微不足道的。

有了這些改進,您應該能夠流利地更新10,000點的圖表,而不會讓您的計算機停止磨削。如果你在一臺性能非常適中的機器(RaspberryPi等)上做這個,那麼配方就是降低更新頻率。

0

從Arduino的串行端口繪製數據時,我遇到了類似的速度問題。該解決方案在以下地址中進行了描述:http://asaf.pm/wordpress/?p=113#comment-273 在這種情況下,我實現了大約700fps的50點數據繪圖。