Benutzer-Werkzeuge

Webseiten-Werkzeuge


hello_mbot_programmorganisation

Hello mBot Programmorganisation

Eine professionelle Programmstruktur für den Arduino (mBot) sollte modular, erweiterbar und gut wartbar sein. Ich verwende hier eine Finite-State-Machine (FSM), um verschiedene Abläufe sauber steuern zu können. Die Steuerung erfolgt hier mit Hilfe der Infrarot-Fernbedienung. Alternativ kann man natürlich auch Bluetooth verwenden. Dies würde auch komplexere Abläufe ermöglichen, da man beispielsweise einen Rechner mit einem Python-Programm als Steuerung verwenden könnte. Zusätzlich (siehe Beispiel) kann der eingebaute Taster genutzt werden, um einfache Befehle direkt am mBot auszuführen.

Vorteile einer geordneten Programmstruktur:

  • Modularität: Jeder Modus ist in einer eigenen Funktion gekapselt.
  • Erweiterbarkeit: Neue Modi oder Befehle können problemlos hinzugefügt werden.
  • Wartbarkeit: Durch die klare Zustandsaufteilung ist der Code auch bei Änderungen leicht nachvollziehbar.
  • Flexibilität: Unterschiedliche Abläufe (wie Kalibrierung, Labyrinth oder Stopp) können unabhängig voneinander optimiert und getestet werden.

Finite State Machine (FSM) ist ein Modell mit einer endlichen Anzahl von Zuständen, das durch Eingaben zwischen diesen wechselt. Sie besteht aus Zuständen, Übergängen und einem Startzustand. FSMs werden in der Informatik und Automatisierung zur Steuerung von Abläufen genutzt.

Ein endlicher Automat (Finite State Machine, FSM) ist ein Modell zur Darstellung von Zuständen und deren Übergängen basierend auf Eingaben.
Die Abbildung zeigt eine FSM mit drei Zuständen (S1, S2, S3) und Übergängen, die durch Eingaben (0 oder 1) gesteuert werden. Beispielsweise wechselt die FSM bei 0 von S1 nach S3, während sie bei 1 von S1 nach S2 übergeht.

Grundstrukur

enum State { 
  STATE_A,
  STATE_B,
  STATE_C
};
State state = STATE_A;

void setup() {
  // Initialisierung 
}

void loop() {
  // step: command
  byte cmd = read(); // Funktion, die IR-Befehle einliest

  // step: state - Befehlsverarbeitungund ggf. Zustand wechseln
  state  = decode(cmd);
 
  // step: action 
  switch (state) {   
    case STATE_A:
         actionA();
         break;
    case STATE_B:
         actionB();
         break;
    case STATE_C:
         actionC();
         break;
  }
}
// ...Implementierung der einzelnen Routinen

Die FSM wird hier an mehreren Punkten deutlich:

  • Feste Zustände
    • Die Enumeration definiert eine endliche Menge von Zuständen.
  • Zustandsübergänge
    • Die Funktion decode(cmd) verarbeitet die eingehenden Befehle und ändert den aktuellen Zustand.
  • Zustandsbasierte Aktionen
    • Der switch-Block im loop() entscheidet, welche Aktion ausgeführt wird, basierend auf dem aktuellen Zustand.

Die Methoden (actions) sollten möglichst nicht blockierend sein, da blockierende Aufrufe den Zustandswechsel verzögern und das System an der schnellen Reaktion auf externe Ereignisse hindern. Gerade in zeitkritischen Anwendungen sorgt ein blockierender Zustand dafür, dass Sensorwerte oder Eingaben zu spät verarbeitet werden, was die Zuverlässigkeit und Leistung der gesamten Anwendung beeinträchtigen kann.

Beispiel

Der mBot soll in diesem Beispiel die Zustände der LEDs über einen Taster ändern. Bei jedem Tastendruck wechselt die LED zyklisch zwischen drei Zuständen: aus, rot und grün. Die Steuerung erfolgt über eine einfache Zustandsmaschine (FSM), die den Tastereingang auswertet und entsprechend die LED-Farbe setzt.

  • STATE_OFF → LED aus
  • STATE_REDLED rot
  • STATE_GREENLED grün

Quellcode (engl. Sourcecode)

Listing 1:MinimalesProgramm.ino

#include <MeMCore.h>

MeRGBLed led(0, 2);   // must be fixed!
int PIN_BUTTON = 7;   // must be fixed!
int threshold  = 500; // Analoger Schwellenwert!
int buttonCount;


enum State {
  STATE_OFF,
  STATE_RED,
  STATE_GREEN

};
State state = STATE_OFF;

void setup() {
  led.setpin(13);
  pinMode(PIN_BUTTON, INPUT);
  buttonCount = 0;
}

void loop() {
  // step: command
  int cmd = read();

  // step: state 
  state  = decode(cmd);

  // step: action
  switch (state) {
    case STATE_RED:
      actionRed();
      break;
    case STATE_GREEN:
      actionGreen();
      break;
    case STATE_OFF:
      actionOff();
      break;
  }
}


/*
 *   Funktionen
 */


bool isButtonPressed() {
  static bool buttonPressed = false;
  int value = analogRead(PIN_BUTTON);

  if (value < threshold) {
    if (!buttonPressed) {
      buttonPressed = true;
      return true;
    }
  } else {
    buttonPressed = false; // Button wurde losgelassen
  }
  return false;

}

int read() {
  if ( isButtonPressed() )
    buttonCount += 1;

  if (buttonCount > 2)
    buttonCount = 0;

  return buttonCount;
}


State decode(int cmd) {
  switch (cmd) {
    case 1: return STATE_RED;
    case 2: return STATE_GREEN;
  }
  return STATE_OFF;
}

void actionRed() {
  led.setColorAt(1, 255, 0, 0);
  led.setColorAt(0, 255, 0, 0);
  led.show();
}

void actionGreen() {
  led.setColorAt(1, 0, 255, 0);
  led.setColorAt(0, 0, 255, 0);
  led.show();
}

void actionOff() {
  led.setColorAt(1, 0, 0, 0);
  led.setColorAt(0, 0, 0, 0);
  led.show();
}

Erklärungen zum Quellcode

  1. Der Taster wird über analogRead(PIN_BUTTON) ausgelesen.
  2. Die Funktion isButtonPressed() erkennt den Tastendruck und verhindert mehrfaches Zählen (Entprellung).
  3. Die Funktion read() zählt die Tasterbetätigungen und wechselt durch die Zustände:
    1. OFF → RED → GREEN → OFF.
  4. Die Funktion decode(cmd) wandelt den Zählerwert in einen State um.
  5. Die entsprechenden LED-Funktionen setzen die LED-Farbe je nach Zustand.

Das Programm ermöglicht eine einfache Steuerung einer LED über einen Taster mit einer Zustandsmaschine.

hello_mbot_programmorganisation.txt · Zuletzt geändert: 2025/02/18 11:21 von torsten.roehl