With the release of the Raspberry Pi 3 Model B+ we wanted to create a project that would use the new Pi board in a fun and engaging way. So The Raspberry Pi 3 Model B+ Treasure Tracker was born. With this device, users can place treasure upon a map, and use GPS to track their progress to the treasure.
Step by Step Guide
- 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
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.txtGo 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=1Now 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.txtIt 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 rootwaitNow 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 hciuartWe next edit the hciaurt service so that it uses the correct UART device (ttyS0) In the terminal type
sudo nano /lib/systemd/system/hciuart.serviceThen find the line starting
After=dev-serial1.deviceand 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/ttyS0You 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 rebootThis 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.serviceReboot 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-gpsIn 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.socketNow lets tell GPSD where to find our GPS unit. In the terminal type
sudo gpsd /dev/ttyS0 -F /var/run/gpsd.sockNow 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.
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 microstacknodeOnce 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.
Now lets install another Python3 library that will enable our project to create points on a live Google map. Gmplot is used to plot objects, areas and information on top of an existing Google map. It is easy to use and the data plotted to the map is in keeping with the Google branding, but we can also change things to meet our needs. To install gmplot in a terminal type the following
sudo pip3 install gmplot
Once installed we are finally ready to start coding the project!
The Raspberry Pi 3B + Treasure Tracker
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
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 python3We next start importing the libraries that we need.
- 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.l80gpsIn order to use the Microstack GPS we need to create an object that we can reference, as
microstacknode.hardware.gps.l80gpsis 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,Zoo,Amusement_Park] longitudes = [Tower,Zoo,Amusement_Park]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
gmap.draw("mymap.html")The last line of this section is where we use
subprocessto 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.
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. The code then waits for five seconds before repeating the process.
gmap = gmplot.GoogleMapPlotter(lat, long, 20) gmap.heatmap(loc_lat,loc_long) time.sleep(5)
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.
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.
<meta http-equiv="refresh" content="5">
<iframe src="mymap.html" width=800px height=480px>
<p>Your browser does not support iframes.</p>
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
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
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)
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!