In der neuen Reihe “Mobile Geeks DIY” geht es, wie der Name schon vermuten lässt, um Hard- & Software-Projekte zum Selbermachen. Wikipedia definiert “DIY” so: “Der Begriff Do it Yourself kommt aus der englischen Sprache und bedeutet Mach es selbst. (…) Oftmals sind Spaß, Kreativität oder finanzielle Gründe der Anlass, Dinge selber zu fertigen.”
In den ersten Teilen dieser Serie werden wir verschiedenste Projekte basierend auf der Arduino-Plattform (Wikipedia) umsetzen. Um die Projekte nachzubauen könnt ihr bei unseren Partnern Exp-Tech.de und PhysicalComputing.at die entsprechenden Bauteile direkt bestellen, diese sind verlinkt. Zum Programmieren wird einerseits die Arduino-Entwicklungsumgebung, zu finden auf arduino.cc, und teilweise die Programmiersprache Python (WICHTIG: Version 2.7) verwendet. Diese ist relativ einfach zu erlernen und auf vielen Betriebssystemen verfügbar (da OpenSource).
Im ersten Projekt bauen wir einen Paketzustellungsdetektor.
Idee
Ein Geek möchte natürlich immer sofort Bescheid wissen, wenn er ein neues Paket erhält. Dazu könnte er zwar die Internetseiten des Logistik-Unternehmens nutzen, jedoch dauert es immer etwas bis die Zustellung angezeigt wird und außerdem möchte der Geek sichergehen, dass das Paket wirklich bei ihm hinterlegt wurde.
Dafür kommt der Paketzustellungsdetektor zum Einsatz. Wenn der Postbote das Paket am festgelegten Ablageort hinterlässt, erhält der Geek sofort eine E-Mail. Außerdem wäre eine Überprüfung mit der Datenbank des Logistikunternehmens möglich, wodurch er Gewissheit hat, dass es sich bei dem abgelegten Gegenstand wirklich um sein Paket handelt.
Material
- Arduino Uno R3 (25,- €)
- Force Sensitive Resistor (FSR) / Drucksensor (20,- €)
- 10 kΩ-Widerstand (beliebiger Hersteller, Widerstand-Set z.B. hier (5,-€))
- Drahtbrücken (Breadboard Jumper Wires M/M) (3,50 €)
- Breadboard (5,- €)
- USB-B auf USB-A- Kabel für den Arduino (beliebiger Hersteller, 3-in-1-Kabel z. B. hier (5,50 €))
- Computer mit Python 2.7 (nicht Python 3.x, da sonst der Code nicht lauffähig wäre)
Umsetzung
Zusammensetzen der Bauteile
Im folgenden Schema könnt ihr den Projekt-Aufbau sehen.
Der Force Sensitive Resistor (FSR) wird einerseits mit dem 3,3V-Port des Arduino verbunden. Außerdem wird er an dem anderen Anschluss mit dem ANALOG 0-Port des Arduinos und über einen 10kΩ-Widerstand mit dem GND-Port (Masse) verbunden.
Programmieren des Arduino
Der Arduino soll ständig den FSR abfragen und Mitteilung geben, sobald ein Grenzwert überschritten wurde, d.h. ein Gegenstand mit einem bestimmten Mindestgewicht auf dem Sensor abgestellt wurde. Der Computer kann dann die gewünschten Aktionen ausführen. Wird der Grenzwert wieder unterschritten, d. h. das Paket wieder aufgehoben, wird der Computer erneut informiert.
Zur Kommunikation zwischen Computer und Arduino verwenden wir die serielle Schnittstelle. Dazu muss der Arduino nur am USB-Port des Computers angeschlossen sein.
Ein Arduino-Programm hat den folgenden Grundaufbau:
void setup() { } void loop() { }
Die Funktion setup() wird dabei genau ein Mal beim Starten des Programms ausgeführt. Die Funktion loop() hingegen wird immer wieder, solange bis das Programm beendet wird, ausgeführt. Außerdem können oberhalb dieser Funktionen bereits Variablen und Konstanten definiert werden.
Hier definieren wir die Variablen und Konstanten, die für den späteren Programmablauf notwendig sind:
#define FSR_GRENZWERT 15 #define ONBOARD_LED 13 #define FORCE_SENSOR 0 int force_value = 0; byte force_state = 0;
In der ersten Zeile legen wir den Grenzwert für den FSR fest, bei dem das Programm eine Mitteilung an den PC sendet. In der zweiten Zeile definieren wir den (digitalen) Port an dem die LED (die bereits auf dem Board angebracht ist) angeschlossen ist. In der dritten Zeile definieren wir den analogen Port, an dem der FSR angeschlossen ist.
In den beiden darauffolgenden Zeilen, initialisieren wir zwei Variablen: force_value undforce_state. force_value ist vom Typ int, d.h. sie kann nur mit natürliche Zahlen belegt werden. force_state ist vom Typ byte, das ist eine natürliche Zahl von 0 bis 255. Inforce_value speichern wir (später) den aktuellen Wert des FSR zwischen; in force_stateob zur Zeit ein Paket auf dem FSR liegt oder nicht (Werte 0 (= Nein) oder 1 (= Ja)).
Gehen wir nun in die Funktion setup(). Diese soll genau zwei Dinge tun: Zum einen soll sie eine serielle Kommunikation(sleitung) mit dem Computer aufbauen (Z. 2). Zum anderen soll sie festlegen, dass es sich bei der ONBOARD_LED auf Port 13 um einen Ausgang handelt (Z. 3). Dies sieht im Programmcode wie folgt aus:
void setup() { Serial.begin(9600); // Startet die serielle Kommunikation mit 9600 Baud pinMode(ONBOARD_LED, OUTPUT); // Setzt den Pin ONBOARD_LED als einen Ausgang }
(Alles hinter den doppelten Schrägstrichen in der jeweiligen Zeile ist ein Kommentar und wird vom Programm ignoriert.)
Nun zur loop()-Funktion. Deren Aufgabe ist es bei jedem Durchlauf den FSR abzufragen. Sollte der zurückgegebene Wert größer sein, als der vorhin definierte Grenzwert, wird über die serielle Schnittstelle eine Meldung an den Computer gesendet. Wenn der Grenzwert dann wieder unterschritten wurde, wird der PC erneut informiert, da das Paket nun wieder aufgenommen wurde.
void loop() { delay(1000); force_value = analogRead(FORCE_SENSOR); switch (force_state){ case 0: if (force_value >= FSR_GRENZWERT) { force_state = 1; digitalWrite(ONBOARD_LED, HIGH); Serial.print("Paket abgelegt"); } break; case 1: // Wurde Paket aufgenommen? if (force_value < FSR_GRENZWERT) { force_state = 0; digitalWrite(ONBOARD_LED, LOW); Serial.print("Paket aufgenommen"); } break; } }
Zeile. Beschreibung
2. Es wird eine Wartezeit pro Durchlauf von 1000 ms festgelegt, damit der FSR nicht zu häufig abgefragt wird.
3. Der Wert vom FSR wird mit der Funktion analogRead() ausgelesen. Dabei wird innerhalb der Klammern der analoge Port (den wir vorhin in der Konstante FORCE_SENSOR gespeichert hatten) angegeben. Den Rückgabewert der Funktion speichern wir in der Variable force_value.
4. switch steht für eine Bedingung. Dabei wird innerhalb der Klammern das zu unterscheidende Element angegeben – hier force_state.
5. Innerhalb von einem switch können die verschiedenen Fälle mit case unterschieden werden. Dabei wird jeweils hinter case der entsprechende Wert des zu unterscheidenden Elements angegeben. In diesem Fall wird der nachfolgende Code (Zeile 7-12) nur ausgeführt, wennforce_state den Wert 1 hat.
6. Hier befindet sich eine weitere Bedingung: Nur wenn der Wert des Drucksensors,force_value, größer oder gleich des definierten Grenzwerts ist, wird der nachfolgende Code ausgeführt (Zeile 7-11). Zeile 12 wird egal ob diese Bedingung erfüllt ist ausgeführt.
7.
8. Hier wird der Status, ob ein Paket auf dem Sensor liegt, force_state, auf 1 gesetzt, da der Grenzwert überschritten wurde.
9. Da ein Paket auf dem Sensor liegt, wird der digitale Ausgang ONBOARD_LED (die LED, die sich auf dem Arduino befindet) aktiviert. Die Funktion digitalWrite() erhält dabei als ersten Parameter den Port, als zweiten ob dieser aktiviert (HIGH) oder deaktiviert (LOW) sein soll.
10. In dieser Zeile wird über die serielle Schnittstelle die Meldung “Paket abgelegt” an den Computer gesendet.
11.
12. In dieser Zeile wird der aktuelle Funktionsdurchlauf abgebrochen, da die Verarbeitung abgeschlossen ist.
Da die restlichen Zeilen ähnlich den Zeilen 5-12 sind, hier nur eine kurze Zusammenfassung der Unterschiede:
13. Hier wird, wenn force_state = 1 ist, der folgende Code (Z. 14-20) ausgeführt (siehe Z. 6-12).
14. Wenn der Wert vom FSR wieder kleiner ist als der Grenzwert, dann…
16. … wird force_state gleich 0 gesetzt.
17. … die LED deaktiviert.
18. … über die serielle Schnittstelle die Meldung “Paket aufgenommen” ausgegeben.
20. … der Funktionsdurchlauf abgebrochen.
Damit ist das Programm für den Arduino fertiggestellt und wir können es auf den Arduino übertragen. Dazu wird der Arduino zuerst mit einen freien USB-Anschluss des Computers verbunden. Dann wird durch einen Klick auf das UPLOAD-Symbol im Arduino-Fenster die Übertragung gestartet.
Wenn die Übertragung fertig ist und erfolgreich war (was ihr am unteren Rand des Arduino-Fensters erkennen könnt), könnt ihr den seriellen Monitor aufrufen und euer Programm testen.
Drückt einfach mal das obere, runde Ende des Drucksensors zusammen und schaut, ob der serielle Monitor eine Meldung vom Arduino empfängt. Wenn ihr wieder loslasst, sollte erneut eine Meldung erscheinen.
Auswertung am PC mit Python
Nun zur Auswertung der vom Arduino gesammelten Daten am Computer. Zur Programmierung verwenden wir die Sprache Python in Version 2.7 (!). Außerdem benötigen wir das Modul pyserial, das ihr hier herunterladen und installieren könnt. Alles weitere dazu findet ihr auf der Website des Projekts.
Um zu Starten öffnen wir die Python IDLE, die ihr nach der Installation auf eurem PC vorfinden solltet. Nach einem Tastendruck von STRG + n (Windows) oder CMD + n (Mac) öffnet sich ein neues, leeres Fenster, in das wir nun den Programmcode schreiben.
Zuerst muss das eben installierte Modul importiert werden, damit wir die Funktionen in unserem Programm verwenden können:
import serial
Nun soll das Programm eine Verbindung mit dem Arduino über den seriellen Port herstellen. Dazu initialisieren wir die Verbindung:
arduino = serial.Serial('SERIELLEN_PORT_AENDERN',baudrate=9600,timeout=1)
In dieser Zeile weisen wir dem Objekt arduino eine serielle Verbindung über den seriellen PortSERIELLEN_PORT_AENDERN mit einer Baud-Rate von 9600 und einer maximalen Wartezeit (timeout) von 1 Sekunde zu. Hierbei müsst ihr aber SERIELLEN_PORT_AENDERN durch den seriellen Port eures Arduinos am Computer ersetzen.
Den serielle Port des Arduinos am Computer könnt ihr leicht ermitteln: Zuerst trennt ihr die USB-Verbindung von Arduino und Computer. Dann öffnet ihr die Arduino-Software und geht in der Menüleiste auf Tools > Serieller Port. Merkt euch alle Elemente der erscheinenden Liste. Nun schließt ihr das Menü wieder und steckt den Arduino an den Computer. Öffnet erneut das Menü und vergleicht die Liste mit der, die ihr euch gemerkt habt. Es sollte(n) ein/zwei neue(s) Element(e) vorhanden sein. Nun notiert euch das neue Element, welches mit /dev/tty beginnt (Mac) bzw. das welches die höchste Nummer am Ende stehen hat (Win). Dieses fügt ihr dann anstelle vonSERIELLEN_PORT_AENDERN ein.
Jetzt soll unser Programm auf Nachrichten vom Arduino warten und eventuell empfangene ausgeben.
while True: nachricht = arduino.readline() print(nachricht)
Zeile. Beschreibung
1. while True bedeutet, dass der nachfolgende, eingerückte Programmcode unendlich oft ausgeführt werden soll.
2. arduino.readline() wartet auf eine Nachricht vom Arduino und speichert diese dann in der Variable nachricht
3. print() gibt das in Klammern stehende, also die Nachricht, auf dem Bildschirm aus.
Um zu testen, ob das Programm wirklich funktioniert, ladet euer Arduino-Programm nochmals auf den Arduino (siehe oben), startet aber nicht den seriellen Monitor. Stattdessen startet ihr, nachdem das Programm auf dem Arduino gestartet ist, das Python-Programm auf eurem Computer (MenüRun > Run Module oder eventuell Taste F5). Sollte nun bei Druck auf den Sensor die Meldung “Paket abgelegt” auf dem Bildschirm (Python-Shell) erscheinen, läuft alles korrekt.
Um das Programm jetzt wieder zu beenden muss ein sog. KeyboardInterrupt gesendet werden (Tastenkombination: ctrl + c (Mac), Strg + c (Windows)).
rbehebung
Python
Die angegebenen rmeldungen sind jeweils nur die letzte Zeile der Meldung.
ImportError: No module named serial
Wahrscheinlich hast du pyserial nicht (korrekt) installiert. Lade es erneut von der Homepage herunter und probiere es noch einmal.
NameError: serial is not definied
Du hast die Zeile import serial ganz oben im Programmcode vergessen.
serial.serialutil.SerialException: could not open port <...>: [Errno 2] No such file or directory: '<...>'
(<…> = beliebig)
Prüfe noch einmal ob du den Arduino angeschlossen hast und das Arduino-Programm läuft. Auch darf der serielle Monitor der Arduino-Software nicht geöffnet sein. Sollte das Problem weiterhin bestehen, wiederhole die Schritte zur Bestimmung des seriellen Ports.
KeyboardInterrupt
Diese (r-)Meldung erscheint sobald du einen KeyboardInterrupt (s.o.) an dein Python-Programm sendest. Das bedeutet nicht, dass ein r im Programmcode vorliegt.
Programmcode-Download
Der gesamte Programmcode steht für euch als Download unter folgenden Links zur Verfügung.
Quelle
Idee & Umsetzung basierend auf: Riley, Mike: Das intelligente Haus. 1. Auflage, Köln: O’Reilly, 2012.
Fortsetzung – Mobile Geeks DIY #2
In der nächsten Ausgabe von MobileGeeks DIY geht es dann um die Verarbeitung der vom Arduino gesendeten Nachrichten mit dem Computer / Python. Dies könnte z. B. das Versenden einer E-Mail o.ä. sein. Auch kann das Programm eine Liste führen, wann Pakete abgelegt und wieder aufgenommen wurden. Ihr seht: Es gibt endlos viele Möglichkeiten, was man alles mit dem Arduino/diesem Projekt machen kann. Wenn ihr selber noch Ideen habt, schreibt mir doch einfach eine kurze Nachricht (Kontaktformular s.u.).
Fragen, Kritik, Vorschläge
Wie hat euch die erste Ausgabe von Mobile Geeks DIY gefallen?
Ich freue mich auf eure Fragen, Kritik, Vorschläge und Feedbacks! Schreibt mir eine Nachricht im folgenden Kontaktformular.
Sollte ein Programm rmeldungen ausgeben, welche nicht durch den Abschnitt rbehebung gelöst werden konnten, bitte immer die vollständige rmeldung, den Programmcode, sowie (wenn möglich) die Schritte zur Reproduktion des rs mit angeben, damit ich auf eure Probleme besser eingehen kann.
Unsere Partner
Mobile Geeks DIY wird freundlich unterstützt von ExpTech.de und PhysicalComputing.at. Schaut doch mal bei ihnen vorbei!
Freue mich auch über Emails: lindholm (punkt) matthias (at) gmail (Punkt) com!
Immer auf dem Laufenden bleiben? Dann abonniere unseren RSS-Feed!
