This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
WPILib-based FRC 2026 robot code (Java 17) built around a sense → schedule → actuate loop. Uses CTRE Phoenix 6 motors, PhotonVision, AdvantageKit (junction) logging, and swerve drive kinematics/estimation.
# Build
./gradlew build
# Format all Java/Gradle/XML/Markdown files (run before committing)
./gradlew spotlessApply
# Deploy to RoboRIO
./gradlew deploy
# Run simulation (opens WPILib sim GUI)
./gradlew simulateJava
# Log replay watcher
./gradlew replayWatchOn Windows use gradlew.bat instead of ./gradlew.
Running from bash (Claude Code / WSL / Git Bash): Gradle requires the WPILib JDK. Set JAVA_HOME before invoking gradlew:
JAVA_HOME="C:/Users/Public/wpilib/2026/jdk" PATH="C:/Users/Public/wpilib/2026/jdk/bin:$PATH" ./gradlew build1. imu.sense() // read sensors
2. drive.sense()
3. vision.sense()
4. CommandScheduler.run() // execute commands
5. drive.actuate() // write actuators
All subsystems are static fields in RobotContainer and statically imported (import static frc.robot.RobotContainer.*) in most files. Do not create new subsystem instances — reference the statics.
| File | Purpose |
|---|---|
| Robot.java | Lifecycle + Logger setup (real vs. simulation/replay) |
| RobotContainer.java | Static subsystem wiring, init()/periodic() order, default commands |
| FieldConstants.java | Field layout, AprilTag JSON lookup |
| SwerveDrive.java | Module configs, kinematics, pose estimator |
| SwerveHW.java | TalonFX/CANcoder hardware interface pattern |
| Vision.java | PhotonPoseEstimator → drive pose estimator fusion |
Every hardware subsystem has three hooks:
init()— configure hardware once at startupsense(Inputs)— read sensors, callLogger.processInputs(path, inputs)actuate(...)— write motor commands, callLogger.recordOutput(path, value)
Inputs is an @AutoLog-annotated POJO. See SwerveInputs.java for an example.
- Create a HW class with
init(),sense(Inputs),actuate(...)and an@AutoLogInputs POJO. - Add static instance to
RobotContainerand callinit()there. - Add
sense()beforeCommandScheduler.run()andactuate()after it inRobotContainer.periodic(). - Use
/SubsystemName/...Logger paths consistent with existing subsystems.
Measured / target / setpoint distinction:
- Sensor readings: short names with no prefix —
angle,vel,drivePos,state - Commanded from higher-level code:
target*—targetVel,targetAng - Controller/trapezoid outputs:
setpoint*—setpointVel,setpointAng
Math-style locals in algorithms/commands:
v_x,v_y(field-relative),vormagfor magnitude,thetafor heading,wfor angular velocity
Constants:
ALL_CAPS_SUBSYSTEM_kGain— e.g.,DRIVE_kS,DRIVE_kV,TURN_kP,TURN_kD- Physical limits:
MAX_VEL(m/s),MAX_W(rad/s)
Trapezoid profiles:
TrapezoidProfile.Constraintsasstatic finalconstantsPIDControllerandTrapezoidProfileas non-static instance fields (they hold state)
Subsystem instances:
- All hardware subsystems (e.g.,
SwerveDrive,Vision) arestaticfields inRobotContainer— initialized once at startup, accessible globally via static import. - Do NOT create new instances of subsystems elsewhere in the codebase.
Visibility (no encapsulation):
- Subsystem and HW class fields:
publicby default (e.g.,SwerveDrive.pose,Vision.cameras). Direct access is preferred over getters — it simplifies data flow and logging. - Command classes:
publiceverywhere
Constants and configuration:
- All constants:
public static final— e.g., gains (DRIVE_kS), limits (MAX_VEL,MAX_W), config arrays (SwerveDrive.configs). - Constants are typically defined in the HW class where they're used or in dedicated constant files (
FieldConstants,RobotContainer).
State holders (not final):
PIDController,TrapezoidProfile, pose estimators: non-static instance fields. These hold state across loop iterations and must not befinal— they may be reset/reconfigured.- Inputs POJOs: instance fields, auto-logged by AdvantageKit.
Summary:
static= single instance, shared across code (subsystems, constants)public= default for fields (no encapsulation; direct access preferred)final= immutable reference for constants and configuration arrays- Avoid
finalon stateful objects (controllers, estimators, profiles)
- CAN bus:
RobotContainer.driveBus(CANBus("Ducky")) — pass to all CTRE device constructors on drivetrain - Swerve module IDs + angle offsets:
SwerveDrive.configsarray — update there, not scattered through code - AprilTag JSONs:
src/main/deploy/apriltags/— loaded byFieldConstants.AprilTagLayoutTypeat runtime
Uses AdvantageKit (junction). Simulation runs in replay mode by default using WPILOGReader (see Robot.robotInit()). Log liberally — sensor readings, setpoints, and control outputs — to enable post-match replay and debugging.
SwerveDrivePoseEstimatorcovariance matrices are tuned inSwerveDrive.init()— don't set them elsewhere.- Vision timestamps must use
Timer.getTimestamp()consistently — seeVision.sense(). FieldConstants.FIELDis currentlyWELDED(2026 Rebuilt Welded field).