In questa lezione descriviamo come rilevare il movimento tramite un sensore PIR e la libreria GPIOZero.
Tutti gli oggetti e gli esseri viventi possono emettere energia sotto forma di radiazioni luminose nello spettro dell'infrarosso pertanto invisibili a occhio nudo.
Quindi un sensore a infrarossi passivo o PIR (Passive InfraRed) è un dispositivo elettronico che misura i raggi infrarossi (IR) irradiati nel suo campo d'azione.
Il più classico dei sensori PIR è quello che viene normalmente utilizzato negli impianti di allarme domestici.
Il sensore PIR
Un tipico modulo PIR per Raspberry Pi è composto dal sensore stesso e da un circuito di controllo con tre pin:
- VCC: pin di alimentazione, normalmente a 5V;
- OUT: pin digitale che rappresenta l'uscita del sensore (rilevazione "presente" o campo libero);
- GND: pin di massa.
La classe MotionSensor
Il sensore PIR, all'interno della libreria GPIOZero, appartiene alla classe dei dispositivi di input (SmoothedInputDevice).
Il costruttore della classe ha la seguente sintassi:
MotionSensor(pin=None,
pull_up=False,
active_state=None,
queue_len=1,
sample_rate=10,
threshold=0.5,
partial=False,
pin_factory=None)
- pin: è un parametro obbligatorio di tipo integer che rappresenta il numero del pin in numerazione BCM a cui è collegato il sensore PIR;
- pull_up: è parametro facoltativo di tipo boolean che abilita la resistenza interna di Pull-Down (False di default) o quella di Pull-Up (True);
- active_state: è parametro facoltativo di tipo boolean. Utile in caso in cui si imposti pull_up a None. Se impostato a True lo stato del pin software segue quello del pin hardware (ad esempio pin hardware True implica pin software True). Se impostato a False lo stato del pin software è opposto allo stato del pin hardware (ad esempio pin hardware True implica pin software False). Se il parametro pull_up è impostato a un valore boolean, allora active_state viene impostato automaticamente al valore corretto;
- queue_len: è un parametro facoltativo di tipo integer che rappresenta la lunghezza della coda utilizzata per memorizzare le letture passate del sensore. Di default è impostato a 1 (in pratica la coda risulta disabilitata). Nel caso in cui il sensore PIR sia instabile può essere utile aumentare il valore di questo parametro;
- sample_rate: è un parametro facoltativo di tipo integer che rappresenta il numero di letture per secondo operate dal sensore. Di default è impostato a 100. Normalmente non è necessario modificare questo parametro;
- threshold: è un parametro facoltativo di tipo float che rappresenta la soglia, calcolata sulla media dei valori presenti nella coda interna, oltre la quale il sensore è considerato attivo. Normalmente non è necessario modificare questo parametro;
- partial: è un parametro facoltativo di tipo boolean impostato per default a False. Quando è impostato a False il valore della proprietà is_active viene restituito solo nel caso in cui la coda interna sia piena (lettura bloccante). Qualora sia impostato a True la lettura è non bloccante quindi il valore is_active viene calcolato solo con i valori presenti nella coda interna senza attendere il suo riempimento;
- pin_factory: è un parametro facoltativo solo per uso avanzato. Permette di specificare un GPIO pin factory differente da quella fornita da GPIOZero.
I metodi e le proprietà più importanti della classe sono i seguenti:
is_active | Restituisce lo stato del sensore PIR in funzione del parametro active_state impostato nel costruttore. |
wait_for_motion(timeout=None) | Sospende il programma fino a quando il sensore non diventa attivo o il timeout è scaduto. |
wait_for_no_motion(timeout=None) | Sospende il programma fino a quando il sensore diventa inattivo o il timeout è scaduto. |
motion_detected | Restituisce un valore True se il sensore ha captato un movimento altrimenti restituisce False. |
when_motion | Funzione che viene eseguita quando il sensore cambia stato da inattivo ad attivo (rilevamento di movimento). |
when_no_motion | Funzione che viene eseguita quando il sensore cambia stato da attivo ad inattivo (rilevamento di assenza movimento). |
Schema di collegamento
Prima di passare al codice python è necessario assemblare il circuito elettrico che collega il sensore PIR al Raspberry Pi. La figura a seguire visualizza i collegamenti necessari.
Colleghiamo i piedini + e - del sensore rispettivamente al pin fisico 1 e 3 della prima linea di GPIO.
Colleghiamo il pin OUT del sensore al pin BCM 14 (il quarto pin sulla prima linea di GPIO).
Rilevare il movimento in python
from gpiozero import MotionSensor
pir = MotionSensor(pin=14, pull_up=False)
print("Inizializzazione PIR: in attesa di movimento...")
pir.wait_for_motion()
print("ALLARME: movimento rilevato!!!")
In questo primo esempio di utilizzo vediamo come adoperare il costruttore. Impostiamo il pin su cui abbiamo collegato l'uscita del sensore e la resistenza di pull-down (pull_up=False).
Dopo aver inizializzato l'oggetto pir rimaniamo in attesa che venga rilevato un movimento tramite l'uso del metodo wait_for_motion. Poiché non abbiamo passato nessun timeout il PIR rimane in attesa di movimento a tempo indeterminato.
from gpiozero import MotionSensor
pir = MotionSensor(pin=14, pull_up=False)
print("Inizializzazione PIR: in attesa di movimento...")
while True:
pir.wait_for_motion(timeout=10)
if pir.is_active:
print("ALLARME: movimento rilevato!!!")
else:
print("nessun movimento rilevato!!!")
In questo secondo esempio realizziamo un rilevamento di movimento più sofisticato.
Questa volta al metodo wait_for_motion passiamo, come parametro, un timeout di 10 secondi.
Ciò significa che il metodo rimane in attesa di un movimento al massimo per 10 secondi dopodiché restituisce il controllo al flusso principale.
In caso di movimento, o di termine del timeout, verifichiamo il valore della proprietà is_active. Se è True "è stato rilevato movimento", se è False significa che "non è stato rilevato movimento". In entrambi i casi veicoliamo un messaggio opportuno. A questo punto il ciclo inizia nuovamente in attesa di movimento.
from gpiozero import MotionSensor
def allarme_movimento():
print("Invio messaggio di ALLARME: movimento rilevato!!!")
pir = MotionSensor(pin=14, pull_up=False)
pir.when_motion = allarme_movimento
print("Inizializzazione PIR: in attesa di movimento...")
while True:
pir.wait_for_motion()
In quest'ultimo esempio utilizziamo il meccanismo degli eventi andando a registrare un handler chiamato allarme_movimento.
Quindi, dopo la creazione dell'oggetto pir, registriamo l'handler tramiter pir.when_motion. Poi ci collochiamo in attesa.
Nel caso in cui il sensore PIR rilevi un movimento l'evento motion viene generato e il suo handler (allarme_movimeto) è immediatamente invocato.
Conclusioni
In questa lezione abbiamo affrontato l'uso di un sensore PIR. GPIOZero fornisce un'astrazione di alto livello rendendo estremamente intuitivo il rilevamento del movimento. Oltre allo schema di collegamento sono stati analizzati alcuni esempi di utilizzo in python e GPIOZero.
Questo sensore può essere utilizzato in molti progetti (ad esempio un antifurto domestico o un robot che reagisce alla presenza di sollecitazioni esterne).