Unit 06 · lesson

State Machines Beat Spaghetti Logic

Robot code becomes difficult when behavior is described only as a growing collection of conditions.

Consider:

if button:
    run_motor
if sensor:
    stop_motor
if timer:
    reverse_motor
if not sensor:
    run_motor

Which rule owns the mechanism? What happens if several are true?

The problem is not syntax. The behavior has no explicit state model.

Name the states

A state machine makes the robot's current mode visible.

For an intake mechanism:

IDLE
  │ start

INTAKING
  │ object detected

HOLDING
  │ release requested

EJECTING
  │ timer complete
  └────────→ IDLE

Each state can define:

  • allowed outputs;
  • conditions for leaving;
  • timeout or failure behavior;
  • sensor expectations.

Why this helps

If the mechanism is in HOLDING, the code should not simultaneously behave as if it is EJECTING.

State machines reduce accidental combinations.

They also improve debugging because a log can say:

state=INTAKING → transition=object_detected → state=HOLDING

That is more useful than "motor changed."

Add a failure state

Real robots need a path for things that do not happen.

What if the object sensor never triggers?

INTAKING
  │ timeout

FAULT

Now the robot can stop, notify the operator, or try a bounded recovery.

Without a timeout, the code may run the mechanism forever.

Trace the machine

Create a state machine for one behavior:

  • elevator homing;
  • door opening;
  • line-following start/stop;
  • object pickup;
  • docking.

Include:

  1. at least three states;
  2. a condition on every transition;
  3. one timeout or fault path;
  4. outputs associated with each active state.

Then run one scenario on paper and record the sequence of states.

If you cannot explain which state owns the output, the logic is not finished.

State makes behavior inspectable

Consider a robot that should wait, drive forward, stop when it reaches a marker, and then signal completion.

A state model makes the sequence explicit:

WAIT
  │ start

DRIVE
  │ marker seen

STOP
  │ velocity = 0

DONE

Each state has a limited job. Each transition has a condition.

Compare that with scattered conditionals:

if start:
    drive()
if marker:
    stop()
if not moving:
    done = True

The code may work in a simple test, but relationships are hidden. What happens if marker is already true when start arrives? What if done remains true on the next run? What outputs are guaranteed while waiting?

Define state invariants

An invariant is something that must remain true while a state is active.

For example:

StateRequired invariant
WAITdrive output is zero
DRIVEstop condition is checked every cycle
STOPcommanded motion is zero
DONEno automatic restart occurs

Those statements are easier to test than "the robot behaves correctly."

When behavior becomes complicated, resist adding another Boolean flag first. Ask whether the system now has a state that deserves a name.