Race Timing advice (teensy 4.0 + gps)

Status
Not open for further replies.

hojo

New member
The project: keep track of time with a GPS (uart + pps). When a racer starts or finishes (signal a GPIO) then take the time stamp and send it out on serial to attached raspberry pi. Secondary function is to drive eight 7-seg displays always displaying the Time of Day down to the 100ths of a second. Environmental constraint: this is for whitewater kayaking where start and finish are often miles apart in remote areas with no reasonable method of communication between the two.

The main design criteria stems from FIS Alpine ski racing where the timers have to be accurate to within 1/1000th of a second.

Currently, my project works and I am ok using it for low end races but I'm not sure if it's the best solution. I'd like to be more confident in my solution when timing bigger races.

My method:
GPS time keeping from UART read into a struct in setup. I disregard all NEMA from this point on. After setup I use the PPS to trigger an interrupt, isrPps(), that increments the second on each pulse and trigger a timer, isr100K(), that counts .00001 second increments. I use this to keep track of time to the thousands of a second in the struct. Then, when a button is pressed (or beam broken) copy the current time and use a simple boolean to tell the main loop a new time was collected.

Optionally, but not yet implemented, I intend to use the metrics from the isr100K interrupt to determine if I need to push or pull the cycles in the 100k timer to compensate for temperature effects (the "over" member of the struct). Also, I have not addressed if a pulse is missed (which has happened in testing).

My main question: Are there any generally accepted algorithmic approachs I should be leveraging? Or, excepting that, is there a time keeping library that does this such that I can get accuracy between the start and finish modules to be within .001 seconds of each other that keeps time based on the GPS PPS?



Code:
struct timeStruct {
  uint8_t seconds;
  uint8_t minutes;
  uint8_t hours;
  uint16_t thous;
  uint16_t over;
};

//in setup
#include <Adafruit_GPS.h>
Adafruit_GPS GPS(&GPSS);
while (digitalRead(goPin)) { //manual "start" function that exits the gps uart sync and leaves setup.
    GPS.read();
    if (GPS.newNMEAreceived() && GPS.parse(GPS.lastNMEA())) {

      aClk.hours = ((GPS.hour + 18) % 24);  //crude timezone offset for mountain time.
      aClk.minutes = GPS.minute;
      aClk.seconds = GPS.seconds;
    }
  }
...


void isrPps() {
  //restart the 100k timer
  //put a block for this so we don't update lower w/o upper?
  cli();
  {
    last100K = hundKths;
    last1K = aClk.thous;
    aClk.thous = 0;
    aClk.seconds += 1;
    updateLowerHalf = true; //7 seg display control variable
    if (aClk.seconds > 59) {
      aClk.seconds = 0;
      aClk.minutes++;

      if (aClk.minutes > 59) {
        aClk.minutes = 0;
        aClk.hours++;
      }
      updateUpperHalf = true;
    }
    hundKths = 0;
    ppsTrigger = true;
  }
  sei();
  hundKTimer.begin(isr100K, 9.98);
}

...


void isr100K() {
  //increment
  cli();
  {
    hundKths++;
    if ((hundKths % 100) == 0) {
      aClk.thous++;
      updateLowerHalf = true;
    }
  }
  sei();
}

...
//isr like function that triggers when the gpio is triggered. Blue trigger in this case.
void buttonPressedCallback(uint8_t pinIn)
{
  // handle pressed state
  cli();
  blueTime.hours = aClk.hours;
  blueTime.minutes = aClk.minutes;
  blueTime.seconds = aClk.seconds;
  blueTime.thous = aClk.thous;
  sei();
  clicked = true;
}
 
you should look at the NTP server thread. PID logic is used to discipline Teensy clock using GPS PPS and NMEA. It has software for Ethernet and NTP, but there is a post about a non-ethernet variant. It might help you develop a disciplined clock on different Teensy's with GPS. Having hardware out in the wild will be affected by temperature changes and loss of GPS lock ... good luck
 
Last edited:
Status
Not open for further replies.
Back
Top