Aide projet, utilisation millis().

Bonjour, J'aurais besoin d'aide sur un programme Arduino pour un projet en terminale S-SI. Mais je suis confronté à un problème qui m'empêche d'avancer. Mon projet est un système d’anti-dessalage pour jeune skippeur sur catamaran. J'utilise un accéléromètre pour détecter l'angle d'inclinaison du bateau. Si celui-ci dépasse 50° alors on active un électroaimant (ici led). Jusqu'ici j'y arrive très bien, malgré cela j'aimerais que l'électroaimant s'active au bout de quelques secondes, et non pas directement après avoir dépassé l'angle de 50°, ceci pour éviter tout déclenchement inopiné.

Concrètement cela donnerais:

Traitement:
Si l'angle est supérieur à 50°
Alors attendre 2 s 
         Si l'angle est toujours supérieur à 50° 
         Alors  continuer.
         Sinon sortir de la boucle.
Sinon ne rien faire

Le problème c'est que si je met un delay() le calcul de l'angle s'arrête lui aussi. Vous vous en doutez sûrement mais je pense qui faut utiliser millis(). Le problème c'est que j'y arrive pas.

Dans mon problème j'ai mis deux leds; Une témoin de l'angle dépassé (jaune) Et l'autre simulant l'électroaimant (vert).

Voici le programme combiné avec un écran LCD pour l'affichage de l'angle.

void setup() 
{
lcd.begin(16, 2);
lcd.setRGB(colorR, colorG, colorB);

Serial.begin(38400);

Serial.println("Initializing I2C devices...");
accelgyro.initialize();
lcd.setCursor(0, 0);
lcd.print("Initializing I2C");
lcd.setCursor(0, 1);
lcd.print("devices..."); 
delay(1000);
lcd.clear(); 
Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
delay(1000);
Serial.println("     ");
lcd.setCursor(0, 0);
lcd.print(accelgyro.testConnection() ? "MPU6050" : "MPU6050");
lcd.setCursor(0, 1);
lcd.print(accelgyro.testConnection() ? "connection success" : "connection failed");
delay(1000);
lcd.clear();

 {
  pinMode(2, OUTPUT);  //led vert
  pinMode(4, OUTPUT);  //led jaune 
 }
}

void loop() 
{   
// calcule de l'angle stocké dans d
float a = sqrt(sq(abs(Axyz[0]))+sq(abs(Axyz[1]))+sq(abs(Axyz[2])));  //vecteur acceleration
float b=(a*10);
lcd.setCursor(0, 0);
lcd.print("angle");   
lcd.setCursor(0, 1);
float c = acos((((Axyz[1])*10))/b);
float d = (180*(c/3.141592654))-90;
lcd.print(d); 

long temps;
temps = millis();
if (abs(d)>50)
 {
   digitalWrite(4, HIGH);
   
    if (abs(d)>50)
    {
      digitalWrite(2, HIGH);   
    }  
    else
    {
      digitalWrite(4, LOW);{ goto sortir;}
    }
 }
else
 {
   { goto sortir;}
 }
sortir:

Quand je compile il n'y a pas d'erreur. J'arrive pas très bien à comprendre la fonction millis() ou plus comment l'utiliser dans mon cas. Je sais qu'elle permet de lancer un chrono mais j'arrive pas à l'utiliser.

Si vous pouviez m'aider cela serais vraiment sympa

redit: 01/04 14h37

Bonjour,

Mets ton code entre balises

Le problème c’est que ton code est partiel et on ne voit pas ou tu lis et calcule ton angle, donc il est difficile de te guider sur l’utilisation de millis()

Bonjour,

Tu lis la valeur de millis() à chaque boucle... Impossible dans ces conditions de mesurer un temps de Gîte...

Voici une ébauche d'algorithme :

angle = Lire_Angle_de_Gite();

// Si au passage précédent, on était déja penché au delà de 50°
Si Gîte == 1 alors
  // Et que l'on est toujours penchés
  si angle > 50 alors
    // Et que le temps de Gîte est dépassé
    si millis() - DebutGite > 1000
      alors Allumer Led_Electro-Aimant
    fin si
  sinon   // Remise à zéro que marqueur de Gîte
    Gîte = 0;
    Eteindre Led_Gite_détectée;
    Eteindre Led_Electro-Aimant;
  fin si
sinon  // Cas où Gîte == 0
  si angle > 50 
    DebutGite = Millis(); // On stocke le moment où la Gite à commencé...
    Gîte = 1; // On note le fait que l'on est en train de Gîter...
  fin si
fin si

A toi d'adapter et de mettre tout cela en musique... :)

Coyotte

@coyote : tu devrais lire ceci @natdop : tu devrais faire ce que dit kamill si tu veux qu'on s'intéresse à ton cas.

@Zorro_X : Désolé, je ne fréquente pas les bars... ;) Je n'ai donc pas vu le sujet :) Mais je plussoie !

Je ne vais pas virer ma réponse mais prendrai garde à ne plus répondre à un sujet mal formulé. Merci pour l'information,

Coyotte

Je viens de lire la charte du forum, j'ai réédité mon message, j'avais peut de temps pour posté. Merci pour vos réponses, je réfléchis sur ce que Coyotte m'a indiqué. Si quelqu'un à d'autres propositions, je reste à l'écoute.

edit:

J'ai refais le programme sur Arduino que vous m'avez donné du coup, cela me donne;

unsigned long debutgite;
boolean gite = 1;
float angle = d;
//Si au passage précédent, on était déja penché au delà de 50°
if (gite = 1)
{
 // Et que l'on est toujours penchés
 if (angle > 50)
  // Et que le temps de Gîte est dépassé
  {
   digitalWrite(2, HIGH); // Allumer led témoin
   if (millis() - debutgite > 1000)
    {
     digitalWrite(4, HIGH); // Allumer électroaimant
    }
  } 
  else  // Remise à zéro que marqueur de Gîte
  {
  gite = 0;
  digitalWrite(4, LOW); Éteindre électroaimant
  digitalWrite(2, LOW); Éteindre led témoin
  }
}
else
{
  if (angle > 50);
  debutgite = millis(); // On stocke le moment où la Gite à commencé...
  gite = 1; // On note le fait que l'on est en train de Gîter...
}

Je n'ai pas de message d'erreur mais la led de l'électroaimant s'active directement, et la led témoin ne s'active pas du tout. J'ai donc rajouter une ligne de code pour la led témoin. Malgré cela, il me reste le problème de l’électroaimant qui s'active en même temps que la led témoin de l'angle dépassé.

Déjà pour ça:

 if (angle > 50)

angle est déclaré de type float donc le test doit être

 if (angle > 50.0)

Pour voir si c'est un problème hard ou soft tu peux insérer des Serial.print() à des emplacements "stratégiques". Par exemple dans tes if tu peux en mettre pour voir si tu passes bien dans les blocs de code prévus. Tu verras dans la console le déroulement de ton programme.

Hello,

Normal... Tu commences avec Gite à 1. Tu pars donc du principe que ton bateau est penché...

De plus, dans ce code je ne vois pas ou et quand tu fais la lecture de l'angle actuel. Si la valeur d'angle ne change pas, la situation ne risque pas d'évoluer... :)

Coyotte

@fdufnews:
Le problème avec serial.print() c’est que il est déjà utiliser pour l’accéléromètre/gyroscope et il m’est très compliqué d’y introduire des informations lisibles sur les Leds.

Mes leds fonctionnent correctement désormais.
J’ai changé les if avec 50.0, étant donné que float() prend des valeurs jusqu’à 10^(39) pourquoi devrait on mettre que 1 seul zéro ? cela est t-il vraiment important ?

@coyotte:

Ha oui je viens de m’en rendre compte pour le gite, je vais essayer de changer cela…

La lecture de l’angle ce fait au-dessus de la déclaration de ces variables;

unsigned long debutgite;
boolean gite;
float angle = abs(d);

Je ne l’ai pas mis car elle me semblait pas utile dans la compréhension du traitement des leds.
elle est dans mon premier post;

float a = sqrt(sq(abs(Axyz[0]))+sq(abs(Axyz[1]))+sq(abs(Axyz[2])));  //vecteur acceleration
        float b=(a*10);
        lcd.setCursor(0, 0);
        lcd.print("angle");   
        lcd.setCursor(0, 1);
        float c = acos((((Axyz[1])*10))/b);
        float d = (180*(c/3.141592654))-90;
        lcd.print(d);

On comprend toujours pas ou est faite la mesure de l'angle. Si tu mettais ton code en entier on pourrait peut être comprendre.

Je peux pas le poster:

The message exceeds the maximum allowed length (9000 characters).

Il y a tout le traitement du gyroscope/accéléro et écran LCD avant. Donc du coup le programme est vraiment long. J'ai donc mis qu'une partie, celle du traitement de ces données;

Le fait de faire ça;

debutgite = millis();

Cela fait quoi concrètement ? ça commence à partir de zéro ? ça réinitialise à chaque fois que l'on effectue la fonction ? ça lance un chrono ?

Que fait la fonction millis() ? As-tu consulté la documentation ?

Coyotte

@coyotte
Oui j’avais lu un guide utilisant millis(), mais le fais de réaliser toujours des programmes erronés m’on fait douter et m’on perdu.
Je voulais donc un petit éclaircissement sur se point :slight_smile:

@pepe
Merci pour ta réponse, je pense avoir compris, je vais essayer de faire un autre programme pour voir si cela marche.

Bonne soirée :slight_smile:

J'essaye des programmes mais j'y arrive toujours pas... Je sais pas comment ne pas repasser par la fonction qui stocke l'heure avec millis quand l'angle est dépassé. Car à chaque fois ça stocke une nouvelle valeur du temps. J'ai essayé avec un tant que, mais c'est pire, l'angle ne varie plus du tout ^^. (Je vois que l'angle varie grâce à un écran LCD). J'arrive pas à comprendre non plus le programme avec des gite=1 ou gite=0. Je suis vraiment coincé :(

Bonjour

L'algorithme fourni est pourtant largement commenté.

Par contre, le programme que tu a écris ne peut fonctionner :

//Si au passage précédent, on était déja penché au delà de 50°
if (gite = 1)

La 2e ligne ne fait pas de test mais assigne toujours la valeur 1 à Gite :-( Comme l'assignation est toujours vraie, tu ne passes jamais dans le cas où il n'y a pas de gîte....

Le code devrait être

//Si au passage précédent, on était déja penché au delà de 50°
if (gite == 1)

Cela devrait déjà aller mieux... Comme il n'est pas possible de vérifier quand et comment tu lis la valeur de l'angle, il est difficile d'en dire plus.

Coyotte

Pour l'angle, je vais essayé d'expliquer;

J'ai un accéléromètre/gyroscope que je peux connecter en I2C. J'ai trouvé un programme tout fait qui donne les valeurs de l'accélération. Stocké dans une variable. A celui-ci, j'y est rajouté un autre programme mettant en jeu un écran LCD lui aussi connecté en I2C. Au début, je l'ai modifié pour qu'il affiche les forces de gravités sur les différents axes.

Puis j'ai fais des recherches et j'ai trouvé une formule qui détermine l'angle en fonction de la force de gravité sur les 3 axes, soit x,y,z. J'ai donc rajouter des lignes de codes pour effectuer cette formule en plusieurs étapes:

float a = sqrt(sq(abs(Axyz[0]))+sq(abs(Axyz[1]))+sq(abs(Axyz[2])));  //vecteur acceleration
float b=(a*10);
lcd.setCursor(0, 0);
lcd.print("angle");   
lcd.setCursor(0, 1);
float c = acos((((Axyz[1])*10))/b);
float d = (180*(c/3.141592654))-90;
lcd.print(d);

Axyz[0] étant la variable de la force en x Axyz[1] en y etc. Ces formules me donne donc un angle, stocké dans d, que j'affiche sur l'écran LCD.

Je veux donc mettre à la suite, le programme qui traite l'angle, donc celui avec millis() et les leds.

Le problème avec if(gite == 1) c'est que, au tout début, comment le programme sait si le gite est égal à 0 ou 1 ? Il doit effectuer la boucle 1 fois d'après moi.. or il peut pas car j'ai juste dit que gite pouvais prendre 1 ou 0. Fin c'est cette subtilité que je comprends pas.. Je sais pas si vous me comprenez, c'est dur à expliquer.

Je dois mettre quoi ?

boolean gite;
ou
boolean gite=0;

Le problème c'est que si je met boolean gite=0; à chaque fois que ça repasse sur cette ligne cela remet le gite à zéro, fin il me semble, vu que c'est une boucle..

Quelqu'un n'aurai pas une idée ?? :/

Bonjour, Voir pour une déclaration en static

Pour savoir au départ si tu gites ou non, il suffit de faire une mesure de l'angle dans le setup() et de positionner gite en conséquence. Ainsi lorsque tu entres dans loop ta variable est correctement positionnée.