Trees

Tree stewardship.

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.

_images/yggdrasil.jpg

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 tree custodian.

It features a few enhancements that go above and beyond just ticking the root behaviour of a tree. These 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 tree

Variables:
  • count – number of times the tree has been ticked.
  • root – root node of the tree
  • visitors – entities that visit traversed parts of the tree when it ticks
  • pre_tick_handlers – functions that run before the entire tree is ticked
  • post_tick_handlers – functions that run after the entire tree is ticked
Raises:

TypeError – if root variable is not an instance of Behaviour

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
24
25
26
27
28
29
30
31
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

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=root
    )
    print(py_trees.display.unicode_tree(root=root))
    behaviour_tree.setup(timeout=15)

    def print_tree(tree):
        print(py_trees.display.unicode_tree(root=tree.root, show_status=True))

    try:
        behaviour_tree.tick_tock(
            period_ms=500,
            number_of_iterations=py_trees.trees.CONTINUOUS_TICK_TOCK,
            pre_tick_handler=None,
            post_tick_handler=print_tree
        )
    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:

pre-tick-handler-function
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
        '--render-with-blackboard-variables',
        action='store_true',
        help='render dot tree to file with blackboard variables'
    )
    group.add_argument('-i', '--interactive', action='store_true', help='pause and wait for keypress at each tick')
    return parser


def pre_tick_handler(behaviour_tree):
    print("\n--------- Run %s ---------\n" % behaviour_tree.count)

pre-tick-handler-adding
1
2
def create_tree():
    every_n_success = SuccessEveryN()

Visitors

Visiting rights to behaviours.

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:

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)