From: Andrea Manni Date: Thu, 9 Mar 2017 11:54:22 +0000 (+0100) Subject: FSM reorder X-Git-Url: http://git.piffa.net/web?p=sketchbook_andrea;a=commitdiff_plain;h=8a90a5875d2fcf8db21835920d57f97a4bca0ade FSM reorder --- diff --git a/advanced_projects/state_machine/README b/advanced_projects/state_machine/README index 15f5175..d17dce6 100644 --- a/advanced_projects/state_machine/README +++ b/advanced_projects/state_machine/README @@ -4,14 +4,33 @@ FSM Risorse utili per le Macchine a stati. +In questi esercizi vengono presentati alcuni paradigmi di base per la creazione +di macchine a stato con Arduino. Vengono proposti esempi con FSM singole e FSM +doppie concorrenti, per altri esempi pratici con semplici cicli IF, gestione degli eventi esterni / interni si puo' guardare anche il codice del progetto "Luci per Aerei RC": +- http://aerei.piffa.net/repo/esempi/base_th_3stati/base_th_3stati.ino +- http://aerei.piffa.net/esempi/2017/02/15/throttle-fsm.html +- http://aerei.piffa.net/esempi/2017/02/20/alettoni-fsm.html +- http://aerei.piffa.net/repo/aerei/ + Tutorials =========== * https://www.sparkfun.com/news/1801 +* http://digitaldiy.io/articles/mcu-programming/general-programming/500-finite-state-+machines#.VT0r1s90yh3 +* http://www.gammon.com.au/forum/?id=12316 +* https://github.com/JChristensen/Button/blob/master/Examples/LongPress/LongPress.pde +* http://www.thebox.myzen.co.uk/Tutorial/State_Machine.html + +Teoria +======== +* https://en.wikipedia.org/wiki/Finite-state_machine +* https://en.wikipedia.org/wiki/Nondeterministic_finite_automaton +* https://en.wikipedia.org/wiki/Deterministic_finite_automaton#Complete_and_incomplete +* http://43oh.com/2017/02/how-to-implement-finite-state-machines-using-energia/ @@ -21,3 +40,4 @@ Elementi * http://playground.arduino.cc/Code/Enum * https://www.arduino.cc/en/Reference/SwitchCase +* https://learn.adafruit.com/multi-tasking-the-arduino-part-1 diff --git a/advanced_projects/state_machine/README.html b/advanced_projects/state_machine/README.html new file mode 100644 index 0000000..fe1f325 --- /dev/null +++ b/advanced_projects/state_machine/README.html @@ -0,0 +1,605 @@ + + + + + +FSM + + + + +
+

FSM

+ +

Risorse utili per le Macchine a stati.

+

In questi esercizi vengono presentati alcuni paradigmi di base per la creazione +di macchine a stato con Arduino. Vengono proposti esempi con FSM singole e FSM +doppie concorrenti, per altri esempi pratici con semplici cicli IF, gestione degli eventi esterni / interni si puo' guardare anche il codice del progetto "Luci per Aerei RC": +- http://aerei.piffa.net/repo/esempi/base_th_3stati/base_th_3stati.ino +- http://aerei.piffa.net/esempi/2017/02/15/throttle-fsm.html +- http://aerei.piffa.net/esempi/2017/02/20/alettoni-fsm.html +- http://aerei.piffa.net/repo/aerei/

+ + + +
+ + diff --git a/advanced_projects/state_machine/blink/blink_1/blink_1.ino b/advanced_projects/state_machine/blink/blink_1/blink_1.ino deleted file mode 100644 index c119794..0000000 --- a/advanced_projects/state_machine/blink/blink_1/blink_1.ino +++ /dev/null @@ -1,43 +0,0 @@ -/* - Blink FSM - - Accensione e spegnimanto di un LED utilizzando - una FSM 2 stati statici. - -Costrutto switch basato su uno struct. - - */ - -// Dichiarazione variabili -int led = 13; -int pausa = 500; // Variabile richiambile nel corso dell'esecuzione - -void setup() { - // Inizializziamo il PIN 13 come OUTPUT - pinMode(led, OUTPUT); -} - -enum fsm_stati { // Stati della FMS - on, - off -}; - -fsm_stati stato; - -void loop() { - switch (stato){ - case on : - digitalWrite(led, HIGH); // Mette il PIN del LED in stato acceso - delay(pausa); // Aspetta un secondo (mille millisecondi) - - stato = off ; // Setta il prossimo state - break; - - case off: - digitalWrite(led, LOW); // Mette il PIN del LED in stato spento - delay(pausa); // Aspetta mezzo secondo - - stato = on ; - break; - } -} diff --git a/advanced_projects/state_machine/blink/blink_2_trans/blink_2_trans.ino b/advanced_projects/state_machine/blink/blink_2_trans/blink_2_trans.ino deleted file mode 100644 index 1841f87..0000000 --- a/advanced_projects/state_machine/blink/blink_2_trans/blink_2_trans.ino +++ /dev/null @@ -1,106 +0,0 @@ -/* - Blink FSM - - Accensione e spegnimanto di un LED utilizzando - una FSM con 4 stati, statici e di transizione. - -Costrutto switch basato su uno struct. - - */ - -// Dichiarazione variabili -int led = 11; // PWM -int pausa = 1000; // Variabile richiambile nel corso dell'esecuzione -byte lum = 0 ; - -void setup() { - // Inizializziamo il PIN 13 come OUTPUT - pinMode(led, OUTPUT); -} - -enum fsm_stati { // Stati della FMS - on, // Statico - to_off, // Transizione - off, - to_on -}; - -fsm_stati stato ; - -void loop() { - switch (stato) { - case on : - // Operativa: Machine - digitalWrite(led, HIGH); // Mette il PIN del LED in stato acceso - delay(pausa); - - // Stati - stato = to_off ; // Setta il prossimo state - lum = 255; - break; - - case to_off : - while (lum > 0) { - lum-- ; - analogWrite(led, lum); // Mette il PIN del LED in stato acceso - delay(1); - } - - stato = off ; // Setta il prossimo state - break; - - case off: - digitalWrite(led, LOW); // Mette il PIN del LED in stato spento - delay(pausa); - - stato = to_on ; - lum = 0; - break; - - case to_on : - while (lum < 255) { - lum++ ; - analogWrite(led, lum); // Mette il PIN del LED in stato acceso - delay(1); - } - - stato = on ; // Setta il prossimo state - break; - } -} - -/* Domande: - - 1.Cosa comporta l'uso della funzione delay? - 2.Come si puo' modificare lo sketch per poter eseguire piu' conpiti contemporaneamente? - -Esercizi successivi: -- Creare una FSM con un LED RGB avente due stati Red e Green, una transizione yellow tra i due -- Creare una FSM per la gestione di un semaforo - (esempio disponibile in sketchbook_andrea/advanced_projects/state_machine ) - - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - Soluzioni: - - 1.Delay rende il codice blocking, null'altro puo' essere eseguito durante i delay - 2.Si potrebbe utilizzare millis(), vedi esercizi multitasking -*/ diff --git a/advanced_projects/state_machine/blink_2_trans/blink_2_trans.ino b/advanced_projects/state_machine/blink_2_trans/blink_2_trans.ino index 4abe599..6545cde 100644 --- a/advanced_projects/state_machine/blink_2_trans/blink_2_trans.ino +++ b/advanced_projects/state_machine/blink_2_trans/blink_2_trans.ino @@ -4,7 +4,7 @@ Accensione e spegnimanto di un LED utilizzando una FSM con 4 stati, statici e di transizione. -Costrutto switch basato su uno struct. +Costrutto switch basato su un enum: */ @@ -18,14 +18,13 @@ void setup() { pinMode(led, OUTPUT); } -enum fsm_stati { // Stati della FMS +enum fsm_stati: byte { // Stati della FMS, explicit type cast on, // Statico to_off, // Transizione off, to_on -}; +} stato ; // denominazione di una variabile -fsm_stati stato ; void loop() { switch (stato) { diff --git a/advanced_projects/state_machine/semaforo_1/semaforo_1.ino b/advanced_projects/state_machine/semaforo_1/semaforo_1.ino index 1318a08..b32e637 100644 --- a/advanced_projects/state_machine/semaforo_1/semaforo_1.ino +++ b/advanced_projects/state_machine/semaforo_1/semaforo_1.ino @@ -4,6 +4,9 @@ Un singolo semaforo costruito col paradigma delle macchine a stato. Viene utilizzato un oggetto della libreria common per gestire il LED. + +- Schema per un led RGB: https://lab.piffa.net/schemi/rgb.jpg + */ #include int pausa = 3000; @@ -14,7 +17,7 @@ enum states_available { // Stati della FMS red }; -states_available state ; +states_available state = red; void setup() { @@ -39,13 +42,12 @@ switch (state) { case turn_red : led.Yellow(); - delay(pausa/3); - led.Red(); - delay(pausa); + delay(pausa / 3); state = red ; break; case red : + led.Red(); delay(pausa); state = turn_green ; break; diff --git a/advanced_projects/state_machine/semaforo_2_1_doppio/semaforo_2_1_doppio.ino b/advanced_projects/state_machine/semaforo_2_1_doppio/semaforo_2_1_doppio.ino deleted file mode 100644 index 412e11f..0000000 --- a/advanced_projects/state_machine/semaforo_2_1_doppio/semaforo_2_1_doppio.ino +++ /dev/null @@ -1,100 +0,0 @@ -/* - Incrocio RGB - - Un incrocio costituito da due strade, una principale e una secondaria. - La via viene concessa al secondario alla pressione di un bottone, - il secondario cambia automaticamente dopo una pausa. - Viene utilizzato un oggetto della libreria common per gestire i LED. - - Uno stimolo esterno rappresentato dalla pressione di un bottone - causa il passaggio di stato. - - */ - -#include -const byte input = 2; // PIN del bottone -int pausa = 3000; -enum states_available { // Stati della FMS - turn_green, // Dinamico, transizione - green, // Statico - wait_button, - turn_red, - red -}; - -states_available FSM1 ; -states_available FSM2 ; - - -void setup() { - pinMode(input, INPUT_PULLUP); - Serial.begin(9600); - Serial.flush(); -} - -RGBLed led_main(11, 10, 9); -RGBLed led_secondary(8, 7, 6); - -void loop() { -switch (FSM1) { - case turn_green : - led_main.Green(); - FSM1 = green ; // Setta il prossimo state - FSM2 = red ; // Setta il prossimo state - break; - - case green: - delay(pausa * 2/3); - FSM1 = wait_button ; - break; - - case wait_button: - if (digitalRead(input) == LOW) { - FSM1 = turn_red ; // Il passaggio di stato avviene alla pressione di un bottone - }; - delay(20); - break; - - case turn_red : - led_main.Yellow(); - delay(pausa/3); - led_main.Red(); - FSM1 = red ; - FSM2 = turn_green; // Stimolo al semafor secondario - break; - - case red : - //delay(pausa); - //main = turn_green ; - break; -} -switch (FSM2) { - case turn_green : - led_secondary.Green(); - FSM2 = green ; // Setta il prossimo state - break; - - case green: - delay(pausa * 2/3); - FSM2 = turn_red ; // Niente stimoli - break; - - case turn_red : - led_secondary.Yellow(); - delay(pausa/3); - FSM1 = turn_green ; - FSM2 = red ; - break; - - case red : - led_secondary.Red(); - break; -} - -Serial.print(millis()); -Serial.print(" \t Stato attuale Main: "); -Serial.print(FSM1); -Serial.print(", secondary: "); -Serial.println(FSM2); - -} diff --git a/advanced_projects/state_machine/semaforo_2_1_stimolo/semaforo_2_1_stimolo.ino b/advanced_projects/state_machine/semaforo_2_1_stimolo/semaforo_2_1_stimolo.ino new file mode 100644 index 0000000..b151838 --- /dev/null +++ b/advanced_projects/state_machine/semaforo_2_1_stimolo/semaforo_2_1_stimolo.ino @@ -0,0 +1,102 @@ +/* + Semaforo RGB + + Un singolo semaforo costruito col paradigma delle macchine a stato. + Viene utilizzato un oggetto della libreria common per gestire il LED. + + Uno stimolo esterno rappresentato dalla pressione di un bottone + causa il passaggio di stato. + +- Schema per un led RGB: https://lab.piffa.net/schemi/rgb.jpg +- Schema per un bottone: https://www.arduino.cc/en/uploads/Tutorial/inputPullupButton.png + */ + +#include +const byte input = 2; // PIN del bottone +int pausa = 3000; +enum states_available { // Stati della FMS + turn_green, // Dinamico, transizione + green, // Statico + wait_button, // Evento - Stimolo + turn_red, // Dinamico, transizione + red // Statico +}; + +states_available state ; + + +void setup() { + pinMode(input, INPUT_PULLUP); + Serial.begin(9600); + Serial.flush(); +} + +RGBLed led(11, 10, 9); //Istanziamo un oggetto led facente parte + // della classe RGBLed + +void loop() { +switch (state) { + case turn_green : + led.Green(); + state = green ; // Setta il prossimo state + break; + + case green: + delay(pausa * 2/3); + state = wait_button ; + break; + + case wait_button: + if (digitalRead(input) == LOW) { + state = turn_red ; // Il passaggio di stato avviene alla pressione di un bottone + delay(20); + }; + + break; + + case turn_red : + led.Yellow(); + delay(pausa/3); + state = red ; + break; + + case red : + led.Red(); + delay(pausa); + state = turn_green ; + break; + + default: // In caso di default si fa giallo lampeggiante + led.Yellow(); + delay(pausa/3); + led.Off(); + delay(pausa/3); + break; + +} +Serial.print(millis()); +Serial.print(" \t Stato attuale "); +Serial.println(state); + +} + +/* Domande: + 1. Introdurre una memoria nello stato green che tenga traccia della pressione del bottone per lo stato successivo. + 2. Introdurre un secondo semaforo che cambia stato quando viene attivato + lo stimolo. + 3. L'uso di delay() puo' essere limitativo: come rimediare? +. +. +. +. +. +. +. +. +. +. + Soluzioni +1. Vedi sketch: semaforo_rgb +3. Si potrebbe utilizzare un interrupt per gli stimoli oppure millis() + per gestire le pause. + */ diff --git a/advanced_projects/state_machine/semaforo_2_2_doppio/semaforo_2_2_doppio.ino b/advanced_projects/state_machine/semaforo_2_2_doppio/semaforo_2_2_doppio.ino new file mode 100644 index 0000000..e25b487 --- /dev/null +++ b/advanced_projects/state_machine/semaforo_2_2_doppio/semaforo_2_2_doppio.ino @@ -0,0 +1,107 @@ +/* + Incrocio RGB + + Un incrocio costituito da due strade, una principale e una secondaria. + La via viene concessa al secondario alla pressione di un bottone, + il secondario cambia automaticamente dopo una pausa. + Viene utilizzato un oggetto della libreria common per gestire i LED. + + Uno stimolo esterno rappresentato dalla pressione di un bottone + causa il passaggio di stato. + + Questo sketch usa due FSM indipendenti che modificano i rispettivi stati. + +- Schema per un led RGB: https://lab.piffa.net/schemi/rgb.jpg +- Schema per un bottone: https://www.arduino.cc/en/uploads/Tutorial/inputPullupButton.png + */ + +#include +const byte input = 2; // PIN del bottone +int pausa = 3000; +enum states_available { // Stati della FMS + turn_green, // Dinamico, transizione + green, // Statico + wait_button, + turn_red, + red +}; + +states_available FSM1 ; +states_available FSM2 ; + + +void setup() { + pinMode(input, INPUT_PULLUP); + Serial.begin(9600); + Serial.flush(); +} + +RGBLed led_main(11, 10, 9); +RGBLed led_secondary(8, 7, 6); + +void loop() { +switch (FSM1) { + // Semaforo principale + case turn_green : + led_main.Green(); + FSM1 = green ; // Setta il prossimo state + FSM2 = red ; // Setta il prossimo state + break; + + case green: + delay(pausa * 2/3); + FSM1 = wait_button ; + break; + + case wait_button: + if (digitalRead(input) == LOW) { + FSM1 = turn_red ; // Il passaggio di stato avviene alla pressione di un bottone + }; + delay(20); + break; + + case turn_red : + led_main.Yellow(); + delay(pausa/3); + led_main.Red(); + FSM1 = red ; + FSM2 = turn_green; // Stimolo al semafor secondario + break; + + case red : + //delay(pausa); + //main = turn_green ; + break; +} + +switch (FSM2) { + // Semaforo Secondario + case turn_green : + led_secondary.Green(); + FSM2 = green ; // Setta il prossimo state + break; + + case green: + delay(pausa * 2/3); + FSM2 = turn_red ; // Niente stimoli + break; + + case turn_red : + led_secondary.Yellow(); + delay(pausa/3); + FSM1 = turn_green ; + FSM2 = red ; + break; + + case red : + led_secondary.Red(); + break; +} +// Debug +Serial.print(millis()); +Serial.print(" \t Stato attuale Main: "); +Serial.print(FSM1); +Serial.print(", secondary: "); +Serial.println(FSM2); + +} diff --git a/advanced_projects/state_machine/semaforo_2_stimolo/semaforo_2_stimolo.ino b/advanced_projects/state_machine/semaforo_2_stimolo/semaforo_2_stimolo.ino deleted file mode 100644 index 9b4b367..0000000 --- a/advanced_projects/state_machine/semaforo_2_stimolo/semaforo_2_stimolo.ino +++ /dev/null @@ -1,101 +0,0 @@ -/* - Semaforo RGB - - Un singolo semaforo costruito col paradigma delle macchine a stato. - Viene utilizzato un oggetto della libreria common per gestire il LED. - - Uno stimolo esterno rappresentato dalla pressione di un bottone - causa il passaggio di stato. - - */ - -#include -const byte input = 2; // PIN del bottone -int pausa = 3000; -enum states_available { // Stati della FMS - turn_green, // Dinamico, transizione - green, // Statico - wait_button, // Evento - Stimolo - turn_red, // Dinamico, transizione - red // Statico -}; - -states_available state ; - - -void setup() { - pinMode(input, INPUT_PULLUP); - Serial.begin(9600); - Serial.flush(); -} - -RGBLed led(11, 10, 9); //Istanziamo un oggetto led facente parte - // della classe RGBLed - -void loop() { -switch (state) { - case turn_green : - led.Green(); - state = green ; // Setta il prossimo state - break; - - case green: - delay(pausa * 2/3); - state = wait_button ; - break; - - case wait_button: - if (digitalRead(input) == LOW) { - state = turn_red ; // Il passaggio di stato avviene alla pressione di un bottone - delay(20); - }; - - break; - - case turn_red : - led.Yellow(); - delay(pausa/3); - led.Red(); - delay(pausa); - state = red ; - break; - - case red : - delay(pausa); - state = turn_green ; - break; - - default: // In caso di default si fa giallo lampeggiante - led.Yellow(); - delay(pausa/3); - led.Off(); - delay(pausa/3); - break; - -} -Serial.print(millis()); -Serial.print(" \t Stato attuale "); -Serial.println(state); - -} - -/* Domande: - 1. Introdurre una memoria nello stato green che tenga traccia della pressione del bottone - per lo stato succiessivo. - 2. Introdurre un secondo semaforo che cambia stato quando viene attivato - lo stimolo. - 3. L'uso di delay() puo' essere limitativo: come rimediare? -. -. -. -. -. -. -. -. -. -. - Soluzioni -3. Si potrebbe utilizzare un interrupt per gli stimoli oppure millis() - per gestire le pause. - */ diff --git a/advanced_projects/state_machine/semaforo_3_millis/semaforo_3_millis.ino b/advanced_projects/state_machine/semaforo_3_millis/semaforo_3_millis.ino index 68825a6..4cc7dcb 100644 --- a/advanced_projects/state_machine/semaforo_3_millis/semaforo_3_millis.ino +++ b/advanced_projects/state_machine/semaforo_3_millis/semaforo_3_millis.ino @@ -10,6 +10,8 @@ Implementata con millis() invece che con delay(), sono stati aggiuntu due stati per meglio gestire lo stato yellow. +- Schema per un led RGB: https://lab.piffa.net/schemi/rgb.jpg +- Schema per un bottone: https://www.arduino.cc/en/uploads/Tutorial/inputPullupButton.png */ #include @@ -17,7 +19,6 @@ const byte input = 2; // PIN del bottone int pausa = 3000; long timer ; enum states_available { // Stati della FMS - turn_green, // Dinamico, transizione green, // Statico wait_button, // Evento - Stimolo turn_yellow, // Dinamico, transizione @@ -30,61 +31,58 @@ states_available state ; void setup() { - pinMode(input, INPUT_PULLUP); - Serial.begin(9600); - timer = millis(); + pinMode(input, INPUT_PULLUP); + Serial.begin(9600); + timer = millis(); } RGBLed led(11, 10, 9); //Istanziamo un oggetto led facente parte - // della classe RGBLed +// della classe RGBLed void loop() { switch (state) { - case turn_green : - state = green ; // Setta il prossimo state - break; - case green: +case green: led.Green(); if (millis() - timer >= pausa * 2/3) { - state = wait_button ; - timer += pausa * 2/3 ; + state = wait_button ; + timer += pausa * 2/3 ; } break; - case wait_button: - if (digitalRead(input) == LOW) { - state = turn_yellow ; // Il passaggio di stato avviene alla pressione di un bottone - delay(20); // Debouncing, si potrebbe fare con millis() - timer = millis(); +case wait_button: + if (digitalRead(input) == LOW) { + state = turn_yellow ; // Il passaggio di stato avviene alla pressione di un bottone + delay(20); // Debouncing, si potrebbe fare con millis() + timer = millis(); }; break; - case turn_yellow : +case turn_yellow : state = yellow ; break; - case yellow : +case yellow : led.Yellow(); - if (millis() - timer >= pausa * 2/3) { - state = turn_red ; - timer += pausa * 2/3; + if (millis() - timer >= pausa / 3) { + state = turn_red ; + timer += pausa / 3; } break; - case turn_red : +case turn_red : state = red ; break; - case red : +case red : led.Red(); if (millis() - timer >= pausa) { - state = turn_green ; - timer += pausa ; + state = green ; + timer += pausa ; } break; - default: // In caso di default si fa giallo lampeggiante +default: // In caso di default si fa giallo lampeggiante led.Yellow(); delay(pausa/3); led.Off(); @@ -92,16 +90,17 @@ switch (state) { break; } -Serial.print(millis()); +// Debug: +Serial.print(millis()); Serial.print(" \t Stato attuale "); Serial.println(state); } /* Domande: - 1. Introdurre un secondo semaforo che cambia stato quando viene attivato - lo stimolo. - 2. L'uso di delay() puo' essere limitativo: come rimediare? + 1. Fare in modo che nello stato verde venga recepito un'eventuale pressione + del bottone, venga comunque garantito un periodo minimo per il verde ma nel caso + sia stato premuto il bottone durante questo si passi poi direttamente al giallo. . . . @@ -113,6 +112,5 @@ Serial.println(state); . . Soluzioni -2. Si potrebbe utilizzare un interrupt per gli stimoli oppure millis() - per gestire le pause. +1. Vedi esercizio: semaforo_rgb */ diff --git a/advanced_projects/state_machine/semaforo_4_doppio/semaforo_4_doppio.ino b/advanced_projects/state_machine/semaforo_4_doppio/semaforo_4_doppio.ino deleted file mode 100644 index ab22ae0..0000000 --- a/advanced_projects/state_machine/semaforo_4_doppio/semaforo_4_doppio.ino +++ /dev/null @@ -1,140 +0,0 @@ -/* - Semaforo RGB - - - Doppio semaforo, una via prinicipale (led) e una secondaria (secondary): - la via secondaria ottiene la precedenza alla pressione di un bottone. - - Implementata con millis() invece che con delay(), - sono stati aggiuntu due stati per gestire lo stato yellow - del semafor secondario. - - Lo sketch e' stato implementato con una sola FSM in cui si incrociano - gli stati dei due semafori. - - */ - -#include -const byte input = 2; // PIN del bottone -int pausa = 3000; -long timer ; -enum states_available { // Stati della FMS - turn_green, // Dinamico, transizione - green, // Statico - wait_button, // Evento - Stimolo - turn_yellow, // Dinamico, transizione - yellow, // Statico - turn_red, // Dinamico, transizione - turn_sec_yellow, // Yellow per semaforo secondario - sec_yellow, - red // Statico -}; - -states_available state ; - - -void setup() { - pinMode(input, INPUT_PULLUP); - Serial.begin(9600); - timer = millis(); -} - -RGBLed led(11, 10, 9); // Semaforo principale -RGBLed secondary(8,7,6); // Semaforo secondario - - -void loop() { -switch (state) { - case turn_green : - led.Green(); - secondary.Red() ; - state = green ; // Setta il prossimo state - break; - - case green: - if (millis() - timer => pausa * 2/3) { - state = wait_button ; - timer += pausa * 2/3 ; - } - break; - - case wait_button: - if (digitalRead(input) == LOW) { - delay(20); // Debouncing, si potrebbe fare con millis() - state = turn_yellow ; // Il passaggio di stato avviene alla pressione di un bottone - timer = millis(); - }; - - break; - - case turn_yellow : - led.Yellow(); - state = yellow ; - break; - - case yellow : - if (millis() - timer >= pausa / 3) { - state = turn_red ; - timer += pausa / 3; - } - break; - - case turn_red : - led.Red(); - secondary.Green(); - state = red ; - break; - - case red : - if (millis() - timer >= pausa /3) { - state = turn_sec_yellow ; - timer += pausa /3 ; - } - break; - - case turn_sec_yellow : - secondary.Yellow(); - state = sec_yellow ; - break; - - case sec_yellow : - if (millis() - timer >= pausa / 3) { - state = turn_green ; - timer += pausa /3; - } - break; - - default: // In caso di default si fa giallo lampeggiante - led.Yellow(); - secondary.Yellow(); - delay(pausa/3); - led.Off(); - secondary.Off(); - delay(pausa/3); - break; - -} -Serial.print(millis()); -Serial.print(" \t Stato attuale "); -Serial.println(state); - -} - -/* Domande: - 1. E' agevole inserire degli altri semafori? - 2. Provare a inserire un altro semafori implementando una FSM - separata. -. -. -. -. -. -. -. -. -. -. - Soluzioni -1. Be' bisogna ragionare sul loro comportamente in rapporto alla FSM principale, diciamo che non e' un approccio plug and play. -2. Vedi esercizio successivo. - */ diff --git a/advanced_projects/state_machine/semaforo_4_doppio_single_FSM/semaforo_4_doppio_single_FSM.ino b/advanced_projects/state_machine/semaforo_4_doppio_single_FSM/semaforo_4_doppio_single_FSM.ino new file mode 100644 index 0000000..be9bb04 --- /dev/null +++ b/advanced_projects/state_machine/semaforo_4_doppio_single_FSM/semaforo_4_doppio_single_FSM.ino @@ -0,0 +1,142 @@ +/* + Semaforo RGB single FSM + + + Doppio semaforo, una via prinicipale (led) e una secondaria (secondary): + la via secondaria ottiene la precedenza alla pressione di un bottone. + + Implementata con millis() invece che con delay(), + sono stati aggiuntu due stati per gestire lo stato yellow + del semafor secondario. + + Lo sketch e' stato implementato con una sola FSM in cui si incrociano + gli stati dei due semafori. + +- Schema per un led RGB: https://lab.piffa.net/schemi/rgb.jpg +- Schema per un bottone: https://www.arduino.cc/en/uploads/Tutorial/inputPullupButton.png + */ + +#include +const byte input = 2; // PIN del bottone +int pausa = 3000; +long timer ; +enum states_available { // Stati della FMS + turn_green, // Dinamico, transizione + green, // Statico + wait_button, // Evento - Stimolo + turn_yellow, // Dinamico, transizione + yellow, // Statico + turn_red, // Dinamico, transizione + turn_sec_yellow, // Yellow per semaforo secondario + sec_yellow, + red // Statico +}; + +states_available state ; + + +void setup() { + pinMode(input, INPUT_PULLUP); + Serial.begin(9600); + timer = millis(); +} + +RGBLed led(11, 10, 9); // Semaforo principale +RGBLed secondary(8,7,6); // Semaforo secondario + + +void loop() { +switch (state) { + case turn_green : + led.Green(); + secondary.Red() ; + state = green ; // Setta il prossimo state + break; + + case green: + if (millis() - timer => pausa * 2/3) { + state = wait_button ; + timer += pausa * 2/3 ; + } + break; + + case wait_button: + if (digitalRead(input) == LOW) { + delay(20); // Debouncing, si potrebbe fare con millis() + state = turn_yellow ; // Il passaggio di stato avviene alla pressione di un bottone + timer = millis(); + }; + + break; + + case turn_yellow : + led.Yellow(); + state = yellow ; + break; + + case yellow : + if (millis() - timer >= pausa / 3) { + state = turn_red ; + timer += pausa / 3; + } + break; + + case turn_red : + led.Red(); + secondary.Green(); + state = red ; + break; + + case red : + if (millis() - timer >= pausa /3) { + state = turn_sec_yellow ; + timer += pausa /3 ; + } + break; + + case turn_sec_yellow : + secondary.Yellow(); + state = sec_yellow ; + break; + + case sec_yellow : + if (millis() - timer >= pausa / 3) { + state = turn_green ; + timer += pausa /3; + } + break; + + default: // In caso di default si fa giallo lampeggiante + led.Yellow(); + secondary.Yellow(); + delay(pausa/3); + led.Off(); + secondary.Off(); + delay(pausa/3); + break; + +} +Serial.print(millis()); +Serial.print(" \t Stato attuale "); +Serial.println(state); + +} + +/* Domande: + 1. E' agevole inserire degli altri semafori? + 2. Provare a inserire un altro semafori implementando una FSM + separata. +. +. +. +. +. +. +. +. +. +. + Soluzioni +1. Be' bisogna ragionare sul loro comportamente in rapporto alla FSM principale, diciamo che non e' un approccio plug and play. +2. Vedi esercizio successivo. + */ diff --git a/advanced_projects/state_machine/semaforo_5_doppia_fsm/semaforo_5_doppia_fsm.ino b/advanced_projects/state_machine/semaforo_5_doppia_fsm/semaforo_5_doppia_fsm.ino index dfcc362..db72e6a 100644 --- a/advanced_projects/state_machine/semaforo_5_doppia_fsm/semaforo_5_doppia_fsm.ino +++ b/advanced_projects/state_machine/semaforo_5_doppia_fsm/semaforo_5_doppia_fsm.ino @@ -1,15 +1,21 @@ /* - Semaforo RGB + Semaforo con doppia FSM - Un singolo semaforo costruito col paradigma delle macchine a stato. - Viene utilizzato un oggetto della libreria common per gestire il LED. +Due FSM indipendenti per la gestione di ognuno dei 2 semafori +che costituiscono un incrocio. Le due FSM possono modificare +i rispettivi stati. - Uno stimolo esterno rappresentato dalla pressione di un bottone - causa il passaggio di stato. +Un singolo semaforo costruito col paradigma delle macchine a stato. +Viene utilizzato un oggetto della libreria common per gestire il LED. - Implementata con millis() invece che con delay(), - sono stati aggiuntu due stati per meglio gestire lo stato yellow. +Uno stimolo esterno rappresentato dalla pressione di un bottone +causa il passaggio di stato. +Implementata con millis() invece che con delay(), +sono stati aggiuntu due stati per meglio gestire lo stato yellow. + +- Schema per un led RGB: https://lab.piffa.net/schemi/rgb.jpg +- Schema per un bottone: https://www.arduino.cc/en/uploads/Tutorial/inputPullupButton.png */ #include diff --git a/advanced_projects/state_machine/semaforo_rgb/semaforo_rgb.ino b/advanced_projects/state_machine/semaforo_rgb/semaforo_rgb.ino new file mode 100644 index 0000000..3260dbb --- /dev/null +++ b/advanced_projects/state_machine/semaforo_rgb/semaforo_rgb.ino @@ -0,0 +1,108 @@ +/* + Semaforo RGB + +Version: singolo semaforo + millis + memoria giallo + + Un singolo semaforo costruito col paradigma delle macchine a stato. + Viene utilizzato un oggetto della libreria common per gestire il LED. + + Uno stimolo esterno rappresentato dalla pressione di un bottone + causa il passaggio di stato. + + Implementata con millis() invece che con delay(), + sono stati aggiuntu due stati per meglio gestire lo stato yellow. + + */ + +#include +const byte input = 2; // PIN del bottone +int pausa = 3000; +long timer ; +enum states_available { // Stati della FMS + green, // Statico + yellow, // Statico + red // Statico +}; + +states_available state ; +boolean wait = 0; + + +void setup() { + pinMode(input, INPUT_PULLUP); + Serial.begin(9600); + timer = millis(); +} + +RGBLed led(11, 10, 9); //Istanziamo un oggetto led facente parte +// della classe RGBLed + +void loop() { + switch (state) { + + case green: + led.Green(); + if (wait && (millis() - timer >= pausa * 2/3)) { + state = yellow; + timer = millis(); + } + + if (digitalRead(input) == LOW) { + wait = 1; + } + break; + + + case yellow : + led.Yellow(); + if (millis() - timer >= pausa /3) { + state = red ; + wait = 0 ; + timer += pausa /3; + } + break; + + case red : + led.Red(); + if (millis() - timer >= pausa) { + state = green ; + timer += pausa ; + } + break; + + default: // In caso di default si fa giallo lampeggiante + led.Yellow(); + delay(pausa/3); + led.Off(); + delay(pausa/3); + break; + + } + + //Debug: + Serial.print(millis()); + Serial.print(" \t Stato attuale "); + Serial.print(state); + Serial.print(" \t Wait: "); + Serial.println(wait); + +} + +/* Domande: + 1. Introdurre un secondo semaforo che cambia stato quando viene attivato + lo stimolo. + 2. L'uso di delay() puo' essere limitativo: come rimediare? +. +. +. +. +. +. +. +. +. +. + Soluzioni +2. Si potrebbe utilizzare un interrupt per gli stimoli oppure millis() + per gestire le pause. + */ diff --git a/advanced_projects/state_machine/semaforo_rgb_stimolo_millis/semaforo_rgb_stimolo_millis.ino b/advanced_projects/state_machine/semaforo_rgb_stimolo_millis/semaforo_rgb_stimolo_millis.ino index a8a14c0..093879b 100644 --- a/advanced_projects/state_machine/semaforo_rgb_stimolo_millis/semaforo_rgb_stimolo_millis.ino +++ b/advanced_projects/state_machine/semaforo_rgb_stimolo_millis/semaforo_rgb_stimolo_millis.ino @@ -19,82 +19,74 @@ long timer ; enum states_available { // Stati della FMS turn_green, // Dinamico, transizione green, // Statico - wait_button, // Evento - Stimolo - turn_yellow, // Dinamico, transizione yellow, // Statico - turn_red, // Dinamico, transizione red // Statico }; states_available state ; +boolean wait = 0; void setup() { - pinMode(input, INPUT_PULLUP); - Serial.begin(9600); - timer = millis(); + pinMode(input, INPUT_PULLUP); + Serial.begin(9600); + timer = millis(); } RGBLed led(11, 10, 9); //Istanziamo un oggetto led facente parte - // della classe RGBLed +// della classe RGBLed void loop() { -switch (state) { + switch (state) { case turn_green : - state = green ; // Setta il prossimo state - break; + state = green ; // Setta il prossimo state + break; case green: - led.Green(); - if (millis() - timer >= pausa * 2/3) { - state = wait_button ; - timer += pausa * 2/3; - } - break; + led.Green(); + if (wait && millis() - timer >= pausa * 2/3) { + state = yellow; + timer = millis(); + } - case wait_button: - if (digitalRead(input) == LOW) { - state = turn_yellow ; // Il passaggio di stato avviene alla pressione di un bottone - delay(20); // Debouncing, si potrebbe fare con millis() - timer = millis(); - }; - break; + if (digitalRead(input) == LOW) { + wait = 1; + } + break; - case turn_yellow : - state = yellow ; - break; case yellow : - led.Yellow(); - if (millis() - timer >= pausa * 2/3) { - state = turn_red ; - timer += pausa * 2/3; - } - break; - - case turn_red : - state = red ; - break; + led.Yellow(); + if (millis() - timer >= pausa /3) { + state = red ; + wait = 0 ; + timer += pausa /3; + } + break; case red : - led.Red(); - if (millis() - timer >= pausa) { - state = turn_green ; - timer += pausa ; - } - break; + led.Red(); + if (millis() - timer >= pausa) { + state = turn_green ; + timer += pausa ; + } + break; default: // In caso di default si fa giallo lampeggiante - led.Yellow(); - delay(pausa/3); - led.Off(); - delay(pausa/3); - break; + led.Yellow(); + delay(pausa/3); + led.Off(); + delay(pausa/3); + break; -} -Serial.print(millis()); -Serial.print(" \t Stato attuale "); -Serial.println(state); + } + + //Debug: + Serial.print(millis()); + Serial.print(" \t Stato attuale "); + Serial.print(state); + Serial.print(" \t Wait: "); + Serial.println(wait); }