Intro :
Se repérer sous terre par rapport à la surface est un problème.
Les méthodes actuelles, basées sur des relevés topographiques, sont précises, mais très complexes à mettre en œuvre.
Alors qu’en surface, le moindre GPS est capable de reproduire un trajet avec une précision suffisante, avec une facilité apparente déconcertante, j’éprouve une certaine frustration de ne pas pouvoir aussi « simplement » reproduire les trajets souterrains.
Le projet Métrocar est né de ce constat.
Abstract Locate yourself underground versus surface is a problem. Current methods, based on topographic surveys are accurate , but very complex to implement. While on surface, any GPS is capable of reproducing a track with sufficient precision, with disconcerting apparent ease, I feel some frustration of not being able also "simply" reproduce underground rides. The Métrocar project was born from this observation.
I La genèse – les contraintes
Le but est de réaliser un outil, facilement reproductible, le plus simple possible d’usage et d’un prix de revient modéré. Cela impose que la partie électronique soit basée le plus possible sur des cartes disponibles dans le commerce, et que la partie logicielle se base sur des langages de programmation standards.
De plus, le milieu souterrain étant « hostile » par nature, un l’appareil devra comporter aussi peu de parties sensibles (électronique, mécanique de précision…) que possible, afin de ne pas compromettre sa fiabilité.
Enfin, je désirais un appareil basé tout ou partie sur du matériel / logiciel libre.
II L’état de la technique
Une carrière souterraine, c’est noir, c’est grand, c’est humide, mais c’est beau…
Cela ressemble à cela :
Traditionnellement, pour les mesures de distance, on peut actuellement utiliser le décamètre, le topofil, ou un odomètre :
Pour les mesures d’angles / directions, on a la boussole et le théodolite :
Sans oublier le carnet de notes, le crayon, et le temps nécessaire à la sortie pour tout tracer sur papier ou entrer les données dans un logiciel informatique.
L’avantage est bien sûr la précision, mais les inconvénients majeurs sont le temps nécessaire aux relevés, le coût du matériel, ainsi que la logistique nécessaire.
Il existe également des applications pour téléphone mobile pouvant simuler un théodolite. Je n’ai pas testé personnellement.
III L’idée
La technologie actuelle nous permet d’envisager un appareil mesurant à la fois la distance parcourue, la direction d’avancement, la distance par rapport aux murs, voir même la hauteur du plafond. Cet appareil enregistrerait les données sous une forme numérique, effectuerait un traitement de base, et permettrait un transfert direct vers un système informatique de traitement. Tout cela de manière simple, pratique, et pour un coût raisonnable .
Voici l’idée de base du Métrocar.
IV La partie matérielle
L’appareil se compose :
– d’une roue, d’un diamètre connu.
– un capteur de nombre de tours de roue
– une boussole (3 axes)
– 2 ou 3 sonars ultrason
– 1 ou plusieurs microcontrôleurs, voire même nano-ordinateur
– 1 support de stockage de données informatique
– 1 moyen d’alimenter l’ensemble en électricité
– 1 châssis pour supporter le tout.
– 1 niveau à bulle pour maintenir l’engin le plus vertical possible (vital pour le bon fonctionnement de la boussole)
V Le prototype
Il est basé sur un ensemble fourche / roue / potence de VTT. La roue fait 26 ». Je pense qu’une roue « tout terrain», d’un diamètre important, permet de mieux absorber les irrégularités du terrain. Il est à noter à ce sujet que, dans ce même but, le pneu est à une pression proche de 0 bar. Il n’y a pas de poids, donc le gonfler serait équivalent à rouler avec une roue en bois.
Sur la jante sont fixés de manière équidistante 6 aimants. Le passage de ces aimants est repéré par un capteur à effet Hall, fixé sur la fourche. Entre 2 aimants, la roue parcourt exactement 26,5 cm.
La direction d’avancement est relevée à partir d’une boussole électronique située en partie haute, sur un « mat » en bois. Il s’agit d’une boussole 3D (mesurant en x, y et z), ce qui permet une correction logicielle d’un éventuel défaut d’inclinaison de l’appareil.
Le relevé de la distance de l’appareil par rapport aux murs est confié à 2 sonars millimétriques à ultrason, de portée unitaire 5 m.
Enfin, toutes les informations issues des capteurs sont relevées à chaque passage d’aimant devant le capteur hall, et un premier traitement est réalisé par une carte micro-contrôleur Arduino Uno. Ces informations sont ensuite stockées sur une carte mémoire.
Rien de bien compliqué donc pour qui s’est un peu frotté à l’automatisme.
Comme un dessin vaut mieux qu’un discours, voici le prototype :
VI La partie logicielle – le traitement réalisé par l’appareil
Lorsque l’appareil est en fonction « mesure », une série de relevés est effectuée à chaque passage d’un aimant devant le capteur hall, c’est à dire tous les 26,5 cm d’avancement par rapport au sol.
Le micro-contrôleur (dans ce cas la carte Arduino Uno) relève alors les valeurs de la boussole (en x,y,z), envoie (avec un très court différé) une impulsion ultrason avec chaque sonar, récupère l’écho de retour et en déduit la distance par rapport à l’obstacle (en l’occurence, aux murs). On additionne les 26,5 cm à la distance précédemment mesurée.
On fait également clignoter une led de contrôle.
Enfin, toutes ces données sont enregistrées sur une carte mémoire (type SD), sous forme d’un fichier texte (type csv).
Toute cette partie est open-source. Pour les lecteurs curieux et techniques, voici le code source :
—————————— Code —————————-
// Logiciel de lecture / stockage de mesures prises par un odomètre de carrières
#include <Wire.h>
#include « compass.h » // lib du compas
#include « Ultrasonic.h » //lib des telemetres a ultrasons
#include <SD.h> // lib pour la carte SD
#include <SPI.h>
// variables du compas
float directionCompas;
// pour debug :
float rawXCompas, rawYCompas, rawZCompas;
// variables des telemetres
Ultrasonic ultrasonic1(8); // sur D8 telemetre gauche
Ultrasonic ultrasonic2(7); // sur D7 telemetre droit
long distanceDroite, distanceGauche;
float distanceParcourue; // en m
// variables du fichier sur carte SD
Sd2Card card; //Variables utilisées par le programme
SdVolume volume;
SdFile root;
File releves; //Fichier à créer et effacer
// Modifier ceci selon le module utilisé, pour le shield Ethernet utiliser pin 4
// Pour les shields et modules Adafruit : pin 10; Sparkfun SD shield: pin 8
const int chipSelect = 4; //Configuré en sortie
int Erreur = 0; // pour la sortie des erreurs
int numSerieMesure = 0; // sert a identifier les series de mesures
int etatHall = 0; // sert a savoir si le capteur a ete active
const int hallPin = 2; // pin du capteur a effet hall (pin pour interuption materielle)
int valeurHall;
const int interMesurePin = 3; // pin pour l’inter mesure On (pin pour interuption materielle)
int mesuresOn = 0; // vaut 1 prise de mesures enclenchee, 0 sinon : cf interrupteur
float cRoue = 206.5 / 6; // circonférence de la roue de mesure en centimetres div par le nombre d’aimants
// les leds :
int ledNoEnregistre = 4;
int ledEnregistre = 5;
int ledTopMesure = 6;
void setup()
{
// Init du port serie (debug)
Serial.begin(9600);
Serial.println(« Starting the I2C interface. »);
Wire.begin(); // Start the I2C interface.
// init des variables à 0;
directionCompas = 0;
distanceDroite = 0;
distanceGauche = 0;
distanceParcourue = -(cRoue);
pinMode(hallPin, INPUT); // entree du capteur a effet hall
pinMode(interMesurePin, INPUT); // entree de l’inter de mesure
// init des leds
pinMode(ledNoEnregistre, OUTPUT);
pinMode(ledEnregistre, OUTPUT);
pinMode(ledTopMesure, OUTPUT);
digitalWrite(ledEnregistre, LOW);
digitalWrite(ledNoEnregistre, LOW);
digitalWrite(ledTopMesure, LOW);
// Séquence d’init du compas
/* Author = helscream (Omer Ikram ul Haq)
Last edit date = 2014-06-22
Website: http://hobbylogs.me.pn/?p=17
Location: Pakistan
Ver: 0.1 beta — Start
Ver: 0.2 beta — Debug feature included
*/
compass_x_offset = -99.87;
compass_y_offset = 84.80;
compass_z_offset = 313.33;
compass_x_gainError = 1.12;
compass_y_gainError = 1.13;
compass_z_gainError = 1.03;
// compass_init(2);
// compass_debug = 0;
// compass_offset_calibration(3); // laissé pour calibration éventuelle
// Init de la cate SD
Serial.print(« \nInitialisation SD … »);
//Laisser en sortie pin 10 sinon SD ne fonctionnera pas
pinMode(10, OUTPUT); // pin 53 si carte Mega
//Tester si la carte fonctionne
if (!SD.begin(chipSelect)) {
Serial.println(« Carte non trouvée »);
Erreur = 1;
testErreur;
return;
} else {
Serial.println(« Montage correct et carte presente »);
Erreur = 0;
}
// Vérifier si ce fichier existe
if (SD.exists(« releves.txt »)) {
// si le fichier existe, on l’ouvre
releves = SD.open(« releves.txt », FILE_WRITE);
releves.close();
}
else {
// sinon, on le cree
releves = SD.open(« releves.txt », FILE_WRITE);
releves.close();
}
// Fin de l’init de la carte SD
// gestion des interruptions materielles :
attachInterrupt(0,calculDistance,FALLING); //mesure la distance si le capteur Hall passe a l’etat bas
attachInterrupt(1,changeSerie,FALLING); // gere le changement de serie de mesures quand l’inter passe OFF
}
void lectureDirection() { // fonction de lecture du compas
compass_heading();
directionCompas = bearing;
// pour debug :
compass_scalled_reading();
rawXCompas = compass_x_scalled;
rawYCompas = compass_y_scalled;
rawZCompas = compass_z_scalled;
// fin du debug
}
void distanceMurs() {
// fonction de prise de mesure avec les telemetres ultrasons, source exemple fournit avec la lib
distanceDroite = ultrasonic1.MeasureInCentimeters(); //mesure de la distance du mur droit (en cm)
delay(20); // car probleme de perturbations des 2 capteurs sinon
distanceGauche = ultrasonic2.MeasureInCentimeters(); //mesure de la distance du mur gauche (en cm)
}
void enregistreDonnees() {
// fonction d’enregistrement des mesures sur la carte SD
releves = SD.open(« releves.txt », FILE_WRITE);
if (releves) {
releves.print(numSerieMesure);
releves.print(« ; »);
releves.print(directionCompas);
releves.print(« ; »);
releves.print(distanceParcourue);
releves.print(« ; »);
releves.print(distanceDroite);
releves.print(« ; »);
releves.print(distanceGauche);
releves.print(« ; »);
releves.print(rawXCompas);
releves.print(« ; »);
releves.print(rawYCompas);
releves.print(« ; »);
releves.println(rawZCompas);
Serial.println(« Enregistrement SD Ok »);
releves.close();
Erreur = 0;
}
else {
Serial.println(« erreur d’enrregistrement « );
Erreur = 1;
}
}
void calculDistance() // fonction de calcul de la distance a partir du capteur Hall
{
if (mesuresOn == HIGH) { // on fait la boucle si l’inter de mesure est on
Serial.println(« InterruptionHall »);
etatHall = 1;
distanceParcourue = distanceParcourue + cRoue;
} // sinon, on ne fait rien
} // fin de la fonction calculDistance
void changeSerie() // Gestion du changement de serie de mesures
{
numSerieMesure = numSerieMesure + 1; // increment du num de mesure
distanceParcourue = 0; // remise a 0 du compteur
} // fin de changeSerie
void testErreur() {
digitalWrite(ledTopMesure, HIGH);
digitalWrite(ledEnregistre, HIGH);
digitalWrite(ledTopMesure, HIGH);
delay(200);
digitalWrite(ledTopMesure, LOW);
digitalWrite(ledEnregistre, LOW);
digitalWrite(ledTopMesure, LOW);
}
void loop() {
mesuresOn = digitalRead(interMesurePin);
if (Erreur == 0) { // on fait la boucle si il n’y a pas d’erreur de carte SD
if (mesuresOn == HIGH) { // on fait la boucle si l’inter de mesure est on
digitalWrite(ledEnregistre, HIGH);
digitalWrite(ledNoEnregistre, LOW);
if (etatHall ==1) { // on lance une mesure que si on a avancé…
digitalWrite(ledTopMesure, HIGH);
lectureDirection();
distanceMurs();
enregistreDonnees();
etatHall = 0; // re-init de l’etat du capteur
digitalWrite(ledTopMesure, LOW);
} // fin de la boucle de mesure
} // fin de la boucle si inter mesure on
else { // si l’inter de mesure est off
digitalWrite(ledEnregistre, LOW);
digitalWrite(ledNoEnregistre, HIGH);
} // fin du else
} // fin de la condition Erreur = 0
else {testErreur; } // on fait clignoter les leds si il y a erreur de carte SD
} // fin du loop
———————— / fin du code / ————————————
Niveau matériel, je me base sur une carte Arduino Uno, du matériel Grove (juste par facilité de câblage), quelques leds et fils… Rien de bien compliqué à reproduire.
VII La partie logicielle – le traitement réalisé sur ordinateur
Cette partie à été développée par mon père, sous Delphi.
C’est sans doute la mise au point de cette partie qui fut la plus délicate et la plus gourmande en temps et énergie.
Pour le moment, il n’est pas possible de mettre le logiciel de traitement en open-source, car celui-ci fait appel à de nombreuses bibliothèques externes. Pour cette même raison, il ne fonctionne pour le moment que sous l’environnement MS Windows.
Donc, lorsque la série de mesures est terminée, on récupère les mesures, via la carte SD, et on les communique au logiciel de traitement.
L’interface de celui-ci se présente au moment de l’écriture de ces lignes comme ceci :
On renseigne également les coordonnées (latitude / longitude) du point de départ. Il est préférable d’ailleurs d’effectuer les mesures en réalisant une boucle fermée (aller-retour), car cela permet de corriger de manière logicielle les petits décalages.
Le logiciel trace alors un plan et permet ensuite un export du tracé vers Google Earth (cf les tests ci après), ou pour tout autre logiciel travaillant avec des fichiers « GPX ».
IIX Les tests
Après moult tests en extérieur afin de valider les parties mécaniques et logicielles, j’ai effectué une série de relevés dans une grande carrière du centre de la France.
Après traitement logiciel, cela donne :
Et avec zoom sur une partie du tracé :
Sur le plan, apparaît en noir le parcours réalisé, et en vert et rouge les murs (avec les entrées donnant sur d’autres galeries).
Le parcours à été réalisé sur le roulage principal de la carrière, environ 2,5 kms aller – retour. Cela nous à pris environ 2h, en comptant la pause… Par rapport à ce que je connais de cette carrière, la projection sur GoogleEarth présente peu d’erreur.
On peut donc maintenant connaître, avec une raisonnable précision, le parcours d’une ou plusieurs galeries souterraines.
VII Les limites actuelles et développements futurs
Bien entendu, les tests terrains vont continuer en 2016.
Le Métrocar fait également l’objet d’un dépôt à l’INPI.
Pour le moment, la grosse contrainte qui ressort des tests terrain est la difficulté à maintenir l’assiette de l’engin.
Une autre limite est la non prise en compte des dénivelés. Cependant, il à été calculé que dans une carrière souterraine, les rampes étant la plupart du temps faibles, cette limite n’induisait pas d’erreur supérieure à la précision de l’appareil.
En ce qui concerne les évolutions possibles, il y a (liste non exhaustive…) :
– stabiliser électroniquement l’engin avec des gyroscopes, ou mécaniquement avec adjonction de roues stabilisatrices
– étudier la possibilité d’envoi de données en temps réel sur une tablette, afin d’avoir un tracé immédiat.
– ajouter un 3 ème sonar pour mesurer la hauteur du plafond
– ajouter un capteur barométrique afin de pouvoir estimer les changement d’altitude
– travailler sur un prototype plus « design »
– tester, tester, tester…
– …
Conclusion
Le Métrocar dans son état actuel est une « preuve de concept ». Il ne demande qu’à évoluer. C’est pourquoi j’ai écrit cet article. Si des lecteurs sont intéressés, qu’ils n’hésitent pas à se mettre en rapport avec moi, afin que nous puissions ensemble tester et faire évoluer l’engin.
Je tiens à remercier par ces lignes mon père, sans qui tout cela ne serait resté qu’à l’état d’idée, ainsi que ma compagne Fabienne et à mon amie Sylvie, pour leur soutien actif lors des tests terrain.
V. Barousse.
Edit du 19/02/17 :
Les librairies fournies par Grove utilisées dans ce projet (dont Ultrasonic.h) génèrent une erreur sous les dernières versions de l’IDE Arduino. il est nécessaire d’utiliser la version 1.0.6 téléchargeable ici. Si quelqu’un à des news par rapport à ce problème, qu’il n’hésite pas à me contacter !