Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
timed_behavior.hpp
1 // Copyright (c) 2018 Intel Corporation
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_BEHAVIORS__TIMED_BEHAVIOR_HPP_
16 #define NAV2_BEHAVIORS__TIMED_BEHAVIOR_HPP_
17 
18 
19 #include <cstdint>
20 #include <memory>
21 #include <string>
22 #include <cmath>
23 #include <chrono>
24 #include <ctime>
25 #include <thread>
26 #include <utility>
27 
28 #include "rclcpp/clock.hpp"
29 #include "rclcpp/duration.hpp"
30 #include "rclcpp/logger.hpp"
31 #include "rclcpp/logging.hpp"
32 #include "rclcpp/utilities.hpp"
33 #include "nav2_ros_common/tf2_factories.hpp"
34 #include "geometry_msgs/msg/pose_stamped.hpp"
35 #include "geometry_msgs/msg/twist.hpp"
36 #include "nav2_util/robot_utils.hpp"
37 #include "nav2_util/twist_publisher.hpp"
38 #include "nav2_ros_common/simple_action_server.hpp"
39 #include "nav2_ros_common/rate.hpp"
40 #include "nav2_core/behavior.hpp"
41 #include "tf2/utils.hpp"
42 
43 
44 namespace nav2_behaviors
45 {
46 
47 enum class Status : int8_t
48 {
49  SUCCEEDED = 1,
50  FAILED = 2,
51  RUNNING = 3,
52 };
53 
55 {
56  Status status;
57  uint16_t error_code{0};
58  std::string error_msg;
59 };
60 
61 using namespace std::chrono_literals; //NOLINT
62 
67 template<typename ActionT>
69 {
70 public:
72 
77  : action_server_(nullptr),
78  cycle_frequency_(10.0),
79  enabled_(false),
80  transform_tolerance_(0.0)
81  {
82  }
83 
84  virtual ~TimedBehavior() = default;
85 
86  // Derived classes can override this method to catch the command and perform some checks
87  // before getting into the main loop. The method will only be called
88  // once and should return SUCCEEDED otherwise behavior will return FAILED.
89  virtual ResultStatus onRun(const std::shared_ptr<const typename ActionT::Goal> command) = 0;
90 
91 
92  // This is the method derived classes should mainly implement
93  // and will be called cyclically while it returns RUNNING.
94  // Implement the behavior such that it runs some unit of work on each call
95  // and provides a status. The Behavior will finish once SUCCEEDED is returned
96  // It's up to the derived class to define the final commanded velocity.
97  virtual ResultStatus onCycleUpdate() = 0;
98 
99  // an opportunity for derived classes to do something on configuration
100  // if they chose
101  virtual void onConfigure()
102  {
103  }
104 
105  // an opportunity for derived classes to do something on cleanup
106  // if they chose
107  virtual void onCleanup()
108  {
109  }
110 
111  // an opportunity for a derived class to do something on action completion
112  virtual void onActionCompletion(std::shared_ptr<typename ActionT::Result>/*result*/)
113  {
114  }
115 
116  // configure the server on lifecycle setup
117  void configure(
118  const nav2::LifecycleNode::WeakPtr & parent,
119  const std::string & name, nav2::TransformBuffer::SharedPtr tf,
120  std::shared_ptr<nav2_costmap_2d::CostmapTopicCollisionChecker> local_collision_checker,
121  std::shared_ptr<nav2_costmap_2d::CostmapTopicCollisionChecker> global_collision_checker)
122  override
123  {
124  node_ = parent;
125  auto node = node_.lock();
126  logger_ = node->get_logger();
127  clock_ = node->get_clock();
128 
129  RCLCPP_INFO(logger_, "Configuring %s", name.c_str());
130 
131  behavior_name_ = name;
132  tf_ = tf;
133 
134  node->get_parameter("cycle_frequency", cycle_frequency_);
135  node->get_parameter("local_frame", local_frame_);
136  node->get_parameter("global_frame", global_frame_);
137  node->get_parameter("robot_base_frame", robot_base_frame_);
138  node->get_parameter("transform_tolerance", transform_tolerance_);
139 
140  action_server_ = node->create_action_server<ActionT>(
141  behavior_name_,
142  std::bind(&TimedBehavior::execute, this), nullptr, nullptr, std::chrono::milliseconds(
143  500), false);
144 
145  local_collision_checker_ = local_collision_checker;
146  global_collision_checker_ = global_collision_checker;
147 
148  vel_pub_ = std::make_unique<nav2_util::TwistPublisher>(node, "cmd_vel");
149 
150  onConfigure();
151  }
152 
153  // Cleanup server on lifecycle transition
154  void cleanup() override
155  {
156  action_server_.reset();
157  vel_pub_.reset();
158  onCleanup();
159  }
160 
161  // Activate server on lifecycle transition
162  void activate() override
163  {
164  RCLCPP_INFO(logger_, "Activating %s", behavior_name_.c_str());
165 
166  vel_pub_->on_activate();
167  action_server_->activate();
168  enabled_ = true;
169  }
170 
171  // Deactivate server on lifecycle transition
172  void deactivate() override
173  {
174  vel_pub_->on_deactivate();
175  action_server_->deactivate();
176  enabled_ = false;
177  }
178 
179 protected:
180  nav2::LifecycleNode::WeakPtr node_;
181 
182  std::string behavior_name_;
183  std::unique_ptr<nav2_util::TwistPublisher> vel_pub_;
184  typename ActionServer::SharedPtr action_server_;
185  std::shared_ptr<nav2_costmap_2d::CostmapTopicCollisionChecker> local_collision_checker_;
186  std::shared_ptr<nav2_costmap_2d::CostmapTopicCollisionChecker> global_collision_checker_;
187  nav2::TransformBuffer::SharedPtr tf_;
188 
189  double cycle_frequency_;
190  double enabled_;
191  std::string local_frame_;
192  std::string global_frame_;
193  std::string robot_base_frame_;
194  double transform_tolerance_;
195  rclcpp::Duration elapsed_time_{0, 0};
196 
197  // Clock
198  rclcpp::Clock::SharedPtr clock_;
199 
200  // Logger
201  rclcpp::Logger logger_{rclcpp::get_logger("nav2_behaviors")};
202 
203  // Main execution callbacks for the action server implementation calling the Behavior's
204  // onRun and cycle functions to execute a specific behavior
205  void execute()
206  {
207  RCLCPP_INFO(logger_, "Running %s", behavior_name_.c_str());
208 
209  if (!enabled_) {
210  RCLCPP_WARN(
211  logger_,
212  "Called while inactive, ignoring request.");
213  return;
214  }
215 
216  // Initialize the ActionT result
217  auto result = std::make_shared<typename ActionT::Result>();
218 
219  ResultStatus on_run_result = onRun(action_server_->get_current_goal());
220  if (on_run_result.status != Status::SUCCEEDED) {
221  result->error_code = on_run_result.error_code;
222  result->error_msg = on_run_result.error_msg;
223  RCLCPP_INFO(
224  logger_, "Initial checks failed for %s - %s", behavior_name_.c_str(),
225  on_run_result.error_msg.c_str());
226  action_server_->terminate_current(result);
227  return;
228  }
229 
230  auto start_time = clock_->now();
231  auto node = node_.lock();
232  if (!node) {
233  RCLCPP_ERROR(
234  logger_,
235  "Failed to run %s because the parent node is no longer available.",
236  behavior_name_.c_str());
237  result->error_msg = behavior_name_ + " failed: parent node expired";
238  result->total_elapsed_time = clock_->now() - start_time;
239  onActionCompletion(result);
240  action_server_->terminate_current(result);
241  return;
242  }
243  nav2::Rate loop_rate(node, cycle_frequency_);
244 
245  while (rclcpp::ok()) {
246  elapsed_time_ = clock_->now() - start_time;
247  // TODO(orduno) #868 Enable preempting a Behavior on-the-fly without stopping
248  if (action_server_->is_preempt_requested()) {
249  RCLCPP_ERROR(
250  logger_, "Received a preemption request for %s,"
251  " however feature is currently not implemented. Aborting and stopping.",
252  behavior_name_.c_str());
253  stopRobot();
254  result->total_elapsed_time = clock_->now() - start_time;
255  onActionCompletion(result);
256  action_server_->terminate_current(result);
257  return;
258  }
259 
260  if (action_server_->is_cancel_requested()) {
261  RCLCPP_INFO(logger_, "Canceling %s", behavior_name_.c_str());
262  stopRobot();
263  result->total_elapsed_time = elapsed_time_;
264  onActionCompletion(result);
265  action_server_->terminate_all(result);
266  return;
267  }
268 
269  ResultStatus on_cycle_update_result = onCycleUpdate();
270  switch (on_cycle_update_result.status) {
271  case Status::SUCCEEDED:
272  RCLCPP_INFO(
273  logger_,
274  "%s completed successfully", behavior_name_.c_str());
275  result->total_elapsed_time = clock_->now() - start_time;
276  onActionCompletion(result);
277  action_server_->succeeded_current(result);
278  return;
279 
280  case Status::FAILED:
281  stopRobot();
282  result->error_code = on_cycle_update_result.error_code;
283  result->error_msg = behavior_name_ + " failed:" + on_cycle_update_result.error_msg;
284  RCLCPP_WARN(logger_, "%s", result->error_msg.c_str());
285  result->total_elapsed_time = clock_->now() - start_time;
286  onActionCompletion(result);
287  action_server_->terminate_current(result);
288  return;
289 
290  case Status::RUNNING:
291 
292  default:
293  loop_rate.sleep();
294  break;
295  }
296  }
297  }
298 
299  // Stop the robot with a commanded velocity
300  void stopRobot()
301  {
302  auto cmd_vel = std::make_unique<geometry_msgs::msg::TwistStamped>();
303  cmd_vel->header.frame_id = robot_base_frame_;
304  cmd_vel->header.stamp = clock_->now();
305  cmd_vel->twist.linear.x = 0.0;
306  cmd_vel->twist.linear.y = 0.0;
307  cmd_vel->twist.angular.z = 0.0;
308 
309  vel_pub_->publish(std::move(cmd_vel));
310  }
311 };
312 
313 } // namespace nav2_behaviors
314 
315 #endif // NAV2_BEHAVIORS__TIMED_BEHAVIOR_HPP_
A sim-time-aware rate for Nav2 loops.
Definition: rate.hpp:61
An action server wrapper to make applications simpler using Actions.
TimedBehavior()
A TimedBehavior constructor.
void deactivate() override
Method to deactivate Behavior and any threads involved in execution.
void activate() override
Method to active Behavior and any threads involved in execution.
void configure(const nav2::LifecycleNode::WeakPtr &parent, const std::string &name, nav2::TransformBuffer::SharedPtr tf, std::shared_ptr< nav2_costmap_2d::CostmapTopicCollisionChecker > local_collision_checker, std::shared_ptr< nav2_costmap_2d::CostmapTopicCollisionChecker > global_collision_checker) override
void cleanup() override
Method to cleanup resources used on shutdown.
Abstract interface for behaviors to adhere to with pluginlib.
Definition: behavior.hpp:41