Resources for FSM design

I'm looking for some links / tutorial / book about State Machines, it would be nice if the code is Arduino compatible of course.

I'm interested in: having multiple FSM in the same sketch, understanding signals, the use of goto. Something borderline for a possible transition from FSMs to *FreeRTOS would be interesting.
The purpose is to design some *robot, rover and related functions. C / C++ / (python in case of scaling up to some kinf of raspberryPi) / OOP

Could you suggest some pointers please?

the use of goto

That part is easy. Don't use them.

eaman:
Could you suggest some pointers please?

Unfortunately the best working (what I think) and as well best documented Finite State Machine (FSM) library for Arduino has been withdrawn from the Arduino community by its author about one year ago.

This had happened about one year ago:

After a new IDE version had been released, forum members reported about "compile errors" when using the FSM library and the newest IDE.

One of the forum members took the source code (it was available for free download, but it was not under any "open source license"), did some fixes and re-uploaded the fixed library to the Arduino playground.

After the original author and copyright owner found out, he was very angry.

He claimed the fixed version to be a copyright violation on his code. nobody except himself would be allowed to change the code and make fixed versions available for download. Nobody had asked him before, and he would not be interested to give somebody the right to fix his library code. So he deleted everything: ZIP file with library source code, example sketches source code and all documentation and hints for usage he made about his library.

So it is gone.

Next best for FSM, I think, is a rather old FSM library made by Alexander Brevig in 2010.
It's rather old, but works.
Unfortunately it is not very well documented.

If you can find and download Alexander Brevigs FSM library, I think it would be a good start.

If you need explanations or have any questions about using, please feel free to ask.

While I myself never used Alexander Brevigs FSM library for anything, I think I understand the concept of "callback functions" and "function pointers" he was using in his FSM library (as well as the other guy did, who deleted his FSM library last year from every place he could find it for download.

We can discuss about Alexander Brevigs FSM library and how to use it, if you like to.

@UKHeliBob : thanks. I’ve seen people around reccomend it so I got curious about it. It kinda make sense in the paradigm of a FSM but it scares me a little how it derails the flow of the program.

@jurs : thanks for the (sad) story, it’s quite a tale actually.

Right now I’m just reading around and doing my first tests, some of the most interesting things that I’ve found are related to videogames so I was wondering if there are some resources more uC related. I wish to thank you for the offer but it’s better for me to spend some time on general concepts / terminology before blabbing boring questions :slight_smile:

That’s where I’m now: state

I implemented one just yesterday. It’s inefficient coding, since there’s no reusability and I did get a cramp from doing lots of ctrl-c ctrl-v, but it does work. Approach used is:

  • Have a boolean for each state, all but one initialised false except for the start state which is true
  • Have a set of ifs, one per state, describing what to do when in that state (in my case just do some stuff with LEDs to show it’s in that state, but could of course be “real” work)
  • Have a(nother) set of ifs, one per state, listening to the sensors that cause transitions from that state, and if a legitimate set of inputs is achieved, set the current state false and the target one true (in my case just just listen to some buttons)

Worked for me, but pretty ugly, and if it had many more states and/or buttons I’d still be typing :wink: or at the ER with RSI.

jurs:
If you can find and download Alexander Brevigs FSM library

It's still here in the Playground.

Hi,
What about using SWITCH CASE?

https://www.arduino.cc/en/Reference/SwitchCase

Tom..... :slight_smile:

TomGeorge:
Hi,
What about using SWITCH CASE?

If that's at me, yeah that would be good too. In fact I need to rejig my code, ENUMs will help as well.

Point is though, an FSM can be implemented in many many ways! Main thing is to stick to the definition* of finite states, that a) they are finite in number b) there are rules for getting in and out of a state and c) a state has specific behaviours.

(Ok, that's not a definition as such, but rather my understanding of how they work.)

The best you will find...

eaman:
it scares me a little how it derails the flow of the program.

If you know about typical Arduino sketches with setup() running once and loop() function is being called infinitely, then it is simple to understand the logical flow of most FSM libraries or do your own litttle framework of FSM functions.

While a typical sketch just has ONE setup() and ONE loop() function for the sketch,the typical FSM based program has several such functions: one per operating state.I think the "loop function per state" is named "state function", which is called over and over while the same state is active. And this state function should provide a mechanism to switch over into a different state.

Additionally there has to be a function to switch from one state to another.

Let's say, your machine has four operating states for one LED, controlled by one single button:

  1. LED off (initial state)
  2. LED fade up
  3. LED on
    4.LED fade down

Then perhaps the logic of the 1st state function would look like:
digitalWrite(ledPin,LOW);
if (buttonPressed()) switchstate(fadeUp());

The fadeUp state function then would perhaps contain something like

  • doTheFadingStuff();
  • if (buttonPressed()) switchstate(ledOn());

And the ledOn() function maybe has a logic like
digitalWrite(ledPin,HIGH);
if (buttonPressed()) switchstate(fadeDown());

In case the switchstate() function remembers the time when a certain state becomes active, then you could also do simple timeout functions, which are switching state by time into a different state.

Details depend on the actual FSM library or FSM functions framework you are using. In most cases, the inner working of the FSM framework will be based on the concept of Function pointer - Wikipedia for using different state functions in the same FSM, reducing the work of switching a state to assigning a different function pointer for the new state to become the active state.

Here is jurs LED program implemented without an FSM library

const byte ledPin = 10;
const byte buttonPin = A1;
byte currentButtonState = HIGH;
unsigned long lastChangedTime;
unsigned long currentTime;
int ledLevel = 255;
unsigned long period = 30;
enum states {LEDOFF, FADINGUP, LEDON, FADINGDOWN};
byte currentState = LEDOFF;

void setup()
{
  Serial.begin(115200);
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
  Serial.println("Waiting for button press");
}

void loop()
{
  currentButtonState = digitalRead(buttonPin);
  currentTime = millis();

  switch (currentState)
  {
    case LEDOFF:  //wait for button press with LED off
      if (currentButtonState == LOW)
      {
        lastChangedTime = currentTime;    //prepare to fade LED up
        digitalWrite(ledPin, HIGH);
        currentState = FADINGUP;
        Serial.print("Changing to state ");
        Serial.println(currentState);
      }
      break;

    case FADINGUP:    //fade up the LED until fully on
      if (currentTime - lastChangedTime >= period)  //time to change LED level
      {
        lastChangedTime = currentTime;
        ledLevel--;
        analogWrite(ledPin, ledLevel);
      }
      if (ledLevel == 0)
      {
        currentState = LEDON;
        Serial.print("Changing to state ");
        Serial.println(currentState);
        Serial.println("Waiting for button press");
      }
      break;

    case LEDON:
      if (currentButtonState == LOW)
      {
        lastChangedTime = currentTime;    //prepare to fade LED down
        analogWrite(ledPin, ledLevel);
        currentState = FADINGDOWN;
        Serial.print("Changing to state ");
        Serial.println(currentState);
      }
      break;

    case FADINGDOWN:    //fade down the LED until fully off
      if (currentTime - lastChangedTime >= period)  //time to change LED level
      {
        lastChangedTime = currentTime;
        ledLevel++;
        analogWrite(ledPin, ledLevel);
      }
      if (ledLevel == 255)
      {
        currentState = LEDOFF;
        Serial.print("Changing to state ");
        Serial.println(currentState);
        Serial.println("Waiting for button press");
      }
      break;
  }
}

Points to note :

Because of the time spent in states 1 and 3 the button does not need to be debounced in this instance.

I chose to detect when the button is pressed as opposed to when it becomes pressed, but that would be easy to incorporate if required.

The board on which I was running this has the LED on pin 10 wired such that pulling it LOW turns on the LED hence at first sight the fading may appear to be reversed in the program.

Some of the code could have been put into functions with appropriate names and parameters but in any case the use of the enum helps to describe what is going on in each state.

The entry conditions for each state generally need to be set on exit from the previous state but some general variables are updated each time through loop() regardless of the current state.

The states do not have to be used in any particular order. For instance, it would be easy to add a "get out of the fade" input that terminated state 1 or 3 early and returned to state 0

I will probably not have the time but I would be interested to see the program written using an FSM library

enum states {LEDOFF, FADINGUP, LEDON, FADINGDOWN};
byte currentState = LEDOFF;

I've never used enum, but do mean to redo my own fsm example with that approach. But, one thing I'm puzzled at @UKHeliBob: how does your code "know" that currentState is subject to the states enum?

I know you explicitly start it out as LEDOFF and later set it to FADINGUP and so on, but what's to stop you setting it to any old bollocks with currentState= ANY_OLD_BOLLOCKS? I know ANY_OLD_BOLLOCKS isn't in the states enum, but I don't see what attaches (for want of a better word) currentState to states.

The values given to the constants in the emum in my program will be 0, 1, 2, and 3. You could do the same with #defines. If you want the values to be anything different then you can explicitly set them when defining the enum.

The important thing is that the compiler (possibly the preprocessor) substitutes the default or explicit values for the names in the program. As a result

enum states {LEDOFF = 10, FADINGUP = 11, LEDON = 12, FADINGDOWN = 13};

works just as well as the default values. In my program I don't care what the state values actually are as long as the program uses them.

You could, of course, explicitly set the current state to any value you like in the program, even to one of the enum generated numbers, but the idea is that the enum gives meaningful names to the values to make the program easier to read and understand. As the program uses switch/case then setting the current state to say 255 would cause the program to hang. The switch/case could also have a default value such that the code for it is executed if none of the caases match the value being tested.

Right, thanks, that's clear.

[sound effects]
penny dropping
[/sound effects]

That explains why this compiles:

enum states {LEDOFF, FADINGUP, LEDON, FADINGDOWN};
enum junk {ANY_OLD_BOLLOCKS};
byte currentState;


void setup() {
  // put your setup code here, to run once:
currentState = LEDOFF;
}

void loop() {
  // put your main code here, to run repeatedly:

  switch (currentState)
  {
    case ANY_OLD_BOLLOCKS:
    //
    break;
  }

}

.... since A_O_B enumerates to 0 and is thus valid.

It also explains why this one doesn't compile, giving a duplicate case value error since, A_O_B and LEDOFF are both 0.

enum states {LEDOFF, FADINGUP, LEDON, FADINGDOWN};
enum junk {ANY_OLD_BOLLOCKS};
byte currentState;


void setup() {
  // put your setup code here, to run once:
currentState = LEDOFF;
}

void loop() {
  // put your main code here, to run repeatedly:

  switch (currentState)
  {
    case ANY_OLD_BOLLOCKS:
    //
    break;

    case LEDOFF:
    //
    break;
  }

}

Apologies to the OP for getting a wee bit [further] off topic, but is there any way that the values taken on by currentState can/ be limited to those in the enum?- It would be very cool if the names LEDOFF etc (or their associated numerical values) were the only ones acceptable to currentState.

So if we had:

enum states {LEDOFF, FADINGUP, LEDON, FADINGDOWN};

....then this would be ok:

byte currentState = LEDOFF;

.... but this would not:

byte currentState = LEDBLINK;

.... since LEDBLINK's not in the enum list. (edit: I mean not in the states enum, but in another one or a define.)

byte currentState = LEDBLINK;That would only compile if you had defined or declared LEDBLINK in the program. If you have done that then it implies that you want to use the value given to it.

currentState is, after all, just a boringly normal variable and can be set to any value that you like whether it is logical or fits in the size allowed for the variable.

What the automatic allocation of values by the enum does do is to ensure that each named constant in the enum has a unique value and you don't generally need to know what they are.

Incidentally, constants defined in the enum are const ints but unless you assign values to them yourself then that is not likely to be a problem !

I may be wrong but I think that enum class can do this.

It is a matter of mindset and discipline. Coming from the old 8051 days (boats made of wood and men made of iron). There are a couple of ways to design your program flow. These are very general.

  • Just make it run. Don’t care how fast it runs, if it blocks. “The code I copied has a delay in it. It doesn’t work right if I take it out.”
  • Get it to run as fast as possible, don’t care what the period is. Usually messy. Hard to follow.
  • Clean the code up, but try to keep it fast. If there are a lot of things going on, generally don’t have a good map to go by.
  • FSM. Gives some structure as to code flow, but depending on its structure, can bloat the code for simple tasks.
  • Want to be able to poll things within a certain time period. You mean clock cycles actually mean something?
  • RTOS. Have a heart beat. Everything needs to either be done, or able to be picked back up, within that heart beat.

Take a look at the sticky at the top of this section - demonstration code for several things at the same time. Not really FSM, but a start in trying to keep things going.

Another thread to look at is Can we do multitasking? - Programming Questions - Arduino Forum
One example given has a heart beat serviced by an ISR. States are declared in an array. Very simple.

Another thing that you can look at is stuff that imatix put out years ago called Libero. They no longer support it, but they have a lot of notes on the thinking behind the product. Libero Home Page

They have all the source code available at openamq/tooling/base1/libero at master · imatix/openamq · GitHub
It is a scripting tool that develops a frame work for a FSM. You define the states, what they do, and where they go. It may be too heavy for an Arduino. This stuff was developed for PC's and OS's. They even have a multithreaded version.

One thing to take away from Libero is that you need to know what your states are, what is done in each state based on input condition, and what the next state is based on input condition. GOTOs aren't a bad thing if you control them well.

UKHeliBob:
I will probably not have the time but I would be interested to see the program written using an FSM library

...

Here is a slightly different program, which is NOT using a FSM library, but the code is using some of the programming logic which is used by FSM libraries sometimes, like a "function pointer" to each "state function", and the loop is calling the current state function over and over while the current state is active.

Functional differences to the UKHeliBob FSM example:

No button is used at all, all state switching is done by time only in this code.

fadeUp duration is 5.1 seconds (5100 milliseconds and ends with LEDON state.

fadeDown duration is the same and ends with LEDOFF state.

Duration of LEDON and LEDOFF is fixed to 10 seconds (10000 milliseconds and they will automatically switch to a fade state after timeout.

As I told: No button at all is used. But could be implemented easily.

Besides of that: LED fading of my code does NOT require to use a PWM pin for the LED.

In fact, I'm using the board LED on pin13 in my code, and I have included a function for some kind of software PWM, so that it does not matter whether the LED pin is PWM enabled or not: My sketch will fade the LED up and down, switch OFF or ON, as required.

Perhaps a "blinking state" could be useful, too.

If the TO is still interested in learning how to do FSM with Arduino, I could possibly work out another example with using a button and possibly more different states. Perhaps the TO likes to throw in some words into this thread, too.

Here is my example code, using FSM and function pointers:

const byte ledPin=13;
byte currentState;
unsigned long stateActiveSince;

void softPWM(byte fadeVal)
{
 digitalWrite(ledPin,HIGH);
 delayMicroseconds(fadeVal*10);
 digitalWrite(ledPin,LOW);
 delayMicroseconds((255-fadeVal)*10);
// Serial.println(fadeVal);
}


enum states {LEDOFF, FADEUP, LEDON, FADEDOWN};

void setState(byte index)
{
  currentState=index;
  stateActiveSince=millis();
  Serial.print("Current state is: ");Serial.println(index);
}


long stateTime()
//returns number of milliseconds since current state was set
{
  return millis()-stateActiveSince;
}


void funcLedOff() 
{
   if (stateTime()>10000) setState(FADEUP);
digitalWrite(ledPin,LOW);  
}
void funcFadeUp() 
{
  byte fadeVal=0;
  if (stateTime()>5100) setState(LEDON);
  else{ fadeVal=stateTime()/20; softPWM(fadeVal);}
 return; 
}

void funcLedOn()
  {
  if (stateTime()>10000) setState(FADEDOWN);
digitalWrite(ledPin,HIGH);  
    
  }
void funcFadeDown() 
{
  byte fadeVal=255;
  if (stateTime()>5100) setState(LEDOFF);
  else {fadeVal=255-stateTime()/20; softPWM(fadeVal);}
  return;
}

int (*stateFunctions[])() = {funcLedOff,funcFadeUp,funcLedOn,funcFadeDown};                         
// *currentFunction=funcLedOff; 

                       






void setup()
{
  Serial.begin(9600);
  pinMode(ledPin,OUTPUT);
  setState(LEDOFF);
}


void loop()
{
  stateFunctions[currentState]();
}