Pages: [1]   Go Down
Author Topic: [RESOLU] Lisser mes valeurs lues en PPM  (Read 1259 times)
0 Members and 1 Guest are viewing this topic.
Paris
Offline Offline
Sr. Member
****
Karma: 2
Posts: 366
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
   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...
« Last Edit: February 24, 2013, 01:55:26 pm by UniseV » Logged

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 !

Paris
Offline Offline
Sr. Member
****
Karma: 2
Posts: 366
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Le code :

Code:
// 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...
« Last Edit: February 20, 2013, 06:22:05 am by UniseV » Logged

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 !

Forum Moderator
Geneva
Offline Offline
Faraday Member
*****
Karma: 30
Posts: 3230
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

PPM, c'est le principe des signaux pour les servos de modelisme non ?
Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

France
Offline Offline
Faraday Member
**
Karma: 38
Posts: 3511
There is an Arduino for that
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
« Last Edit: February 20, 2013, 07:22:55 am by fdufnews » Logged

Offline Offline
Faraday Member
**
Karma: 33
Posts: 5045
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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"
Logged

Forum Moderator
Geneva
Offline Offline
Faraday Member
*****
Karma: 30
Posts: 3230
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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"

Le principe de Pareto
Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Paris
Offline Offline
Sr. Member
****
Karma: 2
Posts: 366
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

PPM, c'est le principe des signaux pour les servos de modelisme non ?

Oui, c'est le signal avant "dégroupage", le récepteur génère à partir de cette trame un signal PWM servo pour chacun des servo :



J'utilise une radio 6 voies comme "joystick" de DEBUG  smiley-wink

Merci pour vos réponses... je m'y plonge.
Logged

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 !

Paris
Offline Offline
Sr. Member
****
Karma: 2
Posts: 366
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Dans cet exemple, doit-on faire le calcul à chaque fois avec l'ancienne valeur CALCULEE et l'ancienne valeur LUE ?
Logged

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 !

Forum Moderator
Geneva
Offline Offline
Faraday Member
*****
Karma: 30
Posts: 3230
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Pas sur que ce soit celui dont parle fddunews :

http://arduino.cc/forum/index.php?topic=50134.0
Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

France
Offline Offline
Faraday Member
**
Karma: 38
Posts: 3511
There is an Arduino for that
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Si, si c'est bien la même chose
Logged

Forum Moderator
Geneva
Offline Offline
Faraday Member
*****
Karma: 30
Posts: 3230
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes....  smiley-lol
Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Paris
Offline Offline
Sr. Member
****
Karma: 2
Posts: 366
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Merci à tous !

Après différent essais avec Excel, j'ai finalement opté pour un solution plus "radicale".

Je ne prend en compte la nouvelle valeur mesurée que si elle dépasse un écart minimum.

Code:
int const ecart=3;    // C'est la valeur de l'hystérésis...

    for (int i=0;i<6;i++) {
      if (vchPos[i] > (cha[i]+ecart) || vchPos[i]< (cha[i]-ecart)) { // Si la nouvelle valeur dépasse l'hystérésis
      cha[i]=vchPos[i]; // Recopie les valeurs des canaux
      }

Ici c'est 3, ça représente 1,5 µs, ça ne bouge donc qu'à partir de 2µs d'écart, pour un servo ça laisse 500 pas, ça me parait correct.
Logged

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 !

Paris
Offline Offline
Sr. Member
****
Karma: 2
Posts: 366
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey,

Ca me donne une idée, cette fameuse lecture PPM, je l'utilise finalement assez souvent, et ça me fait faire pas mal de copier/coller de la reprendre à chaque fois.

Vous parait-il possible de la "librariser" ?

Ca serait ma première...  smiley-confuse
Logged

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 !

Paris
Offline Offline
Sr. Member
****
Karma: 2
Posts: 366
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Voici le code en question :

Code:
// Lecture PPM6ch par INPUT CAPTURE UNIT
// C'est le timer1 qui est utilisé pour la lecture du PPM
// La lecture du PPM ne peut se faire QUE sur la PIN 8 (ICP1)

boolean endTrame=0,failsafe=0,firstEdge=1;
volatile unsigned int vchUp[8];
volatile unsigned int vchPos[6];
unsigned int cha[6];
byte curEdge;
int const ecart=3;    // C'est la valeur de l'hystérésis...

void setup()
{
  // 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
}

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
}

On y retrouve dans l'ordre :
  • La déclaration des variable (dois-je les garder en volatile ?)
  • Le paramétrage du timer1
  • L'interruption sur ICP1
  • L'interruption sur overflow du timer1

C'est principalement ces parties que je souhaite "librariser"...
Logged

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 !

Paris
Offline Offline
Sr. Member
****
Karma: 2
Posts: 366
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

J'ouvre un nouveau sujet pour l'histoire de la librairie, ça sera plus clair  smiley-roll

Lisser les valeurs PPM est résolu.
« Last Edit: February 24, 2013, 01:57:07 pm by UniseV » Logged

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 !

Pages: [1]   Go Up
Jump to: