####################################################################
####################################################################
# Anleitung für die Verwendung von Quartz 2.0 auf dem Lego RCX 2.0 #
####################################################################
####################################################################

Dieses Dokument gibt eine schrittweise Einführung in die Verwendung von Quartz als synchrone Programmiersprache auf dem Lego RCX mit dem Betriebssystem BrickOS. Dabei ist es notwendig, eine anwendungsspezifische Laufzeitumgebung zu erzeugen, die Sensordaten über BrickOS an das Quartz-Modul liefert. Diese Laufzeitumgebung hat ebenfalls die Aufgabe, Motorsteuerungs-Anweisungen an BrickOS weiterzugeben.

Um möglichst viele Anwendungsszenarien zu unterstützen, wird die komplette Laufzeitumgebung dynamisch mit einem XSLT-Programm erzeugt; je nach den Anforderungen des Quartz-Moduls. Hierzu müssen zunächst in einer XML-Konfigurations-Datei Sensoren und Motoren mit ihren Anschlüssen spezifiziert werden. Die erzeugte Laufzeitumgebung wird anschließend zusammen mit dem aus dem Quartz-Modul von Averest erzeugten C-Code gelinkt und kann mit den üblichen Tools auf den RCX übertragen werden. 


###################################################################
Ausführungsmodell
###################################################################

Die Macro-Schritte des Quartz-Moduls werden anhand der Step-Funktion getriggert, die Averest generiert (qrz2aif --cpp --link $(MODULE).qrz && aif2c --step $(MODULE).aifs). Diese Funktion wird durch die Laufzeitumgebung in peridischen Abständen aufgerufen, dessen Intervall durch die Konfigurations-Datei festgelegt werden kann. Je nach Anwendung können dadurch die Macro-Schritte häufiger getriggert werden. Für die Steuerung eines Robotors auf einem Labyrinth hat sich ein Intervall von 10 ms etabliert.


###################################################################
Die Konfiguration
###################################################################

Die Konfiguration besteht aus einem übergeordnetem Element "module", das ein Attribut "name" enthält, welches identisch zu dem Modul-Namen des Quartz-Programms sein muss. Des Weiteren hat "module" ein Attribut "macro_step", durch welches man die bereits diskutierte Macro-Step Intervalllänge bestimmen kann.

In den Kind-Elementen von "module" werden die benötigten Sensoren und Motoren angegeben. Wie bei der allgemeinen Struktur von XML-Dokumenten üblich spielt die Reihenfolge der Einträge eine entscheidende Rolle, denn die Reihenfolge der Sensor/Motor-Einträge muss der Reihenfolge der Parameter des Moduls im Quart-Quellcode entsprechen.

Wir erklären den Inhalt Konfiguration anhand eines Beispiels.

|  <?xml version="1.0" encoding="utf-8" ?>
|  <module name="robot" macro_step="10" >
|  	<param type="light" port="1" active="true" />
|  
| 	<param type="motor-speed" port="a" />
| 	<param type="motor-dir" port="a" />
|  </module>

In diesem Beispiel trägt unser Quartz-Modul den namen "robot". Das Macro-Step-Intervall ist auf 10 eingestellt (Einheit ms).
Das Quartz-Modul verwendet einen Licht-Sensor und einen Motor, die an Port 1 bzw. Port a angeschlossen sind (Attribut "port"). Bei dem Licht-Sensor kann durch das Attribut "active" gesteuert werden, ob der Sensor seine LED aktiviert. Bei Motor muss beachtet werden, das bei sowohl Geschwindigkeit "motor-speed" als auch die Richtung "motor-dir", in welcher sich der Motor drehen soll, spezifiziert werden kann. Da bei beiden Angaben port="a" angegeben ist, beziehen sich beide Steuerwerte auf den gleichen Motor.

Folgende Peripherie-Typen können im param-Element als type-Attribut angegeben werden:
- "light" - Lichtsensor; hat als weitere Attribute "port" (1,2 oder 3) und "active" (LED des Sensors: "true" bedeutet LED ist an, "false" LED ist aus)
- "touch" - Berührungssensor; hat als weiteres Attribut "port" (1,2 oder 3)
- "rotation" - Winkelsensor; hat als weitere Attribute "port" (1,2 oder 3). Der Rotationssensor wird immer aktiviert und zu Beginn auf 0 gesetzt.
- "motor-speed" - Geschwindigkeit von Motor; hat als weiteres Attribut "port" (a, b oder c)
- "motor-dir" - Richtung des Motors; hat als weiteres Attribut "port" (a, b oder c)
- "lcd" - Bietet die Möglichkeit das Display des RCX anzusteuern; bietet als weiteres Attribut "datatype" ("string" oder "int"; wird in der Laufzeit-Umgebung auf cputs() bzw. lcd_unsigned() abgebildet). Kann pro Konfiguration maximal einmal spezifiziert werden!


Zur einfachen Verwendung der BrickOS-spezifischen Sensor-Größen wurden einige Konstanten als defines definiert. Auf diese kann in dem Quartzmodul zugegriffen werden, indem die re_common.h eingebunden wird. Der Inhalt der re_common.h sieht wie folgt aus:


#ifndef __RE_COMMON__H__
#define __RE_COMMON__H__


#define MOTOR_OFF	0
#define MOTOR_FWD	1
#define MOTOR_REV	2
#define MOTOR_BRAKE	3

#define MOTOR_MIN	0
#define MOTOR_MAX	255


#endif  /* __RE_COMMON__H__ */


###################################################################
Das Quartz-Modul
###################################################################

Im Quartz-Modul spiegelt sich die Konfiguration in der Signatur des Moduls wider.

Für obige Konfiguration müsste die Signatur des Quartz-Moduls wie folgt aussehen:


|module robot( int{16} ?light, int{8} !motor_speed, int{2} !motor_dir )
|{
...
|}


Das Modul hat insgesamt 3 Parameter: Die Eingabe "light" liefert den Lichtwert des Sensors, über die Ausgaben "motor_speed" und "motor_dir" können Motoren gesteuert werden.

Wir weisen darauf hin, dass keine zusätzlichen Inputs oder Outputs im Quartz-Modul definiert werden können. Da im aktuellen Stand von Averest, aber nur für einzelne Module Code erzeugt werden kann, sollte dieser Umstand nicht kritisch sein.


###################################################################
Die generierte Laufzeitumgebung
###################################################################

Die Laufzeitumgebung bildet eine Brücke zwischen BrickOS und Quartz-Modul. Für obige Konfiguration würde die erzeugte Laufzeitumgebung wie folgt aussehen:


|#include <conio.h>
|#include <unistd.h>
|#include <dbutton.h>
|#include <dsensor.h>
|#include <dmotor.h>
|#include <sys/tm.h>
|#include <rom/system.h>
|
|#include <robot.h>
|
|int light_1;
|int motor_a_s;
|int motor_a_d;
|
|
|void handle_inputs()
|{
|	light_1 = LIGHT_1;
|}
|
|
|void handle_outputs()
|{
|	motor_a_speed( motor_a_s );
|	motor_a_dir( motor_a_d );
|}
|
|
|int main()
|{
|	ds_active(&SENSOR_1);
|	handle_inputs();
|	robot_init( light_1, &motor_a_s, &motor_a_d);
|
|	handle_outputs();
|
|	while( 1 )
|	{
|		msleep(10);
|
|		handle_inputs();
|		robot_step( light_1, &motor_a_s, &motor_a_d);
|		handle_outputs();
|	}
|	return 0;
|}



###################################################################
Quick start
###################################################################

1. Quartz-Modul schreiben und Konfiguration spezifizieren. Die Konfiguration muss in einer Datei gespeichert sein, die den gleichen Namen wie das Quartz-Modul hat und muss auf .conf enden. Bsp. : robot.qrz -> robot.conf

2. Unser Makefile editieren :-)  (im Roboter-Beispiel enthalten)
  - Modulnamen $MODULE anpassen. Bsp: MODULE = robot ,  wenn Modul robot.qrz heißt

3. "make rcx" eingeben. Dadurch wird das Binary $MODULE.lx erzeugt und auf den RCX übertragen. Dabei muss die Umgebungsvariable RCXTTY gesetzt sein (z.B. export RCXTTY=/dev/usb/legousbtower0). Wenn nur das Binary erstellt werden soll, genügt ein "make $MODULE.rcx"



