arora-behavior-tree 0.1.0

The Arora behavior tree: Groot-compatible trees ticking Arora modules.
docs.rs failed to build arora-behavior-tree-0.1.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

Arora Behavior Trees

Implementation of a behavior tree executor based on Arora module nodes. A BehaviorTree is a set of Nodes arranged in a tree, i.e. with all nodes having a single parent contained in the behavior tree, but the root node. The BehaviorTree holds a list variables, a.k.a. the blackboard. This is property is checked when the behavior tree is loaded from a set of nodes, using load_behavior_tree_nodes or load_behavior_tree_yaml.

Schema

The YAML format to the schema defined in src/schema.rs. It consist of a list of nodes, which arguments can be expressed dynamically with a flexible Expression. It can be:

  • a serialized Value, like defined in arora-types, or more specifically an UUID,
  • a reference to a variable, in-memory or identified with the UUID of blackboard variable.
  • a reference to the argument of another node, so that to skip the general blackboard.
  • the description of a call to perform every time the node is ticked.

Runtime

To run a behavior tree, use BehaviorTreeRuntime::setup to create a BehaviorTreeRuntime instance, that proposes the general tick function: BehaviorTreeRuntime implements Tickable. Tickable::tick takes no argument and returns a behavior_tree::Status.

Note: we call "parameter" the declaration of what function may accept as inputs (or outputs, if mutable). We call "argument" the actual value passed to the function.

behavior_tree::Status is defined in arora-behavior-tree-types, and can be Success, Failure or Running. Any function of a module that returns a behavior_tree::Status can be used by a node, and nodes can refer only to such functions.

Alternatively, a node may set return_binding to an Expression pointing at a blackboard variable. In that case the function's raw return value is written to the variable after each tick, and the node always reports Status::Success to its parent. This lets non-Status functions (e.g. add, cos) participate in a behavior tree.

Setting up the runtime requires a CallBridge, which the Arora engine implements. The setup mechanism will compute every binding of node arguments, so that every node can be ticked with no argument. Thus the tick functions can be registered to the engine in exchange of a CallableId. This identifier is wrapped in a structure called TickId, also defined in arora-behavior-tree-types.

Nodes that have children are required to expose them as their first parameter, that should be named children, identified with the UUID 5b6e9515-dbcc-411d-bee9-3d8cba5fedda, and accept a Vec<TickId>. At runtime, the children are passed as TickIds that can be converted into CallableIds before calling arora_dispatch_indirect. The return value is always expected to be a behavior_tree::Status.

Basic Nodes and Helpers

Some helpers are also available to create behavior trees in code. The basic control nodes (sequence, sequence-star, fallback, parallel) and the status leaves (succeed, fail, run) are built in to this crate and dispatched natively; additional leaf and utility nodes for tests and demos live in the test-behavior-tree-nodes module. TreeNode offers an alternative way to build behavior trees for Rust applications, where the nodes are directly created as trees (instead of being juxtaposed flatly), providing a build-time guarantee of the validity of the structure.

Groot Support

Groot is a behavior tree editor in C++ Qt, that is used along the mainstream BehaviorTreeCPP C++ library for behavior trees. It is used in Nav2, a well-known navigation for ROS. TreeNodes can be converted from and to groot::Nodes. Though most of basic Groot nodes are not implemented in this library, it is possible to edit behavior trees with Groot, and convert them for this library, using BehaviorTree::from_groot_xml. Some example files are available in groot/, and are used in tests. We can use and complete the Groot Arora palette with time.

Dealing with States in a Stateless Design

Some effort was made to keep the nodes stateless, by avoiding the need for a clean-up function for each node function. Instead, stateful information is meant to be passed as mutable parameters to the node functions. Thus, it is the behavior tree that holds this state in variables (anonymously or in the blackboard), and it is capable of resetting them to their default values, if they are mentioned in the module function description.

Statelessness is important in a client / server architecture - behavior tree / module, here - to ensure that the server is designed to not maintain resources busy if the communication with the client is absolutely dropped. It also favors reproducibility, parallelization, reusability and scalability. In this particular case, it also favors introspectability, since states are meant to be accessible in the behavior tree.