Chargeur et testeur de batterie universelle lipo, liion, lifer, LTO, Ni-Mh....

En 2010, des chargeurs de batteries ont été réalisé à l’IUT à partir de microcontrôleur PIC 16F877 et 16F6520 qui pouvait charger différentes batteries jusqu’a 72V, 100 Ampères.
Ce post va présenter le même type de chargeur mais avec un Arduino et la gestion de tous les cellules des éléments.

En effet, il est difficile de trouver sur le net des chargeurs avec des programmes entièrement fini avec une bonne régulation stable.

Par contre, il existe de nombreux chargeurs à partir du circuit TP4506 qui est limité à 1 Ampére pour lipo et li-ion car la tension de limitation est fixée à 4.2V.


Ce chargeur indique par une led allumée que la batterie est chargée à 100%
Les pertes en chaleur de cette alimentation linéaire correspondent à l’équation suivante :
Perte=(5V-4V)Icharge=1V1A= 1W donc par rapport au 4W utile pour la batterie le rendement sera de 80%.

L’alimentation 5V peut provenir d’un chargeur de smarthphone ou par l’alimentation suivante 5V qui est indépendante de la terre.
Son rendement doit être aux alentours de 75%. Par conséquent, le rendement total est de 0.8*0.75=60%

Ce type d’équilibreur permettrait de reconvertir les vieux chargeurs de smarthphone…(il y en a plein dans les brocantes et à la déchèterie)

En effet, si l’on désire charger plusieurs cellules en même temps, il faut des alimentations isolées 5V.

Pour faire l’équilibrage plus rapide que les BMS à résistances classiques (qui dissipent le courant 0.1A). Il est possible d’utiliser les modules circuits intégrés precedents.

Donc pour faire un équilibreur de 12 éléments, le prix reviendrait à
Prix=12*(0.16+1.37)=18.56 €

mais s’il l’on a une batterie de 20A.h dechargée à 100%, il faudra 20h de recharge, c’est un peu long.

Avant de présenter la realisation d’un chargeur rapide pour differents types de batteries,

Voici quelques Bibliographie pour présenter la régulation de la charge de la batterie.
En anglais

En francais

Un testeur de batterie intéressant

un chargeur qui rechargerait des piles primaires mais qui n’ont pas prevu de recharger des batteries ?

en cours de construction :

Lorsqu’on a une batterie de 72V, il y a 18 éléments lipo en série ou 21 éléments Lifer en série.
Lors de la recharge, il faut surveiller la tension de chaque élément.
Par conséquent, cela dépasse le nombre d’entrée analogique d’une carte Méga qui est de 16.

La solution est d’avoir un multiplexeur 24 entrées analogiques qui sélectionne une cellule de la batterie et la met sur A0. Ce multiplexeur utilise 3 entrées numériques 5, 6, 7 pour sélectionner l’entrée désirée.

Le shield ka12 Velleman coute seulement 17 euros et une bibliothèque pour en faire la gestion est fournie sur ce lien

un dossier d’etude a été effectué utilisant ce shield

Pour faire la mesure de chaque élément de la batterie, un pont diviseur de tension est utilisé.
Puis la soustraction de cette tension par rapport à la tension précédente, doit etre effectué pour avoir la tension de l’element.

Attention : Le schéma électrique de simulation ne correspond pas au schéma électrique réel mais permet de debugger le programme.
Les données du chargeur sont affichées sur le LCD (rapport cyclique correspondant à la PWM à 32Khz, le courant batterie, la tension batterie, l’action sur les boutons poussoirs.
Le fichier ISIS est telechargeable sur ce lien

Il est tres facile de réaliser un hacheur abaisseur en fonction du courant demandé (converter buck)

1 Programme en boucle ouverte

BP2 permet d’incrémenter le rapport cyclique PWM, BP3 le décrémenter. BP1 mettre le rapport cyclique à 0, BP4 permet de gérer différents menus avec la mesure des tensions de chaque cellule, des courants, PWM donc de gérer l’afficheur.

Voici la gestion de l’afficheur lors de la simulation du menu 0

la simulation avec le menu 1

Voici les valeurs du pont diviseur pour mesurer la tension de chaque element.

Voici le programme en boucle ouverte

#include <LiquidCrystal.h>
#include <SoftwareSerial.h>
#include <TimerOne.h>
 

#define Led     13       // 13 pour la led jaune sur la carte
#define BP1     30       // 30 BP1
#define BP2     31       // 31 BP2           
#define BP3     32       // 32 BP3
#define BP4     26       // 32 BP3
#define LEDV    33       // 33 led
#define LEDJ    34       // 34 led
#define LEDR    35       // 35 led
#define relay   36       // 36 relay
#define PWM10    10      //11   timer2    

LiquidCrystal lcd(27, 28, 25, 24, 23, 22); // RS=12, Enable=11, D4=5, D5=4, D6= 3, D7=2, BPpoussoir=26
// Configuration des variables

unsigned   int UF = 0;  // variable to store the value coming from the sensor
   float U =  0;


      float Ba1 = 0;
      float Ba2 = 0;
      float Ba3 = 0;
      float Ba4 = 0;
      float Ba5 = 0;
      float Ba6 = 0;
      float Ba7 = 0;
      float Ba8 = 0;
      float Ba9 = 0;
      float Ba10 = 0;

        float IF = 0;  
        float I = 0;
        float I2 = 0;
        float I3 = 0;
        float I4 = 0;
unsigned   int Ah=155;
           byte PWM=0 ;    //rapport cyclique  8bit
unsigned    int temps;
           byte menu=0;


void setup() {
  pinMode(Led, OUTPUT);   //led carte arduino
  pinMode(LEDV, OUTPUT);
  pinMode(LEDR, OUTPUT);
  pinMode(LEDJ, OUTPUT);
  pinMode (PWM10,OUTPUT);     // broche (10) en sortie  timer2

  
//  digitalWrite(LEDV,LOW);
  Timer1.initialize(100000);         // initialize timer1, and set a 0,1 second period =>  100 000
  Timer1.attachInterrupt(callback);  // attaches callback() as a timer overflow interrupt
  lcd.begin(20, 4);  
//  Serial1.begin(9600); 

  TCCR2B = (TCCR2B & 0b11111000) | 0x01;         //pin 10  32khz    http://playground.arduino.cc/Main/TimerPWMCheatsheet
                                                  //http://www.pobot.org/Modifier-la-frequence-d-un-PWM.html
  //   analogWriteResolution(bits)      https://www.arduino.cc/en/Reference/AnalogWriteResolution
}




// Interruptions  tous les 0.1s
void callback()  {
temps++;
//toogle state ledv for check 
  if ( digitalRead(LEDV)== 1 ) {digitalWrite(LEDV,LOW);}  else {digitalWrite(LEDV,HIGH);}
    
analogWrite(PWM10,PWM);   //PWM
I=analogRead(A12);

I2=I;
I3=I2;
I4=I3;
IF=(I4+I3+I2+I)/4 ;  //filtrage numerique du courant
 
}//fin routine


// Boucle correspondant à la fonction main 
void loop() {  

  if ((digitalRead(BP1))==1) {
    PWM=0;               //PWM presque à 0, arret moteur
    }


  if ((digitalRead(BP2))==1) {
//    lcd.setCursor(0,3);      //colonne, ligne
//    lcd.print("BP2");
    digitalWrite(LEDR, LOW);    
    digitalWrite(LEDJ, LOW); 
    PWM=PWM+10;                        //incrementation PWM
//    if ( PWM>254)  {PWM=254;}
    delay(10);               //8bits*10ms=2,5S   pente de l'incremetation 25ssecondes
    }  
    
  if ((digitalRead(BP3))==1) {
//    lcd.setCursor(0,3); 
//    lcd.print("BP3");
     if ( PWM>=0)  { PWM=PWM-5;}   //decrementation PWM
//        delay(100);  
    digitalWrite(LEDR, HIGH);
    digitalWrite(LEDJ, HIGH); 
    } 
    
  if ((digitalRead(BP4))==0) {
    menu++;
    if (menu>1) {menu=0;}
//    lcd.setCursor(0,3);
//    lcd.print("BP4"); 
//delay (100);
    }

************************ 
 if (temps>=1)  {
  lcd.setCursor(0,0);     
  lcd.print(PWM);
  lcd.print(":PWM  ");

  lcd.setCursor(8,0);
  I=I/20;                  //resistance (5/1024)*(10/0.25ohm) si ACS712 66mV/A
                           //pour resistance 0.1ohm (IF)/20;   simulation 5/25
  lcd.print(I,1);
  lcd.print("A   ");

Ba1=analogRead(A0);
Ba1=Ba1*5;
Ba1=Ba1/1023;

Ba2=analogRead(A1);
Ba2=Ba2*5;
Ba2=Ba2/511;
Ba2=Ba2-Ba1;

Ba3=analogRead(A2);
Ba3=Ba3*5;
Ba3=Ba3/367;
Ba3=Ba3-Ba2-Ba1;

Ba4=analogRead(A3);
Ba4=Ba4*5;
Ba4=Ba4/292;
Ba4=Ba4-Ba3-Ba2-Ba1;

Ba5=analogRead(A4);  
Ba5=Ba5*10;         //10/427
Ba5=Ba5/427;
Ba5=Ba5-Ba4-Ba3-Ba2-Ba1;

Ba6=analogRead(A5);
Ba6=Ba6*10;              //10/365
Ba6=Ba6/364;             //coef=(valeur+5*4V)*360/24=
Ba6=Ba6-Ba5-Ba4-Ba3-Ba2-Ba1;   

Ba7=analogRead(A6);
Ba7=Ba7*10;
Ba7=Ba7/316;          //coef=(valeur+6*4V)*152/28=
Ba7=Ba7-Ba6-Ba5-Ba4-Ba3-Ba2-Ba1;

Ba8=analogRead(A7);
Ba8=Ba8*10;
Ba8=Ba8/295;       //coef=(valeur+7*4V)*152/(8*4)=
Ba8=Ba8-Ba7-Ba6-Ba5-Ba4-Ba3-Ba2-Ba1;

Ba9=analogRead(A8);
Ba9=Ba9*10;
Ba9=Ba9/219;
Ba9=Ba9-Ba8-Ba7-Ba6-Ba5-Ba4-Ba3-Ba2-Ba1;

Ba10=analogRead(A9);
Ba10=Ba10*10;
Ba10=Ba10/219;
Ba10=Ba10-Ba9-Ba8-Ba7-Ba6-Ba5-Ba4-Ba3-Ba2-Ba1;

lcd.setCursor(14,0); 
//si il n'y a pas tous les cellules batyteries alors la tesnion sera correcte quand meme
U=Ba10+Ba9+Ba8+Ba7+Ba6+Ba5+Ba4+Ba3+Ba2+Ba1; 

/*U=analogRead(A9);
U=U*10;
U=U/219; */   
lcd.print(U,2);
lcd.print("V  ");

lcd.setCursor(0,1);                     
lcd.print(Ah);
lcd.print("mA.h"); 
lcd.print("   ");   
}




if (menu==0) { 
  if (temps>=1)  {
  //************** affichage des tensions de cellules
lcd.setCursor(0,2);
lcd.print("1:");                           
lcd.print(Ba1,2);
lcd.print("  ");  

lcd.setCursor(8,2);
lcd.print(":");                           
lcd.print(Ba2,2);
lcd.print("   ");  

lcd.setCursor(14,2);
lcd.print(":");                           
lcd.print(Ba3,2);
lcd.print("  ");  
//***********
lcd.setCursor(0,3);
lcd.print("4:");                           
lcd.print(Ba4,2);
lcd.print("   ");  

lcd.setCursor(8,3);
lcd.print(":");                           
lcd.print(Ba5,2);
lcd.print("   ");  

lcd.setCursor(14,3);
lcd.print(":");                           
lcd.print(Ba6,2);
lcd.print("   ");  

temps=0;
}//fin if temps
}//fin menu=0

if (menu==1) { 

lcd.setCursor(0,2);
lcd.print("7:");                           
lcd.print(Ba7,2);
lcd.print("   ");  

lcd.setCursor(8,2);
lcd.print(":");                           
lcd.print(Ba8,2);
lcd.print("   ");  

lcd.setCursor(14,2);
lcd.print(":");                           
lcd.print(Ba9,2);
lcd.print("   ");  

//***************
lcd.setCursor(0,3);
lcd.print("10:");                           
lcd.print(Ba10,2);
lcd.print("            "); 

} 

   
} // fin loop

Maintenant, il reste à gérer la PWM avec la régulation de courant et la limitation de la tension.

charger_battery_open_loop.ino (5.79 KB)

Remarque sur le programme en Boucle ouverte de la PWM précédent

Le temps du déroulement des mesures avec l’affichage dure 6.5ms
La simulation sous ISIS est en temps réel lorsque la PWM est égale à 0. Par contre, dès que la PWM est différent de 0, cela n’est plus le cas car la simulation analogique à 32kHz prend beaucoup de ressource au PC (pas de calcul très petit).
La PWM est à 32kHz pour diminuer la valeur de l’inductance. En effet, la constante de temps électrique doit être 5 fois plus grande que la période de la PWM.
Or, l’inductance L>5TRcharge>(531us(0.05*12+0.1)ohms)=110microHenry
Avec des résistances plus importantes d’élément de batterie, une inductance de 1milli henry est préférable
Avec une PWM de 500 Hz
L>50mH
Mais, avec une PWM de 500Hz, la simulation sous ISIS en temps réel est possible.
On peut observer sur la figure ci jointe l’ondulation de courant avec une PWM à 500 Hz

Programme en boucle fermée

Il existe de nombreux correcteurs pour commander des systémes en automatique.
Le correcteur proportionnel integegral derivée PID) est une base.
Il existe d’ailleurs plusieurs library pour le PID….nous allons utilser celui la
http://playground.arduino.cc/Code/PIDLibrary
https://playground.arduino.cc/Code/PIDLibrarySetSampleTime

Le correcteur de la library ferait le calcul tous les 0.2s, ajustable par la fonction SetSampleTime

#include <PID_v1.h>

#define PIN_INPUT 0
#define PIN_OUTPUT 3

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
double Kp=2, Ki=5, Kd=1;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

void setup()
{
  //initialize the variables we're linked to
  Input = analogRead(PIN_INPUT);
  Setpoint = 100;
SetSampleTime ( 200 )
SetOutputLimits (0,255)


  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}

void loop()
{
  Input = analogRead(PIN_INPUT);
  myPID.Compute();
  analogWrite(PIN_OUTPUT, Output);
}

La library précédente n’utilise pas de float….mais des Int long….
Mais il est très facile de programmer un PID de base. D’ailleurs voici programme qui dure 65micro seconde en float.

erreurP=erreur;                 //erreur precedente ou erreur erreur*Z^Ts  pour faire le calcul de la derive
erreur=Setpoint-I;
Proportionnel=kp*erreur;
Integral= Integral+erreur*ki;
if (Integral>=255) Integral=255;
derive=(erreur-erreurP)*kd;             //derive=(erreur-erreur*Z^Ts)/Ts   avec Ts=Tsampleur

output=Proportionnel+Integral+derive;   //ce n'est pas la peine de divisée par Ts car si Ts est petit cela donne des valeurs enormes 
if (output>=255) {output=255;} 
if (output<=0) {output=0;} 
PWM=output;

Imaginons que l’on désire une consigne indicielle de courant de 10A (donc qui passe de 0 à 10A en 0.1s)
Avec kp=2, Le coefficient donner une valeur de 20 puis diminuera lorsque l’erreur diminuera
Avec kd=1, Le coefficient donnera une valeur de 10 supplémentaire sur le premier échantillon puis étant donné que l’erreur précédente est pratique identique à l’erreur instance, cela ne sert peu dans notre cas.
Avec ki=1, Le coefficient donnera une valeur de 10 supplémentaire puis diminuera puis la valeur intégrale va augmenter jusqu’à ce que l’erreur soit nulle.

Avec le moniteur série, il est possible de visualiser la dynamique des 3 sorties du PID pour une réponse à une rampe de la consigne à cause d’une augmentation de 0.1A tous les de 10ms delays de BP2 en enregistrant les données .csv et en les traçant à partir d’Excel……

Avec les coefficients précédents, on peut observer les valeurs 3 sorties du PID. On peut observer que l’intensité de charge correspond à la consigne grâce au coefficient intégral qui permet d’annuler l’erreur.
On peut observer qu’il y a un courant seulement lorsque la valeur moyenne du hacheur devient supérieure à la tension batterie.
On peut observer que l’intensité ne dépasse jamais la consigne (pas de dépassement, no over shoot) pour les coefficients du PID choisis.

Perspectives :
Pour avoir plus de stabilité, un intégrateur pur avec une zone morte de la commande autour de la consigne de plus ou moins 0.2A permet d’avoir plus de stabilité de la commande

De plus, il faut limiter la tension de seuil en fonction de la technologie choisie de batterie et détecter l’arrêt de la charge.

charger_battery_close_loop.ino (7.59 KB)

Chargeur pour 1 batterie Li-Po avec une carte Arduino Mega 2560.

une carte Arduino Mega 2560 est utilisé mais un carte nano aurait été suffisante.
Mon montage possède un hacheur avec un transistor TIP 127 PNP pour pouvoir mettre une résistance de mesure R1 de 0.5Ω par rapport à la masse pouvant être lu par l’entrée analogique a1 de la carte Arduino.
Matériel :
Pour ce projet nous avons à notre disposition une carte Arduino MEGA, un écran LDC, 4 boutons poussoirs et un hacheur.


Voici le schéma de simulation sous Proteus électronique ISIS.


La mesure de la température se fera par l’intermédiaire d’un capteur lm35 (non gérer par le moment).
J’ai réalisé un premier programme en simulation qui relève la tension et le courant qui sont gérés par la PWM.
Le bouton BP4 permet de mettre en marche le système afin d ‘afficher le courant, la tension et le temps écoulé. Le bouton BP1 incrémente la PWM, le bouton BP2 décrémente la PWM et le bouton BP3 remet à zéro la PWM.

La tension et le courant sont relevés sur les entrées analogiques A0 et A1

Programme Boucle Ouverte :

#include <TimerOne.h>
#include <LiquidCrystal.h>
#include <SoftwareSerial.h>


#define SERIAL_PORT_LOG_ENABLE 1
double  U = 0;  
double  I = 0;
byte PWM=0;
bool flag=0;                 

byte temps=0 ,seconde=0,minute=0,heure=0; 
          
LiquidCrystal lcd(27, 28, 25, 24, 23, 22); // RS=12, Enable=11, D4=5, D5=4, D6= 3, D7=2, BPpoussoir=26

void setup() {
  // put your setup code here, to run once:
  Timer1.initialize(100000);         // initialize timer1, and set a 0,1 second period =>  100 000
  Timer1.attachInterrupt(callback);
#define LEDJ    34 
#define PWM10   10 
#define BP1     30
#define BP2     31                  
#define BP3     32
#define BP4     26

  TCCR2B = (TCCR2B & 0b11111000) | 0x01;         //pin 10  32khz    http://playground.arduino.cc/Main/TimerPWMCheatsheet
                                                  //http://www.pobot.org/Modifier-la-frequence-d-un-PWM.html
  
  
  lcd.begin(20, 4);  
  Serial1.begin(9600);
  
  pinMode(LEDJ, OUTPUT);
      lcd.setCursor(0,1);   //colonne, ligne
      lcd.print("PWM="); 
}

void callback()  //0.1s        
{
  temps++;
  digitalWrite(LEDJ,HIGH);
  analogWrite(PWM10,PWM);   //frequence
  U=analogRead(A3);
  I=analogRead(A1);

  U=(U*5)/1024;
  I= I/100;
}  

void loop() {                
  
  
 

     if (temps==10)    // temps==10
       {
      lcd.setCursor(0,2);
      lcd.print("Tension=");
        lcd.setCursor(10,2);
        lcd.print(U,2);
      lcd.setCursor(0,3);
      lcd.print("Courant="); 
        lcd.setCursor(10,3);
        lcd.print(I,2);  
        }


if (seconde >= 60)
{
minute++;
seconde= 0;
}

if (minute >= 60) 
{
heure++;
minute=0;
} 

if ((digitalRead(BP1))==1) {
    PWM++;            
    lcd.setCursor(7,1);
    lcd.print(PWM);
    if ( PWM>254)  {PWM=254;}
   delay (50);
    } 

 if ((digitalRead(BP2))==1) {
     PWM--;
    lcd.setCursor(7,1);
    lcd.print(PWM);
     if ( PWM<2)  {PWM=2;}  
     delay (50);
    } 
 
 if ((digitalRead(BP3))==1) {
     PWM=0;          
     lcd.setCursor(7,1);
     lcd.print(PWM);
     lcd.print("  ");
      delay (50);
    }
    
 if ((digitalRead(BP4))==0) {    // start stop
      if (flag==1){
        flag=0;
      lcd.setCursor(7,1);
      lcd.print(PWM); 
      lcd.print("  ");
      lcd.setCursor(1,0); 
     // lcd.print("           "); 
      }
      else {flag=1 ;}
      delay (50);                       }

                   

   
   if ( (temps >= 10) && (flag==1)   )
{
  digitalWrite(LEDJ,LOW);
  
    seconde++;
    lcd.setCursor(1,0);
    
    lcd.print(heure);
    lcd.print("h");
    lcd.print(minute);
    lcd.print("min");
    lcd.print(seconde);
    lcd.print("sec");
    temps=0;
    
}
     
  


}//fin loop

Perspectives
Il me reste donc à gérer plusieurs batteries en série, la régulation en boucle fermée, gérer la température.
Grâce aux posts précédents qui m’a bien aidé mais ou j’ai eu des difficultés à comprendre la régulation.

Chargeur 2 éléments NiMH

Le chargeur va se faire en utilisant un hacheur avec une carte arduino. L’arrêt de la charge se fait avec la détection du dV/dt <0 avec un dt de 60s. Mais étant donné que le courant de charge sera de 1/10 de la capacité énergétique même si la détection n’est pas détectée ce n’est pas problématique pour la batterie. Par contre, si le courant de charge est ½ de la capacité énergétique la détection du dV/dt est cruciale
Pour bien comprendre le fonctionnement de la régulation voici le schéma sous simulink téléchargeable sur le lien suivant.

Sur la figure suivante, on peut observer l’augmentation progressive du courant jusqu’à la valeur de la consigne qui est de 1A puis la force électrochimique des batteries passe de 2.4V à 2V ce qui provoque une légère diminution de la tension de la batterie d’où la détection du dV/dt <0 qui correspondra à une charge de 100% de éléments donc de l’arrêt de la charge.


Le temps pour atteindre le courant de consigne est de 25s. La partie intégrale met un certain pour passer à 0 c’est pourquoi ceci se répète pour le courant. On remarque aussi que la Pwm suit la tension de la batterie.

Mais on remarque si le gain à la sortie de la Pwm est égal à 5 on a un temps de 35s pour atteindre le courant de consigne.(Voir ci-dessous)

Cependant après avoir compris le fonctionnement de la régulation grâce au schéma simulink .Voici notre programme arduino en boucle ouverte

1 Programme en boucle ouverte

BP1 permet d’incrémenter le rapport cyclique PWM, BP2 le décrémenter. BP3 mettre le rapport cyclique à 0, BP4 permet de gérer différents menus avec la mesure des tensions de chaque cellule, des courants, PWM donc de gérer l’afficheur.

Voici le programme

#include <LiquidCrystal.h>
#include <SoftwareSerial.h>
#include <TimerOne.h>
 
#define SERIAL_PORT_LOG_ENABLE 1
#define Led     13       // 13 pour la led jaune sur la carte
#define BP1     30       // 30 BP1
#define BP2     31       // 31 BP2           
#define BP3     32       // 32 BP3
#define LEDV    33       // 33 led
#define LEDJ    34       // 34 led
#define LEDR    35       // 35 led
#define relay   36       // 36 relay
#define PWM10    10      //11   timer2 
#define voltag2    
#define voltag1    

LiquidCrystal lcd(27, 28, 25, 24, 23, 22); // RS=12, Enable=11, D4=5, D5=4, D6= 3, D7=2, BPpoussoir=26
// Configuration des variables

//unsigned   int Ub = 0;  // variable to store the value coming from the sensor
double Ub = 0;
double Ib = 0;  
double i=0;
double u=0;
byte PWM=0;
//unsigned    int temps;
byte temps=0 ,seconde=0,minute=0,heure=0;


// the setup function runs once when you press reset or power the board
void setup() {
  pinMode(Led, OUTPUT);   //led carte arduino
  pinMode(LEDV, OUTPUT);
  pinMode(LEDR, OUTPUT);
  pinMode(LEDJ, OUTPUT);
  pinMode (PWM10,OUTPUT);     // broche (10) en sortie  timer2
  

  
//  digitalWrite(LEDV,LOW);
  Timer1.initialize(100000);         // initialize timer1, and set a 0,1 second period =>  100 000
  Timer1.attachInterrupt(callback);  // attaches callback() as a timer overflow interrupt
  lcd.begin(16, 4);  
  Serial1.begin(9600); 

  TCCR2B = (TCCR2B & 0b11111000) | 0x01;         //pin 10  32khz    http://playground.arduino.cc/Main/TimerPWMCheatsheet
                                                  //http://www.pobot.org/Modifier-la-frequence-d-un-PWM.html
  //   analogWriteResolution(bits)      https://www.arduino.cc/en/Reference/AnalogWriteResolution

lcd.setCursor(0,0);   
lcd.print("PWM=");

lcd.setCursor(0,1);
lcd.print("Tension=");

lcd.setCursor(0,2);
lcd.print("Courant=");



}

// Interruptions  tous les 0.1s
void callback()  {
temps++;
 digitalWrite(LEDJ,HIGH);
//toogle state ledv for check 
  if ( digitalRead(LEDV)== 1 ) {digitalWrite(LEDV,LOW);}
    else {digitalWrite(LEDV,HIGH);}
    
analogWrite(PWM10,PWM);   //frequence
Ub=analogRead(A0);
Ib=analogRead(A1);

  
}//fin routine




// Boucle correspondant à la fonction main 
void loop() {  

  // BP + LED
  if ((digitalRead(BP1))==1) {
    //lcd.setCursor(20,0);      //colonne, ligne
    //lcd.print("BP1");
    digitalWrite(LEDR, LOW);    
    digitalWrite(LEDJ, LOW); 
    PWM++;                        //incrementation PWM
    lcd.setCursor(7,0);
    lcd.print(PWM);
    if ( PWM>254)  {PWM=254;}
   // delay(100);              
    }  
    
  if ((digitalRead(BP2))==1) {
   
            PWM--;
    lcd.setCursor(7,0);
    lcd.print(PWM);
     if ( PWM<2)  {PWM=2;}  //PWM presque à 0, arret moteur
    //    delay(100);  
    digitalWrite(LEDR, HIGH);
    digitalWrite(LEDJ, HIGH); 
    
    } 
  if ((digitalRead(BP3))==1) {
    //lcd.setCursor(20,0);
   // lcd.print("BP3"); 
     PWM=0000;               //PWM presque à 0, arret moteur
     lcd.setCursor(7,0);
    lcd.print(PWM);
     
    }
    lcd.setCursor(10,1);
    u= (Ub*5)/1024;        // pas sur de moi ksk j v faire 
    lcd.print(u);
  
    lcd.setCursor(10,2);
   
   i=(Ib/205);
   
    lcd.print(i);

    
    
    
    
    
    
    
    
    if ( temps >= 10 )
{
  digitalWrite(LEDJ,LOW);
  
    seconde++;
    lcd.setCursor(1,4);
    lcd.print(heure);
    lcd.print("h");
    lcd.print(minute);
    lcd.print("min");
    lcd.print(seconde);
    lcd.print("sec");
    temps=0;
    
}

if (seconde >= 60)
{
minute++;
seconde= 0;
}

if (minute >= 60) 
{
heure++;
minute=0;
} 
   
} // fin loop

Résultats de la simulation

Maintenant, il reste à gérer la PWM avec la régulation de courant et la limitation de la tension.
Remarque :
comme dit iutgeiisoissons
La simulation sous ISIS est en temps réel lorsque la PWM est égale à 0. Par contre, dès que la PWM est différent de 0, cela n’est plus le cas car la simulation analogique à 32kHz prend beaucoup de ressource au PC (pas de calcul très petit).
La PWM est à 32kHz pour diminuer la valeur de l’inductance. En effet, la constante de temps électrique doit être 5 fois plus grande que la période de la PWM.

Ce serait intéressant d’avoir un testeur d’accumulateur de batterie NIMH
Mais, il faut aussi une régulation ?

Dans Elektor de fevrier 2010, il y a une présentation d’un testeur mais rien n’est open source….

Il y a aussi de nombreux liens sur le net :
http://lazyelectronics.com/index.php/en/home-en/arduino/item/3-battester-en

La charge des batteries est relativement lente (1 heure) donc les dynamiques de la régulation peuvent être très lentes. La plupart du temps, en régulation, il faut que le temps d’échantillonnage (T sampler) soit très inférieur à la dynamique de la constante électrique. Mais pour un chargeur, c’est le contraire, il faut que le courant est atteint son régime établie puis le correcteur peut agir.

Par conséquent, le correcteur intégral pur discrétisé suivant sera choisi pour avoir une excellente stabilité

Si l’erreur > 0 alors DC(z)= Te/(1-z -1)
Si l’erreur< 0 alors DC(z)=- Te/(1-z -1)
Si ABS (erreur) < DI alors DC(z)= 0 /(1-z -1)

Algorithme précèdent, ce résume en 2 ligne de programmes

if (Setpoint>(I) &&  PWM<254  )  {PWM++;}    
if (Setpoint<(I-0.3)  && PWM>=1)  {PWM=PWM-1;}

On utilisera un terminal pour tracer les courbes des dynamiques du courant de charge, de la PWM en fonction de la consigne. Les données seront enregistrées dans un fichier CSV en ctr+A et Ctrt+C. Puis, tracé dans excel…il est meme possible de le faire avec la simulation sous ISIS

Avec une PWM à 32KHZ et une inductance de 5mH et une periode d’echantilonnage de 0.1s
Il y a une légère oscillation autour de la consigne à cause du filtre passe bas numérique du courant.
On peut observer que le courant met 4 fois plus de temps pour atteindre la consigne par rapport au PID mais ce temps est négligeable par rapport aux temps de charge qui est en générale d’une heure.

On peut observer que la résolution 8 bits de l’Arduino Mega est un peu faible, car un incrément de PWM provoque une augmentation importante du courant
Il faudrait avoir une résolution sur 10 bits avec un Arduino Due.

Avec une période d’échantillonnage de 0.02seconde, mais avec une utilisation la fonction map pour passer à d’incrémentation avec une pwm de 10bits pour passer 8 bits, cela correspondra à un filtre numérique. Donc il faudra pratiquement autant de temps pour atteindre la consigne de 5A. Mais, il n’y a plus d’oscillation de la PWM en régime établi.

On peut comparer les 2 intégrateurs précédents avec un correcteur utilisant une table logique-floue avec un intégrateur. Mais il faudra attendre pour avoir les résultats de cette comparaison.

Bah après 1h de charge complète pour une batterie, c'est déjà pas mal non? Quand on voit le temps que mettent de bêtes téléphones ou PC portables à charger...

Sinon, est-ce qu'il est possible de faire en sorte qu'un seul appareil charge plusieurs types de batteries? En effet, mon fils aîné et moi jouons à l'airsoft ensemble, et utilisons selon le matériel des batteries Ni-MH ET Li-Po, et ce serait cool si on pouvait charger tout d'un coup sans se faire un emploi du temps des chargeurs la veille de la partie!

Il y a 6 PWM dans l’Arduino nano, donc la possibilité de charger 6 batteries avec 6 hacheur évidement mais il faut aussi mesurer les courant et les tensions de chaque batterie……le problème cela va être être la gestion de l’afficheur LCD….
Par contre, 2 chargeur devraient se faire facilement

Bref,
Lorsqu’on fait de la régulation, le temps d’échantillonnage doit être 10 à 100 fois plus rapide que les dynamiques du système à piloter.
Plus, il y a de matériel à contrôler dans un system et plus, il y a du calcul. C’est là où il faut un bien choisir son microcontrôleur.
Mais quels sont les temps d’instructions des fonctions mathématique de l’Arduino ?
Comment le compilateur (IDE) gère le temps des fonctions mathématiques en fonction des variables déclarées ?

On a rien trouver sur le net , ni dans les bouquins….sur les temps d’instructions

donc voici les temps d’instructions pour la catre mega 2560 et la carte nano atm368

Il y a d’autres possibilités d’outil de développement pour programmer l’Arduino, tel que mathlab ou les box sont gratuites :
Voici comment les installer

il y a quelques exemples dans Simulink Support Package for Arduino Hardware :

Voici un astable sous simulink, avec un aruino mega

Si l’on met une période d’échantillon de 1ms en simulation, cela fonctionne bien comme on peut l’observer sur la figure suivante
Par contre, en réel sur la carte méga, le temps sera seulement de 2 ms, ce qui est déjà très bien.

Pourtant en réalité, il est possible de faire beaucoup plus rapide ce qui prouve que mathlab utilise une routine d’interruption de 0.2ms.

Voici une ligne de code pour faire un astable
digitalWrite(Led13, !digitalRead(Led13));
cela peut s’ecrire aussi
if ( digitalRead(LED13)== 1 ) {digitalWrite(LED13,LOW);} else {digitalWrite(LED13,HIGH);}

Une question reste en suspens :
Peut-on changer par programmation dans mathlab, de ce temps minimal de 0.2ms.
Dans les options, il y a bien sample time adjusting
Cela manque de tuto dans mathwork malgré les questions
https://fr.mathworks.com/matlabcentral/answers/321724-optimum-sampling-technique-to-sample-real-data-only-from-arduino?s_tid=srchtitle

Le but à la fin est d’avoir la vitesse d’un PID
Un PID est constitué d’additions, de soustractions, et de multiplication.

Vous avez ci-dessus un tableau récapitulant le temps que prend une carte arduino pour traiter une instruction. Les instructions sont basiques sauf pour le PID. Pour trouver ces valeurs, nous avons défini notre sortie LED sur la pin 13. Nous l’avons mise à 1 avant le calcul et remise à 0 après. On mesure ensuite le temps lorsque la sortie est à 1 en simulation sur ISIS ou en réelle grâce à un oscilloscope. On écrit sur un terminal pour vérifier si le calcul est correct.

Le programme de base est le suivant : la ligne de calcul est à changer ainsi que la déclaration en int ou float.

#define LED 13
int a = 10, b=5,c; //ligne de déclaration
void setup() {
 // put your setup code here, to run once:
pinMode(LED,OUTPUT);
Serial.begin(19200);
}

void loop() {
 // put your main code here, to run repeatedly:
  digitalWrite(LED, 1);
  c=a+b; //ligne de calcul
  digitalWrite(LED, 0);
  Serial.print(c);
  Serial.print("\n\r");
}

Soustraction
c=a-b

Multiplication

c=a*b

Division

c=a/b

/!\ si en int, la valeur sera arrondi a l’entier près.

Exposant

pow(a,b)

/!\ cette commande ne fonctionne correctement que si vous utilisez des floats. Si vous utilisez des entiers, il faudra « caster » le calcul c’est-à-dire forcer le résultat à être en float. On écrira donc
Pow(float(a),float(b));
Le cast ajoute du temps au calcul et il est donc plus rapide d’utiliser des floats.

PID
Nous n’utilisons que des floats pour le PID

#define LED 13
float c;

const float kp = 2;
const float ki = 1;
const float kd = 1;
byte PWM=0 ;
float erreurP = 0;
float erreur = 0;
float Integral = 0;
float derive = 0;
float Proportionnel = 0;
float output = 0;
float Setpoint=0;

void setup() {
 // put your setup code here, to run once:
pinMode(LED,OUTPUT);
Serial.begin(9600);
}

void loop() {
erreurP=erreur;                 //erreur precedente ou erreur erreur*Z^Ts  pour faire le calcul de la derive
erreur=Setpoint-a;
Proportionnel=kp*erreur;
Integral= Integral+erreur*ki;
if (Integral>=255) Integral=255;
derive=(erreur-erreurP)*kd;             //derive=(erreur-erreur*Z^Ts)/Ts   avec Ts=Tsampleur

output=Proportionnel+Integral+derive;   //ce n'est pas la peine de divisée par Ts car si Ts est petit cela donne des valeurs enormes 
if (output>=255) {output=255;} 
if (output<=0) {output=0;} 
PWM=output;
analogWrite(PWM10,PWM);   //PWM
  digitalWrite(LED, 0);
  Serial.print(c);
  Serial.print("\t");
  Serial.println(";");
}

On peut remarquer que les temps de calculs sont plus rapides pour une arduino nano que pour une Mega. Sauf que la carte Méga possède plus de ports. Si vous cherchez la vitesse d’exécution, vous prendrez une nano, si vous avez besoin de beaucoup de pin, vous prendrez une méga.

Voici le programme pour charger 2 batteries lithiums à courant constant, puis à tension constante.
1 résistance de 4,2ohms en parallèle sur chaque élément a été mise pour faire l’équilibrage des batteries. La commande de ces résistances a été faite pas des relais qui permettent de s’affranchir de la commande des masses.

Ces résistances permettent aussi de décharger les éléments à 1 A et de tester la capacité énergétique des éléments. Mais ce n’est pas encore fait en programmation.

Un test de la résistance interne est aussi effectué.
Le fichier isis de la photo suivante est telechargable ici

Le banc de test du chargeur en photo avec ces fils un peu partout

D’abord, Il faut réaliser un typon pour ne plus avoir tous ces fils volants dans tous les sens.

Perspectives ; il faudra faire le programme pour une douzaine d’elements

Le fichier de simulation de la regulation de courant sous matlab des batteries avec les coefficients Arduinos peut etre telechargé ici

Il manque à ajouter un switch pour basculer en regulation de tension et de faire plusieurs choix de valeur de coefficient proportionnel integral.

Edit de jfs : Suppression des liens doute sur l’origine du logiciel
desolé, je ne savais pas

charger_battery_loop_integral_2.ino (8.15 KB)

Bonjour

Remarque : On peut telecharger gratuitement ISIS ici

Quel est le statut des versions versions téléchargeables ci-dessus du point de vue de la license ? S'agit-il de versions légales ou plutôt de versions 'crackées' ? Ces 15 dernières années Labcenter n'était pas connu pour ses "offres gratuites".... un changement récent ?

Je ne sais pas du tout…..si ISIS à changer leur politique….et si c'est une version demo sur le site precedent... Nous on paye une licence pour avoir des bibliothèques à jour…..malgré cela on a des bugs quand meme. Je travaille avec la personne précédente. Ce lien a été mis pour partager le travail sur le forum. mais il y en a d'autres D’ailleurs, on aimerait que IDE Arduino compile le programme en .cof pour pouvoir débuguer le programme pas à pas dans ISIS.

j'ai fait un test de téléchargement./ décompression : logiciel cracké, pas dans l'ethique de ce forum. D'autre part j'ai vérifié : pas de version complète gratuite ni chez Labcenter ni chez le représentant local Mutipower*.*

Je vois que les liens ont été , sans surprise, neutralisés par le modérateur, les logiciels 'crackés' sont bannis de ce forum. Le partage se fait ici sur la base de logiciels multiplateformes et gratuits (pour n'évincer personne) et si possibles libres, open soure. Les différentes réalisations intéressantes présentées par 'iutgeiisoissons' auraient beaucoup plus d'écho si elles n'étaient pas 'formatées' Proteus.

Nous on paye une licence pour avoir des bibliothèques à jour…..malgré cela on a des bugs quand meme. Je travaille avec la personne précédente.

Je connais bien ce type de problème avec ce logiciel en particulier sur les modèles VSM, ça ne justifie pas la diffusion de logiciels crackés, d'autre part la version de demo est sans intérêt

En cour d’ écriture
Intro : Nous voulons déterminer les coefficients PI discrétisé de la régulation de courant précédent avec des périodes d’échantillonnages différente. Sur Arduino, on peut échantillonner facilement avec un ATMEL 328 à 0.1s ou bien 10ms, voire à 1 ms.
On va donc effectuer des essais avec plusieurs valeurs de période d’échantillonnage et différentes valeurs correcteurs.
Nous allons d’abord simuler dans Matlab la régulation de courant, pour ne pas faire de bêtise et détruire les batteries. Notre simulation va être très proche du programme Arduino qui a été fait précédemment.

Essai chargeur avec correcteur PI sous Simulink

Avec un correcteur P.I en analogique, l’équation du courant IB en fonction de la consigne Iconsigne et des paramètres du système Rm, kp, kia, EB, Ualim, P correspond à un premier ordre dont l’équation est la suivante (1) :

Donc en régime final, le courant IB sera bien égale à la consigne sans erreur statique :

La constante de temps de l’asservissement

Evidemment, l’asservissement avec l’Arduino est numérique devrait avoir une fonction de transfert discrétisé en Z mais l’équation (10) est valable si la période d’échantillonnage est très faible par rapport à la constante de temps, mais il y a une différence entre le coefficient intégral analogique et numérique

Exemple si kp=6, kia= kin/Te=4/0.1s=40 alors la constante de temps théorique est de 0.36s alors qu’en simulation et en pratique est de 0.2s
Par contre, avec la période d’échantillonnage de 0.01s, la valeur de kin devra être divisée par 10.
Si kp=6 et kia=10.1 alors la constante de temps théorique devrait être de 1.4s mais en pratique est de 0.5s
Si kp=0 et kia=1
0.1 alors la constante de temps théorique devrait être de 1.4s mais en pratique est de 0.5s
La fonction de transfert discrétisée

En régime final comme en analogique, le courant IB sera bien égale à la consigne sans erreur statique :

Le pôle du dénominateur de la fonction de transfert IB (z) doit être inférieur à 1, pour que l’asservissement soit stable

Donc plus ki est important est plus le pôle sera inférieur à 1, donc meilleur sera la stabilité mais moins bonne sera la rapidité du système1.

La constante de temps de l’asservissement avec la transformation en Z correspond à l’équation suivante

Exemple si kp=6, ki=kin//Te=4/0.1s alors la constante de temps est de 0.27s comme on peut l’observer sur la figure 2, 3, 4
Par contre, avec la période d’échantillonnage de 0.01s, la valeur de ki devra être divisée par 10.
Si kp=6 et ki=4/0.01 alors la constante de temps est toujours de 0.27s.

Voici les dynamiques de cette régulation.

Sur la figure 2, on peut observer qu’il n’y a pas d’erreur statique mais quelques oscillations car la differnce de 1 de la PWM provoque un incrément de 0,11A. on peut observer la zone morte du courant correspondant à la tension du hacheur inferieur à la tensions électrochimique de la batterie. La constante de temps est de τ=0.27s.
Avec Te=0.1, si l’on augmente la valeur intégrale supérieure à 5, il y a une divergence du courant donc instabilité.
La figure 4, permet de vérifier la fonction de transfert analogique
La figure 2 permet de vérifier la fonction de transfert numérique. Il y a un décalage entre la fonction transfert numérique et la simulation réelle à cause du courant négatif qui n’est pas possible avec le hacheur.

Pour voir les autres simulations
Télécharger le dossier d’étude sur le lien suivant :

https://drive.google.com/open?id=1qdHM6_S213kYu8hoVnRF0Qwq8G-lVBET

Afin de changer les paramètre de la fonction analogique plus aisément, on utilise un script.
Pour voir le script
Télécharger le dossier d’étude sur le lien suivant :

https://drive.google.com/open?id=1qdHM6_S213kYu8hoVnRF0Qwq8G-lVBET

Conclusion
Avec ces essais on a pu observer que plus on augmente Ki et plus le système devient rapide mais ce rapproche de l’instabilité. De même, plus on diminue Te, plus on augmente la stabilité et la rapidité du système.

Maintenant que la régulation de courant a été effectué, il faut faire la limitation de la tension de la batterie et de connaitre les nouvelles valeurs du Proportionnel intégral.

Il faut enregistrer les données en réels en programmation.

PROGRAMMATION sous Arduino

Pour avoir le retour d’information du chargeur et pour choisir le courant de consigne, on utilise un afficheur LCD 20x4 avec 4 boutons poussoirs.
On affiche ainsi les valeurs qui nous intéresse pendant la charge soit la tension des deux batteries, la température, le courant de charge ainsi que la capacité.
Les boutons poussoirs servent à démarrer la charge pour BP1, incrémenter et décrémenter le courant de consigne avec BP2 et BP3 ainsi que l’arrêt de la charge avec BP4.

Pour la charge des batteries, on utilise deux résistances de 4.2ohms piloté par deux transistors pour dévier le courant lorsque l’une des deux batteries est chargée.
Avec les résistances de 4,2ohms, le courant dévié maximum est de 1A pour nos relais.
Lorsque l’une des deux batteries est chargée (fin régulation tension), on active le relais correspondant à la batterie afin de dévier le courant. On repart alors en régulation de courant avec une consigne max de 1A pour la charge de la deuxième batterie.
La charge d’une batterie est représentée par le modèle suivant :

le fichier des explications du programme

True_Key.lnk.ino (2.34 KB)

Intéressante l’étude mathématique precedente (analogique et numérique) qui permet de bien choisir les coefficients de la régulation de courant et de tension, avec les simulations

Par contre cela manque d’explication et un algorithme des différents menus serait la bienvenue

Dans les programmes précèdent, l’équilibrage et la charge se fait en même temps.
Donc, il faut limiter le courant de charge à 1A correspondant au courant dévier par la résistance d’équilibrage fait par l’activation relais.
Mais pour faire l’équilibrage, il est plus facile en programmation d’arrêter la charge et décharger la batterie qui est à 4.2V à la même valeur que l’autre batterie.

L’etat de charge des batteries lithiums en pourcentage sera affiché à partir de la tension comme on peut observer avec l’equation suivante

Pour faire le test de l’état santé de la batterie après les avoir chargé à 100%, il faut décharger la batterie à 100% pour connaitre sa capacité énergétique d’où le menu 3 de l’algo suivant et connaitre son état de santé.

Une autre méthode pour déterminer l’état de santé sans décharger à 100% la batterie est l’ICA (incrémental capacity analys)
C’est la courbe de la dérivée de la capacité énergétique par la tension correspondant à l’équation suivante comme indiqué sur l’explication suivante



Algo avec les differents menus

Bouton poussoir 1 :  BP1 choix des differents menus
Menu 1=charge
Menu 2,=equilibrage
Menu 3=decharge
Menu 4=test resistance, test tension et autorisation charge
Menu 5=choix de technologie de batterie et tension de seuil

BP2 increment variable courant pour la charge
BP3 decrement  variable courant pour la charge

BP4 go ou Stop (arret de charge et de decharge)
Il faudra faire un reset du processeur pour remetre les capcité energetique à 0.


Si menu 1 « charge »
si (tension <tension seuil) alors
regulation de courant jusqu’à 50% du courant consigne, integration du courant pour  la capacité energetique, affichage de l’etat de charge.

si (tension batt1 et tension batt2) =tension seuil   alors stop charge
si batt1 =tension seuil et batt2<tension seuil   alors menu 2
si batt2 =tension seuil et batt1<tension seuil   alors menu 2


Si menu 2 « equilibrage »
si batt1 =batt2 alors menu 1 avec consigne de courant 50% du courant precedent.
si batt1 =tension seuil et batt2<tension seuil   alors decharge Batt1 relais 1
si batt2 =tension seuil et batt1<tension seuil   alors decharge Batt2 relais 2


si Menu 3 « decharge »
relais 1 activé jusqu’à ce que la tension batt1 = 3V
relais  2 activé jusqu’à ce que la tension batt2 = 3V
integration de capacité energetique des 2 batteries avec la mesure de la tension divisé par la resistance 

si Menu 4 « test »
mesure resistance interne de la batterie avec la variable du courant de consigne de charge
la courbe de l’ICA sera traité sous excel ou matlab grace à l’enregistrement des données par la liaison serie

si menu 5 « choix de batterie »
choix des differentes tension de seuil max et mini
BP2 increment variable type de batterie
BP3 decrement  variable type de batterie

une partie du programme sur ce lien, mais il reste des choses à faire

charger_battery_loop_integral_menu.ino (10.5 KB)

RÉALISATION DU TYPON

Super :) , à présent nous avons tout ce qu' il faut pour commencer à fabriquer le typon de notre chargeur.

La mesure de la température est effectuée à l’aide d’un capteur LM35 branché directement à la carte Arduino. Comme les entrées analogiques de la carte Arduino sont en résolution 10 bits, on obtient facilement la température : Valeur*(5V/1023)*100=1/2 On doit simplement diviser par deux la valeur obtenue. La résolution finale de la température est de +ou- 0,5°C.

photo LM35:

|500x500

Vous pouvez télécharger ci-dessous le fichier Isis reprenant notre schéma (adapté version PCB) et typon. La liste des composants y est aussi inclus dedans. Attention, ce schéma a été réalisé avec Proteus 8. Si vous n'avez pas Proteus 8 il ce peut que vous rencontrez quelques soucies de compatibilité.

https://drive.google.com/open?id=184IpKNHCqAIuhT0-OgUNn1JK5pi-d_fA

Notre typon étant imprimé on débute le placement des composants.

|500x247

Voilà! les soudure son quasiment terminées, plus que deux éléments à placer

|500x281

Pour avoir plus de stabilité un correcteur flou est facile à implanter dans des microcontrôleurs qui ont peu de puissance de calcul. Il y a des librarys sur la régulation flou sur le net https://blog.zerokol.com/2012/09/arduinofuzzy-fuzzy-library-for-arduino.html

Mais pour commander un chargeur, il n’est pas utile d’avoir une fuzzyfication et une defuzzyfication et les règles peuvent être remplacées par un table de 2 dimensions comme on peut l’observer sur la figure suivante : |500x187

Le floor sont des entrées flous ou les valeurs sont pris par défaut comme dans le programme.

Il faut parametrer le gain de l’erreur k1, le gain de la derivée de l’erreur et le gain de la sortie de la table.

Pour tester le correcteur flou une simple table 3*3 a été réalisée dans un premier temps |500x174

On peut observer que la dérivée de l’erreur reste nulle pratiquement tout le temps, donc que la PWM s’incrémente de 1 jusqu’à ce que l’errer diminue est provoqué une commande de 0 à 1. En régime établi, la commande oscille autour de la consigne. |500x206

Avec une période d’échantillonnage de 0.01s, l’intégration du tableau est 10 fois plus rapide. En régime établi, la commande oscille autour de la consigne

Avec un tableau de 5 par 5, il y a moins oscillation en régime établie. De plus, si l’on diminue le coefficient k3, l’intégration est plus précise donc il y a moins d’oscillation en régime établi. |500x130

Etant donné que la dérivée de l’erreur n’est pas très utilisée, une table à une dimension pourrait être utilisée Mais ce sera pour plus tard.

On décide arbitrairement que si l’erreur est inférieure à 0.2A il n’y a pas de d’incrémentation de la PWM.
Donc à cause du floor de l’entrée de la table k1<consigne/0.2=10
En effet, étant donné que la dimension de la table est de -5 à 5, alors pour la valeur d’entrée de 1 alors il y aura une sortie de 1, donc la PWM s’incrémentera de 1 ou -1.
De plus, pour minimiser les oscillations en régime établi k3 sera choisi à 1/2 pour avoir au moins 2 valeurs de la table pour avoir une incrémentation de 1 de la PWM.

Voici le schéma de la régulation ainsi que le paramétrage de la table.

Plus l’erreur sera grande et plus l’incrémentation sera grande pour augmenter les dynamiques du système.
Donc, lorsque l’erreur sera de 5*consigne alors la sortie de table sera de 20.

On peut observer sur la figure suivante qu’il n’y a pas d’oscillation en régime statique mais qu’il y a une petite erreur statique de 0.1A. DE plus la dynamique est assez rapide.

Avec une période d’échantillonnage de de 0.01s, k1 à 5 alors k3 peut passer à 1/20 pour retrouver les dynamiques précédentes, ainsi que l’erreur statique.
On peut augmenter la valeur de k1 à 11 qui permet d’annuler l’erreur statique mais provoque une oscillation en régime établi. En effet, avec cette d’échelle k1 à 11, la table passe à la valeur 1 et ne reste plus à 0.

Evidement si l’inductance augmente, il y a moins d’oscillation et l’on peut augmenter la valeur de k1 à 40 comme on peut l’observer sur la figure suivante ou l’increment du courant pour un increment de la PWM n’est plus filtré par l’inductance

En synthèse, la régulation avec la logique floue est comme un correcteur intégral mais avec un coefficient non linéaire au niveau de l’erreur. De plus, la logique floue gère mieux les valeurs peu précises ou les parasites de mesures.

REALISATION DES TESTS DE LA MAQUETTE AVEC UN CORRECTEUR PI

Après validation des tests effectué en simulation, on exécute le programme précédent avec le modèle réel avec la même démarche qu’en simulation. A l’aide du moniteur série du logiciel Arduino, on extrait les valeurs de charge obtenue puis on les répertorie sur Excel pour avoir les courbes. Cependant contrairement à la simulation, la consigne de courant passe volontairement de 2A à 1A, car à 2A on a un échauffement important du transistor TIP 127 sur la première maquette d’essai. De plus les tests ont été effectués sur des batteries à fort cyclage, nous offrant ainsi une dynamique de charge/décharge très rapide et une résistance interne élevé. Passer de 2A à 1A nous permet donc de visualiser avec plus de précision des points de fonctionnement précis, tel que par exemple le passage de la régulation tension courant.

Test expérimental à Te=0.1s

Les correcteurs (intégral unitaire et kp=6;ki=6) n’ont pas été testé à cause de leurs défauts (lenteur/stabilité). Les valeurs en tension de chaque batterie à était divisé par 4 et la PWM par 100.
On peut observer sur les figures 1 et 2 un décalage de retard de démarrage du courant qui est liée aux faites que les essais n’ont pas commencées avec les mêmes tensions de batterie (en simulation on avait toujours 7.4V) et que la résistance interne des batteries n’est pas la même (1mΩ en simule contre <20mΩ en pratique). On observe également qu’il n’y pas d’oscillations de courant conformément à la simulation.
A partir de ces essais, la charge fonctionne correctement avec notre le programme. Cependant dès que l’on a commencé l’essai à Te=0.01s des résultat incohérent ont commencé à apparaître. En effet, le temps d’instruction de la routine d’interruption dépassait ce temps Te, ce qui fait que le programme main ne s’exécutait plus. En effet, le temps d’instruction l’affichage LCD vaux 75ms.
Une version de programme avec l’affichage dans le « main », a pu permettre de faire la même chose et diminuer Te à 0.01s est disponible en Piece jointe :

Essai expérimental à Te=0.01s
On peut observer qu’avec un temps d’échantillonnage divisé par 10 et la même valeur de Ki alors les dynamiques sont multipliés par 10 sans être instable.
si l’intégral alors les dynamiques augmentes aussi.

Conclusion :

On peut conclure de ces expériences qu’il y a une bonne cohésion entre nos modèles mathématique, nos simulations et nos essais sur la maquette du correcteur PI. La prochaine étape est d’utiliser le régulateur floue pour plus de stabilité du signal PWM.

sketch_may15b.ino (11.7 KB)