Click the blue text above to follow us


Dear programmers, today we are going to talk about the superstar of embedded systems – the state machine! It acts like a traffic commander, organizing the chaotic behavior of your system into a well-structured manner. Imagine this: your smartwatch is usually “asleep” (low power state), and with a press of a button, it “wakes up” (active state), and with a few more taps, it enters “settings mode.” Isn’t that the state machine quietly directing everything behind the scenes?
Today, our protagonist is a sumo robot, whose goal is to push its opponent out of the ring while ensuring it doesn’t fall off itself. This task sounds simple, but writing the code is no joke! We need to use a state machine to break down the robot’s behavior into blocks of “building blocks,” and then “glue” them together with events. Don’t worry, I will guide you in the most entertaining way, helping you evolve from a “confused novice” to a “state machine master”!


Act One: What is a State Machine? Why is it so appealing?
A state machine, simply put, divides system behavior into several “states,” each state like a small room with its own “rules.” When a certain “event” occurs (like pressing a button or detecting an enemy), the system jumps from one room to another. For example:
– Smartwatch: Usually in the “low power” room, pressing a button (event) jumps to the “display” room; pressing again jumps to the “menu” room.
– Sumo Robot: Starts in the “waiting” room, receives a remote control signal (event), jumps to the “search” room; upon seeing the enemy, it charges into the “attack” room!
Why is the state machine so appealing?
1. Simplifies complexity: Breaks down complex systems into smaller pieces, preventing mental overload.
2. Clear logic: Each state only does its own job, making the code as easy to read as a comic book.
3. Easy to extend: Want to add a new state? Just build a new room and change a few lines of code.
4. Easy debugging: Clear states make bugs obvious, no need to scour through the code for clues.
Act Two: The “State Mansion” of the Sumo Robot
Our sumo robot needs to showcase its skills in a circular ring, with the task of finding the enemy, pushing them out, and not falling off itself! It sounds like an action movie, and we need to design a state machine “script” for it. Using PlantUML, the state machine looks like this:
State List
1. Waiting (Wait): The match hasn’t started yet, the robot patiently waits for the infrared remote control’s “start” signal, like a good child.
2. Searching (Search): After receiving the signal, it starts looking for the enemy, which includes two sub-states:
– Rotating: Spinning around, like a dance partner looking for a partner.
– Advancing: After getting tired of spinning, it charges forward like a runaway horse.
3. Attacking (Attack): Upon discovering the enemy, it charges to push! There are three sub-states:
– Enemy to the left: Slightly turns left, like chasing after “that handsome guy on the left.”
– Enemy to the right: Slightly turns right, aiming at “that target on the right.”
– Enemy directly ahead: Charges at full speed, shouting “Let me show you my strength!”
4. Retreating (Retreat): Detects the white line of the ring and quickly runs away! This is the most complex state, with a bunch of sub-states, such as:
– Reversing: Backing up, like a driver realizing they are in a dead end.
– Turning: Adjusting direction to avoid danger.
– Returning to safety zone: Going back to the center of the ring, sighing in relief.
5. Manual (Manual): A debugging tool, manually controlled with a remote, like playing with a remote-controlled car, fun!
Events and Transitions
– Waiting → Searching: The infrared remote sends a “command” (Command), and the robot transforms from “good child” to “warrior.”
– Searching → Attacking: The sensor detects the enemy, and the robot shouts “Found you!” and charges in.
– Searching → Retreating: Detects the white line, and the robot panics, “Oh no, almost fell off!”
– Searching → Manual: Remote button pressed, and the robot says, “Alright, boss, you take command.”
– Attacking → Searching: The enemy has run away (“none” event), and the robot scratches its head, “Where did they go? Keep searching!”
– Attacking → Retreating: The white line appears, and the robot exclaims, “Safety first!”
– Attacking → Manual: The remote intervenes, and the robot helplessly says, “Okay, you are the boss.”
– Retreating → Searching: Retreat complete, and the robot pats its chest, “Safe now, let’s continue!”
– Manual: Listens to remote commands indefinitely, unless powered off, and the robot says, “I am your puppet.”
Act Three: Drawing a “State Machine Comic” with PlantUML
To visualize this pile of states and transitions, I used PlantUML, a fantastic tool! It can turn plain text into beautiful diagrams, making it ten times faster to modify than using PowerPoint, and it can be version controlled. Here are the steps:
1. Install Java and download the PlantUML JAR file.
2. Install Graphviz (a helper for drawing).
3. Write a text file, for example, StateMachine.uml, starting with @startuml and ending with @enduml.
4. Add some code, for example:
@startuml
hide empty description
[*] --> Wait
Wait --> Search : Command
Search --> Attack : EnemyDetected
Search --> Retreat : LineDetected
Search --> Manual : ButtonPressed
Attack --> Search : None
Attack --> Retreat : LineDetected
Attack --> Manual : ButtonPressed
Retreat --> Search : RetreatComplete
@enduml
5. Run the command to generate the image, and when you open it, the state machine diagram looks like a work of art!
This diagram is our “state machine comic,” where each state is a scene, and each arrow is a plot twist, with the robot switching between different scenes like a skilled actor!
Act Four: Code Implementation – From “Skeleton” to “Flesh and Blood”
Having just a diagram isn’t enough; we need to write the state machine in code! Since the sumo robot project isn’t too complex, I used C language for a simple implementation, focusing on if, switch, and structures, running in the main loop.
File Organization
– state_machine.h: Defines the data structure and interface for the state machine.
typedef enum {
STATE_WAIT,
STATE_SEARCH,
STATE_ATTACK,
STATE_RETREAT,
STATE_MANUAL
} State;
typedef enum {
EVENT_COMMAND,
EVENT_ENEMY_DETECTED,
EVENT_LINE_DETECTED,
EVENT_BUTTON_PRESSED,
EVENT_NONE,
EVENT_RETREAT_COMPLETE
} Event;
typedef struct {
State current_state;
Event last_event;
// Other shared data, like timers, sensor history
} StateMachine;
void state_machine_run(StateMachine* sm);
-
state_machine.c: Core logic, including the transition table and main loop.
#include "state_machine.h"
typedef struct {
State current_state;
Event event;
State next_state;
} Transition;
static Transition transitions[] = {
{STATE_WAIT, EVENT_COMMAND, STATE_SEARCH},
{STATE_SEARCH, EVENT_ENEMY_DETECTED, STATE_ATTACK},
{STATE_SEARCH, EVENT_LINE_DETECTED, STATE_RETREAT},
{STATE_SEARCH, EVENT_BUTTON_PRESSED, STATE_MANUAL},
{STATE_ATTACK, EVENT_NONE, STATE_SEARCH},
{STATE_ATTACK, EVENT_LINE_DETECTED, STATE_RETREAT},
{STATE_ATTACK, EVENT_BUTTON_PRESSED, STATE_MANUAL},
{STATE_RETREAT, EVENT_RETREAT_COMPLETE, STATE_SEARCH},
// More transitions...
};
void state_machine_run(StateMachine* sm) {
while (1) {
Event event = process_inputs(sm); // Read sensors, remote control
State next_state = get_next_state(sm->current_state, event);
if (next_state != sm->current_state) {
enter_state(sm, next_state);
}
sm->last_event = event;
}
}
-
State files (like state_wait.c, state_attack.c): Implement the enter function for each state.
// state_wait.c
void enter_wait(StateMachine* sm) {
// Stop motors, wait for infrared signal
motor_stop();
printf("Entered Wait state\n");
}
Implementation Key Points
1. Non-blocking design: All state functions must not block the main loop, using timers to check for timeouts.
2. Circular buffer: Stores recent sensor data to determine the historical position of the enemy.
3. Transition table: An array defines state transitions, adding a new state requires just one line.
4. Input handling: Prioritization, remote control > enemy detection > white line detection.
5. Internal events: Retreat completion triggers EVENT_RETREAT_COMPLETE.
6. Testing and optimization: Skeleton → simulator → real machine → memory optimization → dual-version Makefile.
Act Five: Development Daily Life – “Hilarious Moments”
– Bug Adventure: Forgot to clear events, the robot jumped from “attacking” directly to “manual,” as if possessed by the remote.
– Memory Crisis: Logging too much, RAM overflow, robot crashed, quickly minimized printf.
– White Line Phobia: Retreat not adjusted properly, saw the white line and spun around, like a lost puppy.
After resolving these issues, the robot smoothly “searches-attacks-retreats” in the simulator, and in reality, it pushes the enemy fiercely, making me feel like a robot tamer!
Act Six: Documentation and Summary – “Leaving Fewer Pits for Future Generations”
– PlantUML diagrams: Stored in the repository, version-controlled.
– Markdown report: Records the logic of each state, design ideas, and the blood and tears history.
– Lessons Learned:
– Avoid complex state machine libraries – they take up memory.
– Break down retreat into sub-states – the logic gets too messy.
– Keep debugging printf concise – RAM is precious.
Documentation = a safety net for the future self, and it helps colleagues who take over to avoid some complaints.
Finale: State Machines, the “Joyful Magic” of Embedded Systems
– Transforming chaotic logic into “comic plots”.
– Expanding by just adding rooms and arrows, without tearing down load-bearing walls.
– Debugging allows you to pinpoint “which room is on fire” at a glance.
Bonus: Still floundering in the sea of if-else? Try state machines – give your code rooms, use events as keys, double the joy and halve the bugs! Next time, I will take you from the simulator to the real machine, verifying the “acting skills” of each state. Charge!
Consulting services range:ASPICE, TISAX, ISO21434
GDPR, ISO42001, ISO27001
WeChat & mobile: 13818301770