ublox NEO 6m: проверка работоспособности команды UBX (с контрольной суммой Флетчера!)

Итак, я бился головой о клавиатуру в течение нескольких дней, потому что не могу понять, как заставить мой новый экран GPS хорошо работать с моим микроконтроллером Teensy 3.1 (совместимым с Arduino).

Рассматриваемый экран GPS создан на основе iteaduino, и его можно увидеть здесь.

У меня нет проблем с использованием библиотеки TinyGPS Arduino для анализа входящих данных из модуля NEO 6 gps на выводах UART Teensy и вывода широты и долготы на мой последовательный монитор в Arduino IDE.

Проблема возникает, когда я пытаюсь передать NEO 6 команду NMEA или команду UBX. Это единственный способ фактически управлять модулем, вместо того, чтобы позволить ему отправлять одни и те же 6 сообщений NMEA каждую секунду. (например, вы не можете установить модуль в режим энергосбережения, не выполнив команду UBX RXM-PMREQ).

Я начал с того, что основал свой код на примере , предоставленном ukhas, но не смог заставить его работать . Итак, я сделал простую небольшую программу, которая в основном выполняет следующие функции:

  1. Устанавливает последовательную связь с модулем NEO 6 на скорости 9600 бод.
  2. Отправляет модулю GPS 11-байтовый пакет данных, который следует протоколу UBX, говоря ему, чтобы он прекратил отправку сообщений NMEA lat / lon
  3. Анализирует входящие пакеты данных от модуля GPS в поисках сообщения ACK (подтверждения)

Никакого подтверждения не приходит! Что я делаю неправильно?!

Вот мой код:

#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, 

person macdonaldtomw    schedule 13.04.2014    source источник
comment
Я все еще жду ответа ... У кого-нибудь есть идеи?   -  person macdonaldtomw    schedule 14.08.2014
comment
Вы когда-нибудь догадывались об этом? У меня такая же проблема ...   -  person JeffR    schedule 02.11.2014


Ответы (4)


Возникла проблема с вычислением контрольной суммы. Вары контрольной суммы объявлены как 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));
  }
person Justin    schedule 23.07.2015

Я могу сказать вам, что пакет disableGLL сформирован правильно. Я отправляю именно этот пакет и получаю ожидаемый пакет ACK.

Поскольку вы получаете сообщения NMEA нормально, мы можем исключить проблему настройки RS232 (скорость передачи и др.).

Я бы посоветовал не чередовать Serial.print утверждения с GPS.print и GPS.read. Если в очередь для вывода поставлено много символов, вызов Serial.print будет заблокирован, пока не останется больше символов. Пока Serial.print ждет, символы все еще поступают из модуля GPS. В конце концов ваш входной буфер переполнится. К тому времени, когда Serial.print вернется, вы, возможно, потеряете некоторые символы для чтения.

Судя по байтам, поступающим от последовательного монитора Arduino, восемь байтов были потеряны. Обратите внимание, что ожидаемый 0x38 находится на восемь байтов после начального 0xB5.

Попробуйте следующее: в 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

Тогда вы узнаете, действительно ли вы получаете 0x38 после 0xB5. Конечно, логический анализатор, анализатор последовательного порта или даже осциллограф могут сказать вам, что на самом деле происходит в сети.

Операторы отладки нередко изменяют время выполнения программы, возможно, достаточно, чтобы неожиданно нарушить ее работу. В этом случае входной буфер переполняется и отбрасываются символы.

person slash-dev    schedule 02.10.2014

У меня была такая же проблема с этим кодом. Я использовал код Habduino, который примерно такой же, как и для модуля MAX8 GPS. Пришлось проверить все команды для Ublox NEO-6M, оказались одинаковыми. Но такая же проблема, как и у вас.

Решил, открыв uCenter. После просмотра сообщений (F9) отключите все сообщения NMEA и UBX (дочерние). У меня по умолчанию было включено сообщение UBX-POSLLH. Сохраните настройки в UBX-CFG-CFG, выбрав UBX-CFG-CFG и затем «отправить».

Я не знаю этой библиотеки «HardwareSerial»; Я подключил свой GPS к аппаратному UART от Arduino (контакты 0 и 1). Это означает, что не нужно отслеживать последовательный порт, но поэтому я использовал очень полезный трюк: http://ava.upuaut.net/?p=757

Если кто-нибудь знает способ отключить сообщения UBX от NEO-6M, дайте мне знать. В документации мне это непонятно. Спасибо!

person Tmatz    schedule 28.04.2015

@Justin, с расчетом CS проблем нет. Просмотрите предоставленные им пакеты, так как они имеют правильный формат.

Использование 32-битных переменных CS, возможно, расточительно, но оно не дает неправильных контрольных сумм. Он маскирует их в конце вычислений в обоих случаях (отправка и получение).

Я проверил это на том же устройстве ublox Neo-6M. Я являюсь автором (на данный момент) самого быстрого и самого маленького доступного парсера NMEA + UBX, NeoGPS.

person slash-dev    schedule 20.09.2015