Seconde SNT |
Localisation, cartographie et mobilité Décoder une trame NMEA |
![]() |
cliquer ici pour faire apparaître le détail
"Entrée[1]"
devraient contenir un numéro et non une étoile "Entrée[*]"
.
Pour transmettre des informations de géolocalisation, on utilise des trames (paquets) dont la forme est normalisée. La norme utilisée est la norme NMEA 0183 (norme spécifique notamment pour la communication entre équipements marins, contrôlée par la National Marine Electronics Association (USA))
Aujourd'hui, les smartphones sont tous dotés d'un récepteur GPS. Ils peuvent se géolocaliser grâce à cette puce, c'est-à-dire connaître leurs positions géographiques. L'objectif de cette activité est de comprendre le fonctionnement de ce dispositif.</span>
Une trame NMEA est une suite de caractères produite par un récepteur GPS. Cette suite de catactères contient des informations de géolocalisation, comme :
Exemple de trame :
`$GPGGA,064036.289,4836.5375,N,00740.9373,E,1,04,3.2,200.2,M,,,,,0000*0E` est un exemple de trame NMEA.
Les deux premiers caractères après le signe $ identifient l'origine du signal.
Les principaux préfixes sont :
Décodons cette trame :
caractères | signification |
---|---|
$ |
Début d'une nouvelle trame |
GP |
Origine du signal : GP pour GPS, GA pour Galiléo, BD ou GB pour Beidu, GL pour Glonass, GN pour GPS + Glonass |
GGA |
Type de trame : GGA pour position (fixe), RMC pour navidation (déplacement), ... |
064036.289 |
Heure de réception : ici à 06h 40m 36,289s (heure UTC) |
4836.5375 |
Latitude : ici 48° 36.5375' (DM) = 48.608958° (DD) = 48° 36' 32.25" (DMS) |
N |
N pour latitude nord, S pour latitude sud |
00740.9373 |
Longitude : ici 7° 40.9373' (DM) = 7.682288° (DD) = 7° 40' 56.238" (DMS) |
E |
E pour longitude est, W pour longitude ouest |
1 |
Positionnement : 0 pour calé, 1 pour positionné, 2 en mode différentiel, 6 pour estimée |
04 |
Nombre de satellites utilisés pour calculer les coordonnées : ici 4 |
3.2 |
Précision horizontale : de 1.0 (optimale) à 8.0 non fiable |
200.2,M |
Altitude : ici 200.2 mètres |
,,,,,0000 |
D'autres informations peuvent être inscrites dans ces champs |
*0E |
Caractères de contrôle |
Objectif : obtenir des fonctions Python qui permettent d'automatiser le déchiffrement d'une telle trame.
L'instruction Python ci-dessous permet d'affecter la trame NMEA à la variable trame_brute
. Cela permet de mettre la trame en mémoire.
Pour ce TP, nous allons utiliser la trame ci-dessous :
`$GPGGA,064036.289,2053.026627,S,05526.895820,E,1,08,3.2,162.2,M,,,,,0000*11`
# Exécuter cette cellule
trame_brute ='$GPGGA,064036.289,2053.026627,S,05526.895820,E,1,08,3.2,162.2,M,,,,,0000*11'
trame_brute #pour afficher le contenu mémoire de trame_brute
La trame GPS est pour l'instant codée sous forme d'une chaine de caractère (str).
Exécuter l'instruction ci-dessous qui va permettre d'obtenir les différentes données séparées par des virgules dans une liste (list).
L'instruction split
permet de découper une chaîne de caractères.
# Exécuter cette cellule
trame = trame_brute.split(",") #création d'une liste (éléments identifiés par une séparation par virgule)
trame #pour afficher le contenu mémoire de trame
Au final, la trame est codée sous forme d'une liste, dont chaque élément est une chaine de caractères.
[ ]
),[...,...,...]
>>> animaux = ["girafe", "tigre", "singe", "souris"] #animaux est une liste de 4 éléments
>>> animaux[0] #extraction de l'élément d'index 0
'girafe'
>>> animaux[1] #extraction de l'élément d'index 1
'tigre'
>>> animaux[3]
'souris'
Par conséquent, si on appelle l'élément d'indice 4 de notre liste, Python renverra un message d'erreur :
>>> animaux[4]
Traceback (most recent call last):
File "<input>", line 2, in <module>
IndexError: list index out of range
Pour accéder aux différents éléments de la trame, on utilise la syntaxe trame[k]
pour accéder au kème élément de la trame. (rappel : les éléments sont numérotés à partir de 0)
1. Saisir l'instruction nécessaire pour obtenir l'altitude.
# Saisir l'instruction pour obtenir l'altitude
trame[9]
2. Saisir l'instruction nécessaire pour obtenir l'altitude avec son unité à la suite.
# Saisir l'instruction pour obtenir l'altitude et son unité
trame[9] + " " + trame[10]
+
placé entre les deux élements.
**remarque**
_Si vous souhaitez concaténer une chaîne et un nombre, tel qu’un entier ou un flottant à virgule flottante, convertissez le nombre en chaîne avec str()
, puis utilisez l’opérateur +
: chaîne + str(nombre)
_3. Exécuter l'instruction suivante et compléter les commentaires.
trame[7] # trame[7] permet d'obtenir "le nombre de satellites"
4. Tester les saisies suivantes, compléter les commentaires et proposer une saisie.
trame[0]
trame[0][1:3] #permet de récupérer "le type de signal ici GPS 'américain)'
#écrire une saisie permettant de récupérer l'information 'GGA' sur le type de trame.
trame[0][3:]
[]
à la fin de la variable stockant la chaîne pour préciser quels caractères nous souhaitons extraire.
Le format des crochets doit être [start : stop : step]
(séparés par deux points (:)).
start
et stop
représentent les index (positions) de départ et de fin de la sous-chaîne à extraire et step
le pas.
exemple : la sous-chaîne retournée est en fait entre l’index start et l’index stop - 1 car l’indexation commence à 0 en Python. Donc, si nous voulons récupérer Miss de Mississippi, nous devrions utiliser [0 : 4]
Les crochets ne peuvent pas être vides. Si le pas n'est pas précisé, sa valeur par défaut est 1. Si vous souhaitez utiliser les valeurs par défaut, le nombre requis de deux points : doit être ajouté avec des espaces entre les deux pour indiquer le paramètre auquel vous faites référence. Reportez-vous à la liste suivante pour une meilleure compréhension.
[:] -> Renvoie la chaîne entière.
[4 : ] -> Renvoie une sous-chaîne à partir de l’index 4 jusqu’au dernier index.
[ : 2] -> Renvoie une sous-chaîne à partir de l’index 0 jusqu’à l’index 2 exclu.
[2 : 4] -> Renvoie une sous-chaîne à partir de l’index 2 jusqu’à l’index 4 exclu.
Objectif : la date doit être convertie pour s'afficher dans le format **06 h 40 min 36 s 289**
Saisir l'instruction nécessaire pour obtenir l'heure.
heure = trame[1]
heure
Le format ne convient pas puisqu'il est HHMMSS,SSS.
Il faut donc extraire les deux premiers chiffres pour obtenir l'heure, puis les 3ème et 4ème pour les minutes et ceux qui restent représentent les secondes (en décimal).
heure = trame[1][:2]
heure
La valeur qui est extraite est une chaîne de caractères (string ou str). Cela peut se vérifier avec la commande type(trame[1][:2])
qui renvoie class 'str'
, ce qui explique la présence de guillemets.
Il est préférable de la convertir en nombre. L'heure est un entier , donc on peut utiliser la commande int(trame[1][:2])
.
heure = int(trame[1][:2])
heure
cliquer ici pour faire apparaître l'aide
Les deux premiers caractères repésentent les heures, les 3ème et 4ème les minutes et les autres les secondes
Saisir l'instruction nécessaire pour obtenir les minutes.
minutes = int(trame[1][2:4])
minutes
Saisir l'instruction nécessaire pour obtenir les secondes.
Attention, les secondes sont en format nombre réel (float
).
secondes= float(trame[1][4:])
secondes
Il est maintenant possible d'afficher l'heure d'enregistrement de la trame NMEA au format 06 h 40 min 36 s 289.
Remarque : pour concaténer tous ces éléments de types différents (int (entier)
, float (réel)
et str (chaîne de caractères)
), il faut les convertir en chaîne de caractères avec str
.
print("La trame a été enregistrée à "+str(heure)+" h "+str(minutes)+" min "+str(secondes)+" s")
Objectif : pouvoir utiliser la latitude et la longitude dans un autre format compatible avec une application de création de carte
Saisir l'instruction nécessaire pour obtenir la latitude.
# Saisir l'instruction pour obtenir la latitude
trame[2]
Dans la trame initiale le codage $2053.026627$ correspond à $20° 53.026627'$ ( ' signifie minute, c'est à dire $\frac{1}{60}$ de degré) et on convertit ainsi en degré : $20 + \dfrac{53.026627}{60} = 20.88377°$. On ajoute un signe - car on est dans l'hemisphère sud. On obtient : -20.88377°
On donne la fonction suivante, qui permet d'obtenir la latitude de la trame en degré.
L'exécuter, puis écrire la fonction longitude
qui permet d'obtenir la longitude en degré.
def latitude(trame):
"fonction qui donne la latitude en degré décimal avec cardinalité"
lat_dm = trame[2]
lat_deg = int(lat_dm[:2]) # récupération du nombre entier de degré (ce sont les deux premiers chiffres)
lat_min = float(lat_dm[2:]) # récupération du nombre de minutes sous forme d'un nombre float à virgule
lat_final = lat_deg + lat_min/60 # calcul final avec conversion des minutes en degrés
lat_card = trame[3] # récupération de la cardinalité (N ou S)
if lat_card == "S":
lat_card_signe = -1
else :
lat_card_signe = 1
lat_final = lat_final * lat_card_signe
return lat_final
#Ecrire ici une fonction qui donne la longitude en degré décimal avec cardinalité
def longitude(trame):
"fonction qui donne la longitude en degré décimal avec cardinalité"
lon_dm = trame[4]
lon_deg = int(lon_dm[:3]) # récupération du nombre entier de degré (ce sont les deux premiers chiffres)
lon_min = float(lon_dm[3:]) # récupération du nombre de minutes sous forme d'un nombre float à virgule
lon_final = lon_deg + lon_min/60 # calcul final avec conversion des minutes en degrés
lon_card = trame[5] # récupération de la cardinalité (N ou S)
if lon_card == "W":
lon_card_signe = -1
else :
lon_card_signe = 1
lon_final = lon_final * lon_card_signe
return lon_final
Tester ces deux fonctions avec les instructions suivantes .
longitude(trame)
latitude(trame)
Objectif : créer une carte centrée sur les coordonnées de la trame GPS
Nous allons utiliser la bibliothèque folium
qui permet de créer une carte.
Cette bibliothèque dispose d'outils permettant de créer une **carte interactive** basée sur un fond cartographique.
Nous allons utiliser le fond cartographique gratuit et collaboratif **OpenStreetMap**.
import folium
.folium.Map
:folium.Map( location, zoom_start)
import folium
# définir les coordonnées du centre de la carte
latitude = 48.6360
longitude = -1.5114
# créer la carte en indiquant les coordonnées du centre et un niveau de zoom, entre 1 (planisphère) et 18 (bâtiment)
carte1 = folium.Map(location=[latitude, longitude],zoom_start = 16)
# affichage de l'objet carte1 que l'on vient de créer
carte1
''' Penser à réexécuter les les fonctions latitude et longitude '''
import folium
# définir les coordonnées du centre de la carte
latitude = latitude(trame)
longitude = longitude(trame)
# créer la carte en indiquant les coordonnées du centre et un niveau de zoom, entre 1 (planisphère) et 18 (bâtiment)
carte1 = folium.Map(location=[latitude, longitude],zoom_start = 18)
carte1.add_child(folium.LatLngPopup())
folium.Marker(location=[latitude, longitude],
popup = "Vous êtes ici",
icon=folium.Icon(color='red',icon='info-sign')
).add_to(carte1)
# affichage de l'objet carte1 que l'on vient de créer
carte1
Pour limiter le risque d'erreurs, il est conseillé de rassembler toutes les instructions nécessaires dans la même cellule de code :
A la fin de la séance, bien penser à
enregistrer
puis cliquer surRendre le devoir
.¶Votre page pourra alors être commentée et notée par le professeur