9#ifndef _DOVES_LAP_TIMER_H
10#define _DOVES_LAP_TIMER_H
12#include "ArxTypeTraits.h"
25#if defined(__SIZEOF_DOUBLE__) && (__SIZEOF_DOUBLE__ < 8)
26#warning "DovesLapTimer: 'double' is only 32 bits on this target (classic AVR). Lap counting works but GPS math runs degraded - distances and interpolated crossing times will be noticeably less accurate. Use a 64-bit-double MCU (e.g. XIAO nRF52840) for full precision."
32#define COURSE_DETECT_SPEED_THRESHOLD_MPH 20
33#define COURSE_DETECT_WAYPOINT_PROXIMITY_METERS 10.0
34#define COURSE_DETECT_MIN_DISTANCE_METERS 200.0
35#define COURSE_DETECT_DISTANCE_TOLERANCE_PCT 0.25
36#define COURSE_DETECT_MAX_REJECTIONS 3
41#define COURSE_DETECT_MAX_NO_MATCH_PASSES 3
46#define COURSE_DETECT_FALLBACK_DISTANCE_FACTOR 4.0
47#define COURSE_DETECT_FALLBACK_MIN_METERS 2000.0
48#define METERS_TO_FEET GEOMATH_METERS_TO_FEET
51#define WAYPOINT_LAP_MIN_DISTANCE_METERS 100.0
52#define WAYPOINT_LAP_PROXIMITY_METERS 30.0
60#define DETECT_STATE_IDLE 0
61#define DETECT_STATE_WAITING_FOR_SPEED 1
62#define DETECT_STATE_WAYPOINT_SET 2
63#define DETECT_STATE_CANDIDATES_READY 3
64#define DETECT_STATE_DETECTED 4
77#define GPS_MAX_PLAUSIBLE_JUMP_METERS 500.0
78#define GPS_JUMP_REACCEPT_COUNT 3
105 DovesLapTimer(
double crossingThresholdMeters = 7, Stream *debugSerial = NULL);
118 int loop(
double currentLat,
double currentLng,
float currentAltitudeMeters,
float currentSpeedKnots);
133 bool isObtuseTriangle(
double lat1,
double lon1,
double lat2,
double lon2,
double lat3,
double lon3);
165 int pointOnSideOfLine(
double driverLat,
double driverLng,
double pointALat,
double pointALng,
double pointBLat,
double pointBLng);
184 double pointLineSegmentDistance(
double pointX,
double pointY,
double startX,
double startY,
double endX,
double endY);
200 double haversine(
double lat1,
double lon1,
double lat2,
double lon2);
216 double haversine3D(
double prevLat,
double prevLng,
double prevAlt,
double currentLat,
double currentLng,
double currentAlt);
232 void setStartFinishLine(
double pointALat,
double pointALng,
double pointBLat,
double pointBLng);
241 void setSector2Line(
double pointALat,
double pointALng,
double pointBLat,
double pointBLng);
250 void setSector3Line(
double pointALat,
double pointALng,
double pointBLat,
double pointBLng);
492#ifdef DOVES_DISABLE_DEBUG
494 template<
typename... Args>
void debug_print(Args&&...) {}
495 template<
typename... Args>
void debug_println(Args&&...) {}
497 template<
typename... Args>
498 void debug_print(Args&&... args) {
500 _serial->print(std::forward<Args>(args)...);
503 template<
typename... Args>
504 void debug_println(Args&&... args) {
506 _serial->println(std::forward<Args>(args)...);
524 bool checkStartFinish(
double currentLat,
double currentLng);
538 bool checkSectorLine(
double currentLat,
double currentLng,
double pointALat,
double pointALng,
double pointBLat,
double pointBLng,
bool& crossingFlag,
int sectorNumber);
554 double currentLat,
double currentLng,
555 double pointALat,
double pointALng,
556 double pointBLat,
double pointBLng,
559 double& outLat,
double& outLng,
560 unsigned long& outTime,
561 double& outOdometer);
568 void handleLineCrossing(
unsigned long crossingTime,
int sectorNumber);
572 void updateBestSectors();
582 unsigned long millisecondsSinceMidnight = 0;
584 double crossingThresholdMeters;
585 bool raceStarted =
false;
586 bool crossing =
false;
587 unsigned long currentLapStartTime = 0;
588 unsigned long lastLapTime = 0;
589 unsigned long bestLapTime = 0;
590 float currentLapOdometerStart = 0.0;
591 float lastLapDistance = 0.0;
592 float bestLapDistance = 0.0;
593 float currentSpeedkmh = 0.0;
594 int bestLapNumber = 0;
598 int currentSector = 0;
599 unsigned long currentSectorStartTime = 0;
600 bool crossingSector2 =
false;
601 bool crossingSector3 =
false;
604 unsigned long currentLapSector1Time = 0;
605 unsigned long currentLapSector2Time = 0;
606 unsigned long currentLapSector3Time = 0;
609 unsigned long bestSector1Time = 0;
610 unsigned long bestSector2Time = 0;
611 unsigned long bestSector3Time = 0;
614 int bestSector1LapNumber = 0;
615 int bestSector2LapNumber = 0;
616 int bestSector3LapNumber = 0;
618 float totalDistanceTraveled = 0;
619 float positionPrevAlt = 0.00;
620 double positionPrevLat = 0.00;
621 double positionPrevLng = 0.00;
622 bool firstPositionReceived =
false;
626 bool hasPrevFix =
false;
628 double startFinishPointALat = 0.0;
629 double startFinishPointALng = 0.0;
630 double startFinishPointBLat = 0.0;
631 double startFinishPointBLng = 0.0;
634 double sector2PointALat = 0.0;
635 double sector2PointALng = 0.0;
636 double sector2PointBLat = 0.0;
637 double sector2PointBLng = 0.0;
640 double sector3PointALat = 0.0;
641 double sector3PointALng = 0.0;
642 double sector3PointBLat = 0.0;
643 double sector3PointBLng = 0.0;
646 bool startFinishLineConfigured =
false;
647 bool sector2LineConfigured =
false;
648 bool sector3LineConfigured =
false;
651 int consecutiveJumpCount = 0;
LineDetectResult
Definition CrossingEngine.h:67
double TRITYPE
Definition DovesLapTimer.h:15
#define DIR_REVERSE
Definition DovesLapTimer.h:57
#define DIR_UNKNOWN
Definition DovesLapTimer.h:55
const double crossingPointBLat
Definition basic_oled_example.ino:21
const double crossingPointALat
Definition basic_oled_example.ino:19
void loop()
Definition basic_oled_example.ino:116
Definition CrossingEngine.h:81
Definition DovesLapTimer.h:103
unsigned long getBestSector2Time() const
Gets the best sector 2 time.
Definition DovesLapTimer.cpp:614
unsigned long getLastLapTime() const
Gets the last lap time.
Definition DovesLapTimer.cpp:557
unsigned long getCurrentLapStartTime() const
Gets the current lap start time.
Definition DovesLapTimer.cpp:549
unsigned int getRejectedCrossingCount() const
Number of crossing-zone exits whose interpolation was rejected.
Definition DovesLapTimer.cpp:654
double pointLineSegmentDistance(double pointX, double pointY, double startX, double startY, double endX, double endY)
Calculate the shortest distance between a point and a line segment.
Definition DovesLapTimer.cpp:254
void updateCurrentTime(unsigned long currentTimeMilliseconds)
Updates the current GPS time since midnight.
Definition DovesLapTimer.cpp:534
unsigned long getOptimalLapTime() const
Gets the optimal lap time calculated from best sector times.
Definition DovesLapTimer.cpp:629
float getTotalDistanceTraveled() const
Gets the total distance traveled.
Definition DovesLapTimer.cpp:575
void forceLinearInterpolation()
forces linear interpolation when checking crossing line
Definition DovesLapTimer.cpp:537
bool isStartFinishLineConfigured() const
Checks if the start/finish line is configured.
Definition DovesLapTimer.cpp:651
float getCurrentSpeedMph() const
Gets the current speed in miles per hour.
Definition DovesLapTimer.cpp:605
float getLastLapDistance() const
Gets the last lap distance.
Definition DovesLapTimer.cpp:569
int getBestSector1LapNumber() const
Gets the lap number that achieved the best sector 1 time.
Definition DovesLapTimer.cpp:636
unsigned long getCurrentLapTime() const
Gets the current lap time.
Definition DovesLapTimer.cpp:552
float getPaceDifference() const
Calculates the pace difference between the current lap and the best lap.
Definition DovesLapTimer.cpp:584
bool getRaceStarted() const
Gets the race started status (passed the line one time).
Definition DovesLapTimer.cpp:543
int getDirection() const
Gets the detected driving direction.
Definition DovesLapTimer.cpp:660
unsigned long getCurrentLapSector2Time() const
Gets the current lap sector 2 time.
Definition DovesLapTimer.cpp:623
void reset()
Reset all parameters back to 0.
Definition DovesLapTimer.cpp:442
void setSector2Line(double pointALat, double pointALng, double pointBLat, double pointBLng)
Sets the sector 2 line using two points (A and B).
Definition DovesLapTimer.cpp:514
int getBestSector3LapNumber() const
Gets the lap number that achieved the best sector 3 time.
Definition DovesLapTimer.cpp:642
bool isObtuseTriangle(double lat1, double lon1, double lat2, double lon2, double lat3, double lon3)
Checks if the triangle formed by the given coordinates is an obtuse triangle.
Definition DovesLapTimer.cpp:220
bool insideLineThreshold(double driverLat, double driverLon, double crossingPointALat, double crossingPointALon, double crossingPointBLat, double crossingPointBLon)
Check if a driver is within a threshold distance of the line formed by the two crossing points.
Definition DovesLapTimer.cpp:216
bool getCrossing() const
Gets the crossing status.
Definition DovesLapTimer.cpp:546
float getCurrentSpeedKmh() const
Gets the current speed in kilometers per hour.
Definition DovesLapTimer.cpp:602
int pointOnSideOfLine(double driverLat, double driverLng, double pointALat, double pointALng, double pointBLat, double pointBLng)
Determines which side of a line a driver is on.
Definition DovesLapTimer.cpp:250
unsigned long getBestSector1Time() const
Gets the best sector 1 time.
Definition DovesLapTimer.cpp:611
void setSector3Line(double pointALat, double pointALng, double pointBLat, double pointBLng)
Sets the sector 3 line using two points (A and B).
Definition DovesLapTimer.cpp:524
int getBestLapNumber() const
Gets the best lap number.
Definition DovesLapTimer.cpp:578
unsigned long getBestSector3Time() const
Gets the best sector 3 time.
Definition DovesLapTimer.cpp:617
float getCurrentLapOdometerStart() const
Gets the current lap odometer start.
Definition DovesLapTimer.cpp:563
unsigned long getCurrentLapSector1Time() const
Gets the current lap sector 1 time.
Definition DovesLapTimer.cpp:620
void setStartFinishLine(double pointALat, double pointALng, double pointBLat, double pointBLng)
Sets the start/finish line using two points (A and B).
Definition DovesLapTimer.cpp:504
bool isDirectionResolved() const
Checks if the driving direction has been resolved.
Definition DovesLapTimer.cpp:663
unsigned long getBestLapTime() const
Gets the best lap time.
Definition DovesLapTimer.cpp:560
void forceCatmullRomInterpolation()
Forces Catmull-Rom spline interpolation when checking crossing line.
Definition DovesLapTimer.cpp:540
float getBestLapDistance() const
Gets the best lap distance.
Definition DovesLapTimer.cpp:572
float getCurrentLapDistance() const
Gets the current lap distance.
Definition DovesLapTimer.cpp:566
double haversine3D(double prevLat, double prevLng, double prevAlt, double currentLat, double currentLng, double currentAlt)
Calculates the distance between two GPS points, including altitude difference.
Definition DovesLapTimer.cpp:262
unsigned long getCurrentLapSector3Time() const
Gets the current lap sector 3 time.
Definition DovesLapTimer.cpp:626
bool areSectorLinesConfigured() const
Checks if sector lines are configured.
Definition DovesLapTimer.cpp:648
int getLaps() const
Gets the total number of laps completed.
Definition DovesLapTimer.cpp:581
int getBestSector2LapNumber() const
Gets the lap number that achieved the best sector 2 time.
Definition DovesLapTimer.cpp:639
double haversine(double lat1, double lon1, double lat2, double lon2)
Calculates the great-circle distance between two points on the Earth's surface using the Haversine fo...
Definition DovesLapTimer.cpp:258
int getCurrentSector() const
Gets the current sector the driver is in.
Definition DovesLapTimer.cpp:645
Definition DovesLapTimer.h:80
DirectionDetector()
Definition DovesLapTimer.h:89
void reset()
Definition DovesLapTimer.h:92
unsigned long lapS2CrossingTime
Definition DovesLapTimer.h:86
void onLineCrossing(int sectorNumber, unsigned long crossingTime)
Definition DovesLapTimer.cpp:268
bool isReverse() const
Definition DovesLapTimer.h:99
bool raceSeen
Definition DovesLapTimer.h:82
unsigned long lapS3CrossingTime
Definition DovesLapTimer.h:87
int direction
Definition DovesLapTimer.h:81
bool isResolved() const
Definition DovesLapTimer.h:100
Definition CrossingEngine.h:73