Formula Student Autonomous Systems
The code for the main driverless system
Loading...
Searching...
No Matches
competitionLogic.cpp
Go to the documentation of this file.
2
3CompetitionLogic::CompetitionLogic(std::shared_ptr<Logger> logger, Track& track, MainConfig config)
4{
5 timeKeepingStatuses = std::vector<int>(track.time_keeping_gates.size(), 0);
6 timeKeepingFirstTriggerStatuses = std::vector<int>(track.time_keeping_gates.size(), 0);
7 triggerTimes = std::vector<std::vector<double>>(track.time_keeping_gates.size(), std::vector<double>());
8 lapTimes = std::vector<double>();
9 currentSectorTimes = std::vector<double>();
10 sectorTimes = std::vector<std::vector<double>>();
11
12 started = false;
13 startedTime = 0;
14 lapCount = 0;
16 discipline = config.discipline;
18 finishConditionsMet = false;
19 alreadyOC = false;
20 Off_Course_Start = 0.0;
21 isDNF = false;
22 dnf_reason = "";
23 penalties = std::vector<Penalty>();
24 ussTriggered = false;
25 finishSignal = false;
33 = (track.left_lane.size() > 3) && (track.right_lane.size() >= 3) && (track.time_keeping_gates.size() >= 1);
34 if (!properTrack)
35 {
36 started = true; // can't check for timeout_start
37 timeout_trackdrive_first = timeout_trackdrive_total; // we can't check first lap
38 logger->logError("Track file is incomplete, very limited competition logic functionality!");
39 }
40}
41
42bool CompetitionLogic::pointInTriangle(Eigen::Vector2d a, Eigen::Vector2d b, Eigen::Vector2d c, Eigen::Vector2d point)
43{
44 double as = ((b.y() - c.y()) * (point.x() - c.x()) + (c.x() - b.x()) * (point.y() - c.y()))
45 / ((b.y() - c.y()) * (a.x() - c.x()) + (c.x() - b.x()) * (a.y() - c.y()));
46 double bs = ((c.y() - a.y()) * (point.x() - c.x()) + (a.x() - c.x()) * (point.y() - c.y()))
47 / ((b.y() - c.y()) * (a.x() - c.x()) + (c.x() - b.x()) * (a.y() - c.y()));
48 double cs = 1 - as - bs;
49
50 return ((as >= 0) && (as <= 1) && (bs >= 0) && (bs <= 1) && (cs >= 0) && (cs <= 1));
51}
52
53std::vector<bool> CompetitionLogic::pointsInTrackConnected(Track& track, std::vector<Eigen::Vector2d> points)
54{
55 std::vector<size_t> leftToRight;
56 leftToRight.reserve(track.left_lane.size());
57 std::vector<size_t> rightToLeft;
58 rightToLeft.reserve(track.right_lane.size());
59 Eigen::Vector2d referencePoint = points.at(0);
60
61 size_t currentLeftIndex = 0;
62 for (size_t i = 0; i < track.left_lane.size(); ++i)
63 {
64 auto left_cone = track.left_lane.at(i);
65 // search in limited window
66 size_t argmin_local = 0;
67 double min_dist_local = std::numeric_limits<double>::max();
68 for (size_t j = 0; j < 5; ++j)
69 {
70 auto right_cone = track.right_lane.at((j + currentLeftIndex) % track.right_lane.size());
71 double dist = (left_cone.position - right_cone.position).norm();
72 if (dist < min_dist_local)
73 {
74 argmin_local = j;
75 min_dist_local = dist;
76 }
77 }
78 currentLeftIndex += argmin_local;
79 leftToRight.push_back(currentLeftIndex);
80 }
81
82 size_t currentRightIndex = 0;
83 for (size_t i = 0; i < track.right_lane.size(); ++i)
84 {
85 auto right_cone = track.right_lane.at(i);
86 // search in limited window
87 size_t argmin_local = 0;
88 double min_dist_local = std::numeric_limits<double>::max();
89 for (size_t j = 0; j < 5; ++j)
90 {
91 auto left_cone = track.left_lane.at((j + currentRightIndex) % track.left_lane.size());
92 double dist = (left_cone.position - right_cone.position).norm();
93 if (dist < min_dist_local)
94 {
95 argmin_local = j;
96 min_dist_local = dist;
97 }
98 }
99 currentRightIndex += argmin_local;
100 rightToLeft.push_back(currentRightIndex);
101 }
102
103 // step 2 find closest cone to car
104 double bestDist = std::numeric_limits<double>::max();
105 size_t indexLeft;
106 size_t indexRight;
107 for (size_t i = 0; i < track.left_lane.size(); ++i)
108 {
109 double dist = (track.left_lane[i].position.head(2) - referencePoint).norm();
110 if (dist < bestDist)
111 {
112 indexLeft = i;
113 indexRight = leftToRight.at(i);
114 bestDist = dist;
115 }
116 }
117 for (size_t i = 0; i < track.right_lane.size(); ++i)
118 {
119 double dist = (track.right_lane[i].position.head(2) - referencePoint).norm();
120 if (dist < bestDist)
121 {
122 indexLeft = rightToLeft.at(i);
123 indexRight = i;
124 bestDist = dist;
125 }
126 }
127 // build triangles from left lane
128 std::vector<std::vector<Eigen::Vector2d>> triPoints;
129 for (int i = -7; i < 7; ++i)
130 {
131 Eigen::Vector2d left1
132 = track.left_lane.at((indexLeft + i - 1 + track.left_lane.size()) % track.left_lane.size())
133 .position.head(2);
134 Eigen::Vector2d left2
135 = track.left_lane.at((indexLeft + i + track.left_lane.size()) % track.left_lane.size()).position.head(2);
136 Eigen::Vector2d right1
137 = track.right_lane
138 .at((leftToRight.at((indexLeft + i - 1 + track.left_lane.size()) % track.left_lane.size())
139 + track.right_lane.size())
140 % track.right_lane.size())
141 .position.head(2);
142 Eigen::Vector2d right2
143 = track.right_lane
144 .at((leftToRight.at((indexLeft + i + track.left_lane.size()) % track.left_lane.size())
145 + track.right_lane.size())
146 % track.right_lane.size())
147 .position.head(2);
148 std::vector<Eigen::Vector2d> tmpVector { left1, left2, right1 };
149 std::vector<Eigen::Vector2d> tmpVector2 { left1, left2, right2 };
150 triPoints.push_back(tmpVector);
151 triPoints.push_back(tmpVector2);
152 }
153 // build triangles from right lane
154 for (int i = -7; i < 7; ++i)
155 {
156 Eigen::Vector2d right1
157 = track.right_lane.at((indexLeft + i - 1 + track.right_lane.size()) % track.right_lane.size())
158 .position.head(2);
159 Eigen::Vector2d right2
160 = track.right_lane.at((indexLeft + i + track.right_lane.size()) % track.right_lane.size()).position.head(2);
161 Eigen::Vector2d left1
162 = track.left_lane
163 .at((rightToLeft.at((indexRight + i - 1 + track.right_lane.size()) % track.right_lane.size())
164 + track.left_lane.size())
165 % track.left_lane.size())
166 .position.head(2);
167 Eigen::Vector2d left2
168 = track.left_lane
169 .at((rightToLeft.at((indexRight + i + track.right_lane.size()) % track.right_lane.size())
170 + track.left_lane.size())
171 % track.left_lane.size())
172 .position.head(2);
173 std::vector<Eigen::Vector2d> tmpVector { right1, right2, left1 };
174 std::vector<Eigen::Vector2d> tmpVector2 { right1, right2, left2 };
175 triPoints.push_back(tmpVector);
176 triPoints.push_back(tmpVector2);
177 }
178 // check all triangels
179 std::vector<bool> ret;
180 for (Eigen::Vector2d& point : points)
181 {
182 bool inTrack = false;
183 for (int i = 0; i < triPoints.size(); ++i)
184 {
185 inTrack = inTrack
186 || pointInTriangle(triPoints.at(i).at(0), triPoints.at(i).at(1), triPoints.at(i).at(2), point);
187 }
188 ret.push_back(inTrack);
189 }
190 return ret;
191}
192
193double CompetitionLogic::cross2d(Eigen::Vector2d a, Eigen::Vector2d b) { return (a.x() * b.y() - a.y() * b.x()); }
194
196 Eigen::Vector2d a, Eigen::Vector2d b, Eigen::Vector2d rayOrigin, Eigen::Vector2d rayDirection)
197{
198 // thank you gareth rees
199 // https://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect/565282#565282
200 Eigen::Vector2d segDirection = b - a;
201 double RayDxSegD = cross2d(rayDirection, segDirection);
202 double aRayOxRayD = cross2d(a - rayOrigin, rayDirection);
203 // colinear
204 if (RayDxSegD == 0 && aRayOxRayD == 0)
205 {
206 return std::make_pair(false, true);
207 }
208 // parallel
209 else if (RayDxSegD == 0 && aRayOxRayD != 0)
210 {
211 return std::make_pair(false, false);
212 }
213 // may intersect
214 else if (RayDxSegD != 0)
215 {
216 double u = aRayOxRayD / RayDxSegD;
217 double t = cross2d(a - rayOrigin, segDirection) / RayDxSegD;
218 if (t > 0 && (u >= 0) && (u <= 1))
219 {
220 return std::make_pair(true, false);
221 }
222 else
223 {
224 return std::make_pair(false, false);
225 }
226 double x = 1;
227 }
228 // not parallel but no intersect
229 else
230 {
231 return std::make_pair(false, false);
232 }
233}
234
235bool CompetitionLogic::pointInPolygon(std::vector<Eigen::Vector2d> polyPoints, Eigen::Vector2d point)
236{
237 // use ray-casting approach https://en.wikipedia.org/wiki/Point_in_polygon
238 // uneven amount of intersections -> in polygon, else not in polygon
239 bool ret = false;
240 int intersectCount = 0;
241 double rayAngle = 0.01;
242 size_t iters = 0;
243 bool tryRays = true;
244 while (tryRays)
245 {
246 // if we tried too often, screw it and just don't trigger a false positive.
247 if (iters > 30)
248 {
249 return true;
250 }
251 iters += 1;
252 Eigen::Vector2d rayDirection(std::cos(rayAngle), std::sin(rayAngle));
253 for (int i = 1; i < polyPoints.size(); ++i)
254 {
255 std::pair<bool, bool> intersectRes
256 = rayIntersectLineSegment(polyPoints[i - 1], polyPoints[i], point, Eigen::Vector2d(1, 0));
257 // if ray is colinear with polygon edge, vary ray direction slightly
258 if (intersectRes.second)
259 {
260 intersectCount = 0;
261 rayAngle += 0.01;
262 break;
263 }
264 if (intersectRes.first)
265 {
266 intersectCount += 1;
267 }
268 }
269 tryRays = false;
270 }
271 ret = (intersectCount % 2) == 1;
272 return ret;
273}
274
275std::vector<bool> CompetitionLogic::pointsInTrackNotConnected(Track& track, std::vector<Eigen::Vector2d> points)
276{
277 std::vector<Eigen::Vector2d> polyPoints;
278 for (Landmark& lm : track.left_lane)
279 {
280 polyPoints.push_back(lm.position.head(2));
281 }
282 for (int i = (track.right_lane.size() - 1); i >= 0; --i)
283 {
284 polyPoints.push_back(track.right_lane[i].position.head(2));
285 }
286 polyPoints.push_back(track.left_lane[0].position.head(2));
287
288 Eigen::Vector2d point(0, 0);
289 std::vector<bool> ret;
290 for (auto& point : points)
291 {
292 ret.push_back(pointInPolygon(polyPoints, point));
293 }
294 return ret;
295}
296
298 Track& track, double time, Eigen::Vector3d& position, Eigen::Vector3d& orientation)
299{
300 double lf = 0.75;
301 double lr = 0.75;
302 double halfwidth = 0.6;
303 Eigen::Vector2d flLocal(lf, halfwidth);
304 Eigen::Vector2d frLocal(lf, -halfwidth);
305 Eigen::Vector2d rlLocal(-lr, halfwidth);
306 Eigen::Vector2d rrLocal(-lr, -halfwidth);
307 Eigen::Matrix2d rotM;
308 rotM << std::cos(orientation.z()), -std::sin(orientation.z()), std::sin(orientation.z()), std::cos(orientation.z());
309 Eigen::Vector2d fl = position.head(2) + rotM * flLocal;
310 Eigen::Vector2d fr = position.head(2) + rotM * frLocal;
311 Eigen::Vector2d rl = position.head(2) + rotM * rlLocal;
312 Eigen::Vector2d rr = position.head(2) + rotM * rrLocal;
313 std::vector<Eigen::Vector2d> pointsToBeChecked { fl, fr, rl, rr };
314 std::vector<bool> inTrack;
316 {
317 inTrack = pointsInTrackConnected(track, pointsToBeChecked);
318 }
319 else
320 {
321 inTrack = pointsInTrackNotConnected(track, pointsToBeChecked);
322 }
323 bool flOk = inTrack.at(0);
324 bool frOk = inTrack.at(1);
325 bool rlOk = inTrack.at(2);
326 bool rrOk = inTrack.at(3);
327
328 bool inLane = flOk || frOk || rlOk || rrOk;
329 if (!inLane)
330 {
332 {
333 Penalty p;
334 p.lap = lapTimes.size();
335 p.penalty_time = 10.0;
337 p.occurence_time = time;
338 penalties.push_back(p);
339 }
340 Off_Course_Start = time;
341 }
342 alreadyOC = !inLane;
343 return inLane;
344}
345
346bool CompetitionLogic::carConePolyIntersect(std::vector<Eigen::Vector2d> carPoly, std::vector<Eigen::Vector2d> conePoly)
347{
348 // assumptions: car shape is a pretty much a rectangle and much bigger than cone, so point in poly is enough of a
349 // check
350 bool result = false;
351 // dont need to check last point because it's equal to first one
352 for (int i = 0; i < (conePoly.size() - 1); ++i)
353 {
354 result = result || pointInPolygon(carPoly, conePoly.at(i));
355 }
356 for (int i = 0; i < (carPoly.size() - 1); ++i)
357 {
358 result = result || pointInPolygon(conePoly, carPoly.at(i));
359 }
360 return result;
361}
362
364 Track& track, double time, Eigen::Vector3d& position, Eigen::Vector3d& orientation)
365{
366 double lf = 0.75 + 0.9;
367 double lr = 0.75 + 0.3;
368 double halfwidth = 0.6;
369 Eigen::Vector2d flLocal(lf, halfwidth);
370 Eigen::Vector2d frLocal(lf, -halfwidth);
371 Eigen::Vector2d rlLocal(-lr, halfwidth);
372 Eigen::Vector2d rrLocal(-lr, -halfwidth);
373 Eigen::Matrix2d rotM;
374 rotM << std::cos(orientation.z()), -std::sin(orientation.z()), std::sin(orientation.z()), std::cos(orientation.z());
375 Eigen::Vector2d fl = position.head(2) + rotM * flLocal;
376 Eigen::Vector2d fr = position.head(2) + rotM * frLocal;
377 Eigen::Vector2d rl = position.head(2) + rotM * rlLocal;
378 Eigen::Vector2d rr = position.head(2) + rotM * rrLocal;
379 std::vector<Eigen::Vector2d> pointsToBeChecked { fl, fr, rr, rl, fl };
380
381 double coneCheckDist = 5.0;
382 double coneWidth = 0.228;
383 std::vector<Landmark*> closeCones;
384 double closeThresh = 5.0;
385 for (int i = 0; i < track.left_lane.size(); ++i)
386 {
387 if ((position.head(2) - track.left_lane.at(i).position.head(2)).norm() <= closeThresh)
388 {
389 closeCones.push_back(&track.left_lane.at(i));
390 }
391 }
392 for (int i = 0; i < track.right_lane.size(); ++i)
393 {
394 if ((position.head(2) - track.right_lane.at(i).position.head(2)).norm() <= closeThresh)
395 {
396 closeCones.push_back(&track.right_lane.at(i));
397 }
398 }
399 for (int i = 0; i < track.unknown.size(); ++i)
400 {
401 if ((position.head(2) - track.unknown.at(i).position.head(2)).norm() <= closeThresh)
402 {
403 closeCones.push_back(&track.unknown.at(i));
404 }
405 }
406
407 for (int i = 0; i < closeCones.size(); ++i)
408 {
409 Eigen::Vector2d conePos = closeCones.at(i)->position.head(2);
410 Eigen::Vector2d p1 = conePos + Eigen::Vector2d(coneWidth * 0.5, coneWidth * 0.5);
411 Eigen::Vector2d p2 = conePos + Eigen::Vector2d(coneWidth * 0.5, -coneWidth * 0.5);
412 Eigen::Vector2d p3 = conePos + Eigen::Vector2d(-coneWidth * 0.5, -coneWidth * 0.5);
413 Eigen::Vector2d p4 = conePos + Eigen::Vector2d(-coneWidth * 0.5, coneWidth * 0.5);
414 std::vector<Eigen::Vector2d> conePoints { p1, p2, p3, p4, p1 };
415 bool hitStatus = carConePolyIntersect(pointsToBeChecked, conePoints);
416 if (!closeCones.at(i)->beenHit && hitStatus)
417 {
418 Penalty p;
419 p.lap = lapTimes.size();
420 p.occurence_time = time;
422 p.penalty_time = 2.0;
424 {
425 p.penalty_time = 0.2;
426 }
427 penalties.push_back(p);
428 }
429 closeCones.at(i)->beenHit = closeCones.at(i)->beenHit || hitStatus;
430 }
431
432 return;
433}
434
435double CompetitionLogic::determinantLinePoint(Eigen::Vector2d a, Eigen::Vector2d b, Eigen::Vector2d c)
436{
437 double ret = (b.x() - a.x()) * (c.y() - a.y()) - (c.x() - a.x()) * (b.y() - a.y());
438 return ret;
439}
440
441bool CompetitionLogic::inLineSegement(Eigen::Vector2d a, Eigen::Vector2d b, Eigen::Vector2d position)
442{
443 Eigen::Vector2d slope = b - a;
444 Eigen::Vector2d slopeOrtho = Eigen::Vector2d(-slope.y(), slope.x()).normalized();
445 Eigen::Vector2d orthoBack1 = a - slopeOrtho;
446 Eigen::Vector2d orthoBack2 = a + slopeOrtho;
447 Eigen::Vector2d orthoFront1 = b - slopeOrtho;
448 Eigen::Vector2d orthoFront2 = b + slopeOrtho;
449 bool backOk = determinantLinePoint(orthoBack1, orthoBack2, position) <= 0;
450 bool frontOk = determinantLinePoint(orthoFront1, orthoFront2, position) >= 0;
451 bool ret = backOk && frontOk;
452 return ret;
453}
454
456 Eigen::Vector3d lm1, Eigen::Vector3d lm2, Eigen::Vector3d& position, Eigen::Vector3d& orientation)
457{
458 Eigen::Vector2d transponderPosition = position.head(2);
459 int ret = 0;
460 if (inLineSegement(lm1.head(2), lm2.head(2), transponderPosition))
461 {
462 double valLine = determinantLinePoint(lm1.head(2), lm2.head(2), transponderPosition);
463 ret = 1 + static_cast<int>(valLine <= 0);
464 }
465 return ret;
466}
467
469{
470 int i = index;
471 // start/finish
472 if (i == 0)
473 {
474 if (!started)
475 {
476 startedTime = time;
477 }
478 started = true;
479 if (triggerTimes[i].size() >= 1)
480 {
481 double timeDiff = time - triggerTimes[0][triggerTimes[0].size() - 1];
482 lapTimes.push_back(timeDiff);
483 lapCount = lapTimes.size();
485 currentSectorTimes.clear();
486 }
487 }
488 else if (i == 1 && !track.lanesFirstWithLastConnected && discipline != Discipline::SKIDPAD)
489 {
490 if (triggerTimes[0].size() >= 1)
491 {
492 double timeDiff = time - triggerTimes[0][triggerTimes[0].size() - 1];
493 lapTimes.push_back(timeDiff);
495 currentSectorTimes.clear();
496 }
497 }
498 // sector time
499 else
500 {
501 double sectorTime = time - lastTriggerTime;
502 currentSectorTimes.push_back(time);
503 }
504 triggerTimes[i].push_back(time);
505 lastTriggerTime = time;
506}
507
509 Track& track, Eigen::Vector3d& position, Eigen::Vector3d& orientation, double time)
510{
511 for (int i = 0; i < track.time_keeping_gates.size(); ++i)
512 {
513 int res = this->timeKeepingStatus(track.time_keeping_gates[i].first.position,
514 track.time_keeping_gates[i].second.position, position, orientation);
515 if (res != 0)
516 {
517 // know which side we first get close to gate, that's "behind"
518 if (timeKeepingStatuses[i] == 0)
519 {
521 }
522 // we just got in front of the gate, trigger lap
523 if ((timeKeepingStatuses[i] != res) && (res != timeKeepingFirstTriggerStatuses[i]))
524 {
525 evaluateTimeKeepingGateTrigger(track, time, i);
526 }
527 timeKeepingStatuses[i] = res;
528 }
529 }
530}
531
533{
534 bool ret = false;
536 {
537 ret = (lapTimes.size() == 4 && triggerTimes.at(1).size() >= 1);
538 }
540 {
541 ret = (triggerTimes[1].size() >= 1);
542 }
544 {
545 ret = lapTimes.size() >= 1;
546 }
548 {
549 ret = lapTimes.size() >= 10;
550 }
551 if (ret && !finishConditionsMet)
552 {
553 RCLCPP_INFO_STREAM(rclcpp::get_logger("pacsim_logger"), "Finish conditions met at!");
556 }
557 return ret;
558}
559
560double distanceToLineSegment(Eigen::Vector2d a, Eigen::Vector2d b, Eigen::Vector2d point)
561{
562 // https://stackoverflow.com/a/6853926
563 double x1 = a.x();
564 double x2 = b.x();
565 double y1 = a.y();
566 double y2 = b.y();
567 double x = point.x();
568 double y = point.y();
569 double A = x - x1;
570 double B = y - y1;
571 double C = x2 - x1;
572 double D = y2 - y1;
573
574 double dot = A * C + B * D;
575 double len_sq = C * C + D * D;
576 double param = -1;
577 if (len_sq != 0) // in case of 0 length line
578 param = dot / len_sq;
579
580 double xx, yy;
581
582 if (param < 0)
583 {
584 xx = x1;
585 yy = y1;
586 }
587 else if (param > 1)
588 {
589 xx = x2;
590 yy = y2;
591 }
592 else
593 {
594 xx = x1 + param * C;
595 yy = y1 + param * D;
596 }
597
598 double dx = x - xx;
599 double dy = y - yy;
600 double ret = std::sqrt(dx * dx + dy * dy);
601 return ret;
602}
603
604bool CompetitionLogic::checkUSS(Track track, double time, Eigen::Vector3d position)
605{
606 bool ret = false;
608 {
610 {
611 ret = ret
612 || (distanceToLineSegment(track.time_keeping_gates[0].first.position.head(2),
613 track.time_keeping_gates[0].second.position.head(2), position.head(2))
614 >= 30.0);
615 }
616 // a bit simplified because a few seconds can pass between passing line and standing in finish area
617 ret = ret || ((time - finishConditionsMetFirstTime) >= (30 + 3));
619 {
620 Penalty p;
621 p.lap = lapTimes.size();
622 p.occurence_time = time;
624 p.penalty_time = 10.0;
625 penalties.push_back(p);
626 }
627 }
628
629 return ret;
630}
631
632bool CompetitionLogic::checkDNF(Track track, double time, Eigen::Vector3d position)
633{
634 // TODO: check for shortcut
635 bool ret = false;
637 {
638 if (checkUSS(track, time, position))
639 {
640 ret = true;
641 dnf_reason = "USS";
642 }
643 }
644 // skidpad icorrect turn direction
646 {
647 bool goneWrongLeft
648 = ((position.y() > 9.125) && (lapTimes.size() == 0 || lapTimes.size() == 1 || lapTimes.size() >= 4));
649 bool goneWrongRight
650 = ((position.y() < -9.125) && (lapTimes.size() == 2 || lapTimes.size() == 3 || lapTimes.size() >= 4));
651 if (goneWrongLeft || goneWrongRight)
652 {
653 ret = true;
654 dnf_reason = "incorrect_turn_direction";
655 }
656 }
657 if (alreadyOC)
658 {
659 bool any = false;
660 any = any || (discipline == Discipline::ACCELERATION);
661 any = any || (discipline == Discipline::SKIDPAD);
662 // excessive off-course check
663 // my definition: too long or too far out
664 // TODO also check too far our case
665 any = any || ((time - Off_Course_Start) >= 8);
666 if (any)
667 {
668 ret = true;
669 dnf_reason = "OC";
670 RCLCPP_INFO_STREAM(rclcpp::get_logger("pacsim_logger"), "checkDNF returned DNF = true");
671 }
672 }
673 isDNF = isDNF || ret;
674 if (isDNF) {
675 RCLCPP_INFO_STREAM(rclcpp::get_logger("pacsim_logger"), "checkDNF returned DNF = true");
676 }
677 return isDNF;
678}
679
681{
682 bool ret = false;
684 {
685 if (!started && (time > timeout_start))
686 {
687 ret = true;
688 }
689 if (started)
690 {
691 double timePassed = time - startedTime;
693 {
694 if (timePassed > timeout_autocross)
695 {
696 ret = true;
697 }
698 }
699 // TODO: rule D 2.7.4, consider track length
701 {
702 if ((lapCount == 0) && timePassed > timeout_trackdrive_first)
703 {
704 ret = true;
705 }
706 if ((lapCount >= 0) && timePassed > timeout_trackdrive_total)
707 {
708 ret = true;
709 }
710 }
712 {
713 if (timePassed > timeout_acceleration)
714 {
715 ret = true;
716 }
717 }
719 {
720 if (timePassed > timeout_skidpad)
721 {
722 ret = true;
723 }
724 }
725 }
726 if (ret)
727 {
728 dnf_reason = "TIMEOUT";
729 }
730 }
731 return ret;
732}
733
735 Track& track, double time, Eigen::Vector3d& position, Eigen::Vector3d& orientation)
736{
737 // return true when simulation should stop
738 bool ret = false;
739 if (properTrack)
740 {
741 evaluateOffCourse(track, time, position, orientation);
742 evaluateTimeKeepings(track, position, orientation, time);
744 ussTriggered = ussTriggered || checkUSS(track, time, position);
745 ret = ret || checkDNF(track, time, position);
746 }
747 evaluateConeHit(track, time, position, orientation);
748 ret = ret || checkTimeout(time);
749 ret = ret || finishSignal;
750 return ret;
751}
752
754{
755 finishSignal = val;
756 return;
757}
758
760{
761 std::string ret = "unknown";
762 if (d == Discipline::AUTOCROSS)
763 {
764 ret = "autocross";
765 }
766 else if (d == Discipline::TRACKDRIVE)
767 {
768 ret = "trackdrive";
769 }
770 else if (d == Discipline::ACCELERATION)
771 {
772 ret = "acceleration";
773 }
774 else if (d == Discipline::SKIDPAD)
775 {
776 ret = "skidpad";
777 }
778 return ret;
779}
780
782{
783 std::string ret = "unknown";
784 if (p == PENALTY_TYPE::DOO)
785 {
786 ret = "doo";
787 }
788 else if (p == PENALTY_TYPE::OC)
789 {
790 ret = "oc";
791 }
792 else if (p == PENALTY_TYPE::USS)
793 {
794 ret = "uss";
795 }
796 return ret;
797}
798
799void CompetitionLogic::fillReport(Report& report, double time)
800{
802 report.success = (!isDNF) && (finishSignal && checkFinishConditionsMet(time));
803 report.dnf_reason = dnf_reason;
804 report.total_sim_time = time;
805 report.final_time_raw = 0;
806 report.timeout_first_lap = 0;
807 report.timeout_total = 0;
809 {
811 report.timeout_first_lap = report.timeout_total;
812 }
814 {
817 }
819 {
821 report.timeout_first_lap = report.timeout_total;
822 }
824 {
826 report.timeout_first_lap = report.timeout_total;
827 }
828
829 if (!properTrack)
830 {
831 report.success = false;
832 report.dnf_reason = "INCORRECT_TRACK_FILE";
833 }
834
835 report.off_course_detect = true && properTrack;
836 report.cone_hit_detect = true;
837 report.uss_detect = true && properTrack;
838
839 for (auto t : lapTimes)
840 {
841 report.final_time_raw += t;
842 }
843 if ((discipline == Discipline::SKIDPAD) && report.success)
844 {
845 report.final_time_raw = 0.5 * (lapTimes.at(1) + lapTimes.at(3));
846 }
847 report.final_time = report.final_time_raw;
848 for (int i = 0; i < lapTimes.size(); ++i)
849 {
850 Report::LapTime time;
851 time.time = lapTimes[i];
852 std::vector<double> sectors;
853 for (int j = 0; j < sectorTimes[i].size(); ++j)
854 {
855 sectors.push_back(sectorTimes[i][j]);
856 }
857 time.sector_times = sectors;
858 report.lap_times.push_back(time);
859 }
860 for (int i = 0; i < penalties.size(); ++i)
861 {
863 p.lap = penalties[i].lap;
864 p.penalty_time = penalties[i].penalty_time;
865 report.final_time += p.penalty_time;
866 p.occurence_time = penalties[i].occurence_time;
867 p.position = penalties[i].position;
868 p.reason = penalty2str(penalties[i].reason);
869 report.penalties.push_back(p);
870 }
871}
bool checkUSS(Track track, double time, Eigen::Vector3d position)
std::vector< std::vector< double > > sectorTimes
double cross2d(Eigen::Vector2d a, Eigen::Vector2d b)
std::vector< double > currentSectorTimes
bool evaluateOffCourse(Track &track, double time, Eigen::Vector3d &position, Eigen::Vector3d &orientation)
bool pointInTriangle(Eigen::Vector2d a, Eigen::Vector2d b, Eigen::Vector2d c, Eigen::Vector2d point)
std::vector< bool > pointsInTrackConnected(Track &track, std::vector< Eigen::Vector2d > points)
bool checkDNF(Track track, double time, Eigen::Vector3d position)
std::vector< int > timeKeepingStatuses
std::vector< Penalty > penalties
bool carConePolyIntersect(std::vector< Eigen::Vector2d > carPoly, std::vector< Eigen::Vector2d > conePoly)
bool inLineSegement(Eigen::Vector2d a, Eigen::Vector2d b, Eigen::Vector2d position)
int timeKeepingStatus(Eigen::Vector3d lm1, Eigen::Vector3d lm2, Eigen::Vector3d &position, Eigen::Vector3d &orientation)
std::vector< bool > pointsInTrackNotConnected(Track &track, std::vector< Eigen::Vector2d > points)
bool pointInPolygon(std::vector< Eigen::Vector2d > polyPoints, Eigen::Vector2d point)
void setFinish(bool val)
std::string discipline2str(Discipline d)
std::vector< double > lapTimes
std::vector< int > timeKeepingFirstTriggerStatuses
std::vector< std::vector< double > > triggerTimes
void evaluateTimeKeepings(Track &track, Eigen::Vector3d &position, Eigen::Vector3d &orientation, double time)
bool checkFinishConditionsMet(double time)
bool performAllChecks(Track &track, double time, Eigen::Vector3d &position, Eigen::Vector3d &orientation)
CompetitionLogic(std::shared_ptr< Logger > logger, Track &track, MainConfig config)
std::pair< bool, bool > rayIntersectLineSegment(Eigen::Vector2d a, Eigen::Vector2d b, Eigen::Vector2d rayOrigin, Eigen::Vector2d rayDirection)
void evaluateTimeKeepingGateTrigger(Track track, double time, int index)
void fillReport(Report &report, double time)
double finishConditionsMetFirstTime
std::string penalty2str(PENALTY_TYPE p)
bool checkTimeout(double time)
void evaluateConeHit(Track &track, double time, Eigen::Vector3d &position, Eigen::Vector3d &orientation)
double determinantLinePoint(Eigen::Vector2d a, Eigen::Vector2d b, Eigen::Vector2d c)
double distanceToLineSegment(Eigen::Vector2d a, Eigen::Vector2d b, Eigen::Vector2d point)
std::shared_ptr< Logger > logger
double timeout_skidpad
Definition types.hpp:184
double timeout_acceleration
Definition types.hpp:182
double timeout_autocross
Definition types.hpp:183
double timeout_start
Definition types.hpp:181
Discipline discipline
Definition types.hpp:191
double timeout_trackdrive_first
Definition types.hpp:185
double timeout_trackdrive_total
Definition types.hpp:186
std::vector< double > sector_times
Definition types.hpp:155
double penalty_time
Definition types.hpp:163
double occurence_time
Definition types.hpp:164
std::string reason
Definition types.hpp:165
Eigen::Vector3d position
Definition types.hpp:166
bool uss_detect
Definition types.hpp:147
double final_time_raw
Definition types.hpp:142
double timeout_total
Definition types.hpp:150
std::vector< Penalty > penalties
Definition types.hpp:168
bool success
Definition types.hpp:139
std::string discipline
Definition types.hpp:138
double final_time
Definition types.hpp:141
bool off_course_detect
Definition types.hpp:145
double timeout_first_lap
Definition types.hpp:151
std::string dnf_reason
Definition types.hpp:140
bool cone_hit_detect
Definition types.hpp:146
std::vector< LapTime > lap_times
Definition types.hpp:157
double total_sim_time
Definition types.hpp:143
std::vector< std::pair< Landmark, Landmark > > time_keeping_gates
Definition types.hpp:45
std::vector< Landmark > left_lane
Definition types.hpp:42
bool lanesFirstWithLastConnected
Definition types.hpp:41
std::vector< Landmark > unknown
Definition types.hpp:44
std::vector< Landmark > right_lane
Definition types.hpp:43
Discipline
Definition types.hpp:172
@ SKIDPAD
Definition types.hpp:176
@ AUTOCROSS
Definition types.hpp:173
@ ACCELERATION
Definition types.hpp:175
@ TRACKDRIVE
Definition types.hpp:174