Trees¶
While a graph of connected behaviours and composites form a tree in their own right (i.e. it can be initialised and ticked), it is usually convenient to wrap your tree in another class to take care of alot of the housework and provide some extra bells and whistles that make your tree flourish.
This package provides a default reference implementation that is directly usable, but can also be easily used as inspiration for your own tree custodians.
The Behaviour Tree¶
-
class
py_trees.trees.
BehaviourTree
(root)[source] Grow, water, prune your behaviour tree with this, the default reference implementation. It features a few enhancements to provide richer logging, introspection and dynamic management of the tree itself:
- Pre and post tick handlers to execute code automatically before and after a tick
- Visitor access to the parts of the tree that were traversed in a tick
- Subtree pruning and insertion operations
- Continuous tick-tock support
See also
The py-trees-demo-tree-stewardship program demonstrates the above features.
Parameters: root (
Behaviour
) – root node of the treeVariables: - count (
int
) – number of times the tree has been ticked. - root (
Behaviour
) – root node of the tree - visitors ([
visitors
]) – entities that visit traversed parts of the tree when it ticks - pre_tick_handlers ([
func
]) – functions that run before the entire tree is ticked - post_tick_handlers ([
func
]) – functions that run after the entire tree is ticked
Raises: AssertionError
– if incoming root variable is not the correct type
Skeleton¶
The most basic feature of the behaviour tree is it’s automatic tick-tock. You can
tick_tock()
for a specific number of iterations,
or indefinitely and use the interrupt()
method to stop it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #!/usr/bin/env python
import py_trees
if __name__ == '__main__':
root = py_trees.composites.Selector("Selector")
high = py_trees.behaviours.Success(name="High Priority")
med = py_trees.behaviours.Success(name="Med Priority")
low = py_trees.behaviours.Success(name="Low Priority")
root.add_children([high, med, low])
behaviour_tree = py_trees.trees.BehaviourTree(root)
behaviour_tree.setup(15)
try:
behaviour_tree.tick_tock(
sleep_ms=500,
number_of_iterations=py_trees.trees.CONTINUOUS_TICK_TOCK,
pre_tick_handler=None,
post_tick_handler=None
)
except KeyboardInterrupt:
behaviour_tree.interrupt()
|
or create your own loop and tick at your own leisure with
the tick()
method.
Pre/Post Tick Handlers¶
Pre and post tick handlers can be used to perform some activity on or with the tree
immediately before and after ticking. This is mostly useful with the continuous
tick_tock()
mechanism.
This is useful for a variety of purposes:
- logging
- doing introspection on the tree to make reports
- extracting data from the blackboard
- triggering on external conditions to modify the tree (e.g. new plan arrived)
This can be done of course, without locking since the tree won’t be ticking while these handlers run. This does however, mean that your handlers should be light. They will be consuming time outside the regular tick period.
The py-trees-demo-tree-stewardship program demonstrates a very simple pre-tick handler that just prints a line to stdout notifying the user of the current run. The relevant code:
1 2 3 4 5 6 7 8 9 10 11 |
def pre_tick_handler(behaviour_tree):
"""
This prints a banner and will run immediately before every tick of the tree.
Args:
behaviour_tree (:class:`~py_trees.trees.BehaviourTree`): the tree custodian
"""
print("\n--------- Run %s ---------\n" % behaviour_tree.count)
|
1 2 | # Rendering
####################
|
Visitors¶
Visitors are entities that can be passed to a tree implementation
(e.g. BehaviourTree
) and used to either visit
each and every behaviour in the tree, or visit behaviours as the tree is
traversed in an executing tick. At each behaviour, the visitor
runs its own method on the behaviour to do as it wishes - logging, introspecting, etc.
Warning
Visitors should not modify the behaviours they visit.
The py-trees-demo-tree-stewardship program demonstrates the two reference visitor implementations:
DebugVisitor
prints debug logging messages to stdout andSnapshotVisitor
collects runtime data to be used by visualisations
Adding visitors to a tree:
behaviour_tree = py_trees.trees.BehaviourTree(root)
behaviour_tree.visitors.append(py_trees.visitors.DebugVisitor())
snapshot_visitor = py_trees.visitors.SnapshotVisitor()
behaviour_tree.visitors.append(snapshot_visitor)
These visitors are automatically run inside the tree’s tick
method.
The former immediately logs to screen, the latter collects information which is then used to display an
ascii tree:
behaviour_tree.tick()
ascii_tree = py_trees.display.ascii_tree(
behaviour_tree.root,
snapshot_information=snapshot_visitor)
)
print(ascii_tree)