Python GPS verisi işleme uygulaması yapalım.

Omega2+ ile yazılım geliştirme bordunun üretimini ve seri port, veritabanı uygulamalarını daha önceki yazılarımda anlatmıştım.
Şimdi de Omega2+ üzerinde Python ile Gps verisi işleme kısmını anlatmaya çalışacağım. Burada GSM/GNSS destekli modül kullandığım için GPS/Glonass verileri  komut gönderince gelecek. Normalde seri porta bir GPS alıcısı bağladığınız zaman 1PPS yani saniyede 1  defa GPS/Glonass verisini gönderecektir. GSM modülle veri alıyorsanız GPS konumu için komut gönderin, GPS alıcısından veri alıyorsanız sadece seri portu kontrol edin.


Yazılım geliştirmek için Quectel MC60 modülü kullanıyorum. GSM modül üzerinden GPS verisi alıp işleme olayına başlayalım.



Seri porta veri yazmak için bir fonksiyon tanımladım.

def seriPortYaz(veri,bekle=1,bildir=""):

 ser.write(veri.encode('utf-8'))

 sayac=0

 while(ser.in_waiting==0) and  (sayac<bekle):

  sleep(0.1)

  sayac+=1

 if (sayac>bekle):

  print("Cevap yok: {}...\r\n".format(veri))  


  if bildir!="":

  print("SER: {}\r\n".format(bildir))



 temp=ser.read(ser.in_waiting)

 gsmRespText=temp.decode('utf-8')

 print("Ser Read: {}\r\n".format(gsmRespText))



Burada veri bekle ve bildir parametreleri var.

veri; seri porta yazılacak komutu,

bekle; komut için beklenecek timeout süresini,

bildir ise komut ile ilgili python etkileşimli kabuğuna bildirim yapılmasını sağlıyor. bekle ve bildir default parametre aldığı için fonksiyonun kullanımı esnasında pas geçilebilir.



while döngüsü ile komut gsm modüle gönderildikten sonra seri porta veri gelene kadar yada timeout olana kadar beklenmesi sağlanıyor.

Eğer veri gelirse döngüden çıkıyor.

Gelen veriyi temp değişkenine alıp decode işlemi uyguluyor. decode önemli çünkü yapılmayınca \r (return) \n (new line) karakterleri ascii formatta değil normal yazı olarak çıkıyor ve bunlarla işlem yapılması zorlaşıyor.



Komut göndermek için bir fonksiyon daha tanımladım.



def atGonder(komut):

    if "AT+QGNSSRD" in komut:

  gelen=seriPortYaz(komut,30,komut)

  # gelen veri GNSS verisi ise

  if "+QGNSSRD:" in gelen:

   

   global latitude

   global longitude

   global rakim

   global yon

   global kms

   global knots

   global uydu

   global gnssTarihSaatListe

   global gnssTarih

   global gnssSaat

   global longitudeGo

   global latitudeGo

   

   

   GNSSListe=gelen.split()

   #print("GNSS: {}\r\n".format(GNSSListe))

   for i in GNSSListe:

    if "VTG" in i:

     VTGListe=i.split(",")

     print("liste: {}\r\n".format(VTGListe))

    if "RMC" in i:

     RMCListe=i.split(",")

     print("liste: {}\r\n".format(RMCListe))

    if "GSA" in i:

     GSAListe=i.split(",")

     print("liste: {}\r\n".format(GSAListe))

    if "GLL" in i:

     GLLListe=i.split(",")

     print("liste: {}\r\n".format(GLLListe))

    if "GSV" in i:

     GSVListe=i.split(",")

     print("liste: {}\r\n".format(GSVListe))

    if "GGA" in i:

     GGAListe=i.split(",")

     print("liste: {}\r\n".format(GGAListe))

   #RMCListe[3] elamanın uzunluğu 3 ten büyükse öyle işlem yap

   if len(RMCListe[3])>3:

    latitude.clear()

    latitude.append(RMCListe[3])

    latitude.append(RMCListe[4])

    longitude.clear()

    longitude.append(RMCListe[5])

    longitude.append(RMCListe[6])

    print("latitude: {} ; longitude: {}\r\n".format(latitude, longitude))

    

    longDeg=longitude[0][:3]

    longMn=longitude[0][3:5]

    longSec=longitude[0][6:8]

    longMs=longitude[0][8:10]

    

    latDeg=latitude[0][:2]

    latMn=latitude[0][2:4]

    latSec=latitude[0][5:7]

    latMs=latitude[0][7:9]

    

    print("degrees: deg:{} mn:{} sec:{} ms:{}\r\n".format(longDeg,longMn,longSec,longMs))

    print("degrees: deg:{} mn:{} sec:{} ms:{}\r\n".format(latDeg,latMn,latSec,latMs))

    

    longStr=longMn+"."+longSec+longMs

    longitudeGo=float(longStr)

    longitudeGo=longitudeGo/60

    longitudeGo=longitudeGo+int(longDeg)

    

    latStr=latMn+"."+latSec+latMs

    latitudeGo=float(latStr)

    latitudeGo=latitudeGo/60

    latitudeGo=latitudeGo+int(latDeg)

    

    

    print("longitudeGo:{}\r\n".format(longitudeGo))

    print("latitudeGo:{}\r\n".format(latitudeGo))

    

    

    

    yon=float(RMCListe[8])

    knot=float(RMCListe[7]) # knot cinsinden hız

    kms=float(VTGListe[7]) # km/s cinsinden hız

    rakim=float(GGAListe[9])

    print("hız: {:.2f} knots, {:.2f} km/s, yon: {:.2f} derece, rakım: {:.2f} mt\r\n".format(knot,kms,yon,rakim))

    gnssSaat=(RMCListe[1].split("."))[0]

    print("gnssSaat: {}\r\n".format(gnssSaat))

    gnssTarih=RMCListe[9]

    

    gnssTarihSaatListe.clear()

    gnssTarihSaatListe.append(gnssTarih[4:6])

    gnssTarihSaatListe.append(gnssTarih[2:4])

    gnssTarihSaatListe.append(gnssTarih[:2])

    gnssTarihSaatListe.append(gnssSaat[:2])

    gnssTarihSaatListe.append(gnssSaat[2:4])

    gnssTarihSaatListe.append(gnssSaat[4:6])

    

    print("gnssTarihSaatListe: {}\r\n".format(gnssTarihSaatListe))


else:  # eğer komut yukardaki komutlardan biri değilse normal işleme devam et   

  gelen=seriPortYaz(komut,3,komut)



Burada

atGonder("AT+QGNSSC=1\r") #GNSS Power On

atGonder("AT+QGNSSCMD=0\r")   #GNSS NMEA Tipi



komutları ile MC60 modülün GNSS'yi aktif ettim ve GPS verisi tipini en çok kullanılan standartlardan biri olan NMEA olarak seçtim.



Yukarıda fonksiyon içinde eğer gelen komut  AT+QGNSSRD ise şartı var. Eğer komut AT+QGNSSRD ise seri porta bu komutu verdikten sonra gelen cevabı alıp parçalamaya başlıyor. Yazımıza konu olan kısım da aslında burası.



global olarak tanımlamanın sebebi fonksiyon içinde tanımlanan değişkenlerin ana program bloğunda, ana blokta tanımlanan değişkenlerinde fonksiyon içinde çalışmaması.



Yani fonksiyon içinde tanımladığım a=5 bütün program genelinde geçerli değil. Aynı şekilde program başında tanımladığım a=3 fonksiyon içinde geçerli değil. Global ile bu sorunu aşıyorum.



GSM modüll değil de GPS ile veri alanlar komut gönderme yapısı ile ilgili işlemleri atlayabilirler.



GPS / GNSS verisi yaklaşık olarak aşağıdaki gibi bir cümledir:


$GPRMC,000009.800,V,,,,,0.00,0.00,060180,,,N*43

$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32

$GPGGA,000010.800,,,,,0,0,,,M,,M,,*41

$GPGSA,A,1,,,,,,,,,,,,,,,*1E

$GPRMC,000010.800,V,,,,,0.00,0.00,060180,,,N*4B

$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32

$GPGGA,000011.800,,,,,0,0,,,M,,M,,*40

$GPGSA,A,1,,,,,,,,,,,,,,,*1E

$GPRMC,000011.800,V,,,,,0.00,0.00,060180,,,N*4A

$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32

$GPGGA,000012.800,,,,,0,0,,,M,,M,,*43

$GPGSA,A,1,,,,,,,,,,,,,,,*1E

$GPGSV,1,1,00*79


GPRMC: minimum gerekli GPS verisi bilgisi

GPVTG: hareket bilgisi

GPGSA: Uydu bilgilerini içermektedir.


Bizim için enlem, boylam, saat, tarih, hız, yön ve rakım bilgileri yeterli olacaktır.

Saat konusunda da saatin Greenwich saati olduğunu belirteyim. Local saat değil. Bu yüzden saati kullanırken yerel saat eklemesini varsa gün / ay hatta yıl düzeltmesi yapılması gerektiğini belirteyim.


Python ile çalışmanın en sevdiğim taraflarında biri listeler. Veriyi alıp a.split(",") virgüllerinden ayırıp listeye ekle gibi basit bir  komutla bütün işi sizin yerinize hallediyor. 

Burada da yaptığımız iş bu. 


$GPRMC,194530.000,A,3051.8007,N,10035.9989,W,1.49,111.67,310714,,,A*74


gelen veriyi \r\n karakterlerinden bölüp listeye attık.


GNSSListe=gelen.split()


sonra GNSSListe içindeki her bir eleman için döngü kurduk.


for i in GNSSListe:


eğer cümle RMC içeriyorsa;


if "RMC" in i:

    RMCListe=i.split(",")

    print("liste: {}\r\n".format(RMCListe))


RMCListe adında bir birlisteye içeriği virgüllerle böl.


Sonra Listenin birinci elemanı saat, ikinci elamanı enlem, boylam, hız, yön, rakım vs sırasıyla değişkenlere alıp işi bitiriyoruz. 


Listenin hangi elemanı hangi değeri tutuyor kodlara bakarak anlaşılabilir.


longDeg=longitude[0][:3]

    longMn=longitude[0][3:5]

    longSec=longitude[0][6:8]

    longMs=longitude[0][8:10]

    

    latDeg=latitude[0][:2]

    latMn=latitude[0][2:4]

    latSec=latitude[0][5:7]

    latMs=latitude[0][7:9]

    

    print("degrees: deg:{} mn:{} sec:{} ms:{}\r\n".format(longDeg,longMn,longSec,longMs))

    print("degrees: deg:{} mn:{} sec:{} ms:{}\r\n".format(latDeg,latMn,latSec,latMs))

    

    longStr=longMn+"."+longSec+longMs

    longitudeGo=float(longStr)

    longitudeGo=longitudeGo/60

    longitudeGo=longitudeGo+int(longDeg)

    

    latStr=latMn+"."+latSec+latMs

    latitudeGo=float(latStr)

    latitudeGo=latitudeGo/60

    latitudeGo=latitudeGo+int(latDeg)



Yukarıdaki satırlarda klasik GPS cümlesi ile google maps'ın kullandığı GPS sistemi arasında 60lık sistem 100lük sistem çevrimi var.

Olay şu:

 3051.8007 koordinatları google maps sistemine çevrilirken 30 derece sabit kalıyor. 51.8007 kısmı alınıp 60'a bölünüyor. Sonra 30 ile toplanıyor. Sonuç 30,863345 çıkıyor.


Buradan sonra GPS  / GNSS verilerini istediğiniz şekilde kullanabilirsiniz.


Faydalı olması umuduyla...