Mehrere Stepper mit unterschiedl. Geschwindigkeiten gleichzeitig ansteuern?

Hallo, ich möchte mind. 3 und mehr Schrittmotoren mit maximaler Geschwindigkeit über einen Arduino Uno ansteuern. Nun ist mir aber aufgefallen, da ich ja jedem Schrittmotor individuell die Stepps diktieren muss, dass es praktisch nicht möglich ist dies zu machen da bei jedem individuellen Stepps "diktieren" Rechenzeit verloren geht.
Ich habe 8 Nema 17 (3,4V,1.7A) Stepper die jeweils über einen A4988 angesteuert werden.

Mit folgendem Code habe ich die kleinste delay von 34 MicroSek. ermittelt. Weiter runter geht nicht außer mit Beschleunigung.

loop(){
digitalWriteFast(stepPin, HIGH); 
//delayMicroseconds(1);  //worked without for max speed
digitalWriteFast(stepPin, LOW); 
delayMicroseconds(34);
}

Nun habe ich mir eine kleine "lib" geschrieben und jeder Stepper lässt sich nun als ein Objekt anlegen. Jeder Stepper hat eine run() Methode die folgendes macht:

void CStepper_A4988::run() {
 if (isRunning && stepsToGo > 0) { //first compare bool before slow unsigned long
 if (micros() >= nextUpdate) {
 nextUpdate = micros() + stepDelay_uSec;
 digitalWriteFast(stepPin, HIGH);
 //delayMicroseconds(1);  //seems not needed
 digitalWriteFast(stepPin, LOW);
 stepsToGo--; 
 }
 }
 else if (isRunning && stepsToGo == 0) {//calc final unsinged long currentpos only after stepstogo is finish (or in ext. getter methods)  
 stop(); //calcs also the currentPos 
 }
}

Tja, nun legte ich mir 4 Stepper Objekte an, setzte die delay auf 34 uSec. und rief in der loop() hintereinander jeweils die run() Methode der Stepper auf. Ergebnis ist: Um so mehr Stepper ich hinzufüge um so langsamer werden sie (iwie logisch wegen der steigenden Anzahl auszuführenden Befehlen). 34uSec. war die kleinste Zeit die damals bei einem Stepper ging. Allerdings wird diese Zeit jetzt niemals bei 4 und mehr Steppern eingehalten.

Nun meine Frage. Wie kann man mehrere Stepper, die getrennt angesteuert werden können müssen (Geschwindigkeit etc) gleichzeitig betreiben? Ist das überhaupt ohne Geschwindigkeitsverlust möglich bei einem einzigen Arduino Uno?

P.S.
Meine erste Idee wäre gewesen, jedem Stepper einen Arduino Nano zu spendieren .. klingt für mich aber Kosten anfällig und verrückt XD
Die zweite Idee wäre, herauszufinden wie die Pololu-Boars funktionieren. Doch nach ersten Kurzrecherchen scheinen dort alle A4988 "gestapelt" zu sein und mit einem Schlag "angesteppt" zu werden. Dadurch könnte ich aber die Steppers nicht mit unterschiedlichen Geschwindigkeiten gleichzeitig ansteuern ...wenn ich das richtig sehe.

Habe gerade noch etwas getestet:

unsigned long start;
void loop() {
	start = micros();
//micros()
	Serial.println(micros() - start);
}

Das braucht angeblich 4 uSek.! O_o Je mehr man danach an micros() hinzufügt um so länger dauert es^^ Scheint als würde micros() 2-4 uSek benötigen. Das ist dann doch erheblich wenn man bei 120000 Steps jedesmal 2-4 uSek verliert.
Heißt ich muss bei "nextUpdate = micros() + stepDelay_uSec;" mehr oder weniger schon 2-4uSek wieder abziehen...
...OK mit einer Korrektur von -2uSek delay pro hinzugefügten Stepper bleiben sie lautstärkemäßig (nicht U/min gemessen) nun pi*Daumen auf der selben Geschwindigkeit. Das Ging mit 4 Steppern gut. Bei 10 Steppern brauchte allerdings schon alleine der Aufrufe aller Steppers nacheinander so lange, dass die delay jedes Einzelnen überschritten wurde. Bin mal gespannt was für Lösungsvorschläge hier kommen :slight_smile:

Patrick_123:
Nun meine Frage. Wie kann man mehrere Stepper, die getrennt angesteuert werden können müssen (Geschwindigkeit etc) gleichzeitig betreiben? Ist das überhaupt ohne Geschwindigkeitsverlust möglich bei einem einzigen Arduino Uno?

Das Einzige, was mir spontan einfällt: Erledige die Stepperei in einer ISR (Interrupt Service Routine). In der Routine musst Du halt die Abfrage der Stepper-Objekte erledigen und jeweils einen Schritt machen (oder eben nicht).

Ob das in der von Dir gewünschten Geschwindigkeit geht, weiß ich nicht. Ich würde das halt einfach probieren.

Gruß

Gregor

Nachtrag:
Meine Erfahrungen mit Steppern sind ziemlich bescheiden. Ich habe zwar schon ein bisschen damit gespielt, aber was Geschwindigkeit angeht, habe ich keine (also wirklich null) Ahnung. Die von Dir genannten 34 Mikrosekunden entsprechen ungefähr 30 kHz. Bei 200 Schritten pro Umdrehung wären das 150 Umdrehungen in der Sekunde. Können Stepper tatsächlich so schnell sein?

K muss ich mir mal anschauen dieses ISR. Momentan scheint mir einfach die run() Methode so rechenintensiv zu sein, dass es der Arduino unmöglich schaffen wird mehrere Stepper gleichzeitig zu handhaben ohne dass diese pro Stepper der hinzugefügt wird an Maximalgeschwindigkeit verlieren.
Meine Stepper laufen im 16er Schrittmodus wodurch ich pro Umdrehung
3200 Schritte benötige ((360/1.8)*16). Momentan schaffe ich max 7-8 Umdrehungen pro Sek was mir ehrlich gesagt sogar noch etwas langsam vorkommt. Ich glaub dass die Nema17 Stepper an meinem 3D Drucker schnelle sind, müsste ich aber genauer prüfen.

Generell tut sich mir der Verdacht auf, dass es nicht möglich ist, mehrere Stepper (ohne ZusatzController etc.) an einem einzigen Arduino zu betreiben ohne dass dabei die Maximalgeschwindigkeit gemindert wird. Da jeder Stepper individuell angesteuert werden muss wird jeder Stepper Rechenzeit beanspruchen die so wie es aussieht im uSek. Bereich liegt.

Nur weiter mit den Vorschlägen. Jeder Hinweis ist ggf. Hilfreich :smiley:

Hallo,

verabschiede dich vom delay. ISR ist in meinen Augen auch nicht notwendig.
Du brauchst am Ende einen endlosen Automaten. Wie immer eigentlich.
"blink without delay" ist das Stichwort. https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay

Oder falls dir das weiter hilft.

Das "blink without delay" solltest du dennoch verstehen lernen, denn darauf baut alles auf.

Hmm nach dem "Blink without Delay" habe ich meine run() methode ebenfalls aufgebaut. Ich rechne mir mit micros() die Zeiten bis zum nächsten Update aus.

Hi
Ich experimentiere auch mit Schrittmotoren und nutze dabei die AccelStepper Libary.
Vll kannst dir da ein paar Anregungen holen, falls du die noch nicht kennst.

Mit der hab ich momentan 3 Stepper parallel am laufen ohne auf Probleme zu stoßen.
Ffalls du die libary schon kennst und bewusst eine eigene schreibst weil die fertige nicht deinen Anforderungen entspricht, beachte meinen post einfach nicht XD Viel spaß noch beim Tüfteln

Ich arbeite ebenso mit der AccelStepper library, habe aber

  1. nur 2 Stepper, die ich ansteuere und
  2. ist der speed nicht so entscheidend bei meiner Applikation

AccelStepper kann im multistepper-Modus arbeiten, allerdings ist die maximale step-Rate ca. 4000steps/sec.
Dieses step-Rate muss aber von allen angeschlossenen Steppern "geteilt" werden, so dass der Speed dann schnell in den Keller gehen kann, wenn mehr als 3-4 Stepper angeschlossen werden und diese "quasi-gleichzeitig" laufen sollen.

Meine Stepper laufen im 16er Schrittmodus

Hier hast du den besten Stellhebel, um auf Speed zu kommen:
Wenn du nicht unbedingt 1/16 Mikroschritte (MS) brauchst, dann stelle doch z.B. auf 1/4 MS und du gewinnst dann den 4fachen speed bei etwas raueren Laufgeräuschen.

Sollte das nicht akzeptabel sein, dann brauchst du einen Arduino mit schnellerem Prozessor (z.B. einen Due mit 84 Mhz).

Patrick_123:
Meine erste Idee wäre gewesen, jedem Stepper einen Arduino Nano zu spendieren .. klingt für mich aber Kosten anfällig und verrückt XD

Wenn Du alles an Zeit herausgeknautscht hast und es geht immer noch nicht, finde ich die Idee der verteilten Resourcen nicht schlecht. 5x Nano V3.0 Modul ATmega328P ist mit 13,80 € gegenüber den Kosten für die Stepper auch nicht so gravierend. Alle Nanos mit I2C kommunizieren lassen und einer gibt als Master die Sollwerte vor.

Wenn Du mehr Geschwindigkeit haben möchtest, könnte auch ein Teensy für Dich interessant sein. Wird mittels Arduino-IDE programmiert.

rpt007:
AccelStepper kann im multistepper-Modus arbeiten, allerdings ist die maximale step-Rate ca. 4000steps/sec.
Dieses step-Rate muss aber von allen angeschlossenen Steppern "geteilt" werden, so dass der Speed dann schnell in den Keller gehen kann, wenn mehr als 3-4 Stepper angeschlossen werden und diese "quasi-gleichzeitig" laufen sollen.

Interessant. Hatte die AccelStepper Lib damals mal aber wollte jetzt für meine Anwendung eine angepasste Lib selbst schreiben. Wenn die AccelStepper auf 4000Steps/die Sec limitiert ist bin ich mit den 22.400-25.600 Steps/Sek. (bei 16 MS) doch noch etwas drüber ... wenn mir nicht Schritte verloren gehen. Momentan hab ich noch nichts gemessen sondern nur die Zeit zwischen den Steps soweit es geht runter gedreht und das Limit war einfach für mich erreicht, wenn sich der Motor nicht mehr gedreht hat :smiley:
Werde ab morgen wieder am Projekt weiter machen und ggf wenn die Lib doch noch brauchbar werden sollte sie mal hier posten. Ich muss es eben noch iwie hinbekommen, dass mehrere Stepper ohne schwerwiegenden Geschwindigkeitsverlust gleichzeitig laufen können... zumindest 3-4 Stück.

Aber schon mal Danke für eure Antworten :slight_smile:

Hallo,

wenn es dir wirklich um max. Speed und Syncronität ankommt, dann würden vielleicht Stepper-Driver helfen.

Dann gibts du nur noch das Takt- und Richtungssignal raus.
Den Takt könnte man dann noch an alle zu gleich rausgeben und jeweils mit einem UND Gatter versehen, dass man jeden Treiber gezielt den Takt zu- und abschalten kann.
Wäre ein Vorschlag.
Die AccelStepper Lib kannste bestimmt dennoch verwenden zum anfahren und bremsen usw.

Hallo Patrick,

Wenn Du viele Stepper gleichzeitig mit verschiedenen Geschwindigkeiten laufen lassen willst, brauchst Du bei Mikroschrittbetrieb für jeden Stepper einen Kontroller Uno z.B.
Den Master lässt Du einfach ein 50/50 moduliertes Signal ausgeben. Geht mit tone ()von 31Hz bis ca 65kHz.
Die Slaves lässt Du das einfach mit pulseIn() messen (geht bis ca 100kHz) und hast als Kehrwert von Taktfrequenz z.B.16MHz-Quarz des Modules wieder eine synchronisierte Frequenz.
Diese kannst Du dann wie gewünscht nachregeln.

Doc_Arduino:
... dann würden vielleicht Stepper-Driver helfen.

Der TO verwendet A4988, nach meiner Vorstellung sind das Stepper-Driver mit STEP und DIR.

In Deinem Link ist aber auch der AMIS-30543 Stepper Motor Driver Carrier enthalten, der mittels SPI konfiguriert werden kann. In der Bibliothek finde ich setStepMode(uint8_t mode) und setPwmFrequencyDouble(), was die Phantasie anregt. Ich habe keine Erfahrung damit, ist nur eine Idee!

Hallo,

upps, dass habe ich übersehen, dass er diese schon hat. Dann wird es doch aus meiner Sicht ganz einfach.
Wie schon erwähnt. Alle Driver bekommen das gleiche Taktsignal, jeweils mit einem UND Gatter zum einzeln steuern.
Sodass für jeden Driver 2 Pins benötigt werden. Ohne UND Gatter laufen immer alle zwangsweise syncron.
Und wenn wirklich immer alle gleichzeitig laufen sollen. Dann alle STEP/DIR der Driver verbinden und man benötigt nur 2 Pins vom Arduino.

Hallo,
Der TO schreibt unterschiedliche Geschwindigkeiten,
Microschritten und Luft nach oben.
aber von einer Quelle ist sein Wunsch.
Das geht dann nicht nur mit Driver schalten, da muss was zum regeln......dazwischen....

1 Master und dann Slaves.

Dann die verschiedenen Endstufen oder Driver oder H-Bridges oder...oder

Es wäre hilfreich, wenn wir mal exakt erfahren könnten, was eigentlich das Projektziel ist.
Im Moment ist das eher ein Ratespiel mit viel guten Ideen und Beiträgen.

Aber: ich weiß jedenfalls nicht (mehr), was das eigentliche ZIEL des Ganzen sein soll und nur dann kann man auch geZIELt weiterhelfen.

Hallo,

genau, momentan bin ich auch wieder eher verwirrt was es am Ende wie werden soll.

@TO. Wie sollen die Motoren am Ende gesteuert werden? Alle zusammen, gleiche Richtung, gleiche Geschwindigkeit, alle zeitgleich, oder doch einzeln steuerbar ... ?

Wow, viele Danke für die vielen hilfreichen Antworten.

Hier mal eine Kurzbeschreibung:

Was soll erreicht werden:
Ich benutze den A4988 Treiber und einen Arduino.
Später werden es 2 Arduino sein. Einer davon wird ausschließlich die Schrittmotoren steuern und über Serial oder iwas anderes mit dem anderen Arduino kommunizieren.
Die Schrittmotoren sollen getrennt angesteuert werden können damit sie getrennt an und ausgeschalten werden können sowie mit unterschiedlichen Geschwindigkeiten betrieben werden können.
Für was:
Momentan versuche ich mir eine Lib für ein kleines ferngesteuertes Auto zu erstellen. Diese soll jedoch universell einsetzbar sein, so dass ich später damit auch einen 3D Drucker oder sonstwas steuern könnte.
Problem:
Sobald man mehrere Schrittmotoren gleichzeitig anschließt werden alle langsamer. Grund ist wohl dass ich für jeden Schrittmotor ein Objekt anlege und diese dann alle jedesmal in der Loop aufrufen muss. Letztendlich scheint die loop iwann so rechenintensiv zu sein, dass die maximale Wartezeit pro Schrittmotor überschritten wird und dadurch alle langsamer werden.

Momentaner Stand:
Ich habe herausgefunden, dass micros() angeblich gar nicht in 1er Mikrosekunde auflöst sonder in 4 uSek. Da eben jeder Stepper (wie im ersten Post zu sehen) in der run() Methode die micros() aufruft, um sich die restliche Wartezeit bis zum nächsten Step auszurechnen, werden die 4 uSek. Ungenauigkeit bei 22400 Steps pro Sek. schnell zum Verhängnis. Im Moment bin ich gerade dran, dies Ungenauigkeit ggf. über einen Timer1 der im 1 uSek. Takt eine Funktion aufruft zu lösen… aber noch habe ich kaum Ahnung davon und suche mich noch zurecht.

Hallo,

ja, die Auflösung beträgt bei micros() "nur" 4µs. Die Rückgabewertgenauigkeit beträgt +/- 4µs.
Bsp. 1:
du liest den aktuellen Stand von micros nach 100µs aus, dann kannste als Ergebnis 100 oder 104 bekommen.
Bsp. 2:
du liest den aktuellen Stand von micros nach 1000µs nochmal aus, dann kannste als Ergebnis 1000 oder 1004 bekommen.

Man könnte jetzt die Genauigkeit erhöhen, wie du es vor hast, dann erzeugt man einen Interrupt aller 1µs. Aber, das heißt das der µC selbst aller 1000ns/62,5ns=16 Takte in einer ISR fest hängt. Dein Programm dürfte damit zum erliegen kommen.

Wegen deinen Schrittmotoren, du willst also doch das "volle Programm" und alle einzeln steuern können.
Die aktuellen 34µs kannste noch reduzieren, in dem du nicht die Aduino Komfortbefehle wie digitalWrite verwendest. Jeder Aufruf kostet ca. 4µs. Du könntest wie bei der klassischen Programmierung den Port und Pin direkt ansprechen.
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
Musst dich allerdings von den gewohnten Pin-Numern verabschieden.
Damit kannste noch etwas rausholen.

Vielleicht musste ja doch bei den Ansprüchen den Aufwand treiben und jeden Motor einen µC verpassen.
Ich habe aktuell keine Idee wie man sonst viele, sehr schnelle und unterschiedliche Takte erzeugen kann.
Die Hardware Timer im Uno reichen nicht aus für 8 individuelle Takterzeuger.
Selbst wenn du millis/micros nicht verwendest.