Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

mikrokontroler atmega i serwomechanizmy

01 Gru 2008 00:31 11386 42
  • Poziom 13  
    Hej
    Zabieram się za tajniki programowania mikrokontrolera atmega16.
    Jako, że nigdy nie programowałem w basic'u (programowałem w C) kwestia wyboru języka będzie zależała od łatwości (sposobów) sterowania poprzez ten kontroler serwomechanizmami modelarskimi. Chcę zbudować manipulator (dla wyobrażenia przenoszący klocki z jednego miejsca na drugie).

    Czy ktoś mógłby mi przybliżyć sposoby sterowania serwomechanizmami? jakieś przykładowe wycinki kodu w mikrokontrolerze... w czym najlepiej zaprogramować uC do tego zadania?

    Od strony komputera napiszę aplikację (W C lub delphi).

    Tajemnicą dla mnie jest także sprzęgnięcie bajtów danych wychodzących z portu rs232, o budowie, która będzie rozumiana w uC, który będzie w wyniku odczytywał poprawnie te bajty i poruszał serwomechanizmami zgodnie z zadanymi wartościami.

    Przeglądam dość dzielnie forum i dowiedziałem się bardzo wielu wartościowych informacji. niestety aby zabrać się za napisanie prościutkiego kodu muszę usystematyzować swoją wiedzę. systmatyzuję ją pozycjami: wprowadzenie do robotyki craig ; rs 232 c praktyczne programowanie daniluk; co do mikrokontrolerów jutro będe miał pozycje "uC AVRavr w praktyce", oraz Programowanie mikrokontrolerów AVR w języku Bascom"

    pozdrawiam. Adam
  • Poziom 29  
    Witam!
    AtMega16 to dobry wybór. Do programowania i uruchamiania polecam interfejs JTAG (można kupić za około 100 zł, lub do poskładania za mniej więcej połowę tej ceny). JTAG to jednak przede wszystkim debugger, którym można podejrzeć w każdej chwili co się dzieje w procku. Tu druga kwestia: język programowania. Przynajmniej troszkę spróbuj się pomęczyć w assemblerze zanim się zajmiesz C czy BASCOm-em. Żeby zrozumieć działanie procka, to jednak trzeba tego assemblera liznąć. Dobrze byłoby spróbować jakieś przerwanie obsłużyć, nic tak nie poprawia humoru, jak działający AVR-ek. ;-)
    Jeśłi chodzi o przyjemniejszy język niż assembler, to polecam C z pakietu WINAVR - jest naprawdę wydajny i nieźle zoptymalizowany, poza tym dobrze się integruje z AVRStudio i najważniejsze - też współpracuje z jtagiem i debuggerem na poziomie kodu źródłowego. Nie bawiłem się BASCOm-em (wyrosłem z BASIC-a w erze Spectruma) ale nie sądzę, żeby był tak wygodny.
    Serwomechanizny - nie wiem jak działają, pewnie podobnie do silników krokowych. Tak czy inaczej na pewno da się je załatwić AVR-kiem, jeśli nie bezpośrednio, to poprzez coś w rodzaju ULN2003.
    RS232 - w procku linie działają na poziomie TTL, ale po dołożeniu konwertera MAX232 można podpiąć do COM-a w PC i przesyłać co tylko się zamarzy. :-)
    Powodzenia!
  • Poziom 12  
    Z serwami prosta sprawa potrzebujesz PWM'y (tryb pracy licznika) przy kwarcu 1MHz muszą mieć rozdzielczość 10 bitów. Więc na atmedze posterujesz se jednym serwem poprzez pwm z licznika 1 . Sprawa prosta częstotliwość PWM = 50 Hz co daje 20 ms czas trwania "1" od 0,3ms do 2,7ms przy czym 1,5ms to serwo w położeniu środkowym. więc obrót w lewo to skrócenie czasu w prawo wydłużenie czasu tak to można najprościej opisać.
    Manipulator to na moje oko minimum 5 serv są do tego procki at90pwm...
  • Poziom 13  
    Czyli, co... ta atmega nie uniesie 6 serw?
    "przy kwarcu 1MHz musza miec rozdzielczosc 10 bitów" - nie rozumiem
    Trochę wiem o czym piszesz, ale skąd te 0,3, 2,7....


    mogłbyś napisać jakiś mały przykład kodu w uC oraz bajtu przesyłanego z aplikacji poprzez rs232 do ruchu serwem o jakiś kąt?
    w sumie nie ma działać, ale pokazać mi drogę..
    teraz znalazłem cos takiego:
    Link
    Link
    oraz Link

    jutro będe czytał :) thxxx
    pozdrawiam i dziękuję za dotychczasowe odpowiedzi!
  • Poziom 13  
    DAKE SEHR!!!!!
    weekend nie mój :)
  • Poziom 12  
    Jak ci się udało zauważyć da się więcej na atmega16 tylko że to jest już realizacja programowa. PWM to taki tryb licznika w którym zmieniasz szerokość wypełnienia impulsu. 0,3 ms - 2,7 ms to taki przedział (czas trwania stanu wysokiego) w którym serwo kręci się od -90 do +90 stopni. Przy ustawieniu PWM z czasem trwania jedynki równym 1,5ms na 20 ms okres masz możliwość kręcenia w lewo i prawo o 90 stopni.
  • Poziom 43  
    Dokładniej mówiąc, to czasy dla serwa od 1ms do 2ms w odstępach 20ms.
    1ms i 2 ms to skrajne położenia, 1,5ms to położenie środkowe. TAkich czasów należy sie trzymać ! Taki jest standard.
    Nie piszcie, że od 0,3 do 2,7 bo to nieprawda !
  • Poziom 33  
    Te 1ms i 2ms to tez nie jest standard ;) W hitecach jest od 0.9 do 2.1, wiec trzeba po prostu przeczytac w nocie jakie sa dokladne czasy
  • Poziom 12  
    HS-325HB hitec - bawię się tym właśnie servem i faktycznie może przesadziłem z przedziałem 0,3-2,7 ale taki znalazłem w jakiejś literaturze ale na to serwo można podać od 0,52-2,48 ms i działa. W takim razie 1-2ms to nie są skrajne położenia tylko jakiś bezpieczny przedział w sterowaniu servem.
  • Poziom 13  
    Fazolek mozesz podac jakiej literaturze? dz
  • Poziom 43  
    Koledzy standardem dla serw jest tak jak napisałem 1ms do 2 ms i 1,5ms położenie neutralne.
    Serwa które mają większy zakres pracy niż 180 stopni mogą mieć większe rozbieżności czasów, zwykle jest to od 0,5 do 2,5
  • Poziom 13  
    Witam

    Robiłem jekieś 3-4 miesiące temu sterownik serw na mikrokontrolerze avr - to był mój pierwszy projekt z wykorzystaniem mikrokontrolera, także nic specjalnego pierwsze kroki (powrót do hobby po 14 latach przerwy).

    A więc sterowałem 2 serwami TowerPro MG995R, tak mniej więcej dla 0° impuls trwał 500us a dla 180° 2300 us.

    Sterowanie serwami odbywało się po rs232 z pc. Załączył bym źródła ale są bardzo zaśmiecone i nie pamiętam czy w obecnej postaci spełniają swoje zadanie.

    Zasada działania programu była intuicyjna:
    Program pc zawierał dwa suwaki. Po modyfikacji któregoś z suwaków przez rs 232 była wysyłana ramka danych, nr serva i pozycja serwa.

    Program uc pobierał dane z rs232 w pętli i aktualizował globalnie dostępne zmienne przechowujące pozycje obu serw. Równolegle były odpalone 2 timery, jeden pilnował odstępów 20 ms, a drugi generował impulsy sterujące.
    Generacja impulsów sterujących:
    Po otrzymaniu przerwania 1 (minęło kolejne 20 ms) stan na wszystkich wyjściach do serw był podnoszony, jednocześnie uruchamiany był timer 2(co ileś us). Timer 2 co przerwanie, wiedząc ile czasu już upłynęło od rozpoczęcia bieżącej sesji sprawdzał czy nie należy zakończyć impulsu któregoś z serw jeśli pozycja została osiągnięta został podawany stan niski. I tak w kółko co 20ms.

    Tak skrótowo to działało, nie mówię że zasada działania była prawidłowa, możliwe że timer 2 był odpalany zbyt często, nie udało mi się wyeliminować szarpnięć serw, które się pojawiały po osiągnięciu ponad 90° przez któreś z serw (nad sterownikiem pracowałem tylko z 5 wieczorów - także go nie dopracowałem).
  • Poziom 12  
    Code:


    #include <avr/io.h>
    #define F_CPU 16000000
    #include <util/delay.h>

    int main ()
    {

    ICR1=20000;      // wartość TOP
    OCR1B=1500;    // wypełnienie dla pozycji środkowej

    TCCR1A=0x22;    //preskaler przez 8 i wyjście OCR1B
    TCCR1B=0x12;   // pwm poprawnej fazy jako TOP ICR1

    DDRD|=(1<<4);  //wyjście OCR1B

    while(1){

    if(OCR1B<2500)
    OCR1B+=10;
    else OCR1B=500;
    _delay_ms(50);
    }

    while(1);
    return 0;
    }


    To powinno ruszyć. Efekt taki, że na początku servo ustawia się na środek, kręci o ok 90 stopni (w prawo) i szybko przechodzi na -90 stopni (w lewo), i tak w kółko aby uwidocznić przedziały czasowe.
    Wyżej wymieniony Hitec pracował na bardzo podobnym kodzie. Tego nie odpalałem ale zdaje się być dobry.
  • Poziom 13  
    ten kod (wartosci oraz formalizm języka są dla mnie zrozumiałe). niestety powoli dopiero wyczajam nazwy takie jak ICR1 OCR1B
    TCCR1A=0x22; //preskaler przez 8 i wyjście OCR1B
    TCCR1B=0x12; // pwm poprawnej fazy jako TOP ICR1

    DDRD ...
    to pewnie nazwy rejestrow (przyznam ze dokumentacje atmegi czytalem na razie jednym okiem :)
    moglibyście napisać, czy szukać wyjaśnień w dokumentacji uC czy gdzie?
    a może w helpie do biblioteki.
    google przewaznie podaje kod

    moze głupie pytanie, ale odpowiedź bardzo mi pomoże
  • VIP Zasłużony dla elektroda
    puntigamer napisał:
    ...
    moze głupie pytanie, ale odpowiedź bardzo mi pomoże


    Dokumentacja mikrokontrolera wyjaśni (prawie) wszystkie pytania. Przed zadaniem następnego proszę się z nią bardzo dokładnie zapoznać.
  • Poziom 13  
    Cześć
    Wiem już to czego nie wiedziałem i poprawiłem kod Fazolka (poprawiłem bo nie mam 16MHz itp:
    Code:

    #include <avr/io.h>
    #define F_CPU 1000000
    #include <util/delay.h>

    int main ()
    {

    ICR1=10000;      // wartość TOP
    OCR1B=750;    // wypełnienie dla pozycji środkowej

    TCCR1A=0x22;    //preskaler przez 1! czyli brak i wyjście OCR1B
    TCCR1B=0x11;   // pwm poprawnej fazy jako TOP ICR1

    DDRB|=(1<<2);  //wyjście OCR1B
       //wyjscie do serva
      PORTB = 0x04;    // :)    PB1(OC1A)


    while(1){

    if(OCR1B<1000)
    OCR1B+=2;
    else OCR1B=500;
    _delay_ms(20);
    }


    return 0;
    }


    Niby wszystko działa 1000000 /2x10000x1(preskaler) = 50Hz
    Teraz wątpliwości:
    Jesli specjalnie zmienie wartość TOP na 20000 impulsy będą identyczne, lecz z podwójnie mniejszą (czyli 25Hz) Częstotliwością. Tak?
    Dla zwykłego poruszania się serwa nie ma to większej różnicy...
    Ale co jeśli wprowadzę zmiany w F_CPU na 8MHz oraz włącze preskaler 8, pozostawiając TOP 10000. Czy powinno wszystko grać? Bo serwo porusza się jedynie w zakresie od lewa do środka i barrdzo powoli.
    Druga sprawa jeśli zmienie jedynie F-CPU na 2MHz pozostawiając resztę programu jak w kodzie wyżej, to, czy nie powinienem zmienić wartości OCR1B na dwa razy większę, aby sygnał był ciągle w granicach 1 >1,5< 2ms?

    Zmiana watości top przy niezmienionej freq daje takiej samej dlugosci impulsy tylko ze czesciej lub rzadziej. Zatem dlaczego jeśli zwiększę F_CPU do 2MHz sero ustawia się (wychyla) tak samo jak dla 1MHz?
    czy mimo zmiany czestotliw licznik zlicza w tym samym tempie?

    Dodam tylko, że datasheet jest w moim życiu teraz księgą-biblią. Za cenne uwagi będę Wam wdzięczny
    Pozdrawiam
  • Pomocny post
    Specjalista - Mikrokontrolery
    do F_CPU mozesz sobie wpisac nawet slowo KOT i nic to nie zmieni. czestotliwosc procka definiujesz w fusebitach. F_CPU jest potrzebne tylko dla funkcji biblitecznych - takich jak _delay_...() - jako parametr. napis ten sam w sobie nic nie zmienia.

    co do dalszych pytan - logiczne jest, ze jesli zmienisz czestotliwosc procka (ale zmienisz czestotliwosc, a nie wpiszesz inne znaczki do F_CPU), to parametry swoich funkcji musisz zmienic. wlasnie dlatego dawno temu wymyslili, zeby takie rzeczy pisac jako makra, a nie recznie, bo teraz bedziesz musial zmienic cyferki w 20 miejscach, a nie w jednym, gdybys zrobil to raz a porzadnie

    #define TOP (F_CPU/costam*cos_innego)
    #define COMPARE (F_CPU/costam*(1-20)/1000)

    gdybys operowal takimi wzorkami, to wtedy zmieniasz F_CPU i reszta liczy sie sama. teraz zas bedziesz robil wszystko od nowa.

    http://en.wikipedia.org/wiki/Magic_number_%28programming%29%23Unnamed_numerical_constant

    4\/3!!
  • Poziom 13  
    Co do F_CPU.. dzieki :) wiem o fusebitach i dlatego sądziłem ze freq sie nei zmienia... bo wszystko działało tylko przy 1MHz.
    Co do makr, to spoko, ten kod jedynie zaznajomił mnie z zasadami, rejestrami. Oczywiście obliczam na wzorach( na razie na papierze:) , a zmiennych i funkcji będę używał podczas pisania kodu aplikacji

    Dzięki za pomoc. pozdrawiam
  • Poziom 13  
    Witam Was ponownie.
    Chciałbym abyście odnieśli się do tego kodu. Steruje na razie 1 serwem stąd atmega 8mhz (aby móc wysterować licznik2 do wartości 20ms)
    Mam rozumieć, że to jest programowy pwm? A może są jeszcze inne sposoby?
    Code:
    #include <avr/io.h>
    
    #define F_CPU 8000000
    #include <util/delay.h>
    #include <avr/interrupt.h>
    int volatile polozenie;

    ISR(TIMER2_COMP_vect)
    {
    OCR1A=polozenie;
    PORTD=0x04;
    TCCR1B|=_BV(CS11);
    }


    ISR(TIMER1_COMPA_vect)
    {
          PORTD=0x00;
       
       TCCR1B=(1<<WGM12)|(0<<CS11);
       //TCNT1=0x000;
    }


    int main ()
    {

    //licznik1
    //TCCR1A=_BV(COM1A1);         
    TCCR1B=_BV(WGM12); 


    //   Ustawienie licznika 2   
       TCCR2=_BV(WGM21)|_BV(CS22)|_BV(CS21)|_BV(CS20);   //presk 1024, aby osaignac co 20 ms przerwanie licznika2
       OCR2=156;    //8000000/1024/156


    //   Przerwania   
       TIMSK=_BV(OCIE1A)|_BV(OCIE1B)|_BV(OCIE2);
       TIFR =_BV(OCF1A)|_BV(OCF1A)|_BV(OCF2);
       sei();
       
    DDRD=0x04;

    while(1){
    polozenie=1500;

    /*if((polozenie<2000))
       {   polozenie+=10;
          
       }
       else {
          polozenie=1000;
          
       }
       _delay_ms(10);*/
       }


    return 0;
    }


    Myślę ze obsługę 8 serw z dokładnością 10 bitową atmega utrzyma (kwarc 16MHz). Zmienna OCR1A z zakresu 1000- 2000 (co odpowiada 1ms i 2 ms). Wieczorem podziałam już na wszystkie 8serw (mam nadzieję, że się nic nie będzie krzaczyło.

    Mnie nachodzi jeszcze taka myśl.
    Zrobić to samo tylko licznik nie w trybie ctc, tylko fast pwm.
    Dać przerwania od licznika2 co 400Hz (2,5ms) i pod koniec tegoż przerwania odpalić licznik 1 w trybie non inverting mode (fast pwm) czyli dostaniemy od razu stan wysoki który będzie trwał do momentu zrównania TCNT1 z wartością ICR1 lub OCR1A(B). Wiem, że ten sygnał jest zawsze na jednym pinie. Czy można jakoś "skopiować" stan tego pinu na inny?. Pewnie kombinuje niepotrzebnie, ale kto pyta nie błądzi.
    Rozróżniałbym serwa w przerwaniu od licznika 1 i kopiował stan OC1A na przeze mnie określony pin. np PORTD=0x01 , 0x02 itd)

    Aha pytanie dotyczące _delay_ms(10);
    te makro powoduje przystopowanie całego uC na 10ms (tzn przerwań itp)? liczników nie, gdyż na sprzętowym pwm to działało ok

    Pozdrawiam
    Adam
  • Poziom 13  
    Witam
    Mam teraz dziwny problem. Przerobiłem kod aby obsłużyć 6 serw i niby jest wszystko w porządku.
    Jeśli zmniejszam wartości dla pozycji serw ( np 1,8ms później 1,5ms, bo na razie zmieniam je ręcznie przy programowaniu uC) to jest wszystko pięknie, serwa automatycznie ustawiają się na zadaną wartość.
    Ale jeśli robię to w drugą stronę (daję wartości zwiększające długość impulsu np z 1ms na 1,5 ms) to serwa przez chwilkę drgają i ustawiają się tak jak powinny.

    Zauważyłem też, że jeśli orczyk jednego serwa obciążę to inne zmieniają pozycję lub drgają. Czy to może być związane z natężeniem prądu? do zasilenia serw używam łącza USB czyli zasilacza w moim pracującym komputerze :) CHieftec 400w a jakie natężenie na USb to nei wiem. wiem tylko, że dla +5V 26A, a natężenie przy napięciu +5VSB - 2 A. Które to USB?

    Aha i w płytce testowej ZL2AVR dioda która sygnalizuje pracę układu lekko przygasza się jak obciążam orczyk serwa

    Czy łącze USB może mieć maksymalne obciążenie ok 0,5 A ? Serwa przy obciążeniu biorą dużo więcej stąd może moje kłopoty ?
  • Poziom 33  
    Serwa zasilaj z osobnego zasilacza!
  • Poziom 13  
    Heh... Czyli z portu USB można wyciągnąć okolo 0,5A...
    Druga sprawa czy jak podłączę płytkę układu do zasilania +5V ale tego 26A, czy będzie oki? czy może sama płytka testowa wprowadza ograniczenie w poborze prądu? (czyli czy podłączyć zasilanie serw przez płytkę czy wprost z zasilacza?
    Jak też nei wyda to załączę osobny. Dzięki Robak!
  • Poziom 33  
    Ja robilem tak, ze zaislanie logigi bralem z 12V (zolty kabelek), a serwa z 5V (czerwony). Nie mozesz zaislac serw przez stabilizator.
  • Poziom 13  
    Troche posprawdzałem

    Zrobiłem tak. Z gniazda atx pobrałem napięcie 5V (czerwony kabelek) i podłączyłem do zestawu uruchomieniowego. Już jest lepiej. Serwa tak mocno nie drgają, ale jednak.

    Jak zmieniam sygnał "w górę" czyli np z 1ms na 2 ms to drgają (mniej ale ciągle) a napięcie z 5,04 spada aż do 4,33V .. i to bez obciążenia :( wydaje się, ze płytka testowa to powoduje...

    przy dwóch serwach nie drga żadne z nich. program na bank jest optymalny

    Mowisz ze nei moge zasilac serw przez stablizator z plytki testowej? dziwne jesli złącza do obslugi jednego serwa są stabilizowane... teraz sprobuje podlaczyc napiecie prosto z zasilacza. dzieki
  • Poziom 33  
    Pokaz schemat :P A nie moze brac zasilania ze stabilizatora bo serwa moga szarpnac duuuzo pradu, a nawet jak nie szarpna to pobor maja spory. Taki stabilizator ile da 1.5A maks, to juz i tak bedzie sie grzal. Moj robot z 18 serwami 3kg i 4 hitecami wiszac w powietrzu, czyli obciazenie minimalne, pobieral 8A. Pusc taki prad przez stabilizator, nawet jak podzielisz przez 4 ten prad ;)
  • Poziom 43  
    _Robak_ napisał:
    A nie moze brac zasilania ze stabilizatora bo serwa moga szarpnac duuuzo pradu, a nawet jak nie szarpna to pobor maja spory. Taki stabilizator ile da 1.5A maks, to juz i tak bedzie sie grzal. Moj robot z 18 serwami 3kg i 4 hitecami wiszac w powietrzu, czyli obciazenie minimalne, pobieral 8A. Pusc taki prad przez stabilizator, nawet jak podzielisz przez 4 ten prad ;)


    A no widzisz.
    Czyli jednak może.
    Może nie powinien ale na pewno może.
    Jak już to nie z tego samego stabilizatora co procesor. Stabilizator musi być po do tego mocny (tzn. na kilka A). No i dużym radiatorem, co jest bez sensu mając stabilizowane napięcie 5V. Ale to nie umniejsza faktu że może.