Operational Model Planning and Acting System (OMPAS)
OMPAS is a complete supervision solution for robotic platforms developed in the context of the thesis "Planning from operational model for deliberative acting in robotics". This thesis is led by Jérémy Turi under the supervision of Arthur Bit-Monnot and Daniel Sidobre at LAAS-CNRS in the RIS team. This official documentation is updated as the project goes, but some shift may appear with the actual implementation.
The system OMPAS is based on the Refinement Acting Engine, that it extends with a native support for tasks concurrency, with a dedicated resource management system. The system uses a Scheme-like language to describe the behavior of a robotic agent as hierarchical operational models.
Several articles have been accepted in conferences and workshops. Here are the references of the paper:
- Extending a Refinement Acting Engine for Fleet Management: Concurrency and Resources(@@turiExtendingRefinementActing2022)
- Guidance of a Refinement-based Acting Engine with a Hierarchical Temporal Planner (@@turiGuidanceRefinementbasedActing2022)
How to run the system
The system can be used in different manners. The project provides an API to define custom binaries linked to specific robotic platforms described in [link to how to create binaries]. The actual project provides a simple binary to use OMPAS in simulation, by loading a domain with the description of the commands model. In simulation, OMPAS executes a command by executing the corresponding Scheme model. The project also provide an integration with Gobot-Sim a benchmark for acting and planning system, providing job shop scheduling problems.
OMPAS in simulation
# if needed go in the root folder of the project
cd rae
cargo run --bin ompas -- -d <path-to-domain> -p <path-to-problem>
OMPAS and Gobot-sim
# if needed go in the root folder of the project
cd gobot-sim
cargo run
Basic commands in OMPAS
Running one of those binary will automatically launch a REPL. Here is a list of basic commands that you can use to interact with the system. The complete list is available here :
(launch)
launches RAE with and starts the platform.(get-state)
returns a map with all the state of RAE, perceived and internal.(trigger-task task p1 ... pn)
triggers a task with the parameters (p1...pn)(get-env <element>)
returns the domain, or a specific element.
Acting System
The acting system is defined as OMPAS with an integration with any robotic platform. Most binaries provide a REPL, so a human operator can interact with the system, to monitor reports (state update, task status) and trigger tasks.
Interacting with the REPL
REPL stands for Read Evaluate Print Loop, which means raw expressions are sent to an interpreter which it will execute in real-time without prior compilation. Such systems are born with Lisp, and the most common language using this feature is Python. The present system proposes a number of primitives to interact with the system.
Monitor
Principal functions
-
(launch)
launches RAE. It will also launch the platform if defined. -
(stop)
stops RAE. -
(configure-platform e1...en)
A number of parameters passed to the platform when launched. -
(set-select <select-mode>)
configure the algorithm that will be used to select a method during the refinement process. The available select-mode are greedy, planning, aries, aries-opt, rae-plan, c-choice, upom (not yet implemented). -
(trigger-task <label> <params>)
trigger a task with instantiated parameters. Launch before triggering tasks. -
(add-task-to-execute <label> <params)
define a task to execute before the launch of RAE. The task will be passed to RAE once the acting system is launched.
Monitoring
(get-state)
returns the whole state of RAE. Contains only initial facts if RAE is not launched yet.(get-resources)
returns the list of resources with some useful information, as the number of waiter for each resource.(get-monitors)
returns the list of dynamic expressions actually monitored.(get-env)
returns the environment of RAE.(get-methods)
returns the list of methods defined.(get-state-functions)
returns the list of state-function.(get-tasks)
returns the list of tasks.(get-config-platform)
returns the config of the platform.(get-select)
returns the select mode used by RAE.(get-agenda <type> <status>)
returns the status of all tasks and commands executed in RAE. The list can be sorted by type (task, command) or/and status (pending, running, done, failure).(get-task-network)
returns the network of tasks and commands.(get-type-hierarchy)
returns the type hierarchy.(get-stats)
returns a bunch of statistics on the current RAE run.(export-stats <csv-file>)
exports the stats in a csv file.
Operational model extraction
Those functions are used to test and debug the extraction of planning models in the form of chronicles from the automated analysis of the method operational models and the command models. The planner used is Aries @@godetChroniclesRepresentingHierarchical2022, the project is available here : https://github.com/plaans/aries
(convert-expr e)
converts the expression e into a chronicle and prints it.(convert-domain)
converts the domain and prints it.(plan-task t p1...pn)
converts the domain and calls the planner aries
Domain definition
Commands
Commands are defined with the macro def-command
that takes a symbol, and a list of typed parameters.
(def-command pick (:params (?obj ball) (?room room) (?gripper gripper)))
A model can be provided and defined with the macro def-command-pddl-model
. Here is an example for the command pick. The pre-conditions takes a list of dynamic expressions (expressions which result will depend on the current values of state-variables).
(def-command-pddl-model pick
(:params (?obj ball) (?room room) (?gripper gripper))
(:pre-conditions
(= (at ?obj) ?room)
(= (at-robby) ?room)
(= (carry ?gripper) no_ball))
(:effects
('carry ?gripper) ?obj)
('at ?obj no_place)))
Tasks
A task is defined with the macro def-task
that takes a label, and a list of typed parameters.
(def-task pick-and-drop (:params (?ball ball) (?room room)))
Methods
A method is defined with the macro def-method
that takes a label, the task it refines, a list of typed parameters, the first ones inherited from the task, a score to sort the method for the basic select of RAE, and the body that is the program executed by the platform is the method is selected.
(def-method m1
(:task pick-and-drop)
(:params (?ball ball) (?room room) (?gripper gripper) (?departure room))
(:pre-conditions
(= (at ?ball) (at-robby))
(= (carry ?gripper) no_ball)
(= ?departure (at-robby)))
(:score 0)
(:body
(do
(pick ?ball ?departure ?gripper)
(move ?departure ?room)
(drop ?ball ?room ?gripper))))
State-function
A state function returns the value of state-variable at a given time.
We define a state function with the macro def-state-function
that takes a label, a list of typed parameters, and a result type.
(def-state-function at (:params (?b ball)) (:result room))
Lambdas
Lambdas can be defined in the evaluation environment of RAE, which is different from the environment of the REPL. A lambda is defined with the macro def-lambda
that takes the label of the lambda, and a lambda.
(def-lambda go_random
(lambda (?r ?l ?u)
(let ((x (rand-int-in-range ?l ?u))
(y (rand-int-in-range ?l ?u)))
(navigate_to ?r x y))))
Types
The system supports the definition of new types, with a hierarchy of types. A type is defined with the macro def-types
that takes a list of types.
;adding new root types
(def-types room gripper ball)
;adding a new subtype to ball
(def-types (football ball))
Objects
Typed objects can be defined in the fact base of the system, in particular when using the system in simulation.
We use the macro def-objects
that takes lists of objects with their type defined as the last element of the list.
(def-objects
(bedroom kitchen living_room room)
(b1 b2 b3 b4 ball))
Initial-state
To define an initial-state for some scenarios (for example to use RAE in simulation), we use the macro def-initial-state
that takes a list of pair <key,value>.
(def-initial-state
(at-robby living_room)
((at b1) bedroom)
((at b2) bedroom)
((at b3) bedroom)
((at b4) bedroom)
((carry left) no_ball)
((carry right) no_ball))
Configuring OMPAS
OMPAS can take several options.
-v, --view
: view the platform interface.-l, --log-path
: path to the directory of the log. The logs of the REPL and RAE will be stored in different files. RAE logs will contain logged message with useful information on the internal functioning of a RAE run.-p, --problem
: path to the problem file.-d, --domain
: path to the domain file.-r, --rae-log
: displays the RAE log in a dedicated window.
Acting Language
The system OMPAS uses a custom acting Language. It is a Lisp dialect and in particular a Scheme variant, with a limited set of primitives. On top of the basic Scheme, primitives for concurrency have been added, and interruptions are supported in the core language. From this reimplementation of Scheme, we propose an acting language that supports information gathering, reasoning on facts, execution and monitoring of commands as well as a specific resource management system.
Scheme
Scheme is derived from the functional language Lisp. Peter Norvig made a tutorial to implement a basic version in Python available at https://norvig.com/lispy.html and https://norvig.com/lispy2.html. The Rust implementation is inspired by Lis.py and Lispy.py (the second version integrates advanced features) but differs on several aspects.
Introduction to Scheme.
Scheme is a Lisp dialect that is based on the recursive evaluation of expressions that we call LValue. An LValue is either an Atom (symbol, boolean, number, function) or a list of expressions. A particularity of the language is that the boolean false is represented by the LValue Nil that represents also the empty list. An expression is evaluated in an environment, in which some symbols can be bound to LValues. Each expression is a new scope, which means that a new binding only lives in the scope it has been defined in, which makes the language way more simple.
Core language
The core of the Scheme implementation has been both simplified, and extended for concurrency. The core language is composed of the following functions:
begin
evaluates a list of expressions and returns the result of the last expression.define
defines in the current scope a new binding for a symbol.if
takes as argument an evaluation that returns a boolean b. In function of the value of b, either the second expression of the third will be executed. The result of the if expression is the result of the evaluated expression.lambda
creates a closure. A closure is defined by parameters and a body. The valid kind of parameters for a lambda are nil for no parameters, a simple symbol for an arbitrary number of parameters or a list of symbol for a defined number of parameters.quote
or'
avoids the evaluation of an expression and returns the raw expression as result.quasiquote
(or `) andunquote
(or,
) are used to partially evaluate an expression. Those functions can be viewed as macros for the formatting of expressions using quote and cons.eval
evaluates an expression.parse
takes as input a string and returns the parsed and expanded expression.expand
expanses an expression.enr
evaluates an expression without evaluating the sub expressions.
>> (eval (cons zip (list (list 2 3) (list 4 5))))
LI>> error: In eval, 2: Got int, expected fn
>> (enr (cons zip (list (list 2 3) (list 4 5))))
LI>> ((2 4) (3 5))
Errors
A specific Err LValue as been added in the current implementation for special cases were an err as result would escape the evaluation of an expression.
do
similar to begin, but stops at the first err returned. The result of the expression is err.check
takes as argument a boolean. It returns true if the boolean is true, an err otherwise
From those two functions, some interesting constructs can be programmed for code that should not return errors.
Concurrency and interruption
To handle concurrency, we implemented an extension to Scheme inspired by asynchronous code from C++ and rust, using schedulers and futures. In addition, we define a new LValue named handle that represents an asynchronous evaluation. A handle can be manipulated with the following functions:
async
takes as argument an expression, starts the evaluation in a new asynchronous process and returns a handle.await
takes as parameter a handle and returns the result of the expression evaluated in the asynchronous process.interrupt
takes as argument a handle, and sends an interruption signal to the asynchronous evaluation. The interruption signal is propagated recursively to all sub-expressions.
In addition to those primitives, it is possible to define the interruptibility of an expression, by avoiding the interruption of some expressions with the keyword uninterruptible. Here is an example of such code:
(begin
(define h
(async
(begin
(uninterruptible (begin
(exec pick ?r ?o)
(exec move ?r ?l)
(exec drop ?r ?o)))
(exec inspect ?r ?o))))
(race
(await h)
(begin
(sleep 10)
(interrupt h))))
Standard library
Functions to get informations on the environment
help
returns the list of functions defined in the environment along their documentation. An extended documentation can be given by giving as parameter a specific function tohelp
.
>> (help)
LI>> ¤ * : Takes 2+ arguments. Ret...
¤ + : Takes 2+ arguments. Return t...
¤ - : Takes 2 arguments. Return th...
>> (help write)
LI>> Write a LValue to a file
Takes two arguments: the name of the file and the LValue
Note: The path of the file is relative to the path of the executable
get_keys
returns the list of all elements defined in the environment.get_macros
returns the list of macros.get_macro
returns the expression of a given macro.get_contexts
returns the list of all contexts defined in the environment.
Get and set functions
get
returns an element either from a list or a map. You can also use directlyget-list
andget-map
.
>> (get (list 1 2 3) 1)
LI>> 2
>> (get (map '((ten 10) (twenty 20))) twenty)
LI>> 20
set
: function to set an element in a list or a map
>> (set (list 1 2 3) 1 1)
LI>> 2
>> (set (map '((ten 10) (twenty 20))) '(twenty twenty))
LI>> twenty: twenty
ten: 10
Functions on list
list
: constructs a list.
>>(list 1 2 3)
LI>>(1 2 3)
car
: returns the first element of a list, nil if the list is empty.
>>(car '(3 4 5))
LI>> 3
cdr
: returns list without the first element, nil if the list has one element.
>>(cdr '(3 4 5))
LI>>(4 5)
first
: returns the first element of a list (same as car)
>>(first (list 1 2 3))
LI>> 1
second
: returns the second element of a list
>>(second (list 1 2 3))
LI>> 2
third
: returns the third element of a list
>>(second (list 1 2 3))
LI>> 3
rest
: returns the rest of a list (same as cdr)
>> (rest '(1 2 3))
LI>> (2 3)
last
: returns the last element of a list.
>>(last '(3 4 5))
LI>>5
cons
: creates a cons of two elements
>> (cons 3 nil)
LI>> (3)
>> (cons nil 3)
LI>> (nil 3)
>> (cons 4 '(3))
LI>> (4 3)
>> (cons '(4) '(3))
LI>> ((4) 3)
len
: returns the length of a list of a map
>>(len '(1 2 3))
LI>> 3
empty
: returns true is a list or a map is empty
>> (empty '())
LI>> true
get-list
: get the element of the list at the given index (starts at 0). The first argument is a list, and the second the index
>> (get-list (list 1 2 3) 1)
LI>> 2
set-list
: set the element of the list at the given index (starts at 0). The first argument is a list, the second the value, and the third the index.
>> (set (list 1 2 3) 1 1)
LI>> 2
append
: append two lists together
>> (append (list 1 2 3) '(4 5))
LI>> (1 2 3 4 5)
member
: It takes two arguments of which the second must be a list, if the first argument is a member of the second argument, and then it returns the remainder of the list beginning with the first argument.
>> (member 3 '(1 2 3 4 5))
LI>> (3 4 5)
reverse
: reverse a list
>> (reverse '(1 2 3 4 5))
LI>> (5 4 3 2 1)
intersection
returns a list containing all elements present in all the lists passed as arguments.
>> (intersection '(1 2 3 4 5) '(1 2 3) '(3 4 2))
LI>> (2 3)
Functions on map
map
: constructs a map.
>> (map '((ten 10) (twenty 20)))
LI>> twenty: 20
ten: 10
get-map
: get the value inside a map
>> (define m1 (map '((test . 10))))
>> (get m1)
LI>> test: 10
>> (get-map m1 test)
LI>> 10
set-map
: returns a map with the new value inserted.
>> (define m1 (set-map m1 '(twenty . 20)))
>> (get m1)
LI>> twenty: 20
test: 10
union-map
: unifies two maps
>> (define map1 (map '((ten 10) (twenty 20))))
LI>> nil
>> map1
LI>> ten: 10
twenty: 20
>> (define map2 (map '((thirty 30) (fourty 40))))
LI>> nil
>> map2
LI>> thirty: 30
fourty: 40
>> (define map3 (union-map map1 map2))
LI>> nil
>> map3
LI>> thirty: 30
twenty: 20
fourty: 40
ten: 10
- ̀
remove-map
: remove from the map an entry. The first argument is a map, and the second the key.
>> (define map1 (map '((ten 10) (twenty 20))))
LI>> nil
>> (define map2 (map '((thirty 30) (fourty 40))))
LI>> nil
>> (define map3 (union-map map1 map2))
LI>> nil
>> (define map4 (remove-map map3 twenty))
LI>> nil
>> map4
LI>> thirty: 30
fourty: 40
ten: 10
remove-key-value-map
: remove a key-value binding if it exists.
>> (define map1 (map '((ten 10) (twenty 20))))
LI>> nil
>> (define map2 (remove-key-value-map map1 '(twenty 20)))
LI>> nil
>> map2
LI>> ten: 10
>> (define map2 (remove-key-value-map map1 '(ten 1)))
LI>> error: In remove-key-value-map, map does not have key value (ten:1)
Mathematical functions
- basic math functions:
- not (!)
- add (+)
- sub (-)
- div (/)
- mul (*)
- eq (=)
- gt (>)
- ge (>=)
- lt (<)
- le (<=)
Type verification
lambda?
: returns true if the LValue is a lambda.integer?
: returns true if the LValue is an integer.float?
: returns true if the LValue is a float.nil?
: returns true if the LValue is nil.bool?
: returns true if the LValue is a boolean.symbol?
: returns true if the LValue is a symbol.fn?
: returns true if the LValue is a function.mut-fn?
: returns true if the LValue is a mutable function.quote?
: returns true if the LValue is a quote.map?
: returns true if the LValue is a map.list?
: returns true if the LValue is a list.pair?
: returns true if the LValue is a list with at least one element.
All above functions are defined in the root environment.
Error
err
construct an err value from a LValue
>> (err test)
LI>> (err (test))
err?
returns true if the LValue is a (Err <lvalue>), false if it is a (Ok <lvalue>)
>> (err? (err test))
LI>> true
interrupted?
returns true is the LValue is an err coming from an interruption.
Modules
A module is a collection of bindings that can be added to an environment to add functions, constants, lambdas etc. It also contains the documentation and contexts that can be used to use any shared object outside LValues.
Module IO
This module contains functions to load lisp code from file, write to files and print either on the console or in the log.
Functions
print
: print a LValue either in the console or in the interpreter log.
>> (print test)
test
__read__
: reads a string from a file. Prefer using the macro read.
>> (__read__ <path-to-file>/<name-file>.scm)
write
: write a LValue to a file.
>> (write <path-to-file>/<name-file>.scm)
Macros
read
: macro used to read, parse and eval a lisp file.
(load test.scm)
=> (eval (parse (__read__ test.scm)))
Module String
This module contains functions to create and format strings. A string is a specific LValue that is different from a symbol.
Functions
string
creates a string LValue.concatenate
: takes a list of args and concatenate them into a string.
>> (concatenate this is a test)
LI>> thisisatest
description: Module providing utilitary functions useful when programming. It also provides lambdas and macros.
Module Utils
Macros
and
: conjunction of boolean expressions
(and (> x 3) (< y 4))
=> (if (> x 3)
(< y 4)
nil)
or
: disjunction of boolean expressions (or (> x 3) (< y 4)) => (if (> x 3) true (< y 4))caar
: takes the first element of the first element of a list
(caar x) => (car (car x))
cadr
: takes the first element of the rest of a list
(cadr x) => (car (cdr x))
cdar
,cddr
,cadar
,cadar
,caddr
,cdadr
,caadr
,cadadr
,cadaddr
, similar tocaar
andcadr
.!=
,neq
: not equal
(!= x y) => (! (= x y))
await-async
await-async block to eval asynchronously while waiting directly for the result
(await-async (+ 3 4))
=> (await (async (+ 3 4)))
apply
apply a function to a list
(apply + (3 4))
=> (cons + (3 4))
Here is an example
>> (apply + (10 6))
LI>> 16
cond
: equivalent to successiveif .. else if .. else
>> (define weather
(lambda (x)
(cond ((< x 10) '(It is cold!))
((< x 20) '(It is cool!))
((< x 30) '(It is warm!))
(else '(It is hot!)))))
>> (weather 10)
LI>> (It is cool!)
>> (weather 9)
LI>> (It is cold!)
>> (weather 25)
LI>> (It is warm!)
>> (weather 36)
LI>> (It is hot!)
Here is an example of how to use it.
>> (let ((x 3)
(y 4))
(+ x y))
LI>> 7
>> (let* ((x 3)
(y (x +1)))
(+ x y))
LI>> 7
loop
: loop the evaluation of an expression
(loop (print 'test))
=> (begin
(define __loop__
(lambda nil
(begin
(print 'test)
(__loop__))))
(__loop__))
let
andlet*
Used to evaluate a code with locally bound variables. The difference lies in the possibility to bind variables in function of previous bindings withlet*
.
(let ((x 3)
(y 4))
(+ x y))
=> ((lambda (x y) (+ x y)) 3 4)
(let* ((x 3)
(y (+ x 1)))
(+ x y))
=> ((lambda (x)
((lambda (y) (+ x y)) (+ x 1))) 3)
combine
: todo
Lambdas
zip
zips elements of two lists in pairs
>> (zip '(1 2 3 4) '(5 6 7 8))
LI>> ((1 5) (2 6) (3 7) (4 8))
unzip
undo a zipped list.
>> (define zipped (zip '(1 2 3 4) '(5 6 7 8)))
>> zipped
LI>> ((1 5) (2 6) (3 7) (4 8))
>> (unzip zipped)
LI>> ((1 2 3 4) (5 6 7 8))
mapf
: maps a function to a list of argument
>> (mapf weather '(9 15 25 36))
;defined in example of cond
LI>> ((It is cold!) (It is cool!) (It is warm!) (It is hot!))
par
evaluates in parallel a list of expressions and awaits on all their result.
>> (par (+ 1 2) (+ 3 4))
LI >> (3 7)
repeat
evaluates n time an expression and returns the result of the last evaluation.
>> (repeat '(print 1) 4)
1
1
1
1
LI>> nil
retry-once
evaluates an expression, and evaluates it again if the result is an err.
Functions
Provides a bunch of utility functions:
rand-element
pick a random element from a list
>> (rand-element '(10 2 6))
LI>> 2
>> (rand-element '(10 2 6))
LI>> 10
>> (rand-element '(10 2 6))
LI>> 2
>> (rand-element '(10 2 6))
LI>> 6
enumerate
enumerates all possible sets of combination from several lists.
>> (enumerate '(1 2) '(3 4) '(5 6))
LI>> ((1 3 5) (1 3 6) (1 4 5) (1 4 6) (2 3 5) (2 3 6) (2 4 5) (2 4 6))
contains
returns true if a list contains an element
>> (contains '(1 2 3 4 5) 1)
LI>> true
>> (contains '(1 2 3 4 5) 6)
LI>> nil
>> (contains '(1 (2 3) 4 5) '(2 3))
LI>> true
sublist
: returns a sublist of a list
>> (sublist '(a b c d e f) 1)
LI>> (b c d e f)
>> (sublist '(a b c d e f) 1 3)
LI>> (b c)
transform-in-singleton-list
: transforms a list of arguments in a list of singleton
>> (transform-in-singleton-list 1 2 3 4)
LI>> ((1) (2) (3) (4))
quote-list
: transform a list in list quoting each element
>> (quote-list '(1 2 3 4))
LI>> ((quote 1) (quote 2) (quote 3) (quote 4))
sleep
awaits that the defined time in second is elapsed to resume the evaluation of the next expressions.
Module Advanced Math
This module contains more advanced mathematical functions and objects.
Functions
sin
: computes the sin of a number
>> (sin 0)
LI>> 0
>> (sin pi)
LI>> 0.00000000000000012246467991473532
>> (sin (/ pi 2))
LI>> 1
cos
: computes the cos of a number
>> (cos 0)
LI>> 1
>> (cos pi)
LI>> -1
>> (cos (/ pi 2))
LI>> 0.00000000000000006123233995736766
pow
: computes a number to a certain power
>> (pow 2 3)
LI>> 8
>> (pow 2 3.5)
LI>> 11.313708498984761
>> (pow 2.3 3.5)
LI>> 18.45216910555504
square
: computes a number to the square.
>> (square 2)
LI>> 4
>> (square 2.3)
LI>> 5.289999999999999
sqrt
computes the square root of a number
>> (sqrt 4)
LI>> 2
abs
: computes the absolute of a number
>> (abs 2)
LI>> 2
>> (abs -2)
LI>> 2
rand-int-in-range
: generates a random int in a range.
>> (rand-int-in-range 0 10)
LI>> 6
rand-float-in-range
: generates a random float in a range.
>> (rand-float-in-range 0 10)
LI>> 1.875527591323538
Constants
pi
: value of constant pi in f64
Acting primitives
The acting language is built on top of the new implementation of Scheme with the following functions and lambdas:
exec-command
sends an execution request to the platform a command and returns an execution handle.
(exec-command pick r1) -> handle
exec-task
executes a task thanks to the RAE algorithm.read-state
returns the current value of a state variable.
(read-state at r1) -> bedroom
arbitrary
: arbitrarily takes an element of a list using a function that can be passed as argument, the default behavior being to take the first element of the list.
>>(arbitrary '(3 4 5))
LI>> 3
>>(arbitrary '(3 4 5) last)
LI>> 5
+>/assert
add/update a fact in the state. <> - ->/retract: Delete a fact in the state.get-state
returns a map of the perceived state.get-facts
returns a map with the perceived state, the resources, and the instances.instance
is used to reason on the presence of objects, and their types.- If no argument is passed, the function will return a map with all the objects of each type.
- If one argument is passed, it should be a type, and the function will return all elements of the type, including elements of subtypes.
- If two arguments are passed, it should be an object and a type. The function returns true if the object is of the given type.
Resource management
To handle concurrency in the evaluation of tasks, the system provides a resource system. We define a resource as an object with an initial capacity $C_{init}$. A resource $r$ can be acquired at time $t$ with an amount $c$ that is lower than or equal to the current capacity $C_t$. Upon acquisition, the acting engine ensures that no race-condition occurs that would result in an over allocation and the capacity is immediately decreased by the amount $c$.
We distinguish unary and divisible resources. A unary resource can be acquired by only one task at a time, where initial capacity and requested amount are always one. A divisible resource with an initial capacity $C_{init}$ can be acquired with any $c_t \in[0, C_{init}]$. At the difference of real-time systems and mutexes, there is no guarantee on the order of access to resources, as it defers this decision to the acting engine and reasoning systems. When a resource is released, its capacity is increased by corresponding amount.
-
new-resource
declares a resource r of the resource, with an initial capacity c for a divisible resource. -
acquire
acquires a resource r with the quantity $c$ needed if $r$ is divisible. Once the acquisition has been validated by the system, the function returns a resource-handle $h$. If $h$ goes out of scope, the resource is automatically released. The acquisition of a resource can be interrupted to avoid blocking a program waiting too long on a resource. -
release
explicitly releases the resource using the resource-handle $h$.
Advanced acting functions
wait-for
takes a dynamic expression and awaits that the evaluation of the expression returns a true value.
(wait-for `(= (robot.battery ,?r) 1)))))
monitor
opposite of wait-for
(monitor `(> (robot.battery ,?r) 0.4)))))
run-monitoring
evaluates an expression while a dynamic expression is true.
(run-monitoring `(move ,?r) `(> (robot.battery ,?r) 0.4))
Gobot-Sim
todo