Formula Student Autonomous Systems
The code for the main driverless system
Loading...
Searching...
No Matches
skidpad.cpp
Go to the documentation of this file.
2
3#include <fstream>
4#include <sstream>
5#include <limits>
6#include <cmath>
7
8#include <CGAL/Delaunay_triangulation_2.h>
9#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
10
11#include <pcl/registration/icp.h>
12#include <pcl/point_cloud.h>
13#include <pcl/point_types.h>
14#include <pcl/kdtree/kdtree_flann.h>
15
17
18Eigen::Matrix4f Skidpad::align_cones_with_icp(const std::vector<Cone>& cone_array) {
19 // Check if we have enough cones for ICP
20 if (reference_cones_.size() < static_cast<std::size_t>(config_.minimum_cones_) ||
21 cone_array.size() < static_cast<std::size_t>(config_.minimum_cones_)) {
22 RCLCPP_ERROR(rclcpp::get_logger("planning"), "Not enough cones to perform ICP alignment.");
23 return Eigen::Matrix4f::Identity();
24 }
25
26 // Convert cone_array (LiDAR) to source cloud
27 pcl::PointCloud<pcl::PointXYZ> cloud_source;
28 cloud_source.reserve(cone_array.size());
29 for (const auto& cone : cone_array) {
30 (void)cloud_source.emplace_back(cone.position.x, cone.position.y, 0.0);
31 }
32
33 // Convert reference cones to target cloud
34 pcl::PointCloud<pcl::PointXYZ> cloud_target;
35 cloud_target.reserve(reference_cones_.size());
36 for (const auto& [x, y] : reference_cones_) {
37 (void)cloud_target.emplace_back(x, y, 0.0);
38 }
39
40 // Run ICP alignment
41 pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;
42 icp.setInputSource(cloud_source.makeShared());
43 icp.setInputTarget(cloud_target.makeShared());
44 icp.setMaxCorrespondenceDistance(config_.tolerance_);
45 icp.setMaximumIterations(std::numeric_limits<int>::max());
46 icp.setTransformationEpsilon(1e-6);
47 icp.setEuclideanFitnessEpsilon(1e-3);
48
49 pcl::PointCloud<pcl::PointXYZ> Final;
50 icp.align(Final);
51
52 if (!icp.hasConverged()) {
53 RCLCPP_ERROR(rclcpp::get_logger("planning"), "ICP did not converge.");
54 return Eigen::Matrix4f::Identity();
55 }
56
57 return icp.getFinalTransformation();
58}
59
61 const std::vector<PathPoint>& path,
62 const common_lib::structures::Pose& pose) {
63
64 double min_dist = std::numeric_limits<double>::max();
65 size_t closest_index = 0;
66
67 for (size_t i = 0; i < path.size(); ++i) {
68 double dx = path[i].position.x - pose.position.x;
69 double dy = path[i].position.y - pose.position.y;
70 double dist = std::sqrt(dx * dx + dy * dy);
71
72 if (dist > min_dist) {
73 break; // Stop searching if distance starts increasing
74 }
75
76 if (dist < min_dist) {
77 min_dist = dist;
78 closest_index = i;
79 }
80 }
81
82 return closest_index;
83}
84
85std::vector<PathPoint> Skidpad::skidpad_path(const std::vector<Cone>& cone_array,
87 std::vector<PathPoint> result;
88
89 // Load data from files only on first iteration
91 const std::string file = "./src/planning/src/utils/skidpad.txt";
92 const std::string conesfile = "./src/planning/src/utils/skidpadcones1.txt";
93
94 // 1. Read reference cones from file
95 std::ifstream cfile(conesfile);
96 reference_cones_.clear();
97 std::string line;
98 while (std::getline(cfile, line)) {
99 std::istringstream iss(line);
100 double x = 0.0, y = 0.0, z = 0.0;
101 if (iss >> x >> y >> z) {
102 (void)reference_cones_.emplace_back(x, y);
103 } else {
104 break;
105 }
106 }
107
108 // 2. Read hardcoded path from file
109 hardcoded_path_.clear();
110 std::ifstream infile(file);
111 while (std::getline(infile, line)) {
112 std::istringstream iss(line);
113 double x = 0.0, y = 0.0, v = 0.0;
114 if (iss >> x >> y >> v) {
115 (void)hardcoded_path_.emplace_back(x, y, v);
116 } else {
117 break;
118 }
119 }
120
122 }
123
124 // Perform ICP alignment
125 Eigen::Matrix4f icp_transform = align_cones_with_icp(cone_array);
126
127 if (icp_transform.isIdentity()) {
128 return result; // empty to indicate failure
129 }
130
131 // Apply transformation to hardcoded path (create a copy)
132 result = hardcoded_path_;
133 Eigen::Matrix4f map_to_lidar_transform = icp_transform.inverse();
134
135 for (auto& point : result) {
136 Eigen::Vector4f p(point.position.x, point.position.y, 0.0f, 1.0f);
137 Eigen::Vector4f transformed = map_to_lidar_transform * p;
138 point.position.x = transformed[0];
139 point.position.y = transformed[1];
140 }
141
142 // Update predefined_path_ with the transformed path
143 predefined_path_ = result;
144
145 // Get the closest points to the car pose
146 if (predefined_path_.empty()) {
147 RCLCPP_ERROR(rclcpp::get_logger("planning"), "Predefined path is empty.");
148 return result;
149 }
150
151 size_t closest_index = find_closest_path_index(predefined_path_, pose);
152
153 RCLCPP_INFO(rclcpp::get_logger("planning"),
154 "predefined path size is %zu, closest index is %zu \n Hardcoded path size is %zu",
155 predefined_path_.size(), closest_index, hardcoded_path_.size());
156
157 // Remove all the points before the closest point not removing the closest point itself
158 (void)predefined_path_.erase(predefined_path_.begin(), predefined_path_.begin() + closest_index);
159 (void)hardcoded_path_.erase(hardcoded_path_.begin(), hardcoded_path_.begin() + closest_index);
160
161 size_t path_size = predefined_path_.size();
162 size_t count = 70;
163 if (path_size < 70) {
164 count = path_size;
165 }
166
167 return std::vector<PathPoint>(predefined_path_.begin(), predefined_path_.begin() + count);
168}
std::vector< std::pair< double, double > > reference_cones_
Definition skidpad.hpp:44
Eigen::Matrix4f align_cones_with_icp(const std::vector< Cone > &cone_array)
Aligns detected cones with reference cones using ICP.
Definition skidpad.cpp:18
bool skidpad_data_loaded_
Definition skidpad.hpp:43
SkidpadConfig config_
Definition skidpad.hpp:41
std::vector< PathPoint > predefined_path_
Definition skidpad.hpp:46
std::vector< PathPoint > skidpad_path(const std::vector< Cone > &cone_array, common_lib::structures::Pose pose)
Generate a path for skidpad course.
Definition skidpad.cpp:85
std::vector< PathPoint > hardcoded_path_
Definition skidpad.hpp:45
size_t find_closest_path_index(const std::vector< PathPoint > &path, const common_lib::structures::Pose &pose)
Finds the closest point index in a path to a given pose.
Definition skidpad.cpp:60
double tolerance_
Maximum distance for matching cone pairs during ICP alignment.
int minimum_cones_
Minimum number of cones required.
Struct for pose representation.
Definition pose.hpp:13