Linearbewegung - bestimmte Positionen anfahren

Einen schönen guten Morgen/Mittag/Abend zusammen,

Ich bin neu hier und auch neu im Arduino Universum. Daher also zu Beginn schon mal sorry, wenn ich dumme Fragen stellen sollte.

Ich möchte gerne einen Stepper Motor nutzen, um eine Linearbewegung umzusetzen. Das erste Ziel wäre das Anfahren einer beliebigen Position, nachdem man die Gewünschte Länge eingegeben hat.

Bei mir auf der Arbeit gibt es eine Kreissäge, die mit einer automatischen Längenverstellung ausgestattet werden soll. Links von der Säge gibt es bereits einen Schlitten mit einer Aufnahme, die manuell verstellt werden kann. Der Bediener soll also in Zukunft über einen kleinen Display eine Länge eingeben und der Schlitten in die gewünschte Position fahren.

Ich habe bereits einen Motor einen Driver einen Arduino UNO R3 ein, ein Netzteil und eine Spindel gekauft.

Nach langem hin und her habe ich es bereits geschafft (dank YouTube) den Motor, Netzteil und Driver anzuschließen. Mit einem Code aus dem Internet war ich auch in der Lage den Motor anzusteuern. Aktuell dreht er sich aber nur dauerhaft, sobald ich das Netzteil einstecke.

Den Code kann ich gerne gleich noch nachliefern.

Mir ist bewusst, dass ich über die Anzahl der Umdrehungen bzw. Steps und der Steigung der Spindel eine genaue x-Bewegung erzielen kann. Nur die Umsetzung und Herangehensweise fehlt mir noch.

Meine Frage wäre also jetzt wie ich im Idealfall weiter vorgehe. Hilfreiche Anlaufstellen und Tipps sind gerne gesehen. Aber wie gesagt - vieles verstehe ich einfach noch nicht. Ich habe in meinem Maschinenbau Studium leider keinerlei Berührungspunkte gehabt und ich will diese Lücke endlich schließen.

Beste Grüße

Damit ein Schrittmotor sich bewegt, muss schon einiges richtig laufen. Glückwunsch!
Dass er sich nicht mehr dreht, ist einfacher. :wink: Zeig mal.

Der nächste Schritt ist übrigens erstmal, rauszukriegen wo dein Schlitten steht, bzw bis in eine Grundstellung zu fahren, von wo aus du Schritte zählen kannst.

// Defin pins
 

int driverPUL = 7;    // PUL- pin
int driverDIR = 6;    // DIR- pin

 
// Variables
 
int pd = 500;       // Pulse Delay period
boolean setdir = LOW; // Set Direction
 

 
void setup() {
 
  pinMode (driverPUL, OUTPUT);
  pinMode (driverDIR, OUTPUT);
  
}
 
void loop() {
  
    pd = (0,1023,2000,50,0);
    digitalWrite(driverDIR,setdir);
    digitalWrite(driverPUL,HIGH);
    delayMicroseconds(pd);
    digitalWrite(driverPUL,LOW);
    delayMicroseconds(pd);
 
}

Das ist der aktuelle Code den ich verwende. In dem Code war ursprünglich noch ein Poti verbaut den ich allerdings nicht brauche. Die entsprechenden Zeilen habe ich also gelöscht. Ich verstehe nur zum Teil was da so alles passiert, da bin ich ehrlich. :sweat_smile:

Der nächste Schritt ist übrigens erstmal, rauszukriegen wo dein Schlitten steht, bzw. bis in eine Grundstellung zu fahren, von wo aus du Schritte zählen kannst.

Den Schlitten bzw. die Spindel habe ich noch gar nicht angeschlossen. Ich wollte erstmal den Motor an sich zum Laufen bringen und im nächsten Schritt den Code weiter ausbauen.

Welchen Arduino verwendest Du ?
Du tust dich wesentlich leichter, wenn Du für die Ansteuerung des Steppers eine Bibliothek verwendest. Da könntest Du z.B. meine MobaTools verwenden, die enthalten auch eine Klasse um Stepper anzusteuern. Vor allem ist es bei Steppern wichtig, sie mit einer Anfahr- und Bremsrampe zu betreiben. Stepper können nicht von null auf gleich mit höherer Geschwindigkeit betrieben werden.
Es sind auch einige Beispiele dabei - z.B. auch für die bereits angesprochene Referenzfahrt am Anfang.

Hallo,
du solltest eine Lib verwenden die nimmt Dir eine Menge Arbeit ab. Dann gibst Du eine absolute Position vor und der Motor fährt dahin. Die ganze Rechnerei macht die Lib für Dich.

MobaTools oder AccelStepper

bei beiden gibt es Beispiele wie man sowas macht. Fang mit den einfachen Beispielen an zu üben.

dann benötigst Du noch einen Endschalter oder Sensor als Referenzpunkt dient damit Du die Null Position ermitteln kannst wenn das System eingeschaltet wird.

Letztlich benötigst Du ja auch noch ein Display und die Möglichkeit die Sollwerte einzugeben, da gingen zwei Taster oder ein Drehencoder.

Vor einiger Zeit, etwa 1 Jahr , da gabs hier sowas schon mal , dabei ging es auch um eine Säge.

Heinz

Hallo zusammen,

danke schon mal für die Antworten. Ich werde mich morgen wieder dran setzten und mich mal durch die Infos arbeiten.

Danach melde ich mich sicher mit neuen Fragen wieder zurück :wink:

Das kannst du durch
pd=0;
ersetzen, oder ganz weglassen, damit du merkst, was die Zeile
int pd = 500; // Pulse Delay period
bewirkt.

Und wenn du möchtest, dass der Motor nur eine zeitlang läuft, wäre die minimale Erweiterung,
in loop() um den ganzen Codeblock ein

if (millis() < 5000) {
 // hier die Motor-Ansteuerung
}

zu setzen, dann läuft der Motor nur 5 sec lang nach jedem RESET.

danke :slight_smile: Hab ich eben mal umgesetzt und bisschen rumprobiert. Funktioniert alles bestens.

Ich habe auch bisschen mit den MobTools gespielt und paar Sachen ausprobiert. Aktuell summt der Motor friedlich im Hintergrund :+1:

Hier nochmal zwei Bilder vom aktuellen Aufbau


Hallo zusammen ich brauche nochmal Eure Hilfe :slight_smile:

Ich habe mittlerweile große Fortschritte gemacht. Der Motor ist über eine Spindel an den Schlitten der Maschine verbunden und läuft. Das ist übrigens mein erstes Projekt jemals und ich habe bei Null angefangen. Daher entschuldigt bitte wenn ich etwas nicht direkt verstehe oder mein Code eventuell diverse Fehler enthält.

Über den Code unten und ein Python Programm kann ich bereits Werte eingeben und die gewünschten Positionen anfahren. Das funktioniert alles wunderbar. ABER:

Wenn ich bestimmte Positionen anfahre passieren manchmal Dinge die ich mir nicht erklären kann. Ich habe nur mal ein paar Werte zur Verdeutlichung in einer Tabelle zusammengefasst. Das Problem ist, dass manche Werte die ich eingebe zwar angefahren werden, aber im LCD Screen meistens mit einer Differenz von 2 angezeigt werden. Die Eingabe und Position des Schlittens passt IMMER. Nur die Ausgabe weicht ab.

Hierfür mal eine Tabelle

|Eingabe | Ausgabe | Position Motor (bzw. Schlitten)|

|160 | 158 | 160|
|158 | 158 | 158|
|150 | 150 | 150|
|198 | 198 | 198|
|199 | 198 | 199|
|200 | 198 | 200|


//#include <Stepper.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <AccelStepper.h>
#define STEPS 200
LiquidCrystal_I2C lcd(0x27,20,4);
AccelStepper nema(1, 2, 3);
#define home_switch 9;
//float schritte = 2038;
float hub = 4;
int End_Btn = 9;
int LED_Signal = 2;
int Vorherig_Wert;
//int new_n;
int Upper_End = 200;
int Under_End = 0;
int n_int_copy;
int Not_Aus = 13;
//int Not_Aus_Einstieg;
int dir= 3;
int pul = 2;
long initial_homing = -1;
float position_print;
//Stepper stepper(schritte, 8, 9, 10, 11); //Stepper stepper(schritte....)

void kalibrieren(){
  nema.setMaxSpeed(300.0);// Max Geschwindigkeit zum Kalibrieren
  nema.setAcceleration(300.0);// Max Beschleunigung zum Kalibrieren
  digitalWrite(LED_Signal, LOW);//LED Aus
  lcd.clear();
  lcd.print("Kalibrieren");
  nema.setCurrentPosition(0);

  while((digitalRead(End_Btn) == HIGH) && (digitalRead(Not_Aus)== HIGH )){// Bedingung für Motorbewegung
    nema.moveTo(initial_homing);
    initial_homing--;
    nema.run(); // Motor verfährt bis End_Btn betätigt oder Not_Aus betätigt
  }
  if ( digitalRead(Not_Aus)== LOW){//Wenn Not_Aus betätigt dann rückmeldung
    Serial.print("0");
    lcd.clear();
    lcd.print("NOT AUS");
    nema.setCurrentPosition(0);
  }
  if( digitalRead(Not_Aus) == HIGH){
      delay(1000);
      nema.setCurrentPosition(0); // Position auf 0
      Serial.print("#"); // Serial Codewort zum beenden und freischalten der Seiten
      lcd.clear();
      lcd.print("Kalibrieren");
      lcd.setCursor(0, 1);
      lcd.print("abgeschlossen");

  }
}

void go_To(float n){   // Vorher war int n
  //digitalWrite(LED_Signal, LOW);
  float distance = n;
  lcd.clear();  
  lcd.setCursor(0,0);
  lcd.print("Maß wird eingestellt");
  lcd.setCursor(0,1);
  lcd.print(distance);
  nema.setAcceleration(-500.0);
  nema.setMaxSpeed(1000.0);
  float soll = ((distance-150) / hub)*200; 
  long round_soll = round(soll);
   
  lcd.setCursor(0,10);
  lcd.print(round_soll);
  while((digitalRead(Not_Aus)== HIGH) && (nema.currentPosition()!= round_soll)){
    nema.moveTo(round_soll);
    nema.run();
    // Überprüfen noch nicht möglich
  } 

  if(digitalRead(Not_Aus)== LOW){
    Serial.print("0");
    lcd.clear();
    lcd.print("NOT AUS");
    }
  if(digitalRead(Not_Aus)== HIGH){
    Serial.print("#");
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Aktuelles Maß");
    position_print = (nema.currentPosition()/200)*hub+150;
    lcd.setCursor(0, 1);
    lcd.print(position_print);
    delay(1000);
    Serial.print(position_print);
  }
}

void setup() {
  //Serial Verbindung
  Serial.begin(9600);
  pinMode(End_Btn, INPUT_PULLUP);
  pinMode(LED_Signal, OUTPUT);
  pinMode(Not_Aus, INPUT_PULLUP);
  digitalWrite(LED_Signal, LOW);
  //SDA on A4 and SCL on A5
  lcd.init();
  lcd.backlight();
  lcd.print("Ready");
}

void loop() {
  // Check ob Serial verfügbar ist
  if (Serial.available() > 0) {
    String prog_wahl = Serial.readStringUntil('\n');
    lcd.clear();
    lcd.print(prog_wahl);
    //IF Programmwahl
    if(prog_wahl == "Soll"){      
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Eingabe folgt");

      int n =-1; // Ungültige zahl für while bedingung
      while (n <= Under_End || n > Upper_End){ // Ungültiges Maß noch ersetzen. 0 200
        while (!Serial.available()){
          //Warte auf Input
        }
      String eingabe = Serial.readStringUntil('\n');
      n_int_copy = eingabe.toInt();
      n = eingabe.toFloat();// Eingabe von String to float
      lcd.clear();
        if ((n_int_copy <= 0) || (n_int_copy > 200)) {  // 0 200
          lcd.clear();
          lcd.print("Ungültige Eingabe");
          Serial.print("#");
          break;
        }
        if(Vorherig_Wert == n_int_copy){ // TESTEN MIT nema.currentPosition
          lcd.clear();
          lcd.print("Wert bereits eingestellt");
          Serial.print("#");
        }
        else if((Vorherig_Wert < n)||(Vorherig_Wert > n)) {
          lcd.clear();
          lcd.print(n);
          go_To(n);
          Vorherig_Wert=n;
        }
      }
    }
    else if(prog_wahl=="Kalibrieren"){
      kalibrieren();
      Vorherig_Wert=0;
     }
    }
  }
apps-fileview.texmex_20240321.01_p0
Code_Jari_26_03.txt
Displaying Code_Jari_26_03.txt.

Warum brauchst du float? Da gibt es immer Ungenauigkeiten.

Brauche ich nicht unbedingt. Ich habe auch schon int ausprobiert. Die Probleme sind geblieben.

Dann baue es bitte mal zurück auf int und entferne die round Befehle.

kannst du auch ersetzen durch

soll = (distance-150) *50;

Zeigt leider keine Änderung

Zeige mal bitte den neuen Code

//#include <Stepper.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <AccelStepper.h>
#define STEPS 200
LiquidCrystal_I2C lcd(0x27,20,4);
AccelStepper nema(1, 2, 3);
#define home_switch 9;
//float schritte = 2038;
int hub = 4;
int End_Btn = 9;
int LED_Signal = 2;
int Vorherig_Wert;
//int new_n;
int Upper_End = 200;
int Under_End = 0;
int n_int_copy;
int Not_Aus = 13;
//int Not_Aus_Einstieg;
int dir= 3;
int pul = 2;
long initial_homing = -1;
int position_print;
//Stepper stepper(schritte, 8, 9, 10, 11); //Stepper stepper(schritte....)

void kalibrieren(){
  nema.setMaxSpeed(300.0);// Max Geschwindigkeit zum Kalibrieren
  nema.setAcceleration(300.0);// Max Beschleunigung zum Kalibrieren
  digitalWrite(LED_Signal, LOW);//LED Aus
  lcd.clear();
  lcd.print("Kalibrieren");
  nema.setCurrentPosition(0);

  while((digitalRead(End_Btn) == HIGH) && (digitalRead(Not_Aus)== HIGH )){// Bedingung für Motorbewegung
    nema.moveTo(initial_homing);
    initial_homing--;
    nema.run(); // Motor verfährt bis End_Btn betätigt oder Not_Aus betätigt
  }
  if ( digitalRead(Not_Aus)== LOW){//Wenn Not_Aus betätigt dann rückmeldung
    Serial.print("0");
    lcd.clear();
    lcd.print("NOT AUS");
    nema.setCurrentPosition(0);
  }
  if( digitalRead(Not_Aus) == HIGH){
      delay(1000);
      nema.setCurrentPosition(0); // Position auf 0
      Serial.print("#"); // Serial Codewort zum beenden und freischalten der Seiten
      lcd.clear();
      lcd.print("Kalibrieren");
      lcd.setCursor(0, 1);
      lcd.print("abgeschlossen");

  }
}

void go_To(int n){   // Vorher war int n
  //digitalWrite(LED_Signal, LOW);
  int distance = n;
  lcd.clear();  
  lcd.setCursor(0,0);
  lcd.print("Maß wird eingestellt");
  lcd.setCursor(0,1);
  lcd.print(distance);
  nema.setAcceleration(-500.0);
  nema.setMaxSpeed(1000.0);
  int soll = ((distance-150) / hub)*200; 
  
   
  lcd.setCursor(0,10);
  lcd.print(soll);
  while((digitalRead(Not_Aus)== HIGH) && (nema.currentPosition()!= soll)){
    nema.moveTo(soll);
    nema.run();
    // Überprüfen noch nicht möglich
  } 

  if(digitalRead(Not_Aus)== LOW){
    Serial.print("0");
    lcd.clear();
    lcd.print("NOT AUS");
    }
  if(digitalRead(Not_Aus)== HIGH){
    Serial.print("#");
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Aktuelles Maß");
    position_print = (nema.currentPosition()/200)*hub+150;
    lcd.setCursor(0, 1);
    lcd.print(position_print);
    delay(1000);
    Serial.print(position_print);
  }
}

void setup() {
  //Serial Verbindung
  Serial.begin(9600);
  pinMode(End_Btn, INPUT_PULLUP);
  pinMode(LED_Signal, OUTPUT);
  pinMode(Not_Aus, INPUT_PULLUP);
  digitalWrite(LED_Signal, LOW);
  //SDA on A4 and SCL on A5
  lcd.init();
  lcd.backlight();
  lcd.print("Ready");
}

void loop() {
  // Check ob Serial verfügbar ist
  if (Serial.available() > 0) {
    String prog_wahl = Serial.readStringUntil('\n');
    lcd.clear();
    lcd.print(prog_wahl);
    //IF Programmwahl
    if(prog_wahl == "Soll"){      
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Eingabe folgt");

      int n =-1; // Ungültige zahl für while bedingung
      while (n <= Under_End || n > Upper_End){ // Ungültiges Maß noch ersetzen. 0 200
        while (!Serial.available()){
          //Warte auf Input
        }
      String eingabe = Serial.readStringUntil('\n');
      n_int_copy = eingabe.toInt();
      n = eingabe.toFloat();// Eingabe von String to float
      lcd.clear();
        if ((n_int_copy <= 0) || (n_int_copy > 200)) {  // 0 200
          lcd.clear();
          lcd.print("Ungültige Eingabe");
          Serial.print("#");
          break;
        }
        if(Vorherig_Wert == n_int_copy){ // TESTEN MIT nema.currentPosition
          lcd.clear();
          lcd.print("Wert bereits eingestellt");
          Serial.print("#");
        }
        else if((Vorherig_Wert < n)||(Vorherig_Wert > n)) {
          lcd.clear();
          lcd.print(n);
          go_To(n);
          Vorherig_Wert=n;
        }
      }
    }
    else if(prog_wahl=="Kalibrieren"){
      kalibrieren();
      Vorherig_Wert=0;
     }
    }
  }

Du arbeitest immer noch mit float

Und die Anpassung au #13 ist auch noch nicht da

das wollte ich vorerst nicht ändern, da ich "hub" gerne weiterhin als Variabel behalten möchte.

habe ich nun auch geändert. Jetzt gibt es keine float mehr.

Dann mach doch bitte zuerst die Multiplikation und dann die Division. an beiden Stellen mit den Hub

1 Like

Habe die Rechnung angepasst. Es scheint wirklich was bewirkt zu haben.
Dafür schon mal vielen Dank! :slight_smile:
Ich werde die nächsten Tage weitere Tests durchführen und mich dann nochmal melden.

Frohe Ostern und nochmals vielen Dank

1 Like