Skip to main content

🔄 Robot Code Lifecycle

Living Documentation

APIs and control systems change season to season, and sometimes mid-season. Specific class names, file paths, and code examples throughout this section reflect FRC 190's codebase at the time of writing and may become outdated or obsolete as WPILib, CTRE, and other vendor libraries evolve. Treat this section as a guide to the underlying concepts, not a guaranteed match to the current source.

Just like any other program, FRC robot code has a lifecycle. There are several defined states that the software moves through when it runs:

Entry

The Entry of a robot program is the portion that tells the rest of the code to start executing. Usually, this is done in a file called Main.java, which usually looks something like this:

Show code
package frc.robot;

import edu.wpi.first.wpilibj.RobotBase;

public final class Main {
private Main() {}

public static void main(String... args) {
RobotBase.startRobot(Robot::new);
}
}

This small class's only job is to call the RobotBase.startRobot(...) method with a Robot configuration. This is what starts all the things that our robot is defined to do. Usually there is no need to change anything about the Main.java class, as it is predefined by most of the WPILib sample projects and is standardized across all of FRC 190's robot codebases.

Initialization

After a robot program is entered, the next step is to create all the different things needed to interface with the robots hardware, such as motors and sensors. This is what the initialization step is for. Usually, the initialization step occurs mostly in the Robot.java class.

Show Code
package frc.robot;

import ...

public class Robot extends LoggedRobot {
# Initialization of variables
...

public Robot() {
# Instantiation of variables
...
}

/**
* This function is run when the robot is first started up and should be used for any
* initialization code.
*/
@Override
public void robotInit() {}

/** This function is called periodically during all modes. */
@Override
public void robotPeriodic() {}

/** This function is called once when the robot is disabled. */
@Override
public void disabledInit() {}

/** This function is called periodically when disabled. */
@Override
public void disabledPeriodic() {}

/** This autonomous runs the autonomous command selected by your {@link RobotContainer} class. */
@Override
public void autonomousInit() {}

/** This function is called periodically during autonomous. */
@Override
public void autonomousPeriodic() {}

/** This function is called once when teleop is enabled. */
@Override
public void teleopInit() {}

/** This function is called periodically during operator control. */
@Override
public void teleopPeriodic() {}

/** This function is called once when test mode is enabled. */
@Override
public void testInit() {}

/** This function is called periodically during test mode. */
@Override
public void testPeriodic() {}

/** This function is called once when the robot is first started up. */
@Override
public void simulationInit() {}

/** This function is called periodically whilst in simulation. */
@Override
public void simulationPeriodic() {}
}

One interesting thing you might have noticed about the Robot.java class above is that there isn't just one initialization method or routine. This is because there are many different sub-states, or modes, that the robot code initializes into. As you know from the game manual and the driver station, there are several different states that the robot can be in when it is connected to the field or a practice computer:

ModeDescription
AutonomousThe robot is performing actions all on its own.
TeleoperatedThe robot is accepting input from human drivers.
TestThe robot accepts specific instructions so as not to pollute the teleoperated mode.
SimulationThe robot accepts inputs specifically programmed to run in a simulated environment.
DisabledThe robot denies all inputs from the human drivers and robot code, and sits idle.

Each of these modes has its own initialization method, such as autonomousInit() or teleopInit(), which runs once when that mode is selected and is used to set up anything the mode needs before it starts running.

Execution

The execution step is the biggest step for a robot to perform, it's where all the things you want the robot to do on the field actually get commanded.

Execution Phases

Just like each mode has its own initialization method, it also has its own periodic method, such as autonomousPeriodic() or teleopPeriodic(). Once a mode's initialization method has run, its periodic method runs perpetually until the mode is exited, and this is where the actual behavior of the robot during a match is commanded.

The word "periodic" is doing a lot of work here: these methods are really just the body of a loop that the robot program is running for you behind the scenes, similar to a while loop that never stops iterating. Every ~20 milliseconds, whichever periodic method matches the current mode gets called once, does its work, and returns, and the whole cycle repeats.

important

Because a periodic method is already one iteration of a loop, you should never write your own while loop (or any other blocking loop) inside of one. A while loop that waits for some condition to become true will block that single 20 millisecond iteration from ever returning, which freezes the entire robot program. No other periodic methods will run, sensor data will stop updating, and the driver station will report the robot as unresponsive. If you need something to happen "over time" or "until a condition is met," let the periodic method's natural, repeated calls act as your loop instead of nesting another one inside it.