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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import py_trees.decorators import py_trees.display if __name__ == '__main__': root = py_trees.composites.Sequence(name="Life") timeout = py_trees.decorators.Timeout( name="Timeout", child=py_trees.behaviours.Success(name="Have a Beer!") ) failure_is_success = py_trees.decorators.Inverter( name="Inverter", child=py_trees.behaviours.Success(name="Busy?") ) root.add_children([failure_is_success, timeout]) py_trees.display.render_dot_tree(root)
Decorators with very specific functionality:
And the X is Y family:
Decorators for Blocking Behaviours
It is worth making a note of the effect of decorators on
behaviours that return
some time before finally returning
FAILURE (blocking behaviours) since
the results are often at first, surprising.
A decorator, such as
a blocking behaviour will immediately terminate the underlying child and
re-intialise on it’s next tick. This is necessary to ensure the underlying
child isn’t left in a dangling state (i.e.
RUNNING), but is often not what is being
The typical use case being attempted is to convert the blocking
behaviour into a non-blocking behaviour. If the underlying child has no
state being modified in either the
terminate() methods (e.g. machinery is
entirely launched at init or setup time), then conversion to a non-blocking
representative of the original succeeds. Otherwise, another approach is
needed. Usually this entails writing a non-blocking counterpart, or
combination of behaviours to affect the non-blocking characteristics.