- 3D-Druck Einstieg und Tipps         
Ergebnis 1 bis 5 von 5

Thema: Servo Ansteuerung

  1. #1
    Benutzer Stammmitglied Avatar von KR-500
    Registriert seit
    26.12.2007
    Alter
    29
    Beiträge
    91

    Servo Ansteuerung

    Anzeige

    Powerstation Test
    Hallo liebes Forum

    ich hab jetzt mal den Code für Servos aus dem RN-Wissen auf 10 Stück umgeschrieben, im Moment benutze ich einen atmega32 mit 16mhz. Später will ich den code für einen attiny2313 umschreiben. Ich wollte jetzt fragen ob es noch verbesserungs Vorschläge/Kritik gibt. Danke.

    Code:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    
    #define F_CPU 16000000
    #define SERVOPIN 7
    #define SERVOPORT PORTD
    #define DDRSERVO DDRD
    
    
    #define USART_BAUD_RATE 	9600
    #define USART_BAUD_SELECT 	(F_CPU/(USART_BAUD_RATE*16L)-1)
    
    #define Low_Servo0 PORTD&=~(1<<PD7)
    #define High_Servo0 PORTD|=(1<<PD7)
    
    #define Low_Servo1 PORTD&=~(1<<PD6)
    #define High_Servo1 PORTD|=(1<<PD6)
    
    #define Low_Servo2 PORTD&=~(1<<PD5)
    #define High_Servo2 PORTD|=(1<<PD5)
    
    #define Low_Servo3 PORTD&=~(1<<PD4)
    #define High_Servo3 PORTD|=(1<<PD4)
    
    #define Low_Servo4 PORTD&=~(1<<PD3)
    #define High_Servo4 PORTD|=(1<<PD3)
    
    #define Low_Servo5 PORTD&=~(1<<PD2)
    #define High_Servo5 PORTD|=(1<<PD2)
    
    #define Low_Servo6 PORTC&=~(1<<PC4)
    #define High_Servo6 PORTC|=(1<<PC4)
    
    #define Low_Servo7 PORTC&=~(1<<PC5)
    #define High_Servo7 PORTC|=(1<<PC5)
    
    #define Low_Servo8 PORTC&=~(1<<PC6)
    #define High_Servo8 PORTC|=(1<<PC6)
    
    #define Low_Servo9 PORTC&=~(1<<PC7)
    #define High_Servo9 PORTC|=(1<<PC7)
    
    
    
    
    void USART_Init( unsigned int baud )
    {
    /* Set baud rate */
    UBRRH = (unsigned char)(baud>>8);
    UBRRL = (unsigned char)baud;
    /* Enable receiver and transmitter */
    UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
    /* Set frame format: 8data, 2stop bit */
    UCSRC = (1<<USBS)|(3<<UCSZ0) | (1<<URSEL);
    }
    
    
    void USART_Transmit( unsigned char data )
    {
    while ( !( UCSRA & (1<<UDRE)) );
    
    UDR = data;
    }
    
    
    unsigned char USART_Receive( void )
    {
    while ( !(UCSRA & (1<<RXC)) );
    
    return UDR;
    }
    
    
    
    volatile unsigned char servopos[10] = {100,100,100,100,100,100,100,100,100,100};
    volatile static int count;
    volatile unsigned char buffer=0,servonr=0,rx_count=0;
    
    
    void servo_init()
    {
    	TIMSK|=(1<<OCIE2);
    	TCCR2 |= (1<<WGM21) | (1<<CS20);	//Prescale=1, CTC mode
    	OCR2 = F_CPU/100000;			//alle 10µS ein IRQ
    	DDRD=0xFF;
    	DDRC=0xFF;
    };
    
    
    int main (void) {
    	servo_init();
    	USART_Init(USART_BAUD_SELECT);
    	sei();
    	
       while (1) {
    //------------------------------------------------------------------------------------------------------------------------------
    	if(count>servopos[0])Low_Servo0;//SERVOPORT&=~(1<<SERVOPIN);
    	else High_Servo0;//SERVOPORT|=(1<<SERVOPIN);
    	if(count>servopos[1])Low_Servo1;//PORTD&=~(1<<PD6);
    	else High_Servo1;//PORTD|=(1<<PD6);
    	if(count>servopos[2])Low_Servo2;
    	else High_Servo2;
    	if(count>servopos[3])Low_Servo3;
    	else High_Servo3;
    	if(count>servopos[4])Low_Servo4;
    	else High_Servo4;
    	if(count>servopos[5])Low_Servo5;
    	else High_Servo5;
    	if(count>servopos[6])Low_Servo6;
    	else High_Servo6;
    	if(count>servopos[7])Low_Servo7;
    	else High_Servo7;
    	if(count>servopos[8])Low_Servo8;
    	else High_Servo8;
    	if(count>servopos[9])Low_Servo9;
    	else High_Servo9;
    	
    //------------------------------------------------------------------------------------------------------------------------------
    	TCCR2 |= (1<<WGM21) | (1<<CS20);
    
      }
    
    	return 0;
    
    }
    
    
    
    
    ISR(TIMER2_COMP_vect)
    {
    	
    	
    	//if(count<2000+servopos)count++;
    	if(count<1800)count++;
    	else count=0;
    	TCCR2 = 0x00;
    };
    	
    
    
    ISR (USART_RXC_vect) {
    	
    	buffer = UDR;
    	switch (rx_count){
    	case 0: if(buffer > 9){
    				rx_count = 0;
    				buffer = 0;
    			}
    			else {
    				servonr = buffer;
    				rx_count = 1;
    			}
    			break;
    	case 1:	servopos[servonr]=buffer;
    			rx_count = 0;
    			break;
    	default:rx_count = 0;
    			break;
    
    
    	}
    	
    	
    }
    KR-500

  2. #2
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    61
    Beiträge
    5.799
    Blog-Einträge
    8
    Hallo

    Eine aussagekräftigere Überschrift für deinen Tread wäre sinnvoll

    Die Idee die Servos in der Hauptschleife zu steuern und nicht direkt in der ISR scheint auf den ersten Blick recht pfiffig. So könnte man vielleicht den Überlauf der ISR verhindern. Allerdings könnte es vorkommen, dass die ISR die while-Schleife "überholt" und sich dadurch count während der einzelnen Servoabfragen ändert. Dann würden die Servos möglicherweise zittern. Ähnliche Effekte könnte auch der Empfang von Zeichen verursachen. Ich bin mir aber nicht sicher, ob das bei 16MHz-Takt auch auftreten kann. Zum Testen könnte man vielleicht diesen Ansatz verwenden:

    Code:
    In der Hauptschleife:
    
       while (1) {
       test='1';
    //------------------------------------------------------------------------------------------------------------------------------
       if(count>servopos[0])Low_Servo0;//SERVOPORT&=~(1<<SERVOPIN);
    
    
    //------------------------------------------------------------------------------------------------------------------------------
       TCCR2 |= (1<<WGM21) | (1<<CS20); // warum wird hier am TCCR2 gefummelt?
    	USART_Transmit(test); // eine '0' gesendet wird gab es einen Überlauf!
    	// UDR = test; // Variante gegen Seiteneffekte von USART_Transmit()?
      }
    
    In der ISR:
    
    ISR(TIMER2_COMP_vect)
    {
    	test='0';
    Wobei sowas eigentlich ja immer auftreten kann, weil die while-Schleife ja nicht syncron mit der ISR läuft. Vielleicht könnte man das so lösen:
    Code:
       while (1) {
       while(count==count_old);
    	count_old=count;
    //------------------------------------------------------------------------------------------------------------------------------
    
    
    //------------------------------------------------------------------------------------------------------------------------------
    
    	if(count!=count_old) UDR = '*';  // Überlauf aufgetreten!
    
       TCCR2 |= (1<<WGM21) | (1<<CS20); // warum wird hier am TCCR2 gefummelt?
     }
    Zeitsparen könnte man mit einzelnen Variablen für die Servopositionen (pos1, pos2,..) ohne Positionen-Array. Es ist ungünstig, wenn alle Servossignale gleichzeitig starten. Das verursacht hohe Einschaltströme.

    Ich hoffe, das ist nicht allzuviel Unsinn. Ich habe das nicht selbst getestet!.

    Gruß

    mic

    [Edit]
    Ich habe das "TCCR2 = 0x00;" am Ende der ISR erst jetzt beachtet. Das stoppt doch das Timeing komplett und es wird erst wieder gestartet, wenn die Hauptschleife fertig ist. Das sollte eigentlich gar nicht funktionieren. Spannend, das muss ich wohl doch selbst mal testen...
    Bild hier  
    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  3. #3
    Benutzer Stammmitglied Avatar von KR-500
    Registriert seit
    26.12.2007
    Alter
    29
    Beiträge
    91
    Hi radbruch,

    Danke für deine schnelle Antwort.

    Ich habe das "TCCR2 = 0x00;" am Ende der ISR erst jetzt beachtet. Das stoppt doch das Timeing komplett und es wird erst wieder gestartet, wenn die Hauptschleife fertig ist. Das sollte eigentlich gar nicht funktionieren. Spannend, das muss ich wohl doch selbst mal testen...
    Das Stoppen des Timers hab ich eingefügt, weil ich vorher mit 8Mhz gearbeitet habe und dann der USART Empfangs Interrupt nicht funktionierte. Beim Debuggen hab ich dann festgestellt ,dass es am Timer_interrupt liegt. Weil durch das Stoppen des Timers der Interrupt aber nicht mehr alle 10 µsec eintrifft habe ich im Code die Variable count nicht mehr bis 2000 sondern bis 1800 gezälht, dieser Wert beruht aber nur auf ausprobieren.
    Es ist ungünstig, wenn alle Servossignale gleichzeitig starten. Das verursacht hohe Einschaltströme.
    Das klingt logisch, davon hab ich glaub ich schon mal gelesen, wie viele Sekunden bzw. millisekunden sollte man denn warten bevor man das Nächste Servosignal ausgibt?
    Kritik, Anregungen und Verbesserungsvorschläge sind weiterhin erwünscht.

    KR-500

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.05.2006
    Beiträge
    184
    Hi,

    Kannst du was zu deiner HW sagen bzw. nen Schaltplan posten?

    Wie hängen die Servos am µC.

    mfg
    Christoph

  5. #5
    Benutzer Stammmitglied Avatar von KR-500
    Registriert seit
    26.12.2007
    Alter
    29
    Beiträge
    91
    Hi,

    im Moment benutze ich das "ATMEL Evaluations-Board Version 2.0.1" von Pollin und das RS-2 Standardservo von Conrad (Artikel-Nr.: 233751 - 62). Die Servos bekommen die selbe Stromversorgung wie der µc und das Signal geht vom Port über einen 10k Schutzwiderstand zum Servo.

    KR-500

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

12V Akku bauen