Registrador GPS Avanzado: Seguimiento de Vuelo en Tiempo Real, Monitor de Altitud y Velocidad Máxima
Componentes y suministros
| Componente | Cantidad |
|---|---|
| Arduino UNO | 1 |
| Jumpers (Barra de bus), Set de cables jumper | 1 |
| Arduino Proto Shield | 1 |
| Pantalla TFT SPI 1.8" con zócalo MicroSD (o similar con tarjeta SD) | 1 |
| Módulo GPS u-blox NEO-6M | 1 |
Herramientas y máquinas necesarias
- Soldador (genérico)
- Estaño para soldar, sin plomo
- Pelacables y cortador, capacidad 18-10 AWG / 0.75-4mm²
Sobre el proyecto
Introducción
Practico aeromodelismo y me gusta conocer la velocidad y altitud de mis aviones. Desafortunadamente, los registradores GPS comerciales son muy caros.
Por eso decidí construir mi propio registrador de datos GPS basado en Arduino por menos de 50€.
Mi primer prototipo utiliza un Arduino Uno R3 con una pantalla Sainsmart ST7735 (con ranura SD integrada) y un módulo GPS NEO 6M V2.
En una segunda versión planeo usar un Arduino Nano con pantalla OLED SSD1306, el mismo módulo GPS y una tarjeta microSD. El peso con carcasa debería ser de unos 40 gramos, fácil de integrar en un avión mediano (dimensiones aprox. 50×30×22 mm). Este será mi próximo proyecto (estoy esperando los materiales).
Pruebas
No es fácil filmar la pantalla del Arduino dentro de un coche, pero lo hice y puedes ver el resultado en el video.
La próxima prueba será con el nuevo prototipo, más pequeño y ligero, en un avión radiocontrolado. ¡Continuará!
Código
Registrador GPS (versión básica)
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#define cs 10
#define dc 9
#define rst 8
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, rst);
static const int RXPin = 4, TXPin = 3; // Comunicación GPS
static const uint32_t GPSBaud = 9600;
#define OLED_RESET 5
TinyGPSPlus gps;
SoftwareSerial ss(RXPin, TXPin);
int x = 80, xh = 80;
int maxhigh = 0;
int maxspeed = 0, speed1 = 0;
int high1 = 0;
void setup() {
Serial.begin(9600);
ss.begin(GPSBaud);
tft.initR(INITR_GREENTAB);
tft.fillScreen(ST7735_BLACK);
tft.setCursor(5, 58);
tft.setTextSize(1);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("inicializacion");
}
void loop() {
tft.setTextSize(1);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
while (ss.available() > 0) {
gps.encode(ss.read());
if (gps.location.isUpdated()) {
dibujarMarco();
// Latitud y longitud
tft.setCursor(5, 44);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("Latitud: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.location.lat(), 6);
tft.setCursor(5, 58);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("Longitud: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.location.lng(), 6);
// Fecha
tft.setCursor(5, 7);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("fecha: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.date.day()); tft.print(" ");
tft.print(gps.date.month()); tft.print(" ");
tft.print(gps.date.year());
// Hora
tft.setCursor(5, 20);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("hora: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.time.hour()+1); tft.print(" ");
tft.print(gps.time.minute()); tft.print(" ");
tft.print(gps.time.second()); tft.print(" ");
// Altitud actual
tft.setCursor(5, 80);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("H m: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.altitude.meters(), 0);
// Altitud máxima
tft.setCursor(5, 95);
actualizarAltitudMax();
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("Hmax: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(maxhigh);
graficarAltitud();
// Velocidad actual
tft.setCursor(5, 115);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("V act: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.speed.kmph(), 0);
// Velocidad máxima
tft.setCursor(5, 130);
actualizarVelocidadMax();
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("vmax: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(maxspeed);
graficarVelocidad();
// Satélites
tft.setCursor(5, 147);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("Sat: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.satellites.value());
// HDOP
Serial.print("HDOP = ");
Serial.println(gps.hdop.value());
smartDelay(400);
}
}
}
static void smartDelay(unsigned long ms) {
unsigned long start = millis();
do {
while (ss.available()) gps.encode(ss.read());
} while (millis() - start < ms);
}
void dibujarMarco() {
// Dibuja el marco de la pantalla en rojo
tft.drawLine(0,0,130,0,ST7735_RED);
tft.drawLine(0,1,130,1,ST7735_RED);
tft.drawLine(0,158,130,158,ST7735_RED);
tft.drawLine(0,142,130,142,ST7735_RED);
tft.drawLine(0,141,130,141,ST7735_RED);
tft.drawLine(0,107,130,107,ST7735_RED);
tft.drawLine(0,108,130,108,ST7735_RED);
tft.drawLine(80,108,80,140,ST7735_RED);
tft.drawLine(81,109,81,140,ST7735_RED);
tft.drawLine(80,70,80,108,ST7735_RED);
tft.drawLine(81,70,81,108,ST7735_RED);
tft.drawLine(0,159,130,159,ST7735_RED);
tft.drawLine(0,0,0,156,ST7735_RED);
tft.drawLine(1,1,1,157,ST7735_RED);
tft.drawLine(127,0,127,156,ST7735_RED);
tft.drawLine(126,0,126,156,ST7735_RED);
tft.drawLine(0,35,130,35,ST7735_RED);
tft.drawLine(0,36,130,36,ST7735_RED);
tft.drawLine(0,70,130,70,ST7735_RED);
tft.drawLine(0,71,130,71,ST7735_RED);
}
void graficarVelocidad() {
int nuevaValor = map(gps.speed.kmph(), 0, 150, 137, 110);
x++;
tft.drawPixel(x, nuevaValor, ST7735_CYAN);
if (x > 123) {
x = 80;
tft.fillRect(82, 110, 43, 30, ST7735_BLACK);
}
}
void graficarAltitud() {
int nuevaValorh = map(gps.altitude.meters(), 0, 1000, 104, 72);
xh++;
tft.drawPixel(xh, nuevaValorh, ST7735_CYAN);
if (xh > 123) {
xh = 80;
tft.fillRect(82, 72, 43, 35, ST7735_BLACK);
}
}
void actualizarVelocidadMax() {
speed1 = gps.speed.kmph();
if (speed1 > maxspeed) maxspeed = speed1;
}
void actualizarAltitudMax() {
high1 = gps.altitude.meters();
if (high1 > maxhigh) maxhigh = high1;
}
Registrador GPS con guardado en tarjeta SD
#include <SPI.h>
#include <SD.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#define cs 10
#define dc 9
#define rst 8
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, rst);
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;
const int cs_sd = 4;
#define OLED_RESET 5
TinyGPSPlus gps;
SoftwareSerial ss(RXPin, TXPin);
int x = 80, xh = 80;
int maxhigh = 0, maxspeed = 0, speed1 = 0, high1 = 0;
void setup() {
Serial.begin(9600);
ss.begin(GPSBaud);
tft.initR(INITR_GREENTAB);
tft.fillScreen(ST7735_BLACK);
tft.setCursor(5, 58);
tft.setTextSize(1);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("inicializacion");
tft.setCursor(5, 70);
tft.print("init SD");
delay(1000);
if (!SD.begin(cs_sd)) {
tft.setCursor(5, 82);
tft.print("Fallo SD");
return;
}
tft.setCursor(5, 82);
tft.print("Tarjeta SD OK");
delay(1000);
tft.fillScreen(ST7735_BLACK);
File data = SD.open("datos.txt", FILE_WRITE);
data.println("");
data.println("Inicio adquisicion");
data.close();
}
void loop() {
tft.setTextSize(1);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
while (ss.available() > 0) {
gps.encode(ss.read());
if (gps.location.isUpdated()) {
dibujarMarco();
// Latitud y longitud
tft.setCursor(5, 44);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("Latitud: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.location.lat(), 6);
tft.setCursor(5, 58);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("Longitud: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.location.lng(), 6);
// Fecha
tft.setCursor(5, 7);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("fecha: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.date.day()); tft.print(" ");
tft.print(gps.date.month()); tft.print(" ");
tft.print(gps.date.year());
String Fecha = String(gps.date.day()) + " " + gps.date.month() + " " + gps.date.year();
// Hora
tft.setCursor(5, 20);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("hora: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.time.hour()+1); tft.print(" ");
tft.print(gps.time.minute()); tft.print(" ");
tft.print(gps.time.second()); tft.print(" ");
String Hora = String(gps.time.hour()+1) + " " + gps.time.minute() + " " + gps.time.second();
// Altitud
tft.setCursor(5, 80);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("H m: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.altitude.meters(), 0);
tft.setCursor(5, 95);
actualizarAltitudMax();
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("Hmax: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(maxhigh);
graficarAltitud();
// Velocidad
tft.setCursor(5, 115);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("V act: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.speed.kmph(), 0);
tft.setCursor(5, 130);
actualizarVelocidadMax();
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("vmax: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(maxspeed);
graficarVelocidad();
// Satélites
tft.setCursor(5, 147);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("Sat: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.satellites.value());
// HDOP
Serial.print("HDOP = ");
Serial.println(gps.hdop.value());
smartDelay(400);
// Guardar en SD
File data = SD.open("datos.txt", FILE_WRITE);
data.println(Fecha + " " + Hora + " " +
String(gps.location.lat(), 6) + " " +
String(gps.location.lng(), 6) + " " +
String(gps.altitude.meters(), 0) + " " +
String(maxhigh) + " " +
String(gps.speed.kmph(), 0) + " " +
String(maxspeed));
data.close();
}
}
}
// Funciones smartDelay, dibujarMarco, graficarVelocidad, graficarAltitud,
// actualizarVelocidadMax, actualizarAltitudMax idénticas a la versión básica
Esquemáticos
Consulte la imagen del esquemático adjunta para las conexiones detalladas.
Proceso de manufactura
- Construya un Sistema Rápido y Fiable de Detección de Incendios con Samsung SAMIIO, Arduino UNO y Raspberry Pi
- Monitorización en Tiempo Real de Panel Solar con Arduino: Sistema de Adquisición de Datos de Bajo Coste
- Construye un Monitor de Energía y Registrador de Datos Fiable con Arduino – Guía Paso a Paso
- Crea Animaciones y Juegos en LCD 16×2 con Arduino UNO
- Registrador de Temperatura y Humedad con Arduino, DHT11 y Ethernet Shield
- Calculadora Básica con Arduino UNO - Proyecto Fácil para Principiantes
- Construir una pantalla de persistencia de visión portátil con Arduino UNO y ATtiny85
- Módulo GPS u-blox LEA‑6H 02: Guía de integración con Arduino y Python
- Construye un Cubo LED 4x4x4 con Arduino Uno y 1Sheeld – Proyecto LED Interactivo
- Control Arduino UNO desde Python 3 – Envío de Comandos y Demo LED
- Construye una Radio FM Compacta con Arduino Nano y RDA5807M