Hallo

"Fortbewegung" ist noch nicht möglich, da bin ich in der ersten Euphorie mit dem Threadtitel etwas über die Realität hinausgeschossen:)

Die Frage die hinter diesem Funktionsmodell steckt: Könnte ein Roboter mit nur zwei solchen "Beinen" laufen? Um das zu Überprüfen musste ich erstmal einen Weg finden, die Beine leicht, stabil und vor allem kostengünstig herzustellen. Und das scheint mir mit den blauen Stützen, die im echten Leben Wattestäbchen sind, gelungen zu sein. Immerhin kann das Teil frei stehen und Kniebeugen machen, mehr schafft die Software leider noch nicht.

Zur Ansteuerung verwende ich die Caterpillar-Platine von arexx. Diese besitzt einen 16MHz-Mega16 und ist für den Betrieb von 8 Servos ausgelegt. Allerdings gefällt mir deren Software nicht so gut, weil sie die Servoimpulse für das Restprogramm blockierend erzeugt. Deshalb verwende ich meine eigene Routinen, die nach vielen Versuchen nun sehr kompakt sind:

Code:
// Servoansteuerung mit 16Bit-Timer1 (mit arexx cat16)             mic 18.1.2011

// Die 8 Servos werden an Port C und D angeschlossen:
// Servo0 - PC0
// Servo1 - PC1
// Servo2 - PD2
// Servo3 - PD3
// Servo4 - PD4
// Servo5 - PD5
// Servo6 - PD6
// Servo7 - PD7

#define mitte 2500 // das sollte 1,25 Millisekunden entsprechen

#define pos1 500
#define pos2 1000

#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint8_t count_20ms;
volatile uint16_t servo[9] ={0, 0, 0, 0, 0, 0, 0, 0, 40000}; // Servopositionen

ISR(TIMER1_COMPA_vect)
{
	static uint8_t nr=0;                      // Nummer des aktuellen Servos

	PORTB &= ~0b00000011;                     // alle Servoimpulse low
	PORTC &= ~0b11111100;

	if(nr>7)                                  // Impuls für Servo oder Pause?
	{
		OCR1A = servo[8];                      // servo[8] ist die Impulspause
		servo[8] = 40000;                      // Startwert 20ms laden
		nr = 0;             							// beim nächsten ISR-Aufruf Impuls
															// für Servo 0 erzeugen
		if(count_20ms) count_20ms--;           // blockierende Pause aktiv?
	}
	else
	{
		if(nr<2) PORTB |= (1<<nr);             // Impulsleitung des aktuellen Servos
			else PORTC |= (1<<nr);              // auf High setzen und
		OCR1A = servo[nr];                     // Impulslänge in OCR1A laden
		servo[8] -= servo[nr];                 // Impulslänge von der Pause abziehen
		nr++;                                  // nächstes Servo
	}
	TCNT1=0x00;                               // Zählregister reseten
}

void Sleep(uint8_t pause)                    // 1/50 Sekunde blockierende Pause
{
   count_20ms=pause+1;
   while(count_20ms);
}

int main(void)
{
	cli();

	// für 16MHz-ATMega16
	TCCR1A = (0<<WGM11)|(0<<WGM10);       		// CTC Mode
	TCCR1B = (0<<WGM13)|(1<<WGM12);

	TCCR1B |= (0<<CS12)|(1<<CS11)|(0<<CS10);	// prescaler /8

	TIMSK = (1<<OCIE1A);                      // MatchCompare-Interrupt erlauben

	DDRB = 0b00000011;                        // Servoausgänge setzen
	DDRC = 0b11111100;
	sei();

	while(1)                                  // Demo
	{
	servo[0]=servo[1]=servo[2]=mitte;
	servo[3]=servo[4]=servo[5]=mitte;
  	Sleep(40);
	servo[0]=servo[1]=servo[2]=mitte-pos1;
	servo[3]=servo[4]=servo[5]=mitte+pos1;
  	Sleep(30);
	servo[0]=servo[1]=servo[2]=mitte;
	servo[3]=servo[4]=servo[5]=mitte;
   Sleep(20);
	servo[0]=servo[1]=servo[2]=mitte+pos2;
	servo[3]=servo[4]=servo[5]=mitte-pos2;
  	Sleep(20);
	servo[0]=servo[1]=servo[2]=mitte;
	servo[3]=servo[4]=servo[5]=mitte;
	}
	return(0);
}
Der Timer läuft im CTC-Mode mit 2MHz, 1ms dauert dann 2000 Zähltakte, 20ms entsprechend 40000 Zähltakte des Timers. Die Servoimpulse werden nacheinander erzeugt, am Ende jedes Zykluses wird die Restpause angehängt. So sind theoretisch bis zu 10 Servos möglich, denn 10 mal 2ms ergibt die Wiederholfrequenz von 50Hz. Ich gehe davon aus, dass sich unter Verwendung des B-Kanals des Timers zusätzlich nochmals 10 Servos ansteuern lassen.

Gruß

mic

[Edit]
Das Laden der 16Bit-Servopositionen funktioniert nur deshalb reibungslos, weil nach Sleep() immer mindestens eine Servoimpulslänge lang kein neuer Interrupt ausgelöst wird und somit das Laden der 16Bit-Variablen an dieser Stelle quasi atomar ist.