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

Skip to content

Commit 15816fe

Browse files
New SubTreePlus
1 parent aeb0d64 commit 15816fe

File tree

7 files changed

+127
-29
lines changed

7 files changed

+127
-29
lines changed

include/behaviortree_cpp_v3/behavior_tree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ inline NodeType getType()
7878
if( std::is_base_of<ActionNodeBase, T>::value ) return NodeType::ACTION;
7979
if( std::is_base_of<ConditionNode, T>::value ) return NodeType::CONDITION;
8080
if( std::is_base_of<SubtreeNode, T>::value ) return NodeType::SUBTREE;
81-
if( std::is_base_of<SubtreeWrapperNode, T>::value ) return NodeType::SUBTREE;
81+
if( std::is_base_of<SubtreePlusNode, T>::value ) return NodeType::SUBTREE;
8282
if( std::is_base_of<DecoratorNode, T>::value ) return NodeType::DECORATOR;
8383
if( std::is_base_of<ControlNode, T>::value ) return NodeType::CONTROL;
8484
return NodeType::UNDEFINED;

include/behaviortree_cpp_v3/decorators/subtree_node.h

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,51 @@ class SubtreeNode : public DecoratorNode
2929
};
3030

3131
/**
32-
* @brief The SubtreeWrapperNode is a way to wrap an entire Subtree.
33-
* It does NOT have a separated BlackBoard and does not need ports remapping.
32+
* @brief The SubtreePlus is a new kind of subtree that gives you much more control over remapping:
33+
*
34+
* Consider this example:
35+
36+
<root main_tree_to_execute = "MainTree" >
37+
38+
<BehaviorTree ID="MainTree">
39+
<Sequence>
40+
41+
<SetBlackboard value="Hello" output_key="myParam" />
42+
<SubTreePlus ID="Talk" param="{myParam}" />
43+
44+
<SubTreePlus ID="Talk" param="World" />
45+
46+
<SetBlackboard value="Auto remapped" output_key="param" />
47+
<SubTreePlus ID="Talk" __autoremap="1" />
48+
49+
</Sequence>
50+
</BehaviorTree>
51+
52+
<BehaviorTree ID="Talk">
53+
<SaySomething message="{param}" />
54+
</BehaviorTree>
55+
</root>
56+
57+
* You may notice three different approaches to remapping:
58+
*
59+
* 1) Subtree: "{param}" -> Parent: "{myParam}" -> Value: "Hello"
60+
* Classical remapping from one port to another, but you need to use the syntax
61+
* {myParam} to say that you are remapping the another port.
62+
*
63+
* 2) Subtree: "{param}" -> Value: "World"
64+
* syntax without {}, in this case param directly point to the string "World".
65+
*
66+
* 3) Subtree: "{param}" -> Parent: "{parent}"
67+
* Setting to true (or 1) the attribute "__autoremap", we are automatically remapping
68+
* each port. Usefull to avoid some boilerplate.
69+
3470
*/
35-
class SubtreeWrapperNode : public DecoratorNode
71+
class SubtreePlusNode : public DecoratorNode
3672
{
3773
public:
38-
SubtreeWrapperNode(const std::string& name);
74+
SubtreePlusNode(const std::string& name);
3975

40-
virtual ~SubtreeWrapperNode() override = default;
76+
virtual ~SubtreePlusNode() override = default;
4177

4278
private:
4379
virtual BT::NodeStatus tick() override;
@@ -49,6 +85,7 @@ class SubtreeWrapperNode : public DecoratorNode
4985
};
5086

5187

88+
5289
}
5390

5491
#endif // DECORATOR_SUBTREE_NODE_H

src/basic_types.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ NodeType convertFromString<NodeType>(StringView str)
208208
if( str == "Condition" ) return NodeType::CONDITION;
209209
if( str == "Control" ) return NodeType::CONTROL;
210210
if( str == "Decorator" ) return NodeType::DECORATOR;
211-
if( str == "SubTree" || str == "SubtreeWrapper" ) return NodeType::SUBTREE;
211+
if( str == "SubTree" || str == "SubTreePlus" ) return NodeType::SUBTREE;
212212
return NodeType::UNDEFINED;
213213
}
214214

src/bt_factory.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ BehaviorTreeFactory::BehaviorTreeFactory()
4343
registerNodeType<SetBlackboard>("SetBlackboard");
4444

4545
registerNodeType<SubtreeNode>("SubTree");
46-
registerNodeType<SubtreeWrapperNode>("SubTreeWrapper");
46+
registerNodeType<SubtreePlusNode>("SubTreePlus");
4747

4848
registerNodeType<BlackboardPreconditionNode<int>>("BlackboardCheckInt");
4949
registerNodeType<BlackboardPreconditionNode<double>>("BlackboardCheckDouble");

src/decorators/subtree_node.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ BT::NodeStatus BT::SubtreeNode::tick()
1717
return child_node_->executeTick();
1818
}
1919

20-
BT::SubtreeWrapperNode::SubtreeWrapperNode(const std::string &name) :
20+
//--------------------------------
21+
BT::SubtreePlusNode::SubtreePlusNode(const std::string &name) :
2122
DecoratorNode(name, {} )
2223
{
23-
setRegistrationID("SubtreeWrapper");
24+
setRegistrationID("SubTreePlus");
2425
}
2526

26-
BT::NodeStatus BT::SubtreeWrapperNode::tick()
27+
BT::NodeStatus BT::SubtreePlusNode::tick()
2728
{
2829
NodeStatus prev_status = status();
2930
if (prev_status == NodeStatus::IDLE)

src/xml_parsing.cpp

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -462,14 +462,16 @@ TreeNode::Ptr XMLParser::Pimpl::createNodeFromXML(const XMLElement *element,
462462
instance_name = ID;
463463
}
464464

465-
if (element_name == "SubTree" || element_name == "SubTreeWrapper" )
465+
if (element_name == "SubTree" ||
466+
element_name == "SubTreePlus" )
466467
{
467468
instance_name = element->Attribute("ID");
468469
}
469470

470471
PortsRemapping parameters_map;
471472

472-
if (element_name != "SubTree") // in Subtree attributes have different meaning...
473+
// in Subtree attributes have different meaning...
474+
if (element_name != "SubTree" && element_name != "SubTreePlus")
473475
{
474476
for (const XMLAttribute* att = element->FirstAttribute(); att; att = att->Next())
475477
{
@@ -612,18 +614,69 @@ void BT::XMLParser::Pimpl::recursivelyCreateTree(const std::string& tree_ID,
612614
{
613615
if( dynamic_cast<const SubtreeNode*>(node.get()) )
614616
{
617+
// This is the former SubTree with manual remapping
615618
auto new_bb = Blackboard::create(blackboard);
616619

617620
for (const XMLAttribute* attr = element->FirstAttribute(); attr != nullptr; attr = attr->Next())
618621
{
622+
if( strcmp(attr->Name(), "ID") == 0 )
623+
{
624+
continue;
625+
}
619626
new_bb->addSubtreeRemapping( attr->Name(), attr->Value() );
620627
}
621628
output_tree.blackboard_stack.emplace_back(new_bb);
622629
recursivelyCreateTree( node->name(), output_tree, new_bb, node );
623630
}
624-
else{
625-
recursivelyCreateTree( node->name(), output_tree, blackboard, node );
626-
}
631+
else if( dynamic_cast<const SubtreePlusNode*>(node.get()) )
632+
{
633+
auto new_bb = Blackboard::create(blackboard);
634+
output_tree.blackboard_stack.emplace_back(new_bb);
635+
std::set<StringView> mapped_keys;
636+
637+
bool do_autoremap = false;
638+
639+
for (const XMLAttribute* attr = element->FirstAttribute(); attr != nullptr; attr = attr->Next())
640+
{
641+
if( strcmp(attr->Name(), "ID") == 0 )
642+
{
643+
continue;
644+
}
645+
if( strcmp(attr->Name(), "__autoremap") == 0 )
646+
{
647+
if( convertFromString<bool>(attr->Value()) )
648+
{
649+
do_autoremap = true;
650+
}
651+
continue;
652+
}
653+
654+
StringView str = attr->Value();
655+
if( TreeNode::isBlackboardPointer(str))
656+
{
657+
StringView port_name = TreeNode::stripBlackboardPointer(str);
658+
new_bb->addSubtreeRemapping( attr->Name(), port_name);
659+
mapped_keys.insert(port_name.to_string());
660+
}
661+
else{
662+
new_bb->set(attr->Name(), std::string(attr->Value()) );
663+
mapped_keys.insert(attr->Value());
664+
}
665+
}
666+
recursivelyCreateTree( node->name(), output_tree, new_bb, node );
667+
668+
if( do_autoremap )
669+
{
670+
auto keys = new_bb->getKeys();
671+
for( StringView key: keys)
672+
{
673+
if( mapped_keys.count(key) == 0)
674+
{
675+
new_bb->addSubtreeRemapping( key, key );
676+
}
677+
}
678+
}
679+
}
627680
}
628681
else
629682
{

tests/gtest_subtree.cpp

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -142,29 +142,36 @@ TEST(SubTree, BadRemapping)
142142
EXPECT_ANY_THROW( tree_bad_out.tickRoot() );
143143
}
144144

145-
TEST(SubTree, SubtreeWrapper)
145+
TEST(SubTree, SubtreePlus)
146146
{
147-
BehaviorTreeFactory factory;
148-
factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
149-
factory.registerNodeType<CopyPorts>("CopyPorts");
147+
static const char* xml_text = R"(
150148
151-
static const char* xml_text = R"(
152149
<root main_tree_to_execute = "MainTree" >
153150
154151
<BehaviorTree ID="MainTree">
155152
<Sequence>
156-
<SetBlackboard value="hello" output_key="thoughts" />
157-
<SubTreeWrapper ID="CopySubtree" />
158-
<SaySomething message="{greetings}" />
153+
<SetBlackboard value="Hello" output_key="myParam" />
154+
155+
<SubTreePlus ID="mySubtree" param="{myParam}" />
156+
157+
<SubTreePlus ID="mySubtree" param="World" />
158+
159+
<SetBlackboard value="Auto remapped" output_key="param" />
160+
<SubTreePlus ID="mySubtree" __autoremap="1" />
159161
</Sequence>
160162
</BehaviorTree>
161163
162-
<BehaviorTree ID="CopySubtree">
163-
<CopyPorts in="{thoughts}" out="{greetings}"/>
164+
<BehaviorTree ID="mySubtree">
165+
<SaySomething message="{param}" />
164166
</BehaviorTree>
165167
</root> )";
166168

167-
Tree tree = factory.createTreeFromText(xml_text);
168-
auto ret = tree.tickRoot();
169-
ASSERT_EQ(ret, NodeStatus::SUCCESS );
169+
BehaviorTreeFactory factory;
170+
factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
171+
172+
Tree tree = factory.createTreeFromText(xml_text);
173+
auto ret = tree.tickRoot();
174+
ASSERT_EQ(ret, NodeStatus::SUCCESS );
170175
}
176+
177+

0 commit comments

Comments
 (0)