2015-01-27 108 views
0

我有以下腳本從Raspberry Pi上的Arduino讀取串行端口。目的是讓Pi監控Arduino rfid輸出,並在識別特定卡號時激活繼電器板上的兩個不同的繼電器。發生了什麼事情是腳本在識別特定卡號時實質上運行了兩次。我無法弄清楚爲什麼這樣做。RFID Arduino to Raspberry Pi串行讀取python動作運行兩次

#!/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) 

...在一個有效的讀卡,我越來越:

報警撤防 鎖門 卡考上 報警撤防 鎖門 卡考上

爲什麼你認爲它通過兩次?

+0

因爲它在'while True'中並且你永遠不會跳出它,所以我猜 - 不知道爲什麼**只有**兩次,我猜'ser.readline()'會阻止第三個它的時間被稱爲,但我無法確定(我手頭沒有HW來重現問題,唉)。 – 2015-01-27 01:52:58

+0

關於True替代品的任何建議?我是Python新手,不確定運行此腳本的最佳選擇是什麼。我確實需要它來持續監視Arduino串行輸出。 – 2015-01-27 02:04:37

+0

當你不想繼續重複時,「休息」是最簡單的想法,但這會阻止監控。如果Arduino「口吃」併發送一行兩次,則可能需要解決該問題,例如,在上次看到「數據」值的時候已經看到「數據」值,這樣就可以忽略過快的重複。在回答中需要一些代碼來指導呢?如果有,請告訴我,謝謝! – 2015-01-27 02:07:12

回答

0

這個問題似乎是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的努力和響應度)。但這是一個合理的方法。還有更多更精細的選擇(例如,有條目的日誌[列表]可以有選擇地用於重建或修剪) - 但是,「實體不能超出必要的倍數」,所以讓我們堅持簡單直到除非有更多的複雜性證明是必要的! )

+0

謝謝亞歷克斯,這很好。我將時間降低到15秒,因爲在第一次讀取後任何卡片讀取都不會響應。一旦我降低它,它完美地工作。 – 2015-01-27 15:29:56