Forum: Compiler & IDEs 2 Servos und 2 verschiedenen Impulslängen mit Timer0?


von Udo S. (Firma: allround) (1udo1)


Lesenswert?

Hallo,

im Arm meines Roboters sind 2 Servos. Servo 1 ist im Schultergelenk und 
Servo 2 im Ellbogengelenk.

Folgende Armbewegung will ich realisieren:

Oberarm und Unterarm hängen gestreckt am Körper runter. Beide Servos 
werden mit 1,5 ms angesteuert (Mittelstellung). Danach wird der 
komplette Arm (Oberarm und Unterarm) nach vorne gestreckt. Das heisst, 
Servo 1 wird mit jetzt mit 0,5 ms angesteuert und der Unterarm müsste 
aber seine 1,5 ms weiter bekommen. Der Unterarm hat ja noch seine 
gestreckte Position. Geht aber nicht, weil Timer0 ja alle 20ms nur eine 
einzige Impulslänge generieren kann, also entweder 0,5ms oder 1,5ms

Meine Frage:

Kann ich an einem Gelenkstück (Hand, Ellenbogen, Schultergelenk) mehrere 
Servos mit unterschiedlichen Impulslängen von 0,5 ms bis 2ms unabhängig 
versorgen? Die Impulse werden in der ISR von TIMER0 generiert.

Ich habe für mich die Frage insofern selbst beantwortet, dass ich sage: 
DAS KANN NICHT FUNZEN! Wie denn auch. Es sei denn, jemand von euch hätte 
eine Anregung, wie man sowas trotzdem realisieren kann. Vielleicht 
mehrere TIMER?

Alle Servos am Roboter arbeiten einwandfrei, wenn sie ihren "privaten" 
Impuls bekommen. Aber zeitgleich 2 unterschiedliche Impulse an den 
Servos am Arm???!!

Ausschnitt aus dem sehr umfangreichen Programm:

In der ISR wird "pos" per switch abgefragt und dementsprechend die PORTS 
gesetzt.
1
void arm_STEMMEN()  // stemmen
2
3
{
4
  switch(count)
5
  {
6
  case  140:   pos=0x0003;  break;  //  Ellenbogen 0,5ms
7
  case  200:   pos=0x0073;  break;  //  Ellenbogen 1,5ms
8
  case  280:   pos=0x0003;  break;   // Ellenbogen 0,5ms
9
  case  400:   count =120;  k++;   break;    
10
  } // Ende switch
11
          
12
    switch(k)
13
    {
14
     case 2:  k=0;  count=401;break;  
15
    } // Ende switch
16
17
} // End
18
19
20
########################## check von "pos" in der ISR #####################
21
22
23
ISR(TIMER0_OVF_vect) 
24
{
25
if (TCCR0 == 5) // wenn ja, dann ist die 20ms Pause zuende, es folgt Port setzen
26
      {
27
28
      switch(pos)
29
      {         
30
      case 0x0000:  TCNT0 = 0xd5; PORTC  &= ~(1<<PC0);   break; // 0 Grad
31
      case 0x0010:  TCNT0 = 0xB0; PORTC  &= ~(1<<PC0);   break; // 12 Grad
32
.............................................................
33
34
...........................................................
35
36
usw.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

> Ich habe für mich die Frage insofern selbst beantwortet, dass ich sage:
> DAS KANN NICHT FUNZEN!

So schlimm ist es nicht! Es kann funzen.

Wie wäre es, wenn du den Timer auf die kleinste gemeinsame Zeit 
einstellst (0,5ms) und alle anderen Zeiten als Vielfache dieser Zeit 
betrachtest, d.h. intern Zähler mitlaufen lässt?

Also der Timer als Taktgeber für eine Stoppuhr mit einem 0,5ms Takt. Der 
Zähler Servo1 startet bei 1 (0,5ms) und läuft bis 41 (Start+20ms) 
beginnt von vorne. Der Zähler Servo2 startet bei 3 (1,5ms) und läuft 
bis 43 (Start+20ms).

von ... .. (docean) Benutzerseite


Lesenswert?

ich hab mal eine Routine geschrieben die 3 Servos versorgt über EINEN 
Timer

Ablauf:

1. 1. Ausgang high -> Timer laden mit Pulslänge 1
2. Timer schlägt zu -> 1.Ausgang low, 2. Ausgang high -> Timer laden mit 
Pulslänge 2
3. Timer schlägt zu -> 2. Ausgang low, 3. Ausgang high -> Timer laden 
mit Pulslänge 3
4. ...

Du mußt dann natürlich die Pins alleine umschalten, das erledigt nicht 
mehr der Timer alleine...

von Udo S. (Firma: allround) (1udo1)


Lesenswert?

Hallo ihr beiden Hotliner,

gute Ideen, die ihr vorgeschlagen habt. Ich glaube, dass ich meine 10 
Servos im Roboter mit Timer0 versorgen kann. Die anderen Timer im MEGA16 
sind schon mit Encoder und Tastenentprellung beschäftigt. Ich setze mich 
diese Woche hin und berichte dann, inwieweit ich das realisieren konnte. 
Sehr interessante Antworten von euch.DANKE!

Udo

von STK500-Besitzer (Gast)


Lesenswert?

>Ich glaube, dass ich meine 10 Servos im Roboter mit Timer0 versorgen kann.
Guck mal da:
http://www.voidpointer.de/tech.html

von Udo S. (Firma: allround) (1udo1)


Lesenswert?

Hallo Hotliner,


Danke für eure Anschubhilfe. Habe das Prinzip bei 2 Servos realisiert. 
Beide Servos werden unabhängig mit frei wählbaren Impulsen angesteuert. 
Der Einfachheit halber drehen in diesem Demoprogramm beide Servos von 
0,8ms nach 2,2ms jeweils in entgegengesetzte Richtung.

Es ist sehr wahrscheinlich die x-te Variante, um Servos unabhängig 
anzusteuern. Wer will, kann das Programm als Einstieg verwenden.

Ich programmiere noch nicht solange in C. Deshalb ist der Code 
möglicherweise noch umständlich.Aber er funktioniert tadellos. Trotzdem 
möcht ich mal bei den Experten nachfragen, wie ein optimierter, 
verkürzter Code aussieht. Würde mich über die eine oder andere Anregung 
freuen.

Hier mein Programm. Liebe Experten: Es ist bestimmt verbesserungswürdig. 
Bitte um eure Anregungen!!

Udo
1
// 2 unabhängige Servos drehen gleichzeitig in entgegengesetzte Richtung 
2
// Wechsel nach ca. 2 Sekunden
3
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
#include <inttypes.h>
7
8
#define  F_CPU  7372800
9
10
// März 2009 o.k.    
11
12
//###################### Globale Variablen ###############################
13
14
volatile int  servolinks=3, scount, LR;
15
16
volatile int16_t warten;
17
18
volatile char s;
19
20
int S01_L_R(int);    //gleichzeitig
21
22
int S01_R_L(int);     //gleichzeitig
23
24
25
//###################### TIMER 0 #######################################
26
27
ISR(TIMER0_OVF_vect)     // Takt/8, alle 277us TOV
28
29
{  
30
31
S01_L_R(LR);
32
33
S01_R_L(LR);
34
35
} // Ende ISR
36
37
// ############### TIMER0 initialisieren ##################################
38
39
void init(void)
40
{  
41
  TIMSK =  (1<<TOIE0) ;   
42
43
  TCCR0 = (1<<CS01);    // Takt/8
44
  
45
46
  DDRC=0xff;
47
  PORTC = 0xff;
48
49
   sei();
50
}
51
52
// ###################### main #################################
53
54
int main(void)
55
{  
56
     init();
57
58
  LR=100;
59
60
      while(1) 
61
    { 
62
    
63
    }  // Ende while
64
    return 0;
65
} // Ende main
66
67
68
69
// ## Funktion Servo 0 und Servo 1  an C0 nach links und C1 nach rechts ##
70
71
int S01_L_R(int LR)      
72
73
{  
74
  if(s==0)
75
  {  
76
    if(scount<servolinks)     // Impuls wieder auf HIGH setzen 3 entspricht 1ms
77
    { 
78
    PORTC &=~((1<<PC1) | (1<<PC0));  // PIN C0 und PC1 LOW, damit Impulse am Servo HIGH
79
    } // Ende if
80
81
      else 
82
      {       
83
        if(scount>=3)
84
        { 
85
          { 
86
          PORTC |=(1<<PC0); // PIN C0 HIGH 0,8 ms erreicht, Impuls Servo LOW
87
          
88
          if(scount>=8)      
89
            { 
90
            PORTC |=(1<<PC1); // PIN C0 LOW 2 ms erreicht, Impuls Servo LOW
91
            }
92
          }
93
        } // Ende if,  jetzt 20ms Pause, damit Impuls LOW
94
        
95
      } // Ende else 
96
97
      scount++;
98
            
99
        if(scount >=72)    // warten bis 20ms vergangen sind
100
        { 
101
        scount=0;
102
        warten++;
103
104
          if(warten==100)
105
            { 
106
            warten=0;
107
            s=1;
108
            }
109
        }
110
  }
111
  return 0;
112
} // Ende funk 
113
114
115
116
// ## Funktion Servo 0 und Servo 1  an C0 nach rechts und C1 nach links ##
117
118
int S01_R_L(int LR)      
119
120
{ 
121
  if(s==1)
122
  { 
123
    if(scount<servolinks)   // Impuls wieder auf HIGH setzen 3 entspricht 1ms  
124
    
125
    { 
126
    PORTC &=~((1<<PC1) | (1<<PC0));  // PIN C0 und PC1 LOW, damit Impulse HIGH
127
    } // Ende if
128
129
      else 
130
      {       
131
        if(scount>=3)
132
        { 
133
          { 
134
          PORTC |=(1<<PC1);   // PIN C0 HIGH 0,8 ms erreicht, Impuls LOW
135
          
136
          if(scount>=8)      
137
            { 
138
            PORTC |=(1<<PC0);   // PIN C0 LOW 2 ms erreicht
139
            }
140
          }
141
        } // Ende if, jetzt 20ms Pause, damit Impuls LOW
142
        
143
      } // Ende else 
144
145
            scount++;
146
            
147
            if(scount >=72)    // warten bis 20ms vergangen sind
148
            { 
149
            scount=0;
150
            warten++;
151
152
              if(warten==100)
153
              { 
154
              warten=0;
155
              s=0;
156
              }
157
            }
158
  } // Ende if
159
  return 0;
160
} // Ende funk

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.