Gray Matter
WorkshopProject Structure
WPILib 2027 is still in alpha: these pages change as the APIs settle.
LESSON 11

Project Structure

A robot project has three kinds of Java file and a handful of files that are not Java at all. Each kind of code has one place it goes, and the folders tell you which.

9 minutes
You’ll need

This page is a map, and nothing on it gets typed. By the end of Workshop 3 your project looks like the tree below. Every lesson after this one adds a file to a folder named here.

The tree

Workshop/ at the end of Workshop 3
Workshop/
build.gradle how to build, and which libraries
settings.gradle where Gradle finds WPILib
gradlew, gradlew.bat run Gradle without installing it
.wpilib/
wpilib_preferences.json your team number
vendordeps/
CommandsV3.json one file per vendor library
Phoenix6-26.70.0-alpha-2.json
src/main/deploy/ files copied onto the robot
src/main/java/first/
Main.java starts the program. Never edited
robot/
Robot.java owns the mechanisms
mechanisms/
Arm.java one class per mechanism
Flywheel.java
opmode/
MyTeleop.java one class per mode
MyAuto.java
build/ made by every build. Never edited

The mechanisms folder does not exist yet. You make it in the next lesson. Everything else is already there from the New Project Creator.

Three things you leave alone. Main.java holds one line that matters, RobotBase.startRobot(first.robot.Robot::new). Its own comment says to leave the file alone. build/ is rewritten on every build, so an edit there disappears. The gradle/wrapper files pin the Gradle version for everyone on the team.

Three kinds of Java file

Robot.java owns the mechanisms, one public final field each, and runs the scheduler once per loop in robotPeriodic(). Its constructor is where a binding goes that must work in every mode. On this course that constructor stays empty.

src/main/java/first/robot/Robot.java
public class Robot extends OpModeRobot {
public final Arm arm = new Arm();
public final Flywheel flywheel = new Flywheel();
 
public Robot() {}
 
@Override
public void robotPeriodic() {
Scheduler.getDefault().run();
}
}

A mechanism class is one physical thing on the robot. It implements Mechanism and keeps its motors and sensors private. Its public methods either return a Command, like arm.vertical(), or answer a question, like arm.isAtTarget(). Nothing outside the class touches the motor.

An OpMode class is one entry on the driver station list. @Teleop or @Autonomous above the class puts it there. Its constructor binds buttons to commands, and it reaches the mechanisms through robot.arm and robot.flywheel.

An OpMode only shows up if it sits in first.robot or a folder under it. The framework searches that package and nowhere else.

Where numbers live

There is no Constants file on any branch of this course. A number sits in the class that uses it, next to the line that uses it.

  • CAN IDs sit where the device is made: new TalonFX(21, canivore).
  • Gains sit in the configuration you paste from Tuner X, in the mechanism's constructor.
  • Setpoints sit in the command that asks for them: setVelocity(75.0) inside runFast().
  • Tolerances are a private final field at the top of the mechanism.

When an OpMode needs to know whether the arm has arrived, it calls robot.arm.isAtTarget(). It never compares angles itself, so the tolerance stays in one place and changes in one place.

Where new code goes

Ask what the code talks to.

  • A motor or a sensor. The mechanism that owns it, as a private method.
  • Something one mechanism does. A public method on that mechanism that returns a Command.
  • A button. The constructor of the OpMode it belongs to. A button for every mode goes in the Robot constructor.
  • Two mechanisms working together. The OpMode that runs the routine. spinUpWhenReady lives in MyTeleop for that reason.
  • A vendor library. vendordeps/, added through the WPILib Vendor Dependencies view, never by copying a jar.
  • A file the robot reads while running. src/main/deploy/. A deploy copies it onto the SystemCore.
Watch out

New file, wrong folder

Every Java file starts with a package line, and it has to match the folder. Arm.java in robot/mechanisms/ says package first.robot.mechanisms;. Put the file one level up and VS Code marks that line red: the declared package does not match the expected package. Move the file, not the line.

Check your work

Open the Explorer in VS Code and expand src/main/java/first. Then sort the four quiz questions below without scrolling back up.

Check

You should see

  • Main.java beside a robot folder, and Robot.java beside an opmode folder.
  • MyTeleop.java and MyAuto.java inside opmode.
  • Four out of four in the quiz.

Check yourself

You need the CAN ID of a second flywheel motor. Where do you write it?

Pressing B should lower the arm to horizontal, but only in Teleop. What do you add, and where?

A routine raises the arm and then spins the flywheel. Where does it go?

You write a new OpMode in src/main/java/first/auto with package first.auto. It builds. Why does it not appear on the driver station?

Pick an answer for each.