Erstellen von LMS-Umgebungen

Eine Umgebung (oder Szene) des LMS wird durch eine Datei im XML-Format definiert. In dieser Datei sind Informationen über die Komponenten Untergrund, Lichter, Wände und Kameras abgelegt. Im Folgenden der generelle Aufbau einer solchen Szene-Datei. Beim Erstellen eigener Umgebungen, 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.    
<Scene ...>                              Starttag der Szene
  <Floor .../>                           Der Untergrund
  <Lights>                               Die Lichtquellen
<SpotLight .../>
<SpotLight .../>
</Lights>
  <StaticObjects>
<WorldObject>
<ParentTransformGroup ...>
<ChildTransformGroup ...>
<Box .../> Definition einer Box (Wand)
</ChildTransformGroup>
<ChildTransformGroup ...>
<Box .../>
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>
</StaticObjects>
   <Cameras>                             Die Kameras
<Camera ...>
<TransformGroup .../>
</Camera>
<Camera ...>
<TransformGroup .../>
</Camera>
</Cameras>
</Scene>

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

Der xml-Tag

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

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

Der Scene-Tag

Bei diesem Eintrag beginnt die Definition einer Szene. Um den korrekten Aufbau der XML-Datei zu definieren, wird auf eine xsd-Datei (xsd=XML Schema Definition) eingebunden. Dies sieht wie folgt aus:

<Scene 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="Scene.xsd">

Die xsd-Datei (Scene.xsd) findet man im Verzeichnis %lms-home%/config/Scene. Wenn Sie Ihre Umgebungsdatei in diesem Verzeichnis ablegen, können Sie den Scene-Tag, wie er oben angegeben ist, genau so übernehmen. Falls Ihre Umgebungsdatei in einem anderen Ordner liegt, können Sie entweder die Datei „Scene.xsd“ in diesen Ordner kopieren oder einen relativen Pfad (von der Scene-Datei aus) auf die Schema-Definition anlegen. Im letzten Fall sieht die Szene-Definition wie folgt aus:

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

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

</Scene>

Der Floor-Tag

Hier wird der Untergrund der Umgebung definiert. Auf ihm bewegen sich die Roboter. Er hat eine feste Größe und eine Textur, die von den Lichtsensoren des RCX als Helligkeit des Untergrunds wahrgenommen werden können.
Die Größe des Untergrunds wird dabei in Metern angegeben. Die Textur kann ein beliebiges Bild in den Formaten „gif“, „jpg“ und „png“ sein. Der Pfad zur Bilddatei wird relativ zum %lms-home% angegeben. In unserem Beispiel liegt im Ordner %lms-home%/scenario/myScenario die Datei „floor.gif“. Der Untergrund ist 1 Meter hoch und breit. Der Tag wird am Ende mit „/>“ wieder geschlossen.

<Floor Length="1.0" Width="1.0" GifFilename="scenario/myScenario/floor.gif" />

Mit diesen einfachen Schritten haben wir nun eine einfache Umgebung erstellt. Öffnet man sie im LMS, sieht man Folgendes:

Lichter definieren

Zusätzlich können in der Umgebungsdatei gerichtete Lichtquellen (Spotlights) gesetzt werden. Die Definition dieser Lichter beginnt mit dem Lights-Tag, gefolgt von einem oder mehreren SpotLight-Tags. Nach den SpotLights wird der Lights-Tag geschlossen:

<Lights>
<SpotLight .../>
<SpotLight .../>
</Lights>

Der SpotLight-Tag

Eine typische Lichtquelle wird folgendermaßen beschrieben:

<SpotLight PositionX="-0.5" PositionY="0.5" PositionZ="1" 
DirectionX="0.5" DirectionY="-.5" DirectionZ="-1"
Concentration="40" SpreadAngle="3"
Red="220" Green="50" Blue="50" />

In diesem Beispiel wird ein rotes Licht definiert. Man erkennt deutlich die Auswirkungen auf den probeweise geladenen Roboter (ATF1).

Ohne Lichtquelle
Mit roter Lichtquelle

 

Ein SpotLight hat 11 Parameter. Die ersten drei Parameter beschreiben die X,Y und Z-Koordinaten des Lichtes. Alle Angaben beziehen sich auf den Mittelpunkt des Untergrundes und sind in Metern angegeben. In diesem Fall kommt das Licht also von einer Lichtquelle, die einen Meter über dem Boden auf der oberen linken Ecke des Untergrundes postiert ist. Die nächsten 3 Parameter beschreiben die Richtung des Lichts. In diesem Fall sind es die negativen Werte der Position, so dass das Licht genau auf das Zentrum strahlt.

Der Parameter Concentration gibt an, wie stark das Licht gebündelt wird. Der SpreadAngle definiert den Öffnungswinkel des Scheinwerfers, also den Winkel des Lichtkegels. Die letzten 3 Parameter beschreiben schließlich die Farbe des Lichts mit den RGB-Werten.
Wir fügen nun einen zweiten Scheinwerfer 2 Meter über dem Untergrund hinzu, der den Untergrund recht homogen beleuchtet:

<SpotLight PositionX="0" PositionY="0" PositionZ="2" 
DirectionX="0" DirectionY="0" DirectionZ="-1"
Concentration="100" SpreadAngle="30"
Red="150" Green="150" Blue="150" />

Statische Objekte

Statische Objekte sind in einem StaticObjects-Tag zusammengefasst. Mit Hilfe von statischen Objekten werden Hindernisse auf dem Untergrund definiert. Dies ist zum Beispiel sinnvoll, wenn man um den Untergrund herum eine Begrenzung legen möchte, so dass Roboter ihn nicht verlassen können. Die Definitionen beginnen mit dem Tag:

<StaticObjects>

In diesem Tag werden die Boxen definiert und schließlich wird der Tag mit

</StaticObjects>

wieder geschlossen.

Weltobjekte

Die WorldObjects fassen einzelne Hindernisse zusammen. StaticObjects können mehrere WorldObjects beinhalten.

Schachtelung von statischen Objekten

Die eigentlichen Hindernisse (Definiert durch den Tag <Box ...>) werden in einer ChildTransformGroup eingebettet. Diese wiederum unterliegt einer ParentTransformGroup, welche wiederum Bestandteil eines sogenannten WoldObjects ist. Hier nun zunächst ein Beispiel für eine einfache gelbe Box in der Mitte des Untergrundes. Diese Box wird später noch um eine weitere, gedrehte Box ergänzt, so dass ein Haus entsteht:

<StaticObjects>
<WorldObject>
<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"
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="0.12" Length="0.08" Height="0.10"
Red="200" Green="200" Blue="0" />
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>
</StaticObjects>

Die einzelnen Parmeter des Box-Tags stellen die Breite, Länge und Höhe, sowie die Farbe des Hindernisses dar. Deutlich komplizierter ist dagegen die 4x4 Matrizen, die in den ChildTransformGroups definiert wird. Mit Hilfe dieser Matrizen können die Boxen positioniert und gedreht werden.
Im folgenden werde ich nicht auf die mathematischen Hintergründe dieser Matrix eingehen, da dies den Rahmen sprengen würde. Stattdessen werden hier Anleitungen gegeben, mit dieser Matrix zu arbeiten.

Verändern der Position:

In der XML-Definition der ChildTransformGroup erkennen wir folgende Matrix:

=

In dem Beispiel sind die Parameter dx, dy und dz jeweils 0, d.h dass das Objekt nicht verschoben ist. Wir verschieben nun das Objekt um 50cm nach rechts und 10cm nach oben. Dazu müssen wir Value14=“0.5“ und Value24=“0.1“ setzen und erhalten Folgendes:

<ChildTransformGroup 
Value11="1" Value12="0" Value13="0" Value14="0.5"
Value21="0" Value22="1" Value23="0" Value24="0.1"
Value31="0" Value32="0" Value33="1" Value34="0"
Value41="0" Value42="0" Value43="0" Value44="1">

Drehen eines Objektes:

Wir fügen nun ein zweites Objekt als „Hausdach“ ein. Es liegt etwas höher als das erste Objekt und hat andere Dimensionen:

<StaticObjects>
<WorldObject>
<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"
Value41="0" Value42="0" Value43="0" Value44="1">
<ChildTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0.5"
Value21="0" Value22="1" Value23="0" Value24="0.1"
Value31="0" Value32="0" Value33="1" Value34="0"
Value41="0" Value42="0" Value43="0" Value44="1">
<Box
Width="0.12" Length="0.08" Height="0.10"
Red="200" Green="200" Blue="0" />
</ChildTransformGroup>
<ChildTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0.5"
Value21="0" Value22="1" Value23="0" Value24="0.1"
Value31="0" Value32="0" Value33="1" Value34="0.1"
Value41="0" Value42="0" Value43="0" Value44="1">
<Box
Width="0.119" Length="0.06" Height="0.06"
Red="200" Green="0" Blue="0" />
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>
</StaticObjects>

Um dieses Objekt zu drehen, muss folgender Teil der Matrix verändert werden:

Die Matrix (R) wird dabei wie folgt berechnet:

Rotation um die x-Achse:
(Rx) =

Rotation um die y-Achse:
(Ry) =

Rotation um die z-Achse:
(Rz) = 

Wenn wir also die Box um 45° in Richtung der X-Achse drehen wollen, so bekommen wir
(Rx) =

und damit:

<StaticObjects>
<WorldObject>
<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"
Value41="0" Value42="0" Value43="0" Value44="1">
<ChildTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0.5"
Value21="0" Value22="1" Value23="0" Value24="0.1"
Value31="0" Value32="0" Value33="1" Value34="0"
Value41="0" Value42="0" Value43="0" Value44="1">
<Box
Width="0.12" Length="0.08" Height="0.10"
Red="200" Green="200" Blue="0" />
</ChildTransformGroup>
<ChildTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0.5"
Value21="0" Value22="0.707" Value23="-0.707" Value24="0.1"
Value31="0" Value32="0.707" Value33="0.707" Value34="0.1"
Value41="0" Value42="0" Value43="0" Value44="1">
<Box
Width="0.119" Length="0.06" Height="0.06"
Red="200" Green="0" Blue="0" />
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>
</StaticObjects>

Um mehrere Rotationen durchzuführen, müssen einzelne Rotationsmatrizen multipliziert werden. Um etwa erst in der X-Achse und anschliessend in der Z-Achse zu drehen, muss man 2 Matrizen (Rx) und (Rz) berechnen, und diese dann dann multiplizieren.
(Rgesamt) = (Rx) x (Rz).
Beim den Multiplikationen ist die Reihenfolge zu beachten. Sie repäsentiert die Reihenfolge der Rotationsschritte.
Verändern der Lage einer ChildTransformGroup
Das Haus und sein Dach sind nun in einer ParentTransformGroup zusammengefasst. Man kann die Lage beider Objekte einfach verändern, indem man nur die Matrix der ParentTransformGroup verändert. Um das komplette Haus etwa 90° um den Mittelpunkt des Untergrundes herum in Z-Richtung zu drehen, reicht folgende Veränderung:

Rotation um die z-Achse:
(R) = =

Daraus folgt für die ParentTransformGroup:

<StaticObjects>
<WorldObject>
<ParentTransformGroup
Value11="0" Value12="-1" Value13="0" Value14="0"
Value21="1" Value22="0" Value23="0" Value24="0"
Value31="0" Value32="0" Value33="1" Value34="0"
Value41="0" Value42="0" Value43="0" Value44="1">
<ChildTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0.5"
Value21="0" Value22="1" Value23="0" Value24="0.1"
Value31="0" Value32="0" Value33="1" Value34="0"
Value41="0" Value42="0" Value43="0" Value44="1">
<Box
Width="0.12" Length="0.08" Height="0.10"
Red="200" Green="200" Blue="0" />
</ChildTransformGroup>
<ChildTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0.5"
Value21="0" Value22="0.707" Value23="-0.707" Value24="0.1"
Value31="0" Value32="0.707" Value33="0.707" Value34="0.1"
Value41="0" Value42="0"Value43="0" Value44="1">
<Box
Width="0.119" Length="0.06" Height="0.06"
Red="200" Green="0" Blue="0" />
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>
</StaticObjects>

Auf diese Weise können wir erstellte ParentTransferGroups durch einfaches Duplizieren und Anpassen der Matrix mehrfach verwenden.

Kameraperspektiven

Im Menüpunkt „View“ des LMS können vorgefertigte Kammeraperspektiven ausgewählt werden, sofern diese in der XML-Datei definiert sind. Es gibt zwei Möglichkeiten, diese Kameraperspektiven zu definieren: manuell oder mit Hilfe des LMS.

Kameraperspektive mit Hilfe des LMS hinzufügen:

Drehen, Ziehen und Zoomen Sie das Hauptfenster mit Hilfe der drei Maustasten in die gewünschte Position und Klicken Sie dann auf „View -> Save Camera Pos“.
Schon haben Sie in der XML-Datei eine Kameraperspektive definiert, die Sie fortan im Menü-Punkt „View“ jederzeit wieder aufrufen können.
Aufgrund dieser einfachen Möglichkeit, Kamerapositionen zu definieren, wir an dieser Stelle lediglich auf den allgemeinen Aufbau des Camera-Tags eingegangen.
Wie oben bereits zu sehen, sind mehrere Perspektiven in einem Cameras-Tag gespeichert:

<Cameras>
<Camera ...>
<TransformGroup .../>
</Camera>
<Camera ...>
<TransformGroup .../>
</Camera>
</Cameras>

Die Kamera selbst hat einen Namen (Standardmäßig “Camera 0”, “Camera 1” usw.) und eine TransformGroup. Diese TransformGroup ist genauso aufgebaut, wie die Parent- und ChildTransformGroup, die wir bereits kennen gelernt haben.
Die Parameter dx, dy und dz definieren die Kamera-Position, die Matrix (R) definiert den Blickwinkel.

<Camera name="Camera 0">
<TransformGroup
Value11="0.8338244" Value12="0.12909822" Value13="-0.53672206"
Value14="-1.4949298" Value21="-0.529671" Value22="0.4610073"
Value23="-0.71198374" Value24="-2.0976896" Value31="0.15551695"
Value32="0.87795556" Value33="0.45277873" Value34="1.1544305"
Value41="0.0" Value42="0.0" Value43="0.0" Value44="1.0"/>
</Camera>

Die Skalierung wird vorgenommen, indem man die Rotationsmatrix mit einer Skalierungmatrix (S) multipliziert:
(Rs) =(R) x
Dabei bezeichnet z den Zoom.

Zusammenfassung

Dieses Tutorial hat gezeigt wie man eine einfache Umgebung (Szene) für den LMS erstellt. Diese Szene beinhaltet einen Untergrund mit einer Textur, die von den Lichtsensoren der Roboter erfasst werden kann, mehrere Lichtquellen, mehrere Häuser, die in Transformationsgruppen zusammengefasst sind und eine Kameraperspektive.

Anhang:

Die komplette Szene-Datei „myScene.xml“:

<?xml version="1.0" encoding="UTF-8"?>
<Scene
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../config/Scene/Scene.xsd">
<Floor Length="1.0" Width="1.0"
GifFilename="scenario/myScenario/floor.gif" />

<Lights>
<SpotLight
PositionX="-0.5" PositionY="0.5" PositionZ="1"
DirectionX="0.5" DirectionY="-.5" DirectionZ="-1"
Concentration="40" SpreadAngle="3"
Red="220" Green="50" Blue="50" />
<SpotLight
PositionX="0" PositionY="0" PositionZ="2"
DirectionX="0" DirectionY="0" DirectionZ="-1"
Concentration="100" SpreadAngle="30"
Red="150" Green="150" Blue="150" />
</Lights>

<StaticObjects>

<WorldObject>
<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"
Value41="0" Value42="0" Value43="0" Value44="1">
<ChildTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0.5"
Value21="0" Value22="1" Value23="0" Value24="0.1"
Value31="0" Value32="0" Value33="1" Value34="0"
Value41="0" Value42="0" Value43="0" Value44="1">
<Box
Width="0.12" Length="0.08" Height="0.10"
Red="200" Green="200" Blue="0" />
</ChildTransformGroup>
<ChildTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0.5"
Value21="0" Value22="0.707" Value23="-0.707" Value24="0.1"
Value31="0" Value32="0.707" Value33="0.707" Value34="0.1"
Value41="0" Value42="0" Value43="0" Value44="1">
<Box
Width="0.119" Length="0.06" Height="0.06"
Red="200" Green="0" Blue="0" />
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>

<WorldObject>
<ParentTransformGroup
Value11="0" Value12="-1" Value13="0" Value14="0"
Value21="1" Value22="0" Value23="0" Value24="0"
Value31="0" Value32="0" Value33="1" Value34="0"
Value41="0" Value42="0" Value43="0" Value44="1">
<ChildTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0.5"
Value21="0" Value22="1" Value23="0" Value24="0.1"
Value31="0" Value32="0" Value33="1" Value34="0"
Value41="0" Value42="0" Value43="0" Value44="1">
<Box
Width="0.12" Length="0.08" Height="0.10"
Red="200" Green="200" Blue="0" />
</ChildTransformGroup>
<ChildTransformGroup
Value11="1" Value12="0" Value13="0" Value14="0.5"
Value21="0" Value22="0.707" Value23="-0.707" Value24="0.1"
Value31="0" Value32="0.707" Value33="0.707" Value34="0.1"
Value41="0" Value42="0" Value43="0" Value44="1">
<Box
Width="0.119" Length="0.06" Height="0.06"
Red="200" Green="0" Blue="0" />
</ChildTransformGroup>
</ParentTransformGroup>
</WorldObject>

</StaticObjects>
  <Cameras>
<Camera name="Camera 0">
<TransformGroup
Value11="0.8338244" Value12="0.12909822" Value13="-0.53672206"
Value14="-1.4949298" Value21="-0.529671" Value22="0.4610073"
Value23="-0.71198374" Value24="-2.0976896" Value31="0.15551695"
Value32="0.87795556" Value33="0.45277873" Value34="1.1544305"
Value41="0.0" Value42="0.0" Value43="0.0" Value44="1.0" />
</Camera>
</Cameras>

</Scene>

 

Impressum | Webmaster | Letzte Änderungen am : 04.10.2007