dev only

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 a switch (Ch.5). Without it, execution falls through into the next case's code — a switch-based state machine with a missing break can 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(). Scattering currentState = ... assignments across multiple methods makes it much harder to reason about when and why transitions actually happen — keeping all transition logic inside the one switch in periodic() keeps the whole state machine's behavior in one place.

Key Takeaways

  • A switch over the state enum, inside periodic(), 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 a switch-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