correct ou pas ?

Bonjour,

je suis toujours dans mes histoires de mesure de distance à partir d'un HC-SR04 monté sur servomoteur.

Dans mon code, en cas d'obstacle, le capteur tourne d'un côté, prend une mesure, tourne à l'opposé et prend une autre mesure. Juste un ping à chaque fois. Ensuite, une comparaison est faite entre les deux mesures et les moteurs sont activés en conséquence. Ceci pour vous expliquer le fonctionnement.

Tout fonctionne correctement, sauf que parfois le capteur donne une mesure à zéro.

Dans ce cas, je veux qu'il refasse aussitôt un ping.

J'ai écrit çà comme ceci:

int getDistance()
{
  int rval;
  digitalWrite(triggPin, LOW);
  delayMicroseconds(2);
  digitalWrite(triggPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(triggPin, LOW);
  duration = pulseIn(echoPin, HIGH, 38000L);
  rval = microsecondsToCentimeters(duration);
//-------boucle en cas de mesure a zero------//
  if (rval = 0) getDistance();
//---   ----continue si mesure != zero- -----  -//
  //Serial.println(rval);
  return rval;
}

Est ce que cette façon de procéder est correcte ou y'a-t-il mieux à faire ? Sachant que le capteur ne sera, normalement, jamais à moins de 3 centimètres de l'obstacle vu sa position et la géométrie du robot.

Merci

déjà if (rval = 0) pas bon, faut un == :wink:

sinon ça serait mieux comme ça :

int getDistance()
{
  int rval;

while(rval==0) {
  digitalWrite(triggPin, LOW);
  delayMicroseconds(2);
  digitalWrite(triggPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(triggPin, LOW);
  duration = pulseIn(echoPin, HIGH, 38000L);
  rval = microsecondsToCentimeters(duration);
}

  //Serial.println(rval);
  return rval;
}

autant pour moi le"==", je me priverai de chocolat ce soir :wink:

j'essaie de comprendre ce qui fait la différence entre les deux codes.

D'un côté, il y a "si la mesure égale zéro, recommence"

et de l'autre "tant que la mesure égale zéro, mesure"

Pour moi, les deux reviennent au même mais je suppose qu'il y a une finesse qui m'échappe

J'avoue que j'ai jamais testé ta façon, l'as-tu fait par hasard ? Une fonction qui reboucle sur elle même ça me parait pas "sain" tout simplement, mais la pour le coup je me suis jamais posé la question donc je suis absolument sûr de rien

j'ai testé et, après correction du "==", ça fonctionne bien.

Par contre, avec le "while", j'obtiens un résultat de mesure de distance à 4 chiffres :astonished:

Voici la fonction telle qu'elle est actuellement:

int getDistance()
{
  int rval;
  digitalWrite(triggPin, LOW);
  delayMicroseconds(5);  //2
  digitalWrite(triggPin, HIGH);
  delayMicroseconds(20);  //10
  digitalWrite(triggPin, LOW);
  duration = pulseIn(echoPin, HIGH, 38000L); 
  rval = microsecondsToCentimeters(duration);
  if (rval == 0) getDistance();
  //Serial.println(rval);
  return rval;
}

Par contre, là où il y a un souci, c'est que de temps en temps, essentiellement quand il fait face au coussin de mon chien ou aux doubles rideaux, le capteur renvoie une valeur à zéro et le robot reste bloqué, la fonction bouclant sur elle-même.

Je pense que pour éviter çà, il faudrait que j'ajoute un compteur du genre:

mesurer la distance
si distance == 0 recommencer.
au bout de 5 essais, si distance égale toujours zéro provoquer un déplacement

Quelqu'un pourrait m'indiquer comment ajouter çà à la fonction ?

tu peut rajoute une variable qui s’incrémente a chaque comptage par exemple
a la grosse un truc comme ça , mais ce serai plus simple a ecrie avec une boucle while!

int getDistance()
{
  int rval;
static byte compteur=0;
  digitalWrite(triggPin, LOW);
  delayMicroseconds(5);  //2
  digitalWrite(triggPin, HIGH);
  delayMicroseconds(20);  //10
  digitalWrite(triggPin, LOW);
  duration = pulseIn(echoPin, HIGH, 38000L); 
  rval = microsecondsToCentimeters(duration);
  if (rval == 0 && compteur<=5){ getDistance(); compteur++}else{ fonctionDeplacement();compteur =0;};
  //Serial.println(rval);
  return rval;
}

Une fonction qui s’appelle elle même hum…

Tu peux vite exploser la pile si jamais elle retourne zéro plusieurs fois de suite.
En plus il me semble que cela ne masque pas les zéros, ils sont seulement perdues au milieu d’autres valeurs.
Pas trop le temps de détailler ça maintenant.

albaflo:
Par contre, là où il y a un souci, c'est que de temps en temps, essentiellement quand il fait face au coussin de mon chien ou aux doubles rideaux, le capteur renvoie une valeur à zéro et le robot reste bloqué, la fonction bouclant sur elle-même.

Je pense que pour éviter çà, il faudrait que j'ajoute un compteur du genre:

Sauf que l'historique ne doit pas être le même que lorsqu'il y a une erreur de mesure.
L'erreur de mesure retourne ponctuellement un zéro au milieu d'autres valeurs.
Dans le cas du coussin de ton chien, tu devrais voir la distance diminuer progressivement avant d'avoir zéro. Et la valeur n'est pas isolée.

D'ailleurs si l'erreur qui te retourne un 0 est vraiment isolée, tu devrais pouvoir la masquer en faisant un filtre majoritaire sur 3 mesures consécutives.

pour le bug avec while, il s’agit peut-être d’un echo “lointain”. Avec un nombre d’essai max + éviter le bug :

int getDistance()
{

  int rval;
  int x=0;

while(rval==0 && x<5) {

  digitalWrite(triggPin, LOW);
  delayMicroseconds(2);
  digitalWrite(triggPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(triggPin, LOW);
  duration = pulseIn(echoPin, HIGH, 38000L);
  rval = microsecondsToCentimeters(duration);
  delay(5);
  x++;

}

  return rval;

}

merci pour toutes ces infos, c'est sympa.

Je teste les solutions dans la soirée.

J'ai lu "filtre majoritaire", kézaco ? :fearful:

Sinon, il me semble avoir lu quelque part que les sonars à ultrasons pouvaient avoir des difficultés à mesurer les distances lorsque les surfaces sur lesquels rebondissent les pings sont de type mousse ou tissus.

Le zéro renvoyé de temps à autre ne proviendrait-il pas de là ?

Filtre majoritaire ça dit ce que ça dit : si tu as 10 mesures, 9 qui dise 25cm et une qui dit 0cm, quelle distance est la bonne ? :wink:

albaflo:
merci pour toutes ces infos, c'est sympa.

Je teste les solutions dans la soirée.

J'ai lu "filtre majoritaire", kézaco ? :fearful:

Sinon, il me semble avoir lu quelque part que les sonars à ultrasons pouvaient avoir des difficultés à mesurer les distances lorsque les surfaces sur lesquels rebondissent les pings sont de type mousse ou tissus.

Le zéro renvoyé de temps à autre ne proviendrait-il pas de là ?

Filtre majoritaire = j'ai plusieurs échantillons (en nombre impaire) je les classe et j'élimine les échantillons singuliers (ceux qui ne sont pas en majorité).
Exemple j'ai trois mesures 56, 60, 0. Laquelle j'élimine?

La mesure de distance par ultrason repose sur la mesure du temps de parcours de l'onde ultrasonore. Il faut donc que les obstacle réflechissent l'onde en question pour qu'il y ait mesure. Les éléments mous absorbent plus ou moins les ondes sonores et si le matériaux est trop absorbant il n'y a pas d'onde réfléchie et donc pas de mesure.

Pour détecter les obstacles, il n'y a pas de solution universelle. il faut généralement utiliser plusieurs capteurs chacun ayant ses avantages et ses inconvénients.
Tu pourrais utiliser un capteur à infrarouge en complément de ton capteur ultrason. Les ultrasons sont assez bon sur les distances moyennes, les capteurs infrarouges les complètent bien pour la détection d'obstacle proches.

après essais, la première solution me renvoie des mesures à zéro et la seconde des mesures à 4 chiffres.

Pour le filtre majoritaire, je vois bien le principe mais il faudrait que le sonar fasse trois mesures consécutives de chaque côté et je ne suis pas certain que ça élimine le souci provoqué par les mousses et tissus suspendus.

Je vais donc ajouter, comme tu le proposes fdufnews, deux capteurs à infrarouge, mais en attendant de les recevoir, j'ai utilisé une méthode surement peu élégante mais qui fonctionne:

int getDistance()
{
  int rval;
  int compteur;
  digitalWrite(triggPin, LOW);
  delayMicroseconds(5);  //2
  digitalWrite(triggPin, HIGH);
  delayMicroseconds(20);  //10
  digitalWrite(triggPin, LOW);
  duration = pulseIn(echoPin, HIGH, 38000L);  // Set timeout to 38mS  //38000L
  rval = microsecondsToCentimeters(duration);
  if (rval == 0) { getDistance(); compteur ++;}
  if (compteur >=5) {compteur == 0; rval == 25;}
  //Serial.println(rval);
  return rval;
}

Si le sonar renvoie 5 mesures à zéro, je donne une valeur par défaut, là même que celle de référence, à rval pour forcer le déplacement.
Pour le moment, je n'ai pas constaté de bug.

J'espère trouver du temps durant le week end pour me pencher sur le filtre majoritaire. Je pense qu'il faudrait inclure un compteur là aussi mais après... ne garder que les deux valeurs les plus hautes et faire une moyenne ?

Oui, mais non, car compteur sera une nouvelle variable pour chaque appel à la fonction, et en plus, son contenu est incertain (se reporter à la portée des variables).

penser à créer une variable static...

je suis vache là... mais c'est la dure loi de la jungle numérique qu'est l'arduino...

*** cherche "variable statique" dans les références puis file vomir aux toilettes ***

bon, çà, c'est fait ! :drooling_face:

finalement, le week end ça sera peut être un peu court :roll_eyes: