Menú Cerrar

Conecta un receptor GPS a tu Arduino

Los receptores GPS habituales transmiten los datos a través de una comunicación serie. Podemos programar nuestro Arduino para recibir estos datos y disponer en nuestro proyecto de coordenadas globales, altitud, velocidad de desplazamiento, rumbo, fecha y hora ultra-precisa. ¡Ésta última procede de los relojes atómicos de los satélites GPS!

Puedes ver un Vídeo-Resumen de 10 minutos:

Navegación Antigua

Los antiguos navegantes observaban las constelaciones mediante instrumentos como la Ballestilla, el Astrolabio, el Cuadrante y el Sextante para medir la posición de los astros y mediante cálculos y estimaciones inferir su propia posición. En la actualidad, hemos instalado nuestra propia constelación para orientarnos:

El Sistema de Posicionamiento Global GPS (Global Positioning System)

La Constelación GPS

El Sistema de Posicionamiento Global GPS, está constituido por 24 satélites, agrupados en 6 orbitas a  20.200 km de altura. Cada satélite da 2 vueltas a la tierra cada día. Disponen de propulsores direccionales que les permiten recolocarse y ajustar su velocidad. Una red de estaciones de seguimiento desplegada por todo el planeta supervisa el funcionamiento del sistema.

Soporte Terrestre

El sistema ha sido instalado por el Departamento de Defensa de Estados Unidos. La Federación Rusa tiene su equivalente: GLONASS. La Unión Europea está desarrollando Galileo.

Cada satélite incorpora a bordo un reloj atómico ultrapreciso. ¡El error es inferior a 1 segundo cada 30.000 años!

Cada satélite, transmite continuamente su posición y la hora en la frecuencia: 1.575 GHz. Orbitando a 20.200 km de altura y siendo la velocidad de la radiación electromagnética de 299.792 km/s, la señal tarda más de 67 ms en llegar a un receptor sobre la superficie de la tierra.

De la misma forma que estimamos lo lejos que ha caído un rayo por el tiempo que transcurre desde que vemos el relámpago hasta que escuchamos el trueno, los receptores GPS calculan la distancia a los distintos satélites por el tiempo que tardan en llegar las señales procedentes de cada uno de ellos. Todas las señales fueron transmitidas en el mismo instante, porque todos los satélites GPS están sincronizados. Los receptores GPS contienen unidades de cálculo especializadas para, mediante trilateración, obtener la posición global propia. A partir de sucesivas medidas, también calculan la velocidad de desplazamiento y el rumbo.

Trilateración (por Heriberto Arribas Abato)

El Receptor GPS EM-406A SiRF III de 20 canales

Es el receptor que utilizaremos para conectarlo al Arduino en esta entrada de blog.

Receptor GPS EM406

Especificaciones

Generales

Chipset: SiRF StarIII
Frequencia: L1, 1575.42 MHz
Canales: 20
Sensibilidad: -159 dBm

Precisión

Posición: 10 metros en modo 2D RMS. 5 metros , 2D RMS, con WAAS habilitado.
Velocidad: 0,1 m/s
Tiempo: 1 μs sincronizado al tiempo GPS
Sistema de referencia geodésico: WGS-84

Tiempo de adquisición

Readquisición: 0,1 segundos de promedio
Arranque caliente: 1 segundo de promedio
Arranque frío: 42 segundos de promedio

Bloques funcionales

Bloques de un GPS

El Receptor GPS incorpora los siguientes bloques funcionales:

  • Recepción RF: Recibe la señal de los satélites y la decodifica.
  • Unidad de cálculo: Considerando el tiempo de llegada de las señales de los distintos satélites, calcula la posición del receptor, altitud, velocidad de desplazamiento y rumbo.
  • Transmisor / Receptor Serie: Envía / Recibe  datos a través de los pines TX / RX.
  • Memoria: Guarda la última posición válida y la configuración del dispositivo.
  • Condensador de alimentación: Es capaz de mantener la memoria durante 12 horas. Permite los arranques del GPS «en caliente», en los que parte de la última posición válida y es capaz de resolver la trilateración más rápidamente. Transcurridas 12 horas sin que se haya conectado a la alimentación, pierde la posición y la configuración vuelve a la de defecto. Por ejemplo, la velocidad de transmisión serie vuelve a ser 4800 baudios.

Receptores GPS en el año 2015

El Receptor GPS EM-406A fue adquirido en el año 2010. Los modelos del año 2015, cuando redactamos esta entrada son:

GPS Adafruit Ultimate

Adafruit Ultimate GPS Breakout – 66 channel w/10 Hz updates – Version 3

GPS SparkFun

GPS Receiver – EM-506 (48 Channel)

GPS crius

Crius CN-06 V2.0

tienen más canales, mayor tasa de refresco, mayor sensibilidad… pero la funcionalidad es similar.

Conexión directa del Receptor GPS EM-406A al Ordenador

El Receptor GPS EM-406A Tiene 6 pines:

Pines del GPS EM406

1: GND
2: VIN. Alimentación 4,5V – 6,5V DC
3: RX. Recibe comandos para configurar el GPS.
4: TX. Transmite la información GPS.
5: GND. Conectar con el pin 1.
6: No se usa

Comenzamos por el principio: Conectamos GND y VIN a la Alimentación de 5 V de un Arduino Mega.

El led encendido fijo nos indica que el receptor GPS ya está funcionando aunque todavía no ha determinado nuestra posición. Cuando lo haga, el led comenzará a parpadear.

Incluso sin haber determinado la posición, se transmite información por el pin TX.

Lo conectamos al osciloscopio:

Comunicación serie en el Osciloscopio

Es una comunicación serie a 4800 baudios, 8 bits de datos, Paridad: ninguna, Bit de stop: 1. Es la configuración por defecto de este GPS.

¿Cómo podemos ver los caracteres ASCII de la transmisión?

Si tuviéramos un chip que fuera interface de la comunicación serie a la comunicación USB, podríamos verlos en el ordenador. Lo cierto es que en nuestras placas Arduino tenemos un chip que hace exactamente eso. Es el chip FT232R en las placas antiguas como el Arduino Mega 1280 que utilizo o yo. O el ATmega16U2 en el actual Arduino Uno.

Si conectamos el pin TX del receptor GPS en el pin 1 TX de nuestra placa Arduino podemos ver los caracteres  de la transmisión mediante el Serial Monitor del IDE del Arduino o cualquier otro software que lea los puertos: Hyperterminal, cutecom

Conexión Arduino FT232

No queremos que la microcontroladora del Arduino emita a través del pin 1 TX, interfiriendo con la transmisión del GPS. Cargamos en el Arduino un programa vacío:

void setup() {}
void loop() {}

Podemos ver la transmisión en el Serial Monitor del IDE de Arduino:

Tramas NMEA 0183 en el Serial Monitor

Si las tramas te aparecen en arameo…

Velocidad de Transmisión Incorrecta

cambia la velocidad.

Yo utilizo un sistema Linux, y puedo ver esas tramas desde un terminal con:

cat /dev/ttyUSB0

¿Para qué sirve el pin RX del GPS?

Para enviarle comandos con los que podemos cambiar su configuración. Estos comandos no pertenecen al protocolo NMEA 0183. Son específicos de cada fabricante y habitualmente configuran:

  • Parámetros de comunicación serie: Velocidad, paridad…
  • Mensajes NMEA que queremos recibir: Lo vemos a continuación.
  • Frecuencia de los mensajes: 1 cada 2 segundos, 1 cada segundo, 10 cada segundo en los GPS más modernos.
  • Activar los mensajes de Debug.
  • Seleccionar el sistema de referencia geodésica. Por defecto es el WGS 84 (World Geodetic System 1984)

Por ejemplo, para cambiar la velocidad de comunicación serie a: 9600 baudios, 8 Bits de datos, 1 Bit de stop, sin paridad, conectamos el pin RX del GPS al pin 0 RX de la placa Arduino y desde el propio IDE de Arduino enviamos el comando:

$PSRF102,9600,8,1,0*12

El formato de la instrucción 102 es:

$PSRF102,<Baud>,<DataBits>,<StopBits>,<Parity>*CKSUM<CR><LF>
<baud> 1200,2400,4800,9600,19200,38400
<DataBits> 8
<StopBits> 0,1
<Parity>
0=None, Odd=1,Even=2

El último *12 es un Checksum XOR de todos los bytes de la trama (sin contar el $ inicial) en Hexadecimal. Puedes calcularlo en la página MTK NMEA checksum calculator

Todos estos comandos vienen detallados las páginas 14 y ss de la adjunta DataSheet:

Hardware DataSheet EM506

Interpretando la tramas del GPS. El protocolo NMEA 0183.

La National Marine Electronics Association (NMEA) es una organización estadounidense que establece estándares de comunicación electrónica marítima.

Su protocolo NMEA 0183 es el que utilizan habitualmente los receptores GPS.

Cada trama comienza por: $GP y le siguen: RMC, GGA, GSA, GSV y otros, que nos indican qué tipo de datos contiene esa trama. A continuación los campos propios de ese tipo de mensaje y finalmente: * y el Checksum.

El mensaje termina con <CR><LF>.

Mensajes GGA-Global Positioning System Fixed Data

Ejemplo: $GPGGA,161229.487,3723.2475,N,12158.3416,W,1,07,1.0,9.0,M,,,,0000*18

se traduce como:

$GPGGA – Identificador del Mensaje

161229.487 – Hora UTC en formato hhmmss.sss 16:12:29.487

3723.2475 – Latitud en formato ddmm.mmmm 37º 23.2475′

N – Indicador Norte o Sur

12158.3416 – Longitud en formato dddmm.mmm 121º 58.3416′

W – Indicador Este u Oeste (W)

1 – Indicador de validez de la posición:

  • 0: Posición no válida. El sistema no ha conseguido deducir una posición coherente con las distancias a los satélites
  • 1: Posición válida en Modo SPS (Standard Positioning System).
  • 2: Posición válida en Modo SPS (Standard Positioning System) con información Diferencial. Además de la señal de los satélites, el GPS considera la señal emitida por un emisor terrestre (Modo diferencial)

07 – Número de satélites usados

1.0 – HDOP: Dilución horizontal de la precisión. Es una indicación de la precisión de la medida horizontal.

  • <1: Ideal
  • 1-2: Excelente
  • 2-5: Buena
  • 5-10: Moderada
  • 10-20: Aproximada
  • >20: Pobre

9.0 – Separación entre el Geoide y el Elipsoide de Referencia. Altitud Elipsoidea = [Altitud sobre el nivel del Mar] + [Separación Geoide]

M – Unidad de la Separación Geoide.

,,,, Segundos de antiguedad de la corrección diferencial. Campos nulos cuando no se usa el DGPS.

0000 – ID de la Estación de Referencia Diferencial

*18 – Checksum

Otros mensajes

Los otros tipos de mensajes: RMC, GSA, GSV… siguen el mismo esquema. En el documento adjunto (en inglés) se detallan todos ellos:

Hardware DataSheet EM506

El Checksum

El CheckSum se representa con un número hexadecimal de 2 dígitos. Sirve para asegurar la integridad de los datos y se calcula aplicando la operación XOR a todos los caracteres ASCII entre el $ y el *.

En C se puede implementar como:

#include <stdio.h>
#include <string.h>

int checksum(char *s) {
    int c = 0;

    while(*s)
        c ^= *s++;

    return c;
}

int main()
{
    char mystring[] = "GPRMC,092751.000,A,5321.6802,N,00630.3371,W,0.06,31.66,280511,,,A";

    printf("String: %s\nChecksum: 0x%02X\n", mystring, checksum(mystring));

    return 0;
}

También lo puedes calcular en la web: MTK NMEA checksum calculator

Arduino extrae los datos de las tramas NMEA. El PARSEADO.

El paso de una «string» o un conjunto de «chars» como:

$GPGGA,161229.487,3723.2475,N,12158.3416,W,1,07,1.0,9.0,M,,,,0000*18

a una asignación de variables como:

GPS.hour = 16

GPS.longitude = 121º 58.3416′

[…]

es un proceso que se denomina «Parseado» (del inglés «parse»)

Para realizarlo, no conectaremos el receptor GPS directamente al ordenador, como vimos en un apartado anterior, sino a 2 pines del Arduino que establecerán la comunicación serie con el receptor GPS. Yo he elegido los pines 50 y 51 de mi Arduino Mega. Habitualmente se eligen los 2 y 3, pero en mi aplicación los tengo ocupados controlando un led multicolor con PWM.

Conexión del GPS a los pines 50 y 51

Hay múltiples algoritmos de parseado. Tienen la forma:

  if (strncmp(buffer, "$GPRMC",6) == 0) {

    // hhmmss time data
    parseptr = buffer+7;
    tmp = parsedecimal(parseptr);
    hour = tmp / 10000;
    minute = (tmp / 100) % 100;
    second = tmp % 100;

    parseptr = strchr(parseptr, ',') + 1;
    status = parseptr[0];
    parseptr += 2;

    // grab latitude & long data
    // latitude
    latitude = parsedecimal(parseptr);
    if (latitude != 0) {
      latitude *= 10000;
      parseptr = strchr(parseptr, '.')+1;
      latitude += parsedecimal(parseptr);
    }
    parseptr = strchr(parseptr, ',') + 1;
    // read latitude N/S data
    if (parseptr[0] != ',') {
      latdir = parseptr[0];
    }

    // longitude
    parseptr = strchr(parseptr, ',')+1;
    longitude = parsedecimal(parseptr);
    if (longitude != 0) {
      longitude *= 10000;
      parseptr = strchr(parseptr, '.')+1;
      longitude += parsedecimal(parseptr);
    }
    parseptr = strchr(parseptr, ',')+1;
    // read longitude E/W data
    if (parseptr[0] != ',') {
      longdir = parseptr[0];
    }

    // groundspeed
    parseptr = strchr(parseptr, ',')+1;
    groundspeed = parsedecimal(parseptr);

    // track angle
    parseptr = strchr(parseptr, ',')+1;
    trackangle = parsedecimal(parseptr);

    // date
    parseptr = strchr(parseptr, ',')+1;
    tmp = parsedecimal(parseptr);
    date = tmp / 10000;
    month = (tmp / 100) % 100;
    year = tmp % 100;

o similar. El más elegante que he encontrado es el de LadyAda de Adafruit que lo hace en 2º plano con la librería AdafruitGPS. Es la opción que utilizo en esta aplicación:

_73_GPS_Arduino_LCD_v3

Montándolo todo en el salpicadero del coche

Pretendo llevar el Arduino con receptor GPS en el coche. Le añado:

  • Un LCD de 20×4 para visualizar los datos.
  • Un regulador de 12V a 5V que alimentará 2 entradas USB para cargar el móvil y otros gadgets.
  • 1 USB tipo B para programar el Arduino in situ y que transmitirá las tramas del GPS, actuando como un GPS-USB.
  • Un led verde indicador de presencia de tensión de 12V.
  • Un led multicolor:
    • Rojo: No hay datos GPS.
    • Azul: Posicionamiento GPS correcto.
  • Una tarjeta interface con:
    • Conectores de 12V y 5V
    • Resistencia limitadoras para los leds.
    • Divisor de tensión para medir la tensión del sistema eléctrico del coche con Arduino.
  • Una pinza impresa en 3D para llevar el móvil.
  • Un monitor TFT LCD de 3,5″ para una cámara trasera de ayuda al aparcamiento.
Funcionando en el coche
Interior del montaje

Notas sobre el Software

El Software del Arduino está comentado en el código:

_73_GPS_Arduino_LCD_v3

Sólo añadir:

Comunicación Serie

Se establecen 2 comunicaciones serie:

  • Entre el Receptor GPS y el Arduino a través de los pines 50 y 51 a 4800 baudios.
  • Entre el Arduino y su conector USB, a través de los pines 0 y 1 a 115200 baudios.

Caducidad de los valores del GPS

Si no llegan nuevos valores válidos procedentes del GPS, se quedan asignados los últimos. Para evitar esto, cogemos el momento en el que llega una nueva trama GPS:

  if (GPS.newNMEAreceived()) {
    timer = millis();

Y si pasan 1,5 segundos sin nuevas tramas, invalidamos los datos haciendo:

 if (millis()>timer+1500) GPS.fix=0;

Cuando GPS.fix=0, en el LCD aparece la indicación «No hay datos GPS» y la tensión del sistema eléctrico del coche.

Pantalla No hay datos GPS

Brújula digital

El valor «GPS.angle» que indica el rumbo en el que nos estamos desplazando, lo represento con:

 | OO | | | NO | | | NN | | | NE | | | EE | | | SE | | | SS | | | SO | | | OO |

centrando en el rumbo.

Los caracteres especiales que marcan el centro se definen como:

byte left[8] = {
  B00000,
  B00001,
  B00011,
  B00111,
  B01111,
  B11111,
  B11111,
};

byte right[8] = {
  B00000,
  B10000,
  B11000,
  B11100,
  B11110,
  B11111,
  B11111,
};

Tensión del sistema eléctrico del coche

La tensión nominal del sistema eléctrico del coche es de 12V, pero la tensión real es mayor. Procede del Alternador del coche. Para medirla con Arduino, la bajamos al nivel TTL con un divisor de tensión de 3 resistencias de 10 kΩ y cogemos la tensión en bornes de una de ellas. La aplicamos a la entrada analógica A0.

Sólo leo los valores una vez cada 2 segundos porque si los leo continuamente, el parpadeo en el LCD le torna ilegible.

Medí la tensión con un multímetro mientras capturaba las lecturas ADC. Saqué las medias y de ahí obtengo la transformación ADC a Voltios.

 if (refresh > millis())  refresh = millis();
  if (millis() > refresh + 2000) {// Cada 2 segundos
    refresh = millis();
    tension = analogRead(0)*13.825/945.54; // Leemos la tension de la bateria
  }

Eco de las tramas del GPS en el puerto USB

Con:

#define GPSECHO true

en el USB tenemos las tramas GPS en formato NMEA 0183 que ya conocemos:

$GPGGA,092750.000,5321.6802,N,00630.3372,W,1,8,1.03,61.7,M,55.2,M,,*76
$GPGSA,A,3,10,07,05,02,29,04,08,13,,,,,1.72,1.03,1.38*0A
$GPGSV,3,1,11,10,63,137,17,07,61,098,15,05,59,290,20,08,54,157,30*70
$GPGSV,3,2,11,02,39,223,19,13,28,070,17,26,23,252,,04,14,186,14*79
$GPGSV,3,3,11,29,09,301,24,16,09,020,,36,,,*76
$GPRMC,092750.000,A,5321.6802,N,00630.3372,W,0.02,31.66,280511,,,A*43

Si a ese puerto USB conectamos un NetBook o PC portátil con el Software libre FoxtrotGPS, el sistema GPS-Arduino se comporta como un GPS-Mice y el FoxtrotGPS nos posiciona sobre el mapa, graba nuestro recorrido y guarda todos los parámetros de posición, altitud, velocidad… en archivos .log

FoxtrotGPS

Artículos relacionados

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de privacidad, pinche el enlace para mayor información. ACEPTAR

Aviso de cookies