Продвинутый GPS-логгер данных: отслеживание полёта в реальном времени, пиковая высота и скорость
Компоненты и материалы
| Компонент | Количество |
|---|---|
| Arduino UNO | 1 |
| Набор перемычек (Busbar), комплект соединительных проводов | 1 |
| Arduino Proto Shield | 1 |
| TFT SPI LCD-экран 1.8" с разъёмом для MicroSD (или другой экран со слотом для SD-карты) | 1 |
| GPS-модуль u-blox NEO-6M | 1 |
Необходимые инструменты
- Паяльник
- Посуд для пайки (бесоловянный припой)
- Стриппер и кусачки для проводов 18-10 AWG / 0.75-4 мм²
О проекте
Введение
Я увлекаюсь авиамоделированием и хочу знать скорость и высоту полёта своих моделей. К сожалению, промышленные GPS-логгеры стоят очень дорого.
Поэтому я решил собрать свой GPS-логгер на базе Arduino за менее чем 50 €.
Первый прототип основан на Arduino Uno R3, экране Sainsmart ST7735 со встроенным слотом для SD-карты и GPS-модуле NEO-6M V2.
Во второй версии планируется использовать Arduino Nano, OLED-экран SSD1306, тот же GPS-модуль и microSD-карту. Вес в корпусе составит около 40 г, размеры — 50×30×22 мм, что позволит легко разместить устройство в модели среднего размера. Этот проект в разработке (жду комплектующие).
Тестирование
Снять работу экрана Arduino в движущейся машине непросто, но мне это удалось — результат на видео.
Следующее тестирование пройдёт с новым компактным прототипом на радиоуправляемой модели. Продолжение следует!
Программный код
Основной скетч GPS-логгера
#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;
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("Initialization");
}
void loop() {
tft.setTextSize(1);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
while (ss.available() > 0) {
gps.encode(ss.read());
if (gps.location.isUpdated()) {
drawFrame();
// Координаты
tft.setCursor(5, 44);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("Latitude: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.location.lat(), 6);
tft.setCursor(5, 58);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("Longitude: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.location.lng(), 6);
// Дата
tft.setCursor(5, 7);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("Date: ");
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());
// Время
tft.setCursor(5, 20);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("Time: ");
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(" ");
// Высота
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.print(" ");
tft.setCursor(5, 95);
updateMaxAltitude();
tft.print("Hmax: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(maxhigh); tft.print(" ");
drawAltitudeGraph();
// Скорость
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.print(" ");
tft.setCursor(5, 130);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
updateMaxSpeed();
tft.print("Vmax: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(maxspeed); tft.print(" ");
drawSpeedGraph();
// Спутники
tft.setCursor(5, 147);
tft.setTextColor(ST7735_GREEN, ST7735_BLACK);
tft.print("Satellites: ");
tft.setTextColor(ST7735_CYAN, ST7735_BLACK);
tft.print(gps.satellites.value()); tft.print(" ");
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 drawFrame() {
// Рисуем рамки и разделители на экране
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 drawSpeedGraph() {
int newValue = map(gps.speed.kmph(), 0, 150, 137, 110);
x++;
tft.drawPixel(x, newValue, ST7735_CYAN);
if (x > 123) {
x = 80;
tft.fillRect(82, 110, 43, 30, ST7735_BLACK);
}
}
void drawAltitudeGraph() {
int newValue = map(gps.altitude.meters(), 0, 1000, 104, 72);
xh++;
tft.drawPixel(xh, newValue, ST7735_CYAN);
if (xh > 123) {
xh = 80;
tft.fillRect(82, 72, 43, 35, ST7735_BLACK);
}
}
void updateMaxSpeed() {
speed1 = gps.speed.kmph();
if (speed1 > maxspeed) maxspeed = speed1;
}
void updateMaxAltitude() {
high1 = gps.altitude.meters();
if (high1 > maxhigh) maxhigh = high1;
}
Версия с записью на 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("Initialization");
tft.setCursor(5, 70);
tft.print("SD init");
delay(1000);
if (!SD.begin(cs_sd)) {
tft.setCursor(5, 82);
tft.print("SD Error");
return;
}
tft.setCursor(5, 82);
tft.print("SD OK");
delay(1000);
tft.fillScreen(ST7735_BLACK);
File data = SD.open("donnees.txt", FILE_WRITE);
data.println("");
data.println("Start logging");
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()) {
drawFrame();
// ... (отображение данных аналогично первому скетчу) ...
// Запись на SD
String Date = String(gps.date.day()) + " " + gps.date.month() + " " + gps.date.year();
String Time = String(gps.time.hour() + 1) + " " + gps.time.minute() + " " + gps.time.second();
File data = SD.open("donnees.txt", FILE_WRITE);
data.println(Date + " " + Time + " " +
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();
smartDelay(400);
}
}
}
// Функции drawFrame, drawSpeedGraph, drawAltitudeGraph, updateMaxSpeed, updateMaxAltitude, smartDelay
// идентичны первому варианту.
Схема подключения
Схема подключения компонентов показана на изображении ниже.
Производственный процесс
- Создание быстрой надежной системы обнаружения пожара с Samsung SAMI, Arduino UNO и Raspberry Pi
- Мониторинг солнечной панели в реальном времени: дешёвая система сбора данных на Arduino и Excel
- Создание надежного монитора энергии и логгера данных на Arduino — пошаговое руководство
- Создание анимации и игр на LCD 16×2 с Arduino UNO
- Логгер температуры и влажности на Arduino с DHT11 и Ethernet Shield
- Простой калькулятор на Arduino UNO — базовый проект для начинающих
- Сборка портативного дисплея на основе эффекта сохранения изображения с Arduino UNO и ATtiny85
- Модуль GPS u-blox LEA-6H 02: Интеграция с Arduino и Python
- Создание интерактивного 4x4x4 светодиодного куба на Arduino Uno и 1Sheeld
- Управление Arduino Uno из Python 3: команды через последовательный порт и демонстрация с LED