Skip to main content

Lesson 6.5: Build a Non-Blocking Timer for Parallel Mechanism Control


Technical Context

"Blocking" code (using sleep() or empty while loops) prevents a robot from performing parallel tasks. A responsive robot may need to drive toward a target while simultaneously raising a lift. A non-blocking timer loop lets the program check time, sensors, and encoders in the same loop cycle, so independent mechanisms can continue updating.


How Non-Blocking Timing Lets Mechanisms Work Together

This lesson uses the SDK's ElapsedTime utility. Calling new ElapsedTime() creates a timer and starts it immediately; calling reset() establishes a new zero point when an action begins. The loop can then check seconds() or milliseconds() without pausing other code.

This pattern is commonly used for state-machine transitions and parallel mechanism control.


Annotated Code

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.util.ElapsedTime;

@TeleOp(name="Parallel_Control_Demo")
public class ParallelControlDemo extends LinearOpMode {

// The constructor starts the timer; reset it when the timed action begins.
private final ElapsedTime liftTimer = new ElapsedTime();

@Override
public void runOpMode() {
DcMotor driveMotor = hardwareMap.get(DcMotor.class, "drive");
DcMotor liftMotor = hardwareMap.get(DcMotor.class, "lift");

waitForStart();
liftTimer.reset();

while (opModeIsActive()) {
// Action 1: Drive can continue responding on each loop cycle
driveMotor.setPower(-gamepad1.left_stick_y);

// Action 2: Lift only runs if the timer window is still open
if (liftTimer.seconds() < 2.0) {
liftMotor.setPower(1.0);
} else {
liftMotor.setPower(0.0);
}

telemetry.addData("Lift Time", "%.2f s", liftTimer.seconds());
telemetry.update();
}
}
}

Competition Code in the Wild

Murray Bridge Bunyips' BunyipsLib wraps a function in a reusable periodic scheduler. Its field initialization also shows the complete new ElapsedTime() expression:

private final ElapsedTime timer = new ElapsedTime();

@Override
public void run() {
if (!init) {
timer.reset();
init = true;
}

if (intervalMs <= 0 || timer.milliseconds() >= intervalMs) {
function.run();
timer.reset();
}
}

Nothing in run() waits. Repeated calls check the deadline, run the function when due, reset the timer, and return. Excerpted from BunyipsLib's Periodic.java at a pinned commit under the MIT License.


Fill-in-the-Blank Practice

  1. Using sleep() is discouraged because it __________ the entire program thread from updating other hardware.
  2. A __________ timer loop is necessary to allow parallel mechanism control.
  3. To trigger an event after 5 seconds without stopping the robot, call reset() when the event begins and compare __________ against 5.0.
Show answers
  1. blocks
  2. non-blocking
  3. timer.seconds() (where timer is an ElapsedTime instance)

Simulator Practice

Use the simulator below to practice running one mechanism on a timer while another still responds every loop cycle.

Telemark Unit 6 Simulator
Supports OpMode and LinearOpMode practice with lesson-specific starter code.
Includes loop stepping, runtime tracking, lifecycle controls, and live gamepad input.
Best for practicing loop structure, timers, and safe control flow patterns.

Ready to move on?

Only mark complete if you genuinely understand the material. Your progress will be saved in this browser.

Stuck on this lesson?

Ask about anything on this page. It can see which lesson you have open and which part you are reading.