navigation_test.cpp
Go to the documentation of this file.
00001 #include "behaviortree_cpp/xml_parsing.h"
00002 #include "behaviortree_cpp/blackboard/blackboard_local.h"
00003 #include <gtest/gtest.h>
00004 
00005 using namespace BT;
00006 
00007 // clang-format off
00008 const std::string xml_text = R"(
00009 
00010 <root main_tree_to_execute="BehaviorTree">
00011     <BehaviorTree ID="BehaviorTree">
00012         <FallbackStar name="root">
00013             <Sequence name="navigation_subtree">
00014                 <Inverter>
00015                     <Condition ID="IsStuck"/>
00016                 </Inverter>
00017                 <SequenceStar name="navigate">
00018                     <Action ID="ComputePathToPose"/>
00019                     <Action ID="FollowPath"/>
00020                 </SequenceStar>
00021             </Sequence>
00022             <SequenceStar name="stuck_recovery">
00023                 <Condition ID="IsStuck"/>
00024                 <Action ID="BackUpAndSpin"/>
00025             </SequenceStar>
00026         </FallbackStar>
00027     </BehaviorTree>
00028 </root>
00029  )";
00030 
00031 // clang-format on
00032 
00033 using Milliseconds = std::chrono::milliseconds;
00034 
00035 inline std::chrono::high_resolution_clock::time_point Now()
00036 {
00037     return std::chrono::high_resolution_clock::now();
00038 }
00039 
00040 
00041 
00042 //--------------------------------------------
00043 
00044 class TestNode
00045 {
00046   public:
00047     TestNode(const std::string& name):
00048       _expected_result(true),
00049       _tick_count(0),
00050       _name(name)
00051     { }
00052 
00053     void setExpectedResult(bool will_succeed)
00054     {
00055         _expected_result = will_succeed;
00056     }
00057     NodeStatus expectedResult() const
00058     {
00059         return _expected_result ? NodeStatus::SUCCESS : NodeStatus::FAILURE;
00060     }
00061     void resetTickCount() { _tick_count = 0; }
00062     int tickCount() const { return _tick_count;}
00063 
00064     NodeStatus tickImpl()
00065     {
00066         std::cout << _name << ": "<< (_expected_result? "true" : "false") << std::endl;
00067         _tick_count++;
00068         return expectedResult();
00069     }
00070 
00071   private:
00072     bool _expected_result;
00073     int _tick_count;
00074     std::string _name;
00075 };
00076 
00077 class IsStuck: public ConditionNode, public TestNode
00078 {
00079   public:
00080     IsStuck(const std::string& name): ConditionNode(name), TestNode(name) {}
00081 
00082     NodeStatus tick() override
00083     {
00084         return tickImpl();
00085     }
00086 };
00087 
00088 class BackUpAndSpin: public SyncActionNode, public TestNode
00089 {
00090   public:
00091     BackUpAndSpin(const std::string& name): SyncActionNode(name), TestNode(name){}
00092 
00093     NodeStatus tick() override
00094     {
00095         return tickImpl();
00096     }
00097 };
00098 
00099 class ComputePathToPose: public SyncActionNode, public TestNode
00100 {
00101   public:
00102     ComputePathToPose(const std::string& name): SyncActionNode(name), TestNode(name){}
00103 
00104     NodeStatus tick() override
00105     {
00106         return tickImpl();
00107     }
00108 };
00109 
00110 class FollowPath: public CoroActionNode, public TestNode
00111 {
00112   public:
00113     FollowPath(const std::string& name): CoroActionNode(name), TestNode(name), _halted(false){}
00114 
00115     NodeStatus tick() override
00116     {
00117         _halted = false;
00118         std::cout << "FollowPath::started" << std::endl;
00119         auto initial_time = Now();
00120 
00121         // Yield for 1 second
00122         while( Now() < initial_time + Milliseconds(600) )
00123         {
00124             setStatusRunningAndYield();
00125 
00126         }
00127         return tickImpl();
00128     }
00129     void halt() override {
00130         std::cout << "FollowPath::halt" << std::endl;
00131         _halted = true;
00132         CoroActionNode::halt();
00133     }
00134 
00135     bool wasHalted() const { return _halted; }
00136 
00137   private:
00138     bool _halted;
00139 };
00140 
00141 //-------------------------------------
00142 
00143 template <typename Original, typename Casted>
00144 void TryDynamicCastPtr(Original* ptr, Casted*& destination)
00145 {
00146     if( dynamic_cast<Casted*>(ptr) )
00147     {
00148         destination = dynamic_cast<Casted*>(ptr);
00149     }
00150 }
00151 
00152 /****************TESTS START HERE***************************/
00153 
00154 TEST(Navigationtest, MoveBaseRecovery)
00155 {
00156     BehaviorTreeFactory factory;
00157 
00158     factory.registerNodeType<IsStuck>("IsStuck");
00159     factory.registerNodeType<BackUpAndSpin>("BackUpAndSpin");
00160     factory.registerNodeType<ComputePathToPose>("ComputePathToPose");
00161     factory.registerNodeType<FollowPath>("FollowPath");
00162 
00163     auto tree = buildTreeFromText(factory, xml_text);
00164 
00165     // Need to retrieve the node pointers with dynamic cast
00166     // In a normal application you would NEVER want to do such a thing.
00167     IsStuck *first_stuck_node = nullptr;
00168     IsStuck *second_stuck_node = nullptr;
00169     BackUpAndSpin* back_spin_node = nullptr;
00170     ComputePathToPose* compute_node = nullptr;
00171     FollowPath* follow_node = nullptr;
00172 
00173     for (auto& node: tree.nodes)
00174     {
00175         auto ptr = node.get();
00176 
00177         if( !first_stuck_node )
00178         {
00179             TryDynamicCastPtr(ptr, first_stuck_node);
00180         }
00181         else{
00182             TryDynamicCastPtr(ptr, second_stuck_node);
00183         }
00184         TryDynamicCastPtr(ptr, back_spin_node);
00185         TryDynamicCastPtr(ptr, follow_node);
00186         TryDynamicCastPtr(ptr, compute_node);
00187     }
00188 
00189     ASSERT_TRUE( first_stuck_node );
00190     ASSERT_TRUE( second_stuck_node );
00191     ASSERT_TRUE( back_spin_node );
00192     ASSERT_TRUE( compute_node );
00193     ASSERT_TRUE( follow_node );
00194 
00195     std::cout << "-----------------------" << std::endl;
00196 
00197     // First case: not stuck, everything fine.
00198     NodeStatus status = NodeStatus::IDLE;
00199 
00200     first_stuck_node->setExpectedResult(false);
00201 
00202     while( status == NodeStatus::IDLE || status == NodeStatus::RUNNING )
00203     {
00204         status = tree.root_node->executeTick();
00205         std::this_thread::sleep_for(Milliseconds(100));
00206     }
00207 
00208     // SUCCESS expected
00209     ASSERT_EQ( status,  NodeStatus::SUCCESS );
00210     // IsStuck on the left branch must run several times
00211     ASSERT_GE( first_stuck_node->tickCount(), 6);
00212     // Never take the right branch (recovery)
00213     ASSERT_EQ( second_stuck_node->tickCount(), 0 );
00214     ASSERT_EQ( back_spin_node->tickCount(), 0 );
00215 
00216     ASSERT_EQ( compute_node->tickCount(), 1 );
00217     ASSERT_EQ( follow_node->tickCount(), 1 );
00218     ASSERT_FALSE( follow_node->wasHalted() );
00219 
00220     std::cout << "-----------------------" << std::endl;
00221 
00222     // Second case: get stuck after a while
00223 
00224     // Initialize evrything first
00225     first_stuck_node->resetTickCount();
00226     second_stuck_node->resetTickCount();
00227     compute_node->resetTickCount();
00228     follow_node->resetTickCount();
00229     back_spin_node->resetTickCount();
00230     status = NodeStatus::IDLE;
00231     int cycle = 0;
00232 
00233     while( status == NodeStatus::IDLE || status == NodeStatus::RUNNING )
00234     {
00235         // At the fifth cycle get stucked
00236         if( ++cycle == 2 )
00237         {
00238             first_stuck_node->setExpectedResult(true);
00239             second_stuck_node->setExpectedResult(true);
00240         }
00241         status = tree.root_node->executeTick();
00242         std::this_thread::sleep_for(Milliseconds(100));
00243     }
00244 
00245     // SUCCESS expected
00246     ASSERT_EQ( status,  NodeStatus::SUCCESS );
00247 
00248     // First IsStuck must run several times
00249     ASSERT_GE( first_stuck_node->tickCount(), 2);
00250     // Second IsStuck probably only once
00251     ASSERT_EQ( second_stuck_node->tickCount(), 1 );
00252     ASSERT_EQ( back_spin_node->tickCount(), 1 );
00253 
00254     // compute done once and follow started but halted
00255     ASSERT_EQ( compute_node->tickCount(), 1 );
00256 
00257     ASSERT_EQ( follow_node->tickCount(), 0 ); // started but never completed
00258     ASSERT_TRUE( follow_node->wasHalted() );
00259 
00260     ASSERT_EQ( compute_node->status(),  NodeStatus::IDLE );
00261     ASSERT_EQ( follow_node->status(),  NodeStatus::IDLE );
00262     ASSERT_EQ( back_spin_node->status(),  NodeStatus::IDLE );
00263 
00264 
00265     std::cout << "-----------------------" << std::endl;
00266 
00267     // Third case: execute again
00268 
00269     // Initialize everything first
00270     first_stuck_node->resetTickCount();
00271     second_stuck_node->resetTickCount();
00272     compute_node->resetTickCount();
00273     follow_node->resetTickCount();
00274     back_spin_node->resetTickCount();
00275     status = NodeStatus::IDLE;
00276     first_stuck_node->setExpectedResult(false);
00277     second_stuck_node->setExpectedResult(false);
00278 
00279     while( status == NodeStatus::IDLE || status == NodeStatus::RUNNING )
00280     {
00281         status = tree.root_node->executeTick();
00282         std::this_thread::sleep_for(Milliseconds(100));
00283     }
00284 
00285     // SUCCESS expected
00286     ASSERT_EQ( status,  NodeStatus::SUCCESS );
00287 
00288     ASSERT_GE( first_stuck_node->tickCount(), 6);
00289     ASSERT_EQ( second_stuck_node->tickCount(), 0 );
00290     ASSERT_EQ( back_spin_node->tickCount(), 0 );
00291 
00292     ASSERT_EQ( compute_node->status(),  NodeStatus::IDLE );
00293     ASSERT_EQ( follow_node->status(),  NodeStatus::IDLE );
00294     ASSERT_EQ( back_spin_node->status(),  NodeStatus::IDLE );
00295     ASSERT_FALSE( follow_node->wasHalted() );
00296 
00297 }
00298 
00299 


behaviortree_cpp
Author(s): Michele Colledanchise, Davide Faconti
autogenerated on Sat Feb 2 2019 03:50:10