ARDUINO + GPS: como montar seu navegador GPS
Usarei 3 peças para fazer este navegador:
- Arduino Duemilanove – http://www.webtronico.com/produtos/view/5
- LCD Shield - http://www.webtronico.com/produtos/view/34
- Módulo GPS (SKM53) – http://www.webtronico.com/produtos/view/22
O LCD Shield possui um LCD 16×2 (16 caracteres e 2 linha) e teclado com 5 push buttons, que vou utilizar para selecionar a função que vai aparecer no display. Este teclado é bem interessante, pois os 5 push buttons são ligados em apenas uma entrada analógica (AD). Isto significa que cada botão “envia” uma tensão diferente para o AD, e como você conhece a tensão de cada botão você consegue mapear qual botão foi pressionado. Muito fácil e muito útil pois economiza pinos I/O.
Para escrever no LCD estou utilizando a biblioteca LCD4Bit_mod, onde simplesmente você precisa utilizar a função lcd.printIn(“Escreve no LCD”);
O módulo GPS também é bastante simples. Ele possui antena embutida e é alimentado com 5V. O pino de TX é ligado no pino RX do Arduino. Quando alimentando o GPS começa a se comunicar com o Arduino automaticamente, com velocidade padrão de 9600 bauds. O GPS envia com frequência de 1Hz (1 vez por segundo) os dados de localização. Estes dados seguem um padrão chamado NMEA que é mais ou menos assim:
Tudo explicado, vamos a montagem!
A montagem é bastante simples: o GPS é conectado no LCD Shield nos seguintes pinos:


| GPS | LCD Shield |
| VCC | 5V |
| GND | GND |
| TX | RX |
Agora basta conectar o LCD Shield com GPS no Arduino
ATENÇÃO: Desconecte o LCD Shield quando for gravar o firmware no Arduino, Pois o TX do GPS conflita com o TX do PC.
Download do programa + biblioteca LCD:
webtronicogps.zip
- Descompacte a pasta “LCD4Bit_mod” em “\arduino-0018\libraries\”
- Abra o arquivo “WebtronicoGPS.pde” no programa de desenvolvimento do Arduino
Abaixo segue o programa comentado:
#include <LCD4Bit_mod.h> #define DADOS_LEN 100 #define IDLEN 6 #define TEMPLEN 11 //cria objeto para controlar LCD LCD4Bit_mod lcd = LCD4Bit_mod(2); //numero de linhas do LCD = 2 char dados[DADOS_LEN]; //buffer dos dados do GPS byte conta=0; //variavel auxiliar para contar char* idnmea[] = {"$GPRMC","$GPGGA"}; //IDs dos NMEA que vou utilizar #define GPRMC 0 #define GPGGA 1 byte verificador[]= {0,0}; //variavel auxiliar para verificar ID NMEA byte indice[12]; //Em uma linha $GPRMC contem 12 valores separados por virgulas. Esta variavel guarda a posição do caracter de inicio de cada valor. byte contindice=0; //variavel auxiliar de controle usada na variavel indice[]; byte menu=0; // Menu do LCD: 0-botão RIGHT, 1-botão UP, 2-botao DOWN, 3-botão LEFT, 4-botão SELECT char tempmsg[TEMPLEN]; //variavel temporaria auxiliar para guarda o valor de um dado extraido do GPS. //teclado int adc_key_val[5] ={30, 150, 360, 535, 760 }; //valores do divisor de tensão do teclado do LCD Shield #define NUM_KEYS 5 //numero de teclas do teclado int adc_valor_in; //valor da entrada analogica do teclado byte key=-1; //tecla pressionada byte oldkey=-1; //tecla pressionada anteriormente void setup(){ lcd.init(); //inicia LCD lcd.clear(); //Limpa LCD lcd.printIn("WebTronico.com"); //Escreve no LCD lcd.cursorTo(2, 0); //Coloca o cursor do LCD na linha 2 e coluna 0 lcd.printIn("Ligando GPS"); //Escreve no LCD limpaBuffer(); //limpa buffer do GPS (dados) limpaTemp(); //limpa dado do GPS (tempmsg) Serial.begin(9600); //Inicia UART para comunicar com módulo GPS } void loop(){ while(Serial.available()){//Enquanto tiver caracteres no buffer dados[conta] = Serial.read(); //pega caracter do buffer da Serial if(dados[conta]==13){ //Se o caracter = 13 então é final de linha. Vamos interpretar esta linha que recebemos verificador[GPRMC]=0; //verifica idnmea[0] ($GPRMC) //verificador[GPGGA]=0;//verifica idnmea[1] ($GPGGA) for(byte i=1;i<=IDLEN;i++){ //verificando o ID NMEA da linha recebida if(dados[i]==idnmea[GPRMC][i-1]){ //Verifica se é $GPRMC verificador[GPRMC]++; //incrementa 1 } //Não vou implementar $GPGGA para não ficar muito confuso /*if(dados[i]==idnmea[GPGGA][i-1]){ //Verifica se é $GPGGA verificador[GPGGA]++; //incrementa 1 }*/ } if(verificador[GPRMC]==IDLEN){ //A linha recebida é $GPRMC //A linha GPRMC tem 11 "," que dividem 12 dados //exemplo: $GPRMC,220516,A,5133.82,N,00042.24,W,173.8,231.8,130694,004.2,W*70 // 0 1 2 3 4 5 6 7 8 9 10 11 // nos interessa: 2-timestamp (UTC), 3-latitude, 4-Norte/Sul, 5-Longitude, 6-Leste(E)/Oeste(W),7-velocidade (em nós),9-date stamp contindice = 0; indice[contindice] = 1; //dados[] inicia no caracter 1 contindice++; for(byte i=1; i<DADOS_LEN;i++){//percorre toda linha dados[] identificando onde começa cada valor do GPS if(dados[i]==','){//achou o final de um dado indice[contindice] = i+1; contindice++; } } adc_valor_in = analogRead(0); //verifica entrada analogica do teclado key = get_key(adc_valor_in); //interpreta valor da entrada analogica if (key != oldkey){ //verifica se o valor encontrado é diferente do valor anterior delay(50); // faz um delay para o debounce adc_valor_in = analogRead(0); // le novamente a entrada analogica para confirmar key = get_key(adc_valor_in); // interpreta if (key != oldkey){ //verifica se é diferente oldkey = key; //atualiza oldkey lcd.clear(); //limpa LCD if (key >=0){ //se alguma tecla foi pressionada menu = key; //atualiza o menu } } } switch(menu){//mostra no LCD o menu pressionado case 4: //SELECT lcd.cursorTo(1,0); //move o cursor do LCD para linha 1 coluna 0 lcd.printIn("webtronico.com"); //escreve no LCD lcd.cursorTo(2,0); //LCD na linha 2 coluna 0 lcd.printIn("@webtronicoBR"); //escreve break; case 3: //LEFT //lcd.clear(); lcd.cursorTo(1,0); lcd.printIn("Lat:"); lcd.printIn(buscaDado(3)); //ler comentario na funcao buscaDado(byte) lcd.printIn(" "); lcd.printIn(buscaDado(4)); lcd.cursorTo(2,0); lcd.printIn("Lon:"); lcd.printIn(buscaDado(5)); lcd.printIn(" "); lcd.printIn(buscaDado(6)); break; case 1: //CIMA lcd.cursorTo(1,0); lcd.printIn("Data:"); lcd.printIn(buscaDado(9)); lcd.cursorTo(2,0); lcd.printIn("Hora:"); lcd.printIn(buscaDado(1)); break; case 2: //BAIXO lcd.cursorTo(1,0); lcd.printIn("Veloc:"); lcd.printIn(buscaDado(7)); lcd.cursorTo(2,0); lcd.printIn("knots"); break; } } conta = 0; //zera conta, ou seja, vai iniciar proxima linha do GPS e dados[conta] esta na posição 0 limpaBuffer(); //limpa dados[] }else{ conta++; //incrementa conta, ou seja, dados[conta] pula para a proxima posição } } } void limpaBuffer(){ for (byte i=0;i<DADOS_LEN;i++){ // limpa variavel (buffer) que recebe dados do GPS dados[i]=' '; } } void limpaTemp(){ for(byte i=0;i<TEMPLEN;i++) tempmsg[i]=' '; } char* buscaDado(byte inicio){ /* Funcao que busca na variavel dados[] o valor procurado do GPS. Lembrando que: 2-timestamp (UTC), 3-latitude, 4-Norte/Sul, 5-Longitude, 6-Leste(E)/Oeste(W),7-velocidade (em nós),9-date stamp */ limpaTemp(); byte i; byte fim = indice[inicio+1]-2; inicio = indice[inicio]; for(i=0;i<=(fim-inicio);i++){ tempmsg[i] = dados[inicio+i]; } tempmsg[i] = '\0'; return tempmsg; } // Convert ADC value to key number byte get_key(unsigned int input) { int k=menu; for (byte i = 0; i < NUM_KEYS; i++){ if (input < adc_key_val[i]){ k=i; return k; } } return k; }
19 Comments
Other Links to this Post
RSS feed for comments on this post. TrackBack URI


By haggerty classic insurance, October 17, 2010 @ 4:15 am
I am glad you said that
By Leonardo, October 24, 2010 @ 7:30 pm
Muito legal! =)
By Leonardo, February 11, 2011 @ 1:27 pm
Gostaria de saber para que serveo pino rx do modulo gps?
By Juliano, February 11, 2011 @ 4:01 pm
O RX do módulo não é conectado. (existe para configuração de fabrica)
By Everton, June 17, 2011 @ 8:23 pm
Olá Qual é a precisão do modulo gps??? É possivel usar em aplicações que precise de alta precisão?
Obrigado
By Pedro, August 20, 2011 @ 3:53 pm
Estou precisando controlar um robô (aparador de grama) por GPS usando minha Arduino e o receptor SKM53, porém estou encontrando dificuldades ao programar… a ideia é definir 4 pontos ou seja delimitar a área que será varrida, bem, através de um comando por botão… exemplo: levo o robô até o primeiro ponto e pressiono o botão, ele emiti um sinal sonoro, lê a coordenada atual do GPS e armazena na arduino, o mesmo ocorre com os outros 3 pontos, a partir disso libero o robô em qualquer lugar ele se localiza e se move até o ponto inicial (como referenciar o robo? como mover o robo sem que ele sai da trajetória? e se sair como corrigi-la?, é possivel trabalhar com latitude e longitude, seria possíveis identificar a posição do robo em graus para definir a frente do robo?), além disso ele terá um sensor infra para localizar objetos a frente (como criar esta interrupção?)… como podem ver estou precisando de muita ajuda!!! qualquer coisa já ajuda!!! desde já obrigado…
By Juliano, August 21, 2011 @ 11:41 pm
Pedro, pelo que entendi você está com dificuldades em trabalhar com posicionamento georeferenciado. Procure entender melhor sobre LATITUDE e LONGITUDE, pois com cálculos básicos você consegue calcular distância entre um ponto e outro, converter em graus…etc. Abraço
By Bishop, November 2, 2011 @ 10:52 am
Boas,
Desde já excelente trabalho.
Gostaria de saber se é possivel ter as coordenadas em UTM?
Abraço
By admin, November 3, 2011 @ 9:21 am
Antonio, para converter Lat/Long para UTM basta fazer alguns calculos. Segue uma página para referencia: http://www.uwgb.edu/dutchs/usefuldata/utmformulas.htm
By GordoGeek, December 5, 2011 @ 10:32 am
Como faz pra ligar o Arduíno Uno com o módulo de GPS, sem utilizar o LCD Shield, apenas lendo a serial? Que pinos devem ser ligados? Obrigado.
By admin, December 5, 2011 @ 11:24 am
GordoGeek, basta remover o LCD SHIELD e seguir a ligação apenas para o GPS. Como o Arduino tem apenas uma serial, você vai ter que “emular” uma segunda serial via programação para ligar o GPS. Existe uma biblioteca pronta para o Arduino que faz isso: NewSoftSerial:http://arduiniana.org/libraries/newsoftserial/
By baruc1967, December 29, 2011 @ 10:30 pm
bem
se vc tem a área mapeada(matriz)do seu gramado
dicamos 0,0 = xx lat por yy long a 99,99 = xx1 lat por yy1 long
por enquanto esquece obstáculos
vc só precisa comparar a posição atual do artefato
digamos 50,50
com a coordenada que vc quer que ele atue
esteja onde ele estiver(posição atual)
quando vc definir vá para a posição zero, zero por exemplo
seja lá qual forem as coordenadas
sua lógica precisa calcular a diferença entre (posição atual)
e sua posição definida, (set point)
e a diferença vai ser exatamente a direção para o robô seguir
ou seja vc terá dois pedidos para o robô
vá 50 para sul e 50 para oeste
e ele chegará ao 0,0
não sei se ficou claro qualquer coisa manda um alô
By Roberto, March 23, 2012 @ 7:07 pm
Olá, Muito bom o projeto e a descrição, porém não consigo carregar o programa no arduino. Descompactei a biblioteca na pasta libraries do arduino, mas quando tento carregar vem várias mensagens de erro de compilação, todas relacionadas com a biblioteca do lcd, algumas C:\arduino-1.0\libraries\LCD4Bit_mod\LCD4Bit_mod.cpp:29:57: error: WConstants.h: No such file or directory
C:\arduino-1.0\libraries\LCD4Bit_mod\LCD4Bit_mod.cpp: In member function ‘void LCD4Bit_mod::pulseEnablePin()’:
C:\arduino-1.0\libraries\LCD4Bit_mod\LCD4Bit_mod.cpp:58: error: ‘LOW’ was not declared in this scope
C:\arduino-1.0\libraries\LCD4Bit_mod\LCD4Bit_mod.cpp:58: error: ‘digitalWrite’ was not declared in this scope
C:\arduino-1.0\libraries\LCD4Bit_mod\LCD4Bit_mod.cpp:59: error: ‘delayMicroseconds’ was not declared in this scope
C:\arduino-1.0\libraries\LCD4Bit_mod\LCD4Bit_mod.cpp:61: error: ‘HIGH’ was not declared in this scope
C:\arduino-1.0\libraries\LCD4Bit_mod\LCD4Bit_mod.cpp:64: error: ‘delay’ was not declared in this scope
C:\arduino-1.0\libraries\LCD4Bit_mod\LCD4Bit_mod.cpp: In member function ‘void LCD4Bit_mod::pushNibble(int)’:
C:\arduino-1.0\libraries\LCD4Bit_mod\LCD4Bit_mod.cpp:73: error: ‘digitalWrite’ was not declared in this scope
C:\arduino-1.0\libraries\LCD4Bit_mod\LCD4Bit_mod.cpp: In member function ‘void LCD4Bit_mod::commandWriteNibble(int)’:
C:\arduino-1.0\libraries\LCD4Bit_mod\LCD4Bit_mod.cpp:99: error: ‘LOW’ was not declared in this scope
C:\arduino-1.0\libraries\LCD4Bit_mod\LCD4Bit_mod.cpp:99: error: ‘digitalWrite’ was not declared in this scope
C:\arduino-1.0\libraries\LCD4Bit_mod\LCD4Bit_mod.cpp: In member function ‘void LCD4Bit_mod::commandWrite(int)’:
C:\arduino-1.0\libraries\LCD4Bit_mod\LCD4Bit_mod.cpp:106: error: ‘LOW’ was not declared in this scope
C:\arduino-1.0\libraries\LCD4Bit_mod\LCD4Bit_mod.cpp:106: error: ‘digitalWrite’ was not declared in this scope. Dá pra me auxiliar ? Sou novo no mundo do arduino.
By Rodrigo, April 2, 2012 @ 8:17 pm
E aí Juliano!Blza?!
Mesmo erro do primeiro post…By Roberto, March 23, 2012
Descompactei a biblioteca na pasta libraries do arduino, mas quando tento carregar vem várias mensagens de erro de compilação, todas relacionadas com a biblioteca do lcd,
By Ediley, October 12, 2012 @ 3:34 am
Amigos, estava com os mesmos problemas de erros. Para o Arduino UNO R3.
consegui resolver usando a versão 0023 (alpha) e a ai compilou sem erro. Valeu?
By Rodrigo, March 13, 2013 @ 3:27 am
Blza Juliano?!
Funcionou direitinho…
É muito complicado implementar o código para que o padrão apresentado seja em coordenadas que o Google entenda e não em NMEA?
By admin, March 13, 2013 @ 10:39 am
Rodrigo, na verdade o protocolo do GPS é NMEA. Mas com ele você tem acesso a LATITUDE, LONGITUDE e etc… Ou seja, são coordenadas que o Google entende. Você pode entrar no Google Maps, digitar uma latitude e longitude que ele te aponta o local.
By Ana Paula, April 1, 2013 @ 9:04 pm
Olá estou com um projeto parecido, não consegui compilar esse código, fica dando erro com a biblioteca, mas ja instalei!! O que fazer?
By Amauri, April 9, 2013 @ 6:44 pm
Ana Paula, tente baixar a IDE 0023 do Arduino, uma mais antiga.
Acho que funcionará!
Estou projetando algo muito parecido com isso.
Muito obrigado pessoal!
Abraços,
Amauri