planner_3d.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2020, 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 <planner_cspace_msgs/PlannerStatus.h>
52 #include <sensor_msgs/PointCloud.h>
53 #include <std_srvs/Empty.h>
54 #include <trajectory_tracker_msgs/PathWithVelocity.h>
56 
57 #include <ros/console.h>
58 #include <tf2/utils.h>
61 
63 #include <move_base_msgs/MoveBaseAction.h>
64 #include <planner_cspace_msgs/MoveWithToleranceAction.h>
65 
67 
68 #include <planner_cspace/bbf.h>
77 
78 namespace planner_cspace
79 {
80 namespace planner_3d
81 {
83 {
84 public:
86 
87 protected:
90 
107 
108  std::shared_ptr<Planner3DActionServer> act_;
109  std::shared_ptr<Planner3DTolerantActionServer> act_tolerant_;
110  planner_cspace_msgs::MoveWithToleranceGoalConstPtr goal_tolerant_;
113 
115  Astar::Gridmap<char, 0x40> cm_;
116  Astar::Gridmap<char, 0x80> cm_rough_;
117  Astar::Gridmap<char, 0x40> cm_base_;
118  Astar::Gridmap<char, 0x80> cm_rough_base_;
119  Astar::Gridmap<char, 0x80> cm_hyst_;
120  Astar::Gridmap<char, 0x80> cm_updates_;
121  Astar::Gridmap<float> cost_estim_cache_;
123 
125  std::array<float, 1024> euclid_cost_lin_cache_;
126 
127  costmap_cspace_msgs::MapMetaData3D map_info_;
128  std_msgs::Header map_header_;
129  float freq_;
130  float freq_min_;
134  int range_;
141  double esc_range_f_;
148  bool has_map_;
149  bool has_goal_;
152  std::vector<Astar::Vec> hyst_updated_cells_;
156  std::vector<Astar::Vec> search_list_;
157  std::vector<Astar::Vec> search_list_rough_;
167 
169  std::string robot_frame_;
170 
172 
175 
176  // Cost weights
178 
179  geometry_msgs::PoseStamped start_;
180  geometry_msgs::PoseStamped goal_;
181  geometry_msgs::PoseStamped goal_raw_;
188 
189  planner_cspace_msgs::PlannerStatus status_;
190 
192  float sw_wait_;
193  geometry_msgs::PoseStamped sw_pos_;
195 
197  bool rough_;
198 
200 
201  bool escaping_;
202 
204 
208 
213 
216 
217  bool cbForget(std_srvs::EmptyRequest& req,
218  std_srvs::EmptyResponse& res)
219  {
220  ROS_WARN("Forgetting remembered costmap.");
221  if (has_map_)
222  bbf_costmap_.clear();
223 
224  return true;
225  }
227  {
228  OK,
229  RELOCATED,
230  IN_ROCK,
231  OUT_OF_MAP,
232  };
233  template <class T>
235  const int tolerance_range,
236  const int tolerance_angle,
237  Astar::Vec& pose_discrete) const
238  {
239  if (!cm.validate(pose_discrete, range_))
240  {
242  }
243  if (cm[pose_discrete] == 100)
244  {
245  if (searchAvailablePos(cm, pose_discrete, tolerance_range, tolerance_angle))
247  else
249  }
250  return DiscretePoseStatus::OK;
251  }
253  const int tolerance_range,
254  const int tolerance_angle,
255  bool use_cm_rough = false) const
256  {
257  if (use_cm_rough)
258  {
259  pose_discrete[2] = 0;
260  return relocateDiscretePoseIfNeededImpl(cm_rough_, tolerance_range, tolerance_angle, pose_discrete);
261  }
262  else
263  {
264  return relocateDiscretePoseIfNeededImpl(cm_, tolerance_range, tolerance_angle, pose_discrete);
265  }
266  }
267 
268  bool cbMakePlan(nav_msgs::GetPlan::Request& req,
269  nav_msgs::GetPlan::Response& res)
270  {
271  if (!has_map_)
272  {
273  ROS_ERROR("make_plan service is called without map.");
274  return false;
275  }
276 
277  if (req.start.header.frame_id != map_header_.frame_id ||
278  req.goal.header.frame_id != map_header_.frame_id)
279  {
280  ROS_ERROR("Start [%s] and Goal [%s] poses must be in the map frame [%s].",
281  req.start.header.frame_id.c_str(),
282  req.goal.header.frame_id.c_str(),
283  map_header_.frame_id.c_str());
284  return false;
285  }
286 
287  Astar::Vec s, e;
289  map_info_, s[0], s[1], s[2],
290  req.start.pose.position.x, req.start.pose.position.y, tf2::getYaw(req.start.pose.orientation));
292  map_info_, e[0], e[1], e[2],
293  req.goal.pose.position.x, req.goal.pose.position.y, tf2::getYaw(req.goal.pose.orientation));
294  ROS_INFO("Path plan from (%d, %d) to (%d, %d)", s[0], s[1], e[0], e[1]);
295 
296  const int tolerance_range = std::lround(req.tolerance / map_info_.linear_resolution);
297  const DiscretePoseStatus start_status = relocateDiscretePoseIfNeeded(s, tolerance_range, tolerance_angle_, true);
298  const DiscretePoseStatus goal_status = relocateDiscretePoseIfNeeded(e, tolerance_range, tolerance_angle_, true);
299  switch (start_status)
300  {
302  ROS_ERROR("Given start is not on the map.");
303  return false;
305  ROS_ERROR("Given start is in Rock.");
306  return false;
308  ROS_INFO("Given start is moved (%d, %d)", s[0], s[1]);
309  break;
310  default:
311  break;
312  }
313  switch (goal_status)
314  {
316  ROS_ERROR("Given goal is not on the map.");
317  return false;
319  ROS_ERROR("Given goal is in Rock.");
320  return false;
322  ROS_INFO("Given goal is moved (%d, %d)", e[0], e[1]);
323  break;
324  default:
325  break;
326  }
327 
328  const auto cb_progress = [](const std::list<Astar::Vec>& /* path_grid */, const SearchStats& /* stats */)
329  {
330  return true;
331  };
332 
333  const auto ts = boost::chrono::high_resolution_clock::now();
334 
335  GridAstarModel2D::Ptr model_2d(new GridAstarModel2D(model_));
336 
337  std::list<Astar::Vec> path_grid;
338  std::vector<GridAstarModel3D::VecWithCost> starts;
339  starts.emplace_back(s);
340  if (!as_.search(
341  starts, e, path_grid,
342  model_2d,
343  cb_progress,
344  0, 1.0f / freq_min_, find_best_))
345  {
346  ROS_WARN("Path plan failed (goal unreachable)");
347  return false;
348  }
349  const auto tnow = boost::chrono::high_resolution_clock::now();
350  ROS_INFO("Path found (%0.4f sec.)",
351  boost::chrono::duration<float>(tnow - ts).count());
352 
353  nav_msgs::Path path;
354  path.header = map_header_;
355  path.header.stamp = ros::Time::now();
356 
357  const std::list<Astar::Vecf> path_interpolated =
358  model_->path_interpolator_.interpolate(path_grid, 0.5, 0.0);
359  grid_metric_converter::grid2MetricPath(map_info_, path_interpolated, path);
360 
361  res.plan.header = map_header_;
362  res.plan.poses.resize(path.poses.size());
363  for (size_t i = 0; i < path.poses.size(); ++i)
364  {
365  res.plan.poses[i] = path.poses[i];
366  }
367  return true;
368  }
369 
370  void cbGoal(const geometry_msgs::PoseStamped::ConstPtr& msg)
371  {
372  if (act_->isActive() || act_tolerant_->isActive())
373  {
374  ROS_ERROR("Setting new goal is ignored since planner_3d is proceeding the action.");
375  return;
376  }
377  setGoal(*msg);
378  }
379  void cbPreempt()
380  {
381  ROS_WARN("Preempting the current goal.");
382  if (act_->isActive())
383  act_->setPreempted(move_base_msgs::MoveBaseResult(), "Preempted.");
384 
385  if (act_tolerant_->isActive())
386  act_tolerant_->setPreempted(planner_cspace_msgs::MoveWithToleranceResult(), "Preempted.");
387 
388  has_goal_ = false;
389  status_.status = planner_cspace_msgs::PlannerStatus::DONE;
390  }
391 
392  bool setGoal(const geometry_msgs::PoseStamped& msg)
393  {
394  if (msg.header.frame_id != map_header_.frame_id)
395  {
396  ROS_ERROR("Goal [%s] pose must be in the map frame [%s].",
397  msg.header.frame_id.c_str(), map_header_.frame_id.c_str());
398  return false;
399  }
400 
401  goal_raw_ = goal_ = msg;
402 
403  const double len2 =
404  goal_.pose.orientation.x * goal_.pose.orientation.x +
405  goal_.pose.orientation.y * goal_.pose.orientation.y +
406  goal_.pose.orientation.z * goal_.pose.orientation.z +
407  goal_.pose.orientation.w * goal_.pose.orientation.w;
408  if (std::abs(len2 - 1.0) < 0.1)
409  {
410  escaping_ = false;
411  has_goal_ = true;
412  cnt_stuck_ = 0;
413  if (!updateGoal())
414  {
415  has_goal_ = false;
416  return false;
417  }
418  status_.status = planner_cspace_msgs::PlannerStatus::DOING;
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  }
434  Astar::Gridmap<float>& g,
435  const Astar::Vec& s, const Astar::Vec& e)
436  {
437  ROS_DEBUG("Cost estimation cache search queue initial size: %lu, capacity: %lu", open.size(), open.capacity());
438 
439  const Astar::Vec s_rough(s[0], s[1], 0);
440 
441  struct SearchDiffs
442  {
443  Astar::Vec d;
444  std::vector<Astar::Vec> pos;
445  float grid_to_len;
446  };
447  std::vector<SearchDiffs> search_diffs;
448  {
449  Astar::Vec d;
450  d[2] = 0;
451  const int range_rough = 4;
452  for (d[0] = -range_rough; d[0] <= range_rough; d[0]++)
453  {
454  for (d[1] = -range_rough; d[1] <= range_rough; d[1]++)
455  {
456  if (d[0] == 0 && d[1] == 0)
457  continue;
458  if (d.sqlen() > range_rough * range_rough)
459  continue;
460 
461  SearchDiffs diffs;
462 
463  const float grid_to_len = d.gridToLenFactor();
464  const int dist = d.len();
465  const float dpx = static_cast<float>(d[0]) / dist;
466  const float dpy = static_cast<float>(d[1]) / dist;
467  Astar::Vecf pos(0, 0, 0);
468  for (int i = 0; i < dist; i++)
469  {
470  Astar::Vec ipos(pos);
471  if (diffs.pos.size() == 0 || diffs.pos.back() != ipos)
472  {
473  diffs.pos.push_back(std::move(ipos));
474  }
475  pos[0] += dpx;
476  pos[1] += dpy;
477  }
478  diffs.grid_to_len = grid_to_len;
479  diffs.d = d;
480  search_diffs.push_back(std::move(diffs));
481  }
482  }
483  }
484 
485  std::vector<Astar::PriorityVec> centers;
486  centers.reserve(num_cost_estim_task_);
487 
488 #pragma omp parallel
489  {
490  std::vector<Astar::GridmapUpdate> updates;
491  updates.reserve(num_cost_estim_task_ * search_diffs.size() / omp_get_num_threads());
492 
493  const float range_overshoot = ec_[0] * (range_ + local_range_ + longcut_range_);
494 
495  while (true)
496  {
497 #pragma omp barrier
498 #pragma omp single
499  {
500  centers.clear();
501  for (size_t i = 0; i < static_cast<size_t>(num_cost_estim_task_);)
502  {
503  if (open.size() < 1)
504  break;
505  Astar::PriorityVec center(open.top());
506  open.pop();
507  if (center.p_raw_ > g[center.v_])
508  continue;
509  if (center.p_raw_ - range_overshoot > g[s_rough])
510  continue;
511  centers.emplace_back(std::move(center));
512  ++i;
513  }
514  } // omp single
515 
516  if (centers.size() == 0)
517  break;
518  updates.clear();
519 
520 #pragma omp for schedule(static)
521  for (auto it = centers.cbegin(); it < centers.cend(); ++it)
522  {
523  const Astar::Vec p = it->v_;
524 
525  for (const SearchDiffs& ds : search_diffs)
526  {
527  const Astar::Vec d = ds.d;
528  const Astar::Vec next = p + d;
529 
530  if (static_cast<size_t>(next[0]) >= static_cast<size_t>(map_info_.width) ||
531  static_cast<size_t>(next[1]) >= static_cast<size_t>(map_info_.height))
532  continue;
533 
534  float cost = model_->euclidCostRough(d);
535 
536  const float gnext = g[next];
537 
538  if (gnext < g[p] + cost)
539  {
540  // Skip as this search task has no chance to find better way.
541  continue;
542  }
543 
544  {
545  float sum = 0, sum_hist = 0;
546  bool collision = false;
547  for (const auto& d : ds.pos)
548  {
549  const Astar::Vec pos = p + d;
550  const char c = cm_rough_[pos];
551  if (c > 99)
552  {
553  collision = true;
554  break;
555  }
556  sum += c;
557  sum_hist += bbf_costmap_.getCost(pos);
558  }
559  if (collision)
560  continue;
561  cost +=
562  (map_info_.linear_resolution * ds.grid_to_len / 100.0) *
563  (sum * cc_.weight_costmap_ + sum_hist * cc_.weight_remembered_);
564 
565  if (cost < 0)
566  {
567  cost = 0;
568  ROS_WARN_THROTTLE(1.0, "Negative cost value is detected. Limited to zero.");
569  }
570  }
571 
572  const float cost_next = it->p_raw_ + cost;
573  if (gnext > cost_next)
574  {
575  updates.emplace_back(p, next, cost_next, cost_next);
576  }
577  }
578  }
579 #pragma omp barrier
580 #pragma omp critical
581  {
582  for (const Astar::GridmapUpdate& u : updates)
583  {
584  if (g[u.getPos()] > u.getCost())
585  {
586  g[u.getPos()] = u.getCost();
587  open.push(std::move(u.getPriorityVec()));
588  }
589  }
590  } // omp critical
591  }
592  } // omp parallel
593  rough_cost_max_ = g[s_rough] + ec_[0] * (range_ + local_range_);
594  }
595 
596  template <class T>
597  bool searchAvailablePos(const T& cm, Astar::Vec& s, const int xy_range, const int angle_range,
598  const int cost_acceptable = 50, const int min_xy_range = 0) const
599  {
600  ROS_DEBUG("%d, %d (%d,%d,%d)", xy_range, angle_range, s[0], s[1], s[2]);
601 
602  float range_min = std::numeric_limits<float>::max();
603  Astar::Vec s_out;
604  Astar::Vec d;
605  for (d[2] = -angle_range; d[2] <= angle_range; d[2]++)
606  {
607  for (d[0] = -xy_range; d[0] <= xy_range; d[0]++)
608  {
609  for (d[1] = -xy_range; d[1] <= xy_range; d[1]++)
610  {
611  if (d[0] == 0 && d[1] == 0 && d[2] == 0)
612  continue;
613  if (d.sqlen() > xy_range * xy_range)
614  continue;
615  if (d.sqlen() < min_xy_range * min_xy_range)
616  continue;
617 
618  Astar::Vec s2 = s + d;
619  if ((unsigned int)s2[0] >= (unsigned int)map_info_.width ||
620  (unsigned int)s2[1] >= (unsigned int)map_info_.height)
621  continue;
622  s2.cycleUnsigned(map_info_.angle);
623  if (!cm_.validate(s2, range_))
624  continue;
625 
626  if (cm_[s2] >= cost_acceptable)
627  continue;
628  const auto cost = model_->euclidCost(d);
629  if (cost < range_min)
630  {
631  range_min = cost;
632  s_out = s2;
633  }
634  }
635  }
636  }
637 
638  if (range_min == std::numeric_limits<float>::max())
639  {
640  if (cost_acceptable != 100)
641  {
642  return searchAvailablePos(cm, s, xy_range, angle_range, 100);
643  }
644  return false;
645  }
646  s = s_out;
647  s.cycleUnsigned(map_info_.angle);
648  ROS_DEBUG(" (%d,%d,%d)", s[0], s[1], s[2]);
649  return true;
650  }
651  bool updateGoal(const bool goal_changed = true)
652  {
653  if (!has_goal_)
654  return true;
655 
656  if (!has_map_ || !has_start_)
657  {
658  ROS_ERROR("Goal received, however map/goal/start are not ready. (%d/%d/%d)",
659  static_cast<int>(has_map_), static_cast<int>(has_goal_), static_cast<int>(has_start_));
660  return true;
661  }
662 
663  Astar::Vec s, e;
665  map_info_, s[0], s[1], s[2],
666  start_.pose.position.x, start_.pose.position.y,
667  tf2::getYaw(start_.pose.orientation));
668  s.cycleUnsigned(map_info_.angle);
670  map_info_, e[0], e[1], e[2],
671  goal_.pose.position.x, goal_.pose.position.y,
672  tf2::getYaw(goal_.pose.orientation));
673  e.cycleUnsigned(map_info_.angle);
674  if (goal_changed)
675  {
676  ROS_INFO(
677  "New goal received (%d, %d, %d)",
678  e[0], e[1], e[2]);
679  }
680  const DiscretePoseStatus start_pose_status = relocateDiscretePoseIfNeeded(s, tolerance_range_, tolerance_angle_);
681  const DiscretePoseStatus goal_pose_status = relocateDiscretePoseIfNeeded(e, tolerance_range_, tolerance_angle_);
682  switch (start_pose_status)
683  {
685  ROS_ERROR("You are on the edge of the world.");
686  return false;
688  ROS_WARN("Oops! You are in Rock!");
689  return true;
690  default:
691  break;
692  }
693  switch (goal_pose_status)
694  {
696  ROS_ERROR("Given goal is not on the map.");
697  return false;
699  ROS_WARN("Oops! Goal is in Rock!");
700  ++cnt_stuck_;
701  return true;
703  ROS_INFO("Goal moved (%d, %d, %d)", e[0], e[1], e[2]);
704  float x, y, yaw;
705  grid_metric_converter::grid2Metric(map_info_, e[0], e[1], e[2], x, y, yaw);
706  goal_.pose.orientation = tf2::toMsg(tf2::Quaternion(tf2::Vector3(0.0, 0.0, 1.0), yaw));
707  goal_.pose.position.x = x;
708  goal_.pose.position.y = y;
709  break;
710  default:
711  break;
712  }
713  const auto ts = boost::chrono::high_resolution_clock::now();
714  pq_open_.clear();
715  cost_estim_cache_.clear(std::numeric_limits<float>::max());
716  e[2] = 0;
717  cost_estim_cache_[e] = -ec_[0] * 0.5; // Decrement to reduce calculation error
718  pq_open_.push(Astar::PriorityVec(cost_estim_cache_[e], cost_estim_cache_[e], e));
719  fillCostmap(pq_open_, cost_estim_cache_, s, e);
720  const auto tnow = boost::chrono::high_resolution_clock::now();
721  ROS_DEBUG("Cost estimation cache generated (%0.4f sec.)",
722  boost::chrono::duration<float>(tnow - ts).count());
723  cost_estim_cache_[e] = 0;
724 
725  if (goal_changed)
726  {
727  clearHysteresis();
728  has_hysteresis_map_ = false;
729  }
730 
731  publishDebug();
732 
733  goal_updated_ = true;
734 
735  return true;
736  }
738  {
739  for (const Astar::Vec& p : hyst_updated_cells_)
740  {
741  cm_hyst_[p] = 100;
742  }
743  hyst_updated_cells_.clear();
744  }
746  {
747  if (pub_distance_map_.getNumSubscribers() > 0)
748  {
749  sensor_msgs::PointCloud distance_map;
750  distance_map.header = map_header_;
751  distance_map.header.stamp = ros::Time::now();
752  distance_map.channels.resize(1);
753  distance_map.channels[0].name = "distance";
754  distance_map.points.reserve(1024);
755  distance_map.channels[0].values.reserve(1024);
756  const float k_dist = map_info_.linear_resolution * cc_.max_vel_;
757  for (Astar::Vec p(0, 0, 0); p[1] < cost_estim_cache_.size()[1]; p[1]++)
758  {
759  for (p[0] = 0; p[0] < cost_estim_cache_.size()[0]; p[0]++)
760  {
761  p[2] = 0;
762  float x, y, yaw;
763  grid_metric_converter::grid2Metric(map_info_, p[0], p[1], p[2], x, y, yaw);
764  geometry_msgs::Point32 point;
765  point.x = x;
766  point.y = y;
767  if (cost_estim_cache_[p] == std::numeric_limits<float>::max())
768  continue;
769  point.z = cost_estim_cache_[p] / 500;
770  distance_map.points.push_back(point);
771  distance_map.channels[0].values.push_back(cost_estim_cache_[p] * k_dist);
772  }
773  }
774  pub_distance_map_.publish(distance_map);
775  }
776 
777  if (pub_hysteresis_map_.getNumSubscribers() > 0)
778  {
779  nav_msgs::OccupancyGrid hysteresis_map;
780  hysteresis_map.header.frame_id = map_header_.frame_id;
781  hysteresis_map.info.resolution = map_info_.linear_resolution;
782  hysteresis_map.info.width = map_info_.width;
783  hysteresis_map.info.height = map_info_.height;
784  hysteresis_map.info.origin = map_info_.origin;
785  hysteresis_map.data.resize(map_info_.width * map_info_.height, 100);
786 
787  for (Astar::Vec p(0, 0, 0); p[1] < cost_estim_cache_.size()[1]; p[1]++)
788  {
789  for (p[0] = 0; p[0] < cost_estim_cache_.size()[0]; p[0]++)
790  {
791  if (cost_estim_cache_[p] == std::numeric_limits<float>::max())
792  continue;
793 
794  char cost = 100;
795  for (Astar::Vec p2 = p; p2[2] < static_cast<int>(map_info_.angle); ++p2[2])
796  {
797  cost = std::min(cm_hyst_[p2], cost);
798  }
799  hysteresis_map.data[p[0] + p[1] * map_info_.width] = cost;
800  }
801  }
802  pub_hysteresis_map_.publish(hysteresis_map);
803  }
804  }
806  {
807  if (pub_remembered_map_.getNumSubscribers() > 0 && remember_updates_)
808  {
809  nav_msgs::OccupancyGrid remembered_map;
810  remembered_map.header.frame_id = map_header_.frame_id;
811  remembered_map.info.resolution = map_info_.linear_resolution;
812  remembered_map.info.width = map_info_.width;
813  remembered_map.info.height = map_info_.height;
814  remembered_map.info.origin = map_info_.origin;
815  remembered_map.data.resize(map_info_.width * map_info_.height);
816 
817  const auto generate_pointcloud = [this, &remembered_map](const Astar::Vec& p, bbf::BinaryBayesFilter& bbf)
818  {
819  remembered_map.data[p[0] + p[1] * map_info_.width] =
820  (bbf.getProbability() - bbf::MIN_PROBABILITY) * 100 / (bbf::MAX_PROBABILITY - bbf::MIN_PROBABILITY);
821  };
822  bbf_costmap_.forEach(generate_pointcloud);
823  pub_remembered_map_.publish(remembered_map);
824  }
825  }
827  {
828  nav_msgs::Path path;
829  path.header.frame_id = robot_frame_;
830  path.header.stamp = ros::Time::now();
831  if (use_path_with_velocity_)
832  {
833  pub_path_velocity_.publish(
835  path, std::numeric_limits<double>::quiet_NaN()));
836  }
837  else
838  {
839  pub_path_.publish(path);
840  }
841  }
842 
843  void cbMapUpdate(const costmap_cspace_msgs::CSpace3DUpdate::ConstPtr& msg)
844  {
845  if (!has_map_)
846  return;
847  ROS_DEBUG("Map updated");
848 
849  const auto ts_cm_init_start = boost::chrono::high_resolution_clock::now();
850  const ros::Time now = ros::Time::now();
851  last_costmap_ = now;
852 
853  cm_.copy_partially(cm_base_, Astar::Vec(prev_map_update_x_min_, prev_map_update_y_min_, 0),
854  Astar::Vec(prev_map_update_x_max_, prev_map_update_y_max_, static_cast<int>(map_info_.angle)));
855  cm_rough_.copy_partially(cm_rough_base_, Astar::Vec(prev_map_update_x_min_, prev_map_update_y_min_, 0),
856  Astar::Vec(prev_map_update_x_max_, prev_map_update_y_max_, 1));
857  cm_updates_.clear_partially(-1, Astar::Vec(prev_map_update_x_min_, prev_map_update_y_min_, 0),
858  Astar::Vec(prev_map_update_x_max_, prev_map_update_y_max_, 1));
859 
860  const int map_update_x_min = static_cast<int>(msg->x);
861  const int map_update_x_max = static_cast<int>(msg->x + msg->width);
862  const int map_update_y_min = static_cast<int>(msg->y);
863  const int map_update_y_max = static_cast<int>(msg->y + msg->height);
864  const int search_range_x_min = std::max(0, std::min(prev_map_update_x_min_, map_update_x_min) - 1);
865  const int search_range_x_max = std::min(static_cast<int>(map_info_.width),
866  std::max(prev_map_update_x_max_, map_update_x_max) + 1);
867  const int search_range_y_min = std::max(0, std::min(prev_map_update_y_min_, map_update_y_min) - 1);
868  const int search_range_y_max = std::min(static_cast<int>(map_info_.height),
869  std::max(prev_map_update_y_max_, map_update_y_max) + 1);
870  prev_map_update_x_min_ = map_update_x_min;
871  prev_map_update_x_max_ = map_update_x_max;
872  prev_map_update_y_min_ = map_update_y_min;
873  prev_map_update_y_max_ = map_update_y_max;
874 
875  bool clear_hysteresis(false);
876 
877  {
878  const Astar::Vec gp(
879  static_cast<int>(msg->x), static_cast<int>(msg->y), static_cast<int>(msg->yaw));
880  const Astar::Vec gp_rough(gp[0], gp[1], 0);
881  for (Astar::Vec p(0, 0, 0); p[0] < static_cast<int>(msg->width); p[0]++)
882  {
883  for (p[1] = 0; p[1] < static_cast<int>(msg->height); p[1]++)
884  {
885  int cost_min = 100;
886  for (p[2] = 0; p[2] < static_cast<int>(msg->angle); p[2]++)
887  {
888  const size_t addr = ((p[2] * msg->height) + p[1]) * msg->width + p[0];
889  const char c = msg->data[addr];
890  if (c < cost_min)
891  cost_min = c;
892  if (c == 100 && !clear_hysteresis && cm_hyst_[gp + p] == 0)
893  clear_hysteresis = true;
894  }
895  p[2] = 0;
896  cm_updates_[gp_rough + p] = cost_min;
897  if (cost_min > cm_rough_[gp_rough + p])
898  cm_rough_[gp_rough + p] = cost_min;
899 
900  for (p[2] = 0; p[2] < static_cast<int>(msg->angle); p[2]++)
901  {
902  const size_t addr = ((p[2] * msg->height) + p[1]) * msg->width + p[0];
903  const char c = msg->data[addr];
904  if (overwrite_cost_)
905  {
906  if (c >= 0)
907  cm_[gp + p] = c;
908  }
909  else
910  {
911  if (cm_[gp + p] < c)
912  cm_[gp + p] = c;
913  }
914  }
915  }
916  }
917  }
918  const auto ts_cm_init_end = boost::chrono::high_resolution_clock::now();
919  ROS_DEBUG("Costmaps updated (%.4f)", boost::chrono::duration<float>(ts_cm_init_end - ts_cm_init_start).count());
920 
921  if (clear_hysteresis && has_hysteresis_map_)
922  {
923  ROS_INFO("The previous path collides to the obstacle. Clearing hysteresis map.");
924  clearHysteresis();
925  has_hysteresis_map_ = false;
926  }
927 
928  if (!has_start_)
929  return;
930 
931  Astar::Vec s;
933  map_info_, s[0], s[1], s[2],
934  start_.pose.position.x, start_.pose.position.y,
935  tf2::getYaw(start_.pose.orientation));
936  s.cycleUnsigned(map_info_.angle);
937 
938  if (remember_updates_)
939  {
940  bbf_costmap_.remember(
941  &cm_updates_, s,
942  remember_hit_odds_, remember_miss_odds_,
943  hist_ignore_range_, hist_ignore_range_max_);
945  bbf_costmap_.updateCostmap();
946  }
947  if (!has_goal_)
948  return;
949 
950  if (!fast_map_update_)
951  {
952  updateGoal(false);
953  return;
954  }
955 
956  Astar::Vec e;
958  map_info_, e[0], e[1], e[2],
959  goal_.pose.position.x, goal_.pose.position.y,
960  tf2::getYaw(goal_.pose.orientation));
961  e.cycleUnsigned(map_info_.angle);
962 
963  if (cm_[e] == 100)
964  {
965  updateGoal(false);
966  return;
967  }
968 
969  e[2] = 0;
970 
971  const auto ts = boost::chrono::high_resolution_clock::now();
972 
973  Astar::Vec p, p_cost_min;
974  p[2] = 0;
975  float cost_min = std::numeric_limits<float>::max();
976  for (p[1] = search_range_y_min; p[1] < search_range_y_max; p[1]++)
977  {
978  for (p[0] = search_range_x_min; p[0] < search_range_x_max; p[0]++)
979  {
980  if (cost_min > cost_estim_cache_[p])
981  {
982  p_cost_min = p;
983  cost_min = cost_estim_cache_[p];
984  }
985  }
986  }
987 
988  pq_open_.clear();
989  pq_erase_.clear();
990 
991  if (cost_min != std::numeric_limits<float>::max())
992  pq_erase_.emplace(cost_min, cost_min, p_cost_min);
993  while (true)
994  {
995  if (pq_erase_.size() < 1)
996  break;
997  const Astar::PriorityVec center(pq_erase_.top());
998  const Astar::Vec p = center.v_;
999  pq_erase_.pop();
1000 
1001  if (cost_estim_cache_[p] == std::numeric_limits<float>::max())
1002  continue;
1003  cost_estim_cache_[p] = std::numeric_limits<float>::max();
1004 
1005  Astar::Vec d;
1006  d[2] = 0;
1007  for (d[0] = -1; d[0] <= 1; d[0]++)
1008  {
1009  for (d[1] = -1; d[1] <= 1; d[1]++)
1010  {
1011  if (!((d[0] == 0) ^ (d[1] == 0)))
1012  continue;
1013  Astar::Vec next = p + d;
1014  next[2] = 0;
1015  if ((unsigned int)next[0] >= (unsigned int)map_info_.width ||
1016  (unsigned int)next[1] >= (unsigned int)map_info_.height)
1017  continue;
1018  const float gn = cost_estim_cache_[next];
1019  if (gn == std::numeric_limits<float>::max())
1020  continue;
1021  if (gn < cost_min)
1022  {
1023  pq_open_.emplace(gn, gn, next);
1024  continue;
1025  }
1026  pq_erase_.emplace(gn, gn, next);
1027  }
1028  }
1029  }
1030  if (pq_open_.size() == 0)
1031  {
1032  pq_open_.emplace(-ec_[0] * 0.5, -ec_[0] * 0.5, e);
1033  }
1034  ROS_DEBUG("Cost estimation cache partial update from: %0.3f", rough_cost_max_);
1035  {
1036  Astar::Vec p;
1037  p[2] = 0;
1038  for (p[0] = 0; p[0] < static_cast<int>(map_info_.width); p[0]++)
1039  {
1040  for (p[1] = 0; p[1] < static_cast<int>(map_info_.height); p[1]++)
1041  {
1042  const auto gp = cost_estim_cache_[p];
1043  if ((gp > rough_cost_max_) && (gp != std::numeric_limits<float>::max()))
1044  {
1045  pq_open_.emplace(gp, gp, p);
1046  }
1047  }
1048  }
1049  }
1050 
1051  fillCostmap(pq_open_, cost_estim_cache_, s, e);
1052  const auto tnow = boost::chrono::high_resolution_clock::now();
1053  ROS_DEBUG("Cost estimation cache updated (%0.4f sec.)",
1054  boost::chrono::duration<float>(tnow - ts).count());
1055  publishDebug();
1056  }
1057  void cbMap(const costmap_cspace_msgs::CSpace3D::ConstPtr& msg)
1058  {
1059  ROS_INFO("Map received");
1060  ROS_INFO(" linear_resolution %0.2f x (%dx%d) px", msg->info.linear_resolution,
1061  msg->info.width, msg->info.height);
1062  ROS_INFO(" angular_resolution %0.2f x %d px", msg->info.angular_resolution,
1063  msg->info.angle);
1064  ROS_INFO(" origin %0.3f m, %0.3f m, %0.3f rad",
1065  msg->info.origin.position.x,
1066  msg->info.origin.position.y,
1067  tf2::getYaw(msg->info.origin.orientation));
1068 
1069  // Stop robot motion until next planning step
1070  publishEmptyPath();
1071 
1072  ec_ = Astar::Vecf(
1073  1.0f / cc_.max_vel_,
1074  1.0f / cc_.max_vel_,
1075  1.0f * cc_.weight_ang_vel_ / cc_.max_ang_vel_);
1076 
1077  if (map_info_.linear_resolution != msg->info.linear_resolution ||
1078  map_info_.angular_resolution != msg->info.angular_resolution)
1079  {
1080  map_info_ = msg->info;
1081 
1082  // Typical open/erase queue size is be approximated by perimeter of the map
1083  pq_open_.reserve((map_info_.width + map_info_.height) * 2);
1084  pq_erase_.reserve((map_info_.width + map_info_.height) * 2);
1085 
1086  range_ = static_cast<int>(search_range_ / map_info_.linear_resolution);
1087  hist_ignore_range_ = std::lround(hist_ignore_range_f_ / map_info_.linear_resolution);
1088  hist_ignore_range_max_ = std::lround(hist_ignore_range_max_f_ / map_info_.linear_resolution);
1089  local_range_ = std::lround(local_range_f_ / map_info_.linear_resolution);
1090  longcut_range_ = std::lround(longcut_range_f_ / map_info_.linear_resolution);
1091  esc_range_ = std::lround(esc_range_f_ / map_info_.linear_resolution);
1092  esc_angle_ = map_info_.angle / 8;
1093  tolerance_range_ = std::lround(tolerance_range_f_ / map_info_.linear_resolution);
1094  tolerance_angle_ = std::lround(tolerance_angle_f_ / map_info_.angular_resolution);
1095  goal_tolerance_lin_ = std::lround(goal_tolerance_lin_f_ / map_info_.linear_resolution);
1096  goal_tolerance_ang_ = std::lround(goal_tolerance_ang_f_ / map_info_.angular_resolution);
1097  cc_.angle_resolution_aspect_ = 2.0 / tanf(map_info_.angular_resolution);
1098 
1099  model_.reset(
1100  new GridAstarModel3D(
1101  map_info_,
1102  ec_,
1103  local_range_,
1104  cost_estim_cache_, cm_, cm_hyst_, cm_rough_,
1105  cc_, range_));
1106 
1107  ROS_DEBUG("Search model updated");
1108  }
1109  else
1110  {
1111  map_info_ = msg->info;
1112  }
1113  map_header_ = msg->header;
1114  jump_.setMapFrame(map_header_.frame_id);
1115 
1116  const int size[3] =
1117  {
1118  static_cast<int>(map_info_.width),
1119  static_cast<int>(map_info_.height),
1120  static_cast<int>(map_info_.angle)
1121  };
1122  as_.reset(Astar::Vec(size[0], size[1], size[2]));
1123  cm_.reset(Astar::Vec(size[0], size[1], size[2]));
1124  cm_hyst_.reset(Astar::Vec(size[0], size[1], size[2]));
1125 
1126  cost_estim_cache_.reset(Astar::Vec(size[0], size[1], 1));
1127  cm_rough_.reset(Astar::Vec(size[0], size[1], 1));
1128  cm_updates_.reset(Astar::Vec(size[0], size[1], 1));
1129  bbf_costmap_.reset(Astar::Vec(size[0], size[1], 1));
1130 
1131  Astar::Vec p;
1132  for (p[0] = 0; p[0] < static_cast<int>(map_info_.width); p[0]++)
1133  {
1134  for (p[1] = 0; p[1] < static_cast<int>(map_info_.height); p[1]++)
1135  {
1136  int cost_min = 100;
1137  for (p[2] = 0; p[2] < static_cast<int>(map_info_.angle); p[2]++)
1138  {
1139  const size_t addr = ((p[2] * size[1]) + p[1]) * size[0] + p[0];
1140  char c = msg->data[addr];
1141  if (c < 0)
1142  c = unknown_cost_;
1143  cm_[p] = c;
1144  if (c < cost_min)
1145  cost_min = c;
1146  }
1147  p[2] = 0;
1148  cm_rough_[p] = cost_min;
1149  }
1150  }
1151  ROS_DEBUG("Map copied");
1152 
1153  cm_hyst_.clear(100);
1154  hyst_updated_cells_.clear();
1155  has_hysteresis_map_ = false;
1156 
1157  has_map_ = true;
1158 
1159  cm_rough_base_ = cm_rough_;
1160  cm_base_ = cm_;
1161  bbf_costmap_.clear();
1162 
1163  prev_map_update_x_min_ = std::numeric_limits<int>::max();
1164  prev_map_update_x_max_ = std::numeric_limits<int>::lowest();
1165  prev_map_update_y_min_ = std::numeric_limits<int>::max();
1166  prev_map_update_y_max_ = std::numeric_limits<int>::lowest();
1167 
1168  updateGoal();
1169  }
1170  void cbAction()
1171  {
1172  if (act_tolerant_->isActive())
1173  {
1174  ROS_ERROR("Setting new goal is ignored since planner_3d is proceeding by tolerant_move action.");
1175  return;
1176  }
1177 
1178  move_base_msgs::MoveBaseGoalConstPtr goal = act_->acceptNewGoal();
1179  if (!setGoal(goal->target_pose))
1180  act_->setAborted(move_base_msgs::MoveBaseResult(), "Given goal is invalid.");
1181  }
1182 
1184  {
1185  if (act_->isActive())
1186  {
1187  ROS_ERROR("Setting new goal is ignored since planner_3d is proceeding by move_base action.");
1188  return;
1189  }
1190 
1191  goal_tolerant_ = act_tolerant_->acceptNewGoal();
1192  if (!setGoal(goal_tolerant_->target_pose))
1193  act_tolerant_->setAborted(planner_cspace_msgs::MoveWithToleranceResult(), "Given goal is invalid.");
1194  }
1195 
1197  {
1198  geometry_msgs::PoseStamped start;
1199  start.header.frame_id = robot_frame_;
1200  start.header.stamp = ros::Time(0);
1201  start.pose.orientation.x = 0.0;
1202  start.pose.orientation.y = 0.0;
1203  start.pose.orientation.z = 0.0;
1204  start.pose.orientation.w = 1.0;
1205  start.pose.position.x = 0;
1206  start.pose.position.y = 0;
1207  start.pose.position.z = 0;
1208  try
1209  {
1210  geometry_msgs::TransformStamped trans =
1211  tfbuf_.lookupTransform(map_header_.frame_id, robot_frame_, ros::Time(), ros::Duration(0.1));
1212  tf2::doTransform(start, start, trans);
1213  }
1214  catch (tf2::TransformException& e)
1215  {
1216  has_start_ = false;
1217  return;
1218  }
1219  start_ = start;
1220  has_start_ = true;
1221  }
1222 
1223 public:
1225  : nh_()
1226  , pnh_("~")
1227  , tfl_(tfbuf_)
1228  , jump_(tfbuf_)
1229  {
1232  nh_, "costmap",
1233  pnh_, "costmap", 1, &Planner3dNode::cbMap, this);
1234  sub_map_update_ = neonavigation_common::compat::subscribe(
1235  nh_, "costmap_update",
1236  pnh_, "costmap_update", 1, &Planner3dNode::cbMapUpdate, this);
1238  nh_, "move_base_simple/goal",
1239  pnh_, "goal", 1, &Planner3dNode::cbGoal, this);
1240  pub_start_ = pnh_.advertise<geometry_msgs::PoseStamped>("path_start", 1, true);
1241  pub_end_ = pnh_.advertise<geometry_msgs::PoseStamped>("path_end", 1, true);
1242  pub_status_ = pnh_.advertise<planner_cspace_msgs::PlannerStatus>("status", 1, true);
1244  nh_, "forget_planning_cost",
1245  pnh_, "forget", &Planner3dNode::cbForget, this);
1246  srs_make_plan_ = pnh_.advertiseService("make_plan", &Planner3dNode::cbMakePlan, this);
1247 
1248  // Debug outputs
1249  pub_distance_map_ = pnh_.advertise<sensor_msgs::PointCloud>("distance_map", 1, true);
1250  pub_hysteresis_map_ = pnh_.advertise<nav_msgs::OccupancyGrid>("hysteresis_map", 1, true);
1251  pub_remembered_map_ = pnh_.advertise<nav_msgs::OccupancyGrid>("remembered_map", 1, true);
1252 
1253  act_.reset(new Planner3DActionServer(ros::NodeHandle(), "move_base", false));
1254  act_->registerGoalCallback(boost::bind(&Planner3dNode::cbAction, this));
1255  act_->registerPreemptCallback(boost::bind(&Planner3dNode::cbPreempt, this));
1256 
1257  act_tolerant_.reset(new Planner3DTolerantActionServer(ros::NodeHandle(), "tolerant_move", false));
1258  act_tolerant_->registerGoalCallback(boost::bind(&Planner3dNode::cbTolerantAction, this));
1259  act_tolerant_->registerPreemptCallback(boost::bind(&Planner3dNode::cbPreempt, this));
1260  goal_tolerant_ = nullptr;
1261 
1262  pnh_.param("use_path_with_velocity", use_path_with_velocity_, false);
1263  if (use_path_with_velocity_)
1264  {
1265  pub_path_velocity_ = nh_.advertise<trajectory_tracker_msgs::PathWithVelocity>(
1266  "path_velocity", 1, true);
1267  }
1268  else
1269  {
1270  pub_path_ = neonavigation_common::compat::advertise<nav_msgs::Path>(
1271  nh_, "path",
1272  pnh_, "path", 1, true);
1273  }
1274  pub_path_poses_ = pnh_.advertise<geometry_msgs::PoseArray>(
1275  "path_poses", 1, true);
1276 
1277  pnh_.param("freq", freq_, 4.0f);
1278  pnh_.param("freq_min", freq_min_, 2.0f);
1279  pnh_.param("search_timeout_abort", search_timeout_abort_, 30.0f);
1280  pnh_.param("search_range", search_range_, 0.4f);
1281  pnh_.param("antialias_start", antialias_start_, false);
1282 
1283  double costmap_watchdog;
1284  pnh_.param("costmap_watchdog", costmap_watchdog, 0.0);
1285  costmap_watchdog_ = ros::Duration(costmap_watchdog);
1286 
1287  pnh_.param("max_vel", cc_.max_vel_, 0.3f);
1288  pnh_.param("max_ang_vel", cc_.max_ang_vel_, 0.6f);
1289  pnh_.param("min_curve_radius", cc_.min_curve_radius_, 0.1f);
1290 
1291  pnh_.param("weight_decel", cc_.weight_decel_, 50.0f);
1292  pnh_.param("weight_backward", cc_.weight_backward_, 0.9f);
1293  pnh_.param("weight_ang_vel", cc_.weight_ang_vel_, 1.0f);
1294  pnh_.param("weight_costmap", cc_.weight_costmap_, 50.0f);
1295  pnh_.param("weight_costmap_turn", cc_.weight_costmap_turn_, 0.0f);
1296  pnh_.param("weight_remembered", cc_.weight_remembered_, 1000.0f);
1297  pnh_.param("cost_in_place_turn", cc_.in_place_turn_, 30.0f);
1298  pnh_.param("hysteresis_max_dist", cc_.hysteresis_max_dist_, 0.1f);
1299  pnh_.param("hysteresis_expand", cc_.hysteresis_expand_, 0.1f);
1300  pnh_.param("weight_hysteresis", cc_.weight_hysteresis_, 5.0f);
1301 
1302  pnh_.param("goal_tolerance_lin", goal_tolerance_lin_f_, 0.05);
1303  pnh_.param("goal_tolerance_ang", goal_tolerance_ang_f_, 0.1);
1304  pnh_.param("goal_tolerance_ang_finish", goal_tolerance_ang_finish_, 0.05);
1305 
1306  pnh_.param("unknown_cost", unknown_cost_, 100);
1307  pnh_.param("overwrite_cost", overwrite_cost_, false);
1308 
1309  pnh_.param("hist_ignore_range", hist_ignore_range_f_, 0.6);
1310  pnh_.param("hist_ignore_range_max", hist_ignore_range_max_f_, 1.25);
1311  pnh_.param("remember_updates", remember_updates_, false);
1312  double remember_hit_prob, remember_miss_prob;
1313  pnh_.param("remember_hit_prob", remember_hit_prob, 0.6);
1314  pnh_.param("remember_miss_prob", remember_miss_prob, 0.3);
1315  remember_hit_odds_ = bbf::probabilityToOdds(remember_hit_prob);
1316  remember_miss_odds_ = bbf::probabilityToOdds(remember_miss_prob);
1317 
1318  pnh_.param("local_range", local_range_f_, 2.5);
1319  pnh_.param("longcut_range", longcut_range_f_, 0.0);
1320  pnh_.param("esc_range", esc_range_f_, 0.25);
1321  pnh_.param("tolerance_range", tolerance_range_f_, 0.25);
1322  pnh_.param("tolerance_angle", tolerance_angle_f_, 0.0);
1323 
1324  pnh_.param("sw_wait", sw_wait_, 2.0f);
1325  pnh_.param("find_best", find_best_, true);
1326 
1327  pnh_.param("robot_frame", robot_frame_, std::string("base_link"));
1328 
1329  double pos_jump, yaw_jump;
1330  std::string jump_detect_frame;
1331  pnh_.param("pos_jump", pos_jump, 1.0);
1332  pnh_.param("yaw_jump", yaw_jump, 1.5);
1333  pnh_.param("jump_detect_frame", jump_detect_frame, std::string("base_link"));
1334  jump_.setBaseFrame(jump_detect_frame);
1335  jump_.setThresholds(pos_jump, yaw_jump);
1336 
1337  pnh_.param("force_goal_orientation", force_goal_orientation_, true);
1338 
1339  pnh_.param("temporary_escape", temporary_escape_, true);
1340 
1341  pnh_.param("fast_map_update", fast_map_update_, false);
1342  if (fast_map_update_)
1343  {
1344  ROS_WARN("planner_3d: Experimental fast_map_update is enabled. ");
1345  }
1346  if (pnh_.hasParam("debug_mode"))
1347  {
1348  ROS_ERROR(
1349  "planner_3d: ~/debug_mode parameter and ~/debug topic are deprecated. "
1350  "Use ~/distance_map, ~/hysteresis_map, and ~/remembered_map topics instead.");
1351  }
1352 
1353  bool print_planning_duration;
1354  pnh_.param("print_planning_duration", print_planning_duration, false);
1355  if (print_planning_duration)
1356  {
1358  {
1360  }
1361  }
1362 
1363  pnh_.param("max_retry_num", max_retry_num_, -1);
1364 
1365  int queue_size_limit;
1366  pnh_.param("queue_size_limit", queue_size_limit, 0);
1367  as_.setQueueSizeLimit(queue_size_limit);
1368 
1369  int num_threads;
1370  pnh_.param("num_threads", num_threads, 1);
1371  omp_set_num_threads(num_threads);
1372 
1373  int num_task;
1374  pnh_.param("num_search_task", num_task, num_threads * 16);
1375  as_.setSearchTaskNum(num_task);
1376  pnh_.param("num_cost_estim_task", num_cost_estim_task_, num_threads * 16);
1377 
1378  pnh_.param("retain_last_error_status", retain_last_error_status_, true);
1379  status_.status = planner_cspace_msgs::PlannerStatus::DONE;
1380 
1381  has_map_ = false;
1382  has_goal_ = false;
1383  has_start_ = false;
1384  goal_updated_ = false;
1385 
1386  escaping_ = false;
1387  cnt_stuck_ = 0;
1388  is_path_switchback_ = false;
1389 
1390  diag_updater_.setHardwareID("none");
1391  diag_updater_.add("Path Planner Status", this, &Planner3dNode::diagnoseStatus);
1392 
1393  act_->start();
1394  act_tolerant_->start();
1395  }
1396 
1397  GridAstarModel3D::Vec pathPose2Grid(const geometry_msgs::PoseStamped& pose) const
1398  {
1399  GridAstarModel3D::Vec grid_vec;
1400  grid_metric_converter::metric2Grid(map_info_, grid_vec[0], grid_vec[1], grid_vec[2],
1401  pose.pose.position.x, pose.pose.position.y, tf2::getYaw(pose.pose.orientation));
1402  grid_vec.cycleUnsigned(map_info_.angle);
1403  return grid_vec;
1404  }
1405 
1406  void waitUntil(const ros::Time& next_replan_time, const nav_msgs::Path& previous_path)
1407  {
1408  while (ros::ok())
1409  {
1410  const ros::Time prev_map_update_stamp = last_costmap_;
1411  ros::spinOnce();
1412  const bool costmap_udpated = last_costmap_ != prev_map_update_stamp;
1413 
1414  if (has_map_)
1415  {
1416  updateStart();
1417 
1418  if (jump_.detectJump())
1419  {
1420  bbf_costmap_.clear();
1421  // Robot pose jumped.
1422  return;
1423  }
1424 
1425  if (costmap_udpated && previous_path.poses.size() > 1)
1426  {
1427  for (const auto& path_pose : previous_path.poses)
1428  {
1429  if (cm_[pathPose2Grid(path_pose)] == 100)
1430  {
1431  // Obstacle on the path.
1432  return;
1433  }
1434  }
1435  }
1436 
1437  if (is_path_switchback_)
1438  {
1439  const float len = std::hypot(
1440  start_.pose.position.y - sw_pos_.pose.position.y,
1441  start_.pose.position.x - sw_pos_.pose.position.x);
1442  const float yaw = tf2::getYaw(start_.pose.orientation);
1443  const float sw_yaw = tf2::getYaw(sw_pos_.pose.orientation);
1444  float yaw_diff = yaw - sw_yaw;
1445  yaw_diff = std::atan2(std::sin(yaw_diff), std::cos(yaw_diff));
1446  if (len < goal_tolerance_lin_f_ && std::fabs(yaw_diff) < goal_tolerance_ang_f_)
1447  {
1448  // robot has arrived at the switchback point
1449  is_path_switchback_ = false;
1450  }
1451  }
1452  }
1453  if (ros::Time::now() > next_replan_time)
1454  {
1455  return;
1456  }
1457  ros::Duration(0.01).sleep();
1458  }
1459  }
1460 
1461  void spin()
1462  {
1463  ROS_DEBUG("Initialized");
1464 
1465  ros::Time next_replan_time = ros::Time::now();
1466  nav_msgs::Path previous_path;
1467 
1468  while (ros::ok())
1469  {
1470  waitUntil(next_replan_time, previous_path);
1471 
1472  const ros::Time now = ros::Time::now();
1473 
1474  if (has_map_ && !goal_updated_ && has_goal_)
1475  {
1476  updateGoal();
1477  }
1478  bool has_costmap(false);
1479  if (costmap_watchdog_ > ros::Duration(0))
1480  {
1481  if (last_costmap_ + costmap_watchdog_ < now)
1482  {
1483  ROS_WARN_THROTTLE(1.0,
1484  "Navigation is stopping since the costmap is too old (costmap: %0.3f)",
1485  last_costmap_.toSec());
1486  status_.error = planner_cspace_msgs::PlannerStatus::DATA_MISSING;
1487  publishEmptyPath();
1488  previous_path.poses.clear();
1489  }
1490  else
1491  {
1492  has_costmap = true;
1493  }
1494  }
1495  else
1496  {
1497  has_costmap = true;
1498  }
1499 
1500  bool is_path_switchback = false;
1501  if (has_map_ && has_goal_ && has_start_ && has_costmap)
1502  {
1503  if (act_->isActive())
1504  {
1505  move_base_msgs::MoveBaseFeedback feedback;
1506  feedback.base_position = start_;
1507  act_->publishFeedback(feedback);
1508  }
1509 
1510  if (act_tolerant_->isActive())
1511  {
1512  planner_cspace_msgs::MoveWithToleranceFeedback feedback;
1513  feedback.base_position = start_;
1514  act_tolerant_->publishFeedback(feedback);
1515  }
1516 
1517  if (status_.status == planner_cspace_msgs::PlannerStatus::FINISHING)
1518  {
1519  const float yaw_s = tf2::getYaw(start_.pose.orientation);
1520  float yaw_g = tf2::getYaw(goal_.pose.orientation);
1521  if (force_goal_orientation_)
1522  yaw_g = tf2::getYaw(goal_raw_.pose.orientation);
1523 
1524  float yaw_diff = yaw_s - yaw_g;
1525  if (yaw_diff > M_PI)
1526  yaw_diff -= M_PI * 2.0;
1527  else if (yaw_diff < -M_PI)
1528  yaw_diff += M_PI * 2.0;
1529  if (std::abs(yaw_diff) <
1530  (act_tolerant_->isActive() ? goal_tolerant_->goal_tolerance_ang_finish : goal_tolerance_ang_finish_))
1531  {
1532  status_.status = planner_cspace_msgs::PlannerStatus::DONE;
1533  has_goal_ = false;
1534  // Don't publish empty path here in order a path follower
1535  // to minimize the error to the desired final pose
1536  ROS_INFO("Path plan finished");
1537 
1538  if (act_->isActive())
1539  act_->setSucceeded(move_base_msgs::MoveBaseResult(), "Goal reached.");
1540  if (act_tolerant_->isActive())
1541  act_tolerant_->setSucceeded(planner_cspace_msgs::MoveWithToleranceResult(), "Goal reached.");
1542  }
1543  }
1544  else
1545  {
1546  if (escaping_)
1547  {
1548  status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1549  }
1550  else if (max_retry_num_ != -1 && cnt_stuck_ > max_retry_num_)
1551  {
1552  status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1553  status_.status = planner_cspace_msgs::PlannerStatus::DONE;
1554  has_goal_ = false;
1555 
1556  publishEmptyPath();
1557  previous_path.poses.clear();
1558  next_replan_time += ros::Duration(1.0 / freq_);
1559  ROS_ERROR("Exceeded max_retry_num:%d", max_retry_num_);
1560 
1561  if (act_->isActive())
1562  act_->setAborted(
1563  move_base_msgs::MoveBaseResult(), "Goal is in Rock");
1564  if (act_tolerant_->isActive())
1565  act_tolerant_->setAborted(
1566  planner_cspace_msgs::MoveWithToleranceResult(), "Goal is in Rock");
1567 
1568  continue;
1569  }
1570  else
1571  {
1572  status_.error = planner_cspace_msgs::PlannerStatus::GOING_WELL;
1573  }
1574  nav_msgs::Path path;
1575  path.header = map_header_;
1576  path.header.stamp = now;
1577  makePlan(start_.pose, goal_.pose, path, true);
1578  if (use_path_with_velocity_)
1579  {
1580  // NaN velocity means that don't care the velocity
1581  pub_path_velocity_.publish(
1582  trajectory_tracker_msgs::toPathWithVelocity(path, std::numeric_limits<double>::quiet_NaN()));
1583  }
1584  else
1585  {
1586  pub_path_.publish(path);
1587  }
1588  previous_path = path;
1589 
1590  if (sw_wait_ > 0.0)
1591  {
1592  const int sw_index = getSwitchIndex(path);
1593  is_path_switchback = (sw_index >= 0);
1594  if (is_path_switchback)
1595  sw_pos_ = path.poses[sw_index];
1596  }
1597  }
1598  }
1599  else if (!has_goal_)
1600  {
1601  if (!retain_last_error_status_)
1602  status_.error = planner_cspace_msgs::PlannerStatus::GOING_WELL;
1603  publishEmptyPath();
1604  previous_path.poses.clear();
1605  }
1606  pub_status_.publish(status_);
1607  diag_updater_.force_update();
1608 
1609  if (is_path_switchback)
1610  {
1611  next_replan_time += ros::Duration(sw_wait_);
1612  ROS_INFO("Planned path has switchback. Planner will stop until: %f at the latest.", next_replan_time.toSec());
1613  }
1614  else
1615  {
1616  next_replan_time += ros::Duration(1.0 / freq_);
1617  }
1618  is_path_switchback_ = is_path_switchback;
1619  }
1620  }
1621 
1622 protected:
1623  bool makePlan(const geometry_msgs::Pose& gs, const geometry_msgs::Pose& ge,
1624  nav_msgs::Path& path, bool hyst)
1625  {
1626  Astar::Vec e;
1628  map_info_, e[0], e[1], e[2],
1629  ge.position.x, ge.position.y, tf2::getYaw(ge.orientation));
1630  e.cycleUnsigned(map_info_.angle);
1631 
1632  Astar::Vecf sf;
1634  map_info_, sf[0], sf[1], sf[2],
1635  gs.position.x, gs.position.y, tf2::getYaw(gs.orientation));
1636  Astar::Vec s(static_cast<int>(std::floor(sf[0])), static_cast<int>(std::floor(sf[1])), std::lround(sf[2]));
1637  s.cycleUnsigned(map_info_.angle);
1638  if (!cm_.validate(s, range_))
1639  {
1640  ROS_ERROR("You are on the edge of the world.");
1641  return false;
1642  }
1643 
1644  std::vector<Astar::VecWithCost> starts;
1645  if (antialias_start_)
1646  {
1647  const int x_cand[] =
1648  {
1649  0, ((sf[0] - s[0]) < 0.5 ? -1 : 1)
1650  };
1651  const int y_cand[] =
1652  {
1653  0, ((sf[1] - s[1]) < 0.5 ? -1 : 1)
1654  };
1655  for (const int x : x_cand)
1656  {
1657  for (const int y : y_cand)
1658  {
1659  const Astar::Vec p = s + Astar::Vec(x, y, 0);
1660  if (!cm_.validate(p, range_))
1661  continue;
1662 
1663  const Astar::Vecf subpx = sf - Astar::Vecf(p[0] + 0.5f, p[1] + 0.5f, 0.0f);
1664  if (subpx.sqlen() > 1.0)
1665  continue;
1666  if (cm_[p] > 99)
1667  continue;
1668 
1669  starts.push_back(Astar::VecWithCost(p));
1670  }
1671  }
1672  }
1673  else
1674  {
1675  if (cm_[s] < 100)
1676  {
1677  starts.push_back(Astar::VecWithCost(s));
1678  }
1679  }
1680  for (Astar::VecWithCost& s : starts)
1681  {
1682  const Astar::Vecf diff =
1683  Astar::Vecf(s.v_[0] + 0.5f, s.v_[1] + 0.5f, 0.0f) - sf;
1684  s.c_ = std::hypot(diff[0] * ec_[0], diff[1] * ec_[0]);
1685  s.c_ += cm_[s.v_] * cc_.weight_costmap_ / 100.0;
1686 
1687  // Check if arrived to the goal
1688  Astar::Vec remain = s.v_ - e;
1689  remain.cycle(map_info_.angle);
1690 
1691  int g_tolerance_lin, g_tolerance_ang;
1692  if (act_tolerant_->isActive())
1693  {
1694  g_tolerance_lin = std::lround(goal_tolerant_->goal_tolerance_lin / map_info_.linear_resolution);
1695  g_tolerance_ang = std::lround(goal_tolerant_->goal_tolerance_ang / map_info_.angular_resolution);
1696  }
1697  else
1698  {
1699  g_tolerance_lin = goal_tolerance_lin_;
1700  g_tolerance_ang = goal_tolerance_ang_;
1701  }
1702 
1703  if (remain.sqlen() <= g_tolerance_lin * g_tolerance_lin &&
1704  std::abs(remain[2]) <= g_tolerance_ang)
1705  {
1706  if (escaping_)
1707  {
1708  goal_ = goal_raw_;
1709  escaping_ = false;
1710  updateGoal();
1711  ROS_INFO("Escaped");
1712  }
1713  else
1714  {
1715  path.poses.resize(1);
1716  path.poses[0].header = path.header;
1717  if (force_goal_orientation_)
1718  path.poses[0].pose = goal_raw_.pose;
1719  else
1720  path.poses[0].pose = ge;
1721 
1722  status_.status = planner_cspace_msgs::PlannerStatus::FINISHING;
1723  ROS_INFO("Path plan finishing");
1724  }
1725  return true;
1726  }
1727  }
1728 
1729  geometry_msgs::PoseStamped p;
1730  p.header = map_header_;
1731  float x, y, yaw;
1732  grid_metric_converter::grid2Metric(map_info_, e[0], e[1], e[2], x, y, yaw);
1733  p.pose.orientation = tf2::toMsg(tf2::Quaternion(tf2::Vector3(0.0, 0.0, 1.0), yaw));
1734  p.pose.position.x = x;
1735  p.pose.position.y = y;
1736  pub_end_.publish(p);
1737 
1738  if (starts.size() == 0)
1739  {
1740  if (!searchAvailablePos(cm_, s, tolerance_range_, tolerance_angle_))
1741  {
1742  ROS_WARN("Oops! You are in Rock!");
1743  status_.error = planner_cspace_msgs::PlannerStatus::IN_ROCK;
1744  return false;
1745  }
1746  ROS_INFO("Start moved");
1747  starts.push_back(Astar::VecWithCost(s));
1748  }
1749  const Astar::Vec s_rough(s[0], s[1], 0);
1750 
1751  // If goal gets occupied, cost_estim_cache_ is not updated to reduce
1752  // computational cost for clearing huge map. In this case, cm_[e] is 100.
1753  if (cost_estim_cache_[s_rough] == std::numeric_limits<float>::max() || cm_[e] >= 100)
1754  {
1755  status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1756  ROS_WARN("Goal unreachable.");
1757  if (!escaping_ && temporary_escape_)
1758  {
1759  e = s;
1760  if (searchAvailablePos(cm_, e, esc_range_, esc_angle_, 50, esc_range_ / 2))
1761  {
1762  escaping_ = true;
1763  ROS_INFO("Temporary goal (%d, %d, %d)",
1764  e[0], e[1], e[2]);
1765  float x, y, yaw;
1766  grid_metric_converter::grid2Metric(map_info_, e[0], e[1], e[2], x, y, yaw);
1767  goal_.pose.orientation = tf2::toMsg(tf2::Quaternion(tf2::Vector3(0.0, 0.0, 1.0), yaw));
1768  goal_.pose.position.x = x;
1769  goal_.pose.position.y = y;
1770 
1771  updateGoal();
1772  return false;
1773  }
1774  }
1775  return false;
1776  }
1777 
1778  grid_metric_converter::grid2Metric(map_info_, s[0], s[1], s[2], x, y, yaw);
1779  p.pose.orientation = tf2::toMsg(tf2::Quaternion(tf2::Vector3(0.0, 0.0, 1.0), yaw));
1780  p.pose.position.x = x;
1781  p.pose.position.y = y;
1782  pub_start_.publish(p);
1783 
1784  const float range_limit = cost_estim_cache_[s_rough] - (local_range_ + range_) * ec_[0];
1785 
1786  const auto ts = boost::chrono::high_resolution_clock::now();
1787  // ROS_INFO("Planning from (%d, %d, %d) to (%d, %d, %d)",
1788  // s[0], s[1], s[2], e[0], e[1], e[2]);
1789 
1790  const auto cb_progress = [this, ts, s, e](const std::list<Astar::Vec>& path_grid, const SearchStats& stats) -> bool
1791  {
1792  const auto tnow = boost::chrono::high_resolution_clock::now();
1793  const auto tdiff = boost::chrono::duration<float>(tnow - ts).count();
1794  publishEmptyPath();
1795  if (tdiff > search_timeout_abort_)
1796  {
1797  ROS_ERROR(
1798  "Search aborted due to timeout. "
1799  "search_timeout_abort may be too small or planner_3d may have a bug: "
1800  "s=(%d, %d, %d), g=(%d, %d, %d), tdiff=%0.4f, "
1801  "num_loop=%lu, "
1802  "num_search_queue=%lu, "
1803  "num_prev_updates=%lu, "
1804  "num_total_updates=%lu, ",
1805  s[0], s[1], s[2], e[0], e[1], e[2], tdiff,
1806  stats.num_loop, stats.num_search_queue, stats.num_prev_updates, stats.num_total_updates);
1807  return false;
1808  }
1809  ROS_WARN("Search timed out (%0.4f sec.)", tdiff);
1810  return true;
1811  };
1812 
1813  model_->enableHysteresis(hyst && has_hysteresis_map_);
1814  std::list<Astar::Vec> path_grid;
1815  if (!as_.search(starts, e, path_grid,
1816  model_,
1817  cb_progress,
1818  range_limit,
1819  1.0f / freq_min_,
1820  find_best_))
1821  {
1822  ROS_WARN("Path plan failed (goal unreachable)");
1823  status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1824  if (!find_best_)
1825  return false;
1826  }
1827  const auto tnow = boost::chrono::high_resolution_clock::now();
1828  ROS_DEBUG("Path found (%0.4f sec.)",
1829  boost::chrono::duration<float>(tnow - ts).count());
1830 
1831  geometry_msgs::PoseArray poses;
1832  poses.header = path.header;
1833  for (const auto& p : path_grid)
1834  {
1835  geometry_msgs::Pose pose;
1836  float x, y, yaw;
1837  grid_metric_converter::grid2Metric(map_info_, p[0], p[1], p[2], x, y, yaw);
1838  pose.position.x = x;
1839  pose.position.y = y;
1840  pose.orientation =
1841  tf2::toMsg(tf2::Quaternion(tf2::Vector3(0.0, 0.0, 1.0), yaw));
1842  poses.poses.push_back(pose);
1843  }
1844  pub_path_poses_.publish(poses);
1845 
1846  const std::list<Astar::Vecf> path_interpolated =
1847  model_->path_interpolator_.interpolate(path_grid, 0.5, local_range_);
1848  grid_metric_converter::grid2MetricPath(map_info_, path_interpolated, path);
1849 
1850  if (hyst)
1851  {
1852  const auto ts = boost::chrono::high_resolution_clock::now();
1853  std::unordered_map<Astar::Vec, bool, Astar::Vec> path_points;
1854  const float max_dist = cc_.hysteresis_max_dist_ / map_info_.linear_resolution;
1855  const float expand_dist = cc_.hysteresis_expand_ / map_info_.linear_resolution;
1856  const int path_range = range_ + max_dist + expand_dist + 5;
1857  for (const Astar::Vecf& p : path_interpolated)
1858  {
1859  Astar::Vec d;
1860  for (d[0] = -path_range; d[0] <= path_range; d[0]++)
1861  {
1862  for (d[1] = -path_range; d[1] <= path_range; d[1]++)
1863  {
1864  Astar::Vec point = p + d;
1865  point.cycleUnsigned(map_info_.angle);
1866  if ((unsigned int)point[0] >= (unsigned int)map_info_.width ||
1867  (unsigned int)point[1] >= (unsigned int)map_info_.height)
1868  continue;
1869  path_points[point] = true;
1870  }
1871  }
1872  }
1873 
1874  clearHysteresis();
1875  for (auto& ps : path_points)
1876  {
1877  const Astar::Vec& p = ps.first;
1878  float d_min = std::numeric_limits<float>::max();
1879  auto it_prev = path_interpolated.cbegin();
1880  for (auto it = path_interpolated.cbegin(); it != path_interpolated.cend(); it++)
1881  {
1882  if (it != it_prev)
1883  {
1884  int yaw = std::lround((*it)[2]) % map_info_.angle;
1885  int yaw_prev = std::lround((*it_prev)[2]) % map_info_.angle;
1886  if (yaw < 0)
1887  yaw += map_info_.angle;
1888  if (yaw_prev < 0)
1889  yaw_prev += map_info_.angle;
1890  if (yaw == p[2] || yaw_prev == p[2])
1891  {
1892  const float d =
1893  CyclicVecFloat<3, 2>(p).distLinestrip2d(*it_prev, *it);
1894  if (d < d_min)
1895  d_min = d;
1896  }
1897  }
1898  it_prev = it;
1899  }
1900  d_min = std::max(expand_dist, std::min(expand_dist + max_dist, d_min));
1901  cm_hyst_[p] = std::lround((d_min - expand_dist) * 100.0 / max_dist);
1902  hyst_updated_cells_.push_back(p);
1903  }
1904  has_hysteresis_map_ = true;
1905  const auto tnow = boost::chrono::high_resolution_clock::now();
1906  ROS_DEBUG("Hysteresis map generated (%0.4f sec.)",
1907  boost::chrono::duration<float>(tnow - ts).count());
1908  publishDebug();
1909  }
1910 
1911  return true;
1912  }
1913 
1914  int getSwitchIndex(const nav_msgs::Path& path) const
1915  {
1916  geometry_msgs::Pose p_prev;
1917  bool first(true);
1918  bool dir_set(false);
1919  bool dir_prev(false);
1920  for (auto it = path.poses.begin(); it != path.poses.end(); ++it)
1921  {
1922  const auto& p = *it;
1923  if (!first)
1924  {
1925  const float x_diff = p.pose.position.x - p_prev.position.x;
1926  const float y_diff = p.pose.position.y - p_prev.position.y;
1927  const float len_sq = std::pow(y_diff, 2) + std::pow(x_diff, 2);
1928  if (len_sq > std::pow(0.001f, 2))
1929  {
1930  const float yaw = tf2::getYaw(p.pose.orientation);
1931  const bool dir = (std::cos(yaw) * x_diff + std::sin(yaw) * y_diff < 0);
1932 
1933  if (dir_set && (dir_prev ^ dir))
1934  {
1935  return std::distance(path.poses.begin(), it);
1936  }
1937  dir_prev = dir;
1938  dir_set = true;
1939  }
1940  }
1941  first = false;
1942  p_prev = p.pose;
1943  }
1944  // -1 means no switchback in the path
1945  return -1;
1946  }
1948  {
1949  switch (status_.error)
1950  {
1951  case planner_cspace_msgs::PlannerStatus::GOING_WELL:
1952  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Going well.");
1953  break;
1954  case planner_cspace_msgs::PlannerStatus::IN_ROCK:
1955  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "The robot is in rock.");
1956  break;
1957  case planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND:
1958  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Path not found.");
1959  break;
1960  case planner_cspace_msgs::PlannerStatus::DATA_MISSING:
1961  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Required data is missing.");
1962  break;
1963  case planner_cspace_msgs::PlannerStatus::INTERNAL_ERROR:
1964  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Planner internal error.");
1965  break;
1966  default:
1967  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Unknown error.");
1968  break;
1969  }
1970  stat.addf("status", "%u", status_.status);
1971  stat.addf("error", "%u", status_.error);
1972  }
1973 };
1974 } // namespace planner_3d
1975 } // namespace planner_cspace
1976 
1977 int main(int argc, char* argv[])
1978 {
1979  ros::init(argc, argv, "planner_3d");
1980 
1982  node.spin();
1983 
1984  return 0;
1985 }
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:110
d
geometry_msgs::PoseStamped goal_raw_
Definition: planner_3d.cpp:181
void cycle(const int res, const ArgList &...rest)
Definition: cyclic_vec.h:282
#define ROS_WARN_THROTTLE(rate,...)
ROSCONSOLE_DECL void notifyLoggerLevelsChanged()
void publish(const boost::shared_ptr< M > &message) const
actionlib::SimpleActionServer< move_base_msgs::MoveBaseAction > Planner3DActionServer
Definition: planner_3d.cpp:88
f
geometry_msgs::PoseStamped start_
Definition: planner_3d.cpp:179
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:127
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:118
const float MIN_PROBABILITY
Definition: bbf.h:47
int getSwitchIndex(const nav_msgs::Path &path) const
void setHardwareID(const std::string &hwid)
XmlRpcServer s
bool sleep() const
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:597
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 cycleUnsigned(const int res, const ArgList &...rest)
Definition: cyclic_vec.h:289
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())
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)
TFSIMD_FORCE_INLINE const tfScalar & y() const
#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,...)
char getCost(const Vec &p) const
Definition: costmap_bbf.h:69
void setBaseFrame(const std::string &frame_id)
Definition: jump_detector.h:73
Astar::Gridmap< char, 0x40 > cm_
Definition: planner_3d.cpp:115
Astar::Gridmap< char, 0x80 > cm_rough_
Definition: planner_3d.cpp:116
bool setGoal(const geometry_msgs::PoseStamped &msg)
Definition: planner_3d.cpp:392
GridAstarModel3D::Vec pathPose2Grid(const geometry_msgs::PoseStamped &pose) const
reservable_priority_queue< Astar::PriorityVec > pq_open_
Definition: planner_3d.cpp:214
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:217
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)
void cbGoal(const geometry_msgs::PoseStamped::ConstPtr &msg)
Definition: planner_3d.cpp:370
geometry_msgs::PoseStamped sw_pos_
Definition: planner_3d.cpp:193
std::shared_ptr< Planner3DTolerantActionServer > act_tolerant_
Definition: planner_3d.cpp:109
actionlib::SimpleActionServer< planner_cspace_msgs::MoveWithToleranceAction > Planner3DTolerantActionServer
Definition: planner_3d.cpp:89
#define ROS_INFO(...)
reservable_priority_queue< Astar::PriorityVec > pq_erase_
Definition: planner_3d.cpp:215
bool param(const std::string &param_name, T &param_val, const T &default_val) const
Astar::Gridmap< float > cost_estim_cache_
Definition: planner_3d.cpp:121
void reset(const Vec size)
Definition: grid_astar.h:147
std::vector< Astar::Vec > search_list_
Definition: planner_3d.cpp:156
ROSCPP_DECL bool ok()
TFSIMD_FORCE_INLINE const tfScalar & x() const
void cbMapUpdate(const costmap_cspace_msgs::CSpace3DUpdate::ConstPtr &msg)
Definition: planner_3d.cpp:843
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:108
const float MAX_PROBABILITY
Definition: bbf.h:48
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:117
B toMsg(const A &a)
std::array< float, 1024 > euclid_cost_lin_cache_
Definition: planner_3d.cpp:125
bool makePlan(const geometry_msgs::Pose &gs, const geometry_msgs::Pose &ge, nav_msgs::Path &path, bool hyst)
uint32_t getNumSubscribers() const
std::vector< Astar::Vec > search_list_rough_
Definition: planner_3d.cpp:157
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)
geometry_msgs::PoseStamped goal_
Definition: planner_3d.cpp:180
planner_cspace_msgs::PlannerStatus status_
Definition: planner_3d.cpp:189
Astar::Gridmap< char, 0x80 > cm_hyst_
Definition: planner_3d.cpp:119
static Time now()
float gridToLenFactor() const
Definition: cyclic_vec.h:253
Astar::Gridmap< char, 0x80 > cm_updates_
Definition: planner_3d.cpp:120
void fillCostmap(reservable_priority_queue< Astar::PriorityVec > &open, Astar::Gridmap< float > &g, const Astar::Vec &s, const Astar::Vec &e)
Definition: planner_3d.cpp:432
ROSCONSOLE_DECL bool set_logger_level(const std::string &name, levels::Level level)
bool hasParam(const std::string &key) const
DiscretePoseStatus relocateDiscretePoseIfNeededImpl(const T &cm, const int tolerance_range, const int tolerance_angle, Astar::Vec &pose_discrete) const
Definition: planner_3d.cpp:234
std::vector< Astar::Vec > hyst_updated_cells_
Definition: planner_3d.cpp:152
bool cbMakePlan(nav_msgs::GetPlan::Request &req, nav_msgs::GetPlan::Response &res)
Definition: planner_3d.cpp:268
ROSCPP_DECL void spinOnce()
#define ROS_ERROR(...)
#define ROSCONSOLE_DEFAULT_NAME
DiscretePoseStatus relocateDiscretePoseIfNeeded(Astar::Vec &pose_discrete, const int tolerance_range, const int tolerance_angle, bool use_cm_rough=false) const
Definition: planner_3d.cpp:252
diagnostic_updater::Updater diag_updater_
Definition: planner_3d.cpp:205
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)
bool updateGoal(const bool goal_changed=true)
Definition: planner_3d.cpp:651
#define ROS_DEBUG(...)


planner_cspace
Author(s): Atsushi Watanabe
autogenerated on Wed May 12 2021 02:20:42