Forum: Mikrocontroller und Digitale Elektronik Servo läuft in eine Richtung


von Dominik F. (Firma: non) (sieds)


Lesenswert?

Hallo,

hab heute meinen ersten Servomotor an meinen Atmega8 angeschlossen gg.

Das mit dem 20ms und 2ms hab ich also verstanden und hin gebracht.

Nun die Frage:
Wie sage ich meinem Servo in welche Richtung er sich bewegen soll.


MfG
Dominik

von Oliver (Gast)


Lesenswert?

Dominik Fa schrieb:
> Das mit dem 20ms und 2ms hab ich also verstanden
>...
> Wie sage ich meinem Servo in welche Richtung er sich bewegen soll.

Die Position des Servos ergibt sich aus der Länge des kurzen Impulses. 
Der darf zwischen 1ms und 2ms lang sein.

Oliver

von hans (Gast)


Lesenswert?

Hallo Dominik,

die Suchfunktion mit "Servo" liefert fst 1000 Treffer!

Da sollte doch was passen ;)

hans

von Dominik F. (Firma: non) (sieds)


Lesenswert?

So weit ich das verstanden habe schauen die Impulse wie folgt aus:

1ms high, 19ms low: links Position
1.5ms high, 18.5ms low: mittlere Position
2ms high, 18ms low: rechte Position


Wenn des jetzt so stimmt, heißt das für ich muss mir ein Oszi zulegen um 
meine Impulse zu prüfen ob ich da keinen rechen Fehler habe.

von Karl H. (kbuchegg)


Lesenswert?

Dominik Fa schrieb:
> So weit ich das verstanden habe schauen die Impulse wie folgt aus:
>
> 1ms high, 19ms low: links Position
> 1.5ms high, 18.5ms low: mittlere Position
> 2ms high, 18ms low: rechte Position
>

Genau.
Wobei nur die 1ms - 2ms kritisch sind. Ob die Pause 10ms oder 15ms oder 
20ms beträgt, ist für die meisten Servos uninteressant. Die Länge des 
Pulses ist das was zählt.

> Wenn des jetzt so stimmt, heißt das für ich muss mir ein Oszi zulegen um
> meine Impulse zu prüfen ob ich da keinen rechen Fehler habe.

Wie wäre es, wenn du einfach mal dein Programm zeigst? Dann könnten wir 
dir helfen, zb indem jemand überprüft, ob dein Timing stimmt.

von Dominik F. (Firma: non) (sieds)


Angehängte Dateien:

Lesenswert?

Ich habe angenommen das der Takt 4MHz ist und ich mit einem Vorteiler 
von 8, auf 512µs komme.

Vielen danke für die Bemühungen und die Unterstützung.

von Karl H. (kbuchegg)


Lesenswert?

Dominik Fa schrieb:

Moment!

> Ich habe angenommen das der Takt 4MHz

Was soll das heißen?
Hast du einen 4Mhz Takt oder hast du ihn nicht!

Servo Ansteuerung ist hauptsächlich eine Timing Sache. Wenn man sich 
schon auf die allem zugrundeliegende Basisfrequenz nicht verlassen kann, 
macht es keinen Sinn weiterzumachen.

Hast du oder hast du nicht?
Hast du das überprüft?

von Karl H. (kbuchegg)


Lesenswert?

Du brauchst kein Oszi.
Du brauchst eine Einführung in Programmierung. Im speziellen wie das mit 
Unterprogramaufrufen funktioniert. Und da wieder im Speziellen, wie das 
dann alles mit ISR funktioniert.

AVR-Tutorial


Dein Einsprungspunkt in die ISR ist bei timer0_overflow. Jeder einzelne 
Pfad, den das Programm nehmen kann, muss letztendlich in einem reti 
münden!

In deinem Programm kommen viel zu viele   rjmp wait  vor!
Idelaerweise hast du nur eine einzige von diesen Endlosschleifen. Und 
die befindet sich in main: Nachdem der Grundaufsatz erledigt ist, geht 
main in eine Endlosschleife über.
Durch dein hin und her Springen hast du dir selbst den Überblick über 
dein Programm genommen, sodass du nicht mehr nachvollziehen kannst, was 
wann wo passiert.
Da hilft dir auch dein
   sei
   rjmp wait
innerhalt der ISR nichts mehr. Ein sei, der in einer ISR auftaucht, ist 
fast immer ein Fehler. Ein Profi, der weiß was er tut, und was er sich 
damit einhandelt kann das machen. Aber für einen Newbie ist so etwas 
tödlich.

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

Karl heinz Buchegger schrieb:
> Du brauchst kein Oszi.
> Du brauchst eine Einführung in Programmierung. Im speziellen wie das mit
> Unterprogramaufrufen funktioniert. Und da wieder im Speziellen, wie das
> dann alles mit ISR funktioniert.
>
> AVR-Tutorial

Und schon ist geklärt, woher die Mär stammt, der Mega8 würde ohne 
weiteres Zutun mit 4 MHz laufen. ;-) Denn das Tutorial arbeitet nunmal 
mit einem Mega8 mit 4 MHz.

Eigentlich braucht Dominik nur mal etwas durch die Threadliste 
schmökern, denn da laufen aktuell mehrere Threads zum Thema Servo. Da 
ist alles erklärt, was man dazu wissen sollte.

Ich habe mir den Quältext kurz angesehen, kann ihm (betreffs 
Programmierstil) aber nichts abgewinnen. Timer-Overflow-Interrupt war 
eine nette Sache, als es noch keine Compare-Interrupts gab. Die Zeiten 
sind vorbei, zumindest bei aktuellen AVRs. Auch sonst enthält dieser 
Quältext allerhand Unsinn.

Also, Dominik, ehe Du ohne Erfahrung weiter draufloswirtschaftest und 
dann auf Hilfe hoffst, solltest Du erstmal schaun, wie es andere machen. 
Ich meine dabei nicht unverstandenes Abschreiben, sondern Analysieren 
fremder Programme. Sollte es an dieser oder jener Stelle zu Fragen 
kommen, so wird sich sicher jemand finden (auch ich), der Dir mal einen 
entsprechenden Hinweis gibt.

von Karl H. (kbuchegg)


Lesenswert?

Kluchscheißer Kluchscheißer schrieb:
> Karl heinz Buchegger schrieb:
>> Du brauchst kein Oszi.
>> Du brauchst eine Einführung in Programmierung. Im speziellen wie das mit
>> Unterprogramaufrufen funktioniert. Und da wieder im Speziellen, wie das
>> dann alles mit ISR funktioniert.
>>
>> AVR-Tutorial
>
> Und schon ist geklärt, woher die Mär stammt, der Mega8 würde ohne
> weiteres Zutun mit 4 MHz laufen. ;-) Denn das Tutorial arbeitet nunmal
> mit einem Mega8 mit 4 MHz.

Schon klar.
Aber auch das Tuorial beginnt damit, einen Quarz bzw. Quarzoszillator 
mit 4Mhz an den Mega8 anzuschliessen :-)

> Auch sonst enthält dieser Quältext allerhand Unsinn.

Hab ich zuerst auch gedacht. Aber wenn man das mal durchgeht ist es gar 
nicht sooo schlimm. Interrupts und was da in der ISR zu passieren hat 
wurde nicht verstanden. Der Code kommt mir vor wie von einem BASIC 
Umsteiger: Hauptsache ich kann mit einem GOTO irgendwo hinspringen - das 
ist cool.

Wenn man sich das wegdenkt , ist der Rest nicht mehr so schlimm. Das man 
das Servo nur auf eine Handvoll Positionen einstellen kann, mangels 
Teil-Möglichkeiten durch den Timer-Overflow, ist zwar eine heftige 
Einschränkung, aber sollte dem Spass erst mal keinen Abbruch tun.

von Marcus B. (raketenfred)


Lesenswert?

muss man da nicht auch beachten, dass _delay_m/us(XXX) nicht ganz genau 
ist, und auch der interne Quarz nicht ganz genau ist??

von Karl H. (kbuchegg)


Lesenswert?

Marcus B. schrieb:
> muss man da nicht auch beachten, dass _delay_m/us(XXX) nicht ganz genau
> ist, und auch der interne Quarz nicht ganz genau ist??

Im Prinzip ja.
Allerdings
* ist das ein Assembler Programm
* benutzt er keine _delay_ms
* ist die Ungenauigkeit im Quarz klein genug, dass sie sich in der
  Servoposition höchstens um ein paar Hundertstel Grad bemerkbar
  machen wird.
  Und ob ein Servogetribe mechanisch diese Genauigkeit überhaupt
  liefert, darf getrost bezweifelt werden. Für praktische Zwecke
  ist das genau genug.

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

Karl heinz Buchegger schrob im Beitrag #1711490 u.A.:

>> Und schon ist geklärt, woher die Mär stammt, der Mega8 würde ohne
>> weiteres Zutun mit 4 MHz laufen. ;-) Denn das Tutorial arbeitet nunmal
>> mit einem Mega8 mit 4 MHz.
>
> Schon klar.
> Aber auch das Tuorial beginnt damit, einen Quarz bzw. Quarzoszillator
> mit 4Mhz an den Mega8 anzuschliessen :-)

Das ist ein alter Zopf aus der Zeit, als das Tutorial mit dem AT90S4433 
gearbeitet hat. Beim Mega8 reicht es nicht, einen Quarz anzuschließen, 
man muss ihn auch per Fusebits anmelden. Dies ist für ein Tutorial ein 
unnötiges Risiko, denn ein Anfänger (wer sonst braucht ein Tutorial) 
kann den AVR leicht verfusen und sich für ISP aussperren. Und das, wo 
der Mega8 die meisten Aufgaben ganz gut im Auslieferungszustand (mit 
internem Takt von 1MHz) erledigen kann.

> Der Code kommt mir vor wie von einem BASIC
> Umsteiger: Hauptsache ich kann mit einem GOTO irgendwo hinspringen - das
> ist cool.

GOTO ist auch in BASIC ein alter Zopf. Dafür gibt es Declare 
Sub/Function und das einfache Aufrufen mit Namen, sowie Exit Do/For zum 
stackverträglichen Verlassen von Schleifen. ASM stelle ich mir aber ohne 
JMP recht schwierig vor.

In jeder Sprache kann man schlecht programmieren. In diesem Forum sehe 
ich z.B. mehr schlechten C-Code als schlechten Basic-Code, weil hier 
einfach mehr C-Anfänger vertreten sind. ;-) Dein Eindruck, dass 
BASIC-Leute einen schlechten Programmierstil haben, stimmt aber, denn an 
vielen Bildungsstätten wird eine Einführung in BASIC von Ausbildern 
gelehrt, die selbst keine Ahnung davon haben.

>
> Wenn man sich das wegdenkt , ist der Rest nicht mehr so schlimm. Das man
> das Servo nur auf eine Handvoll Positionen einstellen kann, mangels
> Teil-Möglichkeiten durch den Timer-Overflow, ist zwar eine heftige
> Einschränkung, aber sollte dem Spass erst mal keinen Abbruch tun.

Naja, mit einem Timertakt von 1µs und Compare-Werten zwischen 1000 und 
2000 lässt sich ein (oder mehrere!) Servo(s) schon recht präzies 
steuern. Und dazu reicht ein CPU-Takt von 1MHz (Auslieferungszustand) 
völlig aus.

Gruß in die Berge...

von Dominik F. (Firma: non) (sieds)


Lesenswert?

Irgendwie befürchte ich dass ich vor lauter Bäume den Wald nicht sehe.

Gut, am besten ist wohl wenn ich mir noch mal Interrupt auf der Zunge 
zergehen lasse.

von Karl H. (kbuchegg)


Lesenswert?

Dominik Fa schrieb:
> Irgendwie befürchte ich dass ich vor lauter Bäume den Wald nicht sehe.
>

fang einfach bei timer0_overflow zu lesen an.
verfolge jede Verzweigung, die in diesem Unterprogramm genommen werden 
kann. Jeder einzelne Pfad, der durch dieses Unterprogramm existiert, 
muss letztendlich in einem reti enden! Egal wieviele Verzweigungen es 
gibt (und daher ist es schlau, wenn man nicht wie ein wilder hin und her 
springt, denn dann wird es immer schwieriger das nachzuvollziehen)

von Dominik F. (Firma: non) (sieds)


Angehängte Dateien:

Lesenswert?

Hab den Servo jetzt Unterkontrolle.

Ich glaub meine Programmstruktur schaut auch etwas besser aus.
Ein Oszi hab ich auch angehängt um mir das Ganz etwas anschaulicher zu 
machen.


Zu dem Kommentar:
die Suchfunktion mit "Servo" liefert fst 1000 Treffer!


Man bekommt vielleicht viele Treffer, aber es würde nicht so viele 
Beiträge dazu geben wenn ein Servo irgendwo gut erklärt wäre.
Vielleicht ein Punkt den man noch ins Tutorial einbaut.

von Karl H. (kbuchegg)


Lesenswert?

Dominik Fa schrieb:
> Hab den Servo jetzt Unterkontrolle.
>
> Ich glaub meine Programmstruktur schaut auch etwas besser aus.

Noch nicht wirklich

Schauen wir uns mal ein paar Stellen an
1
main:
2
    out  PORTD, r16
3
    rjmp main

Warum wird hier an Port D ausgegeben, an dem dein Servo hängt?
Entweder du erledigst alle Servosteuerungen in der ISR oder du erledigst 
sie in main.
Aber nicht beides. Das führt über kurz oder lang immer zu unliebsamen 
Interaktionen zwischen verschiedenen Programmteilen

1
timer0_overflow:
2
    cpi  r16, 0b01111111
3
    BREQ dec_servo_h
4
    BRNE dec_servo_l
Sieh dir das einmal genau an.
Du benutzt einen BREQ um bei Gleichheit einen anderen Weg zu gehen. Wenn 
dieser Weg aber nicht genommen wird, weil eben keine Gleichheit 
vorhanden ist, dann MUSS das nächste BRNE wahr sein und springen. Es 
besteht kein Grund da noch einmal zu testen, weil dieser Test immer wahr 
sein wird.

Wenn du die nachfolgenden Codestücke umdrehen würdest, dann bräuchtest 
du nur im BREQ Fall springen, im gegenteiligen Fall gehts dann einfach 
im Code weiter. Oder aber natürlich im BRNE Fall. Wie auch immer du das 
haben willst, aber eine Abfrage ist überflüsig.
1
timer0_overflow:
2
    cpi  r16, 0b01111111
3
    BRNE dec_servo_l
4
5
dec_servo_h:
6
    dec servo_h
7
    breq set_servo_l
8
    ldi  r16, 0b01111111
9
    out  PORTD, r16
10
    reti
11
12
dec_servo_l:
13
    dec servo_l
14
    breq set_servo_h
15
    ldi  r16, 0b01111110
16
    out  PORTD, r16    
17
    reti

Aber im Grunde machst du das ungeschickt.
Denn im Grunde würdest du nur 1 Zähler benötigen, der einfach nur die 
'Zeit' runterzählt, bis wieder eine Aktion am Portpin notwendig ist. Ein 
Portpin behält sowieso seinen Wert solange, bis du ihn änderst. Das 
hätte dann den Vorteil, dass du so schnell wie möglich wieder aus der 
ISR rauskommst, nämlich dann, wenn die Zeit noch nicht gekommen ist, 
irgendetwas an den Portpins zu machen. Ausserdem brauchst du dann 1 
Register weniger.
1
timer0_overflow:
2
    dec  wait_time
3
    BREQ flip_pin
4
    reti
5
6
flip_pin:
7
    cpi  r16, 0b01111111      // wie steht der Pin jetzt
8
    BREQ dec_servo_l          // auf 1, muss auf 0 
9
10
dec_servo_h:                  // Pin ist low, auf high setzen
11
    ldi  r16, 0b01111111
12
    out  PORTD, r16
13
    ldi  wait_time, 0x05
14
    reti
15
16
dec_servo_l:                  // Pin ist high, auf low setzen
17
    ldi  r16, 0b01111110
18
    out  PORTD, r16    
19
    ldi  wait_time, 0x48
20
    reti

Der Code ist kürzer, einfacher und es gibt weniger Pfade durch die ISR, 
auf die man achten muss. Das ist jetzt noch kein grosses Thema, aber 
spätestens dann, wenn Register gesichert und wiederhergestellt werden 
müssen (denk zb an das SREG Register) wird das zu einem wichtigen Punkt.

von Dominik F. (Firma: non) (sieds)


Lesenswert?

Danke für die ausführliche und gute Hilfestellung ! ! !

von Dominik F. (Firma: non) (sieds)


Angehängte Dateien:

Lesenswert?

Hab meine Schaltung auf zwei Servos aufgestockt. Welche jeweils 3 
Positionen einnehmen.
Pro Servo habe ich dazu zwei Schalter mit denen ich die Postion 
festlege.

Um mich auch ein bisschen in logische Operationen zu üben, werden beide 
über einen Port ausgegeben.

Da ihr ja schon wisst das ich noch nicht viel Erfahrung habe wollte ich 
fragen ob mein Lösung OK ist, oder was besser gemacht werden könnte.

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.