An FSM is a system that is always in exactly one state. Transitions happen based on events. Here a sentry robot searches → approaches → scores → returns to idle.
stateDiagram-v2
[*] --> Idle
Idle --> Searching: enable sentry mode
Searching --> Searching: spinning, no target yet
Searching --> Approaching: AI Vision sees target
Searching --> Idle: timeout (no target in 10s)
Approaching --> Approaching: target still visible
Approaching --> Searching: target lost mid-approach
Approaching --> Scoring: distance ≤ 100mm
Scoring --> Idle: scoring complete
Scoring --> Searching: scoring failed (object dropped)
Idle --> [*]: disable sentry mode
A state machine is the upgrade from nested if-else spaghetti to clean, readable robot logic. Every mechanism has a set of states it can be in. Define the states, define what triggers transitions between them, and the code almost writes itself.
Without a state machine, mechanism logic grows into nested conditionals that are hard to read and impossible to debug:
With a state machine, the same logic becomes:
The transitions (what causes state changes) are handled separately. Each piece of logic has exactly one home.
clawUpdate() handles when to change state. The bottom half handles what to do in each state. Keep these two sections structurally separate in your code — it makes both easier to modify independently.LOADED to the enum, add one transition (stall or optical → LOADED), and add one action (case LOADED: intake.move(0);). No other code changes needed. That is the power of FSM structure.Instead of a linear list of drive commands, think of your autonomous as a sequence of states: DRIVE_TO_GOAL, SCORE, RETURN, AWP_TOUCH. Each state runs until a condition exits it.
pid_drive_set + pid_wait) is simpler and adequate. FSM-based autonomous is most valuable when states need to respond to sensor feedback (did the game element actually score? is the robot stuck?) rather than pure dead-reckoning. Use FSM when you need the extra intelligence, not by default.get_digital_new_press is simpler