36 #include <unordered_map> 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> 65 #include <move_base_msgs/MoveBaseAction.h> 66 #include <planner_cspace_msgs/MoveWithToleranceAction.h> 112 std::shared_ptr<Planner3DActionServer>
act_;
119 Astar::Gridmap<char, 0x40>
cm_;
217 std_srvs::EmptyResponse& res)
219 ROS_WARN(
"Forgetting remembered costmap.");
221 bbf_costmap_.
clear();
234 const int tolerance_range,
235 const int tolerance_angle,
238 if (!cm.validate(pose_discrete, range_))
242 if (cm[pose_discrete] == 100)
252 const int tolerance_range,
253 const int tolerance_angle,
254 bool use_cm_rough =
false)
const 258 pose_discrete[2] = 0;
268 nav_msgs::GetPlan::Response& res)
272 ROS_ERROR(
"make_plan service is called without map.");
276 if (req.start.header.frame_id != map_header_.frame_id ||
277 req.goal.header.frame_id != map_header_.frame_id)
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());
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]);
295 const int tolerance_range = std::lround(req.tolerance / map_info_.linear_resolution);
298 switch (start_status)
301 ROS_ERROR(
"Given start is not on the map.");
307 ROS_INFO(
"Given start is moved (%d, %d)", s[0], s[1]);
315 ROS_ERROR(
"Given goal is not on the map.");
321 ROS_INFO(
"Given goal is moved (%d, %d)", e[0], e[1]);
327 const auto cb_progress = [](
const std::list<Astar::Vec>& ,
const SearchStats& )
332 const auto ts = boost::chrono::high_resolution_clock::now();
336 std::list<Astar::Vec> path_grid;
337 std::vector<GridAstarModel3D::VecWithCost> starts;
338 starts.emplace_back(s);
340 starts, e, path_grid,
343 0, 1.0f / freq_min_, find_best_))
345 ROS_WARN(
"Path plan failed (goal unreachable)");
348 const auto tnow = boost::chrono::high_resolution_clock::now();
350 boost::chrono::duration<float>(tnow - ts).count());
356 const std::list<Astar::Vecf> path_interpolated =
357 model_->path_interpolator_.interpolate(path_grid, 0.5, 0.0);
361 res.plan.poses.resize(path.poses.size());
362 for (
size_t i = 0; i < path.poses.size(); ++i)
364 res.plan.poses[i] = path.poses[i];
369 void cbGoal(
const geometry_msgs::PoseStamped::ConstPtr& msg)
371 if (act_->isActive() || act_tolerant_->isActive())
373 ROS_ERROR(
"Setting new goal is ignored since planner_3d is proceeding the action.");
380 ROS_WARN(
"Preempting the current goal.");
381 if (act_->isActive())
382 act_->setPreempted(move_base_msgs::MoveBaseResult(),
"Preempted.");
384 if (act_tolerant_->isActive())
385 act_tolerant_->setPreempted(planner_cspace_msgs::MoveWithToleranceResult(),
"Preempted.");
388 status_.status = planner_cspace_msgs::PlannerStatus::DONE;
391 bool setGoal(
const geometry_msgs::PoseStamped& msg)
393 if (msg.header.frame_id != map_header_.frame_id)
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());
400 goal_raw_ = goal_ = msg;
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)
417 status_.status = planner_cspace_msgs::PlannerStatus::DOING;
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.");
435 const int cost_acceptable = 50,
const int min_xy_range = 0)
const 437 ROS_DEBUG(
"%d, %d (%d,%d,%d)", xy_range, angle_range, s[0], s[1], s[2]);
439 float range_min = std::numeric_limits<float>::max();
442 for (d[2] = -angle_range; d[2] <= angle_range; d[2]++)
444 for (d[0] = -xy_range; d[0] <= xy_range; d[0]++)
446 for (d[1] = -xy_range; d[1] <= xy_range; d[1]++)
448 if (d[0] == 0 && d[1] == 0 && d[2] == 0)
450 if (d.
sqlen() > xy_range * xy_range)
452 if (d.
sqlen() < min_xy_range * min_xy_range)
456 if ((
unsigned int)s2[0] >= (
unsigned int)map_info_.width ||
457 (
unsigned int)s2[1] >= (
unsigned int)map_info_.height)
460 if (!cm_.validate(s2, range_))
463 if (cm_[s2] >= cost_acceptable)
465 const auto cost = model_->euclidCost(d);
466 if (cost < range_min)
475 if (range_min == std::numeric_limits<float>::max())
477 if (cost_acceptable != 100)
485 ROS_DEBUG(
" (%d,%d,%d)", s[0], s[1], s[2]);
493 if (!has_map_ || !has_start_)
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_));
502 map_info_, s[0], s[1], s[2],
503 start_.pose.position.x, start_.pose.position.y,
507 map_info_, e[0], e[1], e[2],
508 goal_.pose.position.x, goal_.pose.position.y,
514 "New goal received (%d, %d, %d)",
518 has_hysteresis_map_ =
false;
522 switch (start_pose_status)
525 ROS_ERROR(
"You are on the edge of the world.");
534 switch (goal_pose_status)
537 ROS_ERROR(
"Given goal is not on the map.");
544 ROS_INFO(
"Goal moved (%d, %d, %d)", e[0], e[1], e[2]);
548 goal_.pose.position.x = x;
549 goal_.pose.position.y = y;
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);
560 "distance_map_init_dur",
564 "distance_map_update_dur",
570 goal_updated_ =
true;
576 for (
const Astar::Vec& p : hyst_updated_cells_)
580 hyst_updated_cells_.clear();
586 sensor_msgs::PointCloud distance_map;
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]++)
596 for (p[0] = 0; p[0] < cost_estim_cache_.
size()[0]; p[0]++)
601 geometry_msgs::Point32 point;
604 if (cost_estim_cache_[p] == std::numeric_limits<float>::max())
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);
611 pub_distance_map_.
publish(distance_map);
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);
624 for (
Astar::Vec p(0, 0, 0); p[1] < cost_estim_cache_.
size()[1]; p[1]++)
626 for (p[0] = 0; p[0] < cost_estim_cache_.
size()[0]; p[0]++)
628 if (cost_estim_cache_[p] == std::numeric_limits<float>::max())
632 for (
Astar::Vec p2 = p; p2[2] <
static_cast<int>(map_info_.angle); ++p2[2])
634 cost = std::min(cm_hyst_[p2], cost);
636 hysteresis_map.data[p[0] + p[1] * map_info_.width] = cost;
639 pub_hysteresis_map_.
publish(hysteresis_map);
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);
656 remembered_map.data[p[0] + p[1] * map_info_.width] =
659 bbf_costmap_.
forEach(generate_pointcloud);
660 pub_remembered_map_.
publish(remembered_map);
668 if (use_path_with_velocity_)
672 path, std::numeric_limits<double>::quiet_NaN()));
682 path.header.frame_id = map_header_.frame_id;
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;
690 path.poses[0].pose = goal_.pose;
692 if (use_path_with_velocity_)
696 path, std::numeric_limits<double>::quiet_NaN()));
704 void cbMapUpdate(
const costmap_cspace_msgs::CSpace3DUpdate::ConstPtr msg)
710 const auto ts_cm_init_start = boost::chrono::high_resolution_clock::now();
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);
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)
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;
729 map_update_retained_ =
nullptr;
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(
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(
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));
748 const int search_range_x_min = std::max(
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(
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);
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;
766 bool clear_hysteresis(
false);
770 static_cast<int>(msg->x), static_cast<int>(msg->y), static_cast<int>(msg->yaw));
772 for (
Astar::Vec p(0, 0, 0); p[0] <
static_cast<int>(msg->width); p[0]++)
774 for (p[1] = 0; p[1] <
static_cast<int>(msg->height); p[1]++)
777 for (p[2] = 0; p[2] <
static_cast<int>(msg->angle); p[2]++)
779 const size_t addr = ((p[2] * msg->height) + p[1]) * msg->width + p[0];
780 const char c = msg->data[addr];
783 if (c == 100 && !clear_hysteresis && cm_hyst_[gp + p] == 0)
784 clear_hysteresis =
true;
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;
791 for (p[2] = 0; p[2] <
static_cast<int>(msg->angle); p[2]++)
793 const size_t addr = ((p[2] * msg->height) + p[1]) * msg->width + p[0];
794 const char c = msg->data[addr];
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);
817 if (clear_hysteresis && has_hysteresis_map_)
819 ROS_INFO(
"The previous path collides to the obstacle. Clearing hysteresis map.");
821 has_hysteresis_map_ =
false;
829 map_info_, s[0], s[1], s[2],
830 start_.pose.position.x, start_.pose.position.y,
834 if (remember_updates_)
838 remember_hit_odds_, remember_miss_odds_,
839 hist_ignore_range_, hist_ignore_range_max_);
846 if (!fast_map_update_)
854 map_info_, e[0], e[1], e[2],
855 goal_.pose.position.x, goal_.pose.position.y,
865 const auto ts = boost::chrono::high_resolution_clock::now();
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();
875 ROS_WARN(
"Negative cost value is detected. Limited to zero.");
877 ROS_DEBUG(
"Cost estimation cache search queue initial size: %lu, capacity: %lu",
879 const float dur = boost::chrono::duration<float>(tnow - ts).count();
880 ROS_DEBUG(
"Cost estimation cache updated (%0.4f sec.)", dur);
882 "distance_map_update_dur",
886 "distance_map_init_dur",
891 void cbMap(
const costmap_cspace_msgs::CSpace3D::ConstPtr& msg)
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,
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,
911 if (map_info_.linear_resolution != msg->info.linear_resolution ||
912 map_info_.angular_resolution != msg->info.angular_resolution)
914 map_info_ = msg->info;
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);
940 map_info_ = msg->info;
942 map_header_ = msg->header;
947 static_cast<int>(map_info_.width),
948 static_cast<int>(map_info_.height),
949 static_cast<int>(map_info_.angle),
952 const Astar::Vec size3d(size[0], size[1], size[2]);
957 cm_hyst_.reset(size3d);
964 .longcut_range =
static_cast<int>(std::lround(longcut_range_f_ / map_info_.linear_resolution)),
966 .resolution = map_info_.linear_resolution,
968 cost_estim_cache_.
init(model_, dmp);
969 cm_rough_.reset(size2d);
970 cm_updates_.reset(size2d);
971 bbf_costmap_.
reset(size2d);
974 for (p[0] = 0; p[0] <
static_cast<int>(map_info_.width); p[0]++)
976 for (p[1] = 0; p[1] <
static_cast<int>(map_info_.height); p[1]++)
979 for (p[2] = 0; p[2] <
static_cast<int>(map_info_.angle); p[2]++)
981 const size_t addr = ((p[2] * size[1]) + p[1]) * size[0] + p[0];
982 char c = msg->data[addr];
990 cm_rough_[p] = cost_min;
996 hyst_updated_cells_.clear();
997 has_hysteresis_map_ =
false;
999 cm_updates_.clear(0);
1005 bbf_costmap_.
clear();
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;
1014 if (map_update_retained_ && map_update_retained_->header.stamp >= msg->header.stamp)
1016 ROS_INFO(
"Applying retained map update");
1019 map_update_retained_ =
nullptr;
1023 if (act_tolerant_->isActive())
1025 ROS_ERROR(
"Setting new goal is ignored since planner_3d is proceeding by tolerant_move action.");
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.");
1036 if (act_->isActive())
1038 ROS_ERROR(
"Setting new goal is ignored since planner_3d is proceeding by move_base action.");
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.");
1049 geometry_msgs::PoseStamped
start;
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;
1061 geometry_msgs::TransformStamped trans =
1079 , cost_estim_cache_(cm_rough_, bbf_costmap_)
1087 nh_,
"costmap_update",
1090 nh_,
"move_base_simple/goal",
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",
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);
1113 goal_tolerant_ =
nullptr;
1115 pnh_.
param(
"use_path_with_velocity", use_path_with_velocity_,
false);
1116 if (use_path_with_velocity_)
1118 pub_path_velocity_ = nh_.
advertise<trajectory_tracker_msgs::PathWithVelocity>(
1119 "path_velocity", 1,
true);
1123 pub_path_ = neonavigation_common::compat::advertise<nav_msgs::Path>(
1125 pnh_,
"path", 1,
true);
1127 pub_path_poses_ = pnh_.
advertise<geometry_msgs::PoseArray>(
1128 "path_poses", 1,
true);
1130 pnh_.
param(
"freq", freq_, 4.0
f);
1131 pnh_.
param(
"freq_min", freq_min_, 2.0
f);
1132 pnh_.
param(
"search_timeout_abort", search_timeout_abort_, 30.0
f);
1133 pnh_.
param(
"search_range", search_range_, 0.4
f);
1134 pnh_.
param(
"antialias_start", antialias_start_,
false);
1136 double costmap_watchdog;
1137 pnh_.
param(
"costmap_watchdog", costmap_watchdog, 0.0);
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);
1159 pnh_.
param(
"unknown_cost", unknown_cost_, 100);
1160 pnh_.
param(
"overwrite_cost", overwrite_cost_,
false);
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);
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);
1177 pnh_.
param(
"sw_wait", sw_wait_, 2.0
f);
1178 pnh_.
param(
"find_best", find_best_,
true);
1180 pnh_.
param(
"robot_frame", robot_frame_, std::string(
"base_link"));
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"));
1190 pnh_.
param(
"force_goal_orientation", force_goal_orientation_,
true);
1192 pnh_.
param(
"temporary_escape", temporary_escape_,
true);
1194 pnh_.
param(
"fast_map_update", fast_map_update_,
false);
1195 if (fast_map_update_)
1197 ROS_WARN(
"planner_3d: Experimental fast_map_update is enabled. ");
1202 "planner_3d: ~/debug_mode parameter and ~/debug topic are deprecated. " 1203 "Use ~/distance_map, ~/hysteresis_map, and ~/remembered_map topics instead.");
1206 bool print_planning_duration;
1207 pnh_.
param(
"print_planning_duration", print_planning_duration,
false);
1208 if (print_planning_duration)
1216 pnh_.
param(
"max_retry_num", max_retry_num_, -1);
1218 int queue_size_limit;
1219 pnh_.
param(
"queue_size_limit", queue_size_limit, 0);
1223 pnh_.
param(
"num_threads", num_threads, 1);
1224 omp_set_num_threads(num_threads);
1227 pnh_.
param(
"num_search_task", num_task, num_threads * 16);
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);
1233 pnh_.
param(
"retain_last_error_status", retain_last_error_status_,
true);
1234 status_.status = planner_cspace_msgs::PlannerStatus::DONE;
1239 goal_updated_ =
false;
1243 is_path_switchback_ =
false;
1249 act_tolerant_->start();
1256 pose.pose.position.x, pose.pose.position.y,
tf2::getYaw(pose.pose.orientation));
1267 const bool costmap_udpated = last_costmap_ != prev_map_update_stamp;
1275 bbf_costmap_.
clear();
1280 if (costmap_udpated && previous_path.poses.size() > 1)
1282 for (
const auto& path_pose : previous_path.poses)
1292 if (is_path_switchback_)
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_)
1304 is_path_switchback_ =
false;
1321 nav_msgs::Path previous_path;
1325 waitUntil(next_replan_time, previous_path);
1328 next_replan_time = now;
1330 if (has_map_ && !goal_updated_ && has_goal_)
1334 bool has_costmap(
false);
1340 costmap_delay.
toSec(),
1342 if (costmap_delay > costmap_watchdog_)
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;
1349 previous_path.poses.clear();
1365 bool is_path_switchback =
false;
1366 if (has_map_ && has_goal_ && has_start_ && has_costmap)
1368 if (act_->isActive())
1370 move_base_msgs::MoveBaseFeedback feedback;
1371 feedback.base_position =
start_;
1372 act_->publishFeedback(feedback);
1375 if (act_tolerant_->isActive())
1377 planner_cspace_msgs::MoveWithToleranceFeedback feedback;
1378 feedback.base_position =
start_;
1379 act_tolerant_->publishFeedback(feedback);
1382 if (status_.status == planner_cspace_msgs::PlannerStatus::FINISHING)
1384 const float yaw_s =
tf2::getYaw(start_.pose.orientation);
1385 float yaw_g =
tf2::getYaw(goal_.pose.orientation);
1386 if (force_goal_orientation_)
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) <
1397 status_.status = planner_cspace_msgs::PlannerStatus::DONE;
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.");
1417 status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1419 else if (max_retry_num_ != -1 && cnt_stuck_ > max_retry_num_)
1421 status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1422 status_.status = planner_cspace_msgs::PlannerStatus::DONE;
1426 previous_path.poses.clear();
1428 ROS_ERROR(
"Exceeded max_retry_num:%d", max_retry_num_);
1430 if (act_->isActive())
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");
1439 else if (cnt_stuck_ > 0)
1441 status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1445 status_.error = planner_cspace_msgs::PlannerStatus::GOING_WELL;
1447 nav_msgs::Path path;
1449 path.header.stamp = now;
1450 makePlan(start_.pose, goal_.pose, path,
true);
1451 if (use_path_with_velocity_)
1461 previous_path = path;
1466 is_path_switchback = (sw_index >= 0);
1467 if (is_path_switchback)
1468 sw_pos_ = path.poses[sw_index];
1472 else if (!has_goal_)
1474 if (!retain_last_error_status_)
1475 status_.error = planner_cspace_msgs::PlannerStatus::GOING_WELL;
1477 previous_path.poses.clear();
1479 status_.header.stamp = now;
1483 metrics_.header.stamp = now;
1496 pub_metrics_.
publish(metrics_);
1497 metrics_.data.clear();
1499 if (is_path_switchback)
1502 ROS_INFO(
"Planned path has switchback. Planner will stop until: %f at the latest.", next_replan_time.
toSec());
1508 is_path_switchback_ = is_path_switchback;
1513 bool makePlan(
const geometry_msgs::Pose& gs,
const geometry_msgs::Pose& ge,
1514 nav_msgs::Path& path,
bool hyst)
1518 map_info_, e[0], e[1], e[2],
1519 ge.position.x, ge.position.y,
tf2::getYaw(ge.orientation));
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]));
1528 if (!cm_.validate(s, range_))
1530 ROS_ERROR(
"You are on the edge of the world.");
1534 std::vector<Astar::VecWithCost> starts;
1535 if (antialias_start_)
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)
1541 for (
const int y : y_cand)
1544 if (!cm_.validate(p, range_))
1548 if (subpx.
sqlen() > 1.0)
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]);
1573 remain.
cycle(map_info_.angle);
1575 int g_tolerance_lin, g_tolerance_ang;
1576 if (act_tolerant_->isActive())
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);
1587 if (remain.
sqlen() <= g_tolerance_lin * g_tolerance_lin &&
1588 std::abs(remain[2]) <= g_tolerance_ang)
1600 if (act_tolerant_->isActive() && goal_tolerant_->continuous_movement_mode)
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;
1609 status_.status = planner_cspace_msgs::PlannerStatus::FINISHING;
1618 geometry_msgs::PoseStamped p;
1623 p.pose.position.x = x;
1624 p.pose.position.y = y;
1627 if (starts.size() == 0)
1631 ROS_WARN(
"Oops! You are in Rock!");
1632 status_.error = planner_cspace_msgs::PlannerStatus::IN_ROCK;
1642 if (cost_estim_cache_[s_rough] == std::numeric_limits<float>::max() || cm_[e] >= 100)
1644 status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1646 if (!escaping_ && temporary_escape_)
1652 ROS_INFO(
"Temporary goal (%d, %d, %d)",
1657 goal_.pose.position.x = x;
1658 goal_.pose.position.y = y;
1669 p.pose.position.x = x;
1670 p.pose.position.y = y;
1673 const float range_limit = cost_estim_cache_[s_rough] - (local_range_ +
range_) * ec_[0];
1675 const auto ts = boost::chrono::high_resolution_clock::now();
1679 const auto cb_progress = [
this, ts, s, e](
const std::list<Astar::Vec>& path_grid,
const SearchStats& stats) ->
bool 1681 const auto tnow = boost::chrono::high_resolution_clock::now();
1682 const auto tdiff = boost::chrono::duration<float>(tnow - ts).count();
1684 if (tdiff > search_timeout_abort_)
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, " 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);
1698 ROS_WARN(
"Search timed out (%0.4f sec.)", tdiff);
1702 model_->enableHysteresis(hyst && has_hysteresis_map_);
1703 std::list<Astar::Vec> path_grid;
1704 if (!as_.
search(starts, e, path_grid,
1711 ROS_WARN(
"Path plan failed (goal unreachable)");
1712 status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
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);
1724 geometry_msgs::PoseArray poses;
1725 poses.header = path.header;
1726 for (
const auto& p : path_grid)
1728 geometry_msgs::Pose pose;
1731 pose.position.x = x;
1732 pose.position.y = y;
1735 poses.poses.push_back(pose);
1737 pub_path_poses_.
publish(poses);
1739 const std::list<Astar::Vecf> path_interpolated =
1740 model_->path_interpolator_.interpolate(path_grid, 0.5, local_range_);
1745 const auto ts = boost::chrono::high_resolution_clock::now();
1746 std::unordered_map<Astar::Vec, bool, Astar::Vec> path_points;
1749 const int path_range = range_ + max_dist + expand_dist + 5;
1753 for (d[0] = -path_range; d[0] <= path_range; d[0]++)
1755 for (d[1] = -path_range; d[1] <= path_range; d[1]++)
1759 if ((
unsigned int)point[0] >= (
unsigned int)map_info_.width ||
1760 (
unsigned int)point[1] >= (
unsigned int)map_info_.height)
1762 path_points[point] =
true;
1768 for (
auto& ps : path_points)
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++)
1777 int yaw = std::lround((*it)[2]) % map_info_.angle;
1778 int yaw_prev = std::lround((*it_prev)[2]) % map_info_.angle;
1780 yaw += map_info_.angle;
1782 yaw_prev += map_info_.angle;
1783 if (yaw == p[2] || yaw_prev == p[2])
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);
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);
1813 geometry_msgs::Pose p_prev;
1815 bool dir_set(
false);
1816 bool dir_prev(
false);
1817 for (
auto it = path.poses.begin(); it != path.poses.end(); ++it)
1819 const auto& p = *it;
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.001
f, 2))
1827 const float yaw =
tf2::getYaw(p.pose.orientation);
1828 const bool dir = (std::cos(yaw) * x_diff + std::sin(yaw) * y_diff < 0);
1830 if (dir_set && (dir_prev ^ dir))
1832 return std::distance(path.poses.begin(), it);
1846 switch (status_.error)
1848 case planner_cspace_msgs::PlannerStatus::GOING_WELL:
1849 stat.
summary(diagnostic_msgs::DiagnosticStatus::OK,
"Going well.");
1851 case planner_cspace_msgs::PlannerStatus::IN_ROCK:
1852 stat.
summary(diagnostic_msgs::DiagnosticStatus::ERROR,
"The robot is in rock.");
1854 case planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND:
1855 stat.
summary(diagnostic_msgs::DiagnosticStatus::ERROR,
"Path not found.");
1857 case planner_cspace_msgs::PlannerStatus::DATA_MISSING:
1858 stat.
summary(diagnostic_msgs::DiagnosticStatus::ERROR,
"Required data is missing.");
1860 case planner_cspace_msgs::PlannerStatus::INTERNAL_ERROR:
1861 stat.
summary(diagnostic_msgs::DiagnosticStatus::ERROR,
"Planner internal error.");
1864 stat.
summary(diagnostic_msgs::DiagnosticStatus::ERROR,
"Unknown error.");
1867 stat.
addf(
"status",
"%u", status_.status);
1868 stat.
addf(
"error",
"%u", status_.error);
void remember(const BlockMemGridmapBase< char, 3, 2 > *const costmap, const Vec ¢er, const float remember_hit_odds, const float remember_miss_odds, const int range_min, const int range_max)
planner_cspace_msgs::MoveWithToleranceGoalConstPtr goal_tolerant_
geometry_msgs::PoseStamped goal_raw_
ros::Publisher pub_path_velocity_
std::shared_ptr< GridAstarModel3D > Ptr
void init(const GridAstarModel3D::Ptr model, const Params &p)
int hist_ignore_range_max_
float search_timeout_abort_
ros::Publisher pub_hysteresis_map_
ROSCONSOLE_DECL void notifyLoggerLevelsChanged()
actionlib::SimpleActionServer< move_base_msgs::MoveBaseAction > Planner3DActionServer
std_msgs::Header map_header_
geometry_msgs::PoseStamped start_
ros::Publisher pub_path_poses_
DiscretePoseStatus relocateDiscretePoseIfNeeded(Astar::Vec &pose_discrete, const int tolerance_range, const int tolerance_angle, bool use_cm_rough=false) const
void setSearchTaskNum(const size_t &search_task_num)
void summary(unsigned char lvl, const std::string s)
void diagnoseStatus(diagnostic_updater::DiagnosticStatusWrapper &stat)
double tolerance_angle_f_
costmap_cspace_msgs::MapMetaData3D map_info_
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)
Astar::Gridmap< char, 0x80 > cm_rough_base_
const float MIN_PROBABILITY
void setHardwareID(const std::string &hwid)
GridAstarModel3D::Ptr model_
float weight_costmap_turn_
double hist_ignore_range_f_
ros::ServiceServer srs_make_plan_
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
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
void reset(const Vec &size)
void add(const std::string &name, TaskFunction f)
void setQueueSizeLimit(const size_t size)
float remember_miss_odds_
double goal_tolerance_ang_f_
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_
DistanceMap cost_estim_cache_
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)
ros::Subscriber sub_map_update_
Metric metric(const std::string &name, const double value, const std::string &unit, Strings &&... tags)
ros::Publisher pub_start_
bool retain_last_error_status_
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)
void publishRememberedMap()
bool use_path_with_velocity_
Astar::Gridmap< char, 0x40 > cm_
std::shared_ptr< GridAstarModel2D > Ptr
Astar::Gridmap< char, 0x80 > cm_rough_
bool setGoal(const geometry_msgs::PoseStamped &msg)
void cbMapUpdate(const costmap_cspace_msgs::CSpace3DUpdate::ConstPtr msg)
void waitUntil(const ros::Time &next_replan_time, const nav_msgs::Path &previous_path)
bool cbForget(std_srvs::EmptyRequest &req, std_srvs::EmptyResponse &res)
bool param(const std::string ¶m_name, T ¶m_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
void cbGoal(const geometry_msgs::PoseStamped::ConstPtr &msg)
geometry_msgs::PoseStamped sw_pos_
int getSwitchIndex(const nav_msgs::Path &path) const
std::shared_ptr< Planner3DTolerantActionServer > act_tolerant_
actionlib::SimpleActionServer< planner_cspace_msgs::MoveWithToleranceAction > Planner3DTolerantActionServer
#define ROS_WARN_THROTTLE(period,...)
tf2_ros::TransformListener tfl_
void reset(const Vec size)
std::vector< Astar::Vec > search_list_
void cycleUnsigned(const int res, const ArgList &... rest)
ros::Subscriber sub_goal_
double hist_ignore_range_max_f_
int prev_map_update_x_min_
float angle_resolution_aspect_
void setMapFrame(const std::string &frame_id)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
ros::ServiceServer srs_forget_
void setThresholds(const double pos_jump, const double yaw_jump)
std::shared_ptr< Planner3DActionServer > act_
const float MAX_PROBABILITY
bool hasParam(const std::string &key) const
double getYaw(const A &a)
typename GridAstarModelBase< DIM, NONCYCLIC >::VecWithCost VecWithCost
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_
const Astar::Vec & size() const
bool force_goal_orientation_
const Astar::Gridmap< float > & gridmap() const
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_
constexpr float probabilityToOdds(const float &p)
void grid2Metric(const costmap_cspace_msgs::MapMetaData3D &map_info, const T x, const T y, const T yaw, float &gx, float &gy, float &gyaw)
ros::Publisher pub_distance_map_
double goal_tolerance_lin_f_
GridAstarModel3D::Vec pathPose2Grid(const geometry_msgs::PoseStamped &pose) const
double tolerance_range_f_
float hysteresis_max_dist_
ros::Publisher pub_metrics_
geometry_msgs::PoseStamped goal_
ros::Publisher pub_status_
planner_cspace_msgs::PlannerStatus status_
Astar::Gridmap< char, 0x80 > cm_hyst_
int prev_map_update_y_max_
void setParams(const CostCoeff &cc, const int num_cost_estim_task)
int prev_map_update_y_min_
Astar::Gridmap< char, 0x80 > cm_updates_
double goal_tolerance_ang_finish_
costmap_cspace_msgs::CSpace3DUpdate::ConstPtr map_update_retained_
ROSCONSOLE_DECL bool set_logger_level(const std::string &name, levels::Level level)
int prev_map_update_x_max_
void cycle(const int res, const ArgList &... rest)
std::vector< Astar::Vec > hyst_updated_cells_
bool cbMakePlan(nav_msgs::GetPlan::Request &req, nav_msgs::GetPlan::Response &res)
void create(const Astar::Vec &s, const Astar::Vec &e)
uint32_t getNumSubscribers() const
ROSCPP_DECL void spinOnce()
#define ROSCONSOLE_DEFAULT_NAME
const DebugData & getDebugData() const
ros::Duration costmap_watchdog_
diagnostic_updater::Updater diag_updater_
PathWithVelocity toPathWithVelocity(const nav_msgs::Path &src, const double vel)
CyclicVecFloat< DIM, NONCYCLIC > Vecf
void forEach(const std::function< void(const Vec &, bbf::BinaryBayesFilter &)> cb)
void cbMap(const costmap_cspace_msgs::CSpace3D::ConstPtr &msg)
ros::Publisher pub_remembered_map_
void update(const Astar::Vec &s, const Astar::Vec &e, const Rect &rect)
bool updateGoal(const bool goal_changed=true)