Vamos aprender juntos como funciona o sistema GPS (Global Positioning System)? Não há melhor forma de alcançar esse objetivo do que montando seu próprio receptor GPS! Nós do Solucionática adquirimos para estudo um "shield" da www.iteadstudio.com. O "shield", ou módulo, foi feito para ser acoplado ao Arduino, poupando as complexas soldagens de componentes smd,
O módulo vem com um receptor do tipo Sirf III, que equipa muitos dos módulos receptores gps encontrados por aí. Na foto abaixo, retirada do site da Itead Studio, vemos os detalhes do módulo e seus componentes.
Como podemos ver, no centro da placa há o chipset Sirf III da Globalsat EB-365. À esquerda, na parte de baixo, há o slot para cartão SD. Com o sd card é possível gravar os dados obtidos pelo GPS. E é até simples de fazer isso, como veremos mais adiante. Uma pequena falha dos módulos da Itead é a falta de um bom manual. Ainda bem que há os fóruns e blogs na internet para compartilharem o conhecimento, e o Solucionática retribui, repassando as informações obtidas.
Vamos começar? A primeira dica e mais importante: o GPS Shield é serial (RS-232), logo podemos conectar a qualquer microcontrolador ou PC com porta serial, ou até os conversores RS232-USB. Pronto, acabou! Basta conseguir configurar a porta serial, conectar uma antena e começar a receber as informações da constelação de satélites do sistema GPS. Obviamente, alimentar o módulo é a primeira providência!
Certo, é fácil quando se sabe - como dizia uma antiga propaganda. Com o espírito Solucionático vamos logo resolver isso:
O módulo Itead Studio "Arduino GPS Shield V1.1" - que nós testamos - só pode ser ligado na porta serial 0 e 1 que são as seriais de verdade do Arduino, ou seja, são as portas por onde é feito o upload dos "sketchs". Por isso, não se deve utilizá-las simultaneamente quando for carregar o sketch, desse modo lembrem-se de retirar os estrapes (que são aqueles pequenos conectores que fazem a configuração dos equipamentos) que conectam a TX à porta 1 e o RX à porta 0.,
Qual é a problemática? A nossa plataforma de hardware, o Arduino Mega 2560, tem a possibilidade de se conectar a múltiplas portas seriais. Uma biblioteca, denominada SoftwareSerial, permite escolher em qual porta o GPS será conectado ao Arduino. E no nosso caso, infelizmente, não funcionou, pois para o pino RX só podemos usar os pinos 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69 (tanto para o Arduino Mega 1280 quanto para o Mega 256)0,. A biblioteca TinyGPS, que vamos estudar mais a fundo, tem originalmente essa estrutura, usando a biblioteca SoftwareSerial. Outros modelos de Arduino podem funcionar com a biblioteca TinyGPS original, mas nós não testamos. Para resolver esse inconveniente ligamos qualquer um dos pinos da linha de RX do GPS ao pino 10 do Arduino e também ligamos a barra RX do GPS ao pino 11 do Arduino Mega.
Os comentários do sketch (programa do Arduino) original estão em vermelho. Vamos conhecê-lo para depois ver as modificações que foram feitas. Considere o sketch/programa abaixo como uma base para o seu próprio projeto. No começo pode parecer complicado - e às vezes é - mas faça uma "leitura dinâmica" das linhas de comando. Se ficou em dúvida, pesquise exatamente como está escrito que vão surgir diversos sites explicando os pormenores de cada comando. Aqui a regra é reutilizar o esforço alheio - dando o devido crédito - para fazer algo funcionar! Então vamos lá?
SKETCH 1 - Esse programa mostra a latidude, longitude, a quantidade de satélites na visada e a altitude.
/* This sample code demonstrates the normal use of a TinyGPS object.
It requires the use of SoftwareSerial, and assumes that you have a
4800-baud serial GPS device hooked up on pins 10(rx) and 11(tx). Aqui velocidade de transmissão entre o GPS e o Arduino foi configurada em 4800 bps e foram escolhidas as portas seriais (virtuais) do Arduino, sendo a 3 para RX e a 4 para TX.
*/
TinyGPS gps;
SoftwareSerial ss(11, 10); // Aqui é feito o instanciamento, ou seja, atribuimos a comunicação serial denominada de ss (poderia ser gps, minhaporta ou qualquer outra palavra) para as portas 3 e 4.
void setup()
{
Serial.begin(115200); // Aqui é a velocidade de transmissão entre o Arduino e o PC é de 115200 bps.
Serial.print("Simple TinyGPS library v. "); Serial.println(TinyGPS::library_version()); //só perfumaria...e os devidos //créditos do autor
Serial.println("by Mikal Hart");
Serial.println();
}
void loop() //loop principal. Os comentários do autor ajudam a entender.
{
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 (ss.available())
{
char c = ss.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.f_get_position(&flat, &flon, &age);
Serial.print("LAT=");
Serial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
Serial.print(" LON=");
Serial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
Serial.print(" SAT=");
Serial.print(gps.satellites() == TinyGPS::GPS_INVALID_SATELLITES ? 0 : gps.satellites());
Serial.print(" PREC=");
Serial.print(gps.hdop() == TinyGPS::GPS_INVALID_HDOP ? 0 : gps.hdop());
}
gps.stats(&chars, &sentences, &failed);
Serial.print(" CHARS=");
Serial.print(chars);
Serial.print(" SENTENCES=");
Serial.print(sentences);
Serial.print(" CSUM ERR=");
Serial.println(failed);
}
//terminou. Agora vamos ver outro sketch já modificado, é um pouco diferente do exemplo acima, mas as instruções de leitura dos dados do gps são praticamente iguais. Notem que as modificações estão em vermelho.
SKETCH 2 - Além das informações de lon, lat,alt etc, fornece a hora precisa pelo padrão UMT.
//#include <SoftwareSerial.h> A biblioteca foi excluida, para isso basta "comentar", ou seja, colocar // no começo da linha.
#include <TinyGPS.h>
/* This sample code demonstrates the normal use of a TinyGPS object.
It requires the use of SoftwareSerial, and assumes that you have a
4800-baud serial GPS device hooked up on pins 3(rx) and 4(tx).
*/
TinyGPS gps;
//SoftwareSerial nss(3, 4);//tx and rx pins in my arduino GPS shield. O instanciamento não é necessário, pois vamos usar as //portas padrão (0 e 1) . A linha foi retirada, a instância ss não é mais //usada e não pode aparecer em nenhuma linha se não dá erro ao compilar o sketch.
static void gpsdump(TinyGPS &gps);
static bool feedgps();
static void print_float(float val, float invalid, int len, int prec);
static void print_int(unsigned long val, unsigned long invalid, int len);
static void print_date(TinyGPS &gps);
static void print_str(const char *str, int len);
void setup()
{
Serial.begin(9600);
//nss.begin(4800);//baud rate for the GPS shield. Como o instanciamento não foi feito, temos que retirar essa linha.Só relembrando...
Serial.print("Testing TinyGPS library v. "); Serial.println(TinyGPS::library_version());
Serial.println("by Mikal Hart");
Serial.println();
Serial.print("Sizeof(gpsobject) = "); Serial.println(sizeof(TinyGPS));
Serial.println();
Serial.println("Sats HDOP Latitude Longitude Fix Date Time Date Alt Course Speed Card Distance Course Card Chars Sentences Checksum");
Serial.println(" (deg) (deg) Age Age (m) --- from GPS ---- ----ate Casa ---- RX RX Fail");
Serial.println("--------------------------------------------------------------------------------------------------------------------------------------");
}
void loop()
{
bool newdata = false;
unsigned long start = millis();
// Every second we print an update
while (millis() - start < 1000)
{
if (feedgps())
newdata = true;
}
gpsdump(gps);
}
static void gpsdump(TinyGPS &gps)
{
float flat, flon;
unsigned long age, date, time, chars = 0;
unsigned short sentences = 0, failed = 0;
static const float CASA_LAT = "sua latitude", CASA_LON = "sua longitude"; // aqui você põe as coordenadas de sua casa, por exemplo. O sketch calcula a distancia de onde você está até sua casa.
print_int(gps.satellites(), TinyGPS::GPS_INVALID_SATELLITES, 5);
print_int(gps.hdop(), TinyGPS::GPS_INVALID_HDOP, 5);
gps.f_get_position(&flat, &flon, &age);
print_float(flat, TinyGPS::GPS_INVALID_F_ANGLE, 9, 5);
print_float(flon, TinyGPS::GPS_INVALID_F_ANGLE, 10, 5);
print_int(age, TinyGPS::GPS_INVALID_AGE, 5);
print_date(gps);
print_float(gps.f_altitude(), TinyGPS::GPS_INVALID_F_ALTITUDE, 8, 2);
print_float(gps.f_course(), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
print_float(gps.f_speed_kmph(), TinyGPS::GPS_INVALID_F_SPEED, 6, 2);
print_str(gps.f_course() == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(gps.f_course()), 6);
print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0UL : (unsigned long)TinyGPS::distance_between(flat, flon, CASA_LAT, CASA_LON) / 1000, 0xFFFFFFFF, 9);
print_float(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : TinyGPS::course_to(flat, flon, -38.493671, -3.804179), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
print_str(flat == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(TinyGPS::course_to(flat, flon, CASA_LAT, CASA_LON)), 6);
gps.stats(&chars, &sentences, &failed);
print_int(chars, 0xFFFFFFFF, 6);
print_int(sentences, 0xFFFFFFFF, 10);
print_int(failed, 0xFFFFFFFF, 9);
Serial.println();
}
static void print_int(unsigned long val, unsigned long invalid, int len)
{
char sz[32];
if (val == invalid)
strcpy(sz, "*******");
else
sprintf(sz, "%ld", val);
sz[len] = 0;
for (int i=strlen(sz); i<len; ++i)
sz[i] = ' ';
if (len > 0)
sz[len-1] = ' ';
Serial.print(sz);
feedgps();
}
static void print_float(float val, float invalid, int len, int prec)
{
char sz[32];
if (val == invalid)
{
strcpy(sz, "*******");
sz[len] = 0;
if (len > 0)
sz[len-1] = ' ';
for (int i=7; i<len; ++i)
sz[i] = ' ';
Serial.print(sz);
}
else
{
Serial.print(val, prec);
int vi = abs((int)val);
int flen = prec + (val < 0.0 ? 2 : 1);
flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
for (int i=flen; i<len; ++i)
Serial.print(" ");
}
feedgps();
}
static void print_date(TinyGPS &gps)
{
int year;
byte month, day, hour, minute, second, hundredths;
unsigned long age;
gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
if (age == TinyGPS::GPS_INVALID_AGE)
Serial.print("******* ******* ");
else
{
char sz[32];
sprintf(sz, "%02d/%02d/%02d %02d:%02d:%02d ",
month, day, year, hour, minute, second);
Serial.print(sz);
}
print_int(age, TinyGPS::GPS_INVALID_AGE, 5);
feedgps();
}
static void print_str(const char *str, int len)
{
int slen = strlen(str);
for (int i=0; i<len; ++i)
Serial.print(i<slen ? str[i] : ' ');
feedgps();
}
static bool feedgps()
{
while (Serial.available()) // aqui era while (nss.available()
{
if (gps.encode(Serial.read())) // idem
return true;
}
return false;
}
Pronto. Estudamos, apenas por cima, um sketch um pouco mais complexo. A ideia, nesse instante, é apenas identificar as modificações necessárias para se utilizar o nosso modelo de módulo GPS. Depois poderemos alterar mais profundamente o sketch de acordo com nossas necessidades.
Em seguida, vamos entender como são as mensagens enviadas pelos satélites do sistema GPS. Vale à pena estudar esse assunto, pois muitos dos princípios das telecomunicações podem ser esclarecidos com o estudo desse sistema.
Antes, vejam como fica o "shield" conectado ao Arduino:
Uma beleza, não é?! Esse tipo de conector é muito prático, pois permite acesso aos pinos do Arduino, mesmo com uma placa em cima. Ou até com duas placas em cima!
Após um longo intervalo retomamos esse tópico e construímos um GPS inteiramente funcional e portátil. A alimentação está sendo provida por pilhas comuns; Uma nova PSU (ver tópico) padrão Solucionática foi encomendada e assim aumentaremos a autonomia e substituiremos as pilhas comuns por recarregáveis.
Abaixo segue o sketch completo versão Beta V3.37:
#include <TinyGPS.h>
TinyGPS gps;
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);
//const int buttonPin = 8; // the number of the pushbutton pin
const int ledRed = 22;
const int ledBlue = 10;
const int ledGreen = 23;
const int backLight = 9;
float flat, flon;
int buttonPushCounter = 0; // counter for the number of button presses
int buttonState = 0; // current state of the button
int lastButtonState = 0; // previous state of the button
int encoderPin1 = 2;
int encoderPin2 = 3;
int encoderSwitchPin = 8; //push button switch
volatile int lastEncoded = 0;
volatile long encoderValue = 0;
volatile int encoded = 0;
long lastencoderValue = 0;
int lastMSB = 0;
int lastLSB = 0;
void setup()
{
Serial.begin(115200);
Serial1.begin(9600); //This line has been change
Serial.print("Simple TinyGPS library v. "); Serial.println(TinyGPS::library_version());
Serial.println("by Mikal Hart");
pinMode(ledRed, OUTPUT);
pinMode(ledBlue, OUTPUT);
pinMode(ledGreen, OUTPUT);
pinMode(backLight, OUTPUT);
// initialize the pushbutton pin as an input:
//pinMode(buttonPin, INPUT);
pinMode(encoderPin1, INPUT);
pinMode(encoderPin2, INPUT);
pinMode(encoderSwitchPin, INPUT);
digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
digitalWrite(encoderPin2, HIGH); //turn pullup resistor on
//digitalWrite(encoderSwitchPin, HIGH); //turn pullup resistor on
//call updateEncoder() when any high/low changed seen
//on interrupt 0 (pin 2), or interrupt 1 (pin 3)
attachInterrupt(0, updateEncoder, CHANGE);
attachInterrupt(1, updateEncoder, CHANGE);
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("Aguardando ");
delay(150);
lcd.setCursor(0,1);
lcd.print("Satelite!");
delay(1000);
Serial.println();
}
void loop()
{
bool newData = false;
unsigned long chars;
unsigned short sentences, failed;
unsigned long age;
buttonState = digitalRead(encoderSwitchPin);
if(buttonState != lastButtonState){
if (buttonState == HIGH) {
// if the current state is HIGH then the button
// wend from off to on:
buttonPushCounter++;
//button is not being pushed
digitalWrite(ledBlue, HIGH);
delay(50);
analogWrite(backLight, 0);
} else{
//button is being pushed
digitalWrite(ledBlue, LOW);
delay(100);
analogWrite(backLight, 80);
delay(50);
lastButtonState = buttonState;
}
Serial.print("Valor= ");
Serial.println(encoderValue);
// check if the pushbutton is pressed.
// if it is, the buttonState is HIGH:
// For one second we parse GPS data and report some key values
for (unsigned long start = millis(); millis() - start < 1000;)
{
while (Serial1.available()) //This line has been change
{
char c = Serial1.read(); //This line has been change
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)
//{
lcd.print("Engaged!");
gps.f_get_position(&flat, &flon, &age);
switch(encoderValue) {
case 0:
//digitalWrite(backLight, HIGH);
lcd.clear();
lcd.print("GPS Solucionática");
lcd.setCursor(0,1);
lcd.print("Selecione opção");
//delay(5000);
//digitalWrite(backLight, LOW);
break;
case 2:
//digitalWrite(backLight, HIGH);
lcd.clear();
lcd.print("Longitude");
lcd.setCursor(0,1);
lcd.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
delay(150);
//delay(5000);
//digitalWrite(backLight, LOW);
break;
case 6:
digitalWrite(backLight, HIGH);
lcd.clear();
lcd.print("Latitude");
lcd.setCursor(0,1);
lcd.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
delay(150);
//delay(5000);
//digitalWrite(backLight, LOW);
break;
case 10:
//digitalWrite(backLight, HIGH);
lcd.clear();
lcd.print("Satélites");
lcd.setCursor(0,1);
lcd.print(gps.satellites() == TinyGPS::GPS_INVALID_SATELLITES ? 0 : gps.satellites());
//lcd.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
delay(150);
//delay(5000);
// digitalWrite(backLight, LOW);
break;
default:
lcd.clear();
lcd.print(".....");
}
}
}
/* if (newData)
{
float flat, flon;
unsigned long age;
gps.f_get_position(&flat, &flon, &age);
Serial.print("LAT=");
//lcd.clear();
delay(150);
//lcd.print("LAT=");
delay(150);
Serial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
//lcd.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
delay(1000);
//delay(150);
Serial.print(" LON=");
Serial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
Serial.print(" SAT=");
Serial.print(gps.satellites() == TinyGPS::GPS_INVALID_SATELLITES ? 0 : gps.satellites());
Serial.print(" PREC=");
Serial.print(gps.hdop() == TinyGPS::GPS_INVALID_HDOP ? 0 : gps.hdop());
// lcd.clear();
delay(1000);
}
delay(150);
// lcd.setCursor(0, 1);
delay(150);
// lcd.print("LON=");
delay(150);
// lcd.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
delay(150);
gps.stats(&chars, &sentences, &failed);
Serial.print(" CHARS=");
Serial.print(chars);
Serial.print(" SENTENCES=");
Serial.print(sentences);
Serial.print(" CSUM ERR=");
Serial.println(failed);
// print_date();
}
*/
static void print_date(TinyGPS &gps)
{
int year;
byte month, day, hour, minute, second, hundredths;
unsigned long age;
gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
if (age == TinyGPS::GPS_INVALID_AGE)
Serial.print("******* ******* ");
else
{
char sz[32];
sprintf(sz, "%02d/%02d/%02d %02d:%02d:%02d ",
month, day, year, hour, minute, second);
Serial.print(sz);
}
}
void updateEncoder(){
int MSB = digitalRead(encoderPin1); //MSB = most significant bit
int LSB = digitalRead(encoderPin2); //LSB = least significant bit
int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value
if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;
lastEncoded = encoded; //store this value for next time
return;
}
As mensagens do GPS
Não vamos nos deter em todos os detalhes do funcionamento do sistema GPS. Mas, como se sabe, trata-se de uma constelação de 24 a 32 satélites (é que para aumentar a precisão, os satélites que estavam aposentados entraram no sistema novamente, assim não há mais aquele número redondo de satélites), que estão a cerca de 20,2 Km de altura, que descrevem uma trajetória exatamente igual dia após dia, cada um na sua órbita. Para determinar uma posição na superfície da Terra é necessário ter três satélites (2D-fix), ou seja obtém-se as coordenadas do ponto (x,y); e, pelo menos quatro satélites (3D-fix) para se ter (x,y,z), ou seja, obtém-se a altura . Para isso o receptor tem que ter visada com os satélites, ora pois! E o que é visada? Simples. Em faixas de frequências altas, com as dos satélites do sistema GPS (acima de 1 GHz), a transmissão se dá em "linha reta", quer dizer, em visada!
Alguém pode perguntar qual é a referência da altura que o GPS se utiliza para determinar a altitude que o equipamento está. Seria o nível do mar? Do Everest? Não. A coisa é bem mais complicada. Na memória do receptor GPS há os dados de cada um dos satélites da constelação. Vou pegar emprestado umas figuras que vão ajudar a entender esse troço:
Figura 1
Figura 2
Figura 3
Essas figuras foram retiradas de http://www.kowoma.de/en/gps/positioning.htm, no dia 02/11/2012 às 0h15. A explicação de lá é muito melhor que a minha, mas está em inglês. Então vamos tentar explicar sem complicar mais! A Figura 1 ilustra a situação em que a pessoa segurando um receptor gps em "A", só consegue receber o sinal de dois satélites. O tempo em que o sinal do primeiro satélite leva para chegar é de 4s (só um exemplo, pois os tempos reais são muito menores, na casa de 0,07 s). Como há uma tabela gravada dentro do receptor gps indicando qual a altura em que cada satélite está, fica fácil determinar o primeiro "círculo da incerteza", que tem um raio de 4s (lembre-se que o sinal que sai do satélite viaja na velocidade da luz, ou seja, quase 300 mil m/s, assim 4s são equivalentes a h=vt , h=300000*4=1200000 ou 1.200Km (muito mais do que os 20Km das órbitas reais dos satélites do sistema GPS, pois isso é só um exemplo, ok?!).
O outro satélite da Figura 1 está a "5s" de distância,ou seja, a 1.500Km, em linha reta, do sujeito com o gps na mão, perdido e mal pago! A sorte é que agora temos dois "círculos de incerteza", que verdade são esferas. Esse "círculos" se interceptam nos pontos "A" e "B". É importante dizer que os satélites ficam transmitindo constantemente a posição em que se encontram e a que horas essa posição ocorreu (timestamp), ou seja, se eu conheço as órbitas dos satélites e sei com que atraso aquela posição foi transmitida, por triangulação dá para determinar (2D-fix) em que ponto da superfície da Terra está o nosso amigo. Como o sujeito segurando o gps está na superfície da Terra, descartamos o ponto B. Assim, com apenas dois satélites, porém com os relógios dos satélites e do gps perfeitamente sincronizados, determinamos fielmente as coordenadas do ponto A.
Um avião também consegue saber sua posição, pois a altitude em que voa é bem menor do que as órbitas dos satélites. Esse é o princípio dos UAVs, que para nós são os VANT'S (Veículo Aéreo Não Tripulado). Por outro lado, um foguete que está indo para Lua só pode ser acompanhado por GPS no início de sua trajetória. Quando ele passa de 10 Km, acho eu, as estações em terra é que receberão o sinal do foguete e farão a triangulação, para determinar a sua trajetória. Os fabricantes de receptores gps, pelo menos aqueles que negociam com o governo americano, limitam a velocidade e a altitude de operação de seus equipamentos para que ninguém invente de utilizar a tecnologia para outros fins. Então, as companhias de aviação estão certas em proibirem equipamentos eletrônicos nas bagagens. Por quê? Para ninguém testar os modelos de gps que não estão sujeitos às restrições impostas pela ITAR (International Traffic in Arms Regulation).
A figura 2 ilustra um problema sério que os sistemas ordinários de recepção e sinais gps apresentam: a falta de sincronismo entre o relógio atômico do satélite e o relógio de quartz do receptor gps. Uma diferença da ordem de 0,01s implica em um erro de 3 Km! Uma das soluções para essa falta de sincronismo está no sistema AGPS (Assisted GPS), muto usado nos smartphones e outros celulares com gps (ou mesmo sem o chipset gps, o Sirf III, p.ex). Se nós tvermos um gps conectado à rede móvel (ligá-lo na banda larga via ethernet não ia ser muito prático, não é? Só se o cabo utp for bem longo..) a sua localização vai sr faciliada por dois motivos.
Em primeiro lugar, ao ligar o celular e habilitar o gps, com uma conexão estabelecida, o tempo para localizar a posição é bem menor do que um gps comum, sem aceso à internet. O motivo é que quando ligamos o gps pla primeira vez, ou após um longo tempo desligado, ou aina após uma longa viagem - com o gps desligado, o almanaque - aquela tabela com os dados de todos os satélites e suas órbitas - tem que ser atualizado. Além do Almanaque (Almanac), que é uma tabela com os dados menos precisos, poderíamos dizer mais grosseiros, dos satélites, há os Dados Efêmeros (Ephemeris Data) que são os dados mais precisos. O almanaque tem validade de várias semanas, ao passo que o Ephemeris data tem que ser atualizado a cada 30s - nem sempre é preciso fazer essa atualização em período tão curto. O segundo motivo é que o A-GPS usa a triangulação das antenas de celular para ajudar na aquisição do posicionamento do receptor gps, mesmo onde não há visada.
Calma, foi cansativo, mas vamos chegar a um ponto importante agora! Sabe-se que na teoria são necessários quatro (4) satélites para determinar uma posição (x,y,z), mas na prática bastam três (3), não é isso? Qual é o truque? Muito simples: foi adotado o centro de massa da Terra como a origem de um dos sistema de coordenadas do sistema GPS, denominado WGS84 (padrão do World Geodetic System publicado no ano de 1984), que simplificadamente considera a Terra um elipsoide (o datum é o elipsoide de referência). Aqui as coisas se ajustam ou complicam de vez!
Assim o "quarto" satélite é o próprio centro da Terra! Como se sabe, o raio médio da Terra é de 6.378 Km, desse modo já temos um dos lados do triângulo. Agora dá-lhe o método de Newton-Raphson ou o método de Bancroft para calcular a posição em que o gps está.
A Terra não é um elipsoide, é um geoide - na verdade o formato da Terra é muito irregular, nada comportado. E o que isso tem a ver com o gps? Tudo! Se a órbita do satélite é determinada em relação a uma superfície de um elipsoide, bem comportado, portanto, é claro que no mundo real as altitudes indicadas no instrumento vão ser totalmente dependentes do ponto em que se esteja. Pode acontecer de uma pessoa estar na beira da praia e o gps indicar uma altitude de -125m! Esse erro é causado pelas ondulações do geóide. O nível do mar médio é uma das informações contidas nas mensagens que são geradas nos próprios receptores gps - IMPORTANTE: o shield que estamos estudando contém um chipset GPS serial; as mensagns nos padrões aceitos, o NMEA, p.ex, são transmitidas pela saída serial para um microcontolador que deve processar essas mensagens e mostrar a posição em um display ou mesmo na tela de um PC. Há vários programas que recebem diretamente os dados seriais e geram mapas,trilhas etc.
Aqui cabe um esclarecimento: os receptores Sirfstar II, por serem mais baratos ainda, não lidavam bem com os algoritmos de altitude. Os novos Sirfstar III estão bem melhores nesse quesito.
Nada como uma figura para ilustrar a ideia que os parágrafos acima descreveram.
Olhem agora a mensagem GPGGA abaixo. Localizem qual é a altidude que o gps determinou. Para ajudar quem chegou agora: O gps recebeu uma mensagem às 12h35m19s contendo a identidade e a posição do satélite. Como há uma tabela armazenada, o receptor gps determinou que sua antena estava a 545,4 m acima do nível médio do mar e que a altura do geoide naquele ponto em relação ao nível médio do mar é 46,9 m, ou seja, o geoide está separado do elipsoide de referência (WGS84) por 46,9 m! E então, qual é a altitude correta em que o receptor gps está? Basta somar as duas alturas, ou seja Aantena= 545,4+46,9 = 592,3 m.
Não se esqueçam que essa separação não é constante e sofre atualizações periódicas, daí o almanac e o ephemeris data serem tão importantes. Os gps mais simples não tem como ficar atualizados sem que se faça um upload da tabela das separações entre o geoide .. mas, as placas tectônicas da Terra não se deslocam? Por esse motivo é que há um esforço mundial para se manter as bases de dados o mais fiel possível à realidade. E os receptores gps incorporaram um chipset 3G/GSM/GPRS para ficarem sempre atualizados. Além disso, alguns modelos geram, on board, o ephemeris data. Desse modo o gps "encontra" sua posição ao ser ligado muito mais rapidamente.
$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47 Where: GGA Global Positioning System Fix Data 123519 Fix taken at 12:35:19 UTC 4807.038,N Latitude 48 deg 07.038' N 01131.000,E Longitude 11 deg 31.000' E 1 Fix quality: 0 = invalid 1 = GPS fix (SPS) 2 = DGPS fix 3 = PPS fix 4 = Real Time Kinematic 5 = Float RTK 6 = estimated (dead reckoning) (2.3 feature) 7 = Manual input mode 8 = Simulation mode 08 Number of satellites being tracked 0.9 Horizontal dilution of position 545.4,M Altitude, Meters, above mean sea level 46.9,M Height of geoid (mean sea level) above WGS84 ellipsoid (empty field) time in seconds since last DGPS update (empty field) DGPS station ID number *47 the checksum data, always begins with *
Toda mensagem começa com $GP. Os campos são separados por vírgulas - não fique em "comma" com essas explicações. Na biblioteca TinyGPS há uma rotina que separa os campos comparando os caracteres recebidos com a "," . Assim, no primeiro campo de uma mensagem do tipo GGA, no padrão NMEA (National Marine Eletronics Association), a FIFA do GPS, vem a hora no padrão UTC (isso mesmo, é a hora da internet!). Para fazer um relógio de precisão, basta ler esse campo a cada segundo, por exemplo, e separar com ":" a hora, os minutos e os segundos, no exemplo acima seria assim 12:35:19.
O próximo campo da mensagem é a latitude (lat), que no caso é 48° 07.038' N. Em seguida tem-se a longitude (lon) que é 11° 31.000'. O campo seguinte informa a qualidade da determinação da posição, quer dizer, a precisão com que o gps obteve a sua posição. Se o fix quality é igual a zero, os dados obtidos não são suficientes para determinar com um mínimo de precisão o ponto escolhido. Se é igual a um a precisão é referente a SPS (Stardad Positioning System), que é o GPS civil; se for 2 a precisão é de DGPS (Diferencial GPS); no caso do quality fix=3 a precisão é PPS(Precise Positioning System) é o GPS militar. No caso do PPS uma diferença notavel é o uso de duas frequências: a portadora L1 e a portadora L2. Esse arranjo permite determnar a influêcia da ionosfera e corrigir o clock, aumentando a precisão. De todo modo o nosso gps não suporta os fix 3, 4, 5, 7 e 8. As mensagens do padrão NMEA disponíveis são: GGA,GSA,GSV,RMC,VTG,GLL e ZDA. O manual do chipset EB-365 SirfstarIII, em anexo, foi obtido no site da Global Sat (www.globalsat.com.tw). Consultem também o site http://infohost.nmt.edu/~mreece/gps/work.html, que explica em poucas palavras muito do que vimos aqui.
Um resumo:
Aquele aparelho gps da Garmin, por exemplo, amarelinho ou cinzento, seja de qual cor for, recebe os dados dos satélites (indicativo do satélite, posição do satélite, hora precisa em que os dados foram enviados, além de dados gerais da constelação de satélites) e calcula sua própria posição usando muita matemática, com a ajuda de um gabarito (almanac) armazenado em sua memória não volátil, que é atualizado periodicamente e "baixado" dos próprios satélites ou da internet.
Outros gps, como os integrados aos aparelhos celulares, fazem isso tudo e ainda por cima, recebem "cola" da internet, on line! E, de quebra, conseguem aproximar sua posição, mesmo quando os satélites não estão no alcance, por meio da triangulação feita pela própria rede celular.
Outro ponto: a determinação da altura é um grande problema. A tabela (almanac) e as "colas" da internet são atualizadas por uma imensa rede mundial de geodésia, para determinar que naquela coordenada x,y a altura do geoide ou seja o formato considerado real da Terra, é de tantos metros acima do datum (elipsóide), ou seja, da aproximação matemática do formato da Terra. O elipsoide é uma elipse que girou em torno de seu próprio eixo, ou seja, é um sólido de revolução - assunto estudado em Álgebra Vetorial. Essa diferença varia com o humor das placas tectônicas, com as marés etc! A propósito, o geoide atual já não representa fielmente o formato da Terra, segundo as últimas medições da sonda GOCE (Gravity field and steady-state Circulation Explorer), lançada pela ESA (Agência Espacial Europeia).
Em breve um video, em HD, com o sistema funcionando.
Referências:
http://www.gpsinformation.org/dale/nmea.htm#GGA
http://www.kowoma.de/en/gps/positioning.htm
http://arduiniana.org/libraries/tinygps/
http://www.gps.gov/systems/augmentations/
ftp://igs.org/pub/resource/pubs/IGS_why_in_RT.pdf
http://www.gpspassion.com/forumsen/topic.asp?TOPIC_ID=10915
http://infohost.nmt.edu/~mreece/gps/work.html
http://en.wikipedia.org/wiki/Global_Positioning_System
http://www.gpsinformation.org/dale/nmea.htm