Add GPS to Your Raspberry Pi Project with Google Maps

7 min readDec 22, 2022

What was once a tool developed by the US Navy to locate submarines, today’s abundance of satellites in orbit and advancements in technology have granted GPS (Global Positioning System) access to anyone. Although the technology has come in different forms since its original inception, most users access GPS location functionality through applications on their web and mobile devices. GPS applications are used in every industry, ranging from mapping services with Google and Apple Maps, fleet transportation and delivery applications like Uber and Doordash, proximity chat with Snapchat, and even video games such as Pokémon Go.

In this article, you'll learn how to add GPS capabilities to a Raspberry Pi (RPi) with a GPS Module Breakout written in Python, which is used as the GPS receiver to obtain information. This hardware will act as the GPS device to retrieve GPS coordinates. To power the functionality of GPS, you'll use PubNub's Geolocation APIs via the PubNub Python SDK. Although this tutorial will guide you step-by-step in setting up and building the tutorial, you can find the source code of the application in the GitHub repository.

This post contains information that may not be entirely up to date. However, this article still contains valuable insights into setting up and retrieving GPS coordinates using a Raspberry Pi and GPS module all in real time with PubNub. You can check out the tutorial below!

Raspberry Pi GPS Tracker Environment Set up

This tutorial will require the following physical hardware to complete this tutorial.

  • Raspberry Pi 3. The single-board computer used in this tutorial is from Adafruit.

  • Wires (Female to Female)

  • GPS Module Breakout. The GPS Module used in this tutorial is from Adafruit and is used to retrieve the GPS raw data.

  • Soldering Iron Kit.

  • (Optional) An LTE shield (if you want to use GPS without WiFi). This LTE shield used in this tutorial is from Sixfab.

PubNub Account

To power the GPS functionality on the Raspberry Pi, you'll need to create a free PubNub account and obtain the publish/subscribe API keys necessary to communicate on PubNub's communication platform. You can learn how to create your keys by following this how-to guide.

When setting up your PubNub keys, you'll need to enable Presence for the PubNub to detect when you and other clients connect to the network, as well as Message Persistence to save messages across PubNub.

Raspberry Pi Board Set up

Soldering

In order to easily connect wires to the module and RPi, you’ll need to first solder the pins on the GPS Breakout module using the soldering iron.

GPS Breakout Module

Insert the pins from the GPS module (short side first) into the top of the module (the side with the pin labels) and solder the pins to the board. If you are new to soldering, please watch this video first, as you can severely burn yourself.

The GPS breakout module will look like the following once you've finished soldering.

GPS Breakout Module - Complete

Wiring

Since this GPS breakout module is being used with the RPi, you’ll need to have access to the Raspberry Pi’s UART (Universal Asynchronous Receiver-Transmitter) interface. For the purposes of this tutorial, this interface is the best way to send and receive data serially from the GPS breakout module to the RPi rather than through a USB port. The TX (transmitter) pin of the GPS module sends bits to the RPI's RX (receiver) pin and vice versa.

Wire the GPS breakout module to the RPi as shown. Connect the Raspberry Pi to your computer to act as the power supply and program the computer board.

Raspberry Pi & GPS Breakout Module Connection

(Optional): 3G/4G LTE Connectivity

If you would like to have the Raspberry Pi have GPS capabilities without WiFi or Bluetooth dependence, then you’ll need to use an LTE shield. If you purchased the LTE shield discussed earlier, follow this setup to connect the shield to the RPi, and download the necessary libraries, packages, and GitHub repositories to run the software on the hardware.

Install Python3 and pip3

This tutorial is written using Python3. Install this version of Python, add Python to PATH, and ensure you have pip3 installed.

Enable Remote Access

You need to enable remote access on the RPi before continuing in the tutorial. Learn how to do so by following Raspberry Pi's official documentation.

Enable UART on the Raspberry Pi

Open a terminal/console, and SSH in the RPi. Run the following command to open The Raspberry Pi Software Configuration Tool (raspi-config), which allows you to enable/disable specific features for the RPi.

sudo raspi-config

Follow the steps to enable UART.

  1. Select Interfacing Options.

  2. Select P6 Serial

  3. Do not allow a login shell to be accessible over serial.

  4. Allow the serial port hardware to be enabled.

Then reboot the RPi with the following command.

sudo reboot

Configure I2C

You will need to use the CircuitPython Library that is used later on in the tutorial, as many of the I2C drivers require this library. This library is a 2-wire bus protocol that allows one chip to communicate with another.

SSH into the RPi and install the I2C tools utility with the following commands.

sudo apt-get install -y python-smbus
sudo apt-get install -y i2c-tools

For this library to correctly function. you also need to install Kernal Support. Open the RPi software configuration tool.

sudo raspi-config

Install Kernal Support by following the correct menu options.

  1. Select Interfacing Options.

  2. Select I2C.

  3. Enable the ARM I2C interface.

  4. Enable the I2C kernel module to be loaded by default.

Then reboot the RPi.

sudo reboot

Configure SPI

SPI (Serial Peripheral Interface) is another bus protocol that synchronizes serial data communication between chips and will need to be configured for this tutorial. SSH into your RPi and open the RPi Software Configuration Tool.

sudo raspi-config

Configure SPI by following the steps below.

  1. Select Interfacing Options.

  2. Select SPI.

  3. Enable the SPI interface to be enabled.

Then reboot the RPi.

sudo reboot

Verify Hardware

To ensure that the previous steps were performed correctly, you will be running a test script to verify that all the necessary hardware protocols are enabled.

SSH into the RPI and create a working directory for your project.

mkdir gps
cd gps

Install the Raspberry Pi GPIO and Adafruit's test libraries using pip.

pip3 install RPI.GPIO
pip3 install adafruit-blinka

Create the test script named blinkatest.py with nano.

nano blinkatest.py

Copy and paste the following Python code into the test Python script and save.

import board
import digitalio
import busio
 
print("Hello blinka!")
 
# Try to great a Digital input
pin = digitalio.DigitalInOut(board.D4)
print("Digital IO ok!")
 
# Try to create an I2C device
i2c = busio.I2C(board.SCL, board.SDA)
print("I2C ok!")
 
# Try to create an SPI device
spi = busio.SPI(board.SCLK, board.MOSI, board.MISO)
print("SPI ok!")
 
print("done!")

Run the test script with the following command.

python3 blinkatest.py

You should receive the following output. If not, go back and repeat the previous steps based on what is failing.

GPS Raspberry Pi - Run Test Script

Install CircuitPython

You'll begin by installing CircuitPython. CircuitPython is based on Python and is targeted at beginners to program microcontrollers easily. This library bundle, as well as the GPS python library for GPS parsing modules, will be used as the starting points of your codebase.

Download the zip (not the source zip) from the latest release of the repository and unzip the contents in your project directory.

cd into the library you just unzipped and then clone the GPS python library to use as the GPS parsing module library. Install any dependencies with the following command.

sudo pip3 install adafruit-circuitpython-gps

Verify Hardware and Software

In order to make sure everything is correctly set up (both hardware and software), you'll be running an example script in the circuitpython-gps library that was just cloned. In your project directory, enter the following commands in the terminal to open the gps_simpletest.py test file.

cd Adafruit_CircuitPython_GPS
cd examples
Nano gps_simpletest.py

In the gps_simpletest.py file, locate and comment out the following lines to ensure the program runs smoothly with the RPi.

RX = board.RX
TX = board.TX
uart = busio.UART(TX, RX, baudrate=9600, timeout=3000)

Next, uncomment the following lines.

#import serial
#uart = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=3000)

The second line that was just uncommented needs to be changed to the following.

#uart = serial.Serial("/dev/ttyS0", baudrate=9600, timeout=3000)

You are now ready to run the code. Ensure that the GPS module has a clear view of the sky and run the code with the following command.

python3 gps_simpletest.py

While the GPS module searches for the GPS satellites in the sky, you will receive the following terminal output.

pasted image 0 14

Once there is a GPS satellite connection, you will receive GPS data readings that could look like the following.

pasted image 0 15

Build and Run

You are now ready to begin implementing code to add GPS functionality to your Raspberry Pi! Instead of creating a whole new file from scratch, you will make a few modifications to the gps_simpletest.py file that was used to test earlier and add PubNub functionality to communicate GPS information in the PubNub network.

In the same directory of your project that contains the gps_simpletest.py file that was tested earlier, install the PubNub Python SDK using the terminal.

pip3 install pubnub

In the gps_simpletest.py file, import the PubNub packages.

import pubnub
from pubnub.pnconfiguration import PNConfiguration
from pubnub.pubnub import PubNub
from pubnub.callbacks import SubscribeCallback
from pubnub.enums import PNOperationType, PNStatusCategory

At the beginning of the file, after the package imports, configure a PubNub instance with your PubNub Publish and Subscribe Keys you obtained earlier. You'll also add a publishing callback to listen for publish events. It will be left as blank for now, as it is not yet needed.

pnconfig = PNConfiguration()
pnconfig.subscribe_key = "YOUR SUBSCRIBE KEY"
pnconfig.publish_key = "YOUR PUBLISH KEY"
pnconfig.ssl = False
pubnub = PubNub(pnconfig)

def publish_callback(result, status):
    pass
    # Handle PNPublishResult and PNStatus

The data to publish will simply be latitude and longitude coordinates. You'll want to publish this data in JSON and can be published in the following way.

dictionary = {"latitude": gps.latitude, "longitude": gps.longitude}
pubnub.publish().channel("CHANNEL").message(dictionary).pn_async(publish_callback)

Visual GPS Data with Google Maps

The final step of this tutorial is to visualize the GPS data in a way that humans can understand. You will create a simple HTML page that will grab GPS data from the PubNub channel and graph the data with a geolocation API. You will be using the Google Maps API to graph the data received by your Raspberry Pi. To be able to use the Google Maps API, you will need to obtain a Google Maps API Key. Learn how to do so from Google's official documentation.

Create a file in your project directory with an .html extension and copy the following code into the file. Where the script tag is using the Google Maps API, replace the value of the key "YOUR_KEY_HERE" with your Google Maps API key. You'll also need to add the subscribe key in the PubNub initialization that you obtained earlier.

<!DOCTYPE html>
<html>
  <head>
    <title>Simple Map</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <style>
      /* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
      #map {
        height: 100%;
      }
      /* Optional: Makes the sample page fill the window. */
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
    <script src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.23.0.js"></script>
  </head>
  <body>
    <div id="map"></div>
    <script>
  // the smooth zoom function
  function smoothZoom (map, max, cnt) {
      if (cnt >= max) {
          return;
      }
      else {
          z = google.maps.event.addListener(map, 'zoom_changed', function(event){
              google.maps.event.removeListener(z);
              smoothZoom(map, max, cnt + 1);
          });
          setTimeout(function(){map.setZoom(cnt)}, 80); // 80ms is what I found to work well on my system -- it might not work well on all systems
      }
  } 
    var pubnub = new PubNub({
    subscribeKey: "YOUR SUBSCRIBE KEY",
    ssl: true
  });	
  var longitude = 30.5;
  var latitude = 50.5;
  pubnub.addListener({
      message: function(m) {
          // handle message
          var channelName = m.channel; // The channel for which the message belongs
          var channelGroup = m.subscription; // The channel group or wildcard subscription match (if exists)
          var pubTT = m.timetoken; // Publish timetoken
          var msg = m.message; // The Payload
          longitude = msg.longitude;
          latitude = msg.latitude;
          var publisher = m.publisher; //The Publisher
    var myLatlng = new google.maps.LatLng(latitude, longitude);
    var marker = new google.maps.Marker({
        position: myLatlng,
        title:"PubNub GPS"
    });
    // To add the marker to the map, call setMap();
    map.setCenter(marker.position);
    smoothZoom(map, 14, map.getZoom());
    marker.setMap(map);
      },
      presence: function(p) {
          // handle presence
          var action = p.action; // Can be join, leave, state-change or timeout
          var channelName = p.channel; // The channel for which the message belongs
          var occupancy = p.occupancy; // No. of users connected with the channel
          var state = p.state; // User State
          var channelGroup = p.subscription; //  The channel group or wildcard subscription match (if exists)
          var publishTime = p.timestamp; // Publish timetoken
          var timetoken = p.timetoken;  // Current timetoken
          var uuid = p.uuid; // UUIDs of users who are connected with the channel
      },
      status: function(s) {
          var affectedChannelGroups = s.affectedChannelGroups;
          var affectedChannels = s.affectedChannels;
          var category = s.category;
          var operation = s.operation;
      }
  });
  pubnub.subscribe({
      channels: ['ch1'],
  });
      var map;
      function initMap() {
        map = new google.maps.Map(document.getElementById('map'), {
          center: {lat: latitude, lng: longitude},
          zoom: 8
        });
      }
    </script>
    <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_KEY_HERE&callback=initMap"
    async defer></script>
  </body>
</html>

This HTML file will render the map on the HTML page, as well as make use of the PubNub JavaScript SDK to interact with the PubNub network to retrieve the GPS data obtained from the Raspberry Pi that was set up earlier. An event listener is used to listen for any new information and uses the Google Maps API key to graph this information using the Google Maps API. The function smoothZoom is used to add a smooth zooming animation every time you locate a marker. The map is initialized with initial longitude and latitude coordinates that you can change to suit your needs.

Save your work and double-click the HTML file to open it in your default web browser. You'll be able to visually see the GPS information retrieved by your Raspberry Pi and GPS module in real time!

What's Next

You now have an application that can visually view the GPS coordinates that your Raspberry Pi and GPS module retrieve from satellites. Using PubNub, this information is updated in real time. You can find the source code of this application in the GitHub repository.

If you would like to learn more about how to power other IoT applications, take a look at our IoT resources.

If you have any other questions or concerns, please feel free to reach out to devrel@pubnub.com.

More from PubNub

How to Create a Dating App: 7 Steps to Fit Any Design
Insights6 minMar 15, 2023

How to Create a Dating App: 7 Steps to Fit Any Design

There are common underlying technologies for a dating app, and in this post, we’ll talk about the major technologies and designs...

Michael Carroll

Michael Carroll

How to Create a Real-time Public Transportation Schedule App
Build6 minMar 14, 2023

How to Create a Real-time Public Transportation Schedule App

How to use geohashing, JavaScript, Google Maps API, and BART API to build a real-time public transit schedule app.

Michael Carroll

Michael Carroll

How to Create Real-Time Vehicle Location Tracking App
Build2 minMar 9, 2023

How to Create Real-Time Vehicle Location Tracking App

How to track and stream real-time vehicle location on a live-updating map using EON, JavaScript, and the Mapbox API.

Michael Carroll

Michael Carroll

Talk to an expert