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::UTMCoordinate& 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 + 90) * M_PI / 180;
59 double dCurrentSpacingWindUp = 0.0;
60 double dStartingX = stStartingPoint.dEasting;
61 double dStartingY = stStartingPoint.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;
81 stCurrentCoordinate.dEasting = dCurrentX;
82 stCurrentCoordinate.dNorthing = dCurrentY;
83 geoops::Waypoint stCurrentWaypoint(stCurrentCoordinate, geoops::WaypointType::eNavigationWaypoint);
84 vWaypoints.push_back(stCurrentWaypoint);
85
86 // Increment angle and radius for the next waypoint.
87 dAngleRadians += dAngularStepRadians;
88 dCurrentSpacingWindUp += dStartSpacing;
89
90 // Calculate the current distance from the starting point. This is our radius.
91 dCurrentRadius = geoops::CalculateGeoMeasurement(stStartingPoint, stCurrentCoordinate).dDistanceMeters;
92 }
93
94 // Write the search pattern points to the logger, just store the GPS lat/long.
95 std::string szSearchPatternPoints = "Search Pattern Points (Spiral): ";
96 for (geoops::Waypoint& stWaypoint : vWaypoints)
97 {
98 szSearchPatternPoints +=
99 "(" + std::to_string(stWaypoint.GetGPSCoordinate().dLatitude) + ", " + std::to_string(stWaypoint.GetGPSCoordinate().dLongitude) + "), ";
100 }
101 // Submit logger message.
102 LOG_DEBUG(logging::g_qSharedLogger, "{}", szSearchPatternPoints);
103
104 return vWaypoints;
105 }
106
107
124 inline std::vector<geoops::Waypoint> CalculateSpiralPatternWaypoints(const geoops::GPSCoordinate& stStartingPoint,
125 const double dAngularStepDegrees = 57,
126 const double dMaxRadius = 25,
127 const double dStartingHeadingDegrees = 0,
128 const double dStartSpacing = 1)
129 {
130 // Define variables.
131 std::vector<geoops::Waypoint> vWaypoints;
132 geoops::UTMCoordinate stStartingPointUTM = geoops::ConvertGPSToUTM(stStartingPoint);
133 double dAngularStepRadians = dAngularStepDegrees * M_PI / 180;
134 double dAngleRadians = (dStartingHeadingDegrees + 90) * M_PI / 180;
135 double dCurrentSpacingWindUp = 0.0;
136 double dStartingX = stStartingPointUTM.dEasting;
137 double dStartingY = stStartingPointUTM.dNorthing;
138 double dCurrentRadius = 0.0;
139
140 // Check if the MaxRadius is less than 1 meter. If so return an empty vector.
141 if (dMaxRadius < 1)
142 {
143 // Submit logger message.
144 LOG_WARNING(logging::g_qSharedLogger, "MaxRadius is less than 1 meter. Cannot create spiral pattern.");
145 return vWaypoints;
146 }
147
148 // Calculate each waypoint. Stop when the radius exceeds the maximum.
149 while (dCurrentRadius <= dMaxRadius)
150 {
151 // Get X and Y positions for the current point.
152 double dCurrentX = dStartingX + dCurrentSpacingWindUp * cos(dAngleRadians);
153 double dCurrentY = dStartingY + dCurrentSpacingWindUp * sin(dAngleRadians);
154
155 // Add the current waypoint to the final vector.
156 geoops::UTMCoordinate stCurrentCoordinate = stStartingPointUTM;
157 stCurrentCoordinate.dEasting = dCurrentX;
158 stCurrentCoordinate.dNorthing = dCurrentY;
159 geoops::Waypoint stCurrentWaypoint(stCurrentCoordinate, geoops::WaypointType::eNavigationWaypoint);
160 vWaypoints.push_back(stCurrentWaypoint);
161
162 // Increment angle and radius for the next waypoint.
163 dAngleRadians += dAngularStepRadians;
164 dCurrentSpacingWindUp += dStartSpacing;
165
166 // Calculate the current distance from the starting point. This is our radius.
167 dCurrentRadius = geoops::CalculateGeoMeasurement(stStartingPointUTM, stCurrentCoordinate).dDistanceMeters;
168 }
169
170 // Write the search pattern points to the logger, just store the GPS lat/long.
171 std::string szSearchPatternPoints = "Search Pattern Points (Spiral): ";
172 for (geoops::Waypoint& stWaypoint : vWaypoints)
173 {
174 szSearchPatternPoints +=
175 "(" + std::to_string(stWaypoint.GetGPSCoordinate().dLatitude) + ", " + std::to_string(stWaypoint.GetGPSCoordinate().dLongitude) + "), ";
176 }
177 // Submit logger message.
178 LOG_DEBUG(logging::g_qSharedLogger, "{}", szSearchPatternPoints);
179
180 return vWaypoints;
181 }
182
183
200 inline std::vector<geoops::Waypoint> CalculateZigZagPatternWaypoints(const geoops::UTMCoordinate& stCenterPoint,
201 const double dWidth = 20.0,
202 const double dHeight = 20.0,
203 const double dSpacing = 1.0,
204 const bool bVertical = true)
205 {
206 // Create instance variables.
207 std::vector<geoops::Waypoint> vWaypoints;
208 double dStartingX = stCenterPoint.dEasting - (dWidth / 2);
209 double dStartingY = stCenterPoint.dNorthing - (dHeight / 2);
210 double dCurrentX = dStartingX;
211 double dCurrentY = dStartingY;
212 bool bZigNotZag = true;
213 double bCalcSpacing = dSpacing;
214
215 // Check if the width or height is less than 1 meter. If so return an empty vector.
216 if (dWidth < 1 || dHeight < 1 || dSpacing < 1)
217 {
218 // Submit logger message.
219 LOG_WARNING(logging::g_qSharedLogger, "Width or height or spacing is less than 1 meter. Cannot create zigzag pattern.");
220 return vWaypoints;
221 }
222
223 // Limit spacing to the width or height.
224 if (bCalcSpacing > dWidth / 2.0)
225 {
226 // Submit logger message.
227 LOG_WARNING(logging::g_qSharedLogger, "Spacing is greater than width. Setting spacing to width / 2.");
228 // Set spacing to half the width.
229 bCalcSpacing = dWidth / 2.0 - 1.0;
230 }
231 if (bCalcSpacing > dHeight / 2.0)
232 {
233 // Submit logger message.
234 LOG_WARNING(logging::g_qSharedLogger, "Spacing is greater than height. Setting spacing to height / 2.");
235 // Set spacing to half the height.
236 bCalcSpacing = dHeight / 2.0 - 1.0;
237 }
238
239 // Loop until covered entire space of width and height.
240 while ((bVertical && dCurrentY <= dStartingY + dHeight) || (!bVertical && dCurrentX <= dStartingX + dWidth))
241 {
242 // Check if pattern should be vertical or horizontal.
243 if (bVertical)
244 {
245 // Check step direction.
246 if (bZigNotZag)
247 {
248 // Zig.
249 dCurrentX = dStartingX + (dWidth / 2);
250 }
251 else
252 {
253 // Zag.
254 dCurrentX = dStartingX - (dWidth / 2);
255 }
256 }
257 else
258 {
259 // Check step direction.
260 if (bZigNotZag)
261 {
262 // Zig.
263 dCurrentY = dStartingY + (dHeight / 2);
264 }
265 else
266 {
267 // Zag.
268 dCurrentY = dStartingY - (dHeight / 2);
269 }
270 }
271
272 // Loop and add points along line until we reached the limit or width or height.
273 while ((bZigNotZag && bVertical && dCurrentX <= dStartingX + dWidth) || (!bZigNotZag && bVertical && dCurrentX >= dStartingX) ||
274 (bZigNotZag && !bVertical && dCurrentY <= dStartingY + dHeight) || (!bZigNotZag && !bVertical && dCurrentY >= dStartingY))
275 {
276 // Construct UTMCoordinate.
277 geoops::UTMCoordinate stCurrentCoordinate = stCenterPoint;
278 stCurrentCoordinate.dEasting = dCurrentX;
279 stCurrentCoordinate.dNorthing = dCurrentY;
280 geoops::Waypoint stCurrentWaypoint(stCurrentCoordinate, geoops::WaypointType::eNavigationWaypoint);
281 // Add current waypoint to final path.
282 vWaypoints.push_back(stCurrentWaypoint);
283
284 // Move to the next point based on spacing and direction.
285 if (bVertical)
286 {
287 // Increment current position.
288 dCurrentX += bZigNotZag ? bCalcSpacing : -bCalcSpacing;
289 }
290 else
291 {
292 // Increment current position.
293 dCurrentY += bZigNotZag ? bCalcSpacing : -bCalcSpacing;
294 }
295 }
296
297 // Now shift the opposite coordinate forward.
298 if (bVertical)
299 {
300 dCurrentY += bCalcSpacing;
301 }
302 else
303 {
304 dCurrentX += bCalcSpacing;
305 }
306
307 // Toggle zigzag direction.
308 bZigNotZag = !bZigNotZag;
309 }
310
311 // The path now contains the zigzag pattern with points spaced at the specified distance. This means that there
312 // are many points potentially very close to each other. This is not ideal for navigation, so we will filter out
313 // points that are too close to each other, by calculating their GeoMeasurement and testing if the distance is greater
314 // then the CalcSpacing. If the CalcSpacing is greater a certain threshold, we will remove the point since it jumps to the other side.
315 // This will reduce the number of points in the zigzag pattern, making it more efficient for navigation.
316
317 // Create a vector to store the filtered waypoints.
318 std::vector<geoops::Waypoint> vFilterWaypoints;
319 // Always store the first point.
320 vFilterWaypoints.push_back(vWaypoints[0]);
321 // Loop through the waypoints and remove any that are too close to each other.
322 for (size_t i = 0; i < vWaypoints.size() - 1; ++i)
323 {
324 // Calculate the GeoMeasurement between the current waypoint and the next waypoint.
325 geoops::GeoMeasurement stGeoMeasurement = geoops::CalculateGeoMeasurement(vWaypoints[i].GetGPSCoordinate(), vWaypoints[i + 1].GetGPSCoordinate());
326 if (stGeoMeasurement.dDistanceMeters > bCalcSpacing * 1.5)
327 {
328 // Add the points to the filtered waypoints.
329 vFilterWaypoints.push_back(vWaypoints[i]);
330 vFilterWaypoints.push_back(vWaypoints[i + 1]);
331 }
332 }
333
334 // Write the search pattern points to the logger, just store the GPS lat/long.
335 std::string szSearchPatternPoints = "Search Pattern Points (Spiral): ";
336 for (geoops::Waypoint& stWaypoint : vWaypoints)
337 {
338 szSearchPatternPoints +=
339 "(" + std::to_string(stWaypoint.GetGPSCoordinate().dLatitude) + ", " + std::to_string(stWaypoint.GetGPSCoordinate().dLongitude) + "), ";
340 }
341 // Submit logger message.
342 LOG_DEBUG(logging::g_qSharedLogger, "{}", szSearchPatternPoints);
343
344 // Return the final path.
345 return vFilterWaypoints;
346 }
347
348
365 inline std::vector<geoops::Waypoint> CalculateZigZagPatternWaypoints(const geoops::GPSCoordinate& stCenterPoint,
366 const double dWidth = 20.0,
367 const double dHeight = 20.0,
368 const double dSpacing = 1.0,
369 const bool bVertical = true)
370 {
371 // Create instance variables.
372 std::vector<geoops::Waypoint> vWaypoints;
373 geoops::UTMCoordinate stCenterPointUTM = geoops::ConvertGPSToUTM(stCenterPoint);
374 double dStartingX = stCenterPointUTM.dEasting - (dWidth / 2);
375 double dStartingY = stCenterPointUTM.dNorthing - (dHeight / 2);
376 double dCurrentX = dStartingX;
377 double dCurrentY = dStartingY;
378 bool bZigNotZag = true;
379 double bCalcSpacing = dSpacing;
380
381 // Check if the width or height is less than 1 meter. If so return an empty vector.
382 if (dWidth < 1 || dHeight < 1 || dSpacing < 1)
383 {
384 // Submit logger message.
385 LOG_WARNING(logging::g_qSharedLogger, "Width or height or spacing is less than 1 meter. Cannot create zigzag pattern.");
386 return vWaypoints;
387 }
388
389 // Limit spacing to the width or height.
390 if (bCalcSpacing > dWidth / 2.0)
391 {
392 // Submit logger message.
393 LOG_WARNING(logging::g_qSharedLogger, "Spacing is greater than width. Setting spacing to width / 2.");
394 // Set spacing to half the width.
395 bCalcSpacing = dWidth / 2.0 - 1.0;
396 }
397 if (bCalcSpacing > dHeight / 2.0)
398 {
399 // Submit logger message.
400 LOG_WARNING(logging::g_qSharedLogger, "Spacing is greater than height. Setting spacing to height / 2.");
401 // Set spacing to half the height.
402 bCalcSpacing = dHeight / 2.0 - 1.0;
403 }
404
405 // Loop until covered entire space of width and height.
406 while ((bVertical && dCurrentY <= dStartingY + dHeight) || (!bVertical && dCurrentX <= dStartingX + dWidth))
407 {
408 // Check if pattern should be vertical or horizontal.
409 if (bVertical)
410 {
411 // Check step direction.
412 if (bZigNotZag)
413 {
414 // Zig.
415 dCurrentX = dStartingX + bCalcSpacing;
416 }
417 else
418 {
419 // Zag.
420 dCurrentX = dStartingX - bCalcSpacing;
421 }
422 }
423 else
424 {
425 // Check step direction.
426 if (bZigNotZag)
427 {
428 // Zig.
429 dCurrentY = dStartingY + bCalcSpacing;
430 }
431 else
432 {
433 // Zag.
434 dCurrentY = dStartingY - bCalcSpacing;
435 }
436 }
437
438 // Loop and add points along line until we reached the limit or width or height.
439 while ((bZigNotZag && bVertical && dCurrentX <= dStartingX + dWidth) || (!bZigNotZag && bVertical && dCurrentX >= dStartingX) ||
440 (bZigNotZag && !bVertical && dCurrentY <= dStartingY + dHeight) || (!bZigNotZag && !bVertical && dCurrentY >= dStartingY))
441 {
442 // Construct UTMCoordinate.
443 geoops::UTMCoordinate stCurrentCoordinate = stCenterPointUTM;
444 stCurrentCoordinate.dEasting = dCurrentX;
445 stCurrentCoordinate.dNorthing = dCurrentY;
446 geoops::Waypoint stCurrentWaypoint(stCurrentCoordinate, geoops::WaypointType::eNavigationWaypoint);
447 // Add current waypoint to final path.
448 vWaypoints.push_back(stCurrentWaypoint);
449
450 // Move to the next point based on spacing and direction.
451 if (bVertical)
452 {
453 // Increment current position.
454 dCurrentX += bZigNotZag ? bCalcSpacing : -bCalcSpacing;
455 }
456 else
457 {
458 // Increment current position.
459 dCurrentY += bZigNotZag ? bCalcSpacing : -bCalcSpacing;
460 }
461 }
462
463 // Now shift the opposite coordinate forward.
464 if (bVertical)
465 {
466 dCurrentY += bCalcSpacing;
467 }
468 else
469 {
470 dCurrentX += bCalcSpacing;
471 }
472
473 // Toggle zigzag direction.
474 bZigNotZag = !bZigNotZag;
475 }
476
477 // The path now contains the zigzag pattern with points spaced at the specified distance. This means that there
478 // are many points potentially very close to each other. This is not ideal for navigation, so we will filter out
479 // points that are too close to each other, by calculating their GeoMeasurement and testing if the distance is greater
480 // then the CalcSpacing. If the CalcSpacing is greater a certain threshold, we will remove the point since it jumps to the other side.
481 // This will reduce the number of points in the zigzag pattern, making it more efficient for navigation.
482
483 // Create a vector to store the filtered waypoints.
484 std::vector<geoops::Waypoint> vFilterWaypoints;
485 // Always store the first point.
486 vFilterWaypoints.push_back(vWaypoints[0]);
487 // Loop through the waypoints and remove any that are too close to each other.
488 for (size_t i = 0; i < vWaypoints.size() - 1; ++i)
489 {
490 // Calculate the GeoMeasurement between the current waypoint and the next waypoint.
491 geoops::GeoMeasurement stGeoMeasurement = geoops::CalculateGeoMeasurement(vWaypoints[i].GetGPSCoordinate(), vWaypoints[i + 1].GetGPSCoordinate());
492 if (stGeoMeasurement.dDistanceMeters > bCalcSpacing * 1.5)
493 {
494 // Add the points to the filtered waypoints.
495 vFilterWaypoints.push_back(vWaypoints[i]);
496 vFilterWaypoints.push_back(vWaypoints[i + 1]);
497 }
498 }
499
500 // Write the search pattern points to the logger, just store the GPS lat/long.
501 std::string szSearchPatternPoints = "Search Pattern Points (Spiral): ";
502 for (geoops::Waypoint& stWaypoint : vWaypoints)
503 {
504 szSearchPatternPoints +=
505 "(" + std::to_string(stWaypoint.GetGPSCoordinate().dLatitude) + ", " + std::to_string(stWaypoint.GetGPSCoordinate().dLongitude) + "), ";
506 }
507 // Submit logger message.
508 LOG_DEBUG(logging::g_qSharedLogger, "{}", szSearchPatternPoints);
509
510 // Return the final path.
511 return vFilterWaypoints;
512 }
513} // namespace searchpattern
514#endif
__device__ __forceinline__ float1 cos(const uchar1 &a)
__device__ __forceinline__ float4 sin(const uchar4 &a)
UTMCoordinate ConvertGPSToUTM(const GPSCoordinate &stGPSCoord)
Given a GPS coordinate, convert to UTM and create a new UTMCoordinate object.
Definition GeospatialOperations.hpp:351
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:445
Namespace containing algorithms related to calculating drive powers, odometry, trajectories,...
Definition SearchPattern.hpp:31
std::vector< geoops::Waypoint > CalculateZigZagPatternWaypoints(const geoops::UTMCoordinate &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:200
std::vector< geoops::Waypoint > CalculateSpiralPatternWaypoints(const geoops::UTMCoordinate &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
This struct stores/contains information about a GPS data.
Definition GeospatialOperations.hpp:148
This struct is used to store the distance, arc length, and relative bearing for a calculated geodesic...
Definition GeospatialOperations.hpp:82
This struct stores/contains information about a UTM coordinate.
Definition GeospatialOperations.hpp:244
This struct is used by the WaypointHandler class to store location, size, and type information about ...
Definition GeospatialOperations.hpp:551