logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[ATMega8] Sterowanie kilkoma serwami

davidpi 16 Mar 2010 20:30 3778 12
  • #1 7839241
    davidpi
    Poziom 10  
    Witam.
    Na wstępie chciałbym powiedzieć, że być może moje pytania wyda się Wam trywialne, bezsesowne, głupie itd., itp., lecz ja naprawdę od jakiegoś czasu nie mogę znaleźć żadnych konkretnych odpowiedzi na ten temat.
    Otóż problem mój jest następujący.
    Pragnę zapytać bardziej doświadczonych kolegów czy jest możliwe sterowanie za pomocą ATmega8, który jak wiadomo ma trzy kanały PWM, większą ilością serwonapędow, np. czterema lub piecioma.
    Oczywiście rozwiązanie typu: zastosuj mikrokontroler o większej liczbie kanałów PWM mnie nie zadowala, ponieważ problem można uogolnić na każdy mikrokontroler.
    Również programowe tworzenie dodatkowych kanałów też nie jest dobrym rozwiązaniem w niektórych sytuacjach.
    W kilku projektach robotów, również na elektrodzie, czytałem o sterownikach 16 serw na ATMega8, jednak te projekty były dosyć archiwalne wiec nie rozgrzebywałem tam tematu, bo i tak pewnie nikt tam nie zagląda.
    Czy ktoś z Was potrafi mi wytłumaczyć jak to zrobić, jeżeli jest to oczywiście możliwe.
    Pozdrawiam i z góry dziękuje
  • Pomocny post
    #2 7839397
    _Robak_
    Poziom 33  
    No jeśli nie chcesz tworzyć programowo nowych kanałów, ani użyć procesora z większą ilością kanałów PWM to zostaje Ci dodanie sprzętowo tych kanałów, co chyba będzie najtrudniejsze. W każdym razie dobrze pisałeś, atmegą8 spokojnie wysterujesz 16 serw. A jak? Pewnie trafiłeś na mój wątek, jak nie to:
    https://www.elektroda.pl/rtvforum/topic619011.html
  • #3 7839592
    davidpi
    Poziom 10  
    No super.
    Wreszcie zaczynam coś łąpać.
    Jeżeli dobrze rozumiem to ogólna zasada jest taka, żeby użyć dwóch mikrokontrolerów: jeden ktory będzie zarządzał całym programem i drugi ktory będzie tylko sterownikiem ser. Ten pierwszy wysyłą za pomocą jakiejś komunikacji do drugiego mikroprocka pozycję danego serwa, a drugi, ktory zajmuje się programowym generowanie impulsów PWM, odbiera tą pozycje i ustawia dane serwo.
    Dzieki za pomoc. Bardzo mi się przyda Twój wątek odnośnie sterowania serwami
    Pozdrawiam
  • #4 7839718
    _Robak_
    Poziom 33  
    Hmm powiem Ci tak, idea nie jest taka, ale ja akurat taką przyjąłem w moim robocie. Są tego plusy i minusy. Jak podejmowałem decyzję o tym żeby rozbić to na dwa mikrokontrolery znałem jeden poważny plus tego rozwiązania, ale jakoś potem zapomniałem co to było, serio;) Teraz co mi przychodzi do głowy, to jak chcesz móc sterować prędkością czy ładnie zrobić soft start to musisz raczej rozbić to na dwa procesory.
  • #5 7839848
    davidpi
    Poziom 10  
    Aha. Dzięki.
    A możesz mi powiedzieć czy są jeszcze jakiś inne sposoby rozwiązania tego problemu niż te o których tutaj mówimy, czyli: dwa procki, mocniejszy procek, lub jeden procek z programowym tworzeniem kanałów??
  • #6 7839898
    _Robak_
    Poziom 33  
    Generalnie, dając dwa procesory, ATmega128 jako sterownik plus np. ATmega16 jako urządzenie nadzorujące, jesteś w stanie wysterować spokojnie kilkadziesiąt serwomechanizmów. W takim wypadku, możesz się zacząć martwić jak zasilić te pożeracze prądu:) Na razie radzę Ci zrobić prosty sterownik na ATmega16 i szybko zobaczysz czy potrzebujesz większej mocy czy nie i gdzie Ci jej brakuje, czy liczniki czy mocy obliczeniowej itp..
  • #7 7839922
    davidpi
    Poziom 10  
    OK dzięki wielkie jeszcze raz.
    Posłucham Twojej rady i zrobie prosty sterownik. Jeżeli będzie śmigac to może mój manipulator dostanie niedługo kolejne dwa stopnie swobody :)
    Pozdrawiam
  • #8 7842541
    davidpi
    Poziom 10  
    Witam ponownie.
    Słowa moje kieruje w szczególności do moderatora _Robak_, ale oczywiście pomoć innych też mile widziana.
    Posłuchałem Twojej rady i wziąłem się za budowe rostego sterownika do serw w oparciu o ATMega8.

    Od razu się przyznam, że analiza Twojego programu była dla mnie zbyt trudno, więc postanowiłem, że sam coś wyskrobie.

    
    #include "avr/io.h"
    #include "avr/interrupt.h"
    #include "util/delay.h"
    const int wait=500;
    int Pwm=1200, i;
    void Zwieksz()
    {
    	if((bit_is_clear(PIND,PD0)) && (Pwm <2200))
    	{
    		Pwm++;
    		_delay_us(wait);
    	}
    } 
    void Zmniejsz()
    {
    	if((bit_is_clear(PIND,PD1)) && (Pwm >700))
    	{
    		Pwm--;
    		_delay_us(wait);
    	}
    }
    
    void Timer1_init()
    {
    	TCCR1B|=(1<<WGM12) | (1<<CS10);
    }
    
    void Timer2_init()
    {
    	OCR2=156;
    	TCCR2=_BV(WGM21) | _BV(CS20) | _BV(CS22);
    	TIMSK=_BV(OCIE2);
    }
    
    void Timer1(int P, int i)
    {
    	TCNT1=0;
    	TIFR|=(0<<OCF1A) | (0<<OCF1B);
    	OCR1A=P;
    	PORTB|=(1<<i);
    	while(bit_is_clear(TIFR,OCF1A))
    	{
    	}
    	PORTB=0x00;
    }	
    
    int main()
    {
    	DDRB=0xff;
    	DDRD=0x00;
    	PORTD=0xff;
    	Timer1_init();
    	Timer2_init();
    	sei();
    	while(1)
    	{
    	Zwieksz();
    	Zmniejsz();
    	}
    	return 0;
    }
    
    ISR(TIMER2_COMP_vect)
    {
    	for(i=1; i<=7;i++)
    	Timer1(Pwm, i);
    }
    

    Popełniłem taki program.
    Może objaśnie mniej więcej co jest do czego.
    Ma on obsługiwać kilka serw (ich liczba jest zawarta w pętli w obsłudze przerwania).
    Licznik drugi generuje przerwanie co 20ms. W tym przerwaniu uruchamiana jest funkcja Timer1 która generuje impulsy o zadanym wypełnieniu (szerokość wypełnienia to zmienna Pwm) za pomocą pierwszego licznika.

    Program działą nieźle, ale ma jeden szkopuł. Otóż czas trwania funkcji Timer1 jest zależny od wypełnienia (co jest logiczne), a tym samym czast trwania przerwania od Licznika drugiego też jest zależny od wypełnienia.

    Wobec tego faktu czas ktory pozostaje pomiędzy kolejnymi przerwaniami, a ktory jest przeznaczony na ewentualną zmianę wartości Pwm (za pomocą przycisków podpiętych do PD0 i PD1) jest różny.

    Co to wszystko daje?? Otóż poprostu w zależności od kąta obrotu (czyt. od Pwm) serwo obraca się z różną prędkością.

    Czy ktoś mógłby mi powiedzieć jak taki problem rozwiązać??
    Domyślam się, że należałoby np. sprawić aby funkcja Timer1 mimo rożnego Pwm, wykonywała się stały okres czasu (ok 2.5ms), tylko że nie mam pomysłu jak to zrobic.

    W tym miejscu jeszcze raz kieruje moją prośbę do _Robak_.
    Czy mógłbyś napisać dla mnie jakąś prostą wersje programu dla takiego sterownika?? wystraczy obsługa dwóch serwonapędów, zmiana wypełnieenia może się odbywać tak jak u mnie czyli za pomocą przycisków.
    Prosiłbym też o możliwie dużo komentarzy w tym programie.

    Oczywiście zdaję sobie sprawę, że moderator ma wiele innych rzeczy na głowie, a nie tylko edukacja początkujących, dlatego programy innych użytkowników tez mile widziane :)
    Pozdrawiam
  • #9 7842635
    _Robak_
    Poziom 33  
    Zrób tak jak opisałem w temaci do którego dałem linka, weź timer0 który odmierza np. 2.5ms(to jest dla 8 serw) albo 10ms(dla 2 serw), jeśli rozumiesz skąd się biorą te wartości to już połowa sukcesu:) Timerem1 odmierzaj sobie od 1 do 2ms. Pisać Ci programu nie będę bo to nieedukacyjne;)
  • #10 7842712
    davidpi
    Poziom 10  
    Rozumiem skąd te wartości. W sumie mają dać 20 ms, tyle ile okres saygnalu dla serwa. Mam jeszcze pytanko:

    1. Jeżeli wezmę 8 serw i na każde dam 2.5ms, to w którym momencie zwiększac lub zmiejszać wartość Pwm?? Zapewne gdzieś wewnątrz obsługi poszzczególnego serwa??

    Dodano po 4 [godziny] 4 [minuty]:

    Dodam tylko, że wszystko śmiga elegancko. Oto gotowy kod:
    
    #include "avr/io.h"
    #include "avr/interrupt.h"
    #include "util/delay.h"
    
    int Pwm=1500, i=0, Skok=2;
    
    void Zwieksz()
    {
    	if((bit_is_clear(PIND,PD0)) && (Pwm <2400)) Pwm+=Skok;
    }
     
    void Zmniejsz()
    {
    	if((bit_is_clear(PIND,PD1)) && (Pwm >600)) Pwm-=Skok;
    }
    
    void Timer1_init()
    {
    	TCCR1B|=(1<<WGM12) | (1<<CS10);
    }
    
    void Timer2_init()
    {
    	OCR2=78;
    	TCCR2=_BV(WGM21) | _BV(CS20) | _BV(CS21);
    	TIMSK|=(1<<OCIE2);
    }
    
    void Port_init()
    {
    	DDRB=0xff;
    	DDRD=0x00;
    	PORTD=0xff;
    }
    
    void Timer1(int P, int i)
    {
    	Zwieksz();
    	Zmniejsz();
    	TCNT1=0;
    	OCR1A=P;
    	TIFR|=(0<<OCF1A);
    	PORTB|=(1<<i);
    	while(bit_is_clear(TIFR,OCF1A))
    	{
    	}
    	PORTB=0x00;
    }
    
    int main()
    {
    	Port_init();
    	Timer1_init();
    	Timer2_init();
    	sei();
    	while(1)
    	{
    	}
    	return 0;
    }
    
    ISR(TIMER2_COMP_vect)
    {
    	Timer1(Pwm, i);
    	if(++i>7) i=0;
    }
    


    Wykorzystując tą metodę i kanał "B" w Liczniku 1 można sterować spokojnie 16 serwami. Prędkość jest stała niezależnie od kąta obratu, a zależy od precyzji jaką chcemy uzyskać. Dzieki jeszcze raz za pomoc
  • #11 7844008
    PiotrPitucha
    Poziom 34  
    Witam
    A może klasycznie po modelarsku ?
    Zrób koder ( albo weź gotowca jakich masę jest w sieci ) i wygeneruj ramkę 20ms, dajesz start, odliczasz czas pierwszego serwa, potem impuls i odliczasz czas drugiego serwa itd.
    Na wyjściu dajesz dekoder albo klasyczny na CD4015, albo na jakimś małym procesorku, czyli jedno wejście szeregowe i 8 wyjść i po sprawie.
    Nie pamiętam czasu impulsów, ale jeśli nie ślesz tego radiem to nie są krytyczne.
    Pierwszy impuls to początek dla serwa 1, drugi to koniec dla serwa1 i początek dla serwa 2 itd. , jeśli przerwa jest dłuższa to koder i dekoder się synchronizują i bajka kręci się od początku.
    Nie używałbym wcale PWMa, tylko jakiegoś licznika do odmierzania czasu poszczególnych impulsów, musi się to odbywać dość szybko, bo czas między skrajnymi położeniami serwa to około 1ms, zakładając że ma to działać w miarę płynnie czyli powiedzmy 8 bitów rozdzielczości to wychodzi nam 4µs na jeden krok.
    Piotr
  • #12 12208840
    ienecode
    Poziom 21  
    witam. jak zmienic ten program aby z przyciskow (PD0, PD1) sterowac jednym serwem (PB0), nastepnie przyciskiem (PD2,PD3) sterowanie kolejnym serwem (PB1).. i tak dalej ....?
  • #13 12210276
    Dar.El
    Poziom 41  
    :arrow: davidpi
    Popraw Swoje posty, robisz bardzo dużo błędów. Użyj też funkcji SYNTAX do wstawiania kodu. Jutro sprawdzę i podejmę decyzję.
REKLAMA