GPS Verisi Nasıl Ayıklanmalı?

Başlatan muuzoo, 26 Kasım 2010, 20:23:57

muuzoo

GPS kullandığım bir çalışmam var. Fakat GPS verisi içinden almak istediğim sadece belirli bir kısım var. Veriler sürekli akış halinde geldiği için, içinden belli kısmını çekmem gerekiyor. Sizce nasıl bir yol izlemeliyim. İlk aklıma gelen belirli uzunlukta bir buffer'a kaydedip strstr fonksiyonu ile istediğim string i bulmak oldu. Sizce daha iyi bir yol ne olabilir?

Örnek GPS verisi :

$PLSR,245,1,349,0,154,0,11,-248,23,0,2*2D
$PLSR,245,2,-4048,-631,0,-631,4044,181,-26,178,-4092*2C
$PLSR,245,7,-34,-28,12*3B
$GPGSA,A,3,21,29,30,25,31,18,,,,,,,3.1,1.9,2.5*38
$GPGSV,3,1,09,30,73,261,25,21,65,243,28,29,64,044,21,25,46,158,24*7D
$GPGSV,3,2,09,05,27,053,,31,25,262,32,18,19,176,32,16,17,317,*71
$GPGSV,3,3,09,12,10,146,24*47
$HCHDG,349,,,4.9,E*34
$GPRMC,092309.000,A,3758.3544,N,03441.0583,E,0.60,354,251110,4.9,E,A*26
$PLSR,245,1,347,0,160,-1,11,-248,24,0,2*0F
$PLSR,245,2,-3987,-935,-16,-935,3983,181,-24,179,-4092*3D
$PLSR,245,7,-28,-12,13*3E
$GPGSA,A,3,21,29,30,25,31,18,,,,,,,3.1,1.9,2.5*38
$HCHDG,347,,,4.9,E*3A
$GPRMC,092310.000,A,3758.3546,N,03441.0584,E,0.35,352,251110,4.9,E,A*2D
$PLSR,245,1,349,0,161,0,11,-248,22,0,2*2A
$PLSR,245,2,-4038,-696,0,-696,4034,181,-30,178,-4092*2B
$PLSR,245,7,0,17,11*03
$GPGSA,A,3,21,29,30,25,31,18,,,,,,,3.1,1.9,2.5*38


gunluk.muuzoo.gen.tr - Kişisel karalamalarım...

muhittin_kaplan

nmea verisini ancak yazdığınız gibi alırsınız.

sigmoid

2 sene önce MikroC 8.1 de bir arkadaş için yazdığım kodlar. Program önce gelen veriyi takip ediyor ve GPRMC ile başlayan satırı buffera alıyor. Bu satırda konum bilgileri yer alıyor. Sonrada bufferdaki bilgiyi virgülleri takip ederek sırayla lcd ekrana yazıyor. Kolay gelsin.

const char *msgtext = "Gps TEST";
const char *msgesit=" = ";
const char *msguydu="Uydu";
const char *msgaraniyor="aranıyor.";
const char *msgbaglanildi="baglanildi.";
const char *msgsaat="Saat";
const char *msgboylam="Boylam";
const char *msgenlem="Enlem";


char gpstemp[80],lcdtext[20];
unsigned short gpstempkonum;   //gpstempten en son okunan yeri tutar.
void strcopy(char *hedef,const char *kaynak);
unsigned short usarttemp,uydudurum;


void usart_oku();
void virgulatla(unsigned short virgulsay);
void gps2text();
void gprmcoku();

void main()
{

  usart_init(4800);
  TRISB = 0;                // PORTB is output
  Lcd_Init(&PORTB);         // Initialize LCD connected to PORTB

  
  while(1)
  {

                gprmcoku();


                Lcd_Cmd(Lcd_CLEAR);       // Clear display
                Lcd_Cmd(Lcd_CURSOR_OFF);  // Turn cursor off
                strcopy(lcdtext,msgtext);
                lcd_out(1,2, lcdtext);            //ilk gps test yaz
                
                
                virgulatla(1);
                gps2text();               //uydu durumunu yazıyor. önce A veya V harfi gözükür.
                uydudurum=lcdtext[0];
                lcd_out(2,1,lcdtext);
                strcopy(lcdtext,msguydu);
                lcd_out(2,3,lcdtext);
                if(uydudurum=='A')
                {
                  strcopy(lcdtext,msgbaglanildi);
                  lcd_out(2,8,lcdtext);
                }
                else if(uydudurum=='V')
                {
                  strcopy(lcdtext,msgaraniyor);
                  lcd_out(2,8,lcdtext);
                }
                

                strcopy(lcdtext,msgenlem);        //enlem yaz
                lcd_out(3,1,lcdtext);
                strcopy(lcdtext,msgesit); //                eşittir yaz.
                lcd_out_cp(lcdtext); //ekrana eşittir çıkmazsa bu satırı sil.
                gps2text();          //enlem bilgisini lcdtext at.
                lcd_out_cp(lcdtext);
                
                strcopy(lcdtext,msgboylam);  //boylam yaz.
                lcd_out(4,1,lcdtext);
                strcopy(lcdtext,msgesit); //                eşittir yaz.
                lcd_out_cp(lcdtext); //ekrana eşittir çıkmazsa bu satırı sil.
                virgulatla(1);       //1 virgül sonrada boylam bilgisi geliyor.
                gps2text();
                lcd_out_cp(lcdtext); //boylamı yazdır.
                //gpstext() i her çağırdığında sonraki virgülden sonraki veriyi lcdtexte atar.
                //eğer sonrakini yazdırmak istemezsen virgulatla(1) çağır, veya atlamak istediğin veri sayısını gir.
                //ilkinde ben 3 virgul atladım



                 delay_ms(500); //her yarım saniyede bir ekrana gps verilerini yaz.
  }
  

}

//usarttan 1 byte okur ve usarttemp e yazar.
void usart_oku()
{
 while(!Usart_Data_Ready());
 usarttemp=Usart_Read();
}


//dataları alırken kaçıncı virgulden sonrasını almak istiyorsan o kadar virgul atlamanı sağlar.
void virgulatla(unsigned short virgulsay)
{
 unsigned short i=0;      //atlanan virgul sayısı
 while(i<virgulsay)
 {
     if(gpstemp[gpstempkonum]==',')
     {
           i++;
     }
     gpstempkonum++;
 }
}

//gps verisini virgule kadar alır ve lcdtexte atar
//ekrana lcd_out ile kendimiz yazdırmalıyız
void gps2text()
{
 unsigned short i=0;
 while(1)
 {
     if(gpstemp[gpstempkonum]==',')
     {
             gpstempkonum++;
             break;
     }
     lcdtext[i]=gpstemp[gpstempkonum];
     gpstempkonum++;
     i++;
  }
  lcdtext[i]=0;
}


//grpmc satırını bulur ve gpstemp dizisine atar.
void gprmcoku()
{

 gpstempkonum=0;
 t1:
 
         usart_oku();
          if(usarttemp!='$')
              goto t1;
          usart_oku();
          if(usarttemp!='G')
              goto t1;
          usart_oku();
          if(usarttemp!='P')
              goto t1;
          usart_oku();
          if(usarttemp!='R')
              goto t1;
          usart_oku();
          if(usarttemp!='M')
              goto t1;
          usart_oku();
          if(usarttemp!='C')
              goto t1;
          usart_oku();
          if(usarttemp!=',')
              goto t1;         //$GPRMC, karakterleri yoksa döngü başına git.
              
          while(gpstempkonum<80)
          {
            usart_oku();
            if(usarttemp=='\n')
                break;             //yeni satır gelince çık.
            gpstemp[gpstempkonum]=usarttemp;
            gpstempkonum++;
          }
          gpstemp[gpstempkonum]=0;
          gpstempkonum=0;

}


void strcopy(char *hedef,const char *kaynak)
{
  while(*kaynak)
    *hedef++ = *kaynak++;
    
  *hedef=0;
}

ferdem

 Hocam hangi nmea cümlesi işinize yarayacaksa sadece o geldiği zaman kayıt yapmanız daha iyi olur. Cümleyi başındaki $GPGGA gibi kelimeden tanıyıp bu ifadeyi gördükten sonra kaydetmeye başlamalısınız, virgüllere göre de cümleyi ayıklayacaksınız.
Mesela $GPGGA cümlesi neymiş:
$--GGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx
GPGGA yi yakaladıktan sonra 2. virgülden sonra enlem bilgisi var gibi.
Nmea cümlelerin anlamı internette birçok yerde var. Birisi şu:http://aprs.gids.nl/nmea/
Yapmak istediğiniz işe benzer işler yapan kodlar forumda verilmişti[hatırlayamamıştım, abdullaho ben yazarken yetişmiş bile :) ]. Google da NMEA Parser, NMEA Parsing gibi arayabilirsin. İyi çalışmalar.

muuzoo

Herkese teşekkürler arkadaşlar. Demek ki aklın yolu bir. @abdullaho örnek kodlar için sağol.
gunluk.muuzoo.gen.tr - Kişisel karalamalarım...

sigmoid

rica ederim. açıklamayı ferdem arkadaş yaptı.

mikrocde lcd kullanımı biraz gıcık olduğundan dolayı lcdye yazdıracağım metni sürekli kopyalamak zorunda kaldım.
Gerekli değişiklikleri yaparak istediğin derleyicide kullanabilirsin.

kolay gelsin.

BenC

Kullandığınız GPS modülünü bilmiyorum ama çoğu gps modüle komutlarla emir verebilirsiniz. Yani iletişim portuna sadece şu veriyi ver diyebiliyorsunuz. GPS verisinin tamamını bufer a alıp onun üzerinden işlem yapmak hem yazılıma hem mcu ya ek yük getirir. Bu nedenle ilk olarak istediğiniz nmea verisini isteyin(komut vererek). GPS verisinin daha doğrusu nmea0183 sisteminin bir protokolü var. Çoğu modül bu protokole bağlıdır. En basitinden veriyi pars etmek için her veri çeşidini virgül ile ayırırlar. bu virguller ve en sonda gelen checksum byte ile veriyi pars edip değişkene atamanız daha kolay olur.

$GPRMC,083319.00,A,3955.90624,N,03252.90514,E,0.624,23.07,260210,,,A*53


Sizin gps modülünüz enerji verildiğinde hemen size konum vs bilgisi vermeyecektir. Eğer kodunuzu bunu düşünerek yazmaz iseniz daha sonra hatalar verebilir ilgili fonksiyonunuz.

Bir zamanlar PBP de yazdığım GPS kodu

'*******************************************************************************
'*******************************************************************************
'*****                 uBLOX GPS VERİLERİNİN ALINMASI               ************
'*****   Konum Bilgisi, Hız Bilgisi Sapma Bilgisi Ve Zaman Bilgisi  ************
'*******************************************************************************
'******************************************************************** 05.05.2007
GpsVeriOku : For addr=0 TO 64 
				RegGeneral[addr] = SIF
			 Next addr
			 
			 For addr=0 TO 9 
				gpsKuzey[addr] = SIF
			 Next addr
			 
			 For addr=0 TO 10 
				gpsDogu[addr] = SIF
			 Next addr
			 
			 For addr=0 TO 6 
				gpsHiz[addr] = SIF
			 Next addr
			 
			 For addr=0 TO 5 
				gpsSapma[addr] = SIF
			 Next addr
			 
			 gpsGun[0]     = SIF
			 gpsGun[1]     = SIF
			 gpsAy[0]      = SIF
			 gpsAy[1]      = SIF
			 gpsYil[0]     = SIF
			 gpsYil[1]     = SIF
			 gpsSaat[0]    = SIF
			 gpsSaat[1]    = SIF
			 gpsDakika[0]  = SIF
			 gpsDakika[1]  = SIF
			 gpsSaniye[0]  = SIF
			 gpsSaniye[1]  = SIF
			 
			 ErrGPS     = EE 
			 
			 SerIn2 GPS_RXD,GPS_BAUD,3000,GpsErr1,[wait("$GPRMC,")]
		 
			 i = 0
			 
    Loop1 :	 SerIn2 GPS_RXD,GPS_BAUD,[gpsData]		 
			 
			 IF (gpsData = "*") OR (i >=200) Then
			  	
			    GoTo gpsDataOk 
			  
			 Else
			 
			 	RegGeneral[i]=gpsData
			 	i = i + 1
			    GoTo Loop1
			    
			 EndIF
			 	 
			 
	gpsDataOk : IF RegGeneral[1] = "V" Then
					gpsStatu = VV
					GoTo gpsAntYok
				EndIF
					
				IF (RegGeneral[10] = "V") Then 
					gpsStatu = TT
					GoTo gpsOlcYok
				EndIF
				
				IF RegGeneral[10] = "A" Then
					gpsStatu = AA
					GoTo gpsOlcVar
				EndIF
				
				IF (RegGeneral[1] = SIF) OR (RegGeneral[6] = SIF)  Then
					gpsStatu = DOK
					GoTo GpsErr1
				EndIF
				
	gpsAntYok :	GoTo GpsErr1

	gpsOlcYok :	gpsSaat[0]   = RegGeneral[0] 
				gpsSaat[1]   = RegGeneral[1]
							
				gpsDakika[0]   = RegGeneral[2] 
				gpsDakika[1]   = RegGeneral[3]
				
	       		gpsSaniye[0]   = RegGeneral[4] 
				gpsSaniye[1]   = RegGeneral[5] 
				
				gpsGun[0]   = RegGeneral[18] 
				gpsGun[1]   = RegGeneral[19] 
				
				gpsAy[0]  = RegGeneral[20]
				gpsAy[1]   = RegGeneral[21] 
					
				gpsYil[0]   = RegGeneral[22] 
				gpsYil[1]   = RegGeneral[23] 
				
				GoTo GpsErr1

gpsOlcVar     : gpsSaat[0]   = RegGeneral[0] 
				gpsSaat[1]   = RegGeneral[1]
							
				gpsDakika[0]   = RegGeneral[2] 
				gpsDakika[1]   = RegGeneral[3]
				
	       		gpsSaniye[0]   = RegGeneral[4] 
				gpsSaniye[1]   = RegGeneral[5] 
				
				VirSay = 0
				i = 0
				j = 0	
		
	Kuzey1 : 	IF 	(RegGeneral[i] = VI) OR ( i >= 200) Then
			            
			        VirSay = VirSay + 1    
			              
			         	IF  VirSay = 2 Then
							
	Kuzey2 :					IF 	(RegGeneral[(i+1)] = VI) OR ( i >= 200) Then
									GoTo gpsKuzeyOk
								Else
									gpsKuzey[j] = RegGeneral[(i+1)]
						        	i =  i + 1
						        	j = j + 1
						        	GoTo Kuzey2
						    	EndIF
						
						EndIF
					
				EndIF

				i =  i + 1			
					
	GoTo Kuzey1	
					
			
	gpsKuzeyOk : VirSay = 0
				 i = 0
				 j = 0	
					
	Dogu1      :  IF 	(RegGeneral[i] = VI) OR ( i >= 200) Then
			            
			        VirSay = VirSay + 1    
			              
			         	IF  VirSay = 4 Then
							
	Dogu2      :    		IF 	(RegGeneral[(i+1)] = VI) OR ( i >= 200) Then
								GoTo gpsDoguOk
							Else
								gpsDogu[j] = RegGeneral[(i+1)]
						        i =  i + 1
						        j = j + 1
						        GoTo Dogu2
						    EndIF
						
						EndIF
					
				EndIF

				i =  i + 1			
					
	GoTo Dogu1	  				

	gpsDoguOk : VirSay = 0
				i = 0
				j = 0
				
						
	Hiz1       :  IF 	(RegGeneral[i] = VI) OR ( i >= 200) Then
			            
			        VirSay = VirSay + 1    
			              
			         	IF  VirSay = 6 Then
							
	Hiz2      :    		IF 	(RegGeneral[(i+1)] = VI) OR ( i >= 200) Then
								GoTo gpsHizOk
							Else
								gpsHiz[j] = RegGeneral[(i+1)]
						        i =  i + 1
						        j = j + 1
						        GoTo Hiz2
						    EndIF
						
						EndIF
					
				EndIF

				i =  i + 1			
					
	GoTo Hiz1	  				
	
	gpsHizOk   : VirSay = 0
				 i = 0
				 j = 0
				 
							 
	Sapma1	   :  IF 	(RegGeneral[i] = VI) OR ( i >= 200) Then
			            
			        VirSay = VirSay + 1    
			              
			         	IF  VirSay = 7 Then
							
	Sapma2      :    		IF 	(RegGeneral[(i+1)] = VI) OR ( i >= 200) Then
								GoTo gpsSapmaOk
							Else
								gpsSapma[j] = RegGeneral[(i+1)]
						        i =  i + 1
						        j = j + 1
						        GoTo Sapma2
						    EndIF
						
						EndIF
					
				EndIF

				i =  i + 1			
					
	GoTo Sapma1	  				

	gpsSapmaOk : VirSay = 0
				 i = 0
				 j = 0
	
	Tarih1     : IF 	(RegGeneral[i] = VI) OR ( i >= 200) Then
			            
			        VirSay = VirSay + 1    
			              
			         	IF  VirSay = 8 Then
							
	Tarih2      :    		IF 	(RegGeneral[(i+1)] = VI) OR ( i >= 200) Then
								GoTo gpsTarihOk
							Else
								gpsTarih[j] = RegGeneral[(i+1)]
						        i =  i + 1
						        j = j + 1
						        GoTo Tarih2
						    EndIF
						
						EndIF
					
				EndIF

				i =  i + 1			
					
	GoTo Tarih1	 
	
gpsTarihOk    : gpsGun[0]   = gpsTarih[0] 
				gpsGun[1]   = gpsTarih[1] 
				
				gpsAy[0]  = gpsTarih[2]
				gpsAy[1]   = gpsTarih[3] 
					
				gpsYil[0]   = gpsTarih[4] 
				gpsYil[1]   = gpsTarih[5] 
                    
                 
					
gpsVeriOk:	  
			
GpsVeriAlOk :  Low GPS_LED


Birde linkteki kodu incelerseniz yardımcı olur belki.
https://www.picproje.org/index.php/topic,28427.0.html main dosyası içerisinde GPS_VERI_AL fonksiyonu




ŞEHİT KANIYLA ALINMIŞ BU GÜZELİM VATANIN TOPRAKLARI KARIŞ KARIŞ SATILIYOR!!  VATAN HAİNİ OLMA!!

muuzoo

Kullandığım GPS modülünde dahili 3-eksen ivme ölçer ve dijital pusula da mevcut. GPS ile ilgili kimi parametreleri devredışı bırakmak mümkün fakat diğer bilgiler için ne yazık ki değil (kullanım klavuzunda belirtilmemiş). O yüzden veriyi süzmem gerekiyor. Şimdi verdiğiniz projeyi inceliyorum.
gunluk.muuzoo.gen.tr - Kişisel karalamalarım...

BenC

Herhangi bir dokuman koyabilirsmisiniz. Veya marka model söylermisiniz.
ŞEHİT KANIYLA ALINMIŞ BU GÜZELİM VATANIN TOPRAKLARI KARIŞ KARIŞ SATILIYOR!!  VATAN HAİNİ OLMA!!

muuzoo

gunluk.muuzoo.gen.tr - Kişisel karalamalarım...

BenC

Kusura bakma biraz geciktim. Eski dokumanlarımı inceliyordum. $PSRF103,05,00,00,01*21 bu komutu bir denermisiniz. Sizin modül Sirf mimarisi üzerine kurulu. Sirf destekli bütün modüller normallde bu komutları desteklemesi gerekir. Eğer Firma engellemediyse.

Eğer modülü direk olarak seri porta bağlayıp gelen veriyi görebiliyorsanız yukarıda verdiğim komutu bi deneyin. Bu komut VTG mesajı geliyorsa onuu iptal edecektir.
ŞEHİT KANIYLA ALINMIŞ BU GÜZELİM VATANIN TOPRAKLARI KARIŞ KARIŞ SATILIYOR!!  VATAN HAİNİ OLMA!!

BenC

ŞEHİT KANIYLA ALINMIŞ BU GÜZELİM VATANIN TOPRAKLARI KARIŞ KARIŞ SATILIYOR!!  VATAN HAİNİ OLMA!!

muuzoo

Bu akşamlık paydos ediyorum :) Dökümanlar için sağolun.
gunluk.muuzoo.gen.tr - Kişisel karalamalarım...

iyildirim

#13
Kullandığınız GPS chipseti SIRF sanırım. String işlemlerle uğraşmak istemiyorsanız, Modülü NMEA yerine Binary veri gönderecek şekilde konfigüre edebilirsiniz.  Bu durumda veriler aynı sizin RAM'ınız da durduğu gibi gelecektir. Yapacağınız şey gelen veriyi direkt olarak RAM'e yazıp sabit uzunluklu değişkenleri ayıklamak olur.

Eğer C kullanıyorsanız daha iyi yöntem; gelen veriye göre bir struct hazırlayın , gelen veri boyu kadar bir de string değişken oluşturun, bunları union kullanarak aynı bellek bölgesini gösterecek şekilde birlikte tanımlayın. gelen veriyi  stringe aktarın. struct yapıdan direkt olarak bilgileri okuyun. Dikkat etmeniz gereken tek şey liitleendian, bigendian uyumluluğu olacaktır

Kullandığınız chipsete göre ilgili dökümanlar chipset üreticisinin sitesinde mevcut. GPS chipsetlerinin çok büyük bir bölümü Binary modu destekler.
Genel bir tavsiye olarak; GSP modülü çok güçlü bir denetleyici-işlemci ile kullanılmayacaksa Tercih yaparken Binary çıkış verebilen bir chipseti olan GSP modülünün tercih edilmesi işinizi oldukça kolaylaştıracaktır.