PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Warum eine "Finite State Machine"?



benx
10.01.2009, 20:41
Hallo zusammen,

ich weiß das meine Frage nicht so recht in das RP6-Forum rein passt, aber da sich einige Beispiele des RP6 auf eine Finite State Machine (FSM) beziehen, hoffe ich trotzdem hier nicht ganz falsch zu sein.

Ich habe mich ein wenig mit dem RP6 beschäftigt und auch ein erstes Programm geschrieben welches den Robo einfach gerade aus fahren lässt. Auf Hindernisse in Fahrtrichtung (per ACS und Bumper) wird reagiert und ausgewichen. Dies habe ich ohne Programmierung einer FSM gelöst. In der Dokumentation wird erwähnt das man für komplexere Verhalten aber eine solche FSM benutzten sollte. Mein Problem ist nun das ich nicht so recht verstehe warum. Was bringt das für Vorteile? Ich habe mich ein wenig über google in das Thema FSM bzw. endliche Automaten versucht einzulesen, aber warum das jetzt so gut sein soll verstehe ich immer noch nicht.

Vielleicht kann mir ja jemand mal auf die Sprünge helfen. Mein Progi habe ich mal dabei gelegt, vielleicht möchte sich das jemand mal anschauen.

Besten Dank für eure Hilfe... :-)

mfg
ben



/*
RP6 fährt autonom. Erster Versuch. ACS und Bumper werden nicht per Event Handler angesprochen,
sondern direkt in der main loop(). Die Eventhandler haben das eigentliche moven stets unterbrochen.
Dadurch fuhr der RP6 meist im Kreis. Klappt so jetzt besser...

10.01.2009
*/

#include "RP6RobotBaseLib.h" // Always needs to be included!

// prüft den Akku und löst ein Blinklicht aus, wenn die Spannung < ca. 5,5 V ist
// und stopp vorübergehend die Fahrt
void chkAccu (void) {
static uint8_t x=1; // AccuChk-Zähler (static bedeutet, das diese Var. den Wert auch ausserhalb der Funktion behält)
uint16_t ubat = readADC(ADC_BAT);
if (ubat < 550) {
if (x >= 4) {
writeString_P("!!! Akkuspannung gering = ");
writeInteger(ubat, DEC);
writeString_P("\n");
uint8_t i=1;
uint8_t runningLight = 1;

while (i < 50) {
setLEDs(runningLight);
runningLight <<= 1; // bit shift nach links 0b000001, 0b000010, etc.

if(runningLight > 32)
runningLight = 1; // starte wieder bei StatusLED1

i++;
mSleep(100); // delay 100ms = 0.1s
}
setLEDs(0b000000); // alle LEDs aus
x=1;
}
x++;
}
}

// prüft den Motorstrom; der Motorstrom ist hoch, wenn der Antrieb z.b. aufgrund eines Hindernisses
// blockiert wird
void chkMotor(void) {
static uint8_t i=1; // MotorChk-Zähler
if (adcMotorCurrentLeft > 100 || adcMotorCurrentRight > 100) {
writeString_P("\n");
writeString_P("!!! Motorstrom ist zu hoch links: ");
writeInteger(adcMotorCurrentLeft, DEC);
writeString_P(" rechts: ");
writeInteger(adcMotorCurrentRight, DEC);
writeString_P("\n");
if (i >= 3) {
setLEDs(0b110110); // alle roten LEDs an
move(50,BWD,DIST_CM(30),true);
rotate(50,LEFT,180,true);
// sind die Motoren immer noch geblockt ?? wenn ja, versuchen wir es mal 90 Grad links herrum...
if (adcMotorCurrentLeft > 100 || adcMotorCurrentRight > 100) {
rotate(50,LEFT,90,true);
}
setLEDs(0b000000); // alle LEDs aus
i=0;
}
i++;
}
}



// Hindernissen ausweichen
void avoid(void) {
// ACS-Abfrage
if(obstacle_right && obstacle_left) {// left AND right sensor have detected something...
writeString_P("ACS -> middle\n");
setLEDs(0b100100);
move(50,BWD,DIST_CM(30),true);
rotate(30,LEFT,30,true);
setLEDs(0b000000);
} else if (obstacle_left) { // Left "sensor" has detected something
writeString_P("ACS -> left\n");
setLEDs(0b010000);
rotate(30,RIGHT,30,true);
setLEDs(0b000000);
} else if (obstacle_right) {// Right "sensor" has detected something
writeString_P("ACS -> right\n");
setLEDs(0b000100);
rotate(30,LEFT,30,true);
setLEDs(0b000000);
}

// Bumper-Abfrage
if(bumper_left || bumper_right) {
writeString_P("Bumper -> left, right or both\n");
setLEDs(0b010010);
move(50,BWD,DIST_CM(30),true);
rotate(30,LEFT,90,true);
setLEDs(0b000000);
}
}

int main(void)
{
initRobotBase(); // immer als erstes aufrufen, ohne die Funktion geht nix

powerON(); // aktiviert alle wichtigen Systeme

setLEDs(0b111111); // alle LEDs einmal an
mSleep(1000); // 1 sek. warten
setLEDs(0b000000); // alle LEDs wieder aus

// kann man das noch niedriger einstellen? low ist noch zu hoch, der RP6 fährt nicht nah
// genug an Wände heran.
setACSPwrLow(); // ACS Power = low

chkAccu(); // beim ersten Programmstart einmal ausführen, danach wird die Funktion zeitlich getriggert

// Timer starten
startStopwatch1();
startStopwatch2();

// Main loop
while(true)
{
task_RP6System(); // ruft motioncontroll, acs, etc. auf

// alle 30sek. Akku-Spannung prüfen
if(getStopwatch1() > 30000) {
chkAccu();
setStopwatch1(0);
}

// alle 500ms Motor-Spannung prüfen
if(getStopwatch2() > 500) {
chkMotor();
setStopwatch2(0);
}

// fahr mal los... schön gerade aus und mit 80 Speed pro Kette....
changeDirection(FWD);
moveAtSpeed(80,80);

// Hindernissen ausweichen per IR und Bumper...
avoid();
}
return 0;
}

[/code]

error41
10.01.2009, 23:53
Hi!

Automatentheorie ist schon ein wenig her...
Also ich stand den finite state machines anfangs auch SEHR skeptisch gegenüber.
Ich war mit denen vorher bei der normalen Programmierung auch nie in Kontakt gekommen.
Nach der Nutzung von finite state machines bei einem PLD und später beim erlernen von VHDL merkt man eigentlich erst richtig was der ganze Kram soll.
Bei einer FSM hat man eine idiotensichere und lückenlose Dokumentation und Fehler können sich nur schwer einschleichen und sind meist schnell auffindbar.
Also vermeintlich sicherer Code bzw. eine sichere Beschreibung eines Verhaltens.
Ich persönlich finde finite state machines für Architekturbeschreibungen in VHDL genial,
jedoch nur selten in Sprachen wie C zu gebrauchen!
Es geht meiner Meinung nach eine Menge (!) Flexibilität verloren,
erkauft sich dadurch aber Sicherheit und eine leichte Dokumentation.

Das ist so meine Erfahrung und Meinung mit den FSMs,
es gibt hier bestimmt einige die da genau anderer Meinung sind :cheesy:,
würde mich mal interessieren wie die das sehen.

Gruß

p_mork
11.01.2009, 09:13
Gude,

kleinere Programme lassen sich bestimmt einfacher, übersichtlicher und schneller ohne FSM realisieren. Die Vorteile von FSM gegebüber funktionaler Programmierung werden meistens erst bei sehr komplexen Verhaltensweisen deutlich. FSMs ermöglichen einen vergleichsweise einfachen Kontextwechsel bei unerwarteten Ereignissen, weil man eben nur den Zustand zu wecheln braucht. Beim funktionalem Ansatz hingegen könnte es vorkommen, dass quasi aus einer Funktion mitten in eine andere gesprungen werden muss, was natürlich nicht geht und weshalb man teilweise abartige und unübersichtliche Konstrukte bauen muss, um das geschünschte Verhalten zu erziehlen. Ausserdem ist FSM ausfallsicherer, da der Ausfall eines Moduls nicht unbedingt zum Absturz des ganzen Systems führen muss, wie das bei rein funktionalen Lösungen leider meistens der Fall ist. Das beste Beispiel dafür ist das Gehirn, das seine Aufgaben ja nicht sequentiell sondern massiv parallel durchführt.

Aber wie gesagt, das alles gilt nur für längere und komplizierte Programme, bei kurzen Progs kommt man meistens ohne FSM schneller ans Ziel.

MfG Mark

benx
11.01.2009, 22:51
Ok... das mit der schnelleren Realisierung kann ich bis jetzt nur bestätigen. Ohne FSM konnte die Problemstellungen schneller lösen. Mal schauen ob ich die FSM irgendwann einmal brauchen werde...

Vielen Dank für eure Meinungen..:)

mfg
ben