Skip to main content
Version: 4.5

Main Concepts

BehaviorTree.CPP is a C++ library that can be easily integrated into your favourite distributed middleware, such as ROS or SmartSoft.

You can statically link it into your application (for example a game).

These are the main concepts which you need to understand first.

Nodes vs Trees

The user must create his/her own ActionNodes and ConditionNodes (LeafNodes); this library helps you to compose them easily into trees.

Think about the LeafNodes as the building blocks which you need to compose a complex system. If Nodes were lego bricks, your trees would be lego sets.

By definition, your custom Nodes are (or should be) highly reusable.

Instantiate trees at run-time using the XML format

Despite the fact that the library is written in C++, trees themselves can be created and composed at run-time, more specifically, at deployment-time, using an XML base scripting language.

An XML format is described in details here, but the best way to learn the syntax is following the tutorials.

The tick() callbacks

Any TreeNode can be seen as a mechanism to invoke a callback, i.e. to run a piece of code. What this callback does is up to you.

In most of the following tutorials, our Actions will simply print messages on console or sleep for a certain amount of time to simulate a long calculation.

In production code, especially in Model Driven Development and Component Based Software Engineering, an Action/Condition would probably communicate to other components or services of the system.

// The simplest callback you can wrap into a BT Action
NodeStatus HelloTick()
{
std::cout << "Hello World\n";
return NodeStatus::SUCCESS;
}

// Allow the library to create Actions that invoke HelloTick()
// (explained in the tutorials)
factory.registerSimpleAction("Hello", std::bind(HelloTick));
tip

The factory may create multiple instances of the node Hello.

Create custom nodes with inheritance

In the example above, a specific type of TreeNodes which invoke HelloTick was created using a function pointer (dependency injection).

Generally, to define a custom TreeNode, you should inherit from the class TreeNode or, more specifically, its derived classes:

  • ActionNodeBase
  • ConditionNode
  • DecoratorNode

As a reference please look at the first tutorial.

Dataflow, Ports and Blackboard

Ports are explained in detail in the second and third tutorials.

For the time being, it is important to know that:

  • A Blackboard is a key/value storage shared by all the Nodes of a Tree.

  • Ports are a mechanism that Nodes can use to exchange information between each other.

  • Ports are "connected" using the same key of the blackboard.

  • The number, name and kind of ports of a Node must be known at compilation-time (C++); connections between ports are done at deployment-time (XML).

  • You can store as value any C++ type (we use a _type erasure technique similar to std::any).