Home check mon CV check Virgile check Photos check Liens check Passe-Temps

Gestion d'un moteur pas à pas

Sylvain DELPORTE
Michaël BOUTINET
Promotion 5

PROJET D'ELECTRONIQUE


Gestion d'un moteur pas à pas


Sommaire

Introduction

1. Le moteur et sa commande

1.1 Présentation du moteur
1.2 La commande
1.2.1 Les divers types de commandes
1.2.1.1 La commande bipolaire
1.2.1.2 La commande unipolaire
1.2.2 Le circuit de commande : le ULN 2068B
1.2.3 Les instructions de commande

1.2.3.1 1ère méthode
1.2.3.2 2ème méthode
1.2.3.3 Solution pour une vitesse maximale

2. Les systèmes de contrôle du rotor

2.1 Le système optique de commande
2.1.1 Le montage électrique
2.1.1.1 La partie émettrice du capteur.
2.1.1.2 La partie réceptrice du capteur.
2.1.2 Gestion informatique de la remise à zéro
2.2 Le potentiomètre sans butée
2.2.1 Le potentiomètre
2.2.2 Instructions de gestion du potentiomètre

3. l’interface informatique

3.1 Présentation de Labwindows
3.2 Présentation de l'interface
3.3 Aspect graphique
3.4 Fonctions

CONCLUSION


Introduction

Comme tous les transducteurs électromagnétiques, les moteurs pas à pas assurent une conversion d’informations. La particularité de ces moteurs est d’assurer un mouvement mécanique incrémental continu. Le but de notre sujet de projet était de gérer la rotation d'un tel moteur, à partir d'un PC et d'une carte d'interface.

Le principe de fonctionnement de l'ensemble est le suivant (voir le schéma en bas de page). L'ordinateur contrôle la position du moteur en lui envoyant des signaux de phase. Ces signaux passent par une carte électronique de commande, qui répartit la puissance sur les différentes bobines.

De plus, l'ordinateur contrôle la position absolue du rotor, avec un potentiomètre sans butée couplé sur l'axe moteur ; la position pouvant être initialisée grâce à un détecteur optique.

L'ensemble est contrôlé par un programme développé en C sous Labwindows, qui permet de gérer facilement la carte d'acquisition et les interfaces graphiques.


1. Le moteur et sa commande
1.1. Présentation du moteur

Le moteur utilisé a pour référence : Escap P532-258 012. Ces caractéristiques remarquables pour la réalisation de la carte de commande sont :

- le nombre de pas par tour : 100,
- le pas angulaire : 3,6° avec une tolérance de ± 5%,
- le courant nominal par phase pour le montage des bobines en série : 0,4 A,
- la résistance par bobine à 20°C : 12W

Le moteur est constitué de quatre bobines disposées comme sur le schéma par rapport au rotor. Il est de type hybride, c’est-à-dire que la configuration des bobines permet à l’utilisateur de pouvoir choisir entre une commande de type bipolaire et une commande de type unipolaire.

Le choix, que nous développerons plus tard, s’est porté sur la commande unipolaire. Nous avons donc du construit un point milieu. Celui-ci se situe au niveau du raccordement des bobines.

Pour obtenir une rotation du moteur, il faut appliquer des niveaux bien définis aux phases. Les deux phases sont alimentées de la façon suivante.


N° du pas

1

2

3

4

Phase A

+

-

-

+

Phase B

+

+

-

-

Sens de rotation

Þ horaire Þ

Ü anti-horaire Ü

Ci-dessous sont représentés les signaux à appliquer sur les phases A et B afin d’obtenir une rotation horaire.

Nous pouvons remarquer le déphasage d’un quart de période entre les deux signaux de commande des phases. Ces signaux vont être générés par la carte Lab-PC1200AI, elle-même commandée par le programme.

Il nous faut donc dans un premier temps réaliser la mini-carte électronique de commande. Puis, nous élaborerons le programme de gestion des signaux.

1.2. La commande 1.2.1. Les divers types de commandes

Il existe deux grandes catégories de commande du moteur pas à pas.

    1.2.1.1. La commande bipolaire

    Cette technique requiert l’emploi de quatre transistors par phase, soit huit pour notre cas. Deux types de configurations sont possibles pour les bobines :

    - les bobines en série,
    - les bobines en parallèle.

    Dans ce cas, le volume de cuivre est utilisé à 100% contrairement à une commande de type unipolaire où il n’est employé qu’à 50%, ce qui entraîne une réduction de moitié du couple disponible.



    1.2.1.2. La commande unipolaire

Cette méthode de commande a des performances moins bonnes comparées à celles du montage bipolaire du fait de l’utilisation limitée du bobinage. La commande unipolaire n’utilise en effet qu’une bobine par phase. Elle se fait entre une extrémité et le point milieu du bobinage. Cela permet néanmoins de simplifier l’électronique de pilotage vu que l’on travaille dans un environnement numérique. Dans ce cas précis, deux transistors sont nécessaires par phase, soit quatre au total.

Ce type de commande est assez simple à mettre en œuvre. Il nous a été demandé de réaliser la commande du moteur avec cette technique. Cette contrainte est due au fait que les émetteurs du composant de commande, le ULN 2068B, sont obligatoirement reliés à la masse. Or si nous devions réaliser la commande en bipolaire, il nous aurait fallu en connecter certains à un potentiel différent de la masse. Un composant, dont les caractéristiques conviennent au montage bipolaire, est le ULN2803A. Il en existe bien évidemment d’autres.

1.2.2. Le circuit de commande : le ULN 2068B

Le composant principal de la commande est un ULN 2068B. Il est composé de quatre montages Darlington. Ce système permet de disposer d’un courant de sortie élevé, tout en ayant une tension d’entrée de commande faible.

Considérons l’un des Darlington de ce circuit intégré monolithique.

Le schéma équivalent est présenté ci-dessous.

Etudions rapidement le fonctionnement de ce circuit.

Lorsque la base du premier transistor est au potentiel nul, le premier transistor est bloqué. Cet état entraîne alors le blocage des deux autres transistors. La borne C est finalement à un potentiel proche de VCC.

En revanche lorsque la base est alimentée par une tension de 5V, le premier transistor est passant, ainsi que les deux autres. La borne C est alors reliée à la masse.

On peut remarquer que le composant ULN 2068B comporte deux systèmes symétriques. Chacun possède une sortie commune notée K, deux bases B correspondant aux entrées des signaux de commande et deux sorties C.

Nous avons vu précédemment que notre commande devait être de type unipolaire. On connecte donc les deux bobines en série et on crée notre point milieu au niveau de cette connexion. Les bobines sont alimentées en ce point avec une tension que l’on déterminera plus tard.

Le fonctionnement utilisé requiert une alimentation alternative des deux bobines branchées en série. Par conséquent, la commande B de la première bobine doit être l’inverse de celle de la seconde bobine. Nous utilisons donc un inverseur (SN74LS04). Lors de la réalisation du système, nous avons pris soin de connecter les deux Darlingtons, dont la borne K est commune, sur la même phase. Les inverseurs sont donc aussi connectés de cette manière (entre les bornes 3 et 6, et les bornes 11 et 15 du ULN2068B).

Le schéma final pour une seule des phases est schématisé ci-dessous (seul les deux derniers transistors du ULN2068B sont représentés. Le signal de commande est un pulse de tension maximale égale à VCC).

  • Schéma d’une partie de la commande d’une phase
  • Sur le schéma on note la présence d’une diode dont le but est de conduire le courant IR lors des transitions. On évite ainsi une surtension au niveau de la bobine. En effet, on ne peut pas mettre une bobine en circuit ouvert si elle est chargée (même faiblement). Un arc électrique se produirait et pourrait endommager le composant.

    Calculons la tension à appliquer sur notre point milieu M.

    Les spécifications du moteur nous donnent :

    - un courant nominal par phase de 0,4 A pour la mise en série des bobines,
    - une résistance par bobine de 12 W.

    Nous savons de plus que la tension VCE est environ égale à 0,6V.
    D’où la tension VCC=VM : 12´ 0,4+0,6 = 5,4V

  • 1.2.3. Les instructions de commande

    Une fois cette carte de commande réalisée, il nous fallait alors la piloter par l'intermédiaire d'une carte d'acquisition en relation avec un PC. Pour cela, nous avons développé un programme en C, sous le progiciel LabWindows/CVI, sur lequel nous reviendrons dans la troisième partie. Nous allons maintenant présenter la façon dont fonctionnent les procédures qui mettent le moteur en rotation.

    1.2.3.1. 1ère méthode

    Nous avons trouvé deux façons de fournir les signaux adéquats. Reprenons le tableau suivant pour expliquer la première manière :


    N° du pas

    1

    2

    3

    4

    Phase A

    +

    -

    -

    +

    Phase B

    +

    +

    -

    -

    Sens de rotation

    Þ horaire Þ

    Ü anti-horaire Ü

    Pour faire tourner le moteur dans le sens horaire, il suffit de passer d'un numéro de pas au suivant (on revient à 1 après 4). Un tour est se fait donc en répétant 25 fois ce tableau (100 pas). Il reste à envoyer les deux signaux de phase A et B sur les deux canaux de sortie de la carte d'acquisition.

    Voici un morceau de listing pour mieux comprendre le déroulement du programme :

    for (j=0;j<nbpas;j++)
    	{
    	if (sens==0)
    		{
    		if (i==4) {i=0;}
    		i=i+1;
    		switch(i)
    				{
    			case 1 : {AO_VWrite (1, 0, tension_max);AO_VWrite (1, 1, tension_max);}break;
    			case 2 : {AO_VWrite (1, 0, tension_max);AO_VWrite (1, 1, tension_min);}break;
    			case 3 : {AO_VWrite (1, 0, tension_min);AO_VWrite (1, 1, tension_min);}break;
    			case 4 : {AO_VWrite (1, 0, tension_min);AO_VWrite (1, 1, tension_max);}break;
    				}
    		}
    

    La variable 'nbpas' correspond au nombre de pas que l'on veut faire tourner le moteur. 'i' est une variable globale, que l'on incrémente à chaque boucle, de façon qu'il reste entre 1 et 4. Ensuite après un test de la valeur de 'i', on envoie des tensions sur les canaux de sortie avec la fonction AO_VWrite(numéro de carte, numéro de canal, tension à appliquer). Nous remplissons ainsi les signaux de phase A et B, en appliquant 0 V ou 4 V sur les canaux 0 et 1.

    Avantage de cette méthode :
    Très souple, permet de ne tourner que d'un pas

    Inconvénient :
    Fréquence de sortie pas très stable en raison d'un temps de calcul qui diffère de l’un des quatre états au suivant, ce qui entraîne un signal de phase assez irrégulier.

    Face aux problèmes de stabilité dès que l'on dépassait une certaine fréquence, il nous a fallu trouver une autre façon de produire les signaux de phases.

    1.2.3.2. 2ème méthode

    La méthode utilisée se trouve dans la fonction acceleration de notre programme, que nous allons décrire :

    acceleration

    Le but de cette fonction est de faire tourner rapidement le moteur, à la vitesse et au sens voulus par l’utilisateur.

    Nous nous sommes rapidement confronté au problème de la vitesse maximum. Si on applique au moteur des signaux de phase très rapides (correspondants à une rotation de fréquence f), il ne peut pas directement tourner à cette fréquence, c’est à dire passer de 0 tours/secondes à f tours/secondes. Pour faire tourner un moteur pas à pas à une vitesse élevée, il est donc nécessaire de l'accélérer, suivant une rampe d’accélération de ce type :


    Nous nous sommes penchés sur une autre fonction que propose CVI, à savoir AOGenerateWaveforms. Celle ci permet de créer un signal à partir d’une séquence, en séparant éventuellement la séquence sur plusieurs canaux. Comme nous utilisons deux canaux et que les deux signaux sont décalés dans le temps, nous avons donc utilisé la séquence, pour le sens direct, sequence[8]={5,5,5,0,0,0,0,5}. Ainsi, considérons la fonction :

    AOGenerateWaveforms (1, "0,1", vitesse, 4, nbtours*25, sequence, &re).

    1 est l’adresse de la carte dans le PC.

    "0,1" signifie que la ‘sequence’ sera répartie sur les canaux 0 et 1.

    vitesse correspond à la vitesse de balayage de la séquence.

    4 est le nombre de bits par canaux.

    nbtours*25 est le nombre d’itération, c’est à dire le nombre de fois que la séquence sera répétée.

    sequence est la variable tableau à balayer.

    La dernière variable re peut être utilisée pour remettre à zéro les signaux, mais nous ne nous intéresse pas dans notre cas.


    Cette méthode augmentait la vitesse de rotation, grâce à une bonne stabilité, mais ne nous permettait pas d'avoir une rampe correcte, qui devait ressembler en gros à ceci :

    Ces perturbations dans la rampe cassaient le rythme du moteur. Par conséquent, il commençait à perdre des pas, et continuait par des mouvements pour le moins chaotiques. Nous n'avons pas réussi à résoudre ce problème, peut être que la programmation logicielle ne permettait pas d'y arriver.

    En résumé, voici les points à retenir de cette fonction AOGenerateWaveforms.

    + rapidité, stabilité

    - Pas de contrôle possible durant les séquences.


    1.2.3.3. Solution pour une vitesse maximale

    Nous avons depuis pensé à un petit circuit électronique, toujours piloté par l'ordinateur. Ce dernier, au lieu de fournir un signal périodique, de fréquence variable, pourrait simplement sortir une tension variable. Le petit dispositif électronique aurait alors pour travail de transformer cette tension en fréquence, sur deux signaux séparés. A partir de ce signal carré, dont la fréquence dépend de tension appliquée à ce circuit (basé sur les charges – décharges d'un condensateur, voir principe de la maquette 3), on crée les deux phases très facilement, avec des simples bascules (ou en VHDL).



    Avantage de cette méthode :


    Après avoir réussi à commander la rotation de notre moteur, nous devions désormais nous occuper du contrôle de la position absolue du rotor par rapport à un zéro défini par une détection optique. Nous avons donc couplé l’arbre de notre moteur avec un disque. Celui-ci était pourvu d’une fente. C’est en l’associant avec un petit système optique que nous allons pouvoir définir un zéro.



    2. Les systèmes de contrôle du rotor

    2.1. Le système optique de commande

    L’intitulé du sujet spécifiait la réalisation d’une initialisation du rotor par une détection optique, dans le but de déterminer à tout moment la position absolue du rotor ; cette détermination s’effectuant alors à l’aide d’un potentiomètre sans butée, que nous verrons après.


    2.1.1. Le montage électrique

    Le montage conçu se base sur l’association d’un capteur optique à fourche infrarouge (HOA 1873-013 Honeywell) avec un disque, entraîné par le moteur, pourvu d’une fente. Cette dernière a pour objectif de couper ou de laisser passer le faisceau lumineux.

    Un signal électrique, dont la valeur est fonction de l’état de la partie réceptrice du capteur, va permettre de savoir si le moteur est sur la position dite de "remise à zéro". Si la fente est en face de la cellule photoélectrique, le signal VSO (noté 'signal_opto' dans le programme) est non nul.

    Le montage électrique final du système optique est schématisé ci-contre.


    2.1.1.1. La partie émettrice du capteur.

    Elle est constituée d’une diode infrarouge (IR) et d’une résistance de protection RE. Sa valeur est déterminée à partir des spécifications d’utilisation de la diode. La différence de potentiel à ces bornes VF doit être de 1,5 V au maximum, pour un courant IF de 20 mA. Vu que nous utilisons une alimentation de 5V, le calcul de la résistance RE nous donne :

    W soit 175W . Nous avons finalement choisi RE=200W , pour nous réserver un peu de marge.

    2.1.1.2. La partie réceptrice du capteur.

    Elle est composée d’un phototransistor NPN avec sortie de type Darlington et d’une résistance RR.

    La documentation donne aussi des spécifications d’utilisation du phototransistor. Pour une tension VCC de 5V et un courant de 1mA, il nous faut ajouter en série une résistance RR de 1kW . Cette dernière a pour but d’obtenir un courant de faible valeur (» quelques mA) traversant le phototransistor lorsque celui-ci est passant, afin d’éviter son échauffement et un risque de détérioration du canal.

    Nous avons finalement choisi RE=1,5kW pour éviter tous risques de surtension ou d’un courant trop élevé.

    Il existe deux configurations possibles pour le système :

    VE=5V.

    Lorsque nous avons essayé le système, nous avons obtenu en sortie une tension VSO de l’ordre de 4V. Cette valeur ne pose aucun problème quant à l’acquisition, car il est possible d’acquérir des signaux analogiques avec la carte.

    2.1.2. Gestion informatique de la remise à zéro

    Fonction remise_a_zero

    La fonction fait une acquisition du signal provenant du détecteur optique. On rappelle que celui-ci renvoie une valeur entre 0 et 4 volts. Notons qu’il est possible, pour une position particulière du disque (proche du zéro), d’avoir une partie de la lumière qui soit transmise au récepteur, on peut alors avoir une tension de plusieurs centaines de millivolts. De ce fait, on considère alors que si la valeur du signal est inférieure à un seuil (ici 1 volt), le disque n’est pas à zéro. Ensuite, la fonction effectue une boucle : tant que le disque n’est pas à zéro, le moteur est tourné de 1 pas dans le sens direct, et le signal du détecteur est à nouveau acquis. Une fois le disque remis à sa position initiale, le témoin (symbolisant une diode) passe du rouge au vert.

    Lors de nos premiers essais de cette commande, nous avons constaté que notre panneau de commande affichait deux zéros. Pour remédier à ce problème, nous avons alors réduit la largeur d la fente en plaçant un morceau de cuivre autocollant de cette manière (le cuivre ne laisse pas passer les rayons infrarouges).

    Cette modification ne suffisait pas car le problème était toujours présent. En visualisant le signal provenant du détecteur optique, lorsqu'on approchait de la position zéro, on obtenait quelquechose de la sorte :

    On peut expliquer cette courbe par le fait que le disque en aluminium possède une certaine inertie. Ainsi, lorsque celui-ci s'arrête au pas i, il continue quelque peu son mouvement vers i+1 : il oscille donc autour de sa position i, ce qui suffit pour que la lumière passe totalement (signal de 4V). Or l'acquisition pour tester le zéro se fait à ce moment, donc le programme considère que le disque est à la position zéro.

    Il a alors fallu positionner précisément la fente, encore plus fine, à cheval sur un seul pas et non plus deux, de la façon suivante :

    2.2. Le potentiomètre sans butée

    2.2.1. Le potentiomètre

    Ce composant électromécanique est constitué d’un anneau métallique résistif et d’un axe couplé à l’axe du moteur, qui agit sur une tige aussi en métal (cf. schéma ci-contre). La résistance entre la masse et la borne commune varie suivant la position de cette tige.

    Le montage électronique équivalent est schématisé ci-dessous. La valeur de a est comprise entre 0 et 1. Nous sommes finalement en présence d’une simple pont diviseur de tension et nous avons donc :


    Lors du 1er essai du potentiomètre avec l’oscilloscope, nous avons constaté au niveau du potentiel Vpo, la présence d’une sinusoïde de fréquence 50 Hz (de valeur moyenne nulle), pour une position particulière de la tige du potentiomètre. Cette situation a provoqué des erreurs au niveau de la carte (acquisition de valeurs négatives). Cette position correspond en fait à la position (1) de la tige sur le schéma ci-dessus. Celle-ci étant flottante, elle fait office d’antenne, ce explique la sinusoïde de 50 Hz.

    Afin de nous affranchir de ce problème, nous avons ajouté une résistance RM au schéma électrique précédent. Ce nouveau montage est schématisé ci-contre.

    Cette modification entraîne un changement au niveau de l’équation régissant Vpo.

    Il nous faut alors choisir la valeur de la résistance RM.

     

    Dans un premier temps, nous avions adopté une résistance RM de très forte valeur (par rapport à R=10kW ) afin d’obtenir, en approximant, la même équation qu’initialement. Etant donné qu’à cette position particulière nous obtenions une tension résultant de perturbations électriques (du bruit) et de valeur trop élevée par rapport à la position suivante, nous avons opté pour une plus petite résistance. Cette dernière a une valeur de 30kW . Ce choix nous a contraint à revoir l’équation de VPo. En effet, avec cette valeur, nous ne pouvons plus considérer l’approximation suivante : RM>>(1-a )´ R avec a Î [0,1]. Par conséquent, il nous a fallu gérer cette non-linéarité lors de la programmation. Nous avons pu observer ce "phénomène" en faisant tourner le moteur d’un tour et en visualisant la borne commune du potentiomètre (cf. graphique ci-contre).

    Afin de déterminer la position du rotor par rapport au zéro correspondant au "zéro optique" mais aussi à VPo=0V, nous avons décidé d’employer le fait que a était compris entre 0 et 1. Si l’on multiplie a par 100 et en prenant la partie entière de ce résultat, on obtient alors facilement le numéro du pas correspondant à la position du rotor.

    L’idée principale est d’acquérir la valeur de VPo grâce à l’interface PC. Puis connaissant aussi celle de VCC, nous allons pouvoir déterminer la valeur de a . On obtient une équation du second degré avec deux racines réelles.

    Seule la solution négative est valable (a Î [0,1]). Nous avons finalement :


    2.2.2. Instructions de gestion du potentiomètre

    Le calcul de la position du rotor est réalisé par l’ordinateur pour chaque échantillon mesuré par la carte d’acquisition.

    void mesure_position()
    {
    double alpha;  /* alpha est le coefficient de la résistance du pot. (compris entre 0 et 1)*/
    int R = 10400,R1=29710;
    float Ve=5.0, Vs, voltage_potentiometre;
    
    AI_VRead (1, 7, 1, &voltage_potentiometre);
    Vs=voltage_potentiometre;
    	if (Vs<=0) {alpha=0;}
    		else
    		{
    		alpha=.5+(R1*Ve-sqrt(R*R*Vs*Vs+R1*R1*Ve*Ve+2*R*R1*Vs*(2*Vs-Ve)))/(2*R*Vs);
    		}
    SetCtrlVal (PANEL, PANEL_controle, Vs);
    SetCtrlVal (PANEL, PANEL_NUMERICGAUGE, 100*alpha);
    }
    

    Cette fonction, appelée par plusieurs fonctions principales, sert à détecter la position du moteur. Ceci demande une acquisition de la tension au potentiomètre, qui permet de trouver 'alpha', par une formule compensant la perte de linéarité (voir partie précédente). Il reste alors à afficher la position en multipliant 'alpha' par 100 pour obtenir un nombre de pas, référencés par rapport à zéro.



    3. l’interface informatique

    3.1. Présentation de Labwindows

    Labwindows est un progiciel conçu pour développer des interfaces de dialogues sous Windows. CVI est une véritable plate forme pour le développement sous Windows, gérant le pilotage d’instruments de mesure.

    Après une rapide prise en main, il est possible de créer des fenêtres graphiques, permettant d’afficher toutes sortes d’informations, et pouvant déclencher tout type de fonctions. Il existe bien entendu un débogueur, et des aides sur la manière d’utiliser chaque fonction, ce qui facilite l’utilisation de ce logiciel.

    L’élaboration passe par les trois types de fichiers suivants :

    3.2. Présentation de l'interface

    En l’absence de cahier des charges, nous nous sommes fixé ce que l’interface devait permettre de faire. Nous avons décidé de proposer trois d’opérations :

    L’utilisateur aura la possibilité de remettre le moteur à une position initiale correspondant au zéro optique.
    L’interface devra présenter quelques contrôles, pour savoir en quelle position se trouve le moteur.

    3.3. Aspect graphique

    Nous avons construit notre interface, claire et suffisamment complète, suivant nos besoins mais aussi pour qu’elle soit utilisable pour n’importe quel utilisateur, même si nous savons la probabilité qu'une personne la réutilise est très faible.

    L'utilisateur choisit parmi les trois opérations décrites brièvement dans le paragraphe précédent, qu'il lance d'un simple clic de souris.

    Pour le contrôle de la position du moteur, on trouve un cadran, indiquant le numéro de pas actuel (référencé par rapport au zéro). Une diode précise si le disque est à sa position initiale (couleur verte, rouge si ce n'est pas le cas). On trouve aussi une fenêtre faisant figurer la tension relevée aux bornes du potentiomètre (cette indication était pour nous à la base).

    Voici un aperçu de l'interface :

    Un clic sur Aide! nous amène à une petite fenêtre de notre création, expliquant brièvement le fonctionnement des commandes.

    3.4. Fonctions

    Voici quelques explications concernant d'autres fonctions de notre programme. Vous pourrez retrouver le listing complet en annexe, celui ci comporte quelques commentaires pour le rendre compréhensible.

    Run (accessible en cliquant dans la fenêtre)

    Lance la fonction tourner en récupérant les valeurs de ‘sens’ et ‘nbpas’ sur l’interface. Elle se termine en effectuant une vérification de la position, avec la fonction verification_zero.

    verification_zero

    Cette fonction simple teste si le moteur est à sa position de zéro. Le résultat de ce test est visible sur l’interface graphique, sous forme de diode (verte si le disque est à zéro, rouge autrement.

    mesure_position

    (voir partie 2.2.1)

    run_sequence

    Après avoir relevé les paramètres des quatre mouvements (‘sens1’ à ‘sens4’ et ‘nbpas1’ à ‘nbpas4’), cette fonction appelle tourner pour chaque rotation. Nous avons placé un délai de quelques millisecondes pour que le moteur aie le temps de s’arrêter avant de repartir dans un autre sens.

    La fonction est terminée par une vérification du zéro.



    CONCLUSION


    L'objectif de ce projet nous semble atteint. La commande en boucle ouverte fonctionne correctement, ainsi que la détection optique. Le potentiomètre nous a posé quelques soucis. Ses caractéristiques techniques limitent le contrôle de la position à un pas, sur tous les types de potentiomètres que nous avons essayés. Si ce composant avait été plus précis, nous aurions pu envisager un asservissement, donc un circuit en boucle fermée. Nous n'avons pas pu faire tourner le moteur très vite car une rampe d'accélération est délicate à générer à partir d'un programme en C (déroulement séquentiel).


    Durant ce projet, nous avons abordé plusieurs domaines, qui ne nous étaient pas particulièrement familiers. Tout d'abord, nous avons géré ce projet en nous fixant plusieurs objectifs à atteindre, avec un délai temporel pour chacun, ce qui représente des contraintes particulières.

    Nous nous sommes familiarisés avec des notions de mécanique, avec des problèmes d'ajustements, de fixation… De plus, nous avons découvert le fonctionnement du moteur pas à pas, ce qui nous a fait comprendre son utilité dans certains domaines d'application (imprimantes, informatique, lecteur de CD, robotique…)

    Nous avons pu aussi apprécier les nombreuses commodités d'utilisation du progiciel Lab/Windows CVI, toutes les aides possibles se trouvant dans une vaste librairie. Il est facile de réaliser des interfaces graphiques agréables, et des commandes de carte d'acquisition (à condition de rester dans des fréquences peu élevées).


    Ce projet nous permis d'appréhender les méthodes de travail, que nous retrouverons dans nos futurs stages.



    ANNEXE

    Listing
    /***************************************************************************************/
    /** GESTION D'UN MOTEUR PAS A PAS **/
    /** Sylvain Delporte & Michaël Boutinet **/
    /** NFIO promo 5, 05/1998 **/
    /***************************************************************************************/

    /*** Appel des librairies ***/
    #include "easyio.h"
    #include
    #include
    #include
    #include "panel_p.h"
    #include
    #include
    #include

    static int panelHandle;

    /*** DECLARATION DES FONCTIONS ***/
    void tourner(double temps_delay,int nbpas, short int sens);
    void verification_zero(void);
    int remise_a_zero (int panel, int control, int event,
    void *callbackData, int eventData1, int eventData2);
    int run_sequence (int panel, int control, int event,
    void *callbackData, int eventData1, int eventData2);
    int acceleration (int panel, int control, int event,
    void *callbackData, int eventData1, int eventData2);
    void mesure_position(void);

    /*** VARIABLES GLOBALES ***/
    short int i; /* i correspond à la position dans un pas particulier. i varie de 1 à 4 */
    double signal_opto, delay_base=0.002;

    /*** MAIN ***/
    void main ()
    {
    i=1;
    panelHandle = LoadPanel (0, "panel_p.uir", PANEL);
    DisplayPanel (panelHandle);
    RunUserInterface (); /* bascule vers l'interface graphique */
    }

    /*********** fonction testant si le disque est à l'état initial **************/
    void verification_zero()
    {
    float seuil=2.0; /* seuil de détection d'un signal de l'opto */

    AI_VRead (1, 0, 1, &signal_opto);
    if (signal_opto {
    SetCtrlVal (PANEL, PANEL_LED, 0);
    }
    else
    {
    SetCtrlVal (PANEL, PANEL_LED, 1);
    }
    }

    /*** TESTE LA POSITION DU MOTEUR ***/
    void mesure_position()
    {
    double alpha; /* alpha est le coefficient de la résistance du pot. (compris entre 0 et 1)*/
    int R = 10400,R1=29710;
    float Ve=5.0, Vs, voltage_potentiometre;

    AI_VRead (1, 7, 1, &voltage_potentiometre);
    Vs=voltage_potentiometre;
    if (Vs<=0) {alpha=0;}
    else
    {
    alpha=.5+(R1*Ve-sqrt(R*R*Vs*Vs+R1*R1*Ve*Ve+2*R*R1*Vs*(2*Vs-Ve)))/(2*R*Vs);
    }
    SetCtrlVal (PANEL, PANEL_controle, Vs);
    SetCtrlVal (PANEL, PANEL_NUMERICGAUGE, 100*alpha);
    }

    /****fonction envoyant les signaux de phases à la commande par la carte d'acquisition ****/
    void tourner(double temps_delay,int nbpas, short int sens)
    {
    int j;
    float tension_max=4.0;
    float tension_min=0.0;

    for (j=0;j {
    if (sens==0)
    {
    if (i==4) {i=0;}
    i=i+1;
    switch(i)
    {
    case 1 : {AO_VWrite (1, 0, tension_max);AO_VWrite (1, 1, tension_max);}break;
    case 2 : {AO_VWrite (1, 0, tension_max);AO_VWrite (1, 1, tension_min);}break;
    case 3 : {AO_VWrite (1, 0, tension_min);AO_VWrite (1, 1, tension_min);}break;
    case 4 : {AO_VWrite (1, 0, tension_min);AO_VWrite (1, 1, tension_max);}break;
    }
    }
    else
    {
    if (i==1) {i=5;}
    i=i-1;
    switch(i)
    {
    case 3 : {AO_VWrite (1, 0, tension_min);AO_VWrite (1, 1, tension_min);}break;
    case 4 : {AO_VWrite (1, 0, tension_min);AO_VWrite (1, 1, tension_max);}break;
    case 1 : {AO_VWrite (1, 0, tension_max);AO_VWrite (1, 1, tension_max);}break;
    case 2 : {AO_VWrite (1, 0, tension_max);AO_VWrite (1, 1, tension_min);}break;
    }
    }
    Delay (temps_delay);
    void mesure_position();
    }
    }

    /********** Remet le disque à sa position initiale ****************/
    int remise_a_zero (int panel, int control, int event,
    void *callbackData, int eventData1, int eventData2)
    {
    switch (event) {
    case EVENT_COMMIT:
    AI_VRead (1, 0, 1, &signal_opto);
    while (signal_opto<1.0)
    {
    tourner(delay_base,1,1);
    AI_VRead (1, 0, 1, &signal_opto);
    }
    SetCtrlVal (PANEL, PANEL_LED, 1);
    break;
    }
    return 0;
    }

    /** Permet de tourner le disque pas par pas, en fonction de la volonté de l'utilisateur **/
    int run (int panel, int control, int event,
    void *callbackData, int eventData1, int eventData2)
    {
    int nbpas; /* nbpas est le nombre de pas que l'on va décaler le moteur */
    short int sens0;
    switch (event) {
    case EVENT_COMMIT:
    GetCtrlVal (PANEL, PANEL_nbpas, &nbpas);
    GetCtrlVal (PANEL, PANEL_sens, &sens0);
    tourner(delay_base,nbpas, sens0);
    verification_zero();
    break;
    }
    return 0;
    }

    /******** Permet une rotation rapide du moteur ************/
    int acceleration (int panel, int control, int event,
    void *callbackData, int eventData1, int eventData2)
    {
    short int i=1,j, sens0;
    unsigned int nbtours;
    float tours, tension_max=4.0;
    float tension_min=0.0;
    double sequence_directe[8] = {0,5,5,5,5,0,0,0};
    double sequence_indirecte[8]={0,5,0,0,5,0,5,5};
    unsigned long re; /* ne sert absolument à rien, permet seulement au prog de fonctionner*/
    double periode,vitesse;


    switch (event) {
    case EVENT_COMMIT:
    GetCtrlVal (PANEL, PANEL_sens_2, &sens0);
    GetCtrlVal (PANEL, PANEL_vitesse, &vitesse);
    GetCtrlVal (PANEL, PANEL_tours, &nbtours);
    if (sens0==0)
    {
    AOGenerateWaveforms (1, "0,1", vitesse*70.0, 4, 1, sequence_directe, &re);
    AOGenerateWaveforms (1, "0,1", vitesse*80.0, 4, 1, sequence_directe, &re);
    AOGenerateWaveforms (1, "0,1", vitesse*90.0, 4, 1, sequence_directe, &re);
    AOGenerateWaveforms (1, "0,1", vitesse*95.0, 4, 1, sequence_directe, &re);
    AOGenerateWaveforms (1, "0,1", vitesse*100.0, 4, nbtours*25, sequence_directe, &re);
    }
    else
    {
    AOGenerateWaveforms (1, "0,1", vitesse*70.0, 4, 1, sequence_indirecte, &re);
    AOGenerateWaveforms (1, "0,1", vitesse*80.0, 4, 1, sequence_indirecte, &re);
    AOGenerateWaveforms (1, "0,1", vitesse*90.0, 4, 1, sequence_indirecte, &re);
    AOGenerateWaveforms (1, "0,1", vitesse*95.0, 4, 1, sequence_indirecte, &re);
    AOGenerateWaveforms (1, "0,1", vitesse*100.0, 4, nbtours*25, sequence_indirecte, &re);
    }
    verification_zero();
    void mesure_position();
    break;
    }
    return 0;
    }

    /*** Lance le début d'une séquence que l'utilisateur a défini sur l'interface graphique ***/
    int run_sequence (int panel, int control, int event,
    void *callbackData, int eventData1, int eventData2)
    {
    short int sens1, sens2, sens3, sens4;
    short int nbpas1, nbpas2, nbpas3, nbpas4;
    switch (event) {
    case EVENT_COMMIT:
    {
    GetCtrlVal (PANEL, PANEL_sens1, &sens1);
    GetCtrlVal (PANEL, PANEL_sens2, &sens2);
    GetCtrlVal (PANEL, PANEL_sens3, &sens3);
    GetCtrlVal (PANEL, PANEL_sens4, &sens4);
    GetCtrlVal (PANEL, PANEL_sequence1, &nbpas1);
    GetCtrlVal (PANEL, PANEL_sequence2, &nbpas2);
    GetCtrlVal (PANEL, PANEL_sequence3, &nbpas3);
    GetCtrlVal (PANEL, PANEL_sequence4, &nbpas4);
    tourner(delay_base,nbpas1, sens1);
    Delay(delay_base);
    tourner(delay_base,nbpas2, sens2);
    Delay(delay_base);
    tourner(delay_base,nbpas3, sens3);
    Delay(delay_base);
    tourner(delay_base,nbpas4, sens4);
    }
    break;
    verification_zero();
    }
    return 0;
    }

    void aide (int menuBar, int menuItem, void *callbackData, int panel)
    {
    int helpPanel;
    helpPanel = LoadPanel(0, "panel_p.uir", PANEL_HELP);
    InstallPopup(helpPanel);
    GetUserEvent(1, 0,0); /* attend un clic sur le bouton OK*/
    DiscardPanel(helpPanel);
    }

    void quit (int menuBar, int menuItem, void *callbackData,
    int panel)
    {
    QuitUserInterface(0);
    }

    void a_propos (int menuBar, int menuItem, void *callbackData,
    int panel)
    {
    int Panel_apropos;
    Panel_apropos = LoadPanel(0, "panel_p.uir", PANEL_ABOU);
    InstallPopup(Panel_apropos);
    GetUserEvent(1, 0,0); /* attend un clic sur le bouton OK*/
    DiscardPanel(Panel_apropos);
    }

    Désignation des composants utilisés pour ce projet


    Désignation

    référence

    fabricant

    quantité

    Moteur pas à pas

    P532-258 012

    Escap

    1

    PC

    Pentium 133

    Zenith Data systems

    1

    Carte d'acquisition

    Lab PC 1200 AI

    National Instruments

    1

    Carte terminale

    (nappe 50 fils -> 50 bornes)

    TB50

    Armexcel

    1

    Potentiomètre sans butée

    Rotapot 510 10kOhms

    MCB

    1

    Optofourche infrarouge

    HOA 1873-013

    Honeywell

    1

    Circuit de commande

    ULN 2068B

    Motorola

    1

    Inverseur logique

    SN74LS04N

    Motorola

    1

    Condensateurs

    10 nF

    22 µF

     

    3

    1

    Résistances

    200 W

    1.5 kW

    30 kW

     

    1

    1

    1

    Coupleur d'axe

       

    1

    Carte bakélite

       

    2

    Disque aluminium

    diamètre 60 mm, épaisseur 2 mm

     

    1

    Châssis en aluminium, avec support moteur et potentiomètre

    200x126 mm

     

    1

    Connecteur

    DB9

     

    1

    Divers câbles et bornes, support de composant, visserie