กลับไปหน้ารวมไฟล์
object-oriented-state-machine-2ee561-en.md

State machine in a simple project

Many of us who want to program robots or similar applications with the Ardiuno need to run a state machine. For example, my object avoiding robot wants to:

1) Scan the enironment and find the longest possible distance to travel.

2) Turn into the corresponding direction.

3) Drive into that direction while constantly measuring the distance to the next object in front.

4) Stop if that distance is smaller than some minimum value.

5) Go back to step 1.

So how can we write the code in the loop()
function to achieve the above? There are 3 possibilities:

1) We write a very lengthy code block with a switch
or
if
/
else
statement. We might introduce an
enum
to label the state but if we have more than a couple of states and more than a little bit of logic to run in each state, then that code becomes difficult to read, more difficult to understand and even more difficult to maintain.

2) We use one of the FSM (finite state machine) libraries and write the corresponding adapters to these.

3) We write our own simple object oriented state machine that is taylored towards our project.

What I found on the web was that people mainly went for 1) or 2) in their projects. I will further down explain how to progress using 3).

There is a lot of useful information about (finite) state machines on the web. For example:

https://github.com/jonblack/arduino-fsm

For many simple Arduino like projects some of the available packages could be a little bit of an overkill.

Explanation of the code

In order to show the elegance and power of an OO approach I have created a little toy project that demonstrates a state machine with two states only. The state machine initialises two states called white
and
green

The idea is to have a base class State with two virtual functions enter()
and
run()
.

The enter()
code is only called once when a state transition occurs. The
run()
function is called repeatedly and returns a
State*.
This is used by the caller in order to detect if the state is changing. If this is the case, the
enter()
function is called again on the new state.

I have implemented enter()
as empty in the base class, but it could be a pure virtual function, too. I have not added an
exit()
function although it could be useful to have and FSM libraries will likely have it. I discovered in my project that with the two functions
enter()
,
run()
I have enough flexibility to do everything.

Now the loop()
function only checks if the state has changed and calls enter if that is the case. Then it calls
run()
as long as this returns the same state. Hence the logic to determine if a state prevails or is about to change is solely located in the
run()
function of each state. In a multi state process the function could return different states depending on different input parameters, for example, the return value of sensor readings or the pushing of a button.

As we want to utilise the computational power of the Arduino as good as possible, we don't want to use any blocking function, neither in enter()
nor in run(). Please note, that I have violated that principle in the
enter()
method by using a
delay()
call inside the auxiliary function
flash()
.

In a real-world example you would avoid that, and only utilise calls that return immediately. This has been done accordingly in the run()
functions of the states, where a timer is used in order to determine which part of that function should be called.

We create a unique instance of each of the two states.

The state machine toy project

The project simply consists of two LEDs in white and green attached to pin 13 and 12. The two classes White
and
Green
that implement State produce a flashing light signal upon entering. During the
run()
function they will keep the LED switched on for 1s or 2s respectively. At the end of the
run()
function we return the other state.

This video is showing the two states White and Green. Sorry for using a cheap Chinese Arduino clone here, as my proper Arduino is buried deeply in my other project.

The advantages of using your own state machine

It is probably obvious that the approach 3) presented here will outperform solution 1) above. Assume you had 4 states instead of two and would perform very different tasks in the initial run of each state and return different states from the run()
function, depending on other input parameters. Coding this in a big
loop()
function that keeps track of each state and needs to keep track if the state is called the first time or the 2nd and more times will produce lengthy inelegant code.

Also you can add more states to the code without ever requiring to update you loop()
function. You can keep variables like the timer readings locally in your classes without polluting the global namespace (I haven't made use of this in my example code, though).

Solution 2) will likely provide you with a good implementation, too, but you will be tied to the provided framework of the corresponding library. In our example it will be very easy, for example, to detect which was the preceding state. We can simply change the interface of enter()
to
enter(State*)
and then run different codes depending on which state we came from.

EXPANDED TECHNICAL DETAILS

Advanced C++ Programming Architecture

A technical guide for implementing "State Machine" logic using Object-Oriented Programming (OOP) principles, making complex Arduino projects more scalable and easier to debug.

  • Class-Based State Encapsulation: Instead of massive switch-case blocks, each "State" (e.g., IDLE, RUNNING, ALARM) is defined as a separate C++ object with its own enter(), update(), and exit() methods.
  • Polymorphic Event Handlers: The Arduino's main loop simply calls the activeState->update() method. This allows for rapid addition of new features without breaking existing hardware logic.

Complexity Management

  • Hierarchical State Transitions: Includes a "Transition Manager" that handles the logic for switching between states (e.g., from IDLE to WAITING), ensuring that all hardware (like motors or LEDs) is safely reset during the swap.

ข้อมูล Frontmatter ดั้งเดิม

title: "Object oriented state machine"
description: "Educational toy project to show how to write a simple object oriented state machine with your own class hierarchy."
author: "DGarbanzo"
category: "Lab Stuff"
tags:
  - "object oriented"
  - "state machine"
views: 7557
likes: 1
price: 699
difficulty: "Easy"
components:
  - "1x Breadboard (generic)"
  - "2x Resistor 221 ohm"
  - "2x LED (generic)"
  - "1x Arduino UNO"
tools: []
apps:
  - "1x Arduino IDE"
downloadableFiles: []
documentationLinks: []
passwordHash: "a332e5c921d1ce29fe65773fbb2aa28b9867d727dfd8521d66586b64b5b458ab"
encryptedPayload: "U2FsdGVkX19UxKItuhX0yJDWyowlfAptzMbzL008wbYiZTyJsGb5mPIf8xwutPOkis4YYh85xTDIlMHIHWbLrRsk/iZlOWUcmMWZY4kkalw="
seoDescription: "Learn how to build an Object oriented state machine with your own Class hierarchy in this simple Arduino educational project."
videoLinks:
  - "https://www.youtube.com/embed/c6Vtwpx73Ps"
heroImage: "https://cdn.jsdelivr.net/gh/bigboxthailand/arduino-assets@main/images/projects/object-oriented-state-machine-2ee561_cover.jpg"
lang: "en"