Skip to content

Coding Standards

MARSLib follows strict coding standards to maintain consistency, safety, and performance. These standards ensure our code is readable, maintainable, and reliable for FRC competition use.

Avoid memory allocations in time-critical code paths (100Hz+ loops).

Avoid:

@Override
public void periodic() {
// BAD: Creates new object every 20ms
Pose2d pose = new Pose2d(x, y, new Rotation2d(theta));
}
// Reuse objects
private final Pose2d pose = new Pose2d();
@Override
public void periodic() {
pose.setX(x);
pose.setY(y);
pose.getRotation().setTheta(theta);
}

Warning: Mathematical Mutation
Do not pass structural pointers to objects that must preserve historic state (e.g. PID integrators). Always use .clone() if a downstream pipeline requires an immutable snapshot of an Ephemeral Struct.

All shared state must be thread-safe. Use volatile for primitives, concurrent collections, or synchronized blocks.

Avoid:

private double sharedValue; // BAD: Not thread-safe
public void setValue(double v) {
sharedValue = v; // Race condition!
}

Preferred:

private volatile double sharedValue; // Thread-safe primitive
// Or use atomic types
private final AtomicDouble sharedValue = new AtomicDouble();

Write code that’s easily testable with simulated IO.

// Interface-based design enables testing
public class MechanismSubsystem extends Subsystem {
private final MechanismIO io; // Can be real or simulated
// Same code works on robot and in simulation!
}

We use Spotless for automatic formatting. Don’t manually format code.

Terminal window
# Apply Spotless formatting
.\gradlew.bat spotlessApply
# Check formatting
.\gradlew.bat spotlessCheck

Classes: PascalCase

public class SwerveDrive {}
public class MARSVision {}

Methods: camelCase

public void driveRobotRelative() {}
public void updateOdometry() {}

Constants: UPPER_SNAKE_CASE

private static final double MAX_SPEED_MPS = 5.0;
private static final double LOOP_PERIOD_SECS = 0.02;

Private Fields: camelCase with this prefix

private final SwerveDrive drive;
private final VisionIO vision;

Using m_ prefixes to dictate member variables is an archaic C++ practice that poisons Java IDE autocompletion and drastically reduces readability. MARSLib strictly bans Hungarian notation. We rely on modern syntax highlighting and the this. keyword for variable scope.

Avoid:

private final SwerveDrive m_swerve;
private double m_speed;
public void setSpeed(double speed) {
m_speed = speed;
}

Preferred:

private final SwerveDrive swerve;
private double targetVelocity;
public void setVelocity(double targetVelocity) {
this.targetVelocity = targetVelocity;
}

A double named speed has destroyed billions of dollars in real-world aerospace missions through misunderstanding units. Passing raw sensor ticks or ambiguous integers into high-level functions is banned. Variables must describe precisely what they represent.

Avoid:

// What is 'tolerance'? Degrees? Radians?
// What is 'speed'? RPM? M/s? Volts?
public void setAngle(double angle, double tolerance) { ... }
public void runIntake(double speed) { ... }

Preferred:

// Mathematically explicit parameters
public void setAngle(double radians, double toleranceRads) { ... }
public void runIntake(double voltageOut) { ... }

Code that is deeply nested across multiple if/else and for blocks is fragile and requires immense cognitive load to debug under competition pressure. All FRC control loops must remain completely “flat”. use guard clauses and early return expressions immediately.

Avoid:

public void shoot() {
if (systemReady) {
if (targetLocked) {
if (flywheelAtSpeed) {
feeder.run();
}
}
}
}

Preferred:

public void shoot() {
if (!systemReady) return;
if (!targetLocked) return;
if (!flywheelAtSpeed) return;
feeder.run();
}

Separate logic from hardware using interfaces.

// Define the interface
public interface MechanismIO {
double getPosition();
void setVoltage(double voltage);
}
// Hardware implementation
public class MechanismIOReal implements MechanismIO {
private final TalonFX motor;
public double getPosition() {
return motor.getPosition().getValueAsDouble();
}
}
// Simulated implementation
public class MechanismIOSim implements MechanismIO {
private double position = 0.0;
public double getPosition() {
return position;
}
}

Use WPILib’s Command-based pattern for all robot actions.

public class DriveCommand extends Command {
private final SwerveDrive drive;
public DriveCommand(SwerveDrive drive) {
this.drive = drive;
addRequirements(drive); // Always declare requirements
}
@Override
public void execute() {
// Control logic
}
}

Subsystems should manage IO and state, not implement business logic.

public class ElevatorSubsystem extends Subsystem {
private final LinearMechanismIO io;
private final PIDController controller;
@Override
public void periodic() {
// Update control loops
double output = controller.calculate(io.getPosition());
io.setVoltage(output);
}
// Public API for commands
public void setPosition(double meters) {
controller.setSetpoint(meters);
}
}
  • Teleop Periodic: 50Hz (20ms)
  • Auto Periodic: 50Hz (20ms)
  • Odometry: 250Hz (4ms)
  • Vision Processing: As fast as possible (30Hz+)
  • Pre-allocate all objects in constructor.
  • Avoid object creation in periodic() methods.
  • Use object pools for temporary objects.
  • Use AdvantageKit automatic logging.
  • Don’t manually log in time-critical loops.
  • Log at appropriate levels (ERROR, WARN, INFO)
public class SafeSubsystem extends Subsystem {
@Override
public void periodic() {
// Check limits
if (getPosition() > MAX_POSITION) {
stop(); // Emergency stop
MARSFaultManager.fault("Position limit exceeded!");
}
}
}
public class RobustSubsystem extends Subsystem {
private final VisionIO vision;
@Override
public void periodic() {
try {
var pose = vision.getPoseEstimate();
if (pose.isPresent()) {
// Use vision data
} else {
// Handle missing data gracefully
MARSFaultManager.warn("Vision estimate unavailable");
}
} catch (Exception e) {
MARSFaultManager.fault("Vision error: " + e.getMessage());
}
}
}
public class SafeStateMachine extends MARSStateMachine<State> {
public SafeStateMachine() {
super("Safe", State.IDLE);
// Always include emergency stop state
addState(State.ESTOP, () -> {
// Stop all motion
drive.stop();
shooter.stop();
elevator.holdPosition();
});
}
}

Test with real subsystems using simulated IO.

@Test
public void testSwerveOdometry() {
MARSTestHarness.reset();
// Use real subsystem with simulated IO
SwerveDrive drive = new SwerveDrive(new SwerveModuleIOSim());
// Run physics simulation
for (int i = 0; i < 150; i++) {
DriverStationSim.notifyNewData();
SimHooks.stepTiming(0.02);
CommandScheduler.getInstance().run();
}
// Verify results
assertEquals(finalPose, drive.getPose());
}
  • Maintain 80%+ test coverage.
  • Test both success and failure cases.
  • Use realistic physics in tests.

Document all public APIs:

/**
* Swerve drive subsystem with odometry and path following.
*
* <p>This subsystem manages four swerve modules with independent
* wheel angle and velocity control. Odometry is updated at 250Hz
* using a dedicated thread.
*
* @param modules Array of four swerve modules
* @param config Swerve drive configuration parameters
*/
public class SwerveDrive extends Subsystem {
// ...
}
  • Comment why, not what.
  • Explain non-obvious algorithms.
  • Document performance-critical sections.
  • Keep comments up-to-date.
public class PIDSubsystem extends Subsystem {
private final ProfiledPIDController controller;
private final MechanismIO io;
public PIDSubsystem() {
// Use ProfiledPID for smooth motion
controller = new ProfiledPIDController(
8.0, 0.0, 0.15, // Gains from SysId
new TrapezoidProfile.Constraints(2.0, 4.0)
);
}
@Override
public void periodic() {
double output = controller.calculate(io.getPosition());
io.setVoltage(output + calculateFeedforward());
}
}
public class StateMachineExample extends MARSStateMachine<State> {
public StateMachineExample() {
super("Example", State.IDLE);
addState(State.IDLE, () -> {
// Stop all motion
});
addState(State.RUNNING, () -> {
// Run mechanism
});
}
}
public class VisionAlignment extends Command {
private final MARSVision vision;
@Override
public void execute() {
var pose = vision.getPoseEstimate();
if (pose.isPresent()) {
// Use vision data
alignToPose(pose.get());
} else {
// Handle missing data
MARSFaultManager.warn("No vision target");
}
}
}

Before submitting code, verify:

  • Code follows naming conventions.
  • No allocations in periodic() methods.
  • Thread-safe shared state.
  • Proper error handling.
  • Tests added and passing.
  • Documentation updated.
  • Spotless formatting applied.
  • Performance tested (if applicable)

Install git hooks for automatic formatting:

Terminal window
.\install-git-hooks.bat

Our CI automatically verifies:

  • Spotless formatting.
  • 80% test coverage.
  • All tests pass.
  • No compilation errors.
  • Extension Pack for Java - Language support.
  • Gradle for Java - Build integration.
  • Spotless - Format on save.

Next: Learn about our Testing Guide to understand the Digital Twin philosophy!