00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <mir_dwb_critics/path_progress.h>
00035 #include <nav_grid/coordinate_conversion.h>
00036 #include <pluginlib/class_list_macros.h>
00037 #include <nav_2d_utils/path_ops.h>
00038 #include <vector>
00039
00040 namespace mir_dwb_critics {
00041 bool PathProgressCritic::prepare(const geometry_msgs::Pose2D &pose, const nav_2d_msgs::Twist2D &vel,
00042 const geometry_msgs::Pose2D &goal,
00043 const nav_2d_msgs::Path2D &global_plan) {
00044 dwb_critics::MapGridCritic::reset();
00045
00046 unsigned int local_goal_x, local_goal_y;
00047 if (!getGoalPose(pose, global_plan, local_goal_x, local_goal_y, desired_angle_)) {
00048 return false;
00049 }
00050
00051
00052 cell_values_.setValue(local_goal_x, local_goal_y, 0.0);
00053 queue_->enqueueCell(local_goal_x, local_goal_y);
00054
00055 propogateManhattanDistances();
00056
00057 return true;
00058 }
00059
00060 void PathProgressCritic::onInit() {
00061 dwb_critics::MapGridCritic::onInit();
00062 critic_nh_.param("xy_local_goal_tolerance", xy_local_goal_tolerance_, 0.20);
00063 critic_nh_.param("angle_threshold", angle_threshold_, M_PI_4);
00064 critic_nh_.param("heading_scale", heading_scale_, 1.0);
00065
00066
00067 heading_scale_ /= getScale();
00068 }
00069
00070 void PathProgressCritic::reset() {
00071 reached_intermediate_goals_.clear();
00072 }
00073
00074 double PathProgressCritic::scoreTrajectory(const dwb_msgs::Trajectory2D &traj) {
00075 double position_score = MapGridCritic::scoreTrajectory(traj);
00076 double heading_diff = fabs(remainder(traj.poses.back().theta - desired_angle_, 2 * M_PI));
00077 double heading_score = heading_diff * heading_diff;
00078
00079 return position_score + heading_scale_ * heading_score;
00080 }
00081
00082 bool PathProgressCritic::getGoalPose(const geometry_msgs::Pose2D &robot_pose, const nav_2d_msgs::Path2D &global_plan,
00083 unsigned int &x, unsigned int &y, double &desired_angle) {
00084 const nav_core2::Costmap &costmap = *costmap_;
00085 const nav_grid::NavGridInfo &info = costmap.getInfo();
00086
00087 if (global_plan.poses.empty()) {
00088 ROS_ERROR_NAMED("PathProgressCritic", "The global plan was empty.");
00089 return false;
00090 }
00091
00092 std::vector<geometry_msgs::Pose2D> plan = nav_2d_utils::adjustPlanResolution(global_plan, info.resolution).poses;
00093
00094
00095 unsigned int start_index = 0;
00096 double distance_to_start = std::numeric_limits<double>::infinity();
00097 bool started_path = false;
00098 for (unsigned int i = 0; i < plan.size(); i++) {
00099 double g_x = plan[i].x;
00100 double g_y = plan[i].y;
00101 unsigned int map_x, map_y;
00102 if (worldToGridBounded(info, g_x, g_y, map_x, map_y)
00103 && costmap(map_x, map_y) != nav_core2::Costmap::NO_INFORMATION) {
00104
00105 double distance = nav_2d_utils::poseDistance(plan[i], robot_pose);
00106 if (distance_to_start > distance) {
00107 start_index = i;
00108 distance_to_start = distance;
00109 started_path = true;
00110 } else {
00111
00112
00113 break;
00114 }
00115 } else if (started_path) {
00116
00117 break;
00118 }
00119
00120 }
00121
00122 if (!started_path) {
00123 ROS_ERROR_NAMED("PathProgressCritic", "None of the points of the global plan were in the local costmap.");
00124 return false;
00125 }
00126
00127
00128 unsigned int last_valid_index = start_index;
00129 for (unsigned int i = start_index + 1; i < plan.size(); i++) {
00130 double g_x = plan[i].x;
00131 double g_y = plan[i].y;
00132 unsigned int map_x, map_y;
00133 if (worldToGridBounded(info, g_x, g_y, map_x, map_y)
00134 && costmap(map_x, map_y) != nav_core2::Costmap::NO_INFORMATION) {
00135
00136 last_valid_index = i;
00137 } else {
00138
00139 break;
00140 }
00141 }
00142
00143
00144
00145 unsigned int goal_index = start_index;
00146
00147 while (goal_index < last_valid_index) {
00148 goal_index = getGoalIndex(plan, start_index, last_valid_index);
00149
00150
00151 bool goal_already_reached = false;
00152 for (auto &reached_intermediate_goal : reached_intermediate_goals_) {
00153 double distance = nav_2d_utils::poseDistance(reached_intermediate_goal, plan[goal_index]);
00154 if (distance < xy_local_goal_tolerance_) {
00155 goal_already_reached = true;
00156
00157
00158 for (start_index = goal_index; start_index <= last_valid_index; ++start_index) {
00159 distance = nav_2d_utils::poseDistance(reached_intermediate_goal, plan[start_index]);
00160 if (distance >= xy_local_goal_tolerance_) {
00161 break;
00162 }
00163 }
00164 break;
00165 }
00166 }
00167 if (!goal_already_reached) {
00168
00169 double distance = nav_2d_utils::poseDistance(plan[goal_index], robot_pose);
00170 if (distance < xy_local_goal_tolerance_) {
00171
00172 reached_intermediate_goals_.push_back(plan[goal_index]);
00173 ROS_DEBUG_NAMED("PathProgressCritic", "Number of reached_intermediate goals: %zu", reached_intermediate_goals_.size());
00174 } else {
00175
00176 break;
00177 }
00178 }
00179 }
00180 if (start_index > goal_index)
00181 start_index = goal_index;
00182 ROS_ASSERT(goal_index <= last_valid_index);
00183
00184
00185 worldToGridBounded(info, plan[goal_index].x, plan[goal_index].y, x, y);
00186 desired_angle = plan[start_index].theta;
00187 return true;
00188 }
00189
00190 unsigned int PathProgressCritic::getGoalIndex(const std::vector<geometry_msgs::Pose2D> &plan,
00191 unsigned int start_index,
00192 unsigned int last_valid_index) const {
00193 if (start_index >= last_valid_index)
00194 return last_valid_index;
00195
00196 unsigned int goal_index = start_index;
00197 const double start_direction_x = plan[start_index + 1].x - plan[start_index].x;
00198 const double start_direction_y = plan[start_index + 1].y - plan[start_index].y;
00199 if (fabs(start_direction_x) > 1e-9 || fabs(start_direction_y) > 1e-9) {
00200 double start_angle = atan2(start_direction_y, start_direction_x);
00201
00202 for (unsigned int i = start_index + 1; i <= last_valid_index; ++i) {
00203 const double current_direction_x = plan[i].x - plan[i - 1].x;
00204 const double current_direction_y = plan[i].y - plan[i - 1].y;
00205 if (fabs(current_direction_x) > 1e-9 || fabs(current_direction_y) > 1e-9) {
00206 double current_angle = atan2(current_direction_y, current_direction_x);
00207
00208
00209 if (fabs(remainder(start_angle - current_angle, 2 * M_PI)) > angle_threshold_)
00210 break;
00211
00212 goal_index = i;
00213 }
00214 }
00215 }
00216 return goal_index;
00217 }
00218
00219 }
00220
00221 PLUGINLIB_EXPORT_CLASS(mir_dwb_critics::PathProgressCritic, dwb_local_planner::TrajectoryCritic)