path_progress.cpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2019, DFKI GmbH
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
37 #include <nav_2d_utils/path_ops.h>
38 #include <vector>
39 
40 namespace mir_dwb_critics {
41 bool PathProgressCritic::prepare(const geometry_msgs::Pose2D &pose, const nav_2d_msgs::Twist2D &vel,
42  const geometry_msgs::Pose2D &goal,
43  const nav_2d_msgs::Path2D &global_plan) {
45 
46  unsigned int local_goal_x, local_goal_y;
47  if (!getGoalPose(pose, global_plan, local_goal_x, local_goal_y, desired_angle_)) {
48  return false;
49  }
50 
51  // Enqueue just the last pose
52  cell_values_.setValue(local_goal_x, local_goal_y, 0.0);
53  queue_->enqueueCell(local_goal_x, local_goal_y);
54 
56 
57  return true;
58 }
59 
62  critic_nh_.param("xy_local_goal_tolerance", xy_local_goal_tolerance_, 0.20);
63  critic_nh_.param("angle_threshold", angle_threshold_, M_PI_4);
64  critic_nh_.param("heading_scale", heading_scale_, 1.0);
65 
66  // divide heading scale by position scale because the sum will be multiplied by scale again
68 }
69 
72 }
73 
74 double PathProgressCritic::scoreTrajectory(const dwb_msgs::Trajectory2D &traj) {
75  double position_score = MapGridCritic::scoreTrajectory(traj);
76  double heading_diff = fabs(remainder(traj.poses.back().theta - desired_angle_, 2 * M_PI));
77  double heading_score = heading_diff * heading_diff;
78 
79  return position_score + heading_scale_ * heading_score;
80 }
81 
82 bool PathProgressCritic::getGoalPose(const geometry_msgs::Pose2D &robot_pose, const nav_2d_msgs::Path2D &global_plan,
83  unsigned int &x, unsigned int &y, double &desired_angle) {
85  const nav_grid::NavGridInfo &info = costmap.getInfo();
86 
87  if (global_plan.poses.empty()) {
88  ROS_ERROR_NAMED("PathProgressCritic", "The global plan was empty.");
89  return false;
90  }
91 
92  std::vector<geometry_msgs::Pose2D> plan = nav_2d_utils::adjustPlanResolution(global_plan, info.resolution).poses;
93 
94  // find the "start pose", i.e. the pose on the plan closest to the robot that is also on the local map
95  unsigned int start_index = 0;
96  double distance_to_start = std::numeric_limits<double>::infinity();
97  bool started_path = false;
98  for (unsigned int i = 0; i < plan.size(); i++) {
99  double g_x = plan[i].x;
100  double g_y = plan[i].y;
101  unsigned int map_x, map_y;
102  if (worldToGridBounded(info, g_x, g_y, map_x, map_y)
103  && costmap(map_x, map_y) != nav_core2::Costmap::NO_INFORMATION) {
104  // Still on the costmap. Continue.
105  double distance = nav_2d_utils::poseDistance(plan[i], robot_pose);
106  if (distance_to_start > distance) {
107  start_index = i;
108  distance_to_start = distance;
109  started_path = true;
110  } else {
111  // Plan is going away from the robot again. It's possible that it comes back and we would find a pose that's
112  // even closer to the robot, but then we would skip over parts of the plan.
113  break;
114  }
115  } else if (started_path) {
116  // Off the costmap after being on the costmap.
117  break;
118  }
119  // else, we have not yet found a point on the costmap, so we just continue
120  }
121 
122  if (!started_path) {
123  ROS_ERROR_NAMED("PathProgressCritic", "None of the points of the global plan were in the local costmap.");
124  return false;
125  }
126 
127  // find the "last valid pose", i.e. the last pose on the plan after the start pose that is still on the local map
128  unsigned int last_valid_index = start_index;
129  for (unsigned int i = start_index + 1; i < plan.size(); i++) {
130  double g_x = plan[i].x;
131  double g_y = plan[i].y;
132  unsigned int map_x, map_y;
133  if (worldToGridBounded(info, g_x, g_y, map_x, map_y)
134  && costmap(map_x, map_y) != nav_core2::Costmap::NO_INFORMATION) {
135  // Still on the costmap. Continue.
136  last_valid_index = i;
137  } else {
138  // Off the costmap after being on the costmap.
139  break;
140  }
141  }
142 
143  // find the "goal pose" by walking along the plan as long as each step leads far enough away from the starting point,
144  // i.e. is within angle_threshold_ of the starting direction.
145  unsigned int goal_index = start_index;
146 
147  while (goal_index < last_valid_index) {
148  goal_index = getGoalIndex(plan, start_index, last_valid_index);
149 
150  // check if goal already reached
151  bool goal_already_reached = false;
152  for (auto &reached_intermediate_goal : reached_intermediate_goals_) {
153  double distance = nav_2d_utils::poseDistance(reached_intermediate_goal, plan[goal_index]);
154  if (distance < xy_local_goal_tolerance_) {
155  goal_already_reached = true;
156  // choose a new start_index by walking along the plan until we're outside xy_local_goal_tolerance_ and try again
157  // (start_index is now > goal_index)
158  for (start_index = goal_index; start_index <= last_valid_index; ++start_index) {
159  distance = nav_2d_utils::poseDistance(reached_intermediate_goal, plan[start_index]);
160  if (distance >= xy_local_goal_tolerance_) {
161  break;
162  }
163  }
164  break;
165  }
166  }
167  if (!goal_already_reached) {
168  // new goal not in reached_intermediate_goals_
169  double distance = nav_2d_utils::poseDistance(plan[goal_index], robot_pose);
170  if (distance < xy_local_goal_tolerance_) {
171  // the robot has currently reached the goal
172  reached_intermediate_goals_.push_back(plan[goal_index]);
173  ROS_DEBUG_NAMED("PathProgressCritic", "Number of reached_intermediate goals: %zu", reached_intermediate_goals_.size());
174  } else {
175  // we've found a new goal!
176  break;
177  }
178  }
179  }
180  if (start_index > goal_index)
181  start_index = goal_index;
182  ROS_ASSERT(goal_index <= last_valid_index);
183 
184  // save goal in x, y
185  worldToGridBounded(info, plan[goal_index].x, plan[goal_index].y, x, y);
186  desired_angle = plan[start_index].theta;
187  return true;
188 }
189 
190 unsigned int PathProgressCritic::getGoalIndex(const std::vector<geometry_msgs::Pose2D> &plan,
191  unsigned int start_index,
192  unsigned int last_valid_index) const {
193  if (start_index >= last_valid_index)
194  return last_valid_index;
195 
196  unsigned int goal_index = start_index;
197  const double start_direction_x = plan[start_index + 1].x - plan[start_index].x;
198  const double start_direction_y = plan[start_index + 1].y - plan[start_index].y;
199  if (fabs(start_direction_x) > 1e-9 || fabs(start_direction_y) > 1e-9) { // make sure that atan2 is defined
200  double start_angle = atan2(start_direction_y, start_direction_x);
201 
202  for (unsigned int i = start_index + 1; i <= last_valid_index; ++i) {
203  const double current_direction_x = plan[i].x - plan[i - 1].x;
204  const double current_direction_y = plan[i].y - plan[i - 1].y;
205  if (fabs(current_direction_x) > 1e-9 || fabs(current_direction_y) > 1e-9) {
206  double current_angle = atan2(current_direction_y, current_direction_x);
207 
208  // goal pose is found if plan doesn't point far enough away from the starting point
209  if (fabs(remainder(start_angle - current_angle, 2 * M_PI)) > angle_threshold_)
210  break;
211 
212  goal_index = i;
213  }
214  }
215  }
216  return goal_index;
217 }
218 
219 } // namespace mir_dwb_critics
220 
nav_core2::BasicCostmap costmap
TFSIMD_FORCE_INLINE tfScalar distance(const Vector3 &v) const
bool prepare(const geometry_msgs::Pose2D &pose, const nav_2d_msgs::Twist2D &vel, const geometry_msgs::Pose2D &goal, const nav_2d_msgs::Path2D &global_plan) override
unsigned int getGoalIndex(const std::vector< geometry_msgs::Pose2D > &plan, unsigned int start_index, unsigned int last_valid_index) const
static const unsigned char NO_INFORMATION
double scoreTrajectory(const dwb_msgs::Trajectory2D &traj) override
double getScale() const override
#define ROS_DEBUG_NAMED(name,...)
double poseDistance(const geometry_msgs::Pose2D &pose0, const geometry_msgs::Pose2D &pose1)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
nav_core2::Costmap::Ptr costmap_
void setValue(const unsigned int x, const unsigned int y, const T &value) override
nav_2d_msgs::Path2D adjustPlanResolution(const nav_2d_msgs::Path2D &global_plan_in, double resolution)
bool getGoalPose(const geometry_msgs::Pose2D &robot_pose, const nav_2d_msgs::Path2D &global_plan, unsigned int &x, unsigned int &y, double &desired_angle)
#define ROS_ERROR_NAMED(name,...)
Calculates an intermediate goal along the global path and scores trajectories on the distance to that...
Definition: path_progress.h:50
std::shared_ptr< MapGridQueue > queue_
#define ROS_ASSERT(cond)
nav_grid::VectorNavGrid< double > cell_values_
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
std::vector< geometry_msgs::Pose2D > reached_intermediate_goals_
Definition: path_progress.h:76
bool worldToGridBounded(const NavGridInfo &info, double wx, double wy, unsigned int &mx, unsigned int &my)


mir_dwb_critics
Author(s): Martin Günther
autogenerated on Wed May 8 2019 02:38:50