Go to the documentation of this file.00001 #include "behaviortree_cpp/decorators/timeout_node.h"
00002 #include "behaviortree_cpp/behavior_tree.h"
00003 #include <chrono>
00004 #include <gtest/gtest.h>
00005
00006 using namespace std::chrono;
00007
00008 using Millisecond = std::chrono::milliseconds;
00009 using Timepoint = std::chrono::time_point<std::chrono::steady_clock>;
00010
00011 class SimpleCoroAction : public BT::CoroActionNode
00012 {
00013 public:
00014 SimpleCoroAction(milliseconds timeout, bool will_fail,
00015 const std::string &node_name,
00016 const BT::NodeConfiguration &config)
00017 : BT::CoroActionNode(node_name, config)
00018 , will_fail_(will_fail)
00019 , timeout_(timeout)
00020 , start_time_(Timepoint::min())
00021 {
00022 }
00023
00024 virtual void halt() override
00025 {
00026 std::cout << "Action was halted. doing cleanup here" << std::endl;
00027 start_time_ = Timepoint::min();
00028 halted_ = true;
00029 BT::CoroActionNode::halt();
00030 }
00031
00032 bool wasHalted()
00033 {
00034 return halted_;
00035 }
00036
00037 void setRequiredTime(Millisecond ms)
00038 {
00039 timeout_ = ms;
00040 }
00041
00042 protected:
00043 virtual BT::NodeStatus tick() override
00044 {
00045 std::cout << "Starting action " << std::endl;
00046 halted_ = false;
00047
00048 if (start_time_ == Timepoint::min())
00049 {
00050 start_time_ = std::chrono::steady_clock::now();
00051 }
00052
00053 while (std::chrono::steady_clock::now() < (start_time_ + timeout_))
00054 {
00055 setStatusRunningAndYield();
00056 }
00057
00058 halted_ = false;
00059
00060 std::cout << "Done" << std::endl;
00061 start_time_ = Timepoint::min();
00062 return (will_fail_ ? BT::NodeStatus::FAILURE : BT::NodeStatus::SUCCESS);
00063 }
00064
00065 public:
00066 bool will_fail_;
00067
00068 private:
00069 std::chrono::milliseconds timeout_;
00070 Timepoint start_time_;
00071 bool halted_;
00072 };
00073
00074 BT::NodeStatus executeWhileRunning(BT::TreeNode &node)
00075 {
00076 auto status = node.executeTick();
00077 while (status == BT::NodeStatus::RUNNING)
00078 {
00079 status = node.executeTick();
00080 std::this_thread::sleep_for(Millisecond(1));
00081 }
00082 return status;
00083 }
00084
00085
00086 TEST(CoroTest, do_action)
00087 {
00088 BT::NodeConfiguration node_config_;
00089 node_config_.blackboard = BT::Blackboard::create();
00090 BT::assignDefaultRemapping<SimpleCoroAction>(node_config_);
00091 SimpleCoroAction node( milliseconds(200), false, "Action", node_config_);
00092
00093 EXPECT_EQ(BT::NodeStatus::SUCCESS, executeWhileRunning(node));
00094 EXPECT_FALSE( node.wasHalted() );
00095
00096 EXPECT_EQ(BT::NodeStatus::SUCCESS, executeWhileRunning(node)) << "Second call to coro action";
00097 EXPECT_FALSE( node.wasHalted() );
00098
00099 node.will_fail_ = true;
00100 EXPECT_EQ(BT::NodeStatus::FAILURE, executeWhileRunning(node))
00101 << "Should execute again and retun failure";
00102 EXPECT_FALSE( node.wasHalted() );
00103
00104
00105 EXPECT_EQ(BT::NodeStatus::FAILURE, executeWhileRunning(node))
00106 << "Shoudln't fail because we set status to idle";
00107 EXPECT_FALSE( node.wasHalted() );
00108 }
00109
00110
00111 TEST(CoroTest, do_action_timeout)
00112 {
00113 BT::NodeConfiguration node_config_;
00114 node_config_.blackboard = BT::Blackboard::create();
00115 BT::assignDefaultRemapping<SimpleCoroAction>(node_config_);
00116
00117 SimpleCoroAction node( milliseconds(300), false, "Action", node_config_);
00118 BT::TimeoutNode timeout("TimeoutAction", 200);
00119
00120 timeout.setChild(&node);
00121
00122 EXPECT_EQ(BT::NodeStatus::FAILURE, executeWhileRunning(timeout) ) << "should timeout";
00123 EXPECT_TRUE( node.wasHalted() );
00124
00125 node.setRequiredTime( Millisecond(100) );
00126
00127 EXPECT_EQ(BT::NodeStatus::SUCCESS, executeWhileRunning(timeout) );
00128 EXPECT_FALSE( node.wasHalted() );
00129 }
00130
00131 TEST(CoroTest, sequence_child)
00132 {
00133 BT::NodeConfiguration node_config_;
00134 node_config_.blackboard = BT::Blackboard::create();
00135 BT::assignDefaultRemapping<SimpleCoroAction>(node_config_);
00136
00137 SimpleCoroAction actionA( milliseconds(200), false, "action_A", node_config_);
00138 SimpleCoroAction actionB( milliseconds(200), false, "action_B", node_config_);
00139 BT::TimeoutNode timeout("timeout", 300);
00140 BT::SequenceNode sequence("sequence");
00141
00142 timeout.setChild(&sequence);
00143 sequence.addChild(&actionA);
00144 sequence.addChild(&actionB);
00145
00146 EXPECT_EQ(BT::NodeStatus::FAILURE, executeWhileRunning(timeout) ) << "should timeout";
00147 EXPECT_FALSE( actionA.wasHalted() );
00148 EXPECT_TRUE( actionB.wasHalted() );
00149
00150 }
00151