Leniwce.com | blog technologiczny
GPS w lekkostrawnym sosie podany
Kuba Krakowski, 2009-08-05 22:30:00
kategoria: C#, Inne

Prawdopodobnie znakomita większość z nas słyszała o systemie lokalizacji GPS. Biorąc pod uwagę jego rosnącą popularność bardzo możliwe, że już korzystaliśmy z jego usług w praktyce - dziś nawigacja samochodowa nie stanowi luksusu, a wiele popularnych modeli palmtopów / telefonów komórkowych posiada wbudowane odbiorniki gps. Jeśli nawet nasze urządzenie nie posiada takowego, to zawsze można podłączyć je poprzez interfejs bluetooth lub usb (odbiorniki takie można kupić już za kilkadziesiąt złotych).
W tym krótkim atykule chciałbym pokazać, jak, z punktu widzenia programisty, możemy odczytać informacje zawarte w sygnale gps.

 

Co jemy...

Wystarczy zapytać google'a o gps, żeby przekonać się o olbrzymiej ilości informacji na ten temat. W największym możliwym skrócie: jest to system pozwalający ustalić, z dokładnością rzędu metrów, pozycję odbiornika na Ziemi. Zainteresowanym polecam na początek lekturę Wikipedii oraz tego tekstu przystępnie wyjaśniającego działanie systemu. Szukających bardziej technicznych informacji powinien zadowolić ten artykuł.

Czym...

Na początek musimy dysponować odbiornikiem sygnału gps. W moim przypadku użyłem modelu gm720 firmy Navibe podłączanego do komputera przez port usb.

Niezależnie od sposobu podłączenia (wewnętrzny, bluetooth czy usb) odbiornik komunikuje się z komputerem przez wirtualny port szeregowy (COM). W C# obsługa portów szeregowych zawarta jest w System.IO.Ports.
Zgromadzimy teraz kilka informacji o parametrach połączenia. W przypadku komputera sprawdzamy to uruchamiając Menadżera Urządzeń i wyszukując na liście porty COM.

Dzięki temu znamy już nazwę portu. W jego właściwościach znajdziemy kolejne potrzebne parametry.

Informacje te są potrzebne do utworzenia obiektu klasy SerialPort, którego jeden z konstruktorów jest następujący:

 
public SerialPort(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
 

a przykładowe wywołanie może mieć postać:
 
SerialPort port = new SerialPort("COM13", 9600, Parity.None, 8, StopBits.One);
 

Wystarczy teraz ten port otworzyć:
 
port.Open();
 

i odczytywać dane, które z niego napływają:
 
string dane = port.ReadExisting();
 

Jeśli poprawnie skonfigurowaliśmy port, to powinniśmy otrzymać dane w rodzaju tych przedstawionych na obrazku niżej:

Wiemy już, czym ugryźć nadawany sygnał, a teraz pora dowiedzieć się...

Jak...

Mimo, że symbole powyżej wyglądają dość enigmatycznie, to tak naprawdę są nadawane wg ustalonego standardu, który nazywa sie NMEA i jego opisy można znaleźć np. tu lub szczegółowiej tu.
Nam wystarczą informacje, że

  • każda linia zaczyna się od znaku '$', po którym następuję nazwa nagłówka (np. GPGGA) określającego rodzaj informacji w danej linii;
  • dlugość linii nie przekracza 80 znaków;
  • dane oddzielone są znakiem przecinka;
  • liczby mogą posiadać część ułamkową (po przecinku) o nieustalonej z góry liczbie cyfr;
  • na końcu linii może występować suma kontrolna w postaci *dwucyfrowa liczba szesnastkowa, której możemy użyć do sprawdzenia poprawności odczytanych danych.

Opis wszystkich nagłówków i znaczenie danych po nich występujących są podane w linkach powyżej. Nas interesować będą dwa: GPGGA oraz GPRMC.
Najlepiej opisać je będzie na przykładach (wypisując tylko dane użyte w przykładowej aplikacji):

GPGGA:

 
$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
 

Gdzie:

  • GPGGA - nazwa nagłówka;
  • 123519 - czas UTC 12:35:19, kiedy określono poprawnie ostatnią pozycję;
  • 4807.038,N - szerokość geograficzna w formacie 48 stopni 07.038 minut N;
  • 01131.000,E - długość geograficzna w formacie 011 stopni 31.000 minut E;
  • 1 - określa jakoś ustalenia pozycji: 0- brak, 1- poprawna (=potoczne: jest fix), 2- ustalona przy pomocy DGPS;
  • 08 - ilość śledzonych satelitów;
  • 0.9 - pozioma dokładność wyznaczenia pozycji (tzw. HDOP) - im mniejsza, tym lepsza dokładność.

GPRMC:

 
$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
 

Gdzie:

  • GPRMC - nagłówek;
  • A - status pozycji: V- brak fixa, A- pozycja ustalona (jest fix);
  • 022.4 - prędkość w węzłach (należy pomnożyć przez 1.852, aby otrzymać wynik w km/h).

 

Przykład wykorzystania

Na potrzeby artykułu napisałem prostą aplikację, która pobiera dane z odbiornika, odczytuje interesujące nas informacje, formatuje i wyświetla na ekranie, dodatkowo umożliwiając pokazanie odczytanej pozycji na Google Maps. Źródła projektu można pobrać stąd. Starałem się dobrze okomentować kod, więc jego działanie powinno być dość jasne. Wspomnę tylko, że sercem aplikacji przetwarzającym dane jest funkcja:

 
void parseNMEA(string data)
 

,którą wywołujemy cyklicznie korzystając z timera:
 
 private void timer1_Tick(object sender, EventArgs e)
 {
     //odczyt danych z portu szeregowego
     string dane = port.ReadExisting();
     parseNMEA(dane);
  }
 

Na urządzeniach mobilnych z systemem Windows Mobile obsługa sygnału gps wygląda właściwie tak samo - trzeba tylko zadbać o odpowiednią konfigurację portu.

Okno przykładowej aplikacji:

 

oraz lokalizacja zobrazowana dzięki Google Maps:

 

Pod tym linkiem dostępna jest wersja demonstrująca możliwość wyznaczania tras w Google Maps.

Powiązane artykuły
Atraktor Lorenza (2011-08-29)
O związku motyli z pogodą... (2011-08-26)
Równoległy może więcej(?) - czyli kilka słów o Parallel.For (2011-02-06)
Święta, święta - czas pochwalić się (fraktalną) choinką (2010-12-25)
Własny wygaszacz ekranu (2010-06-03)
3.1415926535897932385... (2010-05-19)
Metody rozszerzające (2010-05-07)
Wszechświat na ekranie, czyli słowo o skalowaniu (2009-07-15)
OleDbConnection – Excel jako baza danych(C#) (2009-07-13)
Animacje 3D (OpenGL) (2009-07-05)


Komentarze


Łukasz [2009-08-10 15:05:18]
Cześć,

Ciekawy artykuł, zauważyłem jednak błąd dot. interpretacji danych odbieranych z portu. Piszecie że: 'liczby mogą posiadać część ułamkową (po przecinku) o nieustalonej z góry liczbie cyfr;' - tu jest błąd, bo część ułamkową gdzie separatorem jest kropka, skoro kolejne dane oddzielone są przecinkiem. No ale to drobiazg :)

Pozdrawiam,
Łukasz
Bartek [2009-08-11 11:54:20]
Kubo, a da się wyznaczyć trasę w google maps?
Kuba [2009-08-17 11:37:35]
Tak - dość naiwny (ale działający) sposób przedstawiłem w poprawionym projekcie, do którego link dodałem na końcu artykułu. Trasa liczona jest od bieżącej pozycji gps do podanego przez użytkownika adresu.

Dodaj komentarz:
Autor:*

WWW:

Treść:*

Wprowadź kod zabezpieczający*:


        * - pola wymagane
Kategorie
C# (13)
Inne (6)
Java (3)
Matlab (1)
OpenGL (1)
PHP (2)


Najnowsze wpisy

Ostatnie komentarze