본문 바로가기
dev, tech/navigation

스마트폰(PDA) 이용한 차량용 HUD 만들기 #3 - GPS 신호 수신

by 구띵 2008. 9. 1.
 

GPS 신호를 수신하기 전에 GPS 신호에 대해 간략하게 한번 알아보자.


GPS 에서 제공하는 데이터는 NMEA(The National Marine Electronic Association) code 로 전송되는데, 원래 바다에서 배의 위치를 확인하기 위해 이용되던 녀석이 육지로도 올라와서 차량용 네비게이션등에 활용중이란다.


맞보기로 어떤 녀석들을 보내주는지 데이터를 한번 살펴 보자.


$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
$GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39
$GPGSV,2,1,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75
$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A

일단 위 GPS 데이터는 Ascen GPS Logger(51CH.) 을 기준으로 나타냈으나, 시중의 다른 GPS 수신기들은 위 데이터외에 다른 데이터가 더 들어갈 수 있음을 미리 알아두자. 그럼 다른 데이터들도 모두 알아야 하느냐~?

그건 아니다.  결론을 먼저 이야기 하자면 위 신호중 우리는 $GPRMC 부분만을 사용할 것이다.


뭔가 잔뜩 들어가 있다.. @_@ 도대체 뭔 소린지는 아래에서 차근차근 살펴보자.


모든 신호는 한줄로 나타내고 줄바꿈으로 각각 구분된다.

첫 시작행은 $ 이고 그 이후 줄바꿈 문자가 나타나기 전까지 콤마(,)로 구분된 값들이 나타나는데 각 항목이 특별한 의미를 지니고 있다.


위 신호중 우리가 사용할 $GPRMC 의 각 부분의 의미하는 바는 아래와 같다.


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


앞에서부터 차례대로 적어보면 이렇다.

1. 시간 (ZuluTime)

2. 현재 수신 데이터의 유효 여부 : A (Valid), V (Invaild)
     이 데이터가 A 일 경우만 의미가 있다. V 는 아직 위성이 고정되지 않았다는 말.

3. 위도 (Latitude)

4. North,South

5. 경도 (Longitude)

6. East,West

7. 속도(Knots) - 위에서 말한것 처럼 해상에서 배의 위치를 위해 나온것이라 단위가 knots 이다. 킬로미터로 환산하려면 약 1.8 정도를 곱하면 된다.

8. 진행방향(Track Angle) - 자북 방향 기준으로 현재 이동 방향을 나타낸다.

9. 날짜

10. checksum

그렇다. 여기서 속도와 진행방향만 parsing 하여 사용하면 된다.


GPS 에 대한 강좌가 아니므로 GPS 신호에 대한 이해는 대강 이정도로만 접어두고, 혹시 더 자세한 정보가 필요하다면 NMEA - http://www.gpsinformation.org/dale/nmea.htm 를 참고 하시라~! 이외의 수많은 sentence 들이 즐비하다.


그럼 이제 준비된 GPS 모듈로 부터 NMEA 데이터를 받아보자. 외부 GPS 수신기와 단말기(또는 테스트PC)가 블루투스로 연결되면 우리는 단순히 serial port 를 하나 열어 들어오는 NMEA  데이터를 족족~ 읽어들이기만 하면 된다.


Serial Port 를 열기 위해 System.IO.Ports.SerialPort  객체를 생성하고 아래와 같은 코드를 작성한다.

블루투스로 바인딩된 포트는 COM1 이라 가정하고 해당 Port 에 들어오는 NMEA  데이터를 가져오는 코드는 아래와 같다.


* Read Serial Port

this.serialPort.PortName = "COM1";
this.serialPort.Open();
string msg = this.serialPort.ReadExisting();

미리 생성된 Serial Port 객체에 바인딩할 COM1 이름만 할당하고 ReadExisting 으로 읽어들이면 되는데, 매초 단위로 읽어야 하므로 위 코드는 Timer 객체의 OnTick Event Handler 로 등록해주면 된다.

 이외에 해당 Port 의 내용을 가져올때 원활한 처리를 위한 delegate 몇개를 생성했다.


* Event Delegator

public delegate void ON_FIND_PORT(object sender, int port);
public event ON_FIND_PORT OnFindPort;
public delegate void ON_FOUND_PORT(object sender, int port);
public event ON_FOUND_PORT OnFoundPort;
public delegate void ON_READ_PORT(object sender, string message);
public event ON_READ_PORT OnReadPort;
public delegate void ON_PARSE_GPRMC(object sender, GPSInfo info);
public event ON_PARSE_GPRMC OnParseGPRMC;

이제 GPS 모듈로 부터 NMEA 데이터를 가져오기 위한 대강의 준비는 완료되었다.


그럼 이제 NMEA 데이터를 파싱하는 code 를 살펴보자


* NMEA Data Parser

             public GPSInfo Parse(string msg)
            {
                if (msg == null || msg.Length <= 0)
                {
                    throw new Exception("There are no data in port");
                }
                GPSInfo info = new GPSInfo();

                info.Speed      = 0;
                info.Latitude   = 0;
                info.Longitude  = 0;

                string[] lines = msg.Split('$');

                IEnumerator ie = lines.GetEnumerator();


                while (ie.MoveNext())
                {
                    string[] items = ((string)ie.Current).Split(',');

                    if (items[0].Equals("GPRMC"))
                    {
                        if (items[GPRMC_VALID].Equals("A"))
                        {


                            info.Speed             = Double.Parse(items[GPRMC_KNOT]) * KNOT_TO_KMS;
                            info.Latitude          = Double.Parse(items[GPRMC_LATITUDE]);
                            info.LatitudeType  = items[GPRMC_LATITUDE_TYPE];
                            info.Longitude        = Double.Parse(items[GPRMC_LONGITUDE]);
                            info.LongitudeType = items[GPRMC_LONGITUDE_TYPE];
                            info.Angle                  = Double.Parse(items[GPRMC_ANGLE]);

 

                            if (this.OnParseGPRMC != null)
                            {
                                OnParseGPRMC(this, info);
                            }
                        }

                        return info;
                    }
                }

                return info;

            }

정리하자면 라인단위로 split 하고 다시 , 단위로 split 한 뒤 각 요소위치별로 데이터를 추출하는 것인데, 이때 속도 부분만 1.83 을 곱해 knots 를 km/h 로 변환하였다.
 
가져온 값들은 각각 현재 이동 속도(Speed), 위도(Latitude), 경도(Longitude), 진행 방향(Angle)이다.
 
이제 이 값들을 적절히 화면에 출력하는 일만 남았다.
 

'dev, tech > navigation' 카테고리의 다른 글

최단거리 알고리즘  (0) 2008.09.01
JAVA를 이용한 GPS장비  (0) 2008.09.01
gps 파싱  (0) 2008.09.01
GPS 응용프로그램 작성  (0) 2008.09.01
위치정보 시스템 (12)  (0) 2008.09.01

댓글