Βηματικοί κινητήρες (Stepper motors).

Κάτι έψαχνα να βρω προχθές… Ανοίγω ένα κουτί παπουτσιών και τι βλέπω… Βηματικούς κινητήρες που κατά καιρούς έχω αφαιρέσει από διάφορες μηχανές γραφείου.

Stepper Motors

Είχα γράψει πριν λίγο καιρό για τους σερβοκινητήρες. Οι βηματικοί κινητήρες είναι μία άλλη κατηγορία κινητήρων που μπορούμε να ελέγχουμε με ακρίβεια την θέση τους. Η σημαντικότερη διαφορά με τους σερβοκινητήρες είναι πως δεν χρειάζονται κάποιο μηχανισμό ανατροφοδότησης.


Άρθρο της Wikipedia για τους βηματικούς κινητήρες.
Τεκμηρίωση του ATtiny13.
Τεκμηρίωση του CEP76139.

Η συνηθέστερη μορφή βηματικών κινητήρων αποτελούνται από έναν οδοντωτό μαγνητικό ρότορα και από 2 (bipolar κινητήρας) ή 4 (unipolar κινητήρας) πηνία (στάτορας). Ο ποιο εύκολος τρόπος να καταλάβετε πως είναι είναι να δείτε τις παρακάτω φωτογραφίες.

Rotor DSC01328 DSC01329 Stator

Δεν θα μπω αναλυτικά στο πως ακριβώς λειτουργούν οι βηματικοί κινητήρες. Στα δύο παρακάτω βίντεο εξηγείται με πολύ όμορφο τρόπο η λειτουργία τους.

http://pcbheaven.com/wikipages/How_Stepper_Motors_Work/

Για την δοκιμή των βηματικών κινητήρων (unipolar είναι) για ένα πλήρες βήμα (με την μέγιστη ροπή του κινητήρα) πρέπει να ενεργοποιούμε ταυτόχρονα δύο από τα πηνία 4 πηνία. Αν για παράδειγμα τα πηνία μας είναι A, B, C, D με την διάταξη που βλέπουμε στην παρακάτω εικόνα (Τα Vd είναι η κοινή τροφοδοσία), πρέπει να ενεργοποιήσουμε αρχικά (για ένα βήμα) τα A,C. Για το επόμενο βήμα πρέπει να ενεργοποιήσουμε τα B,C. Στην συνέχεια τα B,D και τέλος τα A,D. Επαναλαμβάνοντας την σειρά αυτή ο κινητήρας θα κινητέ ένα βήμα την φορά προς μία κατεύθυνση (έστω δεξιόστροφα). Αν θέλουμε να αλλάξουμε κατεύθυνση αρκεί να εκτελέσουμε την σειρά ανάποδα. Αν για παράδειγμα είμαστε στην κατάσταση που είναι ενεργοποιημένα τα B,C θα πρέπει να πάμε στην A,C μετά στην A,D κ.τ.λ.

DSC01331

Παρακάτω βλέπουμε και το κύκλωμα. Για την οδήγηση των πηνίων του βηματικού κινητήρα χρησιμοποίησα 4 n-MOSFET (CEP76139) από ένα παλιό UPS και έναν μικροελεγκτή ATtiny13. Η τροφοδοσία των πηνίων είναι ξεχωριστή (4 volt περιορισμένη στα 700 mAmperes, καθώς δεν βρήκα ακριβώς τα στοιχεία του κινητήρα). Κάθε πλήρες βήμα του κινητήρα είναι 1,8 μοίρες (μία πλήρης περιστροφή 200 βήματα).

Label

Schematic

Στον κώδικα για την εκτέλεση του βήματος χρησιμοποιούμε την συνάρτηση makeStep(uint8_t step) που δέχεται σαν όρισμα έναν μη προσημασμένο (uint) ακέραιο (0 έως 3 οι “χρήσιμες” τιμές). Στον κύριο βρόχο του κώδικα χρησιμοποιούμε μία μεταβλητή i τύπου int που την αυξάνουμε ή την μειώνουμε, και στέλνουμε στην συνάρτηση makeStep το αποτέλεσμα i%4 (modulo operation) που δίνει τιμές 0 έως 3. Ανάλογα με την τιμή η συνάρτηση ενεργοποιεί τις αντίστοιχες (switch case) πόρτες. Έτσι αν η επόμενη τιμή του i είναι μεγαλύτερη από την προηγούμενη (έστω i=33, 33%4=1. i++=34, 34%4=2. i–=32, 32%4=0) ο κινητήρας εκτελεί ένα βήμα εμπρός. Αν είναι μικρότερη ένα βήμα πίσω.

#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <util/delay.h>

/*
   Δεν χρησιμοποιώ το PB2 διότι είναι και το SCK
   και κάθε φορά έπρεπε να αφαιρώ το LED για να
   προγραμματίσω τον μικροελεγκτή.
*/
#define A PB0
#define C PB1
#define B PB4
#define D PB3


void makeStep(uint8_t step);

int main(void)
{

    // A,B,C,D ως έξοδοι.
    DDRB |= (1<<A)|(1<<B)|(1<<C)|(1<<D);

    // Βοηθητική μεταβλητή ().
    int16_t i=0;


    while(1){

        while (i<=20){
            makeStep(i%4);
            i++;
            _delay_ms(500);
        };

        while (i<=50){
            makeStep(i%4);
            i++;
            _delay_ms(50);
        };

        _delay_ms(1000);

        while(i>=0){
            makeStep(i%4);
            i--;
            _delay_ms(5);
        };

        _delay_ms(1000);

        while (i<=200){
            makeStep(i%4);
            i++;
            _delay_ms(5);
        };

        _delay_ms(500);

        while(i>=0){
            makeStep(i%4);
            i--;
            _delay_ms(2);
        };
        i=0;
    };

    return 0;
}

void makeStep(uint8_t step){

    switch (step){

        case 0:
            PORTB |= (1<<A)|(1<<C);
            PORTB &= ~((1<<B)|(1<<D));
            break;

        case 1:
            PORTB |= (1<<B)|(1<<C);
            PORTB &= ~((1<<A)|(1<<D));
            break;

        case 2:
            PORTB |= (1<<B)|(1<<D);
            PORTB &= ~((1<<A)|(1<<C));
            break;

        case 3:
            PORTB |= (1<<D)|(1<<A);
            PORTB &= ~((1<<B)|(1<<C));
            break;
    };


};

Ένας άλλος (εύκολος) τρόπος ελέγχου βηματικών κινητήρων είναι αυτός του μισού βήματος. Κάθε κίνηση θα είναι το μισό από την ονομαστική τιμή πλήρους βήματος του κινητήρα. Για παράδειγμα στον παραπάνω κινητήρα το κάθε βήμα στην λειτουργία μισού βήματος θα είναι 0,9 μοίρες. Με τον τρόπο αυτό έχουμε μεγαλύτερη ακρίβεια. Το μειονέκτημα είναι πως το ένα βήμα με το άλλο δεν θα έχει την ίδια ροπή. Αυτό συμβαίνει διότι για το μισό βήμα ενεργοποιούμε ένα πηνίο μετά δύο μετά ένα κοκ. Μία λύση θα ήταν να αυξάνουμε το ρεύμα στο βήμα με το ένα πηνίο. Η σειρά ενεργοποίησης είναι A->AC->C->CB->B->BD->D->DA και τούμπαλιν. Αυτό το επιτυγχάνουμε με την συνάρτηση makeHalfStep(uint8_t step) που λειτουργεί με τρόπο παρόμοιο με την makeStep().

#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <util/delay.h>

/*
   Δεν χρησιμοποιώ το PB2 διότι είναι και το SCK
   και κάθε φορά έπρεπε να αφαιρώ το LED για να
   προγραμματίσω τον μικροελεγκτή.
*/
#define A PB0
#define C PB1
#define B PB4
#define D PB3

void makeHalfStep(uint8_t step);

int main(void)
{

    // A,B,C,D ως έξοδοι.
    DDRB |= (1<<A)|(1<<B)|(1<<C)|(1<<D);

    // Βοηθητική μεταβλητή ().
    int16_t i=0;


    /*
        Λίγος χρόνος για τον μηδενισμό
        του δείκτη. Σε κανονική εφαρμογή
        θα είχαμε κάποιο τερματικό διακόπτη
        για την εύρεση της θέσης 0.
    */
    makeHalfStep(7);
    _delay_ms(10000);


    // Κάθε βήμα είναι 0,9 μοίρες.
    // Για παράδειγμα 20 μοίρες θα είναι
    // 20/0,9=22 βήματα.
    while(1){

        // Κίνηση 20 μοίρες εμπρός.
        while(i<=22){
            makeHalfStep(i%8);
            i++;
            _delay_ms(500);

        };

        _delay_ms(2000);

        // Κίνηση 35 (~39 βήματα) μοίρες εμπρός.
        while(i<=61){
            makeHalfStep(i%8);
            i++;
            _delay_ms(50);

        };

        _delay_ms(2000);

        // Κίνηση 35 (~39 βήματα) μοίρες εμπρός.
        // Πρέπει να βρεθούμε στις 90 μοίρες.
        while(i<=100){
            makeHalfStep(i%8);
            i++;
            _delay_ms(10);
        };

        _delay_ms(2000);

        // Στις 180 μοίρες.
        while(i<=200){
            makeHalfStep(i%8);
            i++;
            _delay_ms(2);
        };

        _delay_ms(2000);

       // Επιστροφή στο 0.
        while(i>=0){
            makeHalfStep(i%8);
            i--;
            _delay_ms(2);
        };

        i=0;
        _delay_ms(2000);

    };

    return 0;
}

void makeHalfStep(uint8_t step){

    switch (step){

        case 0:
            PORTB |= (1<<A);
            PORTB &= ~((1<<B)|(1<<C)|(1<<D));
            break;

        case 1:
            PORTB |= (1<<A)|(1<<C);
            PORTB &= ~((1<<B)|(1<<D));
            break;

        case 2:
            PORTB |= (1<<C);
            PORTB &= ~((1<<B)|(1<<A)|(1<<D));
            break;

        case 3:
            PORTB |= (1<<B)|(1<<C);
            PORTB &= ~((1<<A)|(1<<D));
            break;

        case 4:
            PORTB |= (1<<B);
            PORTB &= ~((1<<C)|(1<<A)|(1<<D));
            break;

        case 5:
            PORTB |= (1<<B)|(1<<D);
            PORTB &= ~((1<<A)|(1<<C));
            break;

        case 6:
            PORTB |= (1<<D);
            PORTB &= ~((1<<C)|(1<<A)|(1<<B));
            break;

        case 7:
            PORTB |= (1<<A)|(1<<D);
            PORTB &= ~((1<<B)|(1<<C));
            break;
    };

}
Advertisements
This entry was posted in AVR, Electronics and tagged , , , , , , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s