Go Down

Topic: [RESOLU] Lisser mes valeurs lues en PPM (Read 1 time) previous topic - next topic

UniseV

Feb 20, 2013, 12:17 pm Last Edit: Feb 24, 2013, 07:55 pm by UniseV Reason: 1
Bonjour,

Je lis un signal PPM grâce l'INPUT CAPTURE PIN de l'Atmega 328P.

Pour ceux que n'imagine pas ce qu'est un signal PPM, voici un exemple trouvé sur le net :


Dans mon cas j'ai 6 canaux, voici ma sortie COM de DEBUG :



En rouge se sont les valeurs calculées des 6 canaux (ce sont des demi micro-secondes, 2000 vaut donc 1ms)

En vert ce sont des valeurs mappées comme suit, à partir des canaux 2,3 & 6 et qui servent à allumer une LED RVB.
Code: [Select]
   R=map(cha[1],1960,3960,0,255);
   V=map(cha[2],1960,3960,0,255);
   B=map(cha[3],1960,3960,0,255);

En Orange, ce sont les "jitters" qui me posent problème.
Ma question :
Comment "lisser" ces valeurs ?

PS : Le code complet dans le message suivant...
EN: Libraries are my Gurus, they make me believe anything they want !
FR: Les librairies sont mes gourous, elles me font croire ce qu'elles veulent !

UniseV

#1
Feb 20, 2013, 12:18 pm Last Edit: Feb 20, 2013, 12:22 pm by UniseV Reason: 1
Le code :

Code: [Select]
// Lecture PPM6ch & pilotage LED RVB
// C'est le timer1 qui est utilisé la lecture du PPM

#define ledRouge 3 // Constante pour la broche 3
#define ledVert 5 // Constante pour la broche 5
#define ledBleu 6 // Constante pour la broche 6
#define ledPin 13 // Pin de la LED "locale" de l'Arduino


// Données de capture du Rx
boolean endTrame=0,failsafe=0,firstEdge=1;
volatile unsigned int vchUp[8];
volatile unsigned int vchPos[6];
unsigned int cha[6];
byte curEdge;

// Valeurs RVB
int R,V,B;

// Variables permettant de faire clignoter la led de l'Arduino
int ledState = LOW;
long previousMillis = 0;
long interval = 500;

void setup()
{
 // Pin setup, parmetrage des PIN en sortie :
 pinMode (ledVert,OUTPUT); // Broche ledVert configurée en sortie
 pinMode (ledRouge,OUTPUT); // Broche ledRouge configurée en sortie
 pinMode (ledBleu,OUTPUT); // Broche ledBleu configurée en sortie
 pinMode(ledPin,OUTPUT); // Arduino LED

 digitalWrite(ledPin,HIGH); // Allumage de la LED de l'Arduino

 // Sortie DEBUG
 Serial.begin(57600);
 Serial.println("");
 Serial.println("PPM read & Led RVB");
 // Timer1 setup
 TCCR1A=B00000000; // OCR2A/OCR2B : disconnected, Timer: normal mode
 TCCR1B=B00000010; // Falling edge CAPTUREPIN detection, Timer:normal mode, Prescaler=clk/8
 TIMSK1=B00100001; // Activate CAPTUREPIN interrupt & OVF interrupt

 delay(1000); // pour etre certain que les interruptions aient tourné avant la main loop

}

ISR(TIMER1_CAPT_vect)
{
 vchUp[curEdge]=ICR1; // Capture des timestamp 1 à 6
 curEdge++;
 if (curEdge>7) {     // A partie du 7ème...  
   TCNT1=0;           // RESET du counter pour éviter le FailSafe
   if ((vchUp[7]-vchUp[1]) > 30000) {  //Si la trame totale dépasse 15ms - Trame KO ou mauvaise synchro
     curEdge=0;            //Remise à 0 du compteur de fronts                      
   }
   else {                  //Sinon, une bonne trame est capturée, on calcule donc la valeur des canaux
     curEdge=1;
     for (int i=0;i<6;i++) {
       vchPos[i]=(vchUp[i+2]-vchUp[i+1]); //Mesure des canaux (diviser par 2 pour obtenir des µs)
     }
     endTrame=1;           // Pour dire à la MainLoop que de nouvelles valeurs sont disponibles
   }
 }
}

ISR(TIMER1_OVF_vect)
{
 failsafe=1;  // Le compteur a attends sa limite (32ms), on déclenche donc le FailSafe
}

void loop()
{
 if (endTrame==1) {
   cli();
   for (int i=0;i<6;i++) {
     cha[i]=vchPos[i]; // Recopie les valeurs des canaux
   }
   sei();
   endTrame=0;
   LedBlink(500);
   if (failsafe){
     failsafe=0;
     Serial.println("End of FailSafe");
   }

   // La 1ere partie "intelligente" du code se trouve ICI
   // Elle n'est jouée que si les canaux ont "bougé"

   for (int i=0; i < 6; i++){ // Imprimer les valeurs des canaux sur le port série
     Serial.print(cha[i]);
     Serial.print(";");
   }

   // Mapper trois canaux vers les couleurs RVB

   R=map(cha[1],1960,3960,0,255);
   V=map(cha[2],1960,3960,0,255);
   B=map(cha[3],1960,3960,0,255);

   ledRVBpwm(R,V,B); // génère impulsion largeur voulue pour la couleur

   // Imprimer les valauers de la LED

   Serial.print(R);
   Serial.print(";");
   Serial.print(V);
   Serial.print(";");
   Serial.print(B);
   Serial.println(";");
 }

 // La 2eme partie "intelligente" du code se trouve ICI
 // Elle est jouée à chaque tour de boucle

 if (failsafe){

   if (R>255) R=0;    // En mode FAILSAFE, on fait varier les 3 couleurs progressivement & simultanément
   else R++;
   if (V>255) V=0;
   else V++;
   if (B>255) B=0;
   else B++;


   ledRVBpwm(R,V,B); // génère impulsion largeur voulue pour la couleur
   Serial.print("FAILSAFE");
   LedBlink(50);
   Serial.print(R);
   Serial.print(";");
   Serial.print(V);
   Serial.print(";");
   Serial.print(B);
   Serial.println(";");
 }
}


void ledRVBpwm(int pwmRouge, int pwmVert, int pwmBleu) { // reçoit valeur 0-255 par couleur

 //--- attention - avec une LED RGB anode commune : la LED s'allume sur niveau BAS !

 analogWrite(ledRouge, 255-pwmRouge); // impulsion largeur voulue sur la broche 0 = 0% et 255 = 100% haut
 analogWrite(ledVert, 255-pwmVert); // impulsion largeur voulue sur la broche 0 = 0% et 255 = 100% haut
 analogWrite(ledBleu, 255-pwmBleu); // impulsion largeur voulue sur la broche 0 = 0% et 255 = 100% haut


}

void LedBlink(long interval) { // reçoit délais de clignotement

 unsigned long currentMillis = millis();

 if(currentMillis - previousMillis > interval) {
   // save the last time you blinked the LED
   previousMillis = currentMillis;  

   // if the LED is off turn it on and vice-versa:
   if (ledState == LOW)
     ledState = HIGH;
   else
     ledState = LOW;

   // set the LED with the ledState of the variable:
   digitalWrite(ledPin, ledState);
 }
}


EDIT : Le mode FAILSAFE indique que le signal PPM en entrée n'est plus fourni...
EN: Libraries are my Gurus, they make me believe anything they want !
FR: Les librairies sont mes gourous, elles me font croire ce qu'elles veulent !

Jean-François

PPM, c'est le principe des signaux pour les servos de modelisme non ?
MacBook intel core 2 duo  os X snow Leopard 10.6
 eMac PPc G4  os X Leopard 10.5
powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

fdufnews

#3
Feb 20, 2013, 01:11 pm Last Edit: Feb 20, 2013, 01:22 pm by fdufnews Reason: 1
Quote
Comment "lisser" ces valeurs ?

Filtrage sur une fenêtre glissante
on fait un tableau avec les n dernières valeurs et on calcule la moyenne sur ces valeurs.

ou alors un filtre récursif
  valeur = nouvelle_valeur*p + valeur*(1-p)
0 < p < 1
on joue sur p pour fixer le temps de réaction du filtre. Plus p est petit plus lente sera la réaction à une variation sur la nouvelle valeur.

Artouste


Quote
Comment "lisser" ces valeurs ?

Filtrage sur une fenêtre glissante
on fait un tableau avec les n dernières valeurs et on calcule la moyenne sur ces valeurs.

ou alors un filtre récursif
  valeur = nouvelle_valeur*p + valeur*(1-p)
0 < p < 1
on joue sur p pour fixer le temps de réaction du filtre. Plus p est petit plus lente sera la réaction à une variation sur la nouvelle valeur.

bonjour fdufnews
pas mieux et le recursif simple ici est surement la meilleure méthode sur arduino.
je n'arrive pas a remettre la main sur la vieille étude qui concluait statistiquement que P=0.85 (0.15)  était le meilleur compromis
C'est ce que j'utilise "tout venant"

Go Up