Bonjour à tous,
je travailles sur un projet consistant à faire tourner un moteur BLDC très lentement avec un asservissement.
J'utilise un arduino DUE avec une résolution de sortie pwm en 12 bits.
La vitesse de rotation du moteur dépend de la fréquence de la boucle principale puisque l'on applique sur chaque phase un signal déphasé de 120°.
Les valeurs de chaque pwm sont issues d'un tableau sur 7200 valeurs pour une phase complete (0 - 4095). Elles sont calculées depuis un fichier excel.
J'ai une roue codeuse 2400 tick par tour connectée à la même carte.
Je souhaiterai mettre en place un asservissement basé sur le nombre de tick mesuré toutes les 100ms.
Donc ma fonction est exécuté avec un timer toutes les 100ms, mesure le nombre de tick depuis la dernière fois et ajuste la fréquence de la boucle principale.
Seulement voilà ça ne fonctionne pas.
Le moteur se colle aux seuils Maxi ou mini défini.
Je fixe par exemple une consigne à 137 tick par 100ms (33 tours minutes)
A partir de la je souhaiterai appliquer une valeur au delayMicroseconds pour atteindre la vitesse voulue.
Voici le code que j'ai utilisé : (j'ai volontairement supprimé les valeurs de pwm du tableau car 7200 ça fait beaucoup dans le poste
#include <Streaming.h>
#include <DueTimer.h>
const int EN1 = 4;
const int IN1 = 6;
const int IN2 = 7;
const int IN3 = 8;
const int freq = 10;
const byte enc1 = 12;
const byte enc2 = 13;
unsigned int ticksCodeur = 0;
const int consnbticks = 137;
int cmd = 200;
float erreur_precedente = consnbticks;
float somme_erreur = 0; // Somme des erreurs pour l'int�grateur
float kp = 5; // Coefficient proportionnel
float ki = 1; // Coefficient int�grateur
float kd = 0; // Coefficient d�rivateur
const int tickpt = 2400;
//#define PWM_FREQUENCY 20000
//#define PWM_MAX_DUTY_CYCLE 4095
//#define PWM_MIN_DUTY_CYCLE 0
//#define PWM_RESOLUTION 12
// SPWM (Sine Wave)
const int pwmSin[] = {7200 valeurs de pwm...};
int currentStepA;
int currentStepB;
int currentStepC;
int sineArraySize;
int increment = 0;
boolean direct = 1; // direction true=forward, false=backward
//////////////////////////////////////////////////////////////////////////////
void setup() {
Serial.begin(115200);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(EN1, OUTPUT);
digitalWrite(EN1, HIGH);
//----------------------------interrupt----------------
pinMode(enc1, INPUT);
pinMode(enc2, INPUT);
attachInterrupt(enc1, encpin1, CHANGE);
attachInterrupt(enc2, encpin2, CHANGE);
//Timer3.attachInterrupt(asservissement).start(655040);
Timer3.attachInterrupt(asservissement).setFrequency(freq).start();
//--------------------------------tableau valeur SinPWM----------------
sineArraySize = sizeof(pwmSin)/sizeof(int); // Find lookup table size
int phaseShift = sineArraySize / 3; // Find phase shift and initial A, B C phase values
currentStepA = 0;
currentStepB = currentStepA + phaseShift;
currentStepC = currentStepB + phaseShift;
sineArraySize--; // Convert from array Size to last PWM array number
}
//////////////////////////////////////////////////////////////////////////////
void loop() {
analogWriteResolution(12);
analogWrite(IN1, pwmSin[currentStepA]);
analogWrite(IN2, pwmSin[currentStepB]);
analogWrite(IN3, pwmSin[currentStepC]);
if (direct==true) increment = 1;
else increment = -1;
currentStepA = currentStepA + increment;
currentStepB = currentStepB + increment;
currentStepC = currentStepC + increment;
//Check for lookup table overflow and return to opposite end if necessary
if(currentStepA > sineArraySize) currentStepA = 0;
if(currentStepA < 0) currentStepA = sineArraySize;
if(currentStepB > sineArraySize) currentStepB = 0;
if(currentStepB < 0) currentStepB = sineArraySize;
if(currentStepC > sineArraySize) currentStepC = 0;
if(currentStepC < 0) currentStepC = sineArraySize;
/// Control speed by this delay
delayMicroseconds(cmd);
}
void encpin1()
{
if( digitalRead(enc2) == 0 ) {
if ( digitalRead(enc1) == 0 ) {
ticksCodeur--;
} else {
ticksCodeur++;
}
} else {
if ( digitalRead(enc1) == 0 ) {
ticksCodeur++;
} else {
ticksCodeur--;
}
}
}
void encpin2(){
if ( digitalRead(enc1) == 0 ) {
if ( digitalRead(enc2) == 0 ) {
ticksCodeur++;
} else {
ticksCodeur--;
}
} else {
if ( digitalRead(enc2) == 0 ) {
ticksCodeur--;
} else {
ticksCodeur++;
}
}
}
void asservissement()
{
int tick = ticksCodeur;
ticksCodeur = 0;
//Serial << tick << endl;
// Calcul de l'erreur
somme_erreur += erreur;
float delta_erreur = erreur - erreur_precedente;
erreur_precedente = erreur;
//PID : calcul de la commande
int pid = kperreur + kisomme_erreur + kd*delta_erreur;
// Normalisation et contr�le du moteur
if (pid < 1) pid = 1;
else if (pid > 200) pid = 200;
cmd = 1000 - pid;
Serial << tick << ";" << nb_tour_par_sec << ";" << erreur << ";" << cmd << endl;
}
Voilà si vous avez une idée elle sera la bienvenue.
ça fait quelques jours que je suis la dessus.
Je pense qu'il y a un soucis dans l'échelle des valeurs car quand mon PID vaut 1, le moteur tourne trop vite.
Merci
William