6. How a Robot Program Runs#
Why it matters#
Robot code is not like a normal program that starts, runs top to bottom, and exits. A robot program starts once and then repeats the same code about 50 times a second until the robot is turned off. Every sensor read, motor command, and button check happens inside that repeating loop.
Once you understand the loop, everything else in this course makes sense: why you never wait inside your code, why commands are built the way they are, and why "loop overrun" warnings matter.
Read this#
- What is WPILib?
- Creating a Robot Program, especially the TimedRobot section
Walkthrough#
What happens when the robot turns on#
- The roboRIO boots and starts your program by calling
Main.main(). main()creates yourRobotobject. Its constructor (orrobotInit()) runs once, and this is whereRobotContainercreates all your subsystems and binds your buttons.- The program enters the loop and stays there until power is cut.
Robot modes#
The Driver Station tells the robot which mode it's in. Each mode has its own pair of methods in Robot.java:
| Mode | When | Methods |
|---|---|---|
| Disabled | Before and after a match, and any time the robot isn't enabled | disabledInit(), disabledPeriodic() |
| Autonomous | The first 15 seconds of a match, no driver input | autonomousInit(), autonomousPeriodic() |
| Teleop | The rest of the match, drivers in control | teleopInit(), teleopPeriodic() |
| Test | Practice and tuning only, never in a match | testInit(), testPeriodic() |
| (every mode) | Always | robotPeriodic() |
- An
Init()method runs once, when the robot enters that mode. - A
Periodic()method runs every loop while the robot is in that mode. robotPeriodic()runs every loop in every mode, including disabled.
The 20 ms loop#
TimedRobot calls your periodic methods every 20 milliseconds, which is 50 times per second:
One loop, start to finish, typically looks like this:
- Read the joysticks and sensors.
- Decide what each mechanism should do.
- Set motor outputs.
- Return, and wait for the next 20 ms tick.
Each loop is a snapshot: "Given what I see right now, what should every motor do right now?" Then 20 ms later, you answer the question again with fresh data.
A full match, step by step#
| Time | What the Driver Station does | What runs |
|---|---|---|
| Before the match | Robot is disabled | disabledInit() once, then disabledPeriodic() every 20 ms |
| 0:00 | Field starts autonomous | autonomousInit() once, then autonomousPeriodic() every 20 ms |
| 0:15 | Autonomous ends, brief disable | disabledInit(), disabledPeriodic() |
| 0:18 | Teleop starts | teleopInit() once, then teleopPeriodic() every 20 ms |
| 2:33 | Match ends | disabledInit(), disabledPeriodic() |
robotPeriodic() runs in every row.
The golden rule#
Never block the loop
Your code has 20 ms to finish each loop. Do a little work, then return. Next loop, do a little more.
No Thread.sleep(). No while loops that wait for something. No slow work like reading a big file.
Here's why. Suppose you want to run a motor for 2 seconds:
// ❌ BAD: freezes the robot for 2 seconds
motor.set(0.5);
Thread.sleep(2000);
motor.set(0);
During those 2 seconds, the loop is stuck. Nothing else runs: the drivetrain ignores the joysticks, other mechanisms freeze, and the robot can't even respond to being disabled. The roboRIO's motor safety feature may also shut off motors because they stopped getting updates.
The right way spreads the work across many loops. Each loop checks how much time has passed:
// ✅ GOOD: checked once per loop, finishes in microseconds
private final Timer timer = new Timer();
@Override
public void autonomousInit() {
timer.restart(); // start timing when auto begins
}
@Override
public void autonomousPeriodic() {
if (timer.get() < 2.0) {
motor.set(0.5);
} else {
motor.set(0);
}
}
Over 2 seconds, autonomousPeriodic() runs 100 times. Each time it asks "has it been 2 seconds yet?" and sets the motor accordingly. Every other part of the robot keeps running the whole time.
The same goes for waiting on a sensor:
// ❌ BAD: waits forever if the switch never closes
while (!limitSwitch.get()) {
motor.set(0.3);
}
// ✅ GOOD: one check per loop
if (!limitSwitch.get()) {
motor.set(0.3);
} else {
motor.set(0);
}
This is why command-based programming exists
Writing every mechanism as timers and if statements inside teleopPeriodic() gets messy fast. Commands (Lesson 7) are a cleaner way to write "do this a little each loop until it's done." Under the hood, they follow exactly this rule.
Loop overruns#
If your code takes longer than 20 ms, the console prints a warning:
Warning: Loop time of 0.02s overrun
teleopPeriodic(): 0.045s
robotPeriodic(): 0.001s
That means the next loop started late. An occasional overrun isn't a disaster, but frequent ones make the robot sluggish and unpredictable. The warning shows which method took the time, so you know where to look.
Common causes: Thread.sleep(), waiting loops, printing too much with System.out.println every loop, or slow work like file reads.
Where your code goes in the Command Robot template#
In the template you created in Lesson 0, Robot.java is short, and you'll rarely edit it:
public class Robot extends TimedRobot {
private Command autonomousCommand;
private final RobotContainer robotContainer;
public Robot() {
robotContainer = new RobotContainer(); // builds subsystems, binds buttons
}
@Override
public void robotPeriodic() {
CommandScheduler.getInstance().run(); // runs all commands, every loop
}
@Override
public void autonomousInit() {
autonomousCommand = robotContainer.getAutonomousCommand();
if (autonomousCommand != null) {
autonomousCommand.schedule();
}
}
@Override
public void teleopInit() {
if (autonomousCommand != null) {
autonomousCommand.cancel(); // stop auto when teleop starts
}
}
}
The important line is CommandScheduler.getInstance().run() in robotPeriodic(). Every loop, the command scheduler runs your commands, checks your buttons, and calls your subsystems' periodic() methods. You'll write subsystems and commands; the scheduler decides when they run. Lesson 7.1 covers it in detail.
Try it#
- Open your project's
Robot.javaand find each mode'sInit()andPeriodic()methods - Add a counter field. Increase it in
robotPeriodic()and print it every 50th loop (if (count % 50 == 0)). Run in simulation. Does it print about once per second? - Add a print to
teleopInit()anddisabledInit(). Switch modes in the Sim GUI and watch when each prints. - Put
Thread.sleep(100);inteleopPeriodic()(you'll need to wrap it intry { } catch (InterruptedException e) { }). Enable teleop and read the loop overrun warnings. Then remove it. - Use a
Timerto print "Two seconds!" exactly once, two seconds after teleop starts
Check yourself#
How many times per second does teleopPeriodic() run?
About 50, once every 20 ms.
What's the difference between teleopInit() and teleopPeriodic()?
teleopInit() runs once when teleop starts. teleopPeriodic() runs every loop for the rest of teleop.
Which method runs in every mode, including disabled?
robotPeriodic()
Why does Thread.sleep() cause a loop overrun warning?
The loop has 20 ms to finish. Sleeping blocks it, so the next loop starts late and the whole robot stops responding until it's done.
How do you run a motor for 2 seconds without blocking?
Start a Timer when the action begins, then check timer.get() every loop and stop the motor once it passes 2 seconds.