Arduino Forum

Topics => Education and Teaching => Topic started by: jbellavance on Oct 16, 2017, 02:03 am

Title: New State machine tutorial
Post by: jbellavance on Oct 16, 2017, 02:03 am
IHi,

I have just finished a 3 parts State machine tutorial.

You can find it here. (https://github.com/j-bellavance/Tutorials/tree/master/State%20machines%20Tutorial)

Let me know what you think about it.

Jacques
Title: Re: New State machine tutorial
Post by: Welease_Woggah on Oct 23, 2017, 07:11 am
Bit of a leap of faith to think that someone new to FSMs will know what an enum is.

Title: Re: New State machine tutorial
Post by: jbellavance on Oct 23, 2017, 08:37 pm
Quote
What is a state machine?
It is a way to describe what a system is designed to do (output) depending of the state is presently in. As an example, we could use an LED. An LED can only be in one of two states: {ON, OFF}. Each state is mutually exclusive of the other. An LED cannot be simultaneously ON and OFF. There has to be one of the states that have to be declared as the start state. We will also have to remember in which state the machine currently is (the current state).
enum LedStates{ON, OFF};  //The names of all states
LedStates ledState = ON;  //The start state (and the current state after that)
I believe that those two lines, along with the the paragraph above them is simple enough to understand.

Someone new to the state machine concept are not necessarily new to programming. This tutorial is not about C++. It is about implanting a state machine in Arduino's environment which happens to be written in C++.

I my mind, using a "switch" construct is not easier than using enum, since I have met on this site, a few persons that only uses "if" constructs, "since you can to everything with that construct" and won't have anything to do with "switch". But I insist in using it because the "switch" construct is , IMHO, ideal to describe a state machine's behaviour.

So, yes, it is a (double) leap of faith.

Jacques
Title: Re: New State machine tutorial
Post by: LukeAWarren on Feb 07, 2018, 04:59 am
Just finished Part 1.  This is great, thank you so much!

I'm using an Arduino Uno and had to ground my push button with a 10k ohm resistor:

https://www.arduino.cc/en/Tutorial/Button (https://www.arduino.cc/en/Tutorial/Button)

Title: Re: New State machine tutorial
Post by: jbellavance on Feb 07, 2018, 02:48 pm
I am glad if it helps.

Jacques
Title: Re: New State machine tutorial
Post by: mennamorato on Apr 10, 2018, 04:03 am
Thanks this is just what i was looking for to translate a growing messy project into something reasonable.
Title: Re: New State machine tutorial
Post by: noweare on Apr 12, 2018, 01:56 am
I haven't done the exercises leading up to the elevator problem. I just started trying to solve it but it is tougher than I expected. Esp. the part of taking button presses and responding to them as the elevator is moving in the same direction as the request. Sounds like a queue needs to be used but I will go through the tutorials.
Title: Re: New State machine tutorial
Post by: noweare on Apr 14, 2018, 07:37 pm
In the TwoStateMachines.ino of Part1 tutorial   this routine:

void switchMachine() {
  byte pinIs = digitalRead(switchPin);
  if (switchMode == PULLUP) pinIs = !pinIs;
  switch (switchState) {
    case IS_OPEN:    { if(pinIs == HIGH) switchState = IS_RISING;  break; }
    case IS_RISING:  {                   switchState = IS_CLOSED;  break; }
    case IS_CLOSED:  { if(pinIs == LOW)  switchState = IS_FALLING; break; }
    case IS_FALLING: { toggleMachine();  switchState = IS_OPEN;    break; }
  }

Turns the led off but how does the Led get turned on again ?

Title: Re: New State machine tutorial
Post by: jbellavance on Apr 22, 2018, 11:01 pm
Hi,

In fact, it is toggleMachine() that turns the LED on and/or off.

Jacques
Title: Re: New State machine tutorial
Post by: noweare on Apr 28, 2018, 03:05 am
Hello Jacques,

Just finished part 2, vending machine & traffic light. I am getting a good handle on state machines. This is

something I have meaning to spend some time learning. Thank you.

I was thinking the led should represent the switch state ie. be on when the switch is closed and off when the switch is open. or visa versa depending on pullups.

The way it is now each time the switch state enters IS_FALLING it is toggled. So for the same state it is on then the next time it enters it is off.

Is that what you intended ?
Title: Re: New State machine tutorial
Post by: kajnorman on May 09, 2018, 08:57 am
Hello Jacques
  I like Your documentation. I am teaching Electronics/IOT/Network on a 2 year programme, so I would like to hear if You will allow me to use your material.  I have allready done a bit of writing and the contents looks much like what you have done.  My examples are : the blinkmachine, the vending machine, the elevator,  and I also like the "two hand safety machine"  illustrated  in this video :
                             https://www.youtube.com/watch?v=LVToQDLEsVE


Title: Re: New State machine tutorial
Post by: noweare on May 09, 2018, 04:49 pm
You have some excellent videos. I subscribed. Thanks
Title: Re: New State machine tutorial
Post by: jbellavance on May 12, 2018, 10:23 pm
Hello Jacques
  I like Your documentation. I am teaching Electronics/IOT/Network on a 2 year programme, so I would like to hear if You will allow me to use your material.  I have allready done a bit of writing and the contents looks much like what you have done.  My examples are : the blinkmachine, the vending machine, the elevator,  and I also like the "two hand safety machine"  illustrated  in this video :
                             https://www.youtube.com/watch?v=LVToQDLEsVE



Hi kajnorman,

I would  love to see your documentation.

Jacques
Title: Re: New State machine tutorial
Post by: cyrut2 on May 30, 2018, 03:55 pm
Good Day Jacques,

I just dove into state machines and while i am limited to programming i have some latter logic from the 80-90s of GE fanuc PLC. I think this type of "thinking" suites my personal way of creating arduino code. I am currently reviewing and trying to understand the part 1 state tutorial but got stuck.

Code: [Select]
The switch machine (Notice the change in the IS_FALLING state):
void switchMachine() {
byte pinIs = digitalRead(switchPin);
if (switchMode == PULLUP) pinIs = !pinIs;
switch (switchState) {
case IS_OPEN: { if(pinIs == HIGH) switchState = IS_RISING; break; }
case IS_RISING: { switchState = IS_CLOSED; break; }
case IS_CLOSED: { if(pinIs == LOW) switchState = IS_FALLING; break; }
case IS_FALLING: { toggleMachine(); switchState = IS_OPEN; break; }
}
}
START
FALLING
OPEN
RISING
CLOSED
digitalRead(pin) == HIGH
digitalRead(pin) == LOW
TRUE
TRUE
OFF
ON
START
TRUE
TRUE
The setup:
void setup() {
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
if (switchMode == PULLDOWN) pinMode(switchPin, INPUT);
else pinMode(switchPin, INPUT_PULLUP);
}


I understand that you are giving the code the option to swtich modes dependent on pullup or pulldown but i cannot rap my head around what is occuring at each case. Can you help me understand this part of the logic?

Thanks Art, i appreciate the time to make the tutorial it has open my eyes to much simple and cleaner arduino projects.
Title: Re: New State machine tutorial
Post by: echigard on May 31, 2018, 05:03 pm
Hello Jacques,
                     first of all your tutorial is great. For the last two weeks I am trying to find a way for a project, I discovered State Machine and I saw that there is a solution there but now, with your tutorial I am sure that I have to walk in this direction.
 I would ask you please for a clue. How I should manage the state machine statement if I have more control devices, in my case I have a motor and its behavior depends of one sensor and two buttons. Sensor always start and stop, and the buttons change direction.
Any suggestion will be very welcome and thank you again for the tutorial

edgardo
Title: Re: New State machine tutorial
Post by: jbellavance on Jun 11, 2018, 10:41 pm
Hi @echigard,

Then you have a motor with 3 states : running CW, stopped and running CCW
You would probably want to rember the last direction your motor was running before it was stopped. (last running state)

The sensor changes the state of the motor's state as:
- if the state is (runningCW or running CCW) then {last running state = motor's state; motor's state = stopped}
- else: the motor's state is the last running state.

button1 state falling -> motor state : running CW
button2 state falling -> motor state : running CCW

Jacques
Title: Re: New State machine tutorial
Post by: jbellavance on Jun 11, 2018, 11:09 pm
Hi @cyrut2,

Read this  (https://www.arduino.cc/en/Tutorial/DigitalPins)first.

PullUp is just the exact opposite of PullDown. hence:
Code: [Select]
if (switchMode == PULLUP) pinIs = !pinIs;
If the mode is pullup, pinIs = not pinIs

Jacques
Title: Re: New State machine tutorial
Post by: nielyay on Aug 29, 2018, 07:05 pm
Hello,

Thanks for the tutorial sir, its very helpfull.

Btw, i want to ask you on Part 1 files > TwoStateMachines

Code: [Select]
enum LedStates{ON, OFF};

*what is [enum] function?
Title: Re: New State machine tutorial
Post by: nielyay on Sep 17, 2018, 03:38 pm
Hi,
its was great!
Thanks for sharing :)
Title: Re: New State machine tutorial
Post by: dfitterman on Sep 24, 2018, 03:40 am
I have enjoyed reading the example PDF's. Very helpful!
I think that there is an error in Part 1, p. 9. The case IS_FALLING should start with a call to toggleMachine() as shown in the c++ files. Without this it is not different from the previous example.
Title: Re: New State machine tutorial
Post by: Taser2012 on Feb 15, 2019, 12:44 am
Very grateful for this Jacgues.
Title: Re: New State machine tutorial
Post by: GoForSmoke on Feb 27, 2019, 10:48 pm
It is best that you make all of your time variables for a use the same size unsigned integers. The lower 8 or 16 bits of millis() and micros() returns work fine as timers with limited max intervals.

I have a button class that debounces using 8 bit time variables. They take less room and use fewer cycles.

16 bit unsigned millis() is good to over a minute, Arduino variable type is word.

The compiler might not turn our mixed-math source into what we think it will in all circumstances.

Have you seen Nick Gammon's state machine example in his tutorial on reading text without blocking? It's at the 2nd address in my sig space.


 
Title: Re: New State machine tutorial
Post by: terryking228 on Mar 08, 2019, 04:34 am
Hi,
Thanks for the push on State Machines.  I once told the vendor of a $200,000  semiconductor tool that we wouldn't buy it until they provided us with a State Machine diagram of the factory communications interface.  They grumbled for 3 months, sent the diagram, and said "Oh, there's a major upgrade of the software we just installed".

Here's a State Machine example for a Traffic Light that includes vehicle detection on the side street and a Walk request button.  This is in a preprogrammed example package for young kids starting to connect hardware to Arduino.  

Awww. it didn't fit in 9000 bytes. Ummm...

OK, put it on my wiki here:  (NOT good formatting. I will figure it out.. )

https://arduinoinfo.mywikis.net/wiki/Easy-Connect-Software-Outline (https://arduinoinfo.mywikis.net/wiki/Easy-Connect-Software-Outline)

Scroll down to last example..
Title: Re: New State machine tutorial
Post by: jeepi on Apr 14, 2019, 11:06 am
Bit of a leap of faith to think that someone new to FSMs will know what an enum is.

Why is that?

An enum is a variable type which is present in many programming languages and is not more related to FSMs than any other variable types.
Title: Re: New State machine tutorial
Post by: johnnycanuck on Aug 16, 2019, 05:14 pm
This is a very cool tutorial. I've been doing it somewhat sloppily the past few years, and this may help clean up my act. Also motivates me to look for and/or (eventually) come up with an object oriented version.
Title: Re: New State machine tutorial
Post by: GoForSmoke on Aug 17, 2019, 03:15 pm
This is a very cool tutorial. I've been doing it somewhat sloppily the past few years, and this may help clean up my act. Also motivates me to look for and/or (eventually) come up with an object oriented version.
Actually, state machines have been used in OOP code since at least 1970 when Charles Moore released Forth.

State machines are a technique, Johnny.

What part of Canada are you from? My family reunion is still held in NB, you might be a cousin.
Title: Re: New State machine tutorial
Post by: GoForSmoke on Aug 17, 2019, 03:30 pm
Code: [Select]
enum LedStates{ON, OFF};

*what is [enum] function?
It is not a function, more like a variable, it tells the compiler to associate labels with numbers under a certain name.

enum unoSpi { mosi=11, miso, sck };  // mosi starts as 11, miso is 12, sck is 13

enum rgbColor { red=1, green, blue }; // starts at 1

enum smallNumbers { zero, one, two, three };  // zero is by default 0, one is 1, etc

When I have a function that has an unoSpi arg, the compiler will only accept unoSpi values in that place.

Title: Re: New State machine tutorial
Post by: wiggleharris on Sep 27, 2019, 07:07 am
Glad that you shared this and found it quite helpful.
Title: Re: New State machine tutorial
Post by: GoForSmoke on Sep 27, 2019, 08:04 am
But on Arduino I would be careful about how many enums I make since they do take up RAM.

One way to make enums use 1 byte instead of default int,

Code: [Select]

enum Color: byte
{
   RED, GREEN, BLUE
};
Title: Re: New State machine tutorial
Post by: lodani on Oct 22, 2019, 09:59 am
The tutorial is superb, well written and clear. I really appreciate the time and effort you put into sharing that with us.
Title: Re: New State machine tutorial
Post by: GoForSmoke on Oct 22, 2019, 01:07 pm
Someone new to the state machine concept are not necessarily new to programming. This tutorial is not about C++. It is about implanting a state machine in Arduino's environment which happens to be written in C++.

I my mind, using a "switch" construct is not easier than using enum, since I have met on this site, a few persons that only uses "if" constructs, "since you can to everything with that construct" and won't have anything to do with "switch". But I insist in using it because the "switch" construct is , IMHO, ideal to describe a state machine's behaviour.

A switch-case state machine is a good way to break a large or long top-down process into small pieces and wait intervals. A function with a state machine can achieve a whole process by running over and over. Your void loop() may run > 60 times a millisecond, over and over can get somewhere fast at that rate.

I have a demo showing how to use switch-case to remove calls to delay(). It hit me while I was de-blocking a greenhouse automation with a lot of wait-for's that one come-back-later code before the switch could replace any number of cases with timing code (the original GSM code had 10 delays).

Code: [Select]

// add-a-sketch_un-delay 2018 by GoForSmoke @ Arduino.cc Forum
// Free for use, Apr 30/18 by GFS. Compiled on Arduino IDE 1.6.9.
// This sketch shows a general method to get rid of delays in code.
// You could upgrade code with delays to work with add-a-sketch.

#include <avr/io.h>
#include "Arduino.h"

const byte ledPin = 13;
unsigned long delayStart, delayWait;

void setup()
{
  Serial.begin( 115200 );
  Serial.println( F( "\n\n\n  Un-Delay Example, free by GoForSmoke\n" ));
  Serial.println( F( "This sketch shows how to get rid of delays in code.\n" ));

  pinMode( ledPin, OUTPUT );
};


/* The section of the original sketch with delays:
 *
 * digitalWrite( ledPin, HIGH );   --  0
 * delay( 500 );
 * digitalWrite( ledPin, LOW );    --  1
 * delay( 250 );
 * digitalWrite( ledPin, HIGH );   --  2
 * delay( 250 );
 * digitalWrite( ledPin, LOW );    --  3
 * delay( 250 );
 * digitalWrite( ledPin, HIGH );   --  4
 * delay( 1000 );
 * digitalWrite( ledPin, LOW );    --  5
 * delay( 1000 );
 */

byte blinkStep; // state tracking for BlinkPattern() below

void BlinkPattern()
{
  // This one-shot timer replaces every delay() removed in one spot. 
  // start of one-shot timer
  if ( delayWait > 0 ) // one-shot timer only runs when set
  {
    if ( millis() - delayStart < delayWait )
    {
      return; // instead of blocking, the undelayed function returns
    }
    else
    {
      delayWait = 0; // time's up! turn off the timer and run the blinkStep case
    }
  }
  // end of one-shot timer

  // here each case has a timed wait but cases could change Step on pin or serial events.
  switch( blinkStep )  // runs the case numbered in blinkStep
  {
    case 0 :
    digitalWrite( ledPin, HIGH );
    Serial.println( F( "Case 0 doing something unspecified here at " ));
    Serial.println( delayStart = millis()); // able to set a var to a value I pass to function
    delayWait = 500; // for the next half second, this function will return on entry.
    blinkStep = 1;   // when the switch-case runs again it will be case 1 that runs
    break; // exit switch-case

    case 1 :
    digitalWrite( ledPin, LOW );
    Serial.println( F( "Case 1 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 250;
    blinkStep = 2;
    break;

    case 2 :
    digitalWrite( ledPin, HIGH );
    Serial.println( F( "Case 2 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 250;
    blinkStep = 3;
    break;

    case 3 :
    digitalWrite( ledPin, LOW );
    Serial.println( F( "Case 3 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 250;
    blinkStep = 4;
    break;

    case 4 :
    digitalWrite( ledPin, HIGH );
    Serial.println( F( "Case 4 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 1000;
    blinkStep = 5;
    break;

    case 5 :
    digitalWrite( ledPin, LOW );
    Serial.print( F( "Case 5 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 1000;
    blinkStep = 0;
    break;
  }
}


void loop()  // runs over and over, see how often
{           
  BlinkPattern();
}


A full state machine tutorial would show a state machine embedded in a state machine to handle delays indented to the ones you just replaced.