/dev:
IF by jumping around, you mean the GPS course (aka heading) is N, then S, then... various random directions, then yes, that's normal. Below 5kph, the course and speed are not accurate. The lat/lon is also wandering around your actual location, so you can't use that to compute speed, either.
BTW, all these GPS values could be "empty", or invalid. The GPS device will send an empty field when it doesn't know something. Like PaulS said, check the validity first.
My NeoGPS library has flags for all values so it's easy to check. It's also faster, smaller and more accurate, especially at smaller distances (<1km). Here is a NeoGPS version of your sketch:
#include <NeoSWSerial.h>
#include <NMEAGPS.h>
#define GPSBaud 9600
#define ConsoleBaud 115200
// The serial connection to the GPS device
//AltSoftSerial gpsPort; // pins 8 & 9 would be better!
#define RXPin 8
#define TXPin 7
NeoSWSerial gpsPort(RXPin, TXPin);
NMEAGPS gps;
uint8_t updates = 0; // used to count elapsed seconds
NeoGPS::Location_t des( 44.88285, -68.67253 ); // Orono, ME
void setup()
{
Serial.begin(ConsoleBaud);
gpsPort.begin(GPSBaud);
}
void loop()
{
// Process characters from the GPS
while (gps.available( gpsPort )) {
gps_fix fix = gps.read();
// Every 5 seconds, do an update.
if (++updates >= 5) {
updates = 0;
Serial.println();
// If we have a location, give instructions
if (fix.valid.location) {
// Establish our current status
double distanceToDestination = fix.location.DistanceKm( des );
double courseToDestination = fix.location.BearingToDegrees( des );
const __FlashStringHelper *directionToDestination =
compassDir(courseToDestination);
int courseChangeNeeded = (int)(360 + courseToDestination - fix.heading()) % 360;
// debug
Serial.print( F("DEBUG: Course2Dest: ") );
Serial.print(courseToDestination);
Serial.print( F(" CurCourse: ") );
if (fix.valid.heading)
Serial.print( fix.heading() );
Serial.print( F(" Dir2Dest: ") );
Serial.print(directionToDestination);
Serial.print( F(" RelCourse: ") );
Serial.print(courseChangeNeeded);
Serial.print( F("Lat: ") );
Serial.print( fix.latitude(), 6 );
Serial.print( F(" Lon: ") );
Serial.println( fix.longitude(), 6 );
Serial.print( F(" CurSpd: ") );
if (fix.valid.speed)
Serial.print( fix.speed_kph() );
Serial.println('\n');
// ??? THIS ISN'T A THING
//Serial.print( F("current Angle: ") );
//Serial.println(atan2(gps.location.lat(), gps.location.lng())*180/M_PI);
// Within 20 meters of destination? We're here!
if (distanceToDestination <= 20.0)
{
Serial.println( F("CONGRATULATIONS: You've arrived!") );
exit(1);
}
Serial.print( F("DISTANCE: ") );
Serial.print(distanceToDestination);
Serial.println( F(" meters to go.") );
Serial.print( F("INSTRUCTION: ") );
// Standing still? Just indicate which direction to go.
if (fix.speed_kph() < 5.0)
{
Serial.print( F("Head ") );
Serial.print(directionToDestination);
Serial.println( '.' );
} else // suggest a course change
if ((courseChangeNeeded >= 345) || (courseChangeNeeded < 15))
Serial.println( F("Keep on straight ahead!") );
else if ((courseChangeNeeded >= 315) && (courseChangeNeeded < 345))
Serial.println( F("Veer slightly to the left.") );
else if ((courseChangeNeeded >= 15) && (courseChangeNeeded < 45))
Serial.println( F("Veer slightly to the right.") );
else if ((courseChangeNeeded >= 255) && (courseChangeNeeded < 315))
Serial.println( F("Turn to the left.") );
else if ((courseChangeNeeded >= 45) && (courseChangeNeeded < 105))
Serial.println( F("Turn to the right.") );
else
Serial.println( F("Turn completely around.") );
} else {
Serial.println( F("Waiting for GPS fix...") );
}
}
}
}
//------------------------------------------------------------
// This snippet is from NMEAaverage. It keeps all the
// compass direction strings in FLASH memory, saving RAM.
const char nCD [] PROGMEM = "N";
const char nneCD[] PROGMEM = "NNE";
const char neCD [] PROGMEM = "NE";
const char eneCD[] PROGMEM = "ENE";
const char eCD [] PROGMEM = "E";
const char eseCD[] PROGMEM = "ESE";
const char seCD [] PROGMEM = "SE";
const char sseCD[] PROGMEM = "SSE";
const char sCD [] PROGMEM = "S";
const char sswCD[] PROGMEM = "SSW";
const char swCD [] PROGMEM = "SW";
const char wswCD[] PROGMEM = "WSW";
const char wCD [] PROGMEM = "W";
const char wnwCD[] PROGMEM = "WNW";
const char nwCD [] PROGMEM = "NW";
const char nnwCD[] PROGMEM = "NNW";
const char * const dirStrings[] PROGMEM =
{ nCD, nneCD, neCD, eneCD, eCD, eseCD, seCD, sseCD,
sCD, sswCD, swCD, wswCD, wCD, wnwCD, nwCD, nnwCD };
const __FlashStringHelper *compassDir( uint16_t bearing ) // degrees CW from N
{
const int16_t directions = sizeof(dirStrings)/sizeof(dirStrings[0]);
const int16_t degreesPerDir = 360 / directions;
int8_t dir = (bearing + degreesPerDir/2) / degreesPerDir;
while (dir < 0)
dir += directions;
while (dir >= directions)
dir -= directions;
return (const __FlashStringHelper *) pgm_read_ptr( &dirStrings[ dir ] );
} // compassDir
The major change is using the 1-second GPS updates for the 5-second interval timer. After 5 GPS updates (fixes) have been received, you know that 5 seconds have elapsed. Although it's not very important for a 5-second interval, you should be aware that the Arduino `millis()` will drift against the GPS clock. Sometimes 5000ms will 4 GPS updates, 6 updates, or even 4.5 updates (some new data, some old data).
Also notice that it uses my [NeoSWSerial](https://github.com/SlashDevin/NeoSWSerial) instead of SoftwareSerial. SoftwareSerial is very inefficient, because it disables interrupts for long periods of time. It will use about 95% of the CPU time, just waiting. This can interfere with other parts of your sketch or with other libraries.
AltSoftSerial is the absolute best choice for a second serial port, but you have to connect the GPS Tx/Rx to specific Arduino pins (e.g., 8/9 on an UNO). Strongly recommended!
Other changes:
* The F macro around string constants is used to save RAM.
* The compass direction strings are stored in FLASH, also saving RAM.
* All GPS fields are checked for validity before being used.
* If the location is not valid, it just displays "Waiting for GPS fix..."
The original sketch uses 11540 bytes of program space and 892 bytes of RAM.
With NeoGPS/NeoSWSerial it uses 13010 bytes of program space and 408 bytes of RAM. NeoGPS saved about 100 bytes of RAM, and putting the strings in FLASH saved about 400 bytes of RAM.
If you want to try it, NeoGPS is available from the Arduino IDE Library Manager, under the menu **Sketch -> Include Library -> Manage Libraries**. Be sure to get v4.1.5, or download from github directly. Download NeoSWSerial from the link above.
Cheers,
/dev
Thanks /dev, I don't think your could will work with me because Im using adafruit ultimate gps+logging shield. Or, is there a way to use your code with adafruit gps?