RoboSoccer: Unterschied zwischen den Versionen

Aus HSHL Mechatronik
Zur Navigation springen Zur Suche springen
Keine Bearbeitungszusammenfassung
 
(41 dazwischenliegende Versionen von 4 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
'''Autoren:'''
* [[Benutzer:Anika_Leinhaeuser| Anika Leinhäuser]]
* [[Benutzer:Andre_Merkel| Andre Merkel]]
==[[Regelwerk RoboSoccer]]==
==[[Basler GigE Vision System]] ==
<!-- == Aufzeichnungen ==
Wenn Testaufzeichnungen gemacht werden, sind diese mit folgendem Dateinamen zu speichern:
<code>YYMMDD_HHMMSS_Kamera_BreitexHöhe_Framerate_Kurzer_beschreibender_Text.mp4</code>
Beispiel:
<code>141210_121011_Kinect_1280x960_30fps.mp4</code>
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.
[[Kategorie:Projekte]]
[[Kategorie:Projekte]]
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.
-->
== 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.  
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 ==
== 1. Schritt: Vorbereitung ==
Zeile 8: Zeile 32:
Im ersten Schritt werden alle Bereiche angesprochen, die als Basis für eine Bluetoothverbindung zwischen den Bricks und dem Host-Rechner dienen:
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 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).
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: [http://www.mindstorms.rwth-aachen.de/trac/browser#trunk/mfiles]. Hinweis: Wichtig ist, dass der Ordner, in dem sich die ebengenannte Toolbox befindet, zum MatLab-Pfad hinzugefügt ist (Add to Path).
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: [http://www.mindstorms.rwth-aachen.de/trac/browser#trunk/mfiles]. 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 ==
== 2. Schritt: Informationssgewinnung ==


In diesem Abschnitt wird die Informationsgewinnung für eine Bluetoothverbidung zwischen den Bricks und dem Host-Rechner beschrieben:
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.
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:  
Zunächst wird die Variable BT angelegt, in welcher die instrhwinfo hinterlegt wird:  
Zeile 30: Zeile 55:
</code>
</code>


Wie aus 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:   
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:   


<code>
<code>
Zeile 55: Zeile 80:
                 Channels: {'1'}
                 Channels: {'1'}


>> </code>
</code>


Aus den oberen Informationen werden der Name sowie der Kanal (Channel) für das weitere Vorgehen unabdingbar.  
Aus den oberen Informationen sind der Name sowie der Kanal (Channel) für das weitere Vorgehen unabdingbar.


== 3. Schritt: Erstellung einer Konfigurationdatei ==
== 3. Schritt: Erstellung einer Konfigurationdatei ==
Zeile 63: Zeile 88:
In diesem Schritt erfolgt eine Erläuterung, wie eine Konfigurationsdatei erstellt und geladen wird:
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, dem MatLab-Pfad hinzugefügt werden muss.) Ist die Wahl des Ordners abgeschlossen, taucht ein zweiter Dialog auf.   
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 "<b>COM_MakeBTConfigFile</b>" 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.   


[[Datei:BTConfig.png|gerahmt|Dialog zum Erstellen einer Konfiguration]]
[[Datei:BTConfig.png|gerahmt|Dialog zum Erstellen einer Konfiguration]]


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 die entsprechenden Textfelder 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.
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:
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:
Zeile 75: Zeile 100:
</code>
</code>


Wie in 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. Entscheidend ist, dass das "handle" alle nötigen Informationen enthält. In der Regel kann die Warnung ignoriert werden.)  
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).
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).
Zeile 81: Zeile 106:




=== Wichtiger Hinweis!===
Für das Informatikpraktikum I WS15/16 wurden alle Konfigurationsdateien bereits erstellt.




 
Vorgehensweise:
 
* Der Betreuer/in startet die Matlab GUI mit der Version Matlab R2014a D:\SVN\ProjektRobosoccer\SRC\m-files\RoboSoccerSkript.m.
 
* Bei der Initialisierung dürfen sich weder Roboter noch Ball auf dem Spielfeld befinden!
 
* Zunächst das ROI durch 2 Punkte ausgewählt.
 
* Jetzt sollen die 4 Spielfeldecken möglichst genau angeklickt werden (OL OR UR UL).
 
* Das Skript muss mittels des RUN/STOP Buttons pausiert werden.
 
* Bevor eine Bluetooth-Verbindung aufgebaut werden kann, muss der Roboter eingeschaltet sein.
 
* Die Bluetooth-Funktion am NXT muss eingeschaltet sein.
 
* Der Sleep-Modus sollte auf 'Never' eingestellt werden.
 
* Über die Buttons BT1 und BT2 kann jetzt eine Bluetooth Konfigurationsdatei für die betroffenen Roboter (siehe Brick_Bezeichner)geladen werden.
 
* Nach ca. 1 Minute soll im Matlab-Konsolenfenster das Bluetooth-Handle auftauchen.
* Das Skript wird jetzt wieder mit RUN/STOP fortgesetzt.




== 4. Schritt: Prüfung der Verbindung ==
== 4. Schritt: Prüfung der Verbindung ==


Nach erfolgreichem Abschluss des 3. Schrittes sollte jetzt eine Verbindung zwsichen dem Host-Rechner und dem Brick bestehen. Die Prüfung, ob die Verbindung tatsächlich hergestellt wurde, findet in diesem Schritt statt:
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 eben genannten 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:
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:


<code>
<code>
Zeile 106: Zeile 134:
</code>
</code>


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 Bluetoth gelungen.
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 ==
== 5. Schritt: Koordinaten senden ==
Zeile 112: Zeile 140:
In diesem Schritt erfolgt eine Beschreibung, wie Daten an den NXT-Brick gesendet werden können.
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:
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:


<pre>
<pre>
Zeile 120: Zeile 148:
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).
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 selbst 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 es wichtig zu beachten, dass die Koordinaten immer in einer Schleife gesendet werden. Dabei darf diese Schleife nicht schnellst möglich ablaufen sondern verzögert. 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).  
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 ==
== Demo-Sourcecode ==
Zeile 153: Zeile 181:
}</pre>
}</pre>


Als erstes wird die "task main()" betrachtet. Die "task main()" ist der Haupteinsprungspunkt jedes Programms welches mit nxc geschrieben wird. Das beudetet, dass ab "task main()" das Programm ausgeführt wird. Vor dem Haupteinsprungspunkt kann zwar ebenfalls Code stehen, dieser darf jedoch nur zu Deklaration, Definition und/oder Initialisierung genutzt werden. Man bezeichnet (je nach Programmiersprache/Skriptsprache) alles was vor dem Haupteinsprungspunkt steht als Präambel.
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 Klammer, so weigert sich der Compiler den Code zu kompilieren. Deswegen sollte immer darauf geachtet werden, dass die Klammern auf- und zugehen.
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 Variablen Name "in" nur für Zeichenketten geeignet ist. Mit einem Semikolon wird die "Anweisung" beendet. Das ist sehr wichtig, denn dadurch weiß der Compiler das die Variable "in" von Typ "string" ist, aber noch keinen Inhalt, 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.
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 ja das Programm für eine längere Zeit in Betrieb haben möchten. An dieser Stelle greift eben diese Endlosschleife. Da diese Schleife nicht verlassen wird, kann auch das Programm nicht mehr von sich aus beendet werden.
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:
Innerhalb der "while"-Schleife steht folgendes:
Zeile 170: Zeile 198:
</pre>
</pre>


Diese "if"-Abfrage bezieht eine Message, also Daten welche von dem Hostrechner mittels Matlab und Bluetooth an den Brick gesendet wurden. Diese Daten werden als String gesendet und 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.
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 Motoren gestartet:
Die letzte "if"-Abfrage kontrolliert, ob der "x"-Wert kleiner 100 ist. Trifft dieser Fall ein, so werden die Motoren gestartet:
<pre>
<pre>
OnFwd(OUT_A,75);
OnFwd(OUT_A,75);
Zeile 178: Zeile 206:
</pre>
</pre>


Der obere Ausschnitt sorgt dafür, dass die Motoren A und C Vorwärts fahren sollen mit einer Leistung von 75% (max 100% ist mögl.).
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 pausiert mit der besonderheit, dass die Motoren weiterhin fahren.
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.  
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:
 
<pre>
%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
 
</pre>
 
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:
 
<pre>
//Sourcecode für die Bricksteuerung
 


Weiteres Tutorial zum Nachschlagen http://www.hsg-kl.de/faecher/inf/msr/lego/nxc/NXC-Tutorial_DE.pdf.
        //TextOut( 0, LCD_LINE1, "Ausgabetext", true);  //zeigt einen String auf dem Brick-Display (ist ggf. bei der Fehlersuche nützlich)
Die Dokumentationen für nxc sind auf der folgenden url hinter legt: 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
 
#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();
      }
      */
  }
 
}
 
</pre>


== Theoretische Betrachtung ==
== Theoretische Betrachtung ==


In diesem Kapitel findet eine Betrachtung statt in der man seinen Code Prüfen kann ohne ein Tracking Skript.
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.
 
 
== Quellen ==
* [http://bricxcc.sourceforge.net/nbc/nxcdoc/nxcapi/index.html NXC Dokumentation]


Sobald alle Schritte erfolgreich verlaufen sind und der ncx-Sourcecode vorliegt, kann dieser privat getestet werden. Hierzu sollte man mit bspw. einem Klebeband ein Feld auf den 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 der Roboter muss in der Lage sein, seine Blickrichtung zu erkennen und zu verändern.
== [[Aktuelle RoboSoccer Weiterentwicklung]] ==

Aktuelle Version vom 19. November 2015, 14:52 Uhr

Autoren:

Regelwerk RoboSoccer

Basler GigE Vision System

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.

Dialog zum Erstellen einer Konfiguration

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).


Wichtiger Hinweis!

Für das Informatikpraktikum I WS15/16 wurden alle Konfigurationsdateien bereits erstellt.


Vorgehensweise:

  • Der Betreuer/in startet die Matlab GUI mit der Version Matlab R2014a D:\SVN\ProjektRobosoccer\SRC\m-files\RoboSoccerSkript.m.
  • Bei der Initialisierung dürfen sich weder Roboter noch Ball auf dem Spielfeld befinden!
  • Zunächst das ROI durch 2 Punkte ausgewählt.
  • Jetzt sollen die 4 Spielfeldecken möglichst genau angeklickt werden (OL OR UR UL).
  • Das Skript muss mittels des RUN/STOP Buttons pausiert werden.
  • Bevor eine Bluetooth-Verbindung aufgebaut werden kann, muss der Roboter eingeschaltet sein.
  • Die Bluetooth-Funktion am NXT muss eingeschaltet sein.
  • Der Sleep-Modus sollte auf 'Never' eingestellt werden.
  • Über die Buttons BT1 und BT2 kann jetzt eine Bluetooth Konfigurationsdatei für die betroffenen Roboter (siehe Brick_Bezeichner)geladen werden.
  • Nach ca. 1 Minute soll im Matlab-Konsolenfenster das Bluetooth-Handle auftauchen.
  • Das Skript wird jetzt wieder mit RUN/STOP fortgesetzt.


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.


Quellen

Aktuelle RoboSoccer Weiterentwicklung