Project - GPS

This project demonstrates how to retrieve and make sense of the data from a NEO-6M GPS Module (costing less than a fiver from ebay).

Other modules can be used, but may have a different serial baud rate,

The Neo-6M defaults to 9600, so needs to use software serial2 for the moment until it is possible to change the speed of hardware serial.

Using software serial for the GPS module leaves the hardware serial available for 'printing' out the satellite data to serial monitor.

It is possible to test the module without even using an esp module, by directly connecting it to computer via a serial to usb UART (as used for flashing) and using free windows software such as:  https://www.u-blox.com/en/u-center-download-windows

It's a quick way to confirm that your module is working correctly and sending back useful data, and it's nice to see where you are on google earth.
It also gives an idea of some of the logging and charting and tracking possibilities available.

When initially powered up it will not have any useful data to send until it has aquired tracking lock on at least 5 satellites, which will then cause it to flash a blue LED to indicate it has tracking lock.
An onboard battery or super-capacitor can hold the satellite info if the module is powered off, but it is not very 'super', so won't hold it very long.
 
While tracking GPS satellites the module will keep issuing data in the form of NMEA 'sentences', I found out what I needed to know about them from:   http://www.gpsinformation.org/dale/nmea.htm    but there are many other websites offering similar information.

Basically an NMEA sentence is a comma-delimited string of data - different sentence 'types' sending out different details.
All sentences start with $GPxxx and end with a checksum prefixed with * (ie:*nn) followed by ascii carraige-return+linefeed.

The Neo-6M will run from 3.3v or 5v, and in normal use only requires its TX to connect to a receivers RX (unless you wish to re-program it).
The following snippet receives GPS data into serial2 RX pin 5 and sends the raw characters straight out for viewing on the serial port monitor...

serial2.mode 9600, 4, 5
onserial2 gpschr:
wait

gpschr:
print serial2.chr$;
return

This next snippet pauses long enough to allow several sentences to be read into a string, then prints the string out to the serial monitor...

serial2.mode 9600, 4, 5
onserial2 gpsinput:
wait

gpsinput:
pause 150
gpsdata$ = serial2.input$
print gpsdata$
return


I don't know why the character data shows sentence types that don't appear in the string data and vice versa, but I wasn't bothered enough to find out, because for my purposes I was only interested in 2 types anyway, $GPRMC and $GPGGA to get all the info I wanted.

They both return...
TIME
LATITUDE
LONGITUDE

In addition $GPGGA returns
ALTITUDE

And $GPRMC returns
GROUND SPEED
DIRECTION
DATE

Unfortunately the same info is returned in different positions in different sentence types, but the following script manages the juggling.


When run, notice that the numbered comma-delimited fields show data differently and in different places when selecting different sentence 'types' from the listbox, but the available data is displayed in the correct appropriate fields below for both the $GPRMC and $GPGGA sentences.

The Exit button was added to disable serial2 branching on exit to try to prevent the frequent 'exception error' rebooted disconnectionss, but it didn't seem to make any difference. Strangely the errors occur after the script has been stopped rather than during its execution, but perhaps it may be more stable if and when hardware serial becomes available. Eventually I hope to use it in my camper as a means of syncing date and time without
internet access rather than using an RTC, and if sufficient storage media becomes available (ie: SD) it should be possible to data-log travels and overlay the journeys onto google earth maps... but that's something for the future.

Basic:
option.lowram 10000
options$ = "$GPRMC,$GPGGA,$GPGSA,$GPVTG"
choice$ = "$GPRMC"
gosub clear
gpsdat$ = ""
gpsdate$ = ""
gpstim$ = ""
gpstime$ = ""
gpslat$ = ""
gpshem$ = ""
gpslon$ = ""
gpsdir$ = ""
gpsalt$ = ""
gpsmet$ = ""
gpsspd$ = ""
gpsang$ = ""
gosub paint
onhtmlreload paint
'                            TX  RX  (Only RX is needed)
serial2.mode 9600, 4, 5
onserial2 gpsinfo:
'onserial2 gpsinput:
'onserial2 gpschr:
wait

paint:
cls
refresh
a$ = ""
a$ = a$ + |<style> td {padding-right:20px;} </style>|
a$ = a$ + |<table style='text-align:right;'>|
a$ = a$ + |<tr><td>| + "1" + |</td><td>| + textbox$(w1$,"win100") + |</td></tr>|
a$ = a$ + |<tr><td>| + "2" + |</td><td>| + textbox$(w2$,"win100") + |</td></tr>|
a$ = a$ + |<tr><td>| + "3" + |</td><td>| + textbox$(w3$,"win100") + |</td></tr>|
a$ = a$ + |<tr><td>| + "4" + |</td><td>| + textbox$(w4$,"win100") + |</td></tr>|
a$ = a$ + |<tr><td>| + "5" + |</td><td>| + textbox$(w5$,"win100") + |</td></tr>|
a$ = a$ + |<tr><td>| + "6" + |</td><td>| + textbox$(w6$,"win100") + |</td></tr>|
a$ = a$ + |<tr><td>| + "7" + |</td><td>| + textbox$(w7$,"win100") + |</td></tr>|
a$ = a$ + |<tr><td>| + "8" + |</td><td>| + textbox$(w8$,"win100") + |</td></tr>|
a$ = a$ + |<tr><td>| + "9" + |</td><td>| + textbox$(w9$,"win100") + |</td></tr>|
a$ = a$ + |<tr><td>| + "10" + |</td><td>| + textbox$(w10$,"win100") + |</td></tr>|
a$ = a$ + |<tr><td>| + "11" + |</td><td>| + textbox$(w11$,"win100") + |</td></tr>|
a$ = a$ + |<tr><td>| + "12" + |</td><td>| + textbox$(w12$,"win100") + |</td></tr>|
a$ = a$ + |<tr><td>| + "13" + |</td><td>| + textbox$(w13$,"win100") + |</td></tr>|
a$ = a$ + |<tr><td>| + "14" + |</td><td>| + textbox$(w14$,"win100") + |</td></tr>|
a$ = a$ + |<tr><td>| + "15" + |</td><td>| + textbox$(w15$,"win100") + |</td></tr>|
a$ = a$ + |</table>|
a$ = a$ + |<br><br>|
a$ = a$ + "Sentence: " + listbox$(choice$,options$,"win100") + string$(10,"&nbsp;")
a$ = a$ + "Time:" + textbox$(gpstime$,"win70") + string$(10,"&nbsp;")
a$ = a$ + "Date:" + textbox$(gpsdate$,"win70") + string$(10,"&nbsp;")
a$ = a$ + "Lat:" + textbox$(gpslat$,"win100") + " " + textbox$(gpshem$,"win25") + string$(10,"&nbsp;")
a$ = a$ + "Lon:" + textbox$(gpslon$,"win100") + " " + textbox$(gpsdir$,"win25") + string$(10,"&nbsp;")
a$ = a$ + "Alt:" + textbox$(gpsalt$,"win50") + " " + textbox$(gpsmet$,"win25") + string$(10,"&nbsp;")
a$ = a$ + "Speed:" + textbox$(gpsspd$,"win50") + string$(10,"&nbsp;")
a$ = a$ + "Angle:" + textbox$(gpsang$,"win50") + "<br><br><br>"
a$ = a$ + cssid$("win25","width:25px;")
a$ = a$ + cssid$("win50","width:50px;")
a$ = a$ + cssid$("win70","width:70px;")
a$ = a$ + cssid$("win100","width:100px;")
a$ = a$ + button$("Exit",serial2exit) + |<br>|
refresh
html a$
return

gpsinfo:
pause 170
'start = millis
gpsdat$ = serial2.input$
type$ = choice$
sentence$ = ""
pos = instr(gpsdat$,type$)
if pos > 0 then
 sentence$ = mid$(gpsdat$,pos)
 'pos = instr(sentence$,chr$(13))
 pos = instr(sentence$,"*")
 if pos > 0 then sentence$ = left$(sentence$,pos + 2)
 if instr(sentence$,type$) = 1 then
  w1$ = word$(sentence$,1,",")
  w2$ = word$(sentence$,2,",")
  w3$ = word$(sentence$,3,",")
  w4$ = word$(sentence$,4,",")
  w5$ = word$(sentence$,5,",")
  w6$ = word$(sentence$,6,",")
  w7$ = word$(sentence$,7,",")
  w8$ = word$(sentence$,8,",")
  w9$ = word$(sentence$,9,",")
  w10$ = word$(sentence$,10,",")
  w11$ = word$(sentence$,11,",")
  w12$ = word$(sentence$,12,",")
  w13$ = word$(sentence$,13,",")
  w14$ = word$(sentence$,14,",")
  w15$ = word$(sentence$,15,",")
  select case type$
  case "$GPRMC"
   gpstim$ = w2$
   gpstime$ = Str$(val(left$(gpstim$,2))+1) + ":" + mid$(gpstim$,3,2) + ":" + mid$(gpstim$,5,2)
   gpslat$ = w4$
   gpshem$ = w5$
   gpslon$ = w6$
   gpsdir$ = w7$
   gpsspd$ = w8$
   gpsang$ = w9$
   gpsdat$ = w10$
   gpsdate$ = Str$(val(left$(gpsdat$,2))+1) + "/" + mid$(gpsdat$,3,2) + "/" + mid$(gpsdat$,5,2)
   gpsalt$ = ""
   gpsmet$ = ""
  case "$GPGGA"
   gpstim$ = w2$
   gpstime$ = Str$(val(left$(gpstim$,2))+1) + ":" + mid$(gpstim$,3,2) + ":" + mid$(gpstim$,5,2)
   gpslat$ = w3$
   gpshem$ = w4$
   gpslon$ = w5$
   gpsdir$ = w6$
   gpsalt$ = w10$
   gpsmet$ = w11$
   gpsspd$ = ""
   gpsang$ = ""
   gpsdate$ = ""
  case else
   gpstim$="": gpslat$="": gpshem$="": gpslon$="": gpsdir$="": gpsalt$="": gpsmet$="": gpsspd$="": gpsang$="": gpsdate$=""
  end select
 else
  gosub clear
 endif
endif
refresh
return

serial2exit:
onserial2 off
end
return

clear:
w1$="": w2$="": w3$="": w4$="": w5$="": w6$="": w7$="": w8$="": w9$="": w10$="": w11$="": w12$="": w13$="": w14$="": w15$=""
refresh
return

gpsinput:
pause 150
gpsdata$ = serial2.input$
print gpsdata$
return

gpschr:
print serial2.chr$;
return


'-------------------- End ---------------------