Ansteuerung einer Schrittmotor-Achse mit Mikrocontrollern am Beispiel eines Arduino-Mega

Aus HSHL Mechatronik
Zur Navigation springen Zur Suche springen


Aufgabenstellung

Innerhalb dieses HSHL-Wikipedia Eintrags wird die Automatisierung einer Achse mit µC „Arduino Mega“ als Steuerungskonzept vorgestellt.

Autoren: Stefan, Hünemeier; Mario, Saake

Regelkreis

Als Regelkreis bezeichnet man ein Wirkungsgefüge, das aus einem Steuerungsprozess mit eingeschalteter Gegenkoppelung besteht.

In unserem Fall wird als Sollgröße ein zuvor definierter Weg vorgegeben, der innerhalb des Arduino-Programmes in digitale Signale übersetzt wird. Diese digitalen Signale bzw. Steps nutzt der Schrittmotorcontroller (Geckodrive G201X) um den Schrittmotor der Linearachse anzusteuern. Die rotatorische Bewegung des Antriebes wird mittels Inkrementalgeber erfasst und durch die Programmierung in absolute Distanzen umgerechnet, sodass diese Werte als Rückführgröße übergeben werden können. Die Regeldifferenz errechnet Abweichungen dieser Rückführgröße zum Sollwert, sodass ggf. der Arduino die Maßabweichung ausgleicht. Ziel ist es, dass die Regeldifferenz Null wird. Die folgende Abbildung visualisiert die beschriebenen Zusammenhänge.

Belegungsplan

Bei der Ansteuerung der Bauteile muss zwischen einem Last- und einem Steuerkreis unterschieden werden. Der Steuerkreis besteht aus einem µc Arduino Mega welcher den Motorcontroller Geckodrive G201X mit den Signalen „step“ für die Schrittanzahl und „direction“ für die Richtungsvorgabe der Bewegung ansteuert. Die Spannungsversorgung des Arduino Megas wird über USB bzw. ein Festspannungsnetzteil sichergestellt. Der Geckodrive wird durch eine externe Spannungsquelle versorgt. Diese Nennspannung von 24 Volt wird durch den Geckodrive derart geschaltet, sodass der Schrittmotor nach Steuervorgaben betrieben wird. Die Bremsvorrichtung des Schrittmotors wird präventiv als Sicherheitseinrichtung bei Spannungsverlust eingesetzt. Deshalb wird diese bei Betrieb der Linieareinheit mit Energie versorgt und damit gelöst bzw. entriegelt.

Aus sicherheitstechnischen Gründen müssen beidseitig je ein Endschalter verwendet werden. Die Endschalter registrieren das Erreichen des maximalen Hubweges des Motorschlittens und erzeugen ein Steuersignal welches den Motorschlitten zum Stillstand zwingt und einen definierten Weg in die entgegengesetzte Richtung fahren lässt. Der Pulldown-Widerstand wird dazu verwendet um den Eingang bei Nichtbeschaltung auf GND zu „ziehen“ um damit Störsignale zu unterbinden. Zur Sicherheit wird beidseitig je ein weiterer Endschalter benötigt, der am Motorcontroller direkt, durch Verbinden der Anschlusspins 7 und 12, die Spannungsversorgung des Motors zu unterbindet. Hierbei wird allerdings keine Rückmeldung an die Steuerung geliefert, allerdings ist die Stromversorgung sofort unterbrochen, falls die davor installierten Endschlater nicht auslösen.

Nachfolgend ist eine mögliche Beschaltung der unterschiedlichen Komponenten detailliert aufgeführt. Die Datei des Schaltplans liegt zur weiteren Bearbeitung der angefühten zip-Datei bei.

Software

Kompatibilitätsermittlung für den Betrieb mit Geckodrive G201 REV-6

Mittels Oszilloskop muss zunächst die Schrittweite des Ausgangssignals vom Ardunio analysiert werden. Mit Betracht auf den folgenden Auszug des Datenblattes vom Geckodrive, kann festgestellt werden, ob die angegebende Mindestperiodendauer von 3,5us (mit der Annahme, dass GND am Common-Terminal des Geckodrives angeschlossen ist) einhalten wird.

STEP AND DIRECTION INPUTS

TERMINAL 8: Direction Connect the DIRECTION line to this terminal.

TERMINAL 9: Step Connect the STEP line to this terminal.

TERMINAL 10: Common Connect the controller’s +3.3VDC, +5VDC or GND to this terminal.

These inputs are optically isolated from the rest of the drive. Terminal 10 is the common connection for the opto-isolators and must be connected to the +3.3VDC, +5VDC or GND of your indexer or pulse generator.

These inputs are meant to be driven by 3.3V to 5.5V logic capable of sourcing or sinking 2.5mA of current. The minimum logic “0” time is .5uS while the minimum logic “1” time is 3uS with 3.3V – 5V connected on the COMMON terminal. The minimum logic “0” time is 3uS while the minimum logic “1” time is 0.5uS when connected to GND on the COMMON terminal. Microstepping occurs on the falling edge of the step input when COMMON is a positive voltage and on the rising edge when COMMON is connected to GND and on the rising edge when connected to 3.3V – 5V.

Quelle: Datenblatt: Geckodrive Motor Controls, G201X / G210X User Manual, 2011, Tustin CA (USA)


Zusammenfassung: Eine Mindestperiodendauer von 3,5 µs wird durch die Festelegeung der Parameter im Programm eingehalten, was mit den oben gezeigten Abbildungen visualisiert wird.

Analyse der Vorwärts- und Rückwärtsbewegung des Hubschlittens

Die folgenden Abbildungen zeigen die Ermittlung des Vorwärts- Rückwärtssignals mittels Oszilloskop.

Zusammenfassung: Wird ein Directionsignal high am Arduino Mega ausgegeben, so verfährt der Hubschlitten in positive Richtung (vorwärts). Wird hingegen ein Directionsignal low am Arduino Mega ausgegeben, so verfährt der Hubschlitten in negative Richtung (rückwärts).

Quellcode für die Ansteuerung der x-Achse

Die in diesem Kapitel vorgestellten Quellcodes werden zur weiteren Bearbeitung mit der angefügten zip-Datei zur Verfügung gestellt. Es werden zunächst die Aspekte und der Umfang des Programmes aufgelistet und im Folgenden durch weiterführende Gedanken ergänzt.

Statusübersicht des Quellcodes für die Ansteuerung der x-Achse:

• Kommunikation des Arduino Mega mit dem seriellen Monitor (RS232-Kommuniaktion) zur Eingabe des Sollweges. Hierbei wird eine Umwandlung von ASCII-Code in Dezimal durchgeführt.

• Es wird bei einer Referenzposition gestartet, auf welche sich alle weiteren Sollwegangeben in Relation beziehen. Das heißt, dass weitere Sollwegeingaben Vielfache der ursprünglich eingegebenen Sollwegangabe sind.

Beispiel: Eine Eingabe des Sollweges von 50 mm zu Beginn der Dateneingabe verfährt den Hubschlitten 50 mm in positive Richtung. Diese Sollposition "merkt" sich die Programmierung. Bei einer weiteren Sollwegeingabe von z.B. 40 mm verfährt der Hubschlitten 10 mm zurück.

• Einbindung Endschalter in Programmablauf. Bei der Auslösung der Endschalter wird ein kurzer Weg in inverse Richtung verfahren. Innerhalb des Monitors wird eine entsprechende Fehlermeldung ausgegeben.


Weiterführende Gedanken:

• Einbindung eines Inkrementalgebers zur Überprüfung des Sollweges

• Einbindung festen Referenzpunktes bei Programmstart:

Vorschlag: Bei Programmstart wird solange in eine Richtung verfahren, bis z.B. eine Lichtschranke ausgelöst wird. Damit ist der Referenzpunkt erreicht, z.B. Koordinatenursprung Null. Hierdurch ist gleichzeitig ein begrenztes Intervall zur Sollwegeingabe geschaffen.


Anbei ist der gesamte Quellcode für die Ansteuerung eines Linearmotors mit dem Mikrocontroller Arduino mega abgebildet. Der Quellcode ist mit ausreichenden Kommentaren versehen, welche jeweilige Programmzeilen nachhaltig erläutern.

Angemerkt werden muss, dass die Bibliothek "Accelstepper" für die Arduino-Software vorinstalliert werden muss. Die Bibliothek liegt der zip-Datei dieses Artikels bei oder kann kostenfrei aus dem Internet geladen werden. Der Order „AccelStepper“ wird komplett in das Verzeichnis der Ardunino Software unter „libraries“ kopiert. Die Bibliothek kann nach Neustart der Software im Ardunio Programm genutzt werden.

Bibliothekseinbindung:

#include <AccelStepper.h> //vordefinierte Bibliothek

Parameter und Variablendefinition:

AccelStepper stepper(1,9,8);          // 1 = Treiberboard(definiert), Schritt, Richtung, (vorwärts fahren = 1, rückwärts fahren = 0 (über Directionsignal), autom. Umsetzung durch Bibliothek)

int EndschalterPinlinks = 22;         // Eingang 22 für Kontakt links
int EndschalterPinrechts = 23;        // Eingang 23 für Kontakt rechts
int sollweg = 0;                      // sollweg in mm
int zielweg = 0;
int Vorzeichen = 1;                   // wird bei der ASCII Umwandlung benötigt
double Schritt = 0.033;               // Verhältnis, um absolute Distanzen anzufahren 66/200 = 0,33 (Übersetzung = 66 mm/Umdrehung -> ZLW/-OD-1040Basic Datenblatt, 
                                      // 200 = Auflösung bei 1,8° Schrittwinkel, Gecko: Verhältnis 1 zu 10 --> 0,033
double Verfahr = 0;                   // Zuordnen des Verfahrweg --> Verfahr = Anzahl der Schritte für den gewünschten Weg
                                      

Initilaisierung:

void setup()
{
        Serial.begin(9600);                    // Port für serielle Kommunikation auf 9600 baud Rate Übertragungsgeschwindigkeit setzen  
        stepper.setAcceleration(24000000);     // Beschleunigung,Geschwindigkeit --> Frequenzänderung
        stepper.setCurrentPosition(0);         // Referenzposition = 0 setzen   
        pinMode(EndschalterPinlinks,  INPUT); 
        pinMode(EndschalterPinrechts, INPUT);    
        Serial.println("Initialisierung abgeschlossen");  
}

Hauptprogramm:

void loop()
{              
    if(Serial.available()>0)                           // Koordinaten einlesen 
        {
          char ascii = Serial.read();
          //Serial.println(ascii, DEC);
          
          if (ascii == '-')                            // feststellen, ob Minusvorzeichen gesetzt wurde
          {
            Vorzeichen = -1;
          }
          
          if(isDigit (ascii))                          // Prüfen, ob ASCII-Zeichen zw. 0 und 9 liegt (Dezimalzahlen 48 bis 57)
          {
           
            zielweg = (zielweg*10) + (ascii - '0');    // der ASCII Wert 48 entspricht der 0 (Synonym: 'ascii - 48') --> es wird aus dem ASCII Wert der Variablen ein Dezimalwert gebildet 
                                                       // die Multiplikation mit 10 erfolgt nach jeder zusätzlich eingegeben Zeichen in einer Zeile, um so auch mehrstellige Dezimalzahlen 
                                                       // darstellen zu können eine Zahleneingabe endet mit dem NewLine Befehl, dieser entspricht dem ASCII-Code '10'
          }
         
          else if(ascii == 10 ) //feststellen, ob Zahleneingabe komplett, d.h NewLine Befehl (ASCII=10)
          {
           zielweg = zielweg*Vorzeichen;               // Wert mit Vorzeichen multiplizieren
           Serial.print("Bekommener Wert: ");
           Serial.println(zielweg, DEC);
           sollweg = zielweg;
           zielweg = 0;
           Vorzeichen = 1;
          }
         }      
        
    if (digitalRead(EndschalterPinlinks) == LOW && digitalRead(EndschalterPinrechts) == LOW) // Sicherheitsabfrage
      {
        Verfahr = sollweg/Schritt;                     // Umrechnen des eingegebenen Koordinatenwertes in Anzahl von Schritten
        stepper.moveTo(Verfahr);                       // Festlegen des Weges
        Verfahren();                                   // Unterprogramm Verfahren() ausführen
      }
      
    else if(digitalRead(EndschalterPinlinks) == HIGH)  // wenn Schalter belegt - rückfahren
       { 
         Serial.println("Endschalter_links");
         stepper.move(500);
         int diff =  stepper.currentPosition() + 500;         
         while(stepper.currentPosition() != diff)
         {
           stepper.run();
         }
           sollweg = stepper.currentPosition()*Schritt;
       } 
         
    else if(digitalRead(EndschalterPinrechts) == HIGH) // wenn Schalter belegt - rückfahren
       { 
         Serial.println("Endschalter_rechts");
         stepper.move(-500); 
         int diff =  stepper.currentPosition() - 500;         
         while(stepper.currentPosition() != diff)
         {
           stepper.run();
         }          
           sollweg = stepper.currentPosition()*Schritt;        
       }        
}
   

Funktion "Verfahren"

void Verfahren() 
{
   if (stepper.currentPosition() != Verfahr )      // solange bis Position erreicht "run"
   {
       stepper.run();
   }                
   stepper.setSpeed(0);
   stepper.moveTo(stepper.currentPosition());     // Beschreiben der aktuellen Position  
}

Quellcode für die die Duplizierung auf alle Achsen

Statusübersicht des Quellcodes für die Duplizierung der Programmierung auf alle drei Achsen (Zusatzaufgabe):

Die Duplizierung des Programmes auf alle Achsen hat zunächst Priorität gegenüber der Einbindung eines Inkrementalgebers. Es damit soll ein Ansprechen der gesamten Maschine per Steuerungsalgortihmus zum Ardunio realisiert werden. Folgende erreichte Aspekte lassen sich festhalten:


• Die Programmierung ist im Stande, alle drei Achsen anzusprechen

• Das Programm ist im Stande per Steuerungsalgorithmus angesprochen zu werden

• Eine eindeutige Zeichenkette (z.B.: x2000y0000z0000e) muss dem Programm vorgegeben werden, um die Achsen anzusteuern


Weiterführende Gedanken:

• Die sich wiederholende Programmabschnitte können mit allgemeingültigen Funktionen umgesetzt werden --> Idee: Einbinden von Switch-Case Anweisungen


Programmablaufplan für die Ansteuerung von drei Achsen mit dem ArduinoMega

Das im Programm eingesetzte Vorgehen, zum Einlesen und Verarbeiten der Koordinaten, soll mit dem abgebildeten Ablaufdiagramm verdeutlicht werden:


Repräsentativ bilden wir die wesentlichen Abschnitte des Programms ab. Hierbei konzentrieren wir uns auf die Abschnitte für die x-Achse. Die Abschnitte für die y- und z-Achse sind identisch, mit der Ausnahme der Beschriftung mit y- und z sowie dem Abbruchkriterium mit dem Buchstaben e für die z-Achse.


Bibliothekseinbindung:

#include <AccelStepper.h>                // vordefinierte Bibliothek

Parameter und Variablendefinition:

AccelStepper stepperx(1,9,8);           // 1 = Treiberboard(definiert), Schritt, Richtung 
int EndschalterPinlinksx = 22;          // Eingang 22 für Kontakt links
int EndschalterPinrechtsx = 23;         // Eingang 23 für Kontakt rechts
int sollwegx = 0;                       // Sollweg in mm
int Vorzeichen = 1;                     // wird bei der ASCII Umwandlung benötigt
double Schritt = 0.033;                 // Verhältnis, um absolute Distanzen anzufahren 
                                        // 66/200 = 0,33 (Übersetzung = 66 mm/Umdrehung -> ZLW/-OD-1040Basic Datenblatt, 
                                        // 200 = Auflösung bei 1,8° Schrittwinkel)
                                        // Gecko: Verhältnis 1 zu 10 --> 0,033
double Verfahrx = 0;                    // Zuordnen des Verfahrweg --> Verfahr = Anzahl der Schritte für den gewünschten Weg
int status_x = 0;
char ascii;

Initilaisierung:

void setup()
{
        Serial.begin(9600);                    // Port für serielle Kommunikation auf 9600 baud Rate Übertragungsgeschwindigkeit setzen  
        stepperx.setAcceleration(24000000);    // Beschleunigung,Geschwindigkeit --> Frequenzänderung
        stepperx.setCurrentPosition(0);        // Referenzposition = 0 setzen  
        pinMode(EndschalterPinlinksx,  INPUT); 
        pinMode(EndschalterPinrechtsx, INPUT);  
        Serial.println("Initialisierung abgeschlossen");
        Serial.flush();
}

Hauptprogramm (Ausschnitt):

 void loop()
{  
  if(Serial.available() > 0)                       // Koordinaten einlesen 
        {
          ascii = Serial.read();
          
     
          if (ascii == 'x')                         // feststellen, ob x gesetzt wurde
          {
            status_x = 1;
            while (status_x == 1)  
             {
               status_x = UmrechnungplusBerechnung(); 
             }
          }           

          if (ascii == 'y')
          {
           Serial.print("Bekommener Wertx: ");
           Serial.println(zielweg, DEC);
           sollwegx = zielweg;
           zielweg = 0;    
          }

Weiterführender Hauptteil (Ausschnitt):

if (digitalRead(EndschalterPinlinksx) == LOW && digitalRead(EndschalterPinrechtsx) == LOW)     // Sicherheitsabfrage
      {
        Verfahrx = sollwegx/Schritt;                   // Umrechnen des eingegebenen Koordinatenwertes in Anzahl von Schritten
        stepperx.moveTo(Verfahrx);                     // Festlegen des Weges
        Verfahrenx();                                  // Unterprogramm Verfahren() ausführen
      }        
    else if(digitalRead(EndschalterPinlinksx) == HIGH)           // wenn Schalter belegt - rückfahren
       { 
         Serial.println("Endschalter_linksx");
         stepperx.move(500);
         int diff =  stepperx.currentPosition() + 500;         
         while(stepperx.currentPosition() != diff)
         {
           stepperx.run();
         }
           sollwegx = stepperx.currentPosition()*Schritt;
       } 
         
    else if(digitalRead(EndschalterPinrechtsx) == HIGH)           // wenn Schalter belegt - rückfahren
       { 
         Serial.println("Endschalter_rechtsx");
         stepperx.move(-500); 
         int diff =  stepperx.currentPosition() - 500;         
         while(stepperx.currentPosition() != diff)
         {
           stepperx.run();
         }          
           sollwegx = stepperx.currentPosition()*Schritt;        
       }

Funktion Verfahren():

void Verfahrenx() 
{
 if (stepperx.currentPosition() != Verfahrx ) //solange bis Position erreicht "run"
 {
   stepperx.run();
 }                
  stepperx.setSpeed(0);
  stepperx.moveTo(stepperx.currentPosition()); //Beschreiben der aktuellen Position       
}

Funktion Umrechnung plus Berechnung:

  int UmrechnungplusBerechnung()
{
     ascii = Serial.read();
     if(isDigit(ascii))           //Prüfen, ob ASCII-Zeichen zw. 0 und 9 liegt (Dezimalzahlen 48 bis 57)
          {                     
             zielweg = (zielweg*10) + (ascii - '0'); // Erklärung siehe Quelltext oben
             return 1;
          }
          else 
          {
               return 0;
          }
}


Zusammenfassung/Ausblick

Den einzelnen Teilkapiteln dieses Artikels sind die aktuellen Status der betrachteten und bearbeiteten Aspekte zu entnehmen. Insgesamt wurde es realisiert, Komponenten, deren Kompatibilität zueinander zunächst unbekannt war, miteinander kommunizieren zu lassen und mit diesen Komponenten schließlich das errichtete Bearbeitungsportal in Bewegung zu setzen. Das Ansprechen des Programmes über den, von einem anderen Team entwickelten Steuerungsalgorithmus, konnte ebenfalls umgesetzt werden. Die Einbindung weiterer Sensoren, wie z.B. die des Inkrementalgebers und einer Referenzpunktabfrage, stellen weiterführende Schritte des Projektes dar, welche zunächst aufgrund priorisierter Teilaufgabenergänzungen zurückgestellt wurden. Weiterführende Gedanken und Vorschläge sind bereits in den Teilkapiteln vorzufinden. Eine Weiterentwicklung des aktuellen Standes ist mit den bereitgestellten Dateien zu diesem Fachthema umsetzbar.

Anhang: Medium:Materialien_Ardunio.zip