Forum: Mikrocontroller und Digitale Elektronik Ansteuerung von 3 Servos alle 20ms


von Sam G. (asiris)


Angehängte Dateien:

Lesenswert?

Hallo zusammen.

Für ein kleines Projekt (Spinnenbein) sollen 3 Servos angesteuert 
werden. Da ich mich erst seit kurzem mit uControllern auseinander setzte 
habe ich mich an einigen Tutorials aus diesem Forum bedient.

Bei den Servos tritt nun ein "zittern" auf, welches ich bereits auf eine 
zu kurze Pausenzeit zwischen den Pulsen zurückführen konnte. Ich habe 
nun versucht eine Pause-Phase nach der Ansteuerung der Servos 
hinzuzufügen. Beim Betrachten der Signale am Oszilloskop habe ich 
festgestellt,dass Kanal B0 nach erfolgreicher ansteuerung aller Känäle 
für ca 21ms "high" und anschliessend der Pausentakt viel länger als 
vorgesehen ist. Leider sehe ich aber den Grund dazu nicht..

Gesamter Code
1
// +------------------------------------------------------------
2
// ¦ Project:    Leg
3
// +------------------------------------------------------------
4
// ¦ Author:    User
5
// ¦ Date:      1/21/2018 4:23:14 PM
6
// ¦
7
// ¦ Processor:    ATmega8
8
// +------------------------------------------------------------
9
10
#define F_CPU 8000000UL
11
#include <avr/io.h>
12
#include <avr/interrupt.h>
13
#include <util/delay.h>
14
15
#define Servos 3
16
#define ServoCycle 20000
17
18
int Servo[Servos] = {1<<PB0, 1<<PB1, 1<<PB2};
19
volatile int ServoValue[Servos];
20
21
// ¦  Interrupt - SERVO-PWM
22
// +------------------------------------------------------------
23
ISR(TIMER1_COMPA_vect)
24
{
25
  static int ServoID = 0;
26
  static int ServoCycleIdle = ServoCycle;
27
28
  if (ServoID < Servos)          
29
  {
30
    // aktuellen Servo absteuern
31
    PORTB &= ~Servo[ServoID];
32
    
33
    // ServoID erhöhen
34
    ServoID ++;
35
    
36
    // aktuellen Servor ansteuern
37
    PORTB |= Servo[ServoID];
38
    
39
    // Pulsdauer übergeben
40
    OCR1A = ServoValue[ServoID];
41
    
42
    // Pausendauer berechnen
43
    ServoCycleIdle -= ServoValue[ServoID];
44
  } 
45
  else                // Pause ausführen / Servo 0 ansteuern
46
  {
47
    if (ServoID == Servos)      // Pause ausführen
48
    {
49
      // aktuellen Servo absteuern
50
      PORTB &= ~Servo[ServoID];
51
      
52
      // ServoID erhöhen
53
      ServoID ++;
54
      
55
      // Pausendauer übergeben & rücksetzen
56
      OCR1A = ServoCycleIdle;
57
      ServoCycleIdle = ServoCycle;
58
    } 
59
    else              // Servo 0 ansteuern
60
    {
61
      // ServoID rücksetzen
62
      ServoID = 0;
63
      
64
      // aktuellen Servor ansteuern
65
      PORTB |= Servo[ServoID];
66
      
67
      // Pulsdauer übergeben
68
      OCR1A = ServoValue[ServoID];
69
      
70
      // Pausendauer berechnen
71
      ServoCycleIdle -= ServoValue[ServoID];
72
    }
73
  }
74
}
75
76
77
78
int main(void)
79
{
80
  // ¦  Konfiguration SERVO
81
  // +------------------------------------------------------------
82
  // Pins setzen
83
  DDRB = (1<<PB0) | (1<<PB1) | (1<<PB2);    // Ausgänge setzen
84
  //Zähler konfigurieren
85
  TCCR1B = (1<<WGM12) | (1<<CS11);      // CTC-Mode & Prescacler=8 (F_CPU / 8 = 100000Hz --> 1us)
86
  TIMSK = (1<<OCIE1A);            // Timer-Interrupts für Vergleichswerte
87
    
88
  // ¦  Interrupt einschalten
89
  // +------------------------------------------------------------
90
  sei();
91
    
92
    while (1) 
93
    {
94
    ServoValue[0] = 1500;
95
    ServoValue[1] = 1500;
96
    ServoValue[2] = 1500;
97
    }
98
}

Hat von Euch jemand eine Idee?

Grüsse Sam

von Falk B. (falk)


Lesenswert?


von Sam G. (asiris)


Lesenswert?

Besten Dank für den Link zum Beitrag. Damit hats geklappt.
1
ISR(TIMER1_COMPA_vect)
2
{
3
  static int ServoID = 0;
4
  static int ServoCycleIdle = ServoCycle;
5
  
6
  
7
  switch (ServoID)
8
  {
9
    case 0:                // Servo 0
10
    PORTB |= Servo[0];          // Servopuls 0 setzten
11
    OCR1A = ServoValue[0];        // Pulsdauer 0 an Timer übergeben
12
    ServoCycleIdle -= ServoValue[0];  // Pulsdauer 0 von CycleIdle abziehen
13
    break;
14
    case 1:                // Servo 1
15
    PORTB &= ~Servo[0];          // Servopuls 0 rücksetzten
16
    PORTB |= Servo[1];          // Servopuls 1 setzten
17
    OCR1A = ServoValue[1];        // Pulsdauer 1 an Timer übergeben
18
    ServoCycleIdle -= ServoValue[1];  // Pulsdauer 1 von CycleIdle abziehen
19
    break;
20
    case 2:                // Servo 2
21
    PORTB &= ~Servo[1];          // Servopuls 1 rücksetzten
22
    PORTB |= Servo[2];          // Servopuls 2 setzten
23
    OCR1A = ServoValue[2];        // Pulsdauer 2 an Timer übergeben  
24
    ServoCycleIdle -= ServoValue[2];  // Pulsdauer 2 von CycleIdle abziehen
25
    break;
26
    case 3:                // Pausendauer
27
    PORTB &= ~Servo[2];          // Servopuls 2 rücksetzten
28
    OCR1A = ServoCycleIdle;        // CycleIdle an Timer übergeben
29
    ServoCycleIdle = ServoCycle;    // CycleIdle rückstzen
30
    break;
31
  }
32
  
33
  ServoID++;                // ServoID hochzählen
34
  if (ServoID > Servos) ServoID = 0;    // ServoID rücksetzen
35
}

von Ent Tabber (Gast)


Lesenswert?

Sam G. schrieb:
> Besten Dank für den Link zum Beitrag. Damit hats geklappt.

Ich kann so ein Chaos nicht ansehen.
1
ISR (TIMER1_COMPA_vect)
2
{
3
  static int ServoID = 0;
4
  static int ServoCycleIdle = ServoCycle;
5
6
  switch (ServoID)
7
  {
8
    case 0:                             // Servo 0
9
      PORTB |= Servo[0];                // Servopuls 0 setzten
10
      OCR1A  = ServoValue[0];           // Pulsdauer 0 an Timer übergeben
11
      ServoCycleIdle -= ServoValue[0];  // Pulsdauer 0 von CycleIdle abziehen
12
    break;
13
    case 1:                             // Servo 1
14
      PORTB &= ~Servo[0];               // Servopuls 0 rücksetzten
15
      PORTB |= Servo[1];                // Servopuls 1 setzten
16
      OCR1A  = ServoValue[1];           // Pulsdauer 1 an Timer übergeben
17
      ServoCycleIdle -= ServoValue[1];  // Pulsdauer 1 von CycleIdle abziehen
18
    break;
19
    case 2:                             // Servo 2
20
      PORTB &= ~Servo[1];               // Servopuls 1 rücksetzten
21
      PORTB |= Servo[2];                // Servopuls 2 setzten
22
      OCR1A  = ServoValue[2];           // Pulsdauer 2 an Timer übergeben
23
      ServoCycleIdle -= ServoValue[2];  // Pulsdauer 2 von CycleIdle abziehen
24
    break;
25
    case 3:                             // Pausendauer
26
      PORTB &= ~Servo[2];               // Servopuls 2 rücksetzten
27
      OCR1A  = ServoCycleIdle;          // CycleIdle an Timer übergeben
28
      ServoCycleIdle = ServoCycle;      // CycleIdle rückstzen
29
    break;
30
  }
31
32
  ServoID++;                            // ServoID hochzählen
33
  if (ServoID > Servos) ServoID = 0;    // ServoID rücksetzen
34
}

von hankok (Gast)


Lesenswert?

Ent Tabber schrieb:
> Sam G. schrieb:
>> Besten Dank für den Link zum Beitrag. Damit hats geklappt.
>
> Ich kann so ein Chaos nicht ansehen.

Ohne einen erläuterten Bezug schau ich deinen Text erst gar nicht an.

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.