Disabling static navigation GPS module PMB-648. SOLVED!!

Hi Guys,

I am pretty new to this stuff still but can usually make stuff work with a certain amount of google and cut/ paste but I am stuck on this one.

I am interfacing with a parallax GPS sensor (PMB-648 NMEA). Everything is working great except it will not transmit speed if it is below aprox 3.0 MPH. This is a problem for what I am trying to do. Turns out this is something called "static navigation", and it can be disabled by sending a command to the unit (after commanding the unit to switch to binary mode).

This is where I need some help, I am obviously not knowledgeable on binary and sending data via serial!

Here is a quote from the parallax forum for arduino code to turn static navigation off. There were reply's to indicate that it was successful.

"The following will turn it off:
Using 4800 baud send/Serial.print
this string:
("$PSRF100,0,4800,8,1,0*0F",\r,\n)
followed by this series of Hex bytes
0xA0,0xA2,0x00,0x02,0x8F,0x00,0x00,0x8F,0xB0,0xB3
0xA0,0xA2,0x00,0x18,0x81,0x02,0x01,001,0x00,0x01
0x00,0x01,0x00,0x01,0x01,0x01,0x00,0x01,0x00,0x01
0x00,0x01,0x00,0x01,0x00,0x01,0x12,0xC0,0x01,0x61
0xB0,0xB3
To clarify:
re. the bytes --
Serial.print(0xA0, BYTE);
Serial.print(0xA2, BYTE);
and so on

I can't seem to make this work. The Sensor is connected to pins A3 (Rx), and A2 (TX) on software serial. I could not get it to compile like the above mentioned (says "BYTE is no longer valid) so I tried this in the setup of my code.:

SoftwareSerial nss(A3, A2);
nss.begin(4800);

nss.println("$PSRF100,0,4800,8,1,0*0F");
nss.write((byte)0xA0);
nss.write((byte)0xA2);
nss.write((byte)0x00);
nss.write((byte)0x02);
nss.write((byte)0x8F);
nss.write((byte)0x00);
nss.write((byte)0x00);
nss.write((byte)0x8F);
nss.write((byte)0xB0);
nss.write((byte)0xB3);

nss.write((byte)0xA0);
nss.write((byte)0xA2);
nss.write((byte)0x00);
nss.write((byte)0x18);
nss.write((byte)0x81);
nss.write((byte)0x02);
nss.write((byte)0x01);
nss.write((byte)0x01);
nss.write((byte)0x00);
nss.write((byte)0x01);

nss.write((byte)0xA0);
nss.write((byte)0xA2);
nss.write((byte)0x00);
nss.write((byte)0x18);
nss.write((byte)0x81);
nss.write((byte)0x02);
nss.write((byte)0x01);
nss.write((byte)0x01);
nss.write((byte)0x00);
nss.write((byte)0x01);

nss.write((byte)0x00);
nss.write((byte)0x01);
nss.write((byte)0x00);
nss.write((byte)0x01);
nss.write((byte)0x00);
nss.write((byte)0x01);
nss.write((byte)0x12);
nss.write((byte)0xC0);
nss.write((byte)0x01);
nss.write((byte)0x61);

nss.write((byte)0xB0);
nss.write((byte)0xB3);

This will compile but does not change anything.

Here is the complete code:

#include <TinyGPS.h>
#include <SoftwareSerial.h>
#include <LiquidCrystal.h>
#include <Servo.h>

Servo myservo1;
Servo myservo2;
TinyGPS gps;

LiquidCrystal lcd(9, 8, 7, 6, 5, 4);
SoftwareSerial nss(A3, A2);



int leftposition;
int rightposition;
int lastleftposition;
int lastrightposition;
float leftright;
float foraft;
unsigned long lastmillis;
int incriment;
int buttondelay;
int leftservomicros;
int rightservomicros;



float rawMPH;
int ALT;
const int numReadings = 5;
int readings[numReadings];      // the readings from the analog input
int index = 0;                  // the index of the current reading
float total = 0;                  // the running total
float smoothMPH = 0;                // the average

void setup(){
  myservo1.attach(3);
  myservo2.attach(10);
  leftposition = 45;  //set intial servo position to 45 degrees, neutral.
  rightposition = 45; //same for the right.
  lastmillis = millis();
  incriment = 1;
  buttondelay = 0;

  Serial.begin(9600);
  lcd.begin(16, 2);
  nss.begin(4800);
  for (int thisReading = 0; thisReading < numReadings; thisReading++) //for smothing speed
    readings[thisReading] = 0; //smothing speed
delay(1000);
nss.println("$PSRF100,0,4800,8,1,0*0F");
nss.write((byte)0xA0);
nss.write((byte)0xA2);
nss.write((byte)0x00);
nss.write((byte)0x02);
nss.write((byte)0x8F);
nss.write((byte)0x00);
nss.write((byte)0x00);
nss.write((byte)0x8F);
nss.write((byte)0xB0);
nss.write((byte)0xB3);

nss.write((byte)0xA0);
nss.write((byte)0xA2);
nss.write((byte)0x00);
nss.write((byte)0x18);
nss.write((byte)0x81);
nss.write((byte)0x02);
nss.write((byte)0x01);
nss.write((byte)0x01);
nss.write((byte)0x00);
nss.write((byte)0x01);

nss.write((byte)0xA0);
nss.write((byte)0xA2);
nss.write((byte)0x00);
nss.write((byte)0x18);
nss.write((byte)0x81);
nss.write((byte)0x02);
nss.write((byte)0x01);
nss.write((byte)0x01);
nss.write((byte)0x00);
nss.write((byte)0x01);

nss.write((byte)0x00);
nss.write((byte)0x01);
nss.write((byte)0x00);
nss.write((byte)0x01);
nss.write((byte)0x00);
nss.write((byte)0x01);
nss.write((byte)0x12);
nss.write((byte)0xC0);
nss.write((byte)0x01);
nss.write((byte)0x61);

nss.write((byte)0xB0);
nss.write((byte)0xB3);

}

void loop(){



  // FLIGHT CONTROLS:



  leftright = map(analogRead(A2), 0, 1023, 0.0, 5.0); // map to volts 0 - 5 (2.5 is neutral!)
  foraft = map(analogRead(A3), 0, 1023, 0.0, 5.0);  // same as above

  if((leftright < 2.0) && (millis() > lastmillis + (buttondelay))){
    leftposition -= (incriment);
    rightposition += (incriment);
    lastmillis = millis();
  }

  if((leftright > 2.9 ) && (millis() > lastmillis + (buttondelay))){
    leftposition += (incriment);
    rightposition -= (incriment);
    lastmillis = millis();
  }

  if((foraft < 2.0) && (millis() > lastmillis + (buttondelay))){
    leftposition -= (incriment);
    rightposition -= (incriment);
    lastmillis = millis();
  }

  if((foraft > 2.9 ) && (millis() > lastmillis + (buttondelay))){
    leftposition += (incriment);
    rightposition += (incriment);
    lastmillis = millis();
  }

  leftposition = constrain(leftposition, 0, 90);
  rightposition = constrain(rightposition, 0, 90);

  leftservomicros = map(leftposition, 0, 90, 1050, 1950); //limits for servo in microseconds
  rightservomicros = map(rightposition, 0, 90, 1950, 1050);// limits for servo

  myservo1.writeMicroseconds(leftservomicros);
  myservo2.writeMicroseconds(rightservomicros);

  /*if(lastleftposition != leftposition){
   lcd.setCursor(0,1);
   lcd.print("L: ");
   lcd.setCursor(2, 1);
   lcd.print(leftposition);
   lastleftposition = leftposition;
   }
   
   if(lastrightposition != rightposition){
   lcd.setCursor(4,1);
   lcd.print("R: ");
   lcd.setCursor(6, 1);
   lcd.print(rightposition);
   lastrightposition = rightposition;
   }
   */

  // GPS INTERFACE:

  bool newData = false;
  unsigned long chars;
  unsigned short sentences, failed;

  // For one second we parse GPS data and report some key values
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (nss.available())
    {
      char c = nss.read();
      // Serial.write(c); // uncomment this line if you want to see the GPS data flowing
      if (gps.encode(c)) // Did a new valid sentence come in?
        newData = true;
    }
  }

  if (newData)
  {
    float flat, flon;
    unsigned long age;

    //GPS SMOOTHING SPEED

    rawMPH = (gps.f_speed_mph() == TinyGPS::GPS_INVALID_F_SPEED ? 0 : gps.f_speed_mph());
    total= total - readings[index];    // subtract the last reading:       
    readings[index] = rawMPH;   // read from the sensor:  
    total= total + readings[index];      // add the reading to the total:
    index = index + 1;      // advance to the next position in the array:             
    if (index >= numReadings)    // if we're at the end of the array...
      index = 0;            // ...wrap around to the beginning: 
    smoothMPH = total / numReadings;     // calculate the average (smoothMPH):
    Serial.println(smoothMPH);  // send it to the computer as ASCII digits

    lcd.setCursor(0, 0);
    lcd.print("MPH:");
    lcd.setCursor(4,0); 
    lcd.print(rawMPH);
    Serial.print(rawMPH);

    lcd.setCursor(0,1);
    lcd.print("sm:");
    lcd.setCursor(3, 1);
    lcd.print(smoothMPH, 1);

    lcd.setCursor(8,1);
    lcd.print("ALT:");
    lcd.setCursor(12 ,1);
    lcd.print((gps.altitude() == TinyGPS::GPS_INVALID_ALTITUDE ? 0 : gps.altitude()) * .0328, 0); // ZERO DECIMALS!
    Serial.print((gps.altitude() == TinyGPS::GPS_INVALID_ALTITUDE ? 0 : gps.altitude()) * .0328);
    lcd.setCursor(10,0);
    lcd.print("SAT:");
    lcd.setCursor(14,0);
    lcd.print(gps.satellites() == TinyGPS::GPS_INVALID_SATELLITES ? 0 : gps.satellites(), 2);
    Serial.print(gps.satellites() == TinyGPS::GPS_INVALID_SATELLITES ? 0 : gps.satellites(), 2);

  }


}

I really hope someone can help me figure this out! I will post the actual SIRF NMEA guide for setting the GPS unit to binary mode and sending the proper command tomorrow (which is what the quote at the beginning is). Thanks for your time in reading this post!

Roto.

The data you send and the list you referred to don't match. Also the .write command now sends byte values according to reference Serial.write() - Arduino Reference but if you remove the (byte) casting from any nss.write((byte)0x00); the compiler complains. Not sure if this is a bug, a feature or my ignorance.

Not sure if this is a bug, a feature or my ignorance.

None of the above. It is a difference between SoftwareSerial and HardwareSerial.

PaulS:

Not sure if this is a bug, a feature or my ignorance.

None of the above. It is a difference between SoftwareSerial and HardwareSerial.

Surly if using these two statement...

nss.write(0xA2);
nss.write(0x00);

and the first (with a non zero number) compiles fine and the latter fails, it's a bug?

Surly if using these two statement...and the first (with a non zero number) compiles fine and the latter fails, it's a bug?

No. Does 0x00 represent a byte, an int, or a pointer? Since there is no type information supplied, the compiler can not tell which of the overloaded write() methods (the one for a byte, the one for an int, or the one for a pointer) to call.

It's hardly a bug in the class definition or the compiler that there is an ambiguity. You can easily make the code compile:

byte val = 0x02;
Serial.write(val);
val = 0x00;
Serial.write(val);

Now, the compiler KNOWS that it is the byte version that you want to use.

Or, the cast you first showed also resolves the ambiguity.

PaulS:

Surly if using these two statement...and the first (with a non zero number) compiles fine and the latter fails, it's a bug?

No. Does 0x00 represent a byte, an int, or a pointer? Since there is no type information supplied, the compiler can not tell which of the overloaded write() methods (the one for a byte, the one for an int, or the one for a pointer) to call.

It's hardly a bug in the class definition or the compiler that there is an ambiguity. You can easily make the code compile:

But couldn't the same be said of the 0xA2 example, how is the class overload to know if it's a byte, int or pointer. As it compiles I assume the value is being picked up by one of the overloads but why not with a value of zero?

But couldn't the same be said of the 0xA2 example, how is the class overload to know if it's a byte, int or pointer. As it compiles I assume the value is being picked up by one of the overloads but why not with a value of zero?

Because 0 is a special case as far as pointers go. 0xA2 is not a valid pointer value, so the compiler knows not to choose the pointer method. 0x00 is a valid pointer value (although meaningless in this context).

Thank you to everyone that replied.

So I am assuming that this portion is correct?

this is what they said to send:

("$PSRF100,0,4800,8,1,0*0F",\r,\n)

and I sent it like this:

nss.println("$PSRF100,0,4800,8,1,0*0F");?

and I need to take Pauls suggestion and follow this format to write the bytes (one after the other like this):

byte val = 0x02;
Serial.write(val);
val = 0x00;
Serial.write(val);

I will try to write this up right now!!
Thanks again!
Roto.

Hi Rotorfixer,

Sorry, I muddied the water with the discussion with PaulS.

The way you was doing it by type casting was fine but the data did not match what you said you had to send. One of them is wrong.
You said you need to send this...

0xA0,0xA2,0x00,0x02,0x8F,0x00,0x00,0x8F,0xB0,0xB3

0xA0,0xA2,0x00,0x18,0x81,0x02,0x01,001,0x00,0x01

0x00,0x01,0x00,0x01,0x01,0x01,0x00,0x01,0x00,0x01

0x00,0x01,0x00,0x01,0x00,0x01,0x12,0xC0,0x01,0x61

0xB0,0xB3

But your sending this... I have highlighted the errors

nss.write((byte)0xA0);
nss.write((byte)0xA2);
nss.write((byte)0x00);
nss.write((byte)0x02);
nss.write((byte)0x8F);
nss.write((byte)0x00);
nss.write((byte)0x00);
nss.write((byte)0x8F);
nss.write((byte)0xB0);
nss.write((byte)0xB3);

nss.write((byte)0xA0);
nss.write((byte)0xA2);
nss.write((byte)0x00);
nss.write((byte)0x18);
nss.write((byte)0x81);
nss.write((byte)0x02);
nss.write((byte)0x01);
nss.write((byte)0x01);
nss.write((byte)0x00);
nss.write((byte)0x01);

nss.write((byte)0xA0); //0x00
nss.write((byte)0xA2); //0x01
nss.write((byte)0x00);
nss.write((byte)0x18); //0x01
nss.write((byte)0x81); //0x01
nss.write((byte)0x02); //0x01
nss.write((byte)0x01); //0x00
nss.write((byte)0x01);
nss.write((byte)0x00);
nss.write((byte)0x01);

nss.write((byte)0x00);
nss.write((byte)0x01);
nss.write((byte)0x00);
nss.write((byte)0x01);
nss.write((byte)0x00);
nss.write((byte)0x01);
nss.write((byte)0x12);
nss.write((byte)0xC0);
nss.write((byte)0x01);
nss.write((byte)0x61);

nss.write((byte)0xB0);
nss.write((byte)0xB3);

Thank you for pointing that out, but still no joy.

This is the SIRF manual.

http://www.google.ca/url?sa=t&rct=j&q=sirf%20v2.4%20manual&source=web&cd=1&ved=0CDAQFjAA&url=http%3A%2F%2Fgpsd.googlecode.com%2Ffiles%2FSiRF-SiRF-v2_4.pdf&ei=g3a7UJW3JuzgigLOr4CwDg&usg=AFQjCNHtBego11gP7wNTiLWqk2stPZXt2g&sig2=sk6PzIqWtwS7TkD0TdoIug

Page 17 is the protocol for messages in general.
Page 30 for binary setting?
page 35 static navigation
Page 25 switching back to NMEA

Roto.

nss.write((byte)0xA0);
nss.write((byte)0xA2);
nss.write((byte)0x00);
nss.write((byte)0x02);
nss.write((byte)0x8F);
nss.write((byte)0x00);
nss.write((byte)0x00);
nss.write((byte)0x8F);
nss.write((byte)0xB0);
nss.write((byte)0xB3);

Can I recommend you become acquainted with for loops and arrays?

Point taken!

I know what you mean, haven't played with them yet and this way I could feel confident that I know exactly what is being sent just by looking at it.

I think I have narrowed it down to the unit not receiving the very first command:

nss.println("$PSRF100,0,4800,8,1,0*0F");

Because when I just send that command it should turn off the NMEA output but it doesn't.

Would it make sense to try to send that command to the RS-232 RX wire of the GPS module instead of the TTL RX (which I am currently)???

Well the CRC for the data codes check out ok.
Is it worth trying a delay after sending nss.println("$PSRF100,0,4800,8,1,0*0F"); as manual says...

When a valid message is received, the parameters are stored in battery-backed SRAM and then the unit restarts using the saved parameters.

I wonder if you start sending the remaining data before the device has rebooted properly and your loosing some of it.

EDIT: You had posted while I was calculating and it seems my idea pans out if your device is resetting

trying that now! Thanks for looking into it.

like a delay(1000) after the nmea command?

rotorfixer:
trying that now! Thanks for looking into it.

like a delay(1000) after the nmea command?

How long does it take to reboot one of these devices? Just add a bit more to that time.

Tried that, doesn't do anything !

again, it does't seem to catch the first nmea message.

I know that the unit sends out responses, but I wouldn't know how to catch them?

It would be nice to see what it is saying!

but even if that was the problem, it WOULD react to that message, even if it did not catch the rest.

If I am not mistaken that NMEA message would set the unit to binary, in order to receive the messages sent in BYTE. If delay was the key then it would be stuck in binary mode don't you think?

trying a larger delay now......

HI !!!!

IT FINALLY WORKED!!!!

I ended up switching the RX wire to arduino pin10 (to try a digital pin) and implementing a delay like you said.

What I didn't see is a conflict, I was using pin 10 to write a servo position. Once I cleared that up it worked!!! SO HAPPY!!!

Thanks for your help with this!

This project might seem like an RC aircraft but it is not. This is for a wing in ground-effect machine flown by a human. It is going to be on the Discovery Channel early next year, the plan will be to go full fly-by-wire but for not it is just running flapperon controls.

Thanks again!!

This forum rocks!

I had seen you was using analogue pins for soft serial but did not realize that would be a problem.
Glad you got it working in the end.
Alas I don't get Discovery so will probably never see the fruits of your labour.

Hi. I was thinking the same thing but because it was receiving the data I thought there wasn't a problem. Maybe I should have set A3 to output first ? Anyways I am going to play with it a bit more and post the final code related to the programming. There are several threads on different forums and this as far as I can tell is the first time of it working with arduino.

Thanks again guys!