Kosinus förmige Beschleunigungskurve eines Nema 17 Schrittmotors mit einem L298N Motortreiber über einen Raspberry Pi 4 mit Python

Registriere dich jetzt, um exklusive Vorteile zu genießen! Als registriertes Mitglied kannst du Inhalte herunterladen und profitierst von einem werbefreien Forum.
Mach mit und werde Teil unserer Community!
  • Hallo!
    Wie der Titel von diesem Beitrag schon aussagt, möchte ich einen Schrittmotor Kosinus förmig auf eine maximal Geschwindigkeit beschleunigen.

    Um einen Schrittmotor zu beschleunigen, muss ja zwischen den einzelnen Schritten die Wartezeit immer weiter verkürzt werden.

    Zu Beginn möchte ich also eine Wartezeit zwischen den Schritten von 0,005 sec haben und bei der maximalen Geschwindigkeit eine Wartezeit von 0,0005 sec.

    Für die Beschleunigung soll in diesen Beispiel 30 Schritte verwendet werden.

    Hierfür habe ich eine Kosinus Funktion ausgelegt, welche folgendermaßen verläuft:


    Um diese in Python umzusetzen habe ich folgenden Code geschrieben wo bei der Funktion perform_steps eine Schrittanzahl übergeben wird:

    Die durch die Funktion berechneten Werte entsprechen exakt denen wie ich sie in Excel zuvor berechnet habe und somit auch den Werten wie sie im ersten Diagramm dargestellt sind.

    Ich würde nach diesem Code folgenden Geschwindigkeitsverlauf des Motors erwarten (Skalierung in Y-Achse ist unrelevant ist nur eine beispielhafte Darstellung):


    Tatsächlich aber fährt der Motor zu Beginn die Kurve so wie er soll aber sobald er die kleinste Wartezeit dauerhaft annimmt verfährt er mit einem Ruck viel schneller. Er geht also nicht flüssig in die höchste Geschwindigkeit über. Das schaut dann ungefähr so aus:

    Zur Hardware:

    Ich verwende einen L298N Motortreiber sowie einen Nema 17 Schrittmotor.

    Des Weiteren verwende ich einen Raspberry Pi 4.

    Der Aufbau gleicht folgender Darstellung:

    Anzumerken ist dabei vllt. noch dass ich das gleich Problem auch bei einer einfacheren Beschleunigungsrampe hatte also einer linearen Beschleunigung, weshalb ich glaube dass es kein Softwarefehler sonder eher was mit der Hardware zu tun hat.


    Für Hilfe wäre ich sehr dankbar.

    Mit freundlichen Grüßen

  • Go to Best Answer
  • Da der Pi kein Echtzeit-Betriebssystem hat, ist nicht auszuschließen, dass du bei den vielen kurzen Zeiträumen, die du berechnen und steuern musst, irgendwo Aussetzer bekommst. Sicherer wäre es, den Motor mit einem Microcontroller zu steuern, dem die wiederum z. B. per UART-Schnitttselle sagst, was der Motor machen soll. Die Schrittberechnungen macht dann der µC.

    Hier gibts ein sehr Interessantes Video, das auf deine Frage wohl ganz gut passt.


    Kann es sein, dass diese Kosinus-Berechnungen relativ lange dauern und du daher beim Rampenfahren längere Zeiten hast als du eigentlich haben willst - weil eben noch die Rechenzeit dazu kommt. Bei voller Geschwindigkeit entfällt wahrscheinlich die Rechnerei und du hast somit kürzere Zeiten.

    Delay ist hier eine ziemlich ungeeignete Art, die Zeit zu steuern, weil sämtliche Programmlaufzeiten noch zum Delay dazu kommen. Deshalb schau dir obiges Video an, da wird das anders gemacht und man kann damit sogar mehrere Motoren parallel und koordiniert steuern.

    Oh, man kann hier unliebsame Nutzer blockieren. Wie praktisch!

    Edited once, last by Gnom ().

  • Hallo,


    für solche zeitkritischen Aktionen bietet sich 'sleep' nicht unbedingt an.

    Ich würde mal versuchen mit 'monotonic' bzw. 'monotonic_ns' und Zeitstempeln die Differenzen anzuschauen und wenn die gleich der Wartezeit sind, den Programmablauf fortsetzen.

    https://docs.python.org/3/library/time.html#time.monotonic


    Um den Code an sich genau anzuschauen fehlt mir gerade die Zeit, eventuell heute Abend.


    Grüße

    Dennis

    🎧 Marylin´s Befehle an meine Junge Seele hör ich in jedem Lied. Heimlich eingegeben, in mein Innenleben, durch den Hard-Rock Beat 🎧

    • Best Answer

    Kann es sein, dass diese Kosinus-Berechnungen relativ lange dauern und du daher beim Rampenfahren längere Zeiten hast als du eigentlich haben willst - weil eben noch die Rechenzeit dazu kommt.

    12 ms bei 3200 Schritten auf einem RPi0W2.


    Testcode nur für Kosinus-Berechnung:


    Code
    In [1]: %timeit run_acc_dacc(STEPS, A, T, C)
    11.5 ms ± 99 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)


    Also daran liegt es nicht. Auch wenn das der Fall wäre, kann man immer noch im Voraus berechnen und erst dann die Schritte ausführen. Das machen manche Industrieroboter auch. Dann wird vorher die Bahn berechnet, um 5 oder 6 Servos simultan anzusteuern, und zwar so, dass im Raum eine lineare Bewegung des Manipulators stattfindet.



    Ich würde auch eher in Richtung Ansteuerung, Controller und Schrittmotor gehen. Möglicherweise ist der Fehler dort.


    Um Fehler mit der Software komplett auszuschließen, würde ich einfach eine Be- und Entschleunigung im Voraus berechnen, dann iterieren und die GPIOs ansteuern, die schon in der Liste für jeden Schritt gespeichert sind.

  • Huge711 Anmerkungen zum Quelltext: Eingerückt wird in Python vier Leerzeichen pro Ebene.


    Namen sollten keine kryptischen Abkürzungen enthalten, oder gar nur daraus bestehen. `kp` und `ki` beispielsweise.


    Namen sollten auch nicht nummeriert werden. Dann will man sich entweder bessere Namen überlegen oder gar keine Einzelnamen und -werte sondern eine Datenstruktur verwenden. Oft eine Liste. So auch bei `out_pin_1` bis `out_pin_4`. Die Werte werden dann ja sowieso in eine Liste gesteckt. Da greift man dann später auch nicht mit hart kodierten Indexwerten von 0 bis 3 drauf zu, sondern schreibt eine Schleife oder nutzt das man bei GPIO auch eine Liste mit Pins an einige Funktionen übergeben kann. Zum Beispiel `setup()`, dem man sogar noch einen initialen Wert angeben kann und sich so ein separates `output()` auch noch sparen kann. Und beim setzen von Ausgaben kann man sogar Listen mit Werten, einen pro Pin übergeben, statt nur einen einzelnen Wert für alle Pins.


    5 von den 11 Attributen sind im gezeigten Code unbenutzt. 11 Attribute sind auch schon reichlich viel für *eine* Klasse. Wobei fast alles was benutzt *wird* sehr nach Konstanten aussieht, die man vielleicht auch eher als solche auf die Klasse verschieben könnte. `self.delay` sollte wohl auch gar kein Attribut sein, denn im gezeigten Code wird der initiale Wert nie verwendet, und das Attribut selbst könnte einfach eine lokale Variable in `perform_steps()` sein.


    Bei `perform_steps()` wird das `direction`-Argument nicht verwendet.


    Die Schrittanzahl sollte wohl immer eine ganze Zahl sein. Das erfüllt die Methode nur in allen Fällen falls das übergebene `amount_steps` gerade ist.


    Bei dem ``if`` sind alle Klammern überflüssig.


    ``for in in range(len(sequence)):`` um dann nur mit dem Laufindex auf Elemente von `sequence` zuzugreifen ist in Python ein „anti pattern“. Man kann direkt über die Elemente von Sequenztypen iterieren, ohne den unnötigen Umweg über einen Indexzugriff. Das im Code statt ``len(sequence)`` die Länge manuell hart kodiert ist, macht das ganze fehleranfälliger beim Schreiben und Warten vom Code.


    Da steht im Grunde nahezu der gleiche Code dreimal in der Methode. Das sollte man in eine eigene Methode herausziehen.


    Ungetestet:

    „Eat the rich — the poor are full of preservatives.“ — Rebecca ”Becky” Connor, The Connors

  • Hallo,


    das wird ja nicht die ganze Klasse sein, den 'ki' und 'kp' wird gar nicht benutzt, aber ich vermute mal dass da noch irgendwo ein PI(D)-Regler auftauchen wird und da wäre 'ki' und 'kp' gebräuchliche Bezeichnungen in der Regelungstechnik: https://en.wikipedia.org/wiki/PID_controller

    Sonst würde ich aber auch keine weiteren genutzten Abkürzungen verteidigen wollen :)



    Grüße

    Dennis

    🎧 Marylin´s Befehle an meine Junge Seele hör ich in jedem Lied. Heimlich eingegeben, in mein Innenleben, durch den Hard-Rock Beat 🎧

  • Da der Pi kein Echtzeit-Betriebssystem hat, ist nicht auszuschließen, dass du bei den vielen kurzen Zeiträumen, die du berechnen und steuern musst, irgendwo Aussetzer bekommst. Sicherer wäre es, den Motor mit einem Microcontroller zu steuern, dem die wiederum z. B. per UART-Schnitttselle sagst, was der Motor machen soll. Die Schrittberechnungen macht dann der µC.

    Hier gibts ein sehr Interessantes Video, das auf deine Frage wohl ganz gut passt.


    Kann es sein, dass diese Kosinus-Berechnungen relativ lange dauern und du daher beim Rampenfahren längere Zeiten hast als du eigentlich haben willst - weil eben noch die Rechenzeit dazu kommt. Bei voller Geschwindigkeit entfällt wahrscheinlich die Rechnerei und du hast somit kürzere Zeiten.

    Delay ist hier eine ziemlich ungeeignete Art, die Zeit zu steuern, weil sämtliche Programmlaufzeiten noch zum Delay dazu kommen. Deshalb schau dir obiges Video an, da wird das anders gemacht und man kann damit sogar mehrere Motoren parallel und koordiniert steuern.

    Hallo und erst einmal vielen Dank für die vielen Antworten!
    Tatsächlich hat sich herausgestellt dass die Berechnung anscheinend viel zu lang gedauert hat. Ich habe die Berechnung jetzt vor die einzelnen Schleifen gepackt und alle Werte in einer Liste gespeichert und tatsächlich hat dass das Verhalten so beeinflusst, das die Bewegung jetzt dem erwarteten Verlauf entspricht also viel Dank für die Hinweise DeaD_EyE und Gnom !

    Den Delay habe ich jetzt noch nicht ausgetauscht aber habe es vor wie von Dennis89 vorgeschlagen zu ersetzen.

    Nochmals Danke!

    Des Weiteren auch Danke an __blackjack__ für deine Anmerkungen zum Code an sich.

    Ich habe jetzt wie du vorgeschlagen hast, die Pins als eine Liste übergeben und alle GPIO Anweisungen nicht mehr mittels hardcodierter Indexe aufgerufen sondern jeweils in einer Schleife. Außerdem habe ich die Konstanten wo ich am Anfang in Attributen hinterlegt hatte in die Klasse ausgelagert. Da ich alle Zeiten in einer Liste zusammenführe und somit nicht mehr dreimal für Beschleunigung, Konstantes Verfahren und Bremsen eine eigene Schleife brauche, habe ich es jetzt auch nicht in eine eigene Funktion ausgelagert. Das einrücken um vier Leerzeichen werde ich in Zukunft beherzigen (hatte auch scon ein bisschen Probleme mit der Leserlichkeit PS: Ist in dem unteren Beispielcode noch nicht umgesetzt wird aber noch gemacht)

    Wie auch von Dennis89 angemerkt waren die Attribute ki und kp anfänglich mal für einen PI Regler gedacht und ich hatte sie vergessen zu entfernen aber trotzdem danke für den Hinweis.



    Mein Code schaut jetzt folgendermaßen aus: