Decorators

Decorate your children. They make great furniture pieces.

Decorators are behaviours that manage a single child and provide common modifications to their underlying child behaviour (e.g. inverting the result). That is, they provide a means for behaviours to wear different ‘hats’ and this combinatorially expands the capabilities of your behaviour library.

_images/many-hats.png

An example:

digraph life {
graph [fontname="times-roman"];
node [fontname="times-roman"];
edge [fontname="times-roman"];
Life [fillcolor=orange, fontcolor=black, fontsize=11, shape=box, style=filled];
Inverter [fillcolor=ghostwhite, fontcolor=black, fontsize=11, shape=ellipse, style=filled];
Life -> Inverter;
"Busy?" [fillcolor=gray, fontcolor=black, fontsize=11, shape=ellipse, style=filled];
Inverter -> "Busy?";
Timeout [fillcolor=ghostwhite, fontcolor=black, fontsize=11, shape=ellipse, style=filled];
Life -> Timeout;
"Have a Beer!" [fillcolor=gray, fontcolor=black, fontsize=11, shape=ellipse, style=filled];
Timeout -> "Have a Beer!";
}
 1#!/usr/bin/env python3
 2# -*- coding: utf-8 -*-
 3
 4import py_trees.decorators
 5import py_trees.display
 6
 7if __name__ == '__main__':
 8
 9    root = py_trees.composites.Sequence(name="Life")
10    timeout = py_trees.decorators.Timeout(
11        name="Timeout",
12        child=py_trees.behaviours.Success(name="Have a Beer!")
13    )
14    failure_is_success = py_trees.decorators.Inverter(
15        name="Inverter",
16        child=py_trees.behaviours.Success(name="Busy?")
17        )
18    root.add_children([failure_is_success, timeout])
19    py_trees.display.render_dot_tree(root)

Decorators (Hats)

Decorators with specific functionality:

And the X is Y family:

Decorators for Blocking Behaviours

It is worth making a note of the effect of decorators on blocking behaviours, i.e. those that return RUNNING before eventually returning SUCCESS or FAILURE.

A decorator, such as py_trees.decorators.RunningIsSuccess() on a blocking behaviour will immediately terminate the underlying child and re-intialise on it’s next tick. This is often surprising (to the user) but is necessary to ensure the underlying child isn’t left in a dangling state (i.e. RUNNING) as subsequent ticks move on to other parts of the tree.

A better approach in this case is to build a non-blocking variant or a combination of non-blocking behaviors that handle construction, monitoring and destruction of the activity represented by the original blocking behaviour.