Arduino C++ finite state machine library [AgileStateMachine]

Hi everyone.
I've recently added to the Arduino library registry, this new library that allows you to easily model and run a finite state machine within urs Arduino projects.

I use FSMs very often in my codes and for this reason some years ago I had developed the YA_FSM library.

AgileStateMachine is born from the ashes of the previous project which performed more or less the same tasks but in a more "rough" way.

The principle according to which it was developed is freely inspired to the "State Machine Framework of the well-known QT" C++ environment (obviously very simplified since it's designed for the embedded world).

Furthermore, this library allows you to associate "Actions" with states. This behavior is inspired by the operation of the SFC (Sequential Function Chart) models widely used in industrial automation.

Some additional info from Github readme:


States represent the different situations in which the machine can be at any time for given inputs.

A Transition connect two states, and are associated with a boolean trigger condition.

The finite state machine can interact with the rest of the firmware:

  • using callback functions;
  • using "boolean" Actions (similar to what is done with PLCs);
  • using a mix between the two methodologies;

.....

SFC_esempio

State definition and callback functions

Each states can be binded up to three different callback functions that will be executed when the state is activated (on enter), when is left (on exit) and while is running (on run).

For each state it is also possible to define an optional maximum and a minimum duration time.

If a callback function is not needed, simply use value nullptr or NULL instead of the name of function.

Transition definition and trigger

To connect two states, a transition need to be defined. The trigger of transition can be performed with a bool function() or a bool variable.
Also the timeout of state itself can be used for triggering to next state.

Action definition

For each state you can define also a set of qualified Actions, that will be executed when state is active causing effect to the target bool variable

The library support this action qualifiers:

Action qualifier Description Short explanation on the effect Duration
N Non-stored Action is active (target = TRUE) as long as the state input is active NO
R Reset Reset to FALSE the value of target variable NO
S Set (or Stored) Set to TRUE the value of target variable NO
L time Limited target = TRUE until the end of the set time or until the state is deactivated YES
D time Delayed target = TRUE after the set time has elapsed until the state is deactivated YES
RE Rising Edge target = TRUE only once after the state is activated NO
FE Falling Edge target = TRUE only once after the state is de-activated*** NO

*** Since the state is not active anymore, target must bel cleared manually

3 Likes

Any comments or suggestions would be greatly appreciated!

Wokwi links of some "scholastic" problems solved with a state machine.

StartStopMotor.ino

Blinky.ino

PedestrianLight.ino

AutomaticGate.ino

RailCrossing.ino

You use new a lot in the code to handle the dynamic construction of the FSM. Any chance to consider a templated, OO based approach with everything of static size ?

also as you are targeting small micro-controllers, on top of const char * for the name, support as well the F() macro so that I could do

State* stCall = fsm.addState(F("Call semaphore"), onEnter, onExit);

(it would mean supporting const __FlashStringHelper * and it would also affect getStateName()`)

HI @J-M-L and thanks for your comment!
I hadn't thought about it, but it's great advice and will be the next thing I do.

As for "a templated, OO based approach with everything of static size" I'm not sure I understand exactly what you mean. I already had plans to include methods to add States, Action and Transitions more ore less like this (so without the "new" constructor)

void addState(State &state) {
	state.setIndex(m_states.size());
	m_states.append(&state);
}
....
....
State stateA ("Name", 0, 1000, fn_a, fn_b, fn_c);
fsm.addState(stStateA);

I meant trying to have a way to describe the fsm at compile time without having to use a linked list and dynamic instantiation but rather a fixed size array (size set from a template approach) . This way the IDE would report exactly how much memory is being used after the compilation.

Understood.
I'm not a big fan of arrays... but I have to admit that on small MCUs it might be a wiser choice.

Although in reality with the most modern MCUs I believe that there are more than enough resources to manage the dynamic allocation of the linked list, especially thinking about a global use of the StateMachine class so that the allocation is done only at firmware startup .

In any case, I'll try to think about it in the next few days, thanks for the food for thought!

Sure, it’s more for the smaller MCU

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.