This is an old revision of the document!


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

We'll need to update a few dependencies first. To your *.asd file, add cram-plan-library to your :depends-on list. You also need to add a :file (which we'll call “selecting-process-modules” in the :components list that depends on all previous tutorial files. Your *.asd file should look like this:

(defsystem cram-beginner-tutorial
  :depends-on (roslisp cram-language turtlesim-msg cl-transforms geometry_msgs-msg designators cram-reasoning 
                 cram-language-designator-support actionlib actionlib_tutorials-msg process-modules turtle_actionlib-msg cl-tf cram-plan-library)
  :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" "location-designators"))
             (:file "selecting-process-modules" :depends-on  ("package" "control-turtlesim" "simple-plans" "action-designators" "turtle-action-client" "location-designators" "process-modules"))))))

We'll need to define a couple new designator properties (navigation and goal) in package.lisp so it should now look like this:

(in-package :cl-user)
 
(desig-props:def-desig-package cram-beginner-tutorial
  (:nicknames :tut)
  (:use #:cpl
        #:roslisp
        #:cl-transforms
        #:cram-designators)
 
  (:desig-properties
   ;; action properties
   #:shape
   #:navigation
   #:goal
   #:radius
   #:triangle
   #:square
   #:pentagon
   #:hexagon
   ;; location Properties
   #:vpos
   #:hpos
   #:left
   #:right
   #:top
   #:bottom
   #:center))

Prerequisites done, let's now create a selecting-process-modules.lisp file in the src folder of your tutorial, and let's first add this bit of code to it:

(in-package :tut)
 
(cram-reasoning:def-fact-group navigation-action-designator (action-desig)
  (cram-reasoning:<- (action-desig ?designator (navigation ?goal))
  (desig-prop ?designator (type navigation))
  (desig-prop ?designator (goal ?goal))))

What this snippet of code does is create a fact group that will be used to resolve action designators. In particular, if the designator contains a (type navigation) pair, and a (goal <an object, assumed to be a location designator by other code in this tutorial>), then the resolution procedure extracts the designator type (navigation in this case) and the object associated to the goal, and puts them both in a list which it returns.

Let's create a process module that can consume designators of type navigation, and append it to selecting-process-modules.lisp:

(cram-process-modules:def-process-module turtle-navigation-handler (action-designator)
  (roslisp:ros-info (turtle-process-modules)
                    "Turtle navigation invoked with action designator `~a'."
                    action-designator)
  (destructuring-bind (cmd action-goal) (reference action-designator)
    (ecase cmd
        (navigation
          (print (cl-transforms:origin (reference action-goal)))
          (move-to (cl-transforms:origin (reference action-goal)))))))

What this process module does is resolve the action designator it receives as a parameter, and if the designator is of type navigation, resolves the goal as a location designator, then moves the turtle to the resolved location.

Now comes the part where we instruct the system how to reason about process modules, and we need to append the following to selecting-process-modules.lisp:

(cram-reasoning:def-fact-group turtle-navigation (cram-process-modules:matching-process-module
                                   cram-process-modules:available-process-module)
  (cram-reasoning:<- (cram-process-modules:matching-process-module ?designator turtle-navigation-handler)
    (desig-prop ?designator (type navigation)))
  (cram-reasoning:<- (cram-process-modules:available-process-module turtle-navigation-handler)))
 
(cram-reasoning:def-fact-group turtle-actuators (cram-process-modules:matching-process-module
                                  cram-process-modules:available-process-module)
  (cram-reasoning:<- (cram-process-modules:matching-process-module ?designator turtle-actuators)
    (desig-prop ?designator (type shape)))
  (cram-reasoning:<- (cram-process-modules:available-process-module turtle-actuators)))

These fact groups extend the predicates cpm:matching-process-module and cpm:available-process-module. Both must be extended, which simply means defining what their values are if applied to the designators defined in this tutorial. For example, the first fact group says that, if a designator has a (type navigation) pair, then the matching-process-module is the turtle-navigation-handler we defined previously. As for turtle-actuators, it is a process module we defined in a previous tutorial; the kinds of designators it consumes also had their resolution mechanism defined previously.

Notice that in this tutorial, available-process-module always gets our process modules. No conditions need to be true, our process modules are simply available.

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

(defun do-action-designator (action-desig)
  (let ((turtle-name "turtle1"))
    (start-ros-node turtle-name)
    (init-ros-turtle turtle-name)
    (top-level
      (cpm:with-process-modules-running (turtle-navigation-handler turtle-actuators)
        (cram-plan-library:perform action-desig)))))

This function is mostly similar to previous ones we used to call process modules; the difference is that rather than calling cpm:pm-execute with a process module and a designator, we call cram-plan-library:perform with an (action) 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 turtle actionlib shape_client running in terminals in the background.

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

CL-USER> (in-package :tut)
TUT> (defparameter shape-action (make-designator 'action `((type shape) (shape triangle) (radius 1.6))))
SHAPE-ACTION
TUT> (defparameter navigation-action (make-designator 'action `((type navigation) (goal ,(make-designator 'location `((vpos center) (hpos center)))))))
NAVIGATION-ACTION

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

TUT> (do-action-designator shape-action)
WARNING:
   Before starting node, node-status equalled RUNNING instead of :shutdown.  Shutting the previous node invocation down now.
[(ROSLISP EVENT-LOOP) INFO] 1415203378.618: Terminating ROS Node event loop
[(ROSLISP TOP) INFO] 1415203379.040: Shutdown complete
[(ROSLISP TOP) INFO] 1415203379.042: Node name is /turtle1
[(ROSLISP TOP) INFO] 1415203379.042: Namespace is /
[(ROSLISP TOP) INFO] 1415203379.042: Params are NIL
[(ROSLISP TOP) INFO] 1415203379.042: Remappings are:
[(ROSLISP TOP) INFO] 1415203379.042: master URI is 127.0.0.1:11311
[(ROSLISP TOP) INFO] 1415203380.047: Node startup complete
[(TURTLE-PROCESS-MODULES) INFO] 1415203380.190: Turtle navigation invoked with action designator `#<ACTION-DESIGNATOR ((TYPE
                                                                        SHAPE)
                                                                       (SHAPE
                                                                        TRIANGLE)
                                                                       (RADIUS
                                                                        1.6)) {1005C58BE3}>'.
[(TURTLE-SHAPE-ACTION-CLIENT) INFO] 1415203380.231: Waiting for turtle shape action server...
[(TURTLE-SHAPE-ACTION-CLIENT) INFO] 1415203382.278: Turtle shape action client created.
[(TURTLE-SHAPE-ACTION-CLIENT) INFO] 1415203394.276: Nav action finished.
[TURTLE_ACTIONLIB-MSG:SHAPERESULT
   INTERIOR_ANGLE:
     1.0471975803375244d0
   APOTHEM:
     0.800000011920929d0]

The turtle should also have moved and traced the requested triangle. We can also try and bring it somewhere near the center of its screen:

TUT> (do-action-designator navigation-action)
WARNING:
   Before starting node, node-status equalled RUNNING instead of :shutdown.  Shutting the previous node invocation down now.
[(ROSLISP EVENT-LOOP) INFO] 1415203565.890: Terminating ROS Node event loop
[(ROSLISP TOP) INFO] 1415203566.382: Shutdown complete
[(ROSLISP TOP) INFO] 1415203566.385: Node name is /turtle1
[(ROSLISP TOP) INFO] 1415203566.385: Namespace is /
[(ROSLISP TOP) INFO] 1415203566.385: Params are NIL
[(ROSLISP TOP) INFO] 1415203566.385: Remappings are:
[(ROSLISP TOP) INFO] 1415203566.386: master URI is 127.0.0.1:11311
[(ROSLISP TOP) INFO] 1415203567.392: Node startup complete
[(TURTLE-PROCESS-MODULES) INFO] 1415203567.525: Turtle navigation invoked with action designator `#<ACTION-DESIGNATOR ((TYPE
                                                                        NAVIGATION)
                                                                       (GOAL
                                                                        #<LOCATION-DESIGNATOR
                                                                          ((VPOS
                                                                            CENTER)
                                                                           (HPOS
                                                                            CENTER))
                                                                          {10074B8163}>)) {10074B8533}>'.
 
#<CL-TRANSFORMS:3D-VECTOR (5.806711673736572d0 5.260904312133789d0 0.0d0)> 
T

You should also see the turtle move to a central location.