Dans ce guide, vous apprendrez comment interfacer le module GPS NEO-6M avec la carte ESP32 programmée avec MicroPython. Vous apprendrez comment obtenir des données GPS brutes et comment obtenir la date, l’heure et votre position actuelle (latitude, longitude et altitude).

Si vous utilisez l’IDE Arduino, suivez plutôt ce tutoriel : ESP32 avec module GPS NEO-6M
Table des matières
Tout au long de ce guide, nous aborderons les sujets suivants :
Conditions préalables
Pour suivre ce tutoriel, vous devez installer le firmware MicroPython sur vos cartes ESP32. Vous avez également besoin d’un IDE pour écrire et télécharger le code sur votre tableau. Nous vous suggérons d’utiliser Thonny IDE :
En savoir plus sur MicroPython : Programmation MicroPython avec ESP32 et ESP8266
Présentation du module GPS NEO-6M
Le module GPS NEO-6M est un récepteur GPS compatible avec la plupart des cartes microcontrôleurs. Il peut obtenir des données sur l’emplacement, la vitesse, l’altitude et l’heure.

Il est livré avec une petite batterie de secours, une EEPROM externe et un indicateur de signal LED. Cette LED commencera à clignoter lorsqu’elle aura obtenu une position fixe.
Habituellement, ces modules sont livrés avec une antenne GPS en céramique.

Mais vous pouvez la remplacer par n’importe quelle autre antenne compatible qui pourrait mieux convenir à votre projet. Par exemple, j’aime utiliser celle de droite sur l’image ci-dessous car elle est étanche et l’antenne est livrée avec un long câble qui permet plus de flexibilité.

Le module GPS NEO-6M communique avec un microcontrôleur via un protocole de communication série.
Ce module fonctionne avec les phrases NMEA standards. NMEA signifie National Marine Electronics Association et, dans le monde du GPS, il s’agit d’un format de données standard pris en charge par les fabricants de GPS.
Caractéristiques du module GPS NEO-6M

En résumé:
- Ce module dispose d’une antenne externe et d’une EEPROM intégrée.
- Interface : RS232 TTL
- Alimentation : 3V à 5V
- Débit en bauds par défaut : 9 600 bps
- Fonctionne avec les phrases NMEA standard
Où acheter ?
Vous pouvez obtenir le module GPS NEO-6M pour un prix compris entre 5 $ et 20 $. Nous vous recommandons de consulter la page du module GPS NEO-6M sur Maker Advisor pour comparer les prix dans différents magasins et trouver le meilleur.
Vous pouvez utiliser les liens précédents ou vous rendre directement sur MakerAdvisor.com/tools pour trouver toutes les pièces pour vos projets au meilleur prix !

Câblage du module GPS NEO-6M à l’ESP32
Nous connecterons le module GPS NEO-6M à l’aide des broches UART2 par défaut de l’ESP32. Vous pouvez utiliser l’image et le tableau suivants comme référence.

| Module GPS NEO-6M | ESP32 |
| VCC | 3V3 |
| RX | TX2 (GPIO17) |
| Émission | RX2 (GPIO16) |
| GND | GND |
Obtention de données GPS brutes – Test du module GPS NEO-6M avec l’ESP32 (MicroPython)
Pour obtenir des données GPS brutes, il vous suffit de démarrer une communication série avec le module GPS et de lire les données disponibles.

Le code suivant établit une communication série avec le module GPS et lit les données disponibles.
# Rui Santos & Sara Santos - Raspberryme.com
# Complete project details at https://Raspberryme.com/micropython-esp32-neo-6m-gps/
import machine
from time import sleep
# Define the UART pins and create a UART object
gps_serial = machine.UART(2, baudrate=9600, tx=17, rx=16)
while True:
if gps_serial.any():
line = gps_serial.readline() # Read a complete line from the UART
if line:
line = line.decode('utf-8')
print(line.strip())
sleep(0.5)
Afficher le code brut
Tester le code
Après avoir établi une connexion avec la carte à l’aide de Thonny IDE, exécutez le code précédent.
Assurez-vous que l’antenne est connectée et que le module ou l’antenne est placé à l’extérieur ou à côté d’une fenêtre afin qu’il puisse recevoir les données des satellites.

La LED bleue du module commencera à clignoter lorsqu’il trouvera une position fixe. Cela peut prendre quelques minutes lors de la première exécution.

La coque affichera des phrases NMEA avec des données GPS.

Chaque ligne que vous obtenez dans le moniteur série est une phrase NMEA.
NMEA signifie National Marine Electronics Association et, dans le monde du GPS, il s’agit d’un format de données standard pris en charge par les fabricants de GPS.
Phrases NMEA
Les phrases NMEA commencent par le caractère $ et chaque champ de données est séparé par une virgule.
$GPRMC,110827.00,A,4107.32485,N,00831.79799,W,0.888,30.44,180724,,,A*4B
$GPVTG,30.44,T,,M,0.888,N,1.644,K,A*01
$GPGGA,110827.00,41XX.32485,N,00831.79799,W,1,07,0.99,123.1,M,50.1,M,,*48
$GPGSA,A,3,03,32,22,08,04,14,17,,,,,,2.25,0.99,2.02*0A
$GPGSV,3,1,11,3,11,22,26,296,29,27,01,142,,32,17,042,23*48
$GPGLL,4107.32485,N,00831.79799,W,110827.00,A,A*7F
Il existe différents types de phrases NMEA. Le type de message est indiqué par les caractères précédant la première virgule.
Le GP après le $ indique qu’il s’agit d’une position GPS. Le $GPGGA est le message GPS NMEA de base, qui fournit des données de localisation et de précision en 3D.
Dans la phrase suivante :
$GPGGA,110827.00,41XX.32485,N,008XX.XXXXX,W,1,07,0.99,123.1,M,50.1,M,,*48
- 110827 – représente l’heure à laquelle l’emplacement fixe a été pris, 11:08:27 UTC
- 41XX.32845,N – latitude 41 degrés XX.32845,N
- 00831.79799,W – Longitude 008 degrés XX.XXXXX′ W
- 1 – qualité du correctif (0 = invalide ; 1 = correctif GPS ; 2 = correctif DGPS ; 3 = correctif PPS ; 4 = cinématique en temps réel ; 5 = RTK flottant ; 6 = estimé (à l’estime) ; 7 = mode de saisie manuel ; 8 = Mode simulation)
- 07 – nombre de satellites suivis
- 0,99 – Dilution horizontale de la position (moins de un est idéal)
- 123.1, M – Altitude, en mètres au-dessus du niveau de la mer
- 50.1, M – Hauteur du géoïde (niveau moyen de la mer) au-dessus de l’ellipsoïde WGS84
- champ vide – temps en secondes depuis la dernière mise à jour du DGPS
- champ vide – numéro d’identification de la station DGPS
- *48 – les données de la somme de contrôle commencent toujours par *
Les autres phrases NMEA fournissent des informations supplémentaires :
- $GPGSA – GPS DOP et satellites actifs
- $GPGSV – Informations détaillées sur les satellites GPS
- $GPGLL – Latitude et longitude géographiques
- $ GPRMC – Données GPS pvt essentielles (position, vitesse, temps)
- $ GPVTG – Vitesse améliorée
Vous pouvez utiliser cet analyseur NME en ligne et y coller vos phrases pour interpréter les données GPS.
Cependant, le moyen le plus simple d’obtenir et d’interpréter les données GPS souhaitées est d’analyser vos phrases NMEA directement dans le code. Pour cela, nous utiliserons le module micropyGPS.
Téléchargement du module micropyGPS
Pour analyser les phrases NMEA du module GPS et obtenir facilement les données GPS, nous utiliserons le module micropyGPS. Cette bibliothèque ne fait pas partie de la bibliothèque MicroPython standard par défaut. Vous devez donc télécharger le fichier suivant sur votre carte ESP32 (enregistrez-le sous le nom micropyGPS.py).
"""
# MicropyGPS - a GPS NMEA sentence parser for Micropython/Python 3.X - https://github.com/inmcm/micropyGPS/tree/master
# Copyright (c) 2017 Michael Calvin McCoy ([email protected])
# The MIT License (MIT) - see LICENSE file
"""
# TODO:
# Time Since First Fix
# Distance/Time to Target
# More Helper Functions
# Dynamically limit sentences types to parse
from math import floor, modf
# Import utime or time for fix time handling
try:
# Assume running on MicroPython
import utime
except ImportError:
# Otherwise default to time module for non-embedded implementations
# Should still support millisecond resolution.
import time
class MicropyGPS(object):
"""GPS NMEA Sentence Parser. Creates object that stores all relevant GPS data and statistics.
Parses sentences one character at a time using update(). """
# Max Number of Characters a valid sentence can be (based on GGA sentence)
SENTENCE_LIMIT = 90
__HEMISPHERES = ('N', 'S', 'E', 'W')
__NO_FIX = 1
__FIX_2D = 2
__FIX_3D = 3
__DIRECTIONS = ('N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W',
'WNW', 'NW', 'NNW')
__MONTHS = ('January', 'February', 'March', 'April', 'May',
'June', 'July', 'August', 'September', 'October',
'November', 'December')
def __init__(self, local_offset=0, location_formatting='ddm'):
"""
Setup GPS Object Status Flags, Internal Data Registers, etc
local_offset (int): Timzone Difference to UTC
location_formatting (str): Style For Presenting Longitude/Latitude:
Decimal Degree Minute (ddm) - 40° 26.767′ N
Degrees Minutes Seconds (dms) - 40° 26′ 46″ N
Decimal Degrees (dd) - 40.446° N
"""
#####################
# Object Status Flags
self.sentence_active = False
self.active_segment = 0
self.process_crc = False
self.gps_segments = []
self.crc_xor = 0
self.char_count = 0
self.fix_time = 0
#####################
# Sentence Statistics
self.crc_fails = 0
self.clean_sentences = 0
self.parsed_sentences = 0
#####################
# Logging Related
self.log_handle = None
self.log_en = False
#####################
# Data From Sentences
# Time
self.timestamp = [0, 0, 0.0]
self.date = [0, 0, 0]
self.local_offset = local_offset
# Position/Motion
self._latitude = [0, 0.0, 'N']
self._longitude = [0, 0.0, 'W']
self.coord_format = location_formatting
self.speed = [0.0, 0.0, 0.0]
self.course = 0.0
self.altitude = 0.0
self.geoid_height = 0.0
# GPS Info
self.satellites_in_view = 0
self.satellites_in_use = 0
self.satellites_used = []
self.last_sv_sentence = 0
self.total_sv_sentences = 0
self.satellite_data = dict()
self.hdop = 0.0
self.pdop = 0.0
self.vdop = 0.0
self.valid = False
self.fix_stat = 0
self.fix_type = 1
########################################
# Coordinates Translation Functions
########################################
@property
def latitude(self):
"""Format Latitude Data Correctly"""
if self.coord_format == 'dd':
decimal_degrees = self._latitude[0] + (self._latitude[1] / 60)
return [decimal_degrees, self._latitude[2]]
elif self.coord_format == 'dms':
minute_parts = modf(self._latitude[1])
seconds = round(minute_parts[0] * 60)
return [self._latitude[0], int(minute_parts[1]), seconds, self._latitude[2]]
else:
return self._latitude
@property
def longitude(self):
"""Format Longitude Data Correctly"""
if self.coord_format == 'dd':
decimal_degrees = self._longitude[0] + (self._longitude[1] / 60)
return [decimal_degrees, self._longitude[2]]
elif self.coord_format == 'dms':
minute_parts = modf(self._longitude[1])
seconds = round(minute_parts[0] * 60)
return [self._longitude[0], int(minute_parts[1]), seconds, self._longitude[2]]
else:
return self._longitude
########################################
# Logging Related Functions
########################################
def start_logging(self, target_file, mode="append"):
"""
Create GPS data log object
"""
# Set Write Mode Overwrite or Append
mode_code="w" if mode == 'new' else 'a'
try:
self.log_handle = open(target_file, mode_code)
except AttributeError:
print("Invalid FileName")
return False
self.log_en = True
return True
def stop_logging(self):
"""
Closes the log file handler and disables further logging
"""
try:
self.log_handle.close()
except AttributeError:
print("Invalid Handle")
return False
self.log_en = False
return True
def write_log(self, log_string):
"""Attempts to write the last valid NMEA sentence character to the active file handler
"""
try:
self.log_handle.write(log_string)
except TypeError:
return False
return True
########################################
# Sentence Parsers
########################################
def gprmc(self):
"""Parse Recommended Minimum Specific GPS/Transit data (RMC)Sentence.
Updates UTC timestamp, latitude, longitude, Course, Speed, Date, and fix status
"""
# UTC Timestamp
try:
utc_string = self.gps_segments[1]
if utc_string: # Possible timestamp found
hours = (int(utc_string[0:2]) + self.local_offset) % 24
minutes = int(utc_string[2:4])
seconds = float(utc_string[4:])
self.timestamp = [hours, minutes, seconds]
else: # No Time stamp yet
self.timestamp = [0, 0, 0.0]
except ValueError: # Bad Timestamp value present
return False
# Date stamp
try:
date_string = self.gps_segments[9]
# Date string printer function assumes to be year >=2000,
# date_string() must be supplied with the correct century argument to display correctly
if date_string: # Possible date stamp found
day = int(date_string[0:2])
month = int(date_string[2:4])
year = int(date_string[4:6])
self.date = (day, month, year)
else: # No Date stamp yet
self.date = (0, 0, 0)
except ValueError: # Bad Date stamp value present
return False
# Check Receiver Data Valid Flag
if self.gps_segments[2] == 'A': # Data from Receiver is Valid/Has Fix
# Longitude / Latitude
try:
# Latitude
l_string = self.gps_segments[3]
lat_degs = int(l_string[0:2])
lat_mins = float(l_string[2:])
lat_hemi = self.gps_segments[4]
# Longitude
l_string = self.gps_segments[5]
lon_degs = int(l_string[0:3])
lon_mins = float(l_string[3:])
lon_hemi = self.gps_segments[6]
except ValueError:
return False
if lat_hemi not in self.__HEMISPHERES:
return False
if lon_hemi not in self.__HEMISPHERES:
return False
# Speed
try:
spd_knt = float(self.gps_segments[7])
except ValueError:
return False
# Course
try:
if self.gps_segments[8]:
course = float(self.gps_segments[8])
else:
course = 0.0
except ValueError:
return False
# TODO - Add Magnetic Variation
# Update Object Data
self._latitude = [lat_degs, lat_mins, lat_hemi]
self._longitude = [lon_degs, lon_mins, lon_hemi]
# Include mph and hm/h
self.speed = [spd_knt, spd_knt * 1.151, spd_knt * 1.852]
self.course = course
self.valid = True
# Update Last Fix Time
self.new_fix_time()
else: # Clear Position Data if Sentence is 'Invalid'
self._latitude = [0, 0.0, 'N']
self._longitude = [0, 0.0, 'W']
self.speed = [0.0, 0.0, 0.0]
self.course = 0.0
self.valid = False
return True
def gpgll(self):
"""Parse Geographic Latitude and Longitude (GLL)Sentence. Updates UTC timestamp, latitude,
longitude, and fix status"""
# UTC Timestamp
try:
utc_string = self.gps_segments[5]
if utc_string: # Possible timestamp found
hours = (int(utc_string[0:2]) + self.local_offset) % 24
minutes = int(utc_string[2:4])
seconds = float(utc_string[4:])
self.timestamp = [hours, minutes, seconds]
else: # No Time stamp yet
self.timestamp = [0, 0, 0.0]
except ValueError: # Bad Timestamp value present
return False
# Check Receiver Data Valid Flag
if self.gps_segments[6] == 'A': # Data from Receiver is Valid/Has Fix
# Longitude / Latitude
try:
# Latitude
l_string = self.gps_segments[1]
lat_degs = int(l_string[0:2])
lat_mins = float(l_string[2:])
lat_hemi = self.gps_segments[2]
# Longitude
l_string = self.gps_segments[3]
lon_degs = int(l_string[0:3])
lon_mins = float(l_string[3:])
lon_hemi = self.gps_segments[4]
except ValueError:
return False
if lat_hemi not in self.__HEMISPHERES:
return False
if lon_hemi not in self.__HEMISPHERES:
return False
# Update Object Data
self._latitude = [lat_degs, lat_mins, lat_hemi]
self._longitude = [lon_degs, lon_mins, lon_hemi]
self.valid = True
# Update Last Fix Time
self.new_fix_time()
else: # Clear Position Data if Sentence is 'Invalid'
self._latitude = [0, 0.0, 'N']
self._longitude = [0, 0.0, 'W']
self.valid = False
return True
def gpvtg(self):
"""Parse Track Made Good and Ground Speed (VTG) Sentence. Updates speed and course"""
try:
course = float(self.gps_segments[1]) if self.gps_segments[1] else 0.0
spd_knt = float(self.gps_segments[5]) if self.gps_segments[5] else 0.0
except ValueError:
return False
# Include mph and km/h
self.speed = (spd_knt, spd_knt * 1.151, spd_knt * 1.852)
self.course = course
return True
def gpgga(self):
"""Parse Global Positioning System Fix Data (GGA) Sentence. Updates UTC timestamp, latitude, longitude,
fix status, satellites in use, Horizontal Dilution of Precision (HDOP), altitude, geoid height and fix status"""
try:
# UTC Timestamp
utc_string = self.gps_segments[1]
# Skip timestamp if receiver doesn't have on yet
if utc_string:
hours = (int(utc_string[0:2]) + self.local_offset) % 24
minutes = int(utc_string[2:4])
seconds = float(utc_string[4:])
else:
hours = 0
minutes = 0
seconds = 0.0
# Number of Satellites in Use
satellites_in_use = int(self.gps_segments[7])
# Get Fix Status
fix_stat = int(self.gps_segments[6])
except (ValueError, IndexError):
return False
try:
# Horizontal Dilution of Precision
hdop = float(self.gps_segments[8])
except (ValueError, IndexError):
hdop = 0.0
# Process Location and Speed Data if Fix is GOOD
if fix_stat:
# Longitude / Latitude
try:
# Latitude
l_string = self.gps_segments[2]
lat_degs = int(l_string[0:2])
lat_mins = float(l_string[2:])
lat_hemi = self.gps_segments[3]
# Longitude
l_string = self.gps_segments[4]
lon_degs = int(l_string[0:3])
lon_mins = float(l_string[3:])
lon_hemi = self.gps_segments[5]
except ValueError:
return False
if lat_hemi not in self.__HEMISPHERES:
return False
if lon_hemi not in self.__HEMISPHERES:
return False
# Altitude / Height Above Geoid
try:
altitude = float(self.gps_segments[9])
geoid_height = float(self.gps_segments[11])
except ValueError:
altitude = 0
geoid_height = 0
# Update Object Data
self._latitude = [lat_degs, lat_mins, lat_hemi]
self._longitude = [lon_degs, lon_mins, lon_hemi]
self.altitude = altitude
self.geoid_height = geoid_height
# Update Object Data
self.timestamp = [hours, minutes, seconds]
self.satellites_in_use = satellites_in_use
self.hdop = hdop
self.fix_stat = fix_stat
# If Fix is GOOD, update fix timestamp
if fix_stat:
self.new_fix_time()
return True
def gpgsa(self):
"""Parse GNSS DOP and Active Satellites (GSA) sentence. Updates GPS fix type, list of satellites used in
fix calculation, Position Dilution of Precision (PDOP), Horizontal Dilution of Precision (HDOP), Vertical
Dilution of Precision, and fix status"""
# Fix Type (None,2D or 3D)
try:
fix_type = int(self.gps_segments[2])
except ValueError:
return False
# Read All (up to 12) Available PRN Satellite Numbers
sats_used = []
for sats in range(12):
sat_number_str = self.gps_segments[3 + sats]
if sat_number_str:
try:
sat_number = int(sat_number_str)
sats_used.append(sat_number)
except ValueError:
return False
else:
break
# PDOP,HDOP,VDOP
try:
pdop = float(self.gps_segments[15])
hdop = float(self.gps_segments[16])
vdop = float(self.gps_segments[17])
except ValueError:
return False
# Update Object Data
self.fix_type = fix_type
# If Fix is GOOD, update fix timestamp
if fix_type > self.__NO_FIX:
self.new_fix_time()
self.satellites_used = sats_used
self.hdop = hdop
self.vdop = vdop
self.pdop = pdop
return True
def gpgsv(self):
"""Parse Satellites in View (GSV) sentence. Updates number of SV Sentences,the number of the last SV sentence
parsed, and data on each satellite present in the sentence"""
try:
num_sv_sentences = int(self.gps_segments[1])
current_sv_sentence = int(self.gps_segments[2])
sats_in_view = int(self.gps_segments[3])
except ValueError:
return False
# Create a blank dict to store all the satellite data from this sentence in:
# satellite PRN is key, tuple containing telemetry is value
satellite_dict = dict()
# Calculate Number of Satelites to pull data for and thus how many segment positions to read
if num_sv_sentences == current_sv_sentence:
# Last sentence may have 1-4 satellites; 5 - 20 positions
sat_segment_limit = (sats_in_view - ((num_sv_sentences - 1) * 4)) * 5
else:
sat_segment_limit = 20 # Non-last sentences have 4 satellites and thus read up to position 20
# Try to recover data for up to 4 satellites in sentence
for sats in range(4, sat_segment_limit, 4):
# If a PRN is present, grab satellite data
if self.gps_segments[sats]:
try:
sat_id = int(self.gps_segments[sats])
except (ValueError,IndexError):
return False
try: # elevation can be null (no value) when not tracking
elevation = int(self.gps_segments[sats+1])
except (ValueError,IndexError):
elevation = None
try: # azimuth can be null (no value) when not tracking
azimuth = int(self.gps_segments[sats+2])
except (ValueError,IndexError):
azimuth = None
try: # SNR can be null (no value) when not tracking
snr = int(self.gps_segments[sats+3])
except (ValueError,IndexError):
snr = None
# If no PRN is found, then the sentence has no more satellites to read
else:
break
# Add Satellite Data to Sentence Dict
satellite_dict[sat_id] = (elevation, azimuth, snr)
# Update Object Data
self.total_sv_sentences = num_sv_sentences
self.last_sv_sentence = current_sv_sentence
self.satellites_in_view = sats_in_view
# For a new set of sentences, we either clear out the existing sat data or
# update it as additional SV sentences are parsed
if current_sv_sentence == 1:
self.satellite_data = satellite_dict
else:
self.satellite_data.update(satellite_dict)
return True
##########################################
# Data Stream Handler Functions
##########################################
def new_sentence(self):
"""Adjust Object Flags in Preparation for a New Sentence"""
self.gps_segments = ['']
self.active_segment = 0
self.crc_xor = 0
self.sentence_active = True
self.process_crc = True
self.char_count = 0
def update(self, new_char):
"""Process a new input char and updates GPS object if necessary based on special characters ('$', ',', '*')
Function builds a list of received string that are validate by CRC prior to parsing by the appropriate
sentence function. Returns sentence type on successful parse, None otherwise"""
valid_sentence = False
# Validate new_char is a printable char
ascii_char = ord(new_char)
if 10 <= ascii_char <= 126:
self.char_count += 1
# Write Character to log file if enabled
if self.log_en:
self.write_log(new_char)
# Check if a new string is starting ($)
if new_char == '$':
self.new_sentence()
return None
elif self.sentence_active:
# Check if sentence is ending (*)
if new_char == '*':
self.process_crc = False
self.active_segment += 1
self.gps_segments.append('')
return None
# Check if a section is ended (,), Create a new substring to feed
# characters to
elif new_char == ',':
self.active_segment += 1
self.gps_segments.append('')
# Store All Other printable character and check CRC when ready
else:
self.gps_segments[self.active_segment] += new_char
# When CRC input is disabled, sentence is nearly complete
if not self.process_crc:
if len(self.gps_segments[self.active_segment]) == 2:
try:
final_crc = int(self.gps_segments[self.active_segment], 16)
if self.crc_xor == final_crc:
valid_sentence = True
else:
self.crc_fails += 1
except ValueError:
pass # CRC Value was deformed and could not have been correct
# Update CRC
if self.process_crc:
self.crc_xor ^= ascii_char
# If a Valid Sentence Was received and it's a supported sentence, then parse it!!
if valid_sentence:
self.clean_sentences += 1 # Increment clean sentences received
self.sentence_active = False # Clear Active Processing Flag
if self.gps_segments[0] in self.supported_sentences:
# parse the Sentence Based on the message type, return True if parse is clean
if self.supported_sentences[self.gps_segments[0]](self):
# Let host know that the GPS object was updated by returning parsed sentence type
self.parsed_sentences += 1
return self.gps_segments[0]
# Check that the sentence buffer isn't filling up with Garage waiting for the sentence to complete
if self.char_count > self.SENTENCE_LIMIT:
self.sentence_active = False
# Tell Host no new sentence was parsed
return None
def new_fix_time(self):
"""Updates a high resolution counter with current time when fix is updated. Currently only triggered from
GGA, GSA and RMC sentences"""
try:
self.fix_time = utime.ticks_ms()
except NameError:
self.fix_time = time.time()
#########################################
# User Helper Functions
# These functions make working with the GPS object data easier
#########################################
def satellite_data_updated(self):
"""
Checks if the all the GSV sentences in a group have been read, making satellite data complete
:return: boolean
"""
if self.total_sv_sentences > 0 and self.total_sv_sentences == self.last_sv_sentence:
return True
else:
return False
def unset_satellite_data_updated(self):
"""
Mark GSV sentences as read indicating the data has been used and future updates are fresh
"""
self.last_sv_sentence = 0
def satellites_visible(self):
"""
Returns a list of of the satellite PRNs currently visible to the receiver
:return: list
"""
return list(self.satellite_data.keys())
def time_since_fix(self):
"""Returns number of millisecond since the last sentence with a valid fix was parsed. Returns 0 if
no fix has been found"""
# Test if a Fix has been found
if self.fix_time == 0:
return -1
# Try calculating fix time using utime; if not running MicroPython
# time.time() returns a floating point value in secs
try:
current = utime.ticks_diff(utime.ticks_ms(), self.fix_time)
except NameError:
current = (time.time() - self.fix_time) * 1000 # ms
return current
def compass_direction(self):
"""
Determine a cardinal or inter-cardinal direction based on current course.
:return: string
"""
# Calculate the offset for a rotated compass
if self.course >= 348.75:
offset_course = 360 - self.course
else:
offset_course = self.course + 11.25
# Each compass point is separated by 22.5 degrees, divide to find lookup value
dir_index = floor(offset_course / 22.5)
final_dir = self.__DIRECTIONS[dir_index]
return final_dir
def latitude_string(self):
"""
Create a readable string of the current latitude data
:return: string
"""
if self.coord_format == 'dd':
formatted_latitude = self.latitude
lat_string = str(formatted_latitude[0]) + '° ' + str(self._latitude[2])
elif self.coord_format == 'dms':
formatted_latitude = self.latitude
lat_string = str(formatted_latitude[0]) + '° ' + str(formatted_latitude[1]) + "' " + str(formatted_latitude[2]) + '" ' + str(formatted_latitude[3])
else:
lat_string = str(self._latitude[0]) + '° ' + str(self._latitude[1]) + "' " + str(self._latitude[2])
return lat_string
def longitude_string(self):
"""
Create a readable string of the current longitude data
:return: string
"""
if self.coord_format == 'dd':
formatted_longitude = self.longitude
lon_string = str(formatted_longitude[0]) + '° ' + str(self._longitude[2])
elif self.coord_format == 'dms':
formatted_longitude = self.longitude
lon_string = str(formatted_longitude[0]) + '° ' + str(formatted_longitude[1]) + "' " + str(formatted_longitude[2]) + '" ' + str(formatted_longitude[3])
else:
lon_string = str(self._longitude[0]) + '° ' + str(self._longitude[1]) + "' " + str(self._longitude[2])
return lon_string
def speed_string(self, unit="kph"):
"""
Creates a readable string of the current speed data in one of three units
:param unit: string of 'kph','mph, or 'knot'
:return:
"""
if unit == 'mph':
speed_string = str(self.speed[1]) + ' mph'
elif unit == 'knot':
if self.speed[0] == 1:
unit_str=" knot"
else:
unit_str=" knots"
speed_string = str(self.speed[0]) + unit_str
else:
speed_string = str(self.speed[2]) + ' km/h'
return speed_string
def date_string(self, formatting='s_mdy', century='20'):
"""
Creates a readable string of the current date.
Can select between long format: Januray 1st, 2014
or two short formats:
11/01/2014 (MM/DD/YYYY)
01/11/2014 (DD/MM/YYYY)
:param formatting: string 's_mdy', 's_dmy', or 'long'
:param century: int delineating the century the GPS data is from (19 for 19XX, 20 for 20XX)
:return: date_string string with long or short format date
"""
# Long Format Januray 1st, 2014
if formatting == 'long':
# Retrieve Month string from private set
month = self.__MONTHS[self.date[1] - 1]
# Determine Date Suffix
if self.date[0] in (1, 21, 31):
suffix = 'st'
elif self.date[0] in (2, 22):
suffix = 'nd'
elif self.date[0] == (3, 23):
suffix = 'rd'
else:
suffix = 'th'
day = str(self.date[0]) + suffix # Create Day String
year = century + str(self.date[2]) # Create Year String
date_string = month + ' ' + day + ', ' + year # Put it all together
else:
# Add leading zeros to day string if necessary
if self.date[0] < 10:
day = '0' + str(self.date[0])
else:
day = str(self.date[0])
# Add leading zeros to month string if necessary
if self.date[1] < 10:
month="0" + str(self.date[1])
else:
month = str(self.date[1])
# Add leading zeros to year string if necessary
if self.date[2] < 10:
year="0" + str(self.date[2])
else:
year = str(self.date[2])
# Build final string based on desired formatting
if formatting == 's_dmy':
date_string = day + '/' + month + '/' + year
else: # Default date format
date_string = month + '/' + day + '/' + year
return date_string
# All the currently supported NMEA sentences
supported_sentences = {'GPRMC': gprmc, 'GLRMC': gprmc,
'GPGGA': gpgga, 'GLGGA': gpgga,
'GPVTG': gpvtg, 'GLVTG': gpvtg,
'GPGSA': gpgsa, 'GLGSA': gpgsa,
'GPGSV': gpgsv, 'GLGSV': gpgsv,
'GPGLL': gpgll, 'GLGLL': gpgll,
'GNGGA': gpgga, 'GNRMC': gprmc,
'GNVTG': gpvtg, 'GNGLL': gpgll,
'GNGSA': gpgsa,
}
if __name__ == "__main__":
pass
Afficher le code brut
Quel que soit l’IDE que vous utilisez, voici les instructions générales pour télécharger la bibliothèque micropyGPS sur votre carte :
- Tout d’abord, assurez-vous que votre carte exécute le micrologiciel MicroPython : consultez la section Prérequis.
- Créez un nouveau fichier dans votre IDE avec le nom micropyGPS.py et collez-y le code précédent. Enregistrez ce fichier.
- Établissez une communication série avec votre carte à l’aide de votre IDE.
- Téléchargez le fichier micropyGPS.py sur votre tableau.
- À ce stade, la bibliothèque devrait avoir été téléchargée avec succès sur votre tableau. Désormais, vous pouvez utiliser les fonctionnalités de la bibliothèque dans votre code en important la bibliothèque : import micropyGPS.
ESP32 avec NEO-6M : obtenir des données GPS avec MicroPython
La bibliothèque micropyGPS facilite l’obtention de données GPS dans un format facile à comprendre.
Le code suivant montre comment utiliser la bibliothèque pour obtenir des données GPS telles que la latitude, la longitude, l’altitude, la date et l’heure, le nombre de satellites visibles et HDOP (une mesure de la précision du signal).
Après avoir importé la bibliothèque micropyGPS sur votre carte, vous pouvez exécuter le code suivant.
# Rui Santos & Sara Santos - Raspberryme.com
# Complete project details at https://Raspberryme.com/micropython-esp32-neo-6m-gps/
import machine
from time import sleep
from micropyGPS import MicropyGPS
# Instantiate the micropyGPS object
my_gps = MicropyGPS()
# Define the UART pins and create a UART object
gps_serial = machine.UART(2, baudrate=9600, tx=17, rx=16)
while True:
try:
while gps_serial.any():
data = gps_serial.read()
for byte in data:
stat = my_gps.update(chr(byte))
if stat is not None:
# Print parsed GPS data
print('UTC Timestamp:', my_gps.timestamp)
print('Date:', my_gps.date_string('long'))
print('Latitude:', my_gps.latitude_string())
print('Longitude:', my_gps.longitude_string())
print('Altitude:', my_gps.altitude)
print('Satellites in use:', my_gps.satellites_in_use)
print('Horizontal Dilution of Precision:', my_gps.hdop)
print()
except Exception as e:
print(f"An error occurred: {e}")
Afficher le code brut
Comment fonctionne le code ?
Continuez à lire pour découvrir comment fonctionne le code ou passez à la section de démonstration.
Tout d’abord, importez les modules requis, y compris la classe MicropyGPS à partir du module micropyGPS que vous avez importé précédemment.
import machine
from time import sleep
from micropyGPS import MicropyGPS
Créez une instance de la classe MicropyGPS appelée my_gps.
# Instantiate the micropyGPS object
my_gps = MicropyGPS()
Ensuite, initialisez une instance UART pour la communication série avec le module. Nous utilisons GPIO 17 pour TX et GPIO 16 pour RX. Nous définissons également le débit en bauds du module GPS (le NEO-6M en utilise 9600).
# Define the UART pins and create a UART object
gps_serial = machine.UART(2, baudrate=9600, tx=17, rx=16)
Ensuite, nous créons une boucle infinie pour lire en continu les données GPS.
Nous vérifions s’il y a de nouvelles données disponibles à lire. Si c’est le cas, nous lisons les données et les transmettons à l’instance my_gps à l’aide de la méthode update().
while gps_serial.any():
data = gps_serial.read()
for byte in data:
stat = my_gps.update(chr(byte))
La méthode update() renvoie des phrases GPS valides ou None si ce n’est pas le cas. Nous vérifions donc si nous disposons de données valides avant de continuer.
if stat is not None:
Ensuite, nous pouvons accéder aux données GPS en utilisant les méthodes micropyGPS sur l’objet my_gps qui doit contenir les données collectées à partir du module GPS.
Les lignes suivantes montrent comment obtenir l’heure, la date, la latitude, la longitude, l’altitude, le nombre de satellites utilisés et HDOP.
# Print parsed GPS data
print('UTC Timestamp:', my_gps.timestamp)
print('Date:', my_gps.date_string('long'))
print('Latitude:', my_gps.latitude_string())
print('Longitude:', my_gps.longitude_string())
print('Altitude:', my_gps.altitude)
print('Satellites in use:', my_gps.satellites_in_use)
print('Horizontal Dilution of Precision:', my_gps.hdop)
print()
La bibliothèque micropyGPS prend en charge d’autres méthodes pour obtenir plus de données GPS et dans différents formats. Nous vous recommandons de consulter la documentation et de voir toutes les options disponibles.
Démonstration
Après avoir téléchargé le module micropyGPS sur votre carte, vous pouvez exécuter ce code précédent pour obtenir des données GPS.

Assurez-vous de placer votre carte ou votre antenne à côté d’une fenêtre, ou de préférence à l’extérieur afin qu’elle puisse recevoir les données des satellites. Vous devrez peut-être attendre quelques minutes jusqu’à ce qu’il obtienne une position et puisse envoyer des données valides. La LED bleue du module GPS NEO-6M commencera à clignoter lorsqu’il sera prêt.
Dans le shell MicroPython, vous devriez obtenir des informations sur votre position actuelle, la date et l’heure en UTC, le nombre de satellites et HDOP. Plus le nombre de satellites est élevé et plus le HDOP est faible, mieux c’est.

Conclusion
Dans ce tutoriel, vous avez appris à utiliser le module GPS NEO-6M avec l’ESP32 à l’aide de MicroPython. Vous avez appris à obtenir votre position actuelle, ainsi que la date et l’heure.
Vous pouvez désormais pousser ce projet plus loin et afficher les données sur un écran OLED ou un écran LCD.
Nous espérons que ce guide vous sera utile. Pour en savoir plus sur MicroPython, consultez nos ressources :
Plongez dans l’histoire de Raspberry Pi avec cette vidéo :

-
GY-NEO6MV2 NEO-6M Lot de 2 modules de commande de vol GPS 3 V-5 V avec antenne en céramique super puissante pour Arduino EEPROM APM 2.5
-
QIQIAZI Module GPS, GPS avec commande de vol d'antenne, super puissant, MWC IMU APM2 pour Arduino
