자기 개발과 IT 프로그래밍을 위한 여행

물처럼 흐르는 시간, 그 속에서의 여행

IoT 장비 개발부/모듈 연구청

GY-GPS6MV2 GPS 모듈 사용 부터 위도 경도 파싱까지

창조의 새싹 2018. 7. 24. 11:26

안녕하세요!

커피백작입니다!

 

음... 먼저, 제가 블로그 시작한지 얼마 안된 초짜라, 업로드할때 '어디서 샀는지, 어디글을 가져다 써도 되는지 등등' 저작권문제등은 잘 모르겠는데요

일단 제가 실제로 구매해서 사용한 제품으로, 직접 사진찍어 올리며,

여기저기서 자료 찾아서 직접 돌려본 소스코드를 올리는 것을 말씀드리며, 일정글을 퍼오면 명시해 남길 것입니다.

혹 문제된다면 알려주세요.

 

자, 그럼 시작하죠

오늘 업로드 내용은 GPS 모듈입니다!

 

 

GY-GPS6MV2 라고 써있는 제품인데요.

부가세 포함 해서 13,200 원 정도에 샀네요.

시리얼 통신을 하는 녀석이구요.

테스트는 아두이노 우노보드에 연결해서 사용했습니다.

선은 VCC, RX, TX, GND 로 4개의 선을 연결하여 사용합니다.

VCC 와 GND 는 전원 부분이고, 

RX, TX 는 시리얼 통신을 담당하는 부분이래요.(저도 잘 몰라욬ㅋㅋㅋ 그렇지만 다음에 파고 들어서 업로드하죠)

 

//  gps - arduino

//  tx - 10 

//  rx - 11

//  vcc - 5v

//  gnd - gnd

 

선의 연결입니다. GPS 모듈과 우노보드를 연결했을때 핀 번호들인데요.

(아시는 분이 많겠지만, 모듈과 보드들의 RX, TX 는 서로 교차 시켜줘야 합니다.

 저도 예전엔 몰라서 TX-TX RX-RX 서로 맞춰서 연결했었는데, 찾다보니 교차 연결해야 된다하더군요.

 저처럼 모르셨을 수 있는 분들 위해 남깁니다)

 

바로 한번 연결해보겠습니다.

 

 

 

자 이렇게 연결을 해 놓은 상태로 진행하겠습니다.

 

아두이노 스케치에 처음 업로드 할 소스는 다음과 같습니다.

 

#include <SoftwareSerial.h>

 

SoftwareSerial gpsSerial(10,11);

//  gps - arduino

//  tx - 10 

//  rx - 11

//  vcc - 5v

//  gnd - gnd

void setup() {

  Serial.begin(9600);

  Serial.println("Start GPS... ");

  gpsSerial.begin(9600);

}

 

void loop() {

    if(gpsSerial.available())

    {

      Serial.write(gpsSerial.read());

    }

}

 

해당 제품에 이상태로 업로드를 합시다!

 

업로드 후 시리얼 모니터를 열면 위의 사진과 같이 값이 주르르르르르르르르르르 나와요.

이 값에서 뭐가 좌표일지, 막막하지 않나요? ㅋㅋㅋ

 

단순히 TinyGPS 같은 라이브러리를 추가해서 불러옴으로 원하는 값만 출력할 수 도 있습니다만.

저는 그러기 싫었기에 이 기본소스에서 계속 바꿔 보았습니다.

 

현재는 시리얼 모니터에 보면 Start GPS 를 출력한 다음

$ 표시와 함께 각각 줄 앞에 5글자와 그 뒤를 이어 각각에 따른 값들이 계속 반복해서 출력합니다.

NMEA 라고 하는 프로토콜인데요.

 

http://blog.naver.com/6k5tvb/120061235070

 

이 분 링크에 가셔서 보시면 잘 정리 되어있어용.

 

이 NMEA에 대한 것은 링크 통해 보시구요.

 

저희가 GPS 모듈에서 가져올 값은 위도Lat 과 경도Long 잖습니까?

시리얼 모니터에 반복적으로 출력되는 문장들중, "GPGGA"의 값을 봐주세요.

 

GPGGA 에서 빨간색으로 밑줄 그어진 부분이 바로 위도와 경도입니다.

N 앞에 있는 값이 위도.

E 앞에 있는 값이 경도입니다.

 

저희는 그 값을 가져와야 합니다.

 

그.런.데.

 

그 부분의 값을 그대로 가져온다고해서 다 되는게 아니더라구요 하하

제가 있는 곳이 순천인데 고흥이 나오지 뭡니까~

그래서 따로 계산을 해줘야 정확한 위치 값이 나왔습니다.

 

계산식은 의외로 간단했습니다.

 

$GPGGA,015442.00, 3458.17997 ,N, 12728.74791 ,E,1,04,6.67,39.9,M,21.1,M,,*61

 

3458.17997 => 34+58.17997/60 -> 34.9696661667

12728.74791 => 127 + 28.74791/60 -> 127.4791318333

 

GPGGA 에서 나온 값을 위와 같이 계산해주면됩니다.

위도는 앞 두자리.

경도는 앞 세자리.

따로 가져다가 더해주면 됩니다.(뒤에있는 값들을 60으로 나눈 값에 더해야지요!)

 

 

이런 계산식을 돌리기위해서,

GPGGA 값을 따로 가져와야겠지요?

 

 

#include <SoftwareSerial.h>

 

SoftwareSerial gpsSerial(10,11);

//  gps - arduino

//  tx - 10 

//  rx - 11

//  vcc - 5v

//  gnd - gnd

char c = "";

String str = "";

String targetStr = "GPGGA";

 

void setup() {

  // put your setup code here, to run once:

  Serial.begin(9600);

  Serial.println("Start GPS... ");

  gpsSerial.begin(9600);

}

 

void loop() {

  // put your main code here, to run repeatedly:

 

  if(gpsSerial.available())

    {

      c=gpsSerial.read();

      if(c == '\n'){

        

        if(targetStr.equals(str.substring(1, 6))){

          Serial.println(str); 

        }

        

        str = "";

      }else{

        str += c;

      }

    }

}

 

소스는 위와 같습니다.

 

이렇게 하면 아래와 같은 모습인데용

 

일단 GPGGA 의 값만을 계속 가져오지요?

 

설명을 드리자면,

먼저 모듈에서 읽어온 값들이 단어 하나씩을 gpsSerial.read()로 읽어와 char 데이터형의 c 변수에 저장합니다.

그리고 이 c의 값이 차곡차곡 str 이라는 변수에 저장되는데, 만약 읽어온 c 의 값이 \n 인 줄바꿈 문자라면.

str.substring(1,6) 을 사용하여 $ 다음의 위치에 있는 ID 값을 가져와 targetStr인 GPGGA 와 비교합니다.

그리고 읽어온 str 이 GPGGA 라면? str을 출력해 주는 거죠!

그 이후 반드시 str = "" 로 str 값을 초기화 해주어야합니다

 

(만약 .substring() 이 무엇인 지 모르시겠다 하시면 다음의 링크로 들어가 보세요

 https://kocoafab.cc/tutorial/view/115

 위 링크에 아두이노의 string 형으로 할 수 있는 기능을 자세히 설명해 주셨습니다.

 저도 덕분에 어떻게 만들어 볼 수 있었죠)

 

 

이렇게 GPGGA 의 값을 읽어 왔다면.

이 GPGGA 에서 위도와 경도 값만을 불러 와야 하지 않겠나요?

 

$GPGGA,015442.00,3458.17997,N,12728.74791,E,1,04,6.67,39.9,M,21.1,M,,*61

 

GPGGA 의 값들을 자세히 보시면 ',' 쉼표로 구분지어져 있다는 것을 아실거예요.

 

로직을 짜다보면 문자열을 잘라서 일부분만 쓰는 경우가 많은데요~

이때 쪼개는 작업을 '파싱(Parsing)' 이라해요.

근데 어떻게 잘라 쓸 수 있을까요?

 

GPGGA 의 예를 들면, 쉼표로 구분 지어서 값을 가져올 수 있지 않겠습니까?

이 때 쉼표 처럼 구분지어 주는 문자열이나 문자를 구분자 라고해요.

(토큰이라는 말도 있는데, 토큰은 전체 문자열을 구분자로 쪼갠 단위 입니다)

 

GPGGA 의 값을 쉼표로 자르기 위해서 코코아팹 링크에도 나와있는 indexOf 를 사용하였습니다.

 

실제 적용 소스를 보면서 이해를 해볼까요?

 

#include <SoftwareSerial.h>

 

SoftwareSerial gpsSerial(10,11);

//  gps - arduino

//  tx - 10 

//  rx - 11

//  vcc - 5v

//  gnd - gnd

char c = ""; // Wn 인지 구분 및 str에 저장.

String str = ""; // \n 전까지 c 값을 저장.

String targetStr = "GPGGA"; // str의 값이 NMEA의 GPGGA 값인지 타겟

 

void setup() {

  // put your setup code here, to run once:

  Serial.begin(9600);

  Serial.println("Start GPS... ");

  gpsSerial.begin(9600);

}

 

void loop() {

  // put your main code here, to run repeatedly:

 

  if(gpsSerial.available()) // gps 센서 통신 가능?

    {

      c=gpsSerial.read(); // 센서의 값 읽기

      if(c == '\n'){ // \n 값인지 구분.

        // \n 일시. 지금까지 저장된 str 값이 targetStr과 맞는지 구분

        if(targetStr.equals(str.substring(1, 6))){

          // NMEA 의 GPGGA 값일시

          Serial.println(str);

          // , 를 토큰으로서 파싱.

          int first = str.indexOf(",");

          int two = str.indexOf(",", first+1);

          int three = str.indexOf(",", two+1);

          int four = str.indexOf(",", three+1);

          int five = str.indexOf(",", four+1);

          // Lat과 Long 위치에 있는 값들을 index로 추출

          String Lat = str.substring(two+1, three);

          String Long = str.substring(four+1, five);

          // Lat의 앞값과 뒷값을 구분

          String Lat1 = Lat.substring(0, 2);

          String Lat2 = Lat.substring(2);

          // Long의 앞값과 뒷값을 구분

          String Long1 = Long.substring(0, 3);

          String Long2 = Long.substring(3);

          // 좌표 계산.

          double LatF = Lat1.toDouble() + Lat2.toDouble()/60;

          float LongF = Long1.toFloat() + Long2.toFloat()/60;

          // 좌표 출력.

          Serial.print("Lat : ");

          Serial.println(LatF, 15);

          Serial.print("Long : ");

          Serial.println(LongF, 15);

        

        }

        // str 값 초기화 

        str = "";

      }else{ // \n 아닐시, str에 문자를 계속 더하기

        str += c;

      }

    }

}

 

 

 

 

GPGGA 가 저장된 str 에서 쉼표로 구분하여 값을 자릅니다.

그리고 위도와 경도를 각각 Lat 과 Long 에 저장한 후

또다시 나누어 계산한 뒤 Lat과 Long 에 저장, 출력합니다.

 

이로써 계산된 위도와 경도 값을 구해왔어요~

GPS 모듈을 이용해 보았는데요~

조금이라도 도움이 되었으면 좋겠습니다~!