Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions include/behaviortree_cpp_v3/bt_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,11 +368,33 @@ class BehaviorTreeFactory
/// List of builtin IDs.
const std::set<std::string>& builtinNodes() const;

/**
* @brief Creates a tree from the xml description in a file.
* @param[in] text String with the xml description of the tree.
* @param[in] blackboard Root blackboard, used by the root of the tree. Defaults to creating a new one.
* @param[in] root_subtree_id Id of the subtree used as the root to build the tree from. Defaults to empty,
* which causes the default root discovery algorithm to be used.
* @param[in] mock_subtrees Replaces subtree instantiations with a special node that can be configured
* to call mock callbacks for testing.
*/
Tree createTreeFromText(const std::string& text,
Blackboard::Ptr blackboard = Blackboard::create());

Blackboard::Ptr blackboard = Blackboard::create(),
const std::string &root_subtree_id = "",
const bool mock_subtrees = false);

/**
* @brief Creates a tree from the xml description in a file.
* @param[in] file_path Path to the file containing the xml description of the tree.
* @param[in] blackboard Root blackboard, used by the root of the tree. Defaults to creating a new one.
* @param[in] root_subtree_id Id of the subtree used as the root to build the tree from. Defaults to empty,
* which causes the default root discovery algorithm to be used.
* @param[in] mock_subtrees Replaces subtree instantiations with a special node that can be configured
* to call mock callbacks for testing.
*/
Tree createTreeFromFile(const std::string& file_path,
Blackboard::Ptr blackboard = Blackboard::create());
Blackboard::Ptr blackboard = Blackboard::create(),
const std::string &root_subtree_id = "",
const bool mock_subtrees = false);

private:
std::unordered_map<std::string, NodeBuilder> builders_;
Expand Down
12 changes: 11 additions & 1 deletion include/behaviortree_cpp_v3/bt_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,17 @@ class Parser

virtual void loadFromText(const std::string& xml_text) = 0;

virtual Tree instantiateTree(const Blackboard::Ptr &root_blackboard) = 0;
/**
* @brief Instantiates a BehaviorTreee from the source, using a given blackboard and given root subtree.
* @param[in] root_blackboard Root blackboard, used by the root of the tree.
* @param[in] root_subtree_id Id of the subtree used as the root to build the tree from. Defaults to empty,
* which causes the default root discovery algorithm to be used.
* @param[in] mock_subtrees Replaces subtree instantiations with a special node that can be configured
* to call mock callbacks for testing.
*/
virtual Tree instantiateTree(const Blackboard::Ptr &root_blackboard,
const std::string &root_subtree = "",
const bool mock_subtrees = false) = 0;
};

}
Expand Down
16 changes: 8 additions & 8 deletions include/behaviortree_cpp_v3/decorators/subtree_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@ namespace BT
class SubtreeNode : public DecoratorNode
{
public:
SubtreeNode(const std::string& name);
SubtreeNode(const std::string& name, const NodeConfiguration& config);

virtual ~SubtreeNode() override = default;

private:
virtual BT::NodeStatus tick() override;

static PortsList providedPorts()
{
return { InputPort<bool>("__shared_blackboard", false,
"If false (default) the subtree has its own blackboard and you"
"need to do port remapping to connect it to the parent") };
}

private:
virtual BT::NodeStatus tick() override;

virtual NodeType type() const override final
{
return NodeType::SUBTREE;
Expand Down Expand Up @@ -80,19 +80,19 @@ class SubtreeNode : public DecoratorNode
class SubtreePlusNode : public DecoratorNode
{
public:
SubtreePlusNode(const std::string& name);
SubtreePlusNode(const std::string& name, const NodeConfiguration& config);

virtual ~SubtreePlusNode() override = default;

private:
virtual BT::NodeStatus tick() override;

static PortsList providedPorts()
{
return { InputPort<bool>("__autoremap", false,
"If true, all the ports with the same name will be remapped") };
}

private:
virtual BT::NodeStatus tick() override;

virtual NodeType type() const override final
{
return NodeType::SUBTREE;
Expand Down
78 changes: 78 additions & 0 deletions include/behaviortree_cpp_v3/decorators/subtreemock_node.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#ifndef ACTION_SUBTREEMOCK_NODE_H
#define ACTION_SUBTREEMOCK_NODE_H

#include "behaviortree_cpp_v3/action_node.h"

#include <functional>
#include <string>

namespace BT
{
/**
* @brief SubtreeMockBlackboardProxy is a wrapper class that provided limited access to
* the blackboard to mocked nodes. The mock callback receives modifiable reference to
* a SubtreeMockBlackboardProxy instance that can be used to access the
* BT blackboard.
*/
class SubtreeMockBlackboardProxy
{
public:
explicit SubtreeMockBlackboardProxy(TreeNode* mock_node) : mock_node_{mock_node}
{
}

// thou shall not propagate or store this object
SubtreeMockBlackboardProxy(const SubtreeMockBlackboardProxy&) = delete;
SubtreeMockBlackboardProxy(SubtreeMockBlackboardProxy&&) = delete;

template <typename T>
Result getInput(const std::string& key, T& destination) const
{
return mock_node_->getInput<T>(key, destination);
}

template <typename T>
Optional<T> getInput(const std::string& key) const
{
return mock_node_->getInput<T>(key);
}

template <typename T>
Result setOutput(const std::string& key, const T& value)
{
return mock_node_->setOutput<T>(key, value);
}

private:
TreeNode* mock_node_;
};

/**
* @brief The SubtreeMockNode is a node that replaces a whole subtree, allowing to replace its
* execution with the execution of a standin callback function. This allows mocking subtrees
* to simplify the testing of large behavior trees.
*/
class SubtreeMockNode : public SyncActionNode
{
public:
using CallbackFunction = std::function<BT::NodeStatus(SubtreeMockBlackboardProxy& proxy)>;

SubtreeMockNode(const std::string& name, const NodeConfiguration& config,
const CallbackFunction& callback)
: SyncActionNode{name, config}, callback_{callback}
{
}

private:
CallbackFunction callback_;

BT::NodeStatus tick() override
{
SubtreeMockBlackboardProxy bp(this);
return callback_(bp);
}
};

} // namespace BT

#endif // ACTION_SUBTREEMOCK_NODE_H
12 changes: 11 additions & 1 deletion include/behaviortree_cpp_v3/xml_parsing.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,17 @@ class XMLParser: public Parser

void loadFromText(const std::string& xml_text) override;

Tree instantiateTree(const Blackboard::Ptr &root_blackboard) override;
/**
* @brief Instantiates a BehaviorTreee from the source, using a given blackboard and given root subtree.
* @param[in] root_blackboard Root blackboard, used by the root of the tree.
* @param[in] root_subtree_id Id of the subtree used as the root to build the tree from. If left empty
* the default root discovery algorithm to be used.
* @param[in] mock_subtrees Replaces subtree instantiations with a special node that can be configured
* to call mock callbacks for testing.
*/
Tree instantiateTree(const Blackboard::Ptr& root_blackboard,
const std::string& root_subtree,
const bool mock_subtrees) override;

private:

Expand Down
19 changes: 15 additions & 4 deletions src/bt_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ BehaviorTreeFactory::BehaviorTreeFactory()
{
builtin_IDs_.insert( it.first );
}

// Register the SubtreeMock node as builtin to disallow unregistering it.
builtin_IDs_.insert("SubtreeMock");
}

bool BehaviorTreeFactory::unregisterBuilder(const std::string& ID)
Expand Down Expand Up @@ -248,21 +251,29 @@ const std::set<std::string> &BehaviorTreeFactory::builtinNodes() const
}

Tree BehaviorTreeFactory::createTreeFromText(const std::string &text,
Blackboard::Ptr blackboard)
Blackboard::Ptr blackboard,
const std::string &root_subtree_id,
const bool mock_subtrees)
{
if (mock_subtrees && (builders_.count("SubtreeMock") == 0)) {
throw RuntimeError("mock_subtrees is true but not SubtreeMock node has been registered "
"with the mock callbacks");
}
XMLParser parser(*this);
parser.loadFromText(text);
auto tree = parser.instantiateTree(blackboard);
auto tree = parser.instantiateTree(blackboard, root_subtree_id, mock_subtrees);
tree.manifests = this->manifests();
return tree;
}

Tree BehaviorTreeFactory::createTreeFromFile(const std::string &file_path,
Blackboard::Ptr blackboard)
Blackboard::Ptr blackboard,
const std::string &root_subtree_id,
const bool mock_subtrees)
{
XMLParser parser(*this);
parser.loadFromFile(file_path);
auto tree = parser.instantiateTree(blackboard);
auto tree = parser.instantiateTree(blackboard, root_subtree_id, mock_subtrees);
tree.manifests = this->manifests();
return tree;
}
Expand Down
8 changes: 4 additions & 4 deletions src/decorators/subtree_node.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#include "behaviortree_cpp_v3/decorators/subtree_node.h"


BT::SubtreeNode::SubtreeNode(const std::string &name) :
DecoratorNode(name, {} )
BT::SubtreeNode::SubtreeNode(const std::string& name, const NodeConfiguration& config) :
DecoratorNode(name, config)
{
setRegistrationID("SubTree");
}
Expand All @@ -19,8 +19,8 @@ BT::NodeStatus BT::SubtreeNode::tick()


//--------------------------------
BT::SubtreePlusNode::SubtreePlusNode(const std::string &name) :
DecoratorNode(name, {} )
BT::SubtreePlusNode::SubtreePlusNode(const std::string& name, const NodeConfiguration& config) :
DecoratorNode(name, config)
{
setRegistrationID("SubTreePlus");
}
Expand Down
Loading