1

MaxSonar EZ1 超音波距離センサーと Arduino Diecimilaを使用した小さなプロジェクトに取り組んでいます。

MaxSonar プレイグラウンド コードを使用して、区切り記号と共に 0.5 秒ごとにシリアルにインチ数を Arduino に書き込みます。シリアル データを監視すると、出力は次のようになります。

5.13.15.12.123.39.345...

Python 側では、シリアル値を持つ JSON オブジェクトを返す /distance ルートを持つ基本的な Flask アプリがあります。

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 は、0.5 秒ごとに /distance をポーリングして新しい読み取り値を取得する JS を含む基本的なサイトです。この値を使用すると、ソナーからの距離に応じて変化する興味深い 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 に答える