Réaliser un télémètre à ultrasons

Comme nous avons pu en parler dans un des chapitres sur les capteurs, il est possible de mesurer une distance via l’utilisation d’un télémètre à ultrasons. Bien que peu précis à l’échelle des centimètres, ces derniers sont relativement fiables à l’échelle de la dizaine de centimètres et utiles. Comme ils balayent un cône (ils sont peu directifs), ils font de très bons détecteurs d’obstacles.
Nous allons donc aujourd’hui nous lancer dans la réalisation d’un petit télémètre à ultrasons avec affichage intégré (parce que la voie série c’est un peu pénible pour se promener 😀 ).

Rappel sur les ultrasons

Faisons un peu de sciences et rappelons ce que sont des ultrasons.
Un ultrason est une onde sonore à haute fréquence. Par haute fréquence j’entends toutes les fréquences sonores inaudibles pour l’oreille humaine, soit celles au-delà de 20 kHz. Elles sont l’opposé des infrasons qui sont les ondes sonores dont la fréquence est inférieure à la plus faible audible pour l’Homme et qui est de 20 Hz.
Bon, c’est bien beau mais cette histoire de fréquence ça ne nous en dit pas beaucoup plus !

Une onde sonore c’est quoi ?

Une onde sonore est un phénomène physique/mécanique de compression/décompression. Lorsqu’une vibration est produite (par n’importe quel objet qui vibre), l’air subit alors une onde de choc qui se traduit en mouvement des atomes. Il y a alors ce phénomène de compression/décompression que des récepteurs dans nos oreilles convertissent en bruit.
Plus les compressions sont proches et plus la fréquence est élevée. On parle alors de son aigu. Au contraire, plus les compressions sont éloignées et plus la fréquence est faible, on parle d’un son grave.
Une fréquence s’exprime en Hertz et traduit la répétition d’un motif d’un phénomène durant une seconde. Par exemple si je cligne des yeux trois fois par seconde, on peut dire que je cligne des yeux à 3 Hz.

Dans le cas des ultrasons, les compressions/décompressions sont très courtes. En effet, le motif se répète plus de 20 000 fois par seconde, donc à plus de 20 kHz. En général, en électronique on utilise un transducteur piézo pour générer cela. C’est une sorte de petit buzzer capable de vibrer très vite. Très souvent, les télémètres à ultrasons vibrent à une fréquence de 40 kHz.

Une dernière caractéristique des ondes sonores est leur capacité à être réfléchie par les obstacles. En effet, les ondes sonores ont tendance à « rebondir » sur les obstacles. On entend alors l’onde de départ et un peu plus tard la même avec un retard et une plus faible intensité. En général, dans le domaine de l’acoustique et de la musique, on cherche à supprimer cette caractéristique en recouvrant les murs de matériaux spéciaux. Cependant, dans le cas d’une mesure de distance, on va exploiter cet effet.

Principe de la mesure

Comme je le disais juste avant, on va tirer parti du fait que l’onde sonore rebondit sur les obstacles et revient souvent vers l’expéditeur. On va aussi exploiter une autre chose connue, sa vitesse !
En effet, la vitesse de déplacement d’une onde sonore dans l’air est connue depuis longtemps. Elle est d’environ 340 mètres par secondes à 25 degrés Celsius (plutôt lent comparé à la lumière et ses 300 000 km/s 😀 ).
À partir de là, si on sait quand l’onde est partie et quand on la reçoit de nouveau (après le rebond), on est en mesure de calculer un temps de vol de l’onde. On a alors une durée, une vitesse, et on peut en déduire une distance !
Comme l’onde fait un aller-retour (le voyage depuis l’émission de l’onde, le rebond, puis le retour sur le récepteur), il faudra diviser le temps de vol par deux pour ne considérer qu’un trajet (l’aller ou le retour).
Le calcul sera alors simple. Une vitesse s’exprime par une distance divisée par un temps \( v = d/t \) donc la distance sera la vitesse multipliée par le temps \( d = v \times t \).

Passons un peu à la pratique pour mieux comprendre !

IMG_4456

Mise en œuvre du télémètre

Le télémètre que nous allons utiliser est assez simple. Son nom est HC-SR04 et existe en différentes variations. Découvrons-le et voyons comment le faire fonctionner avec notre Arduino.

Le HC-SR04

Présentation du composant

Le HC-SR04 est ce que l’on appelle communément un « Télémètre à ultrasons ». Il est trouvable relativement facilement sur de nombreux sites de fournisseurs de composants électroniques. Les sites livrant depuis la Chine proposent des prix inférieurs à 5 euros en général.
Ce composant possède plusieurs petites choses. Tout d’abord, sur la face avant on peux voir l’émetteur US et son récepteur. Ce sont des petites cellules piézo-électriques qui vont soit vibrer lorsqu’une tension est appliquée (émetteur) soit au contraire produire une tension lorsque une vibration est reçue (récepteur).
Sur la face arrière on trouve plusieurs petits circuits permettant la génération du signal et le traitement de ce dernier. Ainsi, un composant va générer une onde de 40 kHz lors d’un « top départ » et la partie restante s’occupera de la mise en forme de la réception (amplification et filtrage) et de mettre en forme cela proprement sur une broche de sortie.
Parlons d’ailleurs des broches.
On en trouve 4. Les premières sont bien sûr VCC et GND qui vont accueillir l’alimentation (respectivement 5V et masse). On trouve ensuite une broche nommée « Trig ». Cela signifie « Trigger » soit « déclencheur ». En mettant cette broche à l’état haut pendant 10µs vous allez déclencher le ping pour la mesure. Enfin, on trouve la broche « echo » sur laquelle sera présent le signal de sortie.
Ce signal de sortie est assez simple à exploiter. Il est initialement à 0, puis passe à 1 lorsque le ping est envoyé. Il repasse ensuite à 0 quand l’écho est revenu au récepteur OU s’il n’y a pas de retour durant les 30ms après l’envoi (l’onde est considérée perdue)

Branchement

Les branchements sont eux-même assez simples. Il suffira de relier 5V et GND à leurs broches respectives sur Arduino et mettre « Trig » et « Echo » sur des I/O numériques (8 et 9 par exemple). Pas la peine d’un schéma pour cela !

Avec Arduino

Passons maintenant à la pratique avec Arduino. Le but ici sera d’être capable de faire une mesure de distance puis de l’afficher en millimètres dans la console de la voie série.

Setup

On va comme toujours commencer par le setup. Pour une fois, pas de bibliothèque externe à rajouter, tout sera fait « à la main ». Comme vu plus tôt, nous allons utiliser deux broches que je vais très justement nommer « USTrig » et « USEcho », pour le déclencheur (une sortie numérique) et le retour d’informations (une entrée numérique).
Je vais ensuite préparer la voie série pour afficher les mesures.

Et c’est tout pour le setup !!

Loop

Les choses faciles sont réglées, passons aux choses amusantes et faisons des mesures !
Comme je le disais dans la présentation du composant, il y a une suite d’actions à faire pour mesurer la distance. Schématiquement cela se traduirait par la liste suivante :

  1. Un état haut de 10 microsecondes est mis sur la broche « Trig »
  2. On remet à l’état bas la broche Trig
  3. On lit la durée d’état haut sur la broche « Echo »
  4. On divise cette durée par deux pour n’avoir qu’un trajet
  5. On calcule la distance avec la formule \( d = v \times t \)
  6. On affiche la distance

Tout ces étapes sont en fait assez simples, à part peut-être la mesure de la durée. Heureusement, une fonction nommée pulseIn() est la pour ça 🙂 . Cette dernière, qui est bloquante, se chargera de mesurer combien de temps une broche reste dans un état (HIGH or LOW). Elle prend en paramètre le numéro de la broche et l’état à observer.

Voici alors un exemple de programme que l’on obtient :

Si vous voulez obtenir la distance en millimètres, il suffira de multiplier par 1000. Mais soyons malins, nous pouvons aussi optimiser en évitant une opération. Pour cela c’est simple, la ligne calculant le temps en seconde passe de :

à

puisque multiplier la distance par 1000 dans notre situation revient exactement à avoir un temps divisé par le même facteur (pour avoir l’information en centimètres, il aurait fallu utiliser un facteur 100 plutôt que 1000).
Je vous laisse poser les maths si vous voulez me croire sur parole 😉 .

Si les mesures ne sont pas ultra-précises, essayez de modifier la constante de vitesse. Les ondes sont sensibles à la température ce qui influe sur leur vitesse. Nous verrons cela plus tard 😉 .

Ajout de l’écran et montage final

Tout va bien ? Les échos reviennent ? Alors place à la portabilité ! Dans cette dernière étape nous allons rajouter l’écran à notre nouvel outil.

Pour rajouter l’écran, commençons par vérifier le câblage nécessaire. Comme vu dans la partie 7, l’écran nécessite 4 fils de données (+ 2 de contrôle) et une alimentation.
L’alimentation sera prise sur les broches 5V et GND de l’Arduino et les fils de données seront sur les broches 2 à 5. Les fils de contrôle EN et R/W seront sur les broches 6 et 7.

Faire fonctionner l’écran seul

En science, lorsque l’on veut tester quelque chose on l’isole du reste. Ici c’est pareil ! Nous avons pu constater que notre télémètre fonctionne bien en le faisant marcher seul, nous allons faire de même en utilisant l’écran seul.
Pour cela, nous allons simplement afficher une ligne de caractères.
On commence logiquement par le setup et ce qui va avec, notamment la bibliothèque LiquidCrystal et un objet du même nom.

Une fois cela fait, on va afficher une simple ligne dans notre programme principal :

Si le message s’affiche correctement comme sur la capture ci-dessous, alors tout va bien et vous pouvez continuer !

L’écran avec le télémètre

Nous y voilà ! Le moment tant attendu ou nous allons afficher les mesures sur l’écran ! Pour cela, commencez par rajouter sur votre montage le télémètre (broche 8 et 9) et fusionner les setup pour n’en faire qu’un sans la voie série. Vous devriez obtenir quelque chose comme ça :

Il faut ensuite fusionner le tout pour faire un affichage sur le LCD. Je vous propose d’exploiter les deux lignes pour afficher :

  • En haut : la distance en millimètres (int)
  • En bas : le temps en millisecondes (int)

Il est pas beau ce télémètre 😀 ? Voici ce que ça donne chez moi :

Aller plus loin

Comme je l’ai brièvement mentionné plus tôt, la température a un impact sur la vitesse des ondes (ainsi que la pression et d’autres choses). Une amélioration de notre télémètre serait donc d’avoir une correction de la vitesse via une mesure de la température !
Pour débuter, prenons connaissance des données. Wikipédia nous dit que la vitesse de propagation du son dans l’air suit à peu près le tableau suivant :

Table temperature

Table temperature

Si l’on fait un graphique avec ce tableau, on obtient une relation \( V = f(t) \) (vitesse en fonction de la température) presque linéaire et donc modélisable par une fonction affine.
En faisant le calcul de la variation via les deux points les plus extrêmes du bout de droite, on obtient un coefficient de 0.6 m/s par degrés Celsius (\( \frac{325.4-349.2}{-10-30} \)). On observe aussi une ordonnée à l’origine (soit à 0 degrés) de 331.5 mètres par seconde.
Tout cela donne la relation : \( V = at+b \) (avec \( V \) la vitesse en mètres par secondes et \( t \) la température en degrés Celsius). \( a \) vaudra ainsi 0.6 et \( b \) vaudra 331.5.

Je ne donnerais pas le détail du montage ni le code ici cependant. Je vous le laisse en tant qu’évolution si vous le souhaitez. Voici cependant la logique de code qu’il faudrait suivre pour implémenter cela :

Vous avez maintenant un outil de mesure complètement fonctionnel. Il suffit de fabriquer un boîtier et de rajouter une batterie ou quelques piles pour avoir un module complètement autonome ! On pourrait aussi pousser le vice en utilisant une Arduino mini ou micro pour réduire encore un peu plus la taille du produit final !

Une expérience (bonne ou mauvaise) à partager ? Des questions à poser ? Des conseils à donner ? Ne soyez pas timide !

27 commentaires

  1. Bonjour,
    Excusez ma questin de newbie, mais la ligne « #define VITESSE 340 » correspond-elle à la definition d’une constante ?
    Si c’est le cas, pourquoi ne pas la declarer par la fonction « const »?
    Merci.

    • C’est effectivement une constante a un detail d’optimisation pres, ce n’est pas une variable. En faisant comme ca, le compilateur va remplacer la valeur VITESSE par sa valeur numérique a chaque fois qu’il la rencontrera

  2. Bonjour,
    * je n’ai pas trouvé de capteur ultrason hc 05, par contre il y a un module bluetooth de ce nom. S’agit-il du module hc sr04 ? Il y a aussi un hc sr05, mais il a 5 pins…
    * est-il possible d’utiliser le même capteur piezo pour l’émission et la réception ? Apparemment, certains capteurs n’ont qu’un seul « rond grillagé » ^^
    * enfin et surtout, merci pour ton site !

  3. Par contre, au niveau programmation, j’ai quelques difficultés !! j’ai commencé par contourner le pièges disséminés ça et là, comme à la ligne 16 – manque le ; à la fin ou ‘declencheur’ à remplacer par ‘USTrig’ et ‘capteur’ à remplacer par ‘USEcho’. Pas bien grave.
    Mon souci est avec

    char message[16] = «  »;
    sprintf(message, « Distance : %4d », distance);

    si on laisse ‘temps’ et ‘distance’ déclarés en int, il affiche n’importe quoi. Si on les déclare en float, il n’affiche rien. J’ai cherché mais je n’ai pas bien compris l’utilisation du marqueur %. Il me semble qu’arduino n’accepte pas les marqueurs float, non ?

    • Je croyais avoir copie mon dernier code fait a la maison mais apparemment c’est juste une « version de travail »… Je vais recoller proprement ce soir le code utilise dans la vidéo (bizarre j’étais persuade de l’avoir fait)

  4. J’ai encore une question par rapport au fonctionnement. Quelque chose m’échappe !!
    On envoie un train d’ultrasons de 10µs et on mesure combien de temps la broche echo reste à l’état haut. Mais ce n’est pas la durée de trajet que l’on mesure !! On mesure un train de 10µs, enfin pas tout à fait puisqu’on commence la mesure à partir du moment où l’on arrête l’envoi.
    Si l’on mesurait la durée de l’état haut d’echo à partir du moment où l’on commence l’envoi, on obtiendrait 10 µs. Là on commence la mesure quand trig est mis à l’état bas. On mesure donc le reste d’us qui sont sur le retour. Évidement se chiffre est plus grand si l’obstacle est plus loin.
    Je sais pas si je me suis bien fais comprendre.
    Pour moi il faudrait envoyer un train d’us et déclencher en même temps un compteur qui mesure le temps que met trig à passer à l’état haut. Là, on aurait réellement la durée du trajet A/R.
    En fait, j’ai remarqué que plus on s’éloigne, plus la mesure est fausse. Malgré la correction de température que j’ai ajouté avec un DS18B20 en 1wire.

    Est-ce que je me plante ?

    • Le nom de broche « echo » employé par le fabricant n’est pas très précis. Sur cette broche est bien présent un signal représentant le temps de vol de l’onde (depuis le ping jusqu’au retour du train d’onde) et non la durée de l’onde revenue elle-même (qui est bien censé être égale a la durée du « ping »).

      En fait, j’ai remarqué que plus on s’éloigne, plus la mesure est fausse. Malgré la correction de température que j’ai ajouté avec un DS18B20 en 1wire.

      A partir de quelles distances ? Personnellement je ne peux pas faire de grandes mesures, mais entre quelques centimètres et un peu plus de deux mètres j’ai une plutôt bonne précision (je ne peux pas simplement mesurer au delà).

  5. D’accord ! En fait il y a une mamaille qui se fait dans la platine US. Je comprends mieux. A approfondir effectivement.
    Moi, je commence à avoir un décalage dès 1 m. Un décalage négatif. La distance est supérieure à celle indiquée. On peut être assez précis car sous les 50cm, le point de mesure est exactement le bord avant du capteur.

    • C’est curieux tout ca, je peux descendre bien en dessous des 50cm et monter bien au dessus du mètre sans souci de mon cote. (par contre en faisant mes mesures « par terre » j’ai du orienter légèrement le capteur vers le haut sinon l’echo revenait trop vite de temps a autre (rebond sur le sol ?))

  6. Pingback: RaspberryPi 2, coupe de france de robotique et autres infos...

  7. Salut,
    Je cherche en ce moment à créer un programme, assez simple, qui allumerait une LED si un obstacle se trouve à (environ) 75 cm ou moins (donc un temps d’environ 4ms si mes calculs sont bons) et qui l’éteindrait, ou la laisserait éteinte, si l’obstacle se trouve à plus de 75 cm environ. Pour cela, j’ai créé ce programme :

    const char LED = 2; // LED sur la broche n°2
    const char TrigEmetteur = 12; // L’émetteur du signal ultrason, noté Trig, est sur la broche n°12
    const char EchoRecepteur = 8; // Le récepteur, noté Echo, est sur la broche n°8

    void setup() // Fonction d’initialisation
    {
    pinMode(LED, OUTPUT); // La LED est en SORTIE
    pinMode(TrigEmetteur, OUTPUT); // L’émetteur est en SORTIE (car il ENVOIE le son)
    pinMode(EchoRecepteur, INPUT); // Le récepteur est en ENTREE (car il RECOIT le son)

    digitalWrite(TrigEmetteur, LOW); // On s’assure que l’émetteur est bien éteint.
    digitalWrite(LED, LOW); // Pareil pour la LED.
    }

    int Envoi_Signal()
    {
    digitalWrite(TrigEmetteur, HIGH); // On allume l’émetteur,
    delayMicroseconds(10); // On attend 10 microsecondes,
    digitalWrite(TrigEmetteur, LOW); // Puis on l’éteint. Un signal de 10 microsecondes vient d’être envoyé.
    }

    int Traitement() // Dans cette fonction, on traite la valeur de « duree », puis on adapte l’allumage de la LED en fonction de ça.
    {

    unsigned long duree = pulseIn(EchoRecepteur, HIGH); // On lit la longueur du signal (une valeur)

    if(duree <= 4) // Si "duree" est inférieure ou égale à 4 ms (environ 75cm),
    {
    digitalWrite(LED, HIGH); // On allume la LED.
    }
    else // Sinon (si "duree" est supérieure à 4 ms),
    {
    digitalWrite(LED, LOW); // On éteint la LED (ou on la laisse éteinte si elle est déjà éteinte)
    }
    }

    void loop()
    {
    int Envoi_Signal();
    int Traitement();
    }

    Mon code doit certainement avoir de grandes erreurs, car il ne fonctionne pas du tout : la LED ne s'allume absolument pas…

  8. Salut, j’ai une question sur un capteur à effet doppler que j’aimerai fabriquer :
    Je voudrais calculer la vitesse d’un objet en utilisant l’effet doppler, sauf que la plupart des systèmes émetteur/récepteur que j’ai trouvé ne le permettent pas car la sortie du signal n’est pas « brut » et on ne peut pas modifier le signal comme on veut.
    Je sais qu’il y a les capteurs tout-fait mais je préfererais vraiment partir d’un truc plus basique et gérer le traitement moi-même avec l’arduino.
    En plus de ça, la vitesse de l’objet sera faible, donc les variations de l’onde réfléchie aussi donc il faut un capteur précis.
    Bref, j’aimerai bien un peu d’aide pour tout ça.
    Merci d’avance

  9. Pingback: RaspberryPi 2, coupe de France de robotique et autres nouvelles… – Amine MAGDICH

  10. bonjour,
    je voudrais réaliser ce projet, mais à la place de l’afficheur LCD ça serait un afficheur matrix 8×8 avec max7219, un smiley qui change d’état selon la distance.
    merci de votre aide pour le code.

    • hello
      j’ai réussi pour mon prog:

      #include
      #include

      #define Trig 4 // pin « Trig » du HC-SR04 connectée à pin 3 de l’Arduino
      #define Echo 3 // pin « Echo » du HC-SR04 connectée à pin 2 de l’Arduino

      unsigned long cm; // stockage de la distance de l’objet en cm

      Ultrasonic HCSR04(Trig,Echo);

      int DIN = 7;
      int CS = 6;
      int CLK = 5;

      LedControl lc=LedControl(DIN,CLK,CS,0);

      void setup(){
      lc.shutdown(0,false); //le MAX72XX est en mode d’économie d’énergie au démarrage
      lc.setIntensity(0,15); // Réglez la luminosité à la valeur maximale
      lc.clearDisplay(0); // et effacer l’affichage
      }

      void loop()
      {
      byte smile[8]= {0x3C,0x42,0xA5,0x81,0xA5,0x99,0x42,0x3C};
      byte neutral[8]= {0x3C,0x42,0xA5,0x81,0xBD,0x81,0x42,0x3C};
      byte frown[8]= {0x3C,0x42,0xA5,0x81,0x99,0xA5,0x42,0x3C};

      // On récupère la distance directement en cm
      cm = HCSR04.Ranging(CM);

      if(cm > 0 && cm = 40 && cm = 80) // objet lointain
      {
      printByte(smile);
      }
      }

      void printByte(byte character [])
      {
      int i = 0;
      for(i=0;i<8;i++)
      {
      lc.setRow(0,i,character[i]);
      }
      }

  11. Bonjour Eskimon,

    Avant tout, je te remercie, vivement, pour tout ce que j’ai pu apprendre sur tes articles.
    Perso, je pense que la sécu devrait te verser un salaire, pour avoir évité, à beaucoup, des dépressions….

    Grâce à toi, j’ai pu réaliser ce petit télémètre, avec une petite variante, car affichage sur 1602 I2C.

    Je n’ai pas grande compétence en la matière, j’essaye de progresser en « faisant », et tes articles m’y aident bien.

    En réalisant ce télémètre, j’avais une idée assez précise de son usage.
    Il s’agit de mesurer une hauteur d’eau dans une citerne souple.
    Seulement, je souhaitais obtenir un pourcentage de remplissage de cette citerne.
    Je me sers de ce pourcentage pour actionner une vanne de vidange et la refermer.
    Et là….. je coince totalement,
    Ma formule d’origine était : (distance lue / distance maxi ) * 100
    Ma seule réussite aura été un zéro affiché ….
    Aurais une l’un de tes judicieux conseils sous le coude, s’il te plait ?

    Merci par avance.

  12. Bonjour
    Je suis dans le même cas que toi. Je me suis entièrement inspirée du programme de Eskimon que je remercie chaleureusement.
    Ton idée de pourcentage m’a bien plus et j’ai essayé de l’appliquer. Tout comme toi j’ai eu zéro comme affichage au début.
    J’ai donc modifier le programme et cela fonctionne maintenant car le temps ne m’intéressait pas
    voir programme ci dessous

    //on calcule lea distanceavec la formule d=v*t
    unsigned int distance = duree*(VITESSE/10000.0);
    unsigned int pourcentage = distance/200.0*100.0; J’AI AJOUTER CETTE LIGNE SANS PARENTHÈSE
    // on affiche
    lcd.clear();
    lcd.home();
    char message[16] = «  »;
    sprintf(message, « Dist : %4d cm », distance);
    lcd.print(message);
    sprintf(message, « Pourc.: %3d pourc. »,pourcentage); J’AI MODIFIE CETTE LIGNE
    lcd.setCursor(0,1);
    lcd.print(message);
    }

    //petite pause
    delay(250);

    Maintenant il faut que que j’adapte le tout pour le mettre dans ma cuve. J’ai comme sensor ultrason
    un WEATHER-PROOF ULTRASONIC SENSOR with Separate SKU SEN0208 étanche à l’humidité et il fonctionne avec le programme à quelques cm près.
    Voilà Mamie Jo c’est moi s’amuse

Laisser un commentaire