Erstellen von virtuellen RCX-Robotern

Ein virtueller RCX-Roboter des LMS wird durch eine Datei im XML-Format definiert. In dieser Datei sind Informationen über die Abmessungen, das Kollisionsverhalten, die Motor/Sensor-Abhängigkeiten und die Programmierung der Roboter beschrieben. In diesem Tutorial wird beschrieben, wie ein einfacher Roboter mit 2 Antriebsmotoren erstellt wird. Dieser Roboter wird um 2 Lichtsensoren und einen Berührungssensor ergänzt. Anschließend werden weitere mögliche Elemente erklärt.

Im Folgenden der generelle Aufbau einer solchen RCX-Datei. Beim Erstellen eigener Roboter, kann sie als Schablone benutzt werden. Die einzelnen Tags werden im Anschluss erläutert.

<?xml version="1.0" encoding="UTF-8"?>  Definition der XML-Datei. Bei allen Dateien identisch.

<RCX ...> Der RCX-Tag
 <WorldObject ...>
<ParentTransferGroup ...>
<ChildTransferGroup ...>
<Box .../> Der Box-Tag
</ChildTransferGroup>
</ParentTransferGroup>
</WorldObject>
  <Motor .../>                          Definition der Motoren
<Motor .../>
  <Sensor .../>                         Sensorenbeschreibung (verschiedene Tags)

<Lejos ...>
<JarFilename>
... Programmierung
</JarFilename>
</Lejos>
</RCX>

In folgenden Erläuterungen bezeichnet %lms-home% das LMS-Stammverzeichnis (z.B. C:\Programme\lms).
Im Beispiel legen wir einen Roboter mit dem Namen myRCX.xml in dem Ordner %lms-home%/scenario/myScenario an.

Der xml-Tag

Der xml-Tag definiert die XML-Datei. Er ist bei allen Umgebungen identisch.

<?xml version="1.0" encoding="UTF-8"?>

Der RCX-Tag

Bei diesem Eintrag beginnt die Definition eines RCX-Roboters. Es wird ein Name für den Roboter festgelegt und um den korrekten Aufbau der XML-Datei zu definieren, wird auf eine xsd-Datei (xsd=XML Schema Definition) eingebunden. Dies sieht wie folgt aus:
<RCX Name=“MyRCX“ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="RCX.xsd">
Die xsd-Datei (RCX.xsd) findet man im Verzeichnis %lms-home%/config/RCX. Wenn Sie Ihre RCX-Datei in diesem Verzeichnis ablegen, können Sie den RCX-Tag, wie er oben angegeben ist, genau so übernehmen. Falls Ihre Umgebungsdatei in einem anderen Ordner liegt, können Sie entweder die Datei „RCX.xsd“ in diesen Ordner kopieren oder einen relativen Pfad (von der RCX-Datei aus) auf die Schema-Definition anlegen. Im letzten Fall sieht die Szene-Definition wie folgt aus:

<RCX Name="Linienverfolger" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../config/RCX/RCX.xsd">

Der RCX-Tag wird am Ende der Datei wieder geschlossen:

</RCX>

Weltobjekte

Die WorldObjects fassen einzelne Teile des Roboters zusammen und legen mit dem Parameter „UseCollisionDetection“ das Kollisionsverhalten fest. In den WorldObjects sind verschiedene TransformGroups (s.u.) eingebettet.

Schachtelungshierarchie von Objekten

Die eigentlichen Teile eines Roboters (Definiert durch den Tag <Box ...>) werden in einer ChildTransformGroup eingebettet. Diese wiederum unterliegt einer ParentTransformGroup, welche wiederum Bestandteil eines WoldObjects ist. Hier nun zunächst ein Beispiel für eine gelbe Box in der Mitte des Untergrundes. Sie soll einen einfachen Roboter darstellen. Der Mittelpunkt dieses Roboters liegt 5cm über dem Boden.

<WorldObject UseCollisionDetection="true">
<ParentTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0"
Value21="0" Value22="1" Value23="0" Value24="0"
Value31="0" Value32="0" Value33="1" Value34="0.05"
Value41="0" Value42="0" Value43="0" Value44="1">
<ChildTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0"
Value21="0" Value22="1" Value23="0" Value24="0"
Value31="0" Value32="0" Value33="1" Value34="0"
Value41="0" Value42="0" Value43="0" Value44="1">
<Box Width=".05" Length=".08" Height=".035"
Red="200" Green="200" Blue="020"/>
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>

Die einzelnen Parmeter des Box-Tags stellen die Breite, Länge und Höhe sowie die Farbe des Roboters dar. Deutlich komplizierter sind dagegen die 4x4 Matrizen, die in den ChildTransformGroups definiert werden. Mit Hilfe dieser Matrizen können die Boxen positioniert und gedreht werden.

Transformgruppen: Positionierung und Ausrichtung eines Objektes:

In dem Tutorial „Lego Minstorms Simulator – Erstellen von Umgebungen“ ist beschrieben, welche Veränderungen vorgenommen werden müssen, um Boxen zu verschieben und zu drehen.

Motoren definieren

Motoren werden durch einen Motor-Tag definiert. Er beschreibt, an welchem Anschluss des RCX der Motor angeschlossen ist (A, B oder C). Außerdem wird ein Kraftvektor definiert. Die Kraft des Motors wirkt in die Richtung dieses Vektors.
In unserem Beispiel haben wir einen einfachen Roboter mit zwei Motoren, die unter dem RCX befestigt sind und an denen jeweils ein Antriebsrad aufgesteckt ist:

...
</WorldObject>
<Motor Connection="A" ForceX="1" ForceY="1" ForceZ="0"/>
<Motor Connection="B" ForceX="1" ForceY="-1" ForceZ="0"/>

Bemerkenswert sind hierbei die Kraftvektoren der beiden Motoren. Wie man deutlich sieht, arbeiten ihre Kräfte nicht ausschließlich in Richtung der Fahrtrichtung des Roboters, sondern entgegengesetzt diagonal (Bild 1).

Bild 1
Bild 2

Dieser seltsame Aufbau der Kraftvektoren lässt sich einfach veranschaulichen. Zum einen liegen die Motoren direkt gegenüber. Wenn beiden Motoren das Kommando „vorwärts“ gegeben wird, so bewegt sich ein Rad in Richtung der y-Achse, das andere Rad aber entgegengesetzt (da ja beide Motoren links herum drehen). Zum vorwärts fahren muss Motor B also rückwärts drehen. Dadurch bekommt er den Kraftvektor, der in Bild 2 zu sehen ist. (Anmerkung: In der Realität wird dieses Problem umgangen, indem man die Motoranschlüsse umdreht)
Sind beide Motoren eingeschaltet, so heben sich die x-Komponenten der Vektoren auf und der RCX bewegt sich nach vorn. Ist jedoch nur einer der Motoren aktiv, verändert sich in der Realität auch die Bewegungsrichtung in der x-Achse. Um dies zu simulieren haben die beiden Motoren eine zusätzliche Kraft in x-Richtung.
Allein durch diese Kräfte wird allerdings noch nicht die Drehung des Roboters beschrieben.

Der Motor-Konnektor

Mit dem MotorConnector-Tag verbinden wir nun die beiden Roboter, damit auch die Drehung des Roboters richtig simuliert wird. Der Tag hat 7 Parameter. Die ersten beiden Parameter geben die beiden beteiligten Motor-Objekte an. Die folgenden 3 Parameter geben die Richtung an, in die sich der Roboter bewegt, wenn sich beide Motoren bewegen. In unserem Fall ist dies die y-Richtung.
Die letzten beiden Parameter geben die Übersetzung des angeschlossenen Rades (abhängig von Radgröße, Getriebe) und den Lenkfaktor an. Dieser hat direkten Einfluss darauf, wie schnell sich der Roboter dreht (abhängig davon, wie weit die Räder auseinander stehen).

...
<Motor Connection="A" ForceX="1" ForceY="1" ForceZ="0"/>
<Motor Connection="B" ForceX="1" ForceY="-1" ForceZ="0"/>
<MotorConnector
LeftMotor="A" RightMotor="B"
ForceX="0" ForceY="1" ForceZ="0"
GearFactor="1.6" SteerFactor="12"/>

Damit ist unser erster Roboter fast fertig. Wir müssen uns nur noch um seine Programmierung kümmern.

Der Lejos-Tag

Um ein Programm einzubinden, wird der Lejos-Tag benutzt. In diesem Lejos-Tag wird mit dem Tag „JarFilename“die Jar-Datei eingebunden, die das Programm enthält. Sie wird nach dem Kompilieren unkomprimiert erzeugt und muss eine Manifest-Datei beinhalten, die auf die Klasse mit der Main-Funktion referiert.
Beispiel: Im Verzeichnis %lms-home%/scenario/myScenario liegt eine Datei MyRobot.java und einige weitere Klassen. Die „MyRobot“-Klasse hat die Main-Funktion. Im gleichen Verzeichnis liegt die Manifest-Datei manifest.txt mit folgendem Inhalt:

Manifest-Version: 1.0
Main-Class: Robot

Das Kompilieren und erzeugen der Jar-Datei erfolgt durch folgende Aufrufe:

lejosc *.java 
jar cvfm0 myrobot.jar manifest.txt *.class

Es ist darauf zu achten, dass die bin-Verzeichnisse von Java und von Lejos in der Umgebungsvariable “Path” stehen.
In unserem Beispiel wird die so erzeugte Jar-Datei nun wie folgt eingebunden:

<Lejos enable="true">
<JarFilename>scenario/myScenario/myrobot.jar</JarFilename>
</Lejos>

Der angegebene Pfad zu der Jar-Datei ist auch hier relativ zum lms-Hauptverzeichnis.
Damit ist unser erster kleiner Roboter fertig. Er hat zwei Motoren (A und B) und kann sich in einer Umgebung bewegen - jedoch nicht mit ihr interagieren.

Berührungssensoren

Berührungssensoren bieten eine einfache Möglichkeit, den Zusammenstoß des Roboters mit einem Hindernis aus der Umgebung oder mit einem anderen Roboter zu erfassen. Kollisionen werden unter allen Weltobjekten wahrgenommen, die mit dem Attribut UseCollisionDetection="true" definiert sind.
Wenn ein Roboter mit einer Wand in der Simulation kollidiert bleibt er stehen und bleibt darin stecken. Ist die Umgebung des Roboters z.B. durch eine Wand begrenzt oder weist Hindernisse auf, so kann man diese Kollisionen mit einem Berührungssensor wahrnehmen und darauf reagieren.

Die zwei Berührungssensoren von LEGO
Beispielroboter mit Berührungssensor

Hier die typische Definition eines Berührungssensors:

<TouchSensor Connection="B">
<WorldObject UseCollisionDetection="true">
<ParentTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0.0"
Value21="0" Value22="1" Value23="0" Value24="0.12"
Value31="0" Value32="0" Value33="1" Value34="0.005"
Value41="0" Value42="0" Value43="0" Value44="1">
<ChildTransformGroup>
<Box Width="0.1" Length="0.004" Height="0.004"
Red="20" Green="20" Blue="20"/>
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>
</TouchSensor>

Wie man sieht, wird der Sensor durch den TouchSensor-Tag eingeleitet. In dem Tag wird der benutzte Anschluss definiert. Dabei stehen die Anschlüsse „A“, „B“ und „C“ in der Definition für die Sensoranschlüsse „1“, „2“ und „3“ des RCX-Bausteins.
Nun wird ein Weltobjekt mit CollisionDetection erstellt, in dem sich eine ParentTransformGroup befindet. Sie legt die Lage des Berührungssensors fest.
Es folgt eine ChildTransformGroup, in der der eigentliche Sensor (bzw. das technische Konstrukt, mit dem der Sensor verbunden ist) definiert wird.
In dem Beispiel wird eine schmale Box oberhalb des bisherigen Roboters definiert. Sie entspricht der schwarzen Stange auf dem Bild mit dem Beispielroboter.
Achtung: Die Box-Objekte der Berührungssensoren müssen frei schwebend sein. Sie dürfen kein anderes Objekt mit Collisiondetection berühren, auch nicht den Roboter selbst oder den Untergrund.

Lichtsensoren

Lichtsensoren, die auf den Boden gerichtet sind, können die Untergrundhelligkeit erfassen. Sie werden durch den FloorLightSensor-Tag definiert, der als Parameter einen Anschluss hat (wie beim Berührungssensor). Auch er beinhaltet ein WorldObject, das eine ParentTransformGroup, eine ChildTransformGroup und eine Box hat.
Eine typische Leichtsensordefinition sieht wie folgt aus:

<FloorLightSensor Connection="A">
<WorldObject UseCollisionDetection="false">
<ParentTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0.0"
Value21="0" Value22="1" Value23="0" Value24="0.1"
Value31="0" Value32="0" Value33="1" Value34="-0.01"
Value41="0" Value42="0" Value43="0" Value44="1">
<ChildTransformGroup>
<Box Width="0.0125" Length="0.0125" Height="0.025"
Red="20" Green="20" Blue="200"/>
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>
</FloorLightSensor>

Der Aufbau ist also ganz analog zu dem Aufbau des Berührungssensors.
In unserem Beispiel liegt der Lichtsensor zwischen Berührungssensor und RCX und hat eine blaue Farbe.

Mit den bisher beschriebenen Konstrukten sind die meist genutzten Arten von Robotern abgedeckt. Zwar können mit dem LMS nicht sämtliche Arten von Robotern simuliert werden, aber einige weitere Möglichkeiten stehen dem Benutzer zur Verfügung. Die wichtigsten werden nun kurz beschrieben.

Rotationssensoren und deren Kopplung an Motoren

Oft kann es sich als hilfreich erweisen, die Motorumdrehungen mit Hilfe von Rotationssensoren (nicht im Baukasten enthalten) zu erfassen. So wird zum Beispiel in der Fallstudie Hochregallager die Position des Regalbediengerätes mit Hilfe von Rotationssensoren gesteuert.
Ein Rotationssensor wird mit dem RotationSensor-Tag definiert. Mit dem LinearMotorConnector können Motoren an Rotationssensoren gekoppelt werden. Das folgende Beispiel ist ein gekürzter Ausschnitt aus dem Regalbediengerätes der Fallstudie Hochregallager und wird später aufgegriffen, um die Schachtelung motorgesteuerter Teilsysteme zu erläutern:

<Motor Connection="A" ForceX="1" ForceY="1" ForceZ="0" GearFactor="1"/>
<Motor Connection="B" ForceX="1" ForceY="1" ForceZ="0" GearFactor="1"/>
<Motor Connection="C" ForceX="1" ForceY="1" ForceZ="0" GearFactor="1"/>

<RotationSensor Connection="A"/>
<RotationSensor Connection="B"/>
<RotationSensor Connection="C"/>

<LinearMotorConnectorName="Slide"
Motor="A" RotationSensor="A"
RotationGear="0.6" MovementSpeed="1.77">
<Beam>
<WorldObject>
<ParentTransformGroup Value11="1" ...>
<ChildTransformGroup Value11="1" ...>
<Box .../>
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>
</Beam>
<Plattform>
<WorldObject>
<ParentTransformGroup Value11="1" ...>
<ChildTransformGroup Value11="1" ...>
<Box .../>
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>
</Plattform>
<!--*****************************->
<LinearMotorConnector Name="Lift"
Motor="B" RotationSensor="B"
RotationGear="0.6" MovementSpeed="1.42">
<Beam>
<WorldObject>
<ParentTransformGroup Value11="-0.0002" ...>
<ChildTransformGroup Value11="1" ...>
<Box .../>
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>
</Beam>
<Plattform>
<WorldObject>
<ParentTransformGroup Value11="1" ...>
<ChildTransformGroup Value11="1" ...>
<Box .../>
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>
</Plattform>
<!--*****************************->
...
<!--*****************************->
</LinearMotorConnector>
</LinearMotorConnector>

Wie man erkennt, hat der LinearMotorConnector die Parameter „Name“ (für Debug-Ausgaben), Motor und RotationSensor.
Der Parameter „Rotationssensor“ beschreibt den Faktor zwischen der Motorumdrehung und den Werten des Rotationssensors. Dadurch wird eine Über- oder Untersetzung zwischen der Motorachse und der Achse des Rotationssensors modelliert. Je größer dieser Faktor ist, desto höhere Werte liefert der Sensor. Durch einen negativen Faktor wird die Drehrichtung des Sensors umgedreht. Der Standardwert beträgt 1.
Das Attribut „MovementSpeed“ beschreibt den Faktor zwischen der Motorgeschwindigkeit und der daraus resultierenden Geschwindigkeit der Plattform.Dadurch wird ebenfalls eine Über- oder Untersetzung modelliert. Je größer dieser Faktor ist, desto schneller bewegt sich die Plattform. Durch einen negativen Faktor wird die Bewegungsrichtung umgedreht. Der Standardwert beträgt 1. Die Bewegungsgeschwindigkeit hat keine Auswirkungen auf die vom Rotationssensor erzeugten Werte, da diese nur von der Geschwindigkeit des Motors abhängen.

Motorgesteuerte Roboterteilsysteme

Am Beispiel von oben kann man deutlich die Schachtelung der Teilsysteme „Schlitten“ (Slide) und „Lift“ erkennen. Bewegt sich der Schlitten, so bewegt sich auch der Lift. Daher ist der LinearMotorConnector des Lifts in dem des Schlittens eingebettet.
Der LinearMotorConnector beinhaltet dabei immer einen Beam-Tag. Er stellt die Schnittstelle zwischen den Systemen dar. In der Fallstudie Hochregallager fallen diese Beams sehr gut durch ihre grüne Farbe auf (gut zu erkennen in Kameraperspektive 4). Die Ausrichtung der Beams (in der ParentTransferGroup) gibt dabei die Bewegungsrichtung an. Sie müssen also korrekt rotiert werden (siehe auch Tutorial „Lego Minstorms Simulator – Erstellen von Umgebungen“). Die Platform-Tags definieren die eigentlichen Teilsysteme.

Zusammenfassung:

In diesem Tutorial haben wir gelernt, einen einfachen Roboter mit zwei Antriebsmotoren, Berührungs- und Lichtsensoren auszustatten und ihn mit der LeJOS-Bibliothek und mit LeJOS-Programmen zu verknüpfen.
Weiterhin wurden Rotationssensoren sowie die Schachtelung von Teilsystemen anhand der Fallstudie Hochregallager erläutert.

Anhang:

Die komplette RCX-Datei „myRCX.xml“.

<?xml version="1.0" encoding="UTF-8"?>
<RCX Name="Linienverfolger" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../config/RCX/RCX.xsd">
  <WorldObject UseCollisionDetection="true">
<ParentTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0"
Value21="0" Value22="1" Value23="0" Value24="0"
Value31="0" Value32="0" Value33="1" Value34="0.05"
Value41="0" Value42="0" Value43="0" Value44="1">
<ChildTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0"
Value21="0" Value22="1" Value23="0" Value24="0"
Value31="0" Value32="0" Value33="1" Value34="0"
Value41="0" Value42="0" Value43="0" Value44="1">
<Box Width=".05" Length=".08" Height=".035"
Red="200" Green="200" Blue="020"/>
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>
  <Motor Connection="A" ForceX="1" ForceY="1" ForceZ="0"/>
<Motor Connection="B" ForceX="1" ForceY="-1" ForceZ="0"/>
<MotorConnector
LeftMotor="A" RightMotor="B"
ForceX="0" ForceY="1" ForceZ="0"
GearFactor="1.6" SteerFactor="12"/>
  <TouchSensor Connection="B">
<WorldObject UseCollisionDetection="true">
<ParentTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0.0"
Value21="0" Value22="1" Value23="0" Value24="0.12"
Value31="0" Value32="0" Value33="1" Value34="0.005"
Value41="0" Value42="0" Value43="0" Value44="1">
<ChildTransformGroup>
<Box Width="0.1" Length="0.004" Height="0.004"
Red="20" Green="20" Blue="20"/>
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>
</TouchSensor>
  <FloorLightSensor Connection="A">
<WorldObject UseCollisionDetection="false">
<ParentTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0.0"
Value21="0" Value22="1" Value23="0" Value24="0.1"
Value31="0" Value32="0" Value33="1" Value34="-0.01"
Value41="0" Value42="0" Value43="0" Value44="1">
<ChildTransformGroup>
<Box Width="0.0125" Length="0.0125" Height="0.025"
Red="20" Green="20" Blue="200"/>
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>
</FloorLightSensor>
  <Lejos enable="true">
<JarFilename>scenario/mySceanrio/myrobot.jar</JarFilename>
</Lejos>
</RCX>

 

Impressum | Webmaster | Letzte Änderungen am : 04.10.2007