action_node.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2015-2018 Michele Colledanchise - All Rights Reserved
2  * Copyright (C) 2018-2020 Davide Faconti, Eurecat - All Rights Reserved
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
6 * 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:
7 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
10 * 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,
11 * 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.
12 */
13 
15 
16 using namespace BT;
17 
18 ActionNodeBase::ActionNodeBase(const std::string& name, const NodeConfiguration& config) :
19  LeafNode::LeafNode(name, config)
20 {}
21 
22 //-------------------------------------------------------
23 
25  SimpleActionNode::TickFunctor tick_functor,
26  const NodeConfiguration& config) :
27  SyncActionNode(name, config), tick_functor_(std::move(tick_functor))
28 {}
29 
31 {
32  NodeStatus prev_status = status();
33 
34  if (prev_status == NodeStatus::IDLE)
35  {
37  prev_status = NodeStatus::RUNNING;
38  }
39 
41  if (status != prev_status)
42  {
43  setStatus(status);
44  }
45  return status;
46 }
47 
48 //-------------------------------------------------------
49 
51  ActionNodeBase(name, config)
52 {}
53 
55 {
56  auto stat = ActionNodeBase::executeTick();
57  if (stat == NodeStatus::RUNNING)
58  {
59  throw LogicError("SyncActionNode MUST never return RUNNING");
60  }
61  return stat;
62 }
63 
64 //-------------------------------------
65 #ifndef BT_NO_COROUTINES
66 
67 #ifdef BT_BOOST_COROUTINE2
68 #include <boost/coroutine2/all.hpp>
69 using namespace boost::coroutines2;
70 #endif
71 
72 #ifdef BT_BOOST_COROUTINE
73 #include <boost/coroutine/all.hpp>
74 using namespace boost::coroutines;
75 #endif
76 
78 {
79  std::unique_ptr<coroutine<void>::pull_type> coro;
80  std::function<void(coroutine<void>::push_type& yield)> func;
81  coroutine<void>::push_type* yield_ptr;
82 };
83 
85  ActionNodeBase(name, config), _p(new Pimpl)
86 {
87  _p->func = [this](coroutine<void>::push_type& yield) {
88  _p->yield_ptr = &yield;
89  setStatus(tick());
90  };
91 }
92 
94 {}
95 
97 {
99  (*_p->yield_ptr)();
100 }
101 
103 {
104  if (!(_p->coro) || !(*_p->coro))
105  {
106  _p->coro.reset(new coroutine<void>::pull_type(_p->func));
107  return status();
108  }
109 
110  if (status() == NodeStatus::RUNNING && (bool)_p->coro)
111  {
112  (*_p->coro)();
113  }
114 
115  return status();
116 }
117 
119 {
120  _p->coro.reset();
121 }
122 #endif
123 
125 {
126  const NodeStatus initial_status = status();
127 
128  if (initial_status == NodeStatus::IDLE)
129  {
130  NodeStatus new_status = onStart();
131  if (new_status == NodeStatus::IDLE)
132  {
133  throw std::logic_error("StatefulActionNode::onStart() must not return IDLE");
134  }
135  return new_status;
136  }
137  //------------------------------------------
138  if (initial_status == NodeStatus::RUNNING)
139  {
140  NodeStatus new_status = onRunning();
141  if (new_status == NodeStatus::IDLE)
142  {
143  throw std::logic_error("StatefulActionNode::onRunning() must not return "
144  "IDLE");
145  }
146  return new_status;
147  }
148  //------------------------------------------
149  return initial_status;
150 }
151 
153 {
154  if (status() == NodeStatus::RUNNING)
155  {
156  onHalted();
157  }
158 }
159 
161 {
162  using lock_type = std::unique_lock<std::mutex>;
163  //send signal to other thread.
164  // The other thread is in charge for changing the status
165  if (status() == NodeStatus::IDLE)
166  {
168  halt_requested_ = false;
169  thread_handle_ = std::async(std::launch::async, [this]() {
170  try
171  {
172  auto status = tick();
173  if (!isHaltRequested())
174  {
175  setStatus(status);
176  }
177  }
178  catch (std::exception&)
179  {
180  std::cerr << "\nUncaught exception from the method tick(): ["
181  << registrationName() << "/" << name() << "]\n"
182  << std::endl;
183  // Set the exception pointer and the status atomically.
184  lock_type l(mutex_);
185  exptr_ = std::current_exception();
187  }
189  });
190  }
191 
192  lock_type l(mutex_);
193  if (exptr_)
194  {
195  // The official interface of std::exception_ptr does not define any move
196  // semantics. Thus, we copy and reset exptr_ manually.
197  const auto exptr_copy = exptr_;
198  exptr_ = nullptr;
199  std::rethrow_exception(exptr_copy);
200  }
201  return status();
202 }
203 
205 {
206  halt_requested_.store(true);
207 
208  if (thread_handle_.valid())
209  {
210  thread_handle_.wait();
211  }
212  thread_handle_ = {};
213 }
The ActionNodeBase is the base class to use to create any kind of action. A particular derived class ...
Definition: action_node.h:35
virtual void halt() override
const NodeConfiguration & config() const
Definition: tree_node.cpp:127
NodeStatus tick() override final
Method to be implemented by the user.
void halt() override final
NodeStatus status() const
Definition: tree_node.cpp:84
Definition: any.hpp:455
virtual NodeStatus executeTick() override
throws if the derived class return RUNNING.
Definition: action_node.cpp:54
SyncActionNode(const std::string &name, const NodeConfiguration &config)
Definition: action_node.cpp:50
void halt() override
The SyncActionNode is an ActionNode that explicitly prevents the status RUNNING and doesn&#39;t require a...
Definition: action_node.h:52
const std::string & name() const
Name of the instance, not the type.
Definition: tree_node.cpp:101
std::unique_ptr< Pimpl > _p
Definition: action_node.h:212
const std::string & registrationName() const
registrationName is the ID used by BehaviorTreeFactory to create an instance.
Definition: tree_node.cpp:122
virtual ~CoroActionNode() override
Definition: action_node.cpp:93
virtual NodeStatus executeTick() override final
The method that should be used to invoke tick() and setStatus();.
ActionNodeBase(const std::string &name, const NodeConfiguration &config)
Definition: action_node.cpp:18
std::unique_ptr< coroutine< void >::pull_type > coro
Definition: action_node.cpp:79
std::function< NodeStatus(TreeNode &)> TickFunctor
Definition: action_node.h:81
SimpleActionNode(const std::string &name, TickFunctor tick_functor, const NodeConfiguration &config)
Definition: action_node.cpp:24
virtual NodeStatus tick() override final
Method to be implemented by the user.
Definition: action_node.cpp:30
void emitStateChanged()
Definition: tree_node.cpp:193
void setStatusRunningAndYield()
Use this method to return RUNNING and temporary "pause" the Action.
Definition: action_node.cpp:96
NodeStatus
Definition: basic_types.h:35
TickFunctor tick_functor_
Definition: action_node.h:92
virtual BT::NodeStatus executeTick()
The method that should be used to invoke tick() and setStatus();.
Definition: tree_node.cpp:32
CoroActionNode(const std::string &name, const NodeConfiguration &config)
Definition: action_node.cpp:84
virtual NodeStatus executeTick() override final
The method that should be used to invoke tick() and setStatus();.
coroutine< void >::push_type * yield_ptr
Definition: action_node.cpp:81
virtual BT::NodeStatus tick()=0
Method to be implemented by the user.
void setStatus(NodeStatus new_status)
Definition: tree_node.cpp:63


behaviortree_cpp_v3
Author(s): Michele Colledanchise, Davide Faconti
autogenerated on Mon Jul 3 2023 02:50:14