The version of the agenda presented in the textbook is a only for simulations. It doesn’t actually create a time delay between running actions. For this lab, we will be using a modified version of the agenda data structure that actually creates a time delay between actions executing at different time segments. Each time unit in the agenda data structure we will be using corresponds to 1 millisecond in real time. So for instance if you have two items in the agenda at time segments separated by 1000, they will execute 1 second apart. The rest of this page describes the procedures you will need to use to interact with the agenda.
(after-delay time action)
This procedure inserts an action into the agenda time
milliseconds after the current time. Action
here must be a procedure that takes no arguments. Many of the
procedures you can use to control the dog already take in no arguments,
such as look-left
, so to command the dog to look left after 2 seconds you could just evaluate: (after-delay 2000 look-left)
. Because look-left is already a procedure that takes in no arguments. Other procedures such as walk
take in arguments. Procedures with arguments can be wrapped inside of
procedures without arguments using a lambda without any arguments. For
instance, you can put the action (walk 1.0)
into the agenda by wrapping it inside of a lambda expression like this: (lambda () (walk 1.0))
.
Now you have a procedure that takes no arguments, so you can add it to
the agenda. For instance, to walk forward quickly after 1/2 second, you
would evaluate: (after-delay 500 (lambda () (walk 1.0)))
.
There are at least two ways to program using after-delay
.
The simple approach is to just fill the agenda with all of the actions
you want to preform at a specific time before any of them start. You
can also create procedures that add each other to the agenda as they
are evaluated. This can be thought of as time delayed recursion.
Here's an example of the simple approach. In this example, the dog will move forward for a second, then stop and wait a second, and then look left and make a sniffing sound. This example also illustrates passing named and unnamed procedures to after-delay.
(after-delay 0 (lambda () (walk .7))) (after-delay 1000 stop) (after-delay 2000 (lambda () (look-left) (sniff)))
It would be cumbersome to design a whole dance this way. A better
approach is to break your dance into different repeating patterns. To
do this, you can create actions that insert each other into the agenda.
This is time delayed recursion. For instance, you can make the AIBO nod
its head up and down repeatly by writing two procedures. One procedure
moves the dog's head up and adds the other procedure to the agenda. The
other procedure moves the dog's head back down and adds the first
procedure to the agenda again. This creates a sort of infinite loop. To
cancel this infinite loop at any time you can add the procedure reset-the-agenda!
to the agenda which removes all actions from the agenda.
(define (my-nod-down) (nod-down) ; nods dogs head down (after-delay 200 my-nod-up)) (define (my-nod-up) (nod-up) ; nods dogs head up (after-delay 200 my-nod-down)) (after-delay 0 my-nod-up) ; Put first call in the agenda, to get the process started (after-delay 20000 reset-the-agenda!) ; Stop the loop after 20 seconds
(propagate)
None of the actions you put in the agenda are executed until you call (propagate)
. This procedure goes through the agenda and executes all of the actions at the right times.(reset-the-agenda!)
This procedure clears all events from the agenda. If you have loops of
procedures adding each other to the agenda, you should use this to
prevent an infinite loop. Add it to the agenda with some large (30
seconds or so) delay.