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

Skip to content

Commit c937839

Browse files
Merge pull request BehaviorTree#37 from BehaviorTree/issue_33
Merging branch related to issue BehaviorTree#33: add TreeNode::onInit
2 parents fb8c965 + 18f43ce commit c937839

File tree

12 files changed

+203
-82
lines changed

12 files changed

+203
-82
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ set(BT_TESTS
166166
gtest/gtest_fallback.cpp
167167
gtest/gtest_factory.cpp
168168
gtest/gtest_decorator.cpp
169+
gtest/gtest_blackboard.cpp
169170
)
170171

171172
if(ament_cmake_FOUND AND BUILD_TESTING)

gtest/gtest_blackboard.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/* Copyright (C) 2018 Davide Faconti - All Rights Reserved
2+
*
3+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
4+
* to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
5+
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7+
*
8+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
10+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11+
*/
12+
13+
#include <gtest/gtest.h>
14+
#include "action_test_node.h"
15+
#include "condition_test_node.h"
16+
#include "behaviortree_cpp/behavior_tree.h"
17+
#include "behaviortree_cpp/blackboard/blackboard_local.h"
18+
19+
using namespace BT;
20+
21+
class InitTestNode: public ActionNodeBase
22+
{
23+
public:
24+
InitTestNode(bool try_to_access_bb, const std::string& name):
25+
ActionNodeBase(name),
26+
_value(0)
27+
{
28+
if( try_to_access_bb )
29+
{
30+
// this should throw
31+
blackboard()->set(KEY(), 33);
32+
}
33+
}
34+
35+
void onInit() {
36+
blackboard()->get(KEY(), _value);
37+
}
38+
void halt() {}
39+
40+
NodeStatus tick()
41+
{
42+
_value *= 2;
43+
blackboard()->set(KEY(), _value);
44+
return NodeStatus::SUCCESS;
45+
}
46+
47+
static const char* KEY() { return "my_entry"; }
48+
49+
private:
50+
int _value;
51+
};
52+
53+
54+
55+
56+
/****************TESTS START HERE***************************/
57+
58+
TEST(BlackboardTest, CheckOInit)
59+
{
60+
auto bb = Blackboard::create<BlackboardLocal>();
61+
const auto KEY = InitTestNode::KEY();
62+
63+
EXPECT_THROW( InitTestNode(true,"init_test"), std::logic_error );
64+
65+
InitTestNode node(false,"init_test");
66+
node.setBlackboard(bb);
67+
68+
bb->set(KEY, 11 );
69+
70+
// this should read and write "my_entry", respectively in onInit() and tick()
71+
node.executeTick();
72+
73+
ASSERT_EQ( bb->get<int>(KEY), 22 );
74+
75+
// check that onInit is executed only once
76+
bb->set(KEY, 1 );
77+
78+
// since this value is read in OnInit(), the node will not notice the change in bb
79+
node.setStatus( NodeStatus::IDLE );
80+
node.executeTick();
81+
ASSERT_EQ( bb->get<int>(KEY), 44 );
82+
}

gtest/gtest_factory.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ TEST(BehaviorTreeFactory, VerifyLargeTree)
8787

8888
std::vector<BT::TreeNode::Ptr> nodes;
8989

90-
BT::TreeNode::Ptr root_node = parser.instantiateTree(nodes);
90+
BT::TreeNode::Ptr root_node = parser.instantiateTree(nodes, Blackboard::Ptr());
9191

9292
BT::printTreeRecursively(root_node.get());
9393

@@ -133,7 +133,7 @@ TEST(BehaviorTreeFactory, Subtree)
133133

134134
std::vector<BT::TreeNode::Ptr> nodes;
135135

136-
BT::TreeNode::Ptr root_node = parser.instantiateTree(nodes);
136+
BT::TreeNode::Ptr root_node = parser.instantiateTree(nodes, Blackboard::Ptr());
137137
BT::printTreeRecursively(root_node.get());
138138

139139
ASSERT_EQ(root_node->name(), "root_selector");

gtest/include/action_test_node.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class SyncActionTest : public ActionNodeBase
3333
int tick_count_;
3434
};
3535

36-
class AsyncActionTest : public ActionNode
36+
class AsyncActionTest : public AsyncActionNode
3737
{
3838
public:
3939
AsyncActionTest(const std::string& name);

include/behaviortree_cpp/action_node.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@
1919

2020
namespace BT
2121
{
22+
/** IMPORTANT: to avoid unexpected behaviors when Sequence (not SequenceStar) is used
23+
* an Action that returned SUCCESS or FAILURE will not be ticked again unless
24+
* setStatus(IDLE) is called first (reset the Action).
25+
*
26+
* Usually the parent node takes care of this for you.
27+
*/
28+
29+
2230
class ActionNodeBase : public LeafNode
2331
{
2432
public:

include/behaviortree_cpp/bt_factory.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ class BehaviorTreeFactory
8484
* @return new node.
8585
*/
8686
std::unique_ptr<TreeNode> instantiateTreeNode(const std::string& ID, const std::string& name,
87-
const NodeParameters& params) const;
87+
const NodeParameters& params,
88+
const Blackboard::Ptr& blackboard) const;
8889

8990
/** registerNodeType is the method to use to register your custom TreeNode.
9091
*

include/behaviortree_cpp/tree_node.h

Lines changed: 73 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ typedef std::chrono::high_resolution_clock::duration Duration;
3838
// Abstract base class for Behavior Tree Nodes
3939
class TreeNode
4040
{
41+
42+
private:
43+
44+
/// This calback will be executed only ONCE after the constructor of the node,
45+
/// before the very first tick.
46+
/// Override if necessary.
47+
virtual void onInit() {}
48+
4149
public:
4250
/**
4351
* @brief TreeNode main constructor.
@@ -103,77 +111,22 @@ class TreeNode
103111
/// creation of the TreeNode instance.
104112
const NodeParameters& initializationParameters() const;
105113

106-
/** Get a parameter from the passed NodeParameters and convert it to type T.
114+
/** Get a parameter from the NodeParameters and convert it to type T.
107115
*/
108116
template <typename T>
109117
BT::optional<T> getParam(const std::string& key) const
110118
{
111119
T out;
112-
if (getParam(key, out))
113-
{
114-
return std::move(out);
115-
}
116-
else
117-
{
118-
return BT::nullopt;
119-
}
120+
return getParam(key, out) ? std::move(out) : BT::nullopt;
120121
}
121122

122123
/** Get a parameter from the passed NodeParameters and convert it to type T.
123-
*
124-
* return false either if there is no parameter with this key or if conversion failed.
124+
* Return false either if there is no parameter with this key or if conversion failed.
125125
*/
126126
template <typename T>
127-
bool getParam(const std::string& key, T& destination) const
128-
{
129-
auto it = parameters_.find(key);
130-
if (it == parameters_.end())
131-
{
132-
return false;
133-
}
134-
const std::string& str = it->second;
127+
bool getParam(const std::string& key, T& destination) const;
135128

136-
try
137-
{
138-
bool bb_pattern = isBlackboardPattern(str);
139-
if( bb_pattern && just_constructed_)
140-
{
141-
std::cerr << "You are calling getParam inside a constructor, but this is not allowed "
142-
"when the parameter contains a blackboard.\n"
143-
"You should call getParam inside your tick() method"<< std::endl;
144-
std::logic_error("Calling getParam inside a constructor");
145-
}
146-
// check if it follows this ${pattern}, if it does, search inside the blackboard
147-
if ( bb_ && bb_pattern)
148-
{
149-
const std::string stripped_key(&str[2], str.size() - 3);
150-
const SafeAny::Any* val = bb_->getAny(stripped_key);
151-
152-
if( val )
153-
{
154-
if( std::is_same<T,std::string>::value == false &&
155-
(val->type() == typeid (std::string) ||
156-
val->type() == typeid (SafeAny::SimpleString)))
157-
{
158-
destination = convertFromString<T>(val->cast<std::string>());
159-
}
160-
else{
161-
destination = val->cast<T>();
162-
}
163-
}
164-
return val != nullptr;
165-
}
166-
else{
167-
destination = convertFromString<T>(str.c_str());
168-
return true;
169-
}
170-
}
171-
catch (std::runtime_error& err)
172-
{
173-
std::cout << "Exception at getParam(" << key << "): " << err.what() << std::endl;
174-
return false;
175-
}
176-
}
129+
static bool isBlackboardPattern(StringView str);
177130

178131
protected:
179132
/// Method to be implemented by the user
@@ -184,9 +137,12 @@ class TreeNode
184137

185138
friend class BehaviorTreeFactory;
186139

187-
bool just_constructed_;
140+
void initializeOnce();
188141

189142
private:
143+
144+
bool not_initialized_;
145+
190146
const std::string name_;
191147

192148
NodeStatus status_;
@@ -205,10 +161,63 @@ class TreeNode
205161

206162
Blackboard::Ptr bb_;
207163

208-
209-
protected:
210-
static bool isBlackboardPattern(const std::string& str );
211164
};
165+
166+
//-------------------------------------------------------
167+
168+
169+
template <typename T> inline
170+
bool TreeNode::getParam(const std::string& key, T& destination) const
171+
{
172+
auto it = parameters_.find(key);
173+
if (it == parameters_.end())
174+
{
175+
return false;
176+
}
177+
const std::string& str = it->second;
178+
179+
try
180+
{
181+
bool bb_pattern = isBlackboardPattern(str);
182+
if( bb_pattern && not_initialized_)
183+
{
184+
std::cerr << "you are calling getParam inside a constructor, but this is not allowed "
185+
"when the parameter contains a blackboard.\n"
186+
"You should call getParam inside your tick() method"<< std::endl;
187+
std::logic_error("Calling getParam inside a constructor");
188+
}
189+
// check if it follows this ${pattern}, if it does, search inside the blackboard
190+
if ( bb_pattern && blackboard() )
191+
{
192+
const std::string stripped_key(&str[2], str.size() - 3);
193+
const SafeAny::Any* val = blackboard()->getAny(stripped_key);
194+
if( val )
195+
{
196+
if( std::is_same<T,std::string>::value == false &&
197+
(val->type() == typeid (std::string) ||
198+
val->type() == typeid (SafeAny::SimpleString)))
199+
{
200+
destination = convertFromString<T>(val->cast<std::string>());
201+
}
202+
else{
203+
destination = val->cast<T>();
204+
}
205+
}
206+
return val != nullptr;
207+
}
208+
else{
209+
destination = convertFromString<T>(str.c_str());
210+
return true;
211+
}
212+
}
213+
catch (std::runtime_error& err)
214+
{
215+
std::cout << "Exception at getParam(" << key << "): " << err.what() << std::endl;
216+
return false;
217+
}
218+
}
219+
220+
212221
}
213222

214223
#endif

include/behaviortree_cpp/xml_parsing.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class XMLParser
2222
using NodeBuilder = std::function<TreeNode::Ptr(const std::string&, const std::string&,
2323
const NodeParameters&, TreeNode::Ptr)>;
2424

25-
TreeNode::Ptr instantiateTree(std::vector<TreeNode::Ptr>& nodes);
25+
TreeNode::Ptr instantiateTree(std::vector<TreeNode::Ptr>& nodes, const Blackboard::Ptr &blackboard);
2626

2727
private:
2828

src/action_node.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ ActionNodeBase::ActionNodeBase(const std::string& name, const NodeParameters& pa
2323

2424
NodeStatus ActionNodeBase::executeTick()
2525
{
26-
just_constructed_ = false;
26+
initializeOnce();
2727
NodeStatus prev_status = status();
2828

2929
if (prev_status == NodeStatus::IDLE || prev_status == NodeStatus::RUNNING)
@@ -94,8 +94,7 @@ void AsyncActionNode::waitForTick()
9494

9595
NodeStatus AsyncActionNode::executeTick()
9696
{
97-
just_constructed_ = false;
98-
97+
initializeOnce();
9998
//send signal to other thread.
10099
// The other thread is in charge for changing the status
101100
if (status() == NodeStatus::IDLE)
@@ -146,6 +145,7 @@ void CoroActionNode::setStatusRunningAndYield()
146145

147146
NodeStatus CoroActionNode::executeTick()
148147
{
148+
initializeOnce();
149149
if (status() == NodeStatus::IDLE)
150150
{
151151
_p->coro = coroutine::create( [this]() { setStatus(tick()); } );

src/bt_factory.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,9 @@ void BehaviorTreeFactory::registerFromPlugin(const std::string file_path)
123123
}
124124

125125
std::unique_ptr<TreeNode> BehaviorTreeFactory::instantiateTreeNode(
126-
const std::string& ID, const std::string& name, const NodeParameters& params) const
126+
const std::string& ID, const std::string& name,
127+
const NodeParameters& params,
128+
const Blackboard::Ptr& blackboard) const
127129
{
128130
auto it = builders_.find(ID);
129131
if (it == builders_.end())
@@ -137,6 +139,9 @@ std::unique_ptr<TreeNode> BehaviorTreeFactory::instantiateTreeNode(
137139
}
138140
std::unique_ptr<TreeNode> node = it->second(name, params);
139141
node->setRegistrationName(ID);
142+
node->setBlackboard(blackboard);
143+
node->initializeOnce();
144+
140145
return node;
141146
}
142147

0 commit comments

Comments
 (0)