AVR-GCC. Σερβοκινητήρες (μοντελισμού). Aka servos.

Οι σερβοκινητήρες είναι μικρές συσκευές που έχουν έναν άξονα ο οποίος μπορεί να περιστρέφεται σε συγκεκριμένη γωνία (0 έως 180 μοίρες) που είναι ελεγχόμενη από τον χρήστη. Ο έλεγχος ενός σερβοκινητήρα γίνεται με την βοήθεια παλμών που επαναλαμβάνονται κάθε 20 msec (ή 1/0,02= 50 Hz). Το μήκος του παλμού ρυθμίζει και την γωνία του άξονα. Τέτοιες συσκευές υπάρχουν σε τηλεκατευθυνόμενα αεροπλανάκια, αυτοκίνητα και φυσικά σε robots.

Άρθρο της Wikipedia για τους Σερβοκινητήρες.
Άρθρο της Wikipedia για τον έλεγχο Σερβοκινητήρων.
Τεκμηρίωση του ATmega8.

Οι σερβοκινητήρες έχουν έναν κινητήρα, ένα ποτενσιόμετρο και ένα κύκλωμα ελέγχου που μετρά συνεχώς την τιμή του ποτενσιόμετρου. Το ποτενσιόμετρο είναι συνδεμένο στον άξονα. Καθώς ο άξονας περιστρέφεται αλλάζει και η τιμή του ποτενσιόμετρου. Έτσι το κύκλωμα ελέγχου γνωρίζει σε ποια θέση βρίσκεται ο άξονας. Βλέποντας το σήμα ελέγχου το κύκλωμα μετακινεί τον άξονα στην κατάλληλη θέση.

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

Από την παραπάνω μορφή του σήματος βλέπουμε πως πρόκειται στην ουσία για ένα PWM σήμα. Μπορούμε λοιπόν να χρησιμοποιήσουμε κάποια PWM έξοδο του μικροελεγκτή μας για τον έλεγχο ενός σερβοκινητήρα. Έτσι διαλέγουμε τον Timer/Counter1 σε λειτουργία Phase Correct PWM (είναι η προτεινόμενη λειτουργία. μπορεί όμως και σε Fast PWM να μην έχουμε κάποιο πρόβλημα).

Γιατί διαλέξαμε τον Timer/Counter1 και όχι για παράδειγμα τον 8-bit Timer/Counter2 που έχει και αυτός PWM; Ας θυμηθούμε την συχνότητα σε PWM λειτουργία του Timer/Counter2.
Για Fast PWM:

Για Phase Correct PWM:

Αμέσως παρατηρούμε πως οι σχέσεις αυτές δεν είναι καθόλου ευέλικτες. Δεν υπάρχει κάποιος όρος που μπορούμε να ρυθμίσουμε εύκολα για να έχουμε συχνότητα 50 Hz. Ο Prescaler παίρνει τιμές 1, 8, 32, 64, 128, 256, 1024. Με Fcpu 4 MHz η Συχνότητες που μπορούμε να έχουμε είναι για Fast PWM 15,625 kHz, 1953,125 Hz, 488,28125 Hz, 244,140625 Hz, 122,0703125 Hz, 61,03515625 Hz και 15,2587890625 Hz. Για Phase Correct PWM 7843,137254902 Hz, 980,3921568627 Hz, 245,0980392157 Hz, 122,5490196078 Hz, 61,2745098039 Hz, 30,637254902 Hz και 7,6593137255 Hz. Καμία τιμή κοντά στα 50 Hz.

Σε αντίθεση για τον Timer/Counter1 έχουμε (για Phase Correct):

Υπάρχει ο όρος TOP, που μπορεί να είναι ο καταχωρητής ICR1, και να ρυθμίζεται κατά βούληση. Με TOP (ICR1) 5000, Prescaler 8 και Fcpu 4 MHz έχουμε Fpwm 50 Hz. Ακριβώς αυτό που θέλουμε.

Για περισσότερα σχετικά με τις λειτουργείς των Timer/Counter δείτε ΕΔΩ και ΕΔΩ.

Στο παρακάτω παράδειγμα περιστρέφουμε τον σερβοκινητήρα από 0 έως 180 μοίρες σε διαστήματα των 30 μοιρών (έξι βήματα). Οι παρακάτω τιμές για τον έλεγχο του σερβοκινητήρα στις 0 και 180 μοίρες προέκυψαν μετά από δοκιμές (αρκετές) μιας και ο συγκεκριμένος σερβοκινητήρας είναι φτηνιάρικος, ~2 ευρώ (βλέπε Κίνα…), και καθόλου αξιόπιστος. Σαν αρχή λειτουργίας όμως δεν διαφέρει σε τίποτε από το να είχαμε έναν καλό σερβοκινητήρα

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


/*Η παρακάτω δήλωση ελέγχει αν στον compiler έχουμε βάλει την παράμετρο F_CPU.
  Αν όχι, την περνά. */

#ifndef F_CPU
    #warning "H F_CPU den exei oristei 8a parei thn timh 4000000"
    #define F_CPU 4000000UL  // Use unsigned long (UL)
#endif



// Οι παρακάτω τιμές προέκυψαν μετά από μερικές
// δοκιμές για τον συγκεκριμένο σερβοκινητήρα.
#define SERVO_MIN 300    // 0 μοίρες.
#define SERVO_MAX 1300   // 180 μοίρες.

void pwm_init(void);
int32_t map(int32_t x, int32_t in_min, int32_t in_max, int32_t out_min, int32_t out_max);


/*
    Η συνάρτηση map χαρτογραφεί την μεταβλητή που της δίνουμε
    σε μια συγκεκριμένη περιοχή τιμών σε σχέση με μία άλλη.
    Στην συγκεκριμένη περίπτωση θέλουμε να βάζουμε τιμές από
    0 έως 180 και να μας επιστρέφει την αντίστοιχη τιμή από
    SERVO_MIN έως SERVO_MAX. αν για παράδειγμα δώσουμε 90 θα
    μας επιστρέψει 800.

*/

int32_t map(int32_t x, int32_t in_min, int32_t in_max, int32_t out_min, int32_t out_max){

    return ((x - in_min)*(out_max - out_min))/(in_max - in_min) + out_min;

}


/*
    Η συχνότητα για Phase correct PWM είναι
    Fpwm = Fcpu/(2*Prescaler*TOP). Οπότε
    TOP = Fcpu/(2*Prescaler*Fpwm). Έχουμε
    Prescaler 8, Fcpu 4 MHz και Fpwm 50 Hz.
    Οπότε TOP=5000.

*/

void pwm_init(void){

    // Phase Correct PWM με TOP τον ICR1
    // Σελίδα 96 έως 98 της τεκμηρίωσης του
    // ATmega8.

    ICR1=5000;  // Η τιμή του TOP.

    TCCR1A |= (1<<COM1A1)|(1<<WGM11);

    TCCR1B |= (1<<WGM13)|(1<<CS11);

}

int main(void){

    int16_t angle=0;

    DDRB |= (1<<PB1);  //PB1 ως έξοδος.

    pwm_init();  // Αρχικοποίηση του Timer/counter1.


    while(1){

    if (angle>=180) angle=0;

    // Μέγιστη τιμή του OCR1A (100% duty cycle) είναι
    // η TOP=5000.
    OCR1A = map(angle,0,180,SERVO_MIN,SERVO_MAX);

    _delay_ms(1000);

    angle+=30;

    _delay_ms(1000);

    };

    return 0;
}

About these ads
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