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 |
5 sec |
BotServices calls |
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.
3. Blink Forever¶
Did you notice that those timeout events were scheduled from the beginning of time - when your program first started? So the LED was on for 4 seconds in the code above.
But you aren’t limited to scheduling events at the start. Callback functions themselves can schedule events using
bot.on_timeout()
.
In the following code each of the callback functions schedules another event. So the fun never ends!
Give it a try:
from botcore import *
from botservices import BotServices
bot = BotServices()
def led_on():
leds.user_num(0, True)
bot.on_timeout(led_off, 1000)
def led_off():
leds.user_num(0, False)
bot.on_timeout(led_on, 1000)
# Turn LED on and schedule led_off for later.
led_on()
# Start the event-loop
bot.loop()
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 toled_dir = -1
Rather than always adding +1 to your
led_num
, useled_dir