168 lines
5.1 KiB
Python
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)
|