Multistepper: STOP von 3 synchronlaufenden Steppern auslösen

Nachdem ich mich zwar als alter Mann, dennoch den Neulingen zuzuordnen, wissbegierig mit den Bibliotheken beschäftige, nach ersten Versuchen mit Multistepper aufgrund von Denkfehlern das erste Projekt habe verwerfen müssen, nun eine Frage zu meinem nächsten Projekt.
Hier erst einmal der Code:

// Drei NEMA 17, im gleichschenkligen Dreieck wegen der gleichmäßigen Lastverteilung, sollen synchron laufen und eine etwas schwere Arbeitsbühne anheben
#include <AccelStepper.h>
#include <MultiStepper.h>

// Schrittmotoren initialisieren
AccelStepper motor1(AccelStepper::DRIVER, 2, 5);  // Schrittmotor 1 an Pins 2 (Step) und 5 (Direction)
AccelStepper motor2(AccelStepper::DRIVER, 3, 6);  // Schrittmotor 2 an Pins 3 (Step) und 6 (Direction)
AccelStepper motor3(AccelStepper::DRIVER, 4, 7);  // Schrittmotor 3 an Pins 4 (Step) und 7 (Direction)

// Multistepper initialisieren
MultiStepper steppers;

// Schalter-Pins
const int rechtsPin = 8;
const int linksPin = 9;
const int stopPin = 10;

void setup() {
  // Geschwindigkeit und Beschleunigung für alle 3 Motoren definieren
  motor1.setMaxSpeed(1000);     // Maximale Geschwindigkeit in Schritten pro Sekunde
  motor1.setAcceleration(500);  // Beschleunigung in Schritten pro Sekunde^2
  motor2.setMaxSpeed(1000);
  motor2.setAcceleration(500);
  motor3.setMaxSpeed(1000);
  motor3.setAcceleration(500);

  // Schalter-Pins als Eingänge konfigurieren
  pinMode(rechtsPin, INPUT);
  pinMode(linksPin, INPUT);
  pinMode(stopPin, INPUT);

  // Motoren zur Multistepper hinzugefügt
  steppers.addStepper(motor1);
  steppers.addStepper(motor2);
  steppers.addStepper(motor3);
}

void loop() {
  // Schalterzustände lesen
  int rechtsStatus = digitalRead(rechtsPin);
  int linksStatus = digitalRead(linksPin);
  int stopStatus = digitalRead(stopPin);

  // Bewege Motoren basierend auf Schalterzuständen
  if (rechtsStatus == HIGH) {
    steppers.moveTo(2000);  // "Richtige" Schrittzahl wird praktisch ermittelt
  } else if (linksStatus == HIGH) {
    steppers.moveTo(-2000);  // "Richtige" Schrittzahl wird praktisch ermittelt
  } else if (stopStatus == HIGH) {
    // ===========================================Meine Frage: =====================================================================
    // steppers.stop(); ==> gibt es nicht in der Bibliothek, verständlich. Wie bekomme ich aber HIER bei Erreichen des Endschalters
    // die 3 Motoren gleichzeitig zum Halten und Zurückfahren um Bsp. 200, um die Schalter/ Taster zu entlasten?
    // =============================================================================================================================
  }

  // Führe die Schritte aus
  steppers.runSpeedToPosition();
}

Im letzten Beitrag habe ich gelernt, dass es kein steppers.stop in der Multistepper- Bibliothek gibt.
Wie kann ich bei Anfahren der 3 Stepper am Taster diese synchron stoppen und danach um etwa 200 Steps zurückfahren, um die (den) Taster zu entlasten?
Ohne Multistepper klappt es für jeden einzelnen. Habe noch keine Dauerschleifen Auf/ Ab getestet, inwieweit es Stepperverluste gibt.
Meine Idee war, die aktuelle Tasterposition unabhängig von bsp. steppers.moveTo(2000); abzufragen, und davon 200 sutrahieren, bzw addieren, je nachdem, ob oben oder unten das Ende der Linearführung(en) erreicht ist.
Aber: Die Funktionen in diesen Bibliotheksblöcken können jedoch die Position erst zurückgeben, wenn die Funktionsblöcke vollständig an die gewünschte/eingestellte Position gebracht wurden.

Gibt es hier eine andere Lösung, oder bin ich in meiner Euphorie wieder einem Denkfehler aufgesessen?

Der Sketch zeigt beim Kompilieren keine Fehler, solange eben die Zeile 46 auskommentiert ist.

Ich glaube Dein Ansatz:

ist kontraproduktiv, wenn Du die Position nicht abfragen kannst und der Antrieb nicht stoppt, wenn die Stop-Taste ausgelöst ist.

MEIN Ansatz wäre:
Die Stepperschritte in eine Variable zu schreiben (in dem Fall also 2000) und dann bei jedem Durchlauf von loop() den Stepper um z.B. 5 Steps zu bewegen und diese 5 von den 2000 abzuziehen.
Das Ganze, biss die 2000 aufgebraucht sind.

Löst Du jetzt mittendrin den Stop aus, bist Du maximal 5 Schritte drüber, bekommst aber mit jedem loop() die Möglichkeit die Stoptaste ausuzulesen - und damit den Schritt die 2000 schlagartig auf 0 zu stellen.
...
bzw. die aktuelle Positin abzufragen und darauf zu reagieren... oder so..

... "Löst Du jetzt mittendrin den Stop aus, bist Du maximal 5 Schritte drüber,"

Finde ich gut, beantwortet aber nicht meine Frage, mit welchem Befehl ich die Dinger stoppen könnte,

also, wie lauten die Zeilen?

Doch. Genau so, wie ich es geschrieben habe.

Las mir einen Moment, ich versuch mal was.

So ähnlich wie das hier:

// Drei NEMA 17, im gleichschenkligen Dreieck wegen der gleichmäßigen Lastverteilung, sollen synchron laufen und eine etwas schwere Arbeitsbühne anheben
#include <AccelStepper.h>
#include <MultiStepper.h>

// Schrittmotoren initialisieren
AccelStepper motor1(AccelStepper::DRIVER, 2, 5);  // Schrittmotor 1 an Pins 2 (Step) und 5 (Direction)
AccelStepper motor2(AccelStepper::DRIVER, 3, 6);  // Schrittmotor 2 an Pins 3 (Step) und 6 (Direction)
AccelStepper motor3(AccelStepper::DRIVER, 4, 7);  // Schrittmotor 3 an Pins 4 (Step) und 7 (Direction)

// Multistepper initialisieren
MultiStepper steppers;

// Schalter-Pins
const int rechtsPin = 8;
const int linksPin = 9;
const int stopPin = 10;

void setup()
{
  // Geschwindigkeit und Beschleunigung für alle 3 Motoren definieren
  motor1.setMaxSpeed(1000);     // Maximale Geschwindigkeit in Schritten pro Sekunde
  motor1.setAcceleration(500);  // Beschleunigung in Schritten pro Sekunde^2
  motor2.setMaxSpeed(1000);
  motor2.setAcceleration(500);
  motor3.setMaxSpeed(1000);
  motor3.setAcceleration(500);
  // Schalter-Pins als Eingänge konfigurieren
  pinMode(rechtsPin, INPUT);
  pinMode(linksPin, INPUT);
  pinMode(stopPin, INPUT);
  // Motoren zur Multistepper hinzugefügt
  steppers.addStepper(motor1);
  steppers.addStepper(motor2);
  steppers.addStepper(motor3);
}

const bool isPressed = HIGH;

const bool left = false;
const bool right = !left;
bool dir = left;

const long int oneStep = 5; // Stpperschritte je Aufruf
int32_t stepsSoll;     //

void loop()
{
  checkBtn();
  setStepper();
}

void checkBtn()
{
  if  (isPressed == digitalRead(rechtsPin))
  {
    if (0 == stepsSoll)  // Lässt sich nur befüllen, wenn stepper steht
    {
      stepsSoll = 2000;     // Sollschritte
      dir = right;
    }
  }
  else if (isPressed == digitalRead(linksPin))
  {
    if (0 == stepsSoll)
    {
      stepsSoll = 2000;
      dir = left;
    }
  }
  if (isPressed == digitalRead(stopPin))
  { stepsSoll = 0; }
}

void setStepper()
{
  if (stepsSoll > oneStep)
  {
    if (left == dir)
    steppers.moveTo(dir == left ? (oneStep * -1) : oneStep);
    stepsSoll -= oneStep;
    steppers.runSpeedToPosition();
  }
  else
  {
    stepsSoll = 0;
  }
}

Ich weiss nur nicht ob stepsSoll direkt verwendet werden kann oder, ob da noch eine Zwischenvariable genutzt werden muss.
Aber der Ansatz sollte klar sein.

Danke, teste es heute noch und melde mich, was passiert. Versuche, die Logik nachzuvollziehen.

Ich befürchte ja. Wie Du die MultiStepper nutzen willst, ist mir nicht klar. Multistepper wird nicht gebraucht. um mehrere Motore gleichzeitig laufen zu lassen. Das kann AccelStepper alleine. MultiStepper ist dazu da, für mehrere Stepper unterschiedliche Ziele zu setzen, die Bewegung aber so zu steuern, dass alle ihr jeweiligens Ziel gleichzeitig erreichen. Dazu berechnet MultiStepper für die Motore unterschiedliche Geschwindigkeiten. Für die eigentliche Bewegung wird dann von MultiStepper wieder einfach AccelStepper genutzt.
Deshalb ist das:

    steppers.moveTo(2000);  // "Richtige" Schrittzahl wird praktisch ermittelt

schonmal falsch. Multistepper erwartet da die Adresse eines Arrays, wo die Ziele aller Motore aufgelistet sind.
[Edit] Wenn Du die Warnungen einschaltest, weist dich der Compiler auch darauf hin, dass da was faul ist. Das ist eine der Warnungen, die tatsächlich eigentlich Fehler sind ( andere Compiler sind da auch restriktiver, und lassen sowas nicht durchgehen).

Da der Zweck von MultiStepper ja ist, dass alle Motore ihr Ziel gleichzeitig erreichen, macht ein vorzeitiger Stop eigentlich keinen Sinn ( ausser vielleicht als NotStop ).

Deshalb erstmal die Frage, was Du da eigentlich machen willst. Mir ist auch nicht klar, wie die 3 Stepper einen Schalter betätigen sollen.
P.S. Ein Bild vom Aufbau wäre hilfreich.

Es gibt eigentlich keinen Befehl zum stoppen. Du darfst eben einfach keine Steps mehr erzeugen.

  steppers.runSpeedToPosition();

Der Aufruf blockiert aber, bis alle Stepper ihr Ziel erreicht haben - da kannst Du nicht eingreifen.
Mit

steppers.run()

Würdest Du die Steps einzeln erzeugen ( in einer Schleife ) und kannst die Schleife dann auch gegebenenfalls abbrechen.

Würdest Du die Steps einzeln erzeugen ( in einer Schleife ) und kannst die Schleife dann auch gegebenenfalls abbrechen.

Leuchtet mir nach mehreren Experimenten ein. Ich glaube, ich habe Multistepper in den Ansätzen verstanden.
Ich werde mal ein paar Bilder anhängen. Ist mein erstes Mal, hoffentlich klappts.
Da ich im Modellbau tätig bin u






nd ab und zu ein paar 3D Scans zu erstellen habe, habe ich vor, zur Unterstützung einen 2- stufigen Lift aufzubauen mit integrierter Linearführung in horizontaler Achse (50cm) um nicht immer den ganzen Wagen mit Liftaufsatz vor- und zurückzubewegen, wenn der Abstand zum Objekt angepasst werden muss.
Ebenso wäre es möglich, eine Person auf einer Drehscheibe von 10cm bis 2m zu scannen.
(ab 1m wird der 2. Lift auf ausgefahrenem 1. Lift mit ausgefahren)
Der Scanner wird dann im oberen Kopfbereich gleichzeitig geneigt. Erfassung über zus. optischen Sensor.
Die Endschalter benötige ich jeweils nur 1x, werden an den 2 Lifts befestigt.
Mechanisch und elektrisch sind die Vorbereitungen getroffen. Der Prototyp der unteren Liftplatte im Bild wird durch eine sauber gefräste 5mm Aluminiumplatte ersetzt. Hier geht es nur darum die Last- und Schwerpunktverteilung zu ermitteln, wenn die Kamera ausgefahren wird. 3 Stepper unten, da mit Lift 2 eine ziemlich hohe Masse zu bewegen ist.
Jetzt ist mein laienhafter Gedankengang evtl. nachzuvollziehen. Ich will eine Verkantung durch Schrittverluste eines der 3 unteren Stepper vermeiden, da ich die Kraft von 3 Steppern brauche, kommt ein Riemenantrieb nicht in Frage. Und da kam mir der Multistepper in den Sinn. Ich werde mich jetzt mal mit Sensoren zur Positionsbestimmung beschäftigen, vielleicht so, dass der nachhängende Stepper "mehr Gas gibt", bis er die anderen eingeholt hat.
Da es hier nur um ein Hobby geht, habe ich Zeit, bis zu meinem 80. allerdings will ich es fertig haben :wink:
Danke erstmal fürs drüberschauen und die guten Erläuterungen.

Falsch! Scheibe fährt mit hoch, sie würde sonst die Kamera in 1m Höhe blockieren. :face_with_raised_eyebrow:

Es ist immer wieder gut wenn man das reale Projekt kennt.
Das eröffnet immer neue Möglichkeiten.

Die Bilder zeigen noch nicht so richtig im Detail wie es funktioniert. Ich vermute die zwei Schrittmotoren bzw. die drei Schrittmotoren sollen absolut synchron laufen.

Lösungsansatz 1:

Allen zwei bzw. drei Schrittmotoren ein und dasselbe Step-Signal zuführen.

Lösungsansatz 2:
Die zwei bzw. drei Trapezgewindespindeln über einen Zahnriemen von einem Schrittmotor antreiben lassen.

Noch einmal zum Vertändnis und damit verbunden meinem Dank für eure Unterstützung:
Ich bin ein alter Mann, aktuell noch 79, rieche schon, aber - bevor ich abtrete will ich noch einiges lernen. Habe viele Ideen, die ich schon umgesetzt habe, auch mit Arduino - was ich vor einigen Monaten für mich entdeckt habe.
3D Drucker, Laser 20W Diode, Resindrucker SATURN etc. erlauben mir, benötigte Teile selbst mit Fusion 360 zu entwickeln und zu drucken. Mit CNC Fräse (ESTLCAM) werden hier z.B. die Lifte aus 5mm ALU gefräst. Will noch viel lernen, brauche eure Hilfe. Nur auf der Couch rumlungern macht keinen Spaß!

Zum Thema:

  • 1 Schrittmotor mit Zahnriementrieb:
    ===========================
    Wenn ich die Last vom Lift 1, der den Lift 2 mit nach oben bewegen muss und die Linearführung samt Scanner, 2 NEMA14, 2 Trapezgewindestangen je 1m, 2 Längskugellager, 2 8mm Alurohre trägt, dann ist die Verwendung eines Motors, der dann auch noch zusätzlich 2 weitere Gewindestangen über Zahnriemen antreiben müsste, würde m.E. die Verwendung EINES Schrittmotors NEMA 17 nicht ausreichen.
    Ein NEMA 24 klappt da schon besser, würde aber die Verwendung eines CNC Shields ausschließen, wie für die Lastverteilung mit 3x NEMA17 vorgesehen war.
    Also, nach meiner Berechnung würde ein NEMA 24 unter folgenden Kriterien die 5kg - Reibung etc. unberücksichtigt - heben können und dabei 2 vorhandene Spindeln über einen Zahnriemen mit antreiben können. Technich kein Problem, kann am WE probieren, bestelle mir einen 24er.
    Allerdings weiß ich nicht, wie ich mit den Kriterien für den Schrittmotor umgehen soll.
    Die Umdrehung müsste 100 U/min sein, damit der Strom proWicklung 4,2A bei 4V und einem Drehmoment von 300 Ncm, Antriebsmoment bei 2mm Gewinde von 98 NM nicht überschritten wird. Dann beträgt die Antriebsleistung etwa 2,7 kW und es würde funktionieren.
    Bei 32V Netzteil am TB6600 könnte die Wicklungsspannung erhöht werden und die Stromstärke/ Wicklung verringert sich.

Soweit die (meine Berechnungen) Theorie, mal sehen, was die Praxis bringt.

  1. Die Lösung mittels 74HC595 klingt auch gut.
    War heute bis jetzt dabei, mich über Schieberegister zu informieren.
    Komme nur noch nicht klar, brauche bestimmt 2 Register, (falsch??)
    1 Array (1 1 1 1 1 1 1 1)
    1 Array (1 1 1 1 0 0 0 0),

um die Motoren ein- und ausschalten / Array's invertieren?
zu können.

SER, SRCLK, STCP an die digitalen PINs ist mir klar. Mit LED's habe ich schon probiert, klappt.
Grundprinzip voll verstanden.

Mir ist nur noch nicht klar, wie ich den einfachen Sketch mit dem Schieberegister in Einklang bringen soll.
Sketch:

#include <AccelStepper.h>

// Pins für 74HC595
//
// SER-Pin (Serial Input)             mit digitalem Ausgang des Arduino (z. B. Pin ??). Welcher ist noch frei? Evtl. Mega, da noch weitere Funktionen wie Joy für Linearführung und Relais für Neigung des Scanners
// SRCLK-Pin (Shift Register Clock)   mit digitalem Ausgang des Arduino (z. B. Pin ??).
// RCLK-Pin (Register Clock / Latch)  mit digitalem Ausgang des Arduino (z. B. Pin ??).

// Pins für die Schrittmotoren am CNC Shield
const int motor1StepPin = 2;
const int motor1DirPin = 3;
const int motor2StepPin = 4;
const int motor2DirPin = 5;
const int motor3StepPin = 6;
const int motor3DirPin = 7;

// Instanzen der AccelStepper-Klasse
AccelStepper motor1(AccelStepper::DRIVER, motor1StepPin, motor1DirPin);
AccelStepper motor2(AccelStepper::DRIVER, motor2StepPin, motor2DirPin);
AccelStepper motor3(AccelStepper::DRIVER, motor3StepPin, motor3DirPin);

// Taster-Pins
const int rechtsTasterPin = 8;
const int linksTasterPin = 9;
const int stopTasterPin = 10;

// Stopschalter-Pins
const int endstop1Pin = 11;
const int endstop2Pin = 12;

void setup() {
  // Initialisiere Motoren
  motor1.setMaxSpeed(1000);  // Maximale Geschwindigkeit einstellen, wird experimentell ermittelt
  motor2.setMaxSpeed(1000);
  motor3.setMaxSpeed(1000);

  // Taster und Stopschalter konfigurieren
  pinMode(rechtsTasterPin, INPUT_PULLUP);
  pinMode(linksTasterPin, INPUT_PULLUP);
  pinMode(stopTasterPin, INPUT_PULLUP);
  pinMode(endstop1Pin, INPUT_PULLUP);
  pinMode(endstop2Pin, INPUT_PULLUP);
}

void loop() {
  // Überwache Taster und Stopschalter
  if (digitalRead(rechtsTasterPin) == LOW) {
    // Rechtsdrehung
    // Implementiere die Logik für Rechtsdrehung
  } else if (digitalRead(linksTasterPin) == LOW) {
    // Linksdrehung
    // Implementiere die Logik für Linksdrehung
  } else if (digitalRead(stopTasterPin) == LOW) {
    // Stopp
    // Implementiere die Logik für Stopp, Befehl?? noch ausprobieren
  }

  // Bewege die Motoren zu ihren Zielpositionen
  motor1.moveTo(1000);  // Exakte Distanz wird noch ermittelt
  motor2.moveTo(1000);
  motor3.moveTo(1000);
}

Hallo,
habe heute NEMA Modell: 24HS40-4204S erhalten.
Zu Testzwecken habe ich 1x zentriert diesen Motor platziert und re. und li. davon je 1x T8 /2 Trapezgewindestangen über Riementrieb.
Mit seinem Stromverbrauch von 4,2A pro Phase und einem Haltemoment von 4,2NM schzafft er locker die Last nach oben, wird nur moderat warm.

Der Tipp war gut, vereinfacht auch den Sketch und schafft "Platz" am UNO für weitere Anschlüsse.
Vielleicht verwende ich auch 2 parallel, die Lastverteilung auf 2 parallel geschaltete Treiber des CNC Shields.

Wenn das Teil fertig ist, stelle ich es hier mal vor.
Ich betrachte mein Anliegen erst einmal als "gelöst" und bedanke mich bei allen Helfern.
Gerhard

Dann solltest Du der Fairness halber auch den Post mit dem Tipp als Lösung markieren.

"Solution" war wohl nicht richtig? Bitte Tipp, was ich sonst machen muss.

In dem Fall 'musst' Du gar nichts. Das Häkchen 'Solution' kannst Du an jeden Post machen, nicht nur an den letzten - allerdings nur an einen. Es ist einfach ein Dankeschön an denjenigen, der dir den entscheidenden Hinweis gegeben hat, wenn Du dessen Post als Lösung markierst.
Außerdem ist es ein Hinweis an diejenigen, die das Ganze später lesen, was denn nun der entscheidende Lösungsvorschlag war.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.