1

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.

M-R
  • 411
  • 2
  • 6
  • 15
  • Too broad. But see [boost meta state machne](http://www.boost.org/doc/libs/1_60_0/libs/msm/doc/HTML/index.html) – juanchopanza Dec 20 '15 at 13:51
  • "Avoid inheritance when writing for MCUs" is nonsensical. Maybe they meant to avoid virtual functions, which still is questionable advice? – John Zwinck Dec 20 '15 at 13:56
  • @JohnZwinck I've seen people on here explicitly state this. Personally, I can't see why, but I'm not expert... – M-R Dec 20 '15 at 13:58
  • Explicitly state what exactly? Have a link you can share? – John Zwinck Dec 20 '15 at 13:59
  • 1
    If You don't want inheritance why You ask about c++. ? Did You interested `State Patern` ? should be right. https://sourcemaking.com/design_patterns/state/cpp/1. – Mbded Dec 20 '15 at 14:00
  • Explicitly stated that inheritance should be avoided. I'll have a look around. – M-R Dec 20 '15 at 14:00
  • Maybe because inheritance means virtual methods and virtual methods mean overhead (a tiny one). I would refine the advice: "Don't _overuse_ inheritance when writing for MCUs". Maybe because of RTTI, but this can be tweaked with compiler. So probably it's just easier to say "don't use it" instead of explaining it all... – Adam Trhon Dec 20 '15 at 14:08
  • @Mbded Maybe because C++ lends itself to writing fine, performant code without requiring inheritance. – juanchopanza Dec 20 '15 at 14:29
  • @Dadam: But inheritance *doesn't* mean virtual methods. In C++ inheritance is separate from polymorphism. – Ben Voigt Dec 20 '15 at 16:08
  • @BenVoigt of course, I phrased it wrong. It _leads_ to virtual methods (or sharing code, but that's not a good practice) – Adam Trhon Dec 20 '15 at 18:42
  • @MartinRand btw, I would remove the 'motion' tag, as this question has nothing to do with motion itself (it's about c++) – Adam Trhon Dec 20 '15 at 19:02
  • I would not regard those as valid states. There are two variables; speed and rate of change of speed, that latter determines the setpoint value of the first. That is current state is the speed and the next state is determined by the acceleration (positive, negative or zero). Motor speed control is best managed by a PID loop rather than a state machine, with acceleration managed by a secondary profile controller that modifies the speed setpoint over time. No state, just arithmetic. If you are using open-loop contro, then you just have the profile controller. – Clifford Dec 20 '15 at 21:25

1 Answers1

2

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.

Adam Trhon
  • 2,915
  • 1
  • 20
  • 51
  • Inheritance doesn't *mean* abstraction. Neither does abstraction imply inheritance. – juanchopanza Dec 20 '15 at 14:15
  • @juanchopanza reworded a bit. Now usually you use abstraction when you want to share code, which is not good, or when you want to "use a class in place of another one" (there was a nice quote about this, cannot remember). This I call abstraction. – Adam Trhon Dec 20 '15 at 14:20
  • It was something as "don't use inheritance when one code is shared between multiple classes, but when one code works with multilple classes". Anyone knows it? – Adam Trhon Dec 20 '15 at 14:27
  • So, why don't you advise the use of a Switch statement? – M-R Dec 20 '15 at 14:29
  • @MartinRand I didn't say that. A switch statement will be a part of FSM main loop. Each case should create it's class, use it, destroy it and set next state. – Adam Trhon Dec 20 '15 at 14:36
  • @Dadam Why not just contain all the motion methods in one class? – M-R Dec 20 '15 at 14:42
  • @MartinRand I updated the answer. You can contain, but if you have more methods for one state, or state specific class attributes, it's probably better to split. – Adam Trhon Dec 20 '15 at 15:52
  • @Dadam This is starting to make sense now :) Do you think you could provide a code example in your answer? – M-R Dec 20 '15 at 15:54
  • @MartinRand if this answer fits you, please consider accepting it. – Adam Trhon Dec 21 '15 at 12:33
  • @Dadam It's good. If you elaborate it a bit more, show object creation deletion, etc, I'll select it as best answer :) – M-R Dec 21 '15 at 17:03
  • @MartinRand You mean how to construct FSM? Or what to put into Idle constructor? – Adam Trhon Dec 21 '15 at 18:46
  • @Dadam Both really, and inside the switch statement :) – M-R Dec 21 '15 at 19:10