mikrocontroller.net

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


Autor: Udo Scharnitzki (Firma: allround) (1udo1)
Datum:

Bewertung
0 lesenswert
nicht 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.

void arm_STEMMEN()  // stemmen

{
  switch(count)
  {
  case  140:   pos=0x0003;  break;  //  Ellenbogen 0,5ms
  case  200:   pos=0x0073;  break;  //  Ellenbogen 1,5ms
  case  280:   pos=0x0003;  break;   // Ellenbogen 0,5ms
  case  400:   count =120;  k++;   break;    
  } // Ende switch
          
    switch(k)
    {
     case 2:  k=0;  count=401;break;  
    } // Ende switch

} // End


########################## check von "pos" in der ISR #####################


ISR(TIMER0_OVF_vect) 
{
if (TCCR0 == 5) // wenn ja, dann ist die 20ms Pause zuende, es folgt Port setzen
      {

      switch(pos)
      {         
      case 0x0000:  TCNT0 = 0xd5; PORTC  &= ~(1<<PC0);   break; // 0 Grad
      case 0x0010:  TCNT0 = 0xB0; PORTC  &= ~(1<<PC0);   break; // 12 Grad
.............................................................

...........................................................

usw.


Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: ... ... (docean) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Udo Scharnitzki (Firma: allround) (1udo1)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: STK500-Besitzer (Gast)
Datum:

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

Autor: Udo Scharnitzki (Firma: allround) (1udo1)
Datum:

Bewertung
0 lesenswert
nicht 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

// 2 unabhängige Servos drehen gleichzeitig in entgegengesetzte Richtung 
// Wechsel nach ca. 2 Sekunden

#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>

#define  F_CPU  7372800

// März 2009 o.k.    

//###################### Globale Variablen ###############################

volatile int  servolinks=3, scount, LR;

volatile int16_t warten;

volatile char s;

int S01_L_R(int);    //gleichzeitig

int S01_R_L(int);     //gleichzeitig


//###################### TIMER 0 #######################################

ISR(TIMER0_OVF_vect)     // Takt/8, alle 277us TOV

{  

S01_L_R(LR);

S01_R_L(LR);

} // Ende ISR

// ############### TIMER0 initialisieren ##################################

void init(void)
{  
  TIMSK =  (1<<TOIE0) ;   

  TCCR0 = (1<<CS01);    // Takt/8
  

  DDRC=0xff;
  PORTC = 0xff;

   sei();
}

// ###################### main #################################

int main(void)
{  
     init();

  LR=100;

      while(1) 
    { 
    
    }  // Ende while
    return 0;
} // Ende main



// ## Funktion Servo 0 und Servo 1  an C0 nach links und C1 nach rechts ##

int S01_L_R(int LR)      

{  
  if(s==0)
  {  
    if(scount<servolinks)     // Impuls wieder auf HIGH setzen 3 entspricht 1ms
    { 
    PORTC &=~((1<<PC1) | (1<<PC0));  // PIN C0 und PC1 LOW, damit Impulse am Servo HIGH
    } // Ende if

      else 
      {       
        if(scount>=3)
        { 
          { 
          PORTC |=(1<<PC0); // PIN C0 HIGH 0,8 ms erreicht, Impuls Servo LOW
          
          if(scount>=8)      
            { 
            PORTC |=(1<<PC1); // PIN C0 LOW 2 ms erreicht, Impuls Servo LOW
            }
          }
        } // Ende if,  jetzt 20ms Pause, damit Impuls LOW
        
      } // Ende else 

      scount++;
            
        if(scount >=72)    // warten bis 20ms vergangen sind
        { 
        scount=0;
        warten++;

          if(warten==100)
            { 
            warten=0;
            s=1;
            }
        }
  }
  return 0;
} // Ende funk 



// ## Funktion Servo 0 und Servo 1  an C0 nach rechts und C1 nach links ##

int S01_R_L(int LR)      

{ 
  if(s==1)
  { 
    if(scount<servolinks)   // Impuls wieder auf HIGH setzen 3 entspricht 1ms  
    
    { 
    PORTC &=~((1<<PC1) | (1<<PC0));  // PIN C0 und PC1 LOW, damit Impulse HIGH
    } // Ende if

      else 
      {       
        if(scount>=3)
        { 
          { 
          PORTC |=(1<<PC1);   // PIN C0 HIGH 0,8 ms erreicht, Impuls LOW
          
          if(scount>=8)      
            { 
            PORTC |=(1<<PC0);   // PIN C0 LOW 2 ms erreicht
            }
          }
        } // Ende if, jetzt 20ms Pause, damit Impuls LOW
        
      } // Ende else 

            scount++;
            
            if(scount >=72)    // warten bis 20ms vergangen sind
            { 
            scount=0;
            warten++;

              if(warten==100)
              { 
              warten=0;
              s=0;
              }
            }
  } // Ende if
  return 0;
} // Ende funk

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.