2014-08-31 2 views
1

여러 번 물어 본 적이 있지만 실제로 검색하고있는 것을 찾을 수 없습니다.arduino를 사용하여 GPS NMEA 코드를 디코딩하십시오.

저는 Arduino Uno와 GPS 쉴드를 사용하여 일련의 GPS 데이터를 보여줍니다.

void loop() // run over and over 
{ 
    while(!(mySerial.available())){} 
     Serial.write(mySerial.read()); 
} 

단지 코드 : 여기

내가 GPS 방패 인터페이스 내 아두 이노에 업로드하고있는 코드입니다. 그럼에도 불구하고 연속적으로 반복되면서 직렬 모니터에서 매초마다 GPS 데이터를 출력합니다.

여기 초마다 출력이다

$GPGGA,013856.000,000.9090,N,9090.90,E,1,09,1.1,316.97,M,0.00,M,,*66 
$GPGSA,A,3,07,08,11,1ÿ3,16,19,23,27,42,,,,2.8,1.1,2.5*3F 
$GPRMC,013856.000,A,000.9090,N,9090.90,E,0.0,038.1,310814,,,A*62 
$GPGSV,ÿ3,1,12,16,26,059,33,27,33,025,44,08,30,330,32,07,31,326,34*7A 
$GPGSV,3,2,12,19,58,354,31,01,33,186,18,23,32,221,24,11,5ÿ9,198,31*70 
$GPGSV,3,3,12,42,60,129,32,13,38,253,27,32,06,161,,31,01,140,*7E 

는 GPS 실드 작동 수단 최소 초마다, 좌표 변화를 갱신한다.

여기에서 문제는 GPGGA 행에서만 GPS 데이터를 구문 분석하고 다른 행은 무시하고 싶다는 것입니다. 상태, 위도, N/S 표시기, 경도 및 E/W 표시기를 구문 분석하고 싶습니다.

나는 NMEA 라이브러리 (http://nmea.sourceforge.net/)를 검색했지만 어떻게 사용하는지 잘 모릅니다.

누군가 나를 도와 줄 수 있습니까? 고맙습니다.

+0

정규식을 사용하여 모든 데이터의 GPS를 구문 분석 할 수 있습니다. –

답변

0

TinyGPS을 사용하여 NMEA 문자열을 구문 분석 할 수 있습니다. 한 문장에만 관심이 있다면. 해당 문장에 대해서만 아래와 같이 사용자 정의 파서를 작성할 수 있습니다.

int handle_byte(int byteGPS) { 
buf[counter1] = byteGPS; 
//Serial.print((char)byteGPS); 
counter1++; 
if (counter1 == 300) { 
    return 0; 
} 

if (byteGPS == ',') { 
    counter2++; 
    offsets[counter2] = counter1; 
    if (counter2 == 13) { 
     return 0; 
    } } if (byteGPS == '*') { 
    offsets[12] = counter1; } 

    // Check if we got a <LF>, which indicates the end of line if (byteGPS == 10) { 

    // Check that we got 12 pieces, and that the first piece is 6 characters 
    if (counter2 != 12 || (get_size(0) != 6)) { 
     return 0; 
    } 

    // Check that we received $GPRMC 
    // CMD buffer contains $GPRMC 
    for (int j=0; j<6; j++) { 

     if (buf[j] != cmd[j]) { 
     return 0; 
     } 
    } 

    // Check that time is well formed 
    if (get_size(1) != 10) { 

     return 0; 
    } 

    // Check that date is well formed 
    if (get_size(9) != 6) { 
     return 0; 
    } 

    SeeedOled.setTextXY(7,0); 
    for (int j=0; j<6; j++) { 
     SeeedOled.putChar(*(buf+offsets[1]+j)); 
    } 
    SeeedOled.setTextXY(7,7); 

    for (int j=0; j<6; j++) { 
     SeeedOled.putChar(*(buf+offsets[9]+j)); 
    } 

    // TODO: compute and validate checksum 

    // TODO: handle timezone offset 

     return 0; } 
return 1; } 
1

저는 인터넷을 검색했으며 가장 좋은 대답은 Arduino에 "TinyGPS ++"라이브러리를 사용하는 것입니다. 거의 모든 GPS 관련 코드가 이미 라이브러리에 포함되어 있습니다.

0

당신에게 도움이 될 수있는이 시도

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

TinyGPS gps; 
SoftwareSerial ss(3,4); 


static void smartdelay(unsigned long ms); 
static void print_float(float val, float invalid, int len, int prec); 
static void print_int(unsigned long val, unsigned long invalid, int len); 
static void print_date(TinyGPS &gps); 
static void print_str(const char *str, int len); 

void setup() 
{ 
    Serial.begin(9600); 
    ss.begin(9600); 
} 

void loop() 
{ 
    float flat, flon; 

    unsigned short sentences = 0, failed = 0; 

    gps.f_get_position(&flat, &flon); 
    Serial.print("LATITUDE: "); 
    print_float(flat, TinyGPS::GPS_INVALID_F_ANGLE, 10, 6); 
    Serial.println(" "); 
    Serial.print("LONGITUDE: "); 
    print_float(flon, TinyGPS::GPS_INVALID_F_ANGLE, 11, 6); 
    Serial.println(" "); 

    Serial.print("altitude: "); 
    print_float(gps.f_altitude(), TinyGPS::GPS_INVALID_F_ALTITUDE, 7, 2); 
    Serial.println(" "); 
    Serial.print("COURSE:"); 
    print_float(gps.f_course(), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2); 
    Serial.println(""); 

    Serial.print("DIRECTION: "); 
    int d; 
    print_str(gps.f_course() == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(gps.f_course()), 6); 
    d=gps.f_course(); 
    Serial.println(); 
    Serial.println(); 
    smartdelay(1000);  

} 

static void smartdelay(unsigned long ms) 
{ 
    unsigned long start = millis(); 
    do 
    { 
    while (ss.available()) 
     gps.encode(ss.read()); 
    } while (millis() - start < ms); 
} 

static void print_float(float val, float invalid, int len, int prec) 
{ 
    if (val == invalid) 
    { 
    while (len-- > 1) 
     Serial.print('*'); 
    Serial.print(' '); 
    } 
    else 
    { 
    Serial.print(val, prec); 
    int vi = abs((int)val); 
    int flen = prec + (val < 0.0 ? 2 : 1); // . and - 
    flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1; 
    for (int i=flen; i<len; ++i) 
     Serial.print(' '); 
    } 
    smartdelay(0); 
} 

static void print_int(unsigned long val, unsigned long invalid, int len) 
{ 
    char sz[32]; 
    if (val == invalid) 
    strcpy(sz, "*******"); 
    else 
    sprintf(sz, "%ld", val); 
    sz[len] = 0; 
    for (int i=strlen(sz); i<len; ++i) 
    sz[i] = ' '; 
    if (len > 0) 
    sz[len-1] = ' '; 
    Serial.print(sz); 
    smartdelay(0); 
} 
static void print_str(const char *str, int len) 
{ 
    int slen = strlen(str); 
    for (int i=0; i<len; ++i) 
    Serial.print(i<slen ? str[i] : ' '); 
    smartdelay(0); 
} 
1

NMEA 데이터는 GPS 스타일 (ddmm.ssss) 형식으로되어, 소수 스타일 (dd.mmssss)에서 원하는 구글하는 coversion 기능에서이있다 이 단계의 코드 맨.

나는 작고 간단한 라이브러리를 만들기 위해 크고 복잡한 라이브러리가 맘에 들지 않기 때문에 이것을 썼다. 특히 어떻게 동작하는지 알아 내려고 할 때 특히 그렇다. 이것은 GLL 문장을 구문 분석하지만 필요한 경우 문장을 변경하고 섹션을 재정렬 할 수 있습니다.

String ReadString; 

void setup() { 
    Serial.begin(9600); //Arduino serial monitor thru USB cable 
    Serial1.begin(9600); // Serial1 port connected to GPS 
} 

void loop() { 
    ReadString=Serial1.readStringUntil(13); //NMEA data ends with 'return' character, which is ascii(13) 
    ReadString.trim();      // they say NMEA data starts with "$", but the Arduino doesn't think so. 
    // Serial.println(ReadString);   //All the raw sentences will be sent to monitor, if you want them, maybe to see the labels and data order. 

    //Start Parsing by finding data, put it in a string of character array, then removing it, leaving the rest of thes sentence for the next 'find' 
    if (ReadString.startsWith("$GPGLL")) { //I picked this sentence, you can pick any of the other labels and rearrange/add sections as needed. 
     Serial.println(ReadString);  // display raw GLL data in Serial Monitor 
    // mine looks like this: "$GPGLL,4053.16598,N,10458.93997,E,224431.00,A,D*7D" 

//This section gets repeated for each delimeted bit of data by looking for the commas 
    //Find Lattitude is first in GLL sentence, other senetences have data in different order 
     int Pos=ReadString.indexOf(','); //look for comma delimetrer 
     ReadString.remove(0, Pos+1); // Remove Pos+1 characters starting at index=0, this one strips off "$GPGLL" in my sentence 
     Pos=ReadString.indexOf(','); //looks for next comma delimetrer, which is now the first comma because I removed the first segment 
     char Lat[Pos];   //declare character array Lat with a size of the dbit of data 
      for (int i=0; i <= Pos-1; i++){ // load charcters into array 
      Lat[i]=ReadString.charAt(i);   
      } 
      Serial.print(Lat);   // display raw latitude data in Serial Monitor, I'll use Lat again in a few lines for converting 
//repeating with a different char array variable   
     //Get Lattitude North or South 
     ReadString.remove(0, Pos+1);    
     Pos=ReadString.indexOf(',');  
     char LatSide[Pos];   //declare different variable name 
      for (int i=0; i <= Pos-1; i++){ 
      LatSide[i]=ReadString.charAt(i); //fill the array   
      Serial.println(LatSide[i]);  //display N or S 
      } 

      //convert the variable array Lat to degrees Google can use 
      float LatAsFloat = atof (Lat);   //atof converts the char array to a float type 
      float LatInDeg; 
      if(LatSide[0]==char(78)) {  //char(69) is decimal for the letter "N" in ascii chart 
       LatInDeg= ConvertData(LatAsFloat); //call the conversion funcion (see below) 
      } 
      if(LatSide[0]==char(83)) {  //char(69) is decimal for the letter "S" in ascii chart 
       LatInDeg= -(ConvertData(LatAsFloat)); //call the conversion funcion (see below) 
      } 
      Serial.println(LatInDeg,15); //display value Google can use in Serial Monitor, set decimal point value high 
//repeating with a different char array variable    
     //Get Longitude 
     ReadString.remove(0, Pos+1);    
     Pos=ReadString.indexOf(',');  
     char Longit[Pos];    //declare different variable name 
      for (int i=0; i <= Pos-1; i++){ 
      Longit[i]=ReadString.charAt(i);  //fill the array 
      } 
      Serial.print(Longit);  //display raw longitude data in Serial Monitor  
//repeating with a different char array variable 
      //Get Longitude East or West 
     ReadString.remove(0, Pos+1);    
     Pos=ReadString.indexOf(',');  
     char LongitSide[Pos];   //declare different variable name 
      for (int i=0; i <= Pos-1; i++){ 
      LongitSide[i]=ReadString.charAt(i);  //fill the array   
      Serial.println(LongitSide[i]);  //display raw longitude data in Serial Monitor 
      }  
      //convert to degrees Google can use 
      float LongitAsFloat = atof (Longit); //atof converts the char array to a float type 
      float LongInDeg; 
     if(LongitSide[0]==char(69)) {  //char(69) is decimal for the letter "E" in ascii chart 
       LongInDeg=ConvertData(LongitAsFloat); //call the conversion funcion (see below 
     }  
     if(LongitSide[0]==char(87)) {   //char(87) is decimal for the letter "W" in ascii chart 
       LongInDeg=-(ConvertData(LongitAsFloat)); //call the conversion funcion (see below 
     }    
      Serial.println(LongInDeg,15); //display value Google can use in Serial Monitor, set decimal point value high 
//repeating with a different char array variable 
      //Get TimeStamp - GMT 
     ReadString.remove(0, Pos+1);     
     Pos=ReadString.indexOf(',');  
     char TimeStamp[Pos];   //declare different variable name 
      for (int i=0; i <= Pos-1; i++){ 
      TimeStamp[i]=ReadString.charAt(i);   //fill the array  
      } 
      Serial.print(TimeStamp); //display raw longitude data in Serial Monitor, GMT 
      Serial.println("");  
    } 
} 

//Conversion function 
float ConvertData(float RawDegrees) 
{ 
    float RawAsFloat = RawDegrees; 
    int firstdigits = ((int)RawAsFloat)/100; // Get the first digits by turning f into an integer, then doing an integer divide by 100; 
    float nexttwodigits = RawAsFloat - (float)(firstdigits*100); 
    float Converted = (float)(firstdigits + nexttwodigits/60.0); 
    return Converted; 
} 
관련 문제