What problem are you trying to solve?
Setting up sector lines before every session is error-prone and inconvenient.
Users shouldn't have to hardcode GPS coordinates in their sketch if they race
at known circuits. And on competition day, the timer needs to be ready
immediately — not after driving a detection lap.
The upstream CourseDetector already solves multi-layout detection via driven
distance (drive ~1 lap, compare odometer to each course's expected length).
This is excellent for venues with multiple layouts where distance is the
discriminator.
But there's a simpler, faster alternative for single-layout venues or any
situation where GPS coordinate proximity is sufficient:
"I'm within X meters of circuit center point A → load circuit A's sector lines."
This works on the FIRST GPS fix after power-on — no driving required.
Proposed solution
Add a GPS proximity scan that finds the nearest pre-configured circuit and
auto-loads its sector definitions.
KEY METHOD:
const CircuitStruct* findClosestCircuit(double currentLat, double currentLon);
- Scans a PROGMEM database of CircuitStruct entries
- For each: haversine(currentLat, currentLon, circuit.lat, circuit.lon)
- Returns pointer to nearest circuit entry (always returns SOMETHING)
- Caller decides whether the returned circuit is "close enough" via their
own distance threshold (or just trust it if only one circuit is in the DB)
CIRCUIT LOADING:
void loadCircuit(const CircuitStruct* ptr);
- deep-copies circuit data from PROGMEM into RAM
- dynamically allocates sector and service sector arrays (malloc)
- sets circuitLoaded = true
- gates loop() processing until circuitLoaded
CIRCUIT DATA STRUCTURE (PROGMEM-stored):
struct CircuitStruct {
const char* name;
double lat, lon; // circuit center point for proximity detection
uint8_t numSectors;
const SectorStruct* sectors; // sector line GPS coordinates
uint8_t numServiceSectors;
const serviceSectorStruct* serviceSectors;
};
ADDITIONAL METHODS:
void reloadCircuit(); // clears circuitLoaded, triggers re-detection
bool circuitLoaded; // public readable — safe to check before loop()
COMPARED TO CourseDetector:
CourseDetector (upstream):
- Detects via DRIVEN DISTANCE (compare odometer to course.lengthFt ±25%)
- Requires completing ~1 lap before detection resolves
- Better for multi-layout tracks at same venue (same GPS location, different distance)
- Handles up to MAX_COURSES simultaneously
GPS Proximity (this proposal):
- Detects via GPS COORDINATE DISTANCE (haversine to circuit center)
- Works on FIRST GPS FIX — instant
- Better for known single-layout circuits where GPS proximity is unambiguous
- Simpler implementation, less RAM overhead
These are COMPLEMENTARY approaches. A possible architecture: try GPS proximity
first (instant, good enough for 90% of cases); fall back to CourseDetector if
multiple circuits are within the proximity threshold.
CIRCUIT DATABASE DESIGN:
The database should live in user-provided PROGMEM in the sketch or a separate
.h file (not hardcoded inside the library itself). The library provides:
- The CircuitStruct/SectorStruct data types
- findClosestCircuit() and loadCircuit() methods
- The user provides their own array of CircuitStructs
This keeps the library hardware-agnostic and geography-agnostic — the library
doesn't need to know about any specific track.
Alternatives considered
-
CourseDetector (upstream's current approach) — driven-distance based.
Works great for multi-layout tracks but requires completing a detection lap.
Complement, not replacement.
-
User calls setStartFinishLine() / setSector2Line() / setSector3Line() manually —
current baseline. Works but requires hardcoding coordinates in the sketch.
Error-prone if the user races at multiple circuits.
-
Automatic on every GPS fix inside loop() — what RaceBoard does. Less suitable
for the library itself; better as a user-implemented pattern using
findClosestCircuit() as the building block.
What problem are you trying to solve?
Setting up sector lines before every session is error-prone and inconvenient.
Users shouldn't have to hardcode GPS coordinates in their sketch if they race
at known circuits. And on competition day, the timer needs to be ready
immediately — not after driving a detection lap.
The upstream CourseDetector already solves multi-layout detection via driven
distance (drive ~1 lap, compare odometer to each course's expected length).
This is excellent for venues with multiple layouts where distance is the
discriminator.
But there's a simpler, faster alternative for single-layout venues or any
situation where GPS coordinate proximity is sufficient:
"I'm within X meters of circuit center point A → load circuit A's sector lines."
This works on the FIRST GPS fix after power-on — no driving required.
Proposed solution
Add a GPS proximity scan that finds the nearest pre-configured circuit and
auto-loads its sector definitions.
KEY METHOD:
own distance threshold (or just trust it if only one circuit is in the DB)
CIRCUIT LOADING:
CIRCUIT DATA STRUCTURE (PROGMEM-stored):
ADDITIONAL METHODS:
COMPARED TO CourseDetector:
CourseDetector (upstream):
- Detects via DRIVEN DISTANCE (compare odometer to course.lengthFt ±25%)
- Requires completing ~1 lap before detection resolves
- Better for multi-layout tracks at same venue (same GPS location, different distance)
- Handles up to MAX_COURSES simultaneously
GPS Proximity (this proposal):
- Detects via GPS COORDINATE DISTANCE (haversine to circuit center)
- Works on FIRST GPS FIX — instant
- Better for known single-layout circuits where GPS proximity is unambiguous
- Simpler implementation, less RAM overhead
These are COMPLEMENTARY approaches. A possible architecture: try GPS proximity
first (instant, good enough for 90% of cases); fall back to CourseDetector if
multiple circuits are within the proximity threshold.
CIRCUIT DATABASE DESIGN:
The database should live in user-provided PROGMEM in the sketch or a separate
.h file (not hardcoded inside the library itself). The library provides:
- The CircuitStruct/SectorStruct data types
- findClosestCircuit() and loadCircuit() methods
- The user provides their own array of CircuitStructs
This keeps the library hardware-agnostic and geography-agnostic — the library
doesn't need to know about any specific track.
Alternatives considered
CourseDetector (upstream's current approach) — driven-distance based.
Works great for multi-layout tracks but requires completing a detection lap.
Complement, not replacement.
User calls setStartFinishLine() / setSector2Line() / setSector3Line() manually —
current baseline. Works but requires hardcoding coordinates in the sketch.
Error-prone if the user races at multiple circuits.
Automatic on every GPS fix inside loop() — what RaceBoard does. Less suitable
for the library itself; better as a user-implemented pattern using
findClosestCircuit() as the building block.