State Machines
State Machines with WPILib Commands V3
A state machine models a system as a set of discrete states, an active behavior per state, and transitions that move between them. WPILib's Commands V3 ships a first-class StateMachine class that gives you all of this, including entry/exit hooks and any-state interrupts, without writing scaffolding by hand.
Reach for a StateMachine whenever a routine has phases that can repeat, skip, or back up to an earlier phase based on sensor input. Auto routines that recover from being knocked off-course, LED logic that escalates between info/warning animations, and superstructure choreography are all natural fits.
A state is a Command that runs while the machine is in it. Transitions are edge-triggered conditions that cancel the current state's command and move to the next state. onEnter / onExit fire around each transition.
StateMachine is a shipped WPILib API
StateMachine class (org.wpilib.command3.StateMachine), released in WPILib 2027 alpha-6 in May 2026. Everything on this page is checked against the published source. Alpha APIs can still shift before the 2027 kickoff release, but this is the real class, not a preview sketch.Anatomy of a StateMachine
Building a state machine takes four steps. Each state wraps a single Command. Transitions are declared on the states themselves and are checked every scheduler tick while that state is active.
arm.low() and friends are factory methods on the Arm mechanism that return a configured Command. The state machine itself doesn't care how they're built — only that each state has one command to run.
Here are those four steps in the workshop's real code: the 6-StateBased branch runs the whole Arm + Flywheel teleop as one state machine — stowed, pickup, spin-up, and ready states, button-driven transitions, a sensor-driven flywheel::isAtTarget handoff, and a switchFromAny panic interrupt.
Loading file...
Two kinds of transitions
Transitions come in two flavors. Use the right one for the kind of state you're leaving.
switchTo(...).when(cond)
Checked every scheduler tick while the state's command is running. Rising-edge guarded, so state.switchTo(state).when(...) never infinite loops — the condition has to go false and then true again to fire a second time.
Does not fire for one-shot commands that never yield — the loop checking it never runs.
switchTo(...).whenComplete()
Checked once, afterthe state's command finishes on its own. Use this for one-shot states that don't loop, or for "and then move on" transitions at the end of a phase.
whenCompleteAnd(cond) is the same idea with an extra check, and takes precedence over a plain whenComplete() when both apply.
Entry and exit hooks
Each state can register any number of onEnter and onExitcallbacks. Useful when entering or leaving a state needs to kick off side-effects that aren't part of the state's main command: schedule a background animation, stiffen the drivetrain, log a marker, etc.
Callbacks fire in the order they were added. Entry callbacks run immediately after the state's command is scheduled, so they can see it running. Exit callbacks run just before the command is canceled (on a transition) or just after it finishes (on a completion).
Cross-cutting transitions with switchFromAny
Some transitions should fire regardless of which state is active: emergency interrupts, mode overrides, "back to idle on disable". Declare those on the state machine itself with switchFromAny(...).
Listing specific states is fine too: sm.switchFromAny(state1, state2).to(state3).when(...) is shorthand for adding the same transition to each listed state. There is also an exit variant: sm.switchFromAny().toExitStateMachine().when(eStop) ends the whole machine instead of moving to another state, and a single state can do the same with state.exitStateMachine().when(...).
Lifecycle, in one breath
- Set
currentStateto the initial state. - The state's command is forked, then
onEntercallbacks fire, so they can see the command already running. - Each scheduler tick, every conditional transition is checked in declaration order. The first rising edge wins:
onExitfires, the command is canceled, and the next state takes over without an extra yield. - If the command finishes on its own, completion transitions are checked once (
whenCompleteAndfirst, then plainwhenComplete). The first matching target becomes the next state. - If no transition matches when the command finishes, the machine exits.
Beyond state machines: where v3 changes what you can write
The StateMachine class is the headline v3 feature for this page, but the underlying coroutine model also unlocks command shapes that would otherwise need a custom Command subclass. The classic case: a command that reads a sensor value mid-sequence and picks a different next step based on what it saw.
The line to notice is int weight = sensors.readPieceWeight(); followed by a three-way if/else picking between different next sub-commands. Because the whole routine is one method body, a value read in one phase is just a local variable the later phases can branch on.
Write control flow as control flow
if/else, and await the step you chose — no phase field, no manual child scheduling. The StateMachine class earlier in this lesson is a structured version of the same idea: declarative transitions between phases without writing the scaffolding by hand.This is the WPILib 2027 alpha
StateMachine class run on Java 25 and deploy to SystemCore. The stack is the WPILib 2027 alpha (GradleRIO 2027.0.0-alpha-6) — the release where StateMachine first shipped.