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

Skip to content

Commit 63d6fd4

Browse files
fultoncjbCam Fultonfacontidavide
authored
Allow BT factory to define clock source for TimerQueue/TimerNode (BehaviorTree#215)
* Allow BT factory to define clock source for TimerQueue/TimerNode * Fix unit tests Co-authored-by: Cam Fulton <[email protected]> Co-authored-by: Davide Faconti <[email protected]>
1 parent 8f1c491 commit 63d6fd4

File tree

7 files changed

+86
-110
lines changed

7 files changed

+86
-110
lines changed

CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,6 @@ list(APPEND BT_SOURCE
161161
src/decorators/repeat_node.cpp
162162
src/decorators/retry_node.cpp
163163
src/decorators/subtree_node.cpp
164-
src/decorators/timeout_node.cpp
165164
src/decorators/delay_node.cpp
166165

167166
src/controls/if_then_else_node.cpp

include/behaviortree_cpp_v3/decorators/timeout_node.h

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace BT
1010
/**
1111
* @brief The TimeoutNode will halt() a running child if
1212
* the latter has been RUNNING for more than a give time.
13-
* The timeout is in millisecons and it is passed using the port "msec".
13+
* The timeout is in milliseconds and it is passed using the port "msec".
1414
*
1515
* If timeout is reached it returns FAILURE.
1616
*
@@ -20,12 +20,30 @@ namespace BT
2020
* <KeepYourBreath/>
2121
* </Timeout>
2222
*/
23+
template <typename _Clock = std::chrono::steady_clock, typename _Duration = std::chrono::steady_clock::duration>
2324
class TimeoutNode : public DecoratorNode
2425
{
2526
public:
26-
TimeoutNode(const std::string& name, unsigned milliseconds);
27+
TimeoutNode(const std::string& name, unsigned milliseconds)
28+
: DecoratorNode(name, {} ),
29+
child_halted_(false),
30+
timer_id_(0),
31+
msec_(milliseconds),
32+
read_parameter_from_ports_(false),
33+
timeout_started_(false)
34+
{
35+
setRegistrationID("Timeout");
36+
}
2737

28-
TimeoutNode(const std::string& name, const NodeConfiguration& config);
38+
TimeoutNode(const std::string& name, const NodeConfiguration& config)
39+
: DecoratorNode(name, config),
40+
child_halted_(false),
41+
timer_id_(0),
42+
msec_(0),
43+
read_parameter_from_ports_(true),
44+
timeout_started_(false)
45+
{
46+
}
2947

3048
~TimeoutNode() override
3149
{
@@ -39,9 +57,59 @@ class TimeoutNode : public DecoratorNode
3957
}
4058

4159
private:
42-
TimerQueue timer_ ;
60+
TimerQueue<_Clock, _Duration> timer_ ;
61+
62+
virtual BT::NodeStatus tick() override
63+
{
64+
if( read_parameter_from_ports_ )
65+
{
66+
if( !getInput("msec", msec_) )
67+
{
68+
throw RuntimeError("Missing parameter [msec] in TimeoutNode");
69+
}
70+
}
71+
72+
if ( !timeout_started_ )
73+
{
74+
timeout_started_ = true;
75+
setStatus(NodeStatus::RUNNING);
76+
child_halted_ = false;
77+
78+
if (msec_ > 0)
79+
{
80+
timer_id_ = timer_.add(std::chrono::milliseconds(msec_),
81+
[this](bool aborted)
82+
{
83+
std::unique_lock<std::mutex> lk( timeout_mutex_ );
84+
if (!aborted && child()->status() == NodeStatus::RUNNING)
85+
{
86+
child_halted_ = true;
87+
haltChild();
88+
}
89+
});
90+
}
91+
}
4392

44-
virtual BT::NodeStatus tick() override;
93+
std::unique_lock<std::mutex> lk( timeout_mutex_ );
94+
95+
if (child_halted_)
96+
{
97+
timeout_started_ = false;
98+
return NodeStatus::FAILURE;
99+
}
100+
else
101+
{
102+
auto child_status = child()->executeTick();
103+
if (child_status != NodeStatus::RUNNING)
104+
{
105+
timeout_started_ = false;
106+
timeout_mutex_.unlock();
107+
timer_.cancel(timer_id_);
108+
timeout_mutex_.lock();
109+
}
110+
return child_status;
111+
}
112+
}
45113

46114
std::atomic<bool> child_halted_;
47115
uint64_t timer_id_;

include/behaviortree_cpp_v3/decorators/timer_queue.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class Semaphore
6262
// - Handlers are ALWAYS executed in the Timer Queue worker thread.
6363
// - Handlers execution order is NOT guaranteed
6464
//
65+
template <typename _Clock, typename _Duration>
6566
class TimerQueue
6667
{
6768
public:
@@ -85,7 +86,7 @@ class TimerQueue
8586
uint64_t add(std::chrono::milliseconds milliseconds, std::function<void(bool)> handler)
8687
{
8788
WorkItem item;
88-
item.end = Clock::now() + milliseconds;
89+
item.end = _Clock::now() + milliseconds;
8990
item.handler = std::move(handler);
9091

9192
std::unique_lock<std::mutex> lk(m_mtx);
@@ -118,7 +119,7 @@ class TimerQueue
118119
{
119120
WorkItem newItem;
120121
// Zero time, so it stays at the top for immediate execution
121-
newItem.end = Clock::time_point();
122+
newItem.end = std::chrono::time_point<_Clock, _Duration>();
122123
newItem.id = 0; // Means it is a canceled item
123124
// Move the handler from item to newitem.
124125
// Also, we need to manually set the handler to nullptr, since
@@ -150,7 +151,7 @@ class TimerQueue
150151
{
151152
if (item.id)
152153
{
153-
item.end = Clock::time_point();
154+
item.end = std::chrono::time_point<_Clock, _Duration>();
154155
item.id = 0;
155156
}
156157
}
@@ -162,7 +163,6 @@ class TimerQueue
162163
}
163164

164165
private:
165-
using Clock = std::chrono::steady_clock;
166166
TimerQueue(const TimerQueue&) = delete;
167167
TimerQueue& operator=(const TimerQueue&) = delete;
168168

@@ -193,7 +193,7 @@ class TimerQueue
193193
assert(m_items.size() == 0);
194194
}
195195

196-
std::pair<bool, Clock::time_point> calcWaitTime()
196+
std::pair<bool, std::chrono::time_point<_Clock, _Duration>> calcWaitTime()
197197
{
198198
std::lock_guard<std::mutex> lk(m_mtx);
199199
while (m_items.size())
@@ -212,13 +212,13 @@ class TimerQueue
212212

213213
// No items found, so return no wait time (causes the thread to wait
214214
// indefinitely)
215-
return std::make_pair(false, Clock::time_point());
215+
return std::make_pair(false, std::chrono::time_point<_Clock, _Duration>());
216216
}
217217

218218
void checkWork()
219219
{
220220
std::unique_lock<std::mutex> lk(m_mtx);
221-
while (m_items.size() && m_items.top().end <= Clock::now())
221+
while (m_items.size() && m_items.top().end <= _Clock::now())
222222
{
223223
WorkItem item(std::move(m_items.top()));
224224
m_items.pop();
@@ -237,7 +237,7 @@ class TimerQueue
237237

238238
struct WorkItem
239239
{
240-
Clock::time_point end;
240+
std::chrono::time_point<_Clock, _Duration> end;
241241
uint64_t id; // id==0 means it was cancelled
242242
std::function<void(bool)> handler;
243243
bool operator>(const WorkItem& other) const

src/bt_factory.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ BehaviorTreeFactory::BehaviorTreeFactory()
3636
registerNodeType<RetryNode>("RetryUntilSuccesful");
3737
registerNodeType<KeepRunningUntilFailureNode>("KeepRunningUntilFailure");
3838
registerNodeType<RepeatNode>("Repeat");
39-
registerNodeType<TimeoutNode>("Timeout");
39+
registerNodeType<TimeoutNode<>>("Timeout");
4040
registerNodeType<DelayNode>("Delay");
4141

4242
registerNodeType<ForceSuccessNode>("ForceSuccess");

src/decorators/timeout_node.cpp

Lines changed: 0 additions & 91 deletions
This file was deleted.

tests/gtest_coroutines.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ TEST(CoroTest, do_action_timeout)
116116
BT::assignDefaultRemapping<SimpleCoroAction>(node_config_);
117117

118118
SimpleCoroAction node( milliseconds(300), false, "Action", node_config_);
119-
BT::TimeoutNode timeout("TimeoutAction", 200);
119+
BT::TimeoutNode<> timeout("TimeoutAction", 200);
120120

121121
timeout.setChild(&node);
122122

@@ -137,7 +137,7 @@ TEST(CoroTest, sequence_child)
137137

138138
SimpleCoroAction actionA( milliseconds(200), false, "action_A", node_config_);
139139
SimpleCoroAction actionB( milliseconds(200), false, "action_B", node_config_);
140-
BT::TimeoutNode timeout("timeout", 300);
140+
BT::TimeoutNode<> timeout("timeout", 300);
141141
BT::SequenceNode sequence("sequence");
142142

143143
timeout.setChild(&sequence);

tests/gtest_decorator.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ using std::chrono::milliseconds;
2020

2121
struct DeadlineTest : testing::Test
2222
{
23-
BT::TimeoutNode root;
23+
BT::TimeoutNode<> root;
2424
BT::AsyncActionTest action;
2525

2626
DeadlineTest() : root("deadline", 300)
@@ -66,7 +66,7 @@ struct RetryTest : testing::Test
6666

6767
struct TimeoutAndRetry : testing::Test
6868
{
69-
BT::TimeoutNode timeout_root;
69+
BT::TimeoutNode<> timeout_root;
7070
BT::RetryNode retry;
7171
BT::SyncActionTest action;
7272

0 commit comments

Comments
 (0)