SR04. Sans utilisation de pulseIn() et sans librarie, très très performant.

Je vois partout des gens qui proposent des sketchs qui utilisent pulseIn() pour la détection du Ping de retour, et par défaut, d'autre gens se plaignent que oui, ça fonctionne mais la détection est très très lente, jusqu'à une seconde par détection. En contre-partie l'utilisation d'une libraire, tel NewPing, est très rapide, cependant on ne voit pas le processus en un seul coup d'oeuil, ce qui est totalement détestable selon moi.

Après analyse, j'ai compris où se trouvait le problème et je vous propose cette solution qui effectue une détection en moins de 12 millisecondes pour une distance maximale 1,5 mètres, ce qui est très respectable pour un petit robot tel un smart car.

#define broche_Trig 12
#define broche_Echo 11
#define broche_Piezo 8

unsigned long dernier_balayage = 0;
const int interval_balayage = 50;

const double k_Mach = 29.41176;

int duree;
double distance;

void setup() {

  pinMode(broche_Trig, OUTPUT);
  pinMode(broche_Echo, INPUT);

  Serial.begin (115200);
  Serial.println(F("Ce programme permet de detecter un objet qui se trouve a moins d'un metre et demi"));
  
}

void loop() {
  
  unsigned long milliseconde_actuelle = millis();
 
  if(milliseconde_actuelle - dernier_balayage >= interval_balayage) {
  
    digitalWrite(broche_Trig, HIGH);
    delayMicroseconds(5);
    digitalWrite(broche_Trig, LOW);

    duree = pulseIn(broche_Echo, HIGH, 44118);
    distance = duree * 0.5 / k_Mach;

    if (!(distance >= 150 || distance <= 0)){
     
      Serial.println((String)distance + F(" cm"));
      tone(broche_Piezo, 10500, 5); 
    
    }

    dernier_balayage = milliseconde_actuelle;   
    //Serial.println(millis()- milliseconde_actuelle); 

  }
  
}

Salut,

Frédéric_Plante:
Je vois partout des gens qui proposent des sketchs qui utilisent pulseIn() pour la détection du Ping de retour, et par défaut, d'autre gens se plaignent que oui, ça fonctionne mais la détection est très très lente, jusqu'à une seconde par détection

Je vois pas trop ce qui bloque dans le code de base mis à part un delay(500). Le timeout de base est à 38 ms. Pour arriver à 1 sec c'est que le code n'est pas bon ... Donc il y a effectivement ta parade, mais à mon avis ça ne changera rien pour ceux qui sont à 1 sec vu que ça sent le ou les delay(). Le mieux est encore d'utiliser les interruptions, la on aurait un code robuste avec une monopolisation du µC minimale

Tiens d’abord!!! :wink: Pourquoi le "- 8"? pour le moment j'en ai aucune idée, mais j'ai hâte de comprendre pourquoi... :stuck_out_tongue:

#define broche_Trig 12
#define broche_Echo 3
#define broche_Piezo 8

volatile unsigned long derniere_mesure = 0;
unsigned long inter_ping = 0;
const int interval_mesure = 150;

const double k_Mach = 29.4117647;

int duree;
int distance;

void setup() {

  attachInterrupt(1, echo_percue, FALLING);
  
  pinMode(broche_Trig, OUTPUT);
  pinMode(broche_Echo, INPUT);

  Serial.begin (115200);
  
}

void loop() {
  
  if(millis() - derniere_mesure >= interval_mesure) {
  
    digitalWrite(broche_Trig, HIGH);
    delayMicroseconds(5);
    digitalWrite(broche_Trig, LOW);
    derniere_mesure = millis();   
    inter_ping = micros();
    
  }

}

void echo_percue(){
  
  duree = micros() - inter_ping ;
  distance = ((duree / k_Mach) * 0.5) - 8  ;
  
  if (!(distance >= 150 || distance <= 0)){
     
    Serial.println((String)distance + F(" cm"));
    tone(broche_Piezo, 10500, 5); 
    
  }
 
}

Est-ce que quelqu'un peut essayer mon 2iem code et me dire si le résultat est juste ou si il y a un décalage de 8cm?

Tu ne peux pas juste prendre FALLING, il y a l'émission du train d'onde entre le trig et le passage à l'état haut du signal. Il faut utiliser RISING tout d'abord pour lancer l'acquisition et configurer l'interruption en FALLING. Au FALLING on prend le temps de fin et on reconfigure en RISING

Ok, tu veux dire que je dois mesurer le temps entre le RISING ET LE FALLING, ah! Ok!

Mais ce que je ne comprend pas, c'est pourquoi est-ce que le 8 cm est constant? Il devrait plutot y avoir une variante directement proportionnelle à la distance mesurée, il me semble.

Non car le chronogramme est celui-ci :

Dans ton cas tu prends le temps de départ sur le front descendant du trig, et le temps de fin sur le front descendant de l’écho. Donc tu mesures la durée des impulsions piezzo en trop

Ah et ce temps d'envois, qui lui est constant, est de 8cm/Mach. Ok je comprend. Je me tape les modifs dès que j'arrive chez moi.

Bon! Je suis satisfait. T'avais totalement raison, c'est bien la manœuvre à suivre. De plus, j'ai fais passé l'impulsion initiale de 5 a 10 microseconde, ça a du aider. Et le 8 cm à disparu.

Voici donc le code finale qui permet de le faire sans librairie, et donc de comprendre facilement la procédures.

#define broche_Trig 12
#define broche_Echo 3
#define broche_Piezo 8

volatile unsigned long derniere_mesure = 0;
unsigned long debut_ping = 0;
const word interval_mesure = 150;

const double k_Mach = 29.4117647;

double duree;
byte distance;

void setup() {
  
  pinMode(broche_Trig, OUTPUT);
  pinMode(broche_Echo, INPUT);

  Serial.begin (115200);
  
}

void loop() {
  
  if(millis() - derniere_mesure >= interval_mesure) {
  
    digitalWrite(broche_Trig, HIGH);
    delayMicroseconds(10);
    digitalWrite(broche_Trig, LOW);
    derniere_mesure = millis();   
    attachInterrupt(1, echo_percue, RISING);
  
  }
  
}

void echo_percue(){
  
  debut_ping = micros();
  detachInterrupt(1);
  attachInterrupt(1, echo_terminee, FALLING);

}  

void echo_terminee(){
  
  duree = micros() - debut_ping ;
  distance = ((0.5 / k_Mach) * duree );//f(x) = ax + b
  
  if (!(distance >= 150 || distance <= 0)){
     
    Serial.println((String)distance + F(" cm"));
    tone(broche_Piezo, 10500, 5); 
    
  }
  
  detachInterrupt(1);

}

Là bien sur pour que ça soit totalement parfait, puisque ce code va finir dans un smart car, je devrai peut-être inclure l’effet Doppler, qui est peut-être négligeable à si basse vitesse, 50 cm/s, on verra.

Any ways, Merci B@tto pour ton aide :slight_smile:

Au finale, j'ai enlevé le procédé basé sur le temps, pour être certain de ne pas avoir de confusion avec un ancien Ping qui entrerait après qu'un nouveau Ping soit envoyé. Et le procédé est tellement rapide que j'ai du ajouter un delay(100) parce que le port série plante parce qu'il a trop de stock à envoyer. lol

#define broche_Trig 12
#define broche_Echo 3
#define broche_Piezo 8

unsigned long debut_ping = 0;

const double k_Mach = 29.4117647;

byte distance;
bool en_attente = false;

void setup() {

  
  pinMode(broche_Trig, OUTPUT);
  pinMode(broche_Echo, INPUT);

  Serial.begin (115200);
  
}

void loop() {
  
  
  if(en_attente == false) {
    delay(100);
    digitalWrite(broche_Trig, HIGH);
    delayMicroseconds(10);
    digitalWrite(broche_Trig, LOW);
    attachInterrupt(1, echo_percue, RISING);
    en_attente = true;
    
  }
  
}

void echo_percue(){
  
  debut_ping = micros();
  detachInterrupt(1);
  attachInterrupt(1, echo_terminee, FALLING);

}  

void echo_terminee(){
  
  distance = ((0.5 / k_Mach) * (micros() - debut_ping));//f(x) = ax
  
  if (!(distance >= 150 || distance <= 0)){
     
    Serial.println((String)distance + F(" cm"));
    tone(broche_Piezo, 10500, 5); 
    
  }
  
  detachInterrupt(1);
  en_attente = false;
 
}