grovepi/Software/Python/grove_gps/dextergps.py
2025-03-21 16:04:17 +01:00

168 lines
5.1 KiB
Python

# Released under the MIT license (http://choosealicense.com/licenses/mit/).
# For more information see https://github.com/DexterInd/GrovePi/blob/master/LICENSE
import grovepi
import serial, time, sys
import re
en_debug = False
def debug(in_str):
if en_debug:
print(in_str)
patterns=["$GPGGA",
"/[0-9]{6}\.[0-9]{2}/", # timestamp hhmmss.ss
"/[0-9]{4}.[0-9]{2,/}", # latitude of position
"/[NS]", # North or South
"/[0-9]{4}.[0-9]{2}", # longitude of position
"/[EW]", # East or West
"/[012]", # GPS Quality Indicator
"/[0-9]+", # Number of satellites
"/./", # horizontal dilution of precision x.x
"/[0-9]+\.[0-9]*/" # altitude x.x
]
class GROVEGPS():
def __init__(self, port='/dev/ttyAMA0', baud=9600, timeout=0):
self.ser = serial.Serial(port, baud, timeout=timeout)
self.ser.flush()
self.raw_line = ""
self.gga = []
self.validation =[] # contains compiled regex
# compile regex once to use later
for i in range(len(patterns)-1):
self.validation.append(re.compile(patterns[i]))
self.clean_data()
# self.get_date() # attempt to gete date from GPS.
def clean_data(self):
'''
clean_data:
ensures that all relevant GPS data is set to either empty string
or -1.0, or -1, depending on appropriate type
This occurs right after initialisation or
after 50 attemps to reach GPS
'''
self.timestamp = ""
self.lat = -1.0 # degrees minutes and decimals of minute
self.NS = ""
self.lon = -1.0
self.EW = ""
self.quality = -1
self.satellites = -1
self.altitude = -1.0
self.latitude = -1.0 #degrees and decimals
self.longitude = -1.0
self.fancylat = "" #
# def get_date(self):
# '''
# attempt to get date from GPS data. So far no luck. GPS does
# not seem to send date sentence at all
# function is unfinished
# '''
# valid = False
# for i in range(50):
# time.sleep(0.5)
# self.raw_line = self.ser.readline().strip()
# if self.raw_line[:6] == "GPZDA": # found date line!
# print (self.raw_line)
def read(self):
'''
Attempts 50 times at most to get valid data from GPS
Returns as soon as valid data is found
If valid data is not found, then clean up data in GPS instance
'''
valid = False
for _ in range(50):
time.sleep(0.5)
self.raw_line = self.ser.readline()
try:
self.line = self.raw_line.decode('utf-8')
self.line = self.line.strip()
except:
self.line = ""
debug(self.line)
if self.validate(self.line):
valid = True
break
if valid:
return self.gga
else:
self.clean_data()
return []
def validate(self, in_line):
'''
Runs regex validation on a GPGAA sentence.
Returns False if the sentence is mangled
Return True if everything is all right and sets internal
class members.
'''
if in_line == "":
return False
if in_line[:6] != "$GPGGA":
return False
self.gga = in_line.split(",")
debug (self.gga)
#Sometimes multiple GPS data packets come into the stream. Take the data only after the last '$GPGGA' is seen
try:
ind=self.gga.index('$GPGGA', 5, len(self.gga))
self.gga=self.gga[ind:]
except ValueError:
pass
if len(self.gga) != 15:
debug ("Failed: wrong number of parameters ")
debug (self.gga)
return False
for i in range(len(self.validation)-1):
if len(self.gga[i]) == 0:
debug ("Failed: empty string %d"%i)
return False
test = self.validation[i].match(self.gga[i])
if test == False:
debug ("Failed: wrong format on parameter %d"%i)
return False
else:
debug("Passed %d"%i)
try:
self.timestamp = self.gga[1]
self.lat = float(self.gga[2])
self.NS = self.gga[3]
self.lon = float(self.gga[4])
self.EW = self.gga[5]
self.quality = int(self.gga[6])
self.satellites = int(self.gga[7])
self.altitude = float(self.gga[9])
self.latitude = self.lat // 100 + self.lat % 100 / 60
if self.NS == "S":
self.latitude = - self.latitude
self.longitude = self.lon // 100 + self.lon % 100 / 60
if self.EW == "W":
self.longitude = -self.longitude
except ValueError:
debug( "FAILED: invalid value")
return True
if __name__ =="__main__":
gps = GROVEGPS()
while True:
time.sleep(1)
in_data = gps.read()
if in_data != []:
print (in_data)