macdonaldtomw
Member
So I've been banging my head against my keyboard for a few days because I can't figure out how to get my new GPS shield to play nicely with my Teensy 3.1 (Arduino compatible) microcontroller.
The GPS shield in question is iteaduino based, and can be seen here.
I have no trouble using the TinyGPS Arduino Library to parse incoming data from the NEO 6 gps module on the Teensy's UART pins, and output latitude and longitude to my serial monitor in the Arduino IDE, as shown on the Teensy GPS page.
The problem arises when I try to issue a NMEA command or a UBX command to the NEO 6. This is the only way to actually control the module, instead of just letting it drone out the same 6 NMEA messages every second. (for example, you can't set the module into power save mode without issuing a UBX RXM-PMREQ command, or disable unneeded messages from being sent without issuing a UBX CFG command).
A guide to these command protocols can be found here.
I started by basing my code on the example provided by ukhas, but couldn't get that to work. So, I made a simple small program that basically does the following:
No acknowledgement message ever comes! What am I doing wrong?!
Here is the UBX data packet that I am sending, along with a graphic from the manual on how a UBX data packet should be formatted:
B5, 62, 6, 1, 3, 0, F0, 1, 0, FB, 11
Here is what the Serial Monitor spits out:
Here is my full test code:
I'm starting to wonder if perhaps my Fletcher Checksum algorithm is incorrect? Here is my algorithm:
And here is the part of in the protocol manual that defines how to calculate the checksum:
If anyone has any ideas, I would be ever so grateful!
The GPS shield in question is iteaduino based, and can be seen here.
I have no trouble using the TinyGPS Arduino Library to parse incoming data from the NEO 6 gps module on the Teensy's UART pins, and output latitude and longitude to my serial monitor in the Arduino IDE, as shown on the Teensy GPS page.
The problem arises when I try to issue a NMEA command or a UBX command to the NEO 6. This is the only way to actually control the module, instead of just letting it drone out the same 6 NMEA messages every second. (for example, you can't set the module into power save mode without issuing a UBX RXM-PMREQ command, or disable unneeded messages from being sent without issuing a UBX CFG command).
A guide to these command protocols can be found here.
I started by basing my code on the example provided by ukhas, but couldn't get that to work. So, I made a simple small program that basically does the following:
- Establishes serial communication to NEO 6 module at 9600 baud
- Sends the GPS module an 11 byte data packet that follows UBX protocol, telling it to stop sending out NMEA lat/lon messages
- Parses incoming data packets from the GPS module in search of an ACK (acknowledgement) message
No acknowledgement message ever comes! What am I doing wrong?!
Here is the UBX data packet that I am sending, along with a graphic from the manual on how a UBX data packet should be formatted:
B5, 62, 6, 1, 3, 0, F0, 1, 0, FB, 11
Here is what the Serial Monitor spits out:
Code:
Attempting to send UBX command to turn of GLL reporting
Original message is 7 bytes:
6, 1, 3, 0, 240, 1, 0,
fullPacket is:
B5, 62, 6, 1, 3, 0, F0, 1, 0, FB, 11,
________________________________
* Reading ACK response:
---->Searching for following UBX ACK response:
Target ACK packet: B5, 62, 5, 1, 2, 0, 6, 1, F, 38,
Candidate packet: B5, 70 -->NOPE!
Candidate packet: B5, 38 -->NOPE!
Candidate packet: <<<Response timed out!>>>
1, ED, 1C, 59, A, BC, 1C, 31, 9D, 9D, B8, 31, B1, B8, 31, 32, B1, 0, 85, 25, 31, 25, 31, 25, B1, 10, 40, BD, 50, B9, 90, 5D, 8B, 3C, 1D, 70, 50, 3D, 30, B9, 35, A1, 35, 62, 8, 21, A1, 21, 39, 38, 31, 31, 30, 3D, 10, 18, 14, 83, B4, 84, 3C, 10, B1, 10, 9D, 3D, 38, 11, 90, 3D, 3C, 3C, 30, 2C, 48, 73, 10, 39, 58, 19, B8, 3C, 38, 11, 11, 39, 39, BD, 30, 2C, 48, 7B, 90, 3D, 5C, 18, 16, 3, 24, 21, 86, 8B, 3C, 1D, 70, 98, 38, 10, 32, FC, 1, ED, 9C, 59, A, BC, BC, 31, 9D, 9D, B8, 31, 95, 86, 94, B2, B1, 0, 85, 25, 31, A5, 18, 8A, 38, 1, 10, 9C, 59, 99, 9D, 3D, 31, 63, 86, B, B8, 19, BD,
B5, 38, 35, BC, 10, 40, 21, 35, A1, 23, 73, 31, 11, BD, 19, 50, 98, 10, 48, 7B, 10, 19, 38, 1D, B8, BC, 11, 39, 18, B8, 11, 59, 19, 39, 1, 17, 50, 5D, BD, 39, BC, 10, 31, B0, 59, 19, B8, 50, 11, FC, 10, 48, 7B, 90, 3D, 5C, 18, 16, 3, 24, 21, 86,
Here is my full test code:
Code:
#include <HardwareSerial.h>
#include <string.h>
#include <TinyGPS.h>
void gpsdump(TinyGPS &gps);
void printFloat(double f, int digits = 2);
HardwareSerial2 GPS= HardwareSerial2(); //Initialize harware serial object for the GPS unit
TinyGPS gps;
byte gps_set_sucess = 0 ;
//Pin Definitions
int GPS_RxPin= 9;
int GPS_TxPin=10;
//I/O variables
int GPSbaud = 9600;
int Serialbaud=9600;
int byteCount;
//----------------------------------GPS unit functions------------------------------------------------
// Send a byte array of UBX protocol to the GPS
void sendUBX(uint8_t *MSG, uint32_t len, long timeout=3000) {
uint32_t CK_A = 0, CK_B = 0;
uint8_t sum1=0x00, sum2=0x00;
uint8_t fullPacket[len+4];
for(int i=0; i<len; i++) {
fullPacket[i+2]=MSG[i];
}
Serial.println();
fullPacket[0]=0xB5;
fullPacket[1]= 0x62;
//Calculate checksum
for(int i=0; i<len; i++){
CK_A = CK_A + MSG[i];
CK_B = CK_B + CK_A;
//Uncomment next two lines to see steps in checksum calculation
//Serial.println("CK_A= " + String(CK_A));
//Serial.println("CK_B= " + String(CK_B));
}
sum1 = CK_A &0xff;//Mask the checksums to be one byte
sum2= CK_B &0xff;
fullPacket[len+2]=sum1; //Add the checksums to the end of the UBX packet
fullPacket[len+3]=sum2;
// Serial.print("Checksum 1 premask= ");
// Serial.println(CK_A,HEX);
// Serial.print("Checksum 1 postmask= ");
// Serial.println(sum1, HEX);
//
// Serial.print("Checksum 2 premask= ");
// Serial.println(CK_B,HEX);
// Serial.print("Checksum 2 postmask= ");
// Serial.println(sum2, HEX);
Serial.println("fullPacket is:");
for(int i=0; i<(len+4); i++) {
Serial.print(fullPacket[i],HEX);//Print out a byt of the UBX data packet to the serial monitor
Serial.print(", ");
GPS.print(fullPacket[i],HEX);//Send a byte of the UBX data packet to the GPS unit
}
GPS.clear();
Serial.println();
Serial.println("________________________________");
}//end function
// Calculate expected UBX ACK packet and parse UBX response from GPS--------------------------
boolean getUBX_ACK(uint8_t *MSG, uint32_t len) {
uint8_t b;
uint8_t ackByteID = 0;
uint8_t ackPacket[10];
unsigned long startTime = millis();
uint32_t CK_A=0, CK_B=0;
boolean notAcknowledged=false;
Serial.println(" * Reading ACK response: ");
// Construct the expected ACK packet
ackPacket[0] = 0xB5; // header
ackPacket[1] = 0x62; // header
ackPacket[2] = 0x05; // class
ackPacket[3] = 0x01; // id
ackPacket[4] = 0x02; // length
ackPacket[5] = 0x00;
ackPacket[6] = MSG[0]; // MGS class
ackPacket[7] = MSG[1]; // MSG id
ackPacket[8] = 0; // CK_A
ackPacket[9] = 0; // CK_B
// Calculate the checksums
for (uint8_t i=2; i<8; i++) {
CK_A = CK_A + ackPacket[i];
CK_B= CK_B + CK_A;
}
ackPacket[8]= CK_A &0xff;//Mask the checksums to be one byte
ackPacket[9]= CK_B &0xff;
Serial.println("---->Searching for following UBX ACK response:");
Serial.print("Target ACK packet: ");
for(int i =0; i<10; i++) {
Serial.print(ackPacket[i], HEX);
Serial.print(", ");
}
Serial.println();
Serial.print("Candidate packet: ");
while (1) {
// Test for success
if (ackByteID > 9) {
// All packets in order!
Serial.println(" (Response received from GPS unit:)");
if(notAcknowledged){
Serial.println("ACK-NAK!");
}
else{
Serial.println("ACK-ACK!");
return true;
}
}
// Timeout if no valid response in 5 seconds
if (millis() - startTime > 5000) {
Serial.println("<<<Response timed out!>>>");
return false;
}
// Make sure data is available to read
if (GPS.available()) {
b = GPS.read();
// Check that bytes arrive in sequence as per expected ACK packet
if (b == ackPacket[ackByteID]) {
ackByteID++;
Serial.print(b, HEX);
Serial.print(", ");
// Check if message was not acknowledged
if (ackByteID==3){
b=GPS.read();
if (b==0x00){
notAcknowledged=true;
ackByteID++;
}
else if (b== 0x01){
notAcknowledged=false;
ackByteID++;
}
}
}
else if(ackByteID>0){
ackByteID = 0; // Reset and look again, invalid order
Serial.print(b,HEX);
Serial.println(" -->NOPE!");
Serial.print("Candidate packet: ");
}
}
}//end while
}//end function
//--------SETUP------------------
void setup()
{
boolean gps_get_success=false;
delay(5000);//Give yourself time to open up the serial monitor
pinMode(GPS_TxPin,OUTPUT); //Define the UART transmission pin for ommunication with the GPS unit
pinMode(GPS_RxPin,INPUT); // Define the UART read pin for communication with the GPS unit
Serial.begin(Serialbaud); //Begin serial ommunication with Serial Monitor
Serial.println("Serial monitor operational");
GPS.begin(GPSbaud); //Begin serial communication with GPS unit
//Compile a UBX data packet to send to GPS - turn off GLL reporting
uint8_t disableGLL[] = {0x06, 0x01, 0x03, 0x00, 0xF0, 0x01, 0x00};
uint32_t len= sizeof(disableGLL)/sizeof(uint8_t);
//Print original command to Serial Monitor
Serial.println("Attempting to send UBX command to turn of GLL reporting");
Serial.println("Original message is " + String(len) + " bytes:");
for(int i=0; i<len; i++) {
Serial.print(disableGLL[i]);
Serial.print(", ");
}
Serial.println();
//Clear the communication buffer
GPS.clear();
sendUBX(disableGLL, len);
getUBX_ACK(disableGLL, len);
// delay(5000);
//Try to disable the automatic messaging by sending some PUBX 40 commands
// Serial.println();
// Serial.println("Attempting to print PUBX messages to the GPS unit");
// Serial.println("$PUBX,40,GLL,0,0,0,0*5C");
// Serial.println("$PUBX,40,GGA,0,0,0,0*5A");
// Serial.println("$PUBX,40,GSA,0,0,0,0*4E");
// Serial.println("$PUBX,40,RMC,0,0,0,0*47");
// Serial.println("$PUBX,40,GSV,0,0,0,0*59");
// Serial.println("$PUBX,40,VTG,0,0,0,0*5E");
// Serial.println("-----------------------");
//
// GPS.println("$PUBX,40,GLL,0,0,0,0*5C");
// GPS.println("$PUBX,40,GGA,0,0,0,0*5A");
// GPS.println("$PUBX,40,GSA,0,0,0,0*4E");
// GPS.println("$PUBX,40,RMC,0,0,0,0*47");
// GPS.println("$PUBX,40,GSV,0,0,0,0*59");
// GPS.println("$PUBX,40,VTG,0,0,0,0*5E");
//End the communication over the 9600 baud frequency and start again at 38400 for NMEA messages
// GPS.end();
// Serial.end();
// delay(1000);
// GPS.begin(38400);
// Serial.begin(38400);
}
//--------MAIN LOOP-------MAIN LOOP-------MAIN LOOP-------MAIN LOOP-------MAIN LOOP-------MAIN LOOP--
void loop()
{
while ( GPS.available())
{
char c = GPS.read();
if(c==0xb5){Serial.println();}
Serial.print(c,HEX); // uncomment this line if you want to see the GPS data flowing
Serial.print(", ");
}
while (Serial.available()){
char input = Serial.read();
if (input=='~'){
GPS.end();
Serial.end();
setup();
}
}
}//END LOOP-------------------
I'm starting to wonder if perhaps my Fletcher Checksum algorithm is incorrect? Here is my algorithm:
Code:
//Calculate checksum
for(int i=0; i<len; i++){
CK_A = CK_A + MSG[i];
CK_B = CK_B + CK_A;
//Uncomment next two lines to see steps in checksum calculation
//Serial.println("CK_A= " + String(CK_A));
//Serial.println("CK_B= " + String(CK_B));
}
sum1 = CK_A &0xff;//Mask the checksums to be one byte
sum2= CK_B &0xff;
fullPacket[len+2]=sum1; //Add the checksums to the end of the UBX packet
fullPacket[len+3]=sum2;
And here is the part of in the protocol manual that defines how to calculate the checksum:
If anyone has any ideas, I would be ever so grateful!