Taktile Schalter oder auch Berührungsschalter werden häufig in der Robotik zur Materialerkennung eines Objektes eingesetzt, um in einem Produktionsprozess Objekte auszurichten oder auf verschiedene Behältnisse zu verteilen.
Wir werden den BoE-Shield Bot Arduino mit einem taktilen Schalter (whiskers) versehen, ihn testen und so programmieren, dass die verschiedenen Zustände des Schalters dargestellt werden und dann entscheiden, wie der Roboter sich verhalten soll, wenn die whiskers ein Hindernis erfühlt haben. Am Ende bewegt sich der Roboter völlig autonom durch den Raum, gesteuert über die Wahrnehmung durch seine Fühler.
Der Bausatz der Fühler kann über die Fa. Parallax bezogen werden.
Wie die Schalter (Whiskers) arbeiten
Die Fühler sind auf der einen Seite über die Befestigungsschrauben direkt mit Masse verbunden und auf der anderen über einen Widerstand von 220 Ohm mit einem digitalen Eingang des Arduino und über einen 10 kOhm pull-up Widerstand mit der Spannungsversorgung von 5V (Abb. 1).
Im Programm werden zuerst die beiden Anschlusspin auf Input-Modus gestellt
pinMode(pin, mode)
und anschließend ihr Zustand HIGH oder LOW mit der Funktion digitalRead(pin) abgefragt.
Ist der Fühler offen (er hat keinen Kontakt mit einem fremden Objekt), dann liegen am Eingang von P7 5Volt an und die Abfrage
digitalRead(7)
gibt eine 1 (HIGH) zurück. Im rechten Bild (Abb. 1) ist der Fühler geschlossen (es besteht Kontakt mit einem fremden Objekt) und
digitalRead(7)
gibt eine 0 (LOW) zurück. Die Rückgabewerte werden in Variablen wLinks und wRechts abgelegt und später genutzt um irgendwelche Aktionen auszulösen oder Entscheidungen zu treffen.
Im folgenden Programm wird überprüft, ob die Fühler funktionieren; dazu werden im Terminal die binären Rückgabewerte der Funktionen digitalRead(7) und digitalRead(5) ausgegeben. Es genügt, wenn die metallenen Fühlerenden mit der Hand gegen einen Kontakt gedrückt werden, um die Funktion zu überprüfen.
Sind beide Fühlerkontakte offen, dann sollte im seriellen Monitor zweimal die 1 angezeigt werden (11). Wird einer der Fühlerkontakte geschlossen, dann erscheint im Monitor auf der entsprechenden rechten oder linken Seite eine Null (01) oder (10). Sind beide Fühler geschlossen, erscheint die Doppelnull (00).
Aufgaben |
|
Programm whiskers_test.ino
Wie arbeitet das Programm whiskers_test?
In der Methode setup() werden die beiden digitalen Pin 5 und 7 als Input deklariert. Über sie wird die Spannung der beiden Fühler-Schaltkreise abgefragt.
In der Methode loop() liefert jeder Programmzeilenaufruf von digitalRead eine Null zurück, wenn die Whiskers geschlossen und eine 1, wenn sie offen sind. Die Werte legt das Programm in den Variablen wLinks und wRechts vom Typ byte ab.
Mit Serial.print werden die Werte der beiden Variablen im Terminalfenster angezeigt. Der abschließende delay(100) Befehl verzögert die Textausgabe etwas.
Bisher haben wir den Roboter nur irgendwelche vordefinierten Bewegungen ausführen lassen. Jetzt gehen wir daran Programme zu entwickeln, die den BoE-Shield Bot Arduino intelligent reagieren lassen, sobald er mit seinen Fühlern ein Hindernis ertastet hat. Es ist ein erstes Beispiel einer selbstständigen Roboter Navigation.
Der Roboter soll geradeaus laufen, während die Pin 5 und 7, die mit den Fühlern verbunden sind, ständig auf Hindernisse abgefragt werden (tatsächlich werden dort Spannungswerte abgefragt).
Sobald ein elektrischer Kontakt zustande kommt, wird über eine if ...else if ... else Entscheidung das weitere Vorgehen bestimmt. Der Entscheidungscode überprüft die verschiedenen Kombinationen der taktilen Sensoren und ruft dann Funktionen auf, die den Roboter in eine Bewegung zurück mit anschließender Drehung bringen. Die Fahrt wird dann wieder mit einer Vorwärtsbewegung fortgesetzt bis zum nächsten Hindernis.
Aufgaben |
|
Das Programm whiskers_Felderkundung.ino
Wie arbeitet das Programm whiskers_felderkundung?
Mit der if ... else if ... else Anweisung in der Methode loop() werden alle möglichen Zustände der Fühler erfasst. Es beginnt mit
if((wLinks == 0) && (wRechts == 0)).
Wenn die Variable wLinks UND die Variable wRechts beide Null sind (dann haben beide whiskers ein Hindernis erfasst und die Taster sind geschlossen), dann fahre 1 Sekunde lang rückwärts und mache eine Linksdrehung.
Innerhalb einer if ... else if ... else Anweisung werden die Programmblöcke übersprungen, für die eine if-Anweisung nicht zutrifft. Es könnte zum Beispiel der linke Fühler gegen ein Hindernis stoßen und den Taster schließen, dann wird innerhalb der if ... else if ... else Anweisung der Programmblock abgearbeitet, für den diese Bedingung zutrifft. Das wäre dann die Bedingung
else if(wLinks == 0)
Der nachfolgende Programmblock wird ausgeführt
{ rueckwaerts(1000); drehungRechts(400); }
und der Rest der if ... else if ... else Anweisung übersprungen. Das Programm geht dann weiter nach dem letzten else-Statement.
Hat nur der rechte Fühler ein Hindernis erfasst, werden die beiden ersten Programmblöcke übersprungen und der auf
else if(wRechts == 0)
folgende Programmblock ausgeführt.
{ rueckwaerts(1000); drehungLinks(400); }
Mit der letzten else-Anweisung werden sozusagen alle restlichen Möglichkeiten erfasst. Sie ist nicht notwendig aber trotzdem ganz nützlich. Wenn dieser Fall eintritt, rollt der Roboter 20ms vorwärts; das ermöglicht ihm eine schnelle Reaktion auf Fühlerkontakte.
Du wirst feststellen, dass der Roboter in Ecken seine Probleme bekommt und häufig nicht mehr aus diesem Bereich herausfindet. Wenn der linke Fühler eine Wand erfasst, setzt der Roboter zurück und macht eine Rechtsdrehung. Anschließend bewegt er sich vorwärts, berührt jetzt mit dem rechten Fühler die andere Wand, setzt zurück und macht eine Linksdrehung. Und so geht es jetzt munter weiter, der Roboter hat sich damit festgefahren.
Solche Situationen kann man vermeiden, wenn man geschachtelte if-Statements anwendet. Das Programm überprüft eine Bedingung und wenn sie wahr ist überprüft sie eine weitere Bedingung innerhalb des ersten Programmblocks.
Im folgenden Programm wird der Roboter angewiesen eine Rückwärtsbewegung mit einem U-Turn einzuleiten, wenn die Whiskers vier oder fünfmal hintereinander rechts und links ein Hindernis detektiert haben.
Aufgaben |
|
Programm whiskers_eckenfalle.ino
Wie arbeitet das Programm whiskers_eckenfalle?
Da es nur wenige zusätzliche Programmzeilen zum bereits bekannten Programm whiskers_felderkundung gibt, beschränken wir uns auf die Kommentierung der neuen Programmzeilen, die sich mit der Eckenfalle befassen.
Es werden drei neue Variablen vom Typ byte eingeführt
wLinksAlt,
wRechtsAlt
zaehler.
Die ersten beiden Variablen speichern den letzten Berührstatus der Whiskers und vergleichen ihn mit dem aktuellen Status. Die Variable zaehler enthält die Anzahl aufeinanderfolgender alternierender Kontakte der Fühler.
Alle drei Variablen werden in der Methode setup() initialisiert. Bis auf eine Variable werden sie alle auf 0 gesetzt.
Im nächsten Schritt wird geprüft, ob einer der beiden Fühler Berührung mit einem Objekt hatte. Dazu wird der ungleich-Operator in der if-Anweisung benutzt.
Wenn(wLinks ungleich wRechts)
ist, bedeutet, wenn einer der beiden Taster eine Berührung mit einem Objekt hatte ...sind die Variablen nicht gleich und das Programm muss herausfinden, ob es ein sich wiederholendes Muster gibt. Um das herauszufinden, wird eine eingebettete zweite if-Anweisung aufgerufen, die überprüft, ob sich der aktuelle wLinks Wert vom wLinksAlt-Wert und der aktuelle wRechts-Wert vom wRechtsAlt-Wert unterscheidet. Treffen beide Bedingungen zu, dann wird die Variable zaehler um 1 erhöht.
if((wLinks != wLinksAlt) && (wRechts != wRechtsAlt))
und die Zustände in den beiden Variablen wRechtsAlt und wLinksAlt werden aktualisiert
zaehler++;
wLinksAlt = wLinks;
wRechtsAlt= wRechts;
Wenn hintereinander vier dieser Berührkontakte gezählt worden sind, wird die Variable zaehler zurück auf 0 gestellt und ein U-Turn des Roboters eingeleitet. Dadurch, dass im Programmblock der if-Anweisung die beiden Variablen wLinks und wRechts auf 0 gestellt werden, interpretiert das Programm das mit einem U-Turn.
if(zaehler == 4) { wLinks = 0; wRechts= 0; zaehler = 0; }
Ist die Bedingung if((wLinks != wLinksAlt) && (wRechts != wRechtsAlt)) nicht wahr, dass heißt, dass es keine aufeinanderfolgenden Berührungen des linken und rechten Whiskers mit einem Hindernis gegeben hat, dann wird sich der Roboter wohl nicht in einer Eckenfalle befinden, die Variable zaehler wird auf 0 zurückgesetzt und das Spiel kann von vorne beginnen.
Bemerkung
Etwas unübersichtlich sind die vielen geschweiften Klammern der verschiedenen Programmblöcke, die häufig nicht korrekt geschlossen werden und dann zu Fehlermeldungen führen. Hilfreich ist, zusammengehörende Programmblöcke und die entsprechenden Klammern einzurücken und darauf zu achten, dass die öffnende und die schließende Klammer gleich weit eingerückt werden.