Ultimate GPS reporting most data, not all

Breakout boards, sensors, other Adafruit kits, etc.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
dianesk8
 
Posts: 20
Joined: Sat Jul 05, 2014 2:03 pm

Ultimate GPS reporting most data, not all

Post by dianesk8 »

Hi,

I've got a curious problem where my Ultimate GPS Breakout will return most of the data when queried but won't finish the string, which means that when I call GPS.parse(GPS.lastNMEA()) it gives me nothing, because a full NMEA string wasn't returned. Once every 10-20 times an NMEA sentence is completed (GPS.newNMEAreceived() == true) and the parser works, but even then I think the last data is getting scrambled because it doesn't match the data format shown here: https://learn.adafruit.com/adafruit-ult ... ter-wiring

The GPS continuously recieves a string close to this:
----- $GPRMC,022110.000,A,4222.5419,N,07109.1683,W,0.05,329.92,170714
Which doesn't count as a new NMEA string. Every so often it receives something garbled at the end like this:
----- $GPRMC,022120.000,A,4222.5424,N,07109.1680,W,0.29,329.92,1707144N006W3220,*
Or like this
----- $GPRMC,022739.000,A,4222.5422,N,07109.1648,W,0.17,312.12,0,*

How can we get good NMEA strings every time? Does anyone at adafruit know what's going wrong here?

This is all running on an Arduino Mega. The code queries the GPS at ~2 Hz instead of using interrupts b/c a slow update rate is fine and it simplifies other code.

At top of file

Code: Select all

#include <Adafruit_GPS.h>
// For the Adafruit GPS module with software serial:
// Connections: GPS Power pin to 5V, GPS Ground pin to ground
// Define a new software serial port on the Arduino called gpsSerial:
SoftwareSerial gpsSerial(53, 52);
Adafruit_GPS GPS(&gpsSerial);
#define GPSECHO true
In setup()

Code: Select all

  // Adafruit MTK GPS setup code
  // First, set the baud rate. 9600 NMEA is the default baud rate
  GPS.begin(9600);
  // Second, turn on only the "minimum recommended" data
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
  // Last, set update rate to 1hz so the code can read the data and print it
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
Finally, being called in loop(), every half second or so

Code: Select all

while (gpsSerial.available())  {
  char c = GPS.read();
  delay(1);
  Serial.print(c);
}

if (GPS.newNMEAreceived()) {
  // Print the string and set the newNMEAreceived() flag to false
  Serial.println(GPS.lastNMEA());
  GPS.parse(GPS.lastNMEA());
  Serial.print("\n read and parsing");

  if (GPS.fix) {
    Serial.print("Location: ");
    Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
    Serial.print(", ");
    Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
  }
}

User avatar
Franklin97355
 
Posts: 23910
Joined: Mon Apr 21, 2008 2:33 pm

Re: Ultimate GPS reporting most data, not all

Post by Franklin97355 »

Could you post your complete code and a description or drawing of your connections between it all?

User avatar
dianesk8
 
Posts: 20
Joined: Sat Jul 05, 2014 2:03 pm

Re: Ultimate GPS reporting most data, not all

Post by dianesk8 »

Here is the code and a description of the hardware. The project is a robotic sailboat
I am using the Mega 2560 and the 16 x 12 bit PWM Servo Shield.
The 3 sensors are Adafruit Ultimate GPS Breakout v3 with active antenna, Adafruit LMS303 magnetic compass, and US Digital magnetic encoder
There is an additional 6V battery power supply for the servo shield

Most connections are on the shield: Servos, encoder on digital pin 7, and compass on SCL SDA pins.
I communicate with the GPS is via Software Serial and was not able to use pins 3,2 as I did when I started with the Arduino Uno. They are now on pins 53, 52
All connections are soldered except those from the shield to the Arduino and the 53, 53 pins on the Mega (came with stacking pins and no place to solder)

I have attached stripped down code that simply reads the 3 sensors and shows the data. I don't command the servos yet, but it works with other code. As I describe in my previous post, the GPS data is not read completely and GPS.newNMEAreceived() does not return true.

The data string I get is $GPRMC,020013.000,A,4222.5409,N,07109.1704,W,0.42,15.22,180714,
this seems to be everything but the checksum.

I would really like to get a functioning GPS asap as I am using this project in a class and it is currently my roadblock. I appreciate any thoughts/ideas/help!

Code: Select all

/* Reads all sensors and attempts to command boat
  7/17/2014 */

#include <Adafruit_PWMServoDriver.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_LSM303_U.h>
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>

/*----------------------SET UP SERVOES-------------------------------*/
//servos will bo on Servo Shield in places 0 and 1
// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

/*----------------------SET UP COMPASS-------------------------------*/
//Assign unique ID to compass sensor
Adafruit_LSM303_Mag_Unified MagComp = Adafruit_LSM303_Mag_Unified(12345);  

/*----------------------SET UP GPS-----------------------------------*/
// For the Adafruit GPS module with software serial:
// Connections: GPS Power pin to 5V, GPS Ground pin to ground
// GPS TX (transmit) and GPS RX (receive) to pins 3 and 2
#define gpsTX         53   //GPS communication pins
#define gpsRX         52
// Define a new software serial port on the Arduino called gpsSerial:
SoftwareSerial gpsSerial(gpsTX, gpsRX);
Adafruit_GPS GPS(&gpsSerial);
//#define GPSECHO true

/*----------------------SET UP WIND SENSOR---------------------------*/
// Wind Sensor MA3 Global Variables
#define windpin       7   //Wind sensor input pin
unsigned long duration;
int WindDirection;

/*----------------------USEFUL GLOBAL VARIABLES----------------------*/
  // Things we can get from the sensors
  float relWind = 0;              // From wind sensor (degrees)
  float absBoatHeading = 0;       // From compass (degrees)
  float absBoatPositionX = 0;     // From the GPS (meters)
  float absBoatPositionY = 0;     // From the GPS (meters)
  float startingPositionX = 0;    // From the GPS (meters)
  float startingPositionY = 0;    // From the GPS (meters)


  // Useful variables
  int GPS_counter = 0;
  int rudderCMD = 0;
  int sailCMD = 0;

  bool verbose = true;
  float pi = 3.14159;



void setup()  
{
  // Set baud rate for the serial monitor
  Serial.begin(9600);
  Serial.println("Code starting up, beginning intialization...");
 

int ch1; // channel values
int ch2;
#define SERVOMIN  150 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  600 // this is the 'maximum' pulse length count (out of 4096)



/*----------------------SET UP GPS SENSOR----------------------------*/
  // Adafruit MTK GPS setup code
  // First, set the baud rate. 9600 NMEA is the default baud rate
  GPS.begin(9600);
  // Second, turn on only the "minimum recommended" data
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
  // Last, set update rate to 1hz so the code can read the data and print it
  // TODO: try higher if necessary
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);/*  */

  // This will run on startup and will save that position as the (0,0) origin
  
  //all variables are global, so we do not pass them to the function or get any in return
  getAbsBoatPosition();
  startingPositionX = absBoatPositionX;
  startingPositionY = absBoatPositionY;


/*----------------------SET UP  SENSOR---------------------------*/
  pinMode(windpin, INPUT);

  MagComp.begin();
} // End of setup

void loop()
{

/*----------------------GET THE SENSOR VALUES------------------------*/
 relWind = getRelativeWind();				//read wind sensor
 absBoatHeading = getAbsBoatHeading();		//read compass
  
  // Get the GPS data every 100 loops b/c it runs so slowly
  if (GPS_counter == 5) {
    // When you call this code it updates the variables instead of returning
    // This is because C can't return multiple things at once
    getAbsBoatPosition();
    delay(500);
    GPS_counter = 0;
  }
  else
    {GPS_counter += 1;}

delay (250);   // main code for logic goes here
/*----------------------COMMAND THE MOTORS--------------------------*/
//commandMotors(rudderIn, true, sailwinchIn, true, rudderCMD, sailCMD);

} // End of loop()



/*----------------- FUNCTIONS TO READ ALL SENSORS--------------------*/

float getRelativeWind()
{
  //read MA3 PWM output
  duration = pulseIn(windpin, HIGH);

  // use a calibration routine to find max pulse width which is typ 1023
  // after calibrating, convert to heading in degrees
  WindDirection= map(duration, 0, 1010, 0, 360);

  // constrain value between 0 and 360 to get rid of noisy outliers
  WindDirection = min(max(WindDirection, 0), 360);
  
  if (verbose) {
    Serial.print("Relative wind direction: ");
    Serial.println(WindDirection);
                }
    return WindDirection;
}

float getAbsBoatHeading()
{
    sensors_event_t event;
        MagComp.getEvent(&event);
    // Calculate the angle of the vector y, x and convert from radians to degrees
    float heading = atan2(event.magnetic.y, event.magnetic.x)*180.0/pi;
    if (heading < 0)    heading += 360;
    if (heading > 360)  heading -= 360;

    if (verbose) {
      //Serial.print("y reading: ");        Serial.print(event.magnetic.y);
      //Serial.print("  ---  x reading: "); Serial.println(event.magnetic.x);
      Serial.print("Compass Heading: ");  Serial.println(heading);
    }
     return heading;
  
}

void getAbsBoatPosition()
{
  while (gpsSerial.available())  {
    char c = GPS.read();
    delay(1);
    Serial.print(c);
    }
  Serial.println("got GPS data using GPS.read");

  if (GPS.newNMEAreceived()) 
  {
     if (verbose) 
     {
			Serial.print("\n\n");
    	// Print the string and set the newNMEAreceived() flag to false
       Serial.println(GPS.lastNMEA());
      GPS.parse(GPS.lastNMEA());

      Serial.print("\n read and parsing");
      Serial.print("\nTime: ");
      Serial.print(GPS.hour, DEC);    Serial.print(':');
      Serial.print(GPS.minute, DEC);  Serial.print(':');
      Serial.print(GPS.seconds, DEC); Serial.print('.');

      Serial.print("Fix: ");          Serial.print((int)GPS.fix);
      Serial.print(" quality: ");     Serial.println((int)GPS.fixquality); 

      if (GPS.fix) {
        Serial.print("Location: ");

        Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
        Serial.print(", ");
        Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
                  }
    }

    // Make the boat position relative to where it was started
    absBoatPositionX = absBoatPositionX - startingPositionX;
    absBoatPositionY = absBoatPositionY - startingPositionY;
  }
  else Serial.println("GPS data not received");
}

User avatar
dianesk8
 
Posts: 20
Joined: Sat Jul 05, 2014 2:03 pm

Re: Ultimate GPS reporting most data, not all

Post by dianesk8 »

Here is simplified code that shows only GPS function where it "hand queried" in a senor read function getAbsPosition(). The delay(50) command in loop is a place holder for the program logic code. I get a complete read and therefore parse only when the delay is about 50 ms. Increased to 100 or 150 it does gives intermittent reads. Delay 50 or less and it is fine, printing out new data every 1 sec, which is the update rate of the GPS (when new data is available).
I would like to be able to call this function at times from my control logic, but doubt the process time will always be less than 50ms, especially if there are print lines. Is there some GPS buffer that is overflowing or needs to be cleared?
Hardware is as described on my previous post
thanks!

Code: Select all

/* Reads all sensors and attempts to command boat
  7/20/2014 */
#include <Wire.h>
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>

/*----------------------SET UP GPS-----------------------------------*/
// For the Adafruit GPS module with software serial:
// Connections: GPS Power pin to 5V, GPS Ground pin to ground
// GPS TX (transmit) and GPS RX (receive) to pins 3 and 2
#define gpsTX         53   //GPS communication pins
#define gpsRX         52
// Define a new software serial port on the Arduino called gpsSerial:
SoftwareSerial gpsSerial(gpsTX, gpsRX);
Adafruit_GPS GPS(&gpsSerial);

void setup()  
{
  // Set baud rate for the serial monitor
  Serial.begin(115200);
  Serial.println("Code starting up, beginning intialization...");
 

/*----------------------SET UP GPS SENSOR----------------------------*/
  // Adafruit MTK GPS setup code
  // First, set the baud rate. 9600 NMEA is the default baud rate
  GPS.begin(9600);
  // Second, turn on only the "minimum recommended" data
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
  // Last, set update rate to 1hz so the code can read the data and print it
  // TODO: try higher if necessary
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);/*  */

  // This will run on startup and will save that position as the (0,0) origin
  
  //all variables are global, so we do not pass them to the function or get any in return
  getAbsPosition();
}
void loop()
{
getAbsPosition();

    delay(50);
}



void getAbsPosition()
{
  while (gpsSerial.available())  {
    char c = GPS.read();
    //Serial.print(c);
    }
//  Serial.println("got GPS data using GPS.read");

  if (GPS.newNMEAreceived()) 
  {
     	Serial.print("\n\n");
    	// Print the string and set the newNMEAreceived() flag to false
       Serial.println(GPS.lastNMEA());

      if (GPS.parse(GPS.lastNMEA()))
      {

        Serial.print("\n read and parsing");
        Serial.print("\nTime: ");
        Serial.print(GPS.hour, DEC);    Serial.print(':');
        Serial.print(GPS.minute, DEC);  Serial.print(':');
        Serial.print(GPS.seconds, DEC); Serial.print('.');

        Serial.print("Fix: ");          Serial.print((int)GPS.fix);
        Serial.print(" quality: ");     Serial.println((int)GPS.fixquality); 

        if (GPS.fix) {
          Serial.print("Location: ");

          Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
          Serial.print(", ");
          Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
                  }
      }
      else Serial.println(" could not 
 }
  //else Serial.println("GPS data not received");
}

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Ultimate GPS reporting most data, not all

Post by adafruit_support_rick »

Code: Select all

  while (gpsSerial.available())  {
    char c = GPS.read();
    delay(1);
    Serial.print(c);
    }
  Serial.println("got GPS data using GPS.read");
The delay(1); will kill you. Try it without.

Software Serial has an input buffer of 64 characters. If you throw in a delay of 150ms, you can easily overrun that buffer. If you absolutely need 150ms, then you are going to have to use the interrupt to read the GPS.

User avatar
adafruit2
 
Posts: 22144
Joined: Fri Mar 11, 2005 7:36 pm

Re: Ultimate GPS reporting most data, not all

Post by adafruit2 »

Also - SoftSerial is really limited in functionality - but IIRC we have hardware serial support for our ultimte GPS library because we've used it with Flora

Stick to hardware serial (there's like 3 hardware serial ports on the MEGA) and you'll have much better luck

User avatar
dianesk8
 
Posts: 20
Joined: Sat Jul 05, 2014 2:03 pm

Re: Ultimate GPS reporting most data, not all

Post by dianesk8 »

My most recent code that I tested and posted did not have the delay(1) in the read section. The 150 ms (or anything over 50 ms) is my processing logic, not all written yet, so I am not sure how long it will take. Is there a way to clear the Software Serial buffer or some other way to do the "hand query"?
Thank you

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Ultimate GPS reporting most data, not all

Post by adafruit_support_rick »

You have to come around in loop more often than 60ms to empty the buffer. That's all there is to it.
If you can't guarantee that, then use the interrupt to read the GPS.

User avatar
andrewa
 
Posts: 145
Joined: Mon Oct 19, 2009 9:53 pm

Re: Ultimate GPS reporting most data, not all

Post by andrewa »

Trying this myself.

I tried with hardware serial on a Mega, and no luck, with code as you have it.

BTW, I did notice you have to put in:

#ifdef __AVR__
#include <SoftwareSerial.h>
#endif

If you don't, you get compile errors. This seems odd, since you don't need SoftwareSerial if you are using a Mega.

Looks like you may need interrupt. My question is why the while (gpsSerial.available) loop doesn't get all of the data, if we are using the *hardware* serial port. I could see where the SoftwareSerial has a problem, though.

A.

User avatar
dianesk8
 
Posts: 20
Joined: Sat Jul 05, 2014 2:03 pm

Re: Ultimate GPS reporting most data, not all

Post by dianesk8 »

Hi,
I finally found this on the tutorial under FAQs
" I've adapted the example code and my GPS NMEA sentences are all garbled and incomplete!
We use SoftwareSerial to read from the GPS, which is 'bitbang' UART support. It isn't super great on the Arduino and does work but adding too many delay()s and not calling the GPS data parser enough will cause it to choke on data.
If you are using Leonardo (or Micro/Flora/ATmega32u4) or Mega, consider using a HardwareSerial port instead of SoftwareSerial! "

Can you give me more information about how to use the Ultimate GPS with hardware serial. Where do I get the parsed data? How often should I/can I read it? What are the connections to the Uno and to the Mega?
thanks!

User avatar
Franklin97355
 
Posts: 23910
Joined: Mon Apr 21, 2008 2:33 pm

Re: Ultimate GPS reporting most data, not all

Post by Franklin97355 »

The Mega has several serial ports see http://arduino.cc/en/Main/arduinoBoardMega2560 in the input/output section.

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Ultimate GPS reporting most data, not all

Post by adafruit_support_rick »

Connect to Mega RX1 and TX1. Use the interrupt to read the GPS. Instead of software serial, you will be using Serial1.

Code: Select all

#include <Adafruit_GPS.h>

// If you're using a GPS module:
// Connect the GPS Power pin to 5V
// Connect the GPS Ground pin to ground

// If using hardware serial (e.g. Arduino Mega):
//   Connect the GPS TX (transmit) pin to Arduino RX1, RX2 or RX3
//   Connect the GPS RX (receive) pin to matching TX1, TX2 or TX3

#define mySerial Serial1
Adafruit_GPS GPS(&mySerial);


User avatar
andrewa
 
Posts: 145
Joined: Mon Oct 19, 2009 9:53 pm

Re: Ultimate GPS reporting most data, not all

Post by andrewa »

So, any luck using the hardware serial port?

My version didn't work with the Mega (non-interrupt).

BTW, I'm still curious about why SoftwareSerial still has to be referenced; is it possible I am still using SoftwareSerial, on hardware pins, and that is why things are failing?

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Ultimate GPS reporting most data, not all

Post by adafruit_support_rick »

andrewa wrote:BTW, I'm still curious about why SoftwareSerial still has to be referenced; is it possible I am still using SoftwareSerial, on hardware pins, and that is why things are failing?
Software Serial doesn't need to be referenced. You should be able to remove all references to it.

User avatar
andrewa
 
Posts: 145
Joined: Mon Oct 19, 2009 9:53 pm

Re: Ultimate GPS reporting most data, not all

Post by andrewa »

Well, if I comment out this part:

// #ifdef __AVR__
// #include <SoftwareSerial.h>
// #endif

I get this error:

In file included from mega_gps.ino:4:
C:\Users\zzz\Documents\Arduino\libraries\Adafruit_GPS/Adafruit_GPS.h:91: error: expected `)' before '*' token
C:\Users\zzz\Documents\Arduino\libraries\Adafruit_GPS/Adafruit_GPS.h:134: error: ISO C++ forbids declaration of 'SoftwareSerial' with no type
C:\Users\zzz\Documents\Arduino\libraries\Adafruit_GPS/Adafruit_GPS.h:134: error: expected ';' before '*' token

I've defined a *hardware* serial port thusly:

#define gpsSerial Serial1
Adafruit_GPS GPS(&gpsSerial);

So, is this something in the Adafruit_GPS.h that is issuing the problem? I see:

#ifdef __AVR__
#if ARDUINO >= 100
Adafruit_GPS(SoftwareSerial *ser); // Constructor when using SoftwareSerial
#else
Adafruit_GPS(NewSoftSerial *ser); // Constructor when using NewSoftSerial
#endif
#endif
Adafruit_GPS(HardwareSerial *ser); // Constructor when using HardwareSerial

Can't seem to uncomment and get it to run... hmmm....

Arduino 1.0.5, latest Adafruit_GPS from repository...

Locked
Please be positive and constructive with your questions and comments.

Return to “Other Products from Adafruit”