Skip to content

Using Timers in Blocks

Chris Johannesen edited this page Nov 24, 2019 · 22 revisions

This tutorial shows FTC Blocks programmers how to use Timers. If you're in a hurry (no time), skip to the < examples below >. Java programmers may benefit from learning here how FTC timers work.

Why not Sleep?

Many new Blocks programmers use the Sleep command (MyOpMode.sleep) as their only control of time.

This is a very basic and common use of timed action in a linear Op Mode used for Autonomous. It tells the robot to process no new instructions for the specified duration.

But what if other activities need to happen, while that motor runs? In Autonomous, for example, you might need to collect sensor data while the robot moves forward for 3 seconds. In TeleOp, you might need to continue driving with gamepads while a CR servo rotates for 2 seconds. The Sleep command will not allow this; "no new instructions".

Timers provide a more flexible solution.

Timer Menu

In FTC Blocks, timer commands are found in menu at the left side, under Utilities, Time, ElapsedTime.

In general you will create your own timer, then use pre-made commands or methods to access the contents of that timer. This is not as simple as 'look at the clock' or 'look at the stopwatch' in real life. There are more steps, based on the structure and protections of Object-Oriented Programming (OOP). Java is an OOP language, and Blocks is based on Java.

Create a Timer

The first step is to create a new timer object. In Java, an Object is an instance or example of a Class. FTC Blocks provides a class called ElapsedTime. A class contains variables and methods (commands). Your new timer is an instance of that class, inheriting its characteristics. Here we call the new timer object "myTimer". You could think of it as "My New Stopwatch", although Timers don't actually stop.

Set myTimer to new Time.ElapsedTime

This is not the usual Blocks "set" command. Instead of assigning a number to a variable, this Block creates, or instantiates, a new object called myTimer. myTimer is an instance of the class ElapsedTime, which we see here is actually a subclass of a more general class called Time.

As soon as a new timer is created, it begins running from a starting time of zero. However you will probably not rely on that zero start value, because you will use the timer later in your Op Mode, when the time value has changed.

Initialize a Timer

At some point your Op Mode is ready to use myTimer, probably somewhere after 'waitForStart'. As a programmer you don't know in advance how much time has passed, so you should set the contents of myTimer to a definite starting value. Your choices are: zero, or the current system time (time since the Op Mode was initialized). The simplest choice is zero.

call ElapsedTime.reset timer
Description: Reset the specified elapsed time object.

This Block uses a method called "reset", from the class called ElapsedTime. It resets your clock myTimer to zero. Your clock will start counting from zero immediately and keep running. Timers don't stop; all you can do is read their changing time value at a single instant.

What Time is It?

It is important to understand that "myTimer" is simply the name of the clock or stopwatch, not the time value itself. The Block is purple like other Variables, but reading "myTimer" as a number will not give you the time.

Instead you must use a built-in method or command, to get or retrieve the contents of myTimer. Here is the simplest way.

← ElapsedTime.Time timer
Description: Return the elapsed time since the last reset of the specified elapsed time object in the resolution of the elapsed time object.

We can read this from right to left. This Block uses a method or command named "Time"; you can consider its real name to be "Get A Timer's Current Time Value". Here the method gets the value from myTimer, and passes, or returns, it to the left. On the left could be a variable to hold that number, or it could be another Block that accepts number input.

The units will be Seconds or Milliseconds, whichever is the current setting for this timer.

Here the variable "currentTime" holds the number of seconds (or milliseconds) that myTimer has been running, since it was last reset to zero. Finally you have the number you want, but remember that this number is fixed, not changing. It was the time value at the exact moment you checked myTimer.

Telemetry

Here is a basic way to display the current value in your timer.

image telemetry-basic

Again, you cannot try to directly show myTimer -- that's just the name of your timer object.

image telemetry-wrong-marked

You may find that a constantly changing time value causes programming problems. You could store the time value once, then use it various places.

image telemetry-correct

Here the Telemetry Block builds a message showing the variable currentTime, containing a value retrieved from your timer. Although its value may be updating constantly in a Repeat loop, currentTime is not actually the running clock. Keep in mind that the variable holds a fixed saved value.

Timer Examples

Here are five common uses of timers:

  1. Loop until a time limit is reached. Think of this as an alarm clock.
  2. Measure the length of time (until an action stops or occurs). Think of this as a stopwatch.
  3. Safety timeout. Think of this as a buzzer on Jeopardy!
  4. Match timer or countdown timer.
  5. Device timer in TeleOp.

1. Loop for Time

This is the most common usage. In the shortest version, create and start the timer immediately before use.

image example-1-looping-smallest

In the more formal, recommended version, create the timer in the Initialize section of your Op Mode (before waitForStart). Then reset the timer before each use.

image example-1-looping-smaller

You may want to observe the timer doing its job, using Telemetry.

image example-1-looping

2. Measure Duration of Action

Create the 'stopwatch' timer in initialize, then reset (re-start) that timer when a robot action begins. When the robot action is finished, store the timer value in a Variable.

image example-2-duration

Here the stored (final) timer value is displayed immediately as Telemetry. When testing, a long Sleep command will keep your Telemetry on the DS screen, before the Op Mode ends.

The example mentions "Optional loop here". If the robot action is simple, a Repeat Loop allows you to monitor the stopwatch as the action continues.

image example-2-duration-loop

This works best in an Autonomous Op Mode, where robot actions happen in a sequence. To monitor a single timer through several actions, make a Telemetry loop for each action.

3. Safety Timeout

This is the same as 'Loop for Time', except the timer is not the primary basis for looping, it's the last resort. Reaching the time limit means the loop did not achieve its primary goal; time to give up and move on. This could be to prevent: motor/servo overheating, mechanism breaking, field damage, or simply wasted time. All action loops should have a safety timeout.

image example-3-safety-timeout

What might cause a timeout? Sensors failed, unexpected field condition, low battery, robot meets robot, etc. If the Op Mode remains stuck in a Repeat Loop, the timeout can allow the Op Mode to continue. Inside the loop, you may want to set a Variable indicating the cause of exiting the loop. This information can be used immediately after the Loop, to carry out the best next action. The next action might be to back up, try again, move on with other scoring attempts, re-establish the robot's location, or simply take no action until the end of Autonomous or Endgame.

4. Match Timer

Monitor the time since the start of Autonomous or TeleOp, give warnings or take action accordingly. Also can 'lock out' or prevent certain actions until a specific time in the match, to reduce driver error. Example from Rover Ruckus: don't begin the "hang" before Endgame. Or, from SKYSTONE: don't release the spring-powered Loading Zone extender before Endgame.

image example-4-match

In this example, the timer was not instantiated in the Initialize section as recommended. Doing so allows re-use of the same timer, through simple Resets at each place needed in the Op Mode.

You might prefer to instantiate a timer just where needed. It makes sense in this example, since a Match Timer will not be used more than once. You get a Reset for free, saving one line of code.

Programming Tip: Boolean (true/false) Variables can be read directly by IF blocks, as shown in the above example. The following two Blocks are equivalent.

image example-4-tip-true

Likewise, these two Blocks are equivalent.

image example-4-tip-false

Carefully select the names of your Boolean variables, so your Op Modes are simple and easy to read.

Programming Tip: Similarly, the Logic Compare Block returns a Boolean value. In the above example, the first IF-DO Blocks could be replaced with:

image example-4-tip-assign

Caution: this replacement is not exactly the same. It can also assign False, where the original IF-DO did not handle the False scenario. Programmers must consider these differences.

5. Device Timer in TeleOp

For TeleOp, an Op Mode typically runs all commands in a single overall Repeat Loop. How can you run a device for time, within that loop? Example: when button B pressed, run a CR servo for 2 seconds.

image example-5-device

The timer here is instantiated with time units or resolution of Milliseconds, rather than the default Seconds. This affects only the programming and display aspects for convenience; the actual timer accuracy is in Nanoseconds.

This example also shows how to capture only the first moment of the button being pressed. The continued pressing of the button is ignored, when the Boolean (true/false) variable CRservoIsRunning is set to True. After 2 seconds of running, this Boolean "flag" is reset to False, which stops checking the timer and allows a fresh press of button B if desired.

Programming tip: The pressing of a gamepad button lasts for some time, much longer than a full cycle of a Repeat Loop. Programmers should beware of unintended effects of continued pressing. Without the flag in the above example, the CR servo could run much longer than 2 seconds.

Other Timer Blocks

For more options, here are the other Blocks from the ElapsedTime menu.

← new ElapsedTime startTime call System.nanoTime
Description: Create a new elapsed time object with seconds resolution and initialize it to the current system time or a value that you plug in in its place.

← new ElapsedTime resolution
Resolution [SECONDS or MILLISECONDS] This version of the standard 'create new timer' Block allows you to specify the units of time used by the new timer. The default is seconds.

← ElapsedTime.StartTime timer
This method provides, or returns, the original starting time value of this timer. This is not a constantly running time value, it's the saved value of the timer's last start (or restart) time. In other words, it gives the time of the start, not the time since the start. The units will be Seconds or Milliseconds, whichever is the current setting for this timer.

← ElapsedTime.seconds timer
This returns the current time value in Seconds, even if the timer uses Milliseconds.

← ElapsedTime.Milliseconds timer
This returns the current time value in milliseconds, even if the timer uses Seconds.

← ElapsedTime.Resolution timer
This returns a value indicating whether the timer is set to Seconds or Milliseconds.

call ElapsedTime.log timer label
This writes a message to the system log file, for later analysis. The message shows the timer's value, with a custom text label for easier identification in the (very detailed) log file. Downloading system logs is described here for Robot Controller (RC) phones: https://github.com/FIRST-Tech-Challenge/SkyStone/wiki/Managing-a-Smartphone-Robot-Controller#Downloading-the-Log-File

And here for REV Control Hubs: https://github.com/FIRST-Tech-Challenge/SkyStone/wiki/Managing-a-Control-Hub#Downloading-the-Log-File

← call ElapsedTime.toText timer
Returns a text string, converted from the timer's numeric value. This allows combining the value with other text.

Timer Options and Potential

You can create and use multiple timers, resetting and reading them at various points in your Op Mode. They can overlap, and have no effect on each other. It's best to give them meaningful names, like LifterLoopTimer or TimeSinceStart or GrabberSafetyTimer.

Use Telemetry to monitor the time inside loops, and give a final time report after the loop. This is a tool to help you cut valuable seconds from Autonomous runs.

When testing your Op Mode, make sure the Telemetry message stays on the screen long enough to read it. If this is not possible, or you are studying a sequence of very close events, consider the logging option below.

image options-telemetry

Timers offer many advanced possibilities, including:

  • stall detection
  • using gamepad buttons as analog inputs
  • complex task automation in Auto and TeleOp
  • custom PI and PID control algorithms

.

Questions, comments and corrections to: [email protected]

Clone this wiki locally