Forum: Mikrocontroller und Digitale Elektronik Poti-Servoansteuerung AVR


von Michi K. (Firma: keine) (cube)


Angehängte Dateien:

Lesenswert?

Hallo ich würde gerne n bißchen Kritik an meinenm Programm und evtl. 
Hilfestellung von euch bekommen.
Ich möchte über ein poti einen Servo ansteuern und habe das jetz erstmal 
wie folgt gelöst oder versucht bin absoluter Anfänger also seid bitte 
nicht zu hart :-)
Ist das so richtig und stimmen meine berechnungen ?

Vielen Dank !

von holger (Gast)


Lesenswert?

Jetzt sind die Leute schon zu blöd
eine Assemblerdatei mit der Endung .asm zu speichern.

von Karl H. (kbuchegg)


Lesenswert?

Du machst den klassischen Anfängerfehler aller Servoansteuerer.
Du klebst an den 20ms.
Dadurch ergeben sich für die Servo-PWM bei dir nur noch 9 mögliche 
Servopositionen, weil du nur 9 gültige Werte für die PWM hast.


Vergiss die 20ms! Sieh zu, dass du den Einstellbereich der PWM für die 1 
bis 2ms vernünftig ausnutzen kannst. Und was dann noch übrig bleibt - 
das Servo ist damit zufrieden.

Wenn du es so hindrehen kannst dass zb du die 1 bis 2 ms mit 64 Werten 
abbilden kannst, dann kannst du den ADC Wert in den OCR Wert umrechnen 
und bist nicht mehr auf lediglich 3 Servowerte fixiert. Dein Servo 
bewegt sich dann einigermassen flüssig mit dem Poti mit anstelle bei nur 
3 Servopositionen 'einzurasten'.

Modellbauservo Ansteuerung

von Kurt H. (Firma: KHTronik) (kurtharders)


Lesenswert?

Karl heinz Buchegger schrieb:
> Vergiss die 20ms! Sieh zu, dass du den Einstellbereich der PWM für die 1
> bis 2ms vernünftig ausnutzen kannst. Und was dann noch übrig bleibt -
> das Servo ist damit zufrieden.

Leider ist das in der Allgemeinheit nicht richtig. Die meisten Servos 
mögen keine Pausenzeit unter ca.15ms. Selbst bei den neuen 
Fernsteuerungen, die mit sehr geringer Pausenzeit < 10ms arbeiten, kann 
man auf 20ms umstellen, damit alte Servos verwendet werden können.
Ich habe mit meinen Weichenantrieben ca. 50 Servotypen getestet, und nur 
ganz wenige konnten Pausenzeiten <10ms.

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Eigentlich doch kein Problem: Man nehme 2 Timer, einen 16-Bit-Timer mit 
PWM und einen anderen 8-Bit-Timer für die Wiederholung. Das PWM wird auf 
rund 1ms bis rund 2ms limitiert (mit einer Auflösung von mindestens 
8Bit) und im Compare-Interrupt wird der PWM-Timer dann abgeschaltet und 
der Wiederholtimer gestartet. Dieser läuft mit einem Overflow oder 
Compare auf 20ms. Ist der 2. Timer abgelaufen, wird in dessen Interrupt 
der 2. Timer gestoppt und der PWM-Timer wieder angestossen. Somit hat 
man eine komplett in Hardware laufende Ausgabe und muss lediglich noch 
die OCR-Register für das PWM updaten. Wenn man 2 oder mehr PWM-Ausgänge 
an dem 16-Bit-Timer hat, kann man die entsprechende Zahl an Servos fast 
komplett in Hardware steuern. Die CPU kann dann andere Peripherie (ADC, 
UART) bedienen oder Werte auf Display oder PC ausgeben.

von Kurt H. (Firma: KHTronik) (kurtharders)


Lesenswert?

Wenn man einen 16-Bit-Timer hat, lässt man den mit ca. 20ms Zyklus 
laufen. In meinen Weichenatrieben habe ich den Timer einfach bis 20000 
zählen lassen. Mit den Compare-Registern hat man dann eine PWM mit 1µs 
Auflösung. Das sind dann, bezogen auf den Impuls, 0,1%. Diese Auflösung 
wird von keinem servo erreicht, und der Totbereich eines Servos liegt 
typisch bei >2µs.
In einem ATMega8 kann man dann ohne jeden Interrupt o.ä. 2 Servos 
steuern. Die Software setzt einfach nur die Compare-Register.

von Michi K. (Firma: keine) (cube)


Lesenswert?

Erstmal vielen Dank

dann muss ich mich mal noch dahintersetzen,
momentan habe ich allerdings nur einen Attiny13 der hat nur 8bit Timer ?
ist es mit dem 13er überhaupt möglich Servos vernünftig anzusteuern oder 
kann ich das mit dem eher vergessen ?

von Karl H. (kbuchegg)


Lesenswert?

Es geht auch mit 8-Bit Timern.
Allerdings darfst du dann nicht mehr auf Hardware PWM setzen, sondern 
musst dem Teil mit einer ISR etwas unter die Arme greifen und die Pins 
in Software ansteuern.
Aber ansonsten ist das kein Problem. Ich steuere mit einem 8-Bit Timer 
12 Servos (allerdings nicht mit einem Tiny, der hätte nicht genug Pins).

von Karl H. (kbuchegg)


Lesenswert?

Ich hab mal ein wenig gerechnet.
Mit den 9.6Mhz geht sichs nicht besonders gut aus.
4.8Mhz wären besser

Bei 4.8Mhz Taktfrequenz und einem Vorteiler von 64 hast du eine 
Durchlauffrequenz des Timers von 0 bis 256 mit 292.9 Hz
Das sind 3.4 ms

Das heisst um Zeiten zwischen 1 und 2 ms einzustellen, bewegt sich der 
Comparewert zwischen 75 und 150. Das wären dann immerhin 75 Positionen, 
die das Servo anfahren kann. Sollte eigentlich reichen.

Meine Strategie wäre deshalb:

Ich klemm mich an den Overflow Interrupt
  Ich zähle die Aufrufe der ISR mit. Bei jedem 5.ten Aufruf mache ich:
    Den Servo-Pin auf 1 schalten
    Ins Compare Register den Vergleichswert für die Zeit laden
    Sicherheitshalber das Interrupt Flag für den Compare Interrupt
    löschen
    Den Compare Interrupt einschalten

Im Compare Interrupt
  Den Pin wieder auf 0 setzen
  den Compare Interrupt ausschalten.


Dadurch ergibt sich automatisch ein Timing, dass einen Puls mit der 
gewünschten Länge erzeugt und eine Pause hinten nach, die sich im 
Bereich von ca 17ms bewegt. Und damit sollte jedes Servo zufrieden sein.

Der Trick besteht darin, dass der Pulsanfang vom Overflow Interrupt 
erzeugt wird und das Pulsende vom Compare Interrupt. Der Overflow 
Interrupt richtet gleichzeitig auch alles so ein, dass der Compare 
Interrupt zum gewünschten Zeitpunkt nach dem Pulsanfang aufgerufen wird.

von Michi K. (Firma: keine) (cube)


Lesenswert?

also software PWM wie im Beispiel: 
http://www.mikrocontroller.net/articles/AVR-Tutorial:_PWM

mit den verschiedenen Helligkeitswerten, nur anstatt den Werten für 
versch. Helligkeit, setze ich dafür meine verschiedenen positionen des 
Servos verstehe ich das so richtig ?
und wie im Beispiel der PWMcount ist dann meine (20 oder 10ms) Pause ?

von Karl H. (kbuchegg)


Lesenswert?

Man könnte auch (etwas einfacher), nur mit dem Compare Match (dem OCR0A 
Register) arbeiten, indem man den CTC Modus benutzt.
Den stellt man so ein, dass der CTC die gewünschte Pulszeit ergibt. 
Zusätzlich benötigt man noch einen Softwarezähler, der die Anzahl der 
ISR Aufrufe mitzählt.
Ist der zähler auf 0, so wird der Ausgangspin auf 1 gesetzt
Ist er auf 1, so wird der Pin wieder abgeschaltet
Hat der Zähler 10 erreicht, so wird der Zähler wieder auf 0 zurück 
gesetzt.


Auch das ergibt ein Timing, mit dem ein Servo etwas anfangen kann.

von Kurt H. (Firma: KHTronik) (kurtharders)


Lesenswert?

Mit dem ATTiny geht es sicher auch, bei meiner PIC-Version hatte ich 
auch nur einen 8-Bit-Timer. Wenn der Prozessor nichts anderes zu tun 
hat, kann man das per Software machen. Wenn allerdings, wie bei meinen 
Weichenantrieben, alle 50µs noch ein Interrupt kommt, kann man alle 
Softwarelösungen vergessen, denn ein Jitter von > 4µs bringt das Servo 
zum Brummen oder sogar Zappeln. Wenn Du es also einfach und sicher haben 
willst, nimm so etwas wie den ATMega8 und mache es in Hardware.

von Karl H. (kbuchegg)


Lesenswert?

Michi K------ schrieb:
> also software PWM wie im Beispiel:
> http://www.mikrocontroller.net/articles/AVR-Tutorial:_PWM
>
> mit den verschiedenen Helligkeitswerten, nur anstatt den Werten für
> versch. Helligkeit, setze ich dafür meine verschiedenen positionen des
> Servos verstehe ich das so richtig ?

Nicht ganz.

> und wie im Beispiel der PWMcount ist dann meine (20 oder 10ms) Pause ?

Nicht wirklich.
Das Prinzip ist ähnlich, aber doch ganz anders.

von Karl H. (kbuchegg)


Lesenswert?

Kurt Harders schrieb:

> Jitter von > 4µs

das bedeutet bei 4.8Mhz eine Verzögerung von 20 Takten.
Die hat er nie (wenn die Anwendung so bleibt, wie sie sich im Moment 
abzeichnet)

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Wichtig ist nur, dass man die Servo-Pins direkt nach dem Einsprung in 
die ISR beeinflusst und bedingte Sprünge, die zwischendrin unbedingt 
sein müssen, mit "NOP" Instruktionen ausgleicht, so dass sich immer 
gleiche Codelaufzeiten ergeben, wenn das Timing kritisch ist. Einen 
Interrupt-Jitter von 0...3 Takten hat man ohnehin immer.

von Karl H. (kbuchegg)


Lesenswert?

Knut Ballhause schrieb:
> Wichtig ist nur, dass man die Servo-Pins direkt nach dem Einsprung in
> die ISR beeinflusst und bedingte Sprünge, die zwischendrin unbedingt
> sein müssen, mit "NOP" Instruktionen ausgleicht, so dass sich immer
> gleiche Codelaufzeiten ergeben, wenn das Timing kritisch ist. Einen
> Interrupt-Jitter von 0...3 Takten hat man ohnehin immer.

Hattest du bei deiner Lösung damit Probleme?
Meine Erfahrung ist eher: die Unterschiede sind so minimal, das lohnt 
nicht, sich da groß den Kopf zu zerbrechen. Ob ein Puls mal 1/10 µs 
länger oder kürzer ausfällt, lässt das Servo völlig kalt. So genau sind 
die Potis (als mechanisches Bauteil) in den Servos gar nicht.

von Kurt H. (Firma: KHTronik) (kurtharders)


Lesenswert?

Du hast recht, aber es sind nicht die Potis, sondern die eingebauten 
Elektroniken haben ca. 4µs Totzeit. Bei Digitalservos kann man diese 
Totzeit einstellen, bekommt dann aber eventuell massives Brummen des 
Servos mit sehr hoher Stromaufnahme.

von Karl H. (kbuchegg)


Lesenswert?

Ich hab mich mal an den Assebmler geklemmt

benutzt hab ich die Variante: Alles im Compare Interrupt mit CTC.

Leider hab ich keinen Tiny13 da, sondern nur einen Mega16.
Daher kann ich den auch nicht mit 4.8Mhz laufen lassen, sondern nur mit 
4Mhz :-)
Die Timer Einstellung sollte aber sonst identisch sein. Vorteiler: 64

Das Servo wird verstellt, indem man an OCR0 neue Werte zuweist. Bei dir 
müssten das rein rechnerisch Werte zwischen 75 und 150 sein. Die im 
Programm momentan verwendeten 100, sind bei mir in etwa Mittelstellung 
meiner Servos, aber ich hab ja auch 4Mhz und nicht 4.8
Ach ja, ich erzeuge an PortA, Pin 7 das Signal. Hat keine besonderen 
Gründe, ausser dass ich da leicht mit dem Servokabel rankomme.
1
.include "m16def.inc"
2
 
3
.equ XTAL = 4000000
4
 
5
          rjmp    init
6
7
.org OC0addr
8
          rjmp    Compare_vect
9
10
init: 
11
          ldi      r16, HIGH(RAMEND)     ; Stackpointer initialisieren
12
          out      SPH, r16
13
          ldi      r16, LOW(RAMEND)
14
          out      SPL, r16
15
16
          ldi  r16, 0x80
17
          out  DDRA, r16                ; Servo Ausgangspin -> Output
18
19
          ldi  r17, 0                   ; Software-Zähler
20
            
21
          ldi  r16, 100
22
          out  OCR0, r16                ; OCR0 ist der Servowert
23
24
          ldi  r16, 1<<OCIE0
25
          out  TIMSK, r16
26
27
          ldi  r16, (1<<WGM01) | (1<<CS01) | (1<<CS00)  ; CTC, Prescaler: 64
28
          out  TCCR0, r16
29
30
          sei
31
32
main:
33
          rjmp main
34
35
Compare_vect:
36
          in   r18, SREG
37
          inc  r17
38
          cpi  r17, 1
39
          breq PulsOn
40
          cpi  r17, 2
41
          breq PulsOff
42
          cpi  r17, 10
43
          brne return
44
          ldi  r17, 0
45
return:   out  SREG, r18
46
          reti
47
48
PulsOn:   sbi  PORTA, 7
49
          rjmp return
50
51
PulsOff:  cbi  PORTA, 7
52
          rjmp return

Da der Wertebereich damit so ca 75 Werte umfasst, würde es sich 
anbieten, den Wert vom ADC (den du ja mittels ADLAR schon auf 0..255 
eingeschränklt hast) noch durch 4 zu dividieren (einfach um 2 Bit nach 
rechts schieben), noch 75 dazuzählen und ab damit ins OCR Register. Das 
ergibt dann 64 Servo Stellungen, die mit dem Poti abgefahren werden 
können.

von Karl H. (kbuchegg)


Lesenswert?

Yep.
Funktioniert bei mir tadellos
1
....
2
3
          ldi  r16, (1<<WGM21) | (1<<CS22) ; CTC, Prescaler: 64
4
          out  TCCR0, r16
5
6
          ldi  r16, (1<<ADLAR)| (1<<REFS0) | (1<<MUX1) | (1<<MUX0)
7
          out  ADMUX, r16
8
          ldi  r16, (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0)
9
          out  ADCSRA, r16
10
11
          sei
12
13
main:
14
          sbi   ADCSRA, ADSC
15
adc_wait: sbic  ADCSRA, ADSC
16
          rjmp  adc_wait
17
18
          in   r16, adch
19
          lsr  r16          ; durch 4
20
          lsr  r16
21
          subi r16, -75     ; +75 addieren!
22
23
          out  OCR0, r16
24
 
25
          rjmp main
26
27
...

von Kurt H. (Firma: KHTronik) (kurtharders)


Lesenswert?

Karl heinz Buchegger schrieb:
> Da der Wertebereich damit so ca 75 Werte umfasst

Bei 75 Schritten auf 90° Drehwinkel sind das 1,2° pro Schritt. Das ist 
sehr grob. Eine Auflösung von 512 Schritten sollte es für 
anspruchsvollere Bewegungen schon sein. Die Totzeit macht es schon 
schwer genug, langsame Bewegungen umzusetzen.

von Karl H. (kbuchegg)


Lesenswert?

Kurt Harders schrieb:
> Karl heinz Buchegger schrieb:
>> Da der Wertebereich damit so ca 75 Werte umfasst
>
> Bei 75 Schritten auf 90° Drehwinkel sind das 1,2° pro Schritt. Das ist
> sehr grob.

Zugegeben. Ich seh bei meinen Servos deutlich den Schritt (auch wenn es 
dann in Natura weit weniger dramatisch aussieht als es sich hier anhört)

Allerdings ist es mit den vorhandenen Mitteln nicht mehr so einfach, 
diese Auflösung zu erreichen.
Machbar ist es, keine Frage.
Aber lass den Fragesteller erst mal mit Timern und den Möglichkeiten 
vertraut werden und wie man mit ISR und Softwarezählern längere 
Zeiträume bei gleichzeitig hoher zeitlicher Auflösung abzählt.

Gegenüber seinen ursprünglich 9 Servostellungen sind 75 schon recht viel 
:-)

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Karl heinz Buchegger schrieb:
> Knut Ballhause schrieb:
>> Wichtig ist nur, dass man die Servo-Pins direkt nach dem Einsprung in
>> die ISR beeinflusst und bedingte Sprünge, die zwischendrin unbedingt
>> sein müssen, mit "NOP" Instruktionen ausgleicht, so dass sich immer
>> gleiche Codelaufzeiten ergeben, wenn das Timing kritisch ist. Einen
>> Interrupt-Jitter von 0...3 Takten hat man ohnehin immer.
>
> Hattest du bei deiner Lösung damit Probleme?
> Meine Erfahrung ist eher: die Unterschiede sind so minimal, das lohnt
> nicht, sich da groß den Kopf zu zerbrechen. Ob ein Puls mal 1/10 µs
> länger oder kürzer ausfällt, lässt das Servo völlig kalt. So genau sind
> die Potis (als mechanisches Bauteil) in den Servos gar nicht.

Jitter kann sich im ungünstigsten Fall addieren. Bei einem mit 
4Mhz-Controller kann der Jitter dann im Bereich von 2µs liegen, bei 
einer Software-Pin-Ansteuerung über Interrupt-Service. Ausserdem darf in 
dem Fall nur ein einziger Interrupt zu einer Zeit erlaubt sein, da sonst 
der Interrupt mit dem PWM auf einen anderen warten muss. Hier kann der 
Jitter dann so groß werden, dass das ganze Signal zusammenbricht. Bei 
einer Hardware-Steuerung des PWM über einen Timer und dessen 
OCR-Register ist der Jitter der steigenden PWM-Flanke praktisch "Null" 
und da das OCR mit dem Timerumlauf übernommen wird, gilt dies auch für 
die fallende Flanke. Am Oszi steht solch ein Signal wie eine 1 ;-). 
Software-PWM für Servos macht also nur auf einem Controller Sinn, der 
recht schnell getaktet ist und wo das Addieren von 
Interrupt-Reaktionszeit plus Portausgabe dann nicht mehr in´s Gewicht 
fällt.

von Michi K. (Firma: keine) (cube)


Lesenswert?

Vielen vielen Dank für die Antworten ich muss jetz wenn ich wieder ein 
bißchen Zeit habe mich nochmal dransetzen und mir alles genau durchlesen 
und dann kommen bestimmt noch viele Fragen :-) wünsche jetz aber erst 
mal nen guten Rutsch !

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.