01) Un fifrelin indispensable de théorie sur le protocole NMEA 0183.

Internet fourmille de sites sur lesquels on trouvera tout ce qu’il faut savoir sur les protocoles définis par l’association National Marine Electronics Association basée au Maryland. La norme NMEA 0183 décrit la communication entre équipements marins dont les systèmes GPS.
Méfiez-vous, j’ai constaté sur certains sites que la vitesse de transmission sur la SCI était de 4800baud. Ce n’est plus vrai, actuellement, tout au moins pour les petits modules GPS, elle est du double. Pour vous épargner initialement d’avoir à consulter les nombreux documents traitant du sujet sur l’Internet, on va passer en revue le contenu des trames de caractères retournés par un GPS qui respecte la norme 0183. Nous allons le faire sur « du concret » par le biais de démonstrateurs.

Experience_01 : Visualisation des signaux GPS NMEA 0183.

D‘une simplicité maximale, ce démonstrateur se contente de surveiller la ligne SCI du petit module NEO-6M, et d’afficher sans aucun formatage les caractères prélevés sur la ligne série secondaire. Pour simplifier au maximum le logiciel, on réserve la voie série d’Arduino au dialogue avec le Moniteur de l’IDE initialisé comme pour tous les autres démonstrateurs à 57600 baud. Puis par logiciel on émule sur D2 et D3 (Pris dans l’ordre des broches disponibles) une deuxième ligne série qui va dialoguer avec le récepteur GPS à 9600bauds. Dans ce but on se simplifie la vie et l’on fait appel à la bibliothèque <SoftwareSerial.h> native dans le compilateur, il suffit de la déclarer. Sur la Fig.3 on a mis en évidence les « paquets » de trames qui se succèdent. Sur cette copie d’écran le GPS vient d’être mis sous tension, il n’a pas encore capté suffisamment de satellites pour extraire des données, raison pour laquelle des informations qui devrait se trouver entre les séparateurs ‘,‘ ne sont pas présentes. Il vous suffit de téléverser le démonstrateur Expérience_01.ino et d’observer les données sur le Moniteur que vous avez initialisé à 57600baud. Dès que vous voyez s’afficher des trames du type de celle de la Fig.1, c’est que le matériel est opérationnel. Pouvant fonctionner à partir de +3,3Vcc jusqu’à +5Vcc personnellement j’ai opté pour la sortie +5Vcc régulée d’Arduino car sur des cartes de type NANO la tension de 3,3V est un peu limite. La première observation montre que chaque trame commence par un préambule mis en évidence en jaune. Le caractère ‘$‘ est par convention le marqueur du début d’une trame. Les deux caractères qui suivent « GP » précisent que le dispositif qui dialogue sur la SCI est un GPS. Les trois lettres qui suivent caractérisent la nature du contenu de la trame. Chaque trame contient une suite d’informations diverses séparées par les délimiteurs ‘,‘ et se termine en principe par le trio « *HH » où ‘*‘ est le marqueur de fin de la trame et HH un CRC de contrôle exprimé en HEXADÉCIMAL. Enfin, on peut constater que des séquences de six trames se succèdent et se répètent plus ou moins une fois par seconde environ. Lorsque plusieurs satellites ont été captés et leurs informations traitées, la LED bleue du module NEO-6M se met à clignoter à la cadence de délivrance des groupes et, comme montré sur la Fig.4, le nombre de séquences peut passer à huit groupes avant de retrouver un nouveau cycle d’affichage. Avant d’analyser le contenu de chaque groupe, et de chaque trame, commençons par détailler ce que représente le CRC et la façon dont il est calculé sur un GPS.

Le CRC de contrôle de la réception.

Toute transmission d’information, que ce soit par voie filaire où par ondes hertziennes peut être affectée par un ou des parasites. Dans le cas d’une transmission de type binaire, codé ici en HEXADÉCIMAL, un ou plusieurs BITs peuvent être perdus ou inversés par présence d’un parasite. Aussi, le dispositif terminal qui va traiter l’information doit s’assurer que l’intégralité de cette dernière est correcte. C’est le but du CRC, qui est l’abréviation de Cyclic Redundancy Code. On peut affirmer que les CRC sont utilisés depuis le début des transmissions de donnée binaires, qu’elles se fassent en série ou en parallèle. Les checksums (Sommes de contrôle) consistent à effectuer avec chaque caractère envoyé un calcul plus ou moins compliqué, et à terminer la transmission par le résultat de ce dernier. Par exemple on effectue la somme OCTET par OCTET et l’on envoie le résultat. Sur le système de réception on va effectuer un traitement identique, et on compare notre résultat avec celui du CRC. Si les deux sont différents, la donnée reçue a été polluée et n’est pas fiable. Alors on traite l’erreur. Pour la norme NMEA 0183, le calcul du CRC est élémentaire. On se contente de faire un OU EXCLUSIF entre tous les caractères ASCII compris entre les délimiteurs ‘$‘ et ‘*‘ bornes non comprises. Naturellement, lors de nos expériences on va traiter le sujet, mais à ce stade c’est prématuré, car on ne sait pas encore extraire et filtrer les données.

Experience_02A : Mise en évidence d’un sérieux problème.

Initialement, j’ai naïvement pensé que la mise en mémoire des différentes trames serait relativement facile, l’organigramme de la Fig.5 traduisant l’algorithme idoine. Si l’on se contente de la définition d’une trame telle que la présente la norme NMEA 0183, on en déduit qu’une trame commence par ‘$‘ et se termine par le CRC suivi de CR et de LF. CR pour « Caridge Return » et LF pour « Line Feed ». Si tel était le cas, on commence à remplir la mémoire tampon dès qu’un ‘$‘ est reçu jusqu’à rencontrer le LF de fin de la trame. Alors on affiche le contenu de la mémoire tampon et on va alors lire et enregistrer la trame suivante. C’est exactement ce que fait Expérience_02A.ino que je vous invite à téléverser. Le résultat de cette stratégie est représenté sur la Fig.6 qui visiblement montre que la trame semble contenir des passages inopinés à la ligne. Pourtant, lorsque l’on téléverse le démonstrateur Expérience_02B.ino on constate sur la Fig.7 qu’il n’y a pas de caractère [10] ni de caractère [13] après ‘$‘. C’est pour moi totalement contradictoire et incompréhensible. Si quelqu’un trouve la réponse … je suis preneur.
CONCLUSION : Si on se réfère à P02B on n’a pas de passage à la ligne après ‘$‘. Si on considère P02A des passages à la ligne fantôme sont enregistré dans la mémoire tampon. Il va falloir « fonctionner en dégradé », c’est à dire filtrer ces CR et LF fantôme pour arriver à des contenus de la mémoire tampon corrects contenant une trame complète commençant par le délimiteur ‘$‘ et s’achevant par l’annonciateur du CRC*‘. C’est le but du prochain démonstrateur. Ces débuts ont été dans ce développement logiciel particulièrement indigestes !

 

Experience_03 : Mise en mémoire tampon des données.

Pour être capable d’effectuer un traitement logiciel sur des données, il importe de les avoir à disposition et dans leur ensemble sous un « format propre ». Hors, sur la voie série secondaires elles arrivent par paquets à une cadence rapide. Ensuite entre deux séquences on dispose d’un délai d’environ une demi-seconde pour les traiter. Il faut au préalable les loger dans une mémoire tampon. C’est exactement ce que fait le démonstrateur Expérience_03.ino qui procède en deux étapes. Il commence par enregistrer une trame complète en effectuant le filtrage des CR et LF fantômes dans la mémoire tampon prévue pour 82 caractères qui est la taille maximale dans la norme NMEA 0183. Puis il procède à l’affichage du contenu du tampon aboutissant au résultat de la Fig.8 qui cette fois est cohérent.

Experience_04 : Premier programme d’exploitation.

Maintenant que l’on peut stocker une trame complète et épurée des CR et LF fantômes on va pouvoir commencer à écrire du programme qui effectue un traitement informatique. Bien que la notion de CRC n’est pas celle qui nous motive le plus dans l’exploitation d’un GPS, comme en page 3 on a abordé le sujet, autant évacuer cette notion. Le traitement effectué par le démonstrateur Expérience_04.ino consiste à filtrer les trames de type GPGGA, à les afficher, et à calculer le CRC affiché entre crochets en fin de ligne. Quand P04 est téléversé dans Arduino, on peut vérifier sur la Fig.8 que le résultat du calcul de vérification affiché dans la colonne violette est bien égal à la valeur du CRC retournée par le module GPS dans la colonne jaune. En particulier, sur la deuxième et la troisième ligne le 5D confirme bien que cette valeur est en HEXADÉCIMAL. Naturellement, pour que nous puissions comparer facilement le résultat du OU EXCLUSIF représenté par l’opérateur ‘^‘ en langage C++ le croquis exprime la valeur également en base 16 par l’instruction Serial.print(CRC,HEX). Pour calculer cette « checksums » on utilise à chaque chargement d’un caractère OCTET reçu sur la ligne série l’instruction CRC = CRC ^ byte(OCTET). La valeur de la variable CRC de type byte est forcée à zéro avant chaque extraction d’une trame. Conformément à la norme NMEA 0183 seuls les caractères compris entre les bornes ‘$‘ et ‘*‘ sont pris en compte.

Le préambule du protocole de la norme NMEA 0183.

Comme c’était annoncé en début de ce didacticiel, nous allons pas à pas décortiquer la structure des trames normalisées, progression imagée par des démonstrateurs adaptés. Nous avons vu avec P1 que chaque trame commence par un préambule de cinq lettre qui suivent l’annonciateur ‘$‘. Ce préambule commence toujours par GP qui est la signature du système qui dialogue sur la SCI, en l’occurrence un GPS dans notre cas. Le tableau de la Fig.10 précise la nature des informations logées dans la trame en fonction de son préambule défini sur trois lettres. On remarque que pour filtrer les trames de type GPGGA, ce sont les seules qui présentent une deuxième lettre du préambule égale à ‘G‘. C’est précisément cette particularité qui est exploitée par P04 pour filtrer ce type de trames. Donc en fonction de ce que l’on désire afficher, nous effectuerons la sélection de la trame à exploiter par une technique analogue à celle adoptée ici.

Experience_05 : L’extraction par fracturation.

Mais non ! Il ne s’agit pas ici de la fracturation hydraulique pour récupérer les combustibles fossiles en polluant l’environnement. On va avec le démonstrateur Expérience_5.ino extraire des séquences de données dans la trame de type GGA que sous savons isoler en mémoire tampon. Le programme va devoir extraire les données chiffrées qui nous intéressent et les transformer en équivalent numérique pour les afficher « en clair ». Considérons la Fig.11 qui est extraite de la Fig.9 et décortiquons les données qui y sont listées. Dans la colonne en rose pastel, on trouve l’heure de réception de ces informations. Dans la colonne bleu clair et la colonne vert clair sont précisées les coordonnées géographiques du récepteur NEO-6M. Dans la colonne jaune on retrouve le CRC qui est analysé par le croquis. La valeur orange précise le nombre de satellites pris en compte pour traiter les données Enfin, dans la colonne ocre l’altitude du récepteur GPS. Dans un premier temps, on va simplifier et la finalité de P05 consiste à extraire l’HEURE de réception des données et à l’afficher en clair sur le Moniteur de l’IDE. Par ailleurs, l’affichage de ces donnée ne sera effectué que si elles sont cohérentes, dans le cas contraire l’opérateur sera prévenu par un texte d’erreur. Ces lignes sont présentées à l’écran environ une fois par seconde qui est la cadence des « rafales » de données sur la SCI. Lorsque vous aurez constaté le bon fonctionnement du programme qui affiche l’heure en T.U. (Une heure de moins en hiver et deux heures de moins en été par rapport à l’heure légale en France.) vous changez la valeur du paramètre PERTURBER en true situé en tête de listage. L’affichage devient celui de la Fig.12, car pour l’un des retours de trame sur deux l’un des caractères du CRC dans ce dernier est faussé. On peut ainsi vérifier la fiabilité de la vérification des trames. On constate au passage qu’il s’écoule bien une seconde entre chaque réception d’un groupe de données. Dans une application digne de ce nom, l’heure devrait être traduite en heure légale, ce sera bien entendu le cas dans certains prochains démonstrateurs. Ceci étant précisé, les techniques pour extraires les autres données vont dériver directement de ce qui vient d’être mis en place. Le chemin vers un système autonome est tout tracé …

Changer de genre !

Banal et permanent en génie logiciel, on doit sans arrêt changer la nature des données. Le cas typique dans P5 consiste à extraire des chaînes de caractères d’une mémoire tampon. Puis, transformer en nombres numériques ces éléments qui sont des suites de lettres et de chiffres. Ce petit chapitre s’adresse à celles et ceux qui ont du temps à consacrer au « comment ça marche ». La technique de base qui sera utilisée chaque fois que l’on veut extraire une donnée numérique consiste à décaler à gauche Tampon[] autant de fois que nécessaire pour y amener le début de la donnée à extraire. Ensuite on recopie les chiffres de cette information dans une chaîne de caractère que l’on transforme en une valeur numérique qui alors se prête facilement à du calcul mathématique. La Fig.13 illustre ce processus dans le cas d’une trame de type GGA dont on désire extraire par fracturation les données qui nous concernent le plus. En 1 le contenu de Tampon[] est décalé 7 fois à gauche en 2 pour y amener la valeur de l’HEURE. Puis les caractères sont extraits par deux pour déduite la valeur de l’heure, des minutes et des secondes. Puis par encore quatre décalages à gauche en 3 on amène en 4 en début du tableau Tampon[] la séquence relative à la latitude. Cette dernière étant traitée, on continue le processus en 5, 6 et 7 pour détacher une à une les autres données.

Experience_06 : Décaler à gauche les valeurs numériques.

Afin d’illustrer concrètement le propos du chapitre précédent, Expérience_02.ino se contente de décaler cinq fois à gauche le contenu de Tampon[] pour isoler par « latéralisation » les données numériques qui sont sensées nous concerner. Le résultat montré sur la Fig.14 est à comparer avec celui de la Fig.13 qui était un montage créé manuellement dans un logiciel de dessin élémentaire.

La suite est ICI.