Raspberry Pi 3 B+ GPS Treasure Tracker
With the release of the Raspberry Pi 3 B+ we wanted to create a project that would use the new Pi in a fun and engaging way. So The Raspberry Pi 3B+ Treasure Tracker was born. With this device, users can place treasure upon a map, and use GPS to track their progress to the treasure.
For this project we will need
- A Raspberry Pi 3B +
- The official Raspberry Pi Screen
- A Microstack Baseboard
- A Microstack GPS
- GPS Antenna
- Enclosure for the project
- USB battery with 2 outputs (1 @ 2A > and another @ 1A >)
- 2 x micro USB to USB A leads
- A 3G/4G Mobile wireless device or hot spot.
Raspberry Pi 3 B +?
Yes we have a new Raspberry Pi! This incremental update to the original Raspberry Pi 3 offers a slightly faster quad core CPU (1.4Ghz) 1 GB RAM but the real improvement is with the networking. There is new WiFi! Via wireless ac (5GHz) which joins the already great wireless package (2.4GHz b/g/n) and we also have Bluetooth 4.2 and BLE! Not to feel left out, the Ethernet has been beefed up to around 300Mb/s thanks to using a LAN7515 chip over a USB2.0 interface. So now we have much better Ethernet speeds, still not Gigabit, but enough...well until the Pi 4 comes out. Along side the now standard 40pin GPIO we see four new pins marked PoE, Power over Ethernet. Yes this Pi can be powered over PoE via a new add on board, available soon! So with the power of the new Raspberry Pi 3 B + we can create our own GPS Treasure Tracker. So what are we waiting for?
Building the kit
With the Raspberry Pi 3 B + powered down, connect the Raspberry Pi 3B + to the official screen via the instructions included with the kit.
We shall be powering the screen from a separate micro USB power supply as the GPIO pins will be in use.
Now attach the Microstack add on board to the first 26 pins of the GPIO, these are the pins nearest the micro SD slot.
Now attach the Microstack GPS unit to the Microstack board, the location of the connections for the GPS unit are quite clearly marked on the Microstack board, and the GPS unit will only fit in one way.
Connect the antenna to the GPS unit but do not allow the metal connectors to touch the Raspberry Pi as this will create a short. Power up the Raspberry Pi and boot to the desktop and we start by configuring the Raspberry Pi 3 B + to use UART. On previous models of Pi (up to Pi 3) UART was found at /dev/ttyAMA0 but that is now used by Bluetooth, and from Pi 3 onwards we can now find the UART device at /dev/ttyS0. But first we need to tell the Pi so. In a terminal type in the following to go to the config.txt document
sudo nano /boot/config.txt
Go to the end of the document and make a new line, then add the following.
#Enable UART for Pi 3 dtparam=spi=on dtoverlay=pi3-disable-bt-overlay core_freq=250 enable_uart=1 force_turbo=1
Now close the editor by pressing CTRL + X, then Y and finally Enter.
Now lets edit the cmdline.txt file which Raspbian uses every time it boots. We need to remove a reference to “console=serial0,115200” and keep “console=tty1”.
In the terminal type
sudo nano /boot/cmdline.txt
It should look similar to this but only change what we have said, leave the rest as it is! Otherwise you Pi may not boot.
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
Now close the editor by pressing CTRL + X, then Y and finally Enter.
To ensure that Bluetooth does not interfere with the UART0 device, we first need to disable the service. In the terminal type.
sudo systemctl disable hciuart
We next edit the hciaurt service so that it uses the correct UART device (ttyS0)
In the terminal type
sudo nano /lib/systemd/system/hciuart.service
Then find the line starting “After=dev-serial1.device” and change it to “After=dev-ttyS0.device”
Now close the editor by pressing CTRL + X, then Y and finally Enter.
With the antenna connected and hung outside of a window for the test, in the terminal enter this command to see the raw output from the GPS unit. It may take your GPS unit a few minutes to get a signal but as long as it can see the sky, it will connect.
sudo cat /dev/ttyS0
You should see raw data stream across the screen, you may be able to see your longitude and latitude as it races across the screen. With the test completed, now we move to installing the software for the project, and for this we need to ensure the system is up to date and that we have the latest software. In a terminal window type.
sudo apt update && sudo apt upgrade -y && sudo reboot
This may take a while, but once completed the system will reboot to ensure all of the changes have been made. After a few minutes you will see the Raspbian desktop again, and you will need to open a new terminal window.
We shall stop and disable the tty service as if left running it may generate a few issues. In the terminal type
sudo systemctl stop serial-getty@ttyS0.service sudo systemctl disable serial-getty@ttyS0.service
Reboot the Raspberry Pi and then return to the Raspbian desktop, open the terminal once more, in here we shall install the software for GPS. In the terminal type.
sudo apt-get install gpsd gpsd-clients python-gps
In order to use GPSD correctly with Raspbian we need to stop and disable a service started by installing GPSD as if left as is it will cause issues for the project. In the terminal enter the following commands to do this.
sudo systemctl stop gpsd.socket sudo systemctl disable gpsd.socket
Now lets tell GPSD where to find our GPS unit. In the terminal type
sudo gpsd /dev/ttyS0 -F /var/run/gpsd.sock
Now we can test to see if our GPS unit is reporting the correct location. In the terminal use the cgps command to open a client that will tell us everything about our device, and hopefully our location.
cgps -s
So where am I?
In cgps we can see that our latitude and longitude have been found. But how do we check that this is correct? The easiest way is to open http://maps.google.co.uk and once loaded look in the address bar. You will see two numbers. First we have the latitude our position as an angle between north and south. The second number is our longitude, our position east to west as an angle. Replace these numbers with those from cgps and you will see the map centre on your GPS location.
Installing the Python Libraries
The Microstack baseboard on to which our Microstack GPS sits, requires a little configuration in order to be used. We need to enable I2C and SPI on our GPIO and to do this we need to go to the Raspbian menu >> Preferences >> Raspberry Pi Configuration. In there select Interfaces and Enable I2C and SPI. Click Ok and for good measure reboot the Pi.
Now back to the terminal!
We now need to install the Microstack Node Python 3 library, so in a terminal type
sudo pip3 install microstacknode
Once installed, lets check that our Python library can connect and use the Microstack GPS. In your favourite Python 3 editor (IDLE, or Thonny) enter the following code to check our GPS location every two seconds.
import microstacknode.hardware.gps.l80gps import time gps = microstacknode.hardware.gps.l80gps.L80GPS() while True: data = gps.get_gprmc() lat = data.get("latitude") long = data.get("longitude") print(lat,long) time.sleep(2)
Save the code as GPSTest.py and then run the code and you should see your position appear in the Python shell.
Google Maps
All across my home town of Blackpool, there is treasure! Not gold or rubies, or bitcoin, rather cultural treasures such as Blackpool Tower, The Blackpool Pleasure Beach (amusement park) and Blackpool Zoo. So lets create a Treasure Tracker that will point us to those locations. But first we need to find those locations on a map.
Open Google Maps once again, and locate these places (or choose your own, as it is a long walk from Australia to Blackpool)
Tower = (53.8159877,-3.0554085) Zoo = (53.8157874,-3.0107095) Amusement_Park = (53.7924182,-3.0556338)
Make a note of the latitude and longitude, in the above example we have noted them as objects called tuples, which we can later use in the code.
Open up your favourite Python editor and lets start coding the project! Oh but first ensure that you save the project as “micromapper.py”
We start by using a line that will later enable our code to be run as an executable, this line tells the code where to find the Python 3 interpreter.
#!/usr/bin/env python3
We next start importing the libraries that we need and they are...
- gmplot = Plotting data on a Google map
- subprocess = Enables us to use Linux commands via Python
- time = Used to control the time between screen updates
import gmplot, subprocess, time import microstacknode.hardware.gps.l80gps
In order to use the Microstack GPS we need to create an object that we can reference, as “microstacknode.hardware.gps.l80gps” is rather a lot to type. So lets call it gps and store the reference in there.
gps = microstacknode.hardware.gps.l80gps.L80GPS()
Next we use the locations chosen and store their data as tuples (Python data type that separates values using a comma. Tuples are immutable, meaning they cannot be updated, so need to be destroyed and recreated as a whole new object)
Tower = (53.8159877,-3.0554085) Zoo = (53.8157874,-3.0107095) Amusement_Park = (53.7924182,-3.0556338)
In order for us to use the location data, we need to split the data into latitudes and longitudes. To do this we shall use two lists (comma separated data type that is mutable, so it can be updated) the first will contain the latitudes of the locations, and the other the longitudes. To extract these from the tuples we tell the list that for the latitudes we wish to extract the first item in the tuple, this is at position 0 (Python starts counting from 0). For the longitudes we tell the list that we need the data from position 1 in each tuple.
latitudes = [Tower[0],Zoo[0],Amusement_Park[0]] longitudes = [Tower[1],Zoo[1],Amusement_Park[1]]
So now that we have our locations, lets find out where we are. We tell Python to wait for 2 seconds before moving onwards.
time.sleep(2)
Then we create an object called “data” that we use to shorten the function that will query the Microstack GPS for information.
data = gps.get_gprmc()
To extract the latitude and longitude data we need to call our new “data” object with an argument to retrieve the information. This is then stored in two variables, lat and long. For debug purposes we then print this information to the Python shell.
lat = data.get("latitude") long = data.get("longitude") print(lat,long)
We next create two lists, used to store the location data saved to our variables lat and long. We need to use a list as we the function used later will need an iterable object, which a list is.
loc_lat = [lat] loc_long = [long]
Now lets get to the code that will centre a Google map on to the users current location. For this we need to create an object called “gmap” and then use that to set the latitude and longitude from the GPS, and set the map to level “20” which zooms the window to nearby street level, but feel free to change this to meet your needs.
gmap = gmplot.GoogleMapPlotter(lat, long, 20)
With the map centred, it would be prudent to locate the user. So to do this we use a heat map, normally used to identify areas of high activity, but in this case it looks like a thermal image of a person from space or it looks like the Predator (80s movie) is on the treasure hunt. When using the heat map we need to iterate over values in a list. In this case there is only one value per list, this is because we are not using the heat map for its true purpose. Really we should be using it to iterate over multiple items in lists and then plotting these hot spots on the map. But we are using it just to identify the user.
gmap.heatmap(loc_lat,loc_long)
With the user located, now we need to scatter the “treasure” across the map. And for this we scatter red makers across the map. We have all seen these markers on Google Maps before. We tell gmplot to use the data stored in the lists “latitudes” and “longitudes” as the location, then ‘r’ denotes a red marker.
gmap.scatter(latitudes, longitudes, 'r', marker=True)
With the user located and the treasure plotted it is now time to create the map. Gmplot can create the HTML needed for the map and in this case we save it as “mymap.html”
gmap.draw("mymap.html")
The last line of this section is where we use “subprocess” to call the Chromium browser in full screen mode and open a specially created HTML page (more on that later.) The syntax of the subprocess.call function is that the command and any parameters / arguments need to passed as items in a list. So we wrap the contents in square brackets “[ ]” and separate the contents using commas. Note that this assumes that you have saved your code to the directory GPS_Treasure_Hunt, so change this to match your own setup.
subprocess.call(["chromium-browser"," --start-fullscreen"," /home/pi/GPS_Treasure_Hunt/frame.html"])
Moving on we now get to the main loop that will continually show the location of the user and update the map to show the direction in which they are moving. Here we use the same “data” object to connect to the GPS unit, then we store the user location into the two variables “lat” and “long”, this is then printed to the Python shell for debug purposes.
while True: data = gps.get_gprmc() lat = data.get("latitude") long = data.get("longitude") print(lat,long)
In the next part of this code we centre the map on the user and plot their location using a heat map. Then we update the values stored inside the loc_lat and loc_long lists, printing the values to the shell for debug and then setting the values for our user location, via the heat map.
gmap = gmplot.GoogleMapPlotter(lat, long, 18) loc_lat = [lat] loc_long = [long] print(loc_lat, loc_long) gmap.heatmap(loc_lat,loc_long)
We lastly update the map data, and then instruct the code to wait for 5 seconds before repeating the process.
That is all the code for this part of the project. Save the code but don’t run it just yet as we need to create an HTML frame to store the Python generated map, and to update the contents.
The HTML
Our Treasure Tracker map is generated and updated by the Python code, but the contents are not dynamically updated in the browser. In order to do this we need to create a new web page, into which we use a http refresh, in the head of the HTML document, to reload the page.
Our Python generated map is stored in “mymap.html” and using an iframe, an HTML inline frame, we can open the map inside our web page and specify the size of the iframe to match the resolution of the screen, in this case the official Pi screen is 800 pixels wide, by 480 tall. Using a notepad editor, create this file and save it as “frame.html” inside the same directory as the Python code that we have just written.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="refresh" content="5">
</head>
<body>
<iframe src="mymap.html" width=800px height=480px>
<p>Your browser does not support iframes.</p>
</iframe>
</body>
</html>
Give the code a test!
Head back over to the Python code and save your work, then run the code (Run >> Run Module for IDLE)
You should see the code start in the Python shell, and if you are quick you will see the GPS coordinates printed to the shell. But what we really want to see is the map, and after a few seconds you will see a new browser window open, and the map will appear, a few seconds more and the map will update to show the position of the user. Walk around the streets and see the map update!
Set the code to auto run
Our code is completed, but in order to automate the process we need to ensure that it runs from boot. So we need to take two steps. The first is to make the Python code executable, and to do this we need to open the terminal and ensure that we are in the same directory as our code and then enter the following command.
chmod +x micromapper.py
We can test that the command works by typing
./micromapper.py
The second part of the process is to add a line to cron so that the code will run on boot. To do this we again need the terminal and enter the command
crontab -e
If you are asked to choose an editor, pick nano, unless you already have a favourite terminal editor.
In the editor scroll to the bottom of the document and type the following (which assumes that our code is saved to /home/pi)
@reboot /home/pi/micromapper.py
Now close the editor by pressing CTRL + X, then Y and finally Enter.
Lets test the code! Reboot the Raspberry Pi 3B + and once it has rebooted we will see the Raspbian desktop, and our Treasure Hunter application will launch!
We’ve done it!
We’ve made our own Raspberry Pi 3 B + powered treasure tracker! Now all we need to do is place it in a case, plastic boxes or a 3D printed enclosure would be perfect. We used the Smarti Pi case as it held the screen perfectly. Once you have a case, go for a walk and enjoy searching for your treasures!