Rechercher sur l'ensemble du site
Asservissement d'un moteur électrique
Fabrication et utilisation d’un capteur incrémental :
Lors de la commande d'un système, on a parfois besoin d'atteindre des consignes précises. Pour respecter cette consigne il existe un outil assez simple à mettre en place : la boucle PID, ou Proportionnel, Intégrale, Dérivé.
Exemples : le régulateur de vitesse de votre voiture, vitesse et position d’une machines à commande numérique ou même pourquoi pas le four de votre cuisine.
Ce système d'asservissement fonctionne suivant la boucle ci-dessous :
- En entrée on a la consigne qui est comparée avec la réponse mesurée par un capteur
- On peut alors avoir un écart entre les deux valeurs
- On applique alors à cet écart des correctifs P, I et D pour ensuite commander le système
Je vous propose comme démonstration d’asservir un moteur électrique en position et en vitesse. Pour ceci, il existe une assez grande diversité de capteurs plus ou moins directs :
– Un capteur direct va donner une information directement utilisable, sinon il va falloir ajouter des calculs pour la trouver (par exemple avec la position il faut dériver pour trouver la vitesse).
Pour asservir mon moteur j’ai choisi d’utiliser un capteur optique, ce capteur est réalisé avec :
– une roue incrémentale , elle est sur l’axe moteur et possède n incrémentations qui donnent une information sur la rotation parcourue par l’axe.
– une diode infra-rouge , elle émet un faisceau infra-rouge qui sera coupé par les incrémentations de la roue.
– un phototransistor , reçoit le faisceau infra-roue et détecte lorsqu’il est coupé.
Une fois que le capteur est installé il ne reste « plus qu’à » contrôler le moteur. Pour cela, on a :
– Le moteur
– Un pont en H , qui va permettre d’alimenter le moteur et avoir deux sens de rotations
– la carte arduino , qui va faire la partie commande logique et fait les calculs.
– Une alimentation
– Un PC , qui va faire l’interface homme machine (IHM).
Code Asservissement en vitesse
#include <FlexiTimer2.h>
const int maxPwm=255;
int increment=0;
int consigne=0;
int byte_read;
int erreur=0;
const float kp=0.01;
const float ki=0.02;
int somerreur=0;
int pwm=0;
void setup() {
Serial.begin(9600);
pinMode(6,OUTPUT);
pinMode(3,INPUT);
attachInterrupt(digitalPinToInterrupt(3), codeur, RISING);
FlexiTimer2::set(50, asserv); // call every 500 1ms "ticks" resolution de lecture 150 tr/min
FlexiTimer2::start();
}
void loop() {
if ( Serial.available() ) {
int sens=1;
consigne=0;
while ( Serial.available() ) {
byte_read = Serial.read();
if (byte_read==45) {sens=-1;}
if ( is_a_number(byte_read) ) {
consigne = ascii2int(consigne, byte_read);
}
delay(2);
}
consigne*=sens;
}}
boolean is_a_number(int n)
{
return n >= 48 && n <= 57;
}
int ascii2int(int n, int byte_read)
{
return n*10 + (byte_read - 48);
}
void codeur(){
increment++;
}
void asserv(){
float freq=increment*2.5*60;
if(pwm<0) {freq*=-1;}
increment=0;
erreur=consigne-freq;
int corr_p=erreur*kp;
if(corr_p>maxPwm){corr_p=maxPwm;}
if(corr_p<-maxPwm){corr_p=-maxPwm;}
if(abs(somerreur+erreur)*ki<maxPwm) { somerreur+=erreur;}
if(consigne==0){somerreur=0;}
int corr_i=somerreur*ki;
if(corr_i>maxPwm){corr_i=maxPwm;}
if(corr_i<-maxPwm){corr_i=-maxPwm;}
pwm=corr_i+corr_p;
if(pwm>maxPwm){pwm=maxPwm;}
if(pwm<-maxPwm){pwm=-maxPwm;}
if(pwm>=0){analogWrite(6,pwm); analogWrite(5,0);}
else{analogWrite(5,-pwm); analogWrite(6,0);}
Serial.print(corr_p);
Serial.print(" ");
Serial.print(corr_i);
Serial.print(" ");
Serial.print(consigne);
Serial.print(" ");
Serial.println(freq);
}
Code Asservissement en position
#include <FlexiTimer2.h>
int increment=0;
int consigne=0;
int byte_read;
int erreur=0;
const int maxPwm=60;
const float kp=8;
const float ki=2;
int somerreur=0;
int pwm=0;
void setup() {
Serial.begin(9600);
pinMode(6,OUTPUT);
pinMode(5,OUTPUT);
pinMode(3,INPUT);
attachInterrupt(digitalPinToInterrupt(3), codeur, RISING);
FlexiTimer2::set(30, asserv); // call every 500 1ms "ticks"
FlexiTimer2::start();
}
void loop() {
if ( Serial.available() ) {
int sens=1;
consigne=0;
while ( Serial.available() ) {
byte_read = Serial.read();
if (byte_read==45) {sens=-1;}
if ( is_a_number(byte_read) ) {
consigne = ascii2int(consigne, byte_read);
}
delay(2);
}
consigne*=sens;
consigne*=8;
}}
boolean is_a_number(int n)
{
return n >= 48 && n <= 57;
}
int ascii2int(int n, int byte_read)
{
return n*10 + (byte_read - 48);
}
void codeur(){
if(pwm>=0) {increment++;}
else{increment--;}
}
void asserv(){
erreur=consigne-increment;
int corr_p=erreur*kp;
if(corr_p>maxPwm){corr_p=maxPwm;}
if(corr_p<-maxPwm){corr_p=-maxPwm;}
if(abs(somerreur+erreur)*ki<maxPwm) { somerreur+=erreur;}
else {
somerreur=maxPwm/ki;
if(erreur<0) {somerreur*=-1;}
}
if(erreur==0) {somerreur=0;}
int corr_i=somerreur*ki;
if(corr_i>maxPwm){corr_i=maxPwm;}
if(corr_i<-maxPwm){corr_i=-maxPwm;}
pwm=corr_i+corr_p;
if(pwm>maxPwm){pwm=maxPwm;}
if(pwm<-maxPwm){pwm=-maxPwm;}
if(pwm>=0){analogWrite(6,pwm); analogWrite(5,0);}
else{analogWrite(5,-pwm); analogWrite(6,0);}
Serial.print(corr_p);
Serial.print(" ");
Serial.print(corr_i);
Serial.print(" ");
Serial.print(consigne);
Serial.print(" ");
Serial.print(erreur);
Serial.print(" ");
Serial.println(increment);
}
Vous trouverez la démonstration du système sur la vidéo qui est sur ma chaine YouTube