O módulo GPS NEO-6M possui alguns recursos bem úteis envolvendo a posição de um objeto ao redor do mundo. Sendo assim, vamos aprender as características do módulo e como utilizá-lo com o Arduino (com e sem bibliotecas).

Não pretendo explicar como configurar o módulo neste post. O foco é apenas na leitura dos dados que ele envia.

Informações básicas

O que é o GPS NEO-6M

O NEO-6M é um pequeno módulo capaz de se comunicar com um Sistema Global de Navegação por Satélite (GNSS). Isto é, ele pode obter informações de sua própria localização no mundo, sua velocidade, a hora atual (GMT) e entre outros detalhes que veremos adiante.

Existem alguns módulos que utilizam o módulo NEO-6M (módulo usando módulo) para facilitar seu uso. No meu caso, cheguei a comprar um chamado GY-NEO6MV2 que veio com uma antena junto. Veja ele na imagem abaixo, onde temos o módulo na esquerda e uma antena na direita.

Modulo GPS NEO-6M

Na imagem acima, o NEO-6M é apenas o componente “retangular” que está localizado no meio do módulo GY-GPS6MV2. O módulo GY-NEO6MV2 é relativamente simples, pois possui poucos componentes além do NEO-6M. Mais detalhes e características sobre os componentes serão vistos adiante.

Aplicações

Adiante estão algumas aplicações:

  • Localizar veículos:
    • A localização de veículos pode ser útil para monitoramento das rotas que um determinado veículo segue. Ou então para monitoramento em caso de roubo.
  • Localizar pessoas:
    • É possível localizar uma pessoa em casos de urgência, como um idoso com Alzheimer que se perdeu.
  • Localização para fins de robótica:
    • Dentro da robótica, a localização é extremamente útil, ainda mais quando o assunto são carros autônomos.
  • Obter a hora atual:
    • Você pode ter um sistema que depende da hora atual para sincronizar certas funcionalidades. Então, utilizar o GPS para obter a hora atual de forma precisa pode ser uma boa ideia.

Como também é possível obter a velocidade e a orientação por meio do GNSS, podem existir diversas aplicações envolvendo estas informações.

GNSS e GPS

A titulo de curiosidade, vou comentar brevemente sobre o significado real do GPS e sua diferença para o GNSS.

O termo “GPS” é associado, por muitos, como um sistema de localização global e genérico. Entretanto, o GPS é um dos sistemas de localização disponíveis. E um sistema genérico de navegação por satélites é chamado de GNSS (mencionei no início do post). Relembrando, GNSS significa Sistema Global de Navegação por Satélite (GNSS).

Sendo assim, o GPS ou Sistema de Posicionamento Global é um sistema GNSS criado e mantido pela Força Espacial dos Estados Unidos (USSF). Além do GPS, existem outros sistemas GNSS, como o GLONASS que é um sistema russo. Os dois têm cobertura global e são os principais sistemas GNSS atualmente.

Como estes sistemas são operados pelo governo, seu funcionamento não é 100% garantido, pois os governos podem decidir desativá-los por motivos de segurança ou outro qualquer. Mas o GPS já está em operação há algumas décadas (iniciou em 1978), e estão surgindo cada vez mais sistemas (COMPASS, Galileo), então a preocupação não é tão grande.

É importante ressaltar que o módulo NEO-6M se comunica apenas com o sistema GPS.

Funcionamento do GPS

Os satélites presentes no sistema GPS ficam enviando, de tempos em tempos, sua própria localização, seu status e a hora de forma precisa. No caso, eles não enviam isso para um dispositivo específico, mas sim para qualquer receptor que estiver presente na terra (ele faz um broadcast).

Portanto, um receptor na terra (módulo NEO-6M por exemplo) pode captar estes dados a qualquer momento. Mas os dados de um único satélite não são suficientes para o receptor identificar sua própria posição. Na verdade, ele precisa de pelo menos 3 satélites diferentes para alcançar esse objetivo.

O receptor faz o seguinte:

1 – Recebe os dados do primeiro satélite e grava a hora que isso aconteceu.

2 – Por meio da hora que ele recebeu do satélite e da hora que ele gravou, o receptor sabe quanto tempo a informação gastou para sair do satélite e chegar até ele.

3 – Com este tempo, o receptor pode calcular a distância que ele se encontra do satélite.

distância = velocidade_onda_radio * tempo_gasto (a onda de rádio viaja praticamente na velocidade da luz)

4 – A partir da distância, é possível criar uma região provável de locais que o receptor se encontra ao redor do satélite. Mas a região é ampla e é preciso de mais satélites diferentes para obter uma posição exata.

5 – Os passos 1 a 3 se repetem para outros satélites diferentes.

6 – Com isto, o receptor pode encontrar sua própria posição fazendo uma interseção entre as 3 regiões prováveis de localização obtidas de cada satélite.

Veja este processo na imagem abaixo. Cada esfera representa uma região de localização provável. No caso abaixo, foram utilizados 4 satélites para obtenção da posição (mais preciso). E a localização do receptor é a interseção das 4 esferas.

Fonte: Gisgeogaphy

Esta técnica de localização é chamada de trilateração. No próprio site do GPS, é possível obter estas informações.

Características do módulo GPS

Neste tópico, irei mostrar as características do NEO-6M, do módulo GY-NEO6MV2 e da antena apresentada na primeira imagem do post. E não serão informações cruciais para a implementação no Arduino. Então, se desejar, pode pular para o tópico seguinte.

NEO-6M e módulo

  • 3,3 a 5V de alimentação (Vcc):
    • O NEO-6M em si trabalha com 3,3V, mas módulo GY-NEO6MV2 possui um regulador de tensão para 3,3V. Então é possível alimentar ele com 5V.
  • Pinos de dados não tolerantes a 5V:
    • Cheguei a ver algumas pessoas que não tiveram problemas ao ligar os pinos de dados diretamente ao Arduino sem converter o nível de tensão. Entretanto, também vi alguns casos onde isso levou à queima do módulo.
    • De toda forma, no datasheet do NEO-6M (pág 14) está escrito que a tensão máxima nos pinos de dados é 3,6V. Ele pode até funcionar em 5V, mas talvez com a vida útil reduzida. Então, na hora de utilizá-lo, vou mostrar a ligação com um divisor de tensão para baixar o nível da tensão que vem do Arduino.
  • Interface UART:
    • A forma de comunicar com o módulo é por meio de sua interface UART (pinos RX e TX). 
    • Baudrate padrão de 9600. Pode ser alterado para 4800, 19200, 38400, 57600, 115200 ou 230400.
  • Consumo de corrente:
    • 45mA no modo normal.
    • 11mA no modo “Power Save Mode” (PSM).
  • Sensibilidade do receptor: -161dBm
    • Sensível a um sinal de cerca de 2nV rms.
  • Conector para antena: IPEX ou UFL.
  • Precisões:
    • Localização horizontal: 2,5 metros.
    • Velocidade: 0,1 m/s ou 0,36 km/h.
    • Ângulo de orientação: 0,5º.
  • Limites:
    • Altitude: 50 km.
    • Velocidade: 500 m/s ou 1800 km/h.
    • Dinâmico: menor ou igual a 4g.
  • Taxa máxima de atualização dos dados: 5Hz.
    • Significa que um dado novo (posição, hora etc) é enviado a cada 0,2 segundos.
    • A taxa padrão é cerca de 1Hz (1 dado novo por segundo).
  • É capaz de se comunicar com até 22 satélites por meio de 50 canais de frequência diferentes.

Mais informações podem ser lidas no datasheet.

Antena

Não consegui encontrar informações da antena específica que veio junto ao módulo. Mas encontrei informações genéricas para esse tipo de antena:

  • É uma antena do tipo ‘patch’.
    • É possível encontrar essa antena com o nome de “ceramic patch antenna”. Isso, porque ela pode ter uma parte da estrutura feita de cerâmica.
  • Ganho de 4 a 5 dBi
    • Encontrei anúncios de antenas deste tipo com mais de 18dBi, mas olhando em datasheets oficiais, achei ganhos apenas na faixa de 4 a 5dBi. Referência 1 e 2.
  • Frequência central: 1575 MHz
  • Impedância: 50Ω.
  • Consumo de corrente: 10mA.
  • Dimensões de 25x25x8mm.
  • Não tenho certeza, mas parece que estas antenas possuem um amplificador interno de cerca de 30dB.
  • Conector IPEX ou UFL.
  • Funciona melhor se for instalada com um plano de terra abaixo dela (placa metálica longa ligada ao terra do sistema).

Recursos adicionais

O módulo GY-NEO6MV2 contém 3 elementos importantes de serem comentados além do próprio NEO-6M:

  •  LED:
    • Apagado indica que está procurando por satélites.
    • Piscando indica que eles foram encontrados.
  • Memória EEPROM HK24C32:
    • Armazena dados úteis do NEO6-M, como a hora e a última posição recebida. Pode armazenar também certas configurações do módulo.
    • É uma memória de 4 kBytes que fica conectada diretamente ao NEO6-M por meio de sua interface I2C.
  • Bateria de botão recarregável:
    • Mantém parte do circuito interno do NEO-6M alimentado de forma que a hora é mantida mesmo quando o módulo é desenergizado.
    • Sem a bateria, toda vez que o módulo fosse energizado, ele demoraria mais tempo para sintonizar sua própria posição.

Pinos do módulo GPS

Retomando a imagem do início do post:

Modulo GPS NEO-6M

Podemos ver que o módulo possui 4 pinos:

  • Vcc – Pino de alimentação do módulo (3,3 a 5V).
  • GND – Terra da alimentação.
  • RX – Pino de recebimento da interface UART.
  • TX – Pino de transmissão da interface UART.

Circuito do módulo

Encontrei o seguinte esquemático disponível online:

Fonte: CircuitDigest

É possível ver que as ligações são bem simples, pois o circuito tem poucos componentes (relativamente). Dentre eles: regulador de tensão (IC2), memória EEPROM, barra de pinos para ligação externa (JP1), NEO-6M, bateria de botão (G1), antena etc.

Utilizando o GPS com o Arduino (sem biblioteca)

Circuito

Tendo em vista a pinagem discutida no tópico anterior, o circuito base para o restante do post é o da imagem abaixo.

Para os exemplos que mostrarei não será preciso ligar o pino RX do módulo, pois a única coisa que faremos será ler os dados do módulo pelo Arduino. Portanto, é necessário apenas ligar o pino de transmissão do módulo no Arduino.

Mas, abaixo, deixei indicado a ligação completa incluindo o divisor de tensão para proteger o pino RX do módulo dos 5V do Arduino. No caso, o pino D2 do Arduino é utilizado como RX e o pino D3 como TX.

Ligação com o módulo GPS

O divisor de tensão precisa diminuir os 5V do pino D3 para 3,3V. Os valores sugeridos acima são resistores de 1k e 2,2kΩ. Outros valores podem ser utilizados, desde que a tensão no pino RX do módulo fique em um valor próximo de 3,3V (não pode ser acima de 3,6V).

Para evitar problemas, recomendo programar o Arduino com um código vazio antes de fazer as ligações. Senão, o Arduino pode estar pré-programado com um código que manda tensão no pino D2, o que danificaria o pino TX do módulo.

Lembrando que nos exemplos adiante, o pino TX do Arduino (D3) não é utilizado. Então, se quiser evitar a parte complicada da ligação, apenas alimente o módulo e ligue o pino D2 no TX do módulo.

Código de exemplo

O código abaixo aguarda algum dado ser recebido pelo módulo e, assim que isso ocorre, ele printa todo o conteúdo recebido. É um código bem simples e direito. Então leia os comentários para entender.

Obs: não consegui fazer o módulo funcionar dentro de casa a princípio, tive que colocar ele bem próximo de uma janela para começar a pegar as conexões com os satélites.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <SoftwareSerial.h>

// Pinos da interface UART
#define PINO_RX   2
#define PINO_TX   3

// Serial para comunicar com o módulo
SoftwareSerial gps(PINO_RX, PINO_TX);

void setup()
{
  // Configura os pinos
  pinMode(PINO_RX, INPUT);
  pinMode(PINO_TX, OUTPUT);
 
  // Inicia a comunicação serial padrão (monitor serial)
  Serial.begin(9600);

  // Inicia a comunicação serial com o modulo
  gps.begin(9600);
}

void loop()
{
  // Enquanto a comunicação estiver disponível, imprime os dados recebidos
  while(gps.available())
  {
    Serial.write(gps.read());
  }
}

Interpretar valores recebidos

As mensagens recebidas são chamadas de sentenças NMEA. Elas começam com o símbolo $, depois vem um “data type” que identifica a sentença e o restante dos dados são informações úteis.

Adiante estão listados os significados de alguns destes códigos:

  • GPRMC – Global Positioning Recommended Minimum Coordinates:
    • 1º valor – Horário GMT atual no formato HHMMSS.
    • 2º valor – Status. Ativo (A) ou inativo (V).
    • 3º valor – Latitude.
    • 4º valor – Letra que identifica se a latitude é Norte ou Sul.
    • 5º valor – Longitude.
    • 6º valor – Letra que identifica se a longitude é oeste (W) ou leste (E).
    • 7º valor – Velocidade em nós.
    • 8º valor – Ângulo de orientação em graus.
    • 9º valor – Data atual no formato DDMMAA.
    • 10º valor – Variação magnética.
    • 11º valor – Checksum dos dados (verificar erro na mensagem).
  • GPGGA – Global Positioning System Fix Data
    • É bem parecido com o GPRMC
    • 7º valor – Número de satélites sendo acompanhados.
    • 9º valor – Altitude em metros acima do nível do mar.

Se desejar entender um pouco melhor o que significam estes códigos, leia este documento.

Valores recebidos

Veja os valores que recebi abaixo. Tive que censurar as informações de longitude e latitude por motivos óbvios.

Mensagem recebida pelo módulo GPS

O módulo funcionou perfeitamente. Mesmo algumas dezenas de segundos após ser energizado, ele já foi capaz de informar a localização com um erro menor que 2 metros. A altitude também foi bem próxima do esperado (diferença de alguns metros).

Reparei, depois, que a localização variou um pouco apresentando diferenças maiores que 2 metros e menores que 5 metros. Mas os testes não foram feitos ao ar livre, então o resultado foi muito bom ao meu ver.

Aqui vale fazer uma observação importante. A imagem acima foi capturada às 21:41 do dia 04/01/21 (ignore o horário do monitor serial, pois ele está adiantado 1h). Mas repare na data e hora da mensagem acima: 00:41:34 (004134) e 05/01/21 (050121). O GPS não errou a hora, a diferença ocorreu porque o horário do GPS é o horário de Greenwich (Greenwich Mean Time).

No caso, a diferença de horas do Brasil pro GMT é de -3. Ou seja, se o GMT marca 00:41, então a hora no Brasil seria 21:41, que era o horário do meu computador no momento do print.

Visualizando coordenadas no Google Maps

Para visualizar as localização no Google Maps, basta digita no campo de busca a latitude e longitude da seguinte forma:

LatitudeN/S LongitudeW/E

Latitude e Longitude podem ser divididos em:

GrausºMinutos’Segundos”S GrausºMinutos’Segundos”W

Darei um exemplo abaixo. Ao invés de segundos, vou colocar os minutos com decimais, pois o formato da mensagem do GPS vem com os decimais:

35º47.2631S 67º13.5513W

A orientação (N, S, E, W) pode ser indicada pelo sinal da latitude e longitude. No caso da latitude, o menos indica Sul e na longitude o menos indica oeste (W). Abaixo tem outro exemplo para uma localização ao Norte (N) e oeste (W). Desta vez, coloquei os graus com seus decimais ao invés de separar em graus, minutos e segundos.

15.353124 -5.523279

Utilizando o GPS com o Arduino (com biblioteca)

Circuito

É o mesmo do tópico “sem biblioteca”. Como a biblioteca não utiliza o pino TX do Arduino (D3 no nosso caso), sua ligação pode ser ignorada.

Baixando biblioteca TinyGPS

A biblioteca pode ser baixada na própria IDE do Arduino em Sketch -> Incluir Biblioteca -> Gerenciar Bibliotecas… E é só pesquisar por “tinygps” e baixar a primeira opção, que tem como autor “Mikal Hart”.

Esta biblioteca serve para interpretar as sentenças NMEA recebidas do módulo e tornar a leitura dos dados de interesse mais fácil. Ela não atua diretamente na comunicação UART, portanto, o código base é o mesmo visto no tópico da implementação “sem biblioteca”.

Acabei não gostando muito desta biblioteca por conta do formato dos comandos dela. Mas a utilização dela é bem direta, pois dá pra baixar ela na própria IDE do Arduino. Se você preferir, existe uma biblioteca chamada TinyGPSPlus, que apresenta comandos melhores para obter os dados desejados.

Código de exemplo

O código abaixo é o mesmo do exemplo da biblioteca, mas um pouco adaptado, incluindo as mudanças necessárias para a ligação que eu havia proposto. Leia os comentários para entender o código.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <SoftwareSerial.h>

#include <TinyGPS.h>

// Pinos da interface UART
#define PINO_RX   2
#define PINO_TX   3

// Instancia da biblioteca
TinyGPS gps;

// Serial para comunicar com o módulo
SoftwareSerial ss(PINO_RX, PINO_TX);

void setup()
{
  // Configura os pinos
  pinMode(PINO_RX, INPUT);
  pinMode(PINO_TX, OUTPUT);

  // Inicia a comunicação serial padrão (monitor serial)
  Serial.begin(9600);

  // Inicia a comunicação serial com o modulo
  ss.begin(9600);
}

void loop()
{
  bool newData = false;
  unsigned long chars;
  unsigned short sentences, failed;

  // Aguarda e lê novos dados por 1 segundo
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (ss.available())
    {
      char c = ss.read();
 
      // Processa a sentença e verifica se ela é válida
      if (gps.encode(c))
      {
        newData = true;
      }
    }
  }

  // Se os dados foram válidos
  if (newData)
  {
    float flat, flon;
    unsigned long age;
    uint16_t ano;
    uint8_t mes, dia, horas, minutos, segundos, centesimos;

    // Extrai a latitude, longitude e o tempo dos dados
    gps.f_get_position(&flat, &flon, &age);
    if (flat != TinyGPS::GPS_INVALID_F_ANGLE && flon != TinyGPS::GPS_INVALID_F_ANGLE)
    {
      Serial.print("Latitude = ");
      Serial.println(flat, 6);
      Serial.print("Longitude = ");
      Serial.println(flon, 6);
      Serial.print("Altitude = ");
      Serial.println(gps.f_altitude());
    }


    // Extrai a data e o horário
    gps.crack_datetime(&ano, &mes, &dia, &horas, &minutos, &segundos, &centesimos, &age);

    Serial.print("Data - ");
    Serial.print(dia);
    Serial.print("/");
    Serial.print(mes);
    Serial.print("/");
    Serial.println(ano);

    Serial.print("Horário - ");
    if (horas < 10)
    {
      Serial.print("0");
    }
    Serial.print(horas);
    Serial.print(":");
    if (minutos < 10)
    {
      Serial.print("0");
    }
    Serial.print(minutos);
    Serial.print(":");
    if (segundos < 10)
    {
      Serial.print("0");
    }
    Serial.print(segundos);
    Serial.print(".");
    if (centesimos < 10)
    {
      Serial.print("0");
    }
    Serial.println(centesimos);
  }
}

Resultado obtido

Veja o código de exemplo funcionando abaixo. Na hora de printar a latitude e longitude, troquei o valor pelo texto “censurado” por motivos óbvios.

Observações finais

Conforme eu havia dito, nós não utilizamos o pino RX do módulo. Isso, porque ele é usado para fazer configurações, como o baudrate e a frequência de leitura do GPS.

Não pretendo mostrar como configurar, mas posso dizer que a configuração do módulo é feita com a ajuda do software “U-center”. Neste caso, é preciso ligar o módulo no computador utilizando um conversor USB-TTL.