Fragen zu Programmaufbau mit state machine für Roboter

Hallo liebe Tüftelgemeinde :slight_smile:

Ich werkel gerade an einem kleinen Roboterprojekt und habe dazu ein paar Fragen, bei denen ihr mir vielleicht helfen könnt...
Zunächst mal zum Projekt: Es geht um einen Roboter, der (irgendwann mal) in einem Kuhstall eine bestimmte Route abfahren soll.
Der Roboter hat 2 getrennt voneinander angetriebene Räder. In jedem der beiden Antriebsstränge kann jeweils über einen kapazitiven Sensor die Zähne eines Kettenrades gezählt werden, sodass darüber Geradeaus- und Kurvenfahren geregelt werden können.
Als zusätzliche Hilfe hat der Roboter auf der rechten Seite ein Tastrad, mit einem Taster kann darüber abgefragt werden ob sich der Robotor genau an einer Kante entlang fährt. Darüber hinaus soll es vorne noch eine bewegliche Stoßstange geben (ebenfalls mit Taster), um Kollisionen mit festen und beweglichen Hindernissen zu vermeiden.
Das ganzen Abfrage der Sensoren und die Ablaufsteuerung soll über ein Arduino Uno Board erfolgen. Habe mir überlegt die Steuerung mit Hilfe einer state machine zu realisieren, eine festgelegte Route ergibt sich aus verschiedenen Fahrmodi hintereinander, z.B.

  1. 5m geradeaus
  2. Linksdrehen um 90°
  3. 10m an der rechten Kante entlang fahren
  4. Linksdrehen um 45°
  5. 15m an der rechten Kante entlang fahren
  6. ...

Die Fahrmodi sind dabei immer die gleichen (Vorwärts, Rückwärts, Rechtsdrehung, Linksdrehung, Vorwärts an rechter Kante, ...), nur immer mit unterschiedlichen Vorgaben bis der Status "abgearbeitet" ist.

Jetzt meine Frage: gibt es eine schönere Programmierung, als die verschiedenen Routenbestandteile in der state machine hart hintereinander zu schreiben mit den fixen Vorgaben? Ist eine state machine überhaupt für meinen Zweck geeignet, oder könnte man das auf eine andere Art viel schöner (und flexibler) lösen?

Stehe da gerade etwas auf dem Schlauch, vielleicht hat jemand von euch schon mal eine vergleichbare Fragestellung gehabt (habe noch nicht angefangen die state machine zu programmieren, wollte mich nicht sofort verhaspeln :wink: )

Bin gespannt auf eure Ideen und Anmerkungen :slight_smile:

Viele Grüße

WALL-E:
Bin gespannt auf ... Anmerkungen :slight_smile:

Meiner Meinung nach ist ein endlicher Automat ideal für derlei Dinge. Da Du zu wissen scheinst, wovon Du sprichst, wird Dir mein Geschreibsel dazu wahrscheinlich nichts Neues bringen.

Gruß

Gregor

Flexibler und übersichtlicher wird so ein Programm, wenn man einen Interpreter schreibt, der eine Liste von Befehlen abarbeitet. Dann können Listen später auch von Serial, EEPROM oder SD-Karte geladen werden.

Insgesamt kommt es drauf an, was genau der Automat machen muß, d.h. auf welche fertigen Funktionen er zugreifen kann. Ist z.B. eine Drehung bereits so codiert, daß man mit robot.turn(45) eine Drehung ausführen lassen kann, oder muß der Automat die Drehung starten und bei 45° wieder stoppen?

DrDiettrich:
Flexibler und übersichtlicher wird so ein Programm, wenn man einen Interpreter schreibt, der eine Liste von Befehlen abarbeitet. Dann können Listen später auch von Serial, EEPROM oder SD-Karte geladen werden.

+1

Ich würde für jede primitive Aktion eine eigene Statemachine vorschlagen.

Whandall:
Ich würde für jede primitive Aktion eine eigene Statemachine vorschlagen.

Frage: wie sollen so viele Automaten am Laufen gehalten werden?

Wenn jeder Automat erst anhält (zurück ins aufrufende Programm), wenn seine Aufgabe erfüllt ist, dann ist der Controller so lange blockiert, und das möchte man eigentlich nicht. Dann könnte z.B. "am rechten Rand entlang" nicht die Automaten für gerade und Kurvenfahrten benutzen, sondern müßte alles nochmal selbst implementieren.

Üblicherweise wird die low-level Programmierung in eine (Bibliotheks-)Klasse gepackt, welche die Abläufe steuert, einschließlich des Timings über Interrupts - dann läuft alles ohne regelmäßige Aufrufe der gerade aktiven Funktion im Anwendungsprogramm. Im Detail kommt es dann z.B. darauf an, ob Stepper oder DC Motoren benutzt werden, und welche Bibliotheken dafür.

DrDiettrich:
Frage: wie sollen so viele Automaten am Laufen gehalten werden?

Indem sie blockierungsfrei programmiert werden, wie es sich gehört.

Wenn jeder Automat erst anhält (zurück ins aufrufende Programm), wenn seine Aufgabe erfüllt ist

Ich kann ja den Denkansatz "endlicher Automat" oder nur den Namen(?) eigentlich nicht leiden (Nachtwächter mit ToDo-Liste und Merkzetteln ist deutlich netter), aber das im Zitat ist doch wohl keiner? Jedenfalls keiner, von dem mehr als einer je Controller existieren kann.

Hallo zusammen,

vielen Dank für eure Anmerkungen und eure Unterstützung! Habe vergessen zu schreiben, dass die Basis für den Roboter (also Motoren, Akkus und Steuergerät incl. Joystick) aktuell von einem ausrangierten elektr. Rollstuhl kommen :smiley: Zur Steuerung habe ich geplant die Spannungssignale des Joystick mit dem Arduino zu simmulieren. Das schien mir im ersten Moment "sicherer" als Anfänger mit Motor Shields für die 24V Motoren rumzuhantieren :wink:

@ gregorss: vielen Dank für deinen link. Es ist ja eine viel schönerer Ansatz, die einzelnen Ablaufschritte (bzw. Fahrmodi) für eine Route hintereinander in ein Array zu schreiben und dann für jeden Fahrmodus nur einen Zustand zu programmieren. Die Parameter für jeden Schritt (z.B. 5m, 90° Drehung, ...) würde ich bei dieser Weise dann in einen/mehrere weitere Arrays schreiben?

@ DrDiettrich: habe leider (noch) keine Ahnung was ein Interpreter ist und wie er genau funktioniert, es hört sich auf alle Fälle sehr professionell (und vermutlich auch entsprechend schwierig) an - zumindest wenn ich mir den Wikipedia Artikel durchlese... Kennst du da vielleicht ein einfaches Beispiel Script durch das ich mich mal durcharbeiten könnte?
Wichtig sind als Anfänger ja auch immer die kleinen Erfolgserlebnisse zwischendurch :wink:

WALL-E:
@ gregorss: ... Die Parameter für jeden Schritt (z.B. 5m, 90° Drehung, ...) würde ich bei dieser Weise dann in einen/mehrere weitere Arrays schreiben?

Das ist im Prinzip genau das, was mir dazu einfällt.

Was ein Interpreter ist: Ein Programm, das Befehle entgegennehmen und entsprechend agieren kann. Ich finde, dass das für den gedachten Einsatzzweck „oversized“ wäre. Mein Leitsatz heißt in solchen Fällen „keep it simple, stupid“ (KISS).

Gruß

Gregor

gregorss:
Ich finde, dass das für den gedachten Einsatzzweck „oversized“ wäre.

Das sehe ich anders.

Eine Text-basierende Methode (sprich Mini-Interpreter) ist wesentlich einfacher interaktiv zu testen und zu debuggen.

Eine simple Befehlssyntax (z.B. "m40" für 40mm vorwärts) hält den Interpreter wirklich klein.

Die Befehlsequenzen lassen sich lesen und mit jedem Editor erstellen.

Whandall:
Das sehe ich anders.
Eine Text-basierende Methode (sprich Mini-Interpreter) ist wesentlich einfacher interaktiv zu testen und zu debuggen.
Eine simple Befehlssyntax (z.B. "m40" für 40mm vorwärts) hält den Interpreter wirklich klein.
Die Befehlsequenzen lassen sich lesen und mit jedem Editor erstellen.

Ja, da hast Du recht. Was ich meinte ist, dass es für einen „Durchschnitts-Anwender“ derlei Dinge einen deutlich höheren Aufwand bedeutet, sowas zu programmieren. „In FSM zu denken“, fällt meiner Erfahrung nach den meisten Leuten leichter.

BTW: Einen Heidenspaß habe ich mir mal gegeben, als ich einen Brainfuck-Interpreter als Bash-Shellskript programmiert habe. Schade, dass es http://www.99bottles.net/ nicht mehr in der Form gibt, in der ich das kennengelernt habe (als Sammlung verschiedener Umsetzungen (in verschiedenen Programmiersprachen) eines Algorithmus, der den Text eines Sauf-Lieds ausgibt. Wirklich witzig fand ich z. B. „Whitespace“ und „Piet“.

Gruß

Gregor

Interessant wird so eine Befehlssyntax durch die möglichen Parameter:

m40 g20 // fahre 40 mit Geschwindigkeit 20, was auch immer für Einheiten
k90 r0 br // Kurve rechts 90° mit Radius 0, Blinker rechts

Ob ein Interpreter in einen UNO paßt, wage ich nicht abzuschätzen.

Die kann man problemlos mit strtok/strtok_r zerlegen und hat die Daten.

Gruß Tommy

Ich fürchte der "Durchschnitts-Anwender" ist schon von der Robot-Komplexität überfordert.

"20 cm an der Kante entlang" ist schon eine Herausforderung
(nach der Klärung von "welche Kante ist die Kante" und "in welche Richtung geht entlang").

Ich fürchte der "Durchschnitts-Anwender" ist schon von der Robot-Komplexität überfordert.

Ich fürchte auch ich sollte erst mal klein anfangen :wink: Da ich aber wissbegierig bin würd ich mich freuen wenn mir jemand eine gute Seite oder Beispielcode empfehlen kann - dann kann ich mich da mal einlesen und anfangen mit dem Arduino zu testen...

Ich habe mich nur auf die Syntax bezogen. Dass da noch mehr Stolperstellen warten, ist klar.

z.B. auch wie gehe ich mit Hindernissen um? Stoppen und auf Personal warten?

Gruß Tommy

WALL-E, du hast in deinem Eingangsposting deinen Rover recht konkret beschrieben,
gibt es den schon, oder planst du so konkret?

WALL-E:
Ich fürchte auch ich sollte erst mal klein anfangen :wink: Da ich aber wissbegierig bin würd ich mich freuen wenn mir jemand eine gute Seite oder Beispielcode empfehlen kann - dann kann ich mich da mal einlesen und anfangen mit dem Arduino zu testen...

Hm. Als erstes Häppchen taugt vielleicht der entsprechende Wikipedia-Artikel. Und als leichtesten Programmiereinstieg würde ich Brainfuck empfehlen. Die dort verwendeten (lediglich acht) Befehle lassen sich zumindest zum Teil sehr leicht umsetzen.
Haarig kann es dann werden, wenn Schleifen-Konstrukte umgesetzt werden sollen. Spätestens dann stolpert man erstmalig über den Stack. Ich habe den Aufwand für dessen Programmierung/Konzeption damals unterschätzt.

Gruß

Gregor

agmue:
Ob ein Interpreter in einen UNO paßt, wage ich nicht abzuschätzen.

Wenn man es richtig macht, ist das eine der kompaktesten Arten zu programmieren.
Man sollte es evtl. nicht Interpreter nennen um weder Ängste noch Größenwahn-Ideen zu erzeugen.
Hat schon Whandall (21:05) angedeutet.

Sollte einerseits für Menschen les- und schreibbar sein, andererseits einfachste Auswertung erlauben.

Und eine eigene universelle Programmiersprache soll es, denke ich, auch nicht werden.
Kommando-Buchstabe + Parameterwert.

Man muss halt sowohl "vorwärts 100 Einheiten" und "vorwärts bis Sensor anspricht" können...

So eine Kommando-Schnittstelle ist auch sehr praktisch um das Gerät via Bluetooth/NRF/Virtualwire/...
aus der Ferne zu kontrollieren/parametrisieren/bedienen.

sh-lite sozusagen. :wink: