Autonomy Software C++ 24.5.1
Welcome to the Autonomy Software repository of the Mars Rover Design Team (MRDT) at Missouri University of Science and Technology (Missouri S&T)! API reference contains the source code and other resources for the development of the autonomy software for our Mars rover. The Autonomy Software project aims to compete in the University Rover Challenge (URC) by demonstrating advanced autonomous capabilities and robust navigation algorithms.
Loading...
Searching...
No Matches
SearchPattern.hpp
Go to the documentation of this file.
1
12#ifndef SEARCH_PATTERN_HPP
13#define SEARCH_PATTERN_HPP
14
15#include "../util/GeospatialOperations.hpp"
16
18#include <cmath>
19#include <vector>
20
22
23
31{
32
49 inline std::vector<geoops::Waypoint> CalculateSpiralPatternWaypoints(const geoops::Waypoint& stStartingPoint,
50 const double dAngularStepDegrees = 57,
51 const double dMaxRadius = 25,
52 const double dStartingHeadingDegrees = 0,
53 const double dStartSpacing = 1)
54 {
55 // Define variables.
56 std::vector<geoops::Waypoint> vWaypoints;
57 double dAngularStepRadians = dAngularStepDegrees * M_PI / 180;
58 double dAngleRadians = (-dStartingHeadingDegrees) * M_PI / 180.0;
59 double dCurrentSpacingWindUp = 0.0;
60 double dStartingX = stStartingPoint.GetUTMCoordinate().dEasting;
61 double dStartingY = stStartingPoint.GetUTMCoordinate().dNorthing;
62 double dCurrentRadius = 0.0;
63
64 // Check if the MaxRadius is less than 1 meter. If so return an empty vector.
65 if (dMaxRadius < 1)
66 {
67 // Submit logger message.
68 LOG_WARNING(logging::g_qSharedLogger, "MaxRadius is less than 1 meter. Cannot create spiral pattern.");
69 return vWaypoints;
70 }
71
72 // Calculate each waypoint. Stop when the radius exceeds the maximum.
73 while (dCurrentRadius <= dMaxRadius)
74 {
75 // Get X and Y positions for the current point.
76 double dCurrentX = dStartingX + dCurrentSpacingWindUp * cos(dAngleRadians);
77 double dCurrentY = dStartingY + dCurrentSpacingWindUp * sin(dAngleRadians);
78
79 // Add the current waypoint to the final vector.
80 geoops::UTMCoordinate stCurrentCoordinate = stStartingPoint.GetUTMCoordinate();
81 stCurrentCoordinate.dEasting = dCurrentX;
82 stCurrentCoordinate.dNorthing = dCurrentY;
83 vWaypoints.emplace_back(stCurrentCoordinate, geoops::WaypointType::eNavigationWaypoint);
84
85 // Increment angle and radius for the next waypoint.
86 dAngleRadians += dAngularStepRadians;
87 dCurrentSpacingWindUp += dStartSpacing;
88
89 // Calculate the current distance from the starting point. This is our radius.
90 dCurrentRadius = geoops::CalculateGeoMeasurement(stStartingPoint.GetUTMCoordinate(), stCurrentCoordinate).dDistanceMeters;
91 }
92 // Same but going back in.
93 while (dCurrentRadius >= 0.5 && dCurrentSpacingWindUp > 0.0)
94 {
95 // Get X and Y positions for the current point.
96 double dCurrentX = dStartingX + dCurrentSpacingWindUp * cos(dAngleRadians);
97 double dCurrentY = dStartingY + dCurrentSpacingWindUp * sin(dAngleRadians);
98
99 // Add the current waypoint to the final vector.
100 geoops::UTMCoordinate stCurrentCoordinate = stStartingPoint.GetUTMCoordinate();
101 stCurrentCoordinate.dEasting = dCurrentX;
102 stCurrentCoordinate.dNorthing = dCurrentY;
103 vWaypoints.emplace_back(stCurrentCoordinate, geoops::WaypointType::eNavigationWaypoint);
104
105 // Increment angle and radius for the next waypoint.
106 dAngleRadians += dAngularStepRadians;
107 dCurrentSpacingWindUp -= dStartSpacing;
108
109 // Calculate the current distance from the starting point. This is our radius.
110 dCurrentRadius = geoops::CalculateGeoMeasurement(stStartingPoint.GetUTMCoordinate(), stCurrentCoordinate).dDistanceMeters;
111 }
112
113 // Write the search pattern points to the logger, just store the GPS lat/long.
114 std::string szSearchPatternPoints = "Search Pattern Points (Spiral): ";
115 for (geoops::Waypoint& stWaypoint : vWaypoints)
116 {
117 szSearchPatternPoints +=
118 "(" + std::to_string(stWaypoint.GetGPSCoordinate().dLatitude) + ", " + std::to_string(stWaypoint.GetGPSCoordinate().dLongitude) + "), ";
119 }
120 // Submit logger message.
121 LOG_DEBUG(logging::g_qSharedLogger, "{}", szSearchPatternPoints);
122
123 return vWaypoints;
124 }
125
126
143 inline std::vector<geoops::Waypoint> CalculateZigZagPatternWaypoints(const geoops::Waypoint& stCenterPoint,
144 const double dWidth = 20.0,
145 const double dHeight = 20.0,
146 const double dSpacing = 1.0,
147 const bool bVertical = true)
148 {
149 // Create instance variables.
150 std::vector<geoops::Waypoint> vWaypoints;
151 double dStartingX = stCenterPoint.GetUTMCoordinate().dEasting - (dWidth / 2);
152 double dStartingY = stCenterPoint.GetUTMCoordinate().dNorthing - (dHeight / 2);
153 double dCurrentX = dStartingX;
154 double dCurrentY = dStartingY;
155 bool bZigNotZag = true;
156 double bCalcSpacing = dSpacing;
157
158 // Check if the width or height is less than 1 meter. If so return an empty vector.
159 if (dWidth < 1 || dHeight < 1 || dSpacing < 1)
160 {
161 // Submit logger message.
162 LOG_WARNING(logging::g_qSharedLogger, "Width or height or spacing is less than 1 meter. Cannot create zigzag pattern.");
163 return vWaypoints;
164 }
165
166 // Limit spacing to the width or height.
167 if (bCalcSpacing > dWidth / 2.0)
168 {
169 // Submit logger message.
170 LOG_WARNING(logging::g_qSharedLogger, "Spacing is greater than width. Setting spacing to width / 2.");
171 // Set spacing to half the width.
172 bCalcSpacing = dWidth / 2.0 - 1.0;
173 }
174 if (bCalcSpacing > dHeight / 2.0)
175 {
176 // Submit logger message.
177 LOG_WARNING(logging::g_qSharedLogger, "Spacing is greater than height. Setting spacing to height / 2.");
178 // Set spacing to half the height.
179 bCalcSpacing = dHeight / 2.0 - 1.0;
180 }
181
182 // Loop until covered entire space of width and height.
183 while ((bVertical && dCurrentY <= dStartingY + dHeight) || (!bVertical && dCurrentX <= dStartingX + dWidth))
184 {
185 // Check if pattern should be vertical or horizontal.
186 if (bVertical)
187 {
188 // Check step direction.
189 if (bZigNotZag)
190 {
191 // Zig.
192 dCurrentX = dStartingX + bCalcSpacing;
193 }
194 else
195 {
196 // Zag.
197 dCurrentX = dStartingX - bCalcSpacing;
198 }
199 }
200 else
201 {
202 // Check step direction.
203 if (bZigNotZag)
204 {
205 // Zig.
206 dCurrentY = dStartingY + bCalcSpacing;
207 }
208 else
209 {
210 // Zag.
211 dCurrentY = dStartingY - bCalcSpacing;
212 }
213 }
214
215 // Loop and add points along line until we reached the limit or width or height.
216 while ((bZigNotZag && bVertical && dCurrentX <= dStartingX + dWidth) || (!bZigNotZag && bVertical && dCurrentX >= dStartingX) ||
217 (bZigNotZag && !bVertical && dCurrentY <= dStartingY + dHeight) || (!bZigNotZag && !bVertical && dCurrentY >= dStartingY))
218 {
219 // Construct UTMCoordinate.
220 geoops::UTMCoordinate stCurrentCoordinate = stCenterPoint.GetUTMCoordinate();
221 stCurrentCoordinate.dEasting = dCurrentX;
222 stCurrentCoordinate.dNorthing = dCurrentY;
223 geoops::Waypoint stCurrentWaypoint(stCurrentCoordinate, geoops::WaypointType::eNavigationWaypoint);
224 // Add current waypoint to final path.
225 vWaypoints.push_back(stCurrentWaypoint);
226
227 // Move to the next point based on spacing and direction.
228 if (bVertical)
229 {
230 // Increment current position.
231 dCurrentX += bZigNotZag ? bCalcSpacing : -bCalcSpacing;
232 }
233 else
234 {
235 // Increment current position.
236 dCurrentY += bZigNotZag ? bCalcSpacing : -bCalcSpacing;
237 }
238 }
239
240 // Now shift the opposite coordinate forward.
241 if (bVertical)
242 {
243 dCurrentY += bCalcSpacing;
244 }
245 else
246 {
247 dCurrentX += bCalcSpacing;
248 }
249
250 // Toggle zigzag direction.
251 bZigNotZag = !bZigNotZag;
252 }
253
254 // The path now contains the zigzag pattern with points spaced at the specified distance. This means that there
255 // are many points potentially very close to each other. This is not ideal for navigation, so we will filter out
256 // points that are too close to each other, by calculating their GeoMeasurement and testing if the distance is greater
257 // then the CalcSpacing. If the CalcSpacing is greater a certain threshold, we will remove the point since it jumps to the other side.
258 // This will reduce the number of points in the zigzag pattern, making it more efficient for navigation.
259
260 // Create a vector to store the filtered waypoints.
261 std::vector<geoops::Waypoint> vFilterWaypoints;
262 // Always store the first point.
263 vFilterWaypoints.push_back(vWaypoints[0]);
264 // Loop through the waypoints and remove any that are too close to each other.
265 for (size_t i = 0; i < vWaypoints.size() - 1; ++i)
266 {
267 // Calculate the GeoMeasurement between the current waypoint and the next waypoint.
268 geoops::GeoMeasurement stGeoMeasurement = geoops::CalculateGeoMeasurement(vWaypoints[i].GetGPSCoordinate(), vWaypoints[i + 1].GetGPSCoordinate());
269 if (stGeoMeasurement.dDistanceMeters > bCalcSpacing * 1.5)
270 {
271 // Add the points to the filtered waypoints.
272 vFilterWaypoints.push_back(vWaypoints[i]);
273 vFilterWaypoints.push_back(vWaypoints[i + 1]);
274 }
275 }
276
277 // Write the search pattern points to the logger, just store the GPS lat/long.
278 std::string szSearchPatternPoints = "Search Pattern Points (Spiral): ";
279 for (geoops::Waypoint& stWaypoint : vWaypoints)
280 {
281 szSearchPatternPoints +=
282 "(" + std::to_string(stWaypoint.GetGPSCoordinate().dLatitude) + ", " + std::to_string(stWaypoint.GetGPSCoordinate().dLongitude) + "), ";
283 }
284 // Submit logger message.
285 LOG_DEBUG(logging::g_qSharedLogger, "{}", szSearchPatternPoints);
286
287 // Return the final path.
288 return vFilterWaypoints;
289 }
290
291
305 inline std::vector<geoops::Waypoint> CalculateSnakeSearchPattern(const geoops::Waypoint& stStartCoord,
306 const double dWidth = 20.0,
307 const double dHeight = 20.0,
308 const double dSpacing = 1.0,
309 const int nNumberOfSlithers = 1.0,
310 const bool bVertical = true)
311 {
312 // Create instance variables.
313 std::vector<geoops::Waypoint> vWaypoints;
314 geoops::UTMCoordinate stStartUTM = stStartCoord.GetUTMCoordinate();
315 double dStartingX = (bVertical) ? stStartUTM.dEasting : stStartUTM.dEasting - (dWidth / 2);
316 double dStartingY = (bVertical) ? stStartUTM.dNorthing - (dHeight / 2) : stStartUTM.dNorthing;
317
318 // Check if the dimensions are valid.
319 if (dWidth < 1.0 || dHeight < 1.0 || dSpacing < 0.1 || nNumberOfSlithers < 1)
320 {
321 // Submit logger message.
322 LOG_WARNING(logging::g_qSharedLogger,
323 "Invalid parameters for snake pattern: width={}, height={}, spacing={}, number of slithers={}",
324 dWidth,
325 dHeight,
326 dSpacing,
327 nNumberOfSlithers);
328 return vWaypoints;
329 }
330
331 // Calculate the number of points based on path length and spacing and the number of slithers.
332 // For a sine wave, we need enough points to make it smooth.
333 int nPoints = static_cast<int>(dWidth + dHeight / dSpacing);
334
335 // Generate the sine wave pattern.
336 for (int nIter = 0; nIter < nPoints; ++nIter)
337 {
338 double dTime = static_cast<double>(nIter) / (nPoints - 1);
339 double dCurrentX, dCurrentY;
340
341 if (bVertical)
342 {
343 // Vertical primary movement: sinusoidal variation in x.
344 dCurrentY = dStartingY + dTime * dWidth;
345 // Sine wave with multiple periods.
346 dCurrentX = dStartingX + (dHeight / 2.0) * std::cos(2.0 * nNumberOfSlithers * M_PI * dTime);
347 }
348 else
349 {
350 // Horizontal primary movement: sinusoidal variation in y.
351 dCurrentX = dStartingX + dTime * dWidth;
352 // Sine wave with multiple periods.
353 dCurrentY = dStartingY + (dHeight / 2.0) * std::cos(2.0 * nNumberOfSlithers * M_PI * dTime);
354 }
355
356 // Create waypoint at current position.
357 geoops::UTMCoordinate stCurrentUTM = stStartUTM;
358 stCurrentUTM.dEasting = dCurrentX;
359 stCurrentUTM.dNorthing = dCurrentY;
360 geoops::Waypoint stCurrentWaypoint(stCurrentUTM, geoops::WaypointType::eNavigationWaypoint);
361 vWaypoints.push_back(stCurrentWaypoint);
362 }
363
364 // Log the waypoints.
365 std::string szSearchPatternPoints = "Search Pattern Points (Snake): ";
366 for (const geoops::Waypoint& stWaypoint : vWaypoints)
367 {
368 szSearchPatternPoints +=
369 "(" + std::to_string(stWaypoint.GetGPSCoordinate().dLatitude) + ", " + std::to_string(stWaypoint.GetGPSCoordinate().dLongitude) + "), ";
370 }
371 LOG_DEBUG(logging::g_qSharedLogger, "{}", szSearchPatternPoints);
372
373 return vWaypoints;
374 }
375
376} // namespace searchpattern
377#endif
__device__ __forceinline__ float1 cos(const uchar1 &a)
__device__ __forceinline__ float4 sin(const uchar4 &a)
GeoMeasurement CalculateGeoMeasurement(const GPSCoordinate &stCoord1, const GPSCoordinate &stCoord2)
The shortest path between two points on an ellipsoid at (lat1, lon1) and (lat2, lon2) is called the g...
Definition GeospatialOperations.hpp:553
Namespace containing algorithms related to calculating drive powers, odometry, trajectories,...
Definition SearchPattern.hpp:31
std::vector< geoops::Waypoint > CalculateSpiralPatternWaypoints(const geoops::Waypoint &stStartingPoint, const double dAngularStepDegrees=57, const double dMaxRadius=25, const double dStartingHeadingDegrees=0, const double dStartSpacing=1)
Perform a spiral search pattern starting from a given point.
Definition SearchPattern.hpp:49
std::vector< geoops::Waypoint > CalculateSnakeSearchPattern(const geoops::Waypoint &stStartCoord, const double dWidth=20.0, const double dHeight=20.0, const double dSpacing=1.0, const int nNumberOfSlithers=1.0, const bool bVertical=true)
Calculate waypoints for a snake search pattern.
Definition SearchPattern.hpp:305
std::vector< geoops::Waypoint > CalculateZigZagPatternWaypoints(const geoops::Waypoint &stCenterPoint, const double dWidth=20.0, const double dHeight=20.0, const double dSpacing=1.0, const bool bVertical=true)
Calculate waypoints for a zigzag pattern. This function generates waypoints for a zigzag pattern star...
Definition SearchPattern.hpp:143
This struct is used to store the distance, arc length, and relative bearing for a calculated geodesic...
Definition GeospatialOperations.hpp:83
This struct stores/contains information about a UTM coordinate.
Definition GeospatialOperations.hpp:211
This struct is used by the WaypointHandler class to store location, size, and type information about ...
Definition GeospatialOperations.hpp:423
const geoops::UTMCoordinate & GetUTMCoordinate() const
Accessor for the geoops::UTMCoordinate member variable.
Definition GeospatialOperations.hpp:508