State Machine
Wenn ein Roboter autonom durch ein Labyrinth fahren soll, muss er ständig Entscheidungen treffen: Soll er geradeaus fahren? Abbiegen? Stoppen? Und was passiert nach einer Drehung?
Ohne eine klare Struktur landet man schnell bei einem Chaos aus if-Bedingungen, das schwer zu lesen und noch schwerer zu erweitern ist.
Eine State Machine löst dieses Problem elegant.
Was ist eine State Machine?
Abschnitt betitelt „Was ist eine State Machine?“Eine State Machine (deutsch: Zustandsautomat) beschreibt ein System, das sich immer in genau einem Zustand befindet. Auf bestimmte Ereignisse (z.B. ein Sensor schlägt an) hin wechselt das System in einen anderen Zustand.
Die drei Kernbegriffe:
| Begriff | Bedeutung | Beispiel |
|---|---|---|
| Zustand (State) | Was der Roboter gerade tut | State.DRIVE, State.TURN_LEFT, State.STOP |
| Ereignis (Event) | Was einen Zustandswechsel auslöst | Wand erkannt, Drehung abgeschlossen |
| Übergang (Transition) | Der Wechsel von einem Zustand in einen anderen | State.DRIVE → State.TURN_LEFT |
Ein einfaches Beispiel
Abschnitt betitelt „Ein einfaches Beispiel“Stellen Sie sich einen Roboter vor, der durch einen Korridor fährt:
- Er fährt geradeaus, solange kein Hindernis vor ihm ist.
- Erkennt er eine Wand, stoppt er.
- Nach dem Stopp dreht er sich nach links.
- Danach fährt er wieder geradeaus.
Dieser Ablauf lässt sich als Diagramm darstellen:
stateDiagram-v2
[*] --> DRIVE
DRIVE --> STOP : Wand erkannt
STOP --> TURN_LEFT : gestoppt
TURN_LEFT --> DRIVE : Drehung abgeschlossen
Jeder Kasten ist ein Zustand. Die Pfeile zeigen, wann und warum das System in den nächsten Zustand wechselt.
Warum keine langen if-Ketten?
Abschnitt betitelt „Warum keine langen if-Ketten?“Ohne State Machine könnte der Code so aussehen:
# ❌ Schwer zu lesen und zu erweiternwhile True: distance = sensor.distance_cm() if distance > 15: motor_left.speed = 40000 motor_right.speed = 40000 else: motor_left.speed = 0 motor_right.speed = 0 time.sleep(0.5) # Drehen... aber wie lange? Und was dann? motor_left.speed = -30000 motor_right.speed = 30000 time.sleep(1)Das Problem: Der Code ist linear. Je mehr Situationen dazukommen, desto verschachtelter und unübersichtlicher wird er.
State Machine in Python umsetzen
Abschnitt betitelt „State Machine in Python umsetzen“Eine State Machine lässt sich in Python sehr sauber mit einer Variable für den aktuellen Zustand und einer Methode pro Zustand umsetzen.
Statt einfacher Strings verwenden wir eine Klasse mit Ganzzahl-Konstanten, um die Zustände zu definieren. Das hat zwei Vorteile: Tippfehler fallen sofort auf, und alle Zustände sind an einem zentralen Ort definiert.
from components.motor import DCMotorfrom components.sensor import UltrasonicSensorfrom config import LEFT_MOTOR_PINS, RIGHT_MOTOR_PINS, FRONT_SENSOR_PINSimport time
class State: DRIVE = 0 STOP = 1 TURN_LEFT = 2
class Controller: def __init__(self): self.left_motor = DCMotor(*LEFT_MOTOR_PINS) self.right_motor = DCMotor(*RIGHT_MOTOR_PINS) self.sensor = UltrasonicSensor(*FRONT_SENSOR_PINS)
self.state = State.DRIVE # Startzustand
def run(self): while True: self._update()
def _update(self): """Wählt basierend auf dem aktuellen Zustand die passende Methode.""" if self.state == State.DRIVE: self._drive() elif self.state == State.STOP: self._stop() elif self.state == State.TURN_LEFT: self._turn_left()
# --- Zustände ---
def _drive(self): distance = self.sensor.distance_cm() if distance < 15: self.state = State.STOP # Übergang: Wand erkannt else: self.left_motor.speed = 40000 self.right_motor.speed = 40000
def _stop(self): self.left_motor.stop() self.right_motor.stop() time.sleep(0.3) self.state = State.TURN_LEFT # Übergang: gestoppt → drehen
def _turn_left(self): self.left_motor.speed = -30000 self.right_motor.speed = 30000 time.sleep(0.8) # Drehen für 0.8 Sekunden self.left_motor.stop() self.right_motor.stop() self.state = State.DRIVE # Übergang: Drehung abgeschlossenZustände im Überblick behalten
Abschnitt betitelt „Zustände im Überblick behalten“Je komplexer der Roboter wird, desto mehr Zustände kommen dazu. Es hilft, das Diagramm von Anfang an mitzupflegen. Für einen vollständigen Micromouse-Algorithmus könnte das so aussehen:
stateDiagram-v2
[*] --> DRIVE
DRIVE --> STOP : Wand vorne
STOP --> TURN_LEFT : kein Weg rechts
STOP --> TURN_RIGHT : Weg rechts frei
TURN_LEFT --> DRIVE : Drehung fertig
TURN_RIGHT --> DRIVE : Drehung fertig
DRIVE --> FINISH : Ziel erreicht
FINISH --> [*]
Verbindung zur Code-Struktur
Abschnitt betitelt „Verbindung zur Code-Struktur“Die State Machine lebt vollständig in controller.py. Die anderen Module (components/, config.py) wissen nichts davon – sie stellen nur ihre Funktionen bereit.
Kontrollfragen
Abschnitt betitelt „Kontrollfragen“Teste dein Wissen
Abschnitt betitelt „Teste dein Wissen“-
Was beschreibt ein Zustand in einer State Machine?
-
Was löst einen Zustandswechsel aus?
-
Wie viele Zustände kann eine State Machine gleichzeitig aktiv haben?
-
Welcher Vorteil ergibt sich daraus, für jeden Zustand eine eigene Methode zu schreiben?
- Ich kann erklären, was ein Zustand, ein Ereignis und ein Übergang sind.
- Ich kann ein einfaches State-Machine-Diagramm für meinen Roboter zeichnen.