Forum: Mikrocontroller und Digitale Elektronik Problem mit Servoansteuerung (AVR, GCC)


von Budd (Gast)


Lesenswert?

Nabend


Ich habe ein Problem mit der Ansteuerung eines HS-475HB Servos von HiTec

Der Servo verlangt eine High-Low-Periode von 20ms mit einem Puls 
zwischen 0,9ms und 2,1ms (wobei 1,5ms die Ruhelage ist). Soweit so gut.

Ich liefere dem Servo EXAKT dieses Signal (mit Pulsdauer 1,5ms).
Mit Logic-Analyzer kontrolliert: High-Low-Periode: 20,0102ms
                                 Pulsbreite: 1,49952ms

Also viel besser geht echt nicht.


Trotz allem rattert der Servo beängstigend. Zwar bewegt er sich, aber es 
hört sich so an, als wäre er gerade dabei sich selbst zu zerstören. Auch 
die Welle "zittert" sich sichtbar.

Habe das ganze mit C programmiert, hier der Code:
1
/*************************************************************************
2
3
   Servo Controller
4
5
   Device: ATmega8
6
   Clock: Internal 8 MHz Oszillator
7
   
8
   Servo:
9
         Pulse refresh rate: 20ms
10
      Pulse duration: 0.9ms to 2.1ms (1.5ms as center position)
11
12
***************************************************************************/
13
14
#include <stdlib.h>
15
#include <inttypes.h>
16
#include <avr/io.h>
17
#include <avr/interrupt.h>
18
19
 
20
21
int main(void)
22
{
23
    DDRB = 0xFF;
24
  
25
26
  // Initialize timer1
27
  ICR1   = 9220;                      
28
  TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11); // OC1A/B CLEAR ON MATCH
29
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS11);    // CTC Mode, Prescaler 8
30
  TCNT1  = 0;                                      // Reset Timer
31
32
  OCR1A  = 690;     //Pulse 1.5ms
33
  OCR1B  = 2000;   
34
35
36
   while(1)
37
   {
38
    //Loop
39
   }
40
}

Warum geht das nicht, das Signal ist wirklich ausgezeichnet (zumindest 
sofern es mir mein Logic-Analyzer zeigt. Die Stromversorgen wurde 
zwischen 3 und 6V vareiert -> keine Änderung.

Wäre super wenn ihr mir helfen könntet, ich sehe da absolut nichts...


Hier das Datenblatt:
http://www.hitecrcd.com/product_file/file/21/Servomanual.pdf

von Daniel B. (und3rt4ker)


Lesenswert?

Hi,

Nur mal so...evtl. braucht das/der Servo invertierte Logik, also 1-2ms 
low anstatt high. Hab mir allerdings nicht das Datenblatt 
durchgelesen.Ist zu spät zum nachdenken^^

MfG
und3rt4ker

von Budd (Gast)


Lesenswert?

Morgen

Nein, der Servo braucht schon High-Pulse.
Habs auch mal mit invertierung ausprobiert aber tut sich nichts.

von Peter B. (pbuenger)


Lesenswert?

Hallo Budd, (?)

wie kommst Du denn bei einem CPU-Clock von 8MHz, einem Vorteiler von 8 
und einem ICR1 von 9220 auf eine Periodendauer von 20ms? Da stimmt doch 
was nicht.

Gruß,
Peter

von Budd (Gast)


Lesenswert?

Hey!

Ich hatte irgendwann die Nase voll von Berechnungen ohne "etwas zu 
sehen". Darum hab ich meinen LA rausgeholt und ICR1 "von Hand" so 
angepasst, dass eine Pulsbreite von 20ms dabei raus kam.

Aber trotzdem, auch wenn ich es nachrechne komme ich auf die 20ms:

(8*10^6)/8 = 1*10^6 (Clock nach Prescaler)

Maximum Count: 9220

9220 / 1*10^6 = 9,92ms

Da der Counter OC1A toggelt, braucht man 2 Durchläufe, also

9,92 = 2 = 19,84ms
Was sich in etwa mit meiner gemessenen Zeit deckt.

Oder habe ich da was falsch verstanden?

von Peter B. (pbuenger)


Lesenswert?

> Da der Counter OC1A toggelt, braucht man 2 Durchläufe, also

Nee, da hast Du was falsch verstanden. Im Fast-PWM Mode wird der Pin 
OC1A beim "Nulldurchgang" des Timers gesetzt, bei Erreichen von OCR1A 
zurückgesetzt. Der Timer selbst läuft hoch bis zum Erreichen von ICR1. 
Also nix mit Toggeln.

Schreib einfach eine 20000 ins ICR1 und eine 1500 ins OCR1A, dann wird 
auch Dein Servopuls stimmen.

Gruß,
Peter

von Budd (Gast)


Lesenswert?

Das ist doch aber kein Fast-PWM-Mode sondern CTC-Mode.

Ich habe mal deine Werte ausprobiert. Da erhalte ich eine Periode von 
ca. 43ms und der Servo zittert weiter :-(

von Albrecht H. (alieninside)


Lesenswert?

Bisher hab ich das nur auf 8051 und PC ausprobiert, das hat ganz 
ordentlich funktioniert, zu deinem AVR-Programm kann ich allerdings 
nicht viel sagen.

Die 20ms, (->50 Hz Refresh), sind unkritisch, im Zweifel lieber weniger 
als mehr nehmen, z.B. 18ms oder 15ms, (bei den meisten Digitalservos 
beträgt der Refresh ohnehin 100Hz -> 10ms). Soweit ich mich erinnere 
läuft das bei einem "realen" Fernsteuerungsempfänger, (z.B. einem 
Standardempfänger von Jamara), so, dass der komplette Zyklus max. 20ms 
dauert, d.h. Wartezeit + Pulsdauer = max. 20 ms. Also wenn der Puls 2ms 
lang ist (2ms + 18ms = 20ms) und wenn der Puls 1,5ms lang ist (1,5ms + 
18ms=19,5ms), ich weiß nicht ob das einen tieferen Sinn hat oder einfach 
nur von der jeweils verwendeten Schaltung herrührt.
Trotzdem funktioniert es auch, wenn man fix z.B. alle 20ms einen 
Interrupt auslöst und dann, (im einfachsten Fall mit einer 
Delayschleife), das Servosignal auf High setzt und dann nach z.B. 1500us 
wieder auf Low, also so, dass alle Zyklen unabhängig von der Pulsbreite 
immer 20ms dauern.

Das mit den Standard-Delayschleifen ist am Anfang, wenn man überhaupt 
noch nicht weiß warum das mit dem Servo nicht klappen will, sowieso eine 
gute Idee.

Irgendwas in der Art:

ServoPin(low)
loop:
delay(18000us)
ServoPin(high)
delay(1500us) ;wahlweise 1000us oder 2000us
ServoPin(low)
goto loop


Dann den Servo im stromlosen Zustand vorsichtig in eine Richtung drehen 
und einschalten, nach einer handvoll Versuchen sieht man dann ob 
zumindest prinzipiell alles funktioniert, vor allem auch elektrisch. 
Apropos elektrisch, beim 8051 hab ich immer noch wahlweise einen 
Treiber, Transistor oder Optokoppler zwischen Portpin und 
Servosignaleingang geschaltet, der Servosignaleingang braucht zwar kaum 
Strom, aber geschadet hat das zumindest nicht und das Rechteck hatte so 
auf dem Oszilloskop "schäfere" Kanten, ohne Treiber sah es manchmal so 
aus als hätte man einen kleinen Kondensator zwischen Signalpin und Masse 
geschaltet, möglich, dass das bei den AVRs komplett überflüssig ist, die 
können glaube ich bei High auch schon ein bisschen Strom liefern, das 
mit dem Optokoppler ist aber nach wie vor eine Option, wenn man vor hat 
Servo und Controller elektrisch soweit als möglich zu trennen, (so ein 
Graupner Digitalservo zieht z.B. bis zu 2A Strom auf der 
Versorgungsleitung).

Zu Bedenken ist eventuell auch noch, dass bei einer "richtigen" 
Fernbedienung, normalerweise die Pulsbreite nie auf einen Schlag von 
z.B. 1500us auf 2000us springt, sondern egal wie schnell man den 
Steuerknüppel auch bedient, da immer noch kleine Zwischenschritte drin 
sind, wieviele genau, hängt von Fernbedienung und Servo ab, (manche 
Digitalservos haben angeblich eine Auflösung von 1024 Schritten, von 
denen dann bei einer Knüppelbewegung von Neutralstellung bis 
Vollausschlag gut die Hälfte durchlaufen wird). Ich schreib das nur, 
weil ich manchmal schon das Gefühl hatte, dass wenn man von 1500us 
direkt auf 2000us geht die Servos etwas zum "Überschwingen" neigen, d.h. 
der Servo fährt mit Maximalgeschwindigkeit zum Vollausschlag und muss 
dann am Ende der Bewegung minimal aber doch wahrnehmbar seine Position 
korrigieren bevor er endgültig zum Stillstand kommt.

Ansonsten: Logikanalyzer ist sicher nicht schlecht aber Oszilloskop ist 
besser, oder zeigt dir dein LA auch die Signalform an, z.B. irgenwelche 
Ripple und Abrundungen?

von Budd (Gast)


Lesenswert?

Hallo und Danke für deinen Beitrag!

Ich habe leider nur einen LA, sonst hätte ich es schon mit dem Oszi 
gemessen.

Ich habe jetzt mal so eine Schleife aufgesetzt:
1
    DDRB = 0xFF;
2
   while(1)
3
   {
4
   PORTB = 0x00;
5
    _delay_us(18500);
6
    PORTB = 0x02;
7
    _delay_us(1500);
8
   }

Die Werte habe ich auch etwas vareiert.
Aber der Servo zittert einfach immer noch total. Ich versteh das einfach 
nicht.

Ein I/O Pin eines AVR kann schon einige mA verkraften. Auch 10mA sind 
noch drin.

Das wirft mir wirklich Rätsel auf...

von Budd (Gast)


Lesenswert?

EDIT: Also nicht dass man es falsch versteht: Er bewegt sich schon, er 
geht auch in die gewünschte Position. Nur dort fängt er an zu zittern.

von Peter B. (pbuenger)


Lesenswert?

Budd, in Deinem Quelltext oben hast Du WGM11, WGM12 und WGM13 gesetzt. 
Damit arbeitet der Timer im Mode 14 und das ist nunmal der Fast-PWM 
Modus. Steht so im Datenblatt.

Wenn jetzt der Servopuls nicht stimmt, ist was anderes faul. Eventuell 
läuft der Prozessor nicht mit 8MHz. Hast Du mal die Fuses kontrolliert? 
Schließe doch mal probehalber einen externen Quartz an.

Gruß,
Peter

von Budd (Gast)


Lesenswert?

Und nochmal...

Habe das ganze nun auch mal mit verschiedenen Pulswerten und Servos 
ausprobiert.

Ergebnis: Alle Servos zeigen ähnliches Verhalten. Sie gehen außerdem 
immer nur in die Nulllage. Egal welchen Pulswert man ihnen gibt.

von Ulli B. (ulli-b)


Lesenswert?

Hallo Budd,
hast Du irgend ein anderes Gerät, an welchem Du den Servo testen kannst 
?

Wenn ein Servo zwar in die richtige Position fährt, dort aber zittert, 
dann ist entweder der Servo defekt (meistens das Poti) oder das 
Steuersignal nicht konstant.
Wenn Du den Servo sicher als nicht defekt einstufen kannst, dann 
verhaspelt sich wahrscheinlich der µC immer mal wieder.
Es kommt also zB. 10 mal ein Impuls mit der richtigen Länge und dann ein 
(oder mehrere) Impuls(e) mit einer anderen Länge.

Falls Du keine Fensteuerung zur Hand hast um den Servo aus zu probieren, 
dann bau Dir einfach mit einem NE555 einen Servotester. (Googel: 
"Servotester ne555").

Als Modellbauer musste ich leider feststellen, dass immer öfter auch 
schon fabrikneue Servos defekt sind (Made in China!?).

MfG
Ulli B.

von Budd (Gast)


Lesenswert?

Hallo

Ich habe leider keinen NE555 zur Hand :-(
Ich habe die Schaltung 3 Servos getestet. Einer davon ist fabrikneu und 
alle zeigen das selbe Verhalten.


Wenn ich mir den Zeitverlauf des LA anschaue kann ich auch keine 
unregelmäßigen Impulse erkennen. Die Pulse sind wirklich seeehr, seeehr 
exakt.

von Albrecht H. (alieninside)


Lesenswert?

Habe die einfachen Beispiele gerade mal in C und Assembler getestet, mit 
einem Atmega88, mit externem 16MHz Quarz auf dem Pollin-Evaluationboard.
Ich habe das mit zwei Servos probiert, einem Miniservo aus einem 
Esky-Lama-V3-Helikopter und einem uralten "Modelcraft-S22"-Servo, der 
ohnehin eine leichte Neigung zum Zittern hat.
Funktioniert bei beiden Servos sozusagen problemlos: Schnelles Anfahren 
der Position, leichtes Überschwingen, dann Stillstand ohne Zittern und 
präzises Halten der Position bei Gegenkraft.

Wie siehts bei dir eigentlich mit Prozessortyp, externem Quarz, 
Stromversorgung und Entwicklungsboard aus?



1
#include <avr/io.h>
2
#define F_CPU 16000000UL 
3
#include <util/delay.h>    
4
 
5
 
6
int main( void )
7
{
8
    DDRD = ( 1 << PD5 ); 
9
  PORTD = ( 0 );
10
    
11
  while( 1 ) {               
12
        
13
    _delay_ms(18);
14
    
15
    PORTD = ( 1 << PB5 );
16
    
17
    _delay_us(1500); //oder 1000 oder 2000
18
        
19
    PORTD = ( 0 );
20
21
        
22
    }
23
 
24
    return 0;
25
}

und
1
.include "m88def.inc"
2
3
4
ldi  r16,high(RAMEND) 
5
out  SPH,r16           
6
ldi  r16,low(RAMEND)   
7
out  SPL,r16
8
9
in r16,DDRD
10
ori r16, (1<<PIND5)
11
out DDRD, r16; set portbits as output
12
13
14
loop1:
15
16
;**********************************************************
17
; Verzoegerung 18ms:
18
          ldi  R17, $02
19
WGLOOP0:  ldi  R18, $CE
20
WGLOOP1:  ldi  R19, $E8
21
WGLOOP2:  dec  R19
22
          brne WGLOOP2
23
          dec  R18
24
          brne WGLOOP1
25
          dec  R17
26
          brne WGLOOP0
27
          ldi  R17, $02
28
WGLOOP3:  dec  R17
29
          brne WGLOOP3
30
;**********************************************************
31
sbi PORTD,5
32
33
;**********************************************************
34
/*
35
;Verzoegerung 1500us:
36
          ldi  R17, $2B
37
WGLOOP02:  ldi  R18, $B9
38
WGLOOP12:  dec  R18
39
          brne WGLOOP12
40
          dec  R17
41
          brne WGLOOP02
42
          ldi  R17, $02
43
WGLOOP22:  dec  R17
44
          brne WGLOOP22
45
*/
46
;**********************************************************
47
48
;Verzoegerung 2000us:
49
          ldi  R17, $2D
50
WGLOOP03:  ldi  R18, $EC
51
WGLOOP13:  dec  R18
52
          brne WGLOOP13
53
          dec  R17
54
          brne WGLOOP03
55
          ldi  R17, $01
56
WGLOOP23:  dec  R17
57
          brne WGLOOP23
58
          nop
59
          nop
60
;**********************************************************
61
62
cbi PORTD,5
63
64
rjmp loop1

von Budd (Gast)


Lesenswert?

Hallo,

meinst du, du hast MEINEN Code getestet der deinen eigenen?

Ich habe grade keinen passenden Quarz da, beim nächsten Einkauf werde 
ich das mal ändern.

Mein Entwicklungskit ist hier nur eine einfache Platine mit ATmega8 mit 
ein paar Steckkontakten. Die Platine nutze ich wegen ihrer Einfachheit 
schon seit Jahren erfolgreich.

Habe als Spannungsversorgung ein regelbares Labornetzteil. Max. Strom 
bis 2,5A. Daran sollte es auch nicht scheitern...

von ThomasL (Gast)


Lesenswert?

Hallo Budd

Dieses Phänomen, welches du beschreibst kann ich bei mir auch 
beobachten.
Ich bin aber auch noch auf keine Lösung gekommen.

Das komische dabei ist, programmiere ich die PWM in Software und nutze 
nicht die Hardware generierte, dann funktioniert es ! Ohne jegliches 
zittern.

Das ganze getestet auf nem STK500 und den Servo direkt am Port.

von Albrecht H. (alieninside)


Lesenswert?

Budd wrote:
> Hallo,
>
> meinst du, du hast MEINEN Code getestet der deinen eigenen?

Den Code der unter meinem Beitrag steht, natürlich. Im Avrstudio muss 
ich in C die Taktfrequenz "F_CPU" angeben und in Assembler das 
Controller Include-File "m88def.inc", sonst gehts halt nicht, also nur 
Copy&Paste von deinem Beispiel hätte sowieso nicht funktioniert.

>
> Ich habe grade keinen passenden Quarz da, beim nächsten Einkauf werde
> ich das mal ändern.

Den eingebauten Oszillator der AVRs habe ich noch nicht getestet, der 
soll ja teilweise recht ungenau sein, wobei ich nicht weiß ob sich das 
nur auf die absolute Frequenz bezieht oder auch auf die 
Frequenzstabilität innerhalb eines bestimmten Zeitraums, 
(Temperaturdrift, Spannungsabhängigkeit etc.). Du kannst ja einfach mal 
mit dem LA die Oszillator-Frequenz deines AVR-Oszillators messen und 
dann bei "F_CPU" angeben, aber es erscheint mir sinnvoller, erstmal 
einen externen Quarz zu beschaffen.

>
> Mein Entwicklungskit ist hier nur eine einfache Platine mit ATmega8 mit
> ein paar Steckkontakten. Die Platine nutze ich wegen ihrer Einfachheit
> schon seit Jahren erfolgreich.
>
> Habe als Spannungsversorgung ein regelbares Labornetzteil. Max. Strom
> bis 2,5A. Daran sollte es auch nicht scheitern...

Also wenn meine beiden Beispiele bei dir problemlos funktionieren liegts 
wohl weder am Board noch an der Stromversorgung.
Der nächste Schritt wäre dann, das Ganze, (immer noch mit einer normalen 
Delayschleife für die Pulsbreite), in eine 18ms bis 20ms 
Interruptroutine zu verpacken, denn so statisch bringt das ja alles 
nichts und erst wenn das ebenfalls problemlos funktioniert, würde ich 
mich an eine Lösung mit den ganzen Spezialfunktionen der AVR-Timer, 
(OCRxx, PWM, etc.), wagen.
Die AVR-Timer bieten ja sehr trickreiche Möglichkeiten an, (soweit ich 
das bisher gelesen habe), aber man muss wohl auch verdammt aufpassen, 
dass man nichts übersieht, so einfach wie beim 8051 ist das auf jeden 
Fall nicht, also z.B. dieser Prescaler, der läuft ja die ganze Zeit und 
wenn man einen Timer auf einen bestimmten Wert setzt kann man erst mal 
gar nicht sagen wann der erste Zählerimpuls vom Prescaler nun 
tatsächlich kommt, es sei denn, man resetet den Prescaler vorher, dabei 
ist aber zu beachten, dass sich zwei Timer denselben Prescaler teilen 
usw. u.s.f., bei den 8051-Derivaten hatte man halt einfach drei 
16-Bit-Timer, die man unabhängig voneinander starten konnte und gut 
wars.

Nachtrag:
Zumindest weiß man ja, dass das alles irgendwie funktionieren muss, (und 
schon funktioniert hat), hier im Forum als auch bei AVRFreaks gibts ja 
genügend Codebeispiele bei denen ein AVR bis zu 20 Servos steuert sowohl 
in C als auch in ASM. Es geht ja nur noch darum das alles zu verstehen 
und seine eigene Lösung zu entwickeln und das ist es doch, was letztlich 
auch den ganzen Spass an der Sache ausmacht :-)

von Budd (Gast)


Lesenswert?

Danke für deinen Post :-)

Ja du hast schon recht, aber der Spaß geht irgendwann auch flöten, wenn 
man einfach jedes Detail schon 5x überprüft hat und doch nichts geht...


Ich mach jetzt die Radikallösung. Ich nehm Board samt Servo mit in meine 
FH und werd das dort mit Oszi und ggf. Funktionsgenerator zerpflügen.

Mein Verdacht liegt langsam in der Flankensteilheit. Zwar zeigt mir mein 
LA tolle Periodenzeiten an, aber wenn die Flankensteilheit "fürn Arsch" 
ist, dann bringen die auch nicht mehr viel.

Naja ich werd dem morgen mal auf den Grund gehen und die Ergebnisse hier 
posten.

Hat denn jemand von euch vielleicht einen Code für die Servoansteuerung 
der bei euch sicher funktioniert und den ich möglichst wenig abändern 
muss? So quasi als Referenztest mal.

von Hannes L. (hannes)


Lesenswert?

Servoimpulse sind aus Sicht des Controllers so schnarchlangsam, dass man 
sie ohne Weiteres in Software machen kann. Hier ein Beispiel in ASM, es 
läuft mit internem Takt von 1 MHz:
http://www.hanneslux.de/avr/mobau/7ksend/7ksend02.html

...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.