[conseil] projet de détéction d'obstacle, question de compréhension

Bonjour,

@cutprod: Merci de me donner ton prog en exemple, le hic, c'est que j'ai un peu de mal a tout comprendre. Du coup je sais pas si ca correspond à mon cahier des charges. c'est à dire plus un obstacle s'approche, plus le buzzer sonne rapidement (entre 2m et 1 m).
Je sais pas comment écrire ça: (en gros) on concidere X la valeur donné par le sonar (1m = 100 et 2m=200) Donc, si X=200 le buzzer bip avec un delay de 1s et plus X diminue en direction de 100 et plus la valeur de delay diminue..
déja je dois utiliser un if (ca tombe bien je commence a maitriser) mais pour ce qui est du reste, je sais pas.
Ps: comment tu fais pour introduire ton code dans cette fenetre ?

@patg_: Tu sous entends quoi par "inversement proportionnel", je pense que ton idée pourrait marcher car si j'ai bien compris (ou pas ^^) la valeur de delay fluctura en fonction de la valeur comprise entre 2m et 1m.

Merci à vous deux pour vos réponses :slight_smile:

Benoit

exemple, tu as la distance * 100 dans la variable x:
à la fin de la boucle du sketch (qui mesure la distance et émet 1 beep si la distance est < 2m) tu mets:

delay (x/200 * 1000);

pour une distance de 2m tu auras 1 beep toutes les secondes
pour une distance de 1m tu auras 1 beep toutes les 500ms

La période entre 2 beeps est donc inversement proportionnelle à la distance mesurée.
En diminuant le facteur 1000 tu augmente la fréquence des beeps (enfin des coups de buzzer).

Ce mécanisme simple fonctionne à condition que tu ne doives rien faire d'autre pendant le temps d'attente (l'AVR est bloqué).
On peut faire autrement si nécessaire (par un timer soft ou par un delay() un peu plus évolué).

Ok merci,ça me parait clair maintenant. Je vais essayer, je vous tiens au courant si je rencontre d'autre difficulté.

Merci Patq_ :slight_smile:

Benoit

Comme promis, je mets mon exemple de captage d'objet entre 1m50 0m. Avec un buzzer et une LED.
Il est peut être basic mais il marche :wink:

int analogPin = 3;     // Sonar branché sur la PIN analogique 3

int val = 0; // variable de type int pour stocker la valeur de la mesure

void setup() {
  
pinMode(12, OUTPUT); //Buzzer
pinMode(11, OUTPUT); // LED
Serial.begin(9600);  
}

void loop() {
  
   val = analogRead(analogPin);
   Serial.println(val);  
   

     if ( val < 100)
  {
     digitalWrite(12, HIGH);  // set the buzzer on
     digitalWrite(11, HIGH);  // set the LED on
    
   }
   else 
   {
     if (val < 150)
     {
      digitalWrite(12, HIGH);   // set the buzzer on 
    digitalWrite(11, HIGH);   // set the LED on 
    delay (1000);
    digitalWrite(12, LOW);   // set the buzzer off
    digitalWrite(11, LOW);   // set the LED off 
    delay (1000);
     }
     else 
     {
     }
     
   }  
}

Cordialement

Benoit

Alors voila j'ai enfin réussis a trouver un programme permettant de réaliser ce que je veux.
Il est super simple, basic mais vue mon niveau je suis assez content du resultat..

int analogPin = 3;     // Sonar branché sur l'entrée analogique 3 

int val = 0; // variable de type int pour stocker la valeur de la mesure

void setup() 
{
  
pinMode(12, OUTPUT); // Le signal est envoyé sur le buzzer qui est branché sur la sortie 12
pinMode(11, OUTPUT); // Le signal est envoyé sur la LED qui est branché sur la sortie 13
Serial.begin(9600); // initialise le serial monitor a 9600 bauds  
}

void loop() 
{
   
   val = analogRead(analogPin); // la valeur lue sera appelé "val"
   Serial.println(val);  // le serial monitor affiche la valeur "val"
   

     if ( val < 100)
  {
     digitalWrite(12, HIGH);  // active le buzzer (ON)
     digitalWrite(11, HIGH);  // active la LED (ON)
    
   }
   else 
   {
     if (val < 200)
     {
      digitalWrite(12, HIGH);   // active le buzzer (ON)
    digitalWrite(11, HIGH);   // active la LED (ON)
    delay (val * 5);   // Temps de l'activation qui sera d'une valeur = val x 5
    digitalWrite(12, LOW);   // désactive le buzzer (OFF)
    digitalWrite(11, LOW);   // désactive la LED (off)
    delay (val * 5 );  // Temps de la désactivation qui sera d'une veleur = val x 5
     } 
     else 
     {
     }
     
   }  
}

J'espere avoir des impressions (positive ou négative) et si vous avez des améliorations à me proposer, je suis prenneur !

Merci

Benoit

bravo.

Suggestion : Je pense que la durée du bip doit être constant et seule la période doit varier en fonction de la distance.

Prochain niveau : ton code utilise delay() qui est une fonction blocante et qui empêche le programme de faire autre chose pendant ce temps.
Regarde le code exemple BlinkNoDelay et essaye de faire évoluer ton programme pour ne plus utiliser delay() mais uniquement des comparaisons et des différences de temps.

Pareil.
Tu devrais allumer le buzzer et la led, attendre un temps bref et fixe, puis les éteindre.
Ensuite seulement tu fais ton attente variable fonction de la distance.

C'est pas mal pour un début.

Je suis moi aussi dans mes "arduineries" :grin:

@barbudor, @Patq_ : merci pour vos remarques :slight_smile:
Je vais bien entendu essayer d'améliorer le programme en fonction de vos remarques.
Dés lundi je m'attaque a l'amélioration de ce programme puis je viendrais le poster afin de vous montrer et bien entendu j’espère de vous avoir des remarques :slight_smile:

Il est vrai que j'avais remarqué que pendant que le buzzer et la LED s'allumaient rien ne ce passait pendant ce temps et ça peut poser problème ^^
Merci @barbudor pour l’exemple, je vais m'en inspirer :slight_smile:

Cordialement

Benoit

Bonjour
Barbudor, j'ai du mal à comprendre l'exemple "blinkwithoutdelay", j'ai compris qu'il y a des differences de temps mais je ne voie pas du tout comment avoir une influence sur le temps de clignotement.
c'est à dire, je ne voie pas comment faire clignoter la LED en fonction de la distance de l'obstacle...

cordialement

Benoit

Voilà, je me suis inspiré d'une part de l'exemple "blinkwithoutdelay" et de programme de cutprod . Voilà ce que ca donne :
dans cette exemple, je me suis servi que de la LED pour faire simple ^^

long previousMillis = 0;       
int interval = 200;           
boolean beep_state;
int analogPin = 3; 
int val = 0;

void setup() 
{
 Serial.begin(9600);     
 pinMode(11, OUTPUT); // Le signal est envoyé sur la LED qui est branché sur la sortie 13
}

void loop()
{
  lecture_val();
  beep();
}


void lecture_val()
{
val = analogRead(analogPin);
interval = 500 - val;
Serial.println (interval);
}


void beep()
{
   unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval)
  {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   


    if (beep_state == 0)
      {
      beep_state = 1;
digitalWrite(11, HIGH);  // active la LED (ON)
 tone(8, 1319);
      }
    else
     {
      beep_state = 0;
digitalWrite(11, LOW );  // active la LED (Off)
  noTone(8);
      }
   }
}

Le hic c'est que ca fait l'inverse de ce que j'attend, c'est a dire plus la distance (appelé ici "interval") est grande, plus la led Bip rapidement
j'ai beau changer des parametres, de changer les 1 et 0, ca m'inverse pas..

Deuxieme hic, je ne vois pas comment integrer un ligne me permettant de faire un bip continue lorsque je suis a moins de 1 m

Je suis à fond dessus pour essayer de trouver un moyen, il se peut que je la trouve cette solution ! si c'est le cas, je mettrais le code ^^

PS : je comprends pas pourquoi cutprod utilise "if beep state == 0" c'est quoi ce beep state? l'etat du beep qui est dans la suite c'est à dire O ou 1 ??
Merci

Cordialement

Benoit

Le principe est de ne gérer que les transitions sans bloquer
Donc il faut savoir dans quel état tu es pour que à l'expiration de la tempo tu sache ce que tu dois faire.

Ton code me parait parfait et tu dis qu'il marche sauf que la période n'évolue pas dans le bon sens.

Cela ne me surprend pas puisque dans ton code initial, le delay() est proportionel à val

delay (val * 5);   // Temps de l'activation qui sera d'une valeur = val x 5

Alors que dans ce nouveau code c'est le contraire :

interval = 500 - val;

Pourquoi n'as tu pas utilisé interval = 5 * val comme dans le 1er code ?

Deuxieme hic, je ne vois pas comment integrer un ligne me permettant de faire un bip continue lorsque je suis a moins de 1 m

Dans beep, il faut gérer ce cas. Il faut gérer les 3 cas d'ailleurs comme dans ton code initial.

unsigned long currentMillis = millis();

if ( val < 100)
{
    beep_state = 1;
    digitalWrite(11, HIGH);  // active la LED (ON)
    tone(8, 1319);
    previousMillis = currentMillis;
}
else if (val < 150)
{
    if ( currentMillis - previousMillis > interval )
    {
        // save the last time you blinked the LED 
        previousMillis = currentMillis;   
        if (beep_state == 0)
        {
            beep_state = 1;
            digitalWrite(11, HIGH);  // active la LED (ON)
            tone(8, 1319);
        }
        else
       {
            beep_state = 0;
            digitalWrite(11, LOW );  // active la LED (Off)
            noTone(8);
        }
    }
}
else 
{
    beep_state = 0;
    digitalWrite(11, LOW );  // active la LED (Off)
    noTone(8);
    previousMillis = currentMillis;
}

Tu remarqueras que je met à jour previousMillis chaque fois qu'il y a un changement d'état de façon a ce que le compteur de temps soit à jour si brutalement la distance change.

Merci beaucoup barbudor !

je vais essayer de faire comme dans le premier c'est a dire faire un 5 * val ou autrement

Voilà je pense que je touche au but ! :slight_smile:

long previousMillis = 0;       
int interval = 200;           
boolean beep_state;
int analogPin = 3; 
int val = 0;

void setup() 
{
 Serial.begin(9600);     
 pinMode(12, OUTPUT); // Le signal est envoyé sur le buzzer qui est branché sur la sortie 12
 pinMode(11, OUTPUT); // Le signal est envoyé sur la LED qui est branché sur la sortie 13
}

void loop()
{
  lecture_val();
  beep();
}


void lecture_val()
{
val = analogRead(analogPin);
interval = val;
Serial.println (interval);
}


void beep()
{
unsigned long currentMillis = millis();

if ( val < 100)
{
    beep_state = 1;
    digitalWrite(11, HIGH);  // active la LED (ON)
    tone(8, 1319);
    previousMillis = currentMillis;
}
else if (val < 250)
{
    if ( currentMillis - previousMillis > interval )
    {
        // save the last time you blinked the LED 
        previousMillis = currentMillis;   
        if (beep_state == 0)
        {
            beep_state = 1;
            digitalWrite(11, HIGH);  // active la LED (ON)
            
            tone(8, 1319);
        }
        else
       {
            beep_state = 0;
            digitalWrite(11, LOW );  // active la LED (Off)
             
            noTone(8);
        }
    }
}
else 
{
    beep_state = 0;
    digitalWrite(11, LOW );  // active la LED (Off)
    
    noTone(8);
    previousMillis = currentMillis;
}
}

mais il me reste encore deux questions que j'ai du mal a résoudre ...

  1. Je ne trouve aucune explication sur la librairie "tone" et "noTone" et à quoi corresponde les valeurs entre parenthese ? (Ca répondra peut être a ma deuxième question)
  2. comment puis je faire pour pour modifier le temps entre chaque bip car je trouve que même à 2 m ça bip assez rapidement..

(Edit : Je suis tombé sur un page wiki qui explique ce qu'est la librairie tones, (elle permet juste de faire des sons différent, grâce aux fréquence des notes). Donc ce ne répond pas à ma 2 eme questions ^^)

Merci

Benoit

comment puis je faire pour pour modifier le temps entre chaque bip car je trouve que même à 2 m ça bip assez rapidement

C'est une remarque purement subjective qui ne dépend que de toi.
A toi de déterminer la fonction intervale = f1(analogRead) sachant que analogRead est déjà f2(distance)

Regarde la spec de ton capteur pour avoir la fonction f2 et détermine f1 en fonction de cela.
Peut être faudra t'il définir un fonction par segment ?
(analogRead entre x1 et x2 -> interval = ?
(analogRead entre x2 et x3 -> interval = ?

Merci Brabudor,

J'ai tout simplement ajouté un *2 :

void lecture_val()
{
val = analogRead(analogPin);
interval = val * 2 ;
Serial.println (interval);
}

Merci

Benoit

Tu peux aussi utiliser la fonction map(...) pour à partir de la valeur de ton capteur, calculer une autre valeur entre les bornes spécifiées.
La doc est ici: map() - Arduino Reference

Ca permet simplement de faire varier les bornes mini et maxi calculées tout en gardant les mêmes bornes en entrée.

Pour te donner un exemple concret de comment je l'utilise sur mon projet actuel:
J'ai un capteur de lumière qui est lu sur une entrée analogique et me fournit une valeur entre 230 et 900 selon l'éclairage de la pièce. Hors j'ai besoin en sortie d'une valeur entre 0 et 15, pour piloter l'intensité lumineuse d'un éclairage.
Je transforme donc la valeur lue comme ceci

int brightness = analogRead(PIN_LDR); //valeur brute
int scaledBrightness = map(brightness,230,900,0,15); //valeur transformée entre 0 et 15

J'ai constaté hier que si la valeur brute passe sous la valeur minimale indiquée on a un débordement. Pour moi ça ressemble à un bug de map() mais bon...je vais faire en sorte de détecter ce cas car mon signal d'entrée pourrait passer sous 230 dans certaines conditions je pense.

@Patq_ : Merci, tu viens de m'apprendre quelque chose qui peut m’être utile pour autre chose :slight_smile:
En revanche dans mon cas, je ne pense pas en avoir besoin car j'ai tout simplement multiplié la valeur de "interval" et ça fonctionne correctement !

Je ne suis pas un expert et peut être ce que je vais dire va paraitre idiot mais pour ton problème, si j'ai bien compris ton capteur te donne un plage entre 230 et 900 en fonction de la lumière mais, c'est toi qui l'a définit comme ça ? ou bien c'est tout simplement la lumière mini et maxi de ta pièce ? car la lumière peut varier suivant certains facteur donc peut être que parfois il fait plus clair que d'habitude ou moins clair ^^ donc cela peut être normal ton soucis..

Merci

Cordialement

Benoit

Benoit1121:
@Patq_ : Merci, tu viens de m'apprendre quelque chose qui peut m’être utile pour autre chose :slight_smile:
En revanche dans mon cas, je ne pense pas en avoir besoin car j'ai tout simplement multiplié la valeur de "interval" et ça fonctionne correctement !

Juste un truc, mon pseudo c'est PatG_ et non PatQ_ :smiley:
En fait si tu multiplies simplement la valeur tu ne fais que changer la pente de la droite, sans pouvoir spécifier le mini et le maxi que tu souhaites en résultat. Ca peut convenir dans certains cas.

Benoit1121:
Je ne suis pas un expert et peut être ce que je vais dire va paraitre idiot mais pour ton problème, si j'ai bien compris ton capteur te donne un plage entre 230 et 900 en fonction de la lumière mais, c'est toi qui l'a définit comme ça ? ou bien c'est tout simplement la lumière mini et maxi de ta pièce ? car la lumière peut varier suivant certains facteur donc peut être que parfois il fait plus clair que d'habitude ou moins clair ^^ donc cela peut être normal ton soucis..

En fait c'est une LDR qui forme un pont diviseur de tension avec une résistance en série.
La résistance est calculée pour obtenir la plage de variation de tension optimale en fonction des éclairements mini et maxi de la pièce où sera situé le dispositif.
De là j'ai les valeurs mini et maxi une fois converties en digital.
Donc les valeurs sont plutôt issues d'un calcul pour optimiser la sensibilité de la mesure de l'intensité lumineuse.

Merci

Cordialement

Benoit

[/quote]

Aaaah désolé ! au temps pour moi Patg_ !

Ensuite, je me répete mais je suis pas pro dans tout ceci, mais d'apres ce que tu dis, (si j'ai bien compris) la plage est définit en fonction de la valeur de la resistance? dans ce cas si c'est pas un bug de map () essais d'élargir ta plage, mais tu optimiseras moins ta sensibilité.. sinon je ne vois pas d'où peut venir ce probleme, je n'ai pas assez de recul dans ce domaine encore désolé..

Benoit