gtest_reactive_backchaining.cpp
Go to the documentation of this file.
1 #include <gtest/gtest.h>
4 
5 namespace BT::test
6 {
7 
9 {
10 private:
11  std::string port_name_;
12 
13 public:
14  SimpleCondition(const std::string& name, const BT::NodeConfig& config,
15  std::string port_name)
16  : BT::ConditionNode(name, config), port_name_(port_name)
17  {}
19  {
20  return {};
21  }
22  BT::NodeStatus tick() override
23  {
24  auto val = config().blackboard->get<bool>(port_name_);
26  }
27 };
28 
29 //--------------------------
31 {
32  int counter_ = 0;
33  std::string port_name_;
34 
35 public:
36  AsyncTestAction(const std::string& name, const BT::NodeConfig& config,
37  std::string port_name)
38  : BT::StatefulActionNode(name, config), port_name_(port_name)
39  {}
40 
42  {
43  return {};
44  }
45 
46  NodeStatus onStart() override
47  {
48  counter_ = 0;
49  return NodeStatus::RUNNING;
50  }
51 
52  NodeStatus onRunning() override
53  {
54  if(++counter_ == 2)
55  {
56  config().blackboard->set<bool>(port_name_, true);
57  return NodeStatus::SUCCESS;
58  }
59  return NodeStatus::RUNNING;
60  }
61  void onHalted() override
62  {}
63 };
64 //--------------------------
65 
66 TEST(ReactiveBackchaining, EnsureWarm)
67 {
68  // This test shows the basic structure of a PPA: a fallback
69  // of a postcondition and an action to make that
70  // postcondition true.
71  static const char* xml_text = R"(
72  <root BTCPP_format="4">
73  <BehaviorTree ID="EnsureWarm">
74  <ReactiveFallback>
75  <IsWarm name="warm"/>
76  <ReactiveSequence>
77  <IsHoldingJacket name="jacket" />
78  <WearJacket name="wear" />
79  </ReactiveSequence>
80  </ReactiveFallback>
81  </BehaviorTree>
82  </root>
83  )";
84 
85  // The final condition of the PPA; the thing that make_warm achieves.
86  // For this example, we're only warm after WearJacket returns success.
87  BehaviorTreeFactory factory;
88  factory.registerNodeType<SimpleCondition>("IsWarm", "is_warm");
89  factory.registerNodeType<SimpleCondition>("IsHoldingJacket", "holding_jacket");
90  factory.registerNodeType<AsyncTestAction>("WearJacket", "is_warm");
91 
92  Tree tree = factory.createTreeFromText(xml_text);
93  BT::TreeObserver observer(tree);
94 
95  auto& blackboard = tree.subtrees.front()->blackboard;
96  blackboard->set("is_warm", false);
97  blackboard->set("holding_jacket", true);
98 
99  // first tick: not warm, have a jacket: start wearing it
100  EXPECT_EQ(tree.tickExactlyOnce(), NodeStatus::RUNNING);
101  EXPECT_FALSE(blackboard->get<bool>("is_warm"));
102 
103  // second tick: not warm (still wearing)
104  EXPECT_EQ(tree.tickExactlyOnce(), NodeStatus::RUNNING);
105  EXPECT_FALSE(blackboard->get<bool>("is_warm"));
106 
107  // third tick: warm (wearing succeeded)
108  EXPECT_EQ(tree.tickExactlyOnce(), NodeStatus::SUCCESS);
109  EXPECT_TRUE(blackboard->get<bool>("is_warm"));
110 
111  // fourth tick: still warm (just the condition ticked)
112  EXPECT_EQ(tree.tickExactlyOnce(), NodeStatus::SUCCESS);
113 
114  EXPECT_EQ(observer.getStatistics("warm").failure_count, 3);
115  EXPECT_EQ(observer.getStatistics("warm").success_count, 1);
116 
117  EXPECT_EQ(observer.getStatistics("jacket").transitions_count, 3);
118  EXPECT_EQ(observer.getStatistics("jacket").success_count, 3);
119 
120  EXPECT_EQ(observer.getStatistics("wear").success_count, 1);
121 }
122 
123 TEST(ReactiveBackchaining, EnsureWarmWithEnsureHoldingHacket)
124 {
125  // This test backchains on HoldingHacket => EnsureHoldingHacket to iteratively add reactivity and functionality to the tree.
126  // The general structure of the PPA remains the same.
127  static const char* xml_text = R"(
128  <root BTCPP_format="4">
129  <BehaviorTree ID="EnsureWarm">
130  <ReactiveFallback>
131  <IsWarm />
132  <ReactiveSequence>
133  <SubTree ID="EnsureHoldingJacket" />
134  <WearJacket />
135  </ReactiveSequence>
136  </ReactiveFallback>
137  </BehaviorTree>
138 
139  <BehaviorTree ID="EnsureHoldingJacket">
140  <ReactiveFallback>
141  <IsHoldingJacket />
142  <ReactiveSequence>
143  <IsNearCloset />
144  <GrabJacket />
145  </ReactiveSequence>
146  </ReactiveFallback>
147  </BehaviorTree>
148  </root>
149  )";
150 
151  BehaviorTreeFactory factory;
152  factory.registerNodeType<SimpleCondition>("IsWarm", "is_warm");
153  factory.registerNodeType<SimpleCondition>("IsHoldingJacket", "holding_jacket");
154  factory.registerNodeType<SimpleCondition>("IsNearCloset", "near_closet");
155  factory.registerNodeType<AsyncTestAction>("WearJacket", "is_warm");
156  factory.registerNodeType<AsyncTestAction>("GrabJacket", "holding_jacket");
157 
159  Tree tree = factory.createTree("EnsureWarm");
160  BT::TreeObserver observer(tree);
161 
162  tree.subtrees[0]->blackboard->set("is_warm", false);
163  tree.subtrees[1]->blackboard->set("holding_jacket", false);
164  tree.subtrees[1]->blackboard->set("near_closet", true);
165 
166  // first tick: not warm, no jacket, start GrabJacket
167  EXPECT_EQ(tree.tickExactlyOnce(), NodeStatus::RUNNING);
168  EXPECT_FALSE(tree.subtrees[0]->blackboard->get<bool>("is_warm"));
169  EXPECT_FALSE(tree.subtrees[1]->blackboard->get<bool>("holding_jacket"));
170  EXPECT_TRUE(tree.subtrees[1]->blackboard->get<bool>("near_closet"));
171 
172  // second tick: still GrabJacket
173  EXPECT_EQ(tree.tickExactlyOnce(), NodeStatus::RUNNING);
174 
175  // third tick: GrabJacket succeeded, start wearing
176  EXPECT_EQ(tree.tickExactlyOnce(), NodeStatus::RUNNING);
177  EXPECT_FALSE(tree.subtrees[0]->blackboard->get<bool>("is_warm"));
178  EXPECT_TRUE(tree.subtrees[1]->blackboard->get<bool>("holding_jacket"));
179 
180  // fourth tick: still WearingJacket
181  EXPECT_EQ(tree.tickExactlyOnce(), NodeStatus::RUNNING);
182 
183  // fifth tick: warm (WearingJacket succeeded)
184  EXPECT_EQ(tree.tickExactlyOnce(), NodeStatus::SUCCESS);
185  EXPECT_TRUE(tree.subtrees[0]->blackboard->get<bool>("is_warm"));
186 
187  // sixr tick: still warm (just the condition ticked)
188  EXPECT_EQ(tree.tickExactlyOnce(), NodeStatus::SUCCESS);
189 }
190 
191 } // namespace BT::test
BT::test::AsyncTestAction::counter_
int counter_
Definition: gtest_reactive_backchaining.cpp:32
BT
Definition: ex01_wrap_legacy.cpp:29
BT::ConditionNode
Definition: condition_node.h:21
BT::BehaviorTreeFactory::createTree
Tree createTree(const std::string &tree_name, Blackboard::Ptr blackboard=Blackboard::create())
Definition: bt_factory.cpp:432
BT::TreeNode::config
const NodeConfig & config() const
Definition: tree_node.cpp:345
BT::TreeObserver::getStatistics
const NodeStatistics & getStatistics(const std::string &path) const
Definition: bt_observer.cpp:80
BT::test::AsyncTestAction::onStart
NodeStatus onStart() override
Definition: gtest_reactive_backchaining.cpp:46
bt_observer.h
BT::Tree
Struct used to store a tree. If this object goes out of scope, the tree is destroyed.
Definition: bt_factory.h:91
BT::TreeObserver::NodeStatistics::transitions_count
unsigned transitions_count
Definition: bt_observer.h:36
bt_factory.h
BT::test::SimpleCondition
Definition: gtest_reactive_backchaining.cpp:8
BT::test::AsyncTestAction::onHalted
void onHalted() override
Definition: gtest_reactive_backchaining.cpp:61
BT::NodeConfig::blackboard
Blackboard::Ptr blackboard
Definition: tree_node.h:79
BT::PortsList
std::unordered_map< std::string, PortInfo > PortsList
Definition: basic_types.h:585
BT::NodeStatus::FAILURE
@ FAILURE
BT::BehaviorTreeFactory::registerNodeType
void registerNodeType(const std::string &ID, const PortsList &ports, ExtraArgs... args)
Definition: bt_factory.h:322
BT::BehaviorTreeFactory::createTreeFromText
Tree createTreeFromText(const std::string &text, Blackboard::Ptr blackboard=Blackboard::create())
createTreeFromText will parse the XML directly from string. The XML needs to contain either a single ...
Definition: bt_factory.cpp:395
BT::TreeObserver::NodeStatistics::failure_count
unsigned failure_count
Definition: bt_observer.h:40
BT::Tree::tickExactlyOnce
NodeStatus tickExactlyOnce()
Definition: bt_factory.cpp:599
BT::test::SimpleCondition::tick
BT::NodeStatus tick() override
Method to be implemented by the user.
Definition: gtest_reactive_backchaining.cpp:22
BT::test::TEST
TEST(ReactiveBackchaining, EnsureWarm)
Definition: gtest_reactive_backchaining.cpp:66
BT::BehaviorTreeFactory
The BehaviorTreeFactory is used to create instances of a TreeNode at run-time.
Definition: bt_factory.h:205
BT::TreeObserver
The TreeObserver is used to collect statistics about which nodes are executed and their returned stat...
Definition: bt_observer.h:17
BT::TreeNode::name
const std::string & name() const
Name of the instance, not the type.
Definition: tree_node.cpp:296
BT::NodeStatus::SUCCESS
@ SUCCESS
BT::TreeObserver::NodeStatistics::success_count
unsigned success_count
Definition: bt_observer.h:38
BT::Tree::subtrees
std::vector< Subtree::Ptr > subtrees
Definition: bt_factory.h:104
BT::NodeStatus::RUNNING
@ RUNNING
BT::test::AsyncTestAction::onRunning
NodeStatus onRunning() override
method invoked when the action is already in the RUNNING state.
Definition: gtest_reactive_backchaining.cpp:52
BT::BehaviorTreeFactory::registerBehaviorTreeFromText
void registerBehaviorTreeFromText(const std::string &xml_text)
Definition: bt_factory.cpp:277
BT::test
Definition: gtest_reactive_backchaining.cpp:5
BT::test::AsyncTestAction::providedPorts
static BT::PortsList providedPorts()
Definition: gtest_reactive_backchaining.cpp:41
BT::test::SimpleCondition::SimpleCondition
SimpleCondition(const std::string &name, const BT::NodeConfig &config, std::string port_name)
Definition: gtest_reactive_backchaining.cpp:14
BT::test::AsyncTestAction::AsyncTestAction
AsyncTestAction(const std::string &name, const BT::NodeConfig &config, std::string port_name)
Definition: gtest_reactive_backchaining.cpp:36
BT::test::SimpleCondition::port_name_
std::string port_name_
Definition: gtest_reactive_backchaining.cpp:11
BT::NodeConfig
Definition: tree_node.h:73
BT::test::AsyncTestAction::port_name_
std::string port_name_
Definition: gtest_reactive_backchaining.cpp:33
xml_text
static const char * xml_text
Definition: ex01_wrap_legacy.cpp:52
BT::NodeStatus
NodeStatus
Definition: basic_types.h:33
BT::test::SimpleCondition::providedPorts
static BT::PortsList providedPorts()
Definition: gtest_reactive_backchaining.cpp:18
BT::test::AsyncTestAction
Definition: gtest_reactive_backchaining.cpp:30
BT::StatefulActionNode
The StatefulActionNode is the preferred way to implement asynchronous Actions. It is actually easier ...
Definition: action_node.h:159


behaviortree_cpp_v4
Author(s): Davide Faconti
autogenerated on Fri Jun 28 2024 02:20:07