-         

Seite 1 von 3 123 LetzteLetzte
Ergebnis 1 bis 10 von 30

Thema: 8 Servos mit dem Atmega32 steuern

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied Avatar von High Light
    Registriert seit
    21.08.2009
    Ort
    Baden Württemberg
    Beiträge
    142

    8 Servos mit dem Atmega32 steuern

    Anzeige

    Hallo zusammen,

    seit ein paar Wochen versuche ich mit einem Atmega32 8 Servos anzusteuern, jedoch kamen einige Probleme auf mich zu.
    Ich denke, dass ich alle Hardware-Fehler beseitigt habe, jedoch funktioniert noch nichts.

    Zur Ansteuerung der Servomotoren wollte ich mich am Quellcode von der Seite
    http://www.mikrocontroller.net/artic...vo_Ansteuerung
    orientieren.

    Ich habe alle Einstellungen mit dem Datenblatt des Atmega 32 verglichen und konnte keine Fehler oder Änderungen feststellen.
    Des Weiteren arbeite ich mit 16MHz, nicht mit 11Mhz wie im Beispiel. Dies habe ich im Quellcode geändert.
    Alle 8 Servomotoren sollen am PortC angeschlossen werden.

    Code:
    //
    // Programm fuer einen ATmega32
    //
    #define F_CPU 16000000UL
     
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
     
    //
    // Der Prescaler muss so gewählt werden, dass der Ausdruck
    // für MILLISEC_BASE einen Wert kleiner als 128 ergibt
    // MILLISEC_BASE ist der Timerwert, der 1 Millisekunde Zeitdauer ergeben
    // soll.
    //
    #define PRESCALER      128
    #define PRESCALER_BITS (1<<CS22) | ( 1 << CS20 )
     
    #define MILLISEC_BASE  ( F_CPU / PRESCALER / 1000 )
    #define CENTER         ( MILLISEC_BASE /2 ) 
     
    //
    // Konfiguration der Servoleitungen
    //
    #define NR_SERVOS      8
    #define SERVO_DDR      DDRC
    #define SERVO_PORT     PORTC
    uint8_t ServoPuls[NR_SERVOS] = { 1<<PC0, 1<<PC1, 1<<PC2, 1<<PC3,
                                     1<<PC4, 1<<PC5, 1<<PC6, 1<<PC7 };
    //
    // Werte für die Servoposition
    // Gültige Werte laufen von 0 bis 2 * CENTER
    // 0           ... ganz links
    // CENTER      ... Mittelstellung
    // 2 * CENTER  ... ganz rechts
    //
    volatile uint16_t ServoValue[NR_SERVOS];
     
    ISR (TIMER2_COMP_vect) 
    {
      static uint8_t ServoId = 0;
     
      //
      // den Puls des aktuellen Servos beenden
      //
      SERVO_PORT &= ~ServoPuls[ServoId];
     
      //
      // welches ist das nächste aktuelle Servo?
      //
      if( ++ServoId >= NR_SERVOS )
        ServoId = 0;
     
      //
      // die Ausgangsleitung fuer dieses Servo auf 1; den Puls beginnen
      //
      SERVO_PORT |= ServoPuls[ServoId];
     
      //
      // den Timer so einstellen, dass bei Pulsende, die ISR erneut aufgerufen wird
      //
      OCR2 = MILLISEC_BASE + ServoValue[ServoId];
    }
     
    void InitServo()
    {
      uint8_t i;
     
      //
      // Die Servoleitungen auf Ausgang stellen
      //
      SERVO_DDR = ServoPuls[0] | ServoPuls[1] | ServoPuls[2] | ServoPuls[3] |
                  ServoPuls[4] | ServoPuls[5] | ServoPuls[6] | ServoPuls[7];
     
      //
      // Alle Servos in Mittelstellung
      //
      for( i = 0; i < NR_SERVOS; ++i )
        ServoValue[i] = CENTER;
     
      //
      // Timer auf CTC Modus konfigurieren
      //
      OCR2 = MILLISEC_BASE + ServoValue[0];
      TIMSK |= (1<<OCIE2);
      TCCR2 = (1<<WGM21) | PRESCALER_BITS;  // CTC mode
    }
     
    int main(void)
    {
      InitServo();
     
      sei();
     
      _delay_ms( 1000 );
     
      //
      // testweise einfach alle 8 Servos ansteuern
      // jedes Servo soll sich unterschiedlich schnell bewegen
      //
      while( 1 ) {
         
        ServoValue[0] += 2;
        if( ServoValue[0] > 2*CENTER )
          ServoValue[0] -= 2*CENTER;
     
        ServoValue[1] += 1;
        if( ServoValue[1] > 2*CENTER )
          ServoValue[1] -= 2*CENTER;
     
        ServoValue[2] += 2;
        if( ServoValue[2] > 2*CENTER )
          ServoValue[2] -= 2*CENTER;
     
        ServoValue[3] += 3;
        if( ServoValue[3] > 2*CENTER )
          ServoValue[3] -= 2*CENTER;
     
        ServoValue[4] += 1;
        if( ServoValue[4] > 2*CENTER )
          ServoValue[4] -= 2*CENTER;
     
        ServoValue[5] += 3;
        if( ServoValue[5] > 2*CENTER )
          ServoValue[5] -= 2*CENTER;
     
        ServoValue[6] += 2;
        if( ServoValue[6] > 2*CENTER )
          ServoValue[6] -= 2*CENTER;
     
        ServoValue[7] += 1;
        if( ServoValue[7] > 2*CENTER )
          ServoValue[7] -= 2*CENTER;
     
        _delay_ms( 400 );
      }
    }
    Kann mir jemand meine Fehler aufzeigen? Bzw. mir einen Tipp geben?

    Grüße High Light
    __________________________________________________ _____________
    http://pe-products.jimdo.com/

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied Avatar von High Light
    Registriert seit
    21.08.2009
    Ort
    Baden Württemberg
    Beiträge
    142
    Oder soll ich die Ansteuerung der Servos ganz anders machen?
    Wie steuert ihr mehrere Servos mit einem Atmega an?
    __________________________________________________ _____________
    http://pe-products.jimdo.com/

  3. #3
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    7.554
    ... Wie steuert ihr mehrere Servos mit einem Atmega an?
    Für (m)einen Roboterkopf habe ich zehn Servos anzusteuern (zum Video runterscrollen). Die Eigenbauplatine bedient die Servos mit besser als 10 Bit Auflösung bei einer Servoperiode von rund 25 ms; es läuft darauf ein mega1284 mit 20 MHz. Mit knapp weniger als 20 ms könnten es dann immer noch acht Servos sein. Das Prinzip ist theoretisch in der Lage auch doppelt so viel Servos anzusteuern. Die Geschichte müsste in ähnlicher Weise auch mit nem mega32 gehen. Da der nur 16 MHz macht (oder?) muss man eben die Anzahl der bedienten Servos entsprechend niedriger ansetzen. Vermutlich sechs bei 20 ms Periodendauer und knapp acht (*gg*) bei 25 ms.

    Das Timingprinzip ist hier in einem Codeauszug gezeigt: ein Timer mit einer Periodendauer von 2,5 ms startet jeweils einen umlaufend adressierten Servopuls (den Pin auf high) und einen zweiten Timer(kanal) dessen Laufzeit OCR1B den entsprechenden Servopin wieder zurücksetzt. Aus den zehn Perioden wird dann die Gesamtperiode für einen der zehn Servos. Servos die nicht adressiert werden laufen dann leer mit. Die Lösung ist also auch für nur einen oder zwei Servos geeignet, dann laufen die restlichen Teilperioden einfach leer.
    Ciao sagt der JoeamBerg

  4. #4
    Neuer Benutzer Öfters hier
    Registriert seit
    18.05.2013
    Beiträge
    18
    Zitat Zitat von High Light Beitrag anzeigen
    Oder soll ich die Ansteuerung der Servos ganz anders machen?
    Wie steuert ihr mehrere Servos mit einem Atmega an?
    Vom Prinzip her schaut die Ansteuerung bei mir gleich aus wie bei dir. Also 1 timer im CTC Modus. Deine Werte sollten auch passen wenn ich sie mit meinen vergleiche. (ATmega8 @16MHz)
    Tut sich gar nix?

    EDIT: Du verwendest keinen Synchronisationszyklus. Am Anfang hast du eine Periode von nur knapp 8ms. Vielleicht ist das für die Servos schon zu wenig.
    Geändert von Siad (16.04.2014 um 08:08 Uhr)

  5. #5
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    7.554
    ... Ich denke, dass ich alle Hardware-Fehler beseitigt habe, jedoch funktioniert noch nichts ...
    Sorry, hab ich erst gerade jetzt gelesen. Dieser Satz, aber "dachte" - tempus perfectum, nicht praesens, wird häufig vor längeren Fehlersuchodysseen gesagt. So wie viele Unfallberichte beginnen mit "Nach Meinung aller Fachleute waren alle denkbaren Sicherheitsmaßnahmen getroffen worden ...".

    WAS hast Du alles getan? GND von allen Baugruppen verbunden (siehe SchaltSCHEMA) - im Link mal runterscrollen. GND eher sternförmig, keine Ringschleife? Separate Servoversorgung, getrennt vom Controller, aber GND!! verbunden, welche Servos, ausreichend Energie für die Servos - manche ziehen im Stillstand satte zig MilliAmpere - PRO Stück, usf. ??? Zum Code, der ja wohl ähnlich angesetzt ist wie meiner, wäre ja auch ein Schaltbild hilfreich - wenn wir dann alle sicher sind, dass das Schaltbild den ISTzustand genau trifft *gg*.
    Ciao sagt der JoeamBerg

  6. #6
    Erfahrener Benutzer Fleißiges Mitglied Avatar von High Light
    Registriert seit
    21.08.2009
    Ort
    Baden Württemberg
    Beiträge
    142
    Danke, für die Antworten.

    In der Tat waren ein paar kleine Fehler auf der Platine, jedoch war das größte Problem, eine defekte Platine zur Programmierung...

    Wenn ich heute Abend daheim bin, werde ich einen Schaltplan posten.
    Getrennte Spannungsquellen und gemeinsame Masse ist umgesetzt.
    Ich vermute, dass es an den Einstellungen des Timers 2 liegt....
    __________________________________________________ _____________
    http://pe-products.jimdo.com/

  7. #7
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    7.554
    Code:
    #define F_CPU 16000000UL
    ...
    // für MILLISEC_BASE einen Wert kleiner als 128 ergibt
    // MILLISEC_BASE ist der Timerwert, der 1 Millisekunde Zeitdauer ergeben
    // soll.
    //
    #define PRESCALER      128
    #define PRESCALER_BITS (1<<CS22) | ( 1 << CS20 )
     
    #define MILLISEC_BASE  ( F_CPU / PRESCALER / 1000 )
    #define CENTER         ( MILLISEC_BASE /2 ) 
    ...
    Also ich rechne mal (und denk dabei nicht weiter nach):
    ( F_CPU / PRESCALER / 1000 )
    16 000 000 [Hz] / 128 / 1000 = 125 [Hz]
    1 ms sind - mal locker gesagt: ... 1000 Hz

    Irre ich mich ??? (Hab grad den Kopf voll mit ungelösten Themen)
    Ciao sagt der JoeamBerg

  8. #8
    Neuer Benutzer Öfters hier
    Registriert seit
    18.05.2013
    Beiträge
    18
    Die 1000Hz sind ja der zweite Divisor bei 16 000 000[Hz] / 128 / 1000 [Hz] = 125.
    Die 125 sind der Wert für OCR2 um auf 1ms zukommen. 16 000 000[Hz] / 128 / 125 = 1000 [Hz].

  9. #9
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    7.554
    ... Die 125 sind der Wert für OCR2 um auf 1ms zukommen ...
    Hast Recht, siad - ich muss mir das aber noch genauer durchsehen. Pingelig: ich denke dass die theoretische Mitte bei OCR2 124 ist (das sind dann 125 Schritte ab 0). Ich muss mir das Ganze mal in Ruhe durcharbeiten, denn nu kann doch OCR2 nicht mehr kleiner als 125 werden in OCR2 = MILLISEC_BASE + ServoValue[ServoId]; wegen uint16_t ServoValue[NR_SERVOS]. Also mehr bis später.
    Ciao sagt der JoeamBerg

  10. #10
    Erfahrener Benutzer Roboter Genie Avatar von BMS
    Registriert seit
    21.06.2006
    Ort
    TT,KA
    Alter
    26
    Beiträge
    1.192
    Hallo,
    wurde auch die JTAGen-Fuse deaktiviert? Sonst gehen am PORTC beim ATmega32 einige Pins nicht richtig (PC2 bis 5).
    Grüße, Bernhard
    "Im Leben geht es nicht darum, gute Karten zu haben, sondern auch mit einem schlechten Blatt gut zu spielen." R.L. Stevenson

Seite 1 von 3 123 LetzteLetzte

Ähnliche Themen

  1. Servos mit PC steuern
    Von Surebetter im Forum Suche bestimmtes Bauteil bzw. Empfehlung
    Antworten: 6
    Letzter Beitrag: 25.04.2010, 15:11
  2. Wie kann ich mit dem CCPR5 Servos steuern ?
    Von Morten im Forum Robby CCRP5
    Antworten: 3
    Letzter Beitrag: 03.05.2009, 14:42
  3. Servos mit ATmega32
    Von murdocg im Forum Vorstellung+Bilder+Ideen zu geplanten eigenen Projekten/Bots
    Antworten: 7
    Letzter Beitrag: 17.10.2008, 07:48
  4. 12 Servos mit PIC steuern
    Von m0 im Forum PIC Controller
    Antworten: 13
    Letzter Beitrag: 18.03.2005, 23:11
  5. Servos mit SD20 steuern
    Von Sebastian im Forum Sensoren / Sensorik
    Antworten: 16
    Letzter Beitrag: 04.12.2003, 15:12

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •