Last Modified 23 March 2008

POSH Action Selection

POSH (Parallel-rooted, Ordered Slip-stack Hierarchical) dynamic plans are the structures used for action selection (also known as behavior arbitration or coordination) in Behavior Oriented Design (BOD). 

Dynamic planning (also known as reactive planning) is a way of doing action selection for a situated agent whereby a system chooses its next action by doing a quick look-up on an existing data structure.  What makes the system dynamic / reactive is that the decision about what to do next is based on the current state of the world, as perceived through the situated agent's sensors.  However, if an agent  responds only to its environment, it can wind up dithering between goals.  Thus a dynamic plan typically also uses some sort of internal state to keep track of the agent's current goals.  POSH plans record some of that state in the plan itself.  An active instance of a POSH plan which is in use by an agent is a dynamic data structure.  It remembers what subtask the agent was currently pursuing, although it also provides a way to encode when that subtask should be abandoned, or when a more important new goal or task should take over.

This page provides information on:

POSH Plan Components

There are five types of POSH plan components.  Two are primitives, and three are aggregates.

POSH Primitives

The primitives are:
Acts and senses both rely on code written in ordinary programming languages, which are provided through the behavior library in BOD.  Typically, they are methods on some behavior module's object.  Before a POSH plan can be executed, these primitives have to be loaded into the POSH planner using function calls (or macros) in the planners native language.  In the LISP version of posh, these calls are add-sense and add-act.  In the python version, the senses and actions are registered in the constructor of a behavior.

In the behaviour module code, there is no real difference between acts and senses.  In behavior-based AI, sensing and acting are always tightly coupled, so a sense may change an agent's state somewhat (e.g. it's memory), and an act will almost certainly require some perception (e.g. a grasp may complete when the inside of a hand feels pressure.)  The difference within the POSH context is that senses return a value which may be compared against some other value (you get to pick the predicate for the comparison as well.)  An act just either succeeds or fails.

POSH Aggregates

Primitives are the leaves of POSH hierarchical plans, they ground down in the code provided by the behavior libraries.  Combining them together into reactive plans requires the aggregates.  There are three types of aggregates in POSH:
To understand the details of these aggregates, you should probably read some of my papers on POSH and BOD.  I have put an HTML version of The Behavior Oriented Design of Modular Agent Intelligence online, here is the part about POSH aggregates.

POSH Plan File Structures

POSH script files have a  .lap extension (it stands for `learnable action patterns', a name I made up early in my PhD research (~1994).  Now I focus more on the design of these plans, though Mark Wood is working on learning them.)  Because the syntax was written to be easy to parse in Lisp,  if you want to edit them by hand you should use an editor that matches parentheses for you, like emacs.

We also now also have a special-purpose editor as part of ABODE, the BOD IDE.  It is useful for visualising some plans, but unfortunately (as of March2008) needs updating to work with current plan files...

There are currently two different lap file formats, one for POSH running a scheduled slip-stack and one for POSH with a strict slip-stack. Details about the two different versions of POSH are described in Sections 4.6.2 & 4.6.3 of my dissertation.

scheduled POSH

Here's the description of a lap file for the scheduled slip-stack, taken from the comments in the file posh-script.lisp, which parses these plans:

#|
Note: acts & senses are represented below just as names / tokens. A name may
be the name of any POSH type, including an act, sense, drive collection,
AP or competence.

name :: [a token]
sol-time :: (<time-unit> #)
time-unit:: minutes, seconds, hz(1/sec), pm(1/min), none(not real time)
should maybe add hours, days, microseconds?
goal :: (goal <ap>)
Competence :: (C <name> <sol-time> <goal> <other-elements>)
where time is for timeout, Ymir-like
Drive-collection :: (DC|RDC <name> <goal> <drive-elements>)
RDC for real-time systems
other-elements :: (elements (<comp-element>+)+)
inner paren is priority level
drive-elements :: (drives (<drive-element>+)+)
inner () is priority
comp-element :: (<name> (trigger <ap>) <name> [#])
2nd name is an action, followed by optional # of retries
drive-element :: (<name> (trigger <ap>) <name> [<sol-time>])
drive name, trigger, POSH root, [freq. for scheduling]
ap :: (<act|(sense [value [predicate]])>*)
default value is t, default predicate is eq
"act" can be an action primitive or a composite
Action-pattern :: (AP <name> <sol-time> <ap>)
where time is for timeout, Ymir-like
|#

Here are some old examples of scheduled POSH lap files.  See my publications page for full reference info on any mentioned papers.

NOTE:  These files were created before ABODE came into use, and use old commenting formats.  If you want a comment to stick in your file where you put it, you need to either:

SPOSH

The following elements have a different syntax when used with the strict slip-stack implementation (see the comments in lapparser.py for the full grammar):

#|
Note: as the strict slip-stack does not support time-outs, the <sol-time>
tokens are accepted but ignored if given.

act :: <name>
can be a primitive or a composite
sense-act :: <name>
a simple sense that might also perform an action.
Its return value is casted to a boolean
sense :: (nil) | (<name> [<value> [<predicate>])
if value is given, then return value of sense is
compared to value. Comparison mode is defined by
predicate, "==" is assumed if no predicate is given.
Sense (nil) always fails
ap :: ( <act | sense-act | sense>* )
value :: # | string | nil
predicate :: == | = | != | < | > | <= | >=
both '==' and '=' test for equality

goal :: nil | (GOAL <ap>)
goal 'nil' always fails
trigger :: nil | (TRIGGER <ap>)
trigger 'nil' always succeeds
time-unit :: HOURS | MINUTES | SECONDS | NONE
freq :: (<freq-unit> #)
freq-unit :: HOURS | MINUTES | SECONDS | HZ | PM | NONE
comment :: "any string"

Drive-collection :: (SDC|SRDC <name> [<goal>] <drive-elements>)
SRDC for real-time systems, goal always fails if
not given
drive-element :: (<name> [<trigger>] <name> [<freq>] [<comment>])
drive name, optional trigger (always triggers if not
given), POSH root, optional frequency, optional comment

Competence :: (C <name> [<sol-time>] [<goal>] <other-elements> [<comment>])
comp-element :: (<name> [<trigger>] <name> [#] [<comment>])
element name, optional trigger (always triggers if
not given), action/competence/action pattern,
optional # of retries, optinal comment

Action-pattern :: (AP <name> [<sol-time>] <ap> [<comment>])
last element of <ap> can also be a competence
|#

The main difference between POSH & SPOSH plans is that in scheduled POSH, the parent of an aggregate stays active for a little while, so may reclaim control when a child achieves its goal.  In SPOSH this is not true, so there is no redundant / back-up mechanism to check that a competence actualy terminates when it achieves its goal.  Generally, this makes no difference, but occassionally it is easier to express plans in POSH than SPOSH.  However, by its nature SPOSH runs faster and is simpler to understand.  By chance, SPOSH is also more recent code that is probably moderately cleaner & better supported, so we currently recommend using it if you are just starting with BOD.  Still, you can look at the files above under scheduled POSH & see almost correct lap files.  Here is one example of an SPOSH plan:

Downloads & Getting Started

The easiest way to get started is to download some of the existing projects and have a look at them.

POSH links


page author: Joanna Bryson, with Jan Drugowitsch