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

Programowy PWM sterowanie microserwem Dynam

tomekw19_1985 09 Lut 2009 14:55 2453 12
REKLAMA
  • #1 6125176
    tomekw19_1985
    Poziom 18  
    Witam Prosiłbym o pomoc w napisaniu kodu do sterowania serwem Dynam DY-014. Szukałem po forum, oczywiście są jakieś zalążki kodów lecz wszystko nie do końca. Z programowania jestem zielony. Potrzebuje wysterować cztery serwa które podpięte są do portów PE4 PE5 PE6 PE7. Nie mogę fizycznie podłączyć ich do innych portów. Chodzi mi o coś takiego by 2 serwa wychyliły się w prawo o 45stopni i 2 serwa w lewo o 45stopni a po pewnym czasie wróciły w położenie 0. Mikrokontroler to atmega128. Pozdrawiam
  • REKLAMA
  • #2 6125880
    marenc
    Poziom 24  
    Sterowanie serwami polega na podawanie impulsów o określonym czasie trwania...

    Naszukałem się, ale znalazłem(zasada działania i timingi): http://www.seattlerobotics.org/encoder/200106/fig1.jpg

    Trudność polega na stabilizacji trwania impulsu podczas pracy całego programu mikrokontrolera.
  • REKLAMA
  • #4 6126870
    tomekw19_1985
    Poziom 18  
    Zapomniałem napisać, że kod programu musi być w C. Czytałem już o tym jak się steruje samym serwem lecz nie wiem jak to napisać programowo. niestety nigdy nie byłem dobry z programowania.
  • REKLAMA
  • #5 6126894
    marenc
    Poziom 24  
    Ehhhhhhh ... nie lubię dawać gotowców, bo ludzie zarabiają na pisaniu programów. W załączniku jest STARY plik ze STAREGO projektu, ale masz tam mniej więcej objaśnione jak to powinno wyglądać...
  • #6 6128109
    tomekw19_1985
    Poziom 18  
    Dzięki za kod to mam lekturę na kilka dni.
  • #7 6128453
    marenc
    Poziom 24  
    Ciebie najbardziej powinien interesować kawałek:
    	uint8_t temp;
    	uint8_t loop;
    
    	PORTA = 0xff;//Rozpoczęcie sygnału sterującego
    
    	_delay_ms(0.6);//Odczekanie minimalnej długości sygnału strującego
    
    	temp = PORTA;
    	
    	for(loop=0;loop<181;loop++)//Kończenie sygnałów sterujących dla odpowiedniego przemieszczenia ramienia
    	{
    
    		if(S0==loop){temp &= 0b11111110;}
    		if(S1==loop){temp &= 0b11111101;}
    		if(S2==loop){temp &= 0b11111011;}
    		if(S3==loop){temp &= 0b11110111;}
    		if(S4==loop){temp &= 0b11101111;}
    		if(S5==loop){temp &= 0b11011111;}
    		if(S6==loop){temp &= 0b10111111;}
    		if(S7==loop){temp &= 0b01111111;}
    
    		PORTA = temp;
    
    		_delay_us(10);//Odczekiwanie pomiędzy kolejnymi stopniami konta przemieszczenia ramienia
    
    	}
    
    	PORTA = 0x00;//Zakończenie wszystkich sygnałów(PEWNOŚĆ ZAKOŃCZENIA)

    Mam trochę czasu, więc tłumaczę:
    -PORTA = 0xff; - rozpoczynał impuls sterujący serwami na porcie A
    -_delay_ms(0.6); - odczekiwało minimalną długość impulsu(u mnie 600us, ale zależne od czasu trwania do zakończenia impulsu o kącie 0 stopni)
    -pętla for wykonywała kończenie impulsów dla odpowiednich wartości(zależne od wartości zmiennych S0..S7). W pętli zmiana stanów linii sterujących serwami jest synchroniczna(PORTA = temp).
    -_delay_us(10); - odczekuje czas dla kolejnych stopni kąta przesunięcia ramienia serwa.
    -PORTA = 0x00; - upewnienie, że wszystkie sygnały zakończone.

    To pewnie działało, bo robiłem to na zlecenie. Poniżej są funkcje ruchu serwami(manualne i czytane z EEPROM'u) oraz zmiany wartości w czasie. U Ciebie zmiana może następować skokowo, ale robot nie mógł wykonywać sztywnych ruchów ;) Jak teraz po pewnym czasie na to patrzę, to całkiem logicznie jest w tym pliku, choć może nie optymalnie ;)
  • #8 6136851
    tomekw19_1985
    Poziom 18  
    Witam Napisałem program według autora riddyk https://www.elektroda.pl/rtvforum/topic1091788.html ,a właściwie pozmieniałem trochę
     #include <avr/io.h>
    #include <inttypes.h>
    #include <avr/signal.h>
    #include <avr/pgmspace.h>
    #define cbi(add,bit) ((add) &= ~(1 << bit));
    #define sbi(add,bit) ((add) |= (1 << bit));
    #define F_CPU 16000000UL
    
    int i, z;
    void serwo (void)
    {
       sbi(PORTE,PE4);              // serwo 1
       for (z=0; z<i ;z++)
       { 
       asm ("nop") ;
       }   
       cbi(PORTE,PE4);
       for (z=0;z<1500-i;z++);     // jeżeli obsługujemy więcej niź jedno
       {
        asm ("nop") ;
    	}                 			// serwo odejmujemy więcej z warunku
                                    // tyle ile trwa wysterowanie kolejnego
                                    // serwa
    }
    
    
    void klawiatura (void)
    {
    	if 
    
    (bit_is_clear(PINA,0))			//(PINA==0xFE)   // w lewo serwo1
    	{
    		i=i+1;
    	}
    if 
    (bit_is_clear(PINA,1))			//(PINA==0xFF)   // w prawo serwo1
    	{
    		i=i-1;
    	}	
    for (z=0; z<10 ;z++)   			// pauza po przyciśnięciu klawisza
    		{
    		asm ("nop");
    		}
    }
       
    int main(void)
    {
       DDRE=_BV(4);   				// port w stanie wyjść tu są podpięte serwa
       PORTA=_BV(0)|_BV(1); 		// podciągnięcie przycisków
    
       i=137;      					// to jest ustawienie środka serwa1, pozycja początkowa
       
       for (;;)
      {
    
       klawiatura();
          
       if (i<=39)   i=40;          // ustawienia krańcowe serwa 1
       if (i>=226)  i=225;
       
       serwo();
    
       }
       return 0;
    }
    i coś nie działa
  • #9 6172265
    tomekw19_1985
    Poziom 18  
    Witam ponownie po małych poprawkach program działa
    #include <avr/io.h>
    #include <util/delay.h>
    #define cbi(add,bit) ((add) &= ~(1 << bit));
    #define sbi(add,bit) ((add) |= (1 << bit));
    #define F_CPU 16000000UL
    
    int i, z ,i1 ,z1;
    void serwo (void)
    {
        	sbi(PORTE,PE5);								// wystaw 1 na serwo 2
        	sbi(PORTE,PE6);								// wystaw 1 na serwo 3
       		for (z=0; z<i ;z++)
       { 
      		asm ("nop") ;								//wstawka asembler
       }   
     		cbi(PORTE,PE5);								// wystaw 0 na serwo 2
     		cbi(PORTE,PE6);								// wystaw 0 na serwo 3
      		for (z=0;z<24000-i;z++);   					// jeżeli obsługujemy więcej niź jedno serwo
      {
      		asm ("nop") ;
    	}
    		sbi(PORTE,PE4);								// wystaw 1 na serwo 2
        	sbi(PORTE,PE7);								// wystaw 1 na serwo 3
       		for (z1=0; z1<i1 ;z1++)
       { 
      		asm ("nop") ;								//wstawka asembler
       }   
     		cbi(PORTE,PE4);								// wystaw 0 na serwo 2
     		cbi(PORTE,PE7);								// wystaw 0 na serwo 3
      		for (z1=0;z1<24000-i1;z1++);   					// jeżeli obsługujemy więcej niź jedno serwo
      {
      		asm ("nop") ;
    	}
    
    }
    
    
    
    
       
    int main(void)									//pętla główna
    {
    DDRE=_BV(4)|_BV(5)|_BV(6)|_BV(7);  				// port w stanie wyjść tu są podpięte serwa
    DDRA=_BV(2)|_BV(3)|_BV(4)|_BV(5)|_BV(6)|_BV(7);	//port w stanie wyjść tu są podbięte diody LED
    DDRB=0xff;										//port w stanie wyjść 
    DDRC=0xf0;										//port w stanie wyjść
    PORTA=_BV(0)|_BV(1)|_BV(7);						// podciągnięcie przycisków oraz silników
    PORTB=_BV(4)|_BV(5)|_BV(6)|_BV(7)|_BV(3);		//ustawienie wyjsc pwm na 1
    PORTC=_BV(6)|_BV(4);							// ustawienie wyjść na 1 części portu
    
    i=4;
    i1=4;
    
    
    if (bit_is_set(ACSR, ACO))						//jeśłi porównanie równe 1
    {
    sbi(PORTA, PA2);								//zapal diode na PA2
    }
    	else cbi(PORTA,PA2);						//w innym wypadku zgaś ją
    
    	      							
       
       for (;;)
    
     {     
       if (i<=2)   i=3600;          				//ustawienia krancowe serw
       if (i1<=2)	i1=3600;
       if (i>=3)	i=2750;
       if (i1>=3)	i1=4450;
       serwo();
    }
    
    return 0;									//powrot do początku
    }
    . Serwa ustawiają się w pozycji 45stopni tak jak chciałem. Chciałem by serwa pierw były w pozycji 0 przez np 5 sekund i następne 5 w pozycji 45 stopni. Gdy dam delaya po i=4 i i1=4 to nie trzyma serw bo wykonuje delaya co zrobić by te czasy tam jakoś wrzucić?
  • REKLAMA
  • #10 6172409
    Freddie Chopin
    Specjalista - Mikrokontrolery
    albo ty w ogole nie rozumiesz zasad programowania, albo ja w ogole nie rozumiem twojego programu...

    co ci da delay po ustawieniu i i i1, skoro ustawianie serwa masz daleko pozniej, nie mowiac juz o tym, ze twoje porownania wewnatrz petli for sa totalnie bez sensu... dlaczego? bo wartosc i oraz i1 jest STALA w calym programie - nigdzie jej nie zmieniasz.

    4\/3!!
  • #11 6173044
    tomekw19_1985
    Poziom 18  
    No to jest bez pętli for
    #include <avr/io.h>
    #include <util/delay.h>
    #define cbi(add,bit) ((add) &= ~(1 << bit));
    #define sbi(add,bit) ((add) |= (1 << bit));
    #define F_CPU 16000000UL
    
    int i, z ,i1 ,z1;
    void serwo (void)
    {
        	sbi(PORTE,PE5);								// wystaw 1 na serwo 2
        	sbi(PORTE,PE6);								// wystaw 1 na serwo 3
       		for (z=0; z<i ;z++)
       { 
      		asm ("nop") ;								//wstawka asembler
       }   
     		cbi(PORTE,PE5);								// wystaw 0 na serwo 2
     		cbi(PORTE,PE6);								// wystaw 0 na serwo 3
      		for (z=0;z<24000-i;z++);   					// jeżeli obsługujemy więcej niź jedno serwo
      {
      		asm ("nop") ;
    	}
    		sbi(PORTE,PE4);								// wystaw 1 na serwo 1
        	sbi(PORTE,PE7);								// wystaw 1 na serwo 4
       		for (z1=0; z1<i1 ;z1++)
       { 
      		asm ("nop") ;								//wstawka asembler
       }   
     		cbi(PORTE,PE4);								// wystaw 0 na serwo 1
     		cbi(PORTE,PE7);								// wystaw 0 na serwo 4
      		for (z1=0;z1<24000-i1;z1++);   					// jeżeli obsługujemy więcej niź jedno serwo
      {
      		asm ("nop") ;
    	}
    
    }
    
    
       
    int main(void)									//pętla główna
    {
    DDRE=_BV(4)|_BV(5)|_BV(6)|_BV(7);  				// port w stanie wyjść tu są podpięte serwa
    DDRA=_BV(2)|_BV(3)|_BV(4)|_BV(5)|_BV(6)|_BV(7);	//port w stanie wyjść tu są podbięte diody LED
    DDRB=0xff;										//port w stanie wyjść 
    DDRC=0xf0;										//port w stanie wyjść
    PORTA=_BV(0)|_BV(1)|_BV(7);						// podciągnięcie przycisków oraz silników
    PORTB=_BV(4)|_BV(5)|_BV(6)|_BV(7)|_BV(3);		//ustawienie wyjsc pwm na 1
    PORTC=_BV(6)|_BV(4);							// ustawienie wyjść na 1 części portu
    
    i=2750;          				//ustawienia krancowe serw
    i1=4470;
    
    
    
    if (bit_is_set(ACSR, ACO))						//jeśłi porównanie równe 1
    {
    sbi(PORTA, PA2);								//zapal diode na PA2
    }
    	else cbi(PORTA,PA2);						//w innym wypadku zgaś ją
    
    	      							
    serwo();
    
    return 0;									//powrot do początku
    }
    Co do programowania nigdy nie miałem podstaw więc proszę o sporo wyrozumiałości. Chcę zrobić tak by serwa przez jakiś czas były w pozycji 45stopni i po czasie przekręciły się do pozycji 0 i wsio
  • #12 6173154
    Freddie Chopin
    Specjalista - Mikrokontrolery
    program zresetuje sie po tak krotkiej chwili, ze nawet tego nie zauwazysz.

    jesli ten program ma miec jakikolwiek sens, to do funkcji servo powinienes podawac parametry, w ktorych okreslasz pozycje serwa (dwoch na raz w 2 parametrach, albo funkcja przyjmuje dodatkowo numer serwa). do tego KONIECZNE sa przerwania od timera i w nich PWM programowy, albo PWM sprzetowy, bo inaczej sie tego nie da zrobic i tyle. potem tylko delay, kolejne wywolanie z inna pozycja, delay, ustawienie, delay ... wszystko dla przykladu zamkniete w nieskonczonej petli.

    4\/3!!
  • #13 6173197
    tomekw19_1985
    Poziom 18  
    Ok i tak tego nie zrobię. Program działa serwa utrzymują pozycję tyle, że nie można w trakcie działania zmienić pozycji serw. Pozdro i dzięki za porady
    Znalazłem na forum program na liczniku
    #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
    
    DDRE=_BV(4);   //wyjście OCR1B
    
    while(1)
    {
    
    if(OCR1B<2500)
    OCR1B+=10;
    else OCR1B=500;
    _delay_ms(50);
    }
    
    while(1);
    return 0;
    }
    
    i serwo stoi w miejscu.
REKLAMA