Comparaison HC-SR04 (ultrasons), Sharp GP2Y0A02YK0F (IR), VL53L0X (Laser), quelle solution choisir pour la mesure de distance avec Arduino ou Raspberry Pi • Domotique et objets connectés à faire soi-même

Nous allons comparer trois technologies de capteur de proximité qui permettent de faire de la mesure de distance. Le HC-SR04 par ultrasons, le Sharp GP2Y0A02YK0F par infrarouge et le VL53L0X par mesure du temps de vol (ToF) d’un faisceau laser. Vous trouverez un montage à imprimer en 3D ainsi que le code Arduino qui vous permettra de réaliser chez vous des tests comparatifs. Vous pourrez plus facilement tester ces capteurs avant de débuter le développement de vos projets Arduino, ESP32, ESP8266 ou Raspberry Pi.

Le HC-SR04 est un capteur assez précis et très simple de mise en oeuvre (à l’aide de l’une des nombreuses librairies Arduino) mais il peut s’avérer trop encombrant dans certains projets. On pourra le remplacer très avantageusement par un VL53L0X, un capteur qui mesure le temps de vol (Time Of Flight, ToF) d’un faisceau laser. Les 3 capteurs reposent tous sur le même principe physique. Ils mesurent le temps nécessaire au retour d’un faisceau réfléchi par un objet situé en face du capteur. Pour le HC-SR04 ce sera des ultra-sons, de la lumière infra-rouge pour le Sharp GP2Y0A02YK0F et un faisceau laser pour le VL53L0X.

Tous les codes source et le fichier ODT sont disponibles sur GitHub sur cette page.

Les spécifications techniques indiquées dans ce tutoriel peuvent varier d’un fabricant à l’autre

Mesure de distance par ultrason, capteur HC-SR04 ou JSN SR04T

Le HC-SR04 est un capteur analogique qui nécessite deux câbles. Le premier (TRIG – Trigger) génère un faisceau d’ultrasons. Le seconde est activé dès que le faisceau retourné est détecté. Inutile de chercher à re-développer la roue, il existe plusieurs librairies Arduino et Python pour intégrer le HC-SR04 dans vos projets.

Il y a au moins 7 librairies disponibles directement depuis le gestionnaire de bibliothèque de l’IDE Arduino. Pour cet article, j’ai utilisé la librairie Bifrost développée par Jeremy Lindsay. On peut l’acheter pour moins d’un euro.

Pour réaliser des mesures de niveau de cuve (eau, fioul…), on pourra se tourner vers le JSN SR04T, un capteur par ultrason étanche. 

Caractéristiques techniques du HC-SR04

  • Plage de mesure de distance : 2cm à 450cm (4,5m)
  • Précision de mesure : 0,3cm
  • Tension d’alimentation : 5V
  • Sortie numérique : PWM
  • Poids : 9g
  • Dimensions : 45mm x 20mm x 18mm

Voir plus d’offres

Caractéristiques techniques du JSN SR04T

Il existe également une version étanche pour la mesure de niveau de cuve.

  • Tension de fonctionnement : DC 5V
  • Courant au repos : 5mA
  • Consommation au travail : 30mA
  • Plage de mesure : 2 à 450cm
  • Trig (commande) RX
  • Echo (récepteur) TX
  • GND (négatif)
  • Résolution: environ 0,5 cm
  • Angle de mesure : inférieur à 50 degrés
  • Température de fonctionnement : -10 ~ 70°C
  • Température de stockage: -20 ~ 80°C

Voir plus d’offres

Mesure de distance par infrarouge (IR), capteur Sharp GP2Y0A02YK0F

Le Sharp GP2Y0A02YK0F renvoi directement un signal analogique proportionnel à la distance. C’est assez difficile de se procurer la version originale de Sharp. On achète le plus souvent des clones sous la référence A02YK0.

Après avoir testé plusieurs librairies, la librairie ZSharpIR développe par zoubworldArduino (page GitHub) donne satisfaction avec les clones chinois à moins de 4 euros.

Caractéristiques du Sharp A02YK0

  • Plage de mesure de distance : de 20cm à 150cm
  • Sortie analogique (signal proportionnel à la distance)
  • Taille de boîtier : 29.5mm x 13mm x 21.6mm
  • Consommation de courant typique : 33mA
  • Plage d’alimentation : de 4.5V à 5.5V
  • Tension de sortie : 0.4V
  • Plage de température de fonctionnement : de -10°C à +60°C

Toutes les promos

Mesure de distance par temps de vol laser, capteur VL53L0X (Adafruit ou équivalent)

Le VL53L0X est un capteur qui permet de réaliser des mesures de distances en mesurant le temps de vol d’un laser. La mesure de distance est numérique. Elle peut être récupérée via le bus I2C. Beaucoup plus compact et plus précis que le HC-SR04, ce capteur sera beaucoup plus facile à intégrer dans les projets robotiques, RC, drones…

J’ai  utilisé la librairie développée par le fabricant Pololu. Elle s’accommode très bien des capteurs compatibles. Pour cet article, j’ai acheté un clone à moins de 4€ sur AliExpress.

Caractéristiques du VL53L0X

  • Plage de mesure de distance : jusqu’à 200cm (2m)
  • Bus i2c : adresse 0x29
  • Longueur d’onde du faisceau laser : 940nm
  • Taille de la carte (hors connecteur) : 25mm x 13mm (dépend du fabricant)
  • Plage d’alimentation : de 2.8V à 5.5V

Le VL53L1X permet d’atteindre 400cm. Il est plus difficile à se procurer. Le VL6180X est dédié à la mesure de précision en dessous de 10cm. Son prix est similaire, environ 4€.

Toutes les promos

Remarque importante pour le fonctionnement sur Arduino

L’emploi de la librairie Pololu nécessite de démarrer manuellement la fonction wire() dans le setup sinon le VL53L0X reste non trouvable sur le bus I2C.

#include 

void setup() {
  Wire.begin();
  Serial.begin(115200);

  vl53.init();
  vl53.startContinuous();
}

void loop() {
  Serial.println(vl53.readRangeContinuousMillimeters();
  delay(1000);
}

Montage de test par impression 3D

Pour tester de façon rigoureuse les 3 capteurs, j’ai préparé un petit support sur lequel on pourra fixer ces derniers. Les trois capteurs sont positionnés de telle façon qu’ils mesurent la même distance. Vous pouvez télécharger le fichier STL sur Thingiverse ici.

Avec les 3 capteurs installés. De gauche à droite :

  • Sharp GP2Y0A02YK0F (clone)
  • HC-SR04
  • VL53L0X (de marque CJMCU)

Programme de test

Voici un programme de test qui réalise un série de 10 mesures. Le délai entre chaque mesure est d’une seconde par défaut. Il peut être modifié à l’aide de la constante DELAY_REFRESH.

Avant de téléverser le programme, vous devrez installer les librairies Arduino suivantes :

/* Distance measurement comparison with HC-SR04, Sharp GP2Y0A02YK0F and VL53L0X SMTe sensors
 * Recording of 10 measurement points. Time between each changeable point with the key DELAY_REFRESH
 * Reset between each distance to restart the program

 * Manual calibration procedure of the Sharp GP2Y0A02YK0F proximity sensor
 * https://projetsdiy.fr/test-and-calibration-of-the-proximity-captor-a02yk0-clone-asiatic-of-sharp-gp2y0a02yk0f/
 *
 * Test support to print in 3D
 * https://www.thingiverse.com/thing:2961289
 * 
 * Comparaison de mesure de distance avec les capteurs HC-SR04, Sharp GP2Y0A02YK0F et VL53L0X SMTe
 * Enregistrement de 10 points de mesure. Temps entre chaque point modifiable avec la clé DELAY_REFRESH
 * Faire un reset entre chaque distance pour relancer le programme
 * 
 * Procédure d'étalonnage manuel du Sharp GP2Y0A02YK0F
 * https://projetsdiy.fr/test-et-etalonnage-du-capteur-de-proximite-a02yk0-clone-asiatique-du-sharp-gp2y0a02yk0f/
 * 
 * Support de test à imprimer en 3D 
 * https://www.thingiverse.com/thing:2961289
 */

#include 
#include 
#include 
#include 
#include 

#define ir A0
#define model 20150
#define OFFSET_HCSR04     -10
#define PIN_HCSR04_ECHO   4
#define PIN_HCSR04_TRIG   3
#define PIN_GP2Y0A02YK0F  A0
#define DELAY_REFRESH     1000
#define POINT_FILTER      10
#define LONG_RANGE       true

int posFilter = 0;
int filterVl53[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int filterSr04[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int filterIr[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

ZSharpIR SharpIR(ir, model);

HCSR04 hcsr04(PIN_HCSR04_TRIG, PIN_HCSR04_ECHO, 20, 4000);
VL53L0X vl53;

void setup() {
  Wire.begin();
  Serial.begin(115200);

  vl53.init();
  vl53.setTimeout(DELAY_REFRESH - 100);

  #if defined LONG_RANGE
    // lower the return signal rate limit (default is 0.25 MCPS)
    vl53.setSignalRateLimit(0.1);
    // increase laser pulse periods (defaults are 14 and 10 PCLKs)
    vl53.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18);
    vl53.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14);
  #endif
  
  vl53.startContinuous(DELAY_REFRESH - 50);

}

void print(String key, String val, boolean returnline ) {
  Serial.print(key); Serial.print(": ");
  if ( returnline ) {
    Serial.println(val);
  } else {
    Serial.print(val);
  }
}

bool measure = true;

void loop() {
  if ( measure ) {
    float distSR04 = hcsr04.distanceInMillimeters() + OFFSET_HCSR04;
    int distSharp = SharpIR.distance();
    float distVl53 = vl53.readRangeContinuousMillimeters();
    if (vl53.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
    print("HR-SR04 (mm)", String(distSR04), false);
    print(" | IR (mm)", String(distSharp), false);
    print(" | VL53L0X (mm)", String(distVl53), true);
    if ( distVl53 != 8190 ) {
       filterVl53[posFilter] = distVl53;
    }
    
    filterSr04[posFilter] = distSR04;
    filterIr[posFilter] = distSharp;
    posFilter++;

    if (posFilter >= 10 ) {
      Serial.println("# résultats des mesures");
      measure = false;
      for ( int k = 0 ; k  10 ) { posFilter = 0;}
  countFilter++;
  
  if (countFilter > 10 ) {
    vl53 = average(filterVl53,POINT_FILTER);
    sr04 = average(filterSr04,POINT_FILTER);

    print("SR04(%)", String(sr04), false);
    print(" | VL53L0X(%)", String(vl53), true);

    int dotVl53 = round(vl53 / 3.125);
    int dotSr04 = round(sr04 / 3.125);
    
    mx.clear();
    mx.update(MD_MAX72XX::OFF);
    for ( int i = 32 ; i >= 32 - dotVl53 ; i--) {
      mx.setPoint(0, i, true);
      mx.setPoint(1, i, true);
      mx.setPoint(2, i, true);
    }
    for ( int i = 32 ; i >= 32 - dotSr04 ; i--) {
      mx.setPoint(5, i, true);
      mx.setPoint(6, i, true);
      mx.setPoint(7, i, true);
    }
    mx.update(MD_MAX72XX::ON);
  }
}

float average (int * array, int len)  // assuming array is int.
{
  long sum = 0L ;  // sum will be larger than an item, long for safety.
  for (int i = 0 ; i < len ; i++)
    sum += array [i] ;
  return  ((float) sum) / len ;  // average will be fractional, so float may be appropriate.
}

float tankLevel(float dist) {
  float tankLev = map(dist, 150, 20, 0, 100);
  //Serial.print("Tank level (%)");
  //Serial.println(tankLev);
  return tankLev;
}

String I2CScanner()
{
  byte error, address;
  int nDevices;
  String s;

  s = "Scanning:\n";

  nDevices = 0;
  for (address = 1; address < 127; address++ )
  {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      //s+="\n";
      s += "I2C device found at address 0x";
      if (address < 16)
        s += "0";
      s += String(address, HEX);
      s += "\n";

      nDevices++;
    }
    else if (error == 4)
    {
      s += "Unknow error at address 0x";
      if (address < 16)
        s += "0";
      s += String(address, HEX);
      s += "\n";
    }
  }
  if (nDevices == 0)
    s += "No I2C devices found\n";
  else
    s += "done\n";
  return s;
}

Vidéo de démo

Rien de mieux qu’une petite vidéo de démonstration

Voilà, cette étude comparative est maintenant terminée, à vous de choisir le capteur le mieux adapté à votre projet. J’ai été très agréablement surpris par les performances des deux capteurs HC-SR04 et VL53L0X. Pour surveiller le niveau de remplissage d’un réservoir, le HC-SR04 se montre plus performant que le laser. L’eau est un milieu qui doit absorber plus le rayonnement laser que les ultrasons. Si vous avez des projets de voiture autonome ou RC, je vous conseille le VL53L0X, beaucoup plus compact et très simple de mise en oeuvre. Coté prix, comptez environ 3,50€ pour le VL53L0X et moins de 1€ pour le HC-SR04. Le . N’oubliez pas de prendre en compte le milieu, la surface et la forme de l’objet. Le mieux est de faire des tests avec ces différents technologie et choisir celle qui donne le meilleur résultat.

Avez-vous aimé cet article ?

[Total: 2 Moyenne: 5]