我正在使用MaxSonar EZ1 ultrasonic range sensor和Arduino Diecimila开展一个小项目。
使用MaxSonar playground code,我让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每半秒轮询/距离一次新的阅读。有了这个价值,我应该能够建立一个有趣的用户界面,根据我与声纳有多近/远来改变。
$(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从serial读取时,无法保证会有值。通常情况下,当它进行轮询时,我会得到一个空值或一个部分值,而有时它会被点亮。
如何更改我的技术,以便我能够一致地轮询串行数据并从Arduino串行输出接收最后一个好的读数?
答案 0 :(得分:1)
您希望将序列读数设置为在后台进行,而不是按需进行。您可以使用threading和Queue。一旦确定具有有效值,就将序列值添加到队列中,然后套接字调用只是从队列中提取。它会是这样的:
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
你需要添加一个方法来加入线程才能正常退出,但这应该让你前进