Skip to content

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.

Speed clamp
        if (speed > 1.0) {
            speed = 1.0;  // clamp to maximum
        }

Add else to handle the false case:

/// tab | SparkMax

Limit switch: stop on trigger
        if (limitSwitch.get()) {
            motor.set(0);       // stop if limit switch is triggered
        } else {
            motor.set(0.5);     // otherwise keep moving
        }
/// /// tab | TalonFX
Limit switch: stop on trigger
        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

Elevator position control
        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
        }
/// /// tab | TalonFX
Elevator position control
        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

Soft limit with if/else
    public void moveUp(double speed) {
        if (getHeight() < MAX_HEIGHT) {
            motor.set(speed);
        } else {
            motor.set(0);
        }
    }
/// /// tab | TalonFX
Soft limit with if/else
    public void moveUp(double speed) {
        if (getHeight() < MAX_HEIGHT) {
            motor.setControl(new DutyCycleOut(speed));
        } else {
            motor.setControl(new DutyCycleOut(0));
        }
    }
///

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

While loop example
        while (!atTarget()) {
            motor.set(0.5);
        }
        motor.set(0);
/// /// tab | TalonFX
While loop example
        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:

isFinished() pattern
    @Override
    public boolean isFinished() {
        return m_subsystem.atTarget();
    }

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#

Counting loop
        for (int i = 0; i < 5; i++) {
            System.out.println("Iteration: " + i);
        }

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

For-each loop
        SparkMax[] motors = {leftLeader, leftFollower, rightLeader, rightFollower};

        for (SparkMax motor : motors) {
            motor.setSmartCurrentLimit(40);
        }
/// /// tab | TalonFX
For-each loop
        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

Motor configuration loop
        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
        }
/// /// tab | TalonFX
Motor configuration loop
        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

Elevator subsystem
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
    }
}
/// /// tab | TalonFX
Elevator subsystem
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