Jak zaprogramować Serwo sterowane AVR (ATTINY84A)
Skoro wiemy już jak wyświetlać bardziej złożone informacje niż zapal i zgaś diodę przyszedł czas na sprawienie aby nasze projekty trochę ożyły.
Serwo to taki stosunkowo prosty mechanizm oparty na silniku krokowym, dzięki któremu możemy na przykład zbudować ramię robota, które będzie się poruszało o określoną ilość stopni w określonym kierunku. Dzięki temu będzie można zbudować już projekt, który robi coś konkretnego jednak ciekawsze stanie się to dopiero jak zapoznamy się z obsługą różnego rodzaju czujników, ale po koleii.
Dzisiaj mam pod ręką Micro servo Tower Pro SG92R. Taki element kosztuje kilkanaście złotych i jest w stanie poruszyć stosunkowo sporo jak na swój rozmiar. Mamy wyprowadzone trzy kable, z których dwa podłączamy do zasilania (plus VCC i minus GND) oraz jedno do PINu naszego mikrokontrolera.
Jak podłączyć serwo?
Ważne żeby zasilania nie podpinać bezpośrednio do mikrokontrolera. Silniki mają stosunkowo duży pobór mocy, oczywiście czym większy silnik tym większy pobór mocy zazwyczaj. Obciążenie z tym związane jest zbyt duże dla naszego mikrokontrolera, który zazwyczaj daje radę w okolicach kilkudziesięciu miliamperów. Dla czujników, diod i tego typu małych elementów zazwyczaj to wystarczająco ale jeśli chodzi o silnik do mikrokontrolera podpinamy tylko sterowanie.
Kabel czerwony do VCC czyli plusa. Kabel brązowy do GND a pomarańczowy do PINu mikrokontrolera, na którym za chwilę zaprogramujemy.
Jak działa sterowanie?
Serwa sterujemy sygnałami zmieniając stan pinu w określonych odstępach czasu. Serwomechanizmy tego typu mają swoją częstotliwość, którą można znaleźć w dokumentacji. W moim przypadku jest to 50Hz oznacza to że jeden cykl nasłuchiwania trwa ok 20ms. W tym czasie należy przesłać sygnał o określonej długości. Długość sygnału odpowiada ilości stopni o ile poruszy się mechanizm. Impuls dla mojego SG92 powinien mieć od 0,5ms do 2,4ms, co odpowiada zakresowi ruchu od 0 do 180 stopni.
Z powyższego wynika że aby zaprogramować zmianę pozycji o 45 stopni należałoby zmienić stan na pinie na 0,975ms po czym zmienić go z powrotem. Skoro już wszystko wiadomo jak podłączyć i jak działa spróbujmy zaprogramować żeby nasz mechanizm się poruszał.
Jak zaprogramować Serwo SG92?
Spróbujemy sobie teraz napisać program, który pomacha nam ramieniem. A dokładniej mechanizm zmieni swoją pozycję o 45 stopni a następnie po krótkiej chwili wróci do swojej początkowej pozycji i tak w pętli.
Jest to prawie tak samo proste jak zrobienie migającej diody z tym że teraz musimy wyliczyć odpowiedni czas pomiędzy zmianami stanu na pinie aby wygenerować sygnał odpowiedniej długości. Już wyżej obliczyłem jak długi powinien być sygnał dla 45 stopni, więc przechodzimy do kodowania.
Będziemy korzystać z PINu PB1 do poruszania „śmigiełkiem” dlatego zaczynam od zdefiniowania. Oczywiście zaraz pod tym jak zaincluduje biblioteki do obsługi avr i delay (opóźnień) tak jak robiliśmy to wcześniej.
#define SERVO (1<<PB1)
Następnie w funkcji głównej programu ustawiam port na wyjście.
#DDRB |= SERVO;
I w pętli głównej programu ustawiam PIN na stan wysoki, czekam długość sygnału odpowiedniego dla 45 stopni i po 2,5sekundy wykonuję analogiczną akcję dla ustawienia na 0 stopni. Po 2.5sekundy powtarzam w pętli w nieskończoność.
PORTB |= SERVO; //ustawiam stan wysoki na PIN
_delay_us(975); //czekam 975 mikrosekund czyli czas sygnału 45 stopni
PORTB &= ~SERVO; //zmieniam stan na niski
_delay_ms(2500); //czekam dwie i pół sekundy przerwy
PORTB |= SERVO;
_delay_us(500); //Czekam długość sygnału 0 stopni pozycja wyjściowa
PORTB &= ~SERVO;_delay_ms(2500);//czekam na powtórzenie pierwszej akcji
I to by było na tyle, kilka linijek kodu i mamy ogarnięte sterowanie serwomechanizmem. Cały kod, który przynajmniej „u mnie działa” można zobaczyć na obrazku poniżej.
Można by się jeszcze ewentualnie pokusić o napisanie funkcji obracającej ramie do zadanego stopnia z przedziału pracy serwo czyli 0 – 180. Wiemy że odpowiednikiem w długości sygnału jest 0,5 – 2,4ms. Jeśli jesteś ambitny zachęcam do podjęcia takiej próby. I tak prędzej czy później zapewne to zrobisz.
Na ten moment mogę zaproponować niezbyt dokładną funkcję. Główne problemy to że _delay_us() nie przyjmuje zmiennych oraz czas sprawdzenia warunku albo wykonania pętli też trochę trwa. Dlatego starałem się ograniczyć ilość operacji. Pierwsze co wpadło mi do głowy to zrobienie pętli z opóźnieniem 1 mikrosekunda ale przejście przez pętlę zajmowało sporo czasu.
Potem funkcja main wygląda już dość prosto.
Już można by zaprogramować jakąś całkiem ciekawą sekwencję i ustawić kilka serwomechanizmów. Za jakiś czas wrócimy do tematu w jakimś ciekawym ale zarazem prostym projekcie.