Go Down

Topic: Sortir VoidLoop (Read 1 time) previous topic - next topic

Julo

Bonsoir tout le monde !

Alors ma question est assez simple, je suis actuellement sur un programme d'asservissement moteur qui doit donc tourner continuellement. Cependant, arrive un moment ou le chariot commandé par mon moteur arrive en butée et il faut que je stop totalement mon programme. Mais je ne sais pas du tout comment faire. J'ai un peu cherché et je ne trouve pas du tout

J'ai donc un capteur linéaire, dans ma boucle void_loop, je met une condition :

Code: [Select]
if(encoderAcount_lineaire>2700 || encoderAcount_lineaire<300){
    analogWrite(pwm_b,0)
    //Et là je met quoi ?
  }


encoderAcount_lineaire étant mon codeur linéaire (je le met en butée avant de lancer le programme, le 0 est donc fixé a une des butée, et la position max étant 3000). Je souhaite donc qu'à chaque fois que je donne une vitesse à mon moteur, la position linéaire soit mesurée et éventuellement sortir de la boucle si mon chariot arrive en butée de l'un ou l'autre des côtés. Je ne sais pas si j'ai été assez clair, je vous met le code complet (le but étant de réaliser un pendule inversé, le codeur angulaire me donne donc la position du pendule)


Code: [Select]
int pwm_b = 9;  //PWM pour le moteur
int dir_b = 8;  //Direction (sens) du moteur

//capteur linéaire
const int clkPinA=2;
const int dirPinA=4;
 
//capteur angulaire
const int clkPinB=7;
const int dirPinB=10;
volatile int encoderAcount_lineaire = 0;
volatile boolean changeFlag_lineaire=false;
volatile int encoderAcount_angulaire = -1079; //Monter le pendule en haut par le bon sens
volatile boolean changeFlag_angulaire=false;

const int K=150; //Constante gain proportionnel
const int Ki=150; //Constante gain intégral
const int Kd=150; //Constante gain dérivé
int angle_1;
int angle_2;

long dt; //On définit la variable de temps


void setup()
{
  Serial.begin(9600);
  pinMode(clkPinA,INPUT);
  pinMode(dirPinA,INPUT);
  attachInterrupt(0,encoderIntA, RISING);
  pinMode(clkPinB,INPUT);
  pinMode(dirPinB,INPUT);
  attachInterrupt(0,encoderIntB, RISING);
 
  pinMode(pwm_b, OUTPUT);
  pinMode(dir_b, OUTPUT);
 
  analogWrite(pwm_b, 0);
 
}
 
void loop()
{
 
  if (changeFlag_lineaire){
    changeFlag_lineaire=false;
    //Serial.println(encoderAcount_lineaire);
  }
  if (changeFlag_angulaire){
    changeFlag_angulaire=false;
    //Serial.println(encoderAcount_angulaire);
  }
 
///////////////////////// Mise du chariot au centre ////////////////////////////
  while(encoderAcount_lineaire<1500){
    digitalWrite(dir_b,HIGH);
    analogWrite(pwm_b,100);
    Serial.print("Position codeur lineaire");
    Serial.println(encoderAcount_lineaire);
  }
  analogWrite(pwm_b,0);

///////////////////////// Boucle d'asservissement, correcteur PID ////////////////////////
                         
  dt=millis(); //On initialise le temps à 0 ici
 
  angle_1=encoderAcount_angulaire;
  if(angle_1>0){
    analogWrite(dir_b,HIGH); //Régler dans le bon sens !
  }
  else{
    analogWrite(dir_b,LOW); //Régler aussi dans le bon sens !
  }
 
  analogWrite(pwm_b,min(angle_1*K,255));
  angle_2=encoderAcount_angulaire;
  dt=(millis()-dt); //On stocke dans dt l'intervalle de tps entre les deux mesures d'angle
  analogWrite(pwm_b,min(255,K*angle_1 + Ki*(angle_2-angle_1)*dt + Kd*(angle_2-angle_1)/dt)); //Asservissement   
                    //La fonction min sert à ne pas dépasser la vitesse max autorisée : 255
  if(encoderAcount_lineaire>2700 || encoderAcount_lineaire<300){
    analogWrite(pwm_b,0)
    // C'est donc ici qu'il faut sortir du loop
  }

}



Merci de l'aide apportée, je suis vraiment débutant sur Arduino.

Bonne soirée à tout le monde :)

B83s

Si ton chariot arrive en butée .. Tu veux sortir du loop ... C'est à dire arrêter le programme ?

Si oui, alors tu mets
Code: [Select]
while (1) ; // le programme va se tourner/bloquer dans cette boucle infinie

Cependant, le seul moyen de relancer ton programme sera de faire un reset sur ta carte

68tjs

#2
Feb 11, 2016, 08:20 am Last Edit: Feb 11, 2016, 08:31 am by 68tjs
Il y a un point que tu n'as pas vu : un micro controleur ne doit jamais s'arréter.
Dans un ordinateur c'est le système d'exploitation qui se charge de maintenir le microprocesseur en activité.
Dans un micro-controleur c'est la boucle infinie qui assure cette fonction.

Même si cela est caché pour l'utilisateur un programme arduino est parfaitement conforme a la structure d'un programme C/C++. Tu n'écris que les fonctions Setup et Loop et c'est l'IDE qui complète pour avoir un vrai fichier Cpp et non pas ino, avec une vraie fonction main à l'intérieur de laquelle on trouve un appel à setup() et à loop().

Donc il est impossible de sortir de loop qui est la boucle infinie.
Tout doit se gérer à l'intérieur de la boucle loop.

Les moyens ne manquent pas : il y a ce qu'on appelle les drapeaux qui sont des variables dont on teste "en boucle" la valeur, pour les cas où il y a urgence il y a les interruptions etc.
Lectures conseillées : le tuto d'Eskimon et des sites comme OpenClassRoom.

Julo

#3
Feb 11, 2016, 09:49 am Last Edit: Feb 11, 2016, 10:03 am by Julo
Bonjour et merci beaucoup à tous les deux !

@B83s : Je vais tenter ça de suite, je n'avais pas pensé ^^

@68tjs : Oui c'est ce qu'il me semble avoir lu, mais j'ai trouvé ca bizarre qu'il ne soit pas possible de quelque façon qu'il soit d'arrêter le programme principal (un simple while(1) infini dans mon cas devrait fonctionner ^^)


EDIT : Voilà après test, le programme reste bloqué dans la boucle, c'est parfait

Merci beaucoup des réponses rapides ! :)

68tjs

Est-tu sur de n'avoir pas besoin de  redémarer le programme autrement qu'en appuyant sur le bouton reset ?
Ce fonctionnement "une fois seulement" me semble  'inahabituel". Mais si c'est ce que veut pourquoi pas.

Julo

Normalement non, lorsque je suis en butée, il faut que je recommence mon expérience. Mon chariot n'aura pas assez d'amplitude du côté de la butée, donc mon pendule tombera. Il faut donc recommencer l'expérience du départ

68tjs

Donc ce n'est pas la solution.
AMHA il faut que tu regarde du coté des drapeaux et des interruptions.

Julo

Je ne comprend pas bien pourquoi ce n'est pas une solution ^^ ?

Je vais jeter un coup d'oeil tout de même aux interruptions et drapeaux

Artouste

#8
Feb 11, 2016, 10:05 pm Last Edit: Feb 11, 2016, 10:06 pm by Artouste
Je ne comprend pas bien pourquoi ce n'est pas une solution ^^ ?

Je vais jeter un coup d'oeil tout de même aux interruptions et drapeaux
bonsoir
lorsque tu trouve dans une situation d'urgence ( contexte arduino 8) )
= surtout "ne plus rien faire"
ça ne sert à rien de vouloir t'en prendre à la boucle loop() elle meme,
il sufiit juste d'inserer une boucle infinie (dont tu ne peux sortir , une fois rentré  dans la loop()

Julo

@Artouse : Oui c'est pour ça que B83s m'a proposé un "while(1)", mais 68tjs me propose autre chose que je ne comprend pas bien

Artouste

@Artouse : Oui c'est pour ça que B83s m'a proposé un "while(1)", mais 68tjs me propose autre chose que je ne comprend pas bien
bien decortiquées , les propositions sont identiques :smiley-mr-green:

68tjs

Quote
Cependant, arrive un moment ou le chariot commandé par mon moteur arrive en butée et il faut que je stop totalement mon programme.
Pourquoi s'en prendre au programme ?
Si le chariot se trouve en fin course déjà ce n'est pas normal et il y a du travail de ce coté.
Ensuite avec un contact fin de course on peut couper l'alim du moteur (sécurité) et déclencher les actions nécessaires (remise en état de fonctionnement)..

Quote
mais 68tjs me propose autre chose que je ne comprend pas bien
Ton message me rappelle mon premier post qui avec le recul était totalement absurde : c'était un problème quasi identique et je n'avais encore rien compris au micro-contrôleur, Depuis j'ai essayé de me soigner.

Drapeau :
Suite à l' exacerbation actuelle des nationalismes je vais changer de nom et parler de "fanion" comme dans la marine à voile.
Imaginons : sur la route il y a des travaux et seule une voie est disponible. Il n'y a pas de feu de chantier un ouvrier règle la circulation avec un fanion rouge.
S'il le leve dans ta direction c'est que tu peux passer, s'il le baisse c'est que tu doit t'arréter.
Dans la programmation un fanion est une variable à laquelle tu donne la valeur 1 ou 0 ( ou true ou false).
Cette variable étant testée dans une boucle if.
Code: [Select]
if(fanion==1)  { // code fonctionnement normal }
else           { //code  en cas de fin de course par exemple }


Interruption :
C'est une faculté des micro-contrôleurs de pouvoir  stopper instantanément le programme en cours  pour effectuer une action précise et dès que l'action est finie le programme reprend là ou il avait été arrêté.

Toutes les pins peuvent être dotés d'une fonction interruption (PCINT)  mais seules deux D2 et D3 sont dotées d'interruptions ultra simple à utiliser (D2 -> int0 et D3 ->  int1). Il existe des fonctions arduino pour les gérer : attachinterrupt et detachinterrupt -> voir l'onglet Learning et Reference.

Le principe
Le fanion est mis à 1 en début de programme.
Quand le chariot arrive en butée, l'interupteur de fin de course change l'état sur la pin D2.
Comme une interruption à été attachée à D2  elle se déclenche et appelle un programme qui change la valeur du fanion et la passe à 0 ce qui interdit au code situé dans la boucle if  d'agir.

Pour la remise en service on peut imaginer un bouton connecté sur D3 avec une interuption attachée à D3 qui fait passer le fanion à 1 ce qui re autorise le code contenu dans la boucle if.

Pour plus de détails il y a la recherche sur ce forum  en haut à droite "Search the Arduino forum".

Maintenant si tu trouves plus simple en cas de fin de course de bloquer le programme, de régler les problèmes mécaniques et de relancer le programme en appuyant sur la touche Raz  finalement pourquoi pas.

Tu peux aussi modifier la boucle while qu'on t'a proposée:
Code: [Select]
While (fanion == 0)
{}

Tu ne sera pas obligé de faire une Raz pour relancer la programme.

Raz = remise à zéro = reset en anglais, Raz c'est franchouillard et c'est plus court !

Julo

D'accord merci beaucoup à toi des précisions. Encore un petit dernier truc, si j'ai bien compris, je met la boucle que je souhaite dans le "if(fanion==1) {ma boucle}". Et dans cette boucle, je met une boucle tout à la fin "if (position > 2000) {fanion=0}", ou alors le "attachInterrup" s'en occupe seul lorsque je le définit ?

Et enfin, le programme ne tourne plus dans cette boucle, mais si j'en ai plusieurs dans mon programme, le programme tournera sur les autres boucles mais plus celle ci (si je suis en butée), c'est bien celà ?

Merci !

68tjs

Je ne suis pas sur de tout bien comprendre, comme j'ai rappelé  en programmation je suis débutant++ mais pas du tout spécialiste.
Note : Il  existe aussi l'instruction "break" pour sortir prématurément d'une boucle -> voir des tutos pour plus de précision, je ne l'ai pratiquée que dans des boucles "switch".
Bien évidement tant qu'une boucle n'est pas controlée par l'état du fanion elle peut s'exécuter librement, de même la variable "fanion" peut être utilisée dans autant de boucle que tu souhaite et tu peux avoir autant de fanions différents que tu veux.

Quote
Et dans cette boucle, je met une boucle tout à la fin "if (position > 2000) {fanion=0}", ou alors le "attachInterrup" s'en occupe seul lorsque je le définit ?
Situ te contente de :
Quote
je met une boucle tout à la fin "if (position > 2000) {fanion=0}"
Oui cela fontionnera sauf s'il y a urgence et que ta boucle est lente., mais il n'y a que toi qui connait la réponse.
Dans ce cas il sera préférable d'utiliser une interruption plus rapide.
As tu des contacts fin de course en sécurité ?

Quote
ou alors le "attachInterrup" s'en occupe seul lorsque je le définit ?
Oui il fera cela. Regarde des exemples, soit ceux qui sont fournis avec l'IDE, soit ceux qui sont sur le playground, soit simplement sur internet, c'est le meilleur moyen pour comprendre.
L'autre meilleur moyen pour comprendre des nouveaux concepts c'est de faire des tous petits programmes qui ne font qu'une seule chose. Une fois le nouveau concept maîtrisé on peut  l'intégrer dans un programme complexe.

Julo

D'accord, je retiens donc l'utilité du fanion. Ca peut me servir. J'aurai en tout deux boucles, une pour positionner mon chariot au centre de sa course, une pour faire tenir mon pendule à la verticale. Donc une fois que mon chariot est au centre, je n'ai plus besoin de rentrer dans cette boucle (qui sera en principe un PID pour se mettre précisément au centre). Et j'utiliserai un "while(1);" pour stopper mon programme s'il y a une mise en butée lors de l'asservissement angulaire (donc de la deuxième boucle)

As tu des contacts fin de course en sécurité ?
Des contacts mécanique c'est bien cela ? J'ai des butées, c'est comme si le chariot de mon imprimante se baladait entre deux murs. Et j'aimerai éviter qu'il continue d'accélérer dans le "mur", c'est pour cela que je veux sortir de la boucle lorsqu'il entre en butée

Go Up