Lesson 13.4: Managing Shared Constants with the static Keyword
Configuration Drift: A Real Competition Problem
Imagine a robot with three OpMode files -- TeleOpMain.java, AutonomousRed.java, and AutonomousBlue.java. Each one maps the drivetrain motors using the strings "left_front", "right_front", "left_back", and "right_back". The drive team re-ports the right rear motor to a different hub slot before a match and updates the configuration name in the Robot Controller app to "right_back_2". Now that string needs to change in three different Java files. One of them gets missed. The autonomous program works. The TeleOp crashes on the second match.
This scenario is called configuration drift, and it is one of the most common sources of last-minute failures at competition. The fix is to store every configuration name and every tunable constant in exactly one location. Any code that needs the value reads it from that single location. When the value needs to change, it changes in one place and every file is automatically updated.
Static and Final
The static keyword applied to a class variable means the variable belongs to the class itself rather than to any particular instance of the class. Every object of that class shares the same static variable. This is the right model for a configuration constant: there is only one configuration, and it should be identical everywhere.
The final keyword applied to a variable means the variable cannot be reassigned after its initial declaration. Combining static and final creates a compile-time constant: a value that is defined once, cannot be changed, belongs to the class rather than any instance, and is accessible from anywhere that can see the class.
By Java naming convention, static final constants are written in ALL_CAPS_WITH_UNDERSCORES to visually distinguish them from regular variables.
A Shared Configuration Class
The most effective pattern for FTC is a dedicated class named something like RobotConfig that contains nothing but public static final declarations. No methods, no instances, no constructor. Just constants. Every OpMode and every mechanism class that needs a hardware name or a tunable value imports this class and reads the constant directly: RobotConfig.LEFT_FRONT_MOTOR.
When the hardware changes, you open RobotConfig.java, change one string, rebuild, and every file is correct again.
Annotated Code
package org.firstinspires.ftc.teamcode;
/**
* Single source of truth for all hardware configuration names and
* tunable constants used across the robot's codebase.
*
* To change a hardware port name: update the constant here only.
* Rebuild the project and every OpMode receives the updated value.
*/
public class RobotConfig {
// ── Drivetrain motor configuration names ──────────────────
public static final String LEFT_FRONT_MOTOR = "left_front";
public static final String RIGHT_FRONT_MOTOR = "right_front";
public static final String LEFT_BACK_MOTOR = "left_back";
public static final String RIGHT_BACK_MOTOR = "right_back";
// ── Mechanism configuration names ─────────────────────────
public static final String LIFT_MOTOR = "lift_motor";
public static final String INTAKE_SERVO = "intake_servo";
public static final String BOTTOM_LIMIT = "limit_bottom";
// ── Tunable drive constants ────────────────────────────────
public static final double DRIVE_SPEED_NORMAL = 0.8;
public static final double DRIVE_SPEED_PRECISION = 0.3;
public static final double DEADZONE_THRESHOLD = 0.08;
// ── Encoder constants ──────────────────────────────────────
public static final double TICKS_PER_REV = 537.7; // GoBILDA 5203 19.2:1
public static final double WHEEL_DIAMETER_IN = 3.78;
}
// Using the constants in an OpMode or mechanism class:
import org.firstinspires.ftc.teamcode.RobotConfig;
leftFront = hardwareMap.get(DcMotor.class, RobotConfig.LEFT_FRONT_MOTOR);
rightFront = hardwareMap.get(DcMotor.class, RobotConfig.RIGHT_FRONT_MOTOR);
if (Math.abs(input) < RobotConfig.DEADZONE_THRESHOLD) {
input = 0;
}
Fill-in-the-Blank Practice
- A variable that belongs to the class itself rather than to any particular instance is declared with the
__________keyword. - A variable that cannot be reassigned after its initial declaration is declared with the
__________keyword. - By Java naming convention, a
static finalconstant should be written in__________to distinguish it from regular variables.
Show answers
staticfinal- ALL_CAPS_WITH_UNDERSCORES
Template Challenge
Robot Scenario: Your team has a claw servo, a wrist motor, and a range sensor all with specific configuration names and tunable constants. Create a HardwareNames configuration class that stores these values as public static final constants so that every OpMode on the robot can reference them from a single location.
Requirements:
- Servo configuration name:
"claw_servo"stored asCLAW_SERVO - Motor configuration name:
"wrist_motor"stored asWRIST_MOTOR - Sensor configuration name:
"front_range"stored asFRONT_RANGE - Maximum wrist speed constant:
0.6stored asWRIST_MAX_SPEED - Claw closed position:
0.9stored asCLAW_CLOSED - Claw open position:
0.1stored asCLAW_OPEN
package org.firstinspires.ftc.teamcode;
// INSERT CODE HERE: Write the complete HardwareNames class with all
// six constants listed above as public static final declarations.
Show answer
package org.firstinspires.ftc.teamcode;
public class HardwareNames {
public static final String CLAW_SERVO = "claw_servo";
public static final String WRIST_MOTOR = "wrist_motor";
public static final String FRONT_RANGE = "front_range";
public static final double WRIST_MAX_SPEED = 0.6;
public static final double CLAW_CLOSED = 0.9;
public static final double CLAW_OPEN = 0.1;
}
Ready to move on?
Sign in with Google to save your progress with Telemark, or continue without saving.