Singleton
Overview
The Singleton pattern ensures that a class has only one instance and provides a global point of access to it. This is especially useful in robotics for components that represent unique hardware systems, such as subsystems (e.g., drivetrain, elevator).
In FRC, subsystems model distinct parts of the robot, and there should only be one instance of each. Using a Singleton pattern guarantees that only one object exists for each subsystem, avoiding conflicts in control and making coordination between commands and subsystems predictable.
Motivation
Consider a robot's drivetrain. If multiple drivetrain instances existed, commands could conflict or hardware might receive inconsistent signals. Singleton enforces a single source of truth for each subsystem.
Benefits:
Prevents multiple conflicting instances
Centralizes access logic
Simplifies debugging and testing
Promotes safe, hardware-accurate design
Structure
In its most basic form, a Singleton class:
Has a private static instance of itself
Provides a public static method to get the instance
Ensures the instance is only created once
public class Elevator extends Subsystem {
private static Elevator instance = null;
private Elevator() {
// Initialization logic
}
public static Elevator getInstance() {
if (instance == null) {
instance = new Elevator();
}
return instance;
}
}
However, the Subsystem class offers a more centralized and consistent Singleton mechanism:
public static Elevator getInstance() {
return (Elevator) Subsystem.getInstance(Elevator.class);
}
Here, Subsystem.getInstance(Class)
uses reflection and internal caching to enforce singleton behavior across all subsystems without repeating the boilerplate.
Subsystem Singleton in Practice
public class Drivetrain extends Subsystem {
private final MotorController leftMotor, rightMotor;
private Drivetrain() {
leftMotor = new MotorController(1);
rightMotor = new MotorController(2);
}
public static Drivetrain getInstance() {
return (Drivetrain) Subsystem.getInstance(Drivetrain.class);
}
public void drive(double speed) {
leftMotor.set(speed);
rightMotor.set(speed);
}
}
In your RobotContainer
or command classes:
Drivetrain.getInstance().drive(0.5);
Common Use Cases in FRC
1. Hardware Subsystems
Drivetrain, Intake, Shooter, Elevator, Arm – all implemented as singletons to ensure consistent access to hardware components.
2. Sensor Interfaces
IMUs, Limelight, Odometry Providers – Singleton patterns prevent double initialization of sensitive hardware.
3. Field Simulators / Robot State
The RobotState
class, which tracks robot pose, speed, and field-relative positioning, is often designed as a singleton to ensure global consistency.
Pose2d robotPose = RobotState.getInstance().getLatestPose();
Best Practices
Avoid Singleton for stateless utility classes (use static methods instead)
Do not use Singleton to replace proper dependency injection in complex systems unless justified
Ensure the constructor is private to block external instantiation
Prefer lazy initialization unless eager initialization is safer or simpler
Last updated