Last active
May 16, 2018 18:43
-
-
Save ibanezmatt13/5750785 to your computer and use it in GitHub Desktop.
This is a Python program for my first HAB (high-altitude balloon) flight. The flight will go ahead with the callsign "MATT-1" as it's my first launch and my name's Matt :) The program is split into three functions. There is a function to read the GPS and process the data receiver; a function to convert the returned position data into decimal lat…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# import required libraries | |
import serial | |
import crcmod | |
import time | |
import time as time_ | |
gps_set_sucess = False # boolean for the status of flightmode | |
# byte array for a UBX command to set flight mode | |
setNav = bytearray.fromhex("B5 62 06 24 24 00 FF FF 06 03 00 00 00 00 10 27 00 00 05 00 FA 00 FA 00 64 00 2C 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 DC") | |
def disable_sentences(): | |
GPS = serial.Serial('/dev/ttyAMA0', 9600, timeout=1) # open serial to write to GPS | |
# Disabling all NMEA sentences except $GPGGA | |
GPS.write("$PUBX,40,GLL,0,0,0,0*5C\r\n") | |
GPS.write("$PUBX,40,GSA,0,0,0,0*4E\r\n") | |
GPS.write("$PUBX,40,RMC,0,0,0,0*47\r\n") | |
GPS.write("$PUBX,40,GSV,0,0,0,0*59\r\n") | |
GPS.write("$PUBX,40,VTG,0,0,0,0*5E\r\n") | |
GPS.close() | |
#create function equivalent to arduino millis(); | |
def millis(): | |
return int(round(time_.time() * 1000)) | |
#calcuate expected UBX ACK packet and parse UBX response from GPS | |
def getUBX_ACK(MSG): | |
b = 0 | |
ackByteID = 0 | |
ackPacket = [0 for x in range(10)] | |
startTime = millis() | |
print "Reading ACK response: " | |
#construct the expected ACK packet | |
ackPacket[0] = int('0xB5', 16) #header | |
ackPacket[1] = int('0x62', 16) #header | |
ackPacket[2] = int('0x05', 16) #class | |
ackPacket[3] = int('0x01', 16) #id | |
ackPacket[4] = int('0x02', 16) #length | |
ackPacket[5] = int('0x00', 16) | |
ackPacket[6] = MSG[2] #ACK class | |
ackPacket[7] = MSG[3] #ACK id | |
ackPacket[8] = 0 #CK_A | |
ackPacket[9] = 0 #CK_B | |
#calculate the checksums | |
for i in range(2,8): | |
ackPacket[8] = ackPacket[8] + ackPacket[i] | |
ackPacket[9] = ackPacket[9] + ackPacket[8] | |
#print expected packet | |
print "Expected ACK Response: " | |
for byt in ackPacket: | |
print byt | |
print "Waiting for UBX ACK reply:" | |
while 1: | |
#test for success | |
if ackByteID > 9 : | |
#all packets are in order | |
print "(SUCCESS!)" | |
return True | |
#timeout if no valid response in 3 secs | |
if millis() - startTime > 3000: | |
print "(FAILED!)" | |
return False | |
#make sure data is availible to read | |
if GPS.inWaiting() > 0: | |
b = GPS.read(1) | |
print b | |
#check that bytes arrive in the sequence as per expected ACK packet | |
if ord(b) == ackPacket[ackByteID]: | |
ackByteID += 1 | |
print ord(b) | |
else: | |
ackByteID = 0 #reset and look again, invalid order | |
def sendUBX(MSG, length): | |
print "Sending UBX Command: " | |
ubxcmds = "" | |
for i in range(0, length): | |
GPS.write(chr(MSG[i])) #write each byte of ubx cmd to serial port | |
ubxcmds = ubxcmds + str(MSG[i]) + " " # build up sent message debug output string | |
GPS.write("\r\n") #send newline to ublox | |
print ubxcmds #print debug message | |
print "UBX Command Sent..." | |
crc16f = crcmod.predefined.mkCrcFun('crc-ccitt-false') # function for CRC-CCITT checksum | |
disable_sentences() | |
counter = 0 # sentence ID start value | |
# function to send both telemetry and packets | |
def send(data): | |
NTX2 = serial.Serial('/dev/ttyAMA0', 300, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_TWO) # opening serial at 300 baud for radio transmission with 8 character bits, no parity and two stop bits | |
NTX2.write(data) # write final datastring to the serial port | |
NTX2.close() | |
# function to read the gps and process the data it returns for transmission | |
def read_gps(): | |
import time # for some reason, importing time at the start is futile | |
global counter | |
gps = serial.Serial('/dev/ttyAMA0', 9600, timeout=1) | |
NMEA_sentence = gps.readline() # read GPS | |
gps.flush() # wait for serial to finish what it's doing | |
while not NMEA_sentence.startswith("$GPGGA"): # while we don't have a GPGGA sentence | |
NMEA_sentence = gps.readline() # re-read ready for re-looping | |
gps.flush() # wait for serial to finish what it's doing | |
print "Still Bad Sentence" | |
disable_sentences() # disable all sentence but GPGGA again | |
time.sleep(1) # wait for no reason what so ever :) | |
gps.close() | |
print NMEA_sentence | |
data = NMEA_sentence.split(",") # split sentence into individual fields | |
if data[6] == "0": # if it does start with a valid sentence but with no fix | |
print "No Lock" | |
pass | |
else: # if it does start with a valid sentence and has a fix | |
lats = data[2] | |
northsouth = data[3] | |
lngs = data[4] | |
westeast = data[5] | |
altitude = data[9] | |
callsign = "MATT_test" # this will be the callsign used primarily for checksum | |
time = data[1] | |
time = float(time) # ensuring that python knows time is a float | |
string = "%06i" % time # creating a string out of time (this format ensures 0 is included at start if any) | |
hours = string[0:2] | |
minutes = string[2:4] | |
seconds = string[4:6] | |
time = str(str(hours) + ':' + str(minutes) + ':' + str(seconds)) # the final time string in form 'hh:mm:ss' | |
latitude = convert(lats, northsouth) | |
longitude = convert(lngs, westeast) | |
string = str(callsign + ',' + time + ',' + str(counter) + ',' + str(latitude) + ',' + str(longitude) + ',' + str(gps_set_sucess) + ',' + altitude) # the data string | |
csum = str(hex(crc16f(string))).upper()[2:] # running the CRC-CCITT checksum | |
csum = csum.zfill(4) # creating the checksum data | |
datastring = str("$$" + string + "*" + csum + "\n") # appending the datastring as per the UKHAS communication protocol | |
counter += 1 # increment the sentence ID for next transmission | |
send(datastring) | |
print datastring | |
def convert(position_data, orientation): | |
decs = "" | |
decs2 = "" | |
for i in range(0, position_data.index('.') - 2): | |
decs = decs + position_data[i] | |
for i in range(position_data.index('.') - 2, len(position_data) - 1): | |
decs2 = decs2 + position_data[i] | |
position = float(decs) + float(str((float(decs2)/60))[:8]) | |
if orientation == ("S") or orientation == ("W"): | |
position = 0 - position | |
return position | |
while True: | |
gps_set_sucess = False | |
while not gps_set_sucess: | |
GPS = serial.Serial('/dev/ttyAMA0', 9600, timeout=3) | |
GPS.flush() | |
sendUBX(setNav, len(setNav)) | |
gps_set_sucess = getUBX_ACK(setNav) | |
GPS.close() | |
read_gps() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment