PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Wie steuert man ein Servo an?



grind
24.10.2004, 22:54
Ja also wie gesagt, wie steuert man ein Servo an?

Ich weiss schon dass man alle 20ms ein Signal an das Servo senden muss und die Länge je nach Lage 1-2ms lang sein muss.

Mein Problem is nur wie schaut so ein Program denn aus? Könntet ihr mir vielleicht ein kleines Beispielprogram posten anhand dessen ich das verstehen kann? Hab schon in vielen Tutorials geschaut aber das stand nirgends so drinnen.

Danke schonmal

Grind

FoCus
26.10.2004, 11:34
-Du initialisierst einen Timer mit 20ms
-Dann einen mit dem Pulswert.
-Der Erste stösst den Zweiten immer an, der Zweite läuft seine Dauer ab und zieht dann das Signal wieder auf low..
-wenn der Zweite eingeschaltet wird, wird das Signal gesetzt..

Oder mit einem Timer:
-Setze Pulsweite (timeroverflow)
-Beim Erreichen berechnest du die Differenz auf 20ms und initialisierst damit den Timer neu
-beim zweiten Overflow wieder Pulsweite setzen
usw.

Aufpassen musst du bei beiden Möglichkeiten beim Ändern der Pulsdauer...
Deshalb:
Vorher Timer anhalten (!!!) und danach nicht einfach wieder loslaufen lassen sondern ZURÜCKSETZEN!!!Sonst enstehen Störsignale die ab und zu sehr blöde Folgen haben ;-)

Oder:
Kauf dir einen sd20 (Servocontroller)

Gruss
Michael

Spurius
08.07.2005, 21:35
Hallo,
bei Möglichkeit 2, was ist mit "Pulsweite" gemeint? Vielleicht versteh ich dann den Rest.

michaelb
08.07.2005, 21:43
Hi FoCus,
kannst du bitte mal ein Beispielcode posten! Das würde mich auch interressieren! Kannst du wenn du einen posten würdest auch bissl was dazu erklären? Wäre voll nett!
Gruß Michi

Spurius
08.07.2005, 22:06
Vielleicht ist mit Pulsweite ja das Steuersignal(+- 2ms, kommt auf gewünschte Pos an oder?) gemeint, d.h. nach der Zeit ein Timeroverflow, dann Timer so einstellen, dass 20ms vergehen, bis wieder ein Overflow ausgelöst wird, dann wieder Steuersignal etc. ...
Aber wäre cool, wenn sich mal einer melden würde, der sich da genauer auskennt.
Und mit PWM hat dass dann wohl eher nichts zu tun oder?

NumberFive
09.07.2005, 09:20
Ich habe meine Ansteuerung per PWM gebaut weil dann muß im rest des programms nicht so auf passen und Cycle zählen.

Ich habe den Code zusammen Kopiert das geben ich zu aber er funktioniert.



void init_servos(void)
{
/* Use Timers 1 generate the pulses for 2 R/C servos; each
* timer can do up to 2 servos. */
/*
* configure OC1A for mode 0: normal, top=0xffff prescale=8 (f~=30):
*
* WGM33=0, WGM23=0, WGM13=0, WGM03=0, CS32=0, CS31=1, CS30=0
*/

SETBIT(DDRD,PD5); //auf ausgang
SETBIT(DDRD,PD4);

TCCR1A &= ~(BV(WGM11) | BV(WGM10) | BV(COM1A1) | BV(COM1B1));
TCCR1A |= BV(COM1A0) | BV(COM1B0);
TCCR1B &= ~(BV(WGM13) | BV(WGM12) | BV(CS12) | BV(CS10));
TCCR1B |= BV(CS11);
TCNT1 = 0;
TIMSK |= BV(TOIE1);

/* set all servos to their center positions */
SERVO1 = SERVO_MID;
SERVO2 = SERVO_MID;
}


Init Timer als PWM mit Mega16 bei 16 Megaherz



void servo1(BYTE s1)
{
if(s1== 0)
{
SERVO1 = 1300;
SendMCData(52,0);
}
if(s1== 1)
{
SERVO1 =2250;
SendMCData(52,1);
}
if(s1== 2)
{
SERVO1 = 3000;
SendMCData(52,2);
}
if(s1== 3)
{
SERVO1 = 3750;
SendMCData(52,3);
}
if(s1== 4)
{
SERVO1 = 4700;
SendMCData(52,4);
}
}

void servo2(BYTE s1)
{
if(s1== 0)
{
SERVO2 = 1300;
SendMCData(53,0);
}
if(s1== 1)
{
SERVO2 =2250;
SendMCData(53,1);
}
if(s1== 2)
{
SERVO2 = 3000;
SendMCData(53,2);
}
if(s1== 3)
{
SERVO2 = 3750;
SendMCData(53,3);
}
if(s1== 4)
{
SERVO2 = 4700;
SendMCData(53,4);
}
}


Setzen der Werte für das servo



// PWM Timmer
SIGNAL(SIG_OVERFLOW1)
{
TCNT1 = 0;

/* configure to set outputs on compare match so we can turn on the
* pulse in the next statement */
TCCR1A |= BV(COM1A1)|BV(COM1A0)|BV(COM1B1)|BV(COM1B0);

/* force compare match to set outputs */
TCCR1A |= BV(FOC1A)|BV(FOC1B);

/* configure to clear outputs on compare match so that the output
* compare function ends the pulse */
TCCR1A &= ~(BV(COM1A0)|BV(COM1B0));
}





#define SETBIT(ADDRESS,BIT)(ADDRESS |=(1<<BIT))
#define CLEARBIT(ADDRESS,BIT)(ADDRESS &= ~(1<<BIT));

#define SERVO_MIN 1300
#define SERVO_MID 3000
#define SERVO_MAX 4700

#define SERVO1 OCR1A
#define SERVO2 OCR1B



Das sind ein teil der define's von mir ich finde das mach den Code
lesbarer. Bitte alle "echten" c programmierer/in mich jetzt nicht er schlagen
Ich programmier normaler weise c++ unter windows mit VC++

Wenn der Timer überläuft hole ich mir die Neuen werte.

Noch mal zur klar stellung das ist nicht alle mein code sondern er ist aus verschieden quelle zusammen kopiert.

Es sei alle gedank die Teile des Quellcodes ver offentlichen.

Ich betreibe mit diesem Code Zwei Modelbau Motortreiber.

Mfg

Spurius
09.07.2005, 12:40
Hm, mag ja sein dass das funktioniert, aber ich verstehe nicht, wie man mit PWM einen Servo ansteuern kann, der in bestimmten Zeitabständen Impulse bestimmter Länge verlangt...

Spurius
09.07.2005, 18:45
Hallo,
hab mcih jetzt mal drangemacht und versucht, einen Servo anzusteuern:


#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <math.h>

int16_t sollwert=(0.001/0.000004);
int16_t wert_alt;
int8_t pos;

int main(void)
{

sei();
DDRB = (1<<DDB0);
PORTB = (0<<PB0);
wert_alt = 5000;
TCCR0 = (0<<CS02) | (1<<CS01) | (1<<CS00); //Vorteiler 64
TCNT0 = (255-5000); //Timer vorladen
TIMSK = (1<<TOIE0); //Interrupt enablen

}

SIGNAL (SIG_OVERFLOW0)
{
PORTB ^= (1<<PB0); //Pin tooglen
if (wert_alt = 5000)
{
TCNT0 = sollwert;
wert_alt = sollwert;
}
else
{
TCNT0 = 5000;
wert_alt = 5000;
}
}

Das Problem ist, das er bei Werten zwischen 0.002 und 0.001 eigentlich immer nur in eine Richtung will, gleiches wenn ich die Werte noch größer oder kleiner mache. D.h. es ist keine genaue Positionierung möglich.

Meine Berechung ist folgendermaßen:
16000000/64 = 2500000
1/250000 =4*10^-6=0.000004 Zeit, die ein Takt braucht
20ms = 0.02s -> 0.02/0.000004 = 5000
1ms = 0.001s -> 0.001/0.000004 = 250

Weiss jemand, wo mein Fehler ist?

Rubi
18.07.2005, 14:46
Hallo Spurius

Wo der Denkfehler liegt kann ich Dir leider nicht sagen, aber:

Ich habe gerade einen Code geschrieben der die HW pwm verwendet.
Mittels diesem kann man mittels 100 Schritten (max. wären 500 möglich)
ein servo von Mitte zu Vollausschlag bringen.
Die bisherigen Programme die ich dazu gesehen habe, waren alle bis auf das vom Kijon viel zu ungenau, es waren max. 10 Schritte möglich
Werde es Heute Abend testen, wenn es funktioniert kann ich ihn ja hier posten wenn Du willst.

LG
Rubi

FoCus
19.07.2005, 11:45
Hm, mag ja sein dass das funktioniert, aber ich verstehe nicht, wie man mit PWM einen Servo ansteuern kann, der in bestimmten Zeitabständen Impulse bestimmter Länge verlangt...

Kleiner Tip:
Es gibt zwei unterschiedliche Arten PWM zu betreiben ;-)
Du benötigst den Fast PWM Mode....
Oder du machst es so, wie oben beschrieben....

Anbei noch ein kleines Beispiel in ASM, bzw das Steuertool unter Win unter C++, das ich vor einem halben Jahr mal geschrieben hab...

Gruss
Michael

Rubi
19.07.2005, 11:54
Hallo Focus

Mit fast pwm bin ich nicht wirklich weit gekommen,
ich habe für meinen "phase and frequency correct pwm"
verwendet.Dadurch bekomme ich genau 50hz und wenn ich OCR1A auf z.b. 1000 setze ist der Puls eine ms lang.
Dieser PWM Modus ist zwar ein wenig komplizierter aufzusetzen, dafür aber viel leichter anzuwenden.

Wenn man ein ungehacktes Servo verwendet und eine kleine Auflösung nicht stört ist fas pwm ok, für alles andere aber IMHO is fast pwm unbrauchbar.

LG
Rubi

FoCus
19.07.2005, 12:05
Mag sein das es damit funktioniert, richtig, Signalmässig gesehen, ist es allerdings nicht.
Schliesslich vergrösserst, bzw verkleinerst du den Puls innerhalb der 20ms nur um die Hälfte, die andere Hälfte schiebst du praktisch in den vorigen Bereich.

Gruss
Michael

Rubi
19.07.2005, 12:21
Hallo FoCus

Was meinst Du ist schlimmer, 62,5 Hz oder 50 Hz wie in der Spec aber der impuls ist nur zur Hälfte im "richtigen" Bereich.

Das Hauptproblem mit fast pwm war aber die Auflösung.
Ich mußte mit meinem 16Mhz AVR einen hohen Prescaler verwenden, damit war aber die Auflösung hinüber.
Wenn ich OCR1A auf 60 gesetzt hatte blieb das Servo mit viel zureden stehen, wenn ich das SFR auf 62 gesetzt hatte lief das "gehackte" Servo auf 100%. Dadurch war ich faktisch gezwungen nach einer anderen Lösung zu suchen.

Wenn für dich alles OK ist, besteht natürlich kein Grund was zu ändern.

LG
Rubi