|
18 | 18 | #include "angles/angles.h"
|
19 | 19 | #include "nav2_core/controller_exceptions.hpp"
|
20 | 20 | #include "nav2_util/geometry_utils.hpp"
|
| 21 | +#include "nav2_util/controller_utils.hpp" |
21 | 22 | #include "nav2_graceful_controller/graceful_controller.hpp"
|
22 | 23 | #include "nav2_costmap_2d/costmap_filters/filter_values.hpp"
|
23 | 24 |
|
@@ -195,46 +196,38 @@ geometry_msgs::msg::TwistStamped GracefulController::computeVelocityCommands(
|
195 | 196 | // Else, fall through and see if we should follow control law longer
|
196 | 197 | }
|
197 | 198 |
|
198 |
| - // Precompute distance to candidate poses |
| 199 | + // Find a valid target pose and its trajectory |
| 200 | + nav_msgs::msg::Path local_plan; |
| 201 | + geometry_msgs::msg::PoseStamped target_pose; |
| 202 | + |
| 203 | + double dist_to_target; |
199 | 204 | std::vector<double> target_distances;
|
200 | 205 | computeDistanceAlongPath(transformed_plan.poses, target_distances);
|
201 | 206 |
|
202 |
| - // Work back from the end of plan to find valid target pose |
| 207 | + bool is_first_iteration = true; |
203 | 208 | for (int i = transformed_plan.poses.size() - 1; i >= 0; --i) {
|
204 |
| - // Underlying control law needs a single target pose, which should: |
205 |
| - // * Be as far away as possible from the robot (for smoothness) |
206 |
| - // * But no further than the max_lookahed_ distance |
207 |
| - // * Be feasible to reach in a collision free manner |
208 |
| - geometry_msgs::msg::PoseStamped target_pose = transformed_plan.poses[i]; |
209 |
| - double dist_to_target = target_distances[i]; |
210 |
| - |
211 |
| - // Continue if target_pose is too far away from robot |
212 |
| - if (dist_to_target > params_->max_lookahead) {continue;} |
213 |
| - |
214 |
| - if (dist_to_goal < params_->max_lookahead) { |
215 |
| - if (params_->prefer_final_rotation) { |
216 |
| - // Avoid instability and big sweeping turns at the end of paths by |
217 |
| - // ignoring final heading |
218 |
| - double yaw = std::atan2(target_pose.pose.position.y, target_pose.pose.position.x); |
219 |
| - target_pose.pose.orientation = nav2_util::geometry_utils::orientationAroundZAxis(yaw); |
220 |
| - } |
221 |
| - } else if (dist_to_target < params_->min_lookahead) { |
222 |
| - // Make sure target is far enough away to avoid instability |
223 |
| - break; |
224 |
| - } |
225 |
| - |
226 |
| - // Flip the orientation of the motion target if the robot is moving backwards |
227 |
| - bool reversing = false; |
228 |
| - if (params_->allow_backward && target_pose.pose.position.x < 0.0) { |
229 |
| - reversing = true; |
230 |
| - target_pose.pose.orientation = nav2_util::geometry_utils::orientationAroundZAxis( |
231 |
| - tf2::getYaw(target_pose.pose.orientation) + M_PI); |
| 209 | + if (is_first_iteration) { |
| 210 | + // Calculate target pose through lookahead interpolation to get most accurate |
| 211 | + // lookahead point, if possible |
| 212 | + dist_to_target = params_->max_lookahead; |
| 213 | + // Interpolate after goal false for graceful controller |
| 214 | + // Requires interpolating the orientation which is not yet implemented |
| 215 | + // Updates dist_to_target for target_pose returned if using the point on the path |
| 216 | + target_pose = nav2_util::getLookAheadPoint(dist_to_target, transformed_plan, false); |
| 217 | + is_first_iteration = false; |
| 218 | + } else { |
| 219 | + // Underlying control law needs a single target pose, which should: |
| 220 | + // * Be as far away as possible from the robot (for smoothness) |
| 221 | + // * But no further than the max_lookahed_ distance |
| 222 | + // * Be feasible to reach in a collision free manner |
| 223 | + dist_to_target = target_distances[i]; |
| 224 | + target_pose = transformed_plan.poses[i]; |
232 | 225 | }
|
233 | 226 |
|
234 |
| - // Actually simulate our path |
235 |
| - nav_msgs::msg::Path local_plan; |
236 |
| - if (simulateTrajectory(target_pose, costmap_transform, local_plan, cmd_vel, reversing)) { |
237 |
| - // Successfully simulated to target_pose - compute velocity at this moment |
| 227 | + // Compute velocity at this moment if valid target pose is found |
| 228 | + if (validateTargetPose( |
| 229 | + target_pose, dist_to_target, dist_to_goal, local_plan, costmap_transform, cmd_vel)) |
| 230 | + { |
238 | 231 | // Publish the selected target_pose
|
239 | 232 | motion_target_pub_->publish(target_pose);
|
240 | 233 | // Publish marker for slowdown radius around motion target for debugging / visualization
|
@@ -283,6 +276,49 @@ void GracefulController::setSpeedLimit(
|
283 | 276 | }
|
284 | 277 | }
|
285 | 278 |
|
| 279 | +bool GracefulController::validateTargetPose( |
| 280 | + geometry_msgs::msg::PoseStamped & target_pose, |
| 281 | + double dist_to_target, |
| 282 | + double dist_to_goal, |
| 283 | + nav_msgs::msg::Path & trajectory, |
| 284 | + geometry_msgs::msg::TransformStamped & costmap_transform, |
| 285 | + geometry_msgs::msg::TwistStamped & cmd_vel) |
| 286 | +{ |
| 287 | + // Continue if target_pose is too far away from robot |
| 288 | + if (dist_to_target > params_->max_lookahead) { |
| 289 | + return false; |
| 290 | + } |
| 291 | + |
| 292 | + if (dist_to_goal < params_->max_lookahead) { |
| 293 | + if (params_->prefer_final_rotation) { |
| 294 | + // Avoid instability and big sweeping turns at the end of paths by |
| 295 | + // ignoring final heading |
| 296 | + double yaw = std::atan2(target_pose.pose.position.y, target_pose.pose.position.x); |
| 297 | + target_pose.pose.orientation = nav2_util::geometry_utils::orientationAroundZAxis(yaw); |
| 298 | + } |
| 299 | + } else if (dist_to_target < params_->min_lookahead) { |
| 300 | + // Make sure target is far enough away to avoid instability |
| 301 | + return false; |
| 302 | + } |
| 303 | + |
| 304 | + // Flip the orientation of the motion target if the robot is moving backwards |
| 305 | + bool reversing = false; |
| 306 | + if (params_->allow_backward && target_pose.pose.position.x < 0.0) { |
| 307 | + reversing = true; |
| 308 | + target_pose.pose.orientation = nav2_util::geometry_utils::orientationAroundZAxis( |
| 309 | + tf2::getYaw(target_pose.pose.orientation) + M_PI); |
| 310 | + } |
| 311 | + |
| 312 | + // Actually simulate the path |
| 313 | + if (simulateTrajectory(target_pose, costmap_transform, trajectory, cmd_vel, reversing)) { |
| 314 | + // Successfully simulated to target_pose |
| 315 | + return true; |
| 316 | + } |
| 317 | + |
| 318 | + // Validation not successful |
| 319 | + return false; |
| 320 | +} |
| 321 | + |
286 | 322 | bool GracefulController::simulateTrajectory(
|
287 | 323 | const geometry_msgs::msg::PoseStamped & motion_target,
|
288 | 324 | const geometry_msgs::msg::TransformStamped & costmap_transform,
|
|
0 commit comments