43 #include <unordered_map>
51 #include <costmap_cspace_msgs/CSpace3D.h>
52 #include <costmap_cspace_msgs/CSpace3DUpdate.h>
54 #include <dynamic_reconfigure/server.h>
55 #include <geometry_msgs/PoseArray.h>
56 #include <nav_msgs/GetPlan.h>
57 #include <nav_msgs/OccupancyGrid.h>
58 #include <nav_msgs/Path.h>
59 #include <neonavigation_metrics_msgs/Metrics.h>
61 #include <planner_cspace_msgs/PlannerStatus.h>
62 #include <sensor_msgs/PointCloud.h>
63 #include <std_srvs/Empty.h>
64 #include <trajectory_tracker_msgs/PathWithVelocity.h>
73 #include <move_base_msgs/MoveBaseAction.h>
74 #include <planner_cspace_msgs/MoveWithToleranceAction.h>
78 #include <planner_cspace/Planner3DConfig.h>
124 std::shared_ptr<Planner3DActionServer>
act_;
132 Astar::Gridmap<char, 0x40>
cm_;
251 std_srvs::EmptyResponse& res)
253 ROS_WARN(
"Forgetting remembered costmap.");
277 const int tolerance_range,
278 const int tolerance_angle,
281 if (!cm.validate(pose_discrete,
range_))
285 if (cm[pose_discrete] == 100)
295 const int tolerance_range,
296 const int tolerance_angle,
297 bool use_cm_rough =
false)
const
301 pose_discrete[2] = 0;
315 pose.position.x, pose.position.y,
324 geometry_msgs::Pose pose;
334 geometry_msgs::Point32 point;
341 nav_msgs::GetPlan::Response& res)
345 ROS_ERROR(
"make_plan service is called without map.");
349 if (req.start.header.frame_id !=
map_header_.frame_id ||
352 ROS_ERROR(
"Start [%s] and Goal [%s] poses must be in the map frame [%s].",
353 req.start.header.frame_id.c_str(),
354 req.goal.header.frame_id.c_str(),
361 ROS_INFO(
"Path plan from (%d, %d) to (%d, %d)",
s[0],
s[1], e[0], e[1]);
363 const int tolerance_range = std::lround(req.tolerance /
map_info_.linear_resolution);
366 switch (start_status)
369 ROS_ERROR(
"Given start is not on the map.");
375 ROS_INFO(
"Given start is moved (%d, %d)",
s[0],
s[1]);
383 ROS_ERROR(
"Given goal is not on the map.");
389 ROS_INFO(
"Given goal is moved (%d, %d)", e[0], e[1]);
395 const auto cb_progress = [](
const std::list<Astar::Vec>& ,
const SearchStats& )
400 const auto ts = boost::chrono::high_resolution_clock::now();
404 std::list<Astar::Vec> path_grid;
405 std::vector<GridAstarModel3D::VecWithCost> starts;
406 starts.emplace_back(
s);
408 starts, e, path_grid,
413 ROS_WARN(
"Path plan failed (goal unreachable)");
416 const auto tnow = boost::chrono::high_resolution_clock::now();
418 boost::chrono::duration<float>(tnow - ts).count());
424 const std::list<Astar::Vecf> path_interpolated =
model_->interpolatePath(path_grid);
428 res.plan.poses.resize(path.poses.size());
429 for (
size_t i = 0; i < path.poses.size(); ++i)
431 res.plan.poses[i] = path.poses[i];
436 void cbGoal(
const geometry_msgs::PoseStamped::ConstPtr& msg)
440 ROS_ERROR(
"Setting new goal is ignored since planner_3d is proceeding the action.");
447 ROS_WARN(
"Preempting the current goal.");
448 if (
act_->isActive())
449 act_->setPreempted(move_base_msgs::MoveBaseResult(),
"Preempted.");
452 act_tolerant_->setPreempted(planner_cspace_msgs::MoveWithToleranceResult(),
"Preempted.");
455 status_.status = planner_cspace_msgs::PlannerStatus::DONE;
458 bool setGoal(
const geometry_msgs::PoseStamped& msg)
462 ROS_ERROR(
"Goal [%s] pose must be in the map frame [%s].",
470 goal_.pose.orientation.x *
goal_.pose.orientation.x +
471 goal_.pose.orientation.y *
goal_.pose.orientation.y +
472 goal_.pose.orientation.z *
goal_.pose.orientation.z +
473 goal_.pose.orientation.w *
goal_.pose.orientation.w;
474 if (std::abs(len2 - 1.0) < 0.1)
484 status_.status = planner_cspace_msgs::PlannerStatus::DOING;
492 if (
act_->isActive())
493 act_->setSucceeded(move_base_msgs::MoveBaseResult(),
"Goal cleared.");
495 act_tolerant_->setSucceeded(planner_cspace_msgs::MoveWithToleranceResult(),
"Goal cleared.");
502 int cost_acceptable = -1,
const int min_xy_range = 0)
const
504 if (cost_acceptable == -1)
508 ROS_DEBUG(
"%d, %d (%d,%d,%d)", xy_range, angle_range,
s[0],
s[1],
s[2]);
510 float range_min = std::numeric_limits<float>::max();
513 for (
d[2] = -angle_range;
d[2] <= angle_range;
d[2]++)
515 for (
d[0] = -xy_range;
d[0] <= xy_range;
d[0]++)
517 for (
d[1] = -xy_range;
d[1] <= xy_range;
d[1]++)
519 if (
d[0] == 0 &&
d[1] == 0 &&
d[2] == 0)
521 if (
d.sqlen() > xy_range * xy_range)
523 if (
d.sqlen() < min_xy_range * min_xy_range)
527 if ((
unsigned int)s2[0] >= (
unsigned int)
map_info_.width ||
528 (
unsigned int)s2[1] >= (
unsigned int)
map_info_.height)
534 if (
cm_[s2] >= cost_acceptable)
536 const auto cost =
model_->euclidCost(
d);
537 if (cost < range_min)
546 if (range_min == std::numeric_limits<float>::max())
548 if (cost_acceptable != 100)
567 ROS_ERROR(
"Goal received, however map/goal/start are not ready. (%d/%d/%d)",
579 ROS_INFO(
"New goal received. Metric: (%.3f, %.3f, %.3f), Grid: (%d, %d, %d)",
587 switch (start_pose_status)
590 ROS_ERROR(
"You are on the edge of the world.");
600 switch (goal_pose_status)
603 ROS_ERROR(
"Given goal is not on the map.");
608 ROS_WARN(
"Oops! Temporary goal is in Rock! Reverting the temporary goal.");
622 ROS_INFO(
"Goal moved. Metric: (%.3f, %.3f, %.3f), Grid: (%d, %d, %d)",
628 if (e[0] != e_prev[0] || e[1] != e_prev[1] || e[2] != e_prev[2])
630 ROS_INFO(
"Goal reverted. Metric: (%.3f, %.3f, %.3f), Grid: (%d, %d, %d)",
639 const auto ts = boost::chrono::high_resolution_clock::now();
641 const auto tnow = boost::chrono::high_resolution_clock::now();
642 const float dur = boost::chrono::duration<float>(tnow - ts).count();
643 ROS_DEBUG(
"Cost estimation cache generated (%0.4f sec.)", dur);
646 "distance_map_init_dur", dur,
"second"));
648 "distance_map_update_dur", 0.0,
"second"));
669 sensor_msgs::PointCloud distance_map;
672 distance_map.channels.resize(1);
673 distance_map.channels[0].name =
"distance";
674 distance_map.points.reserve(1024);
675 distance_map.channels[0].values.reserve(1024);
683 if (cost == std::numeric_limits<float>::max())
687 point.z = cost / 500;
688 distance_map.points.push_back(point);
689 distance_map.channels[0].values.push_back(cost * k_dist);
697 nav_msgs::OccupancyGrid hysteresis_map;
698 hysteresis_map.header.frame_id =
map_header_.frame_id;
699 hysteresis_map.info.resolution =
map_info_.linear_resolution;
700 hysteresis_map.info.width =
map_info_.width;
701 hysteresis_map.info.height =
map_info_.height;
702 hysteresis_map.info.origin =
map_info_.origin;
715 cost = std::min(
cm_hyst_[p2], cost);
717 hysteresis_map.data[p[0] + p[1] *
map_info_.width] = cost;
727 nav_msgs::OccupancyGrid remembered_map;
728 remembered_map.header.frame_id =
map_header_.frame_id;
729 remembered_map.info.resolution =
map_info_.linear_resolution;
730 remembered_map.info.width =
map_info_.width;
731 remembered_map.info.height =
map_info_.height;
732 remembered_map.info.origin =
map_info_.origin;
737 remembered_map.data[p[0] + p[1] *
map_info_.width] =
757 path.poses.resize(1);
758 path.poses[0].header = path.header;
762 path.poses[0].pose =
goal_.pose;
771 path, std::numeric_limits<double>::quiet_NaN()));
782 const auto ts_cm_init_start = boost::chrono::high_resolution_clock::now();
785 const int map_update_x_min =
static_cast<int>(
msg->x);
786 const int map_update_x_max = std::max(
static_cast<int>(
msg->x +
msg->width) - 1, 0);
787 const int map_update_y_min =
static_cast<int>(
msg->y);
788 const int map_update_y_max = std::max(
static_cast<int>(
msg->y +
msg->height) - 1, 0);
790 if (
static_cast<size_t>(map_update_x_max) >=
map_info_.width ||
791 static_cast<size_t>(map_update_y_max) >=
map_info_.height ||
795 "Map update out of range (update range: %dx%dx%d, map range: %dx%dx%d)",
796 map_update_x_max, map_update_y_max,
msg->angle,
819 const int search_range_x_min = std::max(
822 const int search_range_x_max = std::min(
825 const int search_range_y_min = std::max(
828 const int search_range_y_max = std::min(
837 bool clear_hysteresis(
false);
841 static_cast<int>(
msg->x),
static_cast<int>(
msg->y),
static_cast<int>(
msg->yaw));
843 for (
Astar::Vec p(0, 0, 0); p[0] <
static_cast<int>(
msg->width); p[0]++)
845 for (p[1] = 0; p[1] <
static_cast<int>(
msg->height); p[1]++)
848 for (p[2] = 0; p[2] <
static_cast<int>(
msg->angle); p[2]++)
850 const size_t addr = ((p[2] *
msg->height) + p[1]) *
msg->width + p[0];
851 const char c =
msg->data[addr];
854 if (c == 100 && !clear_hysteresis &&
cm_hyst_[gp + p] == 0)
855 clear_hysteresis =
true;
862 for (p[2] = 0; p[2] <
static_cast<int>(
msg->angle); p[2]++)
864 const size_t addr = ((p[2] *
msg->height) + p[1]) *
msg->width + p[0];
865 const char c =
msg->data[addr];
881 const auto ts_cm_init_end = boost::chrono::high_resolution_clock::now();
882 const float ts_cm_init_dur = boost::chrono::duration<float>(ts_cm_init_end - ts_cm_init_start).count();
883 ROS_DEBUG(
"Costmaps updated (%.4f)", ts_cm_init_dur);
891 ROS_INFO(
"The previous path collides to the obstacle. Clearing hysteresis map.");
903 const auto ts = boost::chrono::high_resolution_clock::now();
910 const auto tnow = boost::chrono::high_resolution_clock::now();
911 const float dur = boost::chrono::duration<float>(tnow - ts).count();
912 ROS_DEBUG(
"Remembered costmap updated (%0.4f sec.)", dur);
932 const auto ts = boost::chrono::high_resolution_clock::now();
936 Astar::Vec(search_range_x_min, search_range_y_min, 0),
937 Astar::Vec(search_range_x_max, search_range_y_max, 0)));
938 const auto tnow = boost::chrono::high_resolution_clock::now();
939 const float dur = boost::chrono::duration<float>(tnow - ts).count();
940 ROS_DEBUG(
"Cost estimation cache updated (%0.4f sec.)", dur);
942 "distance_map_update_dur", dur,
"second"));
944 "distance_map_init_dur", 0.0,
"second"));
950 ROS_WARN(
"Negative cost value is detected. Limited to zero.");
952 ROS_DEBUG(
"Cost estimation cache search queue initial size: %lu, capacity: %lu",
964 void cbMapUpdate(
const costmap_cspace_msgs::CSpace3DUpdate::ConstPtr& msg)
986 void cbMap(
const costmap_cspace_msgs::CSpace3D::ConstPtr& msg)
989 ROS_INFO(
" linear_resolution %0.2f x (%dx%d) px",
msg->info.linear_resolution,
990 msg->info.width,
msg->info.height);
991 ROS_INFO(
" angular_resolution %0.2f x %d px",
msg->info.angular_resolution,
993 ROS_INFO(
" origin %0.3f m, %0.3f m, %0.3f rad",
994 msg->info.origin.position.x,
995 msg->info.origin.position.y,
1006 if (
map_info_.linear_resolution !=
msg->info.linear_resolution ||
1007 map_info_.angular_resolution !=
msg->info.angular_resolution)
1027 const Astar::Vec size3d(size[0], size[1], size[2]);
1028 const Astar::Vec size2d(size[0], size[1], 1);
1041 .resolution =
map_info_.linear_resolution,
1053 for (p[0] = 0; p[0] <
static_cast<int>(
map_info_.width); p[0]++)
1055 for (p[1] = 0; p[1] <
static_cast<int>(
map_info_.height); p[1]++)
1058 for (p[2] = 0; p[2] <
static_cast<int>(
map_info_.angle); p[2]++)
1060 const size_t addr = ((p[2] * size[1]) + p[1]) * size[0] + p[0];
1061 char c =
msg->data[addr];
1095 ROS_INFO(
"Applying retained map update");
1104 ROS_ERROR(
"Setting new goal is ignored since planner_3d is proceeding by tolerant_move action.");
1108 move_base_msgs::MoveBaseGoalConstPtr goal =
act_->acceptNewGoal();
1109 if (!
setGoal(goal->target_pose))
1110 act_->setAborted(move_base_msgs::MoveBaseResult(),
"Given goal is invalid.");
1115 if (
act_->isActive())
1117 ROS_ERROR(
"Setting new goal is ignored since planner_3d is proceeding by move_base action.");
1123 act_tolerant_->setAborted(planner_cspace_msgs::MoveWithToleranceResult(),
"Given goal is invalid.");
1128 geometry_msgs::PoseStamped
start;
1131 start.pose.orientation.x = 0.0;
1132 start.pose.orientation.y = 0.0;
1133 start.pose.orientation.z = 0.0;
1134 start.pose.orientation.w = 1.0;
1135 start.pose.position.x = 0;
1136 start.pose.position.y = 0;
1137 start.pose.position.z = 0;
1140 geometry_msgs::TransformStamped trans =
1170 nh_,
"costmap_update",
1173 nh_,
"move_base_simple/goal",
1183 nh_,
"forget_planning_cost",
1205 "path_velocity", 1,
true);
1209 pub_path_ = neonavigation_common::compat::advertise<nav_msgs::Path>(
1211 pnh_,
"path", 1,
true);
1222 double costmap_watchdog;
1223 pnh_.
param(
"costmap_watchdog", costmap_watchdog, 0.0);
1254 double remember_hit_prob, remember_miss_prob;
1255 pnh_.
param(
"remember_hit_prob", remember_hit_prob, 0.6);
1256 pnh_.
param(
"remember_miss_prob", remember_miss_prob, 0.3);
1270 ROS_ERROR(
"path_interpolation_resolution must be greater than or equal to grid_enumeration_resolution.");
1279 double pos_jump, yaw_jump;
1280 std::string jump_detect_frame;
1283 pnh_.
param(
"jump_detect_frame", jump_detect_frame, std::string(
"base_link"));
1295 ROS_WARN(
"planner_3d: Experimental fast_map_update is enabled. ");
1300 "planner_3d: ~/debug_mode parameter and ~/debug topic are deprecated. "
1301 "Use ~/distance_map, ~/hysteresis_map, and ~/remembered_map topics instead.");
1304 bool print_planning_duration;
1305 pnh_.
param(
"print_planning_duration", print_planning_duration,
false);
1306 if (print_planning_duration)
1316 int queue_size_limit;
1317 pnh_.
param(
"queue_size_limit", queue_size_limit, 0);
1321 pnh_.
param(
"num_threads", num_threads, 1);
1322 omp_set_num_threads(num_threads);
1325 pnh_.
param(
"num_search_task", num_task, num_threads * 16);
1332 status_.status = planner_cspace_msgs::PlannerStatus::DONE;
1355 const int previous_range =
range_;
1371 const bool reset_required = force_reset || (previous_range !=
range_);
1390 freq_ = config.freq;
1459 .resolution =
map_info_.linear_resolution,
1470 start_pose_predictor_config.
lin_vel_ = config.max_vel;
1471 start_pose_predictor_config.
ang_vel_ = config.max_ang_vel;
1472 start_pose_predictor_config.
dist_stop_ = config.dist_stop_to_previous_path;
1495 const bool costmap_updated =
last_costmap_ != prev_map_update_stamp;
1522 const float len = std::hypot(
1527 float yaw_diff = yaw - sw_yaw;
1528 yaw_diff = std::atan2(std::sin(yaw_diff), std::cos(yaw_diff));
1551 bool has_costmap(
false);
1557 costmap_delay.
toSec(),
1562 "Navigation is stopping since the costmap is too old (costmap: %0.3f)",
1564 status_.error = planner_cspace_msgs::PlannerStatus::DATA_MISSING;
1583 if (
act_->isActive())
1585 move_base_msgs::MoveBaseFeedback feedback;
1586 feedback.base_position =
start_;
1587 act_->publishFeedback(feedback);
1592 planner_cspace_msgs::MoveWithToleranceFeedback feedback;
1593 feedback.base_position =
start_;
1598 if (
status_.status == planner_cspace_msgs::PlannerStatus::FINISHING)
1605 float yaw_diff = yaw_s - yaw_g;
1606 if (yaw_diff > M_PI)
1607 yaw_diff -= M_PI * 2.0;
1608 else if (yaw_diff < -M_PI)
1609 yaw_diff += M_PI * 2.0;
1610 if (std::abs(yaw_diff) <
1613 status_.status = planner_cspace_msgs::PlannerStatus::DONE;
1619 if (
act_->isActive())
1620 act_->setSucceeded(move_base_msgs::MoveBaseResult(),
"Goal reached.");
1622 act_tolerant_->setSucceeded(planner_cspace_msgs::MoveWithToleranceResult(),
"Goal reached.");
1631 bool skip_path_planning =
false;
1634 status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1638 status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1639 status_.status = planner_cspace_msgs::PlannerStatus::DONE;
1645 if (
act_->isActive())
1647 move_base_msgs::MoveBaseResult(),
"Goal is in Rock");
1650 planner_cspace_msgs::MoveWithToleranceResult(),
"Goal is in Rock");
1655 skip_path_planning =
true;
1658 status_.error = planner_cspace_msgs::PlannerStatus::IN_ROCK;
1662 status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1667 status_.error = planner_cspace_msgs::PlannerStatus::GOING_WELL;
1670 if (skip_path_planning)
1676 nav_msgs::Path path;
1678 path.header.stamp = now;
1686 sw_pos_ = path.poses[sw_index];
1694 status_.error = planner_cspace_msgs::PlannerStatus::GOING_WELL;
1744 ROS_INFO(
"Planned path has switchback. Planner will stop until: %f at the latest.", next_replan_time.
toSec());
1757 geometry_msgs::PoseStamped p;
1767 geometry_msgs::PoseStamped p(
goal_);
1774 int g_tolerance_lin, g_tolerance_ang;
1792 return (remain.
sqlen() <= g_tolerance_lin * g_tolerance_lin && std::abs(remain[2]) <= g_tolerance_ang);
1802 std::vector<Astar::VecWithCost>& result_start_poses)
1804 result_start_poses.clear();
1810 start_metric.position.x, start_metric.position.y,
tf2::getYaw(start_metric.orientation));
1811 Astar::Vec start_grid(
static_cast<int>(std::floor(sf[0])),
static_cast<int>(std::floor(sf[1])), std::lround(sf[2]));
1818 ROS_ERROR(
"You are on the edge of the world.");
1827 ROS_DEBUG(
"Start grid is moved to (%d, %d, %d) from (%d, %d, %d) by start pose predictor.",
1828 expected_start_grid[0], expected_start_grid[1], expected_start_grid[2],
1829 start_grid[0], start_grid[1], start_grid[2]);
1841 const int x_cand[] = {0, ((sf[0] - start_grid[0]) < 0.5 ? -1 : 1)};
1842 const int y_cand[] = {0, ((sf[1] - start_grid[1]) < 0.5 ? -1 : 1)};
1843 for (
const int x : x_cand)
1845 for (
const int y : y_cand)
1852 if (subpx.
sqlen() > 1.0)
1858 const double cost = std::hypot(diff[0] *
ec_[0], diff[1] *
ec_[0]) +
1864 else if (
cm_[start_grid] < 100)
1868 if (result_start_poses.empty())
1870 const Astar::Vec original_start_grid = start_grid;
1873 ROS_WARN(
"Oops! You are in Rock!");
1876 ROS_INFO(
"Start grid is moved to (%d, %d, %d) from (%d, %d, %d) by relocation.",
1877 start_grid[0], start_grid[1], start_grid[2],
1878 original_start_grid[0], original_start_grid[1], original_start_grid[2]);
1891 bool makePlan(
const geometry_msgs::Pose& start_metric,
const geometry_msgs::Pose& end_metric,
1892 nav_msgs::Path& path,
bool hyst)
1898 std::vector<Astar::VecWithCost> starts;
1902 status_.error = planner_cspace_msgs::PlannerStatus::IN_ROCK;
1915 ROS_INFO(
"Robot reached near the goal.");
1916 act_tolerant_->setSucceeded(planner_cspace_msgs::MoveWithToleranceResult(),
1917 "Goal reached (Continuous movement mode).");
1922 status_.status = planner_cspace_msgs::PlannerStatus::FINISHING;
1935 if (initial_2dof_cost == std::numeric_limits<float>::max() ||
cm_[end_grid] >= 100)
1937 status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1948 const auto ts = boost::chrono::high_resolution_clock::now();
1949 const auto cb_progress =
1950 [
this, ts, start_grid, end_grid](
const std::list<Astar::Vec>& path_grid,
const SearchStats& stats) ->
bool
1952 const auto tnow = boost::chrono::high_resolution_clock::now();
1953 const auto tdiff = boost::chrono::duration<float>(tnow - ts).count();
1958 "Search aborted due to timeout. "
1959 "search_timeout_abort may be too small or planner_3d may have a bug: "
1960 "s=(%d, %d, %d), g=(%d, %d, %d), tdiff=%0.4f, "
1962 "num_search_queue=%lu, "
1963 "num_prev_updates=%lu, "
1964 "num_total_updates=%lu, ",
1965 start_grid[0], start_grid[1], start_grid[2], end_grid[0], end_grid[1], end_grid[2], tdiff,
1966 stats.num_loop, stats.num_search_queue, stats.num_prev_updates, stats.num_total_updates);
1969 ROS_WARN(
"Search timed out (%0.4f sec.)", tdiff);
1974 std::list<Astar::Vec> path_grid;
1975 bool is_goal_same_as_start =
false;
1976 for (
const auto s : starts)
1978 if (
s.v_ == end_grid)
1980 ROS_DEBUG(
"The start grid is the same as the end grid. Path planning skipped.");
1981 path_grid.push_back(end_grid);
1982 is_goal_same_as_start =
true;
1986 if (!is_goal_same_as_start && !
as_.
search(starts, end_grid, path_grid,
1993 ROS_WARN(
"Path plan failed (goal unreachable)");
1994 status_.error = planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND;
1998 const auto tnow = boost::chrono::high_resolution_clock::now();
1999 const float dur = boost::chrono::duration<float>(tnow - ts).count();
2000 ROS_DEBUG(
"Path found (%0.4f sec.)", dur);
2006 geometry_msgs::PoseArray poses;
2007 poses.header = path.header;
2008 for (
const auto& p : path_grid)
2017 const std::list<Astar::Vecf> path_interpolated =
model_->interpolatePath(path_grid);
2023 const auto ts = boost::chrono::high_resolution_clock::now();
2024 std::unordered_map<Astar::Vec, bool, Astar::Vec> path_points;
2027 const int path_range =
range_ + max_dist + expand_dist + 5;
2031 for (
d[0] = -path_range;
d[0] <= path_range;
d[0]++)
2033 for (
d[1] = -path_range;
d[1] <= path_range;
d[1]++)
2037 if ((
unsigned int)point[0] >= (
unsigned int)
map_info_.width ||
2038 (
unsigned int)point[1] >= (
unsigned int)
map_info_.height)
2040 path_points[point] =
true;
2046 for (
auto& ps : path_points)
2049 float d_min = std::numeric_limits<float>::max();
2050 auto it_prev = path_interpolated.cbegin();
2051 for (
auto it = path_interpolated.cbegin(); it != path_interpolated.cend(); it++)
2055 int yaw = std::lround((*it)[2]) %
map_info_.angle;
2056 int yaw_prev = std::lround((*it_prev)[2]) %
map_info_.angle;
2061 if (yaw == p[2] || yaw_prev == p[2])
2071 d_min = std::max(expand_dist, std::min(expand_dist + max_dist, d_min));
2072 cm_hyst_[p] = std::lround((d_min - expand_dist) * 100.0 / max_dist);
2076 const auto tnow = boost::chrono::high_resolution_clock::now();
2077 const float dur = boost::chrono::duration<float>(tnow - ts).count();
2078 ROS_DEBUG(
"Hysteresis map generated (%0.4f sec.)", dur);
2095 ROS_WARN(
"Not ready to update temporary escape goal");
2101 ROS_INFO(
"Skipping temporary goal update during switch back");
2111 ROS_WARN(
"No valid temporary escape goal");
2115 ROS_INFO(
"Temporary goal (%d, %d, %d)", te[0], te[1], te[2]);
2125 const Astar::Vec s(start_grid[0], start_grid[1], 0);
2128 ROS_ERROR(
"Crowd escape is disabled on the edge of the world.");
2134 const auto ts = boost::chrono::high_resolution_clock::now();
2140 const auto tnow = boost::chrono::high_resolution_clock::now();
2141 const float dur = boost::chrono::duration<float>(tnow - ts).count();
2142 ROS_DEBUG(
"Cost estimation cache for static map updated (%0.4f sec.)", dur);
2144 "distance_map_static_update_dur", dur,
"second"));
2146 "distance_map_static_init_dur", 0.0,
"second"));
2152 const Astar::Vec local_range(local_width, local_width, 0);
2153 const Astar::Vec local_size(local_width + 1, local_width + 1, 1);
2162 .resolution =
map_info_.linear_resolution,
2173 float cost_min = std::numeric_limits<float>::max();
2181 const int sqlen =
d.sqlen();
2182 if ((
d[0] == 0 &&
d[1] == 0) || sqlen > esc_range_sq || sqlen < esc_range_min_sq)
2187 Astar::Vec te(start_grid[0] +
d[0], start_grid[1] +
d[1], 0);
2188 if ((
unsigned int)te[0] >= (
unsigned int)
map_info_.width ||
2189 (
unsigned int)te[1] >= (
unsigned int)
map_info_.height)
2198 if (cost >= cost_min)
2204 if (
arrivable_map_[te - local_origin] == std::numeric_limits<float>::max())
2209 if (te[0] == g_orig[0] && te[1] == g_orig[1] &&
cm_[g_orig] < 100)
2212 ROS_INFO(
"Original goal is reachable. Back to the original goal.");
2220 float grad[2] = {0, 0};
2223 for (
d[0] = -1;
d[0] <= 1;
d[0]++)
2225 if (
d[0] == 0 &&
d[1] == 0)
2230 const auto p = te +
d;
2232 if (cost2 == std::numeric_limits<float>::max())
2236 const float cost_diff = cost2 - cost;
2237 grad[0] += -cost_diff *
d[0];
2238 grad[1] += -cost_diff *
d[1];
2241 if (grad[0] == 0 && grad[1] == 0)
2245 const float yaw = std::atan2(grad[1], grad[0]);
2246 te[2] =
static_cast<int>(yaw /
map_info_.angular_resolution);
2254 if (cost < cost_min)
2261 if (cost_min == std::numeric_limits<float>::max())
2263 ROS_WARN(
"No valid temporary escape goal");
2268 ROS_INFO(
"Temporary goal (%d, %d, %d)",
2269 te_out[0], te_out[1], te_out[2]);
2279 geometry_msgs::Pose p_prev;
2281 bool dir_set(
false);
2282 bool dir_prev(
false);
2283 for (
auto it = path.poses.begin(); it != path.poses.end(); ++it)
2285 const auto& p = *it;
2288 const float x_diff = p.pose.position.x - p_prev.position.x;
2289 const float y_diff = p.pose.position.y - p_prev.position.y;
2290 const float len_sq = std::pow(y_diff, 2) + std::pow(x_diff, 2);
2291 if (len_sq > std::pow(0.001
f, 2))
2293 const float yaw =
tf2::getYaw(p.pose.orientation);
2294 const bool dir = (std::cos(yaw) * x_diff + std::sin(yaw) * y_diff < 0);
2296 if (dir_set && (dir_prev ^ dir))
2298 return std::distance(path.poses.begin(), it);
2314 case planner_cspace_msgs::PlannerStatus::GOING_WELL:
2315 stat.
summary(diagnostic_msgs::DiagnosticStatus::OK,
"Going well.");
2317 case planner_cspace_msgs::PlannerStatus::IN_ROCK:
2318 stat.
summary(diagnostic_msgs::DiagnosticStatus::ERROR,
"The robot is in rock.");
2320 case planner_cspace_msgs::PlannerStatus::PATH_NOT_FOUND:
2321 stat.
summary(diagnostic_msgs::DiagnosticStatus::ERROR,
"Path not found.");
2323 case planner_cspace_msgs::PlannerStatus::DATA_MISSING:
2324 stat.
summary(diagnostic_msgs::DiagnosticStatus::ERROR,
"Required data is missing.");
2326 case planner_cspace_msgs::PlannerStatus::INTERNAL_ERROR:
2327 stat.
summary(diagnostic_msgs::DiagnosticStatus::ERROR,
"Planner internal error.");
2330 stat.
summary(diagnostic_msgs::DiagnosticStatus::ERROR,
"Unknown error.");