Получение данных с GPS (GY-NEO-6M)

GPS-модуль NEO-6M даёт:

  • координаты (широта, долгота);

  • высоту над уровнем моря;

  • UTC-время и дату;

  • количество спутников и качество приёма (HDOP).

Это самый «капризный» из всех модулей кубсата — его нужно правильно подключить, дождаться холодного старта и понимать особенности прошивки. Прочитайте раздел «Важно» ниже до того, как приступать к тесту.

Важно: GPS «съедает» Serial Monitor

В кубсате GPS подключён к D0 (RX0) — это аппаратный UART Arduino. На этой же линии работает и USB-канал общения Nano с компьютером (Serial Monitor). Из этого следуют три практически важных последствия:

  1. Скорость UART жёстко 9600 бод. Это естественная скорость NEO-6M (NMEA по умолчанию). И main_full, и gps_sd_logger используют Serial.begin(9600).

  2. Скетчи с GPS почти не пишут в Serial Monitor. Шина занята входящим потоком NMEA — если параллельно выводить отладку, она будет смешиваться с RAW-строками от GPS. Поэтому gps_sd_logger.ino сделан «молчащим»: проверка результата = вынуть SD-карту и прочитать GPSLOG.CSV.

  3. При прошивке нужно физически отсоединять TX-провод GPS от ``D0``. Иначе компьютер и GPS оба пытаются говорить в RX0 Nano — avrdude не может синхронизироваться, выдаёт stk500_getsync().

Примечание

Почему так сделано? SoftwareSerial на Arduino Nano работает, но занимает ~1.5 КБ Flash и съедает прерывания. main_full уже близок к лимиту памяти Nano, и каждый килобайт на счету. Жертвуем удобной отладкой ради того, что сборка вообще помещается.

Workflow перепрошивки

Каждый раз когда вы хотите залить новый скетч на Nano, в котором работает GPS:

  1. Отсоедините белый/жёлтый провод TX модуля GPS от пина D0 Nano. Достаточно вытянуть один провод.

  2. Sketch Upload.

  3. Дождитесь сообщения Done uploading.

  4. Подключите TX-провод GPS обратно в D0.

  5. Нажмите Reset на Nano (или просто переподключите USB) — скетч стартует заново и GPS начнёт отдавать NMEA.

Если попытаться залить с подключённым GPS — почти всегда получите avrdude: stk500_getsync(): not in sync: resp=0x00.

Необходимые библиотеки

  • TinyGPSPlus (Mikal Hart) — парсинг NMEA;

  • SD (встроена в Arduino IDE).

Тестовый скетч: GPS → SD логгер

examples/gps_sd_logger/gps_sd_logger.ino
#include <SPI.h>
#include <SD.h>
#include <TinyGPS++.h>

// ВАЖНО: на Nano GPS TX -> D0 (RX0), поэтому Serial занят GPS.
// Во время прошивки лучше отключать TX GPS от D0.

const uint8_t SD_CS = 4;
const char* LOG_FILE = "GPSLOG.CSV";
const unsigned long LOG_PERIOD_MS = 1000;

TinyGPSPlus gps;
unsigned long lastLogMs = 0;

void writeHeaderIfNeeded() {
  if (SD.exists(LOG_FILE)) return;
  File f = SD.open(LOG_FILE, FILE_WRITE);
  if (!f) return;
  f.println("ms,fix,sats,hdop,lat,lon,alt_m,utc_hhmmss,date_ddmmyyyy,chars,crc_ok,crc_bad");
  f.close();
}

void logRow() {
  File f = SD.open(LOG_FILE, FILE_WRITE);
  if (!f) return;

  f.print(millis());
  f.print(',');
  f.print(gps.location.isValid() ? 1 : 0);
  f.print(',');
  f.print(gps.satellites.isValid() ? (int)gps.satellites.value() : 0);
  f.print(',');
  if (gps.hdop.isValid()) f.print(gps.hdop.hdop(), 1); else f.print('0');
  f.print(',');
  if (gps.location.isValid()) f.print(gps.location.lat(), 6); else f.print('0');
  f.print(',');
  if (gps.location.isValid()) f.print(gps.location.lng(), 6); else f.print('0');
  f.print(',');
  if (gps.altitude.isValid()) f.print(gps.altitude.meters(), 1); else f.print('0');
  f.print(',');
  if (gps.time.isValid()) {
    unsigned long t = gps.time.hour() * 10000UL + gps.time.minute() * 100UL + gps.time.second();
    f.print(t);
  } else {
    f.print('0');
  }
  f.print(',');
  if (gps.date.isValid()) {
    unsigned long d = gps.date.day() * 1000000UL + gps.date.month() * 10000UL + gps.date.year();
    f.print(d);
  } else {
    f.print('0');
  }
  f.print(',');
  f.print((unsigned long)gps.charsProcessed());
  f.print(',');
  f.print((unsigned long)gps.passedChecksum());
  f.print(',');
  f.print((unsigned long)gps.failedChecksum());
  f.println();

  f.close();
}

void setup() {
  // Serial используется только как вход GPS @9600
  Serial.begin(9600);

  SD.begin(SD_CS);
  writeHeaderIfNeeded();
  lastLogMs = millis();
}

void loop() {
  while (Serial.available()) {
    gps.encode(Serial.read());
  }

  unsigned long now = millis();
  if (now - lastLogMs >= LOG_PERIOD_MS) {
    lastLogMs = now;
    logRow();
  }
}

Что он делает:

  • читает поток NMEA с Serial (= с GPS);

  • раз в секунду пишет на microSD строку CSV в файл GPSLOG.CSV.

В Serial Monitor скетч ничего не печатает — Serial занят GPS. Это нормально.

Как запустить и проверить

  1. Соберите кубсат / положите его на улицу или у окна с открытым видом на небо. NEO-6M практически не ловит спутники в помещении.

  2. Залейте gps_sd_logger.ino (не забудьте отключить TX GPS на время заливки!).

  3. Подключите TX GPS обратно. Reset.

  4. Подождите 30 секунд - 5 минут — это «холодный старт» NEO-6M. Если это первое включение модуля или после долгого простоя — могут потребоваться все 5 минут на улице.

  5. Извлеките microSD, вставьте в компьютер, откройте GPSLOG.CSV.

Что должно быть в GPSLOG.CSV

Заголовок и строки лога раз в секунду. Первые секунды (нет fix’а):

ms,fix,sats,hdop,lat,lon,alt_m,utc_hhmmss,date_ddmmyyyy,chars,crc_ok,crc_bad
1010,0,0,0,0,0,0,0,0,1234,15,0
2010,0,0,0,0,0,0,0,0,2456,32,0
3010,0,1,0,0,0,0,0,0,3678,48,0

После того как пойман сигнал (fix=1 и заполнились координаты):

62015,1,7,1.2,52.456789,4.123456,12.5,143012,8052026,205314,1812,3
63015,1,7,1.1,52.456789,4.123456,12.6,143013,8052026,208645,1839,3

Колонки:

  • fix — есть позиционирование (0/1);

  • sats — спутников в решении;

  • hdop — горизонтальная погрешность (меньше = лучше; < 2 — отлично, > 5 — плохо);

  • lat/lon/alt_m — координаты и высота;

  • utc_hhmmss/date_ddmmyyyy — UTC время и дата;

  • chars — сколько байт NMEA скетч получил с модуля (растёт всегда);

  • crc_ok/crc_bad — целостность NMEA-предложений.

Если chars=0 и crc_ok=0

GPS вообще не передаёт ничего на Nano:

  • проверьте, что TX модуля GPS подключён к ``D0`` Nano (после заливки часто забывают воткнуть обратно);

  • индикатор на модуле должен моргать (когда есть связь со спутниками — раз в секунду);

  • проверьте питание 5V и GND модуля.

Если chars растёт, но fix=0 много минут

  • Антенна не на открытом небе — занесите кубсат к окну, ещё лучше на балкон/улицу;

  • Холодный старт после долгого хранения — дайте до 15 минут;

  • Многоэтажки/металлические балконы экранируют сигнал — попробуйте открытое место.