построение последовательных данных с использованием arduino и pyserial

Я пытаюсь построить последовательные данные акселерометра, используя arduino и pyserial, numpy и matplotlib. Проблема заключается в том, что всякий раз, когда открывается графический интерфейс, скорость входящих данных становится очень низкой, а график также очень медленным, и если я не открываю графический интерфейс и просто печатаю данные в командном окне, полученные данные будут быстрыми. Пожалуйста, помогите!!

Вот мой код для питона:

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)

person appsdownload    schedule 19.07.2014    source источник
comment
Хотел бы я помочь вам ответить на этот вопрос. У меня есть и я сам играю с Arduino(s) (пока не с Python). Я не могу определить конкретную причину замедления/задержки. Вы пробовали профилировать код?   -  person James Mills    schedule 19.07.2014


Ответы (4)


Есть несколько вещей, которые могут ускорить процесс. У нас были те же проблемы, когда мы пытались считывать геофоны с помощью ардуино.

основная хитрость заключалась в том, чтобы буферизовать десять или более значений перед построением графика, а не отображать график для каждого отдельного нового события.

Использование пакета анимации вместо рисования вручную также может ускорить процесс.

Взгляните на наш код github: https://gist.github.com/ibab/10011590

Почему вы бросаете z 2 раза, чтобы плавать:

z = float(y)
x.append(float(z))
person MaxNoe    schedule 19.07.2014

По моему опыту, перерисовка одной линии с 10 000 точек занимает около 5 миллисекунд, но это зависит от серверной части и компьютера. Если вы пытаетесь сделать это намного быстрее, то у вас проблемы. С другой стороны, обновление графика чаще, чем, скажем, 50 раз в секунду не требуется или нецелесообразно из-за задержки восприятия.

Итак, как говорит MaxNoe, вы должны буферизовать данные, если это быстрые данные. Вы можете использовать либо фиксированный буфер, либо буфер с тайм-аутом. (Кажется, вы все еще получаете постоянный поток данных, иначе у вас были бы проблемы с ser.readline без тайм-аута.)

Есть еще несколько вещей, которые вы можете сделать, чтобы ускорить свой код. Не зная объема данных, я не могу сказать, имеют ли они какое-либо реальное влияние на производительность или нет. Профилирование — это ключ (как говорит James Mills).

Во-первых, вы должны иметь свои x и y как 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 каждый раунд, так как 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 — это список, но поскольку это короткий список, накладные расходы на преобразование незначительны.

С этими улучшениями вы сможете плавно обновлять график из 10000 точек без остановки компьютера. Если вы делаете это на машине с очень скромной производительностью (RaspberryPi и т. д.), то рецепт — уменьшить частоту обновления.

person DrV    schedule 19.07.2014

У меня была аналогичная проблема со скоростью при выводе данных из последовательного порта Arduino. Решение описано по следующим адресам: http://asaf.pm/wordpress/?p=113#comment-273 В этом случае я получаю около 700 кадров в секунду при построении массива с 50 точками данных.

person Marcos Lourenço    schedule 17.02.2015

Я думаю, что основная причина, по которой вы сталкиваетесь с этими проблемами с производительностью, заключается в том, что matplotlib в первую очередь не предназначен для оперативных данных. Он действительно великолепен в создании отличных диаграмм данных из скрипта, но добавление одного образца и перерисовка могут быть не той областью, в которой matplotlib сияет.

Пожалуйста, рассмотрите другие варианты просмотра данных в реальном времени, такие как lognplot (бесстыдная заглушка): https://github.com/windelbouwman/lognplot

Еще один полезный список программ для просмотра данных в реальном времени можно найти здесь: https://arduino.stackexchange.com/questions/1180/serial-data-plotting-programs

person Windel    schedule 01.04.2020