Automatically choosing a process module for an action

Description: in previous tutorials we called a process module explicitly via cram-process-modules:pm-execute, and fed them appropriate action designators. However, it is sometimes useful to reason about what process module to use to handle a given designator. To illustrate the CRAM infrastructure that allows this, we provide a very simple example here.

Previous Tutorial: Using location designators with the turtlesim

Setting up fact groups to select a process module

First let's create a new file selecting-process-modules.lisp and add it to our *.asd file, which should now look like this:

(defsystem cram-beginner-tutorial
  :depends-on (cram-language roslisp turtlesim-msg geometry_msgs-msg cl-transforms
                             cram-designators cram-prolog
                             actionlib actionlib_msgs-msg turtle_actionlib-msg
                             cram-process-modules cram-language-designator-support)
  :components
  ((:module "src"
            :components
            ((:file "package")
             (:file "control-turtlesim" :depends-on ("package"))
             (:file "simple-plans" :depends-on ("package" "control-turtlesim"))
             (:file "action-designators" :depends-on ("package"))
             (:file "turtle-action-client" :depends-on ("package"))
             (:file "location-designators" :depends-on ("package"))
             (:file "process-modules" :depends-on ("package"
                                                   "control-turtlesim"
                                                   "simple-plans"
                                                   "action-designators"
                                                   "turtle-action-client"))
             (:file "selecting-process-modules" :depends-on ("package"
                                                             "action-designators"
                                                             "location-designators"
                                                             "process-modules"))))))

We only need to add a couple of Prolog rules to implement automatic process module choosing, append this to selecting-process-modules.lisp:

(in-package :tut)
 
(def-fact-group navigation-process-modules (available-process-module
                                            matching-process-module)
  (<- (available-process-module actionlib-navigation))
  (<- (available-process-module simple-navigation))
 
  (<- (matching-process-module ?designator actionlib-navigation)
    (desig-prop ?designator (:type :shape)))
  (<- (matching-process-module ?designator simple-navigation)
    (desig-prop ?designator (:type :goal))))

The navigation-process-modules fact group extends the predicates cram-process-modules:matching-process-module and cram-process-modules:available-process-module.

The first two facts say that we have two process modules available for automatically matching them to designators (this is used for switching process modules for simulating and executing on the real robot in parallel), in our case no conditions need to be true for this fact to hold, our process modules are always available. matching-process-module predicates match designators with specific properties (in our case (:type :shape) or (:type :goal))) to corresponding process modules names. See previous tutorials to find how these action designators are resolved and how do their corresponding process modules use them.

For convenience, let's add one more function to selecting-process-modules.lisp:

(defun perform-some-action (action-desig)
  (let ((turtle-name "turtle1"))
    (start-ros-node turtle-name)
    (init-ros-turtle turtle-name)
    (top-level
      (with-turtle-process-modules
        (pm-execute-matching action-desig)))))

This function is mostly similar to previous ones we used to call process modules; the difference is that rather than calling pm-execute with a process module and an action designator, we call pm-execute-matching with a designator and allow the system to decide what process module to use. In our case the decision is very simple, just a matter of matching type to appropriate consumer; more complex inferences are possible for real systems.

Running action designators

Let's load our code in roslisp_repl. Make sure you have roscore, turtlesim, and the TurtleSim ActionLib shape_client running in terminals in the background (see a previous tutorial for the exact commands).

With that, let's first make a couple of designators for test, so type this in REPL's command line:

TUT> (defparameter center-location
       (make-designator :location '((:horizontal-position :center) (:vertical-position :center))))
CENTER-LOCATION
TUT> (defparameter goal-action
       (make-designator :action `((:type :goal) (:goal ,center-location))))
GOAL-ACTION
TUT> (defparameter shape-action
       (make-designator :action '((:type :shape) (:shape :triangle) (:radius 1.6))))
SHAPE-ACTION

With these designators defined, see what happens if you try to execute them. For example,

TUT> (perform-some-action goal-action)
WARNING:
   Before starting node, node-status equalled RUNNING instead of :shutdown.  Shutting the previous node invocation down now.
[(ROSLISP EVENT-LOOP) INFO] 1453760373.719: Terminating ROS Node event loop
[(ROSLISP TOP) INFO] 1453760374.142: Shutdown complete
[(ROSLISP TOP) INFO] 1453760374.149: Node name is /turtle1
[(ROSLISP TOP) INFO] 1453760374.149: Namespace is /
[(ROSLISP TOP) INFO] 1453760374.150: Params are NIL
[(ROSLISP TOP) INFO] 1453760374.150: Remappings are:
[(ROSLISP TOP) INFO] 1453760374.150: master URI is 127.0.0.1:11311
[(ROSLISP TOP) INFO] 1453760375.155: Node startup complete
[(TURTLE-PROCESS-MODULES) INFO] 1453760375.181: Turtle simple navigation invoked with action designator `#<ACTION-DESIGNATOR ((TYPE
                                                                               GOAL)
                                                                              (GOAL
                                                                               #<LOCATION-DESIGNATOR
                                                                                 ((HORIZONTAL-POSITION
                                                                                   CENTER)
                                                                                  (VERTICAL-POSITION
                                                                                   CENTER))
                                                                                 {100A70EDE3}>)) {100B05B333}>'.
[(TURTLE-PROCESS-MODULES) INFO] 1453760375.184: Going to point #<3D-VECTOR (4.381962776184082d0 4.012950897216797d0 0.0d0)>.
T

The turtle should have moved somewhere to the center of its screen.

Let's see if it will draw the triangle shape:

TUT> (perform-some-action shape-action)
WARNING:
   Before starting node, node-status equalled RUNNING instead of :shutdown.  Shutting the previous node invocation down now.
[(ROSLISP EVENT-LOOP) INFO] 1453760384.426: Terminating ROS Node event loop
[(ROSLISP TOP) INFO] 1453760384.903: Shutdown complete
[(ROSLISP TOP) INFO] 1453760384.906: Node name is /turtle1
[(ROSLISP TOP) INFO] 1453760384.907: Namespace is /
[(ROSLISP TOP) INFO] 1453760384.907: Params are NIL
[(ROSLISP TOP) INFO] 1453760384.907: Remappings are:
[(ROSLISP TOP) INFO] 1453760384.907: master URI is 127.0.0.1:11311
[(ROSLISP TOP) INFO] 1453760385.913: Node startup complete
[(TURTLE-PROCESS-MODULES) INFO] 1453760385.930: Turtle shape navigation invoked with action designator `#<ACTION-DESIGNATOR ((TYPE
                                                                              SHAPE)
                                                                             (SHAPE
                                                                              TRIANGLE)
                                                                             (RADIUS
                                                                              1.6)) {100BA6F7A3}>'.
[(TURTLE-SHAPE-ACTION-CLIENT) INFO] 1453760385.968: Waiting for turtle shape action server...
[(TURTLE-SHAPE-ACTION-CLIENT) INFO] 1453760387.968: Turtle shape action client created.
[(TURTLE-SHAPE-ACTION-CLIENT) INFO] 1453760399.919: Nav action finished.
[TURTLE_ACTIONLIB-MSG:SHAPERESULT
   INTERIOR_ANGLE:
     1.0471975803375244d0
   APOTHEM:
     0.800000011920929d0]