Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
tutorials:advanced:events [2015/05/11 19:23] gkazhoyatutorials:advanced:events [2018/04/04 09:20] (current) gkazhoya
Line 1: Line 1:
 ====== Events in CRAM ====== ====== Events in CRAM ======
  
-This is a short tutorial to showcase how to trigger and handle custom-defined events. +This page migrated [[tutorials:intermediate:events|here]].
-CRAM has an event protocol that makes the above-mentioned very simple. +
- +
-Code-wise, the event callback mechanism is based on the notion of hooks of the [[doc/package/cram_utilities|cram_utitlities]] package from the CRAM core. +
-The protocol itself is defined in the ''cram_plan_knowledge'' ROS package. That is also the package where new types of events and their handlers should be defined. +
- +
-In the nutshell, the protocol is pretty trivialthere is a generic function called ''cram-plan-knowledge:on-event'' which is supposed to be overloaded with new handlers and called to emit new events+
- +
-So, let's first load the plan knowledge system and switch to its corresponding Lisp package: +
- +
-<code lisp> +
-CL-USER> (asdf:load-system :cram-plan-knowledge) ; or ,r-l-s RET cram_plan_knowledge RET RET +
-CL-USER> (in-package :cram-plan-knowledge) +
-</code> +
- +
-Next, we define a custom event class that inherits from ''cram-plan-knowledge:event'' and has one data slot: +
- +
-<code lisp> +
-PLAN-KNOWLEDGE> (defclass cat-appeared-event (event) +
-                  ((color-of-cat +
-                    :initarg :cat-color :reader cat-color +
-                    :initform (error +
-                               'simple-error +
-                               :format-control "CAT-APPEARED-EVENT requires CAT-COLOR")))) +
-#<STANDARD-CLASS CAT-APPEARED-EVENT> +
- +
-PLAN-KNOWLEDGE> (describe 'cat-appeared-event) +
-CRAM-PLAN-KNOWLEDGE::CAT-APPEARED-EVENT +
-  [symbol] +
-CAT-APPEARED-EVENT names the standard-class #<STANDARD-CLASS +
-                                              CAT-APPEARED-EVENT>: +
-  Direct superclasses: EVENT +
-  No subclasses. +
-  Not yet finalized. +
-  Direct slots: +
-    COLOR-OF-CAT +
-      Initargs: :CAT-COLOR +
-      Initform: (ERROR 'SIMPLE-ERROR :FORMAT-CONTROL +
-                       "CAT-APPEARED-EVENT requires CAT-COLOR"+
-      Readers: CAT-COLOR +
-</code> +
- +
-Now that we have our custom event type we define an event handler for it: +
- +
-<code lisp> +
-PLAN-KNOWLEDGE> (defmethod on-event ((event cat-appeared-event)) +
-                  (format t "OMG! I just saw a ~a cat!~%" (cat-color event))) +
-</code> +
- +
-To trigger the event we simply call the ''cram-plan-knowledge:on-event'' method: +
- +
-<code lisp> +
-PLAN-KNOWLEDGE> (on-event (make-instance 'cat-appeared-event :cat-color "black")) +
-OMG! I just saw a black cat! +
-(NIL) +
-</code> +
- +
-Now, imagine that we would like to have multiple handlers for the same event. +
-E.g., in addition to screaming excitedly each time we see a cat, we would also like to count the number of cats seen so far: +
- +
-<code lisp> +
-PLAN-KNOWLEDGE> (let ((saw-cats 0)) +
-                  (defmethod on-event cat-counter ((event cat-appeared-event)) +
-                    (incf saw-cats) +
-                    (format t "number of cats seen so far: ~a~%" saw-cats) +
-                    saw-cats)) +
-#<STANDARD-METHOD ON-EVENT CAT-COUNTER (CAT-APPEARED-EVENT) {100F5D3C43}> +
- +
-PLAN-KNOWLEDGE> (on-event (make-instance 'cat-appeared-event :cat-color "black")) +
-number of cats seen so far: 1 +
-OMG! I just saw a black cat! +
-(1 NIL) +
- +
-PLAN-KNOWLEDGE> (on-event (make-instance 'cat-appeared-event :cat-color "black")) +
-number of cats seen so far: 2 +
-OMG! I just saw a black cat! +
-(2 NIL) +
-</code> +
- +
-Let's break this down. +
- +
-  * We define a lexical variable ''saw-cats'' which will be our counter (if ''saw-cats'' confuses you read up on [[http://www.gigamonkeys.com/book/variables.html#lexical-variables-and-closures|closures]]). +
-  * Then we overload our ''on-event'' method while specifying ''cram-plan-knowledge::cat-counter'' as a method combination qualifier. The default method combination of generic function ''on-event'' is ''cram-utilities:hooks'' which simply combines the results of all the suitable methods into a list. That is clearly illustrated in the result of the last ''on-event'' call in the code snippet above: ''(2 NIL)'', where ''2'' is the result of the method qualified with ''cat-counter'' and ''NIL'' results from the ''format'' statement of the other method. Combining the results of all the suitable methods means that the qualifier itself (in our case ''cat-counter'') is of no importance. So, as long as we can come up with new qualifiers we can have new handlers for a particular event (if this paragraph is hard to understand look into the definition of ''cram-utilities:define-hook'' and read up more on [[http://www.lispworks.com/documentation/HyperSpec/Body/m_defi_4.htm|method combinations]]).+