14 if (cone_array.size() < 4) {
15 RCLCPP_ERROR(rclcpp::get_logger(
"planning"),
"Not enough cones to create a path.");
38 int cutoff_index = -1;
39 double min_dist = std::numeric_limits<double>::max();
40 for (
size_t i = 0; i <
past_path_.size(); ++i) {
41 double dist = CGAL::squared_distance(
past_path_[i].point, car_point);
42 if (dist < min_dist) {
44 cutoff_index =
static_cast<int>(i);
48 if (cutoff_index == -1) {
49 RCLCPP_WARN(rclcpp::get_logger(
"planning"),
"No valid path points found near the car.");
81 if (path.size() < 3) {
88 if (best_cutoff_index + 1 <
static_cast<int>(path.size())) {
89 (void)path.erase(path.begin() + best_cutoff_index + 1, path.end());
91 path.push_back(path[0]);
93 RCLCPP_DEBUG(rclcpp::get_logger(
"planning"),
"Loop closure cost: %.4f (threshold: %.4f)",
106 if (result.size() < 3) {
107 RCLCPP_WARN(rclcpp::get_logger(
"planning"),
"Not enough points to create trackdrive loop");
114 if (result.begin() + best_cutoff_index + 1 != result.end()) {
116 (void)result.erase(result.begin() + best_cutoff_index + 1, result.end());
118 RCLCPP_WARN(rclcpp::get_logger(
"planning"),
"The path change to create trackdrive loop");
126 result.push_back(result[0]);
154 RCLCPP_INFO(rclcpp::get_logger(
"planning"),
"Global path reset");
175 if (first_midpoint && second_midpoint) {
177 Colorpoint(first_midpoint->point, *first_midpoint->cone1, *first_midpoint->cone2);
179 Colorpoint(second_midpoint->point, *second_midpoint->cone1, *second_midpoint->cone2);
185 RCLCPP_ERROR(rclcpp::get_logger(
"planning"),
"Failed to find valid starting points.");
190 RCLCPP_DEBUG(rclcpp::get_logger(
"planning"),
"Selecting initial path from %zu points.",
195 Point last_added_point;
196 bool first_point_added =
false;
200 Colorpoint candidate_colorpoint = path_to_car_colorpoint;
203 std::shared_ptr<Midpoint> candidate_midpoint =
207 if (candidate_midpoint) {
208 candidate_colorpoint =
Colorpoint(candidate_midpoint->point, *candidate_midpoint->cone1,
209 *candidate_midpoint->cone2);
214 RCLCPP_DEBUG(rclcpp::get_logger(
"planning"),
"Skipping point: Already visited.");
219 if (first_point_added) {
221 std::sqrt(CGAL::squared_distance(last_added_point, candidate_colorpoint.
point));
223 RCLCPP_DEBUG(rclcpp::get_logger(
"planning"),
224 "Skipping point: Too close to last added point.");
230 if (candidate_midpoint) {
235 last_added_point = candidate_colorpoint.
point;
236 first_point_added =
true;
262 if (!prev_mp || !last_mp) {
263 RCLCPP_WARN(rclcpp::get_logger(
"planning"),
"No valid midpoints found for path extension.");
268 auto [best_cost, best_midpoint] =
272 if (best_cost > worst_cost || !best_midpoint ||
visited_midpoints_.count(best_midpoint) > 0) {
277 Colorpoint(best_midpoint->point, *best_midpoint->cone1, *best_midpoint->cone2));
281 if (n_points >= max_points) {
294std::pair<std::shared_ptr<Midpoint>, std::shared_ptr<Midpoint>>
296 std::pair<std::shared_ptr<Midpoint>, std::shared_ptr<Midpoint>> result{
nullptr,
nullptr};
304 double best_cost = std::numeric_limits<double>::max();
306 for (
const auto& first : anchor_pose_midpoint.close_points) {
307 std::shared_ptr<Midpoint> anchor_mp = std::make_shared<Midpoint>(anchor_pose_midpoint);
310 std::numeric_limits<double>::max());
312 double dx = first->point.x() - anchor_pose_midpoint.point.x();
313 double dy = first->point.y() - anchor_pose_midpoint.point.y();
314 double distance = std::sqrt(dx * dx + dy * dy);
317 double angle_to_point = std::atan2(dy, dx);
318 double angle_deviation =
325 cost += initial_cost;
326 cost += initial_cost;
328 if (cost < best_cost) {
329 result.first = first;
330 result.second = midpoint;
339 const Midpoint& anchor_pose,
int num_candidates)
const {
340 auto cmp = [](
const std::pair<double, std::shared_ptr<Midpoint>>& cost1,
341 const std::pair<double, std::shared_ptr<Midpoint>>& cost2) {
342 return cost1.first > cost2.first;
345 std::priority_queue<std::pair<double, std::shared_ptr<Midpoint>>,
346 std::vector<std::pair<double, std::shared_ptr<Midpoint>>>,
decltype(cmp)>
354 double dx = mp->point.x() - anchor_pose.
point.x();
355 double dy = mp->point.y() - anchor_pose.
point.y();
358 if ((dx * car_direction_x + dy * car_direction_y) <= 0.0) {
362 double dist = std::sqrt(dx * dx + dy * dy);
365 double angle_to_point = std::atan2(dy, dx);
366 double angle_deviation =
377 std::vector<std::shared_ptr<Midpoint>> candidate_points;
379 while (count < num_candidates && !pq.empty()) {
380 candidate_points.push_back(pq.top().second);
385 return candidate_points;
389 int depth,
const std::shared_ptr<Midpoint>& previous,
const std::shared_ptr<Midpoint>& current,
390 double max_cost)
const {
392 return {0.0, current};
396 std::shared_ptr<Midpoint> min_point = current;
398 for (
const auto& next : current->close_points) {
400 if (next == previous) {
404 double local_cost =
calculate_cost(previous->point.x(), previous->point.y(), current->point.x(),
405 current->point.y(), next->point.x(), next->point.y());
408 if (local_cost > max_cost) {
415 double total_cost = local_cost + best_cost;
418 if (total_cost < min_cost) {
419 min_cost = total_cost;
424 return {min_cost, min_point};
428 double current_y,
double next_x,
double next_y)
const {
429 double dx_dist = current_x - next_x;
430 double dy_dist = current_y - next_y;
431 double distance = std::sqrt(dx_dist * dx_dist + dy_dist * dy_dist);
434 double angle_with_previous = std::atan2(current_y - previous_y, current_x - previous_x);
435 double angle_with_next = std::atan2(next_y - current_y, next_x - current_x);
438 double angle = abs(angle_with_next - angle_with_previous);
440 angle = 2 * M_PI - angle;
461 if (!last_mp || !current_midpoint) {
462 RCLCPP_WARN(rclcpp::get_logger(
"planning"),
"No valid midpoints found for discarding cones.");
477 const std::shared_ptr<Midpoint>& current_mp) {
478 if (last_mp->cone1 == current_mp->cone1 || last_mp->cone1 == current_mp->cone2) {
479 if (last_mp->cone2 != current_mp->cone1 && last_mp->cone2 != current_mp->cone2) {
482 }
else if (last_mp->cone2 == current_mp->cone1 || last_mp->cone2 == current_mp->cone2) {
483 if (last_mp->cone1 != current_mp->cone1 && last_mp->cone1 != current_mp->cone2) {
487 RCLCPP_DEBUG(rclcpp::get_logger(
"planning"),
"No valid cones found for discarding.");
507 (void)mp->close_points.erase(
508 remove_if(mp->close_points.begin(), mp->close_points.end(),
509 [](
const std::shared_ptr<Midpoint>& neighbor) {
return !neighbor->valid; }),
510 mp->close_points.end());
518 std::shared_ptr<Midpoint> nearest =
nullptr;
521 double dx = pt.x() - target.x();
522 double dy = pt.y() - target.y();
523 double dist_sq = dx * dx + dy * dy;
525 if (dist_sq < min_dist_sq) {
526 min_dist_sq = dist_sq;
535 const std::vector<PathPoint>& path)
const {
536 if (path.size() < 3) {
537 return {
static_cast<int>(path.size()) - 1, std::numeric_limits<double>::max()};
542 double min_cost = std::numeric_limits<double>::max();
543 int best_cutoff_index =
static_cast<int>(path.size() - 1);
545 for (
int i = 2; i < static_cast<int>(path.size()); ++i) {
552 double cost_into_second =
556 double combined_cost = cost + cost_into_second;
558 if (combined_cost < min_cost) {
559 min_cost = combined_cost;
560 best_cutoff_index = i;
564 return {best_cutoff_index, min_cost};
568 const std::vector<Colorpoint>& colorpoints)
const {
569 std::vector<PathPoint> path_points;
570 path_points.reserve(colorpoints.size());
573 (void)path_points.emplace_back(pt.point.x(), pt.point.y());
Path point with two boundary cones, provides cone classification into left/right boundaries.
Point point
The path point (midpoint between cones).
static void extract_cones(std::vector< Colorpoint > &colorpoints, std::vector< PathPoint > &yellow_cones, std::vector< PathPoint > &blue_cones)
Extracts and classifies all cones from a sequence of colorpoints.
void set_vehicle_pose(const Pose &vehicle_pose)
Updates the vehicle pose for dynamic filtering.
std::vector< std::shared_ptr< Midpoint > > & generate_midpoints(const std::vector< Cone > &cone_array, bool rebuild_all_midpoints)
Generates midpoints from a set of cones.
const std::vector< std::pair< Point, Point > > & get_triangulations() const
Returns the current set of Delaunay edges used for visualization.
std::pair< std::shared_ptr< Midpoint >, std::shared_ptr< Midpoint > > select_starting_midpoints()
Select the first two midpoints to start the path.
std::vector< Colorpoint > past_path_
int reset_path(bool should_reset)
Handle path reset when completing a lap.
const std::vector< PathPoint > & get_yellow_cones() const
Gets the list of yellow cones detected or used in the path calculation.
std::vector< std::shared_ptr< Midpoint > > select_candidate_midpoints(const Midpoint &anchor_pose, int num_candidates) const
Select candidate midpoints in front of the vehicle.
std::unordered_set< std::shared_ptr< Midpoint > > visited_midpoints_
void discard_cone(const std::shared_ptr< Midpoint > &last_mp, const std::shared_ptr< Midpoint > ¤t_mp)
Determine which cone to discard between two consecutive midpoints.
double calculate_cost(double previous_x, double previous_y, double current_x, double current_y, double next_x, double next_y) const
Calculate the cost of transitioning through three consecutive points.
std::vector< PathPoint > get_path_to_car() const
Get the path from the start to a lookback distance behind the car’s current position.
common_lib::structures::Pose vehicle_pose_
std::vector< PathPoint > calculate_path(const std::vector< Cone > &cone_array)
Generate a path from an array of cones.
void initialize_path_from_initial_pose()
Initialize the path from the vehicle's initial pose.
void remove_invalid_neighbors()
Remove invalid neighbors from all midpoint connection lists.
bool is_map_closed(std::vector< PathPoint > &path) const
Checks if the path forms a closed loop and closes it if the transition cost is below config_....
std::unordered_set< std::shared_ptr< Cone > > discarded_cones_
std::vector< PathPoint > yellow_cones_
std::shared_ptr< Midpoint > find_nearest_midpoint(const Point &target) const
Find the nearest valid midpoint to a target position.
void extend_path(int max_points)
Extend the path by adding midpoints.
void clear_path_state()
Reset path construction state.
MidpointGenerator midpoint_generator_
void update_path_from_past_path()
Initialize the path from the previous path.
void invalidate_midpoints_with_discarded_cones()
Mark midpoints as invalid if they use discarded cones.
const std::vector< PathPoint > & get_blue_cones() const
Gets the list of blue cones detected or used in the path calculation.
std::vector< PathPoint > blue_cones_
const std::vector< std::pair< Point, Point > > & get_triangulations() const
Get the triangulation segments used in path generation.
std::pair< double, std::shared_ptr< Midpoint > > find_best_next_midpoint(int depth, const std::shared_ptr< Midpoint > &previous, const std::shared_ptr< Midpoint > ¤t, double max_cost) const
Recursively find the best next midpoint using depth-first search.
std::vector< PathPoint > calculate_trackdrive(const std::vector< Cone > &cone_array)
Generate a closed loop path for trackdrive competition.
common_lib::structures::Pose initial_pose_
std::vector< std::shared_ptr< Midpoint > > midpoints_
std::pair< int, double > find_best_loop_closure(const std::vector< PathPoint > &path) const
Finds the best loop closure point in a path.
std::vector< Colorpoint > current_path_
std::unordered_map< Point, std::shared_ptr< Midpoint > > point_to_midpoint_
void discard_cones_along_path()
Invalidate cones and midpoints along the last path segment.
void set_vehicle_pose(const common_lib::structures::Pose &vehicle_pose)
Set the current vehicle position and orientation.
std::vector< PathPoint > get_path_points_from_colorpoints(const std::vector< Colorpoint > &colorpoints) const
Converts a vector of Colorpoint objects into a vector of PathPoint objects.
std::vector< Colorpoint > path_to_car_
PathCalculationConfig config_
int max_points_
Maximum number of points added in an iteration.
int lookback_points_
Number of recent path points discarded and recalculated each iteration.
double angle_exponent_
Exponent applied to the angle term in the cost function.
double distance_exponent_
Exponent applied to the distance term in the cost function.
double minimum_point_distance_
Minimum allowed distance between consecutive points in the generated path.
double angle_gain_
Gain applied to the angle term in the cost function.
double distance_gain_
Gain applied to the distance term in the cost function.
double close_cost_
Cost threshold to determine whether the path is considered closed.
double max_cost_
Maximum allowed cost for a path.
bool use_sliding_window_
Flag to enable/disable the sliding window for path calculation.
bool use_reset_path_
Flag to enable/disable path reset logic.
int search_depth_
Maximum search depth when exploring candidate paths.
MidPoint struct represents a potential path point with connections.
std::vector< std::shared_ptr< Midpoint > > close_points
Struct for pose representation.