Control Flow#
Making decisions and repeating actions
Overview#
Programs rarely run straight from top to bottom. Control flow statements let your code make decisions, repeat actions, and respond to changing robot state — all essential skills for writing useful robot behavior.
See table of contents for a breakdown of this section.
if / else (conditional statements)#
An if statement runs a block of code only when a condition is true.
Add else to handle the false case:
/// tab | SparkMax
if (limitSwitch.get()) {
motor.set(0); // stop if limit switch is triggered
} else {
motor.set(0.5); // otherwise keep moving
}
if (limitSwitch.get()) {
motor.setControl(new DutyCycleOut(0)); // stop if limit switch is triggered
} else {
motor.setControl(new DutyCycleOut(0.5)); // otherwise keep moving
}
Chain multiple conditions with else if:
/// tab | SparkMax
if (encoderPosition < LOW_SETPOINT) {
elevator.set(0.3);
} else if (encoderPosition > HIGH_SETPOINT) {
elevator.set(-0.3);
} else {
elevator.set(0); // within range — hold position
}
if (encoderPosition < LOW_SETPOINT) {
elevator.setControl(new DutyCycleOut(0.3));
} else if (encoderPosition > HIGH_SETPOINT) {
elevator.setControl(new DutyCycleOut(-0.3));
} else {
elevator.setControl(new DutyCycleOut(0)); // within range — hold position
}
Tip
Conditions must evaluate to a boolean (true or false). See Variables and Data Types for comparison and logical operators.
FRC Example: soft limit
/// tab | SparkMax
/// /// tab | TalonFX ///Warning
If you are setting a value based on a condition, always include an else case to handle the false condition. In FRC code, this is a critical safety practice — for example, if you only set motor power in the if block, then when the condition is false the motor will continue doing whatever it was doing before, which could lead to dangerous runaway behavior.
while Loop#
A while loop repeats its body as long as its condition remains true.
/// tab | SparkMax
/// /// tab | TalonFX while (!atTarget()) {
motor.setControl(new DutyCycleOut(0.5));
}
motor.setControl(new DutyCycleOut(0));
Do not use while loops inside robot commands
In FRC robot code, do not put while loops inside execute(). The robot scheduler calls execute() repeatedly on its own. An inner while loop would block the scheduler and freeze the robot. Use isFinished() to signal when a command is done instead:
while loops are appropriate in:
- Standalone Java programs (learning exercises, GitHub Classroom assignments)
- Utility code that runs outside the robot framework
for Loop#
A for loop runs a fixed number of times, or once for each item in a collection. It is the most common loop for counting and iterating.
Counting loop#
The three parts of the for header:
| Part | Example | Purpose |
|---|---|---|
| Initializer | int i = 0 |
Runs once before the loop starts |
| Condition | i < 5 |
Checked before each iteration; loop stops when false |
| Update | i++ |
Runs after each iteration — i++ is shorthand for i = i + 1 (see Arithmetic Operators) |
Enhanced for-each loop#
When you want every item in a collection and don't need the index, the for-each form is cleaner:
/// tab | SparkMax
SparkMax[] motors = {leftLeader, leftFollower, rightLeader, rightFollower};
for (SparkMax motor : motors) {
motor.setSmartCurrentLimit(40);
}
TalonFX[] motors = {leftLeader, leftFollower, rightLeader, rightFollower};
TalonFXConfiguration config = new TalonFXConfiguration();
config.CurrentLimits.SupplyCurrentLimit = 40; // cap current draw to 40 amps
for (TalonFX motor : motors) {
motor.getConfigurator().apply(config);
}
FRC Example: configuring multiple motors
Instead of calling the configuration method four separate times, apply config to all motors in a loop:
/// tab | SparkMax
SparkMax[] motors = {leftLeader, leftFollower, rightLeader, rightFollower};
for (SparkMax motor : motors) {
motor.setSmartCurrentLimit(40); // REV API: cap current draw to 40 amps
motor.setIdleMode(IdleMode.kBrake); // REV API: hold position when not powered
}
TalonFX[] motors = {leftLeader, leftFollower, rightLeader, rightFollower};
TalonFXConfiguration config = new TalonFXConfiguration();
config.CurrentLimits.SupplyCurrentLimit = 40; // CTRE: cap current draw to 40 amps
config.CurrentLimits.SupplyCurrentLimitEnable = true;
config.MotorOutput.NeutralMode = NeutralModeValue.Brake; // CTRE: hold position when not powered
for (TalonFX motor : motors) {
motor.getConfigurator().apply(config);
}
Putting It Together#
A realistic example combining if/else and a field to implement elevator soft limits:
/// tab | SparkMax
public class ElevatorSubsystem extends SubsystemBase {
private final SparkMax motor;
private static final double MAX_HEIGHT = 50.0; // encoder rotations
private static final double MIN_HEIGHT = 0.0;
public ElevatorSubsystem() {
motor = new SparkMax(5, MotorType.kBrushless);
}
public void moveUp(double speed) {
if (getHeight() < MAX_HEIGHT) {
motor.set(speed);
} else {
motor.set(0);
}
}
public void moveDown(double speed) {
if (getHeight() > MIN_HEIGHT) {
motor.set(-speed);
} else {
motor.set(0);
}
}
public double getHeight() {
return motor.getEncoder().getPosition();
}
@Override
public void periodic() {
// Could log getHeight() to the dashboard here
}
}
public class ElevatorSubsystemTalonFX extends SubsystemBase {
private final TalonFX motor;
private static final double MAX_HEIGHT = 50.0; // rotations
private static final double MIN_HEIGHT = 0.0;
public ElevatorSubsystemTalonFX() {
motor = new TalonFX(5);
TalonFXConfiguration config = new TalonFXConfiguration();
config.MotorOutput.NeutralMode = NeutralModeValue.Brake;
motor.getConfigurator().apply(config);
}
public void moveUp(double speed) {
if (getHeight() < MAX_HEIGHT) {
motor.setControl(new DutyCycleOut(speed));
} else {
motor.setControl(new DutyCycleOut(0));
}
}
public void moveDown(double speed) {
if (getHeight() > MIN_HEIGHT) {
motor.setControl(new DutyCycleOut(-speed));
} else {
motor.setControl(new DutyCycleOut(0));
}
}
public double getHeight() {
return motor.getPosition().getValueAsDouble();
}
@Override
public void periodic() {
// Could log getHeight() to the dashboard here
}
}
Note
Notice that moveUp and moveDown each contain an if/else — the motor only runs if the elevator is within safe bounds. This pattern of checking limits before applying power is a fundamental safety practice in FRC.
Knowledge Check#
Quiz results are saved to your browser's local storage and will persist between sessions.
Why should you not put a while loop inside a command's execute() method in FRC robot code?
In a for loop header (for (int i = 0; i < 5; i++)), which part runs exactly once before the loop begins?
Which loop form is the cleanest choice when you need to visit every element in an array and do not need the index?
What must always be true about the condition inside an if statement?
Quiz Progress
0 / 0 questions answered (0%)
0 correct