Skip to content

Lesson 3: Subsystems

James Li edited this page May 27, 2025 · 16 revisions

Why Use Subsystems?

Think of each subsystem as a self-contained box that manages a specific robot mechanism.

  • Keeps code organized by robot functions (eg. drivetrain, intake)
  • Improve readability
  • Makes testing easier

CTRE Talon FX Motor

alt text

  • Smart motor controller with integrated encoder (can translate mechanical motion into code representing an angle, position, speed, etc)
  • Supports advanced features
    • Built in PID controls
    • Motion profiling
    • Current limiting

Key Talon FX Features

  • Tells the motor to spin forward/backward at x percent power (Motor output power is in between -1.0 to 1.0): .Set(ControlMode::PercentOutput, value)
  • Returns motor's encoder position: .GetSelectedSensorPosition()
  • Tunes motor's built-in PID controllers: .Config_kP(...), .Config_kI(...), .Config_kD(...), .Config_kF(...)
  • .SetNeutralMode(Brake/Coast)

Overview

For each subsystem (eg. Wrist), you may see: image

Each plays a different role to make code clean, testable, and adaptable.

Why This Structure?

  • Makes it easier to switch between real robot and simulation
  • Supports hardware abstraction
  • Enables unit testing without needing the robot
  • Encourages clean separation of logic

File 1 - Wrist.java

aka the main logic of the subsystem

  • Receives sensor data from WristIO
  • Tells WristIO what motor outputs to apply
  • Holds PID loops, state machines, etc.

Think of it as the "brain of the wrist"

File 2 - WristIO.java

aka the Java interface file

  • Defines the contract between the logic and the hardware
  • Includes methods like updateInputs(), setVoltage(), etc. that must be provided by the real/sim classes.
public interface WristIO {
    public void updateInputs(WristIOInputs inputs);
    public void setVoltage(double volts);
}
  • It ensures that implementations like WristIOTalonFX or WristIOSim will work when using Wrist.java

No matter the type of implementation, follow this interface

File 3 - WristIOTalonFX.java

aka real hardware implementation

  • Implements WristIO using a TalonFX motor
  • Talks to real motor controllers
  • Updates sensor readings and sends voltage outputs

Plug in this file for real-world operation

File 4 - WristIOSim.java

aka simulation implementation

  • Mocks sensor values and simulates movement
  • Lets you run and test Wrist.java without a robot
  • Implements WristIO using WPILib's sim features

Swap this in when testing in the simulation

How They Work Together

Wrist.java

↕ (uses)

WristIO.java (interface)

↕ (implemented by)

WristIOTalonFX.java ← for real robot

WristIOSim.java ← for sim/testing

Choose which implementation to use based on which real/sim build mode you want to run

How to "Plug In" The Implementation

  • Inside RobotContainer, create your subsystem like this:
// For real robot
Wrist wrist = new Wrist(new WristIOTalonFX());
// For sim
Wrist wrist = new Wrist(new WristIOSim());

When to Use This Pattern

  • If the subsystem uses motors/sensors
  • Systems that want to be simulated
  • Subsystems that's hardware might change later

Clone this wiki locally