Go Down

Topic: Projet Led haute puissance avec recepteur de modelisme (Read 5358 times) previous topic - next topic

bypbop

Bonjour à tous, je réalise un petit projet en vue d'equiper un avion de modelisme. Je pilote 2 leds haute puissance 10w
Je réalise un strobe. Voila j'utilise une arduino nano et je mesure via l'entrée D4 la valeur renvoyé par mon recepteur RC pour changer de programme.

Mon probleme est que le changement de programme est assez aléatoire vu que la boucle de mon programme doit se terminer.
Parfois je saute un programme aussi ...
Comment je pourrais faire pour que le changement de programme soit instantanée ?
Mon programme.

Code: [Select]



int ledGreen = 11;
int ledBlue = 9;
int ledRed = 10;
int ledWhite = 5;
int rcreceiver;
int Prog;




void setup() {
  Serial.begin(9600);
  pinMode(ledGreen, OUTPUT);     
  pinMode(ledBlue, OUTPUT);
  pinMode(ledRed, OUTPUT);
 
  pinMode(ledWhite, OUTPUT);
 
  pinMode(4, INPUT);
 
  Prog=1;

}

int strobe(int fadeRed, int fadeGreen, int fadeBlue)
{
  analogWrite(ledWhite, 255);
  delay(50);
  analogWrite(ledWhite, 0);
  delay(100);
  analogWrite(ledWhite, 255);
  delay(50);
  analogWrite(ledWhite, 0);
  delay(100);
  analogWrite(ledWhite, 255);
  delay(50);
  analogWrite(ledWhite, 0);
  delay(100);
  analogWrite(ledWhite, 255);
  delay(50);
  analogWrite(ledWhite, 0);
  analogWrite(ledRed, fadeRed);
  analogWrite(ledGreen, fadeGreen);
  analogWrite(ledBlue, fadeBlue);
 
  delay(600);
  analogWrite(ledRed, 0);
  analogWrite(ledGreen, 0);
  analogWrite(ledBlue, 0);

}


void loop() {

if (Prog==1)
{
strobe(127,0,0);
  strobe(127,255,0);
  strobe(0,255,0);
  strobe(0,255,255);
  strobe(0,0,255);
  strobe(127,0,255);
  strobe(127,255,255);
}
   

if (Prog==2)
{
  strobe(0,255,0);   
   
   
}
if (Prog==3)
{
strobe(127,0,0);

}
if (Prog==4)
{
analogWrite(ledWhite, 0);
  analogWrite(ledRed, 0);
  analogWrite(ledGreen, 0);
  analogWrite(ledBlue, 0);

}
rcreceiver = pulseIn(4, HIGH, 25000);
if (rcreceiver <=1200)
{
Prog++;
delay(100);
if (Prog >4) Prog=1;
}
if (rcreceiver <=800)
{
Prog=4;
}
}



Cordialement,
bypbop

skywodd

Bonjour,

Si je comprend bien tu veux pouvoir changer de programme pendant qu'un autre est en cours ?
Si oui il va falloir revoir tout ton programme en non-bloquant (sans delay, ni pulseIn), ou utiliser une RTOS pour avoir deux taches en pseudo-parallèle.
Des news, des tutos et plein de bonnes choses sur http://skyduino.wordpress.com !

B@tto

#2
Oct 02, 2014, 11:39 am Last Edit: Oct 02, 2014, 11:41 am by B@tto Reason: 1
Salut,

Je te conseille de zieuter du côté des interruptions : http://www.laboelectronique.be/ardinterrupt.html
Ca te permettra de te passer de pulseIn.

Sinon pour la" lenteur" c'est parce que tu utilise des delay() forcement bloquant. Il faut utiliser millis() pour faire quelque chose de réactif http://battomicro.wordpress.com/2013/06/07/tutorial-les-interruptions-temporelles-avec-arduino/

Il suffit de scruter millis() et de gérer des étapes. Ta première partie de strobe() pourrais se résumer par :

Code: [Select]

#define ledWhite 5

unsigned long top,delai;

void setup() {

pinMode(ledWhite, OUTPUT);
top = millis();
analogWrite(ledWhite, 255);
delai=50

}

void loop() {

if((top+delai)<=millis()) {

top=millis();

if (delai==50) {
delai=100;
analogWrite(ledWhite,0);
}
else {
analogWrite(ledWhite, 255);
delai=50;
}

}
Blog électronique : battomicro.wordpress.com
Photographie : www.interactive-celebration.fr
Fablab de Montpellier : www.labsud.org

skywodd

B@tto : tu remplaces pas pulseIn par une interruption ;)
Ou alors ça veut dire que tu vas utiliser millis()/micros() derrière pour traiter le signal ce qui est ... ultra chiant (cf code de réception pour les modules blyss d'il y a quelques temps) et peu précis si le signal de contrôle est court.

Pour remplacer le pulseIn bloquant par un équivalent non bloquant il faut détourner un timer (Timer2 par exemple) pour le faire fonctionner en compteur avec la broche ICP (input capture pin) correspondante.
Voir http://www.atmel.com/images/doc8014.pdf pour les détails d'implémentation.

Ainsi à chaque front du signal de contrôle, une interruption avec la longueur du front est générée. Dans l'interruption il faudra refaire le filtrage du code d'origine pour changer le n° de programme.
Dans le code de loop() il faudra refaire la gestion des programmes en non bloquant avec millis() et des tests en fonction de chaque programme possible (c'est long mais c'est plus simple que d'utiliser un RTOS ou de faire un planificateur).
Des news, des tutos et plein de bonnes choses sur http://skyduino.wordpress.com !

B@tto


B@tto : tu remplaces pas pulseIn par une interruption ;)
Ou alors ça veut dire que tu vas utiliser millis()/micros() derrière pour traiter le signal ce qui est ... ultra chiant (cf code de réception pour les modules blyss d'il y a quelques temps) et peu précis si le signal de contrôle est court.


Faire deux relevé de micros() = ultra chiant ?! On m'avait dit que les programmeur était des fainéants mais la :D

La on parle de remplacer un pulseIn(), pas de décoder une trame. Et le signal sera de l'ordre de la ms, largement compatible avec micros().

Code: [Select]
volatile byte flag=0;
volatile unsigned long time,result;

void setup() {
attachInterrupt(4,pulse,RISING);
}

void pulse() {

detachInterrupt(4);

if(flag) {

result=micros()-time;
faitCeQueTuVeuxAvecResult();
attachInterrupt(4,pulse,RISING);

}else {

time=micros();
attachInterrupt(4,pulse,FALLING);
}

flag=!flag;

}

void loop() {}

Blog électronique : battomicro.wordpress.com
Photographie : www.interactive-celebration.fr
Fablab de Montpellier : www.labsud.org

john_lenfr

Je pense que tu devrais aller jeter un œil ici:

http://johnlenfr.1s.fr/index.php?option=com_rokdownloads&view=folder&Itemid=122&id=1002:pwmled
http://johnlenfr.1s.fr/index.php?option=com_content&view=article&id=470:telemetrie-graupner-lipometre11&catid=59:lipometre-hott&Itemid=110

Là:
http://sylvainreynaud.blogspot.fr/2012/10/high-power-leds-sur-dji-f550.html

et là:
http://johnlenfr.1s.fr/index.php?option=com_content&view=article&id=507:dji-f550-flame-wheel-montage-leds-mod&catid=67:dji-f550-flame-wheel-quadcopter&Itemid=117

;)

john_lenfr

J'ai oublié ici:

http://www.youtube.com/watch?v=kG8JeDN8_mA

Tu peux demander le code à Unisev, je sais qu'il traine par ici aussi. A voir avec lui s'il serait d'accord pour t'envoyer un code.
Et après faut être capable de le comprendre...

bypbop

#7
Oct 03, 2014, 10:02 am Last Edit: Oct 03, 2014, 10:25 am by bypbop Reason: 1
Merci pour vos messages je regarde tout j'avais essayé avec une interruption aussi et j 'avais le mm probleme.
Donc je vais regarder dans un premier tps m occuper des programmes dans la boucle loop.

je reviens vers vous ...

Cordialement,
bypbop

bypbop

Re bonjour à tous cela fait drole de penser sequentiel et ensuite penser pseudo multitache ...

J essaye depuis debut d aprés midi a faire une petite sequence allumer une led et puis l autre en utilisant millis() et je n arrive pas ...
Enfin avec une oui je comprends mais deux .... no comment ... Mais c est normal faut que cela rentre !!!

Alors j'ai fait ceci ... d'aprés le post de b@tto

Je verrais par la suite l'interruption ...


Code: [Select]

int ledWhite = 5;
int ledGreen = 11;
int ledRed = 10;


int led = 1;

unsigned long top,delai;


void setup() {
    Serial.begin(9600);
    pinMode(ledRed, OUTPUT);
    pinMode(ledGreen, OUTPUT); 
    pinMode(ledWhite,OUTPUT);

    top = millis(); // Enregistrement de mon point de départ

   delai=100;

}


void loop() {

if((top+delai)<=millis()) {
top=millis();
  if (led==1){

    if (delai==50) {
    delai=100;
     
    analogWrite(ledWhite,0);
    analogWrite(ledGreen,0);
    }
    else {
    analogWrite(ledWhite, 255);
    analogWrite(ledGreen,0);
    delai=50;
    }

  led=2;
  }
  if (led==2){


   
    if (delai==50) {
    delai=100;
    analogWrite(ledGreen,0);
    analogWrite(ledWhite,0);
    }
    else {
    analogWrite(ledGreen, 255);
    analogWrite(ledWhite,0);
    delai=50;
    }
  led=1;
  }
}
}



et le resultat est catastrophique lol je n'arrive pas trop a comprendre pourquoi !!!

Cordialement;
bypbop

jean-I

dans
if (led==1)
tu passe
led=2
et ensuite tu test si led==2, ce qui est forcement vrai.

ce que tu cherche a faire, c'est un genre de sequenceur?
tu peut t'inspirer de ca, le code est non-bloquant:

Code: [Select]

int ledWhite = 5;
int ledGreen = 11;
int ledRed = 10;


int led = 1;

int tache=0;  // equivalent de ta variable led
boolean tacheDone=false;  // indique si la tache a été executé ou pas encore

unsigned long top,delai;


void setup() {
    Serial.begin(9600);
    pinMode(ledRed, OUTPUT);
    pinMode(ledGreen, OUTPUT); 
    pinMode(ledWhite,OUTPUT);

    top = millis(); // Enregistrement de mon point de départ

   delai=100;

}

void loop() {

// gestionnaire du sequenceur de taches
  if((top+delai)<=millis()) {
    tache +=1;
    if (tache>3){tache=0;}
    // a chaque chagement du sequenceur, on met reinit tacheDone et le temps de la tache
    // c'est dans la tache qu'on defini son timing (bof, c'est ce que tu veux, donc ca ira)
    tacheDone == false;
    top=millis();
  }
 
// sequenceur de taches
  if (tacheDone == false){
    if (tache == 0) {
      analogWrite(ledWhite,0);
      analogWrite(ledGreen,0);
      delai=100;
      tacheDone =true;
    }
    if (tache == 1) {
      analogWrite(ledWhite, 255);
      analogWrite(ledGreen,0);
      delai=50;
      tacheDone =true;
    }
    if (tache == 2) {
      analogWrite(ledGreen,0);
      analogWrite(ledWhite,0);
      delai=50;
      tacheDone =true;
    }
    if (tache == 3) {
      analogWrite(ledGreen, 255);
      analogWrite(ledWhite,0);
      delai=50;
      tacheDone =true;
      }

  }
}

bypbop

#10
Oct 06, 2014, 07:24 pm Last Edit: Oct 06, 2014, 07:27 pm by bypbop Reason: 1
Merci jean-l, je comprends mieux maintenant !!

Dans le void set up il y a avait juste une petite erreur dans ton code : j'ai remplacé  tacheDone == false par tacheDone = false; surement une faute de frappe ;-)


Le code marche parfaitement mais je me pose une petite question maintenant ! Comme je vais coder plusier programme vu que j'ai une led blanche et une autre RGB !! le codage des sequence va etre surement trés long en ligne ....

Est ce que je pourrais faire la mm chose en codant un tableau du genre :

LEDBLANCHEPWM 0
LEDRGBBLEU 0
LEDRGBROUGE 0
LEDRGBVERT 0
DELAI 50

et boucler dessus avec le delai dans le millis ?? comme cela je pourais definir mes programmes séparément du loop()

Cordialement,
bypbop


jean-I

faute de frappe, je l'ai fait a l'aveugle.

non, tu n'as pas la bonne methode.
ce qu'il te faut (par exemple) c'est un tableau qui definisse tes sequences/durées.

Code: [Select]

//struct = delai, LEDBLANCHEPWM, LEDRGBBLEU, LEDRGBROUGE, LEDRGBVERT
int sequences[10][5]={
{5000, 100, 10, 20, 0,}, //seq0
{4000, 255, 255, 80, 70,}, //seq1
{3000, 0, 100, 20, 30,}, //seq2
{2000, 0, 0, 0, 0,}, //seq3
{1000, 0, 0, 0, 0,}, //seq4
{500, 0, 0, 0, 0,}, //seq5
{5000, 0, 0, 0, 0,}, //seq6
{2000, 0, 0, 0, 0,}, //seq7
{2000, 0, 0, 0, 0,}, //seq8
{5000, 0, 0, 0, 0,}, //seq9
};


ensuite tu parcours tes 10 sequences

Code: [Select]

// gestionnaire du sequenceur de taches
  if((top+delai)<=millis()) {
    tache +=1;
    if (tache>9){tache=0;}
    // a chaque chagement du sequenceur, on met reinit tacheDone et le temps de la tache
    // c'est dans la tache qu'on defini son timing (bof, c'est ce que tu veux, donc ca ira)
    tacheDone == false;
    top=millis();
    delai=sequences[tache][0];  // delai peut etre geré ici ou dans tache
  }

// sequenceur de taches
  if (tacheDone == false){
      analogWrite(ledWhite,sequences[tache][1]);
      analogWrite(ledRed,sequences[tache][2]);
      analogWrite(ledBlue,sequences[tache][3]);
      analogWrite(ledGreen,sequences[tache][4]);
      //delai=sequences[[tache][0];
      tacheDone =true;
    }


c'est tout

bypbop

Magnifique !!! cela fonctionne parfaitement demain je planche sur l'interruption et le changement de programme ;-)

Encore Merci Jean-l

Code: [Select]

int ledWhite = 5;
int ledGreen = 11;
int ledRed = 10;
int ledBlue= 9;

int Sequence[10][5] = {
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 128  , 0 , 0  , 100},
};


int tache=0;  // equivalent de ta variable led
boolean tacheDone=false;  // indique si la tache a été executé ou pas encore

unsigned long top,delai;


void setup() {
    Serial.begin(9600);
    pinMode(ledRed, OUTPUT);
    pinMode(ledGreen, OUTPUT); 
    pinMode(ledWhite,OUTPUT);

    top = millis(); // Enregistrement de mon point de départ


}

void loop() {

// gestionnaire du sequenceur de taches
  if((top+delai)<=millis()) {
    tache +=1;
    if (tache > 9){tache=0;}
    // a chaque chagement du sequenceur, on met reinit tacheDone et le temps de la tache
    // c'est dans la tache qu'on defini son timing (bof, c'est ce que tu veux, donc ca ira)
    tacheDone = false;
    top=millis();
  }
 
// sequenceur de taches
  if (tacheDone == false){
      analogWrite(ledWhite,Sequence[tache][0]);
      analogWrite(ledRed,Sequence[tache][1]);
      analogWrite(ledGreen,Sequence[tache][2]);
      analogWrite(ledBlue,Sequence[tache][3]);
      delai=Sequence[tache][4];
      tacheDone =true;

}
}



Cordialement,
bypbop

bypbop

Par contre j'ai essayé de faire une petite modif pour ajouter des sequences et connaitre la taille du tableau en faisant ceci

Code: [Select]

int Sequence[][5] = {
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0 , 0  , 50},
{0, 0  , 0 , 0  , 200},
{255, 0  , 0, 0  , 50},
{0, 0  , 255, 0  , 300},
{0, 128  , 0 , 0  , 300},
{0, 0  , 0 , 255  , 300},
};

et ceci : if (tache > siseof(Sequence)){tache=0;}


et cela ne fonctionne pas ??





jean-I

en memoire, ta sequence est une suite de int.
un int prend 2 octet.
sizeof renvoi l'occupation memoire du tableau en octet.
10*5*2=100.

donc
if (tache > (siseof(Sequence)/10)-1){tache=0;}  // /10 parce que 5*2=10, et -1 parce qu'on part de zero

Go Up