1

我正在使用MaxSonar EZ1 超声波测距传感器和 Arduino Diecimila 开展一个小项目。

使用MaxSonar 操场代码,我让 Arduino 每 0.5 秒将英寸数写入串行,并带有一个分隔符。监控串行数据时,输出类似于:

5.13.15.12.123.39.345...

在 Python 方面,我有一个带有 /distance 路由的基本 Flask 应用程序,它返回一个带有序列值的 JSON 对象:

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()

index.html 是一个带有一些 JS 的基本站点,它每半秒轮询一次 /distance 以获取新读数。有了这个值,我应该能够构建一个有趣的 UI,它会根据我与声纳的距离/远近而变化。

$(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();
});

问题

我遇到的问题是,不能保证当 python 从串行读取时,会有一个值。很多时候,当它轮询时,我得到一个空值或部分值,而其他时候它是正确的。

我怎样才能改变我的技术,以便我能够始终如一地轮询串行数据并从 Arduino 串行输出接收最后的良好读数?

4

1 回答 1

1

您希望将串行读取设置为在后台而不是按需进行。您可以使用threadingQueue。一旦你确定你有一个有效的值,你就将你的序列值添加到队列中,然后你的套接字调用只是从队列中提取。它会是这样的:

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

您需要添加一个方法来加入线程以正常退出,但这应该可以帮助您

于 2013-09-12T04:02:09.030 回答