GPS y reloj para Raspberry Pi

Si quieres que tu Raspberry Pi pueda tener GPS, y a la vez sincronizar la fecha y hora, hay una solución muy sencilla: conectala utilizando gpsd con tu movil.

Las Raspberry Pi carecen de un reloj permanente, por lo que si las apagas, pierdes la fecha y la hora que tuviera configurada. Eso no es un problema si la vas a tener conectada a Internet intermitentemente, porque puede recuperar la fecha y la hora de los servidores de NTP disponibles en Internet.

Si utilizas una Raspberry Pi con un Linux basado en raspbian puedes recuperar la fecha y la hora anteriores, porque se incluye el programa fake-hwclock, que guarda la fecha y la hora antes de cada parada, y luego la restaura, pero cuando vuelves a arrancar, se ha producido un retraso con la hora real.

En mi caso, utilizo la Raspberry Pi como ordenador de apoyo en astrofotografía, para conectar la montura, la cámara, etc. Si estoy en casa, no hay problema, pero lo habitual es que la lleve a un lugar remoto, sin conexión electrica. Haré un artículo más adelante con más detalles de cómo he resuelto el tema de la alimentación.

Aqui os cuento cómo he resuelto a la vez el problema de la fecha y hora y el de la posición GPS, que es algo que también necesita el equipamiento de astrofotografía.

Utilizo la distribución astroberry.io que me ofrece una solución con casi todo el software necesario para automatizar las sesiones de astrofotografía.

De serie incluye gpsd y chronyd, así que solamente tengo que conseguir conectar mi móvil a la Raspberry, arrancar un programa que publique la información de GPS, y configurar el demonio de gpsd para que escuche la información que envía el móvil. Además, tengo que asegurarme de que el servicio de NTP gestionado por el demonio chronyd utilice como referencia de hora la que proporciona gpsd.

Una vez que hayamos probado cada uno de estos elementos, podemos automatizar el proceso para que no haya que estar pendiente de ello y que se ejecute automáticamente.

Virtualgps

En el caso de la distribución de astroberry.io, viene activado por defecto el servicio de virtualgps, que actua como un dispositivo GPS con una configuración fija de latitud, longitud y altitud.

virtualgps es un demonio que cuando arranca lee los datos de latitud, longitud y altitud de un fichero (/etc/location.conf) y emite dichas coordenadas como si fuera un dispositivo GPS. El servicio se conecta directamente con gpsd en el arranque.

Si virtualgps está activo, tendrás que desactivarlo previamente o no conseguiras que se actualice correctamente la informacion de localización o de tiempo.

Para no tener que parar y arrancar el demonio, puedes decirle a gpsd que deje de utilizar el dispositivo de virtualgps. Para ello, hay que ejecutar el siguiente comando:

$ sudo gpsdctl remove /tmp/vgps

Si quieres volver a activarlo, solamente tienes que volver a añadir el dispositivo:

$ sudo gpsdctl add /tmp/vgps

Si quieres parar el demonio, basta hacerlo con:

$ sudo systemctl stop virtualgps

Para volver a arrancarlo:

$ sudo systemctl start virtualgps

Prueba directa del dispositivo GPS

Vamos a probar que hay comunicación directa entre el móvil con GPS y nuestra astroberry, y que además, el móvil envía la información de GPS correctamente.

En el movil me instalo NetGPS (aunque diría que hay otros programas que tambien te pueden servir, como GPSd Client). NetGPS te permite publicar la información de GPS durante 10 minutos, más que suficiente para la primera sincronización. Si se llega a los 10 minutos, el programa sigue abierto pero detiene toda la funcionalidad como servidor.

En el terminal Android, tienes que hacer lo siguiente:

  1. Conectar el movil al AP astroberry mediante Wi-Fi.
  2. Arrancar el programa NetGPS , y avanzar por todo el tutorial, en el que te enseña a utilizarlo.
  3. Obtener la direcció IP del movil, para ello se puede consultar en la aplicacion de NetGPS.
  1. Crear un servidor en el puerto 6000, o cualquier otro puerto que se elija.
  2. Activar el servidor, que estará emitiendo la información del GPS durante los próximos 10 minutos.

NOTA: Si has creado un servidor en NetGPS, a veces desaparece de la lista de servidores disponibles, para recuperarlo hay que visitar la pagina de ayuda (icono en la parte inferior de la pantalla), y luego volver a la de servidores.

Utilizando el terminal de la Raspberry, necesitarás la dirección IP del móvil en la red Wi-Fi y el puerto que configuraste antes en NetGPS. Mediante el comando gpsmon, puedes comprobar que todo está funcionando correctamente, porque lee los datos de un dispositivo compatible con la norma NMEA:

$ gpsmon 192.168.1.106:6000

En la pantalla se verá cómo se empiezan a recibir los paquetes de GPS desde el movil.

Si por algún motivo el servidor NMEA no está disponible, el comando gpsmon mostrará un error.

$ gpsmon 192.168.1.106:50000
gpsmon:ERROR: TCP device open error can't connect to host/port pair.

Si no ves nada en gpsmon es porque:

  1. tienes algun problema de comunicación entre el astroberry y el móvil. Revisa que estén en la misma red Wi-Fi.
  2. no has arrancado el servidor NetGPS en el móvil.
  3. el servidor NetGPS se ha detenido porque ha llegado al tiempo máximo de 10 minutos, o porque el sistema operativo Android de tu dispositivo lo ha detenido. En este caso gpsd no conecta con el servidor y lo elimina de la lista. Tendrás que volver a añadirlo mediante gpsdctl, como se describe más arriba.
  4. no has añadido el dispositivo a gpsd. Uno de los errores más comunes es que añadamos el dispositivo a gpsd y que no hayamos arrancado todavía el servidor NetGPS en el móvil, en cuyo caso gpsd no conecta con el servidor y lo elimina de la lista.
  5. se te ha olvidado parar el servicio de virtualgps.

Ahora ya hemos probado que el dispositivo envía los datos correctamente y que los recibimos también en astroberry. El siguiente paso es configurar gpsd para que lo haga sin nuestra intervención.

Configuración de gpsd

Ahora que ya hemos probado la conectividad entre la Raspberry y el móvil, podemos dar el siguiente paso: configurar el demonio de gpsd para que actualice la posicion utilizando la localización enviada desde NetGPS.

Podemos comprobar si ya tenemos el servicio gpsd arrancado y configurado mediante

$ sudo systemctl status gpsd

Ahora se trata solamente indicarle a gpsd que utilice un dispositivo GPS adicional.

Cuando se arranca gpsd el demonio abre un puerto especial en el que escucha peticiones para añadir o eliminar dispositivos. El comando que se utiliza para enviar las peticiones es gpsdctl. Para añadir el dispositivo Android, es tan sencillo como:

$ sudo gpsdctl add tcp://192.168.1.106:6000

El comando hay que ejecutarlo con privilegios de administrador, porque solamente los administradores pueden escribir en el puerto de control.

Si por algún motivo, el demonio de gpsd no puede conectar con el móvil, dejará de consultar al dispositivo. Así que si por algun motivo, el servidor en el móvil se detiene (NetGPS se cuelga a veces, o cuando la aplicación queda en segundo deja de enviar información), dejará de enviar datos y tendrás que volver a añadir el dispositivo. Recomiendo también que se borre antes de volver a añadirlo, así dejas la lista de dispositivos limpia por si acaso:

$ sudo gpsdctl remove tcp://192.168.1.106:6000
$ sudo gpsdctl add tcp://192.168.1.106:6000

Si ahora arrancas gpsmon, verás que está leyendo la informacion enviada por NetGPS:

Si no ves nada en gpsmon es porque:

  1. tienes algun problema de comunicación entre el astroberry y el móvil. Revisa que estén en la misma red Wi-Fi.
  2. no has arrancado el servidor NetGPS en el móvil.
  3. el servidor NetGPS se ha detenido porque ha llegado al tiempo máximo de 10 minutos, o porque el sistema operativo Android de tu dispositivo lo ha detenido. En este caso gpsd no conecta con el servidor y lo elimina de la lista. Tendrás que volver a añadirlo mediante gpsdctl, como se describe más arriba.
  4. no has añadido el dispositivo a gpsd. Uno de los errores más comunes es que añadamos el dispositivo a gpsd y que no hayamos arrancado todavía el servidor NetGPS en el móvil, en cuyo caso gpsd no conecta con el servidor y lo elimina de la lista.
  5. se te ha olvidado parar el servicio de virtualgps.

Automatización

Estos pasos que hemos realizado nos han permitido obtener la fecha y la hora mediante GPS en el móvil y consultarla desde la Raspberry, mediante gpsd. Ahora bien, el dispositivo que hemos añadido no se guarda en la configuración de gpsd, por lo que cada vez que arranques tienes que añadir el dispositivo. Además, si el dispositivo deja de enviar información, gpsd lo borra de su lista interna, y tenemos que volver a registrarlo.

Para que no tengamos que hacer estos pasos cada vez, es conveniente preparar unos scripts que te permitan añadir y borrar el dispositivo a tu conveniencia. En mi caso, he creado el script addgps:

#!/usr/bin/env bash

sudo /usr/sbin/gpsdctl remove /tmp/vgps
sudo /usr/sbin/gpsdctl remove tcp://192.168.1.106:6000
sudo /usr/sbin/gpsdctl add tcp://192.168.1.106:6000

He aprovechado para quitar el dispositivo de virtualgps, por si se me hubiera olvidado hacerlo antes.

Comprobaciones

Una vez que has realizado la configuración anterior, lo único que hay que hacer cada vez que arranques la Raspberry es:

  1. conectar el móvil al AP de astroberry. De esta forma, se le asigna una IP de la subred WiFi.
  2. arrancar el NetGPS en el móvil, e iniciar el servidor. Aprovecha para mirar la IP asignada del móvil.
  3. añadir el móvil como dispositivo GPS en gpsd. Utilizaremos la dirección IP del móvil y el puerto configurado en el móvil.

Al cabo de unos 10-20 segundos (si no hay buena visilidad, puedes tardar algo más si estás en interiores) se puede comprobar que se reciben datos de GPS, utilizando gpsmon o apuntando el navegador de la Raspberry a http://localhost:8625/ para abrir gpspanel,

Después de estas comprobaciones, podemos empezar a configurar el servicio de NTP que proporciona el demonio chronyd, para que utilice la señal horaria que proporciona gpsd.

Configuración de Chronyd

chronyd es una implementacion reducida del protocolo NTP para sincronización de la fecha y la hora. Está especialmente orientado a entornos como el de Raspberry, con conectividad y recursos limitados. Y viene de serie con astroberry.

Se puede configurar chronyd para que utilice como fecha la que proporciona gpsd. Hay una guia disponible aquí.

El tutorial es muy exhaustivo, y está pensado para instalar un servidor NTP completo, con un generador de pulsos PPS, que yo no necesito. Sin embargo, en el tutorial encontrarás la forma de probar que gpsd recibe correctamente los datos del dispositivo GPS, es la guía que yo he seguido para la configuración de gpsd que he indicado más arriba.

gpsd escribe en la memoria compartida la señal horaria que llega desde el dispositivo GPS.

Para que chronyd pueda utilizar la señal horaria que genera gpsd, he tenido que modificar una cosa más en mi configuración de astroberry, añadiendo estas lineas en /etc/chrony/chrony.conf

# delay 0.2, debido a la latencia de la red wifi
# offset 0.2, se podria reducir a 0.0.
refclock SHM 0 refid GPS0 offset 0.2 delay 0.2

# Actualiza directamente la hora si hay mas 1 segundo de diferencia.
makestep 1 -1

Con ello, le decimos a chronyd que utilice como referencia de hora la informacion del elemento 0 de la memoria compartida (SHM 0), asignandole el identificador GPS0.

También hay que asegurarse de que se actualiza inmediatamente (step) en lugar de hacerlo por etapas o poco a poco (slew). Para ello se utiliza makestep, que indica que si la diferencia de la hora es mayor de 1 segundo, se ajuste directamente la hora, sin hacerlo por etapas.

Una vez modificada la configuración se rearranca el servicio de chronyd y ya estamos listos.

Puedes depurar si gpsd está escribiendo correctamente la señal horaria mediante ntpsshmon, que monitoriza los valores que gpsd escribe en la memoria compartida y que chronyd utilizará para actualizar la hora.

$ sudo ntpshmmon
ntpshmmon version 1
Name Seen@ Clock Real L Prec
sample NTP0 1624309188.486877237 1624309188.485854108 1624365224.000000000 0 -20
sample NTP0 1624309188.995274098 1624309188.994528955 1624365225.000000000 0 -20
sample NTP0 1624309190.027582049 1624309190.027305748 1624365226.000000000 0 -20
sample NTP0 1624309191.079066017 1624309191.078682806 1624365227.000000000 0 -20
sample NTP0 1624309192.141597193 1624309192.140538175 1624365228.000000000 0 -20
sample NTP0 1624309193.139779964 1624309193.137365922 1624365229.000000000 0 -20
sample NTP0 1624309194.141768170 1624309194.141345829 1624365230.000000000 0 -20
sample NTP0 1624309195.160646168 1624309195.159846654 1624365231.000000000 0 -20
sample NTP0 1624309196.207258810 1624309196.207035658 1624365232.000000000 0 -20
sample NTP0 1624309197.237495615 1624309197.237314631 1624365233.000000000 0 -20

Prueba extremo a extremo

Las pruebas consisten en:

  1. modificar la fecha de la maquina a un valor muy lejano en el tiempo, para ver facilmente el ajuste de hora.
$ sudo date -s "80 hours ago"
  1. conectar el móvil a la red wifi de astroberry.
  2. abrir en el móvil el programa NetGPS y activar el servidor.
  3. ejecutar el script addgps (ver más arriba).
  4. tienes que hacer que la aplicación NetGPS no se detenga.
  5. puedes comprobar con gpsmon que la señal de GPS con la posición y la hora llegan correctamente.
  6. la hora se ajustará al cabo de aproximadamente 1 minuto. Durante ese tiempo tienes que hacer que la aplicación NetGPS no se detenga.