planner_3d.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2023, the neonavigation authors
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <algorithm>
31 #include <cmath>
32 #include <limits>
33 #include <list>
34 #include <memory>
35 #include <string>
36 #include <unordered_map>
37 #include <utility>
38 #include <vector>
39 
40 #include <omp.h>
41 
42 #include <ros/ros.h>
43 
44 #include <costmap_cspace_msgs/CSpace3D.h>
45 #include <costmap_cspace_msgs/CSpace3DUpdate.h>
47 #include <geometry_msgs/PoseArray.h>
48 #include <nav_msgs/GetPlan.h>
49 #include <nav_msgs/OccupancyGrid.h>
50 #include <nav_msgs/Path.h>
51 #include <neonavigation_metrics_msgs/Metrics.h>
53 #include <planner_cspace_msgs/PlannerStatus.h>
54 #include <sensor_msgs/PointCloud.h>
55 #include <std_srvs/Empty.h>
56 #include <trajectory_tracker_msgs/PathWithVelocity.h>
58 
59 #include <ros/console.h>
60 #include <tf2/utils.h>
63 
65 #include <move_base_msgs/MoveBaseAction.h>
66 #include <planner_cspace_msgs/MoveWithToleranceAction.h>
67 
69 
70 #include <planner_cspace/bbf.h>
80 
81 namespace planner_cspace
82 {
83 namespace planner_3d
84 {
86 {
87 public:
89 
90 protected:
93 
111 
112  std::shared_ptr<Planner3DActionServer> act_;
113  std::shared_ptr<Planner3DTolerantActionServer> act_tolerant_;
114  planner_cspace_msgs::MoveWithToleranceGoalConstPtr goal_tolerant_;
117 
119  Astar::Gridmap<char, 0x40> cm_;
120  Astar::Gridmap<char, 0x80> cm_rough_;
121  Astar::Gridmap<char, 0x40> cm_base_;
122  Astar::Gridmap<char, 0x80> cm_rough_base_;
123  Astar::Gridmap<char, 0x80> cm_hyst_;
124  Astar::Gridmap<char, 0x80> cm_updates_;
127 
129 
130  costmap_cspace_msgs::MapMetaData3D map_info_;
131  costmap_cspace_msgs::CSpace3DUpdate::ConstPtr map_update_retained_;
132  std_msgs::Header map_header_;
133  float freq_;
134  float freq_min_;
138  int range_;
144  double esc_range_f_;
151  bool has_map_;
152  bool has_goal_;
155  std::vector<Astar::Vec> hyst_updated_cells_;
159  std::vector<Astar::Vec> search_list_;
160  std::vector<Astar::Vec> search_list_rough_;
170 
172  std::string robot_frame_;
173 
175 
177 
178  // Cost weights
180 
181  geometry_msgs::PoseStamped start_;
182  geometry_msgs::PoseStamped goal_;
183  geometry_msgs::PoseStamped goal_raw_;
190 
191  planner_cspace_msgs::PlannerStatus status_;
192  neonavigation_metrics_msgs::Metrics metrics_;
193 
195  float sw_wait_;
196  geometry_msgs::PoseStamped sw_pos_;
198 
199  bool rough_;
200 
202 
203  bool escaping_;
204 
206 
210 
215 
216  bool cbForget(std_srvs::EmptyRequest& req,
217  std_srvs::EmptyResponse& res)
218  {
219  ROS_WARN("Forgetting remembered costmap.");
220  if (has_map_)
221  bbf_costmap_.clear();
222 
223  return true;
224  }
226  {
227  OK,
228  RELOCATED,
229  IN_ROCK,
230  OUT_OF_MAP,
231  };
232  template <class T>
234  const int tolerance_range,
235  const int tolerance_angle,
236  Astar::Vec& pose_discrete) const
237  {
238  if (!cm.validate(pose_discrete, range_))
239  {
241  }
242  if (cm[pose_discrete] == 100)
243  {
244  if (searchAvailablePos(cm, pose_discrete, tolerance_range, tolerance_angle))
246  else
248  }
249  return DiscretePoseStatus::OK;
250  }
252  const int tolerance_range,
253  const int tolerance_angle,
254  bool use_cm_rough = false) const
255  {
256  if (use_cm_rough)
257  {
258  pose_discrete[2] = 0;
259  return relocateDiscretePoseIfNeededImpl(cm_rough_, tolerance_range, tolerance_angle, pose_discrete);
260  }
261  else
262  {
263  return relocateDiscretePoseIfNeededImpl(cm_, tolerance_range, tolerance_angle, pose_discrete);
264  }
265  }
266 
267  bool cbMakePlan(nav_msgs::GetPlan::Request& req,
268  nav_msgs::GetPlan::Response& res)
269  {
270  if (!has_map_)
271  {
272  ROS_ERROR("make_plan service is called without map.");
273  return false;
274  }
275 
276  if (req.start.header.frame_id != map_header_.frame_id ||
277  req.goal.header.frame_id != map_header_.frame_id)
278  {
279  ROS_ERROR("Start [%s] and Goal [%s] poses must be in the map frame [%s].",
280  req.start.header.frame_id.c_str(),
281  req.goal.header.frame_id.c_str(),
282  map_header_.frame_id.c_str());
283  return false;
284  }
285 
286  Astar::Vec s, e;
288  map_info_, s[0], s[1], s[2],
289  req.start.pose.position.x, req.start.pose.position.y, tf2::getYaw(req.start.pose.orientation));
291  map_info_, e[0], e[1], e[2],
292  req.goal.pose.position.x, req.goal.pose.position.y, tf2::getYaw(req.goal.pose.orientation));
293  ROS_INFO("Path plan from (%d, %d) to (%d, %d)", s[0], s[1], e[0], e[1]);
294 
295  const int tolerance_range = std::lround(req.tolerance / map_info_.linear_resolution);
296  const DiscretePoseStatus start_status = relocateDiscretePoseIfNeeded(s, tolerance_range, tolerance_angle_, true);
297  const DiscretePoseStatus goal_status = relocateDiscretePoseIfNeeded(e, tolerance_range, tolerance_angle_, true);
298  switch (start_status)
299  {
301  ROS_ERROR("Given start is not on the map.");
302  return false;
304  ROS_ERROR("Given start is in Rock.");
305  return false;
307  ROS_INFO("Given start is moved (%d, %d)", s[0], s[1]);
308  break;
309  default:
310  break;
311  }
312  switch (goal_status)
313  {
315  ROS_ERROR("Given goal is not on the map.");
316  return false;
318  ROS_ERROR("Given goal is in Rock.");
319  return false;
321  ROS_INFO("Given goal is moved (%d, %d)", e[0], e[1]);
322  break;
323  default:
324  break;
325  }
326 
327  const auto cb_progress = [](const std::list<Astar::Vec>& /* path_grid */, const SearchStats& /* stats */)
328  {
329  return true;
330  };
331 
332  const auto ts = boost::chrono::high_resolution_clock::now();
333 
334  GridAstarModel2D::Ptr model_2d(new GridAstarModel2D(model_));
335 
336  std::list<Astar::Vec> path_grid;
337  std::vector<GridAstarModel3D::VecWithCost> starts;
338  starts.emplace_back(s);
339  if (!as_.search(
340  starts, e, path_grid,
341  model_2d,
342  cb_progress,
343  0, 1.0f / freq_min_, find_best_))
344  {
345  ROS_WARN("Path plan failed (goal unreachable)");
346  return false;
347  }
348  const auto tnow = boost::chrono::high_resolution_clock::now();
349  ROS_INFO("Path found (%0.4f sec.)",
350  boost::chrono::duration<float>(tnow - ts).count());
351 
352  nav_msgs::Path path;
353  path.header = map_header_;
354  path.header.stamp = ros::Time::now();
355 
356  const std::list<Astar::Vecf> path_interpolated =
357  model_->path_interpolator_.interpolate(path_grid, 0.5, 0.0);
358  grid_metric_converter::grid2MetricPath(map_info_, path_interpolated, path);
359 
360  res.plan.header = map_header_;
361  res.plan.poses.resize(path.poses.size());
362  for (size_t i = 0; i < path.poses.size(); ++i)
363  {
364  res.plan.poses[i] = path.poses[i];
365  }
366  return true;
367  }
368 
369  void cbGoal(const geometry_msgs::PoseStamped::ConstPtr& msg)
370  {
371  if (act_->isActive() || act_tolerant_->isActive())
372  {
373  ROS_ERROR("Setting new goal is ignored since planner_3d is proceeding the action.");
374  return;
375  }
376  setGoal(*msg);
377  }
378  void cbPreempt()
379  {
380  ROS_WARN("Preempting the current goal.");
381  if (act_->isActive())
382  act_->setPreempted(move_base_msgs::MoveBaseResult(), "Preempted.");
383 
384  if (act_tolerant_->isActive())
385  act_tolerant_->setPreempted(planner_cspace_msgs::MoveWithToleranceResult(), "Preempted.");
386 
387  has_goal_ = false;
388  status_.status = planner_cspace_msgs::PlannerStatus::DONE;
389  }
390 
391  bool setGoal(const geometry_msgs::PoseStamped& msg)
392  {
393  if (msg.header.frame_id != map_header_.frame_id)
394  {
395  ROS_ERROR("Goal [%s] pose must be in the map frame [%s].",
396  msg.header.frame_id.c_str(), map_header_.frame_id.c_str());
397  return false;
398  }
399 
400  goal_raw_ = goal_ = msg;
401 
402  const double len2 =
403  goal_.pose.orientation.x * goal_.pose.orientation.x +
404  goal_.pose.orientation.y * goal_.pose.orientation.y +
405  goal_.pose.orientation.z * goal_.pose.orientation.z +
406  goal_.pose.orientation.w * goal_.pose.orientation.w;
407  if (std::abs(len2 - 1.0) < 0.1)
408  {
409  escaping_ = false;
410  has_goal_ = true;
411  cnt_stuck_ = 0;
412  if (!updateGoal())
413  {
414  has_goal_ = false;
415  return false;
416  }
417  status_.status = planner_cspace_msgs::PlannerStatus::DOING;
418  status_.header.stamp = ros::Time::now();
419  pub_status_.publish(status_);
420  diag_updater_.update();
421  }
422  else
423  {
424  has_goal_ = false;
425  if (act_->isActive())
426  act_->setSucceeded(move_base_msgs::MoveBaseResult(), "Goal cleared.");
427  if (act_tolerant_->isActive())
428  act_tolerant_->setSucceeded(planner_cspace_msgs::MoveWithToleranceResult(), "Goal cleared.");
429  }
430  return true;
431  }
432 
433  template <class T>
434  bool searchAvailablePos(const T& cm, Astar::Vec& s, const int xy_range, const int angle_range,
435  const int cost_acceptable = 50, const int min_xy_range = 0) const
436  {
437  ROS_DEBUG("%d, %d (%d,%d,%d)", xy_range, angle_range, s[0], s[1], s[2]);
438 
439  float range_min = std::numeric_limits<float>::max();
440  Astar::Vec s_out;
441  Astar::Vec d;
442  for (d[2] = -angle_range; d[2] <= angle_range; d[2]++)
443  {
444  for (d[0] = -xy_range; d[0] <= xy_range; d[0]++)
445  {
446  for (d[1] = -xy_range; d[1] <= xy_range; d[1]++)
447  {
448  if (d[0] == 0 && d[1] == 0 && d[2] == 0)
449  continue;
450  if (d.sqlen() > xy_range * xy_range)
451  continue;
452  if (d.sqlen() < min_xy_range * min_xy_range)
453  continue;
454 
455  Astar::Vec s2 = s + d;
456  if ((unsigned int)s2[0] >= (unsigned int)map_info_.width ||
457  (unsigned int)s2[1] >= (unsigned int)map_info_.height)
458  continue;
459  s2.cycleUnsigned(map_info_.angle);
460  if (!cm_.validate(s2, range_))
461  continue;
462 
463  if (cm_[s2] >= cost_acceptable)
464  continue;
465  const auto cost = model_->euclidCost(d);
466  if (cost < range_min)
467  {
468  range_min = cost;
469  s_out = s2;
470  }
471  }
472  }
473  }
474 
475  if (range_min == std::numeric_limits<float>::max())
476  {
477  if (cost_acceptable != 100)
478  {
479  return searchAvailablePos(cm, s, xy_range, angle_range, 100);
480  }
481  return false;
482  }
483  s = s_out;
484  s.cycleUnsigned(map_info_.angle);
485  ROS_DEBUG(" (%d,%d,%d)", s[0], s[1], s[2]);
486  return true;
487  }
488  bool updateGoal(const bool goal_changed = true)
489  {
490  if (!has_goal_)
491  return true;
492 
493  if (!has_map_ || !has_start_)
494  {
495  ROS_ERROR("Goal received, however map/goal/start are not ready. (%d/%d/%d)",
496  static_cast<int>(has_map_), static_cast<int>(has_goal_), static_cast<int>(has_start_));
497  return true;
498  }
499 
500  Astar::Vec s, e;
502  map_info_, s[0], s[1], s[2],
503  start_.pose.position.x, start_.pose.position.y,
504  tf2::getYaw(start_.pose.orientation));
505  s.cycleUnsigned(map_info_.angle);
507  map_info_, e[0], e[1], e[2],
508  goal_.pose.position.x, goal_.pose.position.y,
509  tf2::getYaw(goal_.pose.orientation));
510  e.cycleUnsigned(map_info_.angle);
511  if (goal_changed)
512  {
513  ROS_INFO(
514  "New goal received (%d, %d, %d)",
515  e[0], e[1], e[2]);
516 
517  clearHysteresis();
518  has_hysteresis_map_ = false;
519  }
520  const DiscretePoseStatus start_pose_status = relocateDiscretePoseIfNeeded(s, tolerance_range_, tolerance_angle_);
521  const DiscretePoseStatus goal_pose_status = relocateDiscretePoseIfNeeded(e, tolerance_range_, tolerance_angle_);
522  switch (start_pose_status)
523  {
525  ROS_ERROR("You are on the edge of the world.");
526  return false;
528  ROS_WARN("Oops! You are in Rock!");
529  ++cnt_stuck_;
530  return true;
531  default:
532  break;
533  }
534  switch (goal_pose_status)
535  {
537  ROS_ERROR("Given goal is not on the map.");
538  return false;
540  ROS_WARN("Oops! Goal is in Rock!");
541  ++cnt_stuck_;
542  return true;
544  ROS_INFO("Goal moved (%d, %d, %d)", e[0], e[1], e[2]);
545  float x, y, yaw;
546  grid_metric_converter::grid2Metric(map_info_, e[0], e[1], e[2], x, y, yaw);
547  goal_.pose.orientation = tf2::toMsg(tf2::Quaternion(tf2::Vector3(0.0, 0.0, 1.0), yaw));
548  goal_.pose.position.x = x;
549  goal_.pose.position.y = y;
550  break;
551  default:
552  break;
553  }
554  const auto ts = boost::chrono::high_resolution_clock::now();
555  cost_estim_cache_.create(s, e);
556  const auto tnow = boost::chrono::high_resolution_clock::now();
557  const float dur = boost::chrono::duration<float>(tnow - ts).count();
558  ROS_DEBUG("Cost estimation cache generated (%0.4f sec.)", dur);
559  metrics_.data.push_back(neonavigation_metrics_msgs::metric(
560  "distance_map_init_dur",
561  dur,
562  "second"));
563  metrics_.data.push_back(neonavigation_metrics_msgs::metric(
564  "distance_map_update_dur",
565  0.0,
566  "second"));
567 
568  publishDebug();
569 
570  goal_updated_ = true;
571 
572  return true;
573  }
575  {
576  for (const Astar::Vec& p : hyst_updated_cells_)
577  {
578  cm_hyst_[p] = 100;
579  }
580  hyst_updated_cells_.clear();
581  }
583  {
584  if (pub_distance_map_.getNumSubscribers() > 0)
585  {
586  sensor_msgs::PointCloud distance_map;
587  distance_map.header = map_header_;
588  distance_map.header.stamp = ros::Time::now();
589  distance_map.channels.resize(1);
590  distance_map.channels[0].name = "distance";
591  distance_map.points.reserve(1024);
592  distance_map.channels[0].values.reserve(1024);
593  const float k_dist = map_info_.linear_resolution * cc_.max_vel_;
594  for (Astar::Vec p(0, 0, 0); p[1] < cost_estim_cache_.size()[1]; p[1]++)
595  {
596  for (p[0] = 0; p[0] < cost_estim_cache_.size()[0]; p[0]++)
597  {
598  p[2] = 0;
599  float x, y, yaw;
600  grid_metric_converter::grid2Metric(map_info_, p[0], p[1], p[2], x, y, yaw);
601  geometry_msgs::Point32 point;
602  point.x = x;
603  point.y = y;
604  if (cost_estim_cache_[p] == std::numeric_limits<float>::max())
605  continue;
606  point.z = cost_estim_cache_[p] / 500;
607  distance_map.points.push_back(point);
608  distance_map.channels[0].values.push_back(cost_estim_cache_[p] * k_dist);
609  }
610  }
611  pub_distance_map_.publish(distance_map);
612  }
613 
614  if (pub_hysteresis_map_.getNumSubscribers() > 0)
615  {
616  nav_msgs::OccupancyGrid hysteresis_map;
617  hysteresis_map.header.frame_id = map_header_.frame_id;
618  hysteresis_map.info.resolution = map_info_.linear_resolution;
619  hysteresis_map.info.width = map_info_.width;
620  hysteresis_map.info.height = map_info_.height;
621  hysteresis_map.info.origin = map_info_.origin;
622  hysteresis_map.data.resize(map_info_.width * map_info_.height, 100);
623 
624  for (Astar::Vec p(0, 0, 0); p[1] < cost_estim_cache_.size()[1]; p[1]++)
625  {
626  for (p[0] = 0; p[0] < cost_estim_cache_.size()[0]; p[0]++)
627  {
628  if (cost_estim_cache_[p] == std::numeric_limits<float>::max())
629  continue;
630 
631  char cost = 100;
632  for (Astar::Vec p2 = p; p2[2] < static_cast<int>(map_info_.angle); ++p2[2])
633  {
634  cost = std::min(cm_hyst_[p2], cost);
635  }
636  hysteresis_map.data[p[0] + p[1] * map_info_.width] = cost;
637  }
638  }
639  pub_hysteresis_map_.publish(hysteresis_map);
640  }
641  }
643  {
644  if (pub_remembered_map_.getNumSubscribers() > 0 && remember_updates_)
645  {
646  nav_msgs::OccupancyGrid remembered_map;
647  remembered_map.header.frame_id = map_header_.frame_id;
648  remembered_map.info.resolution = map_info_.linear_resolution;
649  remembered_map.info.width = map_info_.width;
650  remembered_map.info.height = map_info_.height;
651  remembered_map.info.origin = map_info_.origin;
652  remembered_map.data.resize(map_info_.width * map_info_.height);
653 
654  const auto generate_pointcloud = [this, &remembered_map](const Astar::Vec& p, bbf::BinaryBayesFilter& bbf)
655  {
656  remembered_map.data[p[0] + p[1] * map_info_.width] =
657  (bbf.getProbability() - bbf::MIN_PROBABILITY) * 100 / (bbf::MAX_PROBABILITY - bbf::MIN_PROBABILITY);
658  };
659  bbf_costmap_.forEach(generate_pointcloud);
660  pub_remembered_map_.publish(remembered_map);
661  }
662  }
664  {
665  nav_msgs::Path path;
666  path.header.frame_id = robot_frame_;
667  path.header.stamp = ros::Time::now();
668  if (use_path_with_velocity_)
669  {
670  pub_path_velocity_.publish(
672  path, std::numeric_limits<double>::quiet_NaN()));
673  }
674  else
675  {
676  pub_path_.publish(path);
677  }
678  }
680  {
681  nav_msgs::Path path;
682  path.header.frame_id = map_header_.frame_id;
683  path.header.stamp = ros::Time::now();
684  // Specify single pose to control only orientation
685  path.poses.resize(1);
686  path.poses[0].header = path.header;
687  if (force_goal_orientation_)
688  path.poses[0].pose = goal_raw_.pose;
689  else
690  path.poses[0].pose = goal_.pose;
691 
692  if (use_path_with_velocity_)
693  {
694  pub_path_velocity_.publish(
696  path, std::numeric_limits<double>::quiet_NaN()));
697  }
698  else
699  {
700  pub_path_.publish(path);
701  }
702  }
703 
704  void cbMapUpdate(const costmap_cspace_msgs::CSpace3DUpdate::ConstPtr msg)
705  {
706  if (!has_map_)
707  return;
708  ROS_DEBUG("Map updated");
709 
710  const auto ts_cm_init_start = boost::chrono::high_resolution_clock::now();
711  const ros::Time now = ros::Time::now();
712 
713  const int map_update_x_min = static_cast<int>(msg->x);
714  const int map_update_x_max = std::max(static_cast<int>(msg->x + msg->width) - 1, 0);
715  const int map_update_y_min = static_cast<int>(msg->y);
716  const int map_update_y_max = std::max(static_cast<int>(msg->y + msg->height) - 1, 0);
717 
718  if (static_cast<size_t>(map_update_x_max) >= map_info_.width ||
719  static_cast<size_t>(map_update_y_max) >= map_info_.height ||
720  msg->angle > map_info_.angle)
721  {
722  ROS_WARN(
723  "Map update out of range (update range: %dx%dx%d, map range: %dx%dx%d)",
724  map_update_x_max, map_update_y_max, msg->angle,
725  map_info_.width, map_info_.height, map_info_.angle);
726  map_update_retained_ = msg;
727  return;
728  }
729  map_update_retained_ = nullptr;
730 
731  last_costmap_ = now;
732 
733  cm_.copy_partially(
734  cm_base_,
735  Astar::Vec(prev_map_update_x_min_, prev_map_update_y_min_, 0),
736  Astar::Vec(prev_map_update_x_max_, prev_map_update_y_max_, static_cast<int>(map_info_.angle) - 1));
737  cm_rough_.copy_partially(
738  cm_rough_base_,
739  Astar::Vec(prev_map_update_x_min_, prev_map_update_y_min_, 0),
740  Astar::Vec(prev_map_update_x_max_, prev_map_update_y_max_, 0));
741  cm_updates_.clear_partially(
742  -1,
743  Astar::Vec(prev_map_update_x_min_, prev_map_update_y_min_, 0),
744  Astar::Vec(prev_map_update_x_max_, prev_map_update_y_max_, 0));
745 
746  // Should search 1px around the region to
747  // update the costmap even if the edge of the local map is obstacle
748  const int search_range_x_min = std::max(
749  0,
750  std::min(prev_map_update_x_min_, map_update_x_min) - 1);
751  const int search_range_x_max = std::min(
752  static_cast<int>(map_info_.width - 1),
753  std::max(prev_map_update_x_max_, map_update_x_max) + 1);
754  const int search_range_y_min = std::max(
755  0,
756  std::min(prev_map_update_y_min_, map_update_y_min) - 1);
757  const int search_range_y_max = std::min(
758  static_cast<int>(map_info_.height - 1),
759  std::max(prev_map_update_y_max_, map_update_y_max) + 1);
760 
761  prev_map_update_x_min_ = map_update_x_min;
762  prev_map_update_x_max_ = map_update_x_max;
763  prev_map_update_y_min_ = map_update_y_min;
764  prev_map_update_y_max_ = map_update_y_max;
765 
766  bool clear_hysteresis(false);
767 
768  {
769  const Astar::Vec gp(
770  static_cast<int>(msg->x), static_cast<int>(msg->y), static_cast<int>(msg->yaw));
771  const Astar::Vec gp_rough(gp[0], gp[1], 0);
772  for (Astar::Vec p(0, 0, 0); p[0] < static_cast<int>(msg->width); p[0]++)
773  {
774  for (p[1] = 0; p[1] < static_cast<int>(msg->height); p[1]++)
775  {
776  int cost_min = 100;
777  for (p[2] = 0; p[2] < static_cast<int>(msg->angle); p[2]++)
778  {
779  const size_t addr = ((p[2] * msg->height) + p[1]) * msg->width + p[0];
780  const char c = msg->data[addr];
781  if (c < cost_min)
782  cost_min = c;
783  if (c == 100 && !clear_hysteresis && cm_hyst_[gp + p] == 0)
784  clear_hysteresis = true;
785  }
786  p[2] = 0;
787  cm_updates_[gp_rough + p] = cost_min;
788  if (cost_min > cm_rough_[gp_rough + p])
789  cm_rough_[gp_rough + p] = cost_min;
790 
791  for (p[2] = 0; p[2] < static_cast<int>(msg->angle); p[2]++)
792  {
793  const size_t addr = ((p[2] * msg->height) + p[1]) * msg->width + p[0];
794  const char c = msg->data[addr];
795  if (overwrite_cost_)
796  {
797  if (c >= 0)
798  cm_[gp + p] = c;
799  }
800  else
801  {
802  if (cm_[gp + p] < c)
803  cm_[gp + p] = c;
804  }
805  }
806  }
807  }
808  }
809  const auto ts_cm_init_end = boost::chrono::high_resolution_clock::now();
810  const float ts_cm_init_dur = boost::chrono::duration<float>(ts_cm_init_end - ts_cm_init_start).count();
811  ROS_DEBUG("Costmaps updated (%.4f)", ts_cm_init_dur);
812  metrics_.data.push_back(neonavigation_metrics_msgs::metric(
813  "costmap_dur",
814  ts_cm_init_dur,
815  "second"));
816 
817  if (clear_hysteresis && has_hysteresis_map_)
818  {
819  ROS_INFO("The previous path collides to the obstacle. Clearing hysteresis map.");
820  clearHysteresis();
821  has_hysteresis_map_ = false;
822  }
823 
824  if (!has_start_)
825  return;
826 
827  Astar::Vec s;
829  map_info_, s[0], s[1], s[2],
830  start_.pose.position.x, start_.pose.position.y,
831  tf2::getYaw(start_.pose.orientation));
832  s.cycleUnsigned(map_info_.angle);
833 
834  if (remember_updates_)
835  {
836  bbf_costmap_.remember(
837  &cm_updates_, s,
838  remember_hit_odds_, remember_miss_odds_,
839  hist_ignore_range_, hist_ignore_range_max_);
841  bbf_costmap_.updateCostmap();
842  }
843  if (!has_goal_)
844  return;
845 
846  if (!fast_map_update_)
847  {
848  updateGoal(false);
849  return;
850  }
851 
852  Astar::Vec e;
854  map_info_, e[0], e[1], e[2],
855  goal_.pose.position.x, goal_.pose.position.y,
856  tf2::getYaw(goal_.pose.orientation));
857  e.cycleUnsigned(map_info_.angle);
858 
859  if (cm_[e] == 100)
860  {
861  updateGoal(false);
862  return;
863  }
864 
865  const auto ts = boost::chrono::high_resolution_clock::now();
866  cost_estim_cache_.update(
867  s, e,
869  Astar::Vec(search_range_x_min, search_range_y_min, 0),
870  Astar::Vec(search_range_x_max, search_range_y_max, 0)));
871  const auto tnow = boost::chrono::high_resolution_clock::now();
872  const DistanceMap::DebugData dm_debug = cost_estim_cache_.getDebugData();
873  if (dm_debug.has_negative_cost)
874  {
875  ROS_WARN("Negative cost value is detected. Limited to zero.");
876  }
877  ROS_DEBUG("Cost estimation cache search queue initial size: %lu, capacity: %lu",
878  dm_debug.search_queue_size, dm_debug.search_queue_cap);
879  const float dur = boost::chrono::duration<float>(tnow - ts).count();
880  ROS_DEBUG("Cost estimation cache updated (%0.4f sec.)", dur);
881  metrics_.data.push_back(neonavigation_metrics_msgs::metric(
882  "distance_map_update_dur",
883  dur,
884  "second"));
885  metrics_.data.push_back(neonavigation_metrics_msgs::metric(
886  "distance_map_init_dur",
887  0.0,
888  "second"));
889  publishDebug();
890  }
891  void cbMap(const costmap_cspace_msgs::CSpace3D::ConstPtr& msg)
892  {
893  ROS_INFO("Map received");
894  ROS_INFO(" linear_resolution %0.2f x (%dx%d) px", msg->info.linear_resolution,
895  msg->info.width, msg->info.height);
896  ROS_INFO(" angular_resolution %0.2f x %d px", msg->info.angular_resolution,
897  msg->info.angle);
898  ROS_INFO(" origin %0.3f m, %0.3f m, %0.3f rad",
899  msg->info.origin.position.x,
900  msg->info.origin.position.y,
901  tf2::getYaw(msg->info.origin.orientation));
902 
903  // Stop robot motion until next planning step
905 
906  ec_ = Astar::Vecf(
907  1.0f / cc_.max_vel_,
908  1.0f / cc_.max_vel_,
909  1.0f * cc_.weight_ang_vel_ / cc_.max_ang_vel_);
910 
911  if (map_info_.linear_resolution != msg->info.linear_resolution ||
912  map_info_.angular_resolution != msg->info.angular_resolution)
913  {
914  map_info_ = msg->info;
915 
916  range_ = static_cast<int>(search_range_ / map_info_.linear_resolution);
917  hist_ignore_range_ = std::lround(hist_ignore_range_f_ / map_info_.linear_resolution);
918  hist_ignore_range_max_ = std::lround(hist_ignore_range_max_f_ / map_info_.linear_resolution);
919  local_range_ = std::lround(local_range_f_ / map_info_.linear_resolution);
920  esc_range_ = std::lround(esc_range_f_ / map_info_.linear_resolution);
921  esc_angle_ = map_info_.angle / 8;
922  tolerance_range_ = std::lround(tolerance_range_f_ / map_info_.linear_resolution);
923  tolerance_angle_ = std::lround(tolerance_angle_f_ / map_info_.angular_resolution);
924  goal_tolerance_lin_ = std::lround(goal_tolerance_lin_f_ / map_info_.linear_resolution);
925  goal_tolerance_ang_ = std::lround(goal_tolerance_ang_f_ / map_info_.angular_resolution);
926  cc_.angle_resolution_aspect_ = 2.0 / tanf(map_info_.angular_resolution);
927 
928  model_.reset(
929  new GridAstarModel3D(
930  map_info_,
931  ec_,
932  local_range_,
933  cost_estim_cache_.gridmap(), cm_, cm_hyst_, cm_rough_,
934  cc_, range_));
935 
936  ROS_DEBUG("Search model updated");
937  }
938  else
939  {
940  map_info_ = msg->info;
941  }
942  map_header_ = msg->header;
943  jump_.setMapFrame(map_header_.frame_id);
944 
945  const int size[3] =
946  {
947  static_cast<int>(map_info_.width),
948  static_cast<int>(map_info_.height),
949  static_cast<int>(map_info_.angle),
950  };
951 
952  const Astar::Vec size3d(size[0], size[1], size[2]);
953  const Astar::Vec size2d(size[0], size[1], 1);
954 
955  as_.reset(size3d);
956  cm_.reset(size3d);
957  cm_hyst_.reset(size3d);
958 
959  const DistanceMap::Params dmp =
960  {
961  .euclid_cost = ec_,
962  .range = range_,
963  .local_range = local_range_,
964  .longcut_range = static_cast<int>(std::lround(longcut_range_f_ / map_info_.linear_resolution)),
965  .size = size2d,
966  .resolution = map_info_.linear_resolution,
967  };
968  cost_estim_cache_.init(model_, dmp);
969  cm_rough_.reset(size2d);
970  cm_updates_.reset(size2d);
971  bbf_costmap_.reset(size2d);
972 
973  Astar::Vec p;
974  for (p[0] = 0; p[0] < static_cast<int>(map_info_.width); p[0]++)
975  {
976  for (p[1] = 0; p[1] < static_cast<int>(map_info_.height); p[1]++)
977  {
978  int cost_min = 100;
979  for (p[2] = 0; p[2] < static_cast<int>(map_info_.angle); p[2]++)
980  {
981  const size_t addr = ((p[2] * size[1]) + p[1]) * size[0] + p[0];
982  char c = msg->data[addr];
983  if (c < 0)
984  c = unknown_cost_;
985  cm_[p] = c;
986  if (c < cost_min)
987  cost_min = c;
988  }
989  p[2] = 0;
990  cm_rough_[p] = cost_min;
991  }
992  }
993  ROS_DEBUG("Map copied");
994 
995  cm_hyst_.clear(100);
996  hyst_updated_cells_.clear();
997  has_hysteresis_map_ = false;
998 
999  cm_updates_.clear(0);
1000 
1001  has_map_ = true;
1002 
1003  cm_rough_base_ = cm_rough_;
1004  cm_base_ = cm_;
1005  bbf_costmap_.clear();
1006 
1007  prev_map_update_x_min_ = map_info_.width;
1008  prev_map_update_x_max_ = 0;
1009  prev_map_update_y_min_ = map_info_.height;
1010  prev_map_update_y_max_ = 0;
1011 
1012  updateGoal();
1013 
1014  if (map_update_retained_ && map_update_retained_->header.stamp >= msg->header.stamp)
1015  {
1016  ROS_INFO("Applying retained map update");
1017  cbMapUpdate(map_update_retained_);
1018  }
1019  map_update_retained_ = nullptr;
1020  }
1021  void cbAction()
1022  {
1023  if (act_tolerant_->isActive())
1024  {
1025  ROS_ERROR("Setting new goal is ignored since planner_3d is proceeding by tolerant_move action.");
1026  return;
1027  }
1028 
1029  move_base_msgs::MoveBaseGoalConstPtr goal = act_->acceptNewGoal();
1030  if (!setGoal(goal->target_pose))
1031  act_->setAborted(move_base_msgs::MoveBaseResult(), "Given goal is invalid.");
1032  }
1033 
1035  {
1036  if (act_->isActive())
1037  {
1038  ROS_ERROR("Setting new goal is ignored since planner_3d is proceeding by move_base action.");
1039  return;
1040  }
1041 
1042  goal_tolerant_ = act_tolerant_->acceptNewGoal();
1043  if (!setGoal(goal_tolerant_->target_pose))
1044  act_tolerant_->setAborted(planner_cspace_msgs::MoveWithToleranceResult(), "Given goal is invalid.");
1045  }
1046 
1048  {
1049  geometry_msgs::PoseStamped start;
1050  start.header.frame_id = robot_frame_;
1051  start.header.stamp = ros::Time(0);
1052  start.pose.orientation.x = 0.0;
1053  start.pose.orientation.y = 0.0;
1054  start.pose.orientation.z = 0.0;
1055  start.pose.orientation.w = 1.0;
1056  start.pose.position.x = 0;
1057  start.pose.position.y = 0;
1058  start.pose.position.z = 0;
1059  try
1060  {
1061  geometry_msgs::TransformStamped trans =
1062  tfbuf_.lookupTransform(map_header_.frame_id, robot_frame_, ros::Time(), ros::Duration(0.1));
1063  tf2::doTransform(start, start, trans);
1064  }
1065  catch (tf2::TransformException& e)
1066  {
1067  has_start_ = false;
1068  return;
1069  }
1070  start_ = start;
1071  has_start_ = true;
1072  }
1073 
1074 public:
1076  : nh_()
1077  , pnh_("~")
1078  , tfl_(tfbuf_)
1079  , cost_estim_cache_(cm_rough_, bbf_costmap_)
1080  , jump_(tfbuf_)
1081  {
1084  nh_, "costmap",
1085  pnh_, "costmap", 1, &Planner3dNode::cbMap, this);
1086  sub_map_update_ = neonavigation_common::compat::subscribe(
1087  nh_, "costmap_update",
1088  pnh_, "costmap_update", 1, &Planner3dNode::cbMapUpdate, this);
1090  nh_, "move_base_simple/goal",
1091  pnh_, "goal", 1, &Planner3dNode::cbGoal, this);
1092  pub_start_ = pnh_.advertise<geometry_msgs::PoseStamped>("path_start", 1, true);
1093  pub_end_ = pnh_.advertise<geometry_msgs::PoseStamped>("path_end", 1, true);
1094  pub_status_ = pnh_.advertise<planner_cspace_msgs::PlannerStatus>("status", 1, true);
1095  pub_metrics_ = pnh_.advertise<neonavigation_metrics_msgs::Metrics>("metrics", 1, false);
1097  nh_, "forget_planning_cost",
1098  pnh_, "forget", &Planner3dNode::cbForget, this);
1099  srs_make_plan_ = pnh_.advertiseService("make_plan", &Planner3dNode::cbMakePlan, this);
1100 
1101  // Debug outputs
1102  pub_distance_map_ = pnh_.advertise<sensor_msgs::PointCloud>("distance_map", 1, true);
1103  pub_hysteresis_map_ = pnh_.advertise<nav_msgs::OccupancyGrid>("hysteresis_map", 1, true);
1104  pub_remembered_map_ = pnh_.advertise<nav_msgs::OccupancyGrid>("remembered_map", 1, true);
1105 
1106  act_.reset(new Planner3DActionServer(ros::NodeHandle(), "move_base", false));
1107  act_->registerGoalCallback(boost::bind(&Planner3dNode::cbAction, this));
1108  act_->registerPreemptCallback(boost::bind(&Planner3dNode::cbPreempt, this));
1109 
1110  act_tolerant_.reset(new Planner3DTolerantActionServer(ros::NodeHandle(), "tolerant_move", false));
1111  act_tolerant_->registerGoalCallback(boost::bind(&Planner3dNode::cbTolerantAction, this));
1112  act_tolerant_->registerPreemptCallback(boost::bind(&Planner3dNode::cbPreempt, this));
1113  goal_tolerant_ = nullptr;
1114 
1115  pnh_.param("use_path_with_velocity", use_path_with_velocity_, false);
1116  if (use_path_with_velocity_)
1117  {
1118  pub_path_velocity_ = nh_.advertise<trajectory_tracker_msgs::PathWithVelocity>(
1119  "path_velocity", 1, true);
1120  }
1121  else
1122  {
1123  pub_path_ = neonavigation_common::compat::advertise<nav_msgs::Path>(
1124  nh_, "path",
1125  pnh_, "path", 1, true);
1126  }
1127  pub_path_poses_ = pnh_.advertise<geometry_msgs::PoseArray>(
1128  "path_poses", 1, true);
1129 
1130  pnh_.param("freq", freq_, 4.0f);
1131  pnh_.param("freq_min", freq_min_, 2.0f);
1132  pnh_.param("search_timeout_abort", search_timeout_abort_, 30.0f);
1133  pnh_.param("search_range", search_range_, 0.4f);
1134  pnh_.param("antialias_start", antialias_start_, false);
1135 
1136  double costmap_watchdog;
1137  pnh_.param("costmap_watchdog", costmap_watchdog, 0.0);
1138  costmap_watchdog_ = ros::Duration(costmap_watchdog);
1139 
1140  pnh_.param("max_vel", cc_.max_vel_, 0.3f);
1141  pnh_.param("max_ang_vel", cc_.max_ang_vel_, 0.6f);
1142  pnh_.param("min_curve_radius", cc_.min_curve_radius_, 0.1f);
1143 
1144  pnh_.param("weight_decel", cc_.weight_decel_, 50.0f);
1145  pnh_.param("weight_backward", cc_.weight_backward_, 0.9f);
1146  pnh_.param("weight_ang_vel", cc_.weight_ang_vel_, 1.0f);
1147  pnh_.param("weight_costmap", cc_.weight_costmap_, 50.0f);
1148  pnh_.param("weight_costmap_turn", cc_.weight_costmap_turn_, 0.0f);
1149  pnh_.param("weight_remembered", cc_.weight_remembered_, 1000.0f);
1150  pnh_.param("cost_in_place_turn", cc_.in_place_turn_, 30.0f);
1151  pnh_.param("hysteresis_max_dist", cc_.hysteresis_max_dist_, 0.1f);
1152  pnh_.param("hysteresis_expand", cc_.hysteresis_expand_, 0.1f);
1153  pnh_.param("weight_hysteresis", cc_.weight_hysteresis_, 5.0f);
1154 
1155  pnh_.param("goal_tolerance_lin", goal_tolerance_lin_f_, 0.05);
1156  pnh_.param("goal_tolerance_ang", goal_tolerance_ang_f_, 0.1);
1157  pnh_.param("goal_tolerance_ang_finish", goal_tolerance_ang_finish_, 0.05);
1158 
1159  pnh_.param("unknown_cost", unknown_cost_, 100);
1160  pnh_.param("overwrite_cost", overwrite_cost_, false);
1161 
1162  pnh_.param("hist_ignore_range", hist_ignore_range_f_, 0.6);
1163  pnh_.param("hist_ignore_range_max", hist_ignore_range_max_f_, 1.25);
1164  pnh_.param("remember_updates", remember_updates_, false);
1165  double remember_hit_prob, remember_miss_prob;
1166  pnh_.param("remember_hit_prob", remember_hit_prob, 0.6);
1167  pnh_.param("remember_miss_prob", remember_miss_prob, 0.3);
1168  remember_hit_odds_ = bbf::probabilityToOdds(remember_hit_prob);
1169  remember_miss_odds_ = bbf::probabilityToOdds(remember_miss_prob);
1170 
1171  pnh_.param("local_range", local_range_f_, 2.5);
1172  pnh_.param("longcut_range", longcut_range_f_, 0.0);
1173  pnh_.param("esc_range", esc_range_f_, 0.25);
1174  pnh_.param("tolerance_range", tolerance_range_f_, 0.25);
1175  pnh_.param("tolerance_angle", tolerance_angle_f_, 0.0);
1176 
1177  pnh_.param("sw_wait", sw_wait_, 2.0f);
1178  pnh_.param("find_best", find_best_, true);
1179 
1180  pnh_.param("robot_frame", robot_frame_, std::string("base_link"));
1181 
1182  double pos_jump, yaw_jump;
1183  std::string jump_detect_frame;
1184  pnh_.param("pos_jump", pos_jump, 1.0);
1185  pnh_.param("yaw_jump", yaw_jump, 1.5);
1186  pnh_.param("jump_detect_frame", jump_detect_frame, std::string("base_link"));
1187  jump_.setBaseFrame(jump_detect_frame);
1188  jump_.setThresholds(pos_jump, yaw_jump);
1189 
1190  pnh_.param("force_goal_orientation", force_goal_orientation_, true);
1191 
1192  pnh_.param("temporary_escape", temporary_escape_, true);
1193 
1194  pnh_.param("fast_map_update", fast_map_update_, false);
1195  if (fast_map_update_)
1196  {
1197  ROS_WARN("planner_3d: Experimental fast_map_update is enabled. ");
1198  }
1199  if (pnh_.hasParam("debug_mode"))
1200  {
1201  ROS_ERROR(
1202  "planner_3d: ~/debug_mode parameter and ~/debug topic are deprecated. "
1203  "Use ~/distance_map, ~/hysteresis_map, and ~/remembered_map topics instead.");
1204  }
1205 
1206  bool print_planning_duration;
1207  pnh_.param("print_planning_duration", print_planning_duration, false);
1208  if (print_planning_duration)
1209  {
1211  {
1213  }
1214  }
1215 
1216  pnh_.param("max_retry_num", max_retry_num_, -1);
1217 
1218  int queue_size_limit;
1219  pnh_.param("queue_size_limit", queue_size_limit, 0);
1220  as_.setQueueSizeLimit(queue_size_limit);
1221 
1222  int num_threads;
1223  pnh_.param("num_threads", num_threads, 1);
1224  omp_set_num_threads(num_threads);
1225 
1226  int num_task;
1227  pnh_.param("num_search_task", num_task, num_threads * 16);
1228  as_.setSearchTaskNum(num_task);
1229  int num_cost_estim_task;
1230  pnh_.param("num_cost_estim_task", num_cost_estim_task, num_threads * 16);
1231  cost_estim_cache_.setParams(cc_, num_cost_estim_task);
1232 
1233  pnh_.param("retain_last_error_status", retain_last_error_status_, true);
1234  status_.status = planner_cspace_msgs::PlannerStatus::DONE;
1235 
1236  has_map_ = false;
1237  has_goal_ = false;
1238  has_start_ = false;
1239  goal_updated_ = false;
1240 
1241  escaping_ = false;
1242  cnt_stuck_ = 0;
1243  is_path_switchback_ = false;
1244 
1245  diag_updater_.setHardwareID("none");
1246  diag_updater_.add("Path Planner Status", this, &Planner3dNode::diagnoseStatus);
1247 
1248  act_->start();
1249  act_tolerant_->start();
1250  }
1251 
1252  GridAstarModel3D::Vec pathPose2Grid(const geometry_msgs::PoseStamped& pose) const
1253  {
1254  GridAstarModel3D::Vec grid_vec;
1255  grid_metric_converter::metric2Grid(map_info_, grid_vec[0], grid_vec[1], grid_vec[2],
1256  pose.pose.position.x, pose.pose.position.y, tf2::getYaw(pose.pose.orientation));
1257  grid_vec.cycleUnsigned(map_info_.angle);
1258  return grid_vec;
1259  }
1260 
1261  void waitUntil(const ros::Time& next_replan_time, const nav_msgs::Path& previous_path)
1262  {
1263  while (ros::ok())
1264  {
1265  const ros::Time prev_map_update_stamp = last_costmap_;
1266  ros::spinOnce();
1267  const bool costmap_udpated = last_costmap_ != prev_map_update_stamp;
1268 
1269  if (has_map_)
1270  {
1271  updateStart();
1272 
1273  if (jump_.detectJump())
1274  {
1275  bbf_costmap_.clear();
1276  // Robot pose jumped.
1277  return;
1278  }
1279 
1280  if (costmap_udpated && previous_path.poses.size() > 1)
1281  {
1282  for (const auto& path_pose : previous_path.poses)
1283  {
1284  if (cm_[pathPose2Grid(path_pose)] == 100)
1285  {
1286  // Obstacle on the path.
1287  return;
1288  }
1289  }
1290  }
1291 
1292  if (is_path_switchback_)
1293  {
1294  const float len = std::hypot(
1295  start_.pose.position.y - sw_pos_.pose.position.y,
1296  start_.pose.position.x - sw_pos_.pose.position.x);
1297  const float yaw = tf2::getYaw(start_.pose.orientation);
1298  const float sw_yaw = tf2::getYaw(sw_pos_.pose.orientation);
1299  float yaw_diff = yaw - sw_yaw;
1300  yaw_diff = std::atan2(std::sin(yaw_diff), std::cos(yaw_diff));
1301  if (len < goal_tolerance_lin_f_ && std::fabs(yaw_diff) < goal_tolerance_ang_f_)
1302  {
1303  // robot has arrived at the switchback point
1304  is_path_switchback_ = false;
1305  }
1306  }
1307  }
1308  if (ros::Time::now() > next_replan_time)
1309  {
1310  return;
1311  }
1312  ros::Duration(0.01).sleep();
1313  }
1314  }
1315 
1316  void spin()
1317  {
1318  ROS_DEBUG("Initialized");
1319 
1320  ros::Time next_replan_time = ros::Time::now();
1321  nav_msgs::Path previous_path;
1322 
1323  while (ros::ok())
1324  {
1325  waitUntil(next_replan_time, previous_path);
1326 
1327  const ros::Time now = ros::Time::now();
1328  next_replan_time = now;
1329 
1330  if (has_map_ && !goal_updated_ && has_goal_)
1331  {
1332  updateGoal();
1333  }
1334  bool has_costmap(false);
1335  if (costmap_watchdog_ > ros::Duration(0))
1336  {
1337  const ros::Duration costmap_delay = now - last_costmap_;
1338  metrics_.data.push_back(neonavigation_metrics_msgs::metric(
1339  "costmap_delay",
1340  costmap_delay.toSec(),
1341  "second"));
1342  if (costmap_delay > costmap_watchdog_)
1343  {
1344  ROS_WARN_THROTTLE(1.0,
1345  "Navigation is stopping since the costmap is too old (costmap: %0.3f)",
1346  last_costmap_.toSec());
1347  status_.error = planner_cspace_msgs::PlannerStatus::DATA_MISSING;
1348  publishEmptyPath();
1349  previous_path.poses.clear();
1350  }
1351  else
1352  {
1353  has_costmap = true;
1354  }
1355  }
1356  else
1357  {
1358  metrics_.data.push_back(neonavigation_metrics_msgs::metric(
1359  "costmap_delay",
1360  -1.0,
1361  "second"));
1362  has_costmap = true;
1363  }
1364 
1365  bool is_path_switchback = false;
1366  if (has_map_ && has_goal_ && has_start_ && has_costmap)
1367  {
1368  if (act_->isActive())
1369  {
1370  move_base_msgs::MoveBaseFeedback feedback;
1371  feedback.base_position = start_;
1372  act_->publishFeedback(feedback);
1373  }
1374 
1375  if (act_tolerant_->isActive())
1376  {
1377  planner_cspace_msgs::MoveWithToleranceFeedback feedback;
1378  feedback.base_position = start_;
1379  act_tolerant_->publishFeedback(feedback);
1380  }
1381 
1382  if (status_.status == planner_cspace_msgs::PlannerStatus::FINISHING)
1383  {
1384  const float yaw_s = tf2::getYaw(start_.pose.orientation);
1385  float yaw_g = tf2::getYaw(goal_.pose.orientation);
1386  if (force_goal_orientation_)
1387  yaw_g = tf2::getYaw(goal_raw_.pose.orientation);
1388 
1389  float yaw_diff = yaw_s - yaw_g;
1390  if (yaw_diff > M_PI)
1391  yaw_diff -= M_PI * 2.0;
1392  else if (yaw_diff < -M_PI)
1393  yaw_diff += M_PI * 2.0;
1394  if (std::abs(yaw_diff) <
1395  (act_tolerant_->isActive() ? goal_tolerant_->goal_tolerance_ang_finish : goal_tolerance_ang_finish_))
1396  {
1397  status_.status = planner_cspace_msgs::PlannerStatus::DONE;
1398  has_goal_ = false;
1399  // Don't publish empty path here in order a path follower
1400  // to minimize the error to the desired final pose
1401  ROS_INFO("Path plan finished");
1402 
1403  if (act_->isActive())
1404  act_->setSucceeded(move_base_msgs::MoveBaseResult(), "Goal reached.");
1405  if (act_tolerant_->isActive())
1406  act_tolerant_->setSucceeded(planner_cspace_msgs::MoveWithToleranceResult(), "Goal reached.");
1407  }
1408  else
1409  {
1411  }
1412  }
1413  else
1414  {
1415  if (escaping_)
1416  {
1417  status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1418  }
1419  else if (max_retry_num_ != -1 && cnt_stuck_ > max_retry_num_)
1420  {
1421  status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1422  status_.status = planner_cspace_msgs::PlannerStatus::DONE;
1423  has_goal_ = false;
1424 
1425  publishEmptyPath();
1426  previous_path.poses.clear();
1427  next_replan_time += ros::Duration(1.0 / freq_);
1428  ROS_ERROR("Exceeded max_retry_num:%d", max_retry_num_);
1429 
1430  if (act_->isActive())
1431  act_->setAborted(
1432  move_base_msgs::MoveBaseResult(), "Goal is in Rock");
1433  if (act_tolerant_->isActive())
1434  act_tolerant_->setAborted(
1435  planner_cspace_msgs::MoveWithToleranceResult(), "Goal is in Rock");
1436 
1437  continue;
1438  }
1439  else if (cnt_stuck_ > 0)
1440  {
1441  status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1442  }
1443  else
1444  {
1445  status_.error = planner_cspace_msgs::PlannerStatus::GOING_WELL;
1446  }
1447  nav_msgs::Path path;
1448  path.header = map_header_;
1449  path.header.stamp = now;
1450  makePlan(start_.pose, goal_.pose, path, true);
1451  if (use_path_with_velocity_)
1452  {
1453  // NaN velocity means that don't care the velocity
1454  pub_path_velocity_.publish(
1455  trajectory_tracker_msgs::toPathWithVelocity(path, std::numeric_limits<double>::quiet_NaN()));
1456  }
1457  else
1458  {
1459  pub_path_.publish(path);
1460  }
1461  previous_path = path;
1462 
1463  if (sw_wait_ > 0.0)
1464  {
1465  const int sw_index = getSwitchIndex(path);
1466  is_path_switchback = (sw_index >= 0);
1467  if (is_path_switchback)
1468  sw_pos_ = path.poses[sw_index];
1469  }
1470  }
1471  }
1472  else if (!has_goal_)
1473  {
1474  if (!retain_last_error_status_)
1475  status_.error = planner_cspace_msgs::PlannerStatus::GOING_WELL;
1476  publishEmptyPath();
1477  previous_path.poses.clear();
1478  }
1479  status_.header.stamp = now;
1480  pub_status_.publish(status_);
1481  diag_updater_.force_update();
1482 
1483  metrics_.header.stamp = now;
1484  metrics_.data.push_back(neonavigation_metrics_msgs::metric(
1485  "stuck_cnt",
1486  cnt_stuck_,
1487  "count"));
1488  metrics_.data.push_back(neonavigation_metrics_msgs::metric(
1489  "error",
1490  status_.error,
1491  "enum"));
1492  metrics_.data.push_back(neonavigation_metrics_msgs::metric(
1493  "status",
1494  status_.status,
1495  "enum"));
1496  pub_metrics_.publish(metrics_);
1497  metrics_.data.clear();
1498 
1499  if (is_path_switchback)
1500  {
1501  next_replan_time += ros::Duration(sw_wait_);
1502  ROS_INFO("Planned path has switchback. Planner will stop until: %f at the latest.", next_replan_time.toSec());
1503  }
1504  else
1505  {
1506  next_replan_time += ros::Duration(1.0 / freq_);
1507  }
1508  is_path_switchback_ = is_path_switchback;
1509  }
1510  }
1511 
1512 protected:
1513  bool makePlan(const geometry_msgs::Pose& gs, const geometry_msgs::Pose& ge,
1514  nav_msgs::Path& path, bool hyst)
1515  {
1516  Astar::Vec e;
1518  map_info_, e[0], e[1], e[2],
1519  ge.position.x, ge.position.y, tf2::getYaw(ge.orientation));
1520  e.cycleUnsigned(map_info_.angle);
1521 
1522  Astar::Vecf sf;
1524  map_info_, sf[0], sf[1], sf[2],
1525  gs.position.x, gs.position.y, tf2::getYaw(gs.orientation));
1526  Astar::Vec s(static_cast<int>(std::floor(sf[0])), static_cast<int>(std::floor(sf[1])), std::lround(sf[2]));
1527  s.cycleUnsigned(map_info_.angle);
1528  if (!cm_.validate(s, range_))
1529  {
1530  ROS_ERROR("You are on the edge of the world.");
1531  return false;
1532  }
1533 
1534  std::vector<Astar::VecWithCost> starts;
1535  if (antialias_start_)
1536  {
1537  const int x_cand[] = {0, ((sf[0] - s[0]) < 0.5 ? -1 : 1)};
1538  const int y_cand[] = {0, ((sf[1] - s[1]) < 0.5 ? -1 : 1)};
1539  for (const int x : x_cand)
1540  {
1541  for (const int y : y_cand)
1542  {
1543  const Astar::Vec p = s + Astar::Vec(x, y, 0);
1544  if (!cm_.validate(p, range_))
1545  continue;
1546 
1547  const Astar::Vecf subpx = sf - Astar::Vecf(p[0] + 0.5f, p[1] + 0.5f, 0.0f);
1548  if (subpx.sqlen() > 1.0)
1549  continue;
1550  if (cm_[p] > 99)
1551  continue;
1552 
1553  starts.push_back(Astar::VecWithCost(p));
1554  }
1555  }
1556  }
1557  else
1558  {
1559  if (cm_[s] < 100)
1560  {
1561  starts.push_back(Astar::VecWithCost(s));
1562  }
1563  }
1564  for (Astar::VecWithCost& s : starts)
1565  {
1566  const Astar::Vecf diff =
1567  Astar::Vecf(s.v_[0] + 0.5f, s.v_[1] + 0.5f, 0.0f) - sf;
1568  s.c_ = std::hypot(diff[0] * ec_[0], diff[1] * ec_[0]);
1569  s.c_ += cm_[s.v_] * cc_.weight_costmap_ / 100.0;
1570 
1571  // Check if arrived to the goal
1572  Astar::Vec remain = s.v_ - e;
1573  remain.cycle(map_info_.angle);
1574 
1575  int g_tolerance_lin, g_tolerance_ang;
1576  if (act_tolerant_->isActive())
1577  {
1578  g_tolerance_lin = std::lround(goal_tolerant_->goal_tolerance_lin / map_info_.linear_resolution);
1579  g_tolerance_ang = std::lround(goal_tolerant_->goal_tolerance_ang / map_info_.angular_resolution);
1580  }
1581  else
1582  {
1583  g_tolerance_lin = goal_tolerance_lin_;
1584  g_tolerance_ang = goal_tolerance_ang_;
1585  }
1586 
1587  if (remain.sqlen() <= g_tolerance_lin * g_tolerance_lin &&
1588  std::abs(remain[2]) <= g_tolerance_ang)
1589  {
1590  if (escaping_)
1591  {
1592  goal_ = goal_raw_;
1593  escaping_ = false;
1594  updateGoal();
1595  ROS_INFO("Escaped");
1596  return true;
1597  }
1598  else
1599  {
1600  if (act_tolerant_->isActive() && goal_tolerant_->continuous_movement_mode)
1601  {
1602  ROS_INFO("Robot reached near the goal.");
1603  act_tolerant_->setSucceeded(planner_cspace_msgs::MoveWithToleranceResult(),
1604  "Goal reached (Continuous movement mode).");
1605  goal_tolerant_ = nullptr;
1606  }
1607  else
1608  {
1609  status_.status = planner_cspace_msgs::PlannerStatus::FINISHING;
1611  ROS_INFO("Path plan finishing");
1612  return true;
1613  }
1614  }
1615  }
1616  }
1617 
1618  geometry_msgs::PoseStamped p;
1619  p.header = map_header_;
1620  float x, y, yaw;
1621  grid_metric_converter::grid2Metric(map_info_, e[0], e[1], e[2], x, y, yaw);
1622  p.pose.orientation = tf2::toMsg(tf2::Quaternion(tf2::Vector3(0.0, 0.0, 1.0), yaw));
1623  p.pose.position.x = x;
1624  p.pose.position.y = y;
1625  pub_end_.publish(p);
1626 
1627  if (starts.size() == 0)
1628  {
1629  if (!searchAvailablePos(cm_, s, tolerance_range_, tolerance_angle_))
1630  {
1631  ROS_WARN("Oops! You are in Rock!");
1632  status_.error = planner_cspace_msgs::PlannerStatus::IN_ROCK;
1633  return false;
1634  }
1635  ROS_INFO("Start moved");
1636  starts.push_back(Astar::VecWithCost(s));
1637  }
1638  const Astar::Vec s_rough(s[0], s[1], 0);
1639 
1640  // If goal gets occupied, cost_estim_cache_ is not updated to reduce
1641  // computational cost for clearing huge map. In this case, cm_[e] is 100.
1642  if (cost_estim_cache_[s_rough] == std::numeric_limits<float>::max() || cm_[e] >= 100)
1643  {
1644  status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1645  ROS_WARN("Goal unreachable.");
1646  if (!escaping_ && temporary_escape_)
1647  {
1648  e = s;
1649  if (searchAvailablePos(cm_, e, esc_range_, esc_angle_, 50, esc_range_ / 2))
1650  {
1651  escaping_ = true;
1652  ROS_INFO("Temporary goal (%d, %d, %d)",
1653  e[0], e[1], e[2]);
1654  float x, y, yaw;
1655  grid_metric_converter::grid2Metric(map_info_, e[0], e[1], e[2], x, y, yaw);
1656  goal_.pose.orientation = tf2::toMsg(tf2::Quaternion(tf2::Vector3(0.0, 0.0, 1.0), yaw));
1657  goal_.pose.position.x = x;
1658  goal_.pose.position.y = y;
1659 
1660  updateGoal();
1661  return false;
1662  }
1663  }
1664  return false;
1665  }
1666 
1667  grid_metric_converter::grid2Metric(map_info_, s[0], s[1], s[2], x, y, yaw);
1668  p.pose.orientation = tf2::toMsg(tf2::Quaternion(tf2::Vector3(0.0, 0.0, 1.0), yaw));
1669  p.pose.position.x = x;
1670  p.pose.position.y = y;
1671  pub_start_.publish(p);
1672 
1673  const float range_limit = cost_estim_cache_[s_rough] - (local_range_ + range_) * ec_[0];
1674 
1675  const auto ts = boost::chrono::high_resolution_clock::now();
1676  // ROS_INFO("Planning from (%d, %d, %d) to (%d, %d, %d)",
1677  // s[0], s[1], s[2], e[0], e[1], e[2]);
1678 
1679  const auto cb_progress = [this, ts, s, e](const std::list<Astar::Vec>& path_grid, const SearchStats& stats) -> bool
1680  {
1681  const auto tnow = boost::chrono::high_resolution_clock::now();
1682  const auto tdiff = boost::chrono::duration<float>(tnow - ts).count();
1683  publishEmptyPath();
1684  if (tdiff > search_timeout_abort_)
1685  {
1686  ROS_ERROR(
1687  "Search aborted due to timeout. "
1688  "search_timeout_abort may be too small or planner_3d may have a bug: "
1689  "s=(%d, %d, %d), g=(%d, %d, %d), tdiff=%0.4f, "
1690  "num_loop=%lu, "
1691  "num_search_queue=%lu, "
1692  "num_prev_updates=%lu, "
1693  "num_total_updates=%lu, ",
1694  s[0], s[1], s[2], e[0], e[1], e[2], tdiff,
1695  stats.num_loop, stats.num_search_queue, stats.num_prev_updates, stats.num_total_updates);
1696  return false;
1697  }
1698  ROS_WARN("Search timed out (%0.4f sec.)", tdiff);
1699  return true;
1700  };
1701 
1702  model_->enableHysteresis(hyst && has_hysteresis_map_);
1703  std::list<Astar::Vec> path_grid;
1704  if (!as_.search(starts, e, path_grid,
1705  model_,
1706  cb_progress,
1707  range_limit,
1708  1.0f / freq_min_,
1709  find_best_))
1710  {
1711  ROS_WARN("Path plan failed (goal unreachable)");
1712  status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1713  if (!find_best_)
1714  return false;
1715  }
1716  const auto tnow = boost::chrono::high_resolution_clock::now();
1717  const float dur = boost::chrono::duration<float>(tnow - ts).count();
1718  ROS_DEBUG("Path found (%0.4f sec.)", dur);
1719  metrics_.data.push_back(neonavigation_metrics_msgs::metric(
1720  "path_search_dur",
1721  dur,
1722  "second"));
1723 
1724  geometry_msgs::PoseArray poses;
1725  poses.header = path.header;
1726  for (const auto& p : path_grid)
1727  {
1728  geometry_msgs::Pose pose;
1729  float x, y, yaw;
1730  grid_metric_converter::grid2Metric(map_info_, p[0], p[1], p[2], x, y, yaw);
1731  pose.position.x = x;
1732  pose.position.y = y;
1733  pose.orientation =
1734  tf2::toMsg(tf2::Quaternion(tf2::Vector3(0.0, 0.0, 1.0), yaw));
1735  poses.poses.push_back(pose);
1736  }
1737  pub_path_poses_.publish(poses);
1738 
1739  const std::list<Astar::Vecf> path_interpolated =
1740  model_->path_interpolator_.interpolate(path_grid, 0.5, local_range_);
1741  grid_metric_converter::grid2MetricPath(map_info_, path_interpolated, path);
1742 
1743  if (hyst)
1744  {
1745  const auto ts = boost::chrono::high_resolution_clock::now();
1746  std::unordered_map<Astar::Vec, bool, Astar::Vec> path_points;
1747  const float max_dist = cc_.hysteresis_max_dist_ / map_info_.linear_resolution;
1748  const float expand_dist = cc_.hysteresis_expand_ / map_info_.linear_resolution;
1749  const int path_range = range_ + max_dist + expand_dist + 5;
1750  for (const Astar::Vecf& p : path_interpolated)
1751  {
1752  Astar::Vec d;
1753  for (d[0] = -path_range; d[0] <= path_range; d[0]++)
1754  {
1755  for (d[1] = -path_range; d[1] <= path_range; d[1]++)
1756  {
1757  Astar::Vec point = p + d;
1758  point.cycleUnsigned(map_info_.angle);
1759  if ((unsigned int)point[0] >= (unsigned int)map_info_.width ||
1760  (unsigned int)point[1] >= (unsigned int)map_info_.height)
1761  continue;
1762  path_points[point] = true;
1763  }
1764  }
1765  }
1766 
1767  clearHysteresis();
1768  for (auto& ps : path_points)
1769  {
1770  const Astar::Vec& p = ps.first;
1771  float d_min = std::numeric_limits<float>::max();
1772  auto it_prev = path_interpolated.cbegin();
1773  for (auto it = path_interpolated.cbegin(); it != path_interpolated.cend(); it++)
1774  {
1775  if (it != it_prev)
1776  {
1777  int yaw = std::lround((*it)[2]) % map_info_.angle;
1778  int yaw_prev = std::lround((*it_prev)[2]) % map_info_.angle;
1779  if (yaw < 0)
1780  yaw += map_info_.angle;
1781  if (yaw_prev < 0)
1782  yaw_prev += map_info_.angle;
1783  if (yaw == p[2] || yaw_prev == p[2])
1784  {
1785  const float d =
1786  CyclicVecFloat<3, 2>(p).distLinestrip2d(*it_prev, *it);
1787  if (d < d_min)
1788  d_min = d;
1789  }
1790  }
1791  it_prev = it;
1792  }
1793  d_min = std::max(expand_dist, std::min(expand_dist + max_dist, d_min));
1794  cm_hyst_[p] = std::lround((d_min - expand_dist) * 100.0 / max_dist);
1795  hyst_updated_cells_.push_back(p);
1796  }
1797  has_hysteresis_map_ = true;
1798  const auto tnow = boost::chrono::high_resolution_clock::now();
1799  const float dur = boost::chrono::duration<float>(tnow - ts).count();
1800  ROS_DEBUG("Hysteresis map generated (%0.4f sec.)", dur);
1801  metrics_.data.push_back(neonavigation_metrics_msgs::metric(
1802  "hyst_map_dur",
1803  dur,
1804  "second"));
1805  publishDebug();
1806  }
1807 
1808  return true;
1809  }
1810 
1811  int getSwitchIndex(const nav_msgs::Path& path) const
1812  {
1813  geometry_msgs::Pose p_prev;
1814  bool first(true);
1815  bool dir_set(false);
1816  bool dir_prev(false);
1817  for (auto it = path.poses.begin(); it != path.poses.end(); ++it)
1818  {
1819  const auto& p = *it;
1820  if (!first)
1821  {
1822  const float x_diff = p.pose.position.x - p_prev.position.x;
1823  const float y_diff = p.pose.position.y - p_prev.position.y;
1824  const float len_sq = std::pow(y_diff, 2) + std::pow(x_diff, 2);
1825  if (len_sq > std::pow(0.001f, 2))
1826  {
1827  const float yaw = tf2::getYaw(p.pose.orientation);
1828  const bool dir = (std::cos(yaw) * x_diff + std::sin(yaw) * y_diff < 0);
1829 
1830  if (dir_set && (dir_prev ^ dir))
1831  {
1832  return std::distance(path.poses.begin(), it);
1833  }
1834  dir_prev = dir;
1835  dir_set = true;
1836  }
1837  }
1838  first = false;
1839  p_prev = p.pose;
1840  }
1841  // -1 means no switchback in the path
1842  return -1;
1843  }
1845  {
1846  switch (status_.error)
1847  {
1848  case planner_cspace_msgs::PlannerStatus::GOING_WELL:
1849  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Going well.");
1850  break;
1851  case planner_cspace_msgs::PlannerStatus::IN_ROCK:
1852  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "The robot is in rock.");
1853  break;
1854  case planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND:
1855  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Path not found.");
1856  break;
1857  case planner_cspace_msgs::PlannerStatus::DATA_MISSING:
1858  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Required data is missing.");
1859  break;
1860  case planner_cspace_msgs::PlannerStatus::INTERNAL_ERROR:
1861  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Planner internal error.");
1862  break;
1863  default:
1864  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Unknown error.");
1865  break;
1866  }
1867  stat.addf("status", "%u", status_.status);
1868  stat.addf("error", "%u", status_.error);
1869  }
1870 };
1871 } // namespace planner_3d
1872 } // namespace planner_cspace
1873 
1874 int main(int argc, char* argv[])
1875 {
1876  ros::init(argc, argv, "planner_3d");
1877 
1879  node.spin();
1880 
1881  return 0;
1882 }
void remember(const BlockMemGridmapBase< char, 3, 2 > *const costmap, const Vec &center, const float remember_hit_odds, const float remember_miss_odds, const int range_min, const int range_max)
Definition: costmap_bbf.cpp:51
planner_cspace_msgs::MoveWithToleranceGoalConstPtr goal_tolerant_
Definition: planner_3d.cpp:114
d
geometry_msgs::PoseStamped goal_raw_
Definition: planner_3d.cpp:183
void init(const GridAstarModel3D::Ptr model, const Params &p)
ROSCPP_DECL void start()
ROSCONSOLE_DECL void notifyLoggerLevelsChanged()
actionlib::SimpleActionServer< move_base_msgs::MoveBaseAction > Planner3DActionServer
Definition: planner_3d.cpp:91
f
geometry_msgs::PoseStamped start_
Definition: planner_3d.cpp:181
DiscretePoseStatus relocateDiscretePoseIfNeeded(Astar::Vec &pose_discrete, const int tolerance_range, const int tolerance_angle, bool use_cm_rough=false) const
Definition: planner_3d.cpp:251
void setSearchTaskNum(const size_t &search_task_num)
Definition: grid_astar.h:142
void summary(unsigned char lvl, const std::string s)
void diagnoseStatus(diagnostic_updater::DiagnosticStatusWrapper &stat)
costmap_cspace_msgs::MapMetaData3D map_info_
Definition: planner_3d.cpp:130
bool search(const std::vector< VecWithCost > &ss, const Vec &e, std::list< Vec > &path, const typename GridAstarModelBase< DIM, NONCYCLIC >::Ptr &model, ProgressCallback cb_progress, const float cost_leave, const float progress_interval, const bool return_best=false)
Definition: grid_astar.h:169
Astar::Gridmap< char, 0x80 > cm_rough_base_
Definition: planner_3d.cpp:122
const float MIN_PROBABILITY
Definition: bbf.h:47
void setHardwareID(const std::string &hwid)
XmlRpcServer s
bool searchAvailablePos(const T &cm, Astar::Vec &s, const int xy_range, const int angle_range, const int cost_acceptable=50, const int min_xy_range=0) const
Definition: planner_3d.cpp:434
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
IMETHOD Vector diff(const Vector &p_w_a, const Vector &p_w_b, double dt=1)
CyclicVecInt< DIM, NONCYCLIC > Vec
Definition: grid_astar.h:67
void add(const std::string &name, TaskFunction f)
void setQueueSizeLimit(const size_t size)
Definition: grid_astar.h:164
ros::Subscriber subscribe(ros::NodeHandle &nh_new, const std::string &topic_new, ros::NodeHandle &nh_old, const std::string &topic_old, uint32_t queue_size, void(*fp)(M), const ros::TransportHints &transport_hints=ros::TransportHints())
neonavigation_metrics_msgs::Metrics metrics_
Definition: planner_3d.cpp:192
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
void doTransform(const T &data_in, T &data_out, const geometry_msgs::TransformStamped &transform)
Metric metric(const std::string &name, const double value, const std::string &unit, Strings &&... tags)
#define ROS_WARN(...)
void metric2Grid(const costmap_cspace_msgs::MapMetaData3D &map_info, int &x, int &y, int &yaw, const float gx, const float gy, const float gyaw)
int main(int argc, char *argv[])
void addf(const std::string &key, const char *format,...)
void setBaseFrame(const std::string &frame_id)
Definition: jump_detector.h:73
Astar::Gridmap< char, 0x40 > cm_
Definition: planner_3d.cpp:119
Astar::Gridmap< char, 0x80 > cm_rough_
Definition: planner_3d.cpp:120
bool setGoal(const geometry_msgs::PoseStamped &msg)
Definition: planner_3d.cpp:391
void cbMapUpdate(const costmap_cspace_msgs::CSpace3DUpdate::ConstPtr msg)
Definition: planner_3d.cpp:704
void waitUntil(const ros::Time &next_replan_time, const nav_msgs::Path &previous_path)
bool cbForget(std_srvs::EmptyRequest &req, std_srvs::EmptyResponse &res)
Definition: planner_3d.cpp:216
bool param(const std::string &param_name, T &param_val, const T &default_val) const
ros::ServiceServer advertiseService(ros::NodeHandle &nh_new, const std::string &service_new, ros::NodeHandle &nh_old, const std::string &service_old, bool(T::*srv_func)(MReq &, MRes &), T *obj)
virtual geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration timeout) const
void publish(const boost::shared_ptr< M > &message) const
DiscretePoseStatus relocateDiscretePoseIfNeededImpl(const T &cm, const int tolerance_range, const int tolerance_angle, Astar::Vec &pose_discrete) const
Definition: planner_3d.cpp:233
void cbGoal(const geometry_msgs::PoseStamped::ConstPtr &msg)
Definition: planner_3d.cpp:369
geometry_msgs::PoseStamped sw_pos_
Definition: planner_3d.cpp:196
int getSwitchIndex(const nav_msgs::Path &path) const
std::shared_ptr< Planner3DTolerantActionServer > act_tolerant_
Definition: planner_3d.cpp:113
actionlib::SimpleActionServer< planner_cspace_msgs::MoveWithToleranceAction > Planner3DTolerantActionServer
Definition: planner_3d.cpp:92
#define ROS_WARN_THROTTLE(period,...)
#define ROS_INFO(...)
void reset(const Vec size)
Definition: grid_astar.h:147
std::vector< Astar::Vec > search_list_
Definition: planner_3d.cpp:159
ROSCPP_DECL bool ok()
void cycleUnsigned(const int res, const ArgList &... rest)
Definition: cyclic_vec.h:289
void setMapFrame(const std::string &frame_id)
Definition: jump_detector.h:69
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void setThresholds(const double pos_jump, const double yaw_jump)
Definition: jump_detector.h:77
std::shared_ptr< Planner3DActionServer > act_
Definition: planner_3d.cpp:112
const float MAX_PROBABILITY
Definition: bbf.h:48
bool hasParam(const std::string &key) const
double getYaw(const A &a)
typename GridAstarModelBase< DIM, NONCYCLIC >::VecWithCost VecWithCost
Definition: grid_astar.h:69
void grid2MetricPath(const costmap_cspace_msgs::MapMetaData3D &map_info, const STL_CONTAINER< CyclicVecFloat< 3, 2 >, std::allocator< CyclicVecFloat< 3, 2 >>> &path_grid, nav_msgs::Path &path)
Astar::Gridmap< char, 0x40 > cm_base_
Definition: planner_3d.cpp:121
B toMsg(const A &a)
const Astar::Vec & size() const
Definition: distance_map.h:102
const Astar::Gridmap< float > & gridmap() const
Definition: distance_map.h:114
bool makePlan(const geometry_msgs::Pose &gs, const geometry_msgs::Pose &ge, nav_msgs::Path &path, bool hyst)
std::vector< Astar::Vec > search_list_rough_
Definition: planner_3d.cpp:160
constexpr float probabilityToOdds(const float &p)
Definition: bbf.h:42
void grid2Metric(const costmap_cspace_msgs::MapMetaData3D &map_info, const T x, const T y, const T yaw, float &gx, float &gy, float &gyaw)
GridAstarModel3D::Vec pathPose2Grid(const geometry_msgs::PoseStamped &pose) const
geometry_msgs::PoseStamped goal_
Definition: planner_3d.cpp:182
planner_cspace_msgs::PlannerStatus status_
Definition: planner_3d.cpp:191
Astar::Gridmap< char, 0x80 > cm_hyst_
Definition: planner_3d.cpp:123
void setParams(const CostCoeff &cc, const int num_cost_estim_task)
static Time now()
Astar::Gridmap< char, 0x80 > cm_updates_
Definition: planner_3d.cpp:124
costmap_cspace_msgs::CSpace3DUpdate::ConstPtr map_update_retained_
Definition: planner_3d.cpp:131
ROSCONSOLE_DECL bool set_logger_level(const std::string &name, levels::Level level)
void cycle(const int res, const ArgList &... rest)
Definition: cyclic_vec.h:282
bool sleep() const
std::vector< Astar::Vec > hyst_updated_cells_
Definition: planner_3d.cpp:155
bool cbMakePlan(nav_msgs::GetPlan::Request &req, nav_msgs::GetPlan::Response &res)
Definition: planner_3d.cpp:267
void create(const Astar::Vec &s, const Astar::Vec &e)
uint32_t getNumSubscribers() const
ROSCPP_DECL void spinOnce()
#define ROS_ERROR(...)
#define ROSCONSOLE_DEFAULT_NAME
const DebugData & getDebugData() const
Definition: distance_map.h:118
diagnostic_updater::Updater diag_updater_
Definition: planner_3d.cpp:207
PathWithVelocity toPathWithVelocity(const nav_msgs::Path &src, const double vel)
CyclicVecFloat< DIM, NONCYCLIC > Vecf
Definition: grid_astar.h:68
void forEach(const std::function< void(const Vec &, bbf::BinaryBayesFilter &)> cb)
Definition: costmap_bbf.cpp:93
void cbMap(const costmap_cspace_msgs::CSpace3D::ConstPtr &msg)
Definition: planner_3d.cpp:891
void update(const Astar::Vec &s, const Astar::Vec &e, const Rect &rect)
bool updateGoal(const bool goal_changed=true)
Definition: planner_3d.cpp:488
#define ROS_DEBUG(...)


planner_cspace
Author(s): Atsushi Watanabe
autogenerated on Mon Jul 3 2023 02:39:06