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.
An example:
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.