Suche
Spielzeug für Jung und Alt

Einstieg in die Robotikprogrammierung mit LEGO MINDSTORMS EV3

Bernhard Löwenstein

© Shutterstock.com/charles taylor

Mit der MINDSTORMS-Reihe bietet LEGO seit mehr als einem Jahrzehnt Roboterbaukästen für Technikinteressierte egal welchen Alters an. Ende September 2013 kam mit EV3 die neueste Generation auf den Markt, die gegenüber der Vorgängerversion NXT 2.0 deutlich modernisiert wurde. Der zweite Teil unserer Robotikartikelserie (Teil 1 finden Sie auf entwickler.de) gibt eine technologische Einführung und beschreibt anschließend, wie man die EV3-Roboter grafisch bzw. mit Java programmiert.

Es gibt Spielzeug, das ist so genial, dass es zu einem nicht enden wollenden Siegeszug rund um den Globus ansetzt. Die Rede ist nun aber nicht von einem der Geräte mit vorangestelltem „i“, sondern von LEGO. Seit Generationen bauen Kinder damit weltweit mehr oder weniger fantasievolle Gebilde zusammen. Das LEGO-Imperium umfasst aber nicht mehr nur einfache Plastiksteine. Mit der MINDSTORMS-Baukastenserie bietet der dänische Konzern seinen kleinen und großen Fans auch programmierbare Elemente. Das Besondere dabei ist, dass diese speziellen Komponenten nahtlos mit den restlichen LEGO-Steinen kombiniert werden können und sich so unterschiedlichste Roboter konstruieren lassen. Wie man diese mittels der grafischen Programmierumgebung EV3-Software und der Java-Schnittstelle leJOS EV3 programmiert, schauen wir uns in diesem Artikel an.

Südafrikanischer Visionär sorgt für dänische Gedankenblitze

Als geistiger Vater der Baukästen gilt Seymour Papert. Der Südafrikaner beschäftigte sich bereits in den späten 1960ern damit, wie man Kindern und Jugendlichen altersgerecht die Programmierung näherbringen kann. Der Erfinder von Logo suchte eine interessante Anwendung für eben diese Programmiersprache und stieß dabei auf Roboter. Mit LEGO fand er einen passenden Partner zur Realisierung seines Vorhabens und schon bald wurde das Robotersystem LEGO TC logo vorgestellt. 1998 kam mit dem Robotics Invention System der erste Baukasten der MINSTORMS-Reihe auf den Markt. Im Jahr 2006 folgte LEGO MINDSTORMS NXT, drei Jahre später die überarbeitete NXT-2.0-Version. Seit September 2013 ist LEGO MINDSTORMS EV3 in zwei verschiedenen Editionen verfügbar: der Home Edition (um ca. 330 Euro) und der Education Edition (um ca. 400 Euro). Sie unterscheiden sich durch die im Lieferumfang enthaltenen Teile.

EV3-Hardware im Überblick

Jedes Set beinhaltet neben einer großen Zahl an LEGO-Technic-Elementen einen programmierbaren Mikrocontroller, an den sich verschiedene Aktoren und Sensoren anschließen lassen. Ganz der LEGO-Philosophie folgend können mit einem solchen Baukasten unterschiedliche Roboter aus den Kategorien Humanoide, Tier, Fahrzeug oder Maschine konstruiert werden (Abb. 1). Die große Zahl an Variationsmöglichkeiten trägt maßgeblich zur Faszination bei.

Abb. 1: Der R3PTAR ist ein Standardmodell der EV3-Generation

Abb. 1: Der R3PTAR ist ein Standardmodell der EV3-Generation

Das Herzstück des Systems stellt der programmierbare EV3-Stein dar. In ihm steckt ein ARM9-Prozessor, der mit 300 MHz läuft und auf 64 MB Arbeitsspeicher und 16 MB Flashspeicher zurückgreifen kann. Im Vergleich zur Vorgängerversion wurde der Arbeitsspeicher also um den Faktor 1 000 vergrößert. Als Betriebssystem kommt Linux zum Einsatz. Sechs AA-Batterien versorgen den Mikrocontroller mit Energie. Als Alternative lässt sich ein Akkumodul verwenden. Standardmäßig ist dieses nur bei der Education Edition dabei. Auf dem EV3-Stein findet sich weiterhin ein monochromes LCD mit einer Auflösung von 178 x 128 Pixeln sowie mehrere Navigationsknöpfe, die sich bei Bedarf genauso wie das Display programmieren lassen. Ein Lautsprecher komplementiert den Baustein. Für den Anschluss von Aktoren stehen vier Ausgangsports (A bis D) zur Verfügung, für Sensoren bietet er vier Eingänge (1 bis 4). Wem das nicht ausreicht, kann per USB-Kabel zwei oder mehr EV3-Steine miteinander verketten und aus seinem Programm heraus auf die Aktoren und Sensoren der mit dem Hauptstein verketteten EV3-Steine zugreifen (Abb. 2). Wichtig ist hierbei nur, dass in den Projekteigenschaften der Reihenschaltungsmodus aktiviert wird. Zum Transfer des Programms vom Computer auf den Baustein steht USB sowie Bluetooth bereit. Weiterhin lässt sich an den neu hinzugefügten USB-2.0-Anschluss ein Wifi-Dongle zur WLAN-Kommunikation anschließen. Dieser muss aber gesondert erworben werden. Ergänzt wurde außerdem ein Micro-SD-Kartenleser, dank dem der Speicherplatz auf bis zu 32 GB erweitert werden kann.

Abb. 2: Die Motoren und Sensoren werden über Kabel mit dem EV3-Stein verbunden

Abb. 2: Die Motoren und Sensoren werden über Kabel mit dem EV3-Stein verbunden

Als Aktoren sind dem Baukasten zwei große und ein mittlerer Servomotor mit integriertem Rotationssensor beigepackt. Hinsichtlich Sensoren kann der Nutzer bei der Home Edition auf einen Infrarotsensor inkl. Fernsteuerung, einen Farbsensor und einen Berührungssensor sowie bei der Education Edition auf einen Ultraschallsensor, einen Farbsensor, einen Gyrosensor und zwei Berührungssensoren zurückgreifen. Der Infrarotsensor lässt sich genauso wie der Ultraschallsensor für Abstandsmessungen nutzen. In Kombination mit der Fernsteuerung bietet erstgenannter aber noch zwei weitere Modi: Einerseits kann man nämlich auch die Lage des Sensormoduls in Bezug auf die Fernsteuerung abfragen und andererseits über die Fernsteuerung verschiedene Steuerbefehle an den Roboter senden. Der Farbsensor identifiziert Farben, der Gyrosensor registriert Drehbewegungen und der Berührungssensor lässt einen auf Druckkontakte reagieren.

Wem diese Bauteile nicht genügen, kann das Erweiterungsset erwerben. Reicht dies immer noch nicht aus, kann man bei Fremdanbietern weitere Hardware dazukaufen. Auch verschiedene Aktoren und Sensoren, die eigentlich für NXT 2.0 entwickelt wurden, sind mit der EV3-Version weiterhin nutzbar.

Vielfältige Programmiermöglichkeiten

Über spezielle Programme kann der Anwender das Verhalten seiner zusammengebauten Roboter programmieren. Es stehen unterschiedliche Umgebungen und Sprachen dazu bereit. Zwei davon werden wir uns in Folge genauer ansehen.

Die auf LabVIEW basierende EV3-Software stellt die standardmäßige Programmierumgebung dar. Es handelt sich dabei um eine ikonische Programmierumgebung, die auf Kinder und Erwachsene ohne jegliche Programmiererfahrung abzielt. Von den Nutzenden ist kein Programmcode zu schreiben, sondern das Programm wird großteils mittels entsprechender Mausaktionen erstellt. Durch das Verschieben und Verbinden der einzelnen Programmierblöcke entsteht nach und nach das gewünschte Programm. Neben Variablen stehen auch die klassischen Kontrollstrukturen wie bspw. Schleifen und Verzweigungen zur Verfügung. Zusätzlich lässt sich auf bestimmte Ereignisse warten und reagieren. Mithilfe von Datenleitungen können Daten zwischen den einzelnen Blöcken ausgetauscht werden.

Die Programmierung der EV3-Roboter ist weiterhin auch mit Java möglich. Das Softwarepaket leJOS EV3 stellt seinen Nutzern alle benötigten Komponenten bereit, d. h. ein Linux-Image, das eine entsprechende Java-Laufzeitumgebung an Bord hat, und eine Klassenbibliothek, über die man Zugriff auf die einzelnen Roboterbauteile erhält. Da es für Eclipse ein leJOS-EV3-Plug-in gibt, sollte man diese IDE nutzen.

Grafische Programmierung mit EV3-Software

Die grafische Programmierumgebung kann kostenlos von der offiziellen MINDSTORMS-Website heruntergeladen werden. Es sind Versionen für Windows und Mac OS X erhältlich.

Die EV3-Software (Abb. 3) ist im Programmiermodus in drei wesentliche Bereiche unterteilt: das Programmierfeld, innerhalb dessen das eigentliche Programm erstellt wird, eine Leiste mit mehreren Karteireitern, in denen alle Programmierblöcke zu finden sind, und die Hardwareseite, die Informationen zum EV3-Stein und den daran angeschlossenen Aktoren und Sensoren liefert. Dort finden sich auch die Funktionen zur Programmübertragung.

Abb. 3: Die EV3-Software ermöglicht die grafische Programmierung von Robotern

Abb. 3: Die EV3-Software ermöglicht die grafische Programmierung von Robotern

Das Programm wird im Stile eines klassischen Ablaufdiagramms aus einzelnen, miteinander verbundenen Programmierblöcken zusammengesetzt, die dann nach dem Transfer des Programms auf den EV3-Stein und dem Programmstart in der gegebenen Reihenfolge abgearbeitet werden. Den ersten Block seines Programms muss der Entwickler mit dem standardmäßig vorhandenen Startblock verbinden. Das Programm endet, wenn ein Block ohne Nachfolger erreicht wird. Das gewünschte Verhalten eines jeden Blocks lässt sich über dessen Eigenschaften einstellen.

Den Motorsteuerungsblöcken kommt bei der Roboterprogrammierung eine große Bedeutung zu, denn kaum ein Roboter kommt ohne Motoren aus. Unterscheiden lassen sich Blöcke zur Ansteuerung eines mittleren Motors, eines großen Motors und von zwei Motoren gleichzeitig. Hat man mit einem Motor zu tun, so stellen der Port, an dem der Motor angeschlossen ist, die Festlegung wie lange bzw. weit der Motor gedreht werden soll, die Motorrichtung und die Drehgeschwindigkeit wesentliche Stellgrößen dar. Ein Motor lässt sich auch einfach an- oder ausstellen. Im Gegensatz zum Modus, bei dem man eine fixe Größe bzgl. der Umdrehungen vorgibt, wird hier bei der Programmausführung nicht bis zur Erreichung des vorgegebenen Werts blockiert, sondern nach dem Starten bzw. Stoppen des Motors unmittelbar mit dem nächsten Block fortgesetzt. Auch für die Anzeige von Grafiken und Texten am Display sowie dem Abspielen von Sounds und Tönen über den Lautsprecher existieren entsprechende Programmierblöcke. Darüber hinaus lässt sich die Statusleuchte des EV3-Steins setzen.

Klarerweise stehen dem Programmierer in der EV3-Software auch die klassischen Kontrollstrukturen zur Verfügung. So kann dieser den Schleifenblock für Wiederholungen verwenden. Wie oft die innerhalb der Schleife platzierten Programmierblöcke wiederholt werden, lässt sich dabei auf unterschiedliche Weise angeben. Neben einer bestimmten Wiederholungsanzahl steht auch unbegrenzt zur Auswahl. Darüber hinaus kann man auch Sensormesswerte in die Schleifenbedingung einfließen lassen. Mithilfe eines Schleifen-Interrupt-Blocks ist das Rausspringen aus der Schleife jederzeit möglich. Als Beispiel sehen wir uns ein Programm an (Abb. 4), durch das ein zweimotoriges Fahrzeug ein Quadrat abfährt und abschließend „Ziel erreicht!“ am Display ausgibt sowie eine Fanfare abspielt.

Abb. 4: Mit nur wenigen Blöcken lässt sich ein Quadratfahrer realisieren

Abb. 4: Mit nur wenigen Blöcken lässt sich ein Quadratfahrer realisieren

Verzweigungen innerhalb des Programms kann man mit dem Schalterblock realisieren. In der zugehörigen Bedingung bezieht sich der Programmierer meist auf einen Sensormesswert. Neuerdings lässt sich mit dem Schalter auch ein Switch-Konstrukt nachbilden.

Eine weitere wichtige Kontrollstruktur stellt der Wartenblock dar. Hier wird an der Stelle, an der der entsprechende Block im Programm eingefügt wurde, so lange blockiert, bis das festgelegte Ereignis eingetreten ist. Das kann im einfachsten Fall der Ablauf einer definierten Wartezeit sein. In den meisten Fällen wird der Roboter allerdings darauf warten, dass ein Sensor einen bestimmten Messwert zurückliefert. Als Beispiel schauen wir uns ein Programm an (Abb. 5), bei dem der Roboter so lange geradeaus fährt, bis dessen Infrarotsensor ein Hindernis innerhalb von 30 cm Entfernung wahrnimmt. Daraufhin dreht er sich so lange, bis der Weg wieder frei ist, und fährt weiter. Zusätzlich wird auch die Statusleuchte zwischen grün und rot hin- und hergeschaltet.

Abb. 5: Ein derart programmiertes Roboterfahrzeug erkennt Hindernisse und weicht ihnen aus

Abb. 5: Ein derart programmiertes Roboterfahrzeug erkennt Hindernisse und weicht ihnen aus

Sehr einfach lassen sich auch Programmteile parallel ausführen. Ein Block kann nämlich mit mehreren Folgeblöcken verbunden sein. Der Programmfluss teilt sich dann an dieser Stelle – die verschiedenen Zweige werden unabhängig voneinander ausgeführt. Eine andere Möglichkeit ist das Hinzufügen weiterer Startblöcke zum Programm. Beim Programmstart wird hier jeder Programmstrang unabhängig von den anderen ausgeführt. Sobald Parallelität ins Spiel kommt, gilt das Programm erst als beendet, wenn alle Zweige beendet wurden oder wenn irgendwo der spezielle Block zum Programmbeenden aufgerufen wird.

Wer leistungsfähige Programme entwickeln möchte, wird um Datenleitungen nicht herumkommen. Einen Programmierblock kann man im Grunde als eine Funktion ansehen, der man bestimmte Eingangsparameter übergeben und die bestimmte Ausgangsparameter zurückliefern kann. Indem man nun Datenleitungen zwischen Blöcken einrichtet, lassen sich die von einem Block gemessenen bzw. berechneten Ausgangsdaten als Eingaben für einen Folgeblock verwenden. Zu beachten ist, dass die Leitungen immer von einem Ausgang zu einem Eingang verbunden werden. Als Beispiel sehen wir uns dazu ein Programm an (Abb. 6), bei dem zwei Zufallszahlen addiert und ihre Summe am Display ausgegeben wird. Dazu werden zwei Zufallsblöcke verwendet. Über deren Ausgangsparameter Wert lässt sich jeweils die generierte Zufallszahl zwischen 1 und 10 abgreifen. Sie dienen dem Matheblock als Eingangsparameter. Er berechnet daraufhin die Summe der beiden Zahlen und stellt jene über seinen Ausgangsparameter Ergebnis bereit. Durch eine weitere Datenleitung zwischen dem Mathe- und dem Displayblock gelangt das Ergebnis schließlich zur Anzeige.

Abb. 6: Dank der Datenleitungen lassen sich Daten zwischen den Blöcken austauschen

Abb. 6: Dank der Datenleitungen lassen sich Daten zwischen den Blöcken austauschen

Zur Abfrage von Sensoren existieren diverse Blöcke, die die Messdaten über entsprechende Ausgangsparameter bereitstellen. Auch für die Durchführung von Berechnungen sowie die logische Verknüpfung zweier Wahrheitswerte mittels NOT, AND, OR oder XOR-Operator stehen passende Blöcke bereit. Datenleitungen lassen sich weiterhin in Verbindung mit Schleifen- und Schalterbedingungen verwenden.

Natürlich kann der Entwickler auch Variablen innerhalb seines Programms verwenden. Mithilfe des Variablenblocks lassen sich Texte, numerische Werte, logische Werte, numerische Arrays und logische Arrays im Speicher ablegen bzw. aus diesem auslesen. Zum Lesen und Schreiben der Variablenwerte kommen ebenfalls Datenleitungen zum Einsatz. Als Beispiel dient ein Programm (Abb. 7), bei dem im Sekundentakt von 10 auf 1 runtergezählt und abschließend „Game over“ abgespielt wird. Die Variable zaehler wird hierbei eingangs auf den Wert 10 gesetzt. Am Beginn der Schleife wird stets der aktuelle Variablenwert ausgelesen und am Display ausgegeben. Nach einer Wartezeit von 1 Sekunde wird der um 1 verkleinerte Wert in die Variable zaehler zurückgeschrieben und geprüft, ob dieser noch größer als 0 ist. Sobald die Bedingung nicht mehr gültig ist, wird die Schleife unterbrochen und der Sound abgespielt.

Abb. 7: Auch Variablen stehen in der EV3-Software zur Verfügung

Abb. 7: Auch Variablen stehen in der EV3-Software zur Verfügung

Eigene Blöcke kann der Programmierer ebenfalls erstellen. Initial muss er hier den Namen sowie die Eingangs- und Ausgangsparameter festlegen. Den Ablauf innerhalb des Blocks erstellt er analog wie bei herkömmlichen Programmen.

Zum Persistieren von Daten über die Programmausführung hinaus gibt es neuerdings einen Dateizugriffblock. Der Aufbau einer Bluetoothverbindung ist ebenfalls programmatisch mittels eines gleichnamigen Blocks möglich. Leider funktioniert dieses Feature aber immer noch nicht so, wie man sich das wünschen würde. Für einen erfolgreichen Verbindungsaufbau ist es nämlich nach wie vor erforderlich, dass man davor bereits eine manuelle Bluetoothverbindung zwischen den zwei EV3-Steinen aufgebaut hat.

Java-Programmierung mit leJOS EV3

Zur Programmierung der MINDSTORMS-Roboter in der Programmiersprache Java muss man sich das kostenlose und Open Source bereitgestellte Softwarepaket leJOS EV3 von der zugehörigen Website herunterladen und installieren. Es ist für Windows, Linux und Mac OS X verfügbar.

Musste der Java-Entwickler in der Vorgängerversion noch die Firmware des NXT-Steins ersetzen, so gibt es nun eine elegantere Lösung. Mithilfe des EV3 SD Card Creators erzeugt man sich einfach eine bootbare SD-Karte mit einem Linux-Betriebssystem inkl. einer Java-SE-Embedded 7-Laufzeitumgebung. Nach nur wenigen Sekunden steht die SD-Karte, die man anschließend nur mehr in den Micro-SD-Kartenleser einlegen muss, bereit. Der erste Start dauert aufgrund verschiedener Initialisierungsarbeiten mit ca. acht Minuten zwar etwas länger, bei den folgenden Starts bootet der EV3-Stein aber innerhalb einer Minute. Will jemand seinen Roboter wieder mit der EV3-Software programmieren, so muss er lediglich die SD-Karte herausnehmen.

Als IDE empfiehlt sich Eclipse Kepler, denn dafür gibt es ein passendes leJOS-EV3-Plug-in. Wer Windows verwendet und seinen EV3-Stein über USB ansprechen möchte, muss zusätzlich noch den RNDIS/Ethernet-Gadget-Treiber installieren. Danach kann es auch schon mit der Java-Programmierung losgehen.

Am Beginn steht das Anlegen eines passenden Projekts. Durch Auswahl des Projekttyps LeJOS EV3 Project fügt Eclipse automatisch dem neu angelegten Projekt die erforderliche Klassenbibliothek hinzu. Alle Klassen mit main-Methode können außerdem als LeJOS EV3 Program ausgeführt werden, wodurch sie in kompilierter Form auf den EV3-Stein hochgeladen und dort gestartet werden. Das nachträgliche Umwandeln eines Standardprojekts in ein EV3-Projekt ist ebenfalls möglich.

Das Ansprechen der Hardware ist denkbar einfach. Für jedes Bauteil gibt es eine zugehörige Java-Klasse, über die sich der jeweilige Aktor bzw. Sensor steuern bzw. abfragen lässt. Um einen Motor anzusprechen, ist im ersten Schritt ein entsprechendes Objekt zu instanziieren. Dem Konstruktor ist dabei der Port zu übergeben, an dem der Motor hängt. Über das erzeugte Objekt erfolgen anschließend die gewünschten Methodenaufrufe (Listing 1).

Listing 1
// large motor
RegulatedMotor motorL = new EV3LargeRegulatedMotor(MotorPort.A);
// medium motor
RegulatedMotor motorM = new EV3MediumRegulatedMotor(MotorPort.B);

motorL.forward();
//... do something!
motorL.stop();

forward() und backward() stellen wohl die wichtigsten Methoden dar. Sie werden nicht blockierend ausgeführt – bewirken also, dass der Motor in die gewählte Richtung losgedreht wird und setzten unmittelbar danach mit der Programmausführung fort. Erst ein Aufruf von stop() hält den Motor wieder an. Mit rotate() steht zur Motorsteuerung auch eine blockierende Variante zur Verfügung. Hier ist als Aufrufargument der Drehwinkel zu übergeben. Weiterhin können die Motoren auch direkt über die bereitgestellten statischen Objekte angesprochen werden:

Motor.A.forward();
// ... do something!
Motor.A.stop();

Nachdem bei der Steuerung von Fahrzeugen mit zwei angetriebenen Rädern die Synchronisation der beiden Motoren eine bedeutende Rolle spielt und es mühsam wäre, dies stets manuell machen zu müssen, stellt das API für diese Zwecke die Klasse DifferentialPilot bereit. Bei der Instanziierung sind neben dem Raddurchmesser und der Spurbreite die beiden Motor-Objekte zu übergeben:

DifferentialPilot pilot = new DifferentialPilot(3.4, 12.75, Motor.C, Motor.B);
pilot.forward();
// ... do something!
pilot.stop();

Führt der Entwickler forward(), backward() oder stop() aus, wirkt der Methodenaufruf intern nun auf beide Motoren. Mit rotateLeft() und rotateRight() bietet diese Klasse außerdem die Möglichkeit, ein Kettenfahrzeug am Stand in eine bestimmte Richtung zu drehen. Die diversen arc-Methoden erlauben das Fahren von Kreisstrecken. Zu all diesen Methoden gibt es wiederum blockierende Gegenstücke.

Zur Abfrage der Sensoren wurde in leJOS EV3 ein Sensorframework integriert, mit dem sich nun alle Sensoren einheitlich ansprechen lassen. Nachdem ein Sensor mehrere Abfragemodi bieten kann, muss der Programmierer nach der Instanziierung der entsprechenden Sensorklasse – dem Konstruktor ist hier wieder der Port, an dem der Sensor hängt, zu übergeben – den gewünschten Modus wählen. Zurückgeliefert bekommt er einen so genannten Sample-Provider, über den er ab sofort den bzw. die Messwerte in Gestalt eines float-Arrays abfragen kann. Für den Ultraschallsensor sieht dies wie in Listing 2 aus.

Listing 2
SensorModes sensor = new EV3UltrasonicSensor(SensorPort.S1);
SampleProvider distance = sensor.getMode("Distance");
float[] sample = new float[distance.sampleSize()];
distance.fetchSample(sample, 0);
// sample[0] contains distance ... do something!

Wem dieser Ansatz zu generisch ist, der kann auch die Sensorklasse selbst als Referenztyp verwenden. Das vereinfacht zumindest die Modus-Auswahl (Listing 3).

Listing 3
EV3UltrasonicSensor sensor = new EV3UltrasonicSensor(SensorPort.S1);
SampleProvider distance = sensor.getDistanceMode();
float[] sample = new float[distance.sampleSize()];
distance.fetchSample(sample, 0);
// sample[0] contains distance ... do something!

Als weitere wichtige Sensorklassen lassen sich EV3ColorSensor, EV3GyroSensor, EV3IRSensor und EV3TouchSensor nennen.

Neu in leJOS EV3 sind die verschiedenen Filter. So kann es bspw. erforderlich sein, dass nicht nur der letzte Messwert berücksichtigt wird, sondern stets der Mittelwert über die letzten n Messungen berechnet und an den Aufrufer zurückgeliefert wird. Die Integration eines solchen Filters ist denkbar einfach. Bei dessen Instanziierung ist lediglich der Sample-Provider zur Abfrage eines einzelnen Samples zu übergeben. Dem Konstruktor der MeanFilter-Klasse ist weiterhin die Anzahl der zu berücksichtigenden Messungen zu übergeben. Der Filter selbst tritt nach außen wiederum als Sample-Provider auf (Listing 4).

Listing 4
EV3UltrasonicSensor sensor = new EV3UltrasonicSensor(SensorPort.S1);
SampleProvider average = new MeanFilter(sensor.getDistanceMode(), 5);
float[] sample = new float[average.sampleSize()];
average.fetchSample(sample, 0);
// sample[0] contains average of last 5 distances ... do something!

Zur Wiedergabe von Sounds und Tönen stellt leJOS EV3 die Klasse Sound bereit, das Display kann über LCD angesprochen werden, zur Programmierung der Tasten am EV3-Stein dient Button und mithilfe von Delay lassen sich Pausen während der Programmausführung erzwingen. Diese Klassen enthalten allesamt fast ausschließlich statische Methoden:

Sound.beep();
LCD.drawString("Hello World!", 0, 0);
Button.ENTER.waitForPressAndRelease();
Delay.msDelay(1000);

Der Entwickler kann auch Threads erzeugen und so nebenläufige Aktionen implementieren.

Abschließend zeigen wir noch ein Programm (Listing 5), das den besonders bei Burschen sehr beliebten Shooterbot steuert. Dieses Kettenfahrzeug dreht sich im Stand und scannt dabei seine Umgebung. Kommt ein Objekt in seinen Sichtbereich (≤ 30 cm), bleibt es stehen und gibt drei Warntöne ab. Ist das Objekt danach immer noch nicht verschwunden, feuert der Shooterbot eine Kugel ab. Durch Druck auf den Tastsensor kann das Programm jederzeit beendet werden.

Listing 5
...
public class Shooterbot {
  private static final int WAITTIME = 10;
  
  private DifferentialPilot pilot;
  private SampleProvider touch;
  private SampleProvider distance;
  
  public Shooterbot() {
    EV3TouchSensor touchSensor = new EV3TouchSensor(SensorPort.S1);
    EV3UltrasonicSensor ultrasonicSensor = new EV3UltrasonicSensor(SensorPort.S4);

    pilot = new DifferentialPilot(3.4, 12.75, Motor.C, Motor.B);
    touch = touchSensor.getTouchMode();
    distance = ultrasonicSensor.getDistanceMode();    
  }
  
  private boolean isTouchPressed() {
    float[] sample = new float[touch.sampleSize()];
    touch.fetchSample(sample, 0);
    return (sample[0] == 1.0);
  }
  
  private int getUltrasonicDistance() {
    float[] sample = new float[distance.sampleSize()];
    distance.fetchSample(sample, 0);
    return Math.round(sample[0]);
  }
  
  public void run() {
    Thread listener = new Thread(new Runnable() {
      @Override
      public void run() {
        while (!isTouchPressed()) {
          Delay.msDelay(WAITTIME);
        }
        
        System.exit(0);
      }
    });
    listener.start();

    while (true) {
      LCD.clear();
      pilot.rotateLeft();

      while (getUltrasonicDistance() > 30) {
        Delay.msDelay(WAITTIME);
      }

      pilot.stop();

      for (int i = 0; i < 3; i++) {
        LCD.drawInt(3 - i, 0, 0);
        Sound.beep();
        Delay.msDelay(1000);
      }

      if (getUltrasonicDistance() <= 30) {
        LCD.drawString("Game over!", 0, 0);
        Motor.A.rotate(360);
      }
    }
  }
  
  public static void main(String[] args) {
    Shooterbot shooterbot = new Shooterbot();
    shooterbot.run();
  }
}

Fazit

Der Artikel gab eine Einführung in LEGO MINDSTORMS EV3 und zeigte, wie sich die LEGO-Roboter mittels der EV3-Software sowie leJOS EV3 programmieren lassen. Wie wir gesehen haben, ist die grafische Programmierung einfach erlernbar und trotzdem leistungsfähig. In Sachen Java-Programmierung stellt das API zum Steuern bzw. Abfragen der Aktoren bzw. Sensoren passende Klassen bereit, dank derer das Ansprechen der Hardwareteile ebenfalls einfach möglich wird.

Lassen Sie mich zum Abschluss aber eine Warnung aussprechen: Die Beschäftigung mit LEGO MINDSTORMS EV3 kann schnell süchtig machen. Da wird hier noch schnell etwas am Modell umgebaut, dort noch etwas dazuprogrammiert – und ehe man sichs versieht, ist es auch schon weit nach Mitternacht. Sie wissen ja: Wenn das Kind einmal im Erwachsenen erwacht, gibt es kein Halten mehr (Abb. 8).

Abb. 8: LEGO MINDSTORMS begeistert nicht nur Kinder, sondern auch Erwachsene (wie Veronika und Alexandra)

Abb. 8: LEGO MINDSTORMS begeistert nicht nur Kinder, sondern auch Erwachsene (wie Veronika und Alexandra)

Aufmacherbild: a team of vintage robot toys von Shutterstock / Urheberrecht: charles taylor

Geschrieben von
Bernhard Löwenstein
Bernhard Löwenstein
Bernhard Löwenstein (bernhard.loewenstein@java.at) ist als selbstständiger IT-Trainer und Consultant für javatraining.at tätig. Als Gründer und ehrenamtlicher Obmann des Instituts zur Förderung des IT-Nachwuchses führt er außerdem altersgerechte Roboterworkshops für Kinder und Jugendliche durch, um diese für IT und Technik zu begeistern.
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.