Timers

Two things at once, remembered ticks, timeouts.

5.3BehavioursRobot club15 min

Do this lesson in the simulator

"Blink the LED while driving to the zone." Two waits cannot do that: wait(0.5) for the blink stops the driving loop. In a behaviour, nothing waits except the tick. Time is counted, not waited for.

Two things at once

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

ticks = 0
on = False
while position()[1] < 70:
    # drive forward at 60 (keeps going until the next command)
    forward(60)
    # every 5 ticks = every half second
    if ticks % 5 == 0:
        on = not on
        led("green" if on else "off")
    ticks += 1
    # pause 0.1 s (the robot keeps doing what it was told)
    wait(0.1)
# all motors off
stop()
# the LED: off
led("off")
print("arrived after", ticks, "ticks =", ticks / 10, "seconds")

Run this in the simulator

The driving happens every tick. The blink happens on every fifth tick. on = not on flips a True to False and back: a toggle.

A timer is a remembered tick

To do something a fixed time after an event, remember the tick the event happened on:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

ticks = 0
started_turning = None
while position()[1] < 60:
    if started_turning is None:
        # drive forward at 60 (keeps going until the next command)
        forward(60)
        # after two seconds, start a turn
        if ticks == 20:
            started_turning = ticks
    else:
        # spin clockwise on the spot at 50
        turn_right(50)
        # turn for one second, then stop turning
        if ticks - started_turning >= 10:
            started_turning = None
            print("turned at tick", ticks, "now facing", round(heading()))
    ticks += 1
    # pause 0.1 s (the robot keeps doing what it was told)
    wait(0.1)
# all motors off
stop()

Run this in the simulator

ticks - started_turning is the time since the event. None means "no timer running". This pattern, an event tick and a duration, is inside every "do X for N seconds" a robot ever does, without a single blocking wait.

There is also a real clock: clock() returns the seconds since the program started. clock() - started_at >= 1.0 reads better than counting ticks, and it stays right if a tick takes longer than planned. Ticks are still worth understanding, because that is what the clock is made of.

Timeouts

The most important timer is the one that gives up. A search that never finds its tag should stop searching after a while, not spin forever:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

# camera: the tag detector
set_cv("apriltag")
ticks = 0
found = False
# give it three seconds
while ticks < 30:
    if apriltags():
        found = True
        # leave the loop
        break
    # spin clockwise on the spot at 40
    turn_right(40)
    ticks += 1
    # pause 0.1 s (the robot keeps doing what it was told)
    wait(0.1)
# all motors off
stop()
print("found a tag" if found else "gave up after 3 seconds: no tags on this mat")

Run this in the simulator

Task: blink and drive

Drive into the green zone while the LED blinks green and off every half second, at least eight changes.

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

# the LED: green
led("green")
# drive forward at 60 for 70 cm, then stop
forward(60, distance=70)
# the LED: off
led("off")

Challenges

  1. Blink faster as the robot gets closer to the zone.
  2. Drive for two seconds, stop for one, repeat, using one timer variable.
  3. Print the total run time in seconds at the end from the tick count. Check it against the telemetry.