PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : adc0, adc1, scl



Morpheus1997
22.07.2011, 08:56
hey roboterfans...
ich habe mal wieder ein problem.
ich möchte für meinen roboterarm 3 servos an die rp6 base anschließen, einmal an adc0, dann an adc1 und an scl....
allerdings weiß ich nicht wie man sie ansteuert. könnt ihr mir da vielleicht weiter helfen?

DanielSan
22.07.2011, 09:42
Wenns dir um die grundsätzliche Ansteuerung geht, dann benutz mal die Suchfunktion oder schau im RN-Wiki. Das wurde schon oft erklärt.

Gruß Daniel

radbruch
22.07.2011, 09:45
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):

// 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/showthread.php?31931-Domino-Day-f%FCr-den-RP6&p=414115&viewfull=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:

// 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/showthread.php?46512-2-Servos-gleichzeitig-ansteuern-geht-das-nur-mit-Stopwatches&p=447000&viewfull=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:

19387

Vielleicht reicht dir das schon zum Einstieg.

Gruß

mic

Morpheus1997
22.07.2011, 10:31
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:
ok danke bisdahin für die vielen hinweise.. allerdings wollte ich eigentlich nur wissen wie man adc0 und 1 in einem programm mit einbaut. für scl weiß ich es ja jetzt (
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 }
)