class  ConditionCheck
class  ConditionRoot
 ConditionRoot Condition roots are top-level nodes of the expression tree. More...
class  Literal
class  LiteralImpl
 LiteralImpls are the basic elements for defining conditional expressions. More...
class  Operation
class  OperationAnd
class  OperationNot
class  OperationOr
class  Term
class  TermImpl


 Condition Checks

Detailed Description

The ArmarX condition mechanism allows to define a distributed set of condition checks on sensory data and generate events based on the condition checks. These events are used to trigger state transitions in the robot program.

The condition mechanism comprises two main elements:

Condition checks

Condition checks are provided by each observer component in the ArmarX scenario. Condition checks can be instantiated on each datafield provided by the observer. Thereby, datafields are identified by their armarx::DataFieldIdentifier and condition checks are identifier by their name. Further a list of parameters is passed to condition checks.

Typical generic condition checks include "equals", "larger", "inrange", "contains" which are already implemented for all applicable datatypes. Further, the condition checks are easily extensible if special checks are needed. See armarx::ConditionCheck for details.

Definition of conditions

Conditions are defined using logical expressions. Each literal in the logical expression represents the state of a distributed condition check. Using logical operations, complex expressions can be achieved. In general, the definition of a condition is very similar to the if-statement:

// Condition checks are literals in the boolean expression.
// They are defined on a datafield within an observer and with their name.
// A set of parameters can be passed to the check.
Literal targetReached("Head.jointangles.LeftEye", "inrange", Literal::createParameterList(-0.1,0.1));
Literal cupPresent("ObjectMemory.GreenCup.likelihood", "larger", Literal::createParameterList(0.5));
// Literals can be combined to more complex terms in order to achieve complex expressions
Term fixatingObject = targetReached && cupPresent;
// the call to installCondition associated an event with the condition that is emitted once the
// condition is fulfilled. Further, an optional description can be passed.
installCondition(fixatingObject, createEvent<EvFixatingGreenCup>, "Fixating the green cup");

In order to allow a more convenient way for assembling conditions in a loop, an empty term can be defined which is successively defined by adding more literals. Logical operations on empty are not applied, they are replaced by an assignment:

// define an empty term
Term t;
for(int i = 0 ; i < 7 ; i++)
// the first && applied to the term is ignored, because t is an empty term
t = t && Literal(datafield[i], "inrange", Literal::createParameterList(range[i].min, range[i].max));
// the above produces the same result as
Literal t(datafield[0], "inrange", Literal::createParameterList(range[0].min, range[0].max));
for(int i = 1 ; i < 7 ; i++)
t = t && Literal(datafield[i], "inrange", Literal::createParameterList(range[i].min, range[i].max));

Implementation of conditions

The implementation of conditions consists of two parts: the user frontend and the framework implementation. A basic overview is shown in this figure, where the user frontend is colored red and the framework implementation blue.

User frontend

The user frontend offers a convenient way to define a condition by means of assembling a Term using binary operators &&, || and NOT. The condition is an expression composed of literals as introduced in Definition of conditions.

Internally, each term builds a TermImpl which is used within the ArmarX framework, to hande the condition checks and to evaluate the term. This implementation is described in the following.

Framework implementation

The condition is internally represented as binary expression tree. Each node in the tree corresponds to a logical operation such as &&, || and NOT. The leaves of the expression tree correspond to literals, which are associated with condition checks (see Condition checks).

Each node of the tree inherits from the TermImpl superclass, which stores the linkage in the tree and a boolean value which encodes the current state of the node. Further, an update method is provided, which takes the value from the children of the node and performes the operation specific to the node in order to update its state. Once the value has been updated, the update of the parent node is called.

Concrete implementations of TermImpl are provided by subclassing the TermImpl. Three different subclasses are implemented: the LiteralImpl, the Operation, and the ConditionRoot. The LiteralImpl correspond to condition checks and are updated by evaluation atomar checks on datafields. The value of a LiteralImpl corresponds to the result of the condition check. On top of the LiteralImpl, a set of operations can be defined using the Operation subclass. The available operations correspond to the logical operations &&, || and NOT provided by the user frontend. Finally, the top node of the tree is realized by the class ConditionRoot, which fires an event, once the expression represented by the tree is fulfilled.

The following image illustrates a complete expression tree as build by the ArmarX framework:

The expression tree corresponds to the example code given in section Definition of conditions. The trees can be visualized including their state and associated checks with the ConditionViewerWidget from the ArmarX Gui.

std::vector< T > max(const std::vector< T > &v1, const std::vector< T > &v2)
Definition: VectorHelpers.h:267
static VarList createParameterList()
Static helper method to create an empty parameterlist.
Definition: Term.cpp:129
std::vector< T > min(const std::vector< T > &v1, const std::vector< T > &v2)
Definition: VectorHelpers.h:294