A high-precision GPS-based lap timer and data logger designed for motorsports and track day enthusiasts. Features 25Hz logging, sector timing, RPM monitoring via tachometer, and multiple customizable display pages.
- 25Hz GPS Logging - High-frequency data capture straight to SD card
- Track & Layout Selection - Multiple tracks and configurations loaded from SD card
- Sector Timing - Optional 2 and 3-sector support for detailed performance analysis
- Lap Timing - Current lap, best lap, last lap, and optimal lap calculation
- Pace Comparison - Real-time pace difference vs. best lap
- Lap History - Session-based lap history (up to 1000 laps)
- RPM Monitoring - Tachometer input with noise filtering for ignition systems
- Speed Display - Large, easy-to-read speed display
- Simple CSV Format - Easy-to-parse data files with millisecond-precision timestamps
- GPS Statistics (battery, satellites, HDOP, logging status)
- Speed (with current lap number)
- Tachometer (RPM with max RPM tracking)
- Current Lap Time
- Pace Off Best Lap (visual indicators when beating best)
- Best Lap Time
- Optimal Lap (combined best sectors with lap numbers)
- Lap History (paginated list)
- GPS Debug (distance to line, crossing status, etc.)
- Loads track layouts from JSON files on SD card
- Support for forward/reverse direction selection
- Optional sector timing lines (2 and 3 sectors)
- Easy to add new tracks - just add a JSON file
- MCU: Seeed XIAO nRF52840 (64MHz ARM Cortex-M4 with FPU + Bluetooth)
- Low power consumption: ~120mAh with 2.45" screen
- Built-in battery charging circuit
- Note: May switch to Seeed XIAO ESP32 (same form factor) for WiFi data transfer at cost of higher power usage
- GPS: u-blox SAM-M10Q (Matek SAM-M10Q-CAN recommended)
- Configured for 25Hz update rate
- GPS-only mode for maximum performance
- Display: 2.45" 128x64 OLED LCD (SH110X or SSD1306 compatible)
- I2C interface (address: 0x3C)
- SD Card: Standard SD card module
- FAT16/FAT32 formatted
- 4MHz SPI for EMI resistance
- Battery: 1500mAh 103050 LiPo
- ~13 hours runtime on full charge
- Buttons: 3x momentary pushbuttons for navigation
- Up/Left, Select/Enter, Down/Right
- Tachometer Circuit: Inductive pickup for RPM sensing
- Input on pin D0
- Noise filtering for ignition systems
- Circuit diagram:
tachometer-circuit.jpg(README coming soon)
- Current draw: ~120mAh with 2.45" OLED display
- Battery life: ~13 hours continuous operation
- Voltage monitoring with visual battery indicator
The system loads track configurations from JSON files stored on the SD card. Each track file can contain multiple layouts (e.g., "Full Course", "Short Course", "Chicane Bypass").
SDCARD/
└── TRACKS/
├── OKC.json
├── BMP.json
├── PIQUET.json
└── [your-track].json
Each track file contains an array of layouts. Each layout defines a start/finish line and optional sector lines using GPS coordinates:
[
{
"name": "Full Course",
"start_a_lat": 28.41270817,
"start_a_lng": -81.37973266,
"start_b_lat": 28.41273039,
"start_b_lng": -81.37957049,
"sector_2_a_lat": 28.41190499,
"sector_2_a_lng": -81.37907082,
"sector_2_b_lat": 28.41183163,
"sector_2_b_lng": -81.37918567,
"sector_3_a_lat": 28.41150107,
"sector_3_a_lng": -81.37998565,
"sector_3_b_lat": 28.41150844,
"sector_3_b_lng": -81.37980640
},
{
"name": "Short Course",
"start_a_lat": 28.41199350,
"start_a_lng": -81.37995885,
"start_b_lat": 28.41199385,
"start_b_lng": -81.37986484
}
]Coordinate Requirements:
- Start/Finish Line:
start_a_lat,start_a_lng,start_b_lat,start_b_lng(required) - Sector 2 Line:
sector_2_a_lat,sector_2_a_lng,sector_2_b_lat,sector_2_b_lng(optional) - Sector 3 Line:
sector_3_a_lat,sector_3_a_lng,sector_3_b_lat,sector_3_b_lng(optional)
Each line is defined by two GPS coordinate points (A and B). The system detects crossing when you pass through the line segment between these points.
Getting Coordinates: Use Google Maps or your preferred mapping tool:
- Right-click on a point → Copy coordinates
- Paste into JSON (format: latitude, longitude)
- Precision: 8 decimal places recommended for racing accuracy
- Create a new
.jsonfile inSDCARD/TRACKS/directory - Use the format shown above
- Filename should be short (max 8 characters for FAT16 compatibility)
- Example:
LAGUNA.json,COTA.json,BRANDS.json
The track will automatically appear in the track selection menu on next boot.
Data is logged in simple CSV format with the following columns:
timestamp,sats,hdop,lat,lng,speed_mph,altitude_m,rpm,exhaust_temp_c,water_temp_c
Example:
timestamp,sats,hdop,lat,lng,speed_mph,altitude_m,rpm,exhaust_temp_c,water_temp_c
1704724801234,12,0.8,28.41270817,-81.37973266,87.32,125.45,8450,0,0
1704724801274,12,0.8,28.41270821,-81.37973270,87.45,125.46,8475,0,0- timestamp: Unix timestamp in milliseconds (since Jan 1, 1970)
- sats: Number of GPS satellites
- hdop: Horizontal Dilution of Precision (GPS accuracy indicator)
- lat/lng: GPS coordinates (8 decimal places)
- speed_mph: Speed in miles per hour (2 decimal places)
- altitude_m: Altitude in meters (2 decimal places)
- rpm: Engine RPM from tachometer input
- exhaust_temp_c: Reserved for future use (currently 0)
- water_temp_c: Reserved for future use (currently 0)
Log File Naming:
[TRACK]_[LAYOUT]_[DIRECTION]_[YYYY]_[MMDD]_[HHMM].dove
Example: OKC_Normal_fwd_2024_0115_1430.dove
DovesDataLogger/
├── BirdsEye.ino # Main Arduino sketch
├── display_config.h # Display configuration (SH110X/SSD1306)
├── gps_config.h # u-blox GPS UBX configuration commands
├── images.h # Bitmap images for display
├── libraries.txt # Required Arduino libraries
├── diagram.json # Wokwi simulator configuration
│
├── CASE/ # 3D printable enclosure files
│ ├── *.STL # STL files for 3D printing
│ └── README.md # Assembly instructions (coming soon)
│
├── SDCARD/ # SD card file structure
│ └── TRACKS/ # Track configuration files
│ ├── OKC.json
│ ├── BMP.json
│ └── ...
│
├── tachometer-circuit.jpg # Tachometer circuit schematic
└── README.md # This file
BirdsEye.ino (2020 lines)
- Main application logic
- GPS parsing and configuration
- Lap timing integration with DovesLapTimer library
- SD card logging with EMI-resistant retry logic
- Tachometer input with noise filtering
- Multi-page display system
- Button input handling
- Battery voltage monitoring
display_config.h
- Abstraction layer for SH110X and SSD1306 displays
- Screen dimensions and I2C configuration
- Easy to swap display types
gps_config.h
- u-blox UBX binary configuration commands
- NMEA sentence filtering
- Update rate configuration (5/10/18/20/25 Hz)
- Constellation selection (GPS-only for best performance)
images.h
- Bitmap graphics for splash screen and crossing animations
Install these libraries via Arduino Library Manager:
- Adafruit GFX Library - Graphics primitives
- Adafruit SSD1306 - SSD1306 OLED driver (if using SSD1306)
- Adafruit SH110X - SH110X OLED driver (if using SH1106)
- Adafruit GPS Library - GPS parsing
- ArduinoJson - JSON parsing for track files
- SdFat - SD card library (use v1.x for FAT16 support)
- DovesLapTimer (v0.2.1+) - Core GPS timing library
-
Format SD Card
- Format as FAT32 (or FAT16 for maximum compatibility)
- Create folder structure:
TRACKS/in root
-
Add Track Files
- Copy or create
.jsontrack files inSDCARD/TRACKS/ - See "Track Loading System" section above
- Copy or create
-
Flash Firmware
- Install required libraries
- Select board: "Seeed XIAO nRF52840"
- Compile and upload
BirdsEye.ino
-
Hardware Assembly
- 3D printed case assembly instructions coming soon
- Tachometer circuit README coming soon
- STL files available in
CASE/directory - Note: Requires some glue, measuring, and jeweler's screws
Button Controls:
- Left/Right Buttons: Navigate between pages
- Middle Button: Select/Enter (in menus), Quick-jump to Pace/Best Lap (while racing)
Startup Sequence:
- Power on → Boot screen
- Select Track location
- Select Track layout
- Select Direction (Forward/Reverse)
- Logging begins automatically when GPS fix is acquired
Ending Session:
- Navigate to "END RACE" page (only accessible when speed < 2 mph)
- Confirm to stop logging and close file
- Returns to track selection
- Update Rate: 25Hz (40ms between fixes)
- Mode: Automotive navigation mode
- Constellations: GPS-only (reduces processing time)
- NMEA Sentences: GGA only (reduces serial bandwidth)
- Baud Rate: 115200
- Write Frequency: Every GGA packet (~25Hz)
- Flush Interval: Every 2 seconds (prevents data loss)
- SPI Speed: 4MHz (reduced from 25MHz for EMI resistance)
- Retry Logic: 3 attempts on initialization failures
- Input Pin: D0
- Detection: Rising edge interrupt
- Filtering: 2ms minimum pulse gap (noise rejection)
- Dead Time: Prevents interrupt storms from noisy ignition pickups
- Update Rate: 3Hz filtered display
- Configuration: 1 pulse per revolution (adjust
tachRevsPerPulsefor multi-cylinder)
- Refresh: 3Hz (reduces power consumption)
- Exception: Instant refresh on button press
- Update Interval: 5 seconds
- Voltage Divider: 1510Ω / 510Ω ratio
- Display: 5-segment battery indicator
The page system is straightforward to extend. Each page needs:
-
Page Constant (around line 650):
const int MY_NEW_PAGE = 13;
-
Display Function:
void displayPage_my_new_page() { resetDisplay(); display.println(F("My Custom Page")); // Your display code here display.display(); }
-
Page Routing in
displayLoop()(around line 1650):else if (currentPage == MY_NEW_PAGE) { displayPage_my_new_page(); }
-
Update Page Range (line 697):
int runningPageEnd = MY_NEW_PAGE; // Update to new last page
Look at existing pages like displayPage_gps_speed() (line 992) or displayPage_tachometer() (line 1196) as examples.
-
Data Viewer: DovesDataViewer
- Web-based viewer for logged data
- Preview at HackTheTrack.net
-
Core GPS Timing Library: DovesLapTimer
- Line-crossing detection
- Sector timing
- Optimal lap calculation
- WiFi data transfer (if switching to ESP32 variant)
- Additional sensor inputs (exhaust temp, water temp)
- Bluetooth data streaming
- Real-time telemetry to pit crew
- Crossing detection threshold: 7.0 meters (configurable in code)
- Maximum track locations: 100
- Maximum layouts per track: 10
- Maximum lap history: 1000 laps per session
- GPS coordinates stored with 8 decimal places (~1.1mm precision)
See LICENSE file for details.
For issues, questions, or contributions, please visit:
- GitHub Issues: https://github.com/TheAngryRaven/DovesDataLogger/issues