py_trees.trees module
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.
This package provides a default reference implementation that is directly usable, but can also be easily used as inspiration for your own tree custodians.
- class py_trees.trees.BehaviourTree(root: Behaviour)
Bases:
object
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 program demonstrates the above features.
- Args:
root (
Behaviour
): root node of the tree- Attributes:
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
- add_post_tick_handler(handler: Callable[[BehaviourTree], None]) None
Add a function to execute after the tree has ticked.
The function must have a single argument of type
BehaviourTree
.Some ideas that are often used:
logging
modifications on the tree itself (e.g. closing down a plan)
sending data to visualisation tools
introspect the state of the tree to make and send reports
- Args:
handler: function
- add_pre_tick_handler(handler: Callable[[BehaviourTree], None]) None
Add a function to execute before the tree is ticked.
The function must have a single argument of type
BehaviourTree
.Some ideas that are often used:
logging (to file or stdout)
modifications on the tree itself (e.g. starting a new plan)
- Args:
handler: function
- add_visitor(visitor: VisitorBase) None
Welcome a visitor.
Trees can run multiple visitors on each behaviour as they tick through a tree.
- Args:
visitor: sub-classed instance of a visitor
See also
- insert_subtree(child: Behaviour, unique_id: UUID, index: int) bool
Insert a subtree as a child of the specified parent.
If the parent is found, this directly calls the parent’s
insert_child()
method using the child and index arguments.- Args:
child: subtree to insert unique_id: unique id of the parent index: insert the child at this index, pushing all children after it back one.
- Returns:
suceess or failure (parent not found) of the operation
- Raises:
TypeError: if the parent is not a
Composite
- interrupt() None
Interrupt tick-tock if it is tick-tocking.
Note that this will permit a currently executing tick to finish before interrupting the tick-tock.
- prune_subtree(unique_id: UUID) bool
Prune a subtree given the unique id of the root of the subtree.
- Args:
unique id of the subtree root
- Returns:
success or failure of the operation
- Raises:
RuntimeError: if unique id is the root or parent does not have remove_node
- replace_subtree(unique_id: UUID, subtree: Behaviour) bool
Replace the subtree with the specified id for the new subtree.
This is a common pattern where we’d like to swap out a whole sub-behaviour for another one.
- Args:
unique_id: unique id of the parent subtree: root behaviour of the subtree
- Raises
AssertionError: if unique id is the behaviour tree’s root node id
- Returns:
: suceess or failure of the operation
- setup(timeout: float | Duration = Duration.INFINITE, visitor: VisitorBase | None = None, **kwargs: int) None
Crawl across the tree calling
setup()
on each behaviour.Visitors can optionally be provided to provide a node-by-node analysis on the result of each node’s
setup()
before the next node’ssetup()
is called. This is useful on trees with relatively long setup times to progressively report out on the current status of the operation.- Args:
timeout: time (s) to wait (use common.Duration.INFINITE to block indefinitely) visitor: runnable entities on each node after it’s setup **kwargs: distribute args to this behaviour and in turn, to it’s children
- Raises:
Exception: be ready to catch if any of the behaviours raise an exception RuntimeError: in case setup() times out
- shutdown() None
Crawl across the tree, calling
shutdown()
on each behaviour.- Raises:
Exception: be ready to catch if any of the behaviours raise an exception
- tick(pre_tick_handler: Callable[[BehaviourTree], None] | None = None, post_tick_handler: Callable[[BehaviourTree], None] | None = None) None
Tick the tree just once and run any handlers before and after the tick.
This optionally accepts some one-shot handlers (c.f. those added by
add_pre_tick_handler()
andadd_post_tick_handler()
which will be automatically run every time).The handler functions must have a single argument of type
BehaviourTree
.- Args:
pre_tick_handler (
func
): function to execute before ticking post_tick_handler (func
): function to execute after ticking
- tick_tock(period_ms: int, number_of_iterations: int = -1, stop_on_terminal_state: bool = False, pre_tick_handler: Callable[[BehaviourTree], None] | None = None, post_tick_handler: Callable[[BehaviourTree], None] | None = None) None
Tick continuously with period as specified.
Depending on the implementation, the period may be more or less accurately tracked. For example, if your tick time is greater than the specified period, the timing will overrun.
This optionally accepts some handlers that will be used for the duration of this tick tock (c.f. those added by
add_pre_tick_handler()
andadd_post_tick_handler()
which will be automatically run every time).The handler functions must have a single argument of type
BehaviourTree
.- Args:
period_ms (
float
): sleep this much between ticks (milliseconds) number_of_iterations (int
): number of iterations to tick-tock stop_on_terminal_state (:obj: bool): if true, stops when the tree’s status isSUCCESS
or :data:`~py_trees.common.Status.FAILURE.pre_tick_handler (
func
): function to execute before ticking post_tick_handler (func
): function to execute after ticking
- py_trees.trees.setup(root: Behaviour, timeout: float | Duration = Duration.INFINITE, visitor: VisitorBase | None = None, **kwargs: int) None
Crawl across a (sub)tree of behaviours calling
setup()
on each behaviour.Visitors can optionally be provided to provide a node-by-node analysis on the result of each node’s
setup()
before the next node’ssetup()
is called. This is useful on trees with relatively long setup times to progressively report out on the current status of the operation.- Args:
root: unmanaged (sub)tree root behaviour timeout: time (s) to wait (use common.Duration.INFINITE to block indefinitely) visitor: runnable entities on each node after it’s setup **kwargs: dictionary of args to distribute to all behaviours in the (sub)tree
- Raises:
Exception: be ready to catch if any of the behaviours raise an exception RuntimeError: in case setup() times out