Go Down

Topic: Relais thermique numérique pour protéger les moteurs contre les surcharges (Read 391 times) previous topic - next topic

iutgeiisoissons

Comment programmer la protection d'un moteur numériquement ?

Dans cet article qui n'est pas encore fini, un modèle thermique simple est présenté pour un moteur synchrone roue de vélo. Il faut seulement 360 microsecondes pour le modèle 1 et 650micro seconde pour le modèle 2 alors que la période d'échantillonnage est de 1s.
En effet, avec la mesure du courant du moteur, il est possible d'estimer l'échauffement du bobinage interne sans capteur de température.
La programmation va se faire avec un Arduino nano avec dans un premier temps le modelé 1 de l'article suivant.












Le fichier isis de la simulation peut etre telechargeable sur ce lien
https://drive.google.com/open?id=1YrDJJXwwHodMbe5EPk2FP19NNDXtJwnd




Le programme pour le modèle thermique niveau 1
Code: [Select]

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <TimerOne.h>
#include <SoftwareSerial.h>
#include <math.h>

#define led13   13

LiquidCrystal_I2C lcd(0x27, 20, 4);     //A0, A1, A2 non shunter 20x4ligne

       float I=0;
       float kph=0;         //kilometre per heure
       float w=0;           //vitesse angulaire (rad/s)
       float tempestim=25;     //temperature estimée
       float tempestim1;       //temperature estimée n-1
       float Rmoteur=0.12;
       float Perte=0;       //perte(Watt)

       float Capacore=140;      //capacity thermal heat
       float Ythecore=2;      //admitance thermal heat=1/Rth
       float timethcst=70;   //time constant thermal = Capacore*Rthecore

       bool flagtemp=0;
unsigned int T=25;          //temperature reel
        
unsigned int Time=2500;  // si temps trop long alors vitesse=0kph
unsigned int TO;

unsigned int minute=0;
unsigned int seconde=0;

void setup()
{  // initialise l'afficheur LCD
pinMode(led13, OUTPUT);
pinMode(3, OUTPUT);

  Timer1.initialize(1000000);         // initialize timer1, and set a 1 second period =>  1000 000  pour 0.01s  10 000
  Timer1.attachInterrupt(callback);   // attaches callback() as a timer overflow interrupt
  Serial.begin(9600);

attachInterrupt(0, interrup2, CHANGE);
lcd.init();               //et pas lcd begin comme cetraine biblio
lcd.display();            // activer l'affichage
lcd.backlight();          // allumer retroeclairage

TO = millis();
}//fin setup


void interrup2() // la fonction appelée par l'interruption externe n°0
{
Time=(millis()-TO);  //mesure du temps
TO = millis();
}



// Interruptions  tous les 1s fait par le timer1***********************************
void callback()  {
seconde++;

//tempsPC++;
//if (digitalRead(led13)== 1) {digitalWrite(led13,LOW);}  else {digitalWrite(led13,HIGH);}
//digitalWrite(led13,HIGH);
I=analogRead(A1);     //mesure courant
  
I=(I-123)/8.15;            //acs755   0.6V pour 0A  et 2.6V pour 40A
if (tempestim>25) {Rmoteur=0.12+0.0005*(tempestim-25) ;} else {Rmoteur=0.12;}
Perte=Rmoteur*I*I;    // perte cuivre, les pertes fer seront negligées
w=(kph*2*3.1416)/(3.6*2.01);         //vitesse en rad/s  26 pouces rayon 320mm  50us à la place de 35us
Ythecore=w*0.01+2;                   //impedance en fonction
timethcst=Capacore/(Ythecore*1);  //1 correspond à Te periode d'echantillon
tempestim1=tempestim;
tempestim=((Perte/Ythecore)+timethcst*tempestim1)/(1+timethcst);
//digitalWrite(led13,LOW);

//   Serial.print(I); Serial.print(";");  Serial.print("\t");
   Serial.print(tempestim);Serial.print("\t"); Serial.println(";");

}//callback





void loop()
{

  lcd.setCursor(0,0);  // (X,Y)
  lcd.print(I,2);     //duree 10ms
  lcd.print("A   ");

  lcd.setCursor(8,0);  // (X,Y)
  lcd.print(Rmoteur,2);     //duree 10ms
  lcd.print((char)244);
   lcd.print("   ");

if (Time>=2000) {kph=0;   } else {kph=(2.010*1000*3.6)/Time;   }   //2010mm perimetre roue 26 pouces
  lcd.setCursor(0,1);  // (X,Y)
  lcd.print(kph,1);
  lcd.print("kph   ");  

  lcd.setCursor(8,1);  // (X,Y)
  lcd.print(Perte,0);
  lcd.print("W   ");  


if (seconde>59)  {minute++;seconde=0; }
if (minute>59)  {minute=0; }  
lcd.setCursor(0,2);
lcd.print(minute);
lcd.print("m");
lcd.print(seconde);
lcd.print("   ");

T=analogRead(A2);   //mesure temperature LM35
T=T/2;
lcd.setCursor(0,3);
lcd.print(T);
lcd.print((char)223);
lcd.print("C ");

lcd.setCursor(8,3);
lcd.print(tempestim,7);
lcd.print((char)223);
lcd.print("C ");
    
if (tempestim>150 && flagtemp==0) {flagtemp=1; tone(3, 440, 2000);}    //sonnerie moteur atteint 150°C
if (tempestim<120 && flagtemp==1) {flagtemp=0;}   //hysteresis
    
}//fin loop





Ce relais thermique pourrait être utilisé pour la trottinette électrique
Commande et instrumentation de trottinette électrique 500W avec Arduino méga
https://forum.arduino.cc/index.php?topic=473015.0

MarsaMatruh

Intéressant.

Problème inverse mais un peu identique : comment ne pas cramer son alternateur de camping-car en rechargeant sa batterie Li?
Voir aussi la vidéo.

Là, c'est la vitesse du moteur entre en ligne de compte. L'alternateur est conçu pour bien se refroidir quand il tourne vite.

iutgeiisoissons

Entre l'alternateur et la batterie lithium, il te faut un chargeur à courant constant qui limite le courant de charge, à une puissance inférieure à celui de ton alternateur, puis  le chargeur doit limiter la tension sur chaque élément.
Donc, Il n'y a pas de surcharge, donc un fusible suffit.
rien à voir avec l'aticle precedent.

Mais le fusible précèdent est un 200A, et ton alternateur quelle est sa puissance ?

iutgeiisoissons

Attention :
La Library du LCD I2C ne fonctionne pas dans les routines d'interruptions. Comme on n'a pas le point .ino de cette library on ne sait pas pourquoi.
mais il y a un conflit. C'est bien dommage.


Le modèle 2 demande une équation de calcul plus importante que le modèle 1.
Il n'est pas possible de faire le calcul numérique de la température de la bobine à partir de l'équation 5 de l'article precedent de Laplace avec la méthode d'Euler comme on peut l'observer sur la figure suivante dans Matlab.

On est obligé de faire la fonction de transfert de la température estimé avec ces valeurs qui bougent en fonction de la température et de faire tous les calculs
Dans la simulation, il est possible de vérifier la fonction de transfert en fonction de la vitesse en faisant varier la vitesse du GBF.


Donc, voici le programme de ce modele 2
Code: [Select]

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <TimerOne.h>
#include <SoftwareSerial.h>
#include <math.h>

#define led13   13

LiquidCrystal_I2C lcd(0x27, 20, 4);     //A0, A1, A2 non shunter 20x4ligne

       float I=0;
       float kph=0;         //kilometre per heure
       float w=0;           //vitesse angulaire (rad/s)

       float tempestim=0;
       float tempestim1=0;       //temperature estimée core n-1
       float tempestim2=0;       //temperature estimée core n-2
  
       float tempeshell=0;
      
       float Te=1;       //
       float N;       //
       float A;       //
       float B;       //
       float D;       //

      
       float tamb=25;
      
       float Rmoteur=0.12;
       float Perte=0;       //perte(Watt)
       float Perte1=0;       //perte(Watt)  n-1

       float Capacore=140;      //capacity thermal heat
       float Ythecore=2.47;      //admitance thermal heat=1/Rth
      
       float Capashell=210;      //capacity thermal heat
       float Ytheshell=2;      //admitance thermal heat=1/Rth

       bool flagtemp=0;
unsigned int T=25;          //temperature reel
        
unsigned int Time=2500;  // si temps trop long alors vitesse=0kph
unsigned int TO;

unsigned int minute=0;
unsigned int seconde=0;

void setup()
{  // initialise l'afficheur LCD
pinMode(led13, OUTPUT);
pinMode(3, OUTPUT);

  Timer1.initialize(1000000);         // initialize timer1, and set a 1 second period =>  1000 000  pour 0.01s  10 000
  Timer1.attachInterrupt(callback);   // attaches callback() as a timer overflow interrupt
  Serial.begin(9600);

attachInterrupt(0, interrup2, CHANGE);
lcd.init();               //et pas lcd begin comme cetraine biblio
lcd.display();            // activer l'affichage
lcd.backlight();          // allumer retroeclairage

TO = millis();
}//fin setup


void interrup2() // la fonction appelée par l'interruption externe n°0
{
Time=(millis()-TO);  //mesure du temps
TO = millis();
}



// Interruptions  tous les 1s fait par le timer1***********************************
void callback()  {
seconde++;

//tempsPC++;
//if (digitalRead(led13)== 1) {digitalWrite(led13,LOW);}  else {digitalWrite(led13,HIGH);}
//digitalWrite(led13,HIGH);
I=analogRead(A1);     //mesure courant
  
I=(I-123)/8.15;            //acs755   0.6V pour 0A  et 2.6V pour 40A
if (tempestim>25) {Rmoteur=0.12+0.0005*(tempestim-25) ;} else {Rmoteur=0.12;}
Perte=Rmoteur*I*I;    // perte cuivre, les pertes fer seront negligées
w=(kph*2*3.1416)/(3.6*2.01);         //vitesse en rad/s  26 pouces rayon 320mm  50us à la place de 35us

Ytheshell=w*1.66+2;                 //admitance en fonction de la vitesse
Ythecore=w*0.007+2.47;              //admitance vs vitesse
Perte1=Perte;
N=(Perte/Ythecore)+(Perte/Ytheshell)+((Perte-Perte1)*Capashell)/(Te*Ythecore*Ytheshell);           //  
A=(((1/Ythecore+1/Ytheshell)*Capacore+Capashell/Ytheshell)/Te);
B=Capashell*Capacore/(Ythecore*Ytheshell*Te*Te);
D=(1+A+B);

tempestim2=tempestim1;
tempestim1=tempestim;
tempestim=((N/D)+(((A+B*2)*tempestim1)/D)-((B*tempestim2)/D));
//digitalWrite(led13,LOW);
//l'estimation de tempeshell est possible, mais inutile
tempeshell=((Capacore*(tempestim-tempestim1)/(Ythecore*Te))-(Perte/Ythecore)+tempestim);

//   Serial.print(I); Serial.print(";");  Serial.print("\t");
//   Serial.print(tempeshell);Serial.print("\t"); Serial.print(";");
   Serial.print(tempestim);Serial.print("\t"); Serial.println(";");
  
}//callback





void loop()
{

  lcd.setCursor(0,0);  // (X,Y)
  lcd.print(I,2);     //duree 10ms
  lcd.print("A   ");

  lcd.setCursor(8,0);  // (X,Y)
  lcd.print(Rmoteur,2);     //duree 10ms
  lcd.print((char)244);
   lcd.print("   ");

if (Time>=2000) {kph=0;   } else {kph=(2.010*1000*3.6)/Time;   }   //2010mm perimetre roue 26 pouces
  lcd.setCursor(0,1);  // (X,Y)
  lcd.print(kph,1);
  lcd.print("kph   ");  

  lcd.setCursor(8,1);  // (X,Y)
  lcd.print(Perte,0);
  lcd.print("W   ");  


if (seconde>59)  {minute++;seconde=0; }
if (minute>59)  {minute=0; }  
lcd.setCursor(0,2);
lcd.print(minute);
lcd.print("m");
lcd.print(seconde);
lcd.print("   ");


lcd.setCursor(7,2);
lcd.print("Tshell:");
lcd.print(tempeshell,1);        //
lcd.print((char)223);
lcd.print("C   ");

T=analogRead(A2);   //mesure temperature LM35
T=T/2;
lcd.setCursor(0,3);
lcd.print(T);
lcd.print((char)223);
lcd.print("C   ");

lcd.setCursor(7,3);
lcd.print("Tcore :");
lcd.print(tempestim,1);
lcd.print((char)223);
lcd.print("C    ");
    
if (tempestim>150 && flagtemp==0) {flagtemp=1; tone(3, 440, 2000);}    //sonnerie moteur atteint 150°C
if (tempestim<120 && flagtemp==1) {flagtemp=0;}   //hysteresis
    
}//fin loop




hbachetti

Quote
La Library du LCD I2C ne fonctionne pas dans les routines d'interruptions.
Plutôt l'I2C tout court ... Il est plutôt déconseillé de dialoguer dans une interruption.
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

Go Up