ssi_elec_regulation_asservissement
Table des matières
REGULATION ET ASSERVISSEMENT
COURS
MODELES MATLAB A SAUVEGARDER
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 P
- 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
- 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 :
- 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 :
- 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 :
- Débuter avec
= 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
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é :
- Tester avec
= 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 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)
/* ====================================== 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 --- const int M_AV = 3; // PWM forward const int M_AR = 6; // PWM reverse // --- Codeur --- const int canalA = 2; const int canalB = 11; volatile long ticks = 0; // --- PID --- float kp = 0.8; float ki = 0.1; float kd = 0.05; float erreur, erreurPrec = 0; float integral = 0; 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; const unsigned long period = 100; // 100 ms // ============ INTERRUPTIONS CODEUR ============ void ISR_codeur() { if (digitalRead(canalB)) ticks++; else ticks--; } // ============ 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; return map(rpm, 0, 150, 0, 255); } // ============ CONVERSION tr/min -> ticks/s (PID) ============ float rpmToTicksSec(float rpm) { return (rpm * TICKS_PAR_TOUR) / 60.0; } // ============ COMMANDE MOTEUR ============ void setPWM(int pwm) { if (pwm >= 0) { digitalWrite(M_AR, LOW); analogWrite(M_AV, pwm); } else { digitalWrite(M_AV, LOW); analogWrite(M_AR, -pwm); } } // ============================================= // SETUP // ============================================= void setup() { Serial.begin(9600); pinMode(M_AV, OUTPUT); pinMode(M_AR, OUTPUT); pinMode(canalB, INPUT); attachInterrupt(digitalPinToInterrupt(canalA), ISR_codeur, RISING); 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)"); } // ============================================= // LOOP // ============================================= void loop() { // ----------- Lecture mode / consigne ------------ if (Serial.available() > 0) { String txt = Serial.readStringUntil('\n'); txt.trim(); if (txt.equalsIgnoreCase("BO")) { mode = BO; Serial.println("Mode = BOUCLE OUVERTE"); return; } if (txt.equalsIgnoreCase("PID")) { mode = PID_MODE; Serial.println("Mode = PID"); return; } // Sinon c'est une consigne tr/min consigne_rpm = txt.toFloat(); consigne_ticks_s = rpmToTicksSec(consigne_rpm); Serial.print("Consigne = "); Serial.print(consigne_rpm); Serial.print(" tr/min -> "); Serial.print(consigne_ticks_s); Serial.println(" ticks/s"); } // ----------- 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; } }
ssi_elec_regulation_asservissement.txt · Dernière modification : de mistert2
