Forum: Mikrocontroller und Digitale Elektronik Probleme Servo Steuerung


von Michael K. (mr_desmond)


Lesenswert?

Hallo Leute,
ich habe ein kleines Problem bei der Servo Programmierung oder 
vielleicht auch einfach nur ein Verständnisproblem. Ich benutze einen 
Amtel Mega 32 und das AVR Studio.

Ich will mit Hilfe von 2 Tastern den Servo Links bzw. Rechts herum 
steuern lassen. Die Taster funktionieren! Das Problem ist der Servo, der 
sich immer nur um ungefähr 45 grad dreht und das halt nur auf der 
rechten oder linken Seite des Motors. Ich kriege es nicht hin den Servo 
genau auf einen Winkel anzusteuern.

Der Servo ist an BIT 7 von PORT C angeschlossen.

In diesem Programm dreht sich der Servo auf der Rechten hälft des 
Motors(von Mittelpunkt aus gesehen), bei betätigung von Taster 1 (BIT6) 
Linksherum und von betätigung des Tasters 2 (BIT7) Rechts herum. Jeweils 
45 Grad! Ab und zu kommt es vor, das ein Taster nicht wirkt bzw. der 
Motor nur kurz zuckt!

CODE:
1
#include<avr/io.h>
2
#include"../cpu/cpu.h"
3
#include <util/delay.h>
4
5
void Init ();
6
void FlashLed (unsigned char bit);
7
8
#define PORT_LED PORTC
9
#define DDR_LED DDRC
10
#define BIT7 7
11
#define BIT0 0
12
13
14
#define PORT_TASTER PORTA
15
#define DDR_TASTER DDRA
16
#define BIT6 6
17
#define BIT7 7
18
19
int Taster (int tnum)
20
{
21
  if(((~PINA) & (1 <<tnum)))
22
  {
23
    delay_ms(1000);
24
25
    if(((~PINA) & (1 << tnum)))
26
    {
27
    return 1;
28
    }
29
    }
30
    return 0;
31
}
32
33
//*****Hauptprogramm*******
34
int main ()
35
{
36
  Init();
37
38
while(1){
39
//Drücken taste 1
40
while (!Taster(BIT6));
41
  {
42
43
//LED Ein 
44
DDR_LED |=(1 << BIT0);        
45
PORT_LED &=~(1 << BIT0);
46
47
48
//SERVO
49
PORT_LED |=(1 << 7);
50
_delay_us(2000);
51
PORT_LED &=~(1 << 7);
52
delay_ms (18);
53
  }
54
55
56
//Drücken taste 2
57
  while (!Taster(BIT7));
58
  {
59
//LED aus  
60
PORT_LED |=(1 << BIT0);
61
62
63
64
//SERVO
65
PORT_LED |=(1 << 7);
66
_delay_us(1500);
67
PORT_LED &=~(1 << 7);
68
delay_ms (19);
69
70
71
}
72
73
}
74
return 0;
75
}
76
77
//Bit anders herum setzten!
78
void Init()
79
{
80
DDR_LED  |= (1 << 7) | (1 << BIT0);
81
PORT_LED |=(1 << 7) | (1 << BIT0);
82
DDR_TASTER  &=~((1 << BIT7) |(1 << BIT6));
83
PORT_TASTER  |= ((1 << BIT7) | (1 << BIT6));
84
}

Würde mich freuen, wenn ihr mir bei diesem Problem weiterhelfen könnt!

Mit freundlichen Grüßen
mr_desmond

p.s. Die Tutorials auf Microkontroller.net, zu diesem Thema habe ich mir 
schon angeguckt und verstehe diese eher nicht!

: Verschoben durch User
von anigav (Gast)


Lesenswert?

du benötigst für die Servos ein PWM Signal .. je nach Pulsweite stellt 
der Servo den entsprechenden Winkel..

von F_CPU (Gast)


Lesenswert?

Hast du denn mal kontrolliert ob _delay_us / delay_ms richtig 
funktioniert ?
(Led an, eine Sekunde warten, Led aus - Zeit messen)

AVR-GCC-Tutorial - 11 Warteschleifen (delay.h)

von mr_desmond (Gast)


Lesenswert?

Also von der delay_ms weiß ich, das diese funktioniert!
bei der delay_us bin ich mir nicht sicher!

@anigav Kann das sein, dass ich ein Denkfehler habe? Weil das ist doch 
ne PWM oder? Wobei ich mir bei der Delay_us nicht sicher bin, wenn ich 
die beiden auf 1500 stelle, so wie auf einem Beispielprogramm von 
Microkontroller.net
""""""
1
 PORTB |= (1<<PB1);
2
    _delay_us( 1500 );    // in den 1500 steckt die Lageinformation
3
    PORTB &= ~(1<<PB1);
4
 
5
    _delay_ms( 18 );      // ist nicht kritisch
6
  }

dann funktioniert dies auch machmal nicht richtig und bleib auch auf 
einer Hälfte des Servos stecken!

von dgps (Gast)


Lesenswert?

theoretisch ist das eine PWM.
Aber die Megas haben auch einen Timer, mit dem man sehr komfortabel eine 
PWM erzeugen kann. Und man muss sich nicht ständig um das richtige 
Timing kümmern.

Lies dir mal
http://www.mikrocontroller.net/articles/Modellbauservo_Ansteuerung
durch, besonders "Signalerzeugung für 1 Servo mittels Timer (C)"

von mr_desmond (Gast)


Lesenswert?

Also erstmal Dnake für die schnelle antwort!

Den Artikel habe ich schon einmal gelesen aber ich kriege es nicht hin 
diese Programm so abzuändern, dass mein Servo sich per Taster sich 
bewegt!

Was müsste ich an diesem Programm ändern, wenn ich den Servo an PORTC 
BIT7 angelegt habe? Und dieser sich zumindest bewegen soll? Irgenwie 
steige ich dort nicht hindurch!
1
ISR( TIMER1_COMPA_vect )                // Interruptbehandlungsroutine
2
{
3
  OCR1A = 2500-OCR1A;      // Das Servosignal wird aus der Differenz von
4
                                        // Periodenlänge (2500*0,008ms=20ms) und letztem
5
                                        // Vergleichswert (OCR1A) gebildet 
6
}
7
 
8
 
9
int main (void)
10
{
11
  DDRB = 0b11111100;
12
  PORTB = (1<<PB1) | (1<<PB0);          // Pullup für PB0 und PB1
13
 
14
  TCCR1A = (1<<COM1A0);                 // Togglen bei Compare Match
15
  TCCR1B = (1<<WGM12) | (1<<CS11);      // CTC-Mode; Prescaler 8
16
  TIMSK  = (1<<OCIE1A);                 // Timer-Compare Interrupt an
17
 
18
  OCR1A = 2312;                         // Neutralposition ((2500-2312)*0.008ms)=1,5ms)
19
 
20
  sei();                                // Interrupts global an
21
 
22
  while( 1 ) {
23
 
24
    if ( !(PINB & (1<<PINB0)) ) {       // Impuls-Zeit verlängern
25
      cli();
26
      OCR1A = OCR1A + 3;
27
      sei();
28
      _delay_ms(50);
29
    }
30
 
31
    if ( !(PINB & (1<<PINB1)) ) {       // Impuls-Zeit verkürzen
32
      cli();
33
      OCR1A = OCR1A - 3;
34
      sei();
35
      _delay_ms(50);
36
    }
37
  }
38
 
39
  return 0;
40
}

von Thomas M. (thomil)


Lesenswert?

Michael Klink schrieb:
> while (!Taster(BIT6));

Ist das Absicht, dass in diesem while() kein Code ausgeführt wird? Falls 
nein, lass das ';' mal weg.

von mr_desmond (Gast)


Lesenswert?

Die Taster Funktion funktioniert! auch an LEDs usw. ich habe nur das 
Problem der mit dem Servo Code!

von Rolf M. (rmagnus)


Lesenswert?

Michael Klink schrieb:
> In diesem Programm dreht sich der Servo auf der Rechten hälft des
> Motors(von Mittelpunkt aus gesehen), bei betätigung von Taster 1 (BIT6)
> Linksherum und von betätigung des Tasters 2 (BIT7) Rechts herum. Jeweils
> 45 Grad!

Ist doch auch kein Wunder. Du veränderst ja in dem Programm deine 
Pulsweite nirgends. Du gibst immer nur zwei Möglichkeiten vor, nämlich 
1,5 ms (entspricht Mitte) und 2 ms (entspricht 45° rechts). Warum sollte 
der Servo also je irgendeine andere Position annehmen?

mr_desmond schrieb:
> Die Taster Funktion funktioniert! auch an LEDs usw. ich habe nur das
> Problem der mit dem Servo Code!

Ok, aber sowas sieht halt schon sehr danach aus, als ob es nicht so 
gedacht sei:

Michael Klink schrieb:
> while (!Taster(BIT6));
>   {

Die geschweifte Klammer läßt vermuten, daß du den Code danach innerhalb 
der Schleife ausführen willst, aber das Semikolon führt dazu, daß das 
eben nicht so ist. Wozu dann aber die Klammer?
Das führt auch dazu, daß dein Programm so lange komplett stehen bleibt 
(und damit auch gar keine PWM generiert), wie Taster(BIT6) bzw. 
Taster(BIT7) nicht gesetzt ist, und innerhalb der Funktion Taster() 
blockierst du das Programm auch für eine Sekunde. Die PWM muß aber 
eigentlich dauerhaft anliegen. Die PWM-Ausfälle sind vermutlich der 
Grund für das Zucken des Servos.

von F_CPU (Gast)


Lesenswert?

Was den Code aus dem Artikel angeht:
Schau dir doch mal das Datenblatt zu deinem Controller an, besonders die 
Pinbelegung der Taster und den Pin an dem die PWM von OCR1A anliegt.

von mr_desmond (Gast)


Lesenswert?

Ok mir klar was OCR1A ist, aber was beuten diese Funktionen hier im 
Zusammenhang mit der PWM (Oben genannter Microcontroller.net Code)

 TCCR1A = (1<<COM1A0);                 // Togglen bei Compare Match
 TCCR1B = (1<<WGM12) | (1<<CS11);      // CTC-Mode; Prescaler 8
 TIMSK  = (1<<OCIE1A);                 // Timer-Compare Interrupt an

MfG
mr_desmond

von Karl H. (kbuchegg)


Lesenswert?

mr_desmond schrieb:
> Ok mir klar was OCR1A ist,

Das ist aber nur die halbe Miete.
Der Timer erzeugt seine Hardware-PWM, in dem er einen ganz bestimmten 
Pin toggelt. Dere Pin ist festgelegt und du kannst ihn  nicht ändern.

> aber was beuten diese Funktionen hier im
> Zusammenhang mit der PWM (Oben genannter Microcontroller.net Code)
>
>  TCCR1A = (1<<COM1A0);                 // Togglen bei Compare Match
>  TCCR1B = (1<<WGM12) | (1<<CS11);      // CTC-Mode; Prescaler 8
>  TIMSK  = (1<<OCIE1A);                 // Timer-Compare Interrupt an

Genau das was jeweils im Kommentar steht.

FAQ: Timer

Der springende Punkt in diesem Code besteht darin, dass der Timer selbst 
den Ausgangspin umschaltet (toggelt). Aber das kann nicht irgendein Pin 
sein, sondern das ist (bei dieser Art der Programmierung) immer der OC1A 
Pin. Der liegt aber physikalisch an jedem µC woanders. Also musst du in 
deinem Datenblatt nachsehen, an welchem Pin bei dir der OC1A Ausgang 
liegt und du musst dein Servo dann dort anschliessen (und den Pin 
mittels entsprechender DDRx 'Akrobatik' auch auf Ausgang stellen)

von Michael Klink (Gast)


Lesenswert?

Hallo erstmal,
also erstmal danke für die ganzen Hilfen, ich habe paar Dennkfehler 
ausgemertzt und eine einstellung am IC geändert und zack die Scheiße 
funktioniert... Ich kann jetzt 9 Servos direkt ansteuern!

Habe da noch eine frage: Kann man die Servos langsamer laufen lassen? 
durch ein Befhel oder ähnliches?

MfG
Michael Klink

von Karl H. (kbuchegg)


Lesenswert?

Michael Klink schrieb:

> Habe da noch eine frage: Kann man die Servos langsamer laufen lassen?
> durch ein Befhel oder ähnliches?

Durch einen 'Befehl' nicht.
Aber nichts und niemand hindert dich daran, die Vorgabepositionen für 
die Servos langsam und in Schritten zu ändern um die Zielposition zu 
erreichen.

von Udo S. (urschmitt)


Lesenswert?

Michael Klink schrieb:
> Habe da noch eine frage: Kann man die Servos langsamer laufen lassen?
> durch ein Befhel oder ähnliches?

Indem du eine Rampe programmierst.

Wenn er z.B. in 2 Sekunden von Mittelstellung nach 45° rechts gehen 
soll,
dann sende ihm innerhalb von 2 Sekunden länger werdende Impulse 
beginnend von 1,5ms so daß in 2 Sekunden die Impulse 2ms lang sind

von Poster (Gast)


Lesenswert?

Ganz verstanden hast du die Ansteuerung der Servos noch nicht.
die Breite des PWM Signales entspricht der Servostellung. Wenn du jetzt 
immer zwischen zwei Werten springst versucht der Servo mit seiner 
maximalen Geschwindigkeit die neue Position zu erreichen.
das must du sanfter machen, die Breite des Signales immer nur ein 
bischen ändern. Je langsammer du das machst um so langsammer fahrt der 
Servo.

von Mikesch (Gast)


Lesenswert?

Um den Beitrag von meinem Vorredner "Poster" zu illustrieren, poste ich 
hier noch einen Link zu einer entsprechenden Animation:

http://www.electronicsplanet.ch/Roboter/Servo/intern/intern.htm

Gruss
Mikesch

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.