![]() |
Raspberry-Pi-Projekte: PIR Bewegungsmelder HC-SR501Prof. Jürgen Plate |
Mittlerweile gibt es passive Bewegungsmelder für einige Euro bei Ebay, Amazon und anderen Händlern. Solche Bewegungsmelder laufen unter der Bezeichnung "PIR-Sensor", wobei "PIR" für "Passive Infra Red" (passiver Infrarot-Sensor) steht. Solche Infarot-Bewegungsmelder (meist nur "Bewegungsmelder" genannt) dienen oft zum automatischen Einschalten von Beleuchtung etc. Sie erkennen eine bestimmte Menge an Infarotstrahlen/Wärme) und werten diese Information aus. Schlicht gesagt, reagieren Sie auf die Wärme des menschlichen Körpers (oder auch von Hund, Katze usw.). Damit aber nicht staische Wärmequellen (besonntes Fenster, Heizkörper etc.) den Senso triggern, regieren solche Sensoren auf bewegliche Wärmequellen. Damit das funktioniert, ist eine Fesnel-Linse vor dem Sensor augeordnet. Das folgende Bild zeigt den PIR-Sensor auf der Platine und daneben die abgenommene Fresnel-Linse.
Die im Handel erhältliche Sensorplatine HC-SR501 hat eine Reichweite von etwa 7 Metern und einen Erfassungswinkel von ca. 120 Grad. Die Platine trägt die Auswerte-Elekronik mit dem IC BISS0001 und einen 3,3-V-Spannungsregler, was den Vorteil hat, dass sich das Ausgsangssignal direkt in den Raspberry Pi einspeisen lässt. Auf der Platine befinden sich neben den Anschlusspins noch zwei Potenziometer und ein Jumper. Die folgenden Bilder zeigen die Vorder- und Rückseite der Platine. Das Bild darunter einen Schaltplan, der aber nicht ganz der HC-SR501 entspricht. Hier ist noch ein Fotowiderstand (Cos2) enhalten, der die Ausgabe deaktiviert, wenn es hell genug ist - die Schaltung ist speziell für Beleuchtungszwecke gedacht.
Der Anschluss ist denkbar einfach. Es gibt nur drei Anschlusspins, +5 V, GND und Ausgang. Der Ausgang liefert 0 V, wenn keine Bewegung erkannt wird und +3,3 V, wenn sich vor dem Sensor eine Wärmequelle bewegt. Zm Verdrahten mit dem RasPi nimmt man am Besten drei Jumperkabel mit jeweils einer Buchse am Ende. Die Pins auf der Platine des Moduls sind mit "GND", "OUT" und "+5V" bezeichnet.
Die Einstellung des PIR-Moduls erfolgt über zwei Potenziometer und einen Jumper (siehe Bild unten). Mit dem linken Potenziometer ("Time") wird die Haltezeit des Moduls nach dem Erkennen einer Wärmequelle eingestellt. Mit dem rechten Potenziometer ("Sensitive" stellt man die Empfindlichkeit und damit auch die Reichweite des Sensors ein. Der Jumper dient der Einstellung der Arbeitsweise: In der unteren Stellung wird bei jeder erkannten Bewegung ein Impuls erzeugt. Wenn also jemand beisielsweise am Sensor vorbei geht, gibt es im Sekundenabstand Impulse, solange sich die Person innerhalb der Reichweite des Sensors befindet. In der oberen Stellung des Jumpers liefert der Sensor nur einen Impuls, abhängig von der Dauer der Haltezeit. Dies ist auch meist der Dfault-Wert.
Für die folgenden Programme wird das PIR-Modul auf "ein Impuls pro Erkennung" (Default) eingestellt. Die Haltezeit stellen Sie auf den minimalen Wert (Potenziometer auf Linksanschlag). Denken Sie auch daran, dass wegen des Zugriffs auf den GPIO-Pin eventuell Root-Rechte nötig sind.
Das erste Programm demonstriert die Bearbeitung der Impulse von PIR-Modul. Dazu muss eine kleine State Machine mit zwei Zuständen programmiert werden, da die Einschaltzeit relativ lang ist. Würde man nur den Zustand des GPIO-Pins abfragen, bekäme man im Ruhezustand immer eine "0" und bei aktivem PIR für längere Zeit dauernd eine "1". Es gilt also:
#!/usr/bin/python import RPi.GPIO as GPIO import time # BCM GPIO-Referenen verwenden (anstelle der Pin-Nummern) # und GPIO-Eingang definieren GPIO.setmode(GPIO.BCM) GPIO_PIR = 4 print "PIR-Modul gestartet (CTRL-C to exit)" # Set pin as input GPIO.setup(GPIO_PIR,GPIO.IN) # Initialisierung Read = 0 State = 0 try: print "Warten, bis PIR im Ruhezustand ist ..." # Schleife, bis PIR == 0 ist while GPIO.input(GPIO_PIR) != 0: time.sleep(0.1) print "Bereit..." # Endlosschleife, Ende mit STRG-C while True: # PIR-Status lesen Read = GPIO.input(GPIO_PIR) if Read == 1 and State == 0: # PIR wurde getriggert print "Bewegung erkannt!" # Zustand merken State = 1 elif Read == 0 and State == 1: # PIR wieder im Ruhezustand print "Bereit..." # Zustand merken State = 0 # kleine Pause time.sleep(0.1) except KeyboardInterrupt: # Programm beenden print "Ende..." GPIO.cleanup()
Statt des Wartens in einer Schleife besteht die Möglichkeit, den Daten-Pin so zu initialisieren, dass eine Veränderung, genauer ein Wechsel von "0" auf "1", an das Skript übergeben wird. Dazu wird dann eine Callback-Funktion Motion() zum Auslesen des Pinzutands definiert, die beim Auftreten einer positiven Flanke automatisch aufgerufen wird. Der Vorteil dabei ist, das der Code nicht ständig den Pin-Status überprüft, sondern schläft, bis etwas passiert.
#!/usr/bin/python import RPi.GPIO as GPIO import time import datetime # BCM GPIO-Referenen verwenden (anstelle der Pin-Nummern) # und GPIO-Eingang definieren GPIO.setmode(GPIO.BCM) GPIO_PIR = 4 print "PIR-Modul gestartet (CTRL-C to exit)" # Set pin as input GPIO.setup(GPIO_PIR,GPIO.IN) # Initialisierung Read = 0 State = 0 print "Warten, bis PIR im Ruhezustand ist ..." # Schleife, bis PIR == 0 ist while GPIO.input(GPIO_PIR) != 0: time.sleep(0.1) print "Bereit..." # Callback-Funktion def MOTION(PIR_GPIO): print "%s - Bewegung erkannt!" % datetime.datetime.now() print "%s - Warten auf Bewegung" % datetime.datetime.now() try: # Ereignis definieren: steigende Flanke GPIO.add_event_detect(GPIO_PIR, GPIO.RISING, callback=MOTION) # laenger schlafen - Callback wird durch die Flanke aktiviert while True: time.sleep(60) except KeyboardInterrupt: # Programm beenden print "Ende..." GPIO.cleanup()Das Programm ist zudem kürzer als das erste.
Das dritte Programm ist eine C-Implementierung des ersten. Als Bibliothek wird hier wiringPi verwendet. Si könnten aber genausogut die auf der Seite über die GPIO-Programmierung in C vorgestellte Bibliothek oder die die bcm2835-Library verwenden.
/* * Program for PIR-Sensor. * Connect on board pin number 07 to Sensor * * gcc -Wall -o pir -l wiringPi pir.c */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #include <signal.h> #include <wiringPi.h> /* Sensor auf GPIO 4, Pin 7, WiringPi 7 */ #define SENSOR 7 unsigned int state = 0; unsigned int data = 0; struct sigaction sig_struct; /* Signalhandler fuer STRG-C */ void finish(int sig) { printf("Signal %d empfangen. Programm wird beendet.\n", sig); exit(0); } int main(int argc, char **argv) { /* Initialisierung der Bibliothek */ if (wiringPiSetup() == -1) { printf("Please run this as root\n"); return EXIT_FAILURE; } /* Signalhandler fuer STRG-C einrichten */ sig_struct.sa_handler = finish; sigemptyset(&sig_struct.sa_mask); sig_struct.sa_flags = 0; sigaction(SIGINT,&sig_struct,NULL); /* Sensor als Input definieren */ pinMode(SENSOR, INPUT); while((data = digitalRead(SENSOR)) != 0) { /* Pause 0,1 Sekunde */ usleep(100000); } printf("Bereit...\n"); while (1) { data = digitalRead(SENSOR); if(data == 1 && state == 0) { printf("Bewegung erkannt - %d\n",(int)time(NULL)); state = 1; } else if (data == 0 && state == 1) { printf("Bereit...\n"); state = 0; } /* Pause 0,1 Sekunde */ usleep(100000); } return EXIT_SUCCESS; }Auch bei C kann man mit Flankenerkennung arbeiten, siehe oben genannte Webseite.