Outils pour utilisateurs

Outils du site


ssi_elec_regulation_asservissement

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
ssi_elec_regulation_asservissement [2025/11/29 14:03] mistert2ssi_elec_regulation_asservissement [2025/12/09 13:54] (Version actuelle) mistert2
Ligne 1: Ligne 1:
-long ticksMesures ticks; // copie atomique +===== REGULATION ET ASSERVISSEMENT =====
-ticks 0;                 // RAZ pour prochaine fenêtre+
  
-float vitesse ticksMesures * (1000.0 / period);  // en ticks/s+==== COURS ====
  
-// ================= PID ================= +{{https://mistert.freeboxos.fr/cours/_/_herbin/TSI-2022/régulation - asservissement/TSSI cours  asservissement.pdf}}
-erreur = consigne - vitesse; +
-integral += erreur * (period / 1000.0); +
-float deriv = (erreur erreurPrec) (period 1000.0); +
-erreurPrec = erreur;+
  
-float commande kp * erreur + ki * integral + kd * deriv;+==== MODELES MATLAB  A SAUVEGARDER ====
  
-// Limiter entre -255 et 255 +{{https://mistert.freeboxos.fr/cours/_/_herbin/TSI-2022/régulation asservissement/regulationPID_2022a.slx}}
-if (commande > 255) commande = 255; +
-if (commande < -255) commande = -255;+
  
-commandeMoteur(commande);+{{https://mistert.freeboxos.fr/cours/_/_herbin/TSI-2022/régulation - asservissement/filtreNumerique_2022a.slx}}
  
-// --- Affichage TP --- 
-Serial.print("Consigne="); 
-Serial.print(consigne); 
-Serial.print("  | Vitesse="); 
-Serial.print(vitesse); 
-Serial.print("  | PWM="); 
-Serial.println(commande); 
  
-==== Code Arduino du TP ====+----
  
-<code> // === TP PID pour régulation de VITESSE d’un moteur CC === // Mesure vitesse = codeur incrémental sur interruption // Consigne reçue par le Moniteur Série (en tr/min ou en ticks/s)+==== TP – Régulation de vitesse d’un moteur à courant continu avec PID ==== 
 + 
 +=== Objectifs du TP === 
 + 
 +  * Mesurer la vitesse d’un moteur CC avec un codeur incrémental 
 +  * Comprendre la différence entre boucle ouverte et boucle fermée 
 +  * Mettre en œuvre progressivement un correcteur P, puis PI, puis PID 
 +  * Observer l’erreur statique, le dépassement et la sensibilité au bruit 
 + 
 +---- 
 + 
 +=== Travail demandé === 
 + 
 +  * Décrire la réponse du moteur en boucle ouverte 
 +  * Tracer ou décrire la courbe vitesse / consigne pour 
 +  * Expliquer pourquoi un écart statique persiste 
 +  * Montrer comment I supprime cet écart 
 +  * Comparer les dépassements pour P, PI et PID 
 +  * Conclure sur l’intérêt des trois termes du PID 
 + 
 +---- 
 + 
 +=== 1) Commande du moteur en boucle ouverte === 
 + 
 +Manipulations : 
 + 
 +  * Choisir le mode boucle ouverte 
 +  * Choisir une consigne en <mt>tr/min</mt> 
 +  * Observer la vitesse indiquée par le programme 
 +  * Bloquer légèrement l’axe du moteur avec le doigt 
 + 
 +Observations attendues : 
 + 
 +  * La vitesse chute immédiatement lorsque l’axe est freiné 
 +  * Le moteur ne corrige pas cette chute : c’est normal en boucle ouverte 
 +  * La vitesse dépend de la charge, des frottements et de la tension 
 + 
 +Conclusion : 
 +La boucle ouverte ne permet pas de maintenir une vitesse constante 
 + 
 +---- 
 + 
 +=== 2) Mise en place d’un correcteur P (Proportionnel) === 
 + 
 +Manipulations : 
 + 
 +  * Activer le correcteur proportionnel : <mt>u = K_p \cdot e</mt> 
 +  * Fixer une consigne (ex : 1500 tr/min) 
 +  * Le programme convertit automatiquement en ticks/s 
 +  * Freiner légèrement le moteur avec le doigt 
 +  * Augmenter progressivement K_p : 0.2 → 0.5 → 1.0 → 2.0 
 + 
 +Observations attendues : 
 + 
 +  * Le moteur augmente la PWM pour compenser la perturbation 
 +  * La vitesse remonte partiellement  
 +  * Il reste un écart statique : <mt>\text{vitesse réelle} < \text{consigne}</mt> 
 +  * Si K_p devient trop grand : oscillations, vibrations, instabilité 
 + 
 +Conclusion : Le correcteur P réduit l’erreur, mais ne la supprime pas 
 + 
 +---- 
 + 
 +=== 3) Mise en place du correcteur I (Intégral) === 
 + 
 +Manipulations : 
 + 
 +  * Ajouter le terme intégral : <mt>u = K_p e + K_I \int e(t)\,dt</mt> 
 +  * Débuter avec <mt>K_I</mt> = 0.05, puis 0.1 max 
 +  * Freiner l’axe puis relâcher 
 + 
 +Observations attendues : 
 + 
 +  * L’erreur statique disparaît 
 +  * La vitesse atteint précisément la consigne 
 +  * Si <mt>K_I</mt> trop fort : dépassement, oscillations lentes, instabilité 
 + 
 +Conclusion : Le correcteur I supprime l’erreur statique, mais ne doit jamais être trop fort 
 + 
 +---- 
 + 
 +=== 4) Mise en place du correcteur D (Dérivé) === 
 + 
 +Manipulations : 
 + 
 +  * Ajouter le terme dérivé : <mt>u = K_p e + K_I \int e\,dt + K_D \frac{de}{dt}</mt> 
 +  * Tester avec <mt>K_D</mt> = 0.01, puis 0.05 
 +  * Freiner l’axe pour observer la réaction 
 + 
 +Observations attendues : 
 + 
 +  * Le système est mieux amorti 
 +  * Le dépassement diminue 
 +  * La stabilité augmente 
 + 
 +Attention : Si <mt>K_D</mt> trop élevé → bruit, vibrations, instabilité 
 + 
 +Conclusion : Le terme D stabilise le système, mais n’améliore pas la précision 
 + 
 +---- 
 + 
 +=== Synthèse des rôles P / I / D === 
 + 
 +^ Correcteur ^ Rôle principal ^ Risques si trop fort ^ 
 +| P | réduit l’erreur | oscillations | 
 +| I | supprime l’erreur statique | dépassement, instabilité | 
 +| D | amortit, stabilise | amplification du bruit | 
 + 
 +---- 
 + 
 +==== Code Arduino du TP (consigne en tr/min, PID en ticks/s) ==== 
 + 
 +<code C++> 
 +/* 
 +   ====================================== 
 +      TP REGULATION : MODE BO / MODE PID 
 +   ====================================== 
 + 
 +   MODE BO : 
 +     - PWM = conversion(consigne_tr/min) 
 +     - codeur mesure mais NE corrige PAS 
 +     - aucune régulation 
 + 
 +   MODE PID : 
 +     - consigne tr/min convertie en ticks/s 
 +     - codeur mesure vitesse 
 +     - PID corrige PWM 
 +*/ 
 + 
 +const int TICKS_PAR_TOUR = 90;  // à ajuster selon le codeur
  
 // --- Pont en H --- // --- Pont en H ---
-const int M_AV = 3; // PWM forward +const int M_AV = 3;   // PWM forward 
-const int M_AR = 6; // PWM reverse+const int M_AR = 6;   // PWM reverse
  
-// --- Codeur incrémental --- +// --- Codeur --- 
-const int canalA = 2; // interruption 0+const int canalA = 2;
 const int canalB = 11; const int canalB = 11;
  
-volatile long ticks = 0; // compteur modifié par ISR+volatile long ticks = 0;
  
-// === PID === +// --- PID --- 
-float consigne = 0; // vitesse ciblée (ex : en ticks/s) +float kp = 0.8;
-float kp = 0.8; // gains PID : à régler en TP+
 float ki = 0.1; float ki = 0.1;
 float kd = 0.05; float kd = 0.05;
Ligne 49: Ligne 163:
 float integral = 0; float integral = 0;
  
-// ==Mesure période ===+float consigne_rpm = 0;      // consigne entrée par Serial (tr/min) 
 +float consigne_ticks_s 0;  // consigne convertie pour le PID 
 + 
 +// --- Modes --- 
 +enum Mode { BO, PID_MODE }; 
 +Mode mode BO; 
 + 
 +// --- Mesure ---
 unsigned long lastMeasure = 0; unsigned long lastMeasure = 0;
-const unsigned long period = 100; // calcul vitesse toutes les 100 ms+const unsigned long period = 100; // 100 ms
  
-// === Prototypes === 
-void ISR_codeur(); 
-void commandeMoteur(float pwm); 
-float lireConsigne(); 
  
-void setup() { +// ============ INTERRUPTIONS CODEUR ============ 
-Serial.begin(9600);+void ISR_codeur() { 
 +  if (digitalRead(canalB)
 +    ticks++; 
 +  else 
 +    ticks--; 
 +}
  
-pinMode(M_AV, OUTPUT); 
-pinMode(M_AR, OUTPUT); 
  
-pinMode(canalB, INPUT);+// ============ CONVERSION tr/min -> PWM (BO============ 
 +int rpmToPWM(float rpm) { 
 +  // Ajuste selon ton moteur 
 +  // Ex : 0–150 tr/min -> 0–255 PWM 
 +  if (rpm < 0) rpm = 0; 
 +  if (rpm > 150) rpm = 150;
  
-attachInterrupt(digitalPinToInterrupt(canalA)ISR_codeurRISING);+  return map(rpm, 0, 1500255); 
 +}
  
-Serial.println("=== TP : Regulation PID de vitesse ==="); + 
-Serial.println("Entrez une consigne en ticks/s (ex : 200):");+// ============ CONVERSION tr/min -> ticks/s (PID============ 
 +float rpmToTicksSec(float rpm
 +  return (rpm * TICKS_PAR_TOUR) / 60.0;
 } }
  
-// ====================== BOUCLE PRINCIPALE =========================== + 
-void loop() { +// ============ COMMANDE MOTEUR ============ 
-// --- Lecture consigne si disponible --- +void setPWM(int pwm) { 
-if (Serial.available() > 0) { +  if (pwm >0) { 
-consigne = lireConsigne(); +    digitalWrite(M_AR, LOW); 
-Serial.print("Nouvelle consigne = "); +    analogWrite(M_AV, pwm); 
-Serial.println(consigne);+  } else { 
 +    digitalWrite(M_AV, LOW); 
 +    analogWrite(M_AR, -pwm); 
 +  }
 } }
  
-// --- Boucle PID toutes les 100 ms --- 
-unsigned long now = millis(); 
-if (now - lastMeasure >= period) { 
-lastMeasure = now; 
  
-long ticksMesures ticks; // copie atomique +// ============================================= 
-ticks = 0;                 // RAZ pour prochaine fenêtre+//                    SETUP 
 +// ============================================= 
 +void setup() { 
 +  Serial.begin(9600);
  
-float vitesse = ticksMesures * (1000.0 / period);  // en ticks/s+  pinMode(M_AV, OUTPUT); 
 +  pinMode(M_AR, OUTPUT); 
 +  pinMode(canalB, INPUT);
  
-// ================= PID ================= +  attachInterrupt(digitalPinToInterrupt(canalA), ISR_codeur, RISING);
-erreur = consigne - vitesse; +
-integral += erreur * (period / 1000.0); +
-float deriv = (erreur - erreurPrec/ (period / 1000.0)+
-erreurPrec = erreur;+
  
-float commande kp * erreur + ki * integral + kd * deriv;+  Serial.println("=== TP REGULATION : BO / PID ==="); 
 +  Serial.println("Tapez BO ou PID pour changer de mode."); 
 +  Serial.println("Tapez une consigne en tr/min (ex : 150)"); 
 +}
  
-// Limiter entre -255 et 255 
-if (commande > 255) commande = 255; 
-if (commande < -255) commande = -255; 
  
-commandeMoteur(commande);+// ============================================= 
 +//                    LOOP 
 +// ============================================= 
 +void loop() {
  
-// --- Affichage TP --- +  // ----------- Lecture mode / consigne ------------ 
-Serial.print("Consigne="); +  if (Serial.available() > 0) { 
-Serial.print(consigne); +    String txt = Serial.readStringUntil('\n'); 
-Serial.print("  | Vitesse="); +    txt.trim();
-Serial.print(vitesse); +
-Serial.print("  | PWM="); +
-Serial.println(commande);+
  
 +    if (txt.equalsIgnoreCase("BO")) {
 +      mode = BO;
 +      Serial.println("Mode = BOUCLE OUVERTE");
 +      return;
 +    }
  
-} +    if (txt.equalsIgnoreCase("PID")) { 
-}+      mode = PID_MODE; 
 +      Serial.println("Mode = PID"); 
 +      return; 
 +    }
  
-// ========== INTERRUPTIONS CODEUR ========== +    // Sinon c'est une consigne tr/min 
-void ISR_codeur() { +    consigne_rpm txt.toFloat(); 
-if (digitalRead(canalB)+    consigne_ticks_s = rpmToTicksSec(consigne_rpm);
-ticks++; +
-else +
-ticks--; +
-}+
  
-// ========== COMMANDE MOTEUR ========== +    Serial.print("Consigne "); 
-void commandeMoteur(float pwm) { +    Serial.print(consigne_rpm); 
-if (pwm >0{ +    Serial.print(" tr/min  -> "); 
-digitalWrite(M_AR, LOW); +    Serial.print(consigne_ticks_s); 
-analogWrite(M_AV, pwm); +    Serial.println(" ticks/s"); 
-} else { +  }
-digitalWrite(M_AV, LOW); +
-analogWrite(M_AR, -pwm); +
-+
-}+
  
-// ========== LECTURE CONSIGNE ========== 
-float lireConsigne() { 
-String txt = Serial.readStringUntil('\n'); 
-txt.trim(); 
-return txt.toFloat(); 
-} 
-</code> 
  
 +  // ----------- Mesure toutes les 100 ms -----------
 +  unsigned long now = millis();
 +  if (now - lastMeasure < period) return;
 +  lastMeasure = now;
  
 +  long ticks_mes = ticks;
 +  ticks = 0;
 +
 +  float vitesse_ticks_s = ticks_mes * (1000.0 / period);
 +  float vitesse_rpm = (vitesse_ticks_s * 60.0) / TICKS_PAR_TOUR;
 +
 +
 +  // ============================================
 +  //                 MODE BO
 +  // ============================================
 +  if (mode == BO) {
 +
 +    int pwm = rpmToPWM(consigne_rpm);  // conversion directe consigne → PWM
 +    setPWM(pwm);
 +
 +    Serial.print("[BO] consigne = ");
 +    Serial.print(consigne_rpm);
 +    Serial.print(" tr/min | vitesse = ");
 +    Serial.print(vitesse_ticks_s);
 +    Serial.print(" ticks/s | ");
 +    Serial.print(vitesse_rpm);
 +    Serial.print(" tr/min | PWM = ");
 +    Serial.println(pwm);
 +
 +    return;
 +  }
 +
 +
 +  // ============================================
 +  //                 MODE PID
 +  // ============================================
 +  if (mode == PID_MODE) {
 +
 +    erreur = consigne_ticks_s - vitesse_ticks_s;
 +    integral += erreur * (period / 1000.0);
 +    float deriv = (erreur - erreurPrec) / (period / 1000.0);
 +    erreurPrec = erreur;
 +
 +    float commande = kp * erreur + ki * integral + kd * deriv;
 +
 +    // saturation
 +    if (commande > 255) commande = 255;
 +    if (commande < -255) commande = -255;
 +
 +    setPWM(commande);
 +
 +    Serial.print("[PID] consigne = ");
 +    Serial.print(consigne_rpm);
 +    Serial.print(" tr/min | vitesse = ");
 +    Serial.print(vitesse_ticks_s);
 +    Serial.print(" ticks/s | ");
 +    Serial.print(vitesse_rpm);
 +    Serial.print(" tr/min | PWM = ");
 +    Serial.println(commande);
 +
 +    return;
 +  }
 +}
 +
 +</code>
ssi_elec_regulation_asservissement.1764425026.txt.gz · Dernière modification : de mistert2