NMEA : des données structurées
Principe et objectifs
Lors de séances précedentes, nous avons découvert que les programmes échangent des données structurées : Le logiciel qui met en forme les données issues des satellites GPS fabrique une trame NMEA, dans laquelle les différents champs sont séparés par une virgule.
Cette séparation des données s’appelle : comma separated value (csv).
Le format CSV permet d’organiser les informations dans un ordre précis. Dans chaque ligne, les données respectent le même ordre. Le fichier de données csv peut alors être facilement ouvert avec un tableur (ou être sauvegardé en .csv
à partir d’un tableur : Un caractère particulier – généralement la virgule – permet au logiciel de placer les valeurs dans des colonnes différentes.
Une librairie Python peut être utilisée pour découper ces informations et les mettre sous forme de liste.
librairies utilisées
- folium (pour la creation de carte openstreetmap)
- csv (apporte la fonction
reader()
pour le decoupage d’une ligne en csv.
Que contient la trame NMEA ?
Parmi les différentes lignes constituant la trame, l’une d’entre elles débute par les symboles $GPGGA
Les données sont mises dans un format particulier expliqué ici :
Les valeurs numériques recherchées sont celles de la latitude et de la longitude du lieu.
Ces valeurs sont mises sous la forme DDMM.MMMM :
lorsque l’on lit 4836.5375, la valeur doit être comprise comme : 48°36,5375'
c’est à dire :
- 48°
- 36,5375 minutes d’arc
Traitement des trames NMEA sous forme de chaine de caractère
Après l’ouverture du fichier avec l’instruction fichier = open('docs/nmea.log','r')
:
Chaque ligne du fichier nmea.log
est mise dans la liste lignes
avec l’instruction lignes = fichier.readlines()
Pour acceder à la ligne n°2, par exemple, il faut écrire : lignes[1]
Le script suivant permet d’afficher tous les éléments de la liste lignes
grâce à la boucle bornée for i,ligne in enumerate(lignes):
fichier = open('docs/nmea.log','r')
lignes = fichier.readlines()
for i,ligne in enumerate(lignes):
if ligne !='\n': # tester si la ligne est non vide
print('lignes['+ str(i)+'] \n'+ ligne)
fichier.close()
Utiliser la librairie csv et manipuler une liste
la fonction reader de la librairie csv
executer le script suivant pour créer l’objet trames qui contient tous les éléments du fichier nmea.log
Repérer que la fonction utilisée reader() utilise pour paramètre le caractère ‘,’. On pourrait choisir d’autres types de séparateurs, comme ‘;’ par exemple. Mais ici, le fichier nmea.log utilise bien ‘,’.
manipulation d’une liste
La boucle bornée for row in trames:
a pour rôle de créer une liste trame
où chaque élément correspond à l’une des lignes du fichier nmea.log.
Ces éléments sont ajoutés dans la liste trame
à l’aide de la fonction append
Chaque élément trame[i]
est lui même une liste. Ainsi, pour afficher un élément de la liste trame
, il faut faire trame[i]
.
On peut également atteindre chaque élément de trame[i]
en faisant trame[i][j]
.
from csv import reader
trame = []
trames = reader(lignes, delimiter=',')
for row in trames:
trame.append(row)
à vous de jouer
- dans la cellule suivante, taper
trame[0]
pour afficher le premier élément de la listetrame
(correspond à la première ligne du fichier nmea.log) - dans la cellule qui suit, taper
trame[0][0]
pour afficher le premier champs detrame[0]
: s’agit-il bien de $GPGSA, comme on peut le voir dans la liste des lignes de nmea.log ? - Modifier alors le contenu des 2 cellules que vous venez d’utiliser pour accéder aux valeurs des coordonnées GPS latitude et longitude indiquées dans le fichier.
trame[]
trame[0][]
transformer la chaine de caractère en un nombre
La valeur retournée par trame[6][2]
est de la forme : ‘4341.9791’, avec des guillemets. C’est une chaine de caractères, même si le contenu est constitué de chiffres. On ne pourra pas faire d’opérations mathématiques dessus, à moins de la transformer en nombre.
Il faut utiliser pour cela la fonction float() :
par exemple : float(trame[6][2])
qui devrait renvoyer 4341.9791 : un nombre
Deiviser ce résultat par 100 pour avoir la partie entière qui sera constituée uniquement des degrés : trame[6][2]/100
Mettre le résultat dans la variable lat
puis afficher le résulat : print(lat)
lat = float(trame[][])/100
print(lat)
Pour conserver les 2 premiers chiffres : extraire la partie entière avec la fonction int():
int(lat)
Mettre le résultat dans la variable lat_deg
(la partie correspondant aux degrés entiers) puis afficher le résultat
lat_deg =
print(lat_deg)
Retirer la partie entière de lat
pour ne conserver que les nombres après la virgule : lat - lat_deg
Affecter le résultat à la variable lat_min
et afficher le résultat
lat_min =
print(lat_min)
Enfin : transformer lat_min
en une valeur decimale : lat_min *100 /60
Affecter à nouveau le résultat à lat_min
. Afficher lat_min
lat_min =
print(lat_min)
Reconstituer la valeur numérique
- affecter alors à la variable
lat
la nouvelle valeurlat_deg + lat_min
Afficher la valeur de lat
lat =
print(lat)
Pour aller plus loin (partie facultative…mais conseillée)
Vous allez écrire une fonction appelée conversion_base10(latlon)
qui devra transfromer la chaine de caractère extraite de la trame NMEA (chaine de caractères ‘ddmm.mmmm’) en une valeur décimale. Le traitement sera identique à celui que vous avez réalisé. On donne l’algorithme de cette fonction :
fonction conversion_base10(latlon):
l ← flottant(latlon)/100
l_deg ← entier(l)
l_min ← l - l_deg
l_min ← l_min*100/60
l ← l_deg + l_min
retourne l
Faire le même travail pour la longitude.
Créer les variables lon, lon_deg et lon_min à partir du fichier nmea.log. On pourra, au choix, utiliser la même procedure que pour lat, ou bien, utiliser la fonction conversion_base10()
Vérification
Pensez à vérifier vos résultats en affichant avec print()
les valeurs de chacune des variables (lat, lon, lat_deg, lat_min…)
Lorsque vous êtes satisfaits du résultat, executez la cellule suivante pour afficher un marqueur sur la carte, qui sera géolocalisé à partir de votre latitude et longitude…
Remarque : lors de la permière execution du code suivant, il peut être utile d’enlever le # au debut de la première ligne afin de charger la librairie folium.
Remettre alors le commentaire pour les prochaines fois où vous executez ce code (il n’est pas necessaire de recharger cette librairie une deuxieme fois au cours de la même session)
#!pip install folium
import folium
carte = folium.Map(location=[lat,lon], zoom_start=10)
folium.Marker([lat,lon]).add_to(carte)
display(carte)