Hallo

Grundsätzlich unterscheidet man blockierende und nicht blockierende Ansteuerungen. Blockierend bedeutet, das Programm wird nicht weiter fortgeführt wärend die Servoimpulse erzeugt werden. (Wie so ein Impuls aussehen sollte ist Grundlage, das solltest du schon wissen). Die Impulse werden solange erzeugt bis das Servo genug Zeit hatte die Zielpossition zu erreichen. Ein Beispiel mit Servo an LED1 (IO1):
Code:
// RP6 steuert ein Servo an der SL1-LED mit Sleep() 

#include "RP6RobotBaseLib.h" 

uint8_t i; 

int main(void) 
{ 
initRobotBase(); 

   while(true) 
   { 
      i=0;                           // i mit Startwert laden 
      while(getBumperLeft() && (i<5))   // Wenn links gedrückt fünf Impulse senden 
      { 
         setLEDs(1);                // Impuls High senden 
         sleep(10);                 // ca. 10 * 100µs warten 
         setLEDs(0);                // Impuls Low senden 
         sleep(200-10);             // ca. 20ms - 1ms Pause 
         i++; 
      } 

      i=0; 
      while(getBumperRight() && (i<5)) 
      { 
         setLEDs(1); 
         sleep(20); 
         setLEDs(0); 
         sleep(200-20); 
         i++; 
      } 
   } 

   return 0; 
}
https://www.roboternetz.de/community...l=1#post414115

Es wird solange ein Impuls erzeugt wie ein Bumper gedrückt wird. Ein Sleep(1) dauert beim RP6 0,1ms, Sleep(10) entsprechend 1ms bzw. Sleep(20) eben 2ms. Obwohl man mit dieser Methode auch mehrere Servos gleichzeitig ansteuern kann, ist sie letztlich eine Sackgasse, denn der RP6 kann ja nichts nebenher erledigen. Wenn er doch etwas anderes macht erhalten die Servos keine Impulse mehr und dein Roboterarm knickt ab...

Ganz anders verhalten sich interruptgesteuerte Ansteuerungen. Hier wird vom (Haupt-)Programm ledig die Zielposition vorgegeben, die Interruptsteuerung sorgt dann im Hintergrund dafür, das die entsprechenden Impulse erzeugt werden. Blöd ist allerdings dabei, dass die Lib des RP6 alle Timer belegt. Die einfachste libverträgliche Lösung ist deshalb wohl dieser Ansatz:
Code:
// Servoansteuerung mit Timer1                                         31.1.2010 mic

// Einfach und elegant, warum finde ich das erst jetzt? Timer1 (RP6-Motoransteuerung)
// läuft ja sowieso im Hintergrund. Deshalb kann man die "klassische" Servoansteuerung
// in die Overflow-ISR einbauen und mit ca. 19kHz aufrufen lassen. Timersetup der Lib:
// Mode 10, Phase Correct mit ICR1 als Top ergibt bei ICR1=210 ca. 8MHz/420=19047,6Hz ;)

// Drehbereich meiner RS-2-Servos ist von ca. 14 bis ca. 38

#include "RP6RobotBaseLib.h"

volatile uint8_t servo1, servo2, servo3, p; 	// Servopositionen und Impulszähler
uint8_t c; 												// ein Char zur freien Verfügung

int main(void)
{
   initRobotBase();
   servo1=servo2=servo3=26;	// Servomitte?
   TIMSK |= (1 << TOIE1); 		// Die Timer1 Overflow-ISR zur Servoansteuerung
	DDRA |= (E_INT1);          // Servopins auf Ausgang setzen
   DDRC |= (SCL | SDA);
   setLEDs(1);                // und los!
   startStopwatch1();
   startStopwatch2();
   startStopwatch3();
	while(1)
   {
   	for(c=0;c<6;c++)            // 6 mal ein einfaches Demo....
		{
		   setLEDs(1<<c);
			servo1=servo2=servo3=26; // mitte
   		p=50; while(p);          // warten bis 50 Impulse gesendet (ca. 1 Sek.)
   		servo1=servo2=servo3=14; // links
   		p=50; while(p);
   		servo1=servo2=servo3=38; // rechts
   		p=50; while(p);
		}
		setStopwatch1(0);
		setStopwatch2(0);
		setStopwatch3(0);
		while(c)                    // und 6 mal ein etwas anspruchsvolleres Demo
		{
		   setLEDs(1<<c);
		   if(getStopwatch1()>1000)
		   {
		      setStopwatch1(0);
				switch(servo1)
		      {
		         case 38: servo1=30; break;
		         case 30: servo1=20; break;
		         case 20: servo1=14; break;
		         case 14: servo1=21; break;
		         case 21: servo1=31; break;
		         case 31: servo1=38; break;
				}
			}
		   if(getStopwatch2()>100)
		   {
		      setStopwatch2(0);
		      servo2++;
		      if (servo2 > 38) { servo2=14; c--; }
			}
		   if(getStopwatch3()>300)
		   {
		      setStopwatch3(0);
		      if (servo3 == 10) servo3=50; else servo3=10;
			}
			task_RP6System(); // Verträglichkeitstest ;)
		}
   }
   return 0;
}
ISR (TIMER1_OVF_vect)
{
	static uint16_t servocount=1;
	if(servocount > servo1) PORTA &= ~E_INT1; else PORTA |= E_INT1; 		// PA4 XBUS 8
	if(servocount > servo2) PORTC &= ~SCL; else PORTC |= SCL; 				// PC0 XBUS 10
	if(servocount > servo3) PORTC &= ~SDA; else PORTC |= SDA; 				// PC1 XBUS 12
	if(servocount < 400) servocount++; else {servocount=1; if(p) p--;} 	// p = 1/50 Sek
}
https://www.roboternetz.de/community...l=1#post447000

Nachteil dieser eigentlich bestechend einfachen Lösung ist die geringe Auflösung der Servopositionen. (Vielleicht kann man das auch mit einem anderen Timer tricksen?) Vorteil ist eben, dass die Impuls durchgehend erzeugt werden, egal was man im Hauptprogramm macht.

Beim Anschluss an ADC0 oder ADC1 muss man beachten, dass das Pinout auf der RP6-Platine nicht servokonform ist. Deshalb muss man am Servostecker Plus und Minus tauschen:

Klicke auf die Grafik für eine größere Ansicht

Name:	servoanschluss1_klein.jpg
Hits:	7
Größe:	14,4 KB
ID:	19387

Vielleicht reicht dir das schon zum Einstieg.

Gruß

mic