Project in progress
GPS Speedcoach

GPS Speedcoach © GPL3+

Designed for crew rowing, this speedcoach is designed to track split times and total meters traveled.

  • 2 views
  • 0 comments
  • 0 respects

Components and supplies

Necessary tools and machines

09507 01
Soldering iron (generic)

About this project

NK Brand speedcoaches, while small, light, and effective, are often in excess of $400, and sometimes affordable for individual coxswains or clubs who spend their money on boats/boat repairs. For my personal project in high school, I decided to solve that problem by making my own speedcoach, potentially as the basis for future rowing tech. Features include - support for biking and walking, as well as other water sports, a timer, and a battery monitor.

Wiring -

The wiring is quite simple, all that is necessary is a switch between GND and RST and to connect the I2C pins to the display. The FeatherWing should take care of the GPS connections, but if you're using external GPS you should connect it as it says.

Usage-

To start a piece, simply hit the reset button, and after a 3 second delay, the screen should turn on and the piece will start as soon as the screen is lit.

Code

Code (GPSSP)Arduino
Main code for the speedcoach.
//Credit to Adafruit Industries for providing example code

#include <millisDelay.h>
#include <Wire.h>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
#include <Adafruit_GPS.h>   //Libraries
#define GPSSerial Serial1
Adafruit_GPS GPS(&GPSSerial);
#define GPSECHO false
#define I2C_ADDRESS 0x3C
#define RST_PIN -1//Oled reset pin (onboard reset)
uint32_t timer = millis();
float ms = 0; //Meters/Second variable
float avems = 0;  //Average M/S variable
float mscounter = 0;  //Speed total (for average)
int integcounter = 0; //Counts half-seconds
float meterstraveled = 0; //Total meters
int splittotal = 0;   //Split total (in seconds)  (Essential to be an integer)
int splitseconds = 0; //Seconds on split display  (Essential to be an integer)
int splitminutes = 0; //Minutes on split display  (Essential to be an integer)
int seconds = 0;
int minutes = 0;
int hours = 0;    //Self-explanatory (for timers)
int splitaveragetotal = 0; //All split seconds added together (for average split)
int splitaverageseconds = 0; //Split average seconds
int splitaverageminutes = 0; //Split average minutes
int splitaverage = 0; //Split average
int splitaveragesecondsdisp = 0; //Display variables, fixes a bug
int splitaverageminutesdisp = 0; 
int splitmdisp = 0; 
int splitsdisp = 0;
float msfm = 0; //M/S for the meters calculation
float checkBattery(){
  //This returns the current voltage of the battery on a Feather 32u4.
  float measuredvbat = analogRead(9);
  measuredvbat *= 2;    // we divided by 2, so multiply back
  measuredvbat *= 3.3;  // Multiply by 3.3V, our reference voltage
  measuredvbat /= 1024; // convert to voltage

  
  return measuredvbat;
}
SSD1306AsciiWire oled;  //Oled type declaration
millisDelay secdelay;   //Timing delay (for timer)
void setup() {
   Wire.begin();
  Wire.setClock(400000L);
   Serial.begin(115200);
    GPS.begin(9600);
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);   
#if RST_PIN >= 0
GPS.sendCommand(PGCMD_ANTENNA);   
delay(1000);    //GPS init
  oled.begin(&Adafruit128x64, I2C_ADDRESS, RST_PIN);
#else // RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS);
#endif // RST_PIN >= 0  //Oled init

  oled.setFont(TimesNewRoman16_bold);  //Standard Font
GPSSerial.println(PMTK_Q_RELEASE);
  uint32_t m = micros();
  oled.clear();       //Initializing animation
  oled.set1X();
   oled.println("             GPSSP");
  oled.print("Initializing");
  oled.println(); 
  oled.println(); 
  oled.print("RTI Development");
  delay(500);
  oled.clear();
   oled.println("             GPSSP");
  oled.print("Initializing.");
    oled.println(); 
  oled.println(); 
  oled.print("RTI Development");
  delay(500);
  oled.clear();
   oled.println("             GPSSP");
  oled.print("Initializing..");
    oled.println(); 
  oled.println(); 
  oled.print("RTI Development");
  delay(500);
  oled.clear();
   oled.println("             GPSSP");
  oled.print("Initializing...");
    oled.println(); 
  oled.println(); 
  oled.print("RTI Development");
  delay(500);
  oled.clear();
   oled.println("             GPSSP");
  oled.print("Initializing..");
    oled.println(); 
  oled.println(); 
  oled.print("RTI Development");
  delay(500);
  oled.clear();
   oled.println("             GPSSP");
  oled.print("Initializing.");
    oled.println(); 
  oled.println(); 
  oled.print("RTI Development");
  delay(500);
  oled.clear();
   oled.println("             GPSSP");
  oled.print("Initializing");
    oled.println(); 
  oled.println(); 
  oled.print("RTI Development");
  delay(500);
  secdelay.start(1000); //Start timer delay (1 Second)
  oled.clear();
  oled.println("NO GPS FIX");   //GPS Fix Error
  oled.print("RTI Development");
}

void loop() {
  float batVoltage = checkBattery();  //get battery voltage
  Serial.println(batVoltage);  //write battery voltage to serial/usb port
  if (secdelay.justFinished()) {seconds++; secdelay.repeat();} //Checks if 1 second has passed, updates seconds variable
  if (seconds == 60) {seconds = 0; minutes++;}                 //Checks if 60 seconds have passed, resets seconds, increases minutes
  if (minutes == 60) {minutes = 0; hours++;}                   //Checks if 60 minutes have passed, resets minutes, increases hours
  char c = GPS.read();
  if (GPSECHO)
    if (c) Serial.print(c);
  if (GPS.newNMEAreceived()) {
    Serial.println(GPS.lastNMEA()); 
    if (!GPS.parse(GPS.lastNMEA()));  //Serial stuff (pay no attention)
  }
 
  if (timer > millis()) timer = millis();
  
  
  if (millis() - timer > 500) {   //Runs every half-second (responsible for screen-flicker)
    timer = millis(); // Resets timer
    if (GPS.fix) {
      
      oled.clear();
      ms = (GPS.speed*0.5144444); //Converts knots to meters/second
      if (ms <= 0.75) {oled.clear();
                       oled.println("Error: IDLE");
                       oled.print("Time: "); oled.print(hours); oled.print(":"); oled.print(minutes); oled.print(":"); oled.println(seconds);
                       oled.print("Battery: ");
                       oled.println(batVoltage);
                       oled.println("RTI Development"); 
                       }
                       }
      if (ms > 0.75) 
      {
      msfm = ms;
      mscounter = (mscounter+msfm);  //Continually adds speed to total (for averages)
      integcounter = (integcounter+1); //Adds +1 to variable every half second (for averages)
      avems = mscounter/integcounter; //Generates average meters/second (for total)
      meterstraveled = avems*(integcounter/2); //Calculates total (meters/second divided by seconds)
      splittotal = 500/(ms); //Generates seconds per 500m
      splitminutes = splittotal/60; //Generates split minutes from split seconds 
      splitseconds = splittotal - (splitminutes*60); //Displays remaining seconds
      splitaveragetotal = splitaveragetotal+splittotal;   //All split times (in seconds) added together
      splitaverage = splitaveragetotal/(integcounter);  //Averages out split times w/ seconds
      splitaverageminutes = splitaverage/60;   //Calculates split minutes
      splitaverageseconds = splitaverage-splitaverageminutes*60;   //Calculates split seconds
      splitaverageminutesdisp = splitaverageminutes;
      splitaveragesecondsdisp = splitaverageseconds;
      splitmdisp = splitminutes;
      splitsdisp = splitseconds;      //Display variables
      oled.set1X();  //Sets text size
      if (splitaverageminutes > 60) {splitaverageminutesdisp = 59; splitaveragesecondsdisp = 59;}   //Error codes ("59:59")
      if (splitminutes > 25) {splitmdisp = 59; splitsdisp=59;} //Error codes ("S:59:59")
      if (splitaverageminutes < 0) {splitaverageminutesdisp = 59; splitaveragesecondsdisp = 59;}  //Fixes sub-zero average split minutes (relic from previous code iteration)
      oled.print("M: "); oled.println(meterstraveled);  //Displays total meters + m/s
      oled.print("S: "); oled.print(splitmdisp); oled.print(":"); oled.print(splitsdisp);  oled.print("   AS: "); oled.print(splitaverageminutesdisp); oled.print(":");  oled.println(splitaveragesecondsdisp);
      oled.print("T: "); oled.print(hours); oled.print(":"); oled.print(minutes); oled.print(":"); oled.println(seconds); //Displays timer
      oled.print("RTI Development");
      }
      }
      }
      

Schematics

Schematics

Comments

Similar projects you might like

GPS Location Display With GPS And TFT Display Shields

Project tutorial by Boian Mitov

  • 12,623 views
  • 5 comments
  • 33 respects

Kayak GPS Navigation

Project in progress by Chrisroy

  • 3,181 views
  • 3 comments
  • 13 respects

GPS Tracking Using Helium, Azure IoT Hub, and Power BI

Project tutorial by Team Helium

  • 14,088 views
  • 18 comments
  • 36 respects

GPS Tracker with Arduino MKR FOX 1200

by jgallar

  • 14,421 views
  • 16 comments
  • 51 respects

Log GPS Information to MicorSD Card with Visuino

Project tutorial by Boian Mitov

  • 9,274 views
  • 10 comments
  • 31 respects
Add projectSign up / Login