• Bonsoir, je me rends juste compte que les notifications des nouveaux messages étaient limitées aux membres actifs dans les 30 derniers jours. Donc, j'ai supprimé cette option. En espérant que vous aurez bien les notifications attendues. Merci pour votre patience. Yves

Construction Réglage/ Problème Quadcopter Arduino

GwenaelFr

Nouveau membre
Bonjour à tous,

Je suis actuellement en train de fabriquer un Quadcopter basé sur Arduino, avec pour le moment une simple stabilisation avec les gyroscopes (MPU6050). J'utilise des ESC HK SS 25-30

Je bloque au réglage des PID mais je ne sais pas pourquoi..

- les angles obtenus sont corrects
- les commandes de stabilisation sont correctes
- mais le drone reste impossible à stabiliser

Alors plusieurs hypothèses:
- les esc hk sont trop lent? normalement 400Hz donc çà devrait aller...
- mon code arduino est trop lent? la boucle se fait à 10Hz, ça semble bien lent..

Code:
#ifndef QUADARDU
#define QUADARDU

#include <Servo.h>
#include <Wire.h>
#include <I2Cdev.h>
#include <helper_3dmath.h>
#include <MPU6050_6Axis_MotionApps20.h>
#include <PID_v1.h>
#include <PinChangeInt.h>
#include <PinChangeIntConfig.h>



/*  Arduino Pin configuration
 *  
 */

#define ESC_A 26
#define ESC_B 22
#define ESC_C 28
#define ESC_D 24

#define RC_1 46
#define RC_2 44 
#define RC_3 42
#define RC_4 48
#define RC_5 8
#define RC_PWR A0


/* ESC configuration
 *
 */

#define ESC_MIN 20
#define ESC_MAX 120
#define ESC_TAKEOFF_OFFSET 0
#define ESC_ARM_DELAY 5000

/* RC configuration
 * 
 */

#define RC_HIGH_CH1 1000
#define RC_LOW_CH1 2000
#define RC_HIGH_CH2 1000
#define RC_LOW_CH2 2000
#define RC_HIGH_CH3 1000
#define RC_LOW_CH3 2000
#define RC_HIGH_CH4 1000
#define RC_LOW_CH4 2000
#define RC_HIGH_CH5 1000
#define RC_LOW_CH5 2000
#define RC_ROUNDING_BASE 50

/*  PID configuration
 *  
 */

#define PITCH_P_VAL 4
#define PITCH_I_VAL 0.01
#define PITCH_D_VAL 20

#define ROLL_P_VAL 4
#define ROLL_I_VAL 0.01
#define ROLL_D_VAL 20

#define YAW_P_VAL 0
#define YAW_I_VAL 0
#define YAW_D_VAL 0


/* Flight parameters
 *
 */

#define PITCH_MIN -30
#define PITCH_MAX 30
#define ROLL_MIN -30
#define ROLL_MAX 30
#define YAW_MIN -180
#define YAW_MAX 180
#define PID_PITCH_INFLUENCE 20
#define PID_ROLL_INFLUENCE 20
#define PID_YAW_INFLUENCE 20


/*  MPU variables
 *
 */

MPU6050 mpu;                           // mpu interface object


uint8_t mpuIntStatus;                  // mpu statusbyte
uint8_t devStatus;                     // device status    
uint16_t packetSize;                   // estimated packet size  
uint16_t fifoCount;                    // fifo buffer size   
uint8_t fifoBuffer[64];                // fifo buffer 

Quaternion q;                          // quaternion for mpu output
VectorFloat gravity;                   // gravity vector for ypr
float ypr[3] = {0.0f,0.0f,0.0f};       // yaw pitch roll values
float yprLast[3] = {0.0f, 0.0f, 0.0f};


volatile bool mpuInterrupt = false;    //interrupt flag

long temps;
 
boolean interruptLock = false;

float ch1, ch2, ch3, ch4, ch5;         // RC channel inputs


int heightOrder;
int pitchOrder;
int rollOrder;
int yawOrder;

float heightSensor;
float pitchSensor;
float rollSensor;
float yawSensor;

float heightSensorLast;
float pitchSensorLast;
float rollSensorLast;
float yawSensorLast;


int velocity;                          // global velocity

float bal_ac, bal_bd;                 // motor balances can vary between -100 & 100
float bal_axes;                       // throttle balance between axes -100:ac , +100:bd

int va, vb, vc, vd;                    //velocities
int v_ac, v_bd;                        // velocity of axes

Servo a,b,c,d;


PID pitchReg(&pitchSensor, &bal_bd, &ch2, PITCH_P_VAL, PITCH_I_VAL, PITCH_D_VAL, DIRECT);
PID rollReg(&rollSensor, &bal_ac, &ch1, ROLL_P_VAL, ROLL_I_VAL, ROLL_D_VAL, REVERSE);
PID yawReg(&yawSensor, &bal_axes, &ch4, YAW_P_VAL, YAW_I_VAL, YAW_D_VAL, DIRECT);
 
float ch1Last, ch2Last, ch4Last, velocityLast;

void setup(){
  
  //receptor init
  pinMode(47, OUTPUT);
  digitalWrite(47,HIGH);
  pinMode(42, INPUT);
  pinMode(44, INPUT);
  pinMode(46, INPUT);
  pinMode(48, INPUT);
  pinMode(52, INPUT);
  delay(2000);
  
  initMPU();
  initESCs();
  initBalancing();
  initRegulators();
  
  Serial.begin(115200);  
  Serial.println("Initialisation effectué");
  temps = millis();
  
}

/* loop function
 *
 */

void loop(){
  
  //heightOrder = map(pulseIn(42, HIGH, 25000),1000,2000,0,180);
  if (digitalRead(52) == HIGH) {
  if (heightOrder < 60) heightOrder = heightOrder + 1;
  if (heightOrder > 60) heightOrder = 60;
  Serial.println("En marche");
  }
  if (digitalRead(52) == LOW) {
  heightOrder = 20;
  Serial.println("A l'arret");
  }  
  pitchOrder = map(pulseIn(44, HIGH, 25000),1000,2000,-90,90);
  rollOrder = map(pulseIn(46, HIGH, 25000),1000,2000,-90,90);
  yawOrder = map(pulseIn(40, HIGH, 25000),1000,2000,-90,90);
  
  while(!mpuInterrupt && fifoCount < packetSize){
     
    /* Do nothing while MPU is not working
     * This should be a VERY short period
     */
      
  }
  
  getYPR();
//  Serial.print("pitchSensor = "); // Afficher les lectures Arduino
//  Serial.println(pitchSensor);
//  Serial.print("rollSensor = "); // Afficher les lectures Arduino
//  Serial.println(rollSensor);
//  Serial.print("yawSensor = "); // Afficher les lectures Arduino
//  Serial.println(yawSensor);
//  Serial.println(" ");
  computePID();
  calculateVelocities();
  updateMotors();
  Serial.println(millis()-temps);
  temps = millis();
  
}

/*  computePID function
 *
 *  formats data for use with PIDLib
 *  and computes PID output
 */

void computePID(){

  acquireLock();

  ch1 = rollOrder;
  ch2 = pitchOrder;
  ch4 = yawOrder;
  
  if((ch2 < PITCH_MIN) || (ch2 > PITCH_MAX)) ch2 = ch2Last;
  if((ch1 < ROLL_MIN) || (ch1 > ROLL_MAX)) ch1 = ch1Last;
  if((ch4 < YAW_MIN) || (ch4 > YAW_MAX)) ch4 = ch4Last;
  
  ch1Last = ch1;
  ch2Last = ch2;
  ch4Last = ch4;

  pitchReg.Compute();
  rollReg.Compute();
  yawReg.Compute();
  
  releaseLock();

}

/*  getYPR function
 *
 *  gets data from MPU and
 *  computes pitch, roll, yaw on the MPU's DMP
 */

void getYPR(){
  
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();
    fifoCount = mpu.getFIFOCount();
    
    if((mpuIntStatus & 0x10) || fifoCount >= 1024){ 
      
      mpu.resetFIFO(); 
    
    }else if(mpuIntStatus & 0x02){
    
      while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
  
      mpu.getFIFOBytes(fifoBuffer, packetSize);
      
      fifoCount -= packetSize;
    
      mpu.dmpGetQuaternion(&q, fifoBuffer);
      mpu.dmpGetGravity(&gravity, &q);
      mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
      yawSensor = (ypr[0] * 180/M_PI);
      pitchSensor = (ypr[2] * 180/M_PI);
      rollSensor = (ypr[1] * 180/M_PI);
      
//      if(abs(pitchSensor-pitchSensorLast)>30) pitchSensor[0] = yprLast[0];
//      if(abs(ypr[1]-yprLast[1])>30) ypr[1] = yprLast[1];
//      if(abs(ypr[2]-yprLast[2])>30) ypr[2] = yprLast[2];
//      yprLast[0] = ypr[0];
//      yprLast[1] = ypr[1];
//      yprLast[2] = ypr[2];
    
    }

}

/*  calculateVelocities function
 *  
 *  calculates the velocities of every motor
 *  using the PID output
 */

void calculateVelocities(){

  acquireLock();

  //ch3 = floor(ch3/RC_ROUNDING_BASE)*RC_ROUNDING_BASE;
  //velocity = map(ch3, RC_LOW_CH3, RC_HIGH_CH3, ESC_MIN, ESC_MAX);
  velocity = heightOrder;
  
  
  releaseLock();

  if((velocity < ESC_MIN) || (velocity > ESC_MAX)) velocity = velocityLast;
  
  velocityLast = velocity;
  
  v_ac = (abs(-100+bal_axes)/100)*velocity;
  v_bd = ((100+bal_axes)/100)*velocity;
  
  va = ((100+bal_ac)/100)*v_ac;
  vb = ((100+bal_bd)/100)*v_bd;
  
  vc = (abs((-100+bal_ac)/100))*v_ac;
  vd = (abs((-100+bal_bd)/100))*v_bd;
  
  //Serial.println(bal_bd);
  
  if(velocity < ESC_TAKEOFF_OFFSET){
  
    va = ESC_MIN;
    vb = ESC_MIN;
    vc = ESC_MIN;
    vd = ESC_MIN;
  
  }
  
}

void updateMotors(){

  a.write(va);
  c.write(vc);
  b.write(vb);
  d.write(vd);
//  Serial.println("Vitesse a");
//  Serial.println(va);
//  Serial.println("Vitesse b");
//  Serial.println(vb);
//  Serial.println("Vitesse c");
//  Serial.println(vc);
//  Serial.println("Vitesse d");
//  Serial.println(vd);
  

}


void dmpDataReady() {
    mpuInterrupt = true;
}


void initMPU(){
  
  Wire.begin();
  mpu.initialize();
  devStatus = mpu.dmpInitialize();
  if(devStatus == 0){
  
    mpu.setDMPEnabled(true);
    attachInterrupt(2, dmpDataReady, RISING);
    mpuIntStatus = mpu.getIntStatus();
    packetSize = mpu.dmpGetFIFOPacketSize();
  } else {
        // ERROR!
        // 1 = initial memory load failed
        // 2 = DMP configuration updates failed
        // (if it's going to break, usually the code will be 1)
        Serial.print(F("DMP Initialization failed (code "));
        Serial.print(devStatus);
        Serial.println(F(")"));
    }  
}


void initESCs(){
  a.write(ESC_MAX);
  b.write(ESC_MAX);
  c.write(ESC_MAX);
  d.write(ESC_MAX);
  a.attach(ESC_A);
  b.attach(ESC_B);
  c.attach(ESC_C);
  d.attach(ESC_D);
  delay(5000);
  a.write(ESC_MIN);
  b.write(ESC_MIN);
  c.write(ESC_MIN);
  d.write(ESC_MIN);
  delay(5000);
}

void initBalancing(){

  bal_axes = 0;
  bal_ac = 0;
  bal_bd = 0;

}

void initRegulators(){

  pitchReg.SetMode(AUTOMATIC);
  pitchReg.SetOutputLimits(-PID_PITCH_INFLUENCE, PID_PITCH_INFLUENCE);
  
  rollReg.SetMode(AUTOMATIC);
  rollReg.SetOutputLimits(-PID_ROLL_INFLUENCE, PID_ROLL_INFLUENCE);
  
  yawReg.SetMode(AUTOMATIC);
  yawReg.SetOutputLimits(-PID_YAW_INFLUENCE, PID_YAW_INFLUENCE);

}


void acquireLock(){
  interruptLock = true; 
}

void releaseLock(){
  interruptLock = false;
}

#endif
Merci pour votre aide
 
Juste parcouru le code en 2 minutes, mais:

- 10Hz c'est affreusement lent. Un contrôleur de multi typique tourne entre 300 et 1000Hz... donc il va falloir optimiser. Oublier les floats, les quaternions et autres trucs compliqués. Un pauvre AVR 8 bit est incapable de gérer ça. Tu viens de découvrir les limitations du matériel. Un algorithme mathématique parfait c'est cool, mais en général c'est incalculable en temps réel à moins d'avoir un CPU de bourrin. Le vrai talent c'est de trouver les simplifications qui permettent une approximation "pas trop mal" qui elle peut être calculée suffisamment rapidement en pratique. Idem pour les PID, qui sait comment la librairie que tu as l'air d'utiliser est implémentée. Probablement super mathématiquement, mais là y faut optimiser aussi.

- pulseIn et pulseOut sont très lents, et générés en software. Ca bouffe du temps processeur, et on a du jitter du fait qu'on ne réagit pas instantanément aux conditions. On préfère donc des routines plus avancées qui utilisent le hardware (timers et interruptions).

Ca peut valoir la peine de t'inspirer de multiwii, qui est basé sur arduino avec les optimisations qu'il faut.
 
Haut