Last active
August 29, 2015 13:56
-
-
Save ibanezmatt13/8841298 to your computer and use it in GitHub Desktop.
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 | |
# for SSDV, see gist here (https://gist.github.com/ibanezmatt13/5694404) | |
import RPi.GPIO as GPIO | |
import os | |
import serial | |
import crcmod | |
import time | |
import time as time_ # look to change this | |
time_set = False | |
gps_set_success = False | |
GPIO.setmode(GPIO.BOARD) # set GPIO mode to reference literal pin numbers | |
crc16f = crcmod.predefined.mkCrcFun('crc-ccitt-false') # define function for CRC-CCITT checksum | |
disable_sentences() | |
counter = 0 # this counter will increment as our sentence_id | |
# 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") | |
GPIO.setup(7, GPIO.OUT) | |
#GPIO.output(7,True) | |
# function to disable all NMEA except the GPGGA sentences | |
def disable_sentences(): | |
GPS = serial.Serial('/dev/ttyAMA0', 9600, timeout=1) # open serial to write to GPS | |
# Disabling all NMEA sentences | |
time.sleep(0.5) | |
GPS.write("$PUBX,40,GLL,0,0,0,0*5C\r\n") | |
time.sleep(0.5) | |
GPS.write("$PUBX,40,GSA,0,0,0,0*4E\r\n") | |
time.sleep(0.5) | |
GPS.write("$PUBX,40,RMC,0,0,0,0*47\r\n") | |
time.sleep(0.5) | |
GPS.write("$PUBX,40,GSV,0,0,0,0*59\r\n") | |
time.sleep(0.5) | |
GPS.write("$PUBX,40,VTG,0,0,0,0*5E\r\n") | |
time.sleep(0.5) | |
GPS.flush() # flush any existing bytes out of serial buffer | |
GPS.close() # close serial | |
#create function equivalent to arduino millis(); | |
def millis(): | |
return int(round(time_.time() * 1000)) | |
# fucntion to send commands to the GPS | |
def sendUBX(MSG, length): | |
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 new line to ublox | |
# 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() | |
# 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] | |
for byt in ackPacket: | |
print byt | |
while 1: | |
# test for success | |
if ackByteID > 9 : | |
# all packets are in order | |
return True | |
# timeout if no valid response in 3 secs | |
if millis() - startTime > 3000: | |
return False | |
# make sure data is availible to read | |
if GPS.inWaiting() > 0: | |
b = GPS.read(1) | |
# 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 | |
# function to set the OS time to GPS time | |
def set_time(time): | |
data = list(time) # split the time into individual characters | |
# construct the hours and minutes variables | |
hours = time[0] + time[1] | |
minutes = time[2] + time[3] | |
parsed_datetime = hours + minutes # finalise the time to be set | |
os.system('sudo date --set ' + str(parsed_datetime)) # set the OS time | |
time_set = True # show that time is now set | |
# 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 parse_gps(NMEA_sentence, flightmode): | |
# set some fields to zero for transmitting without lock | |
satellites = 0 | |
lats = 0 | |
northsouth = 0 | |
lngs = 0 | |
westeast = 0 | |
altitude = 0 | |
time = 0 | |
latitude = 0 | |
longitude = 0 | |
global counter | |
if NMEA_sentence.startswith("$GPGGA"): # if we got a GPGGA sentence | |
print NMEA_sentence | |
data = NMEA_sentence.split(",") # split sentence into individual fields by comma | |
if data[6] == "0": # if it does start with a valid sentence but with no fix | |
print "No Lock" | |
# set WARN LED to on | |
pass | |
else: # if it does start with a valid sentence and has a fix | |
# parsing required telemetry fields | |
satellites = data[7] | |
lats = data[2] | |
northsouth = data[3] | |
lngs = data[4] | |
westeast = data[5] | |
altitude = int(float(data[9])) | |
raw_time = data[1] | |
if time_set == False: | |
set_time(raw_time) | |
time = float(raw_time) | |
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) | |
# the data fields below can be sent when no lock from GPS (almost, needs work) | |
callsign = "JOHN" | |
string = str(callsign + ',' + str(time) + ',' + str(counter) + ',' + str(latitude) + ',' + str(longitude) + ',' + str(satellites) + ',' + str(flightmode) + ',' + str(altitude)) # the data string | |
csum = str(hex(crc16f(string))).upper() # 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 | |
print "Now sending the following:", datastring | |
send(datastring) # send the datastring to the send function to send to the NTX2 | |
# function to convert latitude and longitude into a different format | |
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 | |
character = "" | |
datastring = "" | |
n = 0 | |
while True: | |
GPS = serial.Serial('/dev/ttyAMA0', 9600, timeout=1) # open serial | |
GPS.flush() | |
n = millis() # set n = current time | |
# while it has been less than 3 seconds since searching began | |
while (millis() - n) < 3000: | |
datastring = GPS.readline() # read new string from serial buffer | |
print "Acquired this data string from serial: " + datastring | |
if datastring.startswith("$GPGGA"): | |
gps_set_success = False | |
sendUBX(setNav, len(setNav)) # send command to enable flightmode | |
gps_set_success = getUBX_ACK(setNav) # check the flightmode is enabled | |
parse_gps(datastring, gps_set_success) # run the parse_gps function to get the data and parse it with status of flightmode | |
break | |
GPS.flush() | |
GPS.close() # close serial port | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment