MicroPython

Eins nach dem Anderen – Das erste Programm

Du schaltest die LEDs und zeichnest deine ersten Bilder auf das Display.

Die LEDs zum Leuchten bringen

Die Vorbereitungen hast du hinter dir – Zeit für das erste Programm.

Zum Mitmachen brauchst du kein Gerät: Im PicoBoy Studio laufen alle Programme dieser Seite direkt im Browser, auf einem eingebauten PicoBoy. Ist ein echter PicoBoy angeschlossen, überträgt das Studio sie auch dorthin.

Öffne das Studio und klicke oben auf „Zu Text wechseln“. Der Editor ist zunächst schreibgeschützt: Klicke im Hinweisbalken auf „Bearbeitung aktivieren“, ersetze den Inhalt des Editors durch diesen Quelltext:

from picoboy import PicoBoy

pb = PicoBoy()

# Den Teil oberhalb dieser Zeile nicht verändern

pb.LED_GREEN.off()          # Grüne LED ausschalten
pb.LED_RED.off()            # Rote LED ausschalten
pb.delay(1000)              # 1000 Millisekunden = 1 Sekunde warten
pb.LED_RED.on()             # Rote LED einschalten
pb.delay(1000)              # 1 Sekunde warten
pb.LED_GREEN.on()           # Grüne LED einschalten

Klicke auf ▶ Testen. Die LEDs leuchten nacheinander auf – am echten PicoBoy, wenn du ihn verbunden hast, sonst im Emulator. Fest auf das Gerät speicherst du ein Programm über „Dateien“ → „Auf den PicoBoy…“.

Programme werden also Zeile für Zeile abgearbeitet – man sagt: sequenziell. Das lässt sich ändern, wie du später sehen wirst.

Programmablaufplan: beide LEDs ausschalten, 1 Sekunde warten, rote LED einschalten, 1 Sekunde warten, grüne LED einschalten

Anmerkungen

  • Die beiden Zeilen über dem Kommentar gehören an den Anfang jedes Programms. Sie laden die Bibliothek picoboy und erzeugen daraus ein Objekt mit dem Namen pb, über das du die Hardware ansprichst.
  • Das Zeichen „#“ leitet einen Kommentar ein: Alles, was in derselben Zeile dahinter steht, wird nicht ausgeführt und dient nur der Erläuterung.
  • Das Objekt „pb“ steht für die Hardware des PicoBoy – Display, LEDs, Joystick und Beschleunigungssensor. Alle Befehle, die die Hardware betreffen, beginnen deshalb mit „pb“.
  • Die drei LEDs heißen pb.LED_RED, pb.LED_YELLOW und pb.LED_GREEN. Jede kennt .on(), .off() und .toggle().
  • Das Programm schaltet zuerst Grün und Rot aus, damit es immer vom selben Zustand aus beginnt. Eine LED bleibt nämlich an, bis du sie ausschaltest, auch über das Programmende hinaus. Am Ende dieses Programms leuchten deshalb Rot und Grün weiter.
  • pb.delay(1000) hält das Programm für die angegebene Zeit an. Ohne diese Zeile läuft es so schnell weiter, dass du die einzelnen Schritte nicht erkennst.
  • Die Klammern gehören zum Befehl. Schreibst du nur pb.LED_RED.on, passiert nichts, und es gibt auch keine Fehlermeldung.

Wenn eine Fehlermeldung erscheint

Vertippst du dich, bricht das Programm ab, und in der Konsole unter dem Editor erscheint eine Meldung. Das ist normal und macht nichts kaputt. Steht im Programm oben zum Beispiel pb.LED_Red statt pb.LED_RED, siehst du das:

Traceback (most recent call last):
  File "<stdin>", line 8, in <module>
AttributeError: 'PicoBoy' object has no attribute 'LED_Red'

Wichtig sind zwei Stellen: line 8 nennt die Zeile im Editor, und die letzte Zeile nennt die Art des Fehlers. Hier kennt das Objekt nichts mit dem Namen LED_Red, denn Python unterscheidet zwischen Groß- und Kleinschreibung.

Viele Tippfehler meldet das Studio schon beim Start in gelber Schrift, zum Beispiel: „Hinweis Zeile 8: pb.LED_Red gibt es nicht. Meintest du pb.LED_RED?“ Das Programm läuft danach trotzdem los und bricht an dieser Stelle ab.

Zwei weitere Meldungen wirst du oft sehen:

  • NameError: name 'pb' isn't defined: Die Zeilen from picoboy import PicoBoy und pb = PicoBoy() fehlen oder sind vertippt.
  • SyntaxError: invalid syntax: Python versteht eine Zeile nicht. Meist fehlt eine Klammer oder ein Anführungszeichen. Bei einer fehlenden Klammer nennt die Meldung oft erst die Zeile danach. Sieh also auch eine Zeile weiter oben nach.

Übung

Programmiere eine Verkehrsampel. Die Ampelphasen werden in dieser Reihenfolge durchlaufen:

  1. Grün
  2. Gelb
  3. Rot
  4. Rot und Gelb gleichzeitig
  5. Grün

„Gleichzeitig“ heißt hier: zwei Befehle direkt nacheinander, ohne pb.delay() dazwischen. Der Abstand ist zu kurz, um ihn zu sehen. Vor jeder neuen Phase schaltest du außerdem die LEDs der alten Phase aus. So beginnt das Programm:

from picoboy import PicoBoy

pb = PicoBoy()

# Den Teil oberhalb dieser Zeile nicht verändern

pb.LED_RED.off()            # Rote LED ausschalten
pb.LED_YELLOW.off()         # Gelbe LED ausschalten
pb.LED_GREEN.on()           # Phase 1: Grün
pb.delay(2000)              # 2 Sekunden warten
pb.LED_GREEN.off()          # Grün aus
pb.LED_YELLOW.on()          # Phase 2: Gelb
pb.delay(1000)              # 1 Sekunde warten

Die restlichen Phasen ergänzt du nach demselben Muster.

Das Display

Natürlich hast du den PicoBoy nicht nur, um ein paar LEDs blinken zu lassen. Probiere das nächste Programm aus.

Beachte dabei, dass nichts sofort erscheint: Du zeichnest zuerst in einen Bildspeicher, und erst pb.show() überträgt ihn auf das Display.

from picoboy import PicoBoy

pb = PicoBoy()

# Den Teil oberhalb dieser Zeile nicht verändern

pb.fill(0)                  # Bildspeicher mit Farbe 0 (schwarz) füllen
pb.text("Hallo", 0, 27, 1)  # "Hallo" in Weiß (Farbe 1) bei (0,27) schreiben
pb.show()                   # Bildspeicher auf das Display übertragen
pb.delay(1000)              # 1 Sekunde warten
pb.fill(0)                  # Bildspeicher wieder schwarz füllen
pb.text("Welt", 0, 27, 1)   # "Welt" an dieselbe Position schreiben
pb.show()                   # Bildspeicher auf das Display übertragen
pb.delay(1000)              # 1 Sekunde warten
pb.line(0, 0, 127, 63, 1)   # Weiße Linie von (0,0) nach (127,63) zeichnen
pb.line(0, 63, 127, 0, 1)   # Weiße Linie von (0,63) nach (127,0) zeichnen
pb.show()                   # Bildspeicher auf das Display übertragen

Wie das erste Beispiel läuft auch dieses Zeile für Zeile durch. Die Positionen sind Displaykoordinaten, ähnlich dem Koordinatensystem, das du aus Mathematik kennst. Das Display ist 128 Pixel breit und 64 Pixel hoch: (0,0) ist der Punkt oben links, (127,63) der Punkt unten rechts.

Das Display des PicoBoy: 128 mal 64 Pixel, der Ursprung (0,0) liegt oben links, (127,63) unten rechts

Was dabei im Bildspeicher passiert

Der Bildspeicher ist wie ein Blatt Papier, auf dem du in Ruhe zeichnest. pb.show() zeigt das fertige Blatt auf dem Display. So siehst du nie ein halb fertiges Bild. Vergisst du pb.show(), gibt es keine Fehlermeldung. Das Display bleibt einfach, wie es war.

  • pb.fill(0) malt den ganzen Bildspeicher schwarz und löscht damit alles, was vorher darin stand.
  • pb.text("Hallo", 0, 27, 1) bekommt vier Angaben: den Text, die x-Position, die y-Position und die Farbe. x und y gehören zur linken oberen Ecke des ersten Buchstabens.
  • Vor den beiden Linien steht kein pb.fill(0). „Welt“ bleibt deshalb im Bildspeicher, und die Linien kommen dazu.

Jeder Buchstabe ist 8 Pixel breit und 8 Pixel hoch. In eine Zeile passen also 16 Zeichen, auf das Display 8 Zeilen. Was über den Rand hinausragt, wird ohne Fehlermeldung abgeschnitten. Der Zeichensatz des Displays kennt keine Umlaute und kein ß. Schreibe auf dem Display deshalb „Groesse“ statt „Größe“.

Übung: Zeichnen über Gezeichnetes

Lösche im Programm oben das pb.fill(0) vor „Welt“. Jetzt liegen die Buchstaben von „Welt“ auf denen von „Hallo“, weil der alte Text im Bildspeicher geblieben ist.

Mit Farbe 0 zeichnest du schwarz. Auf einem weißen Hintergrund ergibt das dunkle Schrift:

from picoboy import PicoBoy

pb = PicoBoy()

# Den Teil oberhalb dieser Zeile nicht verändern

pb.fill(1)                   # Bildspeicher mit Farbe 1 (weiß) füllen
pb.text("Hallo", 44, 28, 0)  # "Hallo" in Farbe 0 (schwarz) schreiben
pb.show()                    # Bildspeicher auf das Display übertragen

Die 44 und die 28 setzen den Text in die Mitte: „Hallo“ ist 5 mal 8 = 40 Pixel breit, also bleiben links (128 – 40) / 2 = 44 Pixel frei. Für die Höhe gilt (64 – 8) / 2 = 28.

Neben den schon verwendeten Befehlen gibt es weitere Grafikbefehle:

from picoboy import PicoBoy       # Bibliothek laden
pb = PicoBoy()                    # Gerät ansprechbar machen

pb.fill(0)                        # Bildspeicher mit Farbe 0 (schwarz) füllen
pb.pixel(64, 32, 1)               # Weißen Punkt bei (64,32) setzen
pb.line(0, 0, 127, 63, 1)         # Linie von (0,0) nach (127,63)
pb.hline(0, 32, 128, 1)           # Waagerechte Linie bei y=32, 128 Pixel lang
pb.vline(64, 0, 64, 1)            # Senkrechte Linie bei x=64, 64 Pixel hoch
pb.rect(10, 10, 5, 10, 1)         # Umriss bei (10,10), 5 breit und 10 hoch
pb.fill_rect(10, 10, 4, 4, 1)     # Gefülltes Quadrat bei (10,10), Kante 4
pb.ellipse(64, 32, 20, 10, 1)     # Ellipse um (64,32) mit den Radien 20 und 10
pb.text("Hello World", 0, 27, 1)  # Text an Position (0,27) schreiben
pb.show(True)                     # Ganzes Bild übertragen, wegen der Ellipse

Die Farbe ist beim schwarz-weißen Display immer 0 (schwarz) oder 1 (weiß).

Eine Besonderheit bei pb.ellipse(): Anders als die übrigen Befehle merkt sie sich nicht, welcher Teil des Bildes sich geändert hat. Übertrage sie deshalb mit pb.show(True): So geht das ganze Bild ans Display, und die Ellipse ist sicher dabei.

Die Zeichenbefehle stammen aus dem MicroPython-Modul framebuf. Eine vollständige Übersicht findest du in dessen Dokumentation.

Übung

Schreibe ein Programm, das aus einem Rechteck und Linien das „Haus vom Nikolaus“ auf das Display zeichnet.

Das Haus vom Nikolaus auf dem Display: ein Quadrat mit beiden Diagonalen und einem Dach

Zeichne das Haus zuerst auf Karopapier und notiere die Koordinaten aller Ecken. Achte dabei auf eine Kleinigkeit: pb.rect(44, 24, 40, 40, 1) ist 40 Pixel breit und hoch, die rechte untere Ecke liegt aber bei (83,63) und nicht bei (84,64). Das Pixel bei x=44 ist nämlich schon das erste der 40 Pixel. Die Diagonalen und das Dach müssen genau an den Ecken beginnen und enden.

Ohne PC starten

Beim Einschalten zeigt der PicoBoy das Startmenü. Es listet alle Programme auf, die in seinem Speicher liegen; mit dem Joystick wählst du eines aus, ein Druck auf den Joystick startet es. Du musst dein Programm also nur auf dem Gerät speichern – im Menü erscheint es von selbst.

So speicherst du ein Programm auf dem Gerät:

  1. Verbinde den PicoBoy mit einem Klick auf Verbinden mit dem Studio.
  2. Wähle „Dateien“ → „Auf den PicoBoy…“.
  3. Gib einen Dateinamen ein, zum Beispiel ampel. Die Endung .py ergänzt das Studio selbst. Nimm kurze Namen, denn längere als 14 Zeichen kürzt das Menü ab.
  4. Drücke die Taste RES auf der Rückseite. Der PicoBoy startet neu und zeigt das Menü mit deinem Programm.

Endet dein Programm, kehrt der PicoBoy ins Menü zurück. Die LEDs gehen dabei aus, und der Lautsprecher verstummt. Bricht das Programm mit einem Fehler ab, zeigt das Display „Fehler im Programm:“ und die Art des Fehlers. Ein Druck auf den Joystick führt dann zurück ins Menü. Ein Programm mit einer Endlosschleife endet nie von selbst. Dann bringt dich die Taste RES zurück.

Das Menü steckt in der Firmware. Aufgerufen wird es von einer kurzen Datei main.py, die der PicoBoy beim ersten Start nach dem Aufspielen anlegt – allerdings nur, wenn sein Speicher noch leer war. Lief auf dem Gerät vorher schon MicroPython, bleiben die Dateien beim Aufspielen erhalten und du richtest das Menü einmal selbst ein: im PicoBoy Studio über „Dateien“ -> „Startmenü installieren…“, oder in der Konsole mit

import startmenu
startmenu.restore()

Ist der PicoBoy verbunden, klicke auf ■ Stop, klicke in die Konsole und tippe beide Zeilen ein, jede gefolgt von der Eingabetaste.

Soll stattdessen ein bestimmtes Programm sofort beim Einschalten loslaufen, speichere es unter dem Namen main.py. Damit ersetzt du den Aufruf des Menüs; mit startmenu.restore() holst du es zurück.

Blockiert ein fehlerhaftes Programm das Gerät, kannst du main.py im PicoBoy Studio unter „Dateien“ -> „Dateien verwalten…“ löschen oder umbenennen.