State Machines: Logic
The Problem: Tracking State With Booleans Doesn't Scale
A subsystem often needs to remember "what am I currently doing" — an intake might be idle, actively intaking, holding a game piece, or scoring. Tracking that with a pile of booleans gets unmanageable fast:
private boolean isIdle;
private boolean isIntaking;
private boolean isHolding;
private boolean isScoring;
Nothing stops two of these from accidentally being true at the same time — a bug that's easy to introduce and hard to spot, since "impossible" combinations (isIdle and isScoring both true) compile just fine.
The Fix: One Enum, One Set of Named States
Enums (Ch.11) are exactly the tool for this — a fixed, named set of mutually exclusive states, with the compiler enforcing that a variable can only ever be one of them:
public enum IntakeState
{
IDLE,
INTAKING,
HOLDING,
SCORING
}
private IntakeState currentState = IntakeState.IDLE;
Now the subsystem's state is a single variable, and it's structurally impossible for it to be two states at once. This is a state machine: a system that's always in exactly one of a fixed set of named states, and moves between them according to defined rules.
Real Codebases Do This at Scale
This exact pattern — an enum representing a fixed set of named states for a subsystem — is how real, competitive FRC codebases (like Team 5817's own production code) structure their subsystems, just with more states and richer per-state behavior than this introductory example: an elevator's states might be tied to interpolated target heights that shift based on scoring distance, or a roller's states might each carry their own target voltage. The underlying idea is identical to IntakeState above — a state machine core built on an enum — dressed up with more sophisticated per-state data as a subsystem's real requirements grow.
What Comes Next
Having a named state is only half the picture — a state machine also needs logic that reads the current state and decides what to do (and when to move to a different state). That's the subject of Lesson 25.5.
Common Pitfalls
- Reaching for several independent booleans instead of one enum. This lets impossible/contradictory combinations exist in the code, even though only one is ever supposed to be true — an enum makes that mistake structurally impossible.
- Forgetting a state machine needs an initial value.
currentStateshould always be initialized to a real starting state (likeIDLE) — an uninitialized state variable is anullwaiting to cause aNullPointerException(Ch.12/13) the first time anything reads it.
Key Takeaways
- Tracking "what state am I in" with multiple independent booleans allows impossible combinations and doesn't scale.
- A single enum field, initialized to a sensible starting value, makes a subsystem's current state both self-documenting and structurally guaranteed to be exactly one thing at a time.
- This pattern — enum-based state machines for subsystems — is exactly what real, competitive FRC codebases use, just with richer per-state data as requirements grow.
Derived from other-reference-repo: team-5817-training/subsystems/02-state-based-servo-subsystems.md, 03-state-based-roller-subsystems.md (T5817 31.1-4)
Deck context: mechacoder-test/src/lessons/java-2.js, slide 10 ("State Machines: Logic") — IntakeState enum example