Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
behavior_tree_navigator.hpp
1 // Copyright (c) 2021-2023 Samsung Research America
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef NAV2_CORE__BEHAVIOR_TREE_NAVIGATOR_HPP_
16 #define NAV2_CORE__BEHAVIOR_TREE_NAVIGATOR_HPP_
17 
18 #include <memory>
19 #include <string>
20 #include <vector>
21 #include <mutex>
22 #include <chrono>
23 
24 #include "nav2_util/odometry_utils.hpp"
25 #include "nav2_ros_common/tf2_factories.hpp"
26 #include "rclcpp/clock.hpp"
27 #include "rclcpp/logger.hpp"
28 #include "rclcpp/logging.hpp"
29 #include "rclcpp/rate.hpp"
30 #include "nav2_ros_common/lifecycle_node.hpp"
31 #include "pluginlib/class_loader.hpp"
32 #include "nav2_behavior_tree/bt_action_server.hpp"
33 #include "nav2_ros_common/node_utils.hpp"
34 
35 namespace nav2_core
36 {
37 class NavigatorMuxer;
38 
44 {
45  std::string robot_frame;
46  std::string global_frame;
47  double transform_tolerance;
48  nav2::TransformBuffer::SharedPtr tf;
49 };
50 
59 {
60 public:
61  NavigatorBase() = default;
62  virtual ~NavigatorBase() = default;
63 
68  virtual bool on_configure(
69  nav2::LifecycleNode::WeakPtr parent_node,
70  const std::vector<std::string> & plugin_lib_names,
71  const FeedbackUtils & feedback_utils,
72  nav2_core::NavigatorMuxer * plugin_muxer,
73  std::shared_ptr<nav2_util::OdomSmoother> odom_smoother) = 0;
74 
79  virtual bool on_activate() = 0;
80 
85  virtual bool on_deactivate() = 0;
86 
91  virtual bool on_cleanup() = 0;
92 
93  virtual void preempt() = 0;
94 };
95 
102 {
103 public:
108  : current_navigator_(nullptr) {}
109 
115  {
116  std::scoped_lock l(mutex_);
117  return current_navigator_ != nullptr;
118  }
119 
125  {
126  std::scoped_lock l(mutex_);
127  if (current_navigator_ != nullptr) {
128  RCLCPP_ERROR(
129  rclcpp::get_logger("NavigatorMutex"),
130  "Major error! Navigation requested while another navigation"
131  " task is in progress! This likely occurred from an incorrect"
132  "implementation of a navigator plugin.");
133  }
134  current_navigator_ = navigator;
135  }
136 
142  {
143  std::scoped_lock l(mutex_);
144  if (current_navigator_ != navigator) {
145  RCLCPP_ERROR(
146  rclcpp::get_logger("NavigatorMutex"),
147  "Major error! Navigation stopped while another navigation"
148  " task is in progress! This likely occurred from an incorrect"
149  "implementation of a navigator plugin.");
150  } else {
151  current_navigator_ = nullptr;
152  }
153  }
154 
155  void preemptCurrentNavigator()
156  {
157  std::scoped_lock l(mutex_);
158  current_navigator_->preempt();
159  }
160 
167  {
168  std::scoped_lock l(mutex_);
169  return current_navigator_ == navigator;
170  }
171 
172 protected:
173  nav2_core::NavigatorBase * current_navigator_{nullptr};
174  std::mutex mutex_;
175 };
176 
183 template<class ActionT>
185 {
186 public:
187  using Ptr = std::shared_ptr<nav2_core::BehaviorTreeNavigator<ActionT>>;
188 
193  : NavigatorBase()
194  {
195  plugin_muxer_ = nullptr;
196  }
197 
201  virtual ~BehaviorTreeNavigator() = default;
202 
214  nav2::LifecycleNode::WeakPtr parent_node,
215  const std::vector<std::string> & plugin_lib_names,
216  const FeedbackUtils & feedback_utils,
217  nav2_core::NavigatorMuxer * plugin_muxer,
218  std::shared_ptr<nav2_util::OdomSmoother> odom_smoother) final
219  {
220  auto node = parent_node.lock();
221  logger_ = node->get_logger();
222  clock_ = node->get_clock();
223  feedback_utils_ = feedback_utils;
224  plugin_muxer_ = plugin_muxer;
225 
226  // get the default behavior tree for this navigator
227  std::string default_bt_xml_filename = getDefaultBTFilepath(parent_node);
228 
229  auto search_directories = node->declare_or_get_parameter(
230  "bt_search_directories",
231  std::vector<std::string>{nav2::get_package_share_directory(
232  "nav2_bt_navigator") + "/behavior_trees"}
233  );
234 
235  allow_navigator_preemption_ = node->declare_or_get_parameter(
236  "allow_navigator_preemption", false);
237 
238  navigator_preemption_timeout_ = std::chrono::milliseconds(
239  node->declare_or_get_parameter("navigator_preemption_timeout", 500));
240 
241  // Create the Behavior Tree Action Server for this navigator
242  bt_action_server_ =
243  std::make_unique<nav2_behavior_tree::BtActionServer<ActionT, nav2::LifecycleNode>>(
244  node,
245  getName(),
246  plugin_lib_names,
247  default_bt_xml_filename,
248  std::bind(&BehaviorTreeNavigator::onGoalReceived, this, std::placeholders::_1),
249  std::bind(&BehaviorTreeNavigator::onLoop, this),
250  std::bind(&BehaviorTreeNavigator::onPreempt, this, std::placeholders::_1),
251  std::bind(
253  std::placeholders::_1, std::placeholders::_2),
254  search_directories);
255 
256  bool ok = true;
257  if (!bt_action_server_->on_configure()) {
258  ok = false;
259  }
260 
261  BT::Blackboard::Ptr blackboard = bt_action_server_->getBlackboard();
262  blackboard->set("tf_buffer", feedback_utils.tf); // NOLINT
263  blackboard->set("initial_pose_received", false); // NOLINT
264  blackboard->set("number_recoveries", 0); // NOLINT
265  blackboard->set("odom_smoother", odom_smoother); // NOLINT
266 
267  return configure(parent_node, odom_smoother) && ok;
268  }
269 
274  bool on_activate() final
275  {
276  bool ok = true;
277 
278  if (!bt_action_server_->on_activate()) {
279  ok = false;
280  }
281 
282  return activate() && ok;
283  }
284 
289  bool on_deactivate() final
290  {
291  bool ok = true;
292  if (!bt_action_server_->on_deactivate()) {
293  ok = false;
294  }
295 
296  return deactivate() && ok;
297  }
298 
303  bool on_cleanup() final
304  {
305  bool ok = true;
306  if (!bt_action_server_->on_cleanup()) {
307  ok = false;
308  }
309 
310  bt_action_server_.reset();
311 
312  return cleanup() && ok;
313  }
314 
315  virtual std::string getDefaultBTFilepath(nav2::LifecycleNode::WeakPtr node) = 0;
316 
321  virtual std::string getName() = 0;
322 
323  void preempt() final
324  {
325  bt_action_server_->preemptCurrentNavigator();
326  }
327 
328 protected:
332  bool onGoalReceived(typename ActionT::Goal::ConstSharedPtr goal)
333  {
334  if (plugin_muxer_->isNavigating() && !plugin_muxer_->isCurrentNavigator(this)) {
335  // A different navigator is processing; check if cross-navigator preemption is allowed
336  if (!allow_navigator_preemption_) {
337  RCLCPP_ERROR(
338  logger_,
339  "Requested navigation from %s while another navigator is processing,"
340  " rejecting request.", getName().c_str());
341  return false;
342  }
343 
344  RCLCPP_INFO(
345  logger_,
346  "Requested navigation from %s while another navigator is processing,"
347  " stopping current navigator.", getName().c_str());
348  plugin_muxer_->preemptCurrentNavigator();
349 
350  const auto start = std::chrono::steady_clock::now();
351  rclcpp::Rate r(100);
352  while (plugin_muxer_->isNavigating()) {
353  if (std::chrono::steady_clock::now() - start > navigator_preemption_timeout_) {
354  RCLCPP_ERROR(
355  logger_,
356  "Timed out waiting for current navigator to stop before accepting"
357  " goal from %s. Rejecting request.", getName().c_str());
358  return false;
359  }
360  r.sleep();
361  }
362  }
363 
364  bool goal_accepted = goalReceived(goal);
365 
366  if (goal_accepted) {
367  plugin_muxer_->startNavigating(this);
368  }
369 
370  return goal_accepted;
371  }
372 
377  typename ActionT::Result::SharedPtr result,
378  nav2_behavior_tree::BtStatus & final_bt_status)
379  {
380  plugin_muxer_->stopNavigating(this);
381  goalCompleted(result, final_bt_status);
382  }
383 
389  virtual bool goalReceived(typename ActionT::Goal::ConstSharedPtr goal) = 0;
390 
395  virtual void onLoop() = 0;
396 
400  virtual void onPreempt(typename ActionT::Goal::ConstSharedPtr goal) = 0;
401 
406  virtual void goalCompleted(
407  typename ActionT::Result::SharedPtr result,
408  nav2_behavior_tree::BtStatus & final_bt_status) = 0;
409 
413  virtual bool configure(
414  nav2::LifecycleNode::WeakPtr /*node*/,
415  std::shared_ptr<nav2_util::OdomSmoother>/*odom_smoother*/)
416  {
417  return true;
418  }
419 
423  virtual bool cleanup() {return true;}
424 
428  virtual bool activate() {return true;}
429 
433  virtual bool deactivate() {return true;}
434 
435  std::unique_ptr<nav2_behavior_tree::BtActionServer<ActionT, nav2::LifecycleNode>>
436  bt_action_server_;
437  rclcpp::Logger logger_{rclcpp::get_logger("Navigator")};
438  rclcpp::Clock::SharedPtr clock_;
439  FeedbackUtils feedback_utils_;
440  NavigatorMuxer * plugin_muxer_;
441 
442  // True if you want to allow navigator preemption
443  bool allow_navigator_preemption_;
444 
445  // Timeout value while waiting for preemption of a navigator by another one
446  std::chrono::milliseconds navigator_preemption_timeout_;
447 };
448 
449 } // namespace nav2_core
450 
451 #endif // NAV2_CORE__BEHAVIOR_TREE_NAVIGATOR_HPP_
Navigator interface that acts as a base class for all BT-based Navigator action's plugins All methods...
virtual void goalCompleted(typename ActionT::Result::SharedPtr result, nav2_behavior_tree::BtStatus &final_bt_status)=0
A callback that is called when a the action is completed; Can fill in action result message or indica...
virtual void onPreempt(typename ActionT::Goal::ConstSharedPtr goal)=0
A callback that is called when a preempt is requested.
void onCompletion(typename ActionT::Result::SharedPtr result, nav2_behavior_tree::BtStatus &final_bt_status)
An intermediate completion function to mux navigators.
BehaviorTreeNavigator()
A Navigator constructor.
virtual ~BehaviorTreeNavigator()=default
Virtual destructor.
virtual std::string getName()=0
Get the action name of this navigator to expose.
bool onGoalReceived(typename ActionT::Goal::ConstSharedPtr goal)
An intermediate goal reception function to mux navigators.
bool on_cleanup() final
Cleanup a navigator.
virtual bool deactivate()
Method to deactivate and any threads involved in execution.
virtual void onLoop()=0
A callback that defines execution that happens on one iteration through the BT Can be used to publish...
virtual bool activate()
Method to activate any threads involved in execution.
bool on_deactivate() final
Deactivation of the navigator's backend BT and actions.
virtual bool cleanup()
Method to cleanup resources.
virtual bool configure(nav2::LifecycleNode::WeakPtr, std::shared_ptr< nav2_util::OdomSmoother >)
virtual bool goalReceived(typename ActionT::Goal::ConstSharedPtr goal)=0
A callback to be called when a new goal is received by the BT action server Can be used to check if g...
bool on_activate() final
Activation of the navigator's backend BT and actions.
bool on_configure(nav2::LifecycleNode::WeakPtr parent_node, const std::vector< std::string > &plugin_lib_names, const FeedbackUtils &feedback_utils, nav2_core::NavigatorMuxer *plugin_muxer, std::shared_ptr< nav2_util::OdomSmoother > odom_smoother) final
Configuration to setup the navigator's backend BT and actions.
Navigator interface to allow navigators to be stored in a vector and accessed via pluginlib due to te...
virtual bool on_cleanup()=0
Cleanup a navigator.
virtual bool on_deactivate()=0
Deactivation of the navigator's backend BT and actions.
virtual bool on_activate()=0
Activation of the navigator's backend BT and actions.
virtual bool on_configure(nav2::LifecycleNode::WeakPtr parent_node, const std::vector< std::string > &plugin_lib_names, const FeedbackUtils &feedback_utils, nav2_core::NavigatorMuxer *plugin_muxer, std::shared_ptr< nav2_util::OdomSmoother > odom_smoother)=0
Configuration of the navigator's backend BT and actions.
A class to control the state of the BT navigator by allowing only a single plugin to be processed at ...
void stopNavigating(nav2_core::NavigatorBase *navigator)
Stop navigating with a given navigator.
void startNavigating(nav2_core::NavigatorBase *navigator)
Start navigating with a given navigator.
bool isNavigating()
Get the navigator muxer state.
NavigatorMuxer()
A Navigator Muxer constructor.
bool isCurrentNavigator(nav2_core::NavigatorBase *navigator)
Check if the given navigator is the currently active navigator.
Navigator feedback utilities required to get transforms and reference frames.