GPS Lap Timer Functionality

Hey guys, I am new here and to the Microcontroller arena, sort of. i got a Duemilanove and some stuff about 5 years ago but tabled an old project until recently. I have a little experience with this stuff but not much, I am a mechanical designer by trade. Ill give you a bit of info about the project I am working on, where i am at etc, but if you want to skip right to the question go to the bottom. Thanks!

The Project Scope: I am building a GPS Lap Timer for my Supermoto Racebike. The practice track i ride is 5/8 mile long and my current lap times are around 40s when its only asphalt. It has mostly clear skies and slight tree coverage on one side of the track but nothing directly overhead so sat fixes should be good. There are 12 turns and the Start/Finish is the second fastest part on the track topping out 3rd gear on my 450cc race bike. What I would like to do is before hand(have the lat/lon) or on the track collect Geofence points for the Start/Finish line, then tear it up. I would like an LCD screen that displays the last lap and fastest speed and have a Green LED lit when the last lap was faster than the previous, or red when it was slower. After the session i would like it to display the fastest lap time and max speed.

The current parts list: I am using an Uno R3, Fastrax UP501 GPS module and an Old Adafruit GPS Shield v1.1. I have various 16x2 LCD displays an a MicroView OLED display that i would like to use.

The current progress: I am new to all this and really have only done simple(blink LED type simple) stuff many years ago. I have configured the UP501 for RMC(position, Velocity, Time) data sampling at 10Hz/9600bps. I set this up right to the Uno and get a nice stream of data to the Serial Monitor. This used the TinyGPS library.

I then setup the GPS Shield using SPI and SD libraries to initialize the SD and write to it. This all worked just fine.

Next I setup the GPS Shield with the UP501(tricky cause the shield powers 5v to the GPS and i needed less since my module is 3-4.2v. I setup a 1N4004 and measure the Vdrop to be sure it was in the right range. Got a nice stream of data to the Serial monitor this was so i knew things were working so this is a retired shield and there really wasn't much info out there for it.

Lastly I setup the GPS shield with SD and GPS and things went south. I got one line of GPS data on the Serial monitor after a few minutes and that partially wrote to the SD card. I think the issue is between SoftwareSerial and SPI. Something with the Bandwidth used and/or buffer. I am still looking into this and not the real reason i am here but any advice there would be great from someone who has run into this. I have seen this issue pop up for various other GPS shields but nothing directly relating to what i am doing.

THE REASON I AM POSTING: So again I am new to all this and learning on the fly. I don't like just grabbing code and running it so i have been doing a lot of learning making sure i understand what is going on and when. While trying to figure out how exactly to trigger the end of lap I think I may be outside of what the Uno is capable of. I basically have 3 main options(unless some of you guys/gals have more) and wanted to see what more experienced users thought.

  1. Determinate of AB(start/finish line) and AC(start line point to current bike position). Find when this goes from (+) to (-) then figure out between those two times what the actual time was when crossing the start/finish line. This means converting to cartesian and doing some math on the fly. I will likely be traveling between 8 and 10fps here so maybe get a gps position every foot if i am lucky. If the start/finish line was "infinite" i would cross it 4 times a lap so likely there would need to be a GeoFence area to trigger this as well.

  2. Two geofence areas and figure when i go from one to the other and again calculate the time based on the position of each point.

  3. have a lookup table and when the bike is in a certain geofence area start looking up its current position in the table to figure out when the start/finish line is crossed.

So i think these 3 ideas will work BUT will they work on the Arduino? Am I well outside of what these things can do? Is there some other way to do this project that I have thought about? I haven't seen any purely GPS lap timers out there(except some over the counter $500 options). Some of you guys might be saying "why don't you just make a track side trigger timer system?" I do have a lap transponder and the track has a system in place(that works sometimes) but these are kart tracks designed to pickup karts so unless its during a bike race the transponder system is touchy. I would like a system that was self contained and ultimately part of my full scope of making a datalogger that collects lean angle, accel data(brake points, acceleration areas) and add more "traps" around the track to see if i am faster/slower in areas. And after the fact i want to put this info into Google maps or google earth and plot my fastest laps to see what lines i took, where/when i got on the gas etc. That and i have the parts already for this and thought it would be a fun project to learn about this stuff.

So what do you guys think? :slight_smile:

Thanks if you made it this far and for any info!

I am sure this is pages back now but still would love some insight. I am chasing down GPS issues right now but still need to sort out the "timing" functionality. If nobody responds i think i have to go with a Lookup table. I don't think the Uno can get all the computations done on the fly that i need in the time i need.

The Aim systems that were used when I was Karting had an IR beacon at the start-finish line. Does you track have a beacon? Could you use if?

I don't see why you would need a lookup table to identify a single rectangular lat/lon region.

groundfungus, yes sort of. I have a MyLaps mx transponder to use with the tracks MyLaps system during races. It(the beacon on the track) needs to be set for bikes and if i go practice during the week there is no guarantee that it will pick up my times. I have mine mounted on the lower frame rail but that is still higher than the karts. last time i went i got no lap data other than time stamps on my camera. The data can be printed but i would like to know more like what lines on the track i took when laps were fast. On a supermoto you slide into the apex of the turn and several of the turns are double apex. The places i brake/accel and so on are important to know. The full scope project will combine gps with an IMU hoping to get data on brake points, lean etc, but that is more complex and starting with this seemed like a place to get my feet wet.... I can post process the data but on the fly would be better to know how i am doing while at the track.

aarg. That's why i am asking the questions of people that know more than me about this stuff :slight_smile: I will need to know when the bike crosses the finish line and calculate the time from the last lap. As far as I understand(which again is all new to me) i will need to convert lat/lon to cartesian to get the determinate for when i approach/cross the line. I already ran into an issue trying to convert my GPS coordinates from TinyGPS and not having enough decimal place/precision. I was concerned this would affect calculations and there were lots of posts talking about the same thing. Based on speed(likely 70mph and possibly already sliding across the finish line), line choice on a 20+ft wide track and GPS update rate i imagine the geofence areas would be pretty large. If you drew the start line all the way across the entire course i would cross it 4times a lap also, hence the need for a geofence.

I don't think you need a point-in-polygon test (i.e., in or out of the geofence). That is definitely more compute-intensive than intersecting two line segments. With a geofence, you would still have to calculate the line segment intersection (your track vs. polygon edge) to know when you crossed into the finish "polygon".

Here are the segments you'll be testing:

Intersection.jpg

For the finish line segment (red), you need the lat/lon (first point) on one side of the track, and the lat/lon (second point) on the other side of the track.

The yellow segment is two consecutive fixes, spaced 0.10s apart. You can use the pro-rated distance from the first point to the intersection point as a partial time interval (perhaps 0.055s offset in that image).

I made a "math" sketch and was entering lat/long values... I am noticing reduced accuracy... I need to convert to X/Y, right?

For the purposes of testing the finish line crossing, you can treat lat/lon as Y/X. This is an equirectangular approximation, and it is quite accurate enough when they're just a few meters apart. But you can only get sub-meter accuracy of the intersection point with the integer lat/lon values. The math still works, if you're careful about divisions. Here is a good source of some code (several answers).

Cheers,
/dev

Thanks dev!

With the line intersection is it truncated to just the endpoints of the line? Some of the info on stackoverflow seems to suggest extending the line. My original idea was sharing a point on the starting line with my current position and calculating the angle. Then when the angle was zero or crossed I could back calculate when. If I can get away with doing cross products of lat/lon values that certainly seems easier!

the line intersection is it truncated to just the endpoints of the line?

Yes. In the most popular answer (with vector notation, by Gareth Rees), he describes the 4 cases:

1) If r × s = 0 and (q − p) × r = 0, then the two lines are collinear [and may intersect.

2) If r × s = 0 and (q − p) × r ≠ 0, then the two lines are parallel and non-intersecting.
3) If r × s ≠ 0 and 0 ≤ t ≤ 1 and 0 ≤ u ≤ 1, the two line segments meet at the point p + t r = q + u s.
4) Otherwise, the two line segments are not parallel but do not intersect.

The code in second most popular answer (by Gavin) checks that the intersection is between the two endpoints of both segments:

        if ((0 <= s) && (s <= 1) && (0 <= t) && (t <= 1))

(Added parens and reordered for clarity, as seen in case 3 by Gareth.) Otherwise, the intersection is on the extended lines (i.e., they do not intersect between the two endpoints of both segments).

My original idea was [mathematically naive]

Fixt. :wink: The great thing about vector math is that vertical lines (slope = ∞) and horizontal lines (slope = 0) are correctly handled.

Thanks again Dev! I am very eager to try this out! Hopefully tonight if I can clear the time(or neglect sleep..)

Ill let you know how it goes.

I did wade through the responses in the link but im glad you clarified! There were a lot of answers and responses saying the answers weren't correct.

How far does your bike go in 1/10 second? If your GPS updates are at 10Hz, that will be the maximum resolution.

aarg:
How far does your bike go in 1/10 second? If your GPS updates are at 10Hz, that will be the maximum resolution.

Hmm... I'm not a metrologist, but I think the resolution is probably better than that. I think you have to identify resolution of what.

If you mean the resolution of the location at which he crosses the finish line, the GPS reports are DDMM.mmmmm. So the degrees resolution is 0.00001/60 degrees, or 1.67 x 10-7 degrees. Given two segments with that resolution, the resolution of the intersection can be 1.8cm (given an Earth radius of 6371.0088km). (The integer lat/lon of NeoGPS has a resolution of 1.1cm.)

If you mean the resolution of the time when he crosses the finish line, I think it can be as small as 1.8cm/(313cm/0.1s), or about 0.57ms. (70mph = 31.3meters/s, or 313cm/0.1s).

However... (it's a beeeg "however")

The accuracy of where and when he crosses the finish line (and thence his lap time) is much less than that. Because the GPS device is only accurate to 3m (at best), the lap time cannot be more accurate than 3m / (31.3m/s) = 0.096s. LOL, darn close to 0.1s, but not because of the 10Hz rate.

Any enjuneers care to comment or correct my babble?

I think this accuracy can be improved by having a base station to provide the current GPS offset from an accurate, stationary position (requires post-processing), and by using a vehicle model for interpolation and smoothing. Care to add an IMU? Sounds like a research project now... :stuck_out_tongue:

Cheers,
/dev

/dev:
I think this accuracy can be improved by having a base station to provide the current GPS offset from an accurate, stationary position (requires post-processing), and by using a vehicle model for interpolation and smoothing. Care to add an IMU? Sounds like a research project now... :stuck_out_tongue:

Cheers,
/dev

The end goal for the project(hopefully) is an IMU with 9dof accelerometer/gyro/mag, maybe some machine vision. who knows. I want to see how far i can take it. If i can get +- 0.25s accuracy for a lap time that is more than enough. The 10hz GPS updates is (hopefully) so i can get a good print of what lines i took when certain lap times happened. If i get a gps fix 5m before the finish line and 5m after that really shouldnt affect the lap time since it is finding the intersection point. The future IMU will let me see when i started braking, getting on the gas, what the lean angle was etc. Very complicated physics involved in a bike that is braking, sliding and leaning all at once and as far as i know, other than million dollar motoGP race teams, there really aren't bike datalogging units(except one) out there. I was involved in a few studies doing MC datalogging but my involvement was on the mechanical side, not the software side. The idea is really not to have my lap times accurate to ms, but to see if i am going faster or slower than previous laps, if my speeds were higher etc. As of now all i can do is go back and watch video, guess at the time stamp when i crossed and watch to see when i was braking, what lines, engine noise, gear etc. Video doesn't give the whole picture either. Here are a few laps from a track day i did last month(2 years off the track). My current situation doesn't allow for a lot of track time, so when it is available i want to be able to gather lots of data :slight_smile:

Dev, i went through the math on StackOverflow and put some of it to the test in a small Microview program. I just used some simple X,Y coordinates for now to test that it can actually pick up on an intersection point. I need to do a lot more testing of all the conditions as i have only looked at #3(intersecting lines between endpoints) and then work with lat/lon values. I will do that with my Microview on a breadboard and layout some coordinates around my house and see if it picks up on an intersection.

So i think i have part of it working. I made a simple test using some basic coordinates(0,0)->(5,5) and (5,0)->(0,5). Then adjusted it to not standard values and ultimately pulled Lat/lon values off google maps for the start/finish line and a point before and after the line. It worked! I then tested it with a line that didn't cross the finish line(just before it) and it didn't return a value. I am going to use the "crossing" case and for all others it will return a value or return to checking the intersection. Lots more to figure out but this is very promising! Thanks for all your help!
Finish Line small.png

Serial Monitor.png

597520c48392158c05fc8de3f0cd01ce81b16427.png

BTW,

The idea is really not to have my lap times accurate to ms, but to see if i am going faster or slower than previous laps, if my speeds were higher etc.

The error doesn't stay the same all the time. The location wanders over time, so the lap time could be 0.1s under on one lap, and 0.1s over on the next lap. But maybe that's ok, 'cuz:

:wink:

Hahaha. Love the pic!

Plus or minus .1s is fine. I'm not a pro looking for fractions of a second. Just ride for fun and I'd like to quantify track time somehow. It's just nice to know if I go through a section in 2nd gear or 3rd gear if it makes a difference. That kind of thing.

Since this works currently and its already calculating I could put in "traps" to get timing for different parts of the track. Not yet but it would be cool!

In case anyone is interested here is my current code to test the "TRIGGER" line using a Microview for the processing and display. If you want to replicate my setup you need

  1. MicroView
  2. UP501 GPS Module(its not a 5v GPS module so you need to wire it appropriately)
  3. Push button (if you don't want to use a push button you can manually set the "Fence" line in the code and it won't go into the push button loop)

The GPS code is based on Dev's NMEAloc.ino sketch and the NeoGPS library and associated config files appropriately modified. I tried to comment the sketch and i left a lot of Dev's comments in from the original NMEAloc.ino sketch. I need to do some more testing with this but then ill pull some of the code over to my GPS logger on an UNO with uSD shield to log gps.

Dev, i do have a question for you about the timer. Do you think it would be better to use GPS time, or simply start a timer/counter every time its trigger and just use that value? I am thinking the latter but wanted to see what your thoughts were. If so i don't need to store GPS Time at all but will need to save the Lap time to the SD file and hopefully/ultimately be able to configure "traps". I need to work out how to store these values once and not have to re-log them every time i power down/up the unit. So far pulling lat/lon values from google maps hasn't been working real well for the triggers, but i will do some more testing. having the option to set them at the track is nice as long as its note required each time.

MV_Fence_Intersection_with_button.ino (13.9 KB)

Do you think it would be better to use GPS time, or simply start a timer/counter every time its trigger and just use that value? I am thinking the latter but wanted to see what your thoughts were. If so i don't need to store GPS Time at all but will need to save the Lap time to the SD file

I would definitely stick with the GPS Time, but I would add another field to the record you save to the SD file. Leave it blank unless you cross a trigger point:

bool collisionDetected = false;
int8_t i_t; // time at intersection (delta from lastFix in hundredths)

static void Intersection()
{
       .
       .
       .

    collisionDetected = (0 <= s) && (s <= 1) && (0 <= t) && (t <= 1);

    if (collisionDetected) {
            i_x = p0_x + (t * s1_x); //Intersection Longitude
            i_y = p0_y + (t * s1_y); //Intersection Latitude

            i_t = fix.dateTime_cs - lastFix.dateTime_cs; // should be 10
            if (i_t < 0) // when 0-90 happens, this is negative 90...
              i_t += 100; // ...so wrap around to positive 10
            i_t = (int8_t) (t * (float)i_t); // Intersection time (0 to 10 hundredths of a second)
              .
              .
              .

static void saveOrSendToUNO
{
    printL( logfile, fix.latitudeL() );
    logfile.print( ',' );
    printL( logfile, fix.longitudeL() );
    logfile.print(',');
       .
       .
       .
    if (collisionDetected) {
      logfile.print(i_x);
      logfile.print(',');
      logfile.print(i_y);
      logfile.print(',');
      logfile.print(i_t);
      logfile.print(',');
    }

This keeps your logfile fairly small, and you can see the exact time & place you crossed those trigger points in the last 3 columns. If you're not saving to the SD on the MV, you send the intersection to the UNO and let it save it to the SD. The GPS Visualizer header would be:

    latitude, longitude, speed, time, logtime, triggerLat, triggerLon, triggerTime

Those last three fields would be empty for most records.

I need to work out how to store these values once and not have to re-log them every time i power down/up the unit.

Write them to the SD card (even from the PC) and read them during setup?

So far pulling lat/lon values from google maps hasn't been working real well for the triggers

You may be running into the accuracy problem we've mentioned. If you can, get at least 10 minutes of records (1Hz is ok, 30 minutes is better) at a point on the finish line that is easy to see on google maps. Then load the SD file into a spreadsheet and calculate the average lat/lon of all those records. If that's different from google maps, you will at least know the offset.

Then you should be able to pick a lat/lon off google maps and offset it to what your GPS would give... if you let your GPS average a bunch of fixes for 10-30 minutes.

The spreadsheet will also let you see how much the GPS wanders. BTW, it wanders by different amounts, depending on the satellite constellation and other more esoteric factors. One possible problem is that the GPS wander offsets your track enough that it never intersects the trigger segments. I would suggest extending the trigger points a few meters on both ends so it has a good chance of intersecting a track that is offset.

Hopefully the GPS offset doesn't make your track intersect the wrong trigger segment. Are there any segments near each other, especially if you extend them?

Cheers,
/dev

/dev:
I would definitely stick with the GPS Time,
If you're not saving to the SD on the MV, you send the intersection to the UNO and let it save it to the SD.

I wasn't planning on letting the MV gather and calculate the intersection, the code would be on the UNO and thats where the GPS module would be wired to. I am just using the MV right now to test that the code works and get a visual of it happening. i was able to record a line and cross it a few times with good results this morning! I am actually considering getting a small touch screen display with an SD socket on it. The MV is nice, especially since it has the Atmega chip but it really is a bit too limited for what i want to display after the fact. A touch screen would also be nice. I am half considering a Pi3... :slight_smile: since i could implement a bit more including post process a bit and hopefully a script to split out each lap, upload to GPS visualizer and overlay them.

The GPS Visualizer header would be:

    latitude, longitude, speed, time, logtime, triggerLat, triggerLon, triggerTime

Those last three fields would be empty for most records.
Write them to the SD card (even from the PC) and read them during setup?

I was thinking along the same lines. having a config.txt file on the SD and reading it during setup. I will likely have have some setup questions like "Record new start/finish line?" and "number of section lines including start line" that will control intermediate trigger points and a way to count through the trigger variables. This is again why testing it on the MV is helpful for me. I don't really need to store the trigger lat/lon values but it won't hurt as long as it doesn't hurt the timing.

Hopefully the GPS offset doesn't make your track intersect the wrong trigger segment. Are there any segments near each other, especially if you extend them?

Cheers,
/dev

Well i can extend it but only so far. On the one side i actually go through the pit "house" to get onto the track which is only about 2m from the wall. On the other side i maybe have 2-3m before another part of the track. The good news is i almost never go over the start finish line on that side so maybe i can filter out crossing the line based on a speed.

LOL, after a little more thought, you could write the intersection point as another record that has computed values. Then just have a single extra field for "crossing" or "trigger" flag:

latitude, longitude, speed, time, logtime, trigger
37.2645967,-80.4014017,0.15,20:05:58.20,4
37.2645607,-80.4014007,0.17,20:05:58.26,4,1   <-- this is i_x, i_y, i_spd, i_t, a calculated record
37.2646067,-80.4013900,0.18,20:05:58.30,3

With a trigger variable I wouldnt have a lap time in the record though. It would have to be post processed. It would be nice if I am able to use a screen and open/view lap times after a session. I think I need to make a program UI flow chart but I like the first idea but ill likely drop intersection x and y. I probably don't need logtime either after initial debugging...or do you see a reason to keep it?