Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 70c7715

Browse files
committed
Added SubTtreeWrapper
1 parent 9743164 commit 70c7715

File tree

6 files changed

+192
-17
lines changed

6 files changed

+192
-17
lines changed

include/behaviortree_cpp_v3/decorators/subtree_node.h

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,18 @@
66
namespace BT
77
{
88

9-
class DecoratorSubtreeNode : public DecoratorNode
9+
/**
10+
* @brief The SubtreeNode is a way to wrap an entire Subtree,
11+
* creating a separated BlackBoard.
12+
* If you want to have data flow through ports, you need to explicitly
13+
* remap the ports.
14+
*/
15+
class SubtreeNode : public DecoratorNode
1016
{
1117
public:
12-
DecoratorSubtreeNode(const std::string& name);
18+
SubtreeNode(const std::string& name);
1319

14-
virtual ~DecoratorSubtreeNode() override = default;
20+
virtual ~SubtreeNode() override = default;
1521

1622
private:
1723
virtual BT::NodeStatus tick() override;
@@ -22,6 +28,26 @@ class DecoratorSubtreeNode : public DecoratorNode
2228
}
2329
};
2430

31+
/**
32+
* @brief The TransparentSubtreeNode is a way to wrap an entire Subtree.
33+
* It does NOT have a separated BlackBoard and does not need ports remapping.
34+
*/
35+
class SubtreeWrapperNode : public DecoratorNode
36+
{
37+
public:
38+
SubtreeWrapperNode(const std::string& name);
39+
40+
virtual ~SubtreeWrapperNode() override = default;
41+
42+
private:
43+
virtual BT::NodeStatus tick() override;
44+
45+
virtual NodeType type() const override final
46+
{
47+
return NodeType::SUBTREE;
48+
}
49+
};
50+
2551

2652
}
2753

src/bt_factory.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ BehaviorTreeFactory::BehaviorTreeFactory()
4242
registerNodeType<AlwaysFailureNode>("AlwaysFailure");
4343
registerNodeType<SetBlackboard>("SetBlackboard");
4444

45-
registerNodeType<DecoratorSubtreeNode>("SubTree");
45+
registerNodeType<SubtreeNode>("SubTree");
46+
registerNodeType<SubtreeWrapperNode>("SubTreeWrapper");
4647

4748
registerNodeType<BlackboardPreconditionNode<int>>("BlackboardCheckInt");
4849
registerNodeType<BlackboardPreconditionNode<double>>("BlackboardCheckDouble");

src/decorators/subtree_node.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
11
#include "behaviortree_cpp_v3/decorators/subtree_node.h"
22

33

4-
BT::DecoratorSubtreeNode::DecoratorSubtreeNode(const std::string &name) :
4+
BT::SubtreeNode::SubtreeNode(const std::string &name) :
55
DecoratorNode(name, {} )
66
{
77
setRegistrationID("SubTree");
88
}
99

10-
BT::NodeStatus BT::DecoratorSubtreeNode::tick()
10+
BT::NodeStatus BT::SubtreeNode::tick()
11+
{
12+
NodeStatus prev_status = status();
13+
if (prev_status == NodeStatus::IDLE)
14+
{
15+
setStatus(NodeStatus::RUNNING);
16+
}
17+
return child_node_->executeTick();
18+
}
19+
20+
BT::SubtreeWrapperNode::SubtreeWrapperNode(const std::string &name) :
21+
DecoratorNode(name, {} )
22+
{
23+
setRegistrationID("TransparentSubtree");
24+
}
25+
26+
BT::NodeStatus BT::SubtreeWrapperNode::tick()
1127
{
1228
NodeStatus prev_status = status();
1329
if (prev_status == NodeStatus::IDLE)

src/xml_parsing.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ TreeNode::Ptr XMLParser::Pimpl::createNodeFromXML(const XMLElement *element,
466466
instance_name = ID;
467467
}
468468

469-
if (element_name == "SubTree")
469+
if (element_name == "SubTree" || element_name == "SubTreeWrapper" )
470470
{
471471
instance_name = element->Attribute("ID");
472472
}
@@ -579,7 +579,7 @@ TreeNode::Ptr XMLParser::Pimpl::createNodeFromXML(const XMLElement *element,
579579
child_node = factory.instantiateTreeNode(instance_name, ID, config);
580580
}
581581
else if( tree_roots.count(ID) != 0) {
582-
child_node = std::make_unique<DecoratorSubtreeNode>( instance_name );
582+
child_node = std::make_unique<SubtreeNode>( instance_name );
583583
}
584584
else{
585585
throw RuntimeError( ID, " is not a registered node, nor a Subtree");
@@ -614,15 +614,20 @@ void BT::XMLParser::Pimpl::recursivelyCreateTree(const std::string& tree_ID,
614614

615615
if( node->type() == NodeType::SUBTREE )
616616
{
617-
auto new_bb = Blackboard::create(blackboard);
618-
619-
for (const XMLAttribute* attr = element->FirstAttribute(); attr != nullptr; attr = attr->Next())
617+
if( dynamic_cast<const SubtreeNode*>(node.get()) )
620618
{
621-
new_bb->addSubtreeRemapping( attr->Name(), attr->Value() );
622-
}
619+
auto new_bb = Blackboard::create(blackboard);
623620

624-
output_tree.blackboard_stack.emplace_back(new_bb);
625-
recursivelyCreateTree( node->name(), output_tree, new_bb, node );
621+
for (const XMLAttribute* attr = element->FirstAttribute(); attr != nullptr; attr = attr->Next())
622+
{
623+
new_bb->addSubtreeRemapping( attr->Name(), attr->Value() );
624+
}
625+
output_tree.blackboard_stack.emplace_back(new_bb);
626+
recursivelyCreateTree( node->name(), output_tree, new_bb, node );
627+
}
628+
else{
629+
recursivelyCreateTree( node->name(), output_tree, blackboard, node );
630+
}
626631
}
627632
else
628633
{

tests/gtest_factory.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ TEST(BehaviorTreeFactory, Subtree)
131131
ASSERT_EQ(root_selector->child(0)->name(), "CrossDoorSubtree");
132132
ASSERT_EQ(root_selector->child(1)->name(), "PassThroughWindow");
133133

134-
auto subtree = dynamic_cast<const DecoratorSubtreeNode*>(root_selector->child(0));
134+
auto subtree = dynamic_cast<const SubtreeNode*>(root_selector->child(0));
135135
ASSERT_TRUE(subtree != nullptr);
136136

137137
auto sequence = dynamic_cast<const SequenceNode*>(subtree->child());

tests/gtest_subtree.cpp

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#include <gtest/gtest.h>
1+
#include <gtest/gtest.h>
22
#include "behaviortree_cpp_v3/bt_factory.h"
33
#include "../sample_nodes/dummy_nodes.h"
44

@@ -41,3 +41,130 @@ static const char* xml_text = R"(
4141
ASSERT_EQ(ret, NodeStatus::SUCCESS );
4242
ASSERT_EQ(tree.blackboard_stack.size(), 3 );
4343
}
44+
45+
class CopyPorts : public BT::SyncActionNode
46+
{
47+
public:
48+
CopyPorts(const std::string& name, const BT::NodeConfiguration& config)
49+
: BT::SyncActionNode(name, config)
50+
{
51+
}
52+
53+
BT::NodeStatus tick() override
54+
{
55+
auto msg = getInput<std::string>("in");
56+
if (!msg)
57+
{
58+
throw BT::RuntimeError( "missing required input [message]: ", msg.error() );
59+
}
60+
setOutput("out", msg.value());
61+
return BT::NodeStatus::SUCCESS;
62+
}
63+
64+
static BT::PortsList providedPorts()
65+
{
66+
return{ BT::InputPort<std::string>("in"),
67+
BT::OutputPort<std::string>("out")};
68+
}
69+
};
70+
71+
72+
TEST(SubTree, GoodRemapping)
73+
{
74+
static const char* xml_text = R"(
75+
76+
<root main_tree_to_execute = "MainTree" >
77+
78+
<BehaviorTree ID="MainTree">
79+
<Sequence>
80+
<SetBlackboard value="hello" output_key="thoughts" />
81+
<SubTree ID="CopySubtree" in_arg="thoughts" out_arg="greetings"/>
82+
<SaySomething message="{greetings}" />
83+
</Sequence>
84+
</BehaviorTree>
85+
86+
<BehaviorTree ID="CopySubtree">
87+
<CopyPorts in="{in_arg}" out="{out_arg}"/>
88+
</BehaviorTree>
89+
</root> )";
90+
91+
BehaviorTreeFactory factory;
92+
factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
93+
factory.registerNodeType<CopyPorts>("CopyPorts");
94+
95+
Tree tree = factory.createTreeFromText(xml_text);
96+
auto ret = tree.root_node->executeTick();
97+
ASSERT_EQ(ret, NodeStatus::SUCCESS );
98+
}
99+
100+
TEST(SubTree, BadRemapping)
101+
{
102+
BehaviorTreeFactory factory;
103+
factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
104+
factory.registerNodeType<CopyPorts>("CopyPorts");
105+
106+
static const char* xml_text_bad_in = R"(
107+
<root main_tree_to_execute = "MainTree" >
108+
109+
<BehaviorTree ID="MainTree">
110+
<Sequence>
111+
<SetBlackboard value="hello" output_key="thoughts" />
112+
<SubTree ID="CopySubtree" out_arg="greetings"/>
113+
<SaySomething message="{greetings}" />
114+
</Sequence>
115+
</BehaviorTree>
116+
117+
<BehaviorTree ID="CopySubtree">
118+
<CopyPorts in="{in_arg}" out="{out_arg}"/>
119+
</BehaviorTree>
120+
</root> )";
121+
122+
Tree tree_bad_in = factory.createTreeFromText(xml_text_bad_in);
123+
EXPECT_ANY_THROW( tree_bad_in.root_node->executeTick() );
124+
125+
static const char* xml_text_bad_out = R"(
126+
<root main_tree_to_execute = "MainTree" >
127+
128+
<BehaviorTree ID="MainTree">
129+
<Sequence>
130+
<SetBlackboard value="hello" output_key="thoughts" />
131+
<SubTree ID="CopySubtree" in_arg="thoughts"/>
132+
<SaySomething message="{greetings}" />
133+
</Sequence>
134+
</BehaviorTree>
135+
136+
<BehaviorTree ID="CopySubtree">
137+
<CopyPorts in="{in_arg}" out="{out_arg}"/>
138+
</BehaviorTree>
139+
</root> )";
140+
141+
Tree tree_bad_out = factory.createTreeFromText(xml_text_bad_out);
142+
EXPECT_ANY_THROW( tree_bad_out.root_node->executeTick() );
143+
}
144+
145+
TEST(SubTree, SubtreeWrapper)
146+
{
147+
BehaviorTreeFactory factory;
148+
factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
149+
factory.registerNodeType<CopyPorts>("CopyPorts");
150+
151+
static const char* xml_text = R"(
152+
<root main_tree_to_execute = "MainTree" >
153+
154+
<BehaviorTree ID="MainTree">
155+
<Sequence>
156+
<SetBlackboard value="hello" output_key="thoughts" />
157+
<SubTreeWrapper ID="CopySubtree" />
158+
<SaySomething message="{greetings}" />
159+
</Sequence>
160+
</BehaviorTree>
161+
162+
<BehaviorTree ID="CopySubtree">
163+
<CopyPorts in="{thoughts}" out="{greetings}"/>
164+
</BehaviorTree>
165+
</root> )";
166+
167+
Tree tree = factory.createTreeFromText(xml_text);
168+
auto ret = tree.root_node->executeTick();
169+
ASSERT_EQ(ret, NodeStatus::SUCCESS );
170+
}

0 commit comments

Comments
 (0)