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.
| Concept | Key Syntax | WRT Rule |
|---|---|---|
| Constants | final int kMotorID = 5; | k prefix, always final |
| Member vars | private double m_speed = 0.0; | m_ prefix, always private |
| Primitive types | int, double, boolean | Use double for motor speeds (−1.0 to 1.0) |
| Widening cast | double d = myInt; (automatic) | int → double is safe, no cast needed |
| Narrowing cast | int 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.
| Concept | Key Syntax | FRC Use Case |
|---|---|---|
| Boolean operators | && || ! | Guard conditions: isEnabled && hasTarget |
| if / else if / else | if (x) { } else if (y) { } else { } | Auto state logic, sensor range checks |
| Switch | switch(val) { case X: ...; break; } | Game state machine, robot mode selection |
| Ternary | int 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.
| Concept | Key Syntax | FRC Use Case |
|---|---|---|
| for loop | for (int i = 0; i < n; i++) | Process encoder arrays, iterate modules |
| while loop | while (condition) | Avoid in robot code — periodic() is your loop |
| enhanced for | for (Type x : array) | Read all swerve module states |
| Array declaration | double[] arr = new double[4]; | Swerve module speeds, sensor history buffers |
| Static methods | public static double clamp(double v, ...) | Math utilities in Constants or MathUtil |
| Return types | public 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.
| Concept | Key Syntax | WRT Pattern |
|---|---|---|
| Subsystem class | public class Shooter extends SubsystemBase | One class per mechanism, in subsystems/ |
| Constructor | public 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 |
| Inheritance | extends SubsystemBase | WPILib gives you the scheduler loop for free |
| Interfaces | implements ISensor | Used for vision targets, sensor abstraction |
| Enums | enum State { IDLE, SPINNING, AT_SPEED } | Subsystem state machines — very common |
| Private modifier | private 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.
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.== 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").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.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.new TalonFX(5); always write new TalonFX(DriveK.kFLMotorID).(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.
// 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.
// 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.
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().
@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.
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.
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.
| File | Created in | What it has |
|---|---|---|
Constants.java | Week 1 | Inner 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.java | Week 2 | A 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.java | Week 3 | Static 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.java | Week 4 | Static math utility methods for unit conversions and clamping. things like ticksToMeters(double ticks), clampSpeed(double speed). all conversion constants come from Constants.java. |
DriveSubsystem.java | Week 5 | Extends 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.java | Week 6 | Extends 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.java | Week 7 | Top-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.
Create Robot.java that:
- Extends
TimedRobot(WRT pattern — no RobotContainer) - Declares
DriveSubsystemandShooterSubsystemasprivate finalfields - Calls
configureBindings()from the constructor - Has a
robotPeriodic()that callsCommandScheduler.getInstance().run() - Has a stub
configureBindings()with comments showing where Trigger bindings would go - Uses
RobotStateenum to track current state in aprivate RobotState m_statefield
Then go through ALL your files from weeks 1–7 and make sure:
- All constants use
kprefix and arefinal - All member vars use
m_prefix and areprivate - Every public method has a Javadoc comment
- No magic numbers anywhere — everything is in Constants.java
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.
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.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.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. 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.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
Week 8 Review Quiz
covers material from all 8 weeks — think of it as a mini version of the final java quiz