Cooles Technikspielzeug für Jung und Alt

LEGO MINDSTORMS NXT

Bernhard Löwenstein
©iStockphoto.com/sammyc

Immer mehr eingebettete Systeme können mit Java programmiert werden, unter anderem auch LEGO-MINDSTORMS-NXT-Roboter. Dieser Beitrag gibt eine technologische Einführung und beschreibt im Anschluss, wie man die Roboter mittels leJOS NXJ in der Sprache des Duke programmieren kann.

Es gibt Spielzeug, das so genial ist, dass es zu einem unglaublichen, nicht enden wollenden Siegeszug rund um den Globus ansetzt. Nein, liebe Freunde des angebissenen Apfels, es ist nicht vom iPhone die Rede, sondern von LEGO. Kaum ein Kind der westlichen Welt hat noch nicht versucht, damit ein mehr oder weniger phantasievolles Gebilde zusammenzubauen. Das LEGO-Imperium umfasst aber nicht mehr nur die einfachen Plastiksteine: Mit der Baukastenserie LEGO MINDSTORMS bietet der dänische Konzern seinen kleinen und großen Fans mittlerweile 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.

Logo meets LEGO

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 auf interessante Weise die Programmierung näherbringen kann. Er suchte eine interessante Anwendung für seine Programmiersprache Logo und stieß dabei auf Roboter. Mit LEGO fand er einen passenden Partner zur Realisierung seines Vorhabens. Mittlerweile gibt es mehrere Generationen dieser Baukästen. Die aktuelle Version ist LEGO MINDSTORMS NXT 2.0, auf die sich auch dieser Artikel bezieht. Im Januar dieses Jahres stellte LEGO auf der International Consumer Electronics Show in Las Vegas den Nachfolger EV3 [1] vor, der deutliche Verbesserungen zur NXT-Version aufweisen und ab Herbst 2013 im Handel erhältlich sein soll.

NXT-Hardware im Überblick

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

Abb. 1: Die Servomotoren und Sensoren werden über Kabel mit dem NXT-Stein verbunden

Das Herzstück des Systems stellt der programmierbare NXT-Stein dar. In ihm steckt ein 32-Bit-Mikroprozessor, der mit 48 MHz läuft und auf 256 KB Flash-Speicher und 64 KB Arbeitsspeicher zurückgreifen kann. Auf dem NXT-Stein findet sich ein monochromes LCD mit einer Auflösung von 100 x 64 Pixel sowie vier Navigationsknöpfe, die sich bei Bedarf genauso wie das Display individuell programmieren lassen. Ein Lautsprecher komplementiert den Baustein. Für den Anschluss von Aktoren stehen die drei Ausgangsports A-C zur Verfügung, für Sensoren bietet er die vier Eingänge 1-4. Zum Transfer des Programms vom Programmiercomputer auf den Baustein stehen USB und Bluetooth bereit. Als Aktoren sind dem Baukasten drei Servomotoren beigepackt. Hinsichtlich Sensoren kann der Nutzer auf einen Ultraschallsensor, zwei Tastsensoren und einen Farbsensor zurückgreifen. Ersterer erlaubt Abstandsmessungen, der Tastsensor reagiert auf Druckkontakt, und der Farbsensor kann einerseits Farben und Lichteinstellungen identifizieren und andererseits als Lampe eingesetzt werden.

Wer sich mit diesen Bauteilen nicht begnügen möchte, der kann das Erweiterungsset erwerben. Reicht dies immer noch nicht aus, kann man bei Fremdanbietern noch weitere Hardware dazu kaufen. Von Solarpaneelen über Beschleunigungs-, Biege-, Gyro-, Kompass- und Temperatursensoren bis hin zu speziellen Rädern, die auch seitliche Bewegung erlauben, ist so gut wie alles erhältlich, was das Herz von Jung und Alt begehrt.

Vielfältige Programmiermöglichkeiten

Über spezielle Programme kann der Anwender das Verhalten seiner zusammengebauten Roboter programmieren. Es stehen unterschiedliche Umgebungen und Sprachen dazu bereit.

Das auf LabVIEW basierende NXT-G stellt die standardmäßige Programmierumgebung für LEGO MINDSTORMS dar. NXT-G ist eine ikonische Programmierumgebung und zielt auf Kinder und Erwachsene ohne jegliche Programmiererfahrung ab. Von den Nutzenden ist kein Programmcode zu schreiben, das Programm wird großteils mittels entsprechender Mausaktionen erstellt. Durch das Verschieben und Verbinden der einzelnen Funktionsblöcke entsteht nach und nach das gewünschte Programm. Neben Variablen stehen auch Kontrollstrukturen wie Schleifen und Verzweigungen zur Verfügung. Zusätzlich lässt sich auf bestimmte Ereignisse warten und reagieren.

Für uns von größerem Interesse ist allerdings leJOS NXJ [2], denn es ermöglicht die Programmierung der NXT-Roboter unter Java. Das Open-Source-Softwarepaket stellt seinen Nutzern alle benötigten Komponenten bereit – einerseits eine modifizierte Firmware, durch die auf dem NXT-Baustein eine JVM installiert wird, und andererseits eine Klassenbibliothek, über die man Zugriff auf die einzelnen Roboterbauteile erhält. Zusätzlich bietet leJOS NXJ noch verschiedene Werkzeuge, die beispielsweise den Firmware-Tausch oder den Programmupload ermöglichen. Nachdem es ein leJOS NXJ-Plug-in für Eclipse gibt, empfiehlt sich die Nutzung dieser IDE. Nach der Installation des Plug-ins finden sich einige zusätzliche Menüpunkte in Eclipse, über die sich die wichtigsten Aktionen einfach und bequem durchführen lassen. Zu beachten ist, dass 32-Bit-Versionen von Eclipse und der JVM zwingend vonnöten sind.

Steigende Beliebtheit im Ausbildungsbereich

In den vergangenen Jahren hat LEGO MINDSTORMS an vielen Schulen, Universitäten und sonstigen Ausbildungsstätten Einzug gehalten. Die Baukästen werden dort zur Durchführung unterschiedlichster Projekte genutzt. Darüber hinaus konnten sich diverse Wettkämpfe etablieren, deren Anwendungsbereiche von Roboterfußball bis hin zur Algorithmenoptimierung reichen. Diese Disziplinen motivieren nicht nur Kinder und Jugendliche, sondern auch Erwachsene, sich intensiver mit den Baukästen zu beschäftigen.

Gegenüber den klassischen Ansätzen, wie beispielsweise dem Sprachkurs, bietet der Robotereinsatz im Unterricht viele Vorteile. So üben Roboter, im Speziellen die menschenähnlichen Humanoiden, schon seit jeher eine Faszination auf den Menschen aus. Deshalb ist es nicht verwunderlich, dass es für Lernende ein besonderes Erlebnis ist, wenn sie die Kontrolle über eine solche Maschine übernehmen können. Weiterhin von Vorteil ist, dass die Roboter direktes Feedback an die Schüler zurückliefern. Das Programm muss lediglich hochgeladen und aufgerufen werden. Danach kann auch schon beobachtet werden, ob es das macht, was es tun soll. Bei einem Fehler kann es schon einmal passieren, dass der Roboter nicht nur sprichwörtlich gegen die Wand fährt. Dieses klare und direkte Feedback wirkt sehr motivierend, da man auf einen Blick erkennen kann: Das Programm funktioniert – oder funktioniert nicht. Besonders hervorzuheben ist auch, dass es sich bei LEGO MINDSTORMS um ein hervorragend skalierbares Medium handelt. Das Spektrum reicht von Personen, die noch nie mit der Computerprogrammierung zu tun hatten, bis hin zu Studierenden, die komplexe Algorithmen wie beispielsweise Schwarmintelligenz-Verfahren anschaulich testen möchten. Ebenfalls positiv zu erwähnen ist, dass die Lernenden sowohl mit Hardware- als auch mit Softwarebelangen konfrontiert werden. Allzu oft lernen sie Hardware und Software als etwas voneinander Isoliertes kennen. In Wahrheit verschwimmen die Grenzen zwischen diesen Welten zunehmend und der Systemgedanke tritt immer mehr in den Vordergrund.

Dem stehen natürlich gewisse Nachteile gegenüber. So kostet ein NXT-Baukasten rund 300 Euro. Da diese nicht mehr produziert werden, sind derzeit nur noch Restposten erhältlich. Die EV3-Version soll rund 350 Euro kosten. Weiterhin weist die NXT-Hardware gewisse Einschränkungen auf. So ist der Speicherplatz für das Programm und die Daten auf einige Kilobyte beschränkt. In Zeiten, in denen üblicherweise in Gigabyte gerechnet wird, ist das natürlich nicht zufriedenstellend. Hier verspricht die neue Version Besserung, denn dort soll endlich ausreichend Speicher zur Verfügung stehen. Weiterhin messen manche der Sensoren etwas ungenau, wenngleich diese Problematik eher vernachlässigbar ist. Zu guter Letzt ist noch zu erwähnen, dass die Programmierumgebung NXT-G mittlerweile ein wenig in die Jahre gekommen ist und in Bezug auf leJOS NXJ manch unglückliche Designentscheidung den Einsatz im Anfängerunterricht erschwert. Letzteres lässt sich mit ein wenig Lehrerfahrung aber gut in den Griff bekommen.

leJOS-Programmierung basic

Nach dieser etwas längeren Einführung wollen wir uns nun endlich auf die Java-Programmierung stürzen. Am Anfang steht das Anlegen eines entsprechenden Projekts. Durch Auswahl des Projekttyps LeJOS NXT Project fügt Eclipse dem neu angelegten Projekt automatisch die leJOS-Klassenbibliothek hinzu. Alle Klassen mit main-Methode können außerdem als LeJOS NXT Program ausgeführt werden, wodurch sie in kompilierter Form auf den verbundenen NXT-Stein hochgeladen und dort gestartet werden. Das nachträgliche Umwandeln eines Standardprojekts in ein leJOS-NXT-Projekt ist ebenfalls möglich.

Das Ansprechen der Hardware ist denkbar einfach. Für jeden 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, wobei dem Konstruktor der Port zu übergeben ist, an dem der Motor hängt. Über das erzeugte Objekt erfolgen anschließend die gewünschten Methodenaufrufe:

RegulatedMotor motor = new NXTRegulatedMotor(MotorPort.A);
motor.forward();
//... do something!
motor.stop();

Die selbstklärenden Methoden forward() und backward() stellen wohl die wichtigsten Methoden dar. Sie werden nichtblockierend ausgeführt, bewirken also, dass der Motor in die gewählte Richtung losgedreht wird und setzen unmittelbar danach die Programmausführung fort. Erst ein Aufruf von stop() hält den Motor wieder an. Mit rotate() steht für die Motorensteuerung 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 einzelnen Motorenaktionen 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 Motorenobjekte 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.

Das Abfragen von Sensorwerten ist ebenfalls recht einfach möglich. Zuerst ist eine Instanz der zugehörigen Sensorklasse zu erstellen. Dem Konstruktor ist hierbei jeweils der Port, an dem der Sensor angeschlossen ist, zu übergeben. Danach kann er auch schon durch entsprechende Methodenaufrufe abgefragt werden.

Die Klasse TouchSensor repräsentiert den Tastsensor. Die Methode isPressed() gibt Auskunft, ob er gedrückt ist oder nicht:

TouchSensor touchSensor = new TouchSensor(SensorPort.S1);
if (touchSensor.isPressed()) {
  // ... do something!
}

Die Klasse UltrasonicSensor ermöglicht die Nutzung des Ultraschallsensors. Mittels getDistance() lässt sich der Abstand zum nächstliegenden Gegenstand ermitteln:

UltrasonicSensor ultrasonicSensor = new UltrasonicSensor(SensorPort.S4);
if (ultrasonicSensor.getDistance() < 30) {
  // ... do something!
}

Zur Farberkennung benötigt man den Farbsensor. Seine Funktionalitäten werden durch die Klasse ColorSensor gekapselt. Die Methode getColorID() führt eine Farbmessung durch und liefert die Farbe in Form einer Farbkonstante zurück. Es ist darüber hinaus auch möglich, den Sensor als Farblampe zu verwenden. Jene kann in den Farben rot, grün oder blau leuchten. Die Methode zum Ein- und Ausschalten der Lampe heißt setFloodlight(). Ihr ist beim Aufruf eine Farbkonstante zu übergeben:

ColorSensor colorSensor = new ColorSensor(SensorPort.S3);
if (colorSensor.getColorID() == Color.BLACK) {
  // ... do something!
}
colorSensor.setFloodlight(Color.RED);

Zur Ausgabe von Tönen und der Wiedergabe kurzer 8-Bit-WAV-Sound-Dateien stellt leJOS NXJ die Klasse Sound bereit, das Display kann über LCD angesprochen werden, zur Programmierung der Tasten am NXT-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. Die bisherigen Informationen reichen bereits aus, um den erfahrungsgemäß besonders bei Jungen sehr beliebten Shooterbot zu realisieren (Abb. 2). Dieses Kettenfahrzeug dreht sich am 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 noch nicht verschwunden, feuert der Shooterbot drei Kugeln ab. Durch Druck auf den Tastsensor kann das Programm jederzeit beendet werden. Listing 1 gibt den Sourcecode wieder.

Abb. 2: Der Shooterbot überwacht nicht nur die Gegend, er kann auch Kugeln abfeuern

 ...
public class Shooterbot {
  public static void main(String[] args) {
    DifferentialPilot pilot = new DifferentialPilot(3.4, 12.75, Motor.C, Motor.B);
    final TouchSensor touchSensor = new TouchSensor(SensorPort.S1);
    ColorSensor colorSensor = new ColorSensor(SensorPort.S3);
    UltrasonicSensor ultrasonicSensor = new UltrasonicSensor(SensorPort.S4);
    
    Thread listener = new Thread(new Runnable() {
      @Override
      public void run() {
        while (!touchSensor.isPressed()) {} 
        System.exit(0);
      }
    });
    listener.start();
        
    while (true) {
      LCD.clear();
      colorSensor.setFloodlight(Color.GREEN);
      pilot.rotateLeft();
  
      while (ultrasonicSensor.getDistance() > 30) {
        Delay.msDelay(50);
      }
      
      pilot.stop();
      colorSensor.setFloodlight(Color.RED);
  
      for (int i = 0; i < 3; i++) {
        Sound.beep();
        LCD.drawString(String.valueOf(3 - i), 0, 0);
        Delay.msDelay(1000);
      }
      
      if (ultrasonicSensor.getDistance() <= 30) {
        LCD.drawString("Game over!", 0, 0);
        Motor.A.rotate(360 * 3);
      }
    }
  }
}

[ header = leJOS-Programmierung extended ]

leJOS-Programmierung extended

Mit dem Behavior Programming bietet leJOS NXJ seinen Nutzern ein Programmiermodell auf höherem Level. Der Entwickler definiert hier die verschiedenen Verhaltensmuster seines Roboters und gibt dabei an, wann das jeweilige Verhalten zu aktivieren ist. Dies kann bei größeren Programmen zu einer übersichtlicheren Programmstruktur führen.

Von zentraler Bedeutung ist die Klasse Arbitrator. Sie implementiert den Scheduler, der zyklisch für alle ihm bekannten Verhaltensmuster überprüft, ob eines davon zu aktivieren ist. Die vom Entwickler definierten Verhaltensmuster müssen die Behavior-Schnittstelle implementieren. Diese schreibt die Methoden takeControl(), action() und suppress() vor. Liefert takeControl() beim Aufruf durch den Arbitrator den Wert true zurück, so bedeutet dies, dass das Verhalten zu aktivieren ist. Konkret wird in diesem Fall die action-Methode ausgeführt. Mithilfe der suppress-Methode soll der Scheduler ein Verhaltensmuster unmittelbar beenden können. Recht häufig bleibt diese Methode aber leer. Listing 2 zeigt den Zusammenhang anhand eines abstrakten Beispiels.

...
public class MyBehaviorDemo {
  public static void main(String[] args) {
    Behavior[] behaviors = new Behavior[] {
      new MyEnterButtonBehavior(),
      new MyUltrasonicSensorBehavior()
    };

    Arbitrator arbitrator = new Arbitrator(behaviors);
    arbitrator.start();
  }

  private static class MyEnterButtonBehavior implements Behavior {
    public boolean takeControl() {
      return Button.ENTER.isDown();
    }

    public void action() {
      // ... do something!
    }

    public void suppress() {}
  }

  private static class MyUltrasonicSensorBehavior implements Behavior { ... }
}

Wer komplexere Roboterprojekte angeht, stößt jedoch schnell an die Grenzen dieses Frameworks. Sehr oft muss nämlich bei der Überprüfung, ob ein bestimmtes Verhalten zu aktivieren ist, der Vorzustand berücksichtigt werden – und schon sind wir bei der klassischen Zustandsmaschine angelangt. Klarerweise kann man alles manuell programmieren. Eleganter ist aber die Nutzung des StateMachine-Frameworks [3], mit dem sich Zustandsgraphen sehr einfach in Code umsetzen lassen.

leJOS-Programmierung professional

leJOS NXJ bietet auch Möglichkeiten zum einfachen Datenaustausch. So lässt sich via USB oder Bluetooth vom Rechner eine Verbindung zu einem NXT-Stein aufbauen. Die Kommunikation zwischen zwei NXT-Steinen ist per Bluetooth möglich. Das wollen wir uns abschließend noch anschauen.

Die Klasse Bluetooth stellt für den Verbindungsaufbau mehrere statische Methoden bereit. Ist das fremde Gerät dem NXT-Stein, der die Verbindung aufbauen möchte, bereits bekannt, so liefert die Methode getKnownDevice() ein RemoteDevice-Objekt zurück, und der Verbindungsaufbau mittels connect() kann sofort erfolgen. Ist das nicht der Fall, muss über inquire() ein Suchlauf gestartet werden. In der Liste der gefundenen Geräte sollte der Remote-Baustein daraufhin enthalten sein. Durch Aufruf von addDevice() fügt man ihn der Liste der bekannten Geräte hinzu. Danach kann auch hier der Verbindungsaufbau erfolgen. Zu beachten ist, dass die PIN als ASCII-Array zu übergeben ist. Die Methode im Listing 3 fasst die beschriebenen Schritte zusammen.

public static NXTConnection connectTo(String name, String pin) throws Exception {
  RemoteDevice device = Bluetooth.getKnownDevice(name);
    
  if (device == null) {
    List<RemoteDevice> foundDevices = Bluetooth.inquire(5, 5, 0);
      
    for (RemoteDevice foundDevice : foundDevices) {
      if (foundDevice.getFriendlyName(false).equalsIgnoreCase(name)) {
        Bluetooth.addDevice(foundDevice);
        device = foundDevice;
        break;
      }
    }
  }
    
  if (device == null) {
    throw new Exception("Can't found device!");
  }
    
  byte[] pinArray = new byte[pin.length()];
  for (int i = 0; i < pin.length(); i++) {
    pinArray[i] = (byte) pin.charAt(i);
  }
      
  return Bluetooth.connect(name, NXTConnection.PACKET, pinArray);
}

Nachdem die Verbindung steht, kann der Entwickler Streams öffnen und der Datenaustausch in der Java-typischen I/O-Weise erfolgen:

NXTConnection con = connectTo("car", "1234");
DataOutputStream out = con.openDataOutputStream();
out.writeInt(accelHTSensor.getXAccel());
// ... write more!
out.flush();

Auf Seite des Geräts, zu dem die Verbindung aufgebaut werden soll, muss lediglich die Methode waitForConnection() aufgerufen werden. Wird der Timeout-Parameter auf 0 gesetzt, so blockiert sie so lange, bis eine Verbindung zustande kommt. Über das NXTConnection-Objekt gelangt der Entwickler auch hier wieder an Streams für den eigentlichen Datenaustausch:

NXTConnection con = Bluetooth.waitForConnection(0, NXTConnection.PACKET, pinArray);
DataInputStream in = con.openDataInputStream();
int x = in.readInt();
// ... read more!

Mit diesem Wissen ausgestattet, können wir nun tolle Projekte realisieren – beispielsweise ein Fahrzeug, das durch das Schwenken vor/zurück bzw. links/rechts eines zweiten NXT-Steins remote gesteuert wird und sich dank seines innovativen Antriebssystems in alle Richtungen bewegen kann (Abb. 3). Ich nenne es das Tedmobil – oder kurz: „The Ted“. Bis zum Embedded Experience Day bei der JAX 2013 in Mainz möchte ich jenes noch ein wenig aufrüsten [Stand: Anfang April, Anm. d. Red.].

Abb. 3: Das Tedmobil kann sich dank der speziellen Räder in alle Himmelsrichtungen bewegen

Fazit

Der Artikel gab eine Einführung in LEGO MINDSTORMS NXT und zeigte, wie man LEGO-Roboter über leJOS NXJ in der Sprache Java programmieren kann. Wie wir gesehen haben, stellt das API zum Steuern bzw. Abfragen der Aktoren bzw. Sensoren passende Klassen bereit, dank derer die Nutzung der Hardware fast zum Kinderspiel wird. Auch die Kommunikation mit einem NXT-Stein sowie zwischen zwei NXT-Steinen ist auf die Java-typische Art möglich.

Lassen Sie mich zum Abschluss aber eine Warnung aussprechen: Die Beschäftigung mit LEGO MINDSTORMS NXT kann sehr schnell süchtig machen. Da wird hier noch schnell etwas am Modell umgebaut, dort noch schnell etwas dazu programmiert – und ehe man sich versieht, ist es auch schon weit nach Mitternacht. Sie wissen ja: Wenn das Kind einmal im Manne erwacht, dann gibt es kein Halten mehr.

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.