Timer Events

Up to now when you’ve wanted CodeBot to do something that takes time, you’ve used this pattern:

do_something()
time.sleep(delay)

do_something_else()
time.sleep(delay)

... etc.

That works okay for doing one thing at a time, but it’s not a good plan for multitasking.

1. Introducing botservices

The botservices module keeps track of time and monitors all of CodeBot’s sensors.

  • You can define callback functions to react to events such as timeouts and sensor changes.
  • After that, just turn control over to the event loop and it will call your functions when needed.

Note

Event-Driven code looks different than the sequential code you’ve written so far. But really your code is still being run one-step-at-a-time just like always. It’s just that the code that calls your callback functions is down inside botservices.BotServices.loop, so it seems a bit like magic as your program runs!

2. Turn LED off after a scheduled time

Use botservices to flash an LED on and off.

The code below shows the basic structure of an event-driven program:
  • Define callback functions.
  • Register callbacks on events of interest.
  • Run the event loop.

Enter the following in CodeSpace and run it on your ‘bot:

from botcore import *
from botservices import BotServices
bot = BotServices()

# ---- Define functions ----

def led_on():
    leds.user_num(0, True)

def led_off():
    leds.user_num(0, False)

# ---- Setup events ----

# Call 'led_on' after 1 second timeout
bot.on_timeout(led_on, 1000)

# Call 'led_off' after 5 second timeout
bot.on_timeout(led_off, 5000)

# Light LED 7 when about to enter event-loop.
leds.user_num(7, True)

# Start the event-loop, which will call our "callback functions"
bot.loop()

Here’s a timeline of how this program runs:

Time Activity
0 sec
Define the functions, call on_timeout() twice.
Light LED 7
Enter the event loop
1 sec BotServices calls led_on()
5 sec BotServices calls led_off()

The program quickly runs through defining the functions and the on_timeout() calls. Then it then enters the event loop, and never returns! After that, BotServices is in charge of “calling back” those functions at the requested times.

4. Sweep LEDs

Our experiments with timed events conclude with a cool display on the User LEDs.

Often you’ll want a repeating timer to call a function over and over while the robot runs.
  • This could be to check a sensor,
  • or to blink some LEDs,
  • or to play the next tone in a musical sequence…

To create a repeating timer, just define a function that registers itself with an on_timeout() call before it ends.

Try the following code, that sets it up so next_led() is continuously called on a 100ms time tick:

from botcore import *
from botservices import BotServices
bot = BotServices()

# Global variable to hold current LED number
led_num = 0

# Callback function to light up next LED in sequence
def next_led():
    global led_num

    # Turn off current LED
    leds.user_num(led_num, False)

    # Move to next LED
    led_num = led_num + 1
    if led_num > 7:
        led_num = 0

    # Turn on next LED
    leds.user_num(led_num, True)

    # Schedule this event to happen again in 0.1 seconds!
    bot.on_timeout(next_led, 100)


# Turn on first LED and schedule next one!
next_led()

# Start the event-loop, which will call our "callbacks"
bot.loop()

5. Bonus Challenge

Can you modify the last program to make the LED move back and forth?

It’s a cool effect adored by movie cyborgs and AI cars!
Tips:
  • Define a new global variable led_dir = 1
  • In your if statement, change direction to led_dir = -1
  • Rather than always adding +1 to your led_num, use led_dir