Forum: Mikrocontroller und Digitale Elektronik Servosteuerung mit ATMEGA88 und Assembler


von A. B. (developer_x)


Lesenswert?

Sehr geehrtes Forum,
ich habe mal wieder ein Problem :|.
(Newbie Problem, einfaches Programm, nicht sinnvoll)

Ich möchte gerne einen Servo ansteuern.
Diesen versorge ich extern mit 5 V, und habe dessen GND
auch mit dem GND des Chips verbunden, welcher übrigstens auch mit 5V
versorgt wird.

Mein Servo hat die Kabelfarben Rot, Gelb und Braun, d.h. Rot = 5V, Braun 
= GND und Geld = Signal?

Nun habe ich folgendes Programm, welches ich schon mehrmals mit dem 
Debugger auf richtige Wartezeit der Wartemethoden geprüft habe, ebenso 
wie auch durch Testen der WAIT_1_SEC Methode mit einer LED in echt.
1
.include "m88def.inc"   
2
3
/*
4
5
  Servosteuerung, durch Pulse zwischen 1ms und 2ms, alle 20ms
6
7
  Taktfrequenz des MC: 1 MHz
8
*/
9
10
.CSEG 
11
//  Definitionen
12
.def POSITION = R20
13
  
14
// Richtung der IO Ports definieren
15
LDI R16, 0b11111111    // 1=Output, 0=Input
16
OUT DDRD, R16
17
18
// Stackpointer initialisieren
19
LDI R16, low(RAMEND)
20
OUT SPL, R16
21
LDI R16, high(RAMEND)
22
OUT SPH, R16
23
24
// Main Methode
25
26
MAIN:
27
  LDI POSITION, 20 // Servo nach links stellen  = 2,0 ms
28
  RCALL SERVO_COMMAND
29
  RCALL WAIT_1_SEC
30
31
  LDI POSITION, 15 // Servo nach mitte stellen  = 1,5 ms
32
  RCALL SERVO_COMMAND
33
  RCALL WAIT_1_SEC
34
35
  LDI POSITION, 10 // Servo nach rechts stellen = 1,0 ms
36
  RCALL SERVO_COMMAND
37
  RCALL WAIT_1_SEC
38
39
RJMP MAIN
40
41
// Servo Motor Positionieren
42
SERVO_COMMAND:
43
  LDI R25, 10
44
  
45
  SERVO_COMMAND_2:
46
47
    MOV R21,R20
48
    SBI PORTD,PD0
49
    SERVO_COMMAND_1:
50
      RCALL WAIT_100_MIC_SECS
51
      DEC R20
52
      BRNE SERVO_COMMAND_1
53
54
    MOV R20,R21
55
    CBI PORTD, PD0
56
    RCALL WAIT_10_MIL_SECS
57
    RCALL WAIT_10_MIL_SECS
58
59
    DEC R25
60
    BRNE SERVO_COMMAND_2
61
RET
62
63
64
// WAIT 100_MIC_SECS
65
WAIT_100_MIC_SECS:
66
  LDI R17, 3
67
  WAIT_100_MIC_SECS_2:
68
    LDI R16,9
69
    WAIT_100_MIC_SECS_1:
70
      DEC R16
71
      BRNE WAIT_100_MIC_SECS_1
72
    DEC R17
73
    BRNE WAIT_100_MIC_SECS_2
74
  NOP
75
  NOP
76
  NOP
77
RET
78
79
// WAIT 10_MIL_SECS
80
WAIT_10_MIL_SECS:
81
  LDI R18, 100
82
  WAIT_10_MIL_SECS_1:
83
    RCALL WAIT_100_MIC_SECS
84
    DEC R18
85
    BRNE WAIT_10_MIL_SECS_1
86
RET
87
88
// WAIT 1_SEC
89
WAIT_1_SEC:
90
  LDI R19, 100
91
  WAIT_1_SEC_1:
92
    RCALL WAIT_10_MIL_SECS
93
    DEC R19
94
    BRNE WAIT_1_SEC_1
95
RET

Das Programm sendet also 10 mal einen Impuls, welcher 2ms dauert, und im 
Abstand von 20ms. Der Servo sollte also nach links.
Dann wartet das Programm 1 Sekunde.
Dann 10 mal einen Impuls, welcher 1,5ms dauert, und ebenfalls im Abstand 
von 20ms. Der Servo sollte also in die mitte.
Dann wartet das Programm 1 Sekunde.
Dann 10 mal einen Impuls, welcher 1,0ms dauert, und ebenfalls im Abstand 
von 20ms. Der Servo sollte also rechts.
Dann wartet das Programm 1 Sekunde.

Ich hab das Signal meines MCs auch schon an ne LED gelegt, es kommt 
definitiv beim Servo an.

Nun passiert folgendes: Der Servo dreht sich bis zum Anschlag nach 
rechts, egal ob ich 1,0ms, 1,5ms oder 2,0ms Pulse sende.

Kann mir jemand sagen was ich falsch mache?

Ich habe den Anschluss mehrfach überprüft, und denke, dass ich laut 
diesem Tutorial 
https://www.mikrocontroller.net/articles/Modellbauservo_Ansteuerung auch 
richtig mit meinen Annahmen in Bezug auf die Belegung gehe.

Danke sehr für eure Hilfe,
m.f.G.: Developer_X

: Bearbeitet durch User
von W.A. (Gast)


Lesenswert?

A. B. schrieb:
> Mein Servo hat die Kabelfarben Rot, Gelb und Braun, d.h. Rot = 5V, Braun
> = GND und Geld = Signal?

Du hast doch den Servo vor dir liegen und kennst als einziger den Typ. 
Wie soll dir hier jemand erzählen, wie der Hersteller sich das mit den 
Anschlüssen gedacht hat.

Hier ein bisschen Auswahl:
http://wiki.rc-network.de/Servo

von A. B. (developer_x)


Lesenswert?

Ein Datenblatt für den Modelcraft Y-3009 zu finden, wird wohl nicht so 
einfach.
http://www.conrad.de/ce/de/product/209089/Modelcraft-YH-3009-Mini-Servo-Y-3009-Gleitlager-Getriebe-Kunststoff-JR

von A. B. (developer_x)


Lesenswert?

Seltsam ist auch, dass manchmal, wenn ich allein schon die Spannung an 
den Servo anschließe, der sich dreht, und zwar auch in dieselbe Richtung 
zum Anschlag.

Hat jemand eine Idee?

von spess53 (Gast)


Lesenswert?

Hi

In der Beschreibung steht: Stecksystem   JR.

http://www.toeging.net/flieger/profi/stecker/stecker.htm#graupner

MfG Spess

von A. B. (developer_x)


Lesenswert?

Ich habe braun und orange jetzt mal getauscht, funktioniert dennoch 
nicht.

von A. B. (developer_x)


Lesenswert?

Habt ihr noch eine Idee woran es liegen könnte :( ?

von hufnala (Gast)


Lesenswert?

Ich weiss ja nicht ob sich da was geändert hat, aber früher (TM) musste 
das Signal kontinuierlich gesendet werden und
1ms / 2ms waren vollausschlag li/re und 1,5ms Neutral. Alles dazwischen 
irgendwas anderes. Pausen mochte das System garnicht =Ausfall, ggf. 
Notstellung.

Wie schon geschrieben, das Datenblatt ist Dein Freund.

//hufnala

von Karl H. (kbuchegg)


Lesenswert?

A. B. schrieb:

> Dann wartet das Programm 1 Sekunde.

Du kannst nicht 1 Sekunde lang nichts tun.
Ein Servo will ständig Pulse!

Die Pulse sagen ihm, welche Position es anfahren (und halten) soll. 
Kommen keine Pulse mehr, dann macht es irgendwas (je nach Typ).
D.h. wenn du das Servo 1 Sekunde lang an einer Position halten willst, 
dann musst du ihm auch 1 Sekunde lang genau die Pulslänge dafür 
schicken.

Und spätestens jetzt rächt sich dein Delay-Ansatz. Denn wenn man das 
geschickt macht, dann erzeugt der Timer ganz von alleine ständig die 
richtigen Pulse.

Ich hab deine Code-Zeiten jetzt nicht kontrolliert und nachgerechnet. 
Aber wenn du erst mal von einem ständigen Wechsel des Servos Abstand 
nimmst, dann schickst du ihm erst mal einfach nur eine immer gleiche 
Pulslänge. Zb 1.7ms. Das Servo muss dann genau diese Position anfahren. 
Als Gegentest schickst du ihn eine andere Pulslänge (natürlich ständig). 
Zum Bleistift 1.2ms. Das Servo muss dann diese andere Position anfahren. 
Und natürlich halten.

Wenn es das nicht tut, dann stimmen deine Pulslängen nicht.

(Deine Kabelbelegung dürfte stimmen. Rot ist Spannung, Braun ist Masse, 
Gelb ist Signal)

: Bearbeitet durch User
von Icke ®. (49636b65)


Lesenswert?


von A. B. (developer_x)


Lesenswert?

So, ich habe mir das lange nochmal durch den Kopf gehen lassen.

Ich habe hier, ein ganz primitives C-Programm, viel schneller lesbar als 
ein Assembler Programm
1
#include <avr/io.h>          
2
#include <util/delay.h>
3
4
int main (void) 
5
{            
6
   DDRD  = 0xFF;             
7
   PORTD = 0b00000000;
8
9
   while(1) 
10
   {               
11
    PORTD = 0b00000001;
12
    _delay_us(1500);
13
14
    PORTD = 0b00000000;
15
    _delay_ms(20);
16
   }  
17
18
   return 0;          
19
}

Ich mein hier sieht man doch, dass die Signale dauerhaft gesendet 
werden, und zwar dauerhaft, im Abstand von 20ms, für eine Pulsdauer von 
1,5ms.

Was konkret passiert: Jedes mal wenn der MC solch einen Puls sendet, 
reagiert der Servo, und dreht sich rechts an den Anschlag, egal wie lang 
ich die Pulslänge mache.

Denkt ihr, es könnte ein Fehler am Servo sein?
Er dreht sich nur in die eine Richtung.

Danke für eine Antwort,
m.f.G.: Developer_X

von Karl H. (kbuchegg)


Lesenswert?

A. B. schrieb:

> Denkt ihr, es könnte ein Fehler am Servo sein?

Wenn ich mal davon ausgehe, dass die Verkabelung stimmt, dann kommt auch 
noch die Stromversorgung in Frage.
Servos können richtige Dreckschweine sein und dir massenhaft Störungen 
auf die Versorungsspannung einkoppeln. Die muss gut gesiebt werden, 
sonst schmiert dir der µC dauernd ab.

von A. B. (developer_x)


Lesenswert?

Ich hab da eine 5V Spannung die mit großen als auch kleinen 
Kondensatoren schön geglättet wird.

Der Punkt ist: Früher hatte ich das einmal hinbekommen, leider 
funktioniert das jetzt nicht mehr. Aber er kann nicht kaputt sein, da 
dieser reagiert, oder?

von A. B. (developer_x)


Lesenswert?

Ich weiß woran es noch liegen könnte:
Wie stellt man bei der Delay.h ein, welche Taktgeschwindigkeit
am MC eingestellt ist? (Ich nutze C nicht, deswegen weiß ich das nicht 
:( )

Ich habe nämlich eine Geschwindigkeit von 1MHz, könnte diese auf 8 MHz 
hochsetzen, hat beides aber auch nichts gebracht.

von Icke ®. (49636b65)


Lesenswert?

A. B. schrieb:
> Aber er kann nicht kaputt sein, da dieser reagiert, oder?

'türlich kann er trotzdem defekt sein. Das Servo bestimmt seine Position 
anhand eines Potentiometers auf der Achse. Hat bspw. der Schleifer 
keinen richtigen Kontakt mehr, spinnt das Servo. Da hilft nur Gegenprobe 
mit einem (funktionierenden) RC-Empfänger oder Servotester.

von A. B. (developer_x)


Lesenswert?

1
#include <avr/io.h>          
2
#include <util/delay.h>
3
4
#define F_CPU 1000000UL
5
6
int main (void) 
7
{            
8
   DDRD  = 0xFF;             
9
   PORTD = 0b00000000;
10
11
   while(1) 
12
   {               
13
    PORTD = 0b00000001;
14
    _delay_us(1500);
15
16
    PORTD = 0b00000000;
17
    _delay_ms(20);
18
   }  
19
20
   return 0;          
21
}

Habs jetzt, funktioniert aber immer noch nicht, der Servo dreht nach wie 
vor nur nach rechts. :(

von A. B. (developer_x)


Lesenswert?

Ich denke, dann liegts wirklich am Servo. Führt wohl kein Weg dran 
vorbei mir nen neuen zu besorgen.

Danke für eure Hilfe,

von Icke ®. (49636b65)


Lesenswert?

A. B. schrieb:
> Wie stellt man bei der Delay.h ein, welche Taktgeschwindigkeit
> am MC eingestellt ist?

Falscher Ansatz. Zeit, sich mit den PWM-Funktionen der Timer zu 
beschäftigen. Die sind für sowas nämlich um Größenordnungen besser 
geeignet als Delay-Schleifen. Keine Angst, so kompliziert ist das nicht.

von A. B. (developer_x)


Lesenswert?

Ok. Aber ich glaube der Servo ist trotzdem nicht funktionsfähig, da er 
immerhin auch schon nach Anschluss, sogar wenn Signal ganz auf VCC oder 
ganz auf GND gleich zum Anschlag dreht.

von chris (Gast)


Lesenswert?

Tschuldig das ich störe...

aber warum nutzt nicht nen Timer der dir die 1-2ms generiert und mit den 
selben Timer kannst du, nach jeweils 20ms, den neuen Impuls anlegen... 
Warum so kompliziert... Auch wenns nur ein nicht Sinnvolles Program ist 
??
Gerade weils hier auf nix ankommt mal alle Möglichkeiten 
durchspielen....

von A. B. (developer_x)


Lesenswert?

Also ich habe jetzt, in Assembler, und mit dem Debugger auf genaue 
Taktzahlen geprüft, ein paar Funktionen geschrieben, die einmal 1ms, 
einmal 1.5ms, und einmal 20ms warten.
1
.include "m88def.inc"   
2
3
4
/*
5
6
  Taktfrequenz des MC: 1 MHz
7
*/
8
9
.CSEG 
10
11
// Richtung der IO Ports definieren
12
  LDI R16, 0b11111111    // 1=Output, 0=Input
13
  OUT DDRB, R16
14
  OUT DDRC, R16
15
  OUT DDRD, R16
16
17
// Stackpointer initialisieren
18
  LDI R16, low(RAMEND)
19
  OUT SPL, R16
20
  LDI R16, high(RAMEND)
21
  OUT SPH, R16
22
23
// Timer Einstellung initialisieren
24
  IN R16, TCCR0B
25
  SBR R16, (1<<CS00) | (1<<CS01)  // Prescaler von 64 einstellen
26
  OUT TCCR0B, R16
27
28
// Main Methode
29
  LDI R17, 0x00
30
31
MAIN:
32
  SBI PORTD, PD0  // LED einschalten
33
          // Warten bis 20ms vergangen
34
  RCALL WAIT_1_5_MS  // Braucht 1000 Takte, also 1,000 ms
35
36
  CBI PORTD, PD0  // LED ausschalten
37
          // Warten bis 20ms vergangen
38
  RCALL WAIT_20_MS
39
RJMP MAIN
40
41
WAIT_1_MS:
42
  OUT TCNT0, R17  // Counter resetten
43
  LOOP_1:      // Warten bis Counter abgelaufen
44
    IN R16, TCNT0
45
    CPI R16, 15
46
    BRLO LOOP_1
47
48
  LDI R18, 9
49
  LOOP_2:
50
    DEC R18
51
    CPI R18, 0
52
    BRNE LOOP_2
53
54
  NOP
55
RET
56
57
WAIT_1_5_MS:
58
  OUT TCNT0, R17  // Counter resetten
59
  LOOP_4:      // Warten bis Counter abgelaufen
60
    IN R16, TCNT0
61
    CPI R16, 23
62
    BRLO LOOP_4
63
64
  LDI R18, 6
65
  LOOP_44:
66
    DEC R18
67
    CPI R18, 0
68
    BRNE LOOP_44
69
70
  NOP
71
RET
72
73
WAIT_20_MS:
74
  LDI R19, 20
75
  LOOP_3:
76
    RCALL WAIT_1_MS
77
    DEC R19
78
    CPI R19, 0
79
    BRNE LOOP_3
80
RET

Es funktioniert weiterhin nicht, der Servo dreht nach rechts.

Jetzt muss es definitiv am Servo liegen, denke ich zumindest.

Was meint ihr?
m.f.G.: Developer_X

von Karl H. (kbuchegg)


Lesenswert?

A. B. schrieb:

> Was meint ihr?

Nicht so schnell.
Du klingst nicht besonders sicher, was die Taktfrequenz deines µC 
angeht.
Die würde ich mal überprüfen.

Das kannst du ganz einfach machen.
Häng mal eine LED an den Ausgang.

(das F_CPU muss am sinnvollsten VOR die Includes. Du weisst nicht, in 
welcher Form der Wert von dem includierten Teil benutzt wird!)
1
#define F_CPU 1000000UL
2
3
#include <avr/io.h>          
4
#include <util/delay.h>
5
6
7
int main (void) 
8
{            
9
   DDRD  = 0xFF;             
10
11
12
   while(1) 
13
   {               
14
     PORTD = 0b00000001;
15
     _delay_ms( 1000 );
16
17
     PORTD = 0b00000000;
18
     _delay_ms( 1000 );
19
   }  
20
}

LED beobachten.
leuchtet sie 1 Sekunde und ist 1 Sekunde aus?
Die Zeiten brauchst du jetzt nicht mit der Stoppuhr kontrollieren. Denn 
die Alternativen sind nicht so gross. Wenn der µC mit 8Mhz läuft, dann 
leuchtet die LED nur 1/8 Sekunde (und ist 1/8 Sekunden aus). Den 
Unterschied sieht man mit freiem Auge.

von Karl H. (kbuchegg)


Lesenswert?

Karl H. schrieb:

> (das F_CPU muss am sinnvollsten VOR die Includes.

d.h. am sinnvollsten kommt sie ins makefile bzw. in die 
Projekteinstellungen. Aber lass uns die Dinge jetzt nicht 
verkomplizieren, wenn du normalerweise kein C benutzt)

von A. B. (developer_x)


Lesenswert?

Ja, ich habs kontrolliert, die Zeit beträgt eine Sekunde.

Ich denke wirklich, dass es am Servo liegt.
Weil es wirklich richtig scheint mit der Zeit und der Impulsdauer.

von Felix A. (madifaxle)


Lesenswert?

Es gibt auch Servos, die einen invertierten Puls haben wollen. Also eine 
Lowphase von 1 bis 2 ms brauchen.

Liegt es vielleicht daran?

von STK500-Besitzer (Gast)


Lesenswert?

Felix A. schrieb:
> Es gibt auch Servos, die einen invertierten Puls haben wollen. Also eine
> Lowphase von 1 bis 2 ms brauchen.

Die gab es vor 30 Jahren zu kaufen.

von Felix A. (madifaxle)


Lesenswert?

Ah, war nur ne Idee. Würde erklären, warum der immer an den einen 
Anschlag fährt...

von Robin (Gast)


Lesenswert?

Schraub mal den Servo auf und kontrolliere die Kabel zum Poti. Würde 
fast wetten, das da entweder eine kalte Lötstelle ist oder das Kabel 
gebrochen.

von Karl H. (kbuchegg)


Lesenswert?

Robin schrieb:
> Schraub mal den Servo auf und kontrolliere die Kabel zum Poti. Würde
> fast wetten, das da entweder eine kalte Lötstelle ist oder das Kabel
> gebrochen.

Jetzt wärs natürlich gut, wenn man das Servo nur zur Kontrolle an einen 
normalen RC-Empfänger anstecken könnte.

von Icke ®. (49636b65)


Lesenswert?

Alternativ den Code aus dem Tutorial stibitzen, der ist zwar nicht 
schön, funktioniert aber. Hab ich auf einem ATmega16 selbst ausprobiert. 
Nur die .include Zeile muß auf den Prozessortyp geändert werden und 
ggfs. der Takt auf 4 MHZ. Für den Funktionstest sollte es reichen.

https://www.mikrocontroller.net/articles/AVR-Tutorial:_Servo#einfache_Servoansteuerung_mittels_Warteschleifen

: Bearbeitet durch User
von Uwe (Gast)


Lesenswert?

Hi,
>Ok. Aber ich glaube der Servo ist trotzdem nicht funktionsfähig, da er
>immerhin auch schon nach Anschluss, sogar wenn Signal ganz auf VCC oder
>ganz auf GND gleich zum Anschlag dreht.

Ist def. weil ein Servo ohne Signal stehen bleibt(sollte).

Viel Erfolg, Uwe

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.