Go Down

Topic: Stepper Anfahrrampe OHNE Accelstepper (Read 252 times) previous topic - next topic

Deltaflyer

Hallo Freunde,

Ich bräuchte da mal nen kräftigen fachkundigen Tritt in die richtige Richtung.

Ich hab nen Stepper grösse Nema23 3,2A/Phase 200 Steps / U, der hängt an ner Endstufe (Takt/Richtung gespiesen mit 50V eingestellt auf 3,2A. nachgeschaltet ist noch eine 2:1 untersetzung, sodass ich für eine umdrehung des Abtriebs 400 Steps benötige. Eine volle Fahrt besteht aus 10 Umdrehungen des Abtriebs innert 1 Sekunde. Sind also 4000 Steps/Sekunde. Der Motor arbeitet somit im Vollschritt

Zurzeit nutze ich die Accelstepper um den Motor zu fahren, allerdings ist diese Lib bei 4000 Steps/Sekunde ausgereizt.

Ich würde nun gerne den Motor im halbschritt oder besser viretelschritt betreiben, da er dann ruhiger und auch leiser läuft. Kraft hat der Motor genug, um die Last auch im Viertelschritt mit diesem Tempo zu bewegen, jedoch nicht ohne Anfahrrampe. (dies hab ich mit nem variablen Taktgenerator gestestet.)

Jetzt mein Problem: Ich weiss nicht, wie man so ne Anfahr-Rampe (Beschleunigungs-Rampe) programiert.
oder anders: wie programmiere ich es, das der Atmega2560 (läuft mit 20MHz) in z.B. max 150ms (dieser Wert soll zwischen etwa 50ms -150ms einstellbar sein, bleibt aber, einmal eingestellt, immer der selbe) an einem Ausgang Impulse mit etwa 20 Mikrosekunden ausgiebt, deren Frequenz von 0 auf etwa 8 Khz steigt , und auf dieser Frequenz bleibt, bis eine Variable sagt : jetzt stop. Bei Stopp soll die Frequenzausgabe einfach stoopen, ohne Rampe ??
Darf also nicht blokierend sein, weder der Hochlauf, noch der Lauf selbst, ich brauche zwischen den Impulsen also noch etwas zeit um variablen hoch (oder runter) zu zählen und zu prüfen.

Ich wäre vor allem dankbar für Hilfe, die mir zeigt, wie man so eine in einer gegebenen Zeit von 0 auf max steigende Frequenz mit fester Impulslänge programmiert.

Besten Dank.
Gruss Stefan
 

postmaster-ino

Hi

Feste Impulslänge?
Dann eben die HIGH-Impulse auf 20µs und die LOW-Impulse entsprechend lang, daß man auf die Frequenz kommt, Die man haben will.

20MHz = 0.00000005s ... 0,05µs pro Takt, macht 400 Takte für 20µs (bei 20MHz - der 08/15-Mega rennt mit 16MHz Quarz)

Viele Berechnungen werden Da zur Laufzeit wohl nicht mehr möglich sein, also
Wartezeit=1000000/Frequenz-20 (Wartezeit/Länge des LOW-Impuls in µs)
wird nicht gehen, da die Division wohl mehr Zeit braucht, als Du 'für Alles' zur Verfügung hast.

Berechnen könnte man die MIN-Wartezeit (also bei Soll-Frequenz), Die der Aktuellen vergleichen und je nach 'Restzeit' entsprechend die Aktuelle reduzieren.

Wenn Du zum Hochlaufen eine Rampe brauchst, wirst Du beim Abbremsen Diese wohl auch brauchen - oder Schritte verlieren (bzw. eher Welche dazu bekommen ;) ).

mikros() löst in 4µs-Happen auf - für Deine 20µs also ausreichen - jetzt muß loop() nur schnell genug durchlaufen werden, daß Du Da auch zeitnah drauf reagieren kannst.

Anderer Ansatz wäre einen PWM ausgeben zu lassen - Das ginge in Hardware - man müsste halt 'mitzählen' wie weit wir schon sind (wenn Das wichtig ist).

MfG

millis() und mikros() sind Takt-Abhängig - mir ist nicht bekannt, ob bzw. wie man dem Arduino eine andere Takzfrequenz im Sketch beibringt.
Ohne Anpassung zählt Dein millis() in 16ms auf 20 hoch (20MHz statt 16MHz).
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

Deltaflyer

Hi, herzlichen Dank für die Antwort. Die Impulslänge soll max 20 Mikrosekunden sein. Minimal sollten sie 10 Mikrosekunden lang sein. für eine Fahrt, die 1 Sekunde dauert, brauche ich max. 8000 impulse, daraus folgt die Impuls-Frequenz von 8Khz.

Zum abbremsen wird später eine wesentlich kürzere Rampe hinzugefügt. Jedoch muss ich es eben zuerst hinbekommen, überhaupt so ne beschleunigungsrampe zu programmieren. Schrittverluste beim Bremsen ist kein Problem, da die nächste Fahrt IMMER in die engegengesetzte Richtung statfindet und die Fahr-Distanz immer dieselbe ist. Ausserdem wird , falls die Endposition nach stop nicht 100%ig erreicht ist, dies automatisch korrigiert.

Deiner Antwort entnehme ich auch, dass es wohl kaum möglich sein wird, während der Fahrt auch noch einen Encoder der 800 impulse/sekunde liefert einzulesen und damit eine Variable runterzuzählen und auf null zu prüfen?

postmaster-ino

Hi

Bei 20MHz hast Du 20 Takte pro µs, Deine zuvor genannte kürzeste Zeit waren 20µs, immerhin 400 Takte - damit kann man schon Was anfangen.
8000kHz -> 125µs, noch Mal eine ganze Ecke mehr Takte.

Ich durfte hier schon einige Male erfahren, daß der Kompiler durchaus schlanken Code erzeugt.
Zuerst würde ich versuchen, wie schnell ich loop() eigentlich hinbekomme.
Da Du mindestens einen Pin wackeln lassen willst und einen Anderen Abfragen möchtest, sollte Das in Deiner Test-loop() vorkommen.
An dem Pin-Wackeln kannst Du direkt per Oszi sehen, wie schnell Das noch ist und ob Es Sinn macht, in diese Richtung weiter zu forschen.

Sollte aber machbar sein - die Neopixel-Libs steuern die LEDs mit 800kHz an (auf 16MHz) - ist schon deutlich schneller als 8Khz, allerdings wird während Dessen NICHTS Anderes gemacht.

Der Encoder soll welche Aufgabe übernehmen?
Nur für die Endpositionen sollte auch eine simple Lochscheibe reichen.

MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

Deltaflyer

Während der Fahrt hat der Encoder die Aufgabe, die reale Position des Antriebs mitzuzählen, indem er lediglich eine variable runterzählt und bei erreichen von null dieser variablen wird ein stopsignal ausgelöst. Ist also ne Art closed loop Steuerung. ich verlasse mich also nicht alleine auf die an den Motor gesendeten Impulse. Ausserdem benutze ich den Encoder zum dedektieren einer händischen bewegung des antriebs (der stepper wird in den endpositionen nicht bestromt, das halte-Moment ist also im Stillstand nicht vorhanden und wird auch nicht benötigt.) Zusätzlich wird die Variable nach einem Notstop des Antriebs zur Positionsabfrage herangezogen.
Da die letzte Bewegungsrichtung des Antriebs bekannt ist, reicht es während fahrten mit Motor, lediglich in eine richtung zu zählen, also gegen 0.

Falls es wirklich programmtechnisch unslösbare zeitliche Probleme gibt, könnte ich durch hardwaremässige Impulsverdoppelung mit 4 KHz auskommen. Dennoch möchte ich es OHNE die Accelstepper machen, damit ich für anfahren und bremsen verschiedene Rampen nutzen kann, den bei einem Not-Stopp sollte die bremsrampe so kurz wie nur irgendmöglich , bis nicht vorhanden sein. Accelstepper benutzt eine einmal eingestellte Rampe leider immer.

Gruss Stefan

p.s. im Moment kann ich leider nicht testen, bin grad beim Packen für meinen Umzug nächsten Donnerstag. 

postmaster-ino

Hi

Gerade mit gespielt - jupp, beim Setzen von SOLL=IST bremst AccellStepper auf Null ab, dreht um, beschleunigt die halbe Strecke, bremst die halbe Strecke ab und steht an dem Punkt, wo man 'Not-Stop' gesagt hat.
... unschön ...
Krücke: Setze die Beschleunigung auf 50000
Code: [Select]

stepper.setAcceleration(50000);
stepper.move(0);

In meinem Test-Sketch kann ich move(0) nicht benutzen, da ich interne Variablen für SOLL verwende und Diese absolut per moveto() an die Lib verfütter.

Das sollte den Stepper unmittelbar anhalten - hier wird der Treiber wohl vom Stepper 'gut was auf die Backen' bekommen - muß Er dann aber wohl durch.
Meinen 28BYJ-48 schadet diese Behandlung gar nicht - Alles Andere hätte mich, bei der Stepper-Klasse, aber auch schwer gewundert ;)

Die aktuelle Beschleunigung kann man nicht auslesen, spätestens nach einem solchen Not-Stop muß man aber eh den ganzen Kram neu initialisieren, auch wird man prüfen müssen, ob wir noch 'auf Fleck' stehen, oder doch Schritte flöten gingen.

MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

Deltaflyer

Ja, wie gesagt, bisher hatte ich es mit der Accelstepper am Laufen, hatte da für den Notstop einen "hardware workaround" drin damit beim Notstop nicht langsam abgebremst wird. Anfahren MUSS ich aber langsam, da der steper die 26KG Last nicht aus dem Stand mit voller Geschwinndigkeit in bewegung zu versetzen mag, Er bleibt dann einfach stehen uns schreit ganz fürchterlich. Aber auch die normale Bremsrampe , am Ende der Fahrstrecke darf einiges kürzer als die Anfahrrampe sein, deshalb und wegen der Pulsfrequenz von 8 KHz eben OHNE Accelstepper. Ansonsten finde ich diese lib sehr gut.

Ich brauche hier einfach mehr Kontrolle über den Stepper.
Gruss Stefan

agmue

#7
Apr 23, 2019, 12:34 pm Last Edit: Apr 23, 2019, 12:48 pm by agmue
Jetzt mein Problem: Ich weiss nicht, wie man so ne Anfahr-Rampe (Beschleunigungs-Rampe) programiert.
Ich konzentriere mich mal auf diese Fragestellung.

Eine Anfahr-Rampe bedeutet bei Beschleunigung, die Zeit an STEP von fallender zu fallender Flanke zu verringern. Zur Veranschaulichung läßt man mal eine LED gemütlich blinken:

Code: [Select]
const uint16_t DELTA = 50;
uint32_t jetzt, vorhin, intervall = 1000;
bool status = HIGH;

void setup(void) {
  Serial.begin(9600);
  Serial.println("Anfang");
  pinMode (LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, !status);
}

void loop() {
  jetzt = millis();
  if (jetzt - vorhin >= intervall)
  {
    vorhin = jetzt;
    digitalWrite(LED_BUILTIN, status);
    if (!status)
    {
      if (intervall > 100) intervall -= DELTA;
    }
  status = !status;
  Serial.println(intervall);
  }
}

Der serielle Monitor zeigt die kleiner werdende Zeit. OK?

Das beschleunigt gibt dann diese errechneten Zeiten:

1062
1012
1012
962
962
912
912
862
862
812
812
762
762
712
712
662
662
612
612
562
562
512
512
462
462
412
412
362
362
312
312
262
262
212
212
162
162
112
112
62
62
62
62
62
62


Die serielle Ausgabe ist aber so schnarchend langsam, daß sie entfernt werden muß:

Code: [Select]
const uint16_t DELTA = 50;
uint32_t jetzt, vorhin, intervall = 1062;
bool status = HIGH;

void setup(void) {
  Serial.begin(9600);
  Serial.println("Anfang");
  pinMode (LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, !status);
}

void loop() {
  jetzt = micros();
  if (jetzt - vorhin >= intervall)
  {
    vorhin = jetzt;
    digitalWrite(LED_BUILTIN, status);
    if (!status)
    {
      if (intervall > 62) intervall -= DELTA;
    }
  status = !status;
  //Serial.println(intervall);  // nur zum Anschauem der Zeiten
  }
}

Die so zu erzielende Frequenz liegt bei 8 kHz:



Es gibt schnellere Alternativen für digitalWrite, wie beispielsweise Pin.h aus Schnelle Digital Eingabe/Ausgabe.
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

Deltaflyer

Herzlichen Dank agmue,
ich werde mich in den nächsten tagen, nach meinem Umzug, damit auseinandersetzen und damit experimentieren. Auch für den Hinweis auf die PIN.h danke ich Dir. habe jenen thread kurz durgesehen und das scheint genau das Richtige zu sein, um während der Pulsausgabe genügend Zeit für die notwendigen Überwachungen einzusparen.

Kann gut sein, dass ich es damit schaffe, Überwachung und (schnelle) Bewegung des Antriebs alles mit einem einzigen Controller zu machen.

Ich habe Deinen Code noch nicht vollständig verinnerlicht, darum die Frage: mit velcer Variable bestimme ich, wie LANGE die Rampe ist? Also wie lange es dauert vom start, bis die 8khz erreicht sind?

Ach ja, danke dass Du hier auf meine Kernfrage, nämlich "wie programmiert man so ne Rampe" eingegangen bist.

Gruss Stefan

agmue

mit velcer Variable bestimme ich, wie LANGE die Rampe ist? Also wie lange es dauert vom start, bis die 8khz erreicht sind?
Mit DELTA, großer Wert sind große Schritte bis ins Ziel und umgekehrt.

Klemm Dir beim Umzug die Finger nicht ein, sonst kann Programmieren schmerzhaft sein.
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

Deltaflyer

Klemm Dir beim Umzug die Finger nicht ein, sonst kann Programmieren schmerzhaft sein.

Ich versuche dies tunlichst zu vermeiden.


Läst sich DELTA irgendwie auf millisekunden umrechnen?

agmue

Läst sich DELTA irgendwie auf millisekunden umrechnen?
DELTA ist eine vorzeichenlose Konstante ohne physikalische Einheit. Erst zusammen mit millis() oder micros() sind es Millisekunden oder Mikrosekunden.

Außerdem 1 Millisekunde = 1000 Mikrosekunden (1 ms = 1000 µs)
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

Deltaflyer

Ja, ist ja eigentlich logisch, meine Frage war sehr ungünstig formuliert. Meine Frage zielte darauf ab, ob ich die Rampenlänge irgendwie in microsekunde festlegen , und daraus den erforderlichen Wert für DELTA errechnen kann.

Ich habe jedoch inzwischen herausgefunden, dass ich dazu das ganze am besten so umschreibe, dass die gesamte beschleunigung dierekt mit mikrosekunden arbeitet.

Deine Hilfe hat mir jedoch gezeigt, wie ich eine beschleunigung prinzipiell programmieren muss, dadurch ist meine Bitte nach nem Tritt in die richtige Richtung von Dir voll und ganz erfüllt. Dankeschön!

Ich habe auch schon die Impulserzeugung dahingehend angepasst, dass ich Impule mit fix definierter Länge zwischen 5 und 20 Mikrosekunden erhalte.

Ich verändere beim beschleunigen also nur die Impuls-Pause , wobei die kürzeste Pause eben so eingestellt ist, dass eine Periodenzeit von maximal 125 Mikrosekunden entsteht, so dass meine geforderten 8Khz erreicht werden.

Ich werde sicher auch noch das schnelle Pinschalten einbinden, damit ich hoffentlich genug Reserve bekomme, um auch meinen Encoder einzulesen zur prüfung, wann das ende der Fahrstrecke wirklich erreicht ist.

Aber inzwischen denke ich, dass dies durchaus möglich ist.
Habe ja auch noch etwas zusätzliche reserve, da mein Atmega 2560 mit einem 20MHz Quarz , und damit etwa 25% schneller als ein normales Mega-Board läuft. (Der Chip arbeitet hir ich einer stand alone Umgebung).

Gruss Stefan


Go Up