Vinay
Vinay

Reputation: 11

python real time plot of serial port data has huge lag

I am trying to read from serial port and plot the data in graph using matplot. Following is my code : I see that because of plot, there is huge lag (data in queue goes up to 10000 bytes) hence i dont see real time plot coming. Can you please help me if i am doing anything wrong.

<

import serial # import Serial Library
   import numpy  # Import numpy
   import matplotlib.pyplot as plt 

   Accelerometer= []
   COM_read = serial.Serial('COM5', 9600, timeout=None,parity='N',stopbits=1,rtscts=0) #Creating our serial object name
plt.ion() #Tell matplotlib you want interactive mode to plot live data
cnt=0
COM_read.flushInput()
COM_read.flushOutput()
def makeFig(): #Create a function that makes our desired plot

    plt.title('My Live Streaming Sensor Data')      #Plot the title
    plt.grid(True)                                  #Turn the grid on
    plt.ylabel('Acc in g')                          #Set ylabels
    plt.plot(Accelerometer, 'ro-', label='Accelerometer g') #plot the temperature
    plt.legend(loc='upper left')                    #plot the legend
    plt.ylim(15000,30000)                           #Set limits of second y axis- adjust to readings you are getting


print "came through"
while True: # While loop that loops forever
    print COM_read.inWaiting()
    while (COM_read.inWaiting()==0): #Wait here until there is data
            pass #do nothing
    s  = COM_read.readline() #read the line of text from the serial port
    decx = int(s[0:4],16)
    decy = int(s[5:9],16)
    decz = int(s[10:14],16)
    if decx > 32768:
          decx = decx - 65536;
    if decy > 32768:
         decy = decy - 65536;
    if decz > 32768:
         decz = decz - 65536;
    #print decx,decy,decz
    res = ((decx*decx) + (decy*decy) + (decz*decz))**(1.0/2.0)




    Accelerometer.append(res)                     #Build our Accelerometer array by appending temp readings

    drawnow(makeFig)                       #Call drawnow to update our live graph
    plt.pause(.000001)                     #Pause Briefly. Important to keep drawnow from crashing

    cnt=cnt+1
    if(cnt>50):                            #If you have 50 or more points, delete the first one from the array
        Accelerometer.pop(0)               #This allows us to just see the last 50 data points

> ----------------Based on Dr.John's suggestion, the code is written as follows -----

import serial
import matplotlib
import threading, time
import pylab
import matplotlib.pyplot as plt
import matplotlib.animation as anim

    class MAIN:
    #ser =0;
    def __init__(self):
        self.res = 0.0
        self.ser = serial.Serial('COM5', 9600, timeout=None,parity='N',stopbits=1,rtscts=0)
        self.ser.flushInput()
        elf.ser.flushOutput()
        c = self.ser.read(1);
        while(c != '\n'):
            =self.ser.read(1)
    return

    def acquire_data(self):
        s = self.ser.readline()
        decx = int(s[0:4],16)
        decy = int(s[5:9],16)
        decz = int(s[10:14],16)
        if decx > 32768:
            decx = decx - 65536;
        if decy > 32768:
            decy = decy - 65536;
        if decz > 32768:
            decz = decz - 65536;


    self.res = ((decx*decx) + (decy*decy) + (decz*decz))**(1.0/2.0)
    print self.res
    return

ex = MAIN()
threading.Timer(2,ex.acquire_data).start() #starts function acquire_data every 2 sec and resets self.res with 0.5Hz
fig, ax = plt.subplots()
ax.plot(time.time(), self.res, 'o-')
print "closed"

Upvotes: 0

Views: 3074

Answers (1)

Dr. John James Cobra
Dr. John James Cobra

Reputation: 216

A while true loop is a bad idea in most cases.

Non-OO-Programming is a bad idea in most cases.

Appending plot-data to lists is a bad idea in most cases (laggy).

Start the data aquisition at defined times with

import threading, time
threading.Timer(2, acquire_data).start() #starts function acquire_data every 2 sec and resets self.res with 0.5Hz

then instead of the while-loop, please define class based functions for your own benefit:

class MAIN:
 def __init__(self):
    self.res = 0

 def acquire_data(self):
    ....
    return self.res

and plot with

fig, ax = plt.subplots()
ax.plot(time.time(), self.res, 'o-')

Greets Dr. Cobra

Upvotes: 1

Related Questions