Executer pendant un Delay

bonjour,

Je possède un module ultrason et je désire l'utiliser pour fabriquer un robot qui détecte les obstacles.
J'ai un soucis, en fait le module ultrason me retourne bien une valeur correcte, mais pour retourner cette valeur il doit émettre l'ultrason et attendre le retour de l'onde (delay). Je veux que si la valeur est supérieur à 30 par exemple, les moteurs tournent puissance maximum.
Le problème est que le delay fait des microcoupure dans le fonctionnement du moteur, ce qui fait qu'on a l'impression que le robot hésite à avancer.

void loop() {

  //ultrason
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(pingPin, LOW);
  //fin ultrason

//fonction conversion temps en CM
cm=....
//fin de la fonction

    if (cm>30) {
     moteur à fond
    } else {
     stop moteur
    }
}

Ya t'il moyen de lancer l'ultrason en parallele du fonctionnement du moteur???

Merci :slight_smile:

il faut que tu utilise millis:

dans ta boucle principale, tu récupères l heure qu il est ( le nombre de ticks) et tu exécutes certains troncons de ton code uniquement si le temps actuel est supérieur au temps du dernier envoi + ton temps d attente

Voilà, voilà :

Maitriser le temps

Tu remplaces SDL_GetTicks par millis() et le tour est joué... enfin presque, il y a encore un peu de boulot à faire :wink:

j'ai essayé ce que vous m'avez dit mais je galère, alors j'ai remplacé le code pour tester avec un LED pour le moment.
En fait quand je met ma main à moins de 30 CM elle doit être éteinte et s'allumer quand je suis plus loin que 30CM.
Or, son comportement est que lorsque ma main est à moins de 30CM du capteur ultrason, la led émet un clignotement régulier, comme si dans le programme à un endroit il y avait un bout de code pour rallumer la diode

long cm=50;
//temps
unsigned long tempsprecedent=0;
unsigned long tempsactuel=0;
unsigned long ecart=0;
long duration;

//je vous passe le setup

void loop() {

if (cm>=30) {
digitalWrite(LED, HIGH);
} else {
  digitalWrite(LED, LOW);
}

//ULTRASON
tempsactuel=millis();
ecart=tempsactuel-tempsprecedent;

//petite pulsation de calibrage
while (ecart<3) {
 digitalWrite(pingPin, LOW);
 tempsactuel=millis();
 ecart=tempsactuel-tempsprecedent;
}

//grande pulsation
while (ecart<14) {
 digitalWrite(pingPin, HIGH);
  tempsactuel=millis();
 ecart=tempsactuel-tempsprecedent;
}

//reception du signal ultrason
digitalWrite(pingPin, LOW);
duration = pulseIn(inPin, HIGH);
cm = microsecondsToCentimeters(duration);
 
tempsactuel=millis();
tempsprecedent=tempsactuel;
}

Une idée?
Pour info le code de l'emetteur ultrason proviens de ce site:
http://iteadstudio.com/application-note/arduino-ultrasonic-ranging-with-hc-sr04/

On croirait qu'a chaque tour de boucle 'loop' la led se rallume avant de passer dans le if.... :o

//grande pulsation
while (ecart<14) {
digitalWrite(pingPin, HIGH);
tempsactuel=millis();
ecart=tempsactuel-tempsprecedent;
}

et prefere faire if que while.

//grande pulsation
while (ecart<14) {
digitalWrite(pingPin, HIGH);
tempsactuel=millis();
ecart=tempsactuel-tempsprecedent;
}

et prefere faire if que while.

je vois pas la différence avec ce que j'ai fait?!
Pourquoi utiliser un if sachant qu'il faut boucler pendant une durée x?
Le if ne boucle pas!?!

Magieweb,

remplacer les delay() par des boucles while ne va pas servir à grandes choses. Si je te comprends bien, tu as des soucis que ton controle de moteur va manquer de précision si le robot est occupé avec l'ultrason.

D'abord if faut se poser la question, quel temps de réaction est nécessaire pour tes moteurs. Si ton récepteur ultrason est la seul source de stimulus pour ton robot et la gestion des moteurs est reduit a ajuster la vitesse, ta première idée suffisait.

int vitesse=0;
loop () {
  // Ping ultrason
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(pingPin, LOW);

  // Mesure ultrason
  int duration = pulseIn(inPin, HIGH);
  int cm = microsecondsToCentimeters(duration);

  // Controle du moteur
  if (cm < 30 && vitesse > VStop) {
    // Freiner
    vitesse = VStop;
    setSpeed (vitesse);
  }
  elsif (cm >= 30 && vitesse < VFoncer) {
    // Foncer
    vitesse = VFoncer;
    setSpeed (vitesse);
  }
}

Un petit détail, je contrôle la vitesse que si elle doit changer, dans certaines instances c'est préférable, dans d'autres ça joue aucun rôle.

Tu commences à avoir de problèmes, lorsque le temps que tu prends pour les mesures te bloque le moteur ou vice-versa. Dans ce cas, tu as deux scénario possible:

Si les durées sont relativement longes (quelques millisecondes), tu crée quasi un calendrier avec des tâches et dans loop() tu enlèves tout delay() ou boucles d'attente. A chaque interation de loop, tu vérifies seulement sur le calendrier ce qui est à faire à ce tour.

Si les durées sont courtes (microsecondes) tu vas avoir besoin de fonctions d'interruption. Mais ça, c'est un peu plus compliquer et souvent pas nécessaire.

Korman

on utilise le while pour boucler dans la boucle.

void loop()
{
//instructions

while(mavariable!=0)
{

blablalbabla//boucle dans la boucle
if(uneaction==1){mavariable=1;}//sortir de la boucle et executer le reste

}

//suite des instructions
}

concernant millis, il permet d envoyer des routines à un temps précis, sans faire de delay. Tu l as utilisé "à l envers" de ce que generalement on fait ( mais tu en as le droit bien sur) en prenant la mesure de temps. celà te permet donc d avoir un programme qui ne bloque pas pendant un delay et qui continue à tourner sans discontinuer ( pas de pertes d infos, pas de problemes de synchro etc etc ).

int montempsactuel=0;
int temspactionprecedente=0;

int tempsaattendre=100;

void loop()
{
montempsactuel=millis();

if(montempsactuel>tempsactionprecedente+tempsaattendre)
{
//action puis:
tempsactionprecedente=montempsactuel;
}

}

J'ai tout recommencé, j'ai fait plein de tests, je me suis aperçu que c'est un probleme d'artefact d'ultrasons!
Exemple:
Le robot doit sarrêter a moins de 30Cm du mur:
Robot à 1M envoie pulsation A
Robot à 70Cm envoie pulsation B
Retour pulsation A
Retour pulsation B
....
au bout de X pulsations le module ultrason peut interpreter un retour de pulsation R a la place d'un retour de pulsation S et donc calculer une distance plus courte que celle réelle et donc arret des moteurs, mais il reçois l'autre pulsation qui elle correspond à une distance plus éloignée et rallume les moteurs...etc etc
enfin bref j'ai l'impression qu'il y a un chevauchement des pulsations
Il faut que je trouve le moyen d'éviter ça :cry:

tu n as pas possibilité de coder un identifiant dans ton retour de pulsation ?
ou de les mettre sur des entrées différentes ?

tu n as pas possibilité de coder un identifiant dans ton retour de pulsation ?
ou de les mettre sur des entrées différentes ?

Je n'en sais rien du tout! :o

http://iteadstudio.com/produce/cheap-cheap-ultrasonic-ranging-modulehc-sr04/

Entre deux impulsions, il faut attendre un aller retour de la plus longue distance attendue.

Plus tu te rapproches de l'obstacle plus ce temps va diminuer et réduire ton temps de réaction.

Il faut aussi tenir compte des réflexions multiples. Si tu est près d'un obstacle et que tu émets à pleine puissance, tu peux avoir des réflexions consécutives : réflexion sur l'obstacle, l'onde en retour rebondi sur le robot et de nouveau sur l'obstacle.

oki merci pour tout ces bons conseils, j'ai tout détruit et j'ai refait un bête montage d'affichage de distance pour voir ce qui se passait....
Mon module ultrason a un problème de soudures, certaines étaient foireuses!!! donc ça marchais une fois sur 2 en fonction de la pression exercée sur les pattes, a priori ça a du céder durant le fonctionnement du robot (pourtant soumis à aucun choque). Demain je refais tout le montage avec les moteurs, en espérant que cette fois ci ça ira et je vous ferai un topo :slight_smile:
En tout cas merci pour tout.