Fahrzeugkennziffer-Erkennung mit dem Raspberry pi

Schon seit längerem war ich auf der Suche nach einer interessanten Weiterbildung, dabei stiess ich auf das CAS IOT Manager an der HSLU. In verschiedenen Modulen haben wir Einblick in die Themen von IoT bekommen. IoT ist nicht neu es ist schon heute an vielen Orten anzutreffen. Es gibt viele positive Anwendungen die uns heute schon das Leben erleichtern. Natürlich gibt es bei IoT auch Gefahren und Ängste, welche einem noch mehr bewusst werden, wenn man sich näher damit befasst.

Die Ängste sind nicht neu, der Kabarettist Erwin Pelzig hatte schon Anfang der neunziger Jahre Angst vor intelligenten Haushaltgeräten.
https://www.youtube.com/watch?v=Y8RbhJXqeVk

Nun zu meinem eigentlichen Thema

Die Module Iot Grundlagen und Prototyping mit dem praktischen Teil haben mich begeistert und mich und meine Kollegen zu einer praktischen Projektarbeit motiviert.

Unser Ziel ist es den Signa Guard-S Parkplatz Parkbügel intelligent zu machen.
https://www.signal.ch/sortiment/signa-guard-parkbuegel/

Ausgangslage

Heute wird dieser Parkbügel über einem Funkhandsender hoch und runtergefahren. Ziel ist es, dass der Parkbügel die Fahrzeugkennziffer erkennt und prüfen kann ob das Fahrzeug für diesen Parkplatz erlaubt ist.

Beim durchstöbern des Internet fand ich viele Lösungen für die Fahrzeugkennziffer-Erkennung welche auf den Raspberry Pi realisiert wurden. Ich entschied mich, für folgende Tests als Vorbereitung für unsere Projektarbeit.

Hardware

Als Edge:                            Raspberry Pi 3, SD Karte min 32GB
Kamera:                              Rasperry Pi Camera V2 oder USB Kamera
Bewegungssensor:            PIR Motion Sensor
Parkbügelsimulation:      SG90 9G Micro Servo Motor

Verdrahtung

Software

Raspbian Stretch with desktop
Node Red
Python 2.7 oder neuer

Weiter braucht es für diese Lösung der Fahrzeugkennziffer-Erkennung einen kostenlosen Account bei OpenALPR.  Mit diesem Account kann man 2000 kostenlose Anfrage pro Monat senden. Dieser kann man unter folgendem Link erstellen.
https://cloud.openalpr.com/account/register

Test 1 – Wird die Fahrzeugkennziffer erkannt?

Als erstes machte ich einen Test mit NodeRed, OpenALPR Cloud und der Raspberry Pi Camera V2. Die Qualität der Fotos der Pi Cam V2 waren so schlecht, dass ich den Test mit der USB Kamera aufbaute.

Hier der Aufbau mit der USB Kamera in NodeRed

Sobald der Flow mit „Timestamp“ gestartet wird erstellt die USB Kamera ein Bild, welches dann im Node cURL POST an die OpenALPR Cloud gesendet wird.

Die Antwort ist dann in „Debug“ ersichtlich.

Hier der NodeRed Code zum importieren

[{"id":"b85e85cb.8b3c8","type":"tab","label":"Camera Test","disabled":false,"info":""},{"id":"1cf41548.8ed4fb","type":"exec","z":"b85e85cb.8b3c8","command":"sudo curl -X POST \"https://api.openalpr.com/v2/recognize?secret_key=sk_secret key&recognize_vehicle=1&country=eu&return_image=0&topn=10\" -F image=@/home/pi/Pictures/car.jpg","addpay":false,"append":"","useSpawn":"false","timer":"",
"oldrc":false,"name":"cURL POST","x":501,"y":300,"wires":[["7f3aeff7.dbdb"],[],[]]},{"id":"7f3aeff7.dbdb","type":"json","z":"b85e85cb.8b3c8","name":"JSON","property":"payload",
"action":"","pretty":false,"x":647.5,"y":287.5,"wires":[["8ce73fa.f56fdc"]]},{"id":"8ce73fa.f56fdc","type":"debug","z":"b85e85cb.8b3c8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":799,"y":287,"wires":[]},{"id":"22ed60b8.04ec6","type":"inject","z":"b85e85cb.8b3c8","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":178.5,"y":301,"wires":[["9fdba568.c9ea58"]]},{"id":"9fdba568.c9ea58","type":"usbcamera","z":"b85e85cb.8b3c8","filemode":"1","filename":"car.jpg","filedefpath":"1","filepath":"","fileformat":"jpeg","resolution":"2","name":"","x":361,"y":220,"wires":[["1cf41548.8ed4fb"]]}]

Hinweis: Je nach verwendeter Kamera muss noch der richtige Kamera Node in NodeRed importiert werden.

Die Konfiguration des cURL POST Nodes muss noch angepasst werden.
Mit dem cURL POST Node wir das Bild zur Erkennung der Fahrzeugkennziffer an OpenALPR gesendet.

sudo curl -X POST "https://api.openalpr.com/v2/recognize?secret_key=sk_Secret key&recognize_vehicle=1&country=eu&
return_image=0&topn=10" -F image=@/home/pi/Pictures/car.jpg

Secret key“ muss mit dem eigenen Key ersetzt werden den findet man im OpenALPR Account
https://cloud.openalpr.com/account/

Der Test von OpenALPR und Kamera war erfolgreich, jetzt geht’s ans eigentliche Vorhaben.

Test 2 – Testaufbau mit Parkbügel Simulation
Mit diesem Aufbau möchte ich die Fahrzeugkennziffer-Erkennung und die Ansteuerung des Parkbügels simulieren.
Dabei dient mir der SG90 9G Micro Servo Motor als Parkbügel.

Funktionschema

Ablauf des Flows:

  1. Timestamp gibt Impuls (Auto kommt)
  2. Bügel oben? Wenn ja, Foto wird gemacht
  3. Abfrage bei OpenALPR
  4. die Antwort wird im „Identify Car“ kontrolliert => nicht richtig dann passiert nichts
  5. Fahrzeugkennziffer erlaubt => Bügel geht runter (Bügel down)
  6. Parkplatz noch besetzt => Bügel bleibt oben
  7. Parkplatz frei => Bügel geht nach 10 Sekunden hoch

Bilder vom Testaufbau

Kamera nimmt Foto von Auto auf.          Verdratung des Raspberry Pi und der Servo

Hier der NodeRed Code zum Importieren

[{"id":"b32d02f5.5b8d2","type":"tab","label":"auto-plate-rec","disabled":false,"info":""},{"id":"b8496327.a7dcb","type":"exec","z":"b32d02f5.5b8d2","command":"sudo curl -X POST \"https://api.openalpr.com/v2/recognize?secret_key=sk_mykey&recognize_vehicle=1&country=eu&return_image=0&topn=10\" -F image=@/home/pi/Pictures/car.jpg","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"cURL POST","x":710,"y":120,"wires":[["7e37f727.b44e48"],[],[]]},{"id":"7e37f727.b44e48","type":"json","z":"b32d02f5.5b8d2","name":"JSON","pretty":false,"x":872.5,"y":135.5,"wires":[["8686e97f.a17c78","7bcb5290.29d70c"]]},{"id":"7bcb5290.29d70c","type":"function","z":"b32d02f5.5b8d2","name":"Identify Car","func":"var carPlate1 = (\"H786POJ\");\nvar carPlate2 = (\"MNP4675\")\n//var carModel = \"renault_r-4\";\n\n//No car or car plate found in photo\nif(msg.payload.results.length === 0) {\n   msg.payload=0;\n   global.set(\"garageOpen\",\"0\"); \n}\n//If car plate and car model match\nelse if(msg.payload.results[0].plate==carPlate1 || carPlate2 ) {\n//&& msg.payload.results[0].vehicle.make_model[0].name==carModel\n   msg.payload=1;\n   global.set(\"garageOpen\",\"1\"); \n}\n//If car plate and car model don't match\nelse {\n   msg.payload=0;   \n   global.set(\"garageOpen\",\"0\"); \n}\n\nreturn msg;\n\n","outputs":1,"noerr":0,"x":161,"y":320,"wires":[["aaa9772.e5b5088","244e10e7.d44af"]]},{"id":"aaa9772.e5b5088","type":"switch","z":"b32d02f5.5b8d2","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"str"},{"t":"eq","v":"0","vt":"str"}],"checkall":"true","outputs":2,"x":301,"y":320,"wires":[["4accb9b7.b228d8","739992ce.6e012c"],["625922d6.0c39bc"]]},{"id":"8686e97f.a17c78","type":"debug","z":"b32d02f5.5b8d2","name":"","active":true,"tosidebar":true,"console":false,"complete":"false","x":1018,"y":100,"wires":[]},{"id":"f8c007ac.ede8f8","type":"switch","z":"b32d02f5.5b8d2","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"str"},{"t":"eq","v":"1","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":401,"y":160,"wires":[["5df5174a.83c738"],["928f3928.a09898"]]},{"id":"951677d2.eac4e8","type":"function","z":"b32d02f5.5b8d2","name":"Buegel oben","func":"var garageOpen = global.get(\"garageOpen\"); \n\nif(garageOpen == \"1\"){\n   msg.payload = 1;\n}\nelse {\n   msg.payload = 0;\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":241.5,"y":162,"wires":[["f8c007ac.ede8f8"]]},{"id":"4accb9b7.b228d8","type":"delay","z":"b32d02f5.5b8d2","name":"","pauseType":"delay","timeout":"10","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":600,"y":331,"wires":[["793cbbe3.a1bb74"]]},{"id":"793cbbe3.a1bb74","type":"function","z":"b32d02f5.5b8d2","name":"Bügel oben","func":"msg.payload=0;   \nglobal.set(\"garageOpen\",\"0\"); \nreturn msg;\n\n","outputs":1,"noerr":0,"x":750,"y":331,"wires":[["b26082d7.1d7a2"]]},{"id":"928f3928.a09898","type":"debug","z":"b32d02f5.5b8d2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":548,"y":169,"wires":[]},{"id":"625922d6.0c39bc","type":"debug","z":"b32d02f5.5b8d2","name":"","active":true,"console":"false","complete":"false","x":597,"y":388,"wires":[]},{"id":"5df5174a.83c738","type":"usbcamera","z":"b32d02f5.5b8d2","filemode":"1","filename":"car.jpg","filedefpath":"1","filepath":"","fileformat":"jpeg","resolution":"2","name":"","x":541,"y":80,"wires":[["b8496327.a7dcb"]]},{"id":"daa9a368.eb6c5","type":"inject","z":"b32d02f5.5b8d2","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":100,"y":240,"wires":[["951677d2.eac4e8"]]},{"id":"739992ce.6e012c","type":"pythonshell in","z":"b32d02f5.5b8d2","name":"Bügel down","pyfile":"/home/pi/close.py","virtualenv":"","continuous":false,"stdInData":false,"x":741,"y":240,"wires":[[]]},{"id":"b26082d7.1d7a2","type":"pythonshell in","z":"b32d02f5.5b8d2","name":"Bügel Auf","pyfile":"/home/pi/open.py","virtualenv":"","continuous":false,"stdInData":false,"x":940,"y":420,"wires":[[]]},{"id":"244e10e7.d44af","type":"debug","z":"b32d02f5.5b8d2","name":"","active":true,"tosidebar":true,"console":false,"complete":"false","x":310,"y":420,"wires":[]}]

Für diesen Aufbau wird in NodeRed der „pythonshel Node“ benötigt.
In der Funktion „Identify Car“ muss die erlaubte Fahrzeugkennziffer eingetragen werden.

Pythonscripts für Servo Ansteuerung

Bügel down: close.py

import RPi.GPIO as GPIO
import time
servoPIN = 24
GPIO.setmode(GPIO.BCM)
GPIO.setup(servoPIN, GPIO.OUT)
p = GPIO.PWM(servoPIN, 50) # GPIO 17 als PWM mit 50Hz
p.start(2.5) # Initialisierung
p.ChangeDutyCycle(2.5)
time.sleep(0.5)
p.stop()
GPIO.cleanup()

Bügel up: open.py

import RPi.GPIO as GPIO
import time
servoPIN = 24
GPIO.setmode(GPIO.BCM)
GPIO.setup(servoPIN, GPIO.OUT)
p = GPIO.PWM(servoPIN, 50) # GPIO 17 als PWM mit 50Hz
p.start(2.5) # Initialisierung
p.ChangeDutyCycle(12.5)
time.sleep(0.5)
p.stop()
GPIO.cleanup()

Viel Spass beim Nachbauen 🙂

Fazit

Es hat Spass gemacht meine IT Kenntnisse wiedermal aufzufrischen. Es braucht auf jeden Fall viel Zeit und Geduld bis alles so wie gewünscht funktioniert. Mit diesen Tests habe ich nun eine Basis für die eigentliche Projektarbeit geschaffen. Ziel ist es nun die Fahrzeugkennziffer-Erkennung lokal auf dem Raspberry Pi zu realisieren plus ein Webinterface für die Eingabe der erlaubten Fahrzeugkennziffern zu bauen. Bin gespannt wie weit wir dies realisieren können.

Auf jeden Fall hat mir das gezeigt, dass es auch mit Ü50 noch Spass macht ein CAS zu besuchen. Ich habe viele positive Reaktionen in meinem privaten Umfeld erhalten. Es gab auch einige die sich fragten wieso ich mir dies in meinem Alter noch antue. Ich bin der Meinung, dass es in jedem Alter wichtig ist, sich weiterzubilden. Speziell im Bereich der Informatik. Man sollte immer seine Kompetenzen und Skills erhalten und erweitern.

 

 

 

 

Beitrag teilen

ibtresch

Bernhard Tresch ist ICT Netzwerk Architekt bei der Swisscom und bloggt aus dem Unterricht des CAS IoT Manager.

Alle Beiträge ansehen von ibtresch →

Schreibe einen Kommentar