State-Based Control
State-Based Control - Structured Subsystem Management
State-based control organizes subsystem behavior into discrete, well-defined states. Each state encapsulates target positions, tolerances, and specific configurations, making robot code more organized and maintainable.
🎯 Key Concept: Instead of manually setting positions and tolerances everywhere, define states that encapsulate all the information needed for each subsystem configuration.
Understanding State-Based Architecture
🏗️ State Pattern Benefits
State-based control provides structure and predictability to subsystem behavior:
⚙️ State Components
State Enum
Defines all possible subsystem states with targets
Current State
Tracks which state the subsystem is currently in
setState() Method
Changes state and applies the new configuration
State-Based Implementation in Code
🔧 State-Based Configuration Example
1// Define possible states with targets and tolerances
2public enum ArmState {
3 LOW(Degrees.of(0), Degrees.of(1)), // Ground pickup
4 HIGH(Degrees.of(90), Degrees.of(2)), // High scoring
5 BACKWARD(Degrees.of(180), Degrees.of(3)); // Defense position
6
7 private final Angle targetPosition;
8 private final Angle tolerance;
9
10 ArmState(Angle targetPosition, Angle tolerance) {
11 this.targetPosition = targetPosition;
12 this.tolerance = tolerance;
13 }
14
15 public Angle getTargetPosition() { return targetPosition; }
16 public Angle getTolerance() { return tolerance; }
17}
18
19// In your subsystem class
20private ArmState currentState = ArmState.LOW;
21
22public void setState(ArmState state) {
23 currentState = state;
24 setPosition(state.getTargetPosition());
25}
26
27public boolean atState() {
28 return Math.abs(getPosition().in(Degrees) -
29 currentState.getTargetPosition().in(Degrees))
30 < currentState.getTolerance().in(Degrees);
31}
32
33public ArmState getCurrentState() {
34 return currentState;
35}
36Workshop Implementation: State-Based Control
🔄 Before → After: Implementation
📋 Before
- • Manual position and tolerance management
- • Hard-coded values scattered throughout code
- • Difficult to add new arm positions
- • No clear organization of arm configurations
- • Tolerance values repeated in multiple places
✅ After
- • Well-defined states: LOW, HIGH, BACKWARD
- • Each state encapsulates target position and tolerance
- • Easy to add new states by extending the enum
- • Clear, readable code with semantic state names
- • Centralized configuration management
Loading file...
🔍 Code Walkthrough
State-Based Architecture:
- • ArmState Enum: Defines LOW, HIGH, and BACKWARD states
- • Encapsulated Targets: Each state contains its target position
- • State-Specific Tolerances: Different tolerance for each position
- • Current State Tracking: Always know which state the arm is in
Enhanced Features:
- • setState() Method: Simple way to change arm configuration
- • atState() Check: Easy validation using state-specific tolerance
- • Semantic Names: Code clearly shows intent (HIGH vs 0.25 rotations)
- • Extensible Design: Add new states without changing existing code
💡 Next Step: State-based control makes our arm subsystem much more organized and maintainable! This pattern scales well as we add more complex behaviors.
⚖️ State-Based vs Manual Control
Manual Control Issues:
- Hard-coded values scattered everywhere
- Difficult to maintain and modify
- No clear organization of configurations
- Prone to inconsistencies and bugs
- Hard to understand code intent
State-Based Benefits:
- Centralized configuration management
- Easy to add and modify states
- Clear, semantic code that shows intent
- Consistent tolerance and target handling
- Scales well with complex behaviors
💡 State Design Best Practices
🏷️ State Naming Guidelines
Use Descriptive Names:
HIGHinstead ofSTATE_1SHOOTINGinstead ofFASTSTARTING_POSITIONinstead ofSTATE_2
Group Related States:
- Arm: LOW, HIGH, MIDDLE, BACKWARD
- Flywheel: STARTING_POSITION, MID_FIELD, FULL_FIELD
- Elevator: INTAKE, HAND_OFF, LEVEL_4
📋 State Organization Tips
Include All Necessary Data:
- Target position/velocity
- State-specific tolerance
- Optional: timing constraints
- Optional: safety limits
Design for Extensibility:
- Start with basic states, add complexity later
- Use constructor parameters for flexibility
- Consider state transitions and validation
- Plan for debugging and telemetry
🎯 Why This Approach Works:
State-based control provides a clean separation between configuration (what the states are) and behavior (how to reach them). This makes code easier to understand, test, and maintain as your robot becomes more complex.