Nav2 Navigation Stack - rolling  main
ROS 2 Navigation Stack
controller_server.cpp
1 // Copyright (c) 2019 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 #include <chrono>
16 #include <vector>
17 #include <memory>
18 #include <string>
19 #include <utility>
20 #include <limits>
21 
22 #include "lifecycle_msgs/msg/state.hpp"
23 #include "nav2_core/controller_exceptions.hpp"
24 #include "nav2_ros_common/node_utils.hpp"
25 #include "nav2_ros_common/rate.hpp"
26 #include "nav2_util/geometry_utils.hpp"
27 #include "nav2_util/path_utils.hpp"
28 #include "nav2_util/robot_utils.hpp"
29 #include "nav2_controller/controller_server.hpp"
30 
31 using namespace std::chrono_literals;
32 using rcl_interfaces::msg::ParameterType;
33 using std::placeholders::_1;
34 using nav2_util::geometry_utils::euclidean_distance;
35 
36 namespace nav2_controller
37 {
38 
39 ControllerServer::ControllerServer(const rclcpp::NodeOptions & options)
40 : nav2::LifecycleNode("controller_server", "", options),
41  progress_checker_loader_("nav2_core", "nav2_core::ProgressChecker"),
42  goal_checker_loader_("nav2_core", "nav2_core::GoalChecker"),
43  lp_loader_("nav2_core", "nav2_core::Controller"),
44  path_handler_loader_("nav2_core", "nav2_core::PathHandler"),
45  start_index_(0)
46 {
47  RCLCPP_INFO(get_logger(), "Creating controller server");
48 
49  // The costmap node is used in the implementation of the controller
50  costmap_ros_ = std::make_shared<nav2_costmap_2d::Costmap2DROS>(
51  "local_costmap", std::string{get_namespace()},
52  get_parameter("use_sim_time").as_bool(), options);
53 }
54 
56 {
57  progress_checkers_.clear();
58  goal_checkers_.clear();
59  controllers_.clear();
60  path_handlers_.clear();
61  costmap_thread_.reset();
62 }
63 
64 nav2::CallbackReturn
65 ControllerServer::on_configure(const rclcpp_lifecycle::State & state)
66 {
67  auto node = shared_from_this();
68 
69  RCLCPP_INFO(get_logger(), "Configuring controller interface");
70 
71  if (costmap_ros_->configure().id() !=
72  lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE)
73  {
74  return nav2::CallbackReturn::FAILURE;
75  }
76  // Launch a thread to run the costmap node
77  costmap_thread_ = std::make_unique<nav2::NodeThread>(costmap_ros_);
78  transform_tolerance_ = costmap_ros_->getTransformTolerance();
79  try {
80  param_handler_ = std::make_unique<ParameterHandler>(
81  node, get_logger());
82  } catch (const std::exception & ex) {
83  RCLCPP_FATAL(get_logger(), "%s", ex.what());
84  on_cleanup(state);
85  return nav2::CallbackReturn::FAILURE;
86  }
87  params_ = param_handler_->getParams();
88 
89  for (size_t i = 0; i != params_->progress_checker_ids.size(); i++) {
90  try {
91  nav2_core::ProgressChecker::Ptr progress_checker =
92  progress_checker_loader_.createUniqueInstance(params_->progress_checker_types[i]);
93  RCLCPP_INFO(
94  get_logger(), "Created progress_checker : %s of type %s",
95  params_->progress_checker_ids[i].c_str(), params_->progress_checker_types[i].c_str());
96  progress_checkers_.insert({params_->progress_checker_ids[i], progress_checker});
97  } catch (const std::exception & ex) {
98  RCLCPP_FATAL(
99  get_logger(),
100  "Failed to create progress_checker. Exception: %s", ex.what());
101  on_cleanup(state);
102  return nav2::CallbackReturn::FAILURE;
103  }
104  }
105 
106  for (size_t i = 0; i != params_->progress_checker_ids.size(); i++) {
107  progress_checker_ids_concat_ += params_->progress_checker_ids[i] + std::string(" ");
108  }
109  if (progress_checker_ids_concat_.empty()) {
110  progress_checker_ids_concat_ = "(none)";
111  }
112 
113  RCLCPP_INFO(
114  get_logger(),
115  "Controller Server has %s progress checkers available.", progress_checker_ids_concat_.c_str());
116 
117  for (size_t i = 0; i != params_->goal_checker_ids.size(); i++) {
118  try {
119  nav2_core::GoalChecker::Ptr goal_checker =
120  goal_checker_loader_.createUniqueInstance(params_->goal_checker_types[i]);
121  RCLCPP_INFO(
122  get_logger(), "Created goal checker : %s of type %s",
123  params_->goal_checker_ids[i].c_str(), params_->goal_checker_types[i].c_str());
124  goal_checkers_.insert({params_->goal_checker_ids[i], goal_checker});
125  } catch (const pluginlib::PluginlibException & ex) {
126  RCLCPP_FATAL(
127  get_logger(),
128  "Failed to create goal checker. Exception: %s", ex.what());
129  on_cleanup(state);
130  return nav2::CallbackReturn::FAILURE;
131  }
132  }
133 
134  for (size_t i = 0; i != params_->goal_checker_ids.size(); i++) {
135  goal_checker_ids_concat_ += params_->goal_checker_ids[i] + std::string(" ");
136  }
137 
138  RCLCPP_INFO(
139  get_logger(),
140  "Controller Server has %s goal checkers available.", goal_checker_ids_concat_.c_str());
141 
142  for (size_t i = 0; i != params_->path_handler_ids.size(); i++) {
143  try {
144  nav2_core::PathHandler::Ptr path_handler =
145  path_handler_loader_.createUniqueInstance(params_->path_handler_types[i]);
146  RCLCPP_INFO(
147  get_logger(), "Created path handler : %s of type %s",
148  params_->path_handler_ids[i].c_str(), params_->path_handler_types[i].c_str());
149  path_handlers_.insert({params_->path_handler_ids[i], path_handler});
150  } catch (const pluginlib::PluginlibException & ex) {
151  RCLCPP_FATAL(
152  get_logger(),
153  "Failed to create path handler Exception: %s", ex.what());
154  on_cleanup(state);
155  return nav2::CallbackReturn::FAILURE;
156  }
157  }
158 
159  for (size_t i = 0; i != params_->path_handler_ids.size(); i++) {
160  path_handler_ids_concat_ += params_->path_handler_ids[i] + std::string(" ");
161  }
162 
163  RCLCPP_INFO(
164  get_logger(),
165  "Controller Server has %s path handlers available.", path_handler_ids_concat_.c_str());
166 
167  for (size_t i = 0; i != params_->controller_ids.size(); i++) {
168  try {
169  nav2_core::Controller::Ptr controller =
170  lp_loader_.createUniqueInstance(params_->controller_types[i]);
171  RCLCPP_INFO(
172  get_logger(), "Created controller : %s of type %s",
173  params_->controller_ids[i].c_str(), params_->controller_types[i].c_str());
174  controller->configure(
175  node, params_->controller_ids[i],
176  costmap_ros_->getTfBuffer(), costmap_ros_);
177  controllers_.insert({params_->controller_ids[i], controller});
178  } catch (const pluginlib::PluginlibException & ex) {
179  RCLCPP_FATAL(
180  get_logger(),
181  "Failed to create controller. Exception: %s", ex.what());
182  on_cleanup(state);
183  return nav2::CallbackReturn::FAILURE;
184  }
185  }
186 
187  for (size_t i = 0; i != params_->controller_ids.size(); i++) {
188  controller_ids_concat_ += params_->controller_ids[i] + std::string(" ");
189  }
190 
191  RCLCPP_INFO(
192  get_logger(),
193  "Controller Server has %s controllers available.", controller_ids_concat_.c_str());
194 
195  odom_sub_ = std::make_unique<nav2_util::OdomSmoother>(node, params_->odom_duration,
196  params_->odom_topic);
197  vel_publisher_ = std::make_unique<nav2_util::TwistPublisher>(node, "cmd_vel");
198  transformed_plan_pub_ = create_publisher<nav_msgs::msg::Path>("transformed_global_plan");
199  tracking_feedback_pub_ = create_publisher<nav2_msgs::msg::TrackingFeedback>("tracking_feedback");
200 
201  // Create the action server that we implement with our followPath method
202  // This may throw due to real-time prioritization if user doesn't have real-time permissions
203  try {
204  action_server_ = create_action_server<Action>(
205  "follow_path",
206  std::bind(&ControllerServer::computeControl, this),
207  std::bind(&ControllerServer::goalReceived, this, std::placeholders::_1),
208  nullptr,
209  std::chrono::milliseconds(500),
210  true /*spin thread*/, params_->use_realtime_priority /*soft realtime*/);
211  } catch (const std::runtime_error & e) {
212  RCLCPP_ERROR(get_logger(), "Error creating action server! %s", e.what());
213  on_cleanup(state);
214  return nav2::CallbackReturn::FAILURE;
215  }
216 
217  // Set subscription to the speed limiting topic
218  speed_limit_sub_ = create_subscription<nav2_msgs::msg::SpeedLimit>(
219  params_->speed_limit_topic,
220  std::bind(&ControllerServer::speedLimitCallback, this, std::placeholders::_1));
221 
222  return nav2::CallbackReturn::SUCCESS;
223 }
224 
225 nav2::CallbackReturn
226 ControllerServer::on_activate(const rclcpp_lifecycle::State & /*state*/)
227 {
228  RCLCPP_INFO(get_logger(), "Activating");
229 
230  const auto costmap_ros_state = costmap_ros_->activate();
231  if (costmap_ros_state.id() != lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE) {
232  return nav2::CallbackReturn::FAILURE;
233  }
234  ControllerMap::iterator it;
235  for (it = controllers_.begin(); it != controllers_.end(); ++it) {
236  it->second->activate();
237  }
238  vel_publisher_->on_activate();
239  transformed_plan_pub_->on_activate();
240  tracking_feedback_pub_->on_activate();
241  action_server_->activate();
242  param_handler_->activate();
243 
244  // activate goal checker, progress checker and path handler
245  auto node = shared_from_this();
246  for (auto & pc : progress_checkers_) {
247  pc.second->initialize(node, pc.first);
248  }
249  for (auto & gc : goal_checkers_) {
250  gc.second->initialize(node, gc.first, costmap_ros_);
251  }
252  for (auto & ph : path_handlers_) {
253  ph.second->initialize(
254  node, get_logger(), ph.first, costmap_ros_,
255  costmap_ros_->getTfBuffer());
256  }
257 
258  // create bond connection
259  createBond();
260 
261  return nav2::CallbackReturn::SUCCESS;
262 }
263 
264 nav2::CallbackReturn
265 ControllerServer::on_deactivate(const rclcpp_lifecycle::State & /*state*/)
266 {
267  RCLCPP_INFO(get_logger(), "Deactivating");
268 
269  action_server_->deactivate();
270  ControllerMap::iterator it;
271  for (it = controllers_.begin(); it != controllers_.end(); ++it) {
272  it->second->deactivate();
273  }
274 
275  /*
276  * The costmap is also a lifecycle node, so it may have already fired on_deactivate
277  * via rcl preshutdown cb. Despite the rclcpp docs saying on_shutdown callbacks fire
278  * in the order added, the preshutdown callbacks clearly don't per se, due to using an
279  * unordered_set iteration. Once this issue is resolved, we can maybe make a stronger
280  * ordering assumption: https://github.com/ros2/rclcpp/issues/2096
281  */
282  costmap_ros_->deactivate();
283 
285  vel_publisher_->on_deactivate();
286  transformed_plan_pub_->on_deactivate();
287  tracking_feedback_pub_->on_deactivate();
288  param_handler_->deactivate();
289 
290  // destroy bond connection
291  destroyBond();
292 
293  return nav2::CallbackReturn::SUCCESS;
294 }
295 
296 nav2::CallbackReturn
297 ControllerServer::on_cleanup(const rclcpp_lifecycle::State & /*state*/)
298 {
299  RCLCPP_INFO(get_logger(), "Cleaning up");
300 
301  // Cleanup the helper classes
302  ControllerMap::iterator it;
303  for (it = controllers_.begin(); it != controllers_.end(); ++it) {
304  it->second->cleanup();
305  }
306  controllers_.clear();
307 
308  goal_checkers_.clear();
309  progress_checkers_.clear();
310  path_handlers_.clear();
311 
312  costmap_ros_->cleanup();
313 
314 
315  // Release any allocated resources
316  action_server_.reset();
317  odom_sub_.reset();
318  costmap_thread_.reset();
319  vel_publisher_.reset();
320  transformed_plan_pub_.reset();
321  tracking_feedback_pub_.reset();
322  speed_limit_sub_.reset();
323 
324  return nav2::CallbackReturn::SUCCESS;
325 }
326 
327 nav2::CallbackReturn
328 ControllerServer::on_shutdown(const rclcpp_lifecycle::State &)
329 {
330  RCLCPP_INFO(get_logger(), "Shutting down");
331  return nav2::CallbackReturn::SUCCESS;
332 }
333 
335  const std::string & c_name,
336  std::string & current_controller)
337 {
338  if (controllers_.find(c_name) == controllers_.end()) {
339  if (controllers_.size() == 1 && c_name.empty()) {
340  RCLCPP_WARN_ONCE(
341  get_logger(), "No controller was specified in action call."
342  " Server will use only plugin loaded %s. "
343  "This warning will appear once.", controller_ids_concat_.c_str());
344  current_controller = controllers_.begin()->first;
345  } else {
346  RCLCPP_ERROR(
347  get_logger(), "FollowPath called with controller name %s, "
348  "which does not exist. Available controllers are: %s.",
349  c_name.c_str(), controller_ids_concat_.c_str());
350  return false;
351  }
352  } else {
353  RCLCPP_DEBUG(get_logger(), "Selected controller: %s.", c_name.c_str());
354  current_controller = c_name;
355  }
356 
357  return true;
358 }
359 
361  const std::string & c_name,
362  std::string & current_goal_checker)
363 {
364  if (goal_checkers_.find(c_name) == goal_checkers_.end()) {
365  if (goal_checkers_.size() == 1 && c_name.empty()) {
366  RCLCPP_WARN_ONCE(
367  get_logger(), "No goal checker was specified in parameter 'current_goal_checker'."
368  " Server will use only plugin loaded %s. "
369  "This warning will appear once.", goal_checker_ids_concat_.c_str());
370  current_goal_checker = goal_checkers_.begin()->first;
371  } else {
372  RCLCPP_ERROR(
373  get_logger(), "FollowPath called with goal_checker name %s in parameter"
374  " 'current_goal_checker', which does not exist. Available goal checkers are: %s.",
375  c_name.c_str(), goal_checker_ids_concat_.c_str());
376  return false;
377  }
378  } else {
379  RCLCPP_DEBUG(get_logger(), "Selected goal checker: %s.", c_name.c_str());
380  current_goal_checker = c_name;
381  }
382 
383  return true;
384 }
385 
387  const std::string & c_name,
388  std::string & current_progress_checker)
389 {
390  if (progress_checkers_.size() == 0) {
391  if (c_name.empty()) {
392  RCLCPP_DEBUG(
393  get_logger(),
394  "No progress checker configured and none requested. Progress checking will be bypassed.");
395  current_progress_checker = "";
396  return true;
397  } else {
398  RCLCPP_ERROR(
399  get_logger(), "FollowPath called with progress_checker name %s in parameter"
400  " 'current_progress_checker', but no progress checkers are configured.",
401  c_name.c_str());
402  return false;
403  }
404  }
405 
406  if (progress_checkers_.find(c_name) == progress_checkers_.end()) {
407  if (progress_checkers_.size() == 1 && c_name.empty()) {
408  RCLCPP_WARN_ONCE(
409  get_logger(), "No progress checker was specified in parameter 'current_progress_checker'."
410  " Server will use only plugin loaded %s. "
411  "This warning will appear once.", progress_checker_ids_concat_.c_str());
412  current_progress_checker = progress_checkers_.begin()->first;
413  } else {
414  RCLCPP_ERROR(
415  get_logger(), "FollowPath called with progress_checker name %s in parameter"
416  " 'current_progress_checker', which does not exist. Available progress checkers are: %s.",
417  c_name.c_str(), progress_checker_ids_concat_.c_str());
418  return false;
419  }
420  } else {
421  RCLCPP_DEBUG(get_logger(), "Selected progress checker: %s.", c_name.c_str());
422  current_progress_checker = c_name;
423  }
424 
425  return true;
426 }
427 
429  const std::string & c_name,
430  std::string & current_path_handler)
431 {
432  if (path_handlers_.find(c_name) == path_handlers_.end()) {
433  if (path_handlers_.size() == 1 && c_name.empty()) {
434  RCLCPP_WARN_ONCE(
435  get_logger(), "No path handler was specified in parameter 'current_path_handler'."
436  " Server will use only plugin loaded %s. "
437  "This warning will appear once.", path_handler_ids_concat_.c_str());
438  current_path_handler = path_handlers_.begin()->first;
439  } else {
440  RCLCPP_ERROR(
441  get_logger(), "FollowPath called with path_handler name %s in parameter"
442  " 'current_path_handler', which does not exist. Available path handlers are: %s.",
443  c_name.c_str(), path_handler_ids_concat_.c_str());
444  return false;
445  }
446  } else {
447  RCLCPP_DEBUG(get_logger(), "Selected path handler: %s.", c_name.c_str());
448  current_path_handler = c_name;
449  }
450 
451  return true;
452 }
453 
454 bool ControllerServer::goalReceived(std::shared_ptr<const Action::Goal> goal)
455 {
456  std::string current_controller;
457  if (!findControllerId(goal->controller_id, current_controller)) {
458  RCLCPP_WARN(
459  get_logger(),
460  "Requested controller %s is not available.", goal->controller_id.c_str());
461  return false;
462  }
463 
464  std::string current_goal_checker;
465  if (!findGoalCheckerId(goal->goal_checker_id, current_goal_checker)) {
466  RCLCPP_WARN(
467  get_logger(),
468  "Requested goal checker %s is not available.", goal->goal_checker_id.c_str());
469  return false;
470  }
471 
472  std::string current_progress_checker;
473  if (!findProgressCheckerId(goal->progress_checker_id, current_progress_checker)) {
474  RCLCPP_WARN(
475  get_logger(),
476  "Requested progress checker %s is not available.", goal->progress_checker_id.c_str());
477  return false;
478  }
479 
480  std::string current_path_handler;
481  if (!findPathHandlerId(goal->path_handler_id, current_path_handler)) {
482  RCLCPP_WARN(
483  get_logger(),
484  "Requested path handler %s is not available.", goal->path_handler_id.c_str());
485  return false;
486  }
487 
488  if (goal->path.poses.empty()) {
489  RCLCPP_WARN(get_logger(), "Requested path to follow is empty.");
490  return false;
491  }
492 
493  return true;
494 }
495 
497 {
498  std::lock_guard<std::mutex> lock_reinit(param_handler_->getMutex());
499 
500  RCLCPP_INFO(get_logger(), "Received a goal, begin computing control effort.");
501 
502  try {
503  auto goal = action_server_->get_current_goal();
504  if (!goal) {
505  return; // goal would be nullptr if action_server_ is deactivate.
506  }
507 
508  std::string c_name = goal->controller_id;
509  std::string current_controller;
510  if (findControllerId(c_name, current_controller)) {
511  current_controller_ = current_controller;
512  } else {
513  throw nav2_core::InvalidController("Failed to find controller name: " + c_name);
514  }
515 
516  std::string gc_name = goal->goal_checker_id;
517  std::string current_goal_checker;
518  if (findGoalCheckerId(gc_name, current_goal_checker)) {
519  current_goal_checker_ = current_goal_checker;
520  } else {
521  throw nav2_core::ControllerException("Failed to find goal checker name: " + gc_name);
522  }
523 
524  std::string pc_name = goal->progress_checker_id;
525  std::string current_progress_checker;
526  if (findProgressCheckerId(pc_name, current_progress_checker)) {
527  current_progress_checker_ = current_progress_checker;
528  } else {
529  throw nav2_core::ControllerException("Failed to find progress checker name: " + pc_name);
530  }
531 
532  std::string ph_name = goal->path_handler_id;
533  std::string current_path_handler;
534  if(findPathHandlerId(ph_name, current_path_handler)) {
535  current_path_handler_ = current_path_handler;
536  } else {
537  throw nav2_core::ControllerException("Failed to find path handler name: " + ph_name);
538  }
539 
540  setPlannerPath(goal->path);
541  if (!current_progress_checker_.empty()) {
542  progress_checkers_[current_progress_checker_]->reset();
543  }
544 
545  last_valid_cmd_time_ = now();
546  nav2::Rate loop_rate(this, params_->controller_frequency);
547  while (rclcpp::ok()) {
548  auto start_time = this->now();
549 
550  if (action_server_ == nullptr || !action_server_->is_server_active()) {
551  RCLCPP_DEBUG(get_logger(), "Action server unavailable or inactive. Stopping.");
552  return;
553  }
554 
555  if (action_server_->is_cancel_requested()) {
556  if (controllers_[current_controller_]->cancel()) {
557  RCLCPP_INFO(get_logger(), "Cancellation was successful. Stopping the robot.");
558  action_server_->terminate_all();
559  onGoalExit(true);
560  return;
561  } else {
562  RCLCPP_INFO_THROTTLE(
563  get_logger(), *get_clock(), 1000, "Waiting for the controller to finish cancellation");
564  }
565  }
566 
567  // Don't compute a trajectory until costmap is valid (after clear costmap)
568  double costmap_wait = waitForCostmap();
569 
571 
572  // The last known pose in the local map frame is retrieved without waiting.
573  // Its value and timestamp are reused across this control cycle.
574  const auto current_robot_pose = getCurrentRobotPose();
575 
576  // Refresh the transformed plan and goal together so they share a single map->odom snapshot
577  transformedPlanAndGoal(current_robot_pose);
578 
579  if (isGoalReached(current_robot_pose)) {
580  RCLCPP_INFO(get_logger(), "Reached the goal!");
581  break;
582  }
583 
584  computeAndPublishVelocity(current_robot_pose);
585 
586  auto cycle_duration = this->now() - start_time;
587  if (!loop_rate.sleep()) {
588  RCLCPP_WARN(
589  get_logger(),
590  "Control loop missed its desired rate of %.4f Hz. Current loop rate is %.4f Hz."
591  "%s",
592  params_->controller_frequency, 1 / cycle_duration.seconds(),
593  costmap_wait > 0.0 ?
594  (" Waited " + std::to_string(costmap_wait) + "s for costmap update.").c_str() : "");
595  loop_rate.reset();
596  }
597  }
598  } catch (nav2_core::InvalidController & e) {
599  RCLCPP_ERROR(this->get_logger(), "%s", e.what());
600  onGoalExit(true);
601  std::shared_ptr<Action::Result> result = std::make_shared<Action::Result>();
602  result->error_code = Action::Result::INVALID_CONTROLLER;
603  result->error_msg = e.what();
604  action_server_->terminate_current(result);
605  return;
606  } catch (nav2_core::ControllerTFError & e) {
607  RCLCPP_ERROR(this->get_logger(), "%s", e.what());
608  onGoalExit(true);
609  std::shared_ptr<Action::Result> result = std::make_shared<Action::Result>();
610  result->error_code = Action::Result::TF_ERROR;
611  result->error_msg = e.what();
612  action_server_->terminate_current(result);
613  return;
614  } catch (nav2_core::NoValidControl & e) {
615  RCLCPP_ERROR(this->get_logger(), "%s", e.what());
616  onGoalExit(true);
617  std::shared_ptr<Action::Result> result = std::make_shared<Action::Result>();
618  result->error_code = Action::Result::NO_VALID_CONTROL;
619  result->error_msg = e.what();
620  action_server_->terminate_current(result);
621  return;
622  } catch (nav2_core::FailedToMakeProgress & e) {
623  RCLCPP_ERROR(this->get_logger(), "%s", e.what());
624  onGoalExit(true);
625  std::shared_ptr<Action::Result> result = std::make_shared<Action::Result>();
626  result->error_code = Action::Result::FAILED_TO_MAKE_PROGRESS;
627  result->error_msg = e.what();
628  action_server_->terminate_current(result);
629  return;
630  } catch (nav2_core::PatienceExceeded & e) {
631  RCLCPP_ERROR(this->get_logger(), "%s", e.what());
632  onGoalExit(true);
633  std::shared_ptr<Action::Result> result = std::make_shared<Action::Result>();
634  result->error_code = Action::Result::PATIENCE_EXCEEDED;
635  result->error_msg = e.what();
636  action_server_->terminate_current(result);
637  return;
638  } catch (nav2_core::InvalidPath & e) {
639  RCLCPP_ERROR(this->get_logger(), "%s", e.what());
640  onGoalExit(true);
641  std::shared_ptr<Action::Result> result = std::make_shared<Action::Result>();
642  result->error_code = Action::Result::INVALID_PATH;
643  result->error_msg = e.what();
644  action_server_->terminate_current(result);
645  return;
646  } catch (nav2_core::ControllerTimedOut & e) {
647  RCLCPP_ERROR(this->get_logger(), "%s", e.what());
648  onGoalExit(true);
649  std::shared_ptr<Action::Result> result = std::make_shared<Action::Result>();
650  result->error_code = Action::Result::CONTROLLER_TIMED_OUT;
651  result->error_msg = e.what();
652  action_server_->terminate_current(result);
653  return;
654  } catch (nav2_core::ControllerException & e) {
655  RCLCPP_ERROR(this->get_logger(), "%s", e.what());
656  onGoalExit(true);
657  std::shared_ptr<Action::Result> result = std::make_shared<Action::Result>();
658  result->error_code = Action::Result::UNKNOWN;
659  result->error_msg = e.what();
660  action_server_->terminate_current(result);
661  return;
662  } catch (std::exception & e) {
663  RCLCPP_ERROR(this->get_logger(), "%s", e.what());
664  onGoalExit(true);
665  std::shared_ptr<Action::Result> result = std::make_shared<Action::Result>();
666  result->error_code = Action::Result::UNKNOWN;
667  result->error_msg = e.what();
668  action_server_->terminate_current(result);
669  return;
670  }
671 
672  RCLCPP_DEBUG(get_logger(), "Controller succeeded, setting result");
673 
674  onGoalExit(false);
675 
676  // TODO(orduno) #861 Handle a pending preemption and set controller name
677  action_server_->succeeded_current();
678 }
679 
681 {
682  if (params_->costmap_update_timeout > rclcpp::Duration(0, 0)) {
683  auto waiting_start = now();
684  bool was_waiting = !costmap_ros_->isCurrent();
685  try {
686  costmap_ros_->waitUntilCurrent(params_->costmap_update_timeout);
687  } catch (const std::runtime_error & ex) {
688  throw nav2_core::ControllerTimedOut(ex.what());
689  }
690  if (was_waiting) {
691  return (now() - waiting_start).seconds();
692  }
693  }
694  return 0.0;
695 }
696 
697 void ControllerServer::setPlannerPath(const nav_msgs::msg::Path & path)
698 {
699  RCLCPP_DEBUG(
700  get_logger(),
701  "Providing path to the controller %s", current_controller_.c_str());
702  if (path.poses.empty()) {
703  throw nav2_core::InvalidPath("Path is empty.");
704  }
705  controllers_[current_controller_]->newPathReceived(path);
706  path_handlers_[current_path_handler_]->setPlan(path);
707 
708  end_pose_ = path.poses.back();
709  end_pose_.header.frame_id = path.header.frame_id;
710  goal_checkers_[current_goal_checker_]->reset();
711 
712  RCLCPP_DEBUG(
713  get_logger(), "Path end point is (%.2f, %.2f)",
714  end_pose_.pose.position.x, end_pose_.pose.position.y);
715 
716  start_index_ = 0;
717  current_path_ = path;
718 }
719 
721  const geometry_msgs::msg::PoseStamped & current_robot_pose)
722 {
723  end_pose_.header.stamp = current_robot_pose.header.stamp;
724  if (!nav2_util::transformPoseInTargetFrame(
725  end_pose_, transformed_end_pose_, *costmap_ros_->getTfBuffer(),
726  costmap_ros_->getGlobalFrameID(), transform_tolerance_))
727  {
728  throw nav2_core::ControllerTFError("Failed to transform end pose to global frame");
729  }
730 
731  auto [closest_point, pruned_plan_end] =
732  path_handlers_[current_path_handler_]->findPlanSegment(current_robot_pose);
733  transformed_global_plan_ =
734  path_handlers_[current_path_handler_]->transformLocalPlan(closest_point, pruned_plan_end);
735 
736  auto path = std::make_unique<nav_msgs::msg::Path>(transformed_global_plan_);
737  if (transformed_plan_pub_->get_subscription_count() > 0) {
738  transformed_plan_pub_->publish(std::move(path));
739  }
740 }
741 
743  const geometry_msgs::msg::PoseStamped & current_robot_pose)
744 {
745  if (!current_progress_checker_.empty()) {
746  if (!progress_checkers_[current_progress_checker_]->check(current_robot_pose)) {
747  throw nav2_core::FailedToMakeProgress("Failed to make progress");
748  }
749  }
750 
751  geometry_msgs::msg::Twist twist = getThresholdedTwist(odom_sub_->getRawTwist());
752 
753  geometry_msgs::msg::PoseStamped goal =
754  path_handlers_[current_path_handler_]->getTransformedGoal(current_robot_pose.header.stamp);
755 
756  geometry_msgs::msg::TwistStamped cmd_vel_2d;
757 
758  try {
759  cmd_vel_2d =
760  controllers_[current_controller_]->computeVelocityCommands(
761  current_robot_pose,
762  twist,
763  goal_checkers_[current_goal_checker_].get(),
764  transformed_global_plan_,
765  goal);
766  last_valid_cmd_time_ = now();
767  cmd_vel_2d.header.frame_id = costmap_ros_->getBaseFrameID();
768  cmd_vel_2d.header.stamp = last_valid_cmd_time_;
769  // Only no valid control exception types are valid to attempt to have control patience, as
770  // other types will not be resolved with more attempts
771  } catch (nav2_core::NoValidControl & e) {
772  if (params_->failure_tolerance > 0 || params_->failure_tolerance == -1.0) {
773  RCLCPP_WARN(this->get_logger(), "%s", e.what());
774  cmd_vel_2d.twist.angular.x = 0;
775  cmd_vel_2d.twist.angular.y = 0;
776  cmd_vel_2d.twist.angular.z = 0;
777  cmd_vel_2d.twist.linear.x = 0;
778  cmd_vel_2d.twist.linear.y = 0;
779  cmd_vel_2d.twist.linear.z = 0;
780  cmd_vel_2d.header.frame_id = costmap_ros_->getBaseFrameID();
781  cmd_vel_2d.header.stamp = now();
782  if ((now() - last_valid_cmd_time_).seconds() > params_->failure_tolerance &&
783  params_->failure_tolerance != -1.0)
784  {
785  throw nav2_core::PatienceExceeded("Controller patience exceeded");
786  }
787  } else {
788  throw nav2_core::NoValidControl(e.what());
789  }
790  }
791 
792  RCLCPP_DEBUG(get_logger(), "Publishing velocity at time %.2f", now().seconds());
793  publishVelocity(cmd_vel_2d);
794 
795  nav2_msgs::msg::TrackingFeedback current_tracking_feedback;
796 
797  if (current_path_.poses.size() >= 2) {
798  double current_distance_to_goal = nav2_util::geometry_utils::euclidean_distance(
799  current_robot_pose, transformed_end_pose_);
800 
801  // Transform robot pose to path frame for path tracking calculations
802  geometry_msgs::msg::PoseStamped robot_pose_in_path_frame;
803  if (!nav2_util::transformPoseInTargetFrame(
804  current_robot_pose, robot_pose_in_path_frame, *costmap_ros_->getTfBuffer(),
805  current_path_.header.frame_id, transform_tolerance_))
806  {
807  throw nav2_core::ControllerTFError("Failed to transform robot pose to path frame");
808  }
809 
810  // Calculate closest point and position error from path
811  const auto path_search_result = nav2_util::distance_from_path(
812  current_path_, robot_pose_in_path_frame.pose, start_index_, params_->search_window);
813 
814  // Calculate heading error
815  double heading_tracking_error = 0.0;
816  if (path_search_result.closest_segment_index <
817  current_path_.poses.size() - 1)
818  {
819  const auto & path_segment_start =
820  current_path_.poses[path_search_result.closest_segment_index].pose;
821  const auto & path_segment_end =
822  current_path_.poses[path_search_result.closest_segment_index + 1].pose;
823  double path_yaw = std::atan2(
824  path_segment_end.position.y - path_segment_start.position.y,
825  path_segment_end.position.x - path_segment_start.position.x);
826  double robot_yaw = tf2::getYaw(robot_pose_in_path_frame.pose.orientation);
827  heading_tracking_error = angles::shortest_angular_distance(
828  robot_yaw, path_yaw);
829  }
830 
831  // Create tracking error message
832  auto tracking_feedback_msg = std::make_unique<nav2_msgs::msg::TrackingFeedback>();
833  tracking_feedback_msg->header = current_robot_pose.header;
834  tracking_feedback_msg->position_tracking_error = path_search_result.distance;
835  tracking_feedback_msg->heading_tracking_error = heading_tracking_error;
836  tracking_feedback_msg->current_path_index = path_search_result.closest_segment_index;
837  tracking_feedback_msg->robot_pose = current_robot_pose;
838  tracking_feedback_msg->distance_to_goal = current_distance_to_goal;
839  tracking_feedback_msg->speed = std::hypot(twist.linear.x, twist.linear.y);
840  start_index_ = path_search_result.closest_segment_index;
841  tracking_feedback_msg->remaining_path_length =
842  nav2_util::geometry_utils::calculate_path_length(current_path_, start_index_);
843 
844  // Update current tracking error and publish
845  current_tracking_feedback = *tracking_feedback_msg;
846  if (tracking_feedback_pub_->get_subscription_count() > 0) {
847  tracking_feedback_pub_->publish(std::move(tracking_feedback_msg));
848  }
849  }
850 
851  // Publish action feedback
852  std::shared_ptr<Action::Feedback> feedback = std::make_shared<Action::Feedback>();
853  feedback->tracking_feedback = current_tracking_feedback;
854  action_server_->publish_feedback(feedback);
855 }
856 
858 {
859  if (action_server_->is_preempt_requested()) {
860  RCLCPP_INFO(get_logger(), "Passing new path to controller.");
861  auto goal = action_server_->accept_pending_goal();
862  std::string current_controller;
863  if (findControllerId(goal->controller_id, current_controller)) {
864  current_controller_ = current_controller;
865  } else {
866  std::shared_ptr<Action::Result> result = std::make_shared<Action::Result>();
867  result->error_code = Action::Result::INVALID_CONTROLLER;
868  result->error_msg = "Terminating action, invalid controller " +
869  goal->controller_id + " requested.";
870  action_server_->terminate_current(result);
871  return;
872  }
873  std::string current_goal_checker;
874  if (findGoalCheckerId(goal->goal_checker_id, current_goal_checker)) {
875  current_goal_checker_ = current_goal_checker;
876  } else {
877  std::shared_ptr<Action::Result> result = std::make_shared<Action::Result>();
878  result->error_code = Action::Result::INVALID_CONTROLLER;
879  result->error_msg = "Terminating action, invalid goal checker " +
880  goal->goal_checker_id + " requested.";
881  action_server_->terminate_current(result);
882  return;
883  }
884  std::string current_progress_checker;
885  if (findProgressCheckerId(goal->progress_checker_id, current_progress_checker)) {
886  if (current_progress_checker_ != current_progress_checker) {
887  RCLCPP_INFO(
888  get_logger(), "Change of progress checker %s requested, resetting it",
889  goal->progress_checker_id.c_str());
890  current_progress_checker_ = current_progress_checker;
891  if (!current_progress_checker_.empty()) {
892  progress_checkers_[current_progress_checker_]->reset();
893  }
894  }
895  } else {
896  std::shared_ptr<Action::Result> result = std::make_shared<Action::Result>();
897  result->error_code = Action::Result::INVALID_CONTROLLER;
898  result->error_msg = "Terminating action, invalid progress checker " +
899  goal->progress_checker_id + " requested.";
900  action_server_->terminate_current(result);
901  return;
902  }
903  std::string current_path_handler;
904  if (findPathHandlerId(goal->path_handler_id, current_path_handler)) {
905  if (current_path_handler_ != current_path_handler) {
906  RCLCPP_INFO(
907  get_logger(), "Change of path handler %s requested, resetting it",
908  goal->path_handler_id.c_str());
909  current_path_handler_ = current_path_handler;
910  }
911  } else {
912  std::shared_ptr<Action::Result> result = std::make_shared<Action::Result>();
913  result->error_code = Action::Result::INVALID_CONTROLLER;
914  result->error_msg = "Terminating action, invalid path handler" +
915  goal->path_handler_id + " requested.";
916  action_server_->terminate_current(result);
917  return;
918  }
919  setPlannerPath(goal->path);
920  }
921 }
922 
923 void ControllerServer::publishVelocity(const geometry_msgs::msg::TwistStamped & velocity)
924 {
925  auto cmd_vel = std::make_unique<geometry_msgs::msg::TwistStamped>(velocity);
926  if (!nav2_util::validateTwist(cmd_vel->twist)) {
927  RCLCPP_ERROR(get_logger(), "Velocity message contains NaNs or Infs! Ignoring as invalid!");
928  return;
929  }
930  if (vel_publisher_->is_activated() && vel_publisher_->get_subscription_count() > 0) {
931  vel_publisher_->publish(std::move(cmd_vel));
932  }
933 }
934 
936 {
937  geometry_msgs::msg::TwistStamped velocity;
938  velocity.twist.angular.x = 0;
939  velocity.twist.angular.y = 0;
940  velocity.twist.angular.z = 0;
941  velocity.twist.linear.x = 0;
942  velocity.twist.linear.y = 0;
943  velocity.twist.linear.z = 0;
944  velocity.header.frame_id = costmap_ros_->getBaseFrameID();
945  velocity.header.stamp = now();
946  publishVelocity(velocity);
947 }
948 
949 void ControllerServer::onGoalExit(bool force_stop)
950 {
951  if (params_->publish_zero_velocity || force_stop) {
953  }
954 
955  // Reset controller state
956  for (auto & controller : controllers_) {
957  controller.second->reset();
958  }
959 }
960 
961 bool ControllerServer::isGoalReached(const geometry_msgs::msg::PoseStamped & current_robot_pose)
962 {
963  geometry_msgs::msg::Twist velocity = getThresholdedTwist(odom_sub_->getRawTwist());
964 
965  return goal_checkers_[current_goal_checker_]->isGoalReached(
966  current_robot_pose.pose, transformed_end_pose_.pose,
967  velocity, transformed_global_plan_);
968 }
969 
970 geometry_msgs::msg::PoseStamped ControllerServer::getCurrentRobotPose()
971 {
972  geometry_msgs::msg::PoseStamped pose;
973  if (!nav2_util::getFreshPose(
974  *costmap_ros_->getTfBuffer(), costmap_ros_->getGlobalFrameID(),
975  costmap_ros_->getBaseFrameID(), now(),
976  params_->transform_staleness_threshold, pose))
977  {
979  "Failed to obtain robot pose in frame '" + costmap_ros_->getGlobalFrameID() +
980  "' for base frame '" + costmap_ros_->getBaseFrameID() + "'");
981  }
982  return pose;
983 }
984 
985 void ControllerServer::speedLimitCallback(const nav2_msgs::msg::SpeedLimit::ConstSharedPtr & msg)
986 {
987  ControllerMap::iterator it;
988  for (it = controllers_.begin(); it != controllers_.end(); ++it) {
989  it->second->setSpeedLimit(msg->speed_limit, msg->percentage);
990  }
991 }
992 
993 } // namespace nav2_controller
994 
995 #include "rclcpp_components/register_node_macro.hpp"
996 
997 // Register the component with class_loader.
998 // This acts as a sort of entry point, allowing the component to be discoverable when its library
999 // is being loaded into a running process.
1000 RCLCPP_COMPONENTS_REGISTER_NODE(nav2_controller::ControllerServer)
void destroyBond()
Destroy bond connection to lifecycle manager.
nav2::LifecycleNode::SharedPtr shared_from_this()
Get a shared pointer of this.
void createBond()
Create bond connection to lifecycle manager.
A sim-time-aware rate for Nav2 loops.
Definition: rate.hpp:61
This class hosts variety of plugins of different algorithms to complete control tasks from the expose...
nav2::CallbackReturn on_cleanup(const rclcpp_lifecycle::State &state) override
Calls clean up states and resets member variables.
double waitForCostmap()
Wait for costmap to become current, with timeout.
bool isGoalReached(const geometry_msgs::msg::PoseStamped &current_robot_pose)
Checks if goal is reached.
void publishVelocity(const geometry_msgs::msg::TwistStamped &velocity)
Calls velocity publisher to publish the velocity on "cmd_vel" topic.
void onGoalExit(bool force_stop)
Called on goal exit.
nav2::CallbackReturn on_configure(const rclcpp_lifecycle::State &state) override
Configures controller parameters and member variables.
void computeControl()
FollowPath action server callback. Handles action server updates and spins server until goal is reach...
geometry_msgs::msg::Twist getThresholdedTwist(const geometry_msgs::msg::Twist &twist)
get the thresholded Twist
~ControllerServer()
Destructor for nav2_controller::ControllerServer.
nav2::CallbackReturn on_deactivate(const rclcpp_lifecycle::State &state) override
Deactivates member variables.
bool findGoalCheckerId(const std::string &c_name, std::string &name)
Find the valid goal checker ID name for the specified parameter.
void updateGlobalPath()
Calls setPlannerPath method with an updated path received from action server.
bool goalReceived(std::shared_ptr< const Action::Goal > goal)
Goal received callback to validate a new goal before acceptance.
void setPlannerPath(const nav_msgs::msg::Path &path)
Assigns path to controller.
nav2::CallbackReturn on_shutdown(const rclcpp_lifecycle::State &state) override
Called when in Shutdown state.
void transformedPlanAndGoal(const geometry_msgs::msg::PoseStamped &current_robot_pose)
Refreshes transformed_global_plan_ and transformed_end_pose_ for the current cycle.
nav2::CallbackReturn on_activate(const rclcpp_lifecycle::State &state) override
Activates member variables.
void publishZeroVelocity()
Calls velocity publisher to publish zero velocity.
geometry_msgs::msg::PoseStamped getCurrentRobotPose()
Obtain the current pose of the robot in the costmap frame.
bool findControllerId(const std::string &c_name, std::string &name)
Find the valid controller ID name for the given request.
bool findProgressCheckerId(const std::string &c_name, std::string &name)
Find the valid progress checker ID name for the specified parameter.
bool findPathHandlerId(const std::string &c_name, std::string &name)
Find the valid path handler ID name for the specified parameter.
void computeAndPublishVelocity(const geometry_msgs::msg::PoseStamped &current_robot_pose)
Calculates velocity and publishes to "cmd_vel" topic.