RoboSoccer: Unterschied zwischen den Versionen
K (Ulrich Schneider verschob Seite RoboSoccer WS 14/15 nach RoboSoccer, ohne dabei eine Weiterleitung anzulegen) |
|
(kein Unterschied)
|
Version vom 10. September 2015, 12:33 Uhr
Autoren:
Regelwerk RoboSoccer
Basler GigE Vision System
Aufzeichnungen
Wenn Testaufzeichnungen gemacht werden, sind diese mit folgendem Dateinamen zu speichern:
YYMMDD_HHMMSS_Kamera_BreitexHöhe_Framerate_Kurzer_beschreibender_Text.mp4
Beispiel:
141210_121011_Kinect_1280x960_30fps.mp4
Schreiben Sie eine Textdatei, die diese Aufzeichnung näher beschreibt. Beachten Sie bei der Aufzeichnung:
- Spielfeld scharf stellen. Schalten Sie für die Aufzeichnung den Autofokus aus, so dass das Spielfeld während der Aufzeichnung scharf gleibt.
- Blende öffnen, um eine hohe Tiefenschärfe zu erzeugen.
- Machen Sie einen einmaligen Weißabgleich, damit die Farben im üblichen Rahmen sind.
- Zeichnen Sie Videos oder Bilder mit maximaler Auflösung und konstanter Framerate auf.
- Falls Sie Einzelbilder speichern, speichern Sie als Referenz die Zeitstempel mit im Bildnamen ab.
Einleitung
In dieser Anleitung wird ein Verbindungsaufbau zweier NXT-Bricks mit einem Host-Rechner via Bluetooth aufgezeigt. Dabei werden keine Kenntnisse über die Funktionsweise in Bluetooth oder der Netzwerktechnik benötigt. Allerdings erfolgt die Verbindung über Matlab, sodass Grundkenntnisse in Matlab vorausgesetzt sind.
Weiterhin wird ein Demo-Sourcecode in NXC (eine C-ähnliche Sprache) kurz beschrieben, welcher in der IDE BricxCC geschrieben wird. Dieser Sourcecode wird auf den Brick geladen und dient zum Steuern und zum Empfangen von Daten (z.B. Koordinaten), welche via Bluetooth über Matlab gesendet werden.
1. Schritt: Vorbereitung
Im ersten Schritt werden alle Bereiche angesprochen, die als Basis für eine Bluetoothverbindung zwischen den Bricks und dem Host-Rechner dienen:
Als Erstes sollte immer überprüft werden, ob der Host-Rechner über eine Bluetooth-Schnittstelle verfügt und ob diese tatsächlich auch eingeschaltet ist. Auch das Bluetooth vom NXT-Brick sollte eingeschaltet sein (Tipp: Der Schlafmodus des Bricks (Sleep) sollte am besten ausgeschaltet sein, damit bei Inaktivität der Brick sich nicht ausschaltet und somit seine Bluetooth-Verbindung nicht beendet). Weiterhin ist es wichtig, den NXT-Brick nicht zu weit vom Host-Rechner zu stellen. Der Grund hierfür liegt in der Sendeleistung, welche die Reichweite bestimmt (abhängig von Interferenzen/Störquellen). Es sollte jedoch von einer Reichweite von max. 10m ausgegangen werden (Sendeleistung von 1mW). Weiterhin muss für die Ausführung die RWTH - Mindstorms NXT Toolbox von RWTH-Aachen auf dem Host-Rechner vorhanden sein. Falls dies nicht der Fall ist, so kann dies bspw. unter folgendem Link heruntergeladen werden: [1]. Hinweis: Wichtig ist, dass der Ordner, in dem sich die ebengenannte Toolbox befindet, zum Matlab-Pfad hinzugefügt ist (Add to Path).
Ein weiterer Punkt stellt die Verwendung von Matlab dar. Alle hier aufgeführten Beispiele, die in Matlab realisiert wurden, beziehen sich auf "Matlab 2014a". Aus diesem Grund sollten alle Beispiele, welche in Matlab ausgeführt werden sollen, auch diese Version nutzen.
2. Schritt: Informationssgewinnung
In diesem Abschnitt wird die Informationsgewinnung für eine Bluetoothverbindung zwischen den Bricks und dem Host-Rechner beschrieben:
Für die Verbindung zwischen den Bricks und dem Host-Rechner wird ein sogenanntes "handle" benötigt. Dieses handle braucht jedoch einige Informationen für eine Bluetoothverbindung und wird im Workspace von Matlab als Variable hinterlegt. Anhand des folgenden Beispiels wird aufgezeigt, wie die benötigten Informationen aufgerufen werden.
Zunächst wird die Variable BT angelegt, in welcher die instrhwinfo hinterlegt wird:
>> BT=instrhwinfo('Bluetooth')
BT =
RemoteNames: {4x1 cell}
RemoteIDs: {4x1 cell}
BluecoveVersion: 'BlueCove-2.1.1-SNAPSHOT'
JarFileVersion: 'Version 3.4'
Wie dem oberen Quelltextausschnitt zu entnehmen ist, liegen in der Variable BT "RemoteNames" vor. Diese "RemoteNames" sind "Gerätenamen", welche über Bluetooth ermittelt wurden bzw. noch im Speicher liegen. Diese Gerätenamen werden an dieser Stelle benötigt. Um sie anzuzeigen, wird folgendes eingegeben:
>> BT.RemoteNames
ans =
'EV3'
'NXT17'
'NXT'
Im oberen Codeausschnitt müssen diejenigen Namen auftauchen, welche auch auf dem Brick-Display zu sehen sind. An dieser Stelle wird der Brick mit dem Namen "NXT17" zum weiteren Vorgehen ausgewählt:
>> BT=instrhwinfo('Bluetooth', 'NXT17')
BT =
RemoteName: 'NXT17'
RemoteID: 'btspp://0016530EC53C'
ObjectConstructorName: {'Bluetooth('NXT17', 1);'}
Channels: {'1'}
Aus den oberen Informationen sind der Name sowie der Kanal (Channel) für das weitere Vorgehen unabdingbar.
3. Schritt: Erstellung einer Konfigurationdatei
In diesem Schritt erfolgt eine Erläuterung, wie eine Konfigurationsdatei erstellt und geladen wird:
Für die Bluetoothverbindung ist die Konfigurationsdatei entscheidend. Allerdings muss diese noch erstellt und mit den obigen Informationen gefüllt werden. Zunächst muss die Funktion "COM_MakeBTConfigFile" aufgerufen werden. Dabei öffnet sich ein Dialog, in welchem ein Ordner für die Konfigurationsdatei ausgewählt werden muss (Tipp: Auch hier sollte man nicht vergessen, dass der Ordner, in welchem die Konfigurationsdatei abgespeichert wird, zum Matlab-Pfad hinzugefügt werden muss). Ist die Wahl des Ordners abgeschlossen, taucht ein zweiter Dialog auf.
Der zweite Dialog, welcher hier rechts abgebildet ist, benötigt den Namen des Bricks und den Kanal. Da der ausgewählte Brick den Namen "NXT17" und den Kanal "1" besitzt, werden diese in den entsprechenden Textfeldern eingetragen (Tipp: Nach Abschluss der Eingabe sollte diese auf Korrektheit überprüft werden. Sollte dennoch ein Fehler auftreten, so kann diese Konfiguration einfach neu erstellt oder die bereits erstellte Konfiguration geändert/verbessert werden). Weiterhin ist die Vergabe eines Namens (Filename) der Konfigurationsdatei wichtig. Der Grund hierfür liegt darin, dass pro Brick eine Konfiguration benötigt wird. Wenn also zwei Bricks benutzt werden, so müssen auch zwei Konfigurationsdateien erstellt werden (mit entsprechenden Informationen). Alle anderen Einstellungen bzw. Textfelder können i.d.R., so wie in dem rechts stehenden Bild, übernommen werden.
Wie bereits im 2. Schritt erwähnt, wird ein "handle" für die Bluetoothverbindung benötigt. Da die Konfigurationsdatei nun erstellt ist, kann nun ein "handle" erstellt werden:
handle = COM_OpenNXT('bluetooth.ini')
Wie dem oberen Codeausschnitt zu entnehmen ist, stellt das "handle" eine Variable dar und kann somit frei gewählt werden (Anmerkung: Gibt man den Befehl, wie oben dargestellt, ein, so kann eine Warnung in roter Schrift auftauchen. Davon sollte man sich nicht verunsichern lassen. Entscheidend ist, dass das "handle" alle nötigen Informationen enthält. In der Regel kann die Warnung ignoriert werden.).
Beim Eingeben des oberen Befehls sollte ebenfalls darauf geachtet werden, dass der Name der erstellten Konfigurationsdatei, in diesem Fall "bluetooth.ini", korrekt ist. Findet der Einsatz bspw. zweier Bricks statt, so müssen ebenfalls zwei Konfigurationsdateien mit den entsprechenden Informationen aus dem 2. Schritt erstellt werden. Dabei ist weiterhin sicherzustellen, dass diese Konfigurationsdateien nicht den gleichen Namen besitzen. Auch die "handle"-Variable gilt immer nur für einen Brick. Setzt man zwei Bricks ein, so müssen auch zwei "handle"-Variablen angelegt werden (Im Praktikum sollten daher die Namen "handle_1" für Brick 1 und "handle_2" für Brick 2 verwendet werden).
4. Schritt: Prüfung der Verbindung
Nach erfolgreichem Abschluss des 3. Schrittes sollte jetzt eine Verbindung zwischen dem Host-Rechner und dem Brick bestehen. Die Prüfung, ob die Verbindung tatsächlich hergestellt wurde, findet in diesem Schritt statt:
Als Erstes muss die Variable "handle" im Workspace von Matlab auftauchen. Außerderm sollte diese von "class: struct" sein und ein "value: 1x1 struct" besitzen. Auf dem Display des Bricks erscheint ebenfalls bei erfolgreicher Verbindung neben dem Bluetooth-Symbol eine Raute. Sind die ebengenannten Punkte vorhanden, muss nun die Verbindung überprüft werden, indem ein Signal vom Host-Rechner an den entsprechenden Brick gesendet wird. Hierzu wird bspw. folgendes in Matlab eingegeben:
NXT_PlayTone(800, 100, handle)
Dieser Befehl bewirkt, dass am Brick ein Ton abgespielt wird (Hinweis: Um den Ton zu hören, sollte man sicherstellen, dass die Lautstärke am Brick laut genug ist). Ertönt nun ein Ton am Brick, so ist die Verbindung zum Brick via Bluetooth gelungen.
5. Schritt: Koordinaten senden
In diesem Schritt erfolgt eine Beschreibung, wie Daten an den NXT-Brick gesendet werden können.
Wurde eine Verbindung zu einem (ggf. mehreren) Brick(s) hergestellt, so ist man in der Lage, an diesen auch Daten, sogenannte "Messages", via Matlab zu senden. Dies sieht wie folgt aus:
NXT_MessageWrite('meineMessage', 0, handle);
Dadurch wird der String 'meineMessage' (Hinweis: Hier sollte man auf die Matlab-Syntax achten) zu dem Brick, welcher über das "handle" kommuniziert, gesendet. Diese Message wird dann auf ein Stack (dt. Stapel) im Brick hinterlegt. Nun kann die Message von dem Stack im eigenen Code (in nxc) abgeholt und verarbeitet werden (siehe dazu auch Demo-Sourcecode).
Die Message kann dabei frei gewählt werden. So kann man bspw. 'BallX200Y200' oder auch 'BallX200' als eine einzige Message senden. Entscheidend ist dabei, wie die Nachricht definiert wird, denn diese muss ebenfalls in dem nxc-Code wieder ausgewertet werden. Generell benötigt man die absoluten Werte (Koordinaten) vom Ball, eigenem Robotor usw., welche über die Tracking-Skripte geliefert werden. Diese müssen dann nur noch entsprechend "verpackt" und gesendet werden. Zum Testen können auch Pseudokoordinaten gesendet werden. Weiterhin ist zu beachten, dass die Koordinaten immer in einer Schleife gesendet werden. Dabei darf diese Schleife nicht schnellstmöglich, sondern verzögert ablaufen. Dies liegt daran, dass der Roboter eine gewisse Zeit braucht, bis er eine bestimmte Koordinate erreicht hat (abhängig von der Motorleistung und der Entfernung).
Demo-Sourcecode
An dieser Stelle wird aufgezeigt, wie ein Brick die gesendeten Daten (via Bluetooth) empfängt und bearbeitet.
Zunächst wird der Sourcecode betrachtet:
task main() { string in; int x = 200; while(true) { if (ReceiveMessage (0, true, in) == NO_ERR) { x = atoi(in); } if(x < 100) { OnFwd ( OUT_A,75 ); OnFwd( OUT_C , 75); Wait ( 4000); Off(OUT_AC); } } }
Als Erstes wird die "task main()" betrachtet. Die "task main()" ist der Haupteinsprungspunkt jedes Programms, welches mit nxc geschrieben wird. Das bedeutet, dass ab "task main()" das Programm ausgeführt wird. Vor dem Haupteinsprungspunkt kann zwar ebenfalls Code stehen, dieser darf jedoch nur zur Deklaration, Definition und/oder Initialisierung genutzt werden. Man bezeichnet (je nach Programmiersprache/Skriptsprache) "alles, was vor dem Haupteinsprungspunkt" steht als Präambel.
Nach "task main()" kommen geschweifte Klammern "{}". Diese sagen aus, wo das "eigentliche" Programm (also die Logik) beginnt und endet. Fehlen die Klammern bzw. gibt es zu viele Klammern, so weigert sich der Compiler den Code zu kompilieren. Deswegen sollte immer darauf geachtet werden, dass die Klammern auf- und zugehen.
Als Nächstes sieht man die Deklaration und Initialisierung zweier Variablen. Die Variablen "string in;" und "int x = 200;" sind in diesem Kontext lediglich als Beispielvariablen zu betrachten, diese können natürlich anders heißen und auch andere Werte bekommen. Generell, wenn man Variablen anlegen möchte, schreibt man (bei nxc) zuerst den Typ der Varaible hin und dann den Namen der Variable. Beispielsweise wurde im oberen Code "string" geschrieben. Dieser Typ sagt dem "Computer", dass der Variablenname "in" nur für Zeichenketten geeignet ist. Mit einem Semikolon wird die "Anweisung" beendet. Das ist sehr wichtig, denn dadurch weiß der Compiler, dass die Variable "in" von Typ "string" ist, aber noch keinen Inhalt besitzt, also leer ist. Die Variable "x" besitzt im Vergleich zur vorherigen Variable einen anderen Typen (int, also Ganzzahlenwert) und besitzt den Wert 200. In diesem Beispiel hat die Zahl keine besondere Bedeutung.
In der nächsten Zeile steht die "while"-Schleife. Diese hat in dem Demobeispiel im Kopf (in den Klammern) "true" stehen, welches dafür sorgt, dass die Schleife nie beendet wird und immer wieder durchlaufen wird. Solche Schleifen nennt man auch Endlosschleifen und sollten immer mit großer Vorsicht eingesetzt werden. Generell ist es so, dass die "task main()" von oben nach unten ablaufen würde und sich schließlich irgendwann beenden würde. Das ist ungünstig, weil man das Programm für eine längere Zeit in Betrieb haben möchte. An dieser Stelle greift diese Endlosschleife. Da diese Schleife nicht verlassen wird, kann auch das Programm nicht mehr von sich aus beendet werden.
Innerhalb der "while"-Schleife steht folgendes:
if (ReceiveMessage (0, true, in) == NO_ERR) { x = atoi(in); }
Diese "if"-Abfrage bezieht eine Message, also Daten, welche von dem Hostrechner mittels Matlab via Bluetooth an den Brick gesendet wurden. Diese Daten werden als String gesendet und in diesem Beispiel in der Variable "in" gespeichert. Allerdings muss dieser String noch zum Typ "int" konvertiert werden. Dies geschieht mit der Funktion "atoi". Das Ergebnis wird in der Variable "x" gespeichert. In diesem Fall könnte man annehmen, dass es sich hierbei um eine x-Koordinate handelt.
Die letzte "if"-Abfrage kontrolliert, ob der "x"-Wert kleiner 100 ist. Trifft dieser Fall ein, so werden die Motoren gestartet:
OnFwd(OUT_A,75); OnFwd(OUT_C,75);
Der obere Ausschnitt sorgt dafür, dass die Motoren A und C mit einer Leistung von 75% vorwärts drehen sollen (max 100% ist mögl.). Mit "Wait(4000);" wird das Programm für vier Sekunden mit der Besonderheit pausiert, dass die Motoren weiterhin drehen. Mit "Off(OUT_AC);" werden die Motoren wieder ausgeschaltet. Allerdings läuft das Programm so schnell ab, dass wenn in diesem Beispiel "x" immer kleiner 100 ist, die Motoren nie sichtbar zum Stehen kommen.
Weiteres Tutorial zum Nachschlagen: http://www.hsg-kl.de/faecher/inf/msr/lego/nxc/NXC-Tutorial_DE.pdf. Die Dokumentationen für nxc sind auf der folgenden Seite hinterlegt: http://bricxcc.sourceforge.net/nbc/nxcdoc/nxcapi/index.html, http://bricxcc.sourceforge.net/nbc/nxcdoc/nxcapi/group___hi_technic_a_p_i_ga6acad43b9093e56fd45d2a76d21a6782.html, http://www.debacher.de/wiki/Sensoren#Der_Kompass-Sensor
Erweiterter Demo-Sourcecode
In dem vorangegangenen Kapitel wurde ein sehr kurzer Einblick in die nxc-Sprache gegeben. An dieser Stelle wird das oben erworbene Wissen über nxc an gewissen Stellen erweitert. Hinzu kommt ebenfalls ein Demo-Code von Matlab, um das Senden und Empfangen von Nachrichten besser zu greifen. Die Beschreibung des vorliegenden Beispiels setzt das erfolgreiche Durchführen der Schritte 1 bis 5 voraus.
Zunächst wird der Matlab-Code betrachtet. Das Senden einer Message kann wie folgt aussehen:
%Matlab Demo-Script while true StrA = 'A'; Koordinate_x = Funktion_x; Koordinaten_y = Funktion_y; KoordinatenA = strcat(StrA, 'X' , int2str(Koordinate_x), 'Y', int2str(Koordinaten_y)); NXT_MessageWrite(PunktA, 0, handle); end
Als Erstes wird eine Bezeichnung erstellt. In dem oberen Matlab-Code ist es "StrA = 'A';". Das 'A' steht stellvertretend für z.B. das Tor oder den Ball. Als Nächstes werden über "Funktion_x" und "Funktion_y" die Koordinaten für das entsprechende Objekt geholt.
In diesem Beispiel sollen die Koordinaten eines Objektes als "Ganzes" gesendet werden. Hierfür werden die Werte in den Typen String umgewandelt mit "int2str()" und zu einem String mithilfe von "strcat()" zusammengefasst. Im nächsten Schritt kann mittels "NXT_MessageWrite(PunktA, 0, handle);" die Message schon gesendet werden. Eine reine Zahlenkodierung wie z.B. für den Ball die Zahl 1 ist durchaus machbar. Allerdings sollte man dann bei der Dekodierung besonders aufpassen, um die einzelnen Bezeichnungen nicht durcheinander zu bringen und diese ebenfalls nicht mit Koordinaten zu verwechseln. Die while-Schleife erlaubt als Endlosschleife die Koordinaten zyklisch zu senden.
Als Nächstes wird der NXC-Code betrachtet:
//Sourcecode für die Bricksteuerung //TextOut( 0, LCD_LINE1, "Ausgabetext", true); //zeigt einen String auf dem Brick-Display (ist ggf. bei der Fehlersuche nützlich) #define Anfangsindex 0 //Makro #define Anfangslaenge 1 //Globale Variablen int X, Y = 0; //X-Koordinate und Y-Koordinate /*Die Message, welche empfangen wird, ist wie folgt aufgebaut: "AXzahlenwertYzahlenwert" Das A entspricht der Position eines Objektes (z.B. Ball), also das was man in Matlab für "StrA" geschrieben hat. Das "X" gibt an, dass alle folgenden Ziffern die X-Koordinate bilden bis zum "Y" (nicht vergessen: es handelt sich hier um einen String, welcher in Matlab von einem selber erstellt wurde!). Das "Y" gibt an, dass alle Ziffern bis zur letzten Stelle nach dem "Y" die Y-Koordinate bilden. Allerdings liegt die empfangene Message, wie bereits mehrfach ausgeführt, als String vor und muss noch mit der Funktion atoi() in ein int-Typ konvertiert werden. Dabei dienen die Zeichenketten wie "Ball" nur zur Erkennung, folglich handelt es sich hierbei um die Koordinaten des Balles. Die angehängten Ziffern müssen noch "gefiltert" werden!*/ sub bezieheMessage() { string MsgEingang; if (ReceiveMessage (0, true, MsgEingang) == NO_ERR) //Hier wird die empfangene Message in den String MsgEingang hinterlegt { int Strlaenge = strlen(MsgEingang); //Gesamtlänge des Strings int i = 2; //Die "2" gibt die Position nach dem "X" in dem MsgEingang an, also die Stelle, an welcher die X-Koordinate anfängt if("A" == SubStr(MsgEingang, Anfangsindex, Anfangslaenge)) //Hier findet die Auswertung des String statt, sofern der String mit "A" //anfängt. Die Anfangslaenge sagt aus, inwieweit der String betrachtet //werden soll, in diesem Fall nur ein Element weit (es wird also das //erste Zeichen untersucht, ob es "A" ist oder nicht!). { if("X" == SubStr(MsgEingang, 1, Anfangslaenge)) //Hier wird das Zeichen nach "X" untersucht, also ob es ein "X" ist { while("Y" != SubStr(MsgEingang, 2, i)) //In der Schleife wird solange inkrementiert bis bei MsgEingang "Y" erreicht wurde { i++; if(i>Strlaenge) {break;} } X = atoi(SubStr(MsgEingang, 2, i-1)); //X-Koordinate wird als Zahlenwert gespeichert //Die "2" gibt an, ab welcher Stelle der String gelesen wird und //"i-1" bis zur welcher Stelle der String gelesen wird. //Da sich "Y" bei der Stelle i befindet, stellt "i-1" den letzten X-Zahlenwert dar! } if("Y" == SubStr(MsgEingang, i, Anfangslaenge)) //i sagt aus, dass die Position von Y betrachtet wird. //Wiederholung: i stellt die Position von dem String "Y" dar(siehe oben)! { Y = atoi(SubStr(MsgEingang, i+1, Strlaenge)); //Y-Koordinate wird als Zahlenwert gespeichert } } else if("B" == MsgEingang) { } else if("C" == MsgEingang) { } else if("D" == MsgEingang) { } else if("E" == MsgEingang) { } } } sub Zeit_In_X_Richtung(int X_Ziel, int X_Roboter) //Berechnung erfolgt bei konstanter Leistung, Strecke wird in cm angegeben { //int Strecke = abs(X_Ziel - X_Roboter); //Rechnung: int Zeit_X = Strecke/50; //50 sind 50% Leistung des Motors } sub Zeit_In_Y_Richtung(int Y_Ziel, int Y_Roboter) //Berechnung erfolgt bei konstanter Leistung, Strecke wird in cm angegeben { //int Strecke = abs(Y_Ziel - Y_Roboter); //Rechnung: int Zeit_Y = Strecke/50; } sub Wenden() { //Roboter kann hier gewendet werden } /*sub MotorenSteuerung() { OnFwd(OUT_AC, 50); Wait(ZEIT); Off(OUT_AC); } */ task main() { while(true) //Programm kann nur manuell vom Benutzer beendet werden { bezieheMessage(); //Zeit_In_X_Richtung(int X_Ziel, int X_Roboter) //Zeit_In_Y_Richtung(int Y_Ziel, int Y_Roboter) /*if(muss gewendet werden?) { Wenden() }*/ /*if(Motoren steuern?) { MotorenSteuerung(); } */ } }
Theoretische Betrachtung
In diesem Kapitel findet eine Betrachtung statt, in der man seinen Code ohne ein Tracking-Skript prüfen kann.
Sobald alle Schritte erfolgreich verlaufen sind und der ncx-Sourcecode vorliegt, kann dieser privat getestet werden. Hierzu sollte man bspw. mit einem Klebeband ein Feld auf dem Boden kleben und die Mitte des Feldes als Koordinate (0|0) festlegen. Als Nächstes misst man einen zufälligen Punkt (Hinweis: Positive X-Koordinatenwerte liegen im rechten Teil und positive Y-Koordinaten liegen im oberen Teil des kartesischen Koordinatensystem etc.). Dieser Punkt kann nun manuell über Matlab mit dem Befehl aus dem 5. Schritt gesendet werden (Angabe des Punktes in cm). Der Roboter sollte dabei ungefähr den Punkt anfahren können. Entscheidend dabei ist die Richtung des Roboters. Das bedeutet, dass der Roboter in der Lage sein muss, seine Blickrichtung zu erkennen und zu verändern.