This is an old revision of the document!
Writing Plans
with-policy
Policies can be used to define generic monitoring behavior that should run concurrently besides main functionality code. Such a policy might be monitoring
- the position of an object inside a robot gripper to see whether it is moving out of the gripper (losing the object)
- the position of an object in the real world, in order to keep the robot's head pointing towards it
- the collision of a robot joint with objects in the real world
- generic events that must definitely interrupt a certain piece of code, but are too specialized to be implemented directly in the monitored code itself
A policy consists of multiple parts:
- A name (to identify it)
- A description string (to make its purpose clear)
- A parameter list (which can be used to specialize a generic policy for a situation at hand, without generating a new policy every time the situation changes slightly)
- Code blocks that need to be evaluated during monitoring
Usage example
An example of how to define a policy is shown here. The policy accepts two custom parameters, one defining a maximum number and one a match number. During execution of the main body
code (which is really just a loop with an output here), it checks a randomly generated number (ranging from 0
to max-num
) against the match number match-num
. If this is the case (and it will be, eventually), it interrupts (and ends) the main body
code and executes the :recover
code, followed by the :clean-up
code (both just outputting something here).
(define-policy my-policy (max-num match-num) (:description "This is an example policy.") (:init (format t "Initializing policy~%") t) (:check (format t "Checking if random number from 0 to ~a equals ~a~%" max-num match-num) (let ((rnd (random max-num))) (format t "Got number ~a~%" rnd) (cond ((eql rnd match-num) (format t "Match~%") t) (t (sleep 1))))) (:recover (format t "Running recovery mechanisms~%")) (:clean-up (format t "Running clean-up~%")))
The calling code for using the policy uses with-named-policy
to refer to the name as specified while defining the policy. The second parameter is a list of parameter values for customizing the policy instance. The rest of the code should be pretty self explanatory.
(top-level (with-named-policy 'my-policy (10 5) (loop do (format t "Main loop cycle.~%") (sleep 2))))
Exception handling
When policies are used, multiple failures can be signalled. The most meaningful of those are
policy-not-found
: Signalled when a named policy is used that was not defined before.policy-init-failed
: Signalled when initialization of a policy went wrong (i.e.:init
returnednil
).policy-check-condition-met
: The:check
condition of the policy returned a non-nil
value,:recover
was executed and thebody
code was interrupted before it could complete execution.
If one wants to monitor the triggering of a policy's :check
condition, this can be achieved like this:
(top-level (with-failure-handling ((policy-check-condition-met (f) (declare (ignore f)) (do-custom-handling-here) (retry))) ;; Or whatever seems appropriate in your use-case (with-named-policy 'my-policy (10 5) (loop do (format t "Main loop cycle.~%") (sleep 2)))))