All pages
Powered by GitBook
1 of 4

Loading...

Loading...

Loading...

Loading...

ElapsedTime - OnBot Java

Introduction to ElapsedTime

When using our gamepad, we can actively communicate with our robot while our program runs. Our robot waits for our input and acts accordingly until a different command is issued. However, this may not always be the case, such as during the autonomous period of a FTC competition.

Our robot is smart enough to navigate some on its own, however we need to help it along to know what to look for. Eventually, you could work up to your robot being able to navigate using a camera and machine learning or its IMU to sense direction, but for now let's start with one of the built in features of the SDK: ElapsedTime


What do you think of when you think of a timer? A stopwatch? Your phone? Maybe the timer on a microwave or oven? Timers commonly consist of two main categories: count up and count down. You can think about the differences of these two by a comparison like keeping track of how fast a runner did a 100m dash vs. needing to know how much longer our food should cook.

ElapsedTime is a count up timer. Registering the amount of time elapsed from the start of a set event, like the starting of a stopwatch. In this situation, it is the amount of time passed from when the timer is created or reset within the code.

For more information on the ElapsedTime object outside this tutorial check out the FTC Java Docs!

Quick Links

Full Code Example

This program uses the same configuration file created at the start of Hello Robot. Some hardware may not be used during this section.

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.hardware.Blinker;
import com.qualcomm.robotcore.hardware.Servo;
import com.qualcomm.robotcore.hardware.TouchSensor;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.DcMotorSimple;
import com.qualcomm.robotcore.util.ElapsedTime;

@TeleOp

public class HelloRobot_ElapsedTime extends LinearOpMode {
    private Blinker control_Hub;
    private DcMotor arm;
    private DcMotor leftmotor;
    private DcMotor rightmotor;
    private DcMotor test_motor;
    private Servo test_servo;
    private TouchSensor test_touch;
    private ElapsedTime     runtime = new ElapsedTime();


    @Override
    public void runOpMode() {
        control_Hub = hardwareMap.get(Blinker.class, "Control Hub");
        arm = hardwareMap.get(DcMotor.class, "arm");
        leftmotor = hardwareMap.get(DcMotor.class, "leftmotor");
        rightmotor = hardwareMap.get(DcMotor.class, "rightmotor");
        test_motor = hardwareMap.get(DcMotor.class, "test_motor");
        test_servo = hardwareMap.get(Servo.class, "test_servo");
        test_touch = hardwareMap.get(TouchSensor.class, "test_touch");

        rightmotor.setDirection(DcMotorSimple.Direction.REVERSE);
        telemetry.addData("Status", "Initialized");
        telemetry.update();
        
        // Wait for the game to start (driver presses PLAY)
        waitForStart();
        runtime.reset();
        while (opModeIsActive() && (runtime.seconds() <= 3.0)) {
            leftmotor.setPower(1);
            rightmotor.setPower(1);
            telemetry.addData("Number of Seconds in Phase 1", runtime.seconds());
            telemetry.update();
        }

        runtime.reset();
        while (opModeIsActive() && (runtime.seconds() <= 3.0)) {
            leftmotor.setPower(-1);
            rightmotor.setPower(-1);
            telemetry.addData("Number of Seconds in Phase 2", runtime.seconds());
            telemetry.update();
        }
    }
 }

ElapsedTime Setup
ElapsedTime Logic
ElapsedTime - Multiple Movements

ElapsedTime Setup

Programming with ElapsedTime

Start by creating a new OpMode called HelloRobot_ElapsedTime using the BlankLinearOpMode sample similar to what we used in Part 1.

Selecting the features discussed above will allow you to start with the following code. Remember that if "Setup Code for Configured Hardware" is selected the OpMode will try to generate a hardwareMap based on the active configuration. This example uses the same Hello Robot config file we originally created!

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.hardware.Blinker;
import com.qualcomm.robotcore.hardware.Servo;
import com.qualcomm.robotcore.hardware.TouchSensor;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.DcMotorSimple;
import com.qualcomm.robotcore.util.ElapsedTime;

@TeleOp

public class HelloRobot_ElapsedTime extends LinearOpMode {
    private Blinker control_Hub;
    private DcMotor arm;
    private DcMotor leftmotor;
    private DcMotor rightmotor;
    private DcMotor test_motor;
    private Servo test_servo;
    private TouchSensor test_touch;

    @Override
    public void runOpMode() {
        control_Hub = hardwareMap.get(Blinker.class, "Control Hub");
        arm = hardwareMap.get(DcMotor.class, "arm");
        leftmotor = hardwareMap.get(DcMotor.class, "leftmotor");
        rightmotor = hardwareMap.get(DcMotor.class, "rightmotor");
        test_motor = hardwareMap.get(DcMotor.class, "test_motor");
        test_servo = hardwareMap.get(Servo.class, "test_servo");
        test_touch = hardwareMap.get(TouchSensor.class, "test_touch");

        telemetry.addData("Status", "Initialized");
        telemetry.update();
        // Wait for the game to start (driver presses PLAY)
        waitForStart();

        // run until the end of the match (driver presses STOP)
        while (opModeIsActive()) {
            telemetry.addData("Status", "Running");
            telemetry.update();

        }
    }
}

Setting up the Basics

To prepare to use ElapsedTime, a variable and an instance of ElapsedTime needs to be created. To do this the following line is needed:

private ElapsedTime     runtime = new ElapsedTime();

In this case we are named our variable runtime.

The above line performs two actions:

  1. A ElapsedTime variable called runtime is created. Once it is created and defined as an ElapsedTime variable, it can hold the relevant time information and data.

  2. The other part of the line, runtime = new ElapsedTime();, creates an instance of the ElapsedTime timer object and assigns it to our new runtime variable.

Add this line to the OpMode with the other private variables:

public class HelloRobot_ElapsedTime extends LinearOpMode {
    private DcMotor leftMotor;
    private DcMotor rightMotor;
    private DcMotor arm;
    private Servo claw;
    private TouchSensor touch;
    private ElapsedTime     runtime = new ElapsedTime();

In OnBot Java the private keyword is an access modifier that, in this situation, means this variable can only be used within the class it was defined. Our class for this project is our "public class HelloRobot_ElapsedTime".

Next we can go ahead and add the basic movement for our motors. For this example, we will set both motors to a power of 1:

@TeleOp

public class HelloRobot_ElapsedTime extends LinearOpMode {
    private Blinker control_Hub;
    private DcMotor arm;
    private DcMotor leftmotor;
    private DcMotor rightmotor;
    private DcMotor test_motor;
    private Servo test_servo;
    private TouchSensor test_touch;
    private ElapsedTime     runtime = new ElapsedTime();

    @Override
    public void runOpMode() {
        control_Hub = hardwareMap.get(Blinker.class, "Control Hub");
        arm = hardwareMap.get(DcMotor.class, "arm");
        leftmotor = hardwareMap.get(DcMotor.class, "leftmotor");
        rightmotor = hardwareMap.get(DcMotor.class, "rightmotor");
        test_motor = hardwareMap.get(DcMotor.class, "test_motor");
        test_servo = hardwareMap.get(Servo.class, "test_servo");
        test_touch = hardwareMap.get(TouchSensor.class, "test_touch");

        telemetry.addData("Status", "Initialized");
        telemetry.update();
        // Wait for the game to start (driver presses PLAY)
        waitForStart();

        // run until the end of the match (driver presses STOP)
        while (opModeIsActive()) {
            leftmotor.setPower(1);
            rightmotor.setPower(1);
            telemetry.addData("Status", "Running");
            telemetry.update();

        }
    }
}

Lastly, we need to make sure our right motor's direction is reversed during initialization:


    @Override
    public void runOpMode() {
        control_Hub = hardwareMap.get(Blinker.class, "Control Hub");
        arm = hardwareMap.get(DcMotor.class, "arm");
        leftmotor = hardwareMap.get(DcMotor.class, "leftmotor");
        rightmotor = hardwareMap.get(DcMotor.class, "rightmotor");
        test_motor = hardwareMap.get(DcMotor.class, "test_motor");
        test_servo = hardwareMap.get(Servo.class, "test_servo");
        test_touch = hardwareMap.get(TouchSensor.class, "test_touch");

        rightmotor.setDirection(DcMotorSimple.Direction.REVERSE);
        telemetry.addData("Status", "Initialized");
        telemetry.update();
        // Wait for the game to start (driver presses PLAY)
        waitForStart();

ElapsedTime - Multiple Movements

Right now our robot should move forward 3 seconds then stop. What if we wanted our robot to do something else after those 3 seconds? How do we request our program to continue?

To save some time we can copy and paste our entire loop and timer reset below our existing code to make adjustments to!

runtime.reset();
while (opModeIsActive() && (runtime.seconds() <= 3.0)) {
    leftmotor.setPower(1);
    rightmotor.setPower(1);
    telemetry.addData("Number of Seconds in Phase 1", runtime.seconds());
    telemetry.update();
        }

runtime.reset();
while (opModeIsActive() && (runtime.seconds() <= 3.0)) {
    leftmotor.setPower(1);
    rightmotor.setPower(1);
    telemetry.addData("Number of Seconds in Phase 1", runtime.seconds());
    telemetry.update();
        }

Notice our second loop also has a call for telemetry data, however the name is the same! Let's edit it to be "Number of Seconds in Phase 2". Keep the names in mind if you duplicate additional loops.

When copying and pasting code within OnBot Java be sure to double check you still have the correct number of brackets! You may see a line highlighted in red in the case of a bracket missing or if there are too many:

Quick Check!

Give your program a test to see what happens. Think about the following while testing:

  • How long does the robot move?

  • Could you tell when the robot switched between Phase 1 and 2?

  • What happens if we change the power in the second loop?

Reversing Movement

Having multiple loops with different amounts of time can give us a lot of power to help our robot navigate an area. For now let's have our robot complete it's first movement forward for 3 seconds, then reverse back to the start.

This simply requires changing our power in the second loop to -1 !

runtime.reset();
while (opModeIsActive() && (runtime.seconds() <= 3.0)) {
    leftmotor.setPower(1);
    rightmotor.setPower(1);
    telemetry.addData("Number of Seconds in Phase 1", runtime.seconds());
    telemetry.update();
        }

runtime.reset();
while (opModeIsActive() && (runtime.seconds() <= 3.0)) {
    leftmotor.setPower(-1);
    rightmotor.setPower(-1);
    telemetry.addData("Number of Seconds in Phase 2", runtime.seconds());
    telemetry.update();
        }

ElapsedTime Logic

Setting a Time Limit

For now our goal will be to have the motors move forward for 3 seconds. To accomplish this we need to edit our main While Loop so that it triggers when the OpMode is active AND the ElapsedTime timer is less than or equal to 3 seconds.

Let's take a look first at how our timer appears in OnBot Java when checking for less than or equal to 3 seconds:

runtime.seconds() <= 3.0
Click to Review OnBot Java Operators

In OnBot Java we can use the following operators when assigning a check for a variable's value:

  • Equal to: ==

  • Less than: <

  • Greater than: >

  • Less than or equal to: <=

  • Greater than or equal to: >=

Modifying Our While Loop

When using our default template, our program will continue running until we press stop on the Driver Hub. However, in this situation we want our program to end when our timer is up. This means we need to modify our while loop to add a second condition!

Alongside our check for opModeIsActive() we will add our check for if runtime is under 3 seconds:

       waitForStart();
       while (opModeIsActive() && (runtime.seconds() <= 3.0)) {

        }

&& is a logical operator in Java. This symbol is the Java equivalent of "and."

Think back to in Part 1 we learned that || means OR in OnBot Java!

Now the While Loop will now activate when both conditions of the AND block are true.

Quick Check!

Let's give our OpMode a try and test the following scenarios:

  • What happens when hitting play quickly after the initialization button is pressed?

  • What happens when hitting play 2 seconds after the initialization button is pressed?

  • What happens when hitting play 10 seconds after the initialization button is pressed?

What happens while testing?

You may notice the robot moves different distances depending on how long the wait is between INITIALIZATION and PLAYING the program. But why is that?

Remember our timer starts counting when created. Currently, our program creates our timer during initialization meaning it's counting up before Play is ever pressed. If we wait too long our robot may not do anything at all when clicking Play!

Resetting the Timer

Not being able to pause between initialization and pressing Play is probably not ideal in most situations. It certainly makes tracking how far the robot will travel more challenging, the opposite of what we'd like ElapsedTime to help us do.

To keep this from happening the timer should be reset once the OpMode is active. Let's add the line runtime.reset(); between the waitForStart(); command and the while loop.

       waitForStart();
       runtime.reset();
       
       // run until the end of the match (driver presses STOP)
       while (opModeIsActive() && (runtime.seconds() <= 3.0)) {

Since this is before our loop our robot will complete it once when Play is pressed. Then will complete the check for our While Loop.

Test your program again with this change!

        rightmotor.setDirection(DcMotorSimple.Direction.REVERSE);
        telemetry.addData("Status", "Initialized");
        telemetry.update();
        
        // Wait for the game to start (driver presses PLAY)
        waitForStart();
        runtime.reset();
        
        // run until the end of the match (driver presses STOP)
        while (opModeIsActive() && (runtime.seconds() <= 3.0)) {
            leftmotor.setPower(1);
            rightmotor.setPower(1);
            telemetry.addData("Status", "Running");
            telemetry.update();

Now let's explore what happens when we change our time limit to different amounts. You can adjust your time limit by changing the 3 seconds within (runtime.seconds() <= 3.0) to different numbers.

Consider marking different goals on the floor with tape to practice determining how much time the robot needs to reach it.

Adding Telemetry

In previous parts, we've looked at adding telemetry as a way for the robot to communicate with us. In this situation, it would be helpful for the robot to be able to tell us how much time it has counted so we can make adjustments to our program!

For our key let's call it "Number of Seconds in Phase 1" for now. This will be useful for distinguishing where in our program our robot is during the next section.

        // run until the end of the match (driver presses STOP)
        while (opModeIsActive() && (runtime.seconds() <= 3.0)) {
            leftmotor.setPower(1);
            rightmotor.setPower(1);
            telemetry.addData("Status", "Running");
            telemetry.addData("Number of Seconds in Phase 1", runtime.seconds());
            telemetry.update();