Finite state machine

algemene C code
Berichten: 167
Geregistreerd: 19 Apr 2014, 15:03

Finite state machine

Berichtdoor Hanneman » 08 Mei 2014, 12:19

Beste medeforum bezoekers,

Er is een leuke oefening voor de Arduino genaamd mood lamp http://www.instructables.com/id/Mood-Lamp-with-Arduino
Om hier meer mee te kunnen doen zou ik graag willen leren hoe je een Finite state machine kunt programmeren.
Door te googlen krijg ik niet echt voorbeelden waar ik wat mee kan.

Ik zou graag de kleuren van de leds aan willen kunnen passen door aan een potmeter te draaien (dit lukt).
Verschillende modi starten, bijv. modi 1 is leds gaan aan/uit (blink led voorbeeld), modi 2 is leds faden in en uit (dit lukt ook)

Het lukt me alleen niet om terwijl modi 1 bijv. draait, de kleur aan te kunnen passen en naar modi 2 te gaan.

Ik hoop dat het duidelijk is zo.
Wie kan/wil er een voorbeeld code voor mij maken waarmee ik het finite state principe beter kan leren begrijpen?
Het hoeft niet met de mood lamp te zijn.

Advertisement

Berichten: 167
Geregistreerd: 19 Apr 2014, 15:03

Re: Finite state machine

Berichtdoor Hanneman » 08 Mei 2014, 15:58

Misschien is dit een stapje in de goede richting?


// PIN definitions
#define REDLEDPIN 6
#define GREENLEDPIN 3
#define BLUELEDPIN 5
#define REDBUTTON 7
#define GREENBUTTON 12
#define BLUEBUTTON 8

// FSM states
#define STATE_RED 0
#define STATE_GREEN 1
#define STATE_BLUE 2

// variables
int fsm_state;
int buttonState = 0;
int buttonState2 = 0;
int buttonState3 = 0;

unsigned long TimerA;
unsigned long TimerB;
unsigned long TimerC;

void setup() {

pinMode(REDLEDPIN, OUTPUT);
pinMode(GREENLEDPIN, OUTPUT);
pinMode(BLUELEDPIN, OUTPUT);
pinMode(REDBUTTON, INPUT);
pinMode(GREENBUTTON, INPUT);
pinMode(BLUEBUTTON, INPUT);
digitalWrite(REDLEDPIN, LOW);
digitalWrite(GREENLEDPIN, LOW);
digitalWrite(BLUELEDPIN, LOW);

}

void loop() {

// FSM states
switch(fsm_state) {

case STATE_RED:

buttonState = digitalRead(REDBUTTON);
if (buttonState == HIGH) {
TimerA = millis();
digitalWrite(REDLEDPIN, HIGH);
}
if (millis()-TimerA >= 1000){
digitalWrite(REDLEDPIN, LOW);
}
fsm_state = STATE_GREEN;

break;

case STATE_GREEN:

buttonState2 = digitalRead(GREENBUTTON);
if (buttonState2 == HIGH) {
TimerB = millis();
digitalWrite(GREENLEDPIN, HIGH);
}
if (millis()-TimerB >= 1000){
digitalWrite(GREENLEDPIN, LOW);
}
fsm_state = STATE_BLUE;

break;

case STATE_BLUE:

buttonState3 = digitalRead(BLUEBUTTON);
if (buttonState3 == HIGH) {
TimerC = millis();
digitalWrite(BLUELEDPIN, HIGH);
}
if (millis()-TimerC >= 1000){
digitalWrite(BLUELEDPIN, LOW);
}
fsm_state = STATE_RED;

break;
}
}

Berichten: 4064
Geregistreerd: 16 Okt 2013, 14:31
Woonplaats: s hertogenbosch

Re: Finite state machine

Berichtdoor shooter » 08 Mei 2014, 19:49

ja je snapt prima wat een state machine is, alleen loopt deze machine nu door alle staten heen in een noodvaart, dat komt door dat je in bijv. state_blue de state altijd verandert dat zou pas na een tijdje moeten zijn.
oplossing is de accolade twee regels naar beneden.
het resultaat is een Sequential programma maar is zeker een goed begin.
je kunt een verschil maken door als deze goed werkt de state afhankelijk maken van de stand van een schakelaar bijv. als er bijv twee uitgangen in je knoop zijn dan moet de state ook in twee standen te zetten zijn, maar dit is zeker een mooi begin.
de volgende stap is een startplaats, waar de buttons allemaal instaan. als blue button dan is state blue
na state blue weer naar state start.
dan kun je op een andere knop duwen en dan is rood bijv 1 seconde aan.

je moet in de gaten houden wanneer je iets uit moet zetten, want als je in een andere state staat dan heeft een tijd geen zin meer want die staat in een state.

state machines zijn niet simpel, maazijn zeer goed voor machines die verschillende toestanden hebben zoals een tablettenmaker of een lift.
voor een dimlamp is gewoon C nog het simpelst.

als je een verkeerslicht bedenkt dan heb je wel mooi statemachine (denk aan knipperlicht en voetgangers die ertussendoor moeten.
paul deelen
shooter@home.nl

Berichten: 167
Geregistreerd: 19 Apr 2014, 15:03

Re: Finite state machine

Berichtdoor Hanneman » 09 Mei 2014, 13:15

Bedankt voor je reactie.

Berichten: 167
Geregistreerd: 19 Apr 2014, 15:03

Re: Finite state machine

Berichtdoor Hanneman » 09 Mei 2014, 17:01

Ik ben al een heel stuk verder gekomen, maar er zijn nog 2 problemen en de code zal vast makkelijker/beter gemaakt kunnen worden.
Wie kan/wil mij helpen deze problemen op te lossen?

// PROBLEMEN!
//
// Delays bij randommode en fade mode zorgen ervoor dat ik niet
// naar een andere mode kan!!!!
//
// LEDS branden niet FEL genoeg als de LDRS van schaduw voorzien worden
//

//Library codes
#include <LiquidCrystal.h>

// PIN definitions LCD
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// PIN definitions LEDS
#define REDLEDPIN 9
#define GREENLEDPIN 10
#define BLUELEDPIN 6

// PIN definitions Buttons
#define REDBUTTON 7
#define GREENBUTTON 13
#define BLUEBUTTON 8

// PIN definitions LDRs
#define LDR01 0
#define LDR02 1
#define LDR03 2

// Value definitions LDR
#define LDRlow 850 // lagere waarde en leds branden makkelijker
#define LDRhigh 950

// FSM states
#define STATE_RED 0
#define STATE_GREEN 1
#define STATE_BLUE 2
#define blinking 3
#define fadingleds 4
#define randommode 5

//
// variables
//

// Finite state Machines
int fsm_state; // Switch variable
int fsm_state2; // Switch variable


//buttonvariables
int buttonState = 0; //button
int buttonState2 = 0; //button
int buttonState3 = 0; //button

//ledvariables
float LDR01read01;
float LDR02read02;
float LDR03read03;
int LDR01Value01;
int LDR02Value02;
int LDR03Value03;
float LDR01Range01;
float LDR02Range02;
float LDR03Range03;

// Variable for Blink without Delay
int ledState = LOW;

// Debouncing buttons
long lastDebounceTime = 0; // the last time the output pin was toggled
long debounceDelay = 50; // the debounce time; increase if the output flickers

// Random mode
float RGB1[3];
float RGB2[3];
float INC[3];
int red, green, blue;

//Fade Mode
float sinVal;
int ledVal;

//timers
unsigned long currentMillis = millis();
long previousMillis = 0;
long interval = 1000;

void setup() {

// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("Mood light");

Serial.begin(9600); //Begin serial communcation

pinMode(REDLEDPIN, OUTPUT);
pinMode(GREENLEDPIN, OUTPUT);
pinMode(BLUELEDPIN, OUTPUT);
pinMode(REDBUTTON, INPUT);
pinMode(GREENBUTTON, INPUT);
pinMode(BLUEBUTTON, INPUT);

digitalWrite(REDLEDPIN, LOW);
digitalWrite(GREENLEDPIN, LOW);
digitalWrite(BLUELEDPIN, LOW);

}

void loop() {
// set the cursor to column 0, line 1
// (note: line 1 is the second row, since counting begins with 0):
lcd.setCursor(0, 1);

Serial.println(analogRead(LDR01)); //Write the value of the photoresistor to the serial monitor.
//you have to divide the value. for example,
//with a 10k resistor divide the value by 2, for 100k resistor divide by 4
// FSM states
switch(fsm_state) {

case STATE_RED:

buttonState = digitalRead(REDBUTTON);
if (buttonState == HIGH) {
digitalWrite(REDLEDPIN, LOW);
digitalWrite(GREENLEDPIN, LOW);
digitalWrite(BLUELEDPIN, LOW);
fsm_state2 = blinking;
}
else
{
fsm_state = STATE_GREEN;
}
break;

case STATE_GREEN:

buttonState2 = digitalRead(GREENBUTTON);
if (buttonState2 == HIGH) {
digitalWrite(REDLEDPIN, LOW);
digitalWrite(GREENLEDPIN, LOW);
digitalWrite(BLUELEDPIN, LOW);
fsm_state2 = fadingleds;
}
else
{
fsm_state = STATE_BLUE;
}
break;

case STATE_BLUE:

buttonState3 = digitalRead(BLUEBUTTON);
if (buttonState3 == HIGH) {
digitalWrite(REDLEDPIN, LOW);
digitalWrite(GREENLEDPIN, LOW);
digitalWrite(BLUELEDPIN, LOW);
fsm_state2 = randommode;
} else {
fsm_state = STATE_RED;
}
break;
}
switch(fsm_state2){

case blinking:

buttonState2 = digitalRead(GREENBUTTON);
if (buttonState2 == HIGH) {
digitalWrite(REDLEDPIN, LOW);
digitalWrite(GREENLEDPIN, LOW);
digitalWrite(BLUELEDPIN, LOW);
fsm_state2 = fadingleds;
}
else
{
fsm_state = STATE_RED;
}
buttonState3 = digitalRead(BLUEBUTTON);
if (buttonState3 == HIGH) {
digitalWrite(REDLEDPIN, LOW);
digitalWrite(GREENLEDPIN, LOW);
digitalWrite(BLUELEDPIN, LOW);
fsm_state2 = randommode;
}
else
{
fsm_state = STATE_BLUE;
}

lcd.println("Blink Mode ");

//setup LDR value
if (LDR01read01 < LDRlow) LDR01read01 = 750;
if (LDR01read01 > LDRhigh) LDR01read01 = 900;
if (LDR02read02 < LDRlow) LDR02read02 = 750;
if (LDR02read02 > LDRhigh) LDR02read02 = 900;
if (LDR03read03 < LDRlow) LDR03read03 = 750;
if (LDR03read03 > LDRhigh) LDR03read03 = 900;
LDR01Range01 = map(LDR01read01,750,900, 0, 255); // This will automatically scale your values
LDR02Range02 = map(LDR02read02,750,900, 0, 255); // This will automatically scale your values
LDR03Range03 = map(LDR03read03,750,900, 0, 255); // This will automatically scale your values

LDR01read01 = analogRead(LDR01);
LDR02read02 = analogRead(LDR02);
LDR03read03 = analogRead(LDR03);
LDR01Value01 = int(LDR01Range01*255);
LDR02Value02 = int(LDR02Range02*255);
LDR03Value03 = int(LDR03Range03*255);

currentMillis = millis();
if(currentMillis - previousMillis > interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;

analogWrite(REDLEDPIN, LDR01Value01 && ledState);
analogWrite(GREENLEDPIN, LDR02Value02 && ledState);
analogWrite(BLUELEDPIN, LDR03Value03 && ledState);

}

break;

case fadingleds:

buttonState = digitalRead(REDBUTTON);
if (buttonState == HIGH) {
digitalWrite(REDLEDPIN, LOW);
digitalWrite(GREENLEDPIN, LOW);
digitalWrite(BLUELEDPIN, LOW);
fsm_state2 = blinking;
}
else
{
fsm_state = STATE_GREEN;
}

buttonState3 = digitalRead(BLUEBUTTON);
if (buttonState3 == HIGH) {
digitalWrite(REDLEDPIN, LOW);
digitalWrite(GREENLEDPIN, LOW);
digitalWrite(BLUELEDPIN, LOW);
fsm_state2 = randommode;
}
else
{
fsm_state = STATE_BLUE;
}

lcd.println("Fade Mode ");
//setup LDR value
if (LDR01read01 < LDRlow) LDR01read01 = 750;
if (LDR01read01 > LDRhigh) LDR01read01 = 900;
if (LDR02read02 < LDRlow) LDR02read02 = 750;
if (LDR02read02 > LDRhigh) LDR02read02 = 900;
if (LDR03read03 < LDRlow) LDR03read03 = 750;
if (LDR03read03 > LDRhigh) LDR03read03 = 900;
LDR01Range01 = map(LDR01read01,750,900, 0, 255); // This will automatically scale your values
LDR02Range02 = map(LDR02read02,750,900, 0, 255); // This will automatically scale your values
LDR03Range03 = map(LDR03read03,750,900, 0, 255); // This will automatically scale your values

LDR01read01 = analogRead(LDR01);
LDR02read02 = analogRead(LDR02);
LDR03read03 = analogRead(LDR03);
LDR01Value01 = int(LDR01Range01*255);
LDR02Value02 = int(LDR02Range02*255);
LDR03Value03 = int(LDR03Range03*255);

for (int x=0; x<180; x++) {
// convert degrees to radians then obtain sin value
sinVal = (sin(x*(3.1412/180)));
ledVal = int(sinVal*255);
analogWrite(REDLEDPIN, ledVal && LDR01Value01);
analogWrite(GREENLEDPIN, ledVal && LDR02Value02);
analogWrite(BLUELEDPIN, ledVal && LDR03Value03);
//delay(100); //zorgt ervoor dat ik niet naar een andere modus kan
}

case randommode:

buttonState = digitalRead(REDBUTTON);
if (buttonState == HIGH) {
digitalWrite(REDLEDPIN, LOW);
digitalWrite(GREENLEDPIN, LOW);
digitalWrite(BLUELEDPIN, LOW);
fsm_state2 = blinking;
}
else
{
fsm_state = STATE_GREEN;
}

buttonState2 = digitalRead(GREENBUTTON);
if (buttonState2 == HIGH) {
digitalWrite(REDLEDPIN, LOW);
digitalWrite(GREENLEDPIN, LOW);
digitalWrite(BLUELEDPIN, LOW);

fsm_state = STATE_RED;
}

lcd.println("Random Mode ");

randomSeed(analogRead(5));
for (int x=0; x<3; x++) {
INC[x] = (RGB1[x] - RGB2[x]) / 256; }
for (int x=0; x<256; x++) {
red = int(RGB1[0]);
green = int(RGB1[1]);
blue = int(RGB1[2]);
analogWrite (REDLEDPIN, red);
analogWrite (GREENLEDPIN, green);
analogWrite (BLUELEDPIN, blue);
//delay(10); // zorgt ervoor dat ik niet naar een andere modus kan
RGB1[0] -= INC[0];
RGB1[1] -= INC[1];
RGB1[2] -= INC[2];
}
for (int x=0; x<3; x++) {
RGB2[x] = random(556)-300;
RGB2[x] = constrain(RGB2[x], 0, 255);
//delay(100); //zorgt ervoor dat ik niet naar een andere modus kan
}

break;

}
}

Berichten: 4064
Geregistreerd: 16 Okt 2013, 14:31
Woonplaats: s hertogenbosch

Re: Finite state machine

Berichtdoor shooter » 09 Mei 2014, 22:08

er gaat nog steeds iets mis met je state opvraag enhet en ja delay is een ramp want dan werkt je state machine niet meer, er gaat dan vanalles mis met je tijden.
paul deelen
shooter@home.nl

Berichten: 167
Geregistreerd: 19 Apr 2014, 15:03

Re: Finite state machine

Berichtdoor Hanneman » 10 Mei 2014, 09:48

Ik heb deze } onder de fsm_state's gezet. Dat bedoelde je toch? wat is er nu nog mis mee dan?

Van modus naar modus gaan, gaat prima.
Het zijn nu nog de delays die me de das omdoen.

De blink without delay snap ik inmiddels een beetje, maar hier heb ik een andere opmaak nodig voor de delay.

Gebruikers-avatar
Berichten: 5043
Geregistreerd: 13 Mei 2013, 20:57
Woonplaats: Heemskerk

Re: Finite state machine

Berichtdoor nicoverduin » 10 Mei 2014, 10:20

Als je nu dit stukje neemt bijvoorbeeld:
Code: Alles selecteren
for (int x=0; x<180; x++) {
// convert degrees to radians then obtain sin value
   sinVal = (sin(x*(3.1412/180)));
   ledVal = int(sinVal*255);
   analogWrite(REDLEDPIN, ledVal && LDR01Value01);
   analogWrite(GREENLEDPIN, ledVal && LDR02Value02);
   analogWrite(BLUELEDPIN, ledVal && LDR03Value03);
//delay(100); //zorgt ervoor dat ik niet naar een andere modus kan
}


Dat kan je ook zo herschrijven: waardoor hij gewoon doorloopt.

Code: Alles selecteren
//
// in de initialisatie. Dus wel de juiste plek zoeken
//
unsigned int x                = 0;
unsigned long delayCtr    = 0L;
#define VERTRAGING 100            // 100 milliseconden voor de vertraging
delayCtr = millis() + VERTRAGING;


//
// en dan in de loop
//
if (delayCtr != 0) {
   //
   // de delay counter is gezet dus we moeten mogelijk iets doen
   //
   if (millis() > delayCtr) {
      //
      // De dealy is verstreken dus nu de graden met 1 verhogen
      //
      if (x < 180) {
         //
         // we zitten nog niet op het eind
         //
         x++;
         //
         // voer de berekening uit
         //
         sinVal = (sin(x*(3.1412/180)));
         ledVal = int(sinVal*255);
         //
         // en zet de LEDs op de gewenste waarde
         //
         analogWrite(REDLEDPIN, ledVal && LDR01Value01);
         analogWrite(GREENLEDPIN, ledVal && LDR02Value02);
         analogWrite(BLUELEDPIN, ledVal && LDR03Value03);
         //
         // en zet de dealy voor de volgende keer
         //
         delayCtr = millis() +  VERTRAGING;
      } else {
         //
         // we zitten al op de 180 dus reset alles (als je wilt
         //
         x             = 0;      // graden weer op 0
         delayCtr    = 0L;      // stop de vertraging. Zolang deze niet gezet wordt,
                                    // zal het bovenstaande niet meer uitgevoerd worden
      }
   }
}
Docent HBO Technische Informatica, Embedded ontwikkelaar & elektronicus
http://www.verelec.nl

Berichten: 167
Geregistreerd: 19 Apr 2014, 15:03

Re: Finite state machine

Berichtdoor Hanneman » 10 Mei 2014, 10:46

Thanks Nico!!!

Berichten: 167
Geregistreerd: 19 Apr 2014, 15:03

Re: Finite state machine

Berichtdoor Hanneman » 10 Mei 2014, 12:25

Helaas werkt dat niet :(

de Leds blijven nu gewoon uit

Volgende

Terug naar C code

Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 12 gasten