Skip to content

How to use multiple XML files to store your subtrees

In the examples which we presented so far, we always create an entire Tree from a single XML file.

If multiple Subtrees were used, they were all included into the same XML.

In recent version of BT.CPP (3.7+), the user can more easily load trees from multiple files, if needed.

Load multiple files with "include"

We will consider a main tree that invoke 2 different subtrees.

File main_tree.xml:

<root main_tree_to_execute = "MainTree">
    <include path="./subtree_A.xml" />
    <include path="./subtree_B.xml" />
    <BehaviorTree ID="MainTree">
        <Sequence>
            <SaySomething message="starting MainTree" />
            <SubTree ID="SubTreeA" />
            <SubTree ID="SubTreeB" />
        </Sequence>
    </BehaviorTree>
<root>
File subtree_A.xml:

<root>
    <BehaviorTree ID="SubTreeA">
        <SaySomething message="Executing Sub_A" />
    </BehaviorTree>
</root>

File subtree_B.xml:

<root>
    <BehaviorTree ID="SubTreeB">
        <SaySomething message="Executing Sub_B" />
    </BehaviorTree>
</root>

As you may notice, we included two relative paths in main_tree.xml that tells to BehaviorTreeFactory where to find the required dependencies.

We need to create the tree as usual:

factory.createTreeFromFile("main_tree.xml")

Load multiple files manually

If we don't want to add relative and hard-coded paths into our XML, or if we want to instantiate a subtree instead of the main tree, there is a new approach, since BT.CPP 3.7+.

The simplified version of main_tree.xml will be:

<root>
    <BehaviorTree ID="MainTree">
        <Sequence>
            <SaySomething message="starting MainTree" />
            <SubTree ID="SubTreeA" />
            <SubTree ID="SubTreeB" />
        </Sequence>
    </BehaviorTree>
<root>

To load manually the multiple files:

int main()
{
    BT::BehaviorTreeFactory factory;
    factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");

    // Register the behavior tree definitions, but don't instantiate them, yet.
    // Order is not important.
    factory.registerBehaviorTreeFromText("main_tree.xml");
    factory.registerBehaviorTreeFromText("subtree_A.xml");
    factory.registerBehaviorTreeFromText("subtree_B.xml");

    //Check that the BTs have been registered correctly
    std::cout << "Registered BehaviorTrees:" << std::endl;
    for(const std::string& bt_name: factory.registeredBehaviorTrees())
    {
        std::cout << " - " << bt_name << std::endl;
    }

    // You can create the MainTree and the subtrees will be added automatically.
    std::cout << "----- MainTree tick ----" << std::endl;
    auto main_tree = factory.createTree("MainTree");
    main_tree.tickRoot();

    // ... or you can create only one of the subtree
    std::cout << "----- SubA tick ----" << std::endl;
    auto subA_tree = factory.createTree("SubTreeA");
    subA_tree.tickRoot();

    return 0;
}
/* Expected output:

Registered BehaviorTrees:
 - MainTree
 - SubTreeA
 - SubTreeB
----- MainTree tick ----
Robot says: starting MainTree
Robot says: Executing Sub_A
Robot says: Executing Sub_B
----- SubA tick ----
Robot says: Executing Sub_A