Multi Wii et SoftwareSerial pour un drone arduino

Portrait de Azerty2289

Bonjour a tous

J'aurais besoin d'un avis externe car certains comportement de ma carte arduino me laisse perplexe...

Je construit actuellement un drone avec multiwi sur une carte nano qui tourne et gère les 4 moteurs. Les commandes sont envoyée par une autre carte nano par un signal PPM sur la broche 2. Cette carte reçois les informations (Throttle, Yaw,Pitch,Roll,Aux1 et Aux2) par un module H-12 depuis la télécommande.

Joystick => Arduino UNO => HC 12 (par les ondes) HC 12 =>  Arduino nano =>(via PPM) arduino nano (avec multiwii)

La chaîne d'information fonctionne bien sauf que il y a un petit problème : les signaux générer par la carte nano sont reconnu par multiWii ( je vois varier les valeurs sur le logiciel ) mais il y a des instabilité. Les valeur font des "sauts" et varie entre 1600 et 1400 aléatoirement  au lieu de reste a 1500 par exemple ce qui rendra le drone instable.

Après beaucoup de recherche jai trouve la source du problème : la bibliothèque SoftwareSerial (qui sert a communiquer avec le HC 12) utilise des interruptions pour fonctionner et les signaux PPM générer par le code que je vous fourni en dessous sont alors instable. En augmentant le baudrate de communication a 115200 bauds ( le maximum avec le HC 12 ) , les valeurs sont plus stable mais cela ne fixe pas totalement le problème. Auriez ne serait ce qu'une piste ou une idée de comment fixer cela car je bloque depuis maintenant 2 semaines.

Voici le code :

#include <SoftwareSerial.h>
SoftwareSerial HC12(10, 11);
#define channel_number 6  //set the number of channels
#define sigPin 2  //set PPM signal output pin on the arduino
#define PPM_FrLen 27000 
#define PPM_PulseLen 400  //set the pulse length
//////////////////////////////////////////////////////////////////

int ppm[channel_number];

struct MyData {
  byte throttle;
  byte yaw;
  byte pitch;
  byte roll;
  byte AUX1;
  byte AUX2;
};

MyData data;

void resetData()
{
  // 'safe' values to use when no radio input is detected
  data.throttle = 0;
  data.yaw = 127;
  data.pitch = 127;
  data.roll = 127;
  data.AUX1 = 0;
  data.AUX2= 0;
 
  setPPMValuesFromData();
}

void setPPMValuesFromData()
{
  ppm[0] = map(data.throttle, 0, 255, 1000, 2000);
  ppm[1] = map(data.yaw,      0, 255, 1000, 2000);
  ppm[2] = map(data.pitch,    0, 255, 1000, 2000);
  ppm[3] = map(data.roll,     0, 255, 1000, 2000);
  ppm[4] = map(data.AUX1,    1, 0, 1000, 2000);
  ppm[5] = map(data.AUX2,     1, 0, 1000, 2000);  
  }

/**************************************************/

void setupPPM() {
  pinMode(sigPin, OUTPUT);
  digitalWrite(sigPin, 0); 

  cli();
  TCCR1A = 0;
  TCCR1B = 0;

  OCR1A = 100; 
  TCCR1B |= (1 << WGM12);  // turn on CTC mode
  TCCR1B |= (1 << CS11);  // 8 prescaler: 0,5 microseconds at 16mhz
  TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
  sei();
}

void setup()
{  
  resetData();
  setupPPM();
  HC12.begin(115200);
  Serial.begin(115200);
}
void loop()
{
  if (HC12.available()) {
    data.AUX1 = HC12.read(); while (!HC12.available()) {}
    data.throttle = HC12.read(); while (!HC12.available()) {}
    data.roll = HC12.read(); while (!HC12.available()) {}
    data.pitch = HC12.read(); while (!HC12.available()) {}
    data.yaw = HC12.read(); while (!HC12.available()) {}
    data.AUX2 = HC12.read(); while (!HC12.available()) {}
 

    Serial.println("eee");
    Serial.println(data.throttle);
    Serial.println(data.yaw);
    Serial.println(data.pitch);
    Serial.println(data.roll);
    Serial.println(data.AUX1);
    Serial.println(data.AUX2);
  }
  setPPMValuesFromData();
}

/**************************************************/

#define clockMultiplier 2

ISR(TIMER1_COMPA_vect){
  static boolean state = true;

  TCNT1 = 0;

  if ( state ) {
    //end pulse
    PORTD = PORTD & ~B00000100;
    OCR1A = PPM_PulseLen * clockMultiplier;
    state = false;
  }
  else {
    //start pulse
    static byte cur_chan_numb;
    static unsigned int calc_rest;

    PORTD = PORTD | B00000100; // turn pin 2 on. Could also use: digitalWrite(sigPin,1)
    state = true;

    if(cur_chan_numb >= channel_number) {
      cur_chan_numb = 0;
      calc_rest += PPM_PulseLen;
      OCR1A = (PPM_FrLen - calc_rest) * clockMultiplier;
      calc_rest = 0;
    }
    else {
      OCR1A = (ppm[cur_chan_numb] - PPM_PulseLen) * clockMultiplier;
      calc_rest += ppm[cur_chan_numb];
      cur_chan_numb++;
    }     
  }
}

Portrait de brossden

Bonjour

Je n'y connais strictement rien aux drônes coté programmation mais pourquoi utiliser une librairie externe pour les ports Séries ?

De plus avant de lire dans le buffer en ajoutant une petite tempo aurais tu le même soucis ?

Si Serial te sers uniquement pour la console série Arduino monte la ! ( "Serial.begin(1000000);")

J'ai modifié ton programme tu le trouveras ci-dessous !

    //#include <SoftwareSerial.h>
    //SoftwareSerial HC12(10, 11);
    #define channel_number 6  //set the number of channels
    #define sigPin 2  //set PPM signal output pin on the arduino
    #define PPM_FrLen 27000
    #define PPM_PulseLen 400  //set the pulse length
    //////////////////////////////////////////////////////////////////

    int ppm[channel_number];

    struct MyData {
      byte throttle;
      byte yaw;
      byte pitch;
      byte roll;
      byte AUX1;
      byte AUX2;
    };

    MyData data;

    void resetData()
    {
      // 'safe' values to use when no radio input is detected
      data.throttle = 0;
      data.yaw = 127;
      data.pitch = 127;
      data.roll = 127;
      data.AUX1 = 0;
      data.AUX2= 0;
     
      setPPMValuesFromData();
    }

    void setPPMValuesFromData()
    {
      ppm[0] = map(data.throttle, 0, 255, 1000, 2000);
      ppm[1] = map(data.yaw,      0, 255, 1000, 2000);
      ppm[2] = map(data.pitch,    0, 255, 1000, 2000);
      ppm[3] = map(data.roll,     0, 255, 1000, 2000);
      ppm[4] = map(data.AUX1,    1, 0, 1000, 2000);
      ppm[5] = map(data.AUX2,     1, 0, 1000, 2000);  
      }

    /**************************************************/

    void setupPPM() {
      pinMode(sigPin, OUTPUT);
      digitalWrite(sigPin, 0);

      cli();
      TCCR1A = 0;
      TCCR1B = 0;

      OCR1A = 100;
      TCCR1B |= (1 << WGM12);  // turn on CTC mode
      TCCR1B |= (1 << CS11);  // 8 prescaler: 0,5 microseconds at 16mhz
      TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
      sei();
    }

    void setup()
    {  
      resetData();
      setupPPM();
      Serial1.begin(115200);
      Serial.begin(115200); // Tester ; Serial.begin(1000000); voir même 2000000
    }
    void loop()
    {
      if (Serial1.available()) {
        delay(10);
        data.AUX1 = Serial1.read(); while (!Serial1.available()) {}
        data.throttle = Serial1.read(); while (!Serial1.available()) {}
        data.roll = Serial1.read(); while (!Serial1.available()) {}
        data.pitch = Serial1.read(); while (!Serial1.available()) {}
        data.yaw = Serial1.read(); while (!Serial1.available()) {}
        data.AUX2 = Serial1.read(); while (!Serial1.available()) {}
     

        Serial.println("eee");
        Serial.println(data.throttle);
        Serial.println(data.yaw);
        Serial.println(data.pitch);
        Serial.println(data.roll);
        Serial.println(data.AUX1);
        Serial.println(data.AUX2);
      }
      setPPMValuesFromData();
    }

    /**************************************************/

    #define clockMultiplier 2

    ISR(TIMER1_COMPA_vect){
      static boolean state = true;

      TCNT1 = 0;

      if ( state ) {
        //end pulse
        PORTD = PORTD & ~B00000100;
        OCR1A = PPM_PulseLen * clockMultiplier;
        state = false;
      }
      else {
        //start pulse
        static byte cur_chan_numb;
        static unsigned int calc_rest;

        PORTD = PORTD | B00000100; // turn pin 2 on. Could also use: digitalWrite(sigPin,1)
        state = true;

        if(cur_chan_numb >= channel_number) {
          cur_chan_numb = 0;
          calc_rest += PPM_PulseLen;
          OCR1A = (PPM_FrLen - calc_rest) * clockMultiplier;
          calc_rest = 0;
        }
        else {
          OCR1A = (ppm[cur_chan_numb] - PPM_PulseLen) * clockMultiplier;
          calc_rest += ppm[cur_chan_numb];
          cur_chan_numb++;
        }     
      }
    }

Portrait de Azerty2289

Me probleme est que le module HC12 ( qui menvoit les informations depuis la telecommande ) est limité a 115200 bauds et c'est lui qui fait beugé les signaux PPM. Jai testé en augmentant a 2000000 et ca ressous les problème mai c'est impossible avec ce module... La communication serie avec le port serie arduino me sert juste a voir les valeurs a l'écran et elle n'influence en rien les signaux.

Portrait de brossden

Qui te parle d'augmenter la vitesse de HC12 ?

Quand on demande une aide mieux vaux comprendre ce qui est écrit !

" Serial te sers uniquement pour la console série Arduino monte la ! ( "Serial.begin(1000000);") "

Portrait de Azerty2289

Tu na pas compris : cest le module HC12 quo fait beuge mes signaux, lorsque je genere des signaux sans avoir déclaré le Hc12 et sa biblioteque ( jenvoie des valeur fixe ) les valeur sont stable . Le serial moniteur na rien a voir la dedans, il le sert juste a avoir un oeil  sur mon programme. Tu t'énerve vite quand même.... 

Portrait de brossden

Il n'y a pire sourd que celui qui ne veut pas entendre !

Le fait de d'augmenter la vitesse de la console diminue le risque d'interférer sur le port série dédié au HC12 !

De plus je ne vois aucune bibliothèque pour le HC12 dans ton soft. Uniquement la bibliothèque multi-série !

Juste pour le Fun ast ut testé mon code ? (Car il y a d'autres modifs) ?

Portrait de Azerty2289

Jai déjà essayé et même de supprimer la communication avec le port serie car je pensé quelle prouvait influencer aussi les signaux mais ca ne change rien cest uniquement la liason avec le HC 12 qui faut beugé 

Portrait de brossden

J'aimerai tester la chaîne complète, te serait il possible de donner ici les trames qui transitent entre les deux HC12 ou mieux encore le code qui te permet de faire les essais et de trouver l'instabilité, la deuxième solution serait la plus judicieuse pour tenter de résoudre ton problème.

De plus tu utilise une interruption "ISR(...)" peut on en avoir l'utilité ?

Bonne et heureuse année à tous

Portrait de Azerty2289

Merci pour tes conseil je vais pour linstant me contenter dun autre module rado le nrf24l01 qui a une porte plus faible mais l'influence pas le signal. Je ferais des modifs avec le HC12 plus tard.