Managing Transitions
Reading the Current State, Every Loop
Lesson 25.4 gave a subsystem a single enum field representing its current state. The natural place to act on that state — and decide when to transition to a different one — is a switch (Ch.5) inside the subsystem's periodic() method, which the scheduler calls once every loop (Lesson 25.3):
@Override
public void periodic()
{
switch (currentState)
{
case INTAKING:
motor.set(0.5);
if (sensor.get())
{
currentState = IntakeState.HOLDING; // transition: a sensor reading changed the state
}
break;
case IDLE:
motor.set(0);
break;
case HOLDING:
motor.set(0.1); // gentle hold pressure
break;
case SCORING:
motor.set(-0.5);
break;
}
}
Each case does two jobs: it runs whatever behavior belongs to that state (motor.set(...)), and it checks whether a transition to a different state should happen (here, a sensor detecting a game piece moves the intake from INTAKING to HOLDING).
Transitions Are Just Reassigning the State Field
A transition is nothing more than assigning a new value to the state field — no special syntax beyond what Ch.2/Ch.11 already covered. What makes a state machine's behavior correct is where those reassignments happen: inside the specific case for the state that condition applies to, based on whatever real-world signal (a sensor, a timer, a driver input) should trigger the change.
Why This Belongs in periodic()
periodic() runs every single scheduler loop, which is exactly the cadence a state machine needs — checking "should I transition now?" once per loop is what makes a sensor-triggered transition (like the intake noticing a game piece) responsive in real time, rather than only checked occasionally.
Common Pitfalls
- Forgetting
break;in aswitch(Ch.5). Without it, execution falls through into the nextcase's code — aswitch-based state machine with a missingbreakcan silently run the wrong state's behavior on top of the intended one. - Putting transition logic in the wrong
case. A transition condition checked inside the wrong state's case either never triggers, or triggers behavior meant for a different state entirely. - Mutating the state field from outside
periodic(). ScatteringcurrentState = ...assignments across multiple methods makes it much harder to reason about when and why transitions actually happen — keeping all transition logic inside the oneswitchinperiodic()keeps the whole state machine's behavior in one place.
Key Takeaways
- A
switchover the state enum, insideperiodic(), is the natural place to both run each state's behavior and check for transitions to a different state. - A transition is just a plain reassignment of the state field — the important part is placing it inside the correct state's
case, gated on the right real-world condition. - Running this logic in
periodic()(called every scheduler loop) is what makes transitions responsive to sensors and other real-time signals. - Missing a
break;is the single most common bug in aswitch-based state machine.
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 11 ("Managing Transitions") — IntakeState switch example