NEO-6M GPS Module with Raspberry Pi Pico using MicroPython

In this tutorial, we will learn about a NEO-6M GPS module and how to interface it with Raspberry Pi Pico to obtain GPS parameters such as latitude, longitude, altitude date, time, speed, satellites, etc. We will learn how GPS works and the overview of the NEO-6M GPS module with an introduction, pinout, and specifications. After that, we will learn to interface a NEO-6M GPS Module module with Raspberry Pi Pico.

NEO-6M GPS Module with Raspberry Pi Pico using MicroPython

For demonstration purposes, we will display the GPS location parameters including Latitude, Longitude, Number of Satellites and current time on the Thonny shell console as well as on an OLED.

We have a similar guide with ESP32 using MicroPython:

Prerequisites

Before we start this lesson make sure you are familiar with and have the latest version Python 3 in your system, have set up MicoPython in Raspberry Pi Pico, and have a running Integrated Development Environment(IDE) in which we will be doing the programming. We will be using the same Thonny IDE as we have done previously when we learned how to blink and chase LEDs in micro-python. If you have not followed our previous tutorial, you check here:

If you are using uPyCraft IDE, you can check this getting started guide:

GPS Introduction

Recommended Reading: GPS ( Global Positioning System) – working

The Global Positioning System (GPS) is a satellite-based navigation system that consists of 24 orbiting satellites, each of which makes two circuits around the Earth every 24 hours. These satellites transmit three bits of information – the satellite’s number, its position in space, and the time the information is sent. These signals are picked up by the GPS receiver, which uses this information to calculate the distance between it and the GPS satellites. With signals from three or more satellites, a GPS receiver can triangulate its location on the ground (i.e., longitude and latitude) from the known position of the satellites. With four or more satellites, a GPS receiver can determine a 3D position (i.e., latitude, longitude, and elevation).

In addition, a GPS receiver can provide data on your speed and direction of travel. Anyone with a GPS receiver can access the system. Because GPS provides real-time, three-dimensional positioning, navigation, and timing 24 hours a day, 7 days a week, all over the world, it is used in numerous applications, including GIS data collection, surveying, and mapping.

Point to Remember: A GPS receiver locates any three or more of the satellites, calculates the distanc­e to each, and uses this information to generate its own location. This operation is based on a simple mathematical principle called Trilateration.

NEO-6M GPS Module Introduction

The NEO-6M GPS module is a GPS receiver that can locate all locations on Earth as it is able to track approximately 22 satellites. It consists of a high-performance u-blox 6 positioning engine. Measuring 16 x 12.2 x 2.4 mm, its compact architecture along with its low power consumption makes it a good choice for IoT projects. Overall it is a good cost-effective GPS receiver.

Hardware Overview

Let us learn a little bit about its hardware. To obtain GPS readings, we have to use the NEO-6M GPS module with an antenna. The antenna is firmly attached to the module via the U.FL connector. This connector is found on the GPS module.

NEO-6M GPS Module hardware overview

NEO-6M GPS Chip

In the middle of the GPS module, you can find the NEO-6M chip. This is responsible for tracking up to 22 satellites and any location on the Earth on several channels. Due to its highly sensitive tracking nature, it makes the NEO-6M module a popular GPS tracker.

Some key features of NEO-6M chip include:

  • High sensitivity for tracking
  • Low supply current (~45mA)
  • Is able to track 5 locations per second with an accuracy of 2.5m (horizontal).
  • Comes equipped with PSM also known as Power Saving Mode. This mode causes very less power consumption by turning the module ON/OFF according to the need.
  • Great use as GPS trackers in smart watches due to very low power consumption (~11mA)

Position Fix LED Indicator

Moving ahead, the module comes with a position fix LED indicator. This LED indicates through its blinking effect whether the module is searching for satellites or has already found them. If the LED blinks after every second, then it indicates that the position fix is found. However, if the LED does not blink then the module is still searching for the satellites.

3.3V low-dropout Regulator

The module also comes equipped with a 3.3V LDO regulator (MIC5205). This provides an efficient linear voltage regulation with ultralow-noise output and very low dropout voltage. Additionally, the module is can also tolerate 5V easily.

Specifications

The table below shows some specifications of the NEO-6M module.

TypeGPS
Supply2.7 V-3.6 V
Operating Current45mA
Operating Temperature-40°C ~ 85°C
Horizontal Position Accuracy2.5m
Communication ProtocolNMEA, UBX Binary, RTCM
FeaturesRTC Crystal and External Interrupt/Wake up
InterfaceUART, SPI, USB and DDC

For more information regarding the NEO-6M module refer to its datasheet given here.

Pinout of NEO 6M Module

The diagram below shows the pinout of the NEO 6M module. It consists of 4 pins named GND, TX, RX, and VCC.

NEO 6M GPS module pin out
GNDThis is the ground pin that will be connected with the ground of the microcontroller.
TXThis is the transmission pin used for serial communication.
RXThis is the receiver pin used for serial communication.
VCCThis is the VCC pin used to power up the GPS module.

Interfacing NEO-6M Module with Raspberry Pi Pico and OLED

Raspberry Pi Pico with NEO 6M and OLED display

We will need the following components to connect our Raspberry Pi Pico with the OLED Display and NEO-6M GPS module.

  1. Raspberry Pi Pico
  2. NEO-6M GPS Module
  3. SSD1306 OLED Display
  4. Connecting Wires

Raspberry Pi Pico with NEO-6M

The NEO-6M GPS module has 4 terminals which we will connect with the Raspberry Pi Pico. We will connect the VCC and GND terminals with 3.3V and GND pins of the Raspberry Pi Pico board respectively. We will connect the TX (transmitter) terminal and the RX (receiver) terminal of the GPS module with the UART pins of the Pi Pico board. Let us first have a look at the Raspberry Pi Pi UART Pins.

Raspberry Pi Pico UART Pins

Raspberry Pi Pico contains two identical UART peripherals with separate 32×8 Tx and 32×12 Rx FIFOs.

Raspberry Pi Pico pinout diagram

The following table lists the GPIO pins for both UART peripherals which are exposed on Raspberry Pi Pico development board pinouts. 

UART PinsGPIO Pins
UART0-TXGP0/GP12/GP16
UART0-RXGP1/GP13/GP17
UART1-TXGP4/GP8
UART1-RXGP5/GP9

For this guide, we will use UART1-TX and RX pins.

Raspberry Pi PicoNEO-6M Module
3.3VVCC
GP5 (UART1 RX)TX
GP4 (UART1 TX)RX
GNDGND

Raspberry Pi Pico with NEO-6M and OLED

The OLED display has 4 terminals which we will connect with our devices. As the OLED display requires an operating voltage in the range of 3.3-5V hence we will connect the VCC terminal with 3.3V which will be in common with the board and the GPS module. SCL of the display will be connected with the SCL pin of the module and the SDA of the display will be connected with the SDA of the module. The ground of both the devices will be held common.

Raspberry Pi Pico I2C Pins

Raspberry Pi Pico has two I2C controllers. Both I2C controllers are accessible through GPIO pins of Raspberry Pi Pico. The following table shows the connection of GPIO pins with both I2C controllers. Each connection of the controller can be configured through multiple GPIO pins as shown in the figure. But before using an I2C controller, you should configure in software which GPIO pins you want to use with a specific I2C controller. 

I2C ControllerGPIO Pins
I2C0 – SDAGP0/GP4/GP8/GP12/GP16/GP20
I2C0 – SCLGP1/GP5/GP9/GP13/GP17/GP21
I2C1 – SDAGP2/GP6/GP10/GP14/GP18/GP26
I2C1 – SCLGP3/GP7/GP11/GP15/GP19/GP27

The connections between the two devices which we are using can be seen below.

SSD1306 OLED DisplayRaspberry Pi Pico
VCC3.3V
SDAGP0 (I2C0 SDA)
SCLGP1 (I2C0 SCL)
GNDGND

Schematic Raspberry Pi Pico with OLED and NEO-6M

Follow the schematic diagram below connect them accordingly.

We have used the same connections as specified in the tables above. However you can use other combinations of SDA/SCL pins and UART pins as well.

Raspberry Pi Pico with NEO 6M and OLED connection diagram
Raspberry Pi Pico with NEO 6M and OLED connection diagram
Raspberry Pi Pico with NEO 6M and OLED hardware

Understanding basic NMEA sentence

The NEO-6M GPS module sends GPS data in NMEA format. It is of various kinds including $GPRMC, $GPGGA etc. Each NMEA data field is separated by a comma and starts with a ‘$’.

Below you can view the $GPXXX syntax that denotes the different types of NMEA messages:

$GPGGAGlobal Positioning System Fix Data. It provides 3D location and accuracy data
$GPGSAIt provides GPS DOP and active satellites
$GPGSVIt provides the detailed information of the GPS satellite
$GPGLLIt provides the geographic Latitude and Longitude
$GPRMCIt provides the position, velocity and time
$GPVTGIt provides the dual ground/water speed

Let us understand how to read the basic NMEA sentence i.e. $GPGGA. Here is an example $GPGGA NMEA sentence:

$GPGGA, 103005, 3807.038, N, 07128.99030, E, 1, 07, 1.43, 134.5, M, 42.9, M, , *78
  • $: This indicates the start of the NMEA sentence
  • GPGGA : Global Positioning System Fix Data
  • 103005 : This is the UTC time when the data was accessed in HH:MM:SS. In this case the time is 10:30:05 UTC
  • 3807.038, N : Latitude 38 degrees 07.038′ N
  • 07128.99030, E : Longitude 71 degrees 28.00030′ E
  • 1 : GPS fix
  • 07 : Number of satellites being tracked
  • 1.43 : Horizontal dilution of position
  • 134.5, M : This shows the altitude (m) above the sea level
  • 42.9, M : Height of geoid (mean sea level)
  • Empty field : time in seconds since last DGPS update
  • Empty field : DGPS station ID number
  • *78 : the checksum data

SSD1306 OLED MicroPython Library

We will have to install the SSD1306 OLED library for MicroPython to continue with our project.

  • To successfully do that, open your Thonny IDE with your Raspberry Pi Pico plugged in your system. Go to Tools > Manage Packages. This will open up the Thonny Package Manager.
Raspberry Pi Pico Installing ssd1306 OLED library MicoPython 1
  • Search for “ssd1306” in the search bar by typing its name and clicking the button ‘Search on PyPI.’
Raspberry Pi Pico Installing ssd1306 OLED library MicoPython 2
  • From the following search results click on the one highlighted below: micropython-ssd1306
Raspberry Pi Pico Installing ssd1306 OLED library MicoPython 3

Install this library.

Raspberry Pi Pico Installing ssd1306 OLED library MicoPython 4

After a few moments this library will get successfully installed. Now we are ready to program our Raspberry Pi Pico with OLED display.

MicroPython Script Obtaining GPS Data from NEO-6M Module

from machine import Pin, UART, I2C
from ssd1306 import SSD1306_I2C

import utime, time

i2c=I2C(0,sda=Pin(0), scl=Pin(1), freq=400000)
oled = SSD1306_I2C(128, 64, i2c)

gpsModule = UART(1, baudrate=9600, tx=Pin(4), rx=Pin(5))
print(gpsModule)

buff = bytearray(255)

TIMEOUT = False
FIX_STATUS = False

latitude = ""
longitude = ""
satellites = ""
GPStime = ""

def getGPS(gpsModule):
    global FIX_STATUS, TIMEOUT, latitude, longitude, satellites, GPStime
    
    timeout = time.time() + 8 
    while True:
        gpsModule.readline()
        buff = str(gpsModule.readline())
        parts = buff.split(',')
    
        if (parts[0] == "b'$GPGGA" and len(parts) == 15):
            if(parts[1] and parts[2] and parts[3] and parts[4] and parts[5] and parts[6] and parts[7]):
                print(buff)
                
                latitude = convertToDegree(parts[2])
                if (parts[3] == 'S'):
                    latitude = -latitude
                longitude = convertToDegree(parts[4])
                if (parts[5] == 'W'):
                    longitude = -longitude
                satellites = parts[7]
                GPStime = parts[1][0:2] + ":" + parts[1][2:4] + ":" + parts[1][4:6]
                FIX_STATUS = True
                break
                
        if (time.time() > timeout):
            TIMEOUT = True
            break
        utime.sleep_ms(500)
        
def convertToDegree(RawDegrees):

    RawAsFloat = float(RawDegrees)
    firstdigits = int(RawAsFloat/100) 
    nexttwodigits = RawAsFloat - float(firstdigits*100) 
    
    Converted = float(firstdigits + nexttwodigits/60.0)
    Converted = '{0:.6f}'.format(Converted) 
    return str(Converted)
    
    
while True:
    
    getGPS(gpsModule)

    if(FIX_STATUS == True):
        print("Printing GPS data...")
        print(" ")
        print("Latitude: "+latitude)
        print("Longitude: "+longitude)
        print("Satellites: " +satellites)
        print("Time: "+GPStime)
        print("----------------------")
        
        oled.fill(0)
        oled.text("Lat: "+latitude, 0, 0)
        oled.text("Lng: "+longitude, 0, 10)
        oled.text("Satellites: "+satellites, 0, 20)
        oled.text("Time: "+GPStime, 0, 30)
        oled.show()
        
        FIX_STATUS = False
        
    if(TIMEOUT == True):
        print("No GPS data is found.")
        TIMEOUT = False

How the Code Works?

We will start by importing the UART, Pin and I2C class from the machine module. Next we will also import utime and time module to incorporate delays. We will also import the ssd1306 which is the OLED display library that we installed earlier. This will help us in accessing all the functions defined inside it.

from machine import Pin, UART, I2C
from ssd1306 import SSD1306_I2C
import utime, time

Initializing OLED

Next, we will initialize the I2C GPIO pins for SCL and SDA respectively. We have used the I2C0 SCL and I2C0 SDA pins.

We have created an I2C() method which takes in four parameters. The first parameter is the I2C channel that we are using. The second parameter specifies the I2C GPIO pin of the board which is connected to the SDA line. The third parameter specifies the I2C GPIO pin of the board which is connected to the SCL line. The last parameter is the frequency connection of the OLED.

We are setting the SCL on pin 1 and the SDA on pin 0.

i2c=I2C(0,sda=Pin(0), scl=Pin(1), freq=400000)

This SCL and SDA pin data gets saved in the object ‘i2c’ which will connect to the I2C bus and help in the communication between the two devices

Now, we will create an object ‘oled’ of SSD1306_I2C which uses the width, height, and the i2c object as parameters.

oled = SSD1306_I2C(128, 64, i2c)

Initialize UART Communication

Then we will define the NEO-6M UART connection by creating an object ‘gpsModule’. By using UART() we specified the UART channel as the first parameter, the baud rate as the second parameter and TX and RX pins used as the third and fourth parameters. We are using UART1 in this case with baud rate 9600 for the uart communication.

Then we will print these NEO-6M module connection details in the Thonny shell console.

gpsModule = UART(1, baudrate=9600, tx=Pin(4), rx=Pin(5))
print(gpsModule)

Data Variables

Then we will create a byte array object called buff to store the NMEA sentences.

buff = bytearray(255)

The following variables will store the GPS parameters including Latitude, Longitude, Number of satellites and UTC time.

latitude = ""
longitude = ""
satellites = ""
GPStime = ""

The following function obtains the GPS coordinates. We are running a while loop to obtain the GPS data from the basic NMEA sentence $GPGGA. Latitude, Longitude, Satellites and time will be acquired from the NMEA sentence accordingly and saved in their respective variables.

def getGPS(gpsModule):
    global FIX_STATUS, TIMEOUT, latitude, longitude, satellites, GPStime
    
    timeout = time.time() + 8 
    while True:
        gpsModule.readline()
        buff = str(gpsModule.readline())
        parts = buff.split(',')
    
        if (parts[0] == "b'$GPGGA" and len(parts) == 15):
            if(parts[1] and parts[2] and parts[3] and parts[4] and parts[5] and parts[6] and parts[7]):
                print(buff)
                
                latitude = convertToDegree(parts[2])
                if (parts[3] == 'S'):
                    latitude = -latitude
                longitude = convertToDegree(parts[4])
                if (parts[5] == 'W'):
                    longitude = -longitude
                satellites = parts[7]
                GPStime = parts[1][0:2] + ":" + parts[1][2:4] + ":" + parts[1][4:6]
                FIX_STATUS = True
                break
                
        if (time.time() > timeout):
            TIMEOUT = True
            break
        utime.sleep_ms(500)

The following function is responsible to convert the raw longitude and latitude data to actual values.

def convertToDegree(RawDegrees):

    RawAsFloat = float(RawDegrees)
    firstdigits = int(RawAsFloat/100) 
    nexttwodigits = RawAsFloat - float(firstdigits*100) 
    
    Converted = float(firstdigits + nexttwodigits/60.0)
    Converted = '{0:.6f}'.format(Converted) 
    return str(Converted)

Inside the infinite loop we will call the getGPS(gpsModule) function first. If the GPS data is available then print it both on the Thonny shell console and the OLED display. If the GPS data is not acquired within the time set within the program, then “No GPS data is found” message is printed on the shell console instead.

while True:
    
    getGPS(gpsModule)

    if(FIX_STATUS == True):
        print("Printing GPS data...")
        print(" ")
        print("Latitude: "+latitude)
        print("Longitude: "+longitude)
        print("Satellites: " +satellites)
        print("Time: "+GPStime)
        print("----------------------")
        
        oled.fill(0)
        oled.text("Lat: "+latitude, 0, 0)
        oled.text("Lng: "+longitude, 0, 10)
        oled.text("Satellites: "+satellites, 0, 20)
        oled.text("Time: "+GPStime, 0, 30)
        oled.show()
        
        FIX_STATUS = False
        
    if(TIMEOUT == True):
        print("No GPS data is found.")
        TIMEOUT = False

Demo

After you have copied the following code onto a new file, click the ‘Save’ icon to save your program code on your PC.

After you have saved the code press the Run button to upload the code to your Raspberry Pi Pico module. Before uploading code make sure the correct board is selected.

In the shell terminal of your IDE, you will be able to view the following GPS parameters:

Raspberry Pi Pico with NEO 6M shell terminal

Once the code is uploaded to Raspberry Pi Pico, you will be able to view the GPS data on the OLED as well:

Raspberry Pi Pico with NEO 6M and OLED demo

To read more GPS related articles, follow the links below:

5 thoughts on “NEO-6M GPS Module with Raspberry Pi Pico using MicroPython”

  1. There is a slight error in the code at lines 7 and 40
    instead of longitude = -longitude and latitude= -latitude

    these should be longitude = ‘-‘+longitude and latitude = ‘-‘+latitude
    as they are string values!

    Reply
  2. struggled with this one, i have bought 3 separate units, wired them up as shown, get no flashing lights, no gps data found ?? any clues would be greatly appreciated

    Reply
  3. I am getting a lot of occurrences where the GPS sentences are merging into a single line.

    b’$GPGGA,143744.00,,,,,0,00,99.99,,,,,,*67\r\n’
    b’$GPGSV,1,1,01,04,,,$GPRMC,143745.00,V,,,,,,,180224,,,N*70\r\n’
    b’$GPGGA,143745.00,,,,,0,00,99.99,,,,,,*6$GPRMC,143746.00,V,,,,,,,180224,,,N*73\r\n’

    I assume it’s a timing issue, but not sure what to do about it – any thoughts/suggestions?

    Reply

Leave a Comment