www.mikrocontroller.net

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


Autor: Budd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
/*************************************************************************

   Servo Controller

   Device: ATmega8
   Clock: Internal 8 MHz Oszillator
   
   Servo:
         Pulse refresh rate: 20ms
      Pulse duration: 0.9ms to 2.1ms (1.5ms as center position)

***************************************************************************/

#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>

 

int main(void)
{
    DDRB = 0xFF;
  

  // Initialize timer1
  ICR1   = 9220;                      
  TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11); // OC1A/B CLEAR ON MATCH
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS11);    // CTC Mode, Prescaler 8
  TCNT1  = 0;                                      // Reset Timer

  OCR1A  = 690;     //Pulse 1.5ms
  OCR1B  = 2000;   


   while(1)
   {
    //Loop
   }
} 

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

Autor: Daniel Bauer (und3rt4ker)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Budd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Morgen

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

Autor: Peter Bünger (pbuenger)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Budd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Peter Bünger (pbuenger)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Budd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :-(

Autor: Albrecht H. (alieninside)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Budd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
    DDRB = 0xFF;
   while(1)
   {
   PORTB = 0x00;
    _delay_us(18500);
    PORTB = 0x02;
    _delay_us(1500);
   }

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...

Autor: Budd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Bünger (pbuenger)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Budd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ulli B. (ulli-b)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Budd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Albrecht H. (alieninside)
Datum:

Bewertung
0 lesenswert
nicht 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?



#include <avr/io.h>
#define F_CPU 16000000UL 
#include <util/delay.h>    
 
 
int main( void )
{
    DDRD = ( 1 << PD5 ); 
  PORTD = ( 0 );
    
  while( 1 ) {               
        
    _delay_ms(18);
    
    PORTD = ( 1 << PB5 );
    
    _delay_us(1500); //oder 1000 oder 2000
        
    PORTD = ( 0 );

        
    }
 
    return 0;
}

und
.include "m88def.inc"


ldi  r16,high(RAMEND) 
out  SPH,r16           
ldi  r16,low(RAMEND)   
out  SPL,r16

in r16,DDRD
ori r16, (1<<PIND5)
out DDRD, r16; set portbits as output


loop1:

;**********************************************************
; Verzoegerung 18ms:
          ldi  R17, $02
WGLOOP0:  ldi  R18, $CE
WGLOOP1:  ldi  R19, $E8
WGLOOP2:  dec  R19
          brne WGLOOP2
          dec  R18
          brne WGLOOP1
          dec  R17
          brne WGLOOP0
          ldi  R17, $02
WGLOOP3:  dec  R17
          brne WGLOOP3
;**********************************************************
sbi PORTD,5

;**********************************************************
/*
;Verzoegerung 1500us:
          ldi  R17, $2B
WGLOOP02:  ldi  R18, $B9
WGLOOP12:  dec  R18
          brne WGLOOP12
          dec  R17
          brne WGLOOP02
          ldi  R17, $02
WGLOOP22:  dec  R17
          brne WGLOOP22
*/
;**********************************************************

;Verzoegerung 2000us:
          ldi  R17, $2D
WGLOOP03:  ldi  R18, $EC
WGLOOP13:  dec  R18
          brne WGLOOP13
          dec  R17
          brne WGLOOP03
          ldi  R17, $01
WGLOOP23:  dec  R17
          brne WGLOOP23
          nop
          nop
;**********************************************************

cbi PORTD,5

rjmp loop1

Autor: Budd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: ThomasL (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Albrecht H. (alieninside)
Datum:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: Budd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht 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

...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.