1
votes

As titled I am using an Arduino that outputs data along the serial port. It outputs as such:

120 1.23 170 2.54 210 2.32

The left column is time in milliseconds and the right column is a voltage value between 0 and 5V. The are separated by a space. EDIT: It appears stackoverflow won't let me print in tabular form, so to make it clear, I have 120 space 1.23 \newline 170 space 2.54 and so on. The Arduino sketch I am using:

#include <eHealth.h>


unsigned long time;
// The setup routine runs once when you press reset:
void setup() {
  Serial.begin(9600);  
}

// The loop routine runs over and over again forever:
void loop() {

  float ECG = eHealth.getECG();
  time = millis();
  Serial.print(time);
  Serial.print(" ");
  Serial.print(ECG, 3); 
  Serial.println(""); 


  delay(50);    // wait for 50 millisecond
}

Now on the python end of things, I have tried a few different scripts to get it to work, but have been unsuccessful so far. I want to print the time in milliseconds along the x-axis (left column of data) against the voltage value (right column) and update the time along the x-axis so it is changing with the incoming data.

One of the pieces of code I have come across is this one, but this appears to be more suitable for plotting two pieces of data on the same graph, which is not what I want:

import sys, serial
import numpy as np
from time import sleep
from collections import deque
from matplotlib import pyplot as plt
import time


# class that holds analog data for N samples
class AnalogData:
  # constr
  def __init__(self, maxLen):
    self.ax = deque([0.0]*maxLen)       # maxLen = no. of samples?
    self.ay = deque([0.0]*maxLen)
    self.maxLen = maxLen

  # ring buffer
  def addToBuf(self, buf, val):
    if len(buf) < self.maxLen:
      buf.append(val)
    else:
      buf.pop()
      buf.appendleft(val)

  # add data
  def add(self, data):
    assert(len(data) == 2)
    self.addToBuf(self.ax, data[0])
    self.addToBuf(self.ay, data[1])

# plot class
class AnalogPlot:
  # constr
  def __init__(self, analogData):
    # set plot to animated
    plt.ion() 
    self.axline, = plt.plot(analogData.ax)
    self.ayline, = plt.plot(analogData.ay)
    plt.ylim([0,10])
   # update plot
  def update(self, analogData):
    self.axline.set_ydata(analogData.ax)
    self.ayline.set_ydata(analogData.ay)
    plt.draw()
def main():                           # main() function
  analogData = AnalogData(200)        # data range (maxLen)
  analogPlot = AnalogPlot(analogData)
  print 'plotting data...'
  # open serial port
  ser = serial.Serial('/dev/tty.usbmodem1411', 9600)
  blt = 0
  blot = []
  for i in range(5) : # total data points to plot
      line = ser.readline()
      data = [float(val) for val in line.split(" ")]
      blt = blt+1
      blot.append(float(val)) 
      #print blot
      print data
      if(len(data) == 2):
        analogData.add(data)
        analogPlot.update(analogData)     
  #close serial
  ser.flush()
  ser.close()
  time.sleep(1)
  plt.close("all")
  f=open("plot_store_1", "w")
  f.write("\n".join(str(x) for x in blot))
  plt.close("all")
# call main
if __name__ == '__main__':
  main()

Ideally I would want an output like this:

http://2.bp.blogspot.com/-IoeJ2QN-3Y0/UqeA2ZTTe9I/AAAAAAAADZg/PEOAZaCnYj0/s1600/VID_20131210_211336.mp4

1
Do you intend on using the code you posted? If not please post the code you are having a problem with. - wwii
The Arduino code, yes. The Python code I would like to since it would be more practical than starting afresh. However it is unclear to me whether this code is useful or not. - hawkar

1 Answers

0
votes

Here you have an example of how could you do what you want, but first some notes:

  1. In the commented lines you have clues of how to get the real data from the serial port (since I don't have a serial port to test it you must try it by yourself...)
  2. With N you control how many points do you want to plot at most
  3. With refreshMillis you control the refresh rate of the plot
  4. You can run the code as it is and see the example plot

Now the code:

from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
import matplotlib.figure as mfig
import PyQt4.QtGui as gui, PyQt4.QtCore as core
import collections
import time
import random

#import serial
#ser = serial.Serial('/dev/tty.usbmodem1411', 9600)
#def get_line():
#    return ser.readline()

def get_line():
    x = time.time()%10000
    y = random.random() * 5
    return "%d %.3f\n" % (x,y)

refreshMillis = 300
N = 10
xs = collections.deque(maxlen=N)
ys = collections.deque(maxlen=N)

app = gui.QApplication([])

fig = mfig.Figure()
canvas = FigureCanvasQTAgg(fig)

ax = fig.add_subplot(111)
ax.set_ylim([0,5])
line2D, = ax.plot(xs,ys)
canvas.show()

def process_line():
    line = get_line()
    data = map(float,line.split(' '))
    xs.append(data[0])
    ys.append(data[1])
    line2D.set_data(xs,ys)
    xmin, xmax = min(xs),max(xs)
    if xmin == xmax:
        ax.set_xlim([xmin,xmin+1])
    else:
        ax.set_xlim([xmin,xmax])
    canvas.draw()

timer = core.QTimer()
timer.timeout.connect(process_line)
timer.start(refreshMillis)

app.exec_()

#ser.flush()
#ser.close()