RFID Arduino to Raspberry Pi serial read python action 运行 两次

RFID Arduino to Raspberry Pi serial read python action running twice

我有以下脚本可以从 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 可以 "stutter" 和 returns 相同的字符串两次(不确定为什么 - 缓冲?重试?)。那么忽略 "too-fast"(比如 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 不断增长,无用地占用内存。需要定期 re-built/pruned 以仅保留 最近 个条目!

因此,例如,扩展上面...:

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 分钟)周期和 "what entries are worth keeping" 的 301(比 300 多一个:)可以根据口味进行调整(平衡内存负载与 CPU 努力和响应)。但这是一种合理的方法。还有更精炼的替代方案(例如,有选择地用于重建或修剪的日志[列表]条目)——但是,"entities must not be multiplied beyond necessity",所以让我们坚持简单,直到并且除非证明需要更多的复杂性!-)