-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathmaps.py
245 lines (213 loc) · 7.33 KB
/
maps.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#
# Python GPS Tracking Example
# SparkFun Electronics, A.Weiss
# Beerware: if you use this and meet me, you must buy me a beer
#
# Function:
# Takes GPS position and altitude data and plots it on a scaled map image of your
# choice. Altitude can also be displayed in a separate graph.
#
# The program has a console menu that allows you to configure your connection.
# The program will run with either a GPS moudle connected or no moudle connected.
# If a GPS is connected, the position and altitude data is automatically saved
# to a file called nmea.txt. If no GPS is connected, you must create your own
# nmea.txt and fill it with GPGGA NMEA sentences.
# A map needs to be created and saved as a file called map.png. When you create
# your map, note the lat and long of the bottom left and top right corner, in decimal
# degrees. Then enter this information into the global variables below. This way,
# your the border of your map image can be used as the graph mins and maxs.
# Once you have a map loaded and a GPS connected, you can run the program and select
# either your position to be displayed on your map, or display altitude on a separate
# graph. The maps are not updated in realtime, so you must close the map and run
# the map command again in order to read new data.
from pynmea import nmea
import matplotlib.pyplot as plt
import serial, time, sys, threading, datetime, shutil
######Global Variables#####################################################
# you must declare the variables as 'global' in the fxn before using#
ser = 0
lat = 0
long = 0
pos_x = 0
pos_y = 0
alt = 0
i = 0 #x units for altitude measurment
#adjust these values based on your location and map, lat and long are in decimal degrees
TRX = -105.1621 #top right longitude
TRY = 40.0868 #top right latitude
BLX = -105.2898 #bottom left longitude
BLY = 40.001 #bottom left latitude
BAUDRATE = 4800
lat_input = 0 #latitude of home marker
long_input = 0 #longitude of home marker
######FUNCTIONS############################################################
def altitude():
global alt, i
#we want to create temporary file to parse, so that we don't mess with the nmea.txt file
f1 = open('temp.txt', 'w') #creates and opens a writable txt file
f1.truncate() #erase contents of file
shutil.copyfile('nmea.txt', 'temp.txt') #copy nmea.txt to temp.txt
f1.close() #close writable file
f1 = open('temp.txt', 'r') #open and read only
try: #best to use try/finally so that the file opens and closes correctly
for line in f1: #read each line in temp.txt
if(line[4] == 'G'): # fifth character in $GPGGA
if(len(line) > 50): # when there is a lock, the sentence gets filled with data
#print line
gpgga = nmea.GPGGA()
gpgga.parse(line)
alt = gpgga.antenna_altitude
i +=1 #increment the counter
print i
print alt
plt.scatter(x=[i], y=[float(alt)], s = 1, c='r') #plot each point
finally:
f1.close()
i=0
#axis is autoscaled
plt.ylabel('meters')
plt.xlabel('counts')
plt.title('ALTITUDE')
plt.show()
def check_serial():
print 'Do you have a GPS connected to the serial port? hit y or n, then enter'
temp = raw_input()
if temp == 'y':
init_serial()
if temp == 'n':
print 'You can enter your own NMEA sentences into a file named nmea.txt'
def init_serial():
#opens the serial port based on the COM number you choose
print "Found Ports:"
for n,s in scan():
print "%s" % s
print " "
#enter your COM port number
print "Choose a COM port #. Enter # only, then enter"
temp = raw_input() #waits here for keyboard input
if temp == 'e':
sys.exit()
comnum = 'COM' + temp #concatenate COM and the port number to define serial port
# configure the serial connections
global ser, BAUDRATE
ser = serial.Serial()
ser.baudrate = BAUDRATE
ser.port = comnum
ser.timeout = 1
ser.open()
ser.isOpen()
#Prints menu and asks for input
global lat_input, long_input
print 'OPEN: '+ ser.name
print ''
#can be used to enter positions through the user interface
#print 'enter your home position'
#print '4001.54351'
#print 'Lat<'
#plat = raw_input()
#lat_input = float(plat)
#print '-10517.3005'
#print 'Long<'
#plong = raw_input()
#long_input = float(plong)
thread()
def position():
#opens a the saved txt file, parses for lat and long, displays on map
global lat, long, lat_input, long_input, pos_x, pos_y, altitude
global BLX, BLY, TRX, TRY
#same process here as in altitude
f1 = open('temp.txt', 'w')
f1.truncate()
shutil.copyfile('nmea.txt', 'temp.txt')
f1.close()
f1 = open('temp.txt', 'r') #open and read only
try:
for line in f1:
if(line[4] == 'G'): # $GPGGA
if(len(line) > 50):
#print line
gpgga = nmea.GPGGA()
gpgga.parse(line)
lats = gpgga.latitude
longs = gpgga.longitude
#convert degrees,decimal minutes to decimal degrees
lat1 = (float(lats[2]+lats[3]+lats[4]+lats[5]+lats[6]+lats[7]+lats[8]))/60
lat = (float(lats[0]+lats[1])+lat1)
long1 = (float(longs[3]+longs[4]+longs[5]+longs[6]+longs[7]+longs[8]+longs[9]))/60
long = (float(longs[0]+longs[1]+longs[2])+long1)
#calc position
pos_y = lat
pos_x = -long #longitude is negaitve
#plot the x and y positions
plt.scatter(x=[pos_x], y=[pos_y], s = 5, c='r')
#shows that we are reading through this loop
print pos_x
print pos_y
finally:
f1.close()
#now plot the data on a graph
#plt.scatter(x=[long_input], y=[lat_input], s = 45, c='b') #sets your home position
plt.xlabel('Longitude')
plt.ylabel('Latitude')
plt.title('POSITION (in Decimal Degrees)')
#lay the image under the graph
#read a png file to map on
im = plt.imread('map.png')
implot = plt.imshow(im,extent=[BLX, TRX, BLY, TRY])
plt.show()
def save_raw():
#this fxn creates a txt file and saves only GPGGA sentences
while 1:
line = ser.readline()
line_str = str(line)
if(line_str[4] == 'G'): # $GPGGA
if(len(line_str) > 50):
# open txt file and log data
f = open('nmea.txt', 'a')
try:
f.write('{0:}'.format(line_str))
finally:
f.close()
else:
stream_serial()
def scan():
#scan for available ports. return a list of tuples (num, name)
available = []
for i in range(256):
try:
s = serial.Serial(i)
available.append( (i, s.name))
s.close() # explicit close 'cause of delayed GC in java
except serial.SerialException:
pass
return available
def stream_serial():
#stream data directly from the serial port
line = ser.readline()
line_str = str(line)
print line_str
def thread():
#threads - run idependent of main loop
thread1 = threading.Thread(target = save_raw) #saves the raw GPS data over serial while the main program runs
#thread2 = threading.Thread(target = user_input) #optional second thread
thread1.start()
#thread2.start()
def user_input():
#runs in main loop looking for user commands
print 'hit a for altitude map'
print 'hit p for position map'
print 'hit e to exit'
tester = raw_input()
if tester == 'a':
altitude()
if tester == 'p':
position()
if tester == 'e':
sys.exit()
########START#####################################################################################
check_serial()
#main program loop
while 1:
user_input() # the main program waits for user input the entire time
ser.close()
#sys.exit()