我有下面的脚本可以从Raspberry Pi上的Arduino读取串行端口。目的是让Pi监控Arduino rfid输出,并在识别出特定卡号时激活继电器板上的两个不同继电器。正在发生的事情是,当识别特定的卡号时,脚本基本上运行两次。我不知道它为什么要这样做。
#!/usr/bin/python # -*- coding: utf-8 -*-
import serial
import time
import RPi.GPIO as GPIO
ser = serial.Serial('/dev/ttyACM0', 9600)
GPIO.setmode(GPIO.BCM)
# init list with pin numbers
pin_assignments = {'Disarm Alarm': 18, 'Unlock Door': 23}
GPIO.setup(18, GPIO.OUT)
GPIO.setup(23, GPIO.OUT)
GPIO.output(18, GPIO.HIGH)
GPIO.output(23, GPIO.HIGH)
while True:
try:
data = ser.readline() .decode("utf-8*)
if "12 34 56 78" in data:
time.sleep(2)
GPIO.output(18, GPIO.LOW) # Disarm alarm
print('Alarm Disarmed')
time.sleep(1)
GPIO.output(23, GPIO.LOW) # Unlock door
print('Door Unlocked')
time.sleep(3)
GPIO.output(18, GPIO.HIGH)
GPIO.output(23, GPIO.HIGH)
print('Card Admitted')
time.sleep(1)
if data == 'no card select':continue
except ser.SerialTimeoutException:
print('Data could not be read')
time.sleep(1)
。在有效的读卡时,我得到:
报警器已撤防门已解锁已获准持卡报警器已撤防门已解锁已获准持卡
你为什么认为它运行了两次?
问题似乎是ser.readline
可以"结结巴巴"并返回相同的字符串两次(不知道为什么 - 缓冲? 重试? 那么忽略"太快"(比如 300 秒内)重复项呢? 例如:
import time
history = {}
while True:
try:
data = ser.readline().decode("utf-8")
when = history.get(data, None)
if when is not None and (time.time()-when) < 300:
continue
history[data] = time.time()
其余代码保持不变。 从本质上讲,这忽略了 5 分钟内数据线的相同重复(调整阈值以适应)。
有什么缺点吗? 是的,history
不断增长,无用地占用记忆。 它需要定期重建/修剪以仅保留最近的条目!
因此,例如,扩展上述内容...:
import time
history = {}
last_update = time.time()
while True:
if time.time() - last_update > 600: # 10 minutes, let's rebuild
deadline = time.time() - 301
history = dict((d,t)
for d, t in history.items()
if t > deadline)
last_update = time.time()
try:
data = ser.readline().decode("utf-8")
when = history.get(data, None)
if when is not None and (time.time()-when) < 300:
continue
history[data] = time.time()
同样,重建的周期600
(10 分钟)和301
(多一个300
:)对于"哪些条目值得保留",可以根据口味进行调整(平衡内存负载与 CPU 工作量和响应性)。 但这是一种合理的方法。 有更精细的替代方案(例如,有选择地用于重建或修剪的条目的日志[列表]) - 但是,"实体不能超过必要性",所以让我们坚持简单,直到并且除非证明需要更复杂的