1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
| // Ce code permet d'asservir en position angulaire un moteur à courant continu.
#include <SimpleTimer.h>
SimpleTimer timer; // Timer pour échantillonnage
int motorA;
// définition des sorties
int pwm_mot = 11; // pwm moteur correspond au rapport cycliqe du hacheur : pilotage de la puissance moteur (11 pour le moteur A et 3 pour le moteur B)
int break_mot = 8; // frein moteur : actionne ou libère le frein avec High et Low (8 pour le moteur A et 9 pour le moteur B)
int sens_mot = 13; // sens de rotation du moteur : positif ou négatif avec High et Low (12 pour le moteur A et 13 pour le moteur B)
// définition des entrées
int PinA = 20;//compteur 1
int PinB = 21;//compteur 2
//init echantillonage
unsigned int time = 5; // la mesure du temps démarre à 5ms
const int periode_echantillonnage = 2; // définit la période d'échantillonnage en ms
//init compteur :
signed int codeur = 0; //position de départ=0
//consigne
int consigne=0; // correspond à 1000 pas du codeur
// initialisation des variables de calcul pour le correcteur PID
signed int erreur = 0; //erreur
signed int erreurPrecedente = 0;
signed int somme_erreur = 0;
//Definition des constantes du correcteur PID
float kp = 15; // Coefficient proportionnel
float ki = 5; // Coefficient intégrateur
float kd = 0; // Coefficient dérivateur
/* Routine d'initialisation */
void setup() {
Serial.begin(115200); // Initialisation port COM
// Déclaration des ports de sortie
pinMode(sens_mot, OUTPUT);
pinMode( pwm_mot, OUTPUT );
pinMode( break_mot, OUTPUT );
// Déclaration des ports d'entrée
pinMode(PinA, INPUT); //sortie encodeur
pinMode(PinB, INPUT); //sortie encodeur
// Définition des fonctions nécessaires à la lecture des signaux du codeur
// Interruption de l'encodeur A en entrée 0 (pin 2) A chaque changement d'état sur le pin concerné on fait tourner la routine codeurA ou codeurB
attachInterrupt(3, codeurA, CHANGE);
// Interruption de l'encodeur A en entrée 1 (pin 3)
attachInterrupt(2, codeurB, CHANGE);
analogWrite(pwm_mot, 0); // Initialisation sortie moteur à 0
delay(300); // Pause de 0,3 sec pour laisser le temps au moteur de s'arréter si celui-ci tourne
motorA=timer.setInterval(periode_echantillonnage, asservissement); // Echantillonage pour calcul du PID et asservissement ; la routine est relancée à chaque période d'échantillonnage
Serial.print("setup");
sequence();
}
void loop() {
timer.run(); //on fait tourner l'horloge
}
void sequence(){
consigne=1000;
timer.enable(motorA);
delay(5000);
timer.disable(motorA);
consigne=-500;
timer.enable(motorA);
}
// Cette fonction est appelée à chaque période pour calcul du correcteur PID
void asservissement()
{
time += periode_echantillonnage; // on ajoute la période d'échantillonnage à la variable "Time" pour pouvoir tracer des variables en fonction du temps
erreur = consigne - codeur; // recalcule l'erreur à chaque période d'échantillonnage
somme_erreur += (erreur*periode_echantillonnage); // permet de calculer l'intégrale de l'erreur par une somme (pour le correcteur intégral)
// Calcul de la commande du hacheur : rapport cyclique
signed int rapport_cyclique = kp * (erreur/periode_echantillonnage) + kd * ((erreur - erreurPrecedente)/(periode_echantillonnage*periode_echantillonnage)) + ki * ((somme_erreur)/time); //calcul de la sortie du correcteur PID
erreurPrecedente = erreur; // Ecrase l'erreur précedente par la nouvelle erreur
// Permet de saturer le rapport cyclique du hacheur à 255
if(rapport_cyclique > 255) rapport_cyclique = 255;
else if (rapport_cyclique < -255) rapport_cyclique = -255;
while (true) { // fonction tant que ... pour limiter la durée de l'asservissement à 2 secondes
if (time<5000) {
Tourner (rapport_cyclique); // permet de lancer la fonction "tourner" avec la valeur du rapport_cyclique majorée (cf à la fin du programme)
Serial.print(" moteur");
break; // on sort ensuite de la fonction "while"
}
else {
Tourner (0); // permet de lancer la fonction "tourner" avec la valeur 0 (cf à la fin du programme)
Serial.print(" stop ");
break;
}
}
Serial.print(time); // affiche sur le moniteur les données voulues
Serial.print(" , ");
Serial.println(codeur); // affiche la valeur "codeur" donc la position du chariot (on affiche le nombre de pas du codeur ...)
}
// Interruption appelée à tous les changements d'état de PinA
void codeurA(){
if (digitalRead(PinA)==digitalRead(PinB)) //à chaque changement d'état de PinA, si PinA=PinB alors le sens de déplacement est négatif ; donc on soustrait 1 à la valeur "codeur"
{codeur--;}
else {codeur++;} // ... sinon +1
}
// Interruption appelée à tous les changements d'état de PinB
void codeurB(){
if (digitalRead(PinA)==digitalRead(PinB)) //à chaque changement d'état de PinB, si PinA=PinB alors le sens de déplacement est positif ; donc on ajoute 1 à la valeur "codeur"
{codeur++;}
else {codeur--;} //... sinon on soustrait 1
}
// La fonction "tourner" est lancée pour contrôler le moteur : définition du sens de rotation, libération du frein et envoi du rapport cyclique au hacheur
void Tourner(int rapport_cyclique ){
if (rapport_cyclique > 0) {
digitalWrite(8, LOW); //libère le frein moteur (sortie 8)
digitalWrite(13, HIGH); //indique le sens positif de rotation du moteur (sortie 13)
}
else {
digitalWrite(8, LOW); //libère le frein moteur (sortie 8)
digitalWrite(13, LOW); //indique le sens de rotation négatif du moteur (sortie 13)
rapport_cyclique=-rapport_cyclique; //changement de signe de la commande car la puissance moteur ne peut pas être négative
}
analogWrite( pwm_mot, rapport_cyclique ); //commande le hacheur avec un rapport cyclique compris entre 0 et 255
} |
Partager