LusoRobótica - Robótica em Português

Electrónica => Protocolos => Tópico iniciado por: TMAsantos em 10 de Julho de 2015, 01:36

Título: GPS GPGGA, NMEA e baudrate
Enviado por: TMAsantos em 10 de Julho de 2015, 01:36
Boas malta, tenho uma questão que me anda a fazer confusão há algum tempo.

O meu GPS comunica em porta série (UART) com o arduino, por exemplo. Esta comunicação é feita a um baud rate de 38400.

Isto significa que transmito 38400 bits por segundo, logo demoro cerca de 0.026 ms a transmitir 1 bit. Como o NMEA transmite strings e a string do GPGGA tem aproximadamente 64 caracteres ASCII (cada 1 tem 8 bits), demoro cerca de 0.026*8 ms a transmitir 1 carácter e 0.026*8*64 a transmitir todos, o que me dá aproximadamente 13 ms, ignorando o start bit e stop bit.

Estou a fazer a leitura no arduino e a medir o tempo que a leitura demora, utilizando a função "millis()" e obtenho um tempo de aproximadamente 0-2 ms na leitura, o que é muito menos do que estava à espera.

Estou a interpretar mal o protocolo?

Obrigado pela ajuda

PS:
Exemplo de uma strinf GPGGA:
Código: [Seleccione]
$GPGGA,205526.500,3938.8970,N,00984.5289,W,1,5,1.86,84.6,M,50.7,
Título: Re: GPS GPGGA, NMEA e baudrate
Enviado por: Njay em 10 de Julho de 2015, 03:00
Não sei ao certo como escolheram implementar no Arduino, mas a leitura provavelmente é feita "em background" para um buffer (array, circular) interno da biblioteca, e quando fazes o read dos bytes esse read só está a ler do buffer. A recepção de 1 byte é feita pelo hardware, e depois é gerada uma interrupção, onde o byte *já recebido* apenas é lido de um registo e guardado no buffer, de onde depois o read lê.
Título: Re: GPS GPGGA, NMEA e baudrate
Enviado por: TMAsantos em 10 de Julho de 2015, 12:54
Estou a utilizar a biblioteca SoftwareSerial do Arduino.
Utilizo a função read() do objecto. Se calhar está a guardar num buffer interno como dizes, mas há outra questão.
O GPS envia dados com uma frequência de 10Hz. Se eu não respeitar esta frequência na leitura, quando chamo o read(), ele manda-me um caracter que não é o inicio da string, o que me faz achar que ele não os guarda num buffer.

A função millis() pode corromper se no meio de dois millis() tiver um ciclo while a fazer a leitura, sem delays internamente?
Título: Re: GPS GPGGA, NMEA e baudrate
Enviado por: Njay em 10 de Julho de 2015, 13:29
O buffer tem um limite de tamanho, se não leres dados do buffer a tempo, os que lá estão são sobrepostos por novos bytes a chegar (ou os novos são descartados, não sei como está implementado).

Mete aí o código do teu teste.
Título: Re: GPS GPGGA, NMEA e baudrate
Enviado por: TMAsantos em 10 de Julho de 2015, 14:26
Estive a ler melhor a documentação e é verdade, tem um buffer de 64 bytes.

O código não é totalmente meu, retirei à uns tempos de um blog, já não me lembro qual. Só fiz umas ligeiras alterações para medir o tempo.

Código: [Seleccione]
SoftwareSerial GPS(2, 3);

String reads;
int sta;

void setup () {
  Serial.begin(38400);
 
  // connect GPS RX-O to pin 2
  pinMode (2, INPUT);
  // connect GPS TX-I to pin 3
  pinMode (3, OUTPUT);
  GPS.begin(38400);

  // setup NMEA output mode.
  GPS.print("$PGCMD,16,1,1,1,1,1*6B\r\n"); 
 
  sta= millis();
}

void loop() {
  char ch = GPS.read();
  if (ch != -1){
   
    if(ch == '$'){ 
      Serial.println(millis()-sta);
      Serial.println(reads);
      sta= millis();
      reads= "$";
    } else 
    reads+=ch;
   
  }

Entretanto depois criei uma biblioteca em cpp para compactar o código, mas faz basicamente a mesma coisa.

O importante aqui é só mesmo verificar os 13 ms, que neste caso são entre 0 e 2 ms (devido ao buffer).
Título: Re: GPS GPGGA, NMEA e baudrate
Enviado por: Njay em 10 de Julho de 2015, 14:33
Humm, a coisa ainda não está bem explicada. Seria interessante saber quanto tempo demora isto a executar:

      Serial.println(millis()-sta);
      Serial.println(reads);


p.s. "char ch" é arriscar um bocado, ch devia ser int.
Título: Re: GPS GPGGA, NMEA e baudrate
Enviado por: TMAsantos em 10 de Julho de 2015, 21:38
Ser char ou int não é a mesma coisa? Ele depois converte de int para ASCII por ser char.

As linhas que indicaste demoram entre 2 e 3 ms a executar, acabei de medir.

Título: Re: GPS GPGGA, NMEA e baudrate
Enviado por: Njay em 10 de Julho de 2015, 21:50
Pois, ainda há por aí qualquer coisa incoerente na explicação do curto tempo de leitura, mas se recebes bem as strings é porque o "erro" está na medição ou na configuração.

Se o GPS te enviasse 0xff provavelmente não, char e int não era a mesma coisa. Noutras plataformas poderias ter ainda outro tipo de problema, porque o char nem sempre é signed por omissão.
Título: Re: GPS GPGGA, NMEA e baudrate
Enviado por: TMAsantos em 10 de Julho de 2015, 22:15
Fiz esta script rápida, para perceber como é que os dados chegam ao buffer:

Código: [Seleccione]
int aval = GPS.available();
  Serial.println(aval);
  if(aval >=63){
    reads="-";
    for(i=0; i<aval; i++)
      reads+= (char)(GPS.read());
    Serial.println(reads);
  }
  delay(1);

O resultado foi o seguinte:

Código: [Seleccione]
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
59
63
-$GPGGA,210610.100,XXXX.XXXX,N,XXXXX.XXXX,W,1,7,1.68,58.5,M,50.7


Basicamente dá para ver que os dados chegam com uma frequência de 10Hz, como esperado, e enchem logo o buffer (em menos de 2ms). Depois ler é num instante, claro, já está no buffer do Arduino.

Não é estranho ser em menos de 2ms? As contas no meu primeiro post não estão bem feitas?
Título: Re: GPS GPGGA, NMEA e baudrate
Enviado por: jm_araujo em 10 de Julho de 2015, 23:33
Isto significa que transmito 38400 bits por segundo, logo demoro cerca de 0.026 ms a transmitir 1 bit. Como o NMEA transmite strings e a string do GPGGA tem aproximadamente 64 caracteres ASCII (cada 1 tem 8 bits), demoro cerca de 0.026*8 ms a transmitir 1 carácter e 0.026*8*64 a transmitir todos, o que me dá aproximadamente 13 ms, ignorando o start bit e stop bit.
Na realidade para enviar um byte de 8 bits via série precisas de mais um start e um stop bit, portanto nas tuas contas deviam ser 0.026*10*64=16.66ms
Assim por alto parece-me que estás a o software serial, que depende de interrupts para ler os dados série, e devem maram-te os millis(), que nem sempre são de fiar.