2017-06-20 130 views
2

我使用pyserial來讀取由arduino發送的數據。 Arduino每隔50毫秒發送一次數據。我試圖用兩種不同的格式接收這兩種字符串。我想知道是否有更快的方式來接收我的Python GUI中的數據,無論它是使用不同的庫,接收不同的數據類型還是優化代碼。 1格式:增加pyserial readline速度

String potcolumn = String(pot0holder) + "." + String(pot1holder) + "." + String(i) + "|" + String(int(pot0holder)+30) + "." + String(int(pot1holder)+30) + "." + String(i) + "|" + String(int(pot0holder)+60) + "." + String(int(pot1holder)+60) + "." + String(i) + "|" + String(int(pot0holder)+90) + "." + String(int(pot1holder)+90) + "." + String(i); 

本均:0.0523106797228秒閱讀

第二格式:

pressure1 = String(pot0array[0]) + "," + String(pot0array[1]); 
    displacement1 = String(pot1array[0]) + "," + String(pot1array[1]); 
    iteration1 = String(i-1) + "," + String(i); 
    full1 = pressure1 + ">" + displacement1 + ">" + iteration1; 
    pressure2 = String(pot0array[0]+30) + "," + String(pot0array[1]+30); 
    displacement2 = String(pot1array[0]+30) + "," + String(pot1array[1]+30); 
    iteration2 = String(i-1) + "," + String(i); 
    full2 = pressure2 + ">" + displacement2 + ">" + iteration2; 
    pressure3 = String(pot0array[0]+60) + "," + String(pot0array[1]+60); 
    displacement3 = String(pot1array[0]+60) + "," + String(pot1array[1]+60); 
    iteration3 = String(i-1) + "," + String(i); 
    full3 = pressure3 + ">" + displacement3 + ">" + iteration3; 
    pressure4 = String(pot0array[0]+90) + "," + String(pot0array[1]+90); 
    displacement4 = String(pot1array[0]+90) + "," + String(pot1array[1]+90); 
    iteration4 = String(i-1) + "," + String(i); 
    full4 = pressure4 + ">" + displacement4 + ">" + iteration4; 
    fulltotal = full1 + "|" + full2 + "|" + full3 + "|" + full4; 
    Serial.println(fulltotal); 

本均:0.0937848151484秒閱讀這是有道理的,因爲它是雙data

這是一個非常簡單的GUI,用於接收數據並使用pyserial,tkinter和python測試讀取時間:

import Tkinter 
import serial 
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg 
from matplotlib.figure import Figure 
from matplotlib import pyplot as plt 
import matplotlib.animation as animation 
from collections import deque 
import random 
import time 
import cProfile 

class App: 
    def __init__(self, master): 
     self.arduinoData = serial.Serial('com5', 250000, timeout=None) 

     frame = Tkinter.Frame(master) 

     self.go = 0 

     self.run = Tkinter.LabelFrame(frame, text="Testing", borderwidth=10, relief=Tkinter.GROOVE, padx=10, pady=10) 
     self.run.grid(row=0, column=0, padx=20, pady=20) 

     self.run_respiration = Tkinter.Button(self.run, text="RUN",bd=10, height=5, width=10, command=self.getData) 
     self.run_respiration.grid(row=0, column=0, padx=5, pady=5) 

     self.test_options = Tkinter.LabelFrame(frame, text="Test Options", borderwidth=10, relief=Tkinter.GROOVE, padx=10, pady=10) 
     self.test_options.grid(row=0, column=1, padx=20, pady=20) 

     self.stop = Tkinter.Button(self.test_options, text="STOP", bd=10, height=5, width=10, command=self.stopTest) 
     self.stop.grid(row=0, column=0, padx=5, pady=5) 


     frame.grid(row=0, column=0, padx=20, pady=20) 


    def getData(self): 
     return self.start() 


    def stopTest(self): 
     self.arduinoData.write("<H>") 
     self.go = 0 

    def start(self): 
     self.arduinoData.write("<L>") 
     self.go = 1 
     self.timer() 

    def readData(self): 
     if (self.arduinoData.inWaiting()>0): 
      t = time.time() 
      x = self.arduinoData.readline() 
      print str(time.time()-t)# + "\t" + str(x) 



    def timer(self): 
     if self.go == 1: 
      self.readData() 
      root.after(0, self.timer) 

root = Tkinter.Tk() 
app = App(root) 
root.mainloop() 

arduino很容易以正確的速度發送數據,它只是python gui讀取速度不夠快而無法使用。

是否有可能使用cython或C++擴展來讀取速度更快,如果有的話,是否有任何資源可以用作指導我還沒有找到任何東西。

甚至只是運行此代碼產生的0.11438秒的平均時間:

import time 
import serial 

def readData(): 
    if arduinoData.inWaiting()>0: 
     t = time.time() 
     x = arduinoData.readline() 
     y = str(time.time()-t) 
     print y 


def run(): 
    x = 5000 
    z = 0 
    while z < x: 
     readData() 
     z += 1 

if __name__ == "__main__": 
    arduinoData = serial.Serial('com5', 250000, timeout=None) 
    arduinoData.write("<L>") 
    run() 
    print('done') 

感謝所有幫助和建議

+0

您確定發送數據實際上需要50毫秒嗎? 「這只是python gui沒有足夠快地讀取我的使用。」當你沒有真正使用gui來顯示任何數據,並且顯然不會在這裏造成任何掛起時沒有意義。看起來你也是在發送端使用python。在開始跳到結論之前,您可能想要提供更多的斷言證據。還有什麼意思是「每50毫秒發送一次數據」,你是指每個字節? – snb

+1

首先,我將首先分析你的python腳本來查看掛斷的位置,因爲這50ms看起來不正確。其次,像這樣砸串一起對arduino中的ram不好,它會導致內存碎片,這會在幾次循環之後崩潰。相反,您可以使用'println'將每個位的多個「打印」(保存轉換爲字符串,然後連接)與最後一個塊進行比較 –

+0

另一個注意事項是,當性能很關鍵時,控制檯打印語句很昂貴。由於緩衝IO通道,將輸出保存到文件實際上更快。通過這種方式,輸出實際上被寫入內存緩衝區,並在緩衝區填滿時刷新到磁盤控制器。 –

回答

0

剖析我收到此作爲輸出

Ordered by: standard name 

ncalls tottime percall cumtime percall filename:lineno(function) 
    1 0.000 0.000 0.001 0.001 profile_stack.py:61(readData) 
    1 0.001 0.001 0.001 0.001 serialwin32.py:234(inWaiting) 
    2 0.000 0.000 0.000 0.000 {_ctypes.byref} 
    1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 


     270 function calls in 0.025 seconds 

Ordered by: standard name 

ncalls tottime percall cumtime percall filename:lineno(function) 
    24 0.000 0.000 0.000 0.000 __init__.py:49(create_string_buffer) 
    1 0.000 0.000 0.025 0.025 profile_stack.py:61(readData) 
    24 0.000 0.000 0.000 0.000 serialutil.py:404(getTimeout) 
    1 0.001 0.001 0.001 0.001 serialwin32.py:234(inWaiting) 
    24 0.023 0.001 0.024 0.001 serialwin32.py:242(read) 
    146 0.000 0.000 0.000 0.000 {_ctypes.byref} 
    48 0.000 0.000 0.000 0.000 {isinstance} 
    1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 
    1 0.000 0.000 0.024 0.024 {method 'readline' of '_io._IOBase' objects} 


     5 function calls in 0.001 seconds 
上面的代碼後

下面是我用來獲取此信息的代碼:

import Tkinter 
import serial 
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg 
from matplotlib.figure import Figure 
from matplotlib import pyplot as plt 
import matplotlib.animation as animation 
from collections import deque 
import random 
import time 
import cProfile 

class App: 
    def __init__(self, master): 
     self.arduinoData = serial.Serial('com5', 250000, timeout=None) 

     frame = Tkinter.Frame(master) 

     self.go = 0 

     self.run = Tkinter.LabelFrame(frame, text="Testing", borderwidth=10, relief=Tkinter.GROOVE, padx=10, pady=10) 
     self.run.grid(row=0, column=0, padx=20, pady=20) 

     self.run_respiration = Tkinter.Button(self.run, text="RUN",bd=10, height=5, width=10, command=self.getData) 
     self.run_respiration.grid(row=0, column=0, padx=5, pady=5) 

     self.test_options = Tkinter.LabelFrame(frame, text="Test Options", borderwidth=10, relief=Tkinter.GROOVE, padx=10, pady=10) 
     self.test_options.grid(row=0, column=1, padx=20, pady=20) 

     self.stop = Tkinter.Button(self.test_options, text="STOP", bd=10, height=5, width=10, command=self.stopTest) 
     self.stop.grid(row=0, column=0, padx=5, pady=5) 


     frame.grid(row=0, column=0, padx=20, pady=20) 

    def do_cprofile(func): 
     def profiled_func(*args, **kwargs): 
      profile = cProfile.Profile() 
      try: 
       profile.enable() 
       result = func(*args, **kwargs) 
       profile.disable() 
       return result 
      finally: 
       profile.print_stats() 
     return profiled_func 

    def getData(self): 
     return self.start() 


    def stopTest(self): 
     self.arduinoData.write("<H>") 
     self.go = 0 

    def start(self): 
     self.arduinoData.write("<L>") 
     self.go = 1 
     self.timer() 


    @do_cprofile 
    def readData(self): 
     if (self.arduinoData.inWaiting()>0): 
      t = time.time() 
      x = self.arduinoData.readline() 
      print str(time.time()-t)# + "\t" + str(x) 



    def timer(self): 
     if self.go == 1: 
      self.readData() 
      root.after(0, self.timer) 

root = Tkinter.Tk() 
app = App(root) 
root.mainloop()