GPS спидометр на NEO-7 и Wemos D1 (ESP8266)

В этой части мы сделаем простой GPS спидометр c возможностью замера времени разгона на базе платы Wemos D1 и модуля VK2828U7G5LF NEO7-M и выведем полученные результаты на OLED дисплей SSD1306.

С этим компонентами по отдельности мы уже научились работать в предыдущих статьях, если вы их до сих пор еще не видели, то настоятельно рекомендую ознакомиться перед прочтениям данного материала: Подключение OLED дисплея SSD1306 к Wemos D1, Подключение U-Blox NEO-7 к Wemos D1.

Подключение

Для начала давайте подключим всё следующим образом:

  1. Соединим дисплей с шиной I2C: VCC -> 3V3, GND -> GND, SCL -> D1, SDA -> D2.
  2. А GPS модуль с программным UART: V -> 3V3, G -> GND, R -> D8, T -> D7.

Спидометр

Напомню, что для максимальной производительности мы будем использовать только протокол UBX. Чтобы не перегружать статью кодом я вывел всю работу по обработке протокола в отдельные файлы, скетч целиком можно будет скачать ниже.

Напишем простой код, который будет выводить на экран текущую скорость.

#include <SSD1306.h>  // Библиотека для работы с дисплеем
#include "UbloxGPS.h" // Библиотека для работы с GPS
#include "font.h"     // Шрифт Orbitron_Light_26
// Инициализируем дисплей подключенный к пинам D2 и D1
SSD1306  display(0x3c, D2, D1);
char gpsSpeed[3];   // Буфер для строки с скоростью
int gpsSpeedKm = 0; // Скорость в км/ч
void setup() {
  serial.begin(115200);
  delay(500);
  gpsSetup(); // Настройка модуля Ublox
  // Первоначальные настройки дисплея
  display.init();
  display.flipScreenVertically();
  display.setTextAlignment(TEXT_ALIGN_CENTER);
  display.setFont(Orbitron_Light_26);
}
void loop() {
  // Обновляем скорость по мере поступления данных от gps модуля
  int msgType = processGPS();
  if (msgType == MT_NAV_PVT) {
    display.clear();
    gpsSpeedKm = ubxMessage.navPvt.gSpeed * 0.0036; // Переводим в км/ч
    sprintf(gpsSpeed, "%03d", gpsSpeedKm);
    display.drawString(64, 22, gpsSpeed);
    display.display();
  }
}

Скачать архив со скетчем: Spedometr.zip

Загрузим его, и попробуем прокатиться.

Немного видео:

Замер разгона

Давайте усложним задачу, добавим замер разгона до 30, 60 и 100 км/ч.

Алгоритм предельно простой:

  1. Ждем когда начнется движение
  2. Замеряем время старта
  3. При достижении определённой скорости вычитаем из текущего времени время старта и сохраняет результат
#include <SSD1306.h>  // Библиотека для работы с дисплеем
#include "UbloxGPS.h" // Библиотека для работы с GPS
#include "font.h"     // Шрифт Orbitron_Light_26
// Инициализируем дисплей подключенный к пинам D2 и D1
SSD1306  display(0x3c, D2, D1);
char gpsSpeed[3];       // Буфер для строки с скоростью
int gpsSpeedKm = 0;     // Скорость в км/ч
bool start = false;     // Старт замера
long startMillis = 0;   // Начало отсчета
long currentMillis = 0; // Текущее время
float meteringTime = 0; // Время замера
// Cтруктура результатов
struct Metering
{
  float accel30;
  float accel60;
  float accel100;
};
Metering metering;
void setup() {
  serial.begin(115200);
  delay(500);
  gpsSetup();                 // Настройка модуля Ublox
  metering = {0.0, 0.0, 0.0}; // Тут будем хранить результаты
  // Первоначальные настройки дисплея
  display.init();
  display.flipScreenVertically();
  display.setTextAlignment(TEXT_ALIGN_CENTER);
  display.setFont(Orbitron_Light_26);
}
int loops = 0;
void loop() {
  currentMillis = millis(); // текущее время в миллисекундах
  int msgType = processGPS();
  if (msgType == MT_NAV_PVT) {
    //loops++;
    gpsSpeedKm = ubxMessage.navPvt.gSpeed * 0.0036; // Переводим в км/ч
    //gpsSpeedKm = loops;
    // Если движемся
    if (gpsSpeedKm > 0) {
      // Если это был старт
      if (!start) {
        start = true;
        startMillis = millis();
      }
      meteringTime = (float)(currentMillis - startMillis) / 1000; // Время замера
      // Результаты замера
      if (0.0 == metering.accel30 && gpsSpeedKm >= 30) {
        metering.accel30 = meteringTime; // Разгон до 30км/ч
      }
      else if (0.0 == metering.accel60 && gpsSpeedKm >= 60) {
        metering.accel60 = meteringTime; // Разгон до 60км/ч
      }
      else if (0.0 == metering.accel100 && gpsSpeedKm >= 100) {
        metering.accel100 = meteringTime; // Разгон до 100км/ч
      }
    }
    else if (start && 0 == gpsSpeedKm) { // Если остановились
      start = false;
    }
    updateDisplay();
  }
}
void updateDisplay() {
  display.clear();
  // Выводим скорость
  display.setTextAlignment(TEXT_ALIGN_CENTER);
  display.setFont(Orbitron_Light_26);
  sprintf(gpsSpeed, "%03d", gpsSpeedKm);
  display.drawString(44, 22, gpsSpeed);
  // Разгон до 30 км/ч
  display.setTextAlignment(TEXT_ALIGN_RIGHT);
  display.setFont(ArialMT_Plain_16);
  display.drawString(122, 10, (String)metering.accel30);
  // Разгон до 60 км/ч
  display.setTextAlignment(TEXT_ALIGN_RIGHT);
  display.setFont(ArialMT_Plain_16);
  display.drawString(122, 24, (String)metering.accel60);
  // Разгон до 100 км/ч
  display.setTextAlignment(TEXT_ALIGN_RIGHT);
  display.setFont(ArialMT_Plain_16);
  display.drawString(122, 38, (String)metering.accel100);
  display.display();
}

Скачайте архив со скетчем и загрузите его в ваш Wemos D1: Spedometr2.zip

Теперь отправляемся на ровный безлюдный участок дороги и проводим тестовый замер.

ВНИМАНИЕ: Я настоятельно рекомендую соблюдать правила ПДД и СКОРОСТНОЙ РЕЖИМ, все действия производятся на Ваш страх и риск, а статья предоставлена исключительно в ознакомительных целях и автор никакой ответственности не несёт.

Вот мой результат разгона, по моему неплохо для "овоща". ))


На этом всё, до скорых встреч!