MoteurSynchrone
Sommaire
Description du projet
Le but de notre projet est de piloter les trois phases d'un moteur synchrone par le biais du microcontrôleur ATMEGA 32u4 pour participer au challenge educeco.
Ce projet est quand même conséquent une fois que pour piloter un moteur il faut alimenter les bobines statoriques par des courants triphasés de pulsation ω, afin de créer un champ magnétique Bs tournant à la vitesse ωs.
Le courant dans le bobinage rotorique engendre un champ magnétique Br fixe par rapport au rotor.
L'interaction de ces deux champs crée un couple électromagnétique.
Le rotor est alors entraîné à la même vitesse que celle du champ statorique Bs: ω=ωs (Vitesse de synchronisme).
Si le rotor tourne à une vitesse différente, le couple change sans cesse selon que le champ statorique Bs précède ou suit le champ Br et le couple moyen est nul.
Le couple maximal est obtenu pour ξ=90°.
Composants utilisés
Moteur LMT Lehner 3080
Etudes préliminaires
Dans un premier temps, il nous a fallu prendre connaissance et établir les différentes parties du projet, commençant par un schéma fonctionnel
Schéma fonctionnel
Etude de la carte
Nous commencerons par l'étude préliminaire des datasheets du Driver de MOS A4935 et du Microcontrôleur 32U4,ensuite nous établirons un schéma reliant le A4935 et le microcontrôleur, et enfin nous ferons la conception de la carte sur le logiciel Eagle.
Etude du codeur
Etude du code pour les MLI
La génération des signaux MLI est la partie l'une des parties les plus importantes, puisque ces signaux remplaceront les tensions triphasées nécessaires pour tourner un moteur.
Donc, il nous faut générer des MLI à la fréquence souhaitée (Quelques KHz).
Composants utilisés:
- Carte Arduino Leonardo
- Condensateurs
- Résistances
- Potentiomètre
Amélioration du système
Supervision
Etude et réalisation de la carte
Avant de commencer la fabrication de la carte il est important de savoir qu'est-ce qu'un Driver MOS et quel est son utilité.
Le A4935 est un composant conçu pour piloter des transistors MOS sur 3 phrases différentes. Il possède des alimentations séparées pour la logique et les sections analogiques de commande, une alimentation logique régulée de 3 à 5,5V avec une alimentation non régulée de 5,5 à 50V. Il possède également un certains nombre de fonction de protection contre les sous-tensions, les surchauffes et les défauts du pont de puissance. En plus de ces défaut il intègre des moniteurs drain-source pour chaque transistors externe afin de détecter les courts-circuits. Deux sorties FF1 et FF2 sont fournies pour signaler les défauts détectés à un contrôleur externe.
Les MLI
Définition
Nous avons commencé le projet avec une carte demo, ce que nous a permis de faire de testes sur le moteur, pendant la réalisation de notre carte.
Pour la génération des MLI, d'abord nous avons commencé par une étude de la datasheet du microcontrôleur ATMEGA32u4.
La carte Arduino Leonardo, propose un timer (le Timer 4) avec une fréquence d'horloge de l'ordre de 64MHz, 3 sorties PWM avec ses complémentaires et un mode de génération de signaux appelé PWM6 permettant de contrôler un moteur brushless.
Nous avons donc utilisé ce timer pour générer 6 MLIavec une fréquence autour de 8kHz.
Comme tous les transistors ne peuvent pas être pilotés en même temps, il va falloir générer un temps mort afin d'éviter un court circuit.
Aprés avoir étudié la datasheet, nous avons réussi à générer les signaux de tests par le code suivant :
Code MLI
int main()
{
DDRB|=(1<<PB5)|(1<<PB6);// OCR4B 9 ET 10
DDRD|=(1<<PD6)|(1<<PD7);// OCR4D 6 ET 12
DDRC|=(1<<PC6)|(1<<PC7);// OCR4A ET OPOSE 13 et 5
//pwm
TCCR4A|=(1<<PWM4A)|(1<<PWM4B);
TCCR4C|=(1<<PWM4D);
//prediviseur:8
TCCR4B|=(1<<CS42);
///Connection de complementarité entre les broches
TCCR4A|=(1<<COM4A0)|(1<<COM4B0);
TCCR4C|=(1<<COM4D0);
OCR4C=255;//comparaison
OCR4A=100; //rapport cyclique
OCR4B=100;
OCR4D=100;
// TEMPS MORT
DT4 =0x80;
while(1)
{
OCR4A++;
OCR4B++;
OCR4D++;
_delay_ms(20);
}
}
Filtrage
Nous avons ensuite utilisé un filtre passe bas afin de récupérer la valeur moyenne du signal.
Pour avoir une idée, utilisons un tableau Excel, partant de 36 valeurs (360° du cercle).
Ensuite, nous avons pris les valeurs des l'angle des trois tableaux et rajouté au code, avec un poentiomètre pour aider à faire varier la vitesse de rotation:
Code MLI
#include"avr/io.h"
unsigned char tab_v1[36]={127,149,170,190,208,224,236,246,252,254,252,246,236,224,208,190,170,149,127,104,83,63,45,29,17,7,1,0,1,7,17,29,45,63,83,104};
unsigned char tab_v2[36]={236,224,208,190,170,149,127,104,83,63,45,29,17,7,1,0,1,7,17,29,45,63,83,104,127,149,170,190,208,224,236,246,252,254,252,246};
unsigned char tab_v3[36]={17,7,1,0,1,7,17,29,45,63,83,104,127,149,170,190,208,224,236,246,252,254,252,246,236,224,208,190,170,149,127,104,83,63,45,29};
int i;
int pot;
int valPot;
void setup()
{
DDRB|=(1<<PB5)|(1<<PB6);// OCR4B 9 ET 10
DDRD|=(1<<PD6)|(1<<PD7);// OCR4D 6 ET 12
DDRC|=(1<<PC6)|(1<<PC7);// OCR4A ET OPOSE 13 et 5
//init config timer : Une fois les fonctions Arduino utilisées, on doit mettre à 0 les valeurs des registres.
TCCR4A=0;
TCCR4B=0;
TCCR4C=0;
//pwm
TCCR4A|=(1<<PWM4A)|(1<<PWM4B);
TCCR4C|=(1<<PWM4D);
//prediviseur:8
TCCR4B|=(1<<CS42);
///Connection de complementarité entre les broches
TCCR4A|=(1<<COM4A0)|(1<<COM4B0);
TCCR4C|=(1<<COM4D0);
OCR4C=255;//comparaison
OCR4A=100; //rapport cyclique
OCR4B=100;
OCR4D=100;
// TEMPS MORT
DT4 =0x80;
}
void loop() {
pot=analogRead(A0);
valPot=pot/32;
if(i==36)i=0;i++;
OCR4A=tab_v1[i]/8;
OCR4B=tab_v2[i]/8;
OCR4D=tab_v3[i]/8;
delay(valPot);
}
Le codeur Incrémental
MLI + codeur
Après l'étude du codeur nous avons donc ressemblé les deux codes pour améliorer la façon de tourner.
Le codeur permet de connaître la position des aimants du rotor et donc celle du champ rotorique. Les information s qu'il fournit permettent au système de commande d'alimenter les enrôlements adéquats via les transistors.
Avec ces altérations le code est donc devenu un peu conséquent:
Code MLI + codeur
#include"avr/io.h"
unsigned char tab_v1[36]={127,149,170,190,208,224,236,246,252,254,252,246,236,224,208,190,170,149,127,104,83,63,45,29,17,7,1,0,1,7,17,29,45,63,83,104};
unsigned char tab_v2[36]={236,224,208,190,170,149,127,104,83,63,45,29,17,7,1,0,1,7,17,29,45,63,83,104,127,149,170,190,208,224,236,246,252,254,252,246};
unsigned char tab_v3[36]={17,7,1,0,1,7,17,29,45,63,83,104,127,149,170,190,208,224,236,246,252,254,252,246,236,224,208,190,170,149,127,104,83,63,45,29};
int teta;
unsigned int pot;
unsigned int valPot = 0;
unsigned const int valeurMaximaleCapteur=499;
volatile int valeur;
volatile char change=0;
const uint8_t pinLedV = 11;
void Interrupt() {
change=1;
if ( (bit_is_set(PINB, PB4) == 0))
{ //regarde le front montant
if ( valeur == valeurMaximaleCapteur ) {
valeur = 0;
}
else {
valeur++;
}
}
if ( (bit_is_clear(PINB, PB4) == 0))
{ //regarde le front descendant
if ( valeur == 0) {
valeur = valeurMaximaleCapteur;
}
else {
valeur--;
}
}
}
void Interrupt1() {
change=1;
if ( bit_is_set (PIND, PD0) ) { //Top Tour
valeur = 0;
}
}
void setup() {
//CONFIGURATION DES SORTIES
DDRB|= (1<<PB5)|(1<<PB6);//9 et 10
DDRD|= (1<<PD6)|(1<<PD7);//6//12
DDRC|= (1<<PC6)|(1<<PC7);//13/5
pinMode(pinLedV, OUTPUT);
// Codeur
Serial.begin (9600);
Serial.println ("Debut");
//attendre top tour
loop_until_bit_is_set (PIND,PD0);
attachInterrupt(0, Interrupt1, CHANGE); //top tour
digitalWrite(pinLedV,HIGH);
attachInterrupt (1, Interrupt, RISING); //front montant
delay(5000);
do
{
pot=analogRead(A0);
}while(pot<980);
//init config timer
TCCR4A=0;
TCCR4B=0;
TCCR4C=0;
// MODE PWM
TCCR4A|=(1<<PWM4A)|(1<<PWM4B);
TCCR4C|=(1<<PWM4D);
//TCCR4D &=~ (1<<WGM41)|(1<<WGM40); // ON PEUT LAISSER CETTE CONFIGURATION
TCCR4B|=(1<<CS41)|(1<<CS40);
// TEMPS MORT
TCCR4B|=(1<<DTPS41)|(1<<DTPS40);
// CONNEXION DE COMPLEMENTARITE ENTRE LES BROCHES
TCCR4A|=(1<<COM4A0)|(1<<COM4B0);
TCCR4C|=(1<<COM4D0);
//VALEUR MAXIMALE DU COMPTEUR
OCR4C=255;//comparaison
OCR4A=100; //rapport cyclique
OCR4B=100;
OCR4D=100;
// TEMPS MORT
DT4 =0x80;
///////////
}
void loop() {
static uint8_t cpt=0;
cpt++;
if (change!=0)
{
change=0;
Serial.println (valeur); // angles lus par le codeur
delay(20);
int32_t angleRotor=(valeur*36)/250;
pot=analogRead(A0);
valPot=pot/8+1;
teta=angleRotor+18;
if (teta>35) teta=teta-36;
if (cpt==0)
{
Serial.print (valPot); // angles lus par le codeur
Serial.print(" ");
Serial.print (angleRotor); // angles lus par le codeur
Serial.print(" ");
Serial.println (teta); // angles lus par le codeur
}
OCR4A=tab_v1[teta]/valPot;
OCR4B=tab_v2[teta]/valPot;
OCR4D=tab_v3[teta]/valPot;
//delay(valPot);
_delay_ms(1);
}
Amélioration du système
Jusqu'ici nous avons réussi à créer un champ tournant et engendrer la rotation du rotor. Mais notre système n'est pas tout à fait parfait.
Nous avons procédé à certaines altérations afin de l'améliorer :