In this post I’m going to write about my experiments with interfacing a low-cost serial GPS module directly to uLisp, to create projects such as a GPS clock:
I’ll also describe a GPS speedometer and odometer, and a simple navigator, in later posts.
The module I used is the GP-20U7, a small GPS module available for under $20 from SparkFun GPS Receiver – GP-20U7 (56 Channel) 11, but almost any other GPS module should be suitable.
The GPS Clock and GPS Speedometer/Odometer will work on any version of uLisp, with sufficient memory, such as the Arduino Mega 2560. The simple navigator requires a 32-bit version of uLisp, running on a board such as the Adafruit ItsyBitsy M0.
The first step is to connect the GPS module to your microcontroller’s Rx input; see Language reference – with-serial 7 for details of which pin to use on your board. Then run the following echo program:
(defun echo () (with-serial (str 1 96) (loop (print (read-line str)))))
At first, before the GPS module has locked onto any satellites, you’ll see something like:
If all is well, after a few seconds you should see lines with the time, followed after a minute or so by lines with location data:
$GPGSV,4,4,13,31,13,032,29*41 $GPGLL,5213.12861,N,00008.23883,E,111152.00,A,A*6D $GPRMC,111153.00,A,5213.12851,N,00008.23852,E,0.408,,101119,,,A*7F $GPVTG,,T,,M,0.408,N,0.756,K,A*2B $GPGGA,111153.00,5213.12851,N,00008.23852,E,1,07,1.26,9.2,M,45.7,M,,*59
GPS modules output the GPS information as a series of text strings, called NMEA sentences. Each NMEA sentence starts with an identifier such as $GPRMC, to identify the sentence, followed by the GPS parameters such as latitude and longitude, separated by commas. The string is terminated by an asterisk and two-digit checksum.
The most useful NMEA sentence is the RMC (Recommended Minimum C) one:
This contains all the most important navigational parameters: time, latitude, longitude, speed, course, and date. The fields in the above example are as follows:
- 113211.00 – Time is 11:32:11 and 00 milliseconds UTC
- A – Status, A=active or V=void
- 5213.12667,N – Latitude 52° 13.12667’ N
- 00008.22177,E – Longitude 0° 8.22177’ E
- 4.955 – Ground speed 4.955 knots
- 266.36 – Course 266.36°
- 101119 – Date 10th November 2019
- A – Mode, A=autonomous, D=differential, E=estimated
- *64 – The checksum
Note that most fields are fixed width, but the ground speed and course are variable width, and if the GPS module is stationary the course may be blank.
Selecting the RMC sentences
The next step is to select just the RMC sentences; here’s the revised version of echo :
(defun echo () (with-serial (str 1 96) (loop (let ((line (read-line str))) (when (and (> (length line) 7) (string= (subseq line 0 7) "$GPRMC,")) (print line))))))
You should now get just one RMC sentence printed every second.
Parsing the RMC sentences
The third step is to parse the parameters from the RMC sentence by extracting the substrings between successive commas. This new version of echo now calls a function parse on each RMC sentence:
(defun echo (fun) (with-serial (str 1 96) (loop (let ((line (read-line str))) (when (and (> (length line) 7) (string= (subseq line 0 7) "$GPRMC,")) (parse line fun))))))
Here’s the definition of parse :
(defun parse (line fun) (let ((start 7) (end (length line)) i result) (loop (setq i start) ; Find comma (loop (when (or (= i end) (eq (char line i) #\,)) (return)) (incf i)) ; Extract parameter (push (if (= start i) nil (subseq line start i)) result) (setq start (1+ i)) (when (= i end) (return))) ; Call function on result (funcall fun (reverse result))))
It splits the string into a list of substrings, one for each parameter. Finally, it calls the function you provide as a parameter on the list of strings. For example, if you do:
it will simply print the list of strings for each RMC sentence, one per second:
("193409.00" "A" "5213.12667" "N" "00008.22177" "E" "2.881" nil "271119" nil nil "A*7D")
Our GPS applications can now simply get the appropriate GPS data from this list; for example the latitude is:
The first project is a GPS clock that takes advantage of the accuracy of the atomic clocks used by the GPS system to provide an accurate time display in hours, minutes, and seconds on an eight digit 7-segment display.
Read more: GPS CLOCK USING ULISP