MoteurSynchrone : Différence entre versions
(→Les MLI) |
|||
(35 révisions intermédiaires par le même utilisateur non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
[[Catégorie:Projets]] | [[Catégorie:Projets]] | ||
− | + | = Description du projet = | |
+ | Le but de notre projet est de piloter les trois phases d'un [https://fr.wikipedia.org/wiki/Machine_synchrone moteur synchrone] par le biais du microcontrôleur ATMEGA 32u4 pour participer au challenge [http://www.educeco.net/ 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'''.<br> | ||
+ | Le courant dans le bobinage rotorique engendre un champ magnétique '''Br''' fixe par rapport au rotor. <br> | ||
+ | L'interaction de ces deux champs crée un couple électromagnétique.<br> | ||
+ | Le rotor est alors entraîné à la même vitesse que celle du champ statorique '''Bs''': '''ω=ωs''' (Vitesse de synchronisme).<br> | ||
+ | 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.<br> | ||
+ | Le couple maximal est obtenu pour '''ξ=90°'''. | ||
+ | |||
+ | == Composants utilisés == | ||
+ | |||
+ | ===== Moteur LMT Lehner 3080 ===== | ||
+ | [[Fichier:Leh-lmt3080-1.jpg|gauche|vignette]] | ||
+ | |||
+ | |||
+ | [[Fichier:Platine-leonardo-arduino 275602 1.jpg|vignette|centré| Carte Arduino Leonardo avec microcontroleur 32u4]] | ||
+ | |||
+ | ==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.<br> | ||
+ | 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é. | ||
+ | [[Fichier:Functionnal block diagram|vignette]] | ||
+ | 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. | ||
==={{Bleu| }}=== | ==={{Bleu| }}=== | ||
==={{Bleu| }}=== | ==={{Bleu| }}=== | ||
− | + | = Les MLI = | |
+ | [[Fichier:Carte arduino leonardo.png|vignette|droite|arduino leonardo pinout]]<br> | ||
+ | ===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. <br> | ||
+ | Pour la génération des MLI, d'abord nous avons commencé par une étude [http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7766-8-bit-AVR-ATmega16U4-32U4_Datasheet.pdf de la datasheet du microcontrôleur ATMEGA32u4]. | ||
+ | <br>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. <br> | ||
+ | Nous avons donc utilisé ce timer pour générer 6 [https://fr.wikipedia.org/wiki/Modulation_de_largeur_d%27impulsion MLI]avec une fréquence autour de 8kHz.<br> | ||
<br> | <br> | ||
− | + | ||
− | < | + | [[Fichier:Capture d’écran 2020-11-27 071501.png|vignette|center|Description mode pwm]] <br> |
− | + | 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.<br> | |
− | + | [[Fichier:Deadtime generator.png|vignette|center|Temps_mort]] <br> | |
+ | |||
+ | <br>Aprés avoir étudié la datasheet, nous avons réussi à générer les signaux de tests par le code suivant : | ||
+ | {{boîte déroulante début | Code MLI}} | ||
+ | <source lang=c> | ||
+ | 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); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | </source> | ||
+ | {{boîte déroulante fin}} | ||
+ | |||
+ | === Filtrage === | ||
+ | Nous avons ensuite utilisé un filtre passe bas afin de récupérer la valeur moyenne du signal.<br> | ||
+ | Pour avoir une idée, utilisons un tableau Excel, partant de 36 valeurs (360° du cercle).<br> | ||
+ | |||
+ | [[Fichier:Capture d’écran 2021-04-11 145731.png|vignette|center|tableau mli]] | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | 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: <br> | ||
+ | [[Fichier:Pot.png|vignette|gauche]] | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | <br>{{boîte déroulante début | Code MLI}} | ||
+ | <source lang=c> | ||
+ | |||
+ | #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); | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | </source> | ||
+ | {{boîte déroulante fin}} | ||
+ | |||
+ | ==Le codeur Incrémental == | ||
+ | |||
+ | == MLI + codeur == | ||
+ | |||
+ | [[Fichier:Systeme.jpg|vignette|gauche]] | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | Après l'étude du codeur nous avons donc ressemblé les deux codes pour améliorer la façon de tourner. <br> | ||
+ | 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.<br> | ||
+ | Avec ces altérations le code est donc devenu un peu conséquent: | ||
+ | |||
+ | <br>{{boîte déroulante début | Code MLI + codeur}} | ||
+ | <source lang=c> | ||
+ | |||
+ | #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; | ||
+ | |||
− | </br> | + | |
+ | // 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); | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | </source> | ||
+ | {{boîte déroulante fin}} | ||
+ | |||
+ | = 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.<br> | ||
+ | Nous avons procédé à certaines altérations afin de l'améliorer : <br> | ||
+ | |||
+ | == Asservissement de courant == |
Version actuelle datée du 13 juin 2021 à 20:30
Sommaire
[masquer]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
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
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
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 :