| Seconde SNT |
Localisation, cartographie et mobilité Décoder une trame NMEA |
|
Prise en main d'un notebook
cliquer ici pour faire apparaître le détail
Un notebook est une suite de cellules contenant, soit du texte, soit du code.
Les cellules de code sont facilement reconnaissables, elles sont précédées de
Entrée [ ]:Pour exécuter le code Python d'une cellule, il faut frapper
<MAJ-Entrée>(ou cliquer sur le bouton , ou encore utiliser le menuCellules>Exécuter les cellules...).Si l'instruction est exécutée, les crochets de
"Entrée[1]"devraient contenir un numéro et non une étoile"Entrée[*]".
Ce notebook a été réalisé par Andjekel 2023-2024. Source © Franck CHEVRIER 2019-2021
Les activités sur Capytale sont sous licence Creative Commons.
1. Lecture et exploitation d'une trame NMEA¶
1.1. La trame NMEA¶
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.
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 :
- l'heure de réception
- la latitude
- la longitude
- l'altitude
- le nombre de satellites utilisés pour le calcul
- etc.
Les quinze composantes de la trame sont séparées par une virgule.
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 :
- BD ou GB - Beidou (Chine) ;
- GA - Galileo (Europe) ;
- GP - GPS (USA) ;
- GL - GLONASS (Russie) ;
- GN - signaux mixés GPS et GLONASS.
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 |
1.2. Analyse d'une trame NMEA¶
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
'$GPGGA,064036.289,2053.026627,S,05526.895820,E,1,08,3.2,162.2,M,,,,,0000*11'
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
['$GPGGA', '064036.289', '2053.026627', 'S', '05526.895820', 'E', '1', '08', '3.2', '162.2', 'M', '', '', '', '', '0000*11']
Au final, la trame est codée sous forme d'une liste, dont chaque élément est une chaine de caractères.
les listes
Structure d'une liste :- les éléments sont entre deux crochets (
[ ]), - et séparés par une virgule
[...,...,...]
Un des gros avantages d'une liste est que vous pouvez appeler ses éléments par leur position.
Ce numéro est appelé indice (ou index) de la liste.
| liste | : | ["girafe", | "tigre", | "singe", | "souris"] |
| indice | : | 0 | 1 | 2 | 3 |
La commande liste[ ] permet d’accéder facilement à un élément d’une liste grâce à son indice.
Soyez très attentif au fait que les indices d'une liste de n éléments commencent à 0 et se terminent à n-1. Voyez l'exemple suivant :
>>> 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]
'162.2'
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]
'162.2 M'
+ 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"
'08'
4. Tester les saisies suivantes, compléter les commentaires et proposer une saisie.
trame[0]
'$GPGGA'
trame[0][1:3] #permet de récupérer "le type de signal ici GPS 'américain)'
'GP'
#écrire une saisie permettant de récupérer l'information 'GGA' sur le type de trame.
trame[0][3:]
'GGA'
Extraire une sous-chaîne à l’aide du découpage de chaînes en Python
Au code ci-dessus, nous allons ajouter des crochets [] à 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.
1.3. Conversion de l'heure¶
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
'064036.289'
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
'06'
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
6
comment utiliser l'indexation d'une chaîne de caractères ?
cliquer ici pour faire apparaître l'aide
Les différents caractères de l'heure sont indexés de la façon suivante :
| heure | : | 0 | 6 | 4 | 0 | 3 | 6 | . | 2 | 8 | 9 |
| indice | : | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| H | H | M | M | s | s | . | s | s | s |
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
40
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
36.289
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")
La trame a été enregistrée à 6 h 40 min 36.289 s
1.4. Latitude et longitude¶
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]
'2053.026627'
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)
55.44826366666667
latitude(trame)
-20.883777116666668
1.5. Association avec une carte géographique¶
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.On créé une carte avec l'instruction
folium.Map :- il faut indiquer les coordonnées du centre de la carte et
- le niveau de zoom avec lequel elle va s'afficher (de 1 à 18).
folium.Map( location, zoom_start)
- Tester l'exemple ci-dessous.
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
- Compléter le code ci-dessous pour qu'une carte s'affiche, centrée sur les coordonnées de la trame GPS.
''' 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 :
- mise en mémoire de la trame,
- découpage de la trame et
- les fonctions de conversion des coordonnées géographiques.
En bonus et si vous avez encore du temps
2. Comment la trame permet de résoudre l'enquête¶
Résolution d'une énigme¶
Passionné d'informatique, le CPE leur demande de lui montrer leur téléphone.
Après avoir cherché dans les fichiers enregistrés, voici ce qu'il y trouve :
pour Mathilde : $ \rm \$GNGGA,114430.249,4911.0400,N,00022.7460,W,0,0,,84.3,M,47.1,M,,*7B$
et pour Arthur : $ \rm \$GNGGA,113550.295,4911.1841,N,00022.825,W,0,0,,84.2,M,47.3,M,,*7B$.
Aidez le CPE à décoder ces informations pour savoir où étaient Mathilde et Arthur.¶
A la fin de la séance, bien penser à
enregistrerpuis cliquer surRendre le devoir.¶Votre page pourra alors être commentée et notée par le professeur