Catching GPS ACKs with GPS v3 breakout

by irvingwashington on Tue Oct 29, 2013 7:15 pm

Hello all-

Further into my testing of my UGPSBB, I'm having a difficult time capture the return ACK NMEA sentences from the GPS. I'm attempting to make sure that the GPS completes the commands before I move on, and while I could use a delay loop, it'd be nice to check for a successful ACK instead.

Reading through the Adafruit GPS library, there is already a class to wait for the ACK (boolean Adafruit_GPS::waitForSentence(char *wait4me, uint8_t max)), so I'm trying to use that to test the exit code of GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA) as such (and I have defined the status code as "$PMTK001,314,3*36")

Code: Select all
do {
    Serial.println("Attempting to set NMEA output");
    GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  } while (!GPS.waitForSentence(PMTK_SET_NMEA_OK));
  Serial.println("NMEA Output set"); 


Probably not the best way to do it, but the ACK is never caught, so I'm wondering if it's coming back too fast to be caught? I noticed a comment in the Adafruit GPS library to that effect.
//return waitForSentence(PMTK_STANDBY_SUCCESS); // don't seem to be fast enough to catch the message, or something else just is not working


If the library can't catch the ACKs fast enough, anyone have any suggestions as to how to catch them? This might be completely academic, but now I want to know!

Thanks,
Z
irvingwashington
 
Posts: 11
Joined: Thu Oct 03, 2013 1:33 pm

Re: Catching GPS ACKs with GPS v3 breakout

by adafruit_support_rick on Wed Oct 30, 2013 5:32 am

How are you reading the GPS? You have to be using the interrupt. If you're reading the GPS synchronously (i.e., in loop()), then you'll block forever at waitForSentence.
User avatar
adafruit_support_rick
 
Posts: 8473
Joined: Tue Mar 15, 2011 10:42 am
Location: Buffalo, NY

Re: Catching GPS ACKs with GPS v3 breakout

by irvingwashington on Thu Oct 31, 2013 9:50 am

I was attempting to do this in the setup(), to initialize the GPS with the correct parameters, since I didn't want to complicate the loop(). I think I've got it working now, but I'm new to serial comms, so this might be working only because I'm lucky and not because it's correct. I'm using TinyGPS++ ATM simply because I found it easier to understand how to trap exactly what I wanted, but I don't think that fundamentally changes anything. And pardon my newbish C++, I'm learning it with this project.

Code: Select all
TinyGPSPlus gps;

TinyGPSCustom ack_ok(gps,"PMTK001",2);
TinyGPSCustom ack_cmd(gps,"PMTK001",1);
boolean gps_init = false;
int count = 0;

struct Init_cmd
{
  const char cmd[50];
  const int code;
  const char reason[30];
};

#define CMD_CNT 5

Init_cmd init_cmds[CMD_CNT] = {
  {"$PMTK251,9600*17",251,"Set baud to 9600" } ,
  {"$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29",314,"Set NMEA to RMCGGA"    } ,
  {"$PMTK220,1000*1F",220,"Set GPS refresh to 1Hz"    },
  {"$PMTK001,397,3*3D",001,"Disabled Nav thresholding"    },
  { "PMTK869,1,1*35",869,"Enabled EASY"    }
};

void setup() {
...

  for (int i = 0; i < CMD_CNT; i++) {
    while (!gps_init && Uart.available() > 0) {
      Uart.println(init_cmds[i].cmd);
      if (gps.encode(Uart.read())) {
        gps_init = check_ack(init_cmds[i].code);         
      }
    }
}

boolean check_ack(int cmd_code)
{
  if (ack_ok.isValid() && ack_ok.isUpdated() && atoi(ack_ok.value()) == 3 && atoi(ack_cmd.value()) == cmd_code) {
    return true;
  }
  else {
    return false;
  }
}




irvingwashington
 
Posts: 11
Joined: Thu Oct 03, 2013 1:33 pm

Re: Catching GPS ACKs with GPS v3 breakout

by adafruit_support_rick on Thu Oct 31, 2013 10:26 am

I don't know the TinyGPS library. If gps.encode doesn't return true until the entire ack is received, then your code could work.
User avatar
adafruit_support_rick
 
Posts: 8473
Joined: Tue Mar 15, 2011 10:42 am
Location: Buffalo, NY

Re: Catching GPS ACKs with GPS v3 breakout

by irvingwashington on Fri Nov 01, 2013 5:57 pm

Rick-

You were right, and some of the ACKs come back and clear the buffer so quickly that I ended up ditching the library approach completely. Serial.find() appears to be quick enough (and more importantly for me, simple enough!) to catch the majority of ACKs. Here's what appears to be working far more robustly for me now. I have to dig into the library parsing routines more, but I was getting several hundred ACK misses using either TinyGPS or the Adafruit GPS libraries before the timing would line up and I'd trap an ACK correctly. I'm almost certainly using the libraries wrong with my newb code, but at least the Serial.find() worked quickly and only drops a half dozen or so ACKs.

Code: Select all
  Uart.setTimeout(250); //shorten timeout as we'll definity miss some ACKs
  for (int i = 0; i < CMD_CNT; i++) {
    while (!gps_init && Uart.available() > 0) {
      Uart.println(init_cmds[i].cmd);
      gps_init = Uart.find(init_cmds[1].ack_code);
    }   
      display.clearDisplay();
      display.setTextSize(1);
      display.setTextColor(WHITE);
      display.setCursor(0,0);
      display.println(init_cmds[i].reason);
      Serial.println(init_cmds[i].reason);
      display.display();
      gps_init = false;
    }
  Uart.setTimeout(1000); //restore default


Thanks for the help, I wish this were easier...
Z
irvingwashington
 
Posts: 11
Joined: Thu Oct 03, 2013 1:33 pm

Re: Catching GPS ACKs with GPS v3 breakout

by homerun4711 on Thu Dec 19, 2013 6:18 pm

Hello,

I came across a similar question and hope that you can help me.
I am trying to read the Adafruit Ultimate GPS's built-in logger
using a python script and pyserial.

The module is connected using the serial-to-usb adapter I also
bought at adafruit.

I get PMTK_ACK responses one some commands but not always
and I could not find a logic so far...

adafruit_support_rick wrote

How are you reading the GPS? You have to be using the interrupt. If you're reading the GPS synchronously (i.e., in loop()), then you'll block forever at waitForSentence.


I am reading the GPS in a loop, why is this called synchronously? But there are sleep-commands
in the loop, does that suffice to allow for the module to send a response? Or how can I send an interrupt?

And does this have something to do with pyserials timeouts:
Possible values for the parameter timeout:

timeout = None: wait forever
timeout = 0: non-blocking mode (return immediately on read)
timeout = x: set timeout to x seconds (float allowed)

Writes are blocking by default, unless writeTimeout is set. For possible values refer to the list for timeout above.


I hope you have some patience and can help me :)

Kind regards,
Joe
homerun4711
 
Posts: 4
Joined: Fri Dec 06, 2013 5:45 pm

Re: Catching GPS ACKs with GPS v3 breakout

by adafruit_support_rick on Fri Dec 20, 2013 12:30 pm

I am really no good at all with python.

"Synchronously" is just a fancy way of saying that you're doing something in your main program context. Interrupts are "asynchronous" because they can happen at any time, regardless of where your main program is executing.

On the Pi, serial data should already be serviced by an interrupt and placed into an input buffer by the operating system. When you do a read from the GPS, you are actually getting data from this input buffer, not directly from the GPS.

If your main program goes to sleep at times, and the ACK comes in while you're sleeping, then you can have what's called a "buffer overrun", in which subsequent data from the GPS over-writes the ACK characters in the serial input buffer.

The short answer is, you don't have to worry about interrupts on the Pi, but you may have to worry about going to sleep for extended periods of time, since that may lead to a buffer overrun condition.
homerun4711 wrote:And does this have something to do with pyserials timeouts:
Possible values for the parameter timeout:

timeout = None: wait forever
timeout = 0: non-blocking mode (return immediately on read)
timeout = x: set timeout to x seconds (float allowed)

Writes are blocking by default, unless writeTimeout is set. For possible values refer to the list for timeout above.

"Blocking" means that, when call read, it will wait until enough data comes in to satisfy the read. Your program will stop and wait (i.e., it is "blocked" from continuing). If you set timeout to 0, then the read is "non-blocking": it will return immediately, whether there was any data to read or not. It will tell you the number of characters it was able to read (possibly 0). With any other timeout value, the read will block for the amount of time specified as the timeout, then it will return and tell you how many characters it was able to read (again, possibly 0).
User avatar
adafruit_support_rick
 
Posts: 8473
Joined: Tue Mar 15, 2011 10:42 am
Location: Buffalo, NY

Re: Catching GPS ACKs with GPS v3 breakout

by irvingwashington on Fri Dec 20, 2013 4:41 pm

Joe-

If you're attempting to catch the PMTA_ACK from a command you issued, you may have to send the command several times until you catch it. You're using something other than an Arduino, so I can't speak to it, but on the duino, I was having issues catch the ack as the serial buffer on the duino was getting overrun (as Rick alludes to) by all the NMEA sentences it's emitting.

I eventually just wrapped my entire initialization in a loop that keeps sending the configuration command until it can catch the ACK. I'm doing this with the arduino serial find, and avoiding any GPS libraries or such since the response can come back super fast.

Another thing to try is to disable the NMEA sentences completely so the only output from the unit should be the ACKs to your commands. Once you finished your configuration, reenable the NMEA output.

Z
irvingwashington
 
Posts: 11
Joined: Thu Oct 03, 2013 1:33 pm

Re: Catching GPS ACKs with GPS v3 breakout

by homerun4711 on Sat Dec 21, 2013 5:47 am

Hello Rick and Z,

thank you very much for your elaborate and very helpful replies!

I will take a look at the code now and try to improve it.

Btw, the Ultimate GPS is attached to a Raspberry Pi.

Kind regards,
Joe
homerun4711
 
Posts: 4
Joined: Fri Dec 06, 2013 5:45 pm