Scripting engine for Player Server. More...

Scripting engine for Player Server.

Scripting engine for Player Server. Note that full description of this driver would be a book size (and maybe one day such a book will be written). Experienced Player user who is also familiar with C++ and Scheme programming languages (being familiar with quasiquote and unquote helps significantly) can figure out how this scripting engine can be used just from examining provided examples and this driver source code. Due to the nature of libguile (embedded Scheme interpreter), this driver is not threaded and is completely message-driven. It is good idea to keep it in separate Player instance. On each message arrival a function defined as follows will be executed:

(define fname (lambda (link hdr data env) (your-code) ))

Such a function can be considered as a think-act part of sense-think-act loop. Using 'scriptfile' or 'script' configuration file option, function body can be provided.

The 'env' parameter is the value returned by previous call of such a function. At first call, 'env' parameter is the value returned by initialization code (see 'globals' configuration file option). If there's no initialization code, the initial value for env is an empty list.

Since this is not threaded driver, requests should be handled carefully. In most cases it is sufficient just to forward them. Following code will send ACK to request sender (here called 'input') and forward request message to another receiver (here called 'output'):

(cond ((player-match-message hdr player-msgtype-req -1 input) (player-publish-ack link input (player-hdr-subtype hdr)) (player-putmsg-timestamped link output player-msgtype-req (player-hdr-subtype hdr) data (player-hdr-timestamp hdr) ) ) )

This approach is not the best one since the reply sent back by final request receiver is not forwarded to original sender (which always gets ACK). However, this example shows how requests can be handled anyway. Another approach is to use player-forwardreq function:

(cond ((player-match-message hdr player-msgtype-req -1 input) (player-forwardreq link output hdr data) ) )

Compile-time dependencies
Provides
Requires
Configuration requests
Configuration file options
Example
driver
(
  name "guile"
  keys ["in" "out" "ranges"]
  requires ["out::6665:position2d:0" "ranges::6665:ranger:0"]
  provides ["in:::position2d:10"]
  globals ["(define start-env '())" "start-env"]
  scriptfile ""
  script ["(display '(alive))" "(newline)" "env"]
  alwayson 1
)

Some bigger example (a drunk robot - 'velcmd' driver tells to go straight ahead at speed 0.4m/s, 'guile' driver makes it to turn left/right randomly; see how random number generator is initialized in 'globals'):

driver
(
  name "velcmd"
  provides ["opaque:0"]
  requires ["position2d:0"]
  px 0.4
  py 0.0
  pa 0.0
  alwayson 1
)

driver
(
  name "guile"
  fname "some"
  keys ["input" "output" "sensor"]
  provides ["input:::position2d:0"]
  requires ["output:127.0.0.1:6672:position2d:0" "sensor:127.0.0.1:6672:bumper:0"]
  globals [
    "(define get-time (lambda () (round (/ (get-internal-real-time) internal-time-units-per-second))))"
    "(let ((time (gettimeofday))) (set! *random-state* (seed->random-state (+ (car time) (cdr time)))))"
    "`(,(get-time) 0.0 0.0 0.0 1.0)"
  ]
  script [
    "(let*"
    "  ("
    "    (warn (cond"
    "               ((player-match-message hdr player-msgtype-data 1 sensor) (not (zero? (apply + (player-read-datapack-elems 'player_bumper_data 'bumpers data 0 (player-read-datapack 'player_bumper_data 'bumpers_count data))))))"
    "               ((player-match-message hdr player-msgtype-data 1 output) (not (zero? (player-read-datapack 'player_position2d_data 'stall data))))"
    "               (else #f)"
    "    ))"
    "    (new-px (cond"
    "                 ((player-match-message hdr player-msgtype-cmd 1 input) (player-read-datapack 'player_pose2d 'px (player-read-datapack 'player_position2d_cmd_vel 'vel data)))"
    "                 (else (cadr env))"
    "    ))"
    "    (timedout (> (abs (- (get-time) (car env))) 0))"
    "    (change (or warn timedout))"
    "    (direction (cond ((and warn timedout) (* -1.0 (car (cddddr env)))) (else (car (cddddr env)))))"
    "    (new-time (cond (change (get-time)) (else (car env))))"
    "    (px (cond (change new-px) (else (caddr env))))"
    "    (pa (cond (change (- (random:uniform) 0.5)) (else (cadddr env))))"
    "  )"
    "  (cond"
    "       ((player-match-message hdr player-msgtype-req -1 input) (player-forwardreq link output hdr data))"
    "       (else"
    "            (player-putmsg link output player-msgtype-cmd 1"
    "              (player-create-datapack link 'player_position2d_cmd_vel"
    "                `((vel . ,(player-create-datapack link 'player_pose2d `((px . ,(* px direction)) (py . 0.0) (pa . ,pa))))"
    "                  (state . ,player-enable)"
    "                 )"
    "              )"
    "            )"
    "       )"
    "  )"
    "  `(,new-time ,new-px ,px ,pa ,direction)"
    ")"
  ]
)

More sophisticated example of drunk robot controller - this time a robot does not like non-black blobs (from blobfinder device) - it tries to go back until those blobs couldn't be detected (it may cause a robot to hit the wall and block). This is important example as it shows how to deal with data array with no size explicitely defined that holds compound data (blob data), see how map function is used:

driver
(
  name "velcmd"
  provides ["opaque:0"]
  requires ["position2d:0"]
  px 0.4
  py 0.0
  pa 0.0
  alwayson 1
)

driver
(
  name "guile"
  fname "some"
  keys ["input" "output" "sensor" "blobs"]
  provides ["input:::position2d:0"]
  requires ["output:127.0.0.1:6665:position2d:0" "sensor:127.0.0.1:6665:bumper:0" "blobs:127.0.0.1:6665:blobfinder:0"]
  globals [
    "(define get-time (lambda () (round (/ (get-internal-real-time) internal-time-units-per-second))))"
    "(let ((time (gettimeofday))) (set! *random-state* (seed->random-state (+ (car time) (cdr time)))))"
    "`(,(get-time) 0.0 0.0 0.0 1.0)"
  ]
  script [
    "(let*"
    "  ("
    "    (warn (cond"
    "               ((player-match-message hdr player-msgtype-data 1 sensor) (not (zero? (apply + (player-read-datapack-elems 'player_bumper_data 'bumpers data 0 (player-read-datapack 'player_bumper_data 'bumpers_count data))))))"
    "               ((player-match-message hdr player-msgtype-data 1 output) (not (zero? (player-read-datapack 'player_position2d_data 'stall data))))"
    "               (else #f)"
    "    ))"
    "    (new-px (cond"
    "                 ((player-match-message hdr player-msgtype-cmd 1 input) (player-read-datapack 'player_pose2d 'px (player-read-datapack 'player_position2d_cmd_vel 'vel data)))"
    "                 (else (cadr env))"
    "    ))"
    "    (timedout (> (abs (- (get-time) (car env))) 0))"
    "    (change (or warn timedout))"
    "    (blob-colors (lambda (blob) (player-read-datapack 'player_blobfinder_blob 'color blob)))"
    "    (alien-blobs (cond"
    "                      ((player-match-message hdr player-msgtype-data 1 blobs)"
    "                        (not (zero? (apply + (map blob-colors (player-read-datapack-elems 'player_blobfinder_data 'blobs data 0 (player-read-datapack 'player_blobfinder_data 'blobs_count data))))))"
    "                      )"
    "                      (else #f)"
    "    ))"
    "    (direction (cond"
    "                    (alien-blobs -1.0)"
    "                    (else (cond ((and warn timedout) (* -1.0 (car (cddddr env)))) (else (car (cddddr env)))))"
    "    ))"
    "    (new-time (cond (change (get-time)) (else (car env))))"
    "    (px (cond (change new-px) (else (caddr env))))"
    "    (pa (cond (change (- (random:uniform) 0.5)) (else (cadddr env))))"
    "  )"
    "  (cond"
    "       ((player-match-message hdr player-msgtype-req -1 input) (player-forwardreq link output hdr data))"
    "       (else"
    "            (player-putmsg link output player-msgtype-cmd 1"
    "              (player-create-datapack link 'player_position2d_cmd_vel"
    "                `((vel . ,(player-create-datapack link 'player_pose2d `((px . ,(* px direction)) (py . 0.0) (pa . ,pa))))"
    "                  (state . ,player-enable)"
    "                 )"
    "              )"
    "            )"
    "       )"
    "  )"
    "  `(,new-time ,new-px ,px ,pa ,direction)"
    ")"
  ]
)
Author
Paul Osmialowski