Reading Serial Data from Arduino with Python
Question: I'm working on a little project using the [MaxSonar EZ1 ultrasonic range
sensor](http://www.maxbotix.com/Ultrasonic_Sensors/MB1010.htm) and Arduino
Diecimila.

Using the [MaxSonar playground
code](http://playground.arduino.cc/Main/MaxSonar), I have Arduino writing the
number of inches to serial every .5 seconds, along with a delimiter. When
monitoring the serial data, the output looks similar to:

    
    
    5.13.15.12.123.39.345...
    

On the Python side, I have a basic Flask app with a /distance route that
returns a JSON object with the serial value:

    
    
    from flask import Flask
    from flask import render_template
    import serial
    import json
    import random
    
    app = Flask(__name__,
                static_folder="public",
                template_folder="templates")
    
    port = "/dev/tty.usbserial-A6004amR"
    ser = serial.Serial(port,9600)
    
    @app.route("/")
    def index():
      return render_template('index.html')
    
    @app.route("/distance")
    def distance():
      distance = read_distance_from_serial()
      return json.dumps({'distance': distance})
    
    def read_distance_from_serial():
      x = ser.read();
      a = '';
      while x is not '.':
        a += x;
        x = ser.read()
    
      print(a)
    
      return a
      # return random.randint(1, 100)
    
    if __name__ == "__main__":
      app.debug = True
      app.run()
    

And index.html is a basic site with some JS that polls /distance every half
second for a new reading. With the value, I should be able to build an
interesting UI that changes based on how close/far I am from the sonar.

    
    
    $(document).ready(function() {
    
      window.GO = function() {
    
        this.frequency = 500; // .5 seconds
    
        this.init = function() {
          window.setInterval(this.update_distance, 500);
        }
    
        this.update_distance = function() {
          $.get('/distance', function(response) {
            var d = response.distance;
            $('#container').animate({"width": d + "%"});
          }, 'json')
        }
      }
    
      go = new GO();
      go.init();
    });
    

**The Question**

The issue I'm running into is that there is no guarantee that when python
reads from serial, that there will be a value. Often times, when it polls, I
get either an empty value or a partial value, while other times it is spot on.

How can I change my technique such that I am able to consistently poll the
serial data and receive the last good reading from the Arduino serial output?


Answer: You want to set your serial reading to happen in the background and not on
demand. You can use
[threading](http://docs.python.org/2/library/threading.html) and
[Queue](http://docs.python.org/2/library/queue.html). You add your serial
values to the Queue once you determine you have a valid value, and then your
socket call simply pulls from the Queue. It'll be something like this:

    
    
    from flask import Flask
    from flask import render_template
    import serial
    import json
    import random
    
    import threading, Queue
    
    import logging
    logging.basicConfig(filename=__file__.replace('.py','.log'),level=logging.DEBUG,format='%(asctime)s [%(name)s.%(funcName)s] %(levelname)s: %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p', filemode='a')
    
    class maxSonarSerialThread(threading.Thread):
      def __init__(self, dataQ, errQ, port=None, baudrate=None):
        self.logger = logging.getLogger('sonarSerialThread')
        self.logger.debug('initializing')
        threading.Thread.__init__(self)
        self.ser = serial.Serial()
        self.ser.timeout = 1
        if port is None:
          self.ser.port = "/dev/tty.usbserial-A6004amR"
        else:
          self.ser.port = port
        if baudrate is None:
          self.baudrate = 115200
        else:
          self.baudrate = baudrate
        #self.ser.flushInput()
        self.readCount = 0
        self.sleepDurSec = 5
        self.waitMaxSec = self.sleepDurSec * self.ser.baudrate / 10
        self.dataQ = dataQ
        self.errQ = errQ
        self.keepAlive = True
        self.stoprequest = threading.Event()
        self.setDaemon(True)
        self.dat = None
        self.inputStarted = False
        self.ver = ver
    
      def run(self):
        self.logger.debug('running')
        dataIn = False
        while not self.stoprequest.isSet():
          if not self.isOpen():
            self.connectForStream()
    
          while self.keepAlive:
            dat = self.ser.readline()
            //some data validation goes here before adding to Queue...
            self.dataQ.put(dat)
            if not self.inputStarted:
              self.logger.debug('reading')
            self.inputStarted = True
          self.dat.close()
          self.close()
          self.join_fin()
    
      def join_fin(self):
        self.logger.debug('stopping')
        self.stoprequest.set()
    
      def connectForStream(self, debug=True):
        '''Attempt to connect to the serial port and fail after waitMaxSec seconds'''
        self.logger.debug('connecting')
        if not self.isOpen():
          self.logger.debug('not open, trying to open')
          try:
            self.open()
          except serial.serialutil.SerialException:
            self.logger.debug('Unable to use port ' + str(self.ser.port) + ', please verify and try again')
            return
        while self.readline() == '' and self.readCount < self.waitMaxSec and self.keepAlive:
            self.logger.debug('reading initial')
            self.readCount += self.sleepDurSec
            if not self.readCount % (self.ser.baudrate / 100):
              self.logger.debug("Verifying MaxSonar data..")
              //some sanity check
    
        if self.readCount >= self.waitMaxSec:
            self.logger.debug('Unable to read from MaxSonar...')
            self.close()
            return False
        else:
          self.logger.debug('MaxSonar data is streaming...')
    
        return True
    
      def isOpen(self):
        self.logger.debug('Open? ' + str(self.ser.isOpen()))
        return self.ser.isOpen()
    
      def open(self):
        self.ser.open()
    
      def stopDataAquisition(self):
        self.logger.debug('Falsifying keepAlive')
        self.keepAlive = False
    
      def close(self):
        self.logger.debug('closing')
        self.stopDataAquisition()
        self.ser.close()
    
      def write(self, msg):
        self.ser.write(msg)
    
      def readline(self):
        return self.ser.readline()
    
    
    app = Flask(__name__,
                static_folder="public",
                template_folder="templates")
    
    port = "/dev/tty.usbserial-A6004amR"
    dataQ = Queue.Queue()
    errQ = Queue.Queue()
    ser = maxSonarSerialThread(dataQ, errQ, port=port, ver=self.hwVersion)
    ser.daemon = True
    ser.start()
    
    @app.route("/")
    def index():
      return render_template('index.html')
    
    @app.route("/distance")
    def distance():
      distance = read_distance_from_serial()
      return json.dumps({'distance': distance})
    
    def read_distance_from_serial():
      a = dataQ.get()
      print str(a)
      return a
    

You'll need to add a method to join the thread for a graceful exit, but that
should get you going

