Bonsoir,
La boucle d'asservissement PID du brushless avec l'arduino marche de façon satisfaisante.
Les oscillations ne se sentent pas au niveau de la broche en régime permanent.
Il faut régler le PID en douceur.....
Voilà le programme; il est configuré pour fonctionner depuis le moniteur série.
à tester.......
#include <Servo.h> //utilisation librairie servo
#include <SimpleTimer.h> // utilisation librairie simpletimer (voir internet)
// --- Déclaration des constantes ---
const int POS_MIN=1000; // PWM mini en µs selon variateur
const int POS_MAX=1700; // PWM maxi en µs selon variateur
int angle_servo=0;
// --- constantes des broches ---
const int broche_servo=9; // sortie PWM sur broche 9
const int SPINDLE_SPEED=0; // entrée consigne (PWM linux CNC ou PWM Mach3 ou potar) sur broche entrée analogique 0
long clic=1; // entrée logique codeur broche 1
SimpleTimer timer;
// --- Déclaration des variables globales ---
Servo mon_servo;
float vit_consigne=0;
float vit_reponse=0;
float vit_erreur=0;
float vit_compar=0;
float delta_erreur=0;
float erreur_precedente=0;
int octetRecu;
float somme_erreur=0;
int kp=10; // gain reel = gain declare/10
int kd=5; // dérivée reelle = dérivée declarée/10
int ki=8; // intégrale reelle = intégrale declarée/10
int vitesse_max=5000; // vitesse maxi moteur à mesurer -10%
int vitesse_mini=1500; // vitesse mini moteur à mesurer
void setup() {
Serial.begin(9600);
mon_servo.attach(broche_servo, POS_MIN, POS_MAX);
pinMode(broche_servo, OUTPUT);
attachInterrupt(clic, compteur, RISING); // interruption sur front montant du capteur
timer.setInterval(100, asservissement); // interruption pour calcul du comparateur toute les 100ms
timer.setInterval(99, envoi); // interruption pour envoi sur moniteur série toute les 99ms
}
//*******************************************************************
void loop(){
timer.run();
if (Serial.available() > 0) { // consigne envoyée par le moniteur série 2=2000tr/min 3=3000tr/min etc...
// à masquer si entrée par COMMANDE PAR PWM OU POTAR 10k SUR BROCHE1 ...
octetRecu= Serial.read();
if (octetRecu == '0') vit_consigne=0;
if (octetRecu == '1') vit_consigne=vitesse_mini;
if (octetRecu == '2') vit_consigne=2000;
if (octetRecu == '3') vit_consigne=3000;
if (octetRecu == '4') vit_consigne=4000;
if (octetRecu == '5') vit_consigne=5000;
}
}
// *******************************************************************
/* Interruption sur signal du codeur */
void compteur()
{
clic++; // On incrémente dans le compteur le nombre d'impulsion du capteur
}
// *******************************************************************
// Interruption pour calcul asservissement
void asservissement()
{
// COMMANDE PAR PWM OU POTAR 10k SUR BROCHE1 à démasquer...
//consigne=analogRead(SPINDLE_SPEED); // lecture consigne sur 10 bits
//vit_consigne=consigne*vitesse_max/1023; // transformation en tr/min
vit_reponse = clic*600/7; // transformation en tr/min du retour codeur 7 impulsions par tour
clic=0; // remise à zéro du compteur
if (vit_consigne<=10) somme_erreur=0; // raz de l'intégrale à l'arret
clic=0; // remise à zéro du compteur
vit_erreur=vit_consigne-vit_reponse; // calcul de l'erreur proportionnelle
delta_erreur = vit_erreur-erreur_precedente; // calcul de l'erreur dérivée
somme_erreur += vit_erreur; //calcul de l'erreur intégrale
vit_compar= (kp*vit_erreur/10) + (delta_erreur*kd/10) +(somme_erreur*ki/10); // calculcomparateur
erreur_precedente = vit_erreur; // enregistrement vitesse actuelle
angle_servo=map(vit_compar,0,vitesse_max,0,180); // remise à l'échelle
mon_servo.write(angle_servo); // écriture
}
// *******************************************************************
// interruption envoi résultats vers moniteur série
void envoi()
{
if (vit_consigne>0){
Serial.print(vit_consigne, DEC);
Serial.print(" ");
Serial.print(vit_reponse, DEC);
Serial.println(" ");
}
}
// --- Fin programme ---