ublox NEO 6m:UBX命令健全性检查(使用Fletcher校验和!)

时间:2014-04-13 01:18:49

标签: gps arduino checksum nmea

因为我无法弄清楚如何让我的新GPS防护罩与我的Teensy 3.1(Arduino兼容)微控制器很好地配合使用,所以我已经在我的键盘上敲了几天。 / p>

有问题的GPS防护罩是iteaduino based, and can be seen here.

使用TinyGPS Arduino Library解析来自Teensy UART引脚上NEO 6 gps模块的输入数据,并将纬度和经度输出到Arduino IDE中的串行监视器,我没有任何问题。

当我尝试向NEO 6发出NMEA命令或UBX命令时出现问题。这是实际控制模块的唯一方法,而不是让它每秒无人机地输出相同的6条NMEA消息。 (例如,您无法在不发出UBX RXM-PMREQ命令的情况下将模块设置为省电模式。)

我的开始是将我的代码基于example provided by ukhas,但无法使其发挥作用。所以,我做了一个简单的小程序,基本上做了以下几点:

  1. 以9600波特率建立与NEO 6模块的串行通信
  2. 向GPS模块发送一个遵循UBX协议的11字节数据包,告诉它停止发送NMEA lat / lon消息
  3. 解析来自GPS模块的输入数据包以搜索ACK(确认)消息
  4. 没有确认消息!我做错了什么?!

    这是我的代码:

    #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=19200;
    
    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;
        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.write(fullPacket[i]);//Send a byte of the UBX data packet to the GPS unit
      }
      GPS.clear(); 
      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.print(" * 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 UBX ACK response:");
      Serial.print("Target data 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(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); 
    
     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
       while ( GPS.available())
        {
          char c = GPS.read();
        }
    
     sendUBX(disableGLL, len);
     getUBX_ACK(disableGLL, len);
    
    
    }
    
    //--------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(", ");
        }
    
    }//END LOOP-------------------
    

    我不确定为什么GPS模块没有响应我的命令。它开始变得傲慢无礼。这是串行监视器输出:

    Serial monitor operational
    Attempting to send UBX command to turn of GLL reporting
    Original message is 7 bytes:
    6, 1, 3, 0, 240, 1, 0, 
    
    CK_A= 6
    CK_B= 6
    CK_A= 7
    CK_B= 13
    CK_A= 10
    CK_B= 23
    CK_A= 10
    CK_B= 33
    CK_A= 250
    CK_B= 283
    CK_A= 251
    CK_B= 534
    CK_A= 251
    CK_B= 785
    Checksum 1 premask= FB
    Checksum 1 postmask= FB
    Checksum 2 premask= 311
    Checksum 2 postmask= 11
    fullPacket is:
    B5, 62, 6, 1, 3, 0, F0, 1, 0, FB, 11, 
     * Reading ACK response: Searching for UBX ACK response:
    Target data packet: B5, 62, 5, 1, 2, 0, 6, 1, F, 38, 
    Candidate   packet: B5, 38 -->NOPE!
    Candidate   packet: B5, CC -->NOPE!
    Candidate   packet: B5, 38 -->NOPE!
    Candidate   packet: <<<Response timed out!>>>
    

    以下是通过UART进入原始字节的示例(这些字节被发送到arduino串行监视器)

    B5, 38, 35, FC, 10, 40, A1, 59, 3C, 10, 1D, 3C, 30, 11, BD, 19, 90, 18, 10, 48, BD, 51, 39, 1C, 3C, 10, 39, 5D, BC, 91, 91, 59, 3D, B9, B1, B1, 10, D5, 3C, B0, 59, 3D, 3C, 10, 91, 3D, B8, BC, 90, 19, 38, BC, 10, 48, BD, 11, 1D, 1C, 38, 50, 39, 11, 1D, 18, 3C, 11, B9, 1D, 3D, 1, 17, 11, 59, BC, 3C, 10, 5D, 18, B8, 50, 9D, 31, AC, 42, 1D, 5C, 71, 98, B1, 3C, B, 99, 59, 8A, 39, 1, CD, 19, 59, A, BC, 18, 31, 9D, 9D, BC, 31, A5, 86, 94, 32, B1, 0, 85, 25, B1, A5, 1C, 8A, 30, 1, 10, 19, 59, 99, 1D, 38, 31, 63, 84, B, B8, 19, BD, 
    

3 个答案:

答案 0 :(得分:1)

校验和计算存在问题。校验和变量声明为uint32_t,它们应声明为uint8_t。或者,每次添加后都应该屏蔽它们,如下所示:

  //Calculate checksum
  for(int i=0; i<len; i++){
    CK_A = CK_A + MSG[i];
    CK_A &= 0xFF;
    CK_B = CK_B + CK_A;
    CK_B &= 0xFF;
    Serial.println("CK_A= " + String(CK_A));
    Serial.println("CK_B= " + String(CK_B));
  }

答案 1 :(得分:0)

我可以告诉你,disableGLL数据包格式正确。我正在发送确切的数据包,并且我收到了您预期的ACK数据包。

因为您正在接收NMEA消息,我们可以排除RS232设置问题(波特率等)。

我建议使用Serial.printGPS.print语句交错GPS.read语句。如果很多字符已排队等待输出,则调用Serial.print将阻止,直到有字符的空间。当Serial.print正在等待时,字符仍然从GPS模块进入。最终,您的输入缓冲区将溢出。到Serial.print返回时,您可能丢失了一些要阅读的字符。

来自Arduino串行监视器的字节,看起来已经丢弃了8个字节。注意预期的0x38在初始0xB5之后是8个字节。

试试这个:在sendUBX中,将最后一个for循环拆分为两个循环:

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(", ");
}
Serial.println();
Serial.flush();  // and wait until all debug messages have been sent

for(int i=0; i<(len+4); i++) { 
  GPS.write(fullPacket[i]);//Send a byte of the UBX data packet to the GPS unit
}
GPS.flush(); // wait until the packet has been sent

然后注释掉Serial.print中的所有getUBX_ACK行。您可以将一个Serial.print留在:

  // Check that bytes arrive in sequence as per expected ACK packet
  if (b == ackPacket[ackByteID]) { 
    ackByteID++;
    Serial.print(b);  //  just output the bad byte
//    Serial.print(b, HEX);
//    Serial.print(", ");
    // Check if message was not acknowledged

然后你会知道你是否真的在0xB5之后获得了0x38。当然,逻辑分析仪,串口嗅探器,甚至是示波器都可以告诉你线路上到底发生了什么。

调试语句改变程序的时间并不罕见,可能足以以意想不到的方式打破它。在这种情况下,输入缓冲区会溢出和丢弃字符。

答案 2 :(得分:0)

我遇到了与该代码相同的问题。我使用的是Habduino代码,它与MAX8 GPS模块的代码相同。必须检查Ublox NEO-6M的所有命令,看起来是一样的。但是和你一样的问题。

我打开uCenter解决了这个问题。比消息视图(F9),禁用所有NMEA和UBX(子)消息。我的默认情况下有一个UBX-POSLLH消息启用。通过选择UBX-CFG-CFG而不是“发送”,在UBX-CFG-CFG下保存设置。

我不知道'HardwareSerial'库;我将我的GPS连接到Arduino的硬件UART(引脚0和1)。这意味着没有Seri​​al监视,但因此我使用了这个非常有用的技巧: http://ava.upuaut.net/?p=757

如果有人知道从NEO-6M禁用UBX消息的方法,请告诉我。文档对我来说并不清楚。 谢谢!