sign in
Start typing to search across all 16 weeks…
home / summer / week 8
Summer · Week 8 of 8

Recap & Resources

pull everything together. here's your java cheat sheet, the links that actually matter, and the final piece of your project.

Java Foundations Recap

Seven weeks of content, distilled. use this as a reference when you're writing code and forget something — that's what it's here for. no shame in checking :)

Week 1 — The Basics

Week 1 gave you the atoms that everything else is built from. types, variables, naming, casting. none of it feels exciting in isolation, but when you're deep in a subsystem at 11pm during build season and a casting bug is silently giving you the wrong encoder (encoders measure how far a motor shaft has rotated, giving you position and velocity data) position, you'll be really glad you understand how this works. these are the rules that never go away.

ConceptKey SyntaxWRT Rule
Constantsfinal int kMotorID = 5;k prefix, always final
Member varsprivate double m_speed = 0.0;m_ prefix, always private
Primitive typesint, double, booleanUse double for motor speeds (−1.0 to 1.0)
Widening castdouble d = myInt; (automatic)int → double is safe, no cast needed
Narrowing castint i = (int) myDouble;Truncates (doesn't round). Watch encoder math!
Comments// inline, /* block */, /** javadoc */Every public method gets a Javadoc

common gotcha: narrowing casts truncate silently. if your encoder calculation returns 3.99 rotations and you cast to int you get 3, not 4. this will not cause a compiler error. you will not know why your robot is off by a full rotation. use Math.round() when you need rounding, and only cast when you genuinely want truncation.

Week 2 — Logic & Control Flow

Week 2 is where your code started making decisions. in real robot code, you're constantly asking questions: is the shooter up to speed? is the intake extended? is the robot in auto or teleop? every sensor check, every state guard, every auto routine selection runs through this logic. if you can write a clean if/switch block you can write 80% of the control flow you'll need in a real robot.

ConceptKey SyntaxFRC Use Case
Boolean operators&& || !Guard conditions: isEnabled && hasTarget
if / else if / elseif (x) { } else if (y) { } else { }Auto state logic, sensor range checks
Switchswitch(val) { case X: ...; break; }Game state machine, robot mode selection
Ternaryint x = (a > b) ? a : b;Compact speed clamping, direction flags

common gotcha: forgetting break; in a switch case causes fall-through. Java will silently execute the next case's code after yours finishes. this is one of the most common first-season bugs and the compiler gives you zero warning about it. every case needs a break; unless you intentionally want fall-through (which is rare).

Weeks 3 & 4 — Loops, Arrays, Methods

Weeks 3 and 4 gave you the ability to repeat work and package it up neatly. swerve drives have four modules — you don't write four copies of the same logic, you loop over an array. unit conversions happen dozens of times per second — you don't inline the math every time, you write a static method in a utility class and call it. these are the tools that keep robot code from becoming a spaghetti mess.

ConceptKey SyntaxFRC Use Case
for loopfor (int i = 0; i < n; i++)Process encoder arrays, iterate modules
while loopwhile (condition)Avoid in robot code — periodic() is your loop
enhanced forfor (Type x : array)Read all swerve module states
Array declarationdouble[] arr = new double[4];Swerve module speeds, sensor history buffers
Static methodspublic static double clamp(double v, ...)Math utilities in Constants or MathUtil
Return typespublic double getVelocity() { return m_vel; }All getters in subsystems

danger: never put a while loop inside periodic(). periodic() is already being called every 20ms by the scheduler — it IS your loop. if you write while (condition) inside it, you will block the entire robot loop, the watchdog will fire, and your robot will fault or disable. this is a disqualification risk during a match. for loops are fine (as long as they're bounded). while loops are not.

Weeks 5, 6, 7 — OOP

Weeks 5, 6, and 7 are where everything came together. classes, inheritance, interfaces, enums — these aren't abstract concepts, they're the direct blueprint of how WRT's robot code is structured. every mechanism on the robot is a class that extends SubsystemBase. every state machine uses an enum. every abstract sensor abstraction uses an interface. you've been learning the actual architecture of our robot, just with simplified examples.

ConceptKey SyntaxWRT Pattern
Subsystem classpublic class Shooter extends SubsystemBaseOne class per mechanism, in subsystems/
Constructorpublic Shooter() { m_motor = new TalonFX(kMotorID); }Initialize hardware, apply configs
periodic()@Override public void periodic()Logging, odometry (estimating where the robot is on the field by tracking motor rotations and gyro angle over time), state updates — runs every 20ms
Inheritanceextends SubsystemBaseWPILib gives you the scheduler loop for free
Interfacesimplements ISensorUsed for vision targets, sensor abstraction
Enumsenum State { IDLE, SPINNING, AT_SPEED }Subsystem state machines — very common
Private modifierprivate final TalonFX m_motor;Hardware fields are ALWAYS private final

the most common mistakes you'll make in your first real code session

knowing the concepts is one thing. actually sitting down to write subsystem code for the first time is another. these are the six things that will trip you up, almost guaranteed, in that first real session.

Integer Division
5 / 2 = 2, not 2.5
When both sides of a division are int, Java discards the decimal entirely. this doesn't round, it truncates. encoder math is where this bites hardest — if you write ticks / kTicksPerRev and both are int, you'll silently lose precision on every cycle. fix: (double) ticks / kTicksPerRev. make one side a double and the whole expression becomes double division.
== vs .equals()
For objects, use .equals()
== asks "are these the exact same object in memory?" which is not what you want for string comparisons. two separate String objects with identical characters will return false from ==. always use .equals() for Strings and objects. primitives (int, double, boolean) are fine with ==. example: if (name.equals("driver")) not if (name == "driver").
While loops in robot
DO NOT DO THIS
periodic() is called every 20ms by the CommandScheduler. it is already a loop. if you put a while (condition) { } inside periodic, you block that thread and the watchdog kills the robot. the symptom is: robot enables, then immediately disables with a "loop overrun" warning. if you see that, look for blocking code (while loops, Thread.sleep(), anything that waits). example of what NOT to do: while (!atSpeed()) { } inside periodic.
Missing break in switch
Fall-through is silent
Forgetting break; in a switch case silently runs the next case after yours finishes. the compiler won't warn you, the linter might not catch it, and it will manifest as weird behavior where two different state transitions happen when only one should. every case needs break; unless you are intentionally falling through (add a comment if you are). example: missing break; after case IDLE: means the DRIVING case also executes immediately.
Hardcoded numbers
Put them in Constants
Magic numbers — raw integers and doubles scattered through your code with no label — make robot code nearly impossible to maintain. when a motor ID changes from port 5 to port 7, you want to change exactly one line in Constants.java, not hunt through ten files. rule: if a number has a physical meaning (an ID, a speed limit, a threshold), it belongs in Constants. never write new TalonFX(5); always write new TalonFX(DriveK.kFLMotorID).
Truncation ≠ Rounding
(int) 3.9 = 3, not 4
Java's cast-to-int operation always chops toward zero. (int) 3.9 gives 3. (int) -3.9 gives -3. neither rounds. this matters any time you're converting a floating-point sensor value or encoder reading to an integer index. if you need actual rounding, use Math.round() which returns a long, or (int) Math.round(x). only use the cast directly when you want truncation on purpose.

patterns you'll use daily in WRT code

beyond the raw syntax, there are a handful of patterns that show up constantly in real robot code. if these feel familiar when you open the Rebuilt repo for the first time, you'll be in great shape.

1. private final field + k constant — every piece of hardware follows this pattern. the constant lives in Constants.java, the hardware object is a private final field in the subsystem.

java
// In Constants.java — the number lives here, nowhere else
public static final class ShooterK {
    public static final int kTopMotorID = 11;
    public static final double kTargetSpeedRPS = 80.0;
}

// In ShooterSubsystem.java — hardware is private final, ID comes from constants
public class ShooterSubsystem extends SubsystemBase {
    private final TalonFX m_topMotor = new TalonFX(ShooterK.kTopMotorID);
}

2. subsystem method that returns a Command — this is how WRT subsystems expose behavior. instead of calling motor.set() from Robot.java, the subsystem returns a Command object that encapsulates the action. Robot.java just wires the command to a trigger.

java
// In ShooterSubsystem.java
/**
 * Spins the shooter to target speed and holds it.
 * @return a Command that runs until interrupted
 */
public Command shoot() {
    return startEnd(
        () -> m_topMotor.set(ShooterK.kTargetSpeedRPS),
        () -> m_topMotor.set(0.0)
    );
}

// In Robot.java — clean, declarative wiring
trg_shootButton.whileTrue(m_shooter.shoot());

3. state machine with enum + switch — when a subsystem has multiple modes, use an enum to name the states and a switch to handle each one. this is cleaner and safer than string or integer comparisons.

java
private enum State { IDLE, SPINNING, AT_SPEED }
private State m_state = State.IDLE;

@Override
public void periodic() {
    switch (m_state) {
        case IDLE:
            m_topMotor.set(0.0);
            break;
        case SPINNING:
            m_topMotor.set(ShooterK.kTargetSpeedRPS);
            // check if we've reached speed
            if (m_topMotor.getVelocity().getValueAsDouble() >= ShooterK.kTargetSpeedRPS) {
                m_state = State.AT_SPEED;
            }
            break;
        case AT_SPEED:
            // hold speed, maybe signal ready
            break;
    }
}

4. the periodic() logging pattern — in WRT code, every subsystem logs its state every cycle. this makes debugging infinitely easier because you can rewind the robot's behavior from a log file. the logging calls go at the end of periodic().

java
@Override
public void periodic() {
    // 1. do the actual subsystem work first
    switch (m_state) { /* ... */ }

    // 2. log everything at the end — WaltLogger is our wrapper over AdvantageKit
    log_state.accept(m_state.toString());
    log_velocity.accept(m_topMotor.getVelocity().getValueAsDouble());
    log_atSpeed.accept(m_state == State.AT_SPEED);
}

WRT convention: logging fields use the log_ prefix, just like m_ for member vars and k for constants. if you see a field like log_velocity in the codebase, it's a WaltLogger instance. you'll use these in the offseason weeks.


FRC & WRT Resources

you don't need to memorize everything — you need to know where to look. these are the only links you'll actually need during build season.

how to actually use these resources

there's a skill to using documentation efficiently. here's the mental model that most experienced WRT members use:

  • Google / W3Schools / GeeksForGeeks — use these when you forget basic Java syntax. "how do i convert int to string java", "java enhanced for loop syntax", "how does switch fall-through work". fast answers for language questions.
  • WPILib Docs — use these when you need to understand a framework concept. "how does SubsystemBase work", "what is the CommandScheduler", "how do Triggers work". if it's a WPILib class, the docs have the definitive answer.
  • CTRE Phoenix 6 API — use this when you're working with hardware. "TalonFX setControl", "CANcoder getAbsolutePosition", "StatusSignal vs getValue". Phoenix 6 has a totally different API than Phoenix 5 so make sure you're on the right version (we're on 6).
  • WRT Rebuilt repo — use this when you want to see how WE actually do something. don't just read the docs and guess, read how Swerve.java or Shooter.java actually uses the API. this is the real thing, not a tutorial.
  • Ask a mentor — last resort after you've checked the docs and the repo. mentors want you to have already looked before asking. "i checked X and Y and couldn't figure out Z" is a way better question than "how do i do Z".

WRT convention: the WRT Rebuilt repo is the single most useful resource you have. before asking a mentor how to do something, search the codebase for it. we probably already solved it. use GitHub's search (Ctrl+K in the browser) or clone the repo and use your IDE's full-text search. finding a real example beats any tutorial.

on WPILib versions: WPILib releases a new version every year, usually in January. make sure you're reading the docs for the same year as the codebase you're working on. a method that exists in 2025 might not exist in 2024, or might have a different signature. check the repo's build.gradle to see which year/version is in use before trusting a doc page.

Learn Java

FRC & WPILib

WRT Codebase Structure (for reference)

This is how our actual robot code is organized. Everything you've learned maps directly to something in here.

project structure — WaltonRobotics/Rebuilt
src/main/java/frc/robot/
├── Main.java                    // entry point: RobotBase.startRobot(Robot::new)
├── Robot.java                   // extends TimedRobot — your periodic() lives here
├── Constants.java               // inner classes: DriveK, ShooterK, IntakeK, etc.
├── FieldConstants.java          // field geometry constants
├── subsystems/
│   ├── Swerve.java              // extends SubsystemBase
│   ├── Intake.java              // extends SubsystemBase
│   ├── Indexer.java             // extends SubsystemBase
│   ├── Superstructure.java      // orchestrates intake + indexer + shooter
│   └── shooter/
│       ├── Shooter.java         // extends SubsystemBase
│       └── ShooterCalc.java     // shot math — static methods
├── autons/
│   └── WaltAdaptableAutonFactory.java  // Choreo-based auto builder
└── vision/
    └── WaltCamera.java          // AprilTag / note detection

No RobotContainer. Unlike some WPILib templates, we don't use a RobotContainer class. Subsystem instantiation and button bindings (button bindings = code that says "when this controller button is pressed, run this Command") happen directly in Robot.java. That said — the command-based concepts you learned still apply. SubsystemBase, Commands.sequence(), Triggers (WPILib Triggers watch for any condition — like a button press or a sensor reading — and run a Command when it becomes true) — all of it is real.

java — Robot.java pattern (simplified)
public class Robot extends TimedRobot {

    // All subsystems instantiated as fields
    private final DriveSubsystem m_drive = new DriveSubsystem();
    private final ShooterSubsystem m_shooter = new ShooterSubsystem();

    public Robot() {
        configureBindings();
    }

    private void configureBindings() {
        // Button → Command mappings go here
        // trg_shootButton.onTrue(m_shooter.shoot());
    }

    @Override
    public void robotPeriodic() {
        // CommandScheduler runs all subsystem periodic() calls
        CommandScheduler.getInstance().run();
    }
}

MiniBot Final Project

this is what you've been building all summer. bring all your files together, make sure they compile and are consistent, and submit. this is a real deliverable!!

before you start — do a quick audit

before you start writing Robot.java, spend 10 minutes going through every file you've written and answering these questions. you'd rather fix these now than discover them in a PR review.

  • Constants.java: are all your inner classes there? does DriveK have all the motor IDs and limits that DriveSubsystem references? does ShooterK have everything ShooterSubsystem needs?
  • AutoLogic.java: does it compile standalone? does it import anything from your other files, or is it just pure Java logic?
  • SensorProcessor.java: does every method take parameters instead of hardcoded values? are the array sizes pulled from constants instead of being magic numbers?
  • DriveCalculator.java: are all the conversion factors in Constants rather than inline in the method bodies?
  • DriveSubsystem.java: do all your getter methods actually return values (not void)? does periodic() have logging calls? are all hardware fields private final?
  • ShooterSubsystem.java: same checklist as DriveSubsystem. does it demonstrate inheritance properly — is it extending the right base class?
  • RobotState.java: does the enum have all the states you plan to use in Robot.java? does the interface from W7 have at least one method that something implements?

tip: open each file in your IDE and let it compile. if you're getting "cannot find symbol" errors, your files probably reference constants or methods that exist in other files but aren't imported yet. fix imports before you start assembling Robot.java.

What You Should Have

by the end of week 7 you should have created all of these files. if any are missing, go back to that week and complete them first.

FileCreated inWhat it has
Constants.javaWeek 1Inner classes DriveK and ShooterK, each with at least 3-4 typed, named constants using the k prefix and public static final. motor IDs, speed limits, encoder ratios — the source of truth for every number in your project.
AutoLogic.javaWeek 2A static class with a method that takes a mode selector (String or int) and uses if/switch to return or describe an auto routine. demonstrates you can write decision logic cleanly.
SensorProcessor.javaWeek 3Static utility methods that take a double[] sensor array as a parameter, process it with a for loop, and return a result (average, max, filtered value, etc.). no while loops, no hardcoded array sizes.
DriveCalculator.javaWeek 4Static math utility methods for unit conversions and clamping. things like ticksToMeters(double ticks), clampSpeed(double speed). all conversion constants come from Constants.java.
DriveSubsystem.javaWeek 5Extends SubsystemBase, has private final motor fields initialized from DriveK constants, implements periodic() with logging calls, has public getter/setter methods with Javadoc, returns a Command from at least one method.
ShooterSubsystem.javaWeek 6Extends the same SubsystemBase base class as DriveSubsystem (demonstrating that both use inheritance the same way). has its own state enum, a shoot() method that returns a Command, and periodic() logging. shows you can apply the same pattern to a different mechanism.
RobotState.javaWeek 7Top-level enum with at least IDLE, DRIVING, SHOOTING states. also contains or references the interface from W7 (something like ILoggable or IStateProvider) that at least one subsystem implements.

how to connect it all together

when you're assembling Robot.java, the order of dependencies matters. think of it as a layered graph where each layer can only depend on layers below it, not above it.

  • Layer 0 — Constants.java: no dependencies on anything in your project. it just has numbers. every other file can import it freely.
  • Layer 1 — utility classes (AutoLogic, SensorProcessor, DriveCalculator): these only depend on Constants (for k values). they're pure logic — no subsystems, no hardware. they can be tested in isolation.
  • Layer 2 — subsystems (DriveSubsystem, ShooterSubsystem): depend on Constants (for IDs and limits) and optionally on the utility classes. they do NOT depend on each other in your minibot (in real code, a Superstructure class would coordinate them). they do NOT depend on Robot.java.
  • Layer 3 — RobotState.java: can be imported by subsystems (they track state) and by Robot.java (it sets the top-level state). it has no dependency on any specific subsystem.
  • Layer 4 — Robot.java: depends on everything. it imports and instantiates the subsystems, uses RobotState, wires commands to triggers. it sits at the top of the dependency graph.

why this matters: if you find that Constants.java is trying to import something from DriveSubsystem, or that SensorProcessor is calling methods on your subsystem, you have a circular dependency. that design is broken. layers should only flow downward. clean dependency graphs are one of the things senior devs look for in code reviews.

Final Assembly — Robot.java

write a Robot.java that ties everything together. it doesn't need to run on actual hardware — focus on the structure being correct.

Final Project — Week 8
Robot.java

Create Robot.java that:

  • Extends TimedRobot (WRT pattern — no RobotContainer)
  • Declares DriveSubsystem and ShooterSubsystem as private final fields
  • Calls configureBindings() from the constructor
  • Has a robotPeriodic() that calls CommandScheduler.getInstance().run()
  • Has a stub configureBindings() with comments showing where Trigger bindings would go
  • Uses RobotState enum to track current state in a private RobotState m_state field

Then go through ALL your files from weeks 1–7 and make sure:

  • All constants use k prefix and are final
  • All member vars use m_ prefix and are private
  • Every public method has a Javadoc comment
  • No magic numbers anywhere — everything is in Constants.java
submit: push all .java files to a branch in the team repo and open a PR. title it "feat: minibot project — [your name]"
java — Robot.java starter
package frc.robot;

import edu.wpi.first.wpilibj.TimedRobot;
import edu.wpi.first.wpilibj2.command.CommandScheduler;
import frc.robot.subsystems.DriveSubsystem;
import frc.robot.subsystems.ShooterSubsystem;

/**
 * Main robot class. Extends TimedRobot — WPILib calls our periodic methods
 * every 20ms. No RobotContainer; subsystems and bindings live here.
 */
public class Robot extends TimedRobot {

    /** Current high-level robot state. */
    private RobotState m_state = RobotState.IDLE;

    /** All subsystems as private final fields. */
    private final DriveSubsystem   m_drive   = new DriveSubsystem();
    private final ShooterSubsystem m_shooter = new ShooterSubsystem();

    public Robot() {
        configureBindings();
    }

    /** Wire controller buttons to commands here. */
    private void configureBindings() {
        // TODO: trg_shootButton.onTrue(m_shooter.shoot());
        // TODO: trg_driveJoystick → m_drive.driveArcade(...);
    }

    @Override
    public void robotPeriodic() {
        // Runs all registered periodic() methods for every subsystem
        CommandScheduler.getInstance().run();
    }

    @Override
    public void teleopInit() {
        m_state = RobotState.DRIVING;
    }

    @Override
    public void disabledInit() {
        m_state = RobotState.IDLE;
    }
}

submission checklist

go through this before you open your PR. each item has a one-line example of what "correct" looks like.

WRT naming (required)
k prefix, m_ prefix, PascalCase classes
every constant has k: public static final int kMotorID = 5;. every member var has m_: private double m_speed = 0.0;. class names are PascalCase, method names are camelCase. if you see a naked number or a variable named just speed, fix it.
Javadocs (required)
Every public method documented
every public method needs a /** ... */ comment above it explaining what it does. example: /** Sets the drive speed. @param speed -1.0 to 1.0 */. if your IDE shows a yellow underline on a public method, that's probably a missing Javadoc warning.
No magic numbers (required)
Everything in Constants.java
search your files for raw literals. new TalonFX(5) is wrong, new TalonFX(DriveK.kFLMotorID) is right. if (speed > 0.8) is wrong, if (speed > DriveK.kMaxSpeed) is right. the only numbers allowed inline are 0, 1, and -1 in trivial arithmetic.
private final hardware (required)
All hardware fields locked down
every motor, sensor, and hardware object in your subsystems must be private final. example: private final TalonFX m_motor = new TalonFX(ShooterK.kTopMotorID);. public hardware fields are a safety and maintainability issue — other classes should never reach into a subsystem and poke hardware directly.
Compiles clean (required)
Zero red errors in IDE
your code must have no compile errors. yellow warnings are ok if you understand them. red errors are not. common sources: missing imports, type mismatches, calling void methods expecting a return value, missing override methods from an interface. fix all red before submitting.
PR title format (required)
feat: minibot project — [name]
your pull request title should follow the format exactly: feat: minibot project — [your name]. this is your first real PR to a team repo and it's also your first exposure to conventional commits format, which WRT uses for all its commit messages. get used to it now.

Grading Rubric

Naming (20pts)
k, m_, proper case
All constants have k prefix. All member vars have m_ prefix. Classes are PascalCase. Methods are camelCase.
Constants (15pts)
No magic numbers
Every number is defined in Constants.java in the appropriate inner class. Nothing hardcoded inline.
OOP (25pts)
Classes, inheritance, interface, enum
DriveSubsystem and ShooterSubsystem show inheritance. RobotState enum is used. Interface from W7 is implemented.
Methods (20pts)
Parameters, return types, Javadoc
All public methods have correct return types, meaningful parameters, and Javadoc. No void where a value should be returned.
Loops + Arrays (10pts)
SensorProcessor usage
SensorProcessor.java uses arrays and loops correctly. No while loops in periodic methods.
Code Style (10pts)
Readable, commented
Code is consistently indented. Comments explain the why, not the what. No dead code or commented-out blocks.

Week 8 Review Quiz

covers material from all 8 weeks — think of it as a mini version of the final java quiz

week 8 test
comprehensive review · 10 questions · all topics