Search code examples
c++oopswitch-statementembeddedmotion

Implementing a State Machine in C++ for Embedded System


I'm designing a simple motor controller which can be in (at least) 4 states - Idle - Accelerate - Max-velocity - Decelerate.

I figured trying to implement some sort of state machine would be the best way to go. Currently, using a switch statement seems to be a good solution, for its simplicity and it would allow me to keep all the "motion stuff" in one object (let's call it Move).

Does this seem sensible? Can anyone suggest a more suitable method? I understand that some prefer to split each state into its object, however I've been told by several people to avoid inheritance when writing for MCUs.


Solution

  • I would not use inheritance here, not because MCU, but because inheritance implies abstraction, and abstraction for 4 states is not worth it (sure, there are exceptions).

    You have to decide if you want to separate state contexts. If no, then keep it in one class. If you end up with many methods and many attributes, you should split it.

    If you need to split, either use the state pattern or, if you don't have many states, keep it simple:

    Define a class for each state. This class represents state behavior. Don't forget to use constructor as enter point and destructor as leaving point.

    Then define a FSM class to switch between states. FSM should contain a loop that creates a current state, runs it, examines its state and, when needed, destroys the current state and create next one.

    Example:

    // Idle
    class Idle {
    public:
        Idle() {
            // entry point
        }
        ~Idle() {
            // leaving point
        }
        void step() {
            // actual work
        }
        // some getters to examine state
    private:
        // helper methods
        // state attributes (context)
    };
    
    class FSM {
    public:
        void run() {
            State current(sIdle);
            while (current != sExit) {
                switch (current) {
                    case sIdle: {
                        Idle ctx;
                        ctx.step();
                        // examine state
                        // get user input or
                        // call step() again or
                        // decide next state:
                        current = Accelerate;
                        break;
                    }
                    ...
             }
        }
    

    What I like about this design is simplicity, no functors (unlike in the State pattern), and that current state is destroyed before next one is constructed. Also, unlike State pattern, state implementations don't know about other state implementations.

    And don't put any abstraction there. Or put it there, but keep the original version and then compare.