Breaking

Adafruit SSD1327 display with Arduino MKR WiFi 1010 with MKR GPS shield @adafruit #Arduino

 Adafruit SSD1327 display with Arduino MKR WiFi 1010 with MKR GPS shield

Adafruit SSD1327 display with Arduino MKR WiFi 1010 with MKR GPS shield

This project uses the Arduino MKR WiFi 1010, Arduino MKR GPS, and an Adafruit SSD1327 display to display the following information once every second: date/time, GPS latitude, GPS longitude, GPS altitude in feet, GPS ground speed in mph, number of GPS satellites received, external battery voltage, distance travelled in miles, distance travelled in feet, and elapsed duration in hours.

PiSquare - Connect Multiple Raspberry Pi HATs Wirelessly

The original plan was to test the MKR GPS's capabilities as a shield for my MKR WiFi 1010 boards. I required a portable, battery-operated, tiny, high-resolution display that had enough space and pixels to display all of the GPS and computed data without scrolling using the I2C connection while I was exploring. On the MKR WiFi 1010, the MKR GPS is positioned as a shield, and nothing can be installed above it without obstructing the GPS signal. For optimal battery life, the hardware required to consume as little electricity as feasible. I utilised an Adafruit 3.7 volt, 2500 mAh Lithium Ion Polymer Battery as a power source.

With a pigtail connection attached to the MKR WiFi 1010's USB connector, I want to install the components in a transparent acrylic project box. This will allow me to download drawings and use the MKR's built-in charging circuit to charge the battery. The components will be protected from dirt, weather, physical, and electrical harm by the project box. The box I chose was the Hammond 1591CTCL.

PiSquare -Connect Multiple Raspberry Pi HATs Wirelessly

My sketch was aided by the Arduino MKRGPS GPSlocation and Adafruit SSD1327 ssd1327 test sketches. The MKR GPS receives time from the GPS satellites in Unix Epoch style, but I wanted to show date and time in a human-readable manner. I initially attempted to use the normal TimeLib.h C library, however it clashed with the Arduino MKR GPS.h library and would not build. Then, because the MKR WiFi 1010 has an inbuilt real-time clock, I decided to use the RTCZero.h library. When the sketch reads the MKR GPS data, it synchronises the real time clock's epoch time with the GPS time.

The MKR GPS displays epoch time, decimal latitude and longitude, GPS-derived altitude in metres, ground speed in kilometres per hour, and the number of GPS satellites received. These are converted to mm-dd-yy hh:mm:00 date/time, height in feet, and ground speed in miles per hour by the drawing. The Haversine Formula is used to translate the difference between past lat/lon and current lat/lon to 2D distance once per second.

PiSquare - Connect Multiple Raspberry Pi HATs Wirelessly

Because the precision of GPS position and ground speed varies, a filter was needed to decrease the amount of erroneous readings. To filter out most of the spurious GPS data, I utilised experimentally calculated criteria for the change in Haversine distance and ground speed. The thresholds are given as constants that may be readily changed to suit various places and conditions.

The Adafruit 1327 is a high-performance 128x128 pixel 1.5-inch grayscale display with low current consumption and excellent quality graphics and text. I just utilised the text function, however the display requires some particular treatment to work successfully via the I2C connection. For example, before and after the other display commands, display.display() statements are necessary.

/* This sketch uses the Arduino MKR WiFi 1010, MKR GPS shield and Adafruit SSD1327 display. Date/time, GPS latitude, longitude, altitude, ground speed and 
distance are displayed on the SSD1327 along with battery voltage and distance traveled in meters, feet and miles. The real time clock on the MKR WiFi 1010 is
synchronized with GPS time and displays the date, hour, minute and second.*/

//Libraries for Adafruit SSD1327 display, Arduino MKR GPS and Arduino Real Time Clock
#include <Adafruit_SSD1327.h>
#include <Arduino_MKRGPS.h>
#include <RTCZero.h>

#define DTHRESH 1.0 //Distance change threshhold to calculate total distance
#define STHRESH 0.3 //Speed threshhold to calculate total distance

//Instantiate the display and real time clock objects
Adafruit_SSD1327 display(128, 128, &Wire, -1, 1000000);
RTCZero rtc;

//Declare the previous lat/long, distance and duration global variables
float plat;
float plon;
float dist;
float dur;
uint32_t tm0;
uint32_t tm1;

//Initial setup
void setup()   {
  //The following serial monitor display statements are commented out in case they are needed for troubleshooting when the board is connected to a computer              
  //Serial.begin(9600);
  //while (! Serial) delay(100);

  //Initialize the Adafruit SSD1327 128x128 pixel display
  if ( ! display.begin(0x3D) ) {
     //Serial.println("Unable to initialize OLED");
     while (1) yield();
  }

  //Set the SSD1327 text size, colors and clear the display
  display.display();
  display.setTextSize(1);
  display.setTextWrap(false);
  display.setTextColor(SSD1327_WHITE,SSD1327_BLACK);
  display.clearDisplay();
  display.display();

  //Initialize the real time clock
  rtc.begin();

  //Initialize the MKR GPS
  if (!GPS.begin(GPS_MODE_SHIELD)) {
    //display.println("Failed to initialize GPS!");
    while (1);
  }

  //Wait for the GPS to become available. This may take up to 15 minutes.
  while (!GPS.available()) {
    ;
  }

  //Declare the global previous latitude, longitude and cumulative distance variables
  plat = GPS.latitude();
  plon = GPS.longitude();
  tm0 = GPS.getTime();
  dist = 0.0;
  dur = 0.0;
  tm1 = 0; 
}

//Main loop
void loop() {
  //Wait for the GPS to become available then display GPS data
  if (GPS.available()) {
    uint32_t tm = GPS.getTime(); //Get GPS epoch time
    if (rtc.getEpoch() != tm) { //Sychronize the real time clock with GPS time
      rtc.setEpoch(tm);
    }
    float lat   = GPS.latitude(); //Get GPS latitude
    float lon  = GPS.longitude(); //Get GPS longitude
    float altm   = GPS.altitude(); //Get GPS altitude in meters
    float altf = 3.28084 * altm; //Convert altiude from meters to feet
    float kph      = GPS.speed(); //Get GPS ground speed in kph
    float mph = 0.621371 * kph; //Convert kph ground speed to mph
    int   satellites = GPS.satellites(); //Get number of GPS satellites received
    int Batt_int = analogRead(ADC_BATTERY); //Read the external battery voltage
    float Batt_int_v = Batt_int * (4.27/1023.0); //Convert the digital battery voltage to analog voltage
    float xkm; //Declare distance variable in km
    float xmt; //Declare distance variable in meters
    
    //Check real time clock every second and calculate distance traveled in km since GPS reading using the Haversine formula
    if (tm > tm1) {
      xkm = HaverSine(plat, plon, lat, lon);
      xmt = 1000.0 * xkm; //Convert km to meters
      /*Reduce false GPS readings by checking for non-numeric Haversine results, distance change greater than threshhold and 
      speed greater than threshhold.*/
      if (! isnan(xmt) && xmt > DTHRESH && mph > STHRESH) {
        dist += xmt; //Add distance reading in meters to cumulative distance
      }
    }

    //Calculate distance and duration
    float distmi = 0.000621371 * dist; //Convert distance in km to miles
    float distft = 3.28084 * dist; //Convert distance in meters to feet
    dur = (tm - tm0)/3600.0; //Hours duration

    //Display values on SSD1327
    display.display(); //Send yield message to SSD1327 display
    display.clearDisplay(); //Clear the SSD1327 display
    display.setCursor(0,0); //Position the SSD1327 cursor at top left
    printZero(rtc.getMonth()); //Display real time clock month with leading zero if needed
    display.print("-");
    printZero(rtc.getDay()); //Display real time clock day with leading zero if needed
    display.print("-");
    printZero(rtc.getYear()); //Display real time clock year with leading zero if needed
    display.print(" ");
    printZero(rtc.getHours()-4); //Display real time clock hour with leading zero if needed and correct for time zone
    display.print(":");
    printZero(rtc.getMinutes()); //Display real time clock minute with leading zero if needed 
    display.print(":");
    printZero(rtc.getSeconds()); //Display real time clock second with leading zero if needed
    display.println();
    display.print(lat,7); //Display GPS latitude as decimal degrees
    display.println(" lat");
    display.print(lon,7); //Display GPS longitude as decimal degrees
    display.println(" lon");
    display.print(altf); //Display GPS altitude in feet
    display.println(" alt ft");
    display.print(mph); //Display GPS ground speed in mph
    display.println(" mph");
    display.print(satellites); //Display number of GPS satellites received
    display.println(" satellites");
    display.print(Batt_int_v); //Display analog battery voltage
    display.println(" volts");
    display.print(distmi,3); //Display cumulative distance traveled in miles
    display.println(" dist miles");
    display.print(distft,1); //Display cumulative distance traveled in feet
    display.println(" dist feet");
    display.print(dur,3);
    display.println(" hours");
    display.display();

    /*Copy current lat/lon into previous lat/lon for next distance measurement
    and current time to previous time for next time measurement.*/
    plat = lat;
    plon = lon;
    tm1 = tm;
  }
}

//Function to display leading zero if single digit
void printZero(int x) {
  if (x < 10) {
    display.print("0");
  }
  display.print(x);
}

//Haversine formula to calculate distance between current and previous latitude/longitude points
float HaverSine(float lat1, float lon1, float lat2, float lon2)
{
  float ToRad = PI / 180.0;
  float R = 6371;   // radius earth in Km
  
  float dLat = (lat2-lat1) * ToRad;
  float dLon = (lon2-lon1) * ToRad; 
  
  float a = sin(dLat/2) * sin(dLat/2) +
        cos(lat1 * ToRad) * cos(lat2 * ToRad) * 
        sin(dLon/2) * sin(dLon/2); 
        
  float c = 2 * atan2(sqrt(a), sqrt(1-a)); 
  
  float d = R * c;
  return d;
}

Credit: Maulepilot


Popular Posts