Lernziele
- Zustandsmaschine implementieren: Sie können verschiedene Betriebsmodi in einem Programm implementieren und zwischen ihnen wechseln.
- Konzepte kombinieren: Sie können Radio-Steuerung, Helligkeitssensoren und Event-Loop zu einem komplexen Programm verbinden.
- Code-Organisation: Sie strukturieren ein grösseres Projekt mit Funktionen und klaren Zuständen.
- Fehlersuche: Sie können ein komplexes System schrittweise testen und Fehler systematisch eingrenzen.
Das Projekt: Ein Multi-Modus Roboter
Bisher haben Sie verschiedene Einzelfunktionen für den Maqueen programmiert: Fernsteuerung, Linienfolger, Distanzsensoren. Nun kombinieren wir diese zu einem intelligenten Roboter, der zwischen verschiedenen Modi wechseln kann.
Unser Roboter soll drei verschiedene Betriebsmodi haben:
- Modus “Fernsteuern”: Beide Motoren werden per Funk ferngesteuert - freie Bewegung in alle Richtungen
- Modus “Tracker”: Der Roboter folgt automatisch einem schwarzen Fleck am Boden (links herum)
- Modus “Off”: Alle Motoren werden abgestellt und das Programm wird sauber beendet
Das Besondere: Sie benötigen zwei Microbits - einen im Roboter und einen als Fernsteuerung!
Planung: Die Zustandsmaschine
Erinnern Sie sich an die Zustandsmaschine aus der Buttons-Lektion? Genau dieses Konzept brauchen wir hier!
# Verschiedene Modi als Konstanten (Strings sind einfacher!)
MODE_OFF = "MODE:OFF"
MODE_FERNSTEUERUNG = "MODE:FERNSTEUERUNG"
MODE_TRACKER = "MODE:TRACKER"
# Aktueller Modus (starten im Fernsteuerungsmodus)
mode = MODE_FERNSTEUERUNGUnser Event-Loop muss dann je nach Modus unterschiedlich reagieren. Elegant ist es, den Modus direkt in der Loop-Bedingung zu nutzen:
while mode != MODE_OFF:
if mode == MODE_FERNSTEUERUNG:
# Auf Funksignale reagieren, Motoren steuern
elif mode == MODE_TRACKER:
# Helligkeitssensoren auslesen, automatisch fahren
# Wenn die Loop beendet wird, stoppen wir alle Motoren
maqueen.motor_stop_all()Challenge 1: Das Grundgerüst
Erstellen Sie zuerst die Grundstruktur für den Roboter (nicht die Fernsteuerung!):
Aufgaben:
- Importieren Sie die nötigen Module (
microbit,maqueen,radio)- Definieren Sie die drei Modus-Konstanten
- Setzen Sie die Radio-Gruppe (z.B.
radio.config(group=42))- Erstellen Sie einen Event-Loop mit
while mode != MODE_OFF- Bauen Sie die
if/elif-Struktur für die Modi (nur Fernsteuerung und Tracker, OFF ist ja die Loop-Bedingung!)- Zeigen Sie auf dem Display an, in welchem Modus Sie sich befinden (z.B. “F” für Fernsteuerung, “T” für Tracker)
- Nach der Loop stoppen Sie alle Motoren und zeigen “0” auf dem Display
Tipps:
- Starten Sie testweise im
MODE_FERNSTEUERUNG- die Loop sollte laufen und “F” anzeigen- Ändern Sie testweise zu
mode = MODE_OFF- die Loop sollte gar nicht starten- Vergessen Sie nicht
radio.on()am Anfang!
Mögliche Lösung Challenge 1
from microbit import * import maqueen import radio # Modi definieren MODE_OFF = "MODE:OFF" MODE_FERNSTEUERUNG = "MODE:FERNSTEUERUNG" MODE_TRACKER = "MODE:TRACKER" # Radio konfigurieren radio.config(group=42) radio.on() # Startzustand mode = MODE_FERNSTEUERUNG while mode != MODE_OFF: if mode == MODE_FERNSTEUERUNG: display.show("F") # Hier kommt die Fernsteuerung hin elif mode == MODE_TRACKER: display.show("T") # Hier kommt der Tracker hin # Programm wird beendet maqueen.motor_stop_all() display.show("0")
Challenge 2: Die Fernsteuerung programmieren
Jetzt programmieren Sie die Fernsteuerung auf dem zweiten Microbit. Auch sie braucht Modi!
Die Modi der Fernsteuerung:
- Modus “Fernsteuerung”: Tasten steuern die Bewegung des Roboters
- Modus “Tracker”: Der Roboter fährt automatisch, keine Tasten nötig
- Moduswechsel: Schütteln wechselt zwischen den Modi
- Ausschalten: Fernsteuerung umdrehen (face down) schaltet beide aus
Aufgaben:
- Erstellen Sie Modi für die Fernsteuerung (gleiche Konstanten wie beim Roboter)
- Schütteln (
accelerometer.was_gesture('shake')) wechselt zwischen MODE_FERNSTEUERUNG und MODE_TRACKER:
- Ändert den Modus der Fernsteuerung selbst
- Sendet den neuen Modus an den Roboter, um ihn zu synchronisieren (z.B.
radio.send(MODE_FERNSTEUERUNG))- Umdrehen (
accelerometer.was_gesture('face down')) sendet MODE_OFF und beendet beide Loops- Zeigen Sie den aktuellen Modus auf dem Display an (F oder T)
Im Fernsteuerungsmodus:
button_a.is_pressed() and button_b.is_pressed(): Sende “MOVE:FF” (vorwärts)button_a.is_pressed(): Sende “MOVE:LT” (left turn - nach links drehen)button_b.is_pressed(): Sende “MOVE:RT” (right turn - nach rechts drehen)- Keine Taste gedrückt: Sende “MOVE:00” (stopp)
Im Tracker-Modus:
- Keine Tasten-Steuerung nötig - der Roboter fährt automatisch!
Tipps:
- Beim Moduswechsel: Erst den eigenen Modus ändern, dann den Befehl senden
- Nutzen Sie
is_pressed()für kontinuierliche Bewegung (Taste gedrückt halten)- Da die Modi jetzt Strings sind, können Sie sie direkt mit
radio.send(mode)senden!- Testen Sie zuerst nur den Moduswechsel mit Schütteln
Mögliche Lösung Challenge 2
from microbit import * import radio # Modi definieren (gleich wie beim Roboter!) MODE_OFF = "MODE:OFF" MODE_FERNSTEUERUNG = "MODE:FERNSTEUERUNG" MODE_TRACKER = "MODE:TRACKER" # Radio konfigurieren radio.config(group=42) radio.on() # Startzustand mode = MODE_FERNSTEUERUNG while mode != MODE_OFF: # Moduswechsel mit Schütteln if accelerometer.was_gesture('shake'): # Zwischen den Modi wechseln if mode == MODE_FERNSTEUERUNG: mode = MODE_TRACKER else: mode = MODE_FERNSTEUERUNG # Roboter synchronisieren - einfach den Modus senden! radio.send(mode) sleep(500) # Kurz warten, damit nicht mehrfach gewechselt wird # Ausschalten durch Umdrehen if accelerometer.was_gesture('face down'): mode = MODE_OFF radio.send(mode) # Fernsteuerungsmodus: Tasten steuern Bewegung if mode == MODE_FERNSTEUERUNG: # Display aktualisieren display.show("F") # Befehle senden if button_a.is_pressed() and button_b.is_pressed(): radio.send("MOVE:FF") elif button_a.is_pressed(): radio.send("MOVE:LT") elif button_b.is_pressed(): radio.send("MOVE:RT") else: radio.send("MOVE:00") # Tracker-Modus: Roboter fährt automatisch elif mode == MODE_TRACKER: # Display aktualisieren display.show("T") # Keine Tasten-Steuerung nötig! sleep(100) # Fernsteuerung beendet display.show("0")
Challenge 3: Fernsteuerung im Roboter empfangen
Jetzt muss der Roboter die Funknachrichten empfangen und verarbeiten.
Aufgaben:
- Empfangen Sie Funknachrichten mit
radio.receive()- Prüfen Sie, ob eine Nachricht empfangen wurde (nicht
None)- Vergleichen Sie die Nachricht direkt mit den möglichen Befehlen:
- MODE_OFF, MODE_FERNSTEUERUNG, MODE_TRACKER → Modus wechseln
- “MOVE:FF”, “MOVE:LT”, “MOVE:RT”, “MOVE:00” → Motoren steuern (nur im Fernsteuerungsmodus)
Tipps:
- “MOVE:FF” bedeutet beide Motoren Full vorwärts (beide Tasten gedrückt)
- “MOVE:LT” (left turn) bedeutet auf der Stelle nach links drehen (linker Motor rückwärts, rechter vorwärts)
- “MOVE:RT” (right turn) bedeutet auf der Stelle nach rechts drehen (linker Motor vorwärts, rechter rückwärts)
- “MOVE:00” bedeutet Stopp (keine Taste gedrückt)
- Nutzen Sie
if nachricht == MODE_FERNSTEUERUNG:statt kompliziertem String-Splitting!
Mögliche Lösung Challenge 3
from microbit import * import maqueen import radio # Modi definieren MODE_OFF = "MODE:OFF" MODE_FERNSTEUERUNG = "MODE:FERNSTEUERUNG" MODE_TRACKER = "MODE:TRACKER" # Geschwindigkeiten FULL = 100 SLOW = 50 # Radio konfigurieren radio.config(group=42) radio.on() # Startzustand mode = MODE_FERNSTEUERUNG while mode != MODE_OFF: # Funknachrichten empfangen nachricht = radio.receive() # Moduswechsel - einfacher Vergleich mit den Konstanten! if nachricht == MODE_OFF: mode = MODE_OFF elif nachricht == MODE_FERNSTEUERUNG: mode = MODE_FERNSTEUERUNG elif nachricht == MODE_TRACKER: mode = MODE_TRACKER # Je nach Modus handeln if mode == MODE_FERNSTEUERUNG: display.show("F") # Bewegungsbefehle verarbeiten if nachricht == "MOVE:FF": # Beide Motoren vorwärts maqueen.set_motor(0, FULL) maqueen.set_motor(1, FULL) elif nachricht == "MOVE:LT": # Links drehen: linker Motor rückwärts, rechter vorwärts maqueen.set_motor(0, -FULL) maqueen.set_motor(1, FULL) elif nachricht == "MOVE:RT": # Rechts drehen: linker Motor vorwärts, rechter rückwärts maqueen.set_motor(0, FULL) maqueen.set_motor(1, -FULL) elif nachricht == "MOVE:00": # Stopp maqueen.motor_stop_all() elif mode == MODE_TRACKER: display.show("T") # Hier kommt der Tracker hin # Programm wird beendet maqueen.motor_stop_all() display.show("0")
Challenge 4: Tracker-Modus implementieren
Jetzt implementieren Sie den automatischen Tracker-Modus. Der Roboter soll einem schwarzen Fleck am Boden folgen - er fährt am Rand des Flecks entlang (links herum).
Aufgaben:
- Lesen Sie die Helligkeitssensoren aus:
maqueen.read_patrol(0)undmaqueen.read_patrol(1)- Implementieren Sie die Tracker-Logik für einen schwarzen Fleck:
left == 0 and right == 1(linker Sensor auf schwarz): Perfekt! Geradeaus fahrenleft == 1 and right == 1(beide auf hell): Zu weit rechts! Nach links drehenleft == 0 and right == 0(beide auf schwarz): Zu weit links! Nach rechts drehen- Im Fall
left == 1 and right == 0drehen wir uns weiterTipps:
- Der Roboter folgt dem Fleck “links herum” - der linke Sensor ist auf dem Fleck
- SLOW können Sie auf 0 setzen für schärfere Kurven (Drehen auf der Stelle)
- Bei “nach links drehen” ist der linke Motor langsam (SLOW), der rechte schnell (FULL)
- Bei “nach rechts drehen” ist der linke Motor schnell (FULL), der rechte langsam (SLOW)
Mögliche Lösung Challenge 4
Roboter-Code erweitern:
# Im Tracker-Modus diesen Code einfügen: elif mode == MODE_TRACKER: display.show("T") # Helligkeitssensoren auslesen left = maqueen.read_patrol(0) right = maqueen.read_patrol(1) # Tracker-Logik (0 = dunkel/schwarz, 1 = hell/weiss) # Der Roboter fährt links herum um den schwarzen Fleck if left == 0 and right == 1: # Perfekt! Linker Sensor auf schwarz → Geradeaus maqueen.set_motor(0, FULL) maqueen.set_motor(1, FULL) elif left == 0 and right == 0: # Beide auf schwarz → zu weit links! Nach rechts drehen maqueen.set_motor(0, FULL) maqueen.set_motor(1, SLOW) else: # Beide auf hell → zu weit rechts! Nach links drehen # Sie könnten auch schreiben: elif left == 1 and right == 1 , # aber so dreht der Roboter auch, wenn er verkehrt auf der Kante steht maqueen.set_motor(0, SLOW) maqueen.set_motor(1, FULL)
Challenge 5: Alles zusammenfügen und testen
Jetzt haben Sie alle Teile! Zeit für den Systemtest.
Test-Checkliste:
- ✅ Roboter und Fernsteuerung starten beide im Fernsteuerungsmodus (F angezeigt)
- ✅ Beide Tasten zusammen: Roboter fährt vorwärts (FF)
- ✅ Taste A alleine: Roboter dreht nach links (LT)
- ✅ Taste B alleine: Roboter dreht nach rechts (RT)
- ✅ Keine Taste: Roboter stoppt (00)
- ✅ Fernsteuerung schütteln: Beide wechseln synchron zum Tracker-Modus (T angezeigt)
- ✅ Im Tracker-Modus folgt der Roboter automatisch dem schwarzen Fleck (links herum)
- ✅ Nochmal schütteln: Beide wechseln zurück zum Fernsteuerungsmodus
- ✅ Fernsteuerung umdrehen (face down): Beide beenden ihre Loops, Display zeigt “0”, alle Motoren stoppen
Fehlersuche:
- Funktioniert die Fernsteuerung nicht? → Prüfen Sie die Radio-Gruppe auf beiden Geräten
- Modi werden nicht synchronisiert? → Prüfen Sie, ob
radio.send(mode)korrekt verwendet wird- Roboter dreht in falsche Richtung? → Prüfen Sie die Motor-Nummern (0 = links, 1 = rechts) und Vorzeichen
- Schütteln wechselt mehrfach? → Das
sleep(500)nach dem Moduswechsel verhindert Doppel-Wechsel- Roboter reagiert nicht auf Tracker? → Testen Sie die Helligkeitssensoren einzeln (display.show(left) und display.show(right))
- Roboter fährt vom Fleck weg? → Prüfen Sie die Logik: left == 0 bedeutet “linker Sensor auf schwarz”
- Umdrehen schaltet nicht aus? → Prüfen Sie die Schreibweise:
'face down'(mit Leerzeichen!)
Bonus-Challenge: Verbesserungen
Ihr Roboter funktioniert? Perfekt! Jetzt können Sie ihn noch verbessern:
- Rückwärtsfahren hinzufügen: Wenn man im Fernsteuerungsmodus beide Tasten gedrückt hält UND den Microbit nach unten neigt, fährt der Roboter rückwärts
- Geschwindigkeitsregelung: Im Tracker-Modus können Sie mit Taste A/B die Geschwindigkeit zwischen verschiedenen Stufen wechseln
- LED-Feedback auf Roboter: Nutzen Sie die LEDs des Maqueen (
maqueen.set_led()) um den aktuellen Modus anzuzeigen- Automatischer Moduswechsel: Wenn im Tracker-Modus lange keine Linie gefunden wird (beide Sensoren = 1), wechseln Sie automatisch zur Fernsteuerung
- Sanfteres Drehen: Statt auf der Stelle zu drehen (LT/RT), könnten Sie mit verschiedenen Geschwindigkeiten sanftere Kurven fahren
- Code aufräumen: Lagern Sie die Tracker-Logik in eine eigene Funktion
folge_linie()aus (siehe Linienfinder-Lektion)- Notfall-Stop: Fügen Sie einen Notfall-Stop hinzu - wenn man die Fernsteuerung stark schüttelt (3x hintereinander), stoppen sofort alle Motoren
- Zweite Fahrtrichtung: Als Herausforderung können Sie einen zweiten Tracker-Modus hinzufügen, der rechts herum um den Fleck fährt
Vollständiges Beispiel: Roboter-Code
from microbit import * import maqueen import radio # Modi definieren MODE_OFF = "MODE:OFF" MODE_FERNSTEUERUNG = "MODE:FERNSTEUERUNG" MODE_TRACKER = "MODE:TRACKER" # Geschwindigkeiten FULL = 100 SLOW = 0 # 0 für scharfe Kurven, oder 50 für sanftere Kurven # Radio konfigurieren radio.config(group=42) radio.on() # Startzustand mode = MODE_FERNSTEUERUNG while mode != MODE_OFF: # Funknachrichten empfangen nachricht = radio.receive() # Moduswechsel if nachricht == MODE_OFF: mode = MODE_OFF elif nachricht == MODE_FERNSTEUERUNG: mode = MODE_FERNSTEUERUNG elif nachricht == MODE_TRACKER: mode = MODE_TRACKER # Je nach Modus handeln if mode == MODE_FERNSTEUERUNG: display.show("F") # Bewegungsbefehle verarbeiten if nachricht == "MOVE:FF": maqueen.set_motor(0, FULL) maqueen.set_motor(1, FULL) elif nachricht == "MOVE:LT": maqueen.set_motor(0, -FULL) maqueen.set_motor(1, FULL) elif nachricht == "MOVE:RT": maqueen.set_motor(0, FULL) maqueen.set_motor(1, -FULL) elif nachricht == "MOVE:00": maqueen.motor_stop_all() elif mode == MODE_TRACKER: display.show("T") # Helligkeitssensoren auslesen left = maqueen.read_patrol(0) right = maqueen.read_patrol(1) # Tracker-Logik (0 = dunkel/schwarz, 1 = hell/weiss) # Der Roboter fährt links herum um den schwarzen Fleck if left == 0 and right == 1: # Perfekt! Linker Sensor auf schwarz → Geradeaus maqueen.set_motor(0, FULL) maqueen.set_motor(1, FULL) elif left == 0 and right == 0: # Beide auf schwarz → zu weit links! Nach rechts drehen maqueen.set_motor(0, FULL) maqueen.set_motor(1, SLOW) else: # Beide auf hell → zu weit rechts! Nach links drehen # Sie könnten auch schreiben: elif left == 1 and right == 1 , # aber so dreht der Roboter auch, wenn er verkehrt auf der Kante steht maqueen.set_motor(0, SLOW) maqueen.set_motor(1, FULL) # Programm wird beendet maqueen.motor_stop_all() display.show("0")
Vollständiges Beispiel: Fernsteuerungs-Code
from microbit import * import radio # Modi definieren MODE_OFF = "MODE:OFF" MODE_FERNSTEUERUNG = "MODE:FERNSTEUERUNG" MODE_TRACKER = "MODE:TRACKER" # Radio konfigurieren radio.config(group=42) radio.on() # Startzustand mode = MODE_FERNSTEUERUNG while mode != MODE_OFF: # Moduswechsel mit Schütteln if accelerometer.was_gesture('shake'): if mode == MODE_FERNSTEUERUNG: mode = MODE_TRACKER else: mode = MODE_FERNSTEUERUNG # Einfach den Modus senden! radio.send(mode) sleep(500) # Ausschalten durch Umdrehen if accelerometer.was_gesture('face down'): mode = MODE_OFF radio.send(mode) # Display aktualisieren if mode == MODE_FERNSTEUERUNG: display.show("F") elif mode == MODE_TRACKER: display.show("T") # Fernsteuerungsmodus: Tasten steuern Bewegung if mode == MODE_FERNSTEUERUNG: if button_a.is_pressed() and button_b.is_pressed(): radio.send("MOVE:FF") elif button_a.is_pressed(): radio.send("MOVE:LT") elif button_b.is_pressed(): radio.send("MOVE:RT") else: radio.send("MOVE:00") # Tracker-Modus: Roboter fährt automatisch # (keine Tasten-Steuerung nötig) sleep(100) # Fernsteuerung beendet display.show("0")
Reflexion
Sie haben jetzt ein komplexes System gebaut, das verschiedene Konzepte elegant kombiniert:
- Event-Loop als Herzstück des Programms
- Zustandsmaschine zur Verwaltung verschiedener Modi
- Radio-Kommunikation zwischen zwei Geräten
- Sensoren zur Umgebungswahrnehmung
- Motorsteuerung für präzise Bewegungen
Das ist genau so, wie echte Roboter und autonome Systeme funktionieren! Sie haben die Grundlagen der Robotik und der eingebetteten Systeme kennengelernt.