Go Down

Topic: Code HC SR04 + Servomoteur (Read 420 times) previous topic - next topic

Marsian

Mar 25, 2019, 09:20 pm Last Edit: Mar 27, 2019, 10:02 am by Marsian
Bonjour à tous,
Je rencontre un problème avec un capteur HC SR04 et un servomoteur.
Le servo est sensé tourné de 0 à 150° de gauche à droite et le capteur placé dessus doit permettre la mesure.
Voici mon code actuel, le problème se situant au niveau du delay ;(
J'ai rajouté un delay(100); après le serial.print mais rien n'y fait ...



Code: [Select]
#include <Servo.h>
Servo monServomoteur;
const int Trig = 8;
const int Echo = 9;

float duration;
float distance;

void setup() {
  
// Attache le servomoteur à la broche 7
monServomoteur.attach(7);
pinMode(Trig, OUTPUT);
pinMode(Echo, INPUT);
Serial.begin(9600);
}

void loop() {
digitalWrite(Trig, LOW);
delayMicroseconds(2);
digitalWrite(Trig, HIGH);
delayMicroseconds(10);
digitalWrite(Trig, LOW);

duration = pulseIn(Echo, HIGH);
distance = (duration/2) * 0.034;
Serial.print("Distance: ");
Serial.println(distance);
// Fait bouger le bras de 0° à 150°
for (int position = 0; position <= 150; position++) {
  monServomoteur.write(position);
  delay(20);
}

// Fait bouger le bras de 150° à 0°
for (int position = 150; position >= 0; position--) {
  monServomoteur.write(position);
  delay(20);
}

}

dbrion06

Quel est votre problème?

a) le capteur ultrason donne-t-il une mesure realiste (tel que c'est codé, avec la position 0 du servo)
b) le servo bouge-t-il de 150 degres en 3 secondes, puis revient il à sa postion initiale en 3 secondes (tel que c'est code, si je n'ai rien saute et que le servo fonctionne, c'est ce qui devrait se passer, sans que le capteut US ne soit consulté)

c) souhaiteriez vous faire une mesure de distance pour chaque secteur angulaire? A ce stade, c'est une pure spéculation (mais que se passerait-il si c'est votre souhait, en mettant le bloc de code qui fait la mesure dans une des boucles de débattement du servo)

Marsian

Bonjour dbrion06,
Je réalise un petit robot Arduino à 4 roues, le moteur est placé à l'avant et porte le capteur à ultrason.
Le code pour le capteur me permet d'obtenir des mesures de distance avec delay variable, le code marche bien. Le code pour déplacer le moteur marche bien aussi, concernant la rotation. Mais je voudrait faire tourner le moteur et obtenir des mesures via le moniteur série mais le delay pour le print n'est pas pris en compte...
Le code donne des mesures du capteur mais à la fin des rotations (droite et gauche finies)
Le servo bouge à la bonne vitesse
Oui j'aimerais mesurer la distance au moins 5 fois par rotation mais je ne sais pas comment m'y prendre, j'ai essayé de séparer le print et delay dans une boucle sans résultat

dbrion06

#3
Mar 26, 2019, 01:11 pm Last Edit: Mar 26, 2019, 01:35 pm by dbrion06
pour me simplifier la vie (et vous aussi), je vais faire une fonction gérant l'US:
Code: [Select]

float US(){
  digitalWrite(Trig, LOW);
  delayMicroseconds(2);
  digitalWrite(Trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(Trig, LOW);

  duration = pulseIn(Echo, HIGH);
  distance = (duration/2) * 0.034;
  Serial.print("Distance: ");
  Serial.println(distance);

  return distance;


et, si je veux afficher 5 fois la distance (i.e le débattement est un multiple de 30 degrés), il faut le faire pendant que le cerf veau tourne:

Code: [Select]


// Fait bouger le bras de 150° à 0°
for (int position = 150; position >= 0; position--) {
  monServomoteur.write(position);
  delay(20);
}


 deviendrait

Code: [Select]

// Fait bouger le bras de 150° à 0°
for (int position = 150; position >= 0; position--) {
  monServomoteur.write(position);
  delay(20);
  if (9 == (position % 30)) { // tirs à  129,99,69,39,9 degrés: 5 par débattement
    distance =US();
  }
}

NOTA ce n'est certainement pas le plus beau bout de code du monde; l'usage de delays posera problème si votre robot devient plus complexe -millis() est mieux-; l'astuce de passer presque tout par variables globales est laide, aussi...

Marsian

#4
Mar 27, 2019, 09:58 am Last Edit: Mar 27, 2019, 10:01 am by Marsian
Bonjour dbrion06,
Je vous remercie pour cette réponse détaillée. J'ai essayé de faire la boucle float US mais je n'y arrive pas :/ En revanche, j'ai appliqué votre méthode pour le servo et le capteur enregistre en effet 5 mesures par "tour" de gauche à droite et droite à gauche; cependant ce sont les mêmes mesures ( 1 seule mesure est répétée 5 fois :smiley-confuse: )

Voici le seul changement que j'ai fais :
Code: [Select]
// Fait bouger le bras de 0° à 150°
  for (int position = 0; position <= 150; position++) {
    monServomoteur.write(position);
    delay(10);
    if (9 == (position % 30)){
  Serial.print("Distance: ");
 Serial.println(distance);
  }
    }
  
  
  // Fait bouger le bras de 150° à 0°
  for (int position = 150; position >= 0; position--) {
    monServomoteur.write(position);
   delay(10);
   if (9 == (position % 30)){
  Serial.print("Distance: ");
 Serial.println(distance);
  }
  }


Désolé, je suis vraiment débutant en code et je n'ai pu faire que ça :smiley-confuse:
J'ai essayé de placer la boucle float en variable mais rien n'y fait …
Faut-il remplacer le void loop() par float US() ?
(Désolé pour le retard je rencontrais des problèmes internet :smiley-confuse: )

dbrion06

C'est normal: tel que vous l'avez écrit, vos boucles faisant tourner votre cerf veau ne font qu'afficher la distance précédemment calculée.
Il faudrait, pour bien faire, intercaler le code qui ... calcule la distance, avec l'ultra çon.

Pour ça, il y a deux façons de faire

a) un copier coller du bloc calculant la distance: c'est une méthode hideuse, qui mène à des problèmes de dépannage désespérants (on a copié collé un bloc faux, et on ne sait plus où dépanner). NE l'envisagez SURTOUT pas.

b) l'écriture d'une fonction qui est appelée (comme delay(), Serial.print()... vous utilisez plein de fonctions et vous êtes libre d'en créer)  et son utilisation là où elle est utile. L'avantage est double:

b1)ça fait du code lisible  (plus concis; même la génération de binaire prend moins de place, mais je ne me place que du point de vue d'un hêtre humain)

b2) si vous n'en êtes pas satisfait, vous n'avez qu'un endroit où faire des modifs, évitant de tourner en bourrique.

Je n'ai pas d'arduino sous la main -et j'ai donc codé "de tête":
Quote
J'ai essayé de faire la boucle float US mais je n'y arrive pas
-tout d'abord, ce n'est pas une boucle, mais une fonction dans le jargon.

Pouvez vous montrer votre essai infructueux? (et éventuellement le message d'horreur?)

Marsian

Bonjour,
Merci de l'aide, j'ai utilisé la technique immonde mais qui me paraissait la plus simple à savoir insérer le bloc entier de mesures  :smiley-confuse:

Code: [Select]
void loop() {
 
  // Fait bouger le bras de 0° à 150°
  for (int position = 0; position <= 150; position++) {
    monServomoteur.write(position);
    delay(10);

    if (9 == (position % 30)){
 digitalWrite(Trig, LOW);
 delayMicroseconds(2);
 digitalWrite(Trig, HIGH);
 delayMicroseconds(10);
 digitalWrite(Trig, LOW);

 duration = pulseIn(Echo, HIGH);
 distance = (duration/2) * 0.034;
  Serial.print("Distance: ");
 Serial.println(distance);
  }
    }
 
 
  // Fait bouger le bras de 150° à 0°
  for (int position = 150; position >= 0; position--) {
    monServomoteur.write(position);
   delay(10);

   if (9 == (position % 30)){
 digitalWrite(Trig, LOW);
 delayMicroseconds(2);
 digitalWrite(Trig, HIGH);
 delayMicroseconds(10);
 digitalWrite(Trig, LOW);

 duration = pulseIn(Echo, HIGH);
 distance = (duration/2) * 0.034;
  Serial.print("Distance: ");
 Serial.println(distance);
  }
 }
 
}


Le capteur envoies des mesures cohérentes : 5 mesures par rotation  :) L'objectif est atteint malgré le manque d'esthétisme….  :)  :)
D'après ce que j'ai compris, il faudrait créer une fonction englobant ce bloc et y faire appel dans les rotations ? Le bloc de mesure peut être compris dans une variable ?

dbrion06

Bon,
la structure d'un programme arduino est la suivante:
Code: [Select]

variables globales
void setup() {
// ceque vous voulez pour assurer le démarrage
}
void loop() {
// ce que vous voulez pour assumer des taches repetitives
}


Vous avez déjà deux fonctions, setup et loop, qui sont préremplies pour vous et qui appellent d'autres fonctions :digitalWrite,  pulseIn... (et vous n'avez pas besoin de copier coller le contenu de digitalWrite, pulseIn: outre l'usure des boutons de la souris et le caractère très long du programme qui en resulterait, si un de ces blocs était mal programmé, le remplacer partout serait effrayant)

De même -supposons que vous trouviez un autre capteur de distance plus performant et qui ne se programme pas exactement pareil: dans 6 mois, vous ne vous souviendrez pas de tous les copie collers que vous avez faits-, j'ai proposé de faire une fonction que j'ai appelée US. Ce qui donnerait la structure suivante
Code: [Select]

variables globales
float US() {
  digitalWrite(Trig, LOW);
  delayMicroseconds(2);
  digitalWrite(Trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(Trig, LOW);

  duration = pulseIn(Echo, HIGH);
  distance = (duration/2) * 0.034;
  Serial.print("Distance: ");
  Serial.println(distance);

  return distance;
} // LA FIN DE BLOC AVAIT ETE OMISE DANS L ORIGINAL; désolé

void setup() {
// ceque vous voulez pour assurer le démarrage
}
void loop() {
// ce que vous voulez pour assumer des taches repetitives
}

Et là, si vous avez un nouveau capteur, vous n'avez qu'à faire une nouvelle fonction et l'appeler à la place de l'ancienne (2 lignes de code à modifier, au lieu de scier à la bonne place 2 blocs;). De même, si vous voulez faire un point fixe....
C'est pour ça que je ne peux que vous conseiller (même et surtout si le copier coller brutal marche .. ou semble marcher) de faire vos propres fonctions, qui vous permettront de faire évoluer vos programmes ou de les dépanner, même dans 6 mois, sans trop tourner en bourrique.

Marsian

#8
Mar 27, 2019, 05:55 pm Last Edit: Mar 27, 2019, 06:04 pm by Marsian
Parfait,  merci pour ces informations !  :)
Je viens de tester, le code marche bien cependant il y a des mesures aberrantes …
Code: [Select]

Distance: 71.84
Distance: 33.00
Distance: 85.00
Distance: 28.95
Distance: 31.88
Distance: 0.00
Distance: 0.00
Distance: 0.00
Distance: 0.00
Distance: 0.00

 

Voici le moniteur série,
Les valeurs manquantes correspondent à la moitié de chaque rotation (3 manquantes de droite à gauche et 2 manquantes de gauche à droite). Vraiment bizarre…

PROBLEME RESOLU !!! LEGER FAUX CONTACT… MERCI BEAUCOUP DE VOTRE AIDE  :)  :)  :)  :)

Concernant le code entier :
Code: [Select]

#include <Servo.h>
Servo monServomoteur;
const int Trig = 8;
const int Echo = 9;

float duration;
float distance;
int position;

float US() {
  digitalWrite(Trig, LOW);
 delayMicroseconds(2);
 digitalWrite(Trig, HIGH);
 delayMicroseconds(10);
 digitalWrite(Trig, LOW);

 duration = pulseIn(Echo, HIGH);
 distance = (duration/2) * 0.034;
 
 Serial.print("Distance: ");
 Serial.println(distance);
 return distance;
}

void setup() {
    
  monServomoteur.attach(7);
  pinMode(Trig, OUTPUT);
  pinMode(Echo, INPUT);
  Serial.begin(9600);
}

void loop() {
 
  // Fait bouger le bras de 0° à 150°
  for (int position = 0; position <= 150; position++) {
    monServomoteur.write(position);
    delay(10);
    
    if (9 == (position % 30)){
distance =US();
   }
  }
  
  
  // Fait bouger le bras de 150° à 0°
  for (int position = 150; position >= 0; position--) {
    monServomoteur.write(position);
   delay(10);
  
   if (9 == (position % 30)){
 distance =US();
  }
 }
}
  

 
(Le int position vient d'une erreur lors d'un test..)
Autre question de noob, comment rajouter le "cm" après les valeurs mesurées ?

dbrion06

Est ce que les valeurs non nulles sont réalistes?

Est ce que ce comportement aberrant se reproduit au cours du temps ? Est ce pire au fur et à mesure que le temps passe?

Est ce que 10 ms est un temps suffisant pour que la "tourelle " soit arrêtée (il suffit de mettre un "delay (200) ;" en tête de la fonction US pour voir si stabiliser la rotation améliorerait les choses ... ou pas). Là, je suis un peu aveugle....

Marsian

Les valeurs étaient aléatoires mais venaient du matériel, les câbles s'étaient légèrement déplacés dû aux mouvements générant de faux contacts…

Tous fonctionne très bien, merci pour votre aide  :) Mon but étant de réaliser un robot commandé par Bluetooth, je demanderais des informations en cas de pépin !  :)

dbrion06

Il serait plus sage d'essayer d'éviter des pépins, qui peuvent être dûs à une trop grande complexité;
J'ai vu (ma liste ne peut être exhaustive) que vous feriez bien d'apprendre les structures de base en informatique -notion de fonction; de portée des variables -j'ai "triché" avec des variables globales; est ce sain à long terme-; d'interruption (pour le bluetooth.
si vous complexifiez, les delays(sont bloquants) devraient être évités, car ils font perdre du temps qui pourrait être employé à autre chose :
un bel exemple, très simple (et donc simple à lire, fait pour être compris) est, de mémoire, dans fichiers-> exemples->BlinkWithoutDelay;
pour la gestion du bluetooth -c'est une ligne série, les événements -ordre bluetooth-  se produisant hors de contrôle de l'arduino-, https://forum.arduino.cc/index.php?topic=500683.0 explique, avec les notions théoriques adaptées,  comment récupèrer  sainement des caractères, et les décoder quand l'arduino est prêt...

Go Up