-
        

Ergebnis 1 bis 10 von 10

Thema: Arduino Leistungsfähig genug? 6 Schrittmotoren + Inkrementalgeber

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    21.12.2009
    Beiträge
    8

    Arduino Leistungsfähig genug? 6 Schrittmotoren + Inkrementalgeber

    Anzeige

    Hallo,

    folgendes Problem beschäftigt mich zurzeit. Da ich selber noch recht wenig Erfahrung habe, hoffe ich dass einige von euch mir weiter helfen können.

    Ich Suche momentan einen Weg 6 Schrittmotoren sowie deren Inkrementalgeber zu steuern sowie auszulesen.
    Nun liegt das Problem in der Sache, dass ich die Inkrementalgeber gerne über Interrupts auslesen würde, um möglichst keine Schritte zu verpassen. Bei 6 Inkrementalgebern die jeweils ungefähr 7000 mal pro Sekunde ein Signal senden, kommt da einiges zusammen. Ist das direkt auf einem Arduino von der Geschwindigkeit realisierbar?
    Desweiteren bräuchte ich ja dann 6 Interrupt pins, allerdings habe ich da noch keinen Weg gefunden, da die Arduinos meistens ja 2 Interruptpins besitzten. Wenn jemand einen Link zu einem Shield hätte, der mir da weiterhilft wäre das echt super.
    Welches Arduino Board benutzt wird, steht noch offen, daher haben wir da noch freie Wahl

    Ansonsten sollte auf diesem Arduino noch 7 Servomotoren in einem vorher festgelegten Bewegungsablauf gesteuert werden, was ich über eine Maestro Karte realisieren werde.

    Die alternative Idee, sollte die Schrittmotorsteuerung nicht möglich sein, wäre diese durch Nanotec Treiber zu realisieren, die sich dann mittels RS485 Bus mit dem Arduino unterhalten. Dies wäre allerdings erheblich teurer mMn.

    Gruß,
    Sagre

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    1.892
    Bei den Arduinos sind meines Wissens AVR Controller verbaut.
    Einige, vor allem die neueren Typen unterstützen Pin Change Interrupts.
    Das bedeutet ein Interrupt wird ausgelöst, sobald sich ein Pegel an einem Pin der Gruppe ändert.
    Welcher das nun war müsstest Du in der Interruptroutine selber rausfinden.
    Ich fürche auch fast, das das ein ATMEGA auch nicht mehr schafft.
    Im Extremfall hast Du ja 7000 x 6 = 42000 Interrupts pro Sekunde.
    Auch wenn der Controller mit 20MHz läuft hast Du gerade mal 476 Maschinenzyklen ( Takte ) pro Interrupt.
    Das geht mit Assembler sicher noch, mit Bascom wird das wohl nichts mehr.
    Zusätzlich entstehen ja noch weitere Interrupts duch die Servoroutinen.

    Wenn dein Programm für den Interrupt fertig ist, kannst Du per Simulator erproben, wieviele Zyklen der Controller für die Abarbeitung der Interruptroutine braucht.

    Ob das mit den Servos noch geht oder nicht lässt sich vermutlich nur in der Praxis erproben.
    Du könntest ja zum Beispiel einen Port auf 1 setzen, sobald der Controller im Interrupt ist, verlässt der Controller den Interrupt kannst Du diesen Port wieder auf 0 setzen.
    Wenn Du dann ein Oszilloskop auf diesen Pin hängst siehst Du, ob der Controller noch Zyklen frei hat.

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    21.12.2009
    Beiträge
    8
    Hallo, danke dir erst einmal für deine Antwort.

    Ich werde mich ersteimal langsam herantasten, und erst einmal einen Sensor und einen Motor steuern. Leider bin ich sehr unerfahren was Mikokontroller anbegeht, und muss mich ersteinmal für jeden Begriff einlesen. Aber das wird schon

    Vermutlich meinst du mit den Interupts einen Pin Change interrupt? Dadrin werde ich mich aufjedenfall mal einlesen, scheint genau das zu sein was ich brauche
    Wir sind allerdings jetzt von einem Arduino weg, und versuchen uns gerade an einem Atmega32, der hier noch herumlag.

    Da ist bereits bei uns eine Frage aufgetaucht:

    Momentan versuchen wir erst einmal die USB-Kommunikation mit einem Rechner aufzubauen, um überhaupt rückmeldungen über die Sensor Daten zu erhalten. Das schicken von Nachrichten vom Atmega zum Rechner (hTerm) funktioniert schonmal super.
    Nur leider reagiert der Atmega rein gar nicht auf die Nachrichten des Rechners.
    Wir arbeiten mit der UART Library von PeterFleury. Kann uns da evt jemand weiterhelfen?

    char UART_RECIEVE(void) {
    unsigned int x;
    for(; {
    x= uart_getc();
    if(!(x&UART_NO_DATA)) return (char)x;
    }
    }


    in der main sieht es dann so (im Ausschnitt) so aus:

    int main() {
    while(1){
    char c = UART_RECIEVE();
    uart_puts(c);
    sleep(1000);
    }

  4. #4
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    7.551
    ... meinst du mit den Interupts einen Pin Change interrupt? ... mal einlesen ... Atmega32, der hier noch herumlag ...
    Nur mal so als Anmerkung: gerade der ATmega32/ATmega32L hat keinen Pin Change Interrupt, siehe das (vermutlich aktuellste) Datenblatt 2503Q–AVR–02/11. Hier wird der pinkompatible mega1284 Deinen Vorstellungen eher entsprechen, drei externe Interrupts und vier Pingruppen ready for PCI - somit theoretisch sieben (externe, pinbezogene) Interrupts. Selbst beim Übertakten der maximal spezifizierten 20 MHz wirst Du aber feststellen müssen, dass wkrug mit seiner Abschätzung ziemlich gut liegt.

    ... Wenn dein Programm für den Interrupt fertig ... wieviele Zyklen ... für die Abarbeitung der Interruptroutine ...
    Die Zyklenzahl kannst Du aus der deincompilat.lls herauslesen. Da drin stehts nämlich haarklein. Ein Beispiel dazu hier.
    Ciao sagt der JoeamBerg

  5. #5
    Erfahrener Benutzer Roboter Genie Avatar von malthy
    Registriert seit
    19.04.2004
    Ort
    Oldenburg
    Beiträge
    1.379
    Hi!

    Vermutlich geben die Inkrementalgeber ein Quadratursignal aus. Es ist im Allgemeinen nicht die beste Lösung, dieses per ext. Interrupts (INTx/PCINT) auzuwerten (siehe: http://www.mikrocontroller.net/articles/Drehgeber). Unter gewissen Randbedingungen (insb. Encocder prellt nicht, weil magnetischer Encoder) mag das dennoch eine Variante sein. Grundsätzlich sollte man die Encodersignale besser per Timerinterrupt mit festem Intervall abtasten und auswerten. Dann müsstest Du pro Timer-ISR Aufruf dann eben alle Encoder auswerten. Die Auswertung ist nicht sonderlich rechenintensiv. Wenn Du Dir sicher bist dass die 7k Ticks/s reichen, sollte das grundsätzlich mit einem AVR zu machen sein. Ob das High-Level mit dieser Arduino Sprache hinhaut, kann ich nicht beurteilen, damit kenne ich mich nicht aus. Das wäre ansonsten ein klassischer Fall für Assembler. Zum Festlegen der Abtastrate solltest Du brücksichtigen, dass das Quadratursignal in den seltensten Fällen wirklich symmetrisch ist, zur Sicherheit könnte man größenordnungsmäßig mit Faktor zwei Abtasten.

    Gruß
    Malte
    Geändert von malthy (10.09.2014 um 13:50 Uhr) Grund: typos

  6. #6
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    15.12.2008
    Ort
    Bad Ems
    Alter
    55
    Beiträge
    109
    Hallo,

    ich muss malthy Recht geben. Die Auswertung per Pin-Change-Interrupt ist nicht zu empfehlen. Für Dein Problem solltest Du den oder die Encoder im Timer-Interrupt mit einer festen Frequenz abfragen. Mir ist allerdings nicht ganz klar, ob Du jetzt nur einen AVR-Controller oder aber wirklich einen Arduino benutzt. Falls Du den Arduino nimmst, könntest Du einmal hier nachlesen: http://www.meinduino.de/drehencoder.shtml. Da ist in Teil I die Auswertung per Polling und in Teil II die Auswertung des Encoders im Timer-Interrupt beschrieben. Vielleicht gelingt es Dir, den Sketch im II. Teil an Deine Bedürfnisse anzupassen.

    Gruß,
    Ralf
    Geändert von Schachmann (10.09.2014 um 23:43 Uhr) Grund: Tippfehler
    http://www.Elektronik-Bastelkeller.de - Elektronik und Mikrocontroller als Hobby

  7. #7
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    7.551
    ... Vermutlich geben die Inkrementalgeber ein Quadratursignal ... im Allgemeinen nicht die beste Lösung, dieses per ext. Interrupts ... auzuwerten ...
    Die Frage ist ja, ob es Sinn macht das komplette Quadratursignal (wenn es eins ist) auszuwerten.

    ......

    Warum? Weil ich einigermassen sicher bin, dass der Versatz der Signalflanken nicht genau gleich ist (so lange ich den Encoder nicht selbst hergestellt oder ausführlich getestet habe). Dann kommt eine Ungenauigkeit rein, die sich bei hohen Drehzahlen - und den damit verbundenen wenigen Timerticks schon wesentlich auf die Regelung auswirken kann. Hier wäre zu überlegen, ob man nicht (nur) jede gleichsinnige Flanke einer Encoderspur auswertet. Wenns nicht gerade eine hochgenaue Drehzahlregelung für etliche zehntausend Touren sein soll dürfte das reichen und möglicherweise eine genauere Regelungsgrundlage liefern als die Auswertung aller Flanken.

    Die Lösung mit dem externen Interrupt ist nicht die schlechteste. Ich fahre bei meinem Dottie, beim MiniD0 und beim Archie, alles aber KEINE Schrittmotoren, mit dem externen Interrupt für steigende Flanke (beim Archie nur für EINE Endoderspur - je Motor *gg*) und werte in der zugehörigen ISR natürlich auch gleich die zweite Spur zur korrekten Wegberechnung (Drehrichtungserkennung) aus. Der Erfolg ist eine überraschend hohe Geschwindigkeitstreue. Ob Schrittmotoren in dieser Hinsicht empfindlicher sind, kann ich aber nicht sagen.

    ... Inkrementalgeber gerne über Interrupts auslesen würde, um möglichst keine Schritte zu verpassen ...
    Wenns nicht um genaue Drehzahlregelung geht, sondern nur um exakte Wegerfassung (Drehwinkel), dann sehe ich das CPU-Laufzeitproblem nicht so gravierend, weil es nur wenige Codezeilen sind:

    Die vollständige ISR für (m)einen Encoder bei Archie (der zugehörige *lls-Auszug ist gaaaanz unten) :
    Code:
    // ============================================================================= =
    // ===  Nicht unterbrechbare ISR für EXT_INT0 auf Pin 4/PD2/mega328
    // Der Timer tmrE0 für Laufzeit des EXT_INT0 wird ausgelesen
    //      Der zugehörige Motor auf PD7/PB0 = re,li und PB1 Geschwind./PWM
     ISR(INT0_vect)                 // INT0 triggert auf RISING edge => 
     {                              //   => Wenn Aufruf, dann PORTD2 = high
    // - - - - - - - - - - - - - - - -
    //      Encoderticks Iencdrx nur hochzählen, IencBx rauf- od runterzählen
      Iz_diff0  = tmrE0;    // Abspeichern Zeit seit dem letzten ISR-Aufruf
      tmrE0     =    0;     // Resetten ##>> IN der ISR ohne CLI/SEI möglich
      Iencdr0 ++;           // Incrementiere Encodercounter, zählt NUR aufwärts
      if (IsBitSet (PIND, 4)) IencB0++;     // Rad treibt vorwärts,  math. negativ
      else                    IencB0--;     // Rad treibt rückwärts, math. positiv
     }      // Ende ISR(INT0_vect)
    // ============================================================================= =
    In der Timer-ISR - 20 kHz <=> 50 µs - wird der Zeitwert tmrE0 getickert:
    Code:
    // ===  Nicht unterbrechbare ISR für timer2 =================================== */
    // Routine zählt hoch im Takt 20 kHz = 50 µs.  Der Zählerwert wird von den ISR für
    //      EXT_INT0 und -INT1 ausgelesen
     ISR(TIMER2_COMPA_vect)         // 
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     {                              //
      Izeit_1 --;           //  ###>>> Izeit_1 ist aktuell int16_t ==>>
                            //  Izeit_1 bleibt bis 32000 in der int16-Grenze
      tupUM0 ++;            // Tupsicounter für Umdrehungsmessung(en)
      tmrE0   ++;           // Encodertimer hochtickern
      tmrE1   ++;           // Encodertimer hochtickern
    //RCzeit1 ++;           // Tupsicounter uint16_t für RC-5-Decoding
    
      if ( Izeit_1 )        // Interrupt-Timer = 1 ... 20 000 ... (1 sec blink)
        {  }                // WENN Izeit_1 =|= Null => wahr => Anweisung ausgeführen
      else                  // Izeit_1 = Null = unwahr, daher "else" ausführen
      {                     // Eine Sekunde ist voll =>
        Izeit_1 = Izthrznt; // ansonsten: Rückstellen auf Zeithorizont
        ToggleBit (PgLED, L1g);     // gnLED toggeln    HEARTBEAT <<####, aktuell PC1
        Isecundn ++;                // Sekundenzähler hochtackern, max 9 Std
      }             // Ende if (Izeit_1 )
    
      if (tmrE0 > 2000)     // Grenzwert für Stillstand
    // ... usf
    Der *lls-teil zur Encoder-ISR:
    Code:
    // ============================================================================= =
    // ===  Nicht unterbrechbare ISR für EXT_INT0 auf Pin 4/PD2/mega328
    // Der Timer tmrE0 für Laufzeit des EXT_INT0 wird ausgelesen
    //      Der zugehörige Motor auf PD7/PB0 = re,li und PB1 Geschwind./PWM
     ISR(INT0_vect)                 // INT0 triggert auf RISING edge => 
     {                              //   => Wenn Aufruf, dann PORTD2 = high
         8d4:    1f 92           push    r1
         8d6:    0f 92           push    r0
         8d8:    0f b6           in    r0, 0x3f    ; 63
         8da:    0f 92           push    r0
         8dc:    11 24           eor    r1, r1
         8de:    8f 93           push    r24
         8e0:    9f 93           push    r25
    // - - - - - - - - - - - - - - - -
    //      Encoderticks Iencdrx nur hochzählen, IencBx rauf- od runterzählen
      Iz_diff0  = tmrE0;    // Abspeichern Zeit seit dem letzten ISR-Aufruf
         8e2:    80 91 2f 07     lds    r24, 0x072F
         8e6:    90 91 30 07     lds    r25, 0x0730
         8ea:    90 93 0f 07     sts    0x070F, r25
         8ee:    80 93 0e 07     sts    0x070E, r24
      tmrE0     =    0;     // Resetten ##>> IN der ISR ohne CLI/SEI möglich
         8f2:    10 92 30 07     sts    0x0730, r1
         8f6:    10 92 2f 07     sts    0x072F, r1
      Iencdr0 ++;           // Incrementiere Encodercounter, zählt NUR aufwärts
         8fa:    80 91 0a 06     lds    r24, 0x060A
         8fe:    90 91 0b 06     lds    r25, 0x060B
         902:    01 96           adiw    r24, 0x01    ; 1
         904:    90 93 0b 06     sts    0x060B, r25
         908:    80 93 0a 06     sts    0x060A, r24
      if (IsBitSet (PIND, 4)) IencB0++;     // Rad treibt vorwärts,  math. negativ
         90c:    4c 9b           sbis    0x09, 4    ; 9
         90e:    06 c0           rjmp    .+12         ; 0x91c <__stack+0x1d>
         910:    80 91 48 06     lds    r24, 0x0648
         914:    90 91 49 06     lds    r25, 0x0649
         918:    01 96           adiw    r24, 0x01    ; 1
         91a:    05 c0           rjmp    .+10         ; 0x926 <__stack+0x27>
      else                    IencB0--;     // Rad treibt rückwärts, math. positiv
         91c:    80 91 48 06     lds    r24, 0x0648
         920:    90 91 49 06     lds    r25, 0x0649
         924:    01 97           sbiw    r24, 0x01    ; 1
         926:    90 93 49 06     sts    0x0649, r25
         92a:    80 93 48 06     sts    0x0648, r24
     }      // Ende ISR(INT0_vect)
         92e:    9f 91           pop    r25
         930:    8f 91           pop    r24
         932:    0f 90           pop    r0
         934:    0f be           out    0x3f, r0    ; 63
         936:    0f 90           pop    r0
         938:    1f 90           pop    r1
         93a:    18 95           reti
    ... das sind schlappe vierzig Maschinenzyklen für einen Encoder.
    Ciao sagt der JoeamBerg

  8. #8
    Erfahrener Benutzer Roboter Genie Avatar von malthy
    Registriert seit
    19.04.2004
    Ort
    Oldenburg
    Beiträge
    1.379
    Hi!

    Ich zitiere aus dem verlinkten µC.net Artikel (http://www.mikrocontroller.net/articles/Drehgeber):

    Warum Sparvarianten nicht gut sind

    Oft sieht man im Netz "clevere" Sparvarianten, welche angeblich ebensogut zur Auswertung von Drehgebern geeignet sind. Ein genaueres Hinschauen sowie Tests unter realen Bedingungen zeigen jedoch schnell die Schwächen dieser Ansätze.

    Flankenerkennung von A und Pegelauswertung von B


    Viele Sparvarianten verwenden einen externen Interrupt, welcher auf die steigende oder fallende Flanke von Spur A auslöst und dann den Pegel von B auswertet. Ist B=0, dann dreht der Encoder nach rechts, anderenfalls nach links. Diese Auswertung hat zwei Schwachstellen.


    1. Die Auflösung wird auf ein Viertel reduziert, weil nur jede steigende Flanke von A ausgewertet wird.
    2. Pendelt der Encoder zwischen zwei Codes, bei denen A seinen Pegel wechselt,
      1. kommt es zu (sehr) vielen Interrupts, die den Mikrocontroller vollkommen auslasten können.
      2. interpretiert die Auswertung jede steigende Flanke als neuen Schritt. Der Encoder scheint sich für die Auswertung immer weiter zu drehen (wenn man nicht prüft, ob auch B den Pegel ändert), obwohl er nur pendelt.


    Das Pendeln kann zwei Ursachen haben.

    1. Der Encoder pendelt wirklich; das kann z. B. bei hochauflösenden Encodern ohne Rastung geschehen, welche an jeder beliebigen Stelle stehen bleiben können und durch geringe mechanische Erschütterungen dann zwischen zwei Codes pendeln; das kann z. B. bei hochauflösenden Encodern in CNC-Maschinen der Fall sein.
    2. Die Signale prellen; das kommt vor allem bei billigen elektromechanischen Drehknöpfen vor, welche einfache Schleifkontakte zur Kodierung nutzen.

    Wie man sieht ist diese Methode nicht geeignet, einen Drehgeber solide zu dekodieren.

    Auswertung mit Interrupt durch Pegelwechsel


    Es wird bisweilen die Auffassung vertreten, dass mit Hilfe von sog. Pin Change Interrupts Rechenzeit gespart werden kann. Dabei wird bei einem Pegelwechsel von Spur A oder B ein Interrupt erzeugt. Dort werden dann A und B eingelesen und vollständig ausgewertet. Diese Methode ist besser, aber nicht gut genug. Sie vermeidet Fehler 1. und 2.2 der oben genannten Auswertung, aber nicht 2.1, da auch sie durch einen pendelnden/prellenden Encoder die CPU stark belastet.
    Das deckt sich so mit meiner persönlichen Erfahrung. Darauf, dass man in diesem Falle auch schon relativ nah an ein Performance-Problem mit der ext. Interrupt Methode (PCINT) kommen kann, wurde ja schon hingewiesen. Das Problem hat man ziemlich sicher nicht, wenn man mit einem festen Intervall abtastet und auswertet.

    Gruß
    Malte
    Geändert von malthy (12.09.2014 um 13:08 Uhr)

  9. #9
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    7.551
    ... Ich zitiere aus dem verlinkten µC.net Artikel (http://www.mikrocontroller.net/articles/Drehgeber): ... Das deckt sich so ...
    Au, Malte. Da hast Du mich aber fein aus meiner laufenden Arbeit abgelenkt und - eigentlich wollte ich meine Auswertemethode beibehalten. Habe mal kurz in diesem m-net-Artikel gelesen. Die Auswertung auf Basis eines Zeitrasters kam mir u.A. deswegen suboptimal vor, weil z.B. ein Drehrichtungswechsel erst am Rasterende erkannt wird - andererseits ist die Stillstandserkennung mitunter . . . egal, ich sah Gründe für und wider.

    Nun ist Peter Dannegger nach meiner bescheidenen Erfahrung mit allen Datenblättern - ähhhh - Wassern gewaschen. Und diesen Artikel kannte ich bisher nicht. Ich geh mal bald drüber.

    Danke für den Hinweis auf den Artikel.
    Ciao sagt der JoeamBerg

  10. #10
    Zitat Zitat von Schachmann Beitrag anzeigen
    http://www.meinduino.de/drehencoder.shtml. Da ist in Teil I die Auswertung per Polling und in Teil II die Auswertung des Encoders im Timer-Interrupt beschrieben. Vielleicht gelingt es Dir, den Sketch im II. Teil an Deine Bedürfnisse anzupassen.

    Hallo, leider kommt es immer wieder vor, das gute Seiten nicht mehr betrieben werden bzw. völlig verschwinden, so wie bei der oben genannten.
    Vielleicht habe ich das unverschämte Glück, das diese Seite bzw. der Artikel archiviert wurde und zur Verfügung gestellt werden kann.
    Ich weiß, ist schon eine ganze Weile her, aber die Hoffnung stirbt ja zuletzt.......

    Gruß Frank

Ähnliche Themen

  1. Schrittmotoren + Arduino Motorshield
    Von horschl im Forum Suche bestimmtes Bauteil bzw. Empfehlung
    Antworten: 0
    Letzter Beitrag: 28.05.2014, 12:44
  2. Inkrementalgeber
    Von baensch im Forum Suche bestimmtes Bauteil bzw. Empfehlung
    Antworten: 2
    Letzter Beitrag: 16.07.2009, 17:37
  3. Inkrementalgeber
    Von bartolomeos im Forum Sensoren / Sensorik
    Antworten: 9
    Letzter Beitrag: 09.11.2005, 20:16
  4. inkrementalgeber
    Von curmet im Forum Sensoren / Sensorik
    Antworten: 8
    Letzter Beitrag: 17.06.2005, 22:11
  5. [ERLEDIGT] Inkrementalgeber
    Von demerzel im Forum Motoren
    Antworten: 2
    Letzter Beitrag: 25.06.2004, 21:53

Berechtigungen

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