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 :
alimenter correctement chacun des bobinages
le faire au bon moment (on doit s'avoir en permanence où nous en sommes...)
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
on ne garde que le moteur du disque dur avec son ou ses plateaux. On débarrasse le chassis de tout ses accessoires (platine de commande, aimants, têtes de lecture)
réglage de la vitesse avec un potentiomètre
utilisation d'un ESC pour la partie puissance du disque dur. L'ESC prend un signal PWM en entrée pour gèrer la vitesse du moteur
génération d'un signal PWM avec un attiny
alimenter le tout avec 12V
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.
Un micro-controlleur genre attiny45 ou attiny85 (un 45 suffit le code est tout petit), avec ce qu'il faut pour le programmer evidemment.
Un potentiometre pour régler la vitesse
Un controlleur ESC
Une source d'alimentation 12V (bloc secteur, alimentation de labo, vieille alimentation ATX de PC recyclée...)
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.
D'abord elle se charge de faire tourner les plateaux à une vitesse constante (de 5000 à 7500 tours pour les HDD grand public mais certains disques dur pros tournent jusqu'a 15000 tours.).
une fois que les plateaux sont en mouvement, les têtes de lectures se chargent d'écrire ou de lire les données, la platine électronique se charge donc aussi des déplacements des têtes et des séquences le lecture/écriture.
Suite à un choc externe, ou une coupure/micro-coupure d'alimentation, la platine se charge de parquer les têtes (elles se rangent automatiquement sur le coté afin de limiter les dégats) et ralentir la vitesse du disque jusqu'a l'arrêter si besoin est.
enfin le circuit sert bien évidemment d'interface avec le reste de l'ordinateur pour transmettre et recevoir les données
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.
L'ESC est branché à une source d'alimentation, j'ai choisi 12V, cela permet de faire tourner le moteur à une vitesse assez rapide.
Ensuite, les 3 fils de sorties de l'ESC sont reliés aux 3 points extremes des bobinages du disque dur (le point commun des 3 bobinages n'est pas utilisé).
L'entrée PWM est reliée à une sortie de l'attiny
pour finir l'attiny est alimenté en 5V via le régulateur intégré de l'ESC.
Voici des exemples de séquences qui pourraient être envoyées par l'ESC.
Un modèle simple :
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 :
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.
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 :
Voici les pins qui seront utilisées sur l'attiny 85/45 :
GND : masse du circuit, relié à la masse alimentation et les 2 masses ESC
VCC : masse du circuit, relié à la sortie 5V de l'ESC
PWM : sortie du signal PWM. A relier sur l'entrée PWM de l'ESC
ADC2 : convertisseur analogique numerique 2. A relier sur le curseur du potentiomètre de réglage de vitesse
Et voici le schéma final, extrêmement simple.
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.
ADEN : permet d'activer le convertisseur analogique/numérique
ADPS1 et ADPS2 : voir page 136 du datasheet. Permet d'avoir un facteur de division de 8 entre l'horloge de l'attiny et l'horloge d'entrée de l'ADC.
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.
ADMUX : on met a 1 les bits ADLAR et MUX1 afin d'utiliser le convertisseur ADC2 qui correspond à la broche physique n°3. Les données sont shiftées, le résultat sera sur 8 bits.
ADCSRA : on met à 1 les bits ADEN et ADSC pour lancer une premiere conversion. La boucle while permet d'attendre la fin de la conversion (il faut attendre que le bit ADSC du registre ADCSRA repasse à zero) Vous remarquerez qu'on le fait 2 fois de suite. On laisse tomber la premiere conversion.
Ensuite on arrête le convertisseur en mettant à zero le bit ADEN du registre ADCSRA.
ADCH contient la valeur mesurée. Comme il s'agit d'une valeur 8 bits seul ce registre est nécessaire, inutile de lire ADCL. Nous multilions cette valeur par 8 (ce qui doit nous donner une valeur entre 0 et 2040) et nous la limitons à 2000 maximum. Pourquoi 2000 ? Parce que nous utiliserons une fonction de delay qui multipliée par 2000 nous donnera 1ms, nous verrons cela plus loin... La valeur lu est stockée dans ValPot qui est déclarée en volatile afin de pouvoir être utilisée dans une interruption (cela dit, on écrit pas dans ValPot à l'interieur de l'interruption donc ce n'est pas forcément nécessaire de la passer en volatile)
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...
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 :
Potentiomètre au maximum (largeur 2ms):
Et voila.
Pour finir voici le code source à télécharger dans votre Attiny85, cliquez sur le lien ci-dessous...