Programování | Pojďme programovat elektroniku | GPS

Pojďme programovat elektroniku: Postavíme si vlastní turistickou GPS

  • Moje první GPS stála deset tisíc korun
  • Dnes poskládám novou za pětistovku
  • Bude mít OLED, vydrží celý den a trasu uloží do GPX

V roce 2003 jsem si pořídil svoji první turistickou GPS. Tehdejší eTrex Legend od Garminu patřil k těm nejpopulárnějším modelům, byl totiž relativně levný, jednoduchý, ale přesto s rozměrným displejem, na kterém bylo možné zobrazit alespoň primitivní mapu. Horší to už ale bylo s pamětí, která se omezovala jen na několik málo zaznamenaných tras.

Postavíme si vlastní GPSku za pár stovek

Amatérské GPSky za tu dobu udělaly obrovský skok vpřed počínaje samotným přijímačem, jeho přesností, rychlostí, podporou nejrůznějších satelitních technologií nebo spotřebou a konče cenou. GPS dnes najdete v každém chytrém telefonu za pár tisíc a stejně tak na eBay ve formě základních modulů pro Raspberry Pi, Arduino a další stavebnice.

Dnes se tedy podíváme na prototypovací moduly GPS, se kterými se ve světě Arduina pracuje velmi jednoduše, přijímače totiž komunikují skrze sériovou linku.

230737192 996175607
Levný švýcarský GPS přijímač Ublox Neo-6M s typickou anténou na čínské prototypovací destičce se čtveřicí napájecích a RX/TX pinů pro sériovou komunikaci

Já si pořídil starší model Neo-6M (dokumentace v PDF) od švýcarského Ubloxu, jehož cena na čínských prototypovacích destičkách včetně antény začíná okolo dvou stovek. V obálce vám dorazí plošný spoj s piny sériového rozhraní UART a typická anténa GPS.

GPSka na nás vykřikuje věty NMEA

Samotný přijímač je už od výroby nakonfigurovaný takovým způsobem, že stačí otevřít sériové spojení rychlostí 9 600 bps a Ublox krátce poté začne zasílat údaje v textovém formátu NMEA (National Marine Electronics Association).

842647714 497163267
Připojil jsem GPS přijímač pomocí UART převodníku k USB notebooku a sériový monitor se okamžitě začal plnit větami protokolu NMEA

Ten obrázek výše s výpisem dat je docela guláš, viďte? NMEA se totiž skládá z tzv. vět (řádků) a dílčích hodnot oddělených čárkou. Podívejte se na obrázek výše ještě jednou a zkuste najít třeba větu, která začíná identifikátorem $GPGGA. Jedná se o jednu z hlavních vět (Global Positioning System Fix Data), ze které lze vyčíst prakticky vše k samotné poloze.

Může vypadat třeba takto:

$GPGGA,201946.00,4913.91692,N,01635.34344,E,1,04,1.58,269.9,M,42.4,M,,*55

Tučně jsem vyznačil postupně přesný čas z atomových hodin systému GPS, poté zeměpisnou šířku, zeměpisnou délku a nadmořskou výšku.

  • 201946.00 = 20:19:46 GMT
  • 4913.91692,N = 49° 13,91692' s.š.
  • 01635.34344,E = 16° 35,34344' v.d.
  • 269.9,M = 269,9 m n.m.

V dalších větách NMEA jsou pak uložené údaje o jednotlivých satelitech, od kterých přijímáme signál, ještě přesnější čas a datum, rychlost a azimut pohybu, odchylka a případně další informace, které nemusí podporovat každý přijímač. NMEA věty jsou tedy zpětně kompatibilní. Zatímco naprosto každá GPSka bude podporovat větu $GPGGA, některé exotické a proprietární věty třeba s nejrůznějšími korekcemi a výpočty naopak jen sofistikovanější přijímače.

Švýcarský výrobce si dal záležet a vedle samotného čipu nabízí volně ke stažení i aplikaci U-center pro kompletní GPS monitoring. Aplikace se s přijímačem spojí opět skrze sériovou linku a pomocí vět NMEA, nebo vlastního protokolu UBX, načte z přijímače vše, co jen dokáže zjistit.

833164682 199634574
U-center od švýcarského Ubloxu je téměř dokonalý správce pro management GPS přijímačů komunikujících nejen na protokolu NMEA

Takže si to spočítejme. Utratil jsem dvě stovky za přijímač Ublox připájený na destičce s piny pro snadnou komunikaci skrze sériovou linku. S PC mohu přijímač propojit pomocí jakéhokoliv Arduina nebo USB/UART převodníku (okolo padesátikoruny) a zdarma si budu moci stáhnout propracovaného správce U-center.

Takže za 250-300 kaček získáte z eBaye apod. kompletní řešení pro záznam trasy třeba pomocí notebooku.

Nicméně náš seriál se jmenuje Pojďme programovat elektroniku, a tak Ublox připojíme opravdu spíše k tomu Arduinu a postavíme si vlastní přijímač s displejem.

TinyGPS++ za nás přelouská věty NMEA

Čím začít? Samozřejmě luštěním vět NMEA. Internet je naštěstí plný C/C++ knihoven nejen pro Arduino. K těm nejzdařilejším patří TinyGPS++, která veškerou špinavou práci udělá za nás, a my ji pouze nakrmíme daty ze sériové linky.

Dejme tedy tomu, že bych modul GPS přijímače připojil k napájení (3,3-5V/GND) a jeho UART piny RX a TX na piny 3 a 2 na Arduinu.

Kód, který by pak skrze sériovou linku vypisoval v PC čerstvou GPS polohu, by mohl s využitím vestavěné knihovny SoftwareSerial vypadat třeba takto:

#include <SoftwareSerial.h>
#include <TinyGPS++.h>

// GPS prijimac pripojeny na piny 2 (GPS TX) a 3 (GPS RX)
SoftwareSerial gpsModul(2, 3);
TinyGPSPlus gps;

// Funkce setup se spusti pri startu
void setup() {
  // Spusteni seriove linky do PC a GPS prijimace
  Serial.begin(9600);
  gpsModul.begin(9600);
}

// Funkce loop se stale opakuje
void loop() {
  // Pokud z GPS prichazeji nejaka data, posli je do knihovny TinyGPS++
  if (gpsModul.available()) {
    gps.encode(gpsModul.read());
  }

  // Pokud knihovna nasla polohu, vypis ji od seriove linky
  if ((gps.location.isUpdated()) && (gps.altitude.isUpdated())) {
    Serial.print("Zemepisna sirka: ");
    Serial.println(gps.location.lat(), 6);
    Serial.print("Zemepisna delka: ");
    Serial.println(gps.location.lng(), 6);
    Serial.print("Nadmorska vyska: ");
    Serial.println(gps.altitude.meters());
  }
}

Jednoduché jako facka, že? Podobným způsobem mohu z knihovny získat cokoliv, co obsahují věty NMEA. Pokud některé hodnoty sama knihovna nepodporuje, mohu ji přikázat, ať získá n-tou hodnotu z konkrétní věty, takže parser knihovny TinyGPS++ mohu použít i na exotičtější údaje.

Při dekódování informací musím myslet jen na jednu věc. GPS přijímač posílá Arduinu věty průběžně a knihovna je také průběžně porcuje na kousky a průběžně se plní údaji. Proto je naprosto klíčová podmínka isUpdated().


Arduino proměnilo smršť NMEA vět v čitelný výstup, který se opět vypisuje v sériové lince, jakmile GPS přijímač vypočítá novou polohu

V kódu výše pomocí ní ověřuji, jestli už knihovna obdržela údaje o poloze a nadmořské výšce. Kdybych ale ověřil jen existenci nové polohy (gps.location.isUpdated), do sériové linky by se mohla poslat nadmořská výška s nulovou hodnotou, protože údaj o poloze může být součástí věty, která však neobsahuje nadmořskou výšku. Proto v kódu čekám, až budu mít zaručeně všechny tři hodnoty.

Podobným způsobem bych si mohl počkat, až knihovna získá další praktické údaje. Třeba:

  • Odchylka/HDOP: gps.hdop.value()
  • Počet viditelných satelitů: gps.satellites.value()
  • Rychlost v km/h: gps.speed.kmph()
  • Kurz: gps.course.deg()
  • Rok: gps.date.year()
  • Měsíc: gps.date.month()
  • Den: gps.date.day()
  • Hodina: gps.time.hour()
  • Minuta: gps.time.minute()
  • Sekunda: gps.time.second()

Kolik to vlastně žere?

Přijímač Ublox je ve výchozím továrním nastavení konfigurovaný na nejlepší příjem. NMEA zprávy chodí prakticky neustále a knihovna TinyGPS++ vyplivne nový fix zhruba každou sekundu. V této konfiguraci si model NEO-6M podle manuálu řekne o 39 mA, přičemž během studeného startu, kdy se čeká na první fix, může odběr proudu vystřelit až na 47 mA.

Vyjma tohoto režimu max performance mode nabízí Ublox ještě eco mode (37 mA) a power save mode (11 mA).

592735516 394521183
Mozkem mé GPSky bude drobné Arduino Pro Mini s taktem 8 MHz a pracovním napětím 3,3V. Má totiž minimální spotřebu.

Jelikož jsem GPS přijímač připojil k maličkému Arduino Pro Mini s taktem 8 MHz, jehož aktivní odběr proudu se pohybuje okolo 5 mA, a jako zdroj energie použil Li-Ion baterii ze starého telefonu (2 745 mAh), podle kalkulačky jsem se dostal (za ideálních podmínek) na dvoudenní výdrž GPS i bez jakéhokoliv úsporného režimu.

Data budu ukládat na SD ve formátu GPX

Jenže musím také někam data ukládat. Pokud by bylo maličké Arduino připojené k PC, baterie nebude potřeba, USB totiž dodá dostatečný proud. K mikropočítači jsem tedy připojil další modul – tentokrát destičku se slotem na microSD kartu.

656501020 927649983
Modul SD čtečky Catalex s rozhraním SPI

Se čtečkami karet microSD se zpravidla komunikuje skrze rychlejší rozhraní SPI, jehož jedinou nevýhodou je snad pouze to, že spotřebuje čtyři drahocenné piny na drobném Arduinu. V každém případě, s využitím knihovny SdFat pak můžeme hodnoty z GPS přijímače ukládat třeba do textového souboru – ideálně ve formátu GPX, se kterým si rozumí každý mapový software a od relativně nedávné doby i Mapy.cz.

Takto by mohl vypadat ukázkový kód základní práce s knihovnou SdFat:

#include <SPI.h>
#include "SdFat.h"

SdFat SD;
File soubor;

void setup() {
  // Spusteni seriove linky do PC
  Serial.begin(9600);
  /* Spusteni SD. V pripade chyby zastav dalsi zpracovavani programu.
    Duvodem chyby muze byt nizke napeti, spatne zapojene piny rozhrani
    SPI, spatne naformatovana SD karta (musi byt FAT) aj.
    Cislo 9 oznacuje pin na Arduinu, do ktereho jsem pripojil pin SS/CS na modulu SD ctecky
  */
  if (!SD.begin(9)) {
    Serial.println("Chyba SD karty! Zastavuji program.");
    while (1);
  }

  // Pokusim se otevrit/vytvorit soubor
  soubor = SD.open("soubor.gpx", FILE_WRITE);
  if (!soubor) {
    Serial.println("Chyba souboru! Zastavuji program.");
    while (1);
  }
  else {
    // Pokud vse probehlo v poradku, ulozim do souboru radek textu a zavru jej
    soubor.println("Muj prvni radek v mem prvnim souboru na me prvni microSD!");
    soubor.close();
  }
}

// Smycka loop je prazdna, program tedy konci
void loop() {
  ;
}

GPX je vlastně XML soubor, nejprve je tedy třeba do souboru uložit rozměrnou hlavičku a jednotlivé uzly trasy pak v tomto formátu:

<trkpt lat="49.231948" lon="16.391448"><ele>267</ele><time>2017-04-01T17:59:00Z</time></trkpt>

Řádek postupně obsahuje zeměpisnou šířku, zeměpisnou délku, nadmořskou výšku v metrech a datum a čas na nultém poledníku (GMT).

975586173
Kompletní GPX soubor s trasou o čtyřech uzlech

A jéje, dochází mi RAM

Zatímco na webu a velkých počítačích není XML a obecně text žádnou překážkou, ve světě drobných arduin, která mají k dispozici jen pár kB operační paměti, je každý textový znak přítěží. Vždyť jen ten řádek výše zabírá 93 bajtů!

V takových chvílích programátor ocení třeba makro F() a klíčové slovo PROGMEM, pomocí kterých lze některé neměnné proměnné uložit do flashové paměti, kde je uložený samotný program a která je větší (v tomto případě 32 kB), namísto SRAM (2 kB), která tak zbude pro důležitější věci.

Když bych tedy napsal třeba:

Serial.println("Ahoj, jak se mas?");

Text „Ahoj, jak se mas“ se po spouštění programu nahraje jako proměnná do operační paměti RAM. Pokud však napíšu:

Serial.println(F("Ahoj, jak se mas?"));

Statický text se uloží do flashové paměti programu a ušetří drahocenný prostor v RAM.

Podobným způsobem jsem tedy mohl do flashové paměti mikrokontroleru ATmega328 uložit celou hlavičku GPX souboru, která je pokaždé stejná, a ušetřil jsem tak dobrých 300 bajtů.

Výborně, takže nyní může Arduino přijímat informace z GPS a třeba každých pět sekund je ukládat do GPX souboru. Stejně tak bych mohl měřit vzdálenost mezi dvěma GPS fixy a ukládat ten nový pouze v případě, že se změnila poloha alespoň o deset metrů. Meze v optimalizaci se v tomto případě už opravdu nekladou a knihovna TinyGPS++ má pro tyto účely metodu distanceBetween.

A ještě malý OLED, který nahradí živý výpis do sériové linky

Co tomu teda ještě chybí? Displej! Na podzim jsme si v našem seriálu ukázali poměrně rozšířený 0,96“ OLED displej s ovladačem SSD1306 a rozlišením 128×64 pixelů. Jelikož na OLED svítí pouze aktivní pixely a nenajdete tu žádné plošné podsvícení, může se pochlubit relativně nízkou spotřebou (odvíjí se podle toho, kolik pixelů svítí; průměrně okolo 20 mA). To se nám hodí.

Bohužel jsem ale nemohl použít knihovnu z podzimního příkladu, protože by už spotřebovala veškerou RAM a to i při sebevětší úspoře. Při pokusu o přeložení programu mi prostředí Arduino napsalo, že mi chybí 64 bajtů RAM.

911038972 160679758
Drobný 0,96" OLED s rozlišením 128×64 pixelů a rozhraním I2C

Přesně pro tyto případy je tu naštěstí silně odtučněná textová verze knihovny SSD1306Ascii, která je určená pouze pro psaní textu (k dispozici je hromada rastrových písem) a co je nejdůležitější, oproti plnotučné knihovně zabere v SRAM mikrokontroleru pouhý zlomek paměti. Rázem mi po spuštění programu zbylo v RAM celých 600 B. Vzhledem k využití šesti různých knihoven (SPI, SdFat, TinyGPS++, SoftwareSerial a SSD1306Ascii/Wire) to není až tak špatné.

A to je celé. Kompletní kód vám tentokrát neukážu, je totiž už přeci jen rozsáhlejší a článek by se proměnil v nekonečnou nudli. Nicméně vycházím z citovaných knihoven a příkladů a v principu se nejedná o nic složitého.

Takže jak to nakonec celé funguje?

Jakmile bude Arduino pod napětím (spínač), na OLED se zobrazí uvítací obrazovka. Po získání první polohy (GPS fix) se vypíšou na displej souřadnice, nadmořská výška a počet viditelných satelitů. Tento údaj se aktualizuje každých pět sekund. Častěji ne, displej je totiž k Arduinu připojený na pomalejší sběrnici I2C a překreslení tedy trvá několik desítek milisekund. Displej by prostě neustále problikával.

729441992 524155833 597591757 210253845
Jedno sobotní odpoledne, malé Arduino, GPS přijímač, OLED displej, SD čtečka a zdroj energie... A vyrobíte si vlastní GPS logger.

Na nepájivém poli je vedle Arduina a microSD modulu také tlačítko. Když na něj klepnu, spustí se (nebo naopak zastaví) nahrávání trasy do GPX. Pokaždé se přitom vytvoří nový soubor pojmenovaný časovým údajem (mmddhhmm.gpx). Jakmile je nahrávání aktivní, na displeji se začne zobrazovat celková vzdálenost nejprve v metrech a posléze v kilometrech.

IMG_20170402_151757.jpg IMG_20170402_152233.jpg 323189089
Prototypovací začátky jsou těžké. Jako schránka pro živý test musí poslouží třeba obal od zmrzliny. Výsledný GPX soubor je však stejně přesný jako z leckteré sportovní aplikace.

A to už je opravdu vše. Suma sumárum, s trochou píle a pětistovkou na účtu si vytvoříte funkční a docela přesný GPS logger s vlastním displejem. Pak už budete potřebovat jen dvě věci: 3D tiskárnu, na které si vyrobíte hezkou krabičku na míru, a tištěný spoj, kterým nahradíte rozměrné nepájivé pole s hromadou drátků. Buď si jej vyrobíte sami, anebo to za vás udělají jiní – třeba plosnaky.cz.


Ach, málem bych zapomněl. Modul SD čtečky a OLED displeje se samozřejmě podepsaly na spotřebě, výdrž na baterii tedy klesla z dvou dnů asi na jeden bez jakéhokoliv úsporného režimu a při neustálém zaměřování polohy a svítícím displeji. Dokáže to vaše GPSka?

Diskuze (38) Další článek: Létající kombinéza ve stylu Iron Mana má několik tryskových motorů

Témata článku: , , , , , , , , , , , , , , , , , , , , , , , ,