Overview
WPILib robot programs follow a structured lifecycle with specific methods called at different stages of robot operation. Understanding this lifecycle is crucial for proper initialization, periodic updates, and mode transitions.
Robot Base Classes
WPILib provides several base classes for robot programs:
| Class | Description | Use Case |
|---|
TimedRobot | Periodic callback-based robot | Most common, recommended for teams |
IterativeRobot | Legacy iterative robot (deprecated) | Older codebases |
RobotBase | Abstract base class | Custom implementations |
TimedRobot is the recommended base class. It provides precise timing using hardware notifiers and is used in 95%+ of FRC robot programs.
TimedRobot Lifecycle
Program Startup
Lifecycle Methods
From wpilibj/src/main/java/edu/wpi/first/wpilibj/IterativeRobotBase.java and TimedRobot.java:
Initialization Methods
robotInit()
Called once when the robot is first powered on.
public void robotInit() {
// Initialize subsystems
// Configure autonomous chooser
// Set up dashboard
// Initialize camera server
}
Use for:
- Creating subsystem instances
- Configuring sensors and actuators
- Setting up autonomous selection
- Initializing NetworkTables
- Starting camera feeds
In C++, prefer using the class constructor over robotInit() for initialization.
simulationInit()
Called once after robotInit(), only when running in simulation.
public void simulationInit() {
// Initialize physics simulation
// Set up simulated sensors
}
driverStationConnected()
Called once when the Driver Station first connects.
public void driverStationConnected() {
// Get alliance station
// Read game-specific data
}
Use for:
- Reading alliance color
- Getting field configuration
- Match-specific initialization
Mode Init Methods
Called once each time the robot enters a specific mode.
disabledInit()
public void disabledInit() {
// Stop all motors
// Reset state machines
}
autonomousInit()
public void autonomousInit() {
// Schedule autonomous command
// Reset odometry
// Get autonomous selection
}
teleopInit()
public void teleopInit() {
// Cancel autonomous commands
// Enable driver control
}
testInit()
public void testInit() {
// Enable LiveWindow (optional)
// Start test routines
}
Periodic Methods
Called repeatedly (default: every 20ms) while in the corresponding mode.
robotPeriodic()
Called in all modes (disabled, autonomous, teleop, test).
public void robotPeriodic() {
// Run command scheduler (REQUIRED for command-based)
CommandScheduler.getInstance().run();
// Update telemetry
SmartDashboard.putNumber("Battery Voltage", RobotController.getBatteryVoltage());
// Update vision processing
// Log data
}
Command-based programs MUST call CommandScheduler.getInstance().run() in robotPeriodic(). This is the only required code for command-based programming.
disabledPeriodic()
public void disabledPeriodic() {
// Update autonomous selection
// Monitor robot state
}
autonomousPeriodic()
public void autonomousPeriodic() {
// Command scheduler handles execution
// Manual autonomous code (if not using commands)
}
teleopPeriodic()
public void teleopPeriodic() {
// Command scheduler handles execution
// Manual teleop code (if not using commands)
}
testPeriodic()
public void testPeriodic() {
// Test-specific code
}
simulationPeriodic()
Called after all other periodic methods during simulation.
public void simulationPeriodic() {
// Update physics simulation
// Simulate sensor inputs
}
Exit Methods
Called once when exiting a mode.
disabledExit()
public void disabledExit() {
// Prepare for enabled mode
}
autonomousExit()
public void autonomousExit() {
// Clean up autonomous resources
}
teleopExit()
public void teleopExit() {
// Stop driver control
}
testExit()
public void testExit() {
// Disable LiveWindow
// Clean up test resources
}
Mode Transition Flow
Execution Order Within Each Cycle
From IterativeRobotBase.loopFunc() (line 301-428):
Execution Details
Order of execution in each 20ms loop:
- Refresh Driver Station data
- Check for mode changes
- If mode changed: call old mode’s
exit(), then new mode’s init()
- Call current mode’s
periodic() method:
disabledPeriodic() / autonomousPeriodic() / teleopPeriodic() / testPeriodic()
- Call
robotPeriodic() (in ALL modes)
- Update SmartDashboard values
- Update LiveWindow values (if enabled)
- Update Shuffleboard
- If simulation:
- Call
HAL.simPeriodicBefore()
- Call
simulationPeriodic()
- Call
HAL.simPeriodicAfter()
- Flush NetworkTables
- Check for loop overruns (prints warning if >20ms)
TimedRobot Implementation Details
Precise Timing with Notifiers
From frc/TimedRobot.h and TimedRobot.java:
class TimedRobot : public IterativeRobotBase {
public:
static constexpr auto kDefaultPeriod = 20_ms;
explicit TimedRobot(units::second_t period = kDefaultPeriod);
// Add custom periodic callbacks
void AddPeriodic(std::function<void()> callback,
units::second_t period,
units::second_t offset = 0_s);
private:
hal::Handle<HAL_NotifierHandle, HAL_CleanNotifier> m_notifier;
std::chrono::microseconds m_startTime;
wpi::priority_queue<Callback> m_callbacks;
};
Custom Periodic Callbacks
Add additional periodic functions at different rates:
C++:
class Robot : public frc::TimedRobot {
public:
Robot() {
// Default 20ms period
AddPeriodic([&] { FastUpdate(); }, 10_ms);
// Slower update with offset
AddPeriodic([&] { SlowUpdate(); }, 100_ms, 5_ms);
}
private:
void FastUpdate() {
// Called every 10ms
}
void SlowUpdate() {
// Called every 100ms, offset by 5ms
}
};
Java:
public class Robot extends TimedRobot {
public Robot() {
super();
// Default 0.02s period
addPeriodic(this::fastUpdate, 0.01); // 10ms
addPeriodic(this::slowUpdate, 0.1, 0.005); // 100ms, 5ms offset
}
private void fastUpdate() {
// Called every 10ms
}
private void slowUpdate() {
// Called every 100ms, offset by 5ms
}
}
Loop Overrun Detection
TimedRobot monitors loop execution time:
public double getPeriod() {
return m_period; // Returns configured period (default 0.02s)
}
public void printWatchdogEpochs() {
m_watchdog.printEpochs(); // Shows timing of each epoch
}
If a loop takes longer than the period, a warning is printed:
Warning at edu.wpi.first.wpilibj.IterativeRobotBase.printLoopOverrunMessage(IterativeRobotBase.java:436): Loop time of 0.02s overrun
Complete Example
Command-Based Robot (C++):
class Robot : public frc::TimedRobot {
public:
void RobotInit() override {
// Create subsystems
m_drive = new DriveSubsystem();
m_shooter = new ShooterSubsystem();
// Configure button bindings
ConfigureButtonBindings();
// Set up autonomous chooser
m_chooser.SetDefaultOption("Simple Auto", &m_simpleAuto);
m_chooser.AddOption("Complex Auto", &m_complexAuto);
frc::SmartDashboard::PutData("Auto Mode", &m_chooser);
}
void RobotPeriodic() override {
// REQUIRED: Run command scheduler
frc2::CommandScheduler::GetInstance().Run();
}
void AutonomousInit() override {
// Get selected autonomous command
m_autonomousCommand = m_chooser.GetSelected();
if (m_autonomousCommand != nullptr) {
m_autonomousCommand->Schedule();
}
}
void AutonomousExit() override {
// Autonomous command will be auto-cancelled
}
void TeleopInit() override {
// Cancel autonomous command
if (m_autonomousCommand != nullptr) {
m_autonomousCommand->Cancel();
}
}
void DisabledInit() override {
// Stop all commands
frc2::CommandScheduler::GetInstance().CancelAll();
}
void SimulationPeriodic() override {
// Update physics simulation
m_driveSimulation.Update();
}
private:
DriveSubsystem* m_drive;
ShooterSubsystem* m_shooter;
frc::SendableChooser<frc2::Command*> m_chooser;
frc2::Command* m_autonomousCommand;
};
#ifndef RUNNING_FRC_TESTS
int main() {
return frc::StartRobot<Robot>();
}
#endif
Key Takeaways
- robotInit() runs once at startup
- robotPeriodic() runs every cycle in ALL modes
- Mode init methods run once when entering a mode
- Mode periodic methods run every cycle in that mode
- Mode exit methods run once when leaving a mode
- Command-based programs MUST call CommandScheduler.run() in robotPeriodic()
- Default period is 20ms (50Hz)
- Loop overruns are detected and reported automatically
Next Steps