Servo Problemm

Gast #2494562
Lesenswert?

Ich würde gerne an einem kleinen Rc Auto eine Kamera einbauen, und sie 
dann mit einem mini servo nach links und nach rechts schwenken.
Nun habe ich dieses mini servo:
http://www.cnchelicopter.com/servlet/the-RC-heli-Mini-servo/Categories

mit einem atmega8 und 4 Mhz verbunden.
1
#define F_CPU 4000000UL
2
 
3
#include <avr/io.h>
4
#include <util/delay.h>
5
 
6
int main (void)
7
{
8
  DDRB = (1<<PB1);
9
 
10
  while( 1 ) {
11
 
12
  
13
    PORTB |= (1<<PB1);
14
    _delay_us( 1500 );    // in den 1500 steckt die Lageinformation
15
    PORTB &= ~(1<<PB1);
16
 
17
    _delay_ms( 18 );      // ist nicht kritisch
18
 
19

20

21
  }
22
 
23
  return 0;
24
}
Jetzt ist das Problem das das Servo, nicht immer in der selben Position 
endet.
Wenn ich Zb denn servo zu beginn mit der hand verstelle.
Oder.
Ich die Stromversorgung unterbreche und dann wieder schließe.
und diesen Vorgang mehrmals durchführe verstellt sich die Endposition 
beim gleichen signal vom Atmega8

Brauche ich ein anderes Servo ?


Die Kamera soll zu beginn (spannung angeschaltet)
geradeaus schwenken.

Bei betätigen eines Knopfes  nach links in eine bestimmte Position 
schwenken.
Bei betätigen eines Knopfes  nach rechts in eine bestimmte Position 
schwenken.
#2494598
Lesenswert?

Joel schrieb:

> mit einem atmega8 und 4 Mhz verbunden.

hast du die 4Mhz kontrolliert?


> Jetzt ist das Problem das das Servo, nicht immer in der selben Position
> endet.
> Wenn ich Zb denn servo zu beginn mit der hand verstelle.
> Oder.
> Ich die Stromversorgung unterbreche und dann wieder schließe.
> und diesen Vorgang mehrmals durchführe verstellt sich die Endposition
> beim gleichen signal vom Atmega8
>
> Brauche ich ein anderes Servo ?

Wenn dein µC das Servo ansteuert, kannst du dann das Servo mit der Hand 
verdrehen oder leistet es Widerstand?

Wenn es keinen Widerstand leistet, dann könnte zb das Signaltiming nicht 
stimmen. Höchst wahrscheinlich, weil die 4Mhz, die du im Code 
eingetragen hast, gelogen sind und dein Mega8 immer noch mit 1Mhz läuft.
Wie hast du denn das Servo an den µC angeschlossen?


Alle: Ja, das Programm ist grottig. Aber es reicht um erst mal 
festzustellen, ob das ganze überhaupt funktioniert oder nicht. Seine 
beschriebenen Symptome dürften auch mit dem grottigen Programm nicht 
auftreten.
Gast #2494615
Lesenswert?

1
#define SERVOPIN 7
2
#define SERVOPORT PORTD
3
#define DDRSERVO DDRD
4

5
volatile unsigned char servopos;
6

7
void servo_init()
8
{
9
  TIMSK|=(1<<OCIE2);
10
  TCCR2 |= (1<<WGM21) | (1<<CS20);  //Prescale=1, CTC mode
11
  OCR2 = F_CPU/100000;      //alle 10µS ein IRQ
12
  DDRSERVO|=(1<<SERVOPIN);
13
};
14

15
ISR(TIMER2_COMP_vect)
16
{
17
  static int count;
18
  if(count>servopos)SERVOPORT&=~(1<<SERVOPIN);
19
    else SERVOPORT|=(1<<SERVOPIN);
20
  if(count<2000)count++; // Die Impulse sollten alle 20ms gesendet werden! 6.2.11 mic
21
    else count=0;
22
};
Diesen Code habe ich auch schon getestet doch es geht einfach nicht.
Gilt der auch für ein atmega8?
Gast #2494635
Lesenswert?

1
#define F_CPU 4000000UL
2
 
3
#include <avr/io.h>
4
#include <util/delay.h>
5
 #define SERVOPIN 7
6
#define SERVOPORT PORTD
7
#define DDRSERVO DDRD
8

9
volatile unsigned char servopos;
10

11
void servo_init()
12
{
13
  TIMSK|=(1<<OCIE2);
14
  TCCR2 |= (1<<WGM21) | (1<<CS20);  //Prescale=1, CTC mode
15
  OCR2 = F_CPU/100000;      //alle 10µS ein IRQ
16
  DDRSERVO|=(1<<SERVOPIN);
17
};
18

19
ISR(TIMER2_COMP_vect)
20
{
21
  static int count;
22
  if(count>servopos)SERVOPORT&=~(1<<SERVOPIN);
23
    else SERVOPORT|=(1<<SERVOPIN);
24
  if(count<2000)count++; // Die Impulse sollten alle 20ms gesendet werden! 6.2.11 mic
25
    else count=0;
26
};
27

28
int main (void)
29
{
30
   servo_init();
31
  return 0;
32
}
Hier mein code ist der richtig?

Habe ein Qartz mit 4.000Mhz stehen.
Und es mit dem Atmega8 richtig angeschlossen.
(ich glaube sonst hätte sich der servo mit dem 1 code nicht bewegt.)
Gast #2494637
Lesenswert?

Joel schrieb:
> Jetzt ist das Problem das das Servo, nicht immer in der selben Position
> endet.
> Wenn ich Zb denn servo zu beginn mit der hand verstelle.
> Oder.
> Ich die Stromversorgung unterbreche und dann wieder schließe.
> und diesen Vorgang mehrmals durchführe verstellt sich die Endposition
> beim gleichen signal vom Atmega8
>
> Brauche ich ein anderes Servo ?

abgesehen davon, ob das Programm nun genau 1500µs Pulse erzeugt oder 
nicht, es wird immer die gleiche Pulslänge erzeugen und der Servo sollte 
immer ziemlich genau (Stichwort Totzeit) an der gleichen Position 
landen.

Durch mehrfache Betätigung könnte er innen warm werden und dadurch durch 
eigene Regelabweichungen geringe andere Stellungen einnehmen.

Wie groß sind die Abweichungen?

Test: Nachdem der Servo nicht mehr in der ersten Stellung landet - 
Signal angeschlossen lassen - warten auf Abkühlung und der Servo sollte 
sich in winzigen Schritten seiner ersten, abgekühlten Stellung wieder 
nähern.

Da würde dann ein besserer Servo Abhilfe schaffen.

Es ist keine gute Idee das Servohorn von Hand zu verdrehen. Schädigt das 
Servogetriebe/lager
#2494721
Lesenswert?

Test schrieb:
> abgesehen davon, ob das Programm nun genau 1500µs Pulse erzeugt oder
> nicht, es wird immer die gleiche Pulslänge erzeugen und der Servo sollte
> immer ziemlich genau (Stichwort Totzeit) an der gleichen Position
> landen.

Das sollte zwar in der Theorie stimmen, aber wenn der uC mit 1 MHz statt 
mit 4 läuft, werden aus den 1.5 ms plötzlich 6 ms, was weit ausserhalb 
des Regelbereichs liegen dürfte. Was das Servo dann macht, würde ich 
nicht unbedingt vorhersagen wollen.

Abgesehen davon wäre es eine interessante Frage, wie groß eigentlich die 
Abweichungen sind.

Nur weil ein Quarz dransteckt, muss der uC den nicht unbedingt 
benutzen...
Und nur weil es sich bewegt, muss es nicht korrekt angeschlossen sein, 
man hat auch schon von Wackelkontakten und Konsorten gehört.
#2494807
Lesenswert?

Klaus T. schrieb:

> Und nur weil es sich bewegt, muss es nicht korrekt angeschlossen sein,
> man hat auch schon von Wackelkontakten und Konsorten gehört.


Ich habe viele Servos, die beim Anlegen der Versorgunsspannung erst mal 
einen kleinen Hüpfer machen, ehe sie sich dann beim Eintreffen der 
ersten Signalpulse auf die Position stellen.


> Es ist keine gute Idee das Servohorn von Hand zu verdrehen. Schädigt
> das Servogetriebe/lager

Grundsätzlich richtig. Sollte man nicht machen.
Allerdings, wenn man nicht gerade mit 2 linken Händen an die Sache 
rangeht, kann man mal gegen den Servohebel drücken. Das merkt man 
sofort, ob das Servo dagegenhält oder ob es nachgibt. Hält es dagegen, 
dann hat es Pulse und wird angesteuert. Gibt es nach, dann hat es keine 
Ansteuerpulse. Zumindest keine verwertbaren.


(Ich glaube immer noch, dass sein µC nicht mit den 4Mhz läuft. Entweder 
das, oder er hat nur die Signalleitung verbunden und das Servo hängt 
masseseitig in der Luft)
#2494829
Lesenswert?

Klaus Wachtler schrieb:
> Joel schrieb:
>> Hier mein code ist der richtig?
>
> sei()?

Und die obligate Hauptschleife fehlt auch.

Aber grundsätzlich müsste sein Servo auch auf die erste Version mit den 
_delay_us() reagieren.
Wenn die 4Mhz stimmen, der Optimizer eingeschaltet ist, der Anschluss 
stimmt, die Stromversorgung nicht einbricht, dann kann da nichts mehr 
schief gehen. Ob das Servo dann tatsächlich in der Mitte steht oder 
leicht daneben, ist IMHO erst mal nicht so wichtig. Erst mal muss es 
überhaupt arbeiten.
#2494907
Lesenswert?

Hallo,
Zu allem was hier schon steht (im besonderen Prüfen des echten Taktes) 
scheint auch der Compare Wert für den Timer nicht zu stimmen, wenn Du 
tatsächlich 10µS benötigst.
1
  OCR2 = F_CPU/100000;      //alle 10µS ein IRQ
Nach meinem Kalkulator müssten da bei 4 Mhz -20- als Comparewert stehen 
und nicht 40 (F_CPU/100000)

Grüße Carsten
#2494939
Lesenswert?

@Joel

Wenn du nicht weißt, wie man mit einfachen Mitteln die Taktfrequenz des 
µC überprüfen kann, dann sags einfach. Aber überprüfen musst du sie! Das 
ist einer der Bausteine, ohne die gar nichts geht. Servoansteuerung ist 
eine reine Frage von korrekten Zeiten. Und da diese Zeiten letztendlich 
immer in irgendeiner Form mit der µC-Taktfrequenz verknüpft sind, muss 
letztere 100% stimmen. Sonst suchst du dir und wir hier uns einen Wolf 
an Problemen, die in Wirklichkeit keine sind.
Gast #2495008
Lesenswert?

1
#define F_CPU 4000000UL
2
 #include <avr/interrupt.h>
3
#include <avr/io.h>
4
#include <util/delay.h>
5
 #define SERVOPIN 7
6
#define SERVOPORT PORTD
7
#define DDRSERVO DDRD
8

9
volatile unsigned char servopos;
10

11
void servo_init()
12
{
13
  TIMSK|=(1<<OCIE2);
14
  TCCR2 |= (1<<WGM21) | (1<<CS20);  //Prescale=1, CTC mode
15
  OCR2 = F_CPU/100000;      //alle 10µS ein IRQ
16
  DDRSERVO|=(1<<SERVOPIN);
17
};
18

19
ISR(TIMER2_COMP_vect)
20
{
21
  static int count;
22
  if(count>servopos)SERVOPORT&=~(1<<SERVOPIN);
23
    else SERVOPORT|=(1<<SERVOPIN);
24
  if(count<2000)count++; // Die Impulse sollten alle 20ms gesendet werden! 6.2.11 mic
25
    else count=0;
26
};
27

28
int main (void)
29
{
30
     sei();
31
   servo_init();
32
   while(1)
33
   {
34

35
   }
36
  return 0;
37
}
So das ist mein verbesserter code.
Der Quartz ist 100% ein 4Mgz
Hier ein bild:
http://www.henri.de/images/articles/11103_9325b18f1f01ae44ced2485504615715_5.jpg
#2495013
Lesenswert?

joel schrieb:

> Der Quartz ist 100% ein 4Mgz

Du verstehst es immer noch nicht.

Ich glaub dir, dass auf deinem Quarz 4Mhz draufsteht.
Das ist nicht die Frage.

Die Frage lautet: Wird der Quarz vom µC auch BENUTZT?

Wenn du den Quarz einfach nur an den µC angebaut hast und keine 
Fuse-Bits umgestellt hast, dann wird er nämlich NICHT benutzt und dein 
µC läuft auch weiterhin mit 1Mhz.

Ist das wirklich so schwer zu verstehen?
Gast #2495021
Lesenswert?

Zur Taktfrequenz:
Es kann entweder der interne oder die externe laufen.
Wenn ich denn Quartz aus der schaltung nehme arbeitet der Atmega nicht 
mehr.
Somit nehme ich an das es mit 4 Mhz arbeiten muss wenn ich ihn intern 
nicht noch teile.
Sehr sehr vielen dank für eure hilfe mit so schneller antworten habe ich 
gar nicht gerechnet.
Danke
#2495029
Lesenswert?

joel schrieb:
> Zur Taktfrequenz:
> Es kann entweder der interne oder die externe laufen.
> Wenn ich denn Quartz aus der schaltung nehme arbeitet der Atmega nicht
> mehr.

Gut. Das überzeugt mich.
(Schwere Geburt.
Der Grund warum ich darauf rumreite: Weil ca 80% aller Timingprobleme 
hier im Forum genau darauf zurückzuführen sind)

Nächster Punkt:
Wie hast du das Servo angeschlossen

  rot    Versorgungsspannung
  braun  Masse
  orange Da kommen die Pulse vom µC rein. Sicher, dass du am richtigen
         Pin abgreifst?
#2495049
Lesenswert?

joel schrieb:
> Der Servo ist richtig angeschlossen, habe ihn ja auch schon zu laufen
> gebracht.

Wenn ich deine Beschreibung noch mal lese, dann lese ich heraus, dass 
dein Servo beim Anlegen der Versorgungsspannung einen Hüpfer macht. Das 
hat aber nichts mit 'zum Laufen gebracht' zu tun.
'Zum Laufen gebracht' müsste bedeuten, dass das Servo immer (im 
wesentlichen) die gleiche Position anfährt, egal wie du es vorher mit 
der Hand verdreht hast. Dieses Anfahren der Position muss auch schnell 
geschehen. Man hört richtiggehend, dass sich das Servo nicht einfach 
irgendwie dreht, sondern gezielt an seine Sollposition schnurrt.
Gast #2495056
Lesenswert?

Mit meinen ersten code
1
#define F_CPU 4000000UL
2
 
3
#include <avr/io.h>
4
#include <util/delay.h>
5
 
6
int main (void)
7
{
8
  DDRB = (1<<PB1);
9
 
10
  while( 1 ) {
11
 
12
  
13
    PORTB |= (1<<PB1);
14
    _delay_us( 1500 );    // in den 1500 steckt die Lageinformation
15
    PORTB &= ~(1<<PB1);
16
 
17
    _delay_ms( 18 );      // ist nicht kritisch
18
 
19

20

21
  }
22
 
23
  return 0;
24
}
Hat es geklappt.
Doch mit dem Timer code leider nicht mehr
Gast #2495100
Lesenswert?

1
#define F_CPU 4000000UL
2
 #include <avr/interrupt.h>
3
#include <avr/io.h>
4
#include <util/delay.h>
5
 #define SERVOPIN 7
6
#define SERVOPORT PORTD
7
#define DDRSERVO DDRD
8

9
volatile unsigned char servopos = 150;
10

11
void servo_init()
12
{
13
       
14
  TIMSK|=(1<<OCIE2);
15
  TCCR2 |= (1<<WGM21) | (1<<CS20);  //Prescale=1, CTC mode
16
  OCR2 = F_CPU/100000;      //alle 10µS ein IRQ
17
  DDRSERVO|=(1<<SERVOPIN);
18
};
19

20
 
21

22
int main (void)
23
{
24
   
25
   DDRD = 0xff;
26
   sei();
27
   servo_init();
28
   while(1)
29
   {
30
     
31
   }
32
  return 0;
33
}
34

35
ISR(TIMER2_COMP_vect)
36
{
37
   
38
  static int count;
39
  if(count>servopos)SERVOPORT&=~(1<<SERVOPIN);
40
    else SERVOPORT|=(1<<SERVOPIN);
41
  if(count<2000)count++; // Die Impulse sollten alle 20ms gesendet werden! 6.2.11 mic
42
    else count=0;
43
};
hier der neue code
Gast #2495161
Lesenswert?

Ich wuerde sagen, dass es so um die 6ms sind.
Denn das hier passt nicht zusammen:

  TCCR2 |= (1<<WGM21) | (1<<CS20);  //Prescale=1, CTC mode
  OCR2 = F_CPU/100000;      //alle 10µS ein IRQ

#define F_CPU 4000000UL
#2495171
Lesenswert?

joel schrieb:
> Es ist 5 ms lang

Das ist zwar länger als hier bei mir in der Simulation, aber:

Deine ISR ist zu lang. Die wird nicht in 10µs abgearbeitet.

Wenn ich den OCR Wert verdopple, kommen in der Simualtion die Zeiten 
richtig raus:
1
#define F_CPU 4000000UL
2
 #include <avr/interrupt.h>
3
#include <avr/io.h>
4
#include <util/delay.h>
5
 #define SERVOPIN 7
6
#define SERVOPORT PORTD
7
#define DDRSERVO DDRD
8

9
volatile unsigned char servopos = 75;
10

11
void servo_init()
12
{
13
       
14
  TIMSK|=(1<<OCIE2);
15
  TCCR2 |= (1<<WGM21) | (1<<CS20);  //Prescale=1, CTC mode
16
  OCR2 = F_CPU/50000;      //alle 20µS ein IRQ
17
  DDRSERVO|=(1<<SERVOPIN);
18
};
19

20
 
21

22
int main (void)
23
{
24
   
25
   DDRD = 0xff;
26
   sei();
27
   servo_init();
28
   while(1)
29
   {
30
     
31
   }
32
  return 0;
33
}
34

35
ISR(TIMER2_COMP_vect)
36
{
37
   
38
  static int count;
39
  if(count>servopos)
40
    SERVOPORT&=~(1<<SERVOPIN);
41
  else
42
    SERVOPORT|=(1<<SERVOPIN);
43

44
  if(count<1000)
45
    count++; // Die Impulse sollten alle 20ms gesendet werden! 6.2.11 mic
46
  else
47
    count=0;
48
};
#2495174
Lesenswert?

STK500-Besitzer schrieb:
> Ich wuerde sagen, dass es so um die 6ms sind.
> Denn das hier passt nicht zusammen:
>
>   TCCR2 |= (1<<WGM21) | (1<<CS20);  //Prescale=1, CTC mode
>   OCR2 = F_CPU/100000;      //alle 10µS ein IRQ
>
> #define F_CPU 4000000UL

Warum soll das nicht passen?
Für 10µs stimmt das grundsätzlich schon.
Nur sind 10µs zu kurz für die ISR. Das schafft der Mega nicht.
Gast #2495179
Lesenswert?

Karl Heinz Buchegger schrieb:
> STK500-Besitzer schrieb:
>> Ich wuerde sagen, dass es so um die 6ms sind.
>> Denn das hier passt nicht zusammen:
>>
>>   TCCR2 |= (1<<WGM21) | (1<<CS20);  //Prescale=1, CTC mode
>>   OCR2 = F_CPU/100000;      //alle 10µS ein IRQ
>>
>> #define F_CPU 4000000UL
>
> Warum soll das nicht passen?
> Für 10µs stimmt das grundsätzlich schon.
> Nur sind 10µs zu kurz für die ISR. Das schafft der Mega nicht.

bei 4MHz ergibt ein Vorteiler = 1 nur 2,5µs, nicht 10µs...
#2495186
Lesenswert?

STK500-Besitzer schrieb:
> Karl Heinz Buchegger schrieb:
>> STK500-Besitzer schrieb:
>>> Ich wuerde sagen, dass es so um die 6ms sind.
>>> Denn das hier passt nicht zusammen:
>>>
>>>   TCCR2 |= (1<<WGM21) | (1<<CS20);  //Prescale=1, CTC mode
>>>   OCR2 = F_CPU/100000;      //alle 10µS ein IRQ
>>>
>>> #define F_CPU 4000000UL
>>
>> Warum soll das nicht passen?
>> Für 10µs stimmt das grundsätzlich schon.
>> Nur sind 10µs zu kurz für die ISR. Das schafft der Mega nicht.
>
> bei 4MHz ergibt ein Vorteiler = 1 nur 2,5µs, nicht 10µs...


wenn der Timer in 1 Sekunde bis 4000000 zählt, wie lang braucht er dann 
um bis 40 zu zählen (denn genau das ergibt dann F_CPU/100000)

     4000000        1
          40        x
    -------------------
               40
       x = ---------- = 0.00001 Sekunden oder 0.01 Millisekunden
            4000000                      oder eben 10 µs

Nur reichen 40 Takte nicht für einen Durchlauf durch die ISR
Gast #2495214
Lesenswert?

Karl Heinz Buchegger schrieb:
>
>
> wenn der Timer in 1 Sekunde bis 4000000 zählt, wie lang braucht er dann
> um bis 40 zu zählen (denn genau das ergibt dann F_CPU/100000)
>
>      4000000        1
>           40        x
>     -------------------
>                40
>        x = ---------- = 0.00001 Sekunden oder 0.01 Millisekunden
>             4000000                      oder eben 10 µs
>
> Nur reichen 40 Takte nicht für einen Durchlauf durch die ISR

Wo bekommst du die 40 her?
...(1<<CS20) sorgt für einen ungeteilten Takt, oder nicht?
#2495216
Lesenswert?

STK500-Besitzer schrieb:
> Karl Heinz Buchegger schrieb:
>>
>>
>> wenn der Timer in 1 Sekunde bis 4000000 zählt, wie lang braucht er dann
>> um bis 40 zu zählen (denn genau das ergibt dann F_CPU/100000)
>>
>>      4000000        1
>>           40        x
>>     -------------------
>>                40
>>        x = ---------- = 0.00001 Sekunden oder 0.01 Millisekunden
>>             4000000                      oder eben 10 µs
>>
>> Nur reichen 40 Takte nicht für einen Durchlauf durch die ISR
>
> Wo bekommst du die 40 her?

Hier

  OCR2 = F_CPU/100000;      //alle 10µS ein IRQ

> ...(1<<CS20) sorgt für einen ungeteilten Takt, oder nicht?

Ja. Aber: CTC Modus! OCR2 ist TOP. D.h alle 40 Takte (*) ein Overflow.

(4 Mhz bedeutet einen Timertick alle 0.25µs, nicht 2.5µs. Du hast dich 
im Komma vertan)

* eigentlich 41. Aber lass uns nicht kleinlich sein :-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren