Variables
Every number in your robot code controls something you could touch, measure, or break. Variables are how we give those numbers a name, a type, and a home — so that when something goes wrong at 9 AM on the competition field, you can find it and fix it in under two minutes.
By the end of this lesson, you will:
- Declare and initialize variables using correct Java syntax
- Explain the difference between a variable's type, name, and value
- Describe how the four most common Java types map to real robot hardware
- Recognize when to use a local variable versus an instance variable in a robot loop
- Apply the naming conventions used in professional FRC code — including Team 2910's standards
Why Variables? A Field Story
Picture this: it's 9 AM at a regional, and your robot's intake is running too fast — it's spitting out game pieces instead of holding them. A mentor walks up and asks, "What speed is the intake set to?" Your programmer shrugs and says, "I don't know, I just put 0.8 in there." Now you have to read through all of teleopPeriodic() to find where the motor is being set, figure out which of the three 0.8 values is the intake, change it, rebuild, and redeploy — in a ten-minute pit window, with matches starting.
That is a variable problem. Or more precisely, the absence of one. A variable is how a number gets a name. And a name is how your team can find it, understand it, and change it without breaking three other things in the process.
As a Lead Robot Inspector, one of the most common things I see in struggling robots is the same number appearing in multiple places in the code — sometimes with slightly different values, because the programmer edited one copy and not the others. During inspection that's a warning sign. During a match, it's usually the root cause of a fault that nobody can reproduce reliably. One well-named variable would have prevented it.
Anatomy of a Variable Declaration
In Java, every variable has exactly three required pieces. Click each part of the declaration below to learn what it does and why it matters on a robot.
The pattern is always the same: type name = value;. The semicolon at the end is not optional — Java is not Python. Missing a semicolon is one of the five most common compiler errors you will see this year. The compiler will tell you where it expected one, and it will be right.
The Four Types You'll Use Every Day
Java has many data types, and Unit 2, Lesson 2 covers them in full depth. For now, here are the four that appear in almost every FRC program you will ever write. Understanding what they store physically — not just abstractly — is what keeps you from making the mistakes that are invisible to the compiler but fatal to the robot.
👇 Click each card to see the robot contextDecimal numbers. Motor outputs (−1.0 to 1.0), PID gains, encoder positions in degrees, and wheel speeds in RPM are all double. When in doubt and the value might ever be fractional, use double.
Whole numbers. CAN bus IDs, PWM port numbers, current limits in amps, and button IDs on a controller are all int. You can't have CAN ID 2.7 — it's always a whole number.
True or false only. Limit switch state, beam break sensor readings, "is the intake running," "has the arm been zeroed" — anything that is a yes/no question about the physical world.
Text. Subsystem names on Shuffleboard, fault messages to log, and chooser labels for auto selection are all String. Note the capital S — String is a class, not a primitive type.
Motor controllers expect a double in the range of −1.0 to 1.0. If you accidentally declare your speed as an int and initialize it to 0, your motor will not move — because integer 0 and double 0.0 both pass to motor.set() just fine. The compiler won't complain. The robot just won't do anything, and you'll spend ten minutes checking wiring before noticing the type.
Naming Variables: The 2910 Standard
Variable names are not just for the compiler — they're for every programmer who touches that file after you, including the student who inherits the robot in two years. A good name is the cheapest documentation you will ever write.
The rules
- Use camelCase. Start with a lowercase letter; capitalize the first letter of each subsequent word.
intakeSpeed, notintakespeed, notIntakeSpeed. - Name the physical thing it controls. If you read the name in six months with no context, you should know exactly what motor, sensor, or state it represents.
- Constants get
ALL_CAPS_SNAKE_CASE. Values that should never change during a match are declaredstatic finaland written in uppercase with underscores. We'll cover thestatickeyword properly in Unit 4, but you'll see this pattern immediately in real code.
A letter tells you nothing. Motor speed? Arm angle? Battery voltage? A mentor reading this at 10 PM the night before a competition has no idea what to change or why.
This is actually the current limit in amps. The name says it's temporary and meaningless. A current limit is neither — it's a hardware protection value and it deserves a proper name.
The mechanism (shooter wheel), what it describes (speed), and the unit (RPM) are all in the name. No guesswork. No comments needed to explain it.
static final tells the compiler and every reader this value won't change. The name tells you the mechanism, the thing it limits, and the unit. Change it once, everywhere updates.
I've inspected robots where the same motor's current limit was set to 80 amps in one method and 40 amps in another — because the programmer copy-pasted a number and changed one but not the other. The robot passed inspection both times because neither limit was technically illegal. It browned out in its first real match because 80 amps on that motor was higher than the breaker. One well-named static final constant, referenced in both places, would have made it physically impossible for those two values to differ.
Where Variables Live: Scope
Scope defines where in your code a variable exists and can be used. In most programming contexts this is a mild annoyance. In robot code, where the same methods are called 50 times per second, getting scope wrong produces bugs that are nearly impossible to reproduce because they depend on timing.
A local variable is declared inside a method. It is created when the method is called and destroyed when the method returns. In a TimedRobot, that means it's recreated from scratch every 20 milliseconds.
Use a local variable when the value only needs to exist for the duration of a single loop iteration — like reading a joystick and immediately passing it to a motor.
The key thing to internalize: a local variable cannot remember anything between loop cycles. Every time teleopPeriodic() runs, joystickY starts fresh. That's fine here — we want the current joystick value, not last frame's value.
An instance variable (also called a field) is declared inside the class but outside any method. It persists for the entire lifetime of the object — in practice, for the entire match. This is where you store things that the robot needs to remember across loop cycles.
Use an instance variable when you need to track state over time: is the intake currently running? Has the arm been zeroed? Was a fault logged in the previous cycle?
If intakeRunning were a local variable, it would reset to false every 20ms and the toggle would never work. The physical mechanism would never actually run. This is a scope bug — and the robot compiles and deploys perfectly while doing completely the wrong thing.
Putting It Together: Variables in a Real Robot
Here is a complete intake example that uses all three kinds of variables — constants, instance variables, and local variables — each doing exactly the job it should do. Read through the comments carefully; this is the pattern you'll use in almost every subsystem you write.
Notice that INTAKE_SPEED_FORWARD appears exactly once. If a mentor says "slow the intake down a little," you change one number in one place and every reference updates. If that number were scattered across five motor.set(0.6) calls, you'd hunt for all of them — and you'd probably miss one, and have different speeds on different bumpers, and spend a match wondering why the intake behaves inconsistently.
🔌 System Check
Variables are laptop-side work — no robot required to learn the syntax. But before your variables connect to real hardware, verify these:
- Every variable connected to a motor has a physically meaningful name. If a teammate can't tell what mechanism it controls from the name alone, rename it before merging into main.
- Current limit constants must be lower than the breaker rating. A NEO stalls at ~105A. Your 40A breaker will trip first — and it should. Set your software limit below 40A so the software stops the motor before the breaker does.
- Boolean state variables must default to the safe state.
boolean intakeRunning = falseis safe — the intake starts stopped.boolean intakeRunning = truemeans the motor runs the moment the robot enables. Guess which one causes pit accidents. - Use a
Constants.javafile as the single source of truth. All port numbers, current limits, and tunable values live there. If the same number appears in more than one file as a literal, that's a bug waiting to happen. - Sensor-driven variables need working sensors. A disconnected encoder returns 0, which looks like a valid position. Before trusting any variable that reads from hardware, confirm the hardware is plugged in and returning reasonable values.
Knowledge Check
Click an answer to check your understanding.
int shooterSpeed = 0; and then calls shooterMotor.set(shooterSpeed). The code compiles and deploys. The shooter wheel doesn't spin. What is most likely the problem?boolean intakeRunning = false; inside teleopPeriodic() instead of as a class-level field. The A button is supposed to toggle the intake on. What will happen at runtime?motor.set(0.7) in three different places. A mentor asks you to reduce the drive speed for a tighter field layout. What is the risk of this approach compared to using a named constant?Refactor the Magic Numbers
Open WPILib VS Code and create a new Java file called IntakePractice.java. Start with the code below — it works, but it has five magic numbers that would cause real problems on a competition field.
- Identify all five magic numbers and write a sentence for each explaining what physical thing it controls.
- Declare a
static finalconstant for each one at the top of the class with an appropriate name and type. Add a comment explaining the physical significance of the value — not just what it is, but why that specific number. - Replace all five literals in
teleopPeriodic()with your new constants. - Add an instance variable to track whether the intake is currently running, and update it correctly in all three branches.
- Bonus: Find Team 2910's most recent robot repository on GitHub. Open
Constants.java(or the equivalent). Choose any five constants and write a sentence explaining what you think each one controls and why that value was probably chosen.