Un pilote de moteur brusless à base d'attiny






Les moteurs de disques dur sont des moteurs brusless (moteur sans balais). L'avantage de ces moteurs est un rapport poids/puissance important, une longue durée de vie et un relatif silence de fonctionnement. L'inconvenient, c'est qu'ils sont un peu plus compliqués à alimenter qu'un moteur à courant continu classique. Les moteurs de disques durs comportent 3 bobinages avec un point commun. Les bobinages sont fixés au chassis et une cloche munie d'aimants constitue le rotor.

Le moteur ne peut pas s'alimenter en branchant directement une source d'énergie sur les bobinages, il faut alimenter des bobinages séquentiellement et la séquence est particulière si on veut avoir le meilleur rendement. Ce qui nous amène à régler 2 problèmes :


Dans ce petit article je fabriquerai une petite meuleuse en collant un disque de papier de verre sur le plateau du disque dur, mais vous pouvez trouver d'autres applications comme faire un ventilateur, une pompe, animer un montage quelconque, faire une perceuse...


Principe du montage



Voici mon cahier des charges Il faudra donc disposer des éléments suivants :

Un disque dur. Oui, c'est tout l'intérêt de l'article :). Cela dit, n'importe quel moteur brushless avec 3 ou 4 entrées fera l'affaire.

dd-inside.png


Un micro-controlleur genre attiny45 ou attiny85 (un 45 suffit le code est tout petit), avec ce qu'il faut pour le programmer evidemment.

attiny85-2.png


Un potentiometre pour régler la vitesse

potentiometre.png


Un controlleur ESC

ESC-2.png


Une source d'alimentation 12V (bloc secteur, alimentation de labo, vieille alimentation ATX de PC recyclée...)

atx.png


Un disque dur comporte un ou plusieurs plateaux ses lequels les informations sont écrites ou lues via un ensemble de têtes de lecture/écriture fixées sur un bras.

La platine électronique qui équipe le disque dur à plusieurs fonctions.
La plupart des disques durs ne démarrent pas s'ils ne sont pas connectés à un controleur (IDE/SATA/SCSI/etc...), encore moins acceptent de tourner si le bras munis de ses têtes est démonté (après tout, le bras pourrait être en défaut, et cela représenterait un risque de faire tourner les plateaux), ce qui rend la carte électronique du disque inutilisable. Il faut donc trouver un autre moyen pour mettre en route ce moteur brushless.



C'est la qu'intervient l'ESC (Electronic Speed Control). Ce circuit va se charger d'alimenter correctement les différents bobinages du disque dur et nous permettre de régler la vitesse de rotation. Les ESC sont beaucoup utilisés en modélisme pour piloter les moteurs d'hélicoptère ou de drone qui ont la même constitution qu'un moteur de disque dur, mais on les utilise aussi dans des velos ou scooter électrique et même des voitures électrique.



Voici des exemples de séquences qui pourraient être envoyées par l'ESC.

Un modèle simple :

seq1.png


Et un modèle amélioré. Si je devais construire un équivalent de l'ESC, je simulerai une alimentation des bobinages comme sur le schéma suivant :

seq2.png


Cela dit, nous n'avons pas à nous en préoccuper puisque c'est l'ESC qui gère cette partie.

Autre petit détail que gère l'ESC,et ce n'est pas rien, c'est l'envoi de ces séquences au bon moment !!! Et comment peut-il faire pour inverser les phases au bon moment compte tenu du fait que le point commun n'est pas relié et que nous n'avons pas de capteur de position ? L'ESC utilise le bobinage qui n'est pas alimenté pour faire la mesure. Vous vous souvenez des expériences à l'école avec des bobinages et des aimants ? Un bobinage parcouru par un courant crée un champ magnetique qui va attirer l'aimant. Mais l'inverse est vrai aussi, remuer l'aimant devant une bobine crée un courant électrique (c'est le principe de votre dynamo de velo. Enfin sur un vieux velo :) .
Le rotor du moteur brusless est constitué d'aimants et le stator de bobinages. Le circuit de l'ESC, lorsqu'il alimente en courant les bobinages 1 et 2 se met en mesure sur le bobinage 3. Le passage d'un aimant devant le bobinage 3 crée un signal qui est mesurable, c'est comme cela que l'ESC calcule la position relative du rotor. Ensuite, séquence suivante, alimentation des bobinages 2 et 3, mesure sur le 1, puis alimentation des bobinages 3 et 1, mesure sur le 2, etc.....



De manière générale en modélisme les commandes de servos utilise un signal carré de largeur variable (PWM : Pulse Width Modulation) de fréquence 50hz. La largeur d'impulsion se règle entre 1ms et 2ms. Par exemple pour un servo qui permet de régler le positionnement d'un gouvernail, un signal PWM avec une largeur de 1ms positionne le servo sur 0°, un signal de 2ms le positionne à l'opposé sur 180°. C'est le même principe qui sera utilisé pour régler la vitesse du moteur via l'ESC. Un signal de largeur 1ms correspond à la vitesse minimum (l'arrêt en fait) et 2ms correspond a la vitesse maximum du moteur. Toutes les valeurs intermédiaires permettent de régler la vitesse du moteur du minimum au maximum.

De manière générale en modélisme les commandes de servos utilise un signal carré de largeur variable (PWM : Pulse Width Modulation) de fréquence 50hz. La largeur d'impulsion se règle entre 1ms et 2ms. Par exemple pour un servo qui permet de régler le positionnement d'un gouvernail, un signal PWM avec une largeur de 1ms positionne le servo sur 0°, un signal de 2ms le positionne à l'opposé sur 180°. C'est le même principe qui sera utilisé pour régler la vitesse du moteur via l'ESC. Un signal de largeur 1ms correspond à la vitesse minimum (l'arrêt en fait) et 2ms correspond a la vitesse maximum du moteur. Toutes les valeurs intermédiaires permettent de régler la vitesse du moteur du minimum au maximum.

principe.png


Nous allons donc utiliser un attiny pour lire la valeur d'un potentiomètre. Ce dernier sera branché sur la source d'alimentation de l'attiny et sur le curseur nous allons recueillir une tension de 0 à 5V qui sera convertie par un ADC de l'attiny. C'est l'acquisition de cette valeur qui permettra de générer un signal PWM de largeur proportionnelle à la position du potentiomètre. Avec 0V nous aurons une largeur de 1ms, avec 5V un signal PWM de largeur 2ms. Nous utilisons une conversion simple et rapide de 8 bits pour gagner du temps, ce qui permettra d'avoir 256 paliers pour le PWM.

Les branchements de l'ESC :

ESC.png

Voici les pins qui seront utilisées sur l'attiny 85/45 :

attiny-pwm.png

Et voici le schéma final, extrêmement simple.

schematic.png





Mesure de tension du potentiometre



On va faire au plus simple. La source de tension 5V régulée provient du circuit ESC ce qui est bien pratique. On alimente d'abord l'atttiny85 en reliant la broche 4 à la masse et la 8 au +5V. J'ai ajouté une petit condensateur de 100nf pour le decouplage de l'alimentation.

Cette source de 5V est appliquée aux bornes extrêmes d'un potentiomètre de 10K, ce qui nous permet d'avoir une tension variable entre 0V et 5V sur le curseur du potentiomètre. Ce curseur sera relié sur la broche 3 de l'attiny (La broche 3 correspond en interne à la pin 4 mais aussi au convertisseur ADC n°2). Il suffit ensuite de paramètrer le convertisseur, j'ai pris un mode simple avec une résolution de 8 bits. On fait ensuite une petite fonction capable d'aller lire le convertisseur.

Il n'y a pas de procedure setup() dans ce programme, j'ai tout mis dans le main(). Le convertisseur et le timer sont initialisés au début du programme principal.

Pour utiliser les convertisseurs analogique nous devons positionner certains bits du registre ADCSRA.

ADCSRA |= _BV(ADEN) | _BV(ADPS1) | _BV(ADPS0); // ADC Enable and Div 8 prescaler

Maintenant que l'ADC est initialisé nous allons écrire une petite procédure simple pour lire les valeurs. C'est en quelque sorte l'équivalent de la fonction analogRead qui existe sur les arduinos. Mais on l'écrit nous même c'est plus sympathique.

void analogRead() { ADMUX = _BV(ADLAR) | _BV(MUX1); // left shift result and use ADC2 for pot ADCSRA |= _BV(ADEN); // Analog-Digital enable bit ADCSRA |= _BV(ADSC); // Discard first conversion while (ADCSRA & _BV(ADSC)) {}; // Wait until conversion is done ADCSRA |= _BV(ADSC); // Start single conversion while (ADCSRA & _BV(ADSC)) {}; // Wait until conversion is done ADCSRA &= ~_BV(ADEN); // Shut down ADC ValPot=ADCH*8; if (ValPot>2000) ValPot=2000; }




Génération du PWM



On va faire à l'ancienne. Les circuits ATMEL sont prévus pour gérer de la PWM nativement, mais nous allons programmer ca manuellement. D'abord, le PWM est à une fréquence de 50hz. Nous allons donc setter des registres pour avoir l'execution d'une interruption à une fréquence 50hz. Dans cette interruption nous fabriquerons le PWM.

La fréquence du processeur est de 8mhz.

Nous allons utiliser le mode CTC pour le timer 0 (Timer 8 bits). Le mode CTC permet de comparer le timer à un registre et lorsque que les 2 valeurs concordent, on a un branchement sur une interruption et le compteur est remis à zero automatiquement. Pour faire cela on met a 1 le bit WGM01 du registre TCCR0A

Ensuite on autorise le fait qu'une interruption soit déclenchée à chaque fois que la comparaison est valide, c'est le bit OCIE0A qui est à 1 dans le registre TIMSK.

On initialise ensuite le prescaler à 1024, ce qui revient à dire selon les datasheets que nous devons mettre à 1 les bits CS00 et CS02 dans le registre TCCR0B.

Le compteur va donc s'incrémenter à la fréquence de 8Mhz/1024 = 7812 hz environ. Nous allons ensuite mettre le registre de comparaison OCR0A à 156, ce qui fait que la comparaison sera OK à une fréquence de 7812 / 157 (156+1, la valeur 0 compte donc ca fait bien 157) soit 49,76hz, quasiment 50hz ne chipotons pas...
TCCR0A |= (1<<WGM01); // Configure timer 1 for CTC mode TIMSK |= (1<<OCIE0A); // Enable CTC interrupt TCCR0B |= (1<<CS02) | (1<<CS00); // Prescaler clk/1024 OCR0A = 156; // Set CTC pour execution 50hz

Donc, pour résumer, une fois ces registres initialisés, nous avons une redirection automatique sur le vecteur d'interruption TIM0_COMPA_vect à une fréquence de 50hz (peu importe où nous nous trouvons dans le programme principal. Mais bon, c'est un peu le but de l'utilisation des timers...)

Et sur cette redirection nous allons gèrer le PWM. Pour la fréquence de 50hz, c'est déja fait. Par contre il nous reste à régler le problème de largeur et en fait c'est très simple. On passe la pin 0 (ou PB0) à 1.

PORTB |= (1<<PB0); // PIN 0 a l'etat haut
On attend ensuite un certain temps

_delay_loop_2(ValPot+2000);
Et on repasse la pin 0 à 0.

PORTB &= ~(1<<PB0); // PIN 0 a l'etat bas
Rapellez vous que l'ESC attend un PWM dont la largeur est comprise entre 1 et 2ms. Donc, on attend au minimum 1ms même si le potard est à 0. Ensuite suivant la valeur du potentiomètre on attend entre 0 et 1ms en plus.

Etant donné que les attiny sont assez rudimentaires pour les fonctions de delay, on peut toujours se rabattre sur des fonctions qui sont assez bas-niveau comme par exemple la fonction _delay_loop_2(x). Cette fonction execute x fois 4 cycles d'horloge avant de rendre la main.

Donc si le potard est au minimum, on a ValPot=0, nous executons _delay_loop_2(0+2000), qui permet d'attendre 1ms. 1/8000000*2000*4=0,001 soit 1ms.

Si le potard est au maximum, on a ValPot=2000, nous executons alors _delay_loop_2(2000+2000) soit _delay_loop_2(4000), ce qui permet d'attendre 2ms. En effet 1/8000000*4000*4=0,002 soit 2ms.

Nous avons donc bien un signal carré, de fréquence 50hz , donc la largeur varie entre 1ms et 2ms, ce qui correspond parfaitement au besoin de l'ESC.

Etant donné que le PWM est géré automatiquement par interruption, que reste il a faire dans le programme ? simplement une boucle infinie qui lit la valeur du potentiomètre, c'est tout.

while(1) { analogRead(); // read pot value and refresh ValPot }

Et voila ce que donne le signal sur un oscilloscope. Potentiomètre au minimum largeur 1ms :

PWM-1MS.png


Potentiomètre au maximum (largeur 2ms):

PWM-2MS.png


Et voila.

Pour finir voici le code source à télécharger dans votre Attiny85, cliquez sur le lien ci-dessous...

Code source


Voila, c'est fini. zou....