1919#include < memory>
2020#include < vector>
2121#include < utility>
22+ #include < numeric>
2223
2324#include " nav2_regulated_pure_pursuit_controller/regulated_pure_pursuit_controller.hpp"
2425#include " nav2_core/exceptions.hpp"
@@ -232,7 +233,8 @@ std::unique_ptr<geometry_msgs::msg::PointStamped> RegulatedPurePursuitController
232233 return carrot_msg;
233234}
234235
235- double RegulatedPurePursuitController::getLookAheadDistance (const geometry_msgs::msg::Twist & speed)
236+ double RegulatedPurePursuitController::getLookAheadDistance (
237+ const geometry_msgs::msg::Twist & speed)
236238{
237239 // If using velocity-scaled look ahead distances, find and clamp the dist
238240 // Else, use the static look ahead distance
@@ -261,13 +263,14 @@ geometry_msgs::msg::TwistStamped RegulatedPurePursuitController::computeVelocity
261263 goal_dist_tol_ = pose_tolerance.position .x ;
262264 }
263265
264- double dist_to_cusp = findCusp (pose);
266+ auto cusp_pose_it = findCusp ();
267+
268+ double lookahead_dist = getLookAheadDistance (speed);
265269
266270 // Transform path to robot base frame
267- auto transformed_plan = transformGlobalPlan (pose, dist_to_cusp );
271+ auto transformed_plan = transformGlobalPlan (pose, cusp_pose_it, lookahead_dist );
268272
269- // Find look ahead distance and point on path and publish
270- double lookahead_dist = getLookAheadDistance (speed);
273+ double dist_to_cusp = integratedDistanceToPose (transformed_plan, cusp_pose_it);
271274
272275 // if the lookahead distance is further than the cusp, use the cusp distance instead
273276 if (dist_to_cusp < lookahead_dist) {
@@ -366,10 +369,8 @@ geometry_msgs::msg::PoseStamped RegulatedPurePursuitController::getLookAheadPoin
366369 const nav_msgs::msg::Path & transformed_plan)
367370{
368371 // Find the first pose which is at a distance greater than the lookahead distance
369- auto goal_pose_it = std::find_if (
370- transformed_plan.poses .begin (), transformed_plan.poses .end (), [&](const auto & ps) {
371- return hypot (ps.pose .position .x , ps.pose .position .y ) >= lookahead_dist;
372- });
372+ auto goal_pose_it = nav2_util::geometry_utils::first_element_beyond (
373+ transformed_plan.poses .begin (), transformed_plan.poses .end (), lookahead_dist);
373374
374375 // If the no pose is not far enough, take the last pose
375376 if (goal_pose_it == transformed_plan.poses .end ()) {
@@ -585,7 +586,9 @@ void RegulatedPurePursuitController::setSpeedLimit(
585586}
586587
587588nav_msgs::msg::Path RegulatedPurePursuitController::transformGlobalPlan (
588- const geometry_msgs::msg::PoseStamped & pose, double dist_to_cusp)
589+ const geometry_msgs::msg::PoseStamped & pose,
590+ const std::vector<geometry_msgs::msg::PoseStamped>::iterator cusp_it,
591+ double lookahead_distance)
589592{
590593 if (global_plan_.poses .empty ()) {
591594 throw nav2_core::PlannerException (" Received plan with zero length" );
@@ -602,29 +605,31 @@ nav_msgs::msg::Path RegulatedPurePursuitController::transformGlobalPlan(
602605 const double max_costmap_dim = std::max (costmap->getSizeInCellsX (), costmap->getSizeInCellsY ());
603606 const double max_costmap_extent = max_costmap_dim * costmap->getResolution () / 2.0 ;
604607
605- // Find the first pose that turns in the opposite direction from the first pose
606- findPathUpToTurn (global_plan_, M_PI);
607-
608- const double max_transform_dist = std::min (max_costmap_extent, dist_to_cusp);
609-
608+ // This bound is based on the assumption that the robot can't have traveled very far
609+ // since the last iteration, and that when the global_plan was first passed, the robot
610+ // was intended to start at the beginning.
611+ // lookahead distance should be a pretty good proxy for this bound.
610612 auto closest_pose_upper_bound =
611613 nav2_util::geometry_utils::first_element_beyond (
612- global_plan_.poses .begin (), global_plan_.poses .end (), max_transform_dist );
614+ global_plan_.poses .begin (), global_plan_.poses .end (), lookahead_distance );
613615
614- // First find the closest pose on the path to the robot
615- // bounded by when the path turns around (if it does) so we don't get a pose from a later
616- // portion of the path
617616 auto transformation_begin =
618- nav2_util::geometry_utils::min_by (
617+ std::min_element (
619618 global_plan_.poses .begin (), closest_pose_upper_bound,
620- [&robot_pose](const geometry_msgs::msg::PoseStamped & ps ) {
621- return euclidean_distance (robot_pose, ps );
619+ [&robot_pose](const auto & pose1, const auto & pose2 ) {
620+ return euclidean_distance (robot_pose, pose1) < euclidean_distance (robot_pose, pose2 );
622621 });
623622
624- // Find points up to max_transform_dist so we only transform them.
623+ auto first_pose_after_cusp = cusp_it != global_plan_.poses .end () ? std::next (cusp_it) : cusp_it;
624+
625+ // Find points within the local costmap up to the cusp pose
625626 auto transformation_end =
626- nav2_util::geometry_utils::first_element_beyond (
627- transformation_begin, global_plan_.poses .end (), max_transform_dist);
627+ std::find_if (
628+ transformation_begin, first_pose_after_cusp,
629+ [&](const auto & pose) -> bool {
630+ // This is constraining us to the biggest circle we can fit inside the local costmap
631+ return euclidean_distance (pose, robot_pose) > max_costmap_extent;
632+ });
628633
629634 // Lambda to transform a PoseStamped from global frame to local
630635 auto transformGlobalPoseToLocal = [&](const auto & global_plan_pose) {
@@ -638,9 +643,10 @@ nav_msgs::msg::Path RegulatedPurePursuitController::transformGlobalPlan(
638643
639644 // Transform the near part of the global plan into the robot's frame of reference.
640645 nav_msgs::msg::Path transformed_plan;
646+ transformed_plan.poses .resize (std::distance (transformation_begin, transformation_end));
641647 std::transform (
642648 transformation_begin, transformation_end,
643- std::back_inserter ( transformed_plan.poses ),
649+ transformed_plan.poses . begin ( ),
644650 transformGlobalPoseToLocal);
645651 transformed_plan.header .frame_id = costmap_ros_->getBaseFrameID ();
646652 transformed_plan.header .stamp = robot_pose.header .stamp ;
@@ -657,48 +663,35 @@ nav_msgs::msg::Path RegulatedPurePursuitController::transformGlobalPlan(
657663 return transformed_plan;
658664}
659665
660- double RegulatedPurePursuitController::findCusp (
661- const geometry_msgs::msg::PoseStamped & pose)
666+ std::vector<geometry_msgs::msg::PoseStamped>::iterator RegulatedPurePursuitController::findCusp ()
662667{
663668 // Iterating through the global path to determine the position of the cusp
664- for (unsigned int pose_id = 1 ; pose_id < global_plan_.poses .size () - 1 ; ++pose_id) {
669+ for (auto a = std::next (global_plan_.poses .begin ()); a != std::prev (global_plan_.poses .end ());
670+ ++a)
671+ {
672+ auto o = std::prev (a);
673+ auto b = std::next (a);
665674 // We have two vectors for the dot product OA and AB. Determining the vectors.
666- double oa_x = global_plan_.poses [pose_id].pose .position .x -
667- global_plan_.poses [pose_id - 1 ].pose .position .x ;
668- double oa_y = global_plan_.poses [pose_id].pose .position .y -
669- global_plan_.poses [pose_id - 1 ].pose .position .y ;
670- double ab_x = global_plan_.poses [pose_id + 1 ].pose .position .x -
671- global_plan_.poses [pose_id].pose .position .x ;
672- double ab_y = global_plan_.poses [pose_id + 1 ].pose .position .y -
673- global_plan_.poses [pose_id].pose .position .y ;
674-
675- /* Checking for the existance of cusp, in the path, using the dot product
676- and determine it's distance from the robot. If there is no cusp in the path,
677- then just determine the distance to the goal location. */
675+ double oa_x = a->pose .position .x - o->pose .position .x ;
676+ double oa_y = a->pose .position .y - o->pose .position .y ;
677+ double ab_x = b->pose .position .x - a->pose .position .x ;
678+ double ab_y = b->pose .position .y - a->pose .position .y ;
679+
680+ // Checking for the existance of cusp, in the path, using the dot product
678681 if ( (oa_x * ab_x) + (oa_y * ab_y) < 0.0 ) {
679- auto x = global_plan_.poses [pose_id].pose .position .x - pose.pose .position .x ;
680- auto y = global_plan_.poses [pose_id].pose .position .y - pose.pose .position .y ;
681- return hypot (x, y); // returning the distance if there is a cusp
682+ return a;
682683 }
683684 }
684685
685- return std::numeric_limits< double >:: max ();
686+ return global_plan_. poses . end ();
686687}
687688
688- std::vector<geometry_msgs::msg::PoseStamped>::iterator findPathUpToTurn (
689+ double RegulatedPurePursuitController::integratedDistanceToPose (
689690 const nav_msgs::msg::Path & path,
690- double angle )
691+ std::vector<geometry_msgs::msg::PoseStamped>::iterator pose_it )
691692{
692- tf2::Quaternion starting_orientation;
693- tf2::fromMsg (path.poses .begin ()->pose .orientation , starting_orientation);
694- return std::find_if (
695- path.poses .begin (), path.poses .end (),
696- [](const auto & pose) {
697- tf2::Quaternion quat;
698- tf2::fromMsg (pose.pose .orientation , quat);
699- return quat.angleShortestPath (starting_orientation) > angle;
700- }
701- );
693+ auto after_pose_it = pose_it != path.poses .end () ? std::next (pose_it) : pose_it;
694+ return nav2_util::geometry_utils::calculate_path_length (path.poses .begin (), after_pose_it);
702695}
703696
704697bool RegulatedPurePursuitController::transformPose (
0 commit comments