The IO Layer Pattern
The most important architectural rule in MARSLib is the separation of hardware from logic. We use the AdvantageKit IO abstraction pattern to ensure that our robot code is deterministic, testable, and capable of bit-perfect log replay.
1 The Interface
Section titled “1 The Interface”First, we define an interface that lists all inputs the subsystem needs from the hardware. We use @AutoLog from AdvantageKit to automatically generate the logging boilerplate.
public interface FlywheelIO {@AutoLogpublic static class FlywheelIOInputs { public double positionRad = 0.0; public double velocityRadPerSec = 0.0; public double appliedVolts = 0.0; public double currentAmps = 0.0;}
public default void updateInputs(FlywheelIOInputs inputs) {}public default void setVoltage(double volts) {}}2 Hardware setup
Section titled “2 Hardware setup”The “Real” setup talks to actual motors. It has no logicâ€â€it only moves data between the hardware and the Inputs object.
public class FlywheelIOTalonFX implements FlywheelIO {private final [TalonFX](https://v6.docs.ctr-electronics.com/en/stable/docs/api-reference/api-usage/talonfx.html) motor;
public FlywheelIOTalonFX(int id) { motor = new TalonFX(id);}
@Overridepublic void updateInputs(FlywheelIOInputs inputs) { inputs.positionRad = motor.getPosition().getValueAsDouble(); inputs.velocityRadPerSec = motor.getVelocity().getValueAsDouble();}
@Overridepublic void setVoltage(double volts) { motor.setControl(new VoltageOut(volts));}}3 Physics setup
Section titled “3 Physics setup”The “Sim” setup uses math to calculate how a motor would behave. MARSLib uses WPILib Physics Sims (like DCMotorSim) and MARSPhysicsWorld for high-fidelity physics.
public class FlywheelIOSim implements FlywheelIO {private final DCMotorSim sim = new DCMotorSim(DCMotor.getFalcon500(1), 1.0, 0.01);
@Overridepublic void updateInputs(FlywheelIOInputs inputs) { sim.update(0.020); inputs.positionRad = sim.getAngularPositionRad(); inputs.velocityRadPerSec = sim.getAngularVelocityRadPerSec();}}4 Dependency Injection
Section titled “4 Dependency Injection”In RobotContainer, we decide which version to use based on the robot mode. The Subsystem itself only ever sees the FlywheelIO interface!
FlywheelIO io;if (isReal) {io = new FlywheelIOTalonFX(1);} else {io = new FlywheelIOSim();}subsystem = new FlywheelSubsystem(io);📖 Further Reading & External Resources
Section titled “📖 Further Reading & External Resources”-
FRC Log Replay and Simulation - Mechanical Advantage’s definitive 2024 Championship presentation on the why behind the IO-Layer abstraction.
-
AdvantageKit structure - The core repository governing deterministic replay loops on the RIO.
-
AdvantageScope Documentation - Visualizing 3D logs natively in real-time.