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.
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 distance 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 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.
Type | GPS |
---|---|
Supply | 2.7 V-3.6 V |
Operating Current | 45mA |
Operating Temperature | -40°C ~ 85°C |
Horizontal Position Accuracy | 2.5m |
Communication Protocol | NMEA, UBX Binary, RTCM |
Features | RTC Crystal and External Interrupt/Wake up |
Interface | UART, 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.
GND | This is the ground pin that will be connected with the ground of the microcontroller. |
TX | This is the transmission pin used for serial communication. |
RX | This is the receiver pin used for serial communication. |
VCC | This is the VCC pin used to power up the GPS module. |
Interfacing NEO-6M Module with Raspberry Pi Pico and OLED
We will need the following components to connect our Raspberry Pi Pico with the OLED Display and NEO-6M GPS module.
- Raspberry Pi Pico
- NEO-6M GPS Module
- SSD1306 OLED Display
- 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.
The following table lists the GPIO pins for both UART peripherals which are exposed on Raspberry Pi Pico development board pinouts.
UART Pins | GPIO Pins |
---|---|
UART0-TX | GP0/GP12/GP16 |
UART0-RX | GP1/GP13/GP17 |
UART1-TX | GP4/GP8 |
UART1-RX | GP5/GP9 |
For this guide, we will use UART1-TX and RX pins.
Raspberry Pi Pico | NEO-6M Module |
---|---|
3.3V | VCC |
GP5 (UART1 RX) | TX |
GP4 (UART1 TX) | RX |
GND | GND |
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 Controller | GPIO Pins |
---|---|
I2C0 – SDA | GP0/GP4/GP8/GP12/GP16/GP20 |
I2C0 – SCL | GP1/GP5/GP9/GP13/GP17/GP21 |
I2C1 – SDA | GP2/GP6/GP10/GP14/GP18/GP26 |
I2C1 – SCL | GP3/GP7/GP11/GP15/GP19/GP27 |
The connections between the two devices which we are using can be seen below.
SSD1306 OLED Display | Raspberry Pi Pico |
---|---|
VCC | 3.3V |
SDA | GP0 (I2C0 SDA) |
SCL | GP1 (I2C0 SCL) |
GND | GND |
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.
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:
$GPGGA | Global Positioning System Fix Data. It provides 3D location and accuracy data |
$GPGSA | It provides GPS DOP and active satellites |
$GPGSV | It provides the detailed information of the GPS satellite |
$GPGLL | It provides the geographic Latitude and Longitude |
$GPRMC | It provides the position, velocity and time |
$GPVTG | It 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.
- Search for “ssd1306” in the search bar by typing its name and clicking the button ‘Search on PyPI.’
- From the following search results click on the one highlighted below: micropython-ssd1306
Install this library.
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:
Once the code is uploaded to Raspberry Pi Pico, you will be able to view the GPS data on the OLED as well:
To read more GPS related articles, follow the links below:
- NEO-6M GPS Module with ESP8266 NodeMCU and Track Location on Google Maps
- ESP32 GPS tracker – IoT based Vehicle Tracking System
- GPS Data Logger with Arduino and Micro SD Card – GPS Tracker
- Interface NEO-6M GPS Module with Arduino
- Display GPS Co-ordinates on LCD using pic microcontroller
- Interfacing GPS module with Arduino: GPS coordinates on Lcd
- Vehicle Tracking System Through GPS-GSM Modules
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!
Thank you. I was going crazy.
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
Please make sue the antenna is connected or try taking your circuit outside the building.
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?