본문 바로가기
임베디드 개발/STM32 (ARM Cortex-M)

STM32 ] NEO-6M 모듈 사용 , GPS 데이터 파싱하는 법 - 프로젝트 준비과정 (1)

by eteo 2022. 7. 3.

 

 

 

 

NEO-6M, GPS 수신 모듈

 

GPS는 Global Positioning Sytem 의 약자로 미국이 개발 및 관리하는 위성항법 시스템이다. 그리고 GPS 수신 모듈은 지구 궤도를 돌고 있는 위성으로부터 나온 데이터의 분석을 통해 현재 위치의 위도, 경도, 시간 등을 시리얼 통신을 통해 받아 볼 수 있는 모듈이다.

 

여러 송출원에서 신호를 쏘고 이를 모듈에서 수신하여 자신의 현재 위치를 계산하여 알아내는데, 수신기의 위치를 특정하기 위해서는 최소 4개의 위성이 필요하다. 이 중 3개 이상의 위성이 정확한 시간과 변위를 측정한 뒤 삼각점의 위치를 구하는 삼변 측량기법으로 위치를 파악하고, 3개 위성이 각각 측정하는 세 개의 범위가 서로 교차되는 지점이 수신기의 위치가 된다. 나머지 1개의 위성은 시간 오차를 보정하기 위해 사용한다.

 

GPS 모듈은 NMEA(National Marine Electronics Association) 프로토콜이라 불리는 형식으로 위치, 방향, 시간, 좌표 등의 데이터가 담긴 정보를 문자열 형태로 출력해준다. 따라서 GPS 수신기로 들어오는 문자열을 파싱(Parsing)해서 정수, 실수 등 원하는 값을 추출해 내는 작업이 필요하다.

 

GPS Raw 데이터는 굉장히 복잡하기 때문에 라이브러리를 사용하면 간편하게 원하는 정보를 얻어낼 수 있다.

 

 

 

 

스펙

 

 

 

 

 

라이브러리 출처 : https://github.com/leech001/gps

 

위 코드를 프로젝트 파일에 머지한다. 사용 방법도 ReadMe 파일에 나와있으니 쉽게 머지할 수 있다. 해당 라이브러리를 약간 수정해 프로젝트에 사용하고 있다.

 

 

 

 

배선

NEO-6M
VCC +5V
GND GND
TX PA3 (UART2-RX)
RX PD5 (UART2-TX)

 

 

 

사용시 참고사항

 

실내에서는 GPS 데이터가 측정이 안된다. 실외에서도 탁 트인곳에서 측정해야 한다.

야외로 나가더라도 GPS 신호를 잡아서 출력하기 까지 최대 10분가량 기다려야 할 수도 있다.

 

그리고 모듈에 달려있는 빨간 LED는 전원공급시 깜빡이는게 아니라 GPS 데이터 수신에 성공한 경우에 깜빡이기 때문에 불이 들어오지 않는다고 하더라도 테스트 출력시 $ 과 , 로 구분된 프로토콜 양식이 출력된다면 고장난게 아닐 확률이 높으니 기다려봐야 한다.

 

 

 

 

 

NMEA 프로토콜

 

데이터의 형식은 $로 시작해서 GP가 앞에 붙는 NMEA 코드 이름, 콤마로 구분되는 각 필드 데이터, 맨 마지막은 16진수 두자리 *3C 같은 형태의 체크섬이 나오고 CR, LF를 붙여 한줄로 끝난다.

 

GPS 모듈로 수신되는 정보 중 대표적인 데이터 셋

 

$GPGGA : GPS의 기준값

$GPRMC : GPS 데이터 사용을 위해 추천되는 최소한의 필수 데이터

$GPGSA : GNSS DOP and Active Satelite 의 약자, 현 위치에서 잡히는 각각의 위성 상태 확인. GPS의 수신상태를 점검하는데 사용된다.

$GPGSV : GNSS Satellite in View 의 약자, 현재 위치에서 보이는 각각 위성의 상태에 대해 나와있다. 한문장에 4개의 위성 정보가 나온다.

$GPGLL : 지리적 위치의 위도, 경도

$GPVTG : 지구 표면상의 항공 궤도와 대지 속도

 

 

 

 

 

$GPGGA 해석 

 

 

 

 

$GPRMC 해석

 

 

 

 

 

 

실제 수신되는 데이터를 UART로 출력해 본것

 

 

이중에서 위도와 경도를 얻어낼 수 있는 것은 $GPGGA와 $GPRMC인데 $GPGGA 데이터를 사용하였다.

 

 

 

 

 

 

문자열을 파싱해 전역으로 선언된 구조체 변수에 담고 있다.

 

 

 

 

 

 

 

이때 sscanf 라는 매우 유용한 함수를 사용해서 실수, 정수 또는 문자 형태로 파싱한다.

 

void GPS_parse(char *GPSstrParse){
    if(!strncmp(GPSstrParse, "$GPGGA", 6)){
    	if (sscanf(GPSstrParse, "$GPGGA,%f,%f,%c,%f,%c,%d,%d,%f,%f,%c", 
        	&GPS.utc_time, &GPS.nmea_latitude, &GPS.ns, 
            &GPS.nmea_longitude, &GPS.ew, &GPS.lock, &GPS.satelites, 
            &GPS.hdop, &GPS.msl_altitude, &GPS.msl_units) >= 1){
            
    		GPS.dec_latitude = GPS_nmea_to_dec(GPS.nmea_latitude, 
            GPS.ns);
    		GPS.dec_longitude = GPS_nmea_to_dec(GPS.nmea_longitude, 
            GPS.ew);
    		return;
    	}
    }
}

 

 

 

 

 

그리고 얻어진 위도, 경도 데이터  nmea_latitude, nmea_longitude 를 구글맵과 같은 지도 서비스에서 쓰이는 표준 좌표(WGS84)로 변환하기 위해 아래 함수를 통해 dec_latitude, dec_longitude 변수에 저장한다.

 

함수를 보면 NMEA  위도(Latitude), 경도(Longitude)에서 100의 자리까지가 도° 이고 나머지를 60으로 나눈것을 소수점으로 더한다.

 

float GPS_nmea_to_dec(float deg_coord, char nsew) {
    int degree = (int)(deg_coord/100);
    float minutes = deg_coord - degree*100;
    float dec_deg = minutes / 60;
    float decimal = degree + dec_deg;
    if (nsew == 'S' || nsew == 'W') { // return negative
        decimal *= -1;
    }
    return decimal;
}