Bateau autonome Coller aux parois d'une piscine 1/2

Bonjour
Je suis nouveau sur le forum. Je voulais faire un bateau autonome ( pour une piscine) pour ma fille et j’ai trouvé un article avec ce code. Si j’ai bien compris, le bateau avance seul, s’il détecte un objet il recule et repart.
Il tourne grâce à 2 moteurs sans gouvernail.

Par contre, peut-on me dire s’il se déplace toujours en ligne droite ou bien s’il se déplace aléatoirement ?
Code trouvé ici

Ceci pour la maquette de base

Voir le premier code dans la suite du post
‘‘Bateau autonome Coller aux parois d’une piscine 2/2’’

Avec ce que j’ai compris, j’ai ajouté une pompe à eau pour faire comme les bateaux pompiers.

Voir le deuxième code dans la suite du post
‘‘Bateau autonome Coller aux parois d’une piscine 2/2’’

En faisant ‘‘Croquis/ Vérifier compiler’’ sur la console, je n’ai pas eu d’erreur.

Ma question est la suivante
Tel que, le code a une seule fonction qui fait que le bateau avance et dès qu’il rencontre un obstacle, détecté par les ultra-sons, à 15 cm, il recule et repart ( aléatoirement ou en ligne droite ?)
Donc détection ultrason, bateau avance ou recule

Je voudrais ajouter une deuxième ‘‘fonction’’ qui plaque le bateau sur un coté.

Un détecteur sur le coté droit du bateau détecte le contact avec la parois et déclenche le moteur gauche pour plaquer le bateau sur la parois droite.
Donc contact droit et pas de détection ultrason, moteur gauche
Quand le bateau arrive dans un angle à gauche, le bateau tourne à gauche (moteur droit en fonction)
jusqu’à ce que le détecteur ultrason ne renvoie pas de signal
Donc contact droit ET détection ultrason à 5 cm , moteur droit
Puis quand le détecteur ultrason ne renvoie pas de signal, le bateau se recolle à la parois de droite.

Idem sur le coté gauche du bateau et même logique
Voir l’image ci-dessous

Je ne sais pas comment faire pour associer 2 conditions :
contact ET ultrason, plaquage aux parois de la piscine
contact SANS ultrason, déplacement aléatoire dans la piscine
Passer d’une fonction à l’autre

Comment modifier le code pour qu’il fasse ceci :

La première fonction est lancée , au bout de X minutes, à la fin détection par les ultra-sons d’une parois alors le bateau tourne pour venir se plaquer sur la parois de la piscine (aléatoirement la parois de droite ou de gauche).
Ensuite la deuxième fonction est déclenchée pendant Y minutes.
Puis la première fonction repart
Puis la seconde, etc… Le bateau se plaque une fois sur 2 à droite puis à gauche

Je cherche juste à faire ce programme pour le mettre sur un Arduino et donner à ma fille ce dernier tout prêt pour qu’elle puisse faire la maquette de bateau
Merci de votre aide

code d’origine

/*

This code corresponds to a floating boat with rudimentary sensing capabilities - 

 step by step instructions and images are at levinegabriella.com/teaching

 It includes an parallax ultrasonic rangefinder :  see data sheet

 http://www.arduino.cc/en/Tutorial/Ping

 which allows the boat to turn away from obstacles ahead.

 It also includes two reed switches so if it hits barriers from the side, it 

 turns around away from the wall

 *****
 Ce code correspond à un bateau flottant aux capacités de sentiment rudimentaires - 

Pas à pas les instructions et les images sont à levinegabriella.com/teaching

Il inclut une parallaxe le télémètre ultrasonique: voir la fiche technique

Http://www.arduino.cc/en/Tutorial/Ping

Ce qui permet au bateau de se détourner d'obstacles en avant.

Il inclut aussi deux échanges de roseau donc s'il frappe des barrières du côté, cela 

Se retourne loin du mur

 created 2011 by gabriella levine

 */



// constants

// set pin numbers:

const int pingPin = 7;

const int buttonPin1 = 2;     // the number of the pushbutton pin  Le numéro de l'épingle à commande automatique(presse-bouton)

const int buttonPin2 = 4;

const int motor =  3;      // the number of the motor pin    le (numéro l'épingle du moteur

const int motor2=11;



// variables 

int buttonState = 0;         // variable for reading the pushbutton status     variable pour lire le statut à commande automatique

int buttonState1  =0;

void setup() {

  //begin serial

  Serial.begin(9600);

  // initialize the motors  as output:

  pinMode(motor, OUTPUT); 

  pinMode(motor2, OUTPUT);  

  // initialize the pushbutton pins as  input:

  pinMode(buttonPin1, INPUT);    

  pinMode(buttonPin2, INPUT); 

}



void loop(){

  // establish variables for duration of the ping, 

  // and the distance result in inches and centimeters:

  long duration, inches, cm;

      // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
//Le PING))) est déclenché par une HAUTE impulsion de 2 ou plusieurs micro-secondes.
      // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
//Donnez une impulsion BASSE courte à l'avance pour assurer une HAUTE impulsion propre
  pinMode(pingPin, OUTPUT);

  digitalWrite(pingPin, LOW);

  delayMicroseconds(2);

  digitalWrite(pingPin, HIGH);

  delayMicroseconds(5);

  digitalWrite(pingPin, LOW);

  
  
      /* The same pin is used to read the signal from the PING))): a HIGH
       pulse whose duration is the time (in microseconds) from the sending
       of the ping to the reception of its echo off of an object.

      
la même épingle est utilisée pour lire le signal du PING))) : UN HAUT
pulse dont la durée est le temps (en micro-secondes) de l'envoi
Du Ping à la réception de son écho d'un objet.
*/

  pinMode(pingPin, INPUT);

  duration = pulseIn(pingPin, HIGH);



  // convert the time into a distance

  inches = microsecondsToInches(duration);

  cm = microsecondsToCentimeters(duration);

  // read the state of the pushbutton value:

  buttonState1 = digitalRead(buttonPin1);

  buttonState = digitalRead(buttonPin2);

  if (cm<=15){

    //digitalWrite(motor, LOW); 

    digitalWrite(motor2, LOW);

  }

  else{

    //digitalWrite(motor, HIGH);

    digitalWrite(motor2, HIGH);

    button();

  }

  delay(100);





}

void button(){

  // check if the pushbutton is pressed.

  // if it is, the buttonState is HIGH:

  if (buttonState1 == HIGH) {     

    // turn LED on:    

    digitalWrite(motor, LOW);  

  } 

  else {

    // turn LED off:

    digitalWrite(motor, HIGH); 

  }

  if (buttonState == HIGH) {     

    // turn LED on:    

    digitalWrite(motor2, LOW);  

  } 

  else {

    // turn LED off:

    digitalWrite(motor2, HIGH); 

  }

}

long microsecondsToInches(long microseconds)

{
/*
According to Parallax's datasheet for the PING))), there are
73.746 microseconds per inch (i.e. sound travels at 1130 feet per
second).  This gives the distance travelled by the ping, outbound
and return, so we divide by 2 to get the distance of the obstacle.

Selon la fiche technique de la Parallaxe pour le PING))), il y a
73.746 micro-secondes par pouce (c'est-à-dire le son voyage à 1130 pieds par seconde)(1 pied = 30.48 cm). 
Ceci donne la distance voyagée par le Ping, pour l'aller retour
Donc nous nous divisons par 2 pour obtenir la distance de l'obstacle.
   See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
*/
  return microseconds / 74 / 2;

}



long microsecondsToCentimeters(long microseconds)

{

  /*
  The speed of sound is 340 m/s or 29 microseconds per centimeter.
  The ping travels out and back, so to find the distance of the
  object we take half of the distance travelled.

  La vitesse du son est 340 m/s ou 29 micro-secondes par centimètre.
  Le tintement voyage d'et en arrière, ainsi trouver la distance de le
  L'objet nous prenons la moitié de la distance a voyagé.
  */
  return microseconds / 29 / 2;

}

A suivre mon code modifé

Code modifié pour ajouter une pompe

/*
created 2011 by gabriella levine
*/
// constants
// set pin numbers:
const int pingPin = 7;
const int buttonPin1 = 2; // the number of the pushbutton pin
const int buttonPin2 = 4;
const int motor = 3; // the number of the motor pin
const int motor2=11;
//
//**************************************************************************************************
const int pompe=10; // declaration pompe au pin 10 ********************************************
//**************************************************************************************************

// variables
int buttonState = 0; // variable for reading the pushbutton status
int buttonState1 =0;
void setup() {
//begin serial
Serial.begin(9600);
// initialize the motors as output:
pinMode(motor, OUTPUT);
pinMode(motor2, OUTPUT);
// initialize the pushbutton pins as input:
pinMode(buttonPin1, INPUT);
pinMode(buttonPin2, INPUT);

//**************************************************************************************************
// initialize the pump pins as output:   au démarrage la pompe ne marche pas ***********************
pinMode(pompe, OUTPUT);
// *************************************************************************************************
//
}
void loop(){
// establish variables for duration of the ping,
// and the distance result in inches and centimeters:
long duration, inches, cm;
// The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(5);
digitalWrite(pingPin, LOW);
// The same pin is used to read the signal from the PING))): a HIGH
// pulse whose duration is the time (in microseconds) from the sending
// of the ping to the reception of its echo off of an object.
pinMode(pingPin, INPUT);
duration = pulseIn(pingPin, HIGH);
// convert the time into a distance
inches = microsecondsToInches(duration);
cm = microsecondsToCentimeters(duration);
// read the state of the pushbutton value:
buttonState1 = digitalRead(buttonPin1);
buttonState = digitalRead(buttonPin2);
if (cm<=15){
//digitalWrite(motor, LOW);
digitalWrite(motor2, LOW);
//
//**************************************************************************************************
// à moins de 15 cm la pompe fonctionne ************************************************************
digitalWrite(pompe, HIGH);
//**************************************************************************************************
}
else{
//digitalWrite(motor, HIGH);
digitalWrite(motor2, HIGH);
//
//**************************************************************************************************
// sinon à plus de 15 cm la pompe stoppe ***********************************************************
digitalWrite(pompe, LOW);
//**************************************************************************************************
button();
}
delay(100);
}
void button(){
// check if the pushbutton is pressed.
// if it is, the buttonState is HIGH:
if (buttonState1 == HIGH) {
// turn LED on:
digitalWrite(motor, LOW);
//
//**************************************************************************************************
// si le bouton touche le bord la pompe fonctionne *************************************************
digitalWrite(pompe, HIGH);
//**************************************************************************************************
}
else {
// turn LED off:
digitalWrite(motor, HIGH);
//
//**************************************************************************************************
// sinon pas de contact la pompe stoppe ************************************************************
digitalWrite(pompe, LOW);
//**************************************************************************************************
}
if (buttonState == HIGH) {
// turn LED on:
digitalWrite(motor2, LOW);
//
//**************************************************************************************************
// si le bouton touche le bord la pompe fonctionne *************************************************
digitalWrite(pompe, HIGH);
//**************************************************************************************************
}
else {
// turn LED off:
digitalWrite(motor2, HIGH);
//
//**************************************************************************************************
// sinon pas de contact la pompe stoppe ************************************************************
digitalWrite(pompe, LOW);
//**************************************************************************************************
}
}
long microsecondsToInches(long microseconds)
{
// According to Parallax's datasheet for the PING))), there are
// 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
// second). This gives the distance travelled by the ping, outbound
// and return, so we divide by 2 to get the distance of the obstacle.
// See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
return microseconds / 74 / 2;
}
long microsecondsToCentimeters(long microseconds)
{
// The speed of sound is 340 m/s or 29 microseconds per centimeter.
// The ping travels out and back, so to find the distance of the
// object we take half of the distance travelled.
return microseconds / 29 / 2;
}

En faisant ‘‘Croquis/ Vérifier compiler’’ sur la console, je n’ai pas eu d’erreur.

Bonsoir,

merci pour la découverte de ce sympathique projet :wink:

ArduinoFree:
Ma question est la suivante
Tel que, le code a une seule fonction qui fait que le bateau avance et dès qu’il rencontre un obstacle, détecté par les ultra-sons, à 15 cm, il recule et repart ( aléatoirement ou en ligne droite ?)
Donc détection ultrason, bateau avance ou recule

En fait, d’après le code lorsque ultrason <=15 cm le moteur 2 est coupé donc le comportement du bateau dépend de l’état du moteur 1. Si le moteur 1 est coupé le bateau s’arrête, sinon si le moteur 1 est en fonctionnement le bateau tourne.

En C/C++ un ET logique se note &&. Un OU logique se note ||. La négation se note !. Donc cela ressemblera à :

if( (buttonState==HIGHT) && (cm<=15) ) … // contact ET ultrason

if( (buttonState==HIGHT) && !(cm<=15) ) … // contact sans ultrason

Remarque : pour le dernier cas on peut écrire if( (buttonState==HIGHT) && (cm>15) ) … // contact sans ultrason

Bonne continuation !

Bonjour et merci de ta réponse rapide.

Si j'ai bien compris ton explication.
Au départ, le bateau part du bord tout droit.
Arrivé à 15 cm du bord opposé, sans contact à droite et à gauche du bateau il ne se passe rien non ?

Ensuite le bateau continue d'avancer , contact avec l'un ou l'autre (buttonState ou buttonState1)
et donc mise en route du moteur du coté du contact.
Si contact droit, moteur droit et donc rotation vers la gauche.

J'ai bon jusque là ?

Compréhension du code
Explication de la void loop
Pour moi c'est une fonction qui définit l'émission/réception des ultrasons puis lisant la fonction button() pour savoir quel contact sur le coté est activé (buttonState ou buttonState1).
En conséquence, cela lance un moteur ou l'autre et ce pendant un temps de 'delay (100)'
100 secondes ou microsecondes ?

J'ai bon jusque là ?

Pour faire la fonction de ''collage'' au bords de la piscine, il faudrait que j'arrête pendant X minutes la détection permanente due aux ultrasons pour la reprendre ensuite après Y minutes de la fonction de ''collage''.

Cette fonction ''collage
void collage { ...} serait une copie de loop ( mais comment faire un doublon de loop ?)
avec les ET et OU mais avec une détection à 5 cm.

Comment faire ?

Merci

delay bloque le code pendant la durée spécifiée en millisecondes. Il existe delaymicroseconds pour des durées plus courtes.

Pour ton code, je te conseille de le réécrire avec des noms de variables plus explicites, tels que ‘boutonDroite’, ‘boutonGauche’, ‘moteurDroite’, etc. Pour une meilleur lecture il vaut mieux aussi mettre un maximum de choses dans des fonctions pour simplifier la loop.

Par exemple, toutes ces lignes peuvent être mises dans une fonction :

long mesureDistanceCm () {

// establish variables for duration of the ping,
// and the distance result in inches and centimeters:
long duration, inches, cm;
// The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(5);
digitalWrite(pingPin, LOW);
// The same pin is used to read the signal from the PING))): a HIGH
// pulse whose duration is the time (in microseconds) from the sending
// of the ping to the reception of its echo off of an object.
pinMode(pingPin, INPUT);
duration = pulseIn(pingPin, HIGH);
// convert the time into a distance
// long inches = microsecondsToInches(duration); // <-- ne pas garder cette ligne si elle ne sert pas
long cm = microsecondsToCentimeters(duration); 

return cm; }

qui est appelée dans la loop comme suit :
long cm = mesureDistanceCm ();et ainsi de suite avec la gestion des moteurs. Au final, ta loop n’est plus qu’une suite d’appels de fonctions.

Mais c’est juste une suggestion…

Bonjour

J’ai essayé de le faire mais j’ai eu des erreurs de noms. Je verrai plus tard
J’ai mieux renommer les éléments, et c’est plus clair effectivement :slight_smile:

Sur le code suivant , si j’ai compris, arrivé à 15 cm d’un mur, le bateau ne fait qu’éteindre le moteur 2 pendant 100 millisecondes, soit 0.1 secondes ?

Et du coup , il ne tournera toujours que dans un seul sens ?

/*
This code corresponds to a floating boat with rudimentary sensing capabilities -
step by step instructions and images are at levinegabriella.com/teaching
It includes an parallax ultrasonic rangefinder : see data sheet
http://www.arduino.cc/en/Tutorial/Ping
which allows the boat to turn away from obstacles ahead.
It also includes two reed switches so if it hits barriers from the side, it
turns around away from the wall
created 2011 by gabriella levine
*/


/*
En C/C++ un ET logique se note &&. Un OU logique se note ||. La négation se note !. Donc cela ressemblera à :
if( (buttonState==HIGHT) && (cm<=15) ) ... // contact ET ultrason
if( (buttonState==HIGHT) && !(cm<=15) ) ... // contact sans ultrason
Remarque : pour le dernier cas on peut écrire if( (buttonState==HIGHT) && (cm>15) ) ... // contact sans ultrason
*/

// constants
// set pin numbers:
const int pingPin = 7;
const int DetecteurPin1 = 2; // the number of the pushbutton pin  Le numéro de l'épingle à commande automatique(presse-bouton)
const int DetecteurPin2 = 4;
const int moteur1 = 3; // the number of the motor pin    le (numéro l'épingle du moteur
const int moteur2=11;
//
//**************************************************************************************************
const int pompe=10; // declaration pompe au pin 10 ********************************************
//**************************************************************************************************

// variables
int BtnContact = 0; // variable for reading the pushbutton status     variable pour lire le statut du 1er bouton de contact
int BtnContact1 =0; //                                                variable pour lire le statut du 2 ieme bouton de contact
void setup() {
//begin serial
Serial.begin(9600);
// initialise  les pin moteurs à OUTPUT, soit éteint
pinMode(moteur1, OUTPUT);
pinMode(moteur2, OUTPUT);
// initialise les boutons contact pins à INPUT, soit actif:
pinMode(DetecteurPin1, INPUT);
pinMode(DetecteurPin2, INPUT);

//**************************************************************************************************
// initialize the pump pins as output:   au démarrage la pompe ne marche pas ***********************
pinMode(pompe, OUTPUT);
// *************************************************************************************************
//
}
void loop(){
// establish variables for duration of the ping,
// and the distance result in inches and centimeters:
long duration, inches, cm;
// The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse.
//Le PING))) est déclenché par un contact de 2 ou plusieurs micro-secondes.
//Donnez une impulsion ETEINT courte à l'avance pour assurer une impulsion MARCHE propre
pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(5);
digitalWrite(pingPin, LOW);
  /* 
    le même pin est utilisé pour lire le signal du PING))) : impulsion 
    dont la durée est le temps (en micro-secondes) de l'émission 
    du Ping à la réception de son écho sur un objet.
  */
pinMode(pingPin, INPUT);
duration = pulseIn(pingPin, HIGH);
// convert the time into a distance
inches = microsecondsToInches(duration);
cm = microsecondsToCentimeters(duration);
// read the state of the pushbutton value:
BtnContact1 = digitalRead(DetecteurPin1);
BtnContact = digitalRead(DetecteurPin2);
if (cm<=15){
//digitalWrite(moteur, LOW);
digitalWrite(moteur2, LOW);
//
//**************************************************************************************************
// à moins de 15 cm la pompe fonctionne ************************************************************
digitalWrite(pompe, HIGH);
//**************************************************************************************************
}
else{
//digitalWrite(moteur, HIGH);
digitalWrite(moteur2, HIGH);
//
//**************************************************************************************************
// sinon à plus de 15 cm la pompe stoppe ***********************************************************
digitalWrite(pompe, LOW);
//**************************************************************************************************
button();
}
delay(100);
}

//******
//******
//******

void button(){
// vérifie si les boutoncontact sont actifs(HIGHT), si oui le moteur passe à actif(HIGHT) ou éteint(LOW) selon le programme
if (BtnContact1 == HIGH) {
// turn LED on:
digitalWrite(moteur1, LOW);
//
//**************************************************************************************************
// si le bouton touche le bord la pompe fonctionne *************************************************
digitalWrite(pompe, HIGH);
//**************************************************************************************************
}
else {
// turn LED off:
digitalWrite(moteur1, HIGH);
//
//**************************************************************************************************
// sinon pas de contact la pompe stoppe ************************************************************
digitalWrite(pompe, LOW);
//**************************************************************************************************
}
if (BtnContact == HIGH) {
// turn LED on:
digitalWrite(moteur2, LOW);
//
//**************************************************************************************************
// si le bouton touche le bord la pompe fonctionne *************************************************
digitalWrite(pompe, HIGH);
//**************************************************************************************************
}
else {
// turn LED off:
digitalWrite(moteur2, HIGH);
//
//**************************************************************************************************
// sinon pas de contact la pompe stoppe ************************************************************
digitalWrite(pompe, LOW);
//**************************************************************************************************
}
}

//******
//******
//******

long microsecondsToInches(long microseconds)
{
  /*
    Selon la fiche technique de la Parallaxe pour le PING))), il y a
    73.746 micro-secondes par pouce (c'est-à-dire le son voyage à 1130 pieds par seconde)(1 pied = 30.48 cm).
    Ceci donne la distance voyagée par le Ping, pour l'aller retour
    Donc nous nous divisons par 2 pour obtenir la distance de l'obstacle.
     See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
  */

return microseconds / 74 / 2;
}

//******
//******
//******

long microsecondsToCentimeters(long microseconds)
{
  /*
    La vitesse du son est 340 m/s ou 29 micro-secondes par centimètre.
    Le tintement voyage d'et en arrière, ainsi trouver la distance de le
    L'objet nous prenons la moitié de la distance a voyagé.
  */
return microseconds / 29 / 2;
}

+1 avec lesept pour un renommage explicite des variables cela évitera de s’emmêler les pinceaux.

J'essaye de répondre à tes questions :

Arrivé à 15 cm du bord opposé, sans contact à droite et à gauche du bateau il ne se passe rien non ?

Si, le moteur2 se coupe, le bateau tourne, mais tu l'as compris depuis :wink:

Ensuite le bateau continue d'avancer , contact avec l'un ou l'autre (buttonState ou buttonState1)
et donc mise en route du moteur du coté du contact.
Si contact droit, moteur droit et donc rotation vers la gauche.

Non, quand contact droit, arrêt du moteur gauche (donc seul le moteur droit pousse donc virage à gauche et vice versa.

En conséquence, cela lance un moteur ou l'autre et ce pendant un temps de 'delay (100)'

Non, le moteur est lancé jusqu'à ce qu'une condition fasse qu'il est explicitement arrêté. En fait, il faut bien comprendre que la fonction loop est automatiquement rappelée dès qu'elle se termine.

Le delay(100) fait "dormir" la fonction pendant 100ms (soit 0.1 seconde). Sa présence est là je pense pour éviter que des fluctuations trop rapides des valeurs des capteurs provoquent des allumages/arrêts trop fréquents des moteurs.

Bonnes cogitations :wink:

Merci de ton aide

Je pense à une chose pour les 2 fonctions de déplacement aléatoire et de ‘collage’ au parois .

Comment dire à la fonction loop pendant 10 mn de ‘boucler’ sur le déplacement aléatoire ?
Ensuite j’utilise les conditions associées contacts et/sans ultrason
if( (buttonState==HIGHT) && (cm<=15) ) … // contact ET ultrason
if( (buttonState==HIGHT) && !(cm<=15) ) … // contact sans ultrason
idem dire à la fonction loop pendant 10 mn de ‘boucler’ sur le ‘collage’ au parois ?

et si j’ai compris loop repart sur la fonction de déplacement aléatoire

Merci

Pour pouvoir enchaîner différents comportements (ultrason, aleatoire, suiviDeBord) ton programme devra être capable de déterminer s’il est temps de passer au comportement suivant.

C’est possible car un programme est capable de connaître le nombre de millisecondes depuis son démarrage, grâce à la fonction millis() (cela revient à lire l’heure relative au début du programme).

Par exemple le test suivant sera vrai seulement pendant les 10 premières secondes du programme
if(millis() < 10*1000L) …

Remarque : dans l’exemple précédent le L après le 1000 indique une constante de type long int (entiers sur 32 bits). Quand on joue avec millis() il faut utiliser des types entier long ou entier long non signés. La fonction millis() retourne un entier de type “unsigned long”.

Si maintenant on veut un test vrai seulement pendant 10 secondes après un instant arbitraire il faut faire comme ceci :

unsigned long startMillis; // déclaration de la variable startMillis destinée à mémoriser un temps arbitraire
...
startMillis=millis(); // mémorisation de l'instant arbitraire
...
if(millis() - startMillis < 10*1000L) ... // vrai seulement pendant 10 secondes après l'affectation de startMillis

Du coup voici un bout de code qui devrait répondre à la question (fait à partir de cet exemple) :

// Variable globale
unsigned long startMillis; // à 0 par défaut

// ...

void loop() {
	if(millis()-startMillis < 10*60*1000L) { // < 10 minutes
		aleatoire();
	}
	else {
		if(millis()-startMillis < 20*60*1000L) { // vrai si < 20 minutes
			ultrasons();
		}
		else {
			if(millis()-startMillis < 30*60*1000L) { // vrai si < 30 minutes
				bordures();
			}
			else {
				startMillis=millis(); // le cycle est terminé, temps initial mis à jour
			}
		}
	}
}

Et sinon la partie électronique tu l’as préparée pour tester ?

Pour l’ électronique, je regarde sur Aliexpress et j’ai commandé les moteurs, les cartes, la pompe…
Je dois recevoir tout entre 4 jours et 3 semaines.
Donc j’essaie de voir le code pour l’instant.n

Dans ton code
ultrasons() : je remplace par le code actuel

// establish variables for duration of the ping,
// and the distance result in inches and centimeters:
long duration, inches, cm;
// The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse.
//Le PING))) est déclenché par un contact de 2 ou plusieurs micro-secondes.
//Donnez une impulsion ETEINT courte à l'avance pour assurer une impulsion MARCHE propre
pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(5);
digitalWrite(pingPin, LOW);
  /* 
    le même pin est utilisé pour lire le signal du PING))) : impulsion 
    dont la durée est le temps (en micro-secondes) de l'émission 
    du Ping à la réception de son écho sur un objet.
  */
pinMode(pingPin, INPUT);
duration = pulseIn(pingPin, HIGH);
// convert the time into a distance
inches = microsecondsToInches(duration);
cm = microsecondsToCentimeters(duration);
// read the state of the pushbutton value:
BtnContact1 = digitalRead(DetecteurPin1);
BtnContact = digitalRead(DetecteurPin2);
if (cm<=15){
//digitalWrite(moteur, LOW);
digitalWrite(moteur2, LOW);
//
//**************************************************************************************************
// à moins de 15 cm la pompe fonctionne ************************************************************
digitalWrite(pompe, HIGH);
//**************************************************************************************************
}
else{
//digitalWrite(moteur, HIGH);
digitalWrite(moteur2, HIGH);
//
//**************************************************************************************************
// sinon à plus de 15 cm la pompe stoppe ***********************************************************
digitalWrite(pompe, LOW);
//**************************************************************************************************
button();
}
delay(100);
}

et dans
bordures() je mets
if( (buttonState==HIGHT) && (cm<=15) ) … // contact ET ultrason
if( (buttonState==HIGHT) && !(cm<=15) ) … // contact sans ultrason

Attention : c'est HIGH, pas HIGHT !!!

Bonjour

Vu pour HIGH , merci :slight_smile:

J’ai modifié le code.
Mais comme je m’y attendais il buggue
Les variables inch, cm, aleatoire etc, ne sont pas déclarées dans ce scope (?)

Puis-je et comment, supprimer les lignes ayant rapport aux inches, ou bien dois-je les garder ?

Merci

/*
This code corresponds to a floating boat with rudimentary sensing capabilities -
step by step instructions and images are at levinegabriella.com/teaching
It includes an parallax ultrasonic rangefinder : see data sheet
http://www.arduino.cc/en/Tutorial/Ping
which allows the boat to turn away from obstacles ahead.
It also includes two reed switches so if it hits barriers from the side, it
turns around away from the wall
created 2011 by gabriella levine
*/


/*
En C/C++ un ET logique se note &&. Un OU logique se note ||. La négation se note !. Donc cela ressemblera à :
if( (buttonState==HIGH) && (cm<=15) ) ... // contact ET ultrason
if( (buttonState==HIGH) && !(cm<=15) ) ... // contact sans ultrason
Remarque : pour le dernier cas on peut écrire if( (buttonState==HIGHT) && (cm>15) ) ... // contact sans ultrason
*/

// constants
// set pin numbers:
const int pingPin = 7;
const int DetecteurPin1 = 2; // the number of the pushbutton pin  Le numéro de l'épingle à commande automatique(presse-bouton)
const int DetecteurPin2 = 4;
const int moteur1 = 3; // the number of the motor pin    le (numéro l'épingle du moteur
const int moteur2=11;
//
//**************************************************************************************************
const int pompe=10; // declaration pompe au pin 10 ********************************************
//**************************************************************************************************

// variables
int BtnContact = 0; // variable for reading the pushbutton status     variable pour lire le statut du 1er bouton de contact
int BtnContact1 =0; // 

// Variable globale pour faire le décompte du temps
unsigned long startMillis; // à 0 par défaut

//variable pour lire le statut du 2 ieme bouton de contact
void setup() {
//begin serial
Serial.begin(9600);
// initialise  les pin moteurs à OUTPUT, soit éteint
pinMode(moteur1, OUTPUT);
pinMode(moteur2, OUTPUT);
// initialise les boutons contact pins à INPUT, soit actif:
pinMode(DetecteurPin1, INPUT);
pinMode(DetecteurPin2, INPUT);

//**************************************************************************************************
// initialize the pump pins as output:   au démarrage la pompe ne marche pas ***********************
pinMode(pompe, OUTPUT);
// *************************************************************************************************
//
}
void loop(){
  
if(millis()-startMillis < 10*60*1000L) { // < 10 minutes
aleatoire();
}
  else {
    if(millis()-startMillis < 20*60*1000L) { // vrai si < 20 minutes
      ultrasons();
    }
    else {
      if(millis()-startMillis < 30*60*1000L) { // vrai si < 30 minutes
       bordures();
      }
      else {
        startMillis=millis(); // le cycle est terminé, temps initial mis à jour
      }
    }
  }
  delay (100);
}





//******
//******
//******

void button(){
// vérifie si les boutoncontact sont actifs(HIGHT), si oui le moteur passe à actif(HIGHT) ou éteint(LOW) selon le programme
if (BtnContact1 == HIGH) {
// turn LED on:
digitalWrite(moteur1, LOW);
//
//**************************************************************************************************
// si le bouton touche le bord la pompe fonctionne *************************************************
digitalWrite(pompe, HIGH);
//**************************************************************************************************
}
else {
// turn LED off:
digitalWrite(moteur1, HIGH);
//
//**************************************************************************************************
// sinon pas de contact la pompe stoppe ************************************************************
digitalWrite(pompe, LOW);
//**************************************************************************************************
}
if (BtnContact == HIGH) {
// turn LED on:
digitalWrite(moteur2, LOW);
//
//**************************************************************************************************
// si le bouton touche le bord la pompe fonctionne *************************************************
digitalWrite(pompe, HIGH);
//**************************************************************************************************
}
else {
// turn LED off:
digitalWrite(moteur2, HIGH);
//
//**************************************************************************************************
// sinon pas de contact la pompe stoppe ************************************************************
digitalWrite(pompe, LOW);
//**************************************************************************************************
}
}


void ultrasons(){
    
// establish variables for duration of the ping,
// and the distance result in inches and centimeters:
long duration, inches, cm;
// The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse.
//Le PING))) est déclenché par un contact de 2 ou plusieurs micro-secondes.
//Donnez une impulsion ETEINT courte à l'avance pour assurer une impulsion MARCHE propre
pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(5);
digitalWrite(pingPin, LOW);
  /* 
    le même pin est utilisé pour lire le signal du PING))) : impulsion 
    dont la durée est le temps (en micro-secondes) de l'émission 
    du Ping à la réception de son écho sur un objet.
  */
pinMode(pingPin, INPUT);
duration = pulseIn(pingPin, HIGH);

}

void aleatoire(){
  
  if (cm<=15){
//digitalWrite(moteur, LOW);
digitalWrite(moteur2, LOW);
//
//**************************************************************************************************
// à moins de 15 cm la pompe fonctionne ************************************************************
digitalWrite(pompe, HIGH);
//**************************************************************************************************
}
else{
//digitalWrite(moteur, HIGH);
digitalWrite(moteur2, HIGH);
//
//**************************************************************************************************
// sinon à plus de 15 cm la pompe stoppe ***********************************************************
digitalWrite(pompe, LOW);
//**************************************************************************************************
button();
}
}

void bordures(){
 /*
En C/C++ un ET logique se note &&. Un OU logique se note ||. La négation se note !. Donc cela ressemblera à :
if( (buttonState==HIGH) && (cm<=5) ) ... // contact ET ultrason
if( (buttonState==HIGH) && !(cm<=5) ) ... // contact sans ultrason
Remarque : pour le dernier cas on peut écrire if( (buttonState==HIGHT) && (cm>5) ) ... // contact sans ultrason
*/ 
}

//******
//******
//******

long microsecondsToInches(long microseconds)
{
  /*
    Selon la fiche technique de la Parallaxe pour le PING))), il y a
    73.746 micro-secondes par pouce (c'est-à-dire le son voyage à 1130 pieds par seconde)(1 pied = 30.48 cm).
    Ceci donne la distance voyagée par le Ping, pour l'aller retour
    Donc nous nous divisons par 2 pour obtenir la distance de l'obstacle.
     See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
  */

return microseconds / 74 / 2;
}

//******
//******
//******

long microsecondsToCentimeters(long microseconds)
{
  /*
    La vitesse du son est 340 m/s ou 29 micro-secondes par centimètre.
    Le tintement voyage d'et en arrière, ainsi trouver la distance de le
    L'objet nous prenons la moitié de la distance a voyagé.
  */
return microseconds / 29 / 2;
}

Tu as fait un peu trop de ménage dans ton code, tu ne calcules plus la distance. Après
duration = pulseIn(pingPin, HIGH);il faut ajouter cm = microsecondsToCentimeters(duration);et définir cm en début de programme :long cm = 0;

Ta gestion du temps n’est pas bonne : tu remets le chrono à zéro à chaque exécution de la loop. Les conditions de temps ne seront jamais remplies.
startMillis=millis();Il faut faire un truc du genre :

void loop(){
  
   if(millis()-startMillis < 10*60*1000L) { // < 10 minutes
      startMillis=millis(); 
      aleatoire();
  }
  else if(millis()-startMillis < 20*60*1000L) { // vrai si < 20 minutes
      startMillis=millis(); 
      ultrasons(); 
    }
    else if(millis()-startMillis < 30*60*1000L) { // vrai si < 30 minutes
      startMillis=millis(); 
       bordures();
    }
  delay (100);
}

Mais même comme ça, ça ne marchera pas : il va rester dans l’aléatoire, jamais faire ultrasons ni bordures car la condition ‘10 minutes’ sera toujours vue avant les autres.

Ton programme est complexe : tu dois faire un schéma simple qui montre les différents états et les conditions associées, un peu comme ça :
afin de bien voir ce que ton code doit faire et sous quelles conditions. Ensuite, tu pourras le coder plus facilement, voire même l’écrire comme une machine d’états, ce qui te donnera un code très propre et très lisible, voire même très facile à modifier (pour ajouter des fonctionnalités).

Tu peux virer les inches si tu ne fais tes mesures qu’en centimètres (pas besoin de la fonction microsecondsToInches).

Ne peut-on pas encadrer millis ?

Et si on pouvait dire à loop
si 0=< millis < 10601000L, alors c’est la fonction ‘aléatoire’

puis
si 10601000L=< millis < 20601000L, alors c’est la fonction ‘bordure’

sinon retour au départ

Je n’ai besoin que de la fonction ‘aléatoire’ et ‘bordure’ dans les ‘millis’ car la fonction ‘ultrasons’ est toujours valide par défaut.
Même dans ‘bordure’, on doit détecter son état pour changer de moteur ( voir l’image jointe d’explication de la fonction)

void loop() {
   // dès le départ le bateau bouge aléatoirement
  if ((millis() - startMillis >= 0 * 60 * 1000L)&& (millis() - startMillis < 10 * 60 * 1000L)) { // < 10 minutes
    startMillis = millis();
aleatoire();
  }
  else {
    if ((millis() - startMillis >= 10 * 60 * 1000L)&& (millis() - startMillis < 20 * 60 * 1000L)) { // vrai si < 20 minutes
      startMillis = millis();
      bordures();
    }
    else {
      startMillis = millis(); // le cycle est terminé, temps initial mis à jour
    }
  }
  ultrasons (); // valide par défaut ?
delay (100);
}





//******
//******
//******

void button() {
  // vérifie si les boutoncontact sont actifs(HIGH), si oui le moteur passe à actif(HIGH) ou éteint(LOW) selon le programme
  if (BtnContact1 == HIGH) {
    // turn LED on:
    digitalWrite(moteur1, LOW);
    //
    //**************************************************************************************************
    // si le bouton touche le bord la pompe fonctionne *************************************************
    digitalWrite(pompe, HIGH);
    //**************************************************************************************************
  }
  else {
    // turn LED off:
    digitalWrite(moteur1, HIGH);
    //
    //**************************************************************************************************
    // sinon pas de contact la pompe stoppe ************************************************************
    digitalWrite(pompe, LOW);
    //**************************************************************************************************
  }
  if (BtnContact == HIGH) {
    // turn LED on:
    digitalWrite(moteur2, LOW);
    //
    //**************************************************************************************************
    // si le bouton touche le bord la pompe fonctionne *************************************************
    digitalWrite(pompe, HIGH);
    //**************************************************************************************************
  }
  else {
    // turn LED off:
    digitalWrite(moteur2, HIGH);
    //
    //**************************************************************************************************
    // sinon pas de contact la pompe stoppe ************************************************************
    digitalWrite(pompe, LOW);
    //**************************************************************************************************
  }
}


void ultrasons() {

  // establish variables for duration of the ping,
  // and the distance result in inches and centimeters:
  long duration, inches, cm;
  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse.
  //Le PING))) est déclenché par un contact de 2 ou plusieurs micro-secondes.
  //Donnez une impulsion ETEINT courte à l'avance pour assurer une impulsion MARCHE propre
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);
  /*
    le même pin est utilisé pour lire le signal du PING))) : impulsion
    dont la durée est le temps (en micro-secondes) de l'émission
    du Ping à la réception de son écho sur un objet.
  */
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);
  cm = microsecondsToCentimeters(duration);

}

void aleatoire() {

  if (cm <= 15) {
    //digitalWrite(moteur, LOW);
    digitalWrite(moteur2, LOW);
    //
    //**************************************************************************************************
    // à moins de 15 cm la pompe fonctionne ************************************************************
    digitalWrite(pompe, HIGH);
    //**************************************************************************************************
  }
  else {
    //digitalWrite(moteur, HIGH);
    digitalWrite(moteur2, HIGH);
    //
    //**************************************************************************************************
    // sinon à plus de 15 cm la pompe stoppe ***********************************************************
    digitalWrite(pompe, LOW);
    //**************************************************************************************************
    button();
  }
}

void bordures() {
  /*
    En C/C++ un ET logique se note &&. Un OU logique se note ||. La négation se note !. Donc cela ressemblera à :
    if( (buttonState==HIGH) && (cm<=5) ) ... // contact ET ultrason
    if( (buttonState==HIGH) && !(cm<=5) ) ... // contact sans ultrason
    Remarque : pour le dernier cas on peut écrire if( (buttonState==HIGHT) && (cm>5) ) ... // contact sans ultrason
  */
}



//******
//******
//******

long microsecondsToCentimeters(long microseconds)
{
  /*
    La vitesse du son est 340 m/s ou 29 micro-secondes par centimètre.
    Le tintement voyage d'et en arrière, ainsi trouver la distance de le
    L'objet nous prenons la moitié de la distance a voyagé.
  */
  return microseconds / 29 / 2;
}

Ce n’est pas le problème : lorsque le premier test est passé, tu remets le chrono à 0, donc on repart pour le premier test.

J’insiste : fais un schéma avec des conditions, car je pense que tes idées ne sont pas assez claires pour une mise en oeuvre.

Au passage, regarde la syntaxe du if else :

if (brocheCinqEntree < 500) 
{
  // faire l'action A
}
else if (brocheCinqEntree >= 1000)
{
  // faire l'action B
}
else
{
  // faire l'action C
}

Donc voici ce que je comprends pour mon graphe logique

Oups !

J’ai oublié une boucle de condition :frowning:

voici le bon graphe

OK, c'est un début.

Tel que je le comprends, il n'ira jamais dans la branche de gauche (le 'non' du premier test chrono < 10). Tu peux virer cette branche.
Et on ne sait pas ce qu'il fait entre le premier appel de la fonction aléatoire (qui sera fait dès le début) et le passage du chrono à 10 : tu dois mettre un oui / non pour expliciter ce qui se passe dans le test '>10' de la branche de droite.

ArduinoFree:
Oups !

J'ai oublié une boucle de condition :frowning:

voici le bon graphe

OK, ça répond à une de mes remarques.

Maintenant, en oubliant la première branche de gauche, on voit ceci :

  • de 0 à 10 minutes : aléatoire
  • de 10 à 20 minutes : bordure
  • au delà de 20 minutes : aléatoire puis bordure (en boucle)

Est-ce bien ce que tu veux faire ?