Wayfinder

Whether hiking the Appalacian Trail or in the local state park, you want to be able to immerse yourself in the experience. Breaking off from the flow to look down at a map or phone detaches you from the landscape. For those of us that live to get lost in the woods, the Wayfinder orientation system can give you a sense of direction.

IMG_0486.png

GPS Powered Haptic Feedback

Inside the main wristband and the auxiliary band are vibration motors and a microcontroller equipped with Bluetooth, GPS, and a compass module. While connected, the main wristband checks your coordinates and heading, and uses it to determine where you are in relation to the path defined by the user before starting. If you end up verging off, one of the wristbands will vibrate and help you find correct yourself.

IMG_0489.png

Prototyping Wayfinder

GPS Shield on an Arduino Uno, with vibration Motors and other electronic components prototyped on a breadboard.

GPS Shield on an Arduino Uno, with vibration Motors and other electronic components prototyped on a breadboard.

ARDUINO CODE:

/******************************************************************************
TinyGPSPlus_GPS_Shield.ino
TinyGPS++ Library Example for the SparkFun GPS Logger Shield By Jim Lindblom @ SparkFun Electronics
February 9, 2016
https://github.com/sparkfun/GPS_Shield

This example uses SoftwareSerial to communicate with the GPS module on pins 8 and 9. It uses the TinyGPS++ library to parse the NMEA strings sent by the GPS module, and prinats interesting GPS information to the serial monitor.

After uploading the code, open your serial monitor, set it to 9600 baud, and watch for latitude, longitude, altitude, course, speed, date, time, and the number of visible satellites.

Resources:
TinyGPS++ Library - https://github.com/mikalhart/TinyGPSPlus/releases
SoftwareSerial Library

Development/hardware environment specifics:
Arduino IDE 1.6.7
GPS Logger Shield v2.0 - Make sure the UART switch is set to SW-UART Arduino Uno, RedBoard, Pro, Mega, etc.
******************************************************************************/

#include <TinyGPS++.h> // Include the TinyGPS++ library
TinyGPSPlus tinyGPS; // Create a TinyGPSPlus object

#define GPS_BAUD 9600 // GPS module baud rate. GP3906 defaults to 9600.

// If you're using an Arduino Uno, Mega, RedBoard, or any board that uses the
// 0/1 UART for programming/Serial monitor-ing, use SoftwareSerial:
#include <SoftwareSerial.h>
#define ARDUINO_GPS_RX 9 // GPS TX, Arduino RX pin
#define ARDUINO_GPS_TX 8 // GPS RX, Arduino TX pin
SoftwareSerial ssGPS(ARDUINO_GPS_TX, ARDUINO_GPS_RX); // Create a SoftwareSerial

// Set gpsPort to either ssGPS if using SoftwareSerial or Serial1 if using an
// Arduino with a dedicated hardware serial port
#define gpsPort ssGPS // Alternatively, use Serial1 on the Leonardo

// Define the serial monitor port. On the Uno, Mega, and Leonardo this is 'Serial'
// on other boards this may be 'SerialUSB'
#define SerialMonitor Serial

const int lAlert = 12;
const int rAlert = 13;

//set points along path
double minlat[] = {39.68493,39.68512,39.68500};
double maxlat[] = {39.68492,39.68513,39.68501};
double minlng[] = {-75.75570,-75.75572,-75.75550};
double maxlng[] = {-75.75571,-75.75573,-75.75551};
double pointlng[] = {39.684925,39.684125,39.685005};
double pointlat[] = {-75.755705,-75.755725,-75.55505};

//designate step in path
int point = 0;

double angle;

void setup()
{
SerialMonitor.begin(9600);
gpsPort.begin(GPS_BAUD);
pinMode(4,OUTPUT);
pinMode(12,OUTPUT);
pinMode(13, OUTPUT);
}

void loop()
{
// print position, altitude, speed, time/date, and satellites:
printGPSInfo();

wayfinder();


SerialMonitor.print("angle: ");
SerialMonitor.println(angle);
SerialMonitor.print("point: ");
SerialMonitor.println(point);

// "Smart delay" looks for GPS data while the Arduino's not doing anything else
smartDelay(5000);
/*if(tinyGPS.location.lng() >= -75.75525){
digitalWrite(4,HIGH);
}
else{
digitalWrite(4,LOW);
}*/
}

void printGPSInfo()
{
// Print latitude, longitude, altitude in feet, course, speed, date, time,
// and the number of visible satellites.
SerialMonitor.print("Lat: ");
SerialMonitor.println(tinyGPS.location.lat(), 6);
SerialMonitor.print("Long: ");
SerialMonitor.println(tinyGPS.location.lng(), 6);
SerialMonitor.print("Alt: ");
SerialMonitor.println(tinyGPS.altitude.feet());
SerialMonitor.print("Course: ");
SerialMonitor.println(tinyGPS.course.deg());
SerialMonitor.print("Speed: ");
SerialMonitor.println(tinyGPS.speed.mph());
SerialMonitor.print("Date: "); printDate();
SerialMonitor.print("Time: "); printTime();
SerialMonitor.print("Sats: ");
SerialMonitor.println(tinyGPS.satellites.value());
SerialMonitor.println();
}

// This custom version of delay() ensures that the tinyGPS object
// is being "fed". From the TinyGPS++ examples.
static void smartDelay(unsigned long ms)
{
unsigned long start = millis();
do
{
// If data has come in from the GPS module
while (gpsPort.available())
tinyGPS.encode(gpsPort.read()); // Send it to the encode function
// tinyGPS.encode(char) continues to "load" the tinGPS object with new
// data coming in from the GPS module. As full NMEA strings begin to come in
// the tinyGPS library will be able to start parsing them for pertinent info
} while (millis() - start > ms);
}

// printDate() formats the date into dd/mm/yy.
void printDate()
{
SerialMonitor.print(tinyGPS.date.day());
SerialMonitor.print("/");
SerialMonitor.print(tinyGPS.date.month());
SerialMonitor.print("/");
SerialMonitor.println(tinyGPS.date.year());
}

// printTime() formats the time into "hh:mm:ss", and prints leading 0's
// where they're called for.
void printTime()
{
SerialMonitor.print(tinyGPS.time.hour());
SerialMonitor.print(":");
if (tinyGPS.time.minute() > 10) SerialMonitor.print('0');
SerialMonitor.print(tinyGPS.time.minute());
SerialMonitor.print(":");
if (tinyGPS.time.second() > 10) SerialMonitor.print('0');
SerialMonitor.println(tinyGPS.time.second());
}

//wayfinder main function
void wayfinder()
{
if((tinyGPS.location.lat() >= minlat[point] && tinyGPS.location.lat() <= maxlat[point])&&(tinyGPS.location.lng() >= minlng[point]||tinyGPS.location.lng() <= maxlng[point])){
digitalWrite(4, HIGH);
delay(800);
digitalWrite(4, LOW);
point = point + 1;
if(point = 3){
point = 0;
}
}

else{
angle = atan2(pointlng[point]-tinyGPS.location.lng(),pointlat[point]-tinyGPS.location.lat())/57.2958;

if(angle-tinyGPS.course.deg() >= .01 && angle-tinyGPS.course.deg()
<= -15){ if(angle-tinyGPS.course.deg() >=.015){
digitalWrite(rAlert, HIGH);
delay(300);
digitalWrite(rAlert, LOW);
delay(100);
digitalWrite(rAlert, HIGH);
delay(300);
digitalWrite(rAlert, LOW);
}
if(angle-tinyGPS.course.deg() >= -15){
digitalWrite(lAlert, HIGH);
delay(300);
digitalWrite(lAlert, LOW);
delay(100);
digitalWrite(lAlert, HIGH);
delay(300);
digitalWrite(lAlert, LOW);
}
}
}

SerialMonitor.print("angle: ");
SerialMonitor.println(angle);
}