Welcome to MARSLib, FRC Team 2614's flagship AdvantageKit architecture! We are thrilled to have you writing code for the 2026 REBUILT season.
This repository isn't just standard Java—it is a championship-tier Simulator and Data-Logging framework. Writing code here requires understanding a few core design rules. This guide will walk you through them so your code merges cleanly into the robot.
We never talk to hardware directly inside a Subsystem (like SwerveDrive.java or Elevator.java). If you instantiate a TalonFX directly inside your Subsystem, you break the simulator!
Instead, we use Dependency Injection. Every mechanism must be split into three core files:
This defines what data the mechanism needs to log and what commands it can receive.
public interface ElevatorIO {
public static class ElevatorIOInputs {
public double positionMeters = 0.0;
public double currentAmps = 0.0;
}
public default void updateInputs(ElevatorIOInputs inputs) {}
public default void setVoltage(double volts) {}
}This is the ONLY place a Motor Controller or Physical Sensor can exist.
public class ElevatorIOReal implements ElevatorIO {
private final TalonFX motor = new TalonFX(Constants.ElevatorConstants.MOTOR_ID);
@Override
public void updateInputs(ElevatorIOInputs inputs) {
inputs.positionMeters = motor.getPosition().getValueAsDouble();
inputs.currentAmps = motor.getStatorCurrent().getValueAsDouble();
}
@Override
public void setVoltage(double volts) {
motor.setVoltage(volts);
}
}This is how we test offline! Wrap it in a Dyn4j physics body or WPILib math model.
public class ElevatorIOSim implements ElevatorIO {
private double position = 0.0;
private double simulationVelocity = 0.0;
@Override
public void updateInputs(ElevatorIOInputs inputs) {
// Run theoretical time-step math
position += simulationVelocity * Constants.LOOP_PERIOD_SECS;
inputs.positionMeters = position;
inputs.currentAmps = 0.0; // Perfect world!
}
}Your actual Elevator.java subsystem will inject this IO layer inside its constructor. RobotContainer.java will decide whether to inject the Real or Sim version based on whether you are running a deployment or a desktop test.
If it isn't logged, it doesn't exist. AdvantageKit makes our codebase completely deterministic.
Almost all your sensor data is handled automatically by the updateInputs routine above. However, if you are computing logic (like a target state machine goal, an odometry pose, or an autonomous trajectory), you must log it explicitly using the Logger.
// Inside your Subsystem's periodic() loop:
Logger.recordOutput("Elevator/TargetHeight", targetHeightMeters);
Logger.recordOutput("Elevator/AtGoal", Math.abs(current - target) < 0.1);Once logged, open advantagescope_layout.json to visualize these outputs natively in the 3D viewer.
We strictly enforce Google Java Style guidelines. If you try to push code with messy indents or unused imports, GitHub Actions will reject your Pull Request.
To fix formatting automatically, run this command in your VS Code terminal before pushing:
# On Windows:
.\gradlew spotlessApply
# On Mac/Linux:
./gradlew spotlessApplyTip
Run ./gradlew installGitHooks in your terminal! It forces your computer to automatically run spotlessApply locally every time you type git commit.
- Create a branch (e.g.
feature/auto-alignorbugfix/elevator-jitter). - Do not hesitate to use the desktop simulator (
.\gradlew simulateJava) to verify your logic offline. - Once satisfied, execute
.\gradlew buildto ensure no compile errors exist. - Stage, commit, and push your branch.
- Create a Pull Request (PR) against the
mainbranch. - The CI pipeline will automatically run all JUnit physics-integration tests. If the tests pass and the code is formatted properly, you can request a review from a Robotics Lead.
All subsystem tests use physics-backed IOSim implementations and the dyn4j engine—never Mockito for mechanism behavior. Every test's @BeforeEach must call MARSTestHarness.reset() to prevent static state bleed:
import com.marslib.testing.MARSTestHarness;
@BeforeEach
public void setUp() {
MARSTestHarness.reset();
// ... construct your subsystems here
}
@AfterEach
public void tearDown() {
MARSTestHarness.cleanup();
}Warning
Omitting MARSFaultManager.clear() will cause phantom critical-fault flags to leak between test methods, causing random assertion failures that only appear when the full suite runs.
All tunable parameters live in frc.robot.constants.*:
| Class | Purpose |
|---|---|
ModeConstants |
REAL/SIM/REPLAY auto-detection |
SwerveConstants |
Module offsets, kinematics, PID gains |
VisionConstants |
Ambiguity thresholds, std dev scaling |
FieldConstants |
Hub positions, field dimensions |
ShooterConstants |
Shot speeds, exit heights |
SuperstructureConstants |
Cowl angles, intake positions |
SimulationConstants |
Dyn4j physics tuning |
Never hard-code magic numbers in subsystem files — always define them in the appropriate constants class.
The BuildConstants.java file is auto-generated by the Gradle build task generateVersionFile. If your IDE shows resolution errors:
- Run
.\gradlew.bat generateVersionFileonce to create the file. - Reload/refresh the Java project in your IDE.
- The generated file is at
build/generated/source/version/main/java/frc/robot/BuildConstants.java.
This file is .gitignore'd by design — it must be regenerated on each machine. If the git command is not available (e.g., on CI without Git), the fields will default to "unknown".
We enforce championship-grade formatting and logic structuring. Your agents and pull requests will be rejected if you violate these rules:
- Never Nester: Deeply nested conditional loops are banned. Force early returns and immediate guard clauses.
- WPILib Units: Leverage
edu.wpi.first.unitswhere applicable. If storing physics values in a primitivedouble, the unit suffix MUST be explicit in the variable name (e.g.,double velocityMetersPerSecond,double accelerationNewtons, NOTdouble vel). - No Hungarian Notation: Strip prefixes like
m_from variables. - Explicit Descriptions: Ensure all mathematical bounds variables are descriptive and explicit. Exclude single character names except inside standard increment iterations (
for (int i = 0...). - Citation Required: Mathematical equations in algorithms or kinematics must carry a JavaDoc class/inline URL reference indicating the text/math paper they implement.
Happy Coding! 🪐