Skip to content

Commit ba1d475

Browse files
committed
fix issue #624 : add TimeoutNode::halt()
1 parent 8453012 commit ba1d475

File tree

8 files changed

+133
-75
lines changed

8 files changed

+133
-75
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,12 @@ list(APPEND BT_SOURCE
9797
src/actions/test_node.cpp
9898
src/actions/sleep_node.cpp
9999

100+
src/decorators/delay_node.cpp
100101
src/decorators/inverter_node.cpp
101102
src/decorators/repeat_node.cpp
102103
src/decorators/retry_node.cpp
104+
src/decorators/timeout_node.cpp
103105
src/decorators/subtree_node.cpp
104-
src/decorators/delay_node.cpp
105106

106107
src/controls/if_then_else_node.cpp
107108
src/controls/fallback_node.cpp

include/behaviortree_cpp/decorators/delay_node.h

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
/* Copyright (C) 2018-2023 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+
113
#pragma once
214

315
#include "behaviortree_cpp/decorator_node.h"
@@ -35,12 +47,8 @@ class DelayNode : public DecoratorNode
3547
{
3648
return {InputPort<unsigned>("delay_msec", "Tick the child after a few milliseconds")};
3749
}
38-
void halt() override
39-
{
40-
delay_started_ = false;
41-
timer_.cancelAll();
42-
DecoratorNode::halt();
43-
}
50+
51+
void halt() override;
4452

4553
private:
4654
TimerQueue<> timer_;
Lines changed: 19 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
/* Copyright (C) 2018-2023 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+
113
#pragma once
214

315
#include "behaviortree_cpp/decorator_node.h"
@@ -8,19 +20,18 @@ namespace BT
820
{
921
/**
1022
* @brief The TimeoutNode will halt() a running child if
11-
* the latter has been RUNNING for more than a give time.
23+
* the latter has been RUNNING longer than a given time.
1224
* The timeout is in milliseconds and it is passed using the port "msec".
1325
*
14-
* If timeout is reached it returns FAILURE.
26+
* If timeout is reached, the node returns FAILURE.
1527
*
1628
* Example:
1729
*
1830
* <Timeout msec="5000">
1931
* <KeepYourBreath/>
2032
* </Timeout>
2133
*/
22-
template <typename _Clock = std::chrono::steady_clock,
23-
typename _Duration = std::chrono::steady_clock::duration>
34+
2435
class TimeoutNode : public DecoratorNode
2536
{
2637
public:
@@ -56,67 +67,12 @@ class TimeoutNode : public DecoratorNode
5667
}
5768

5869
private:
59-
TimerQueue<_Clock, _Duration> timer_;
60-
61-
virtual BT::NodeStatus tick() override
62-
{
63-
if (read_parameter_from_ports_)
64-
{
65-
if (!getInput("msec", msec_))
66-
{
67-
throw RuntimeError("Missing parameter [msec] in TimeoutNode");
68-
}
69-
}
7070

71-
if (!timeout_started_)
72-
{
73-
timeout_started_ = true;
74-
setStatus(NodeStatus::RUNNING);
75-
child_halted_ = false;
71+
virtual BT::NodeStatus tick() override;
7672

77-
if (msec_ > 0)
78-
{
79-
timer_id_ = timer_.add(std::chrono::milliseconds(msec_), [this](bool aborted) {
80-
// Return immediately if the timer was aborted.
81-
// This function could be invoked during destruction of this object and
82-
// we don't want to access member variables if not needed.
83-
if (aborted)
84-
{
85-
return;
86-
}
87-
std::unique_lock<std::mutex> lk(timeout_mutex_);
88-
if (child()->status() == NodeStatus::RUNNING)
89-
{
90-
child_halted_ = true;
91-
haltChild();
92-
emitWakeUpSignal();
93-
}
94-
});
95-
}
96-
}
97-
98-
std::unique_lock<std::mutex> lk(timeout_mutex_);
99-
100-
if (child_halted_)
101-
{
102-
timeout_started_ = false;
103-
return NodeStatus::FAILURE;
104-
}
105-
else
106-
{
107-
const NodeStatus child_status = child()->executeTick();
108-
if(isStatusCompleted(child_status))
109-
{
110-
timeout_started_ = false;
111-
timeout_mutex_.unlock();
112-
timer_.cancel(timer_id_);
113-
timeout_mutex_.lock();
114-
resetChild();
115-
}
116-
return child_status;
117-
}
118-
}
73+
void halt() override;
11974

75+
TimerQueue<> timer_;
12076
std::atomic<bool> child_halted_;
12177
uint64_t timer_id_;
12278

@@ -125,4 +81,5 @@ class TimeoutNode : public DecoratorNode
12581
bool timeout_started_;
12682
std::mutex timeout_mutex_;
12783
};
84+
12885
} // namespace BT

src/bt_factory.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ BehaviorTreeFactory::BehaviorTreeFactory():
6767
registerNodeType<RetryNode>("RetryUntilSuccessful");
6868
registerNodeType<KeepRunningUntilFailureNode>("KeepRunningUntilFailure");
6969
registerNodeType<RepeatNode>("Repeat");
70-
registerNodeType<TimeoutNode<>>("Timeout");
70+
registerNodeType<TimeoutNode>("Timeout");
7171
registerNodeType<DelayNode>("Delay");
7272
registerNodeType<RunOnceNode>("RunOnce");
7373

src/decorators/delay_node.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* Contributed by Indraneel on 26/04/2020
22
*/
3+
34
#include "behaviortree_cpp/decorators/delay_node.h"
4-
#include "behaviortree_cpp/action_node.h"
55

66
namespace BT
77
{
@@ -23,6 +23,13 @@ DelayNode::DelayNode(const std::string& name, const NodeConfig& config) :
2323
read_parameter_from_ports_(true)
2424
{}
2525

26+
void DelayNode::halt()
27+
{
28+
delay_started_ = false;
29+
timer_.cancelAll();
30+
DecoratorNode::halt();
31+
}
32+
2633
NodeStatus DelayNode::tick()
2734
{
2835
if (read_parameter_from_ports_)

src/decorators/timeout_node.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/* Copyright (C) 2018-2023 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 "behaviortree_cpp/decorators/timeout_node.h"
14+
15+
namespace BT
16+
{
17+
18+
NodeStatus TimeoutNode::tick()
19+
{
20+
if (read_parameter_from_ports_)
21+
{
22+
if (!getInput("msec", msec_))
23+
{
24+
throw RuntimeError("Missing parameter [msec] in TimeoutNode");
25+
}
26+
}
27+
28+
if (!timeout_started_)
29+
{
30+
timeout_started_ = true;
31+
setStatus(NodeStatus::RUNNING);
32+
child_halted_ = false;
33+
34+
if (msec_ > 0)
35+
{
36+
timer_id_ = timer_.add(std::chrono::milliseconds(msec_), [this](bool aborted) {
37+
// Return immediately if the timer was aborted.
38+
// This function could be invoked during destruction of this object and
39+
// we don't want to access member variables if not needed.
40+
if (aborted)
41+
{
42+
return;
43+
}
44+
std::unique_lock<std::mutex> lk(timeout_mutex_);
45+
if (child()->status() == NodeStatus::RUNNING)
46+
{
47+
child_halted_ = true;
48+
haltChild();
49+
emitWakeUpSignal();
50+
}
51+
});
52+
}
53+
}
54+
55+
std::unique_lock<std::mutex> lk(timeout_mutex_);
56+
57+
if (child_halted_)
58+
{
59+
timeout_started_ = false;
60+
return NodeStatus::FAILURE;
61+
}
62+
else
63+
{
64+
const NodeStatus child_status = child()->executeTick();
65+
if(isStatusCompleted(child_status))
66+
{
67+
timeout_started_ = false;
68+
timeout_mutex_.unlock();
69+
timer_.cancel(timer_id_);
70+
timeout_mutex_.lock();
71+
resetChild();
72+
}
73+
return child_status;
74+
}
75+
}
76+
77+
void TimeoutNode::halt()
78+
{
79+
timeout_started_ = false;
80+
timer_.cancelAll();
81+
DecoratorNode::halt();
82+
}
83+
84+
85+
} // namespace BT

tests/gtest_coroutines.cpp

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

115115
SimpleCoroAction node(milliseconds(300), false, "Action", node_config_);
116-
BT::TimeoutNode<> timeout("TimeoutAction", 200);
116+
BT::TimeoutNode timeout("TimeoutAction", 200);
117117

118118
timeout.setChild(&node);
119119

@@ -134,7 +134,7 @@ TEST(CoroTest, sequence_child)
134134

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

140140
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), action("action", milliseconds(500))
@@ -68,7 +68,7 @@ struct RetryTest : testing::Test
6868

6969
struct TimeoutAndRetry : testing::Test
7070
{
71-
BT::TimeoutNode<> timeout_root;
71+
BT::TimeoutNode timeout_root;
7272
BT::RetryNode retry;
7373
BT::SyncActionTest action;
7474

0 commit comments

Comments
 (0)