Seite 6 von 15
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Freitag 18. März 2022, 22:41
von Dennis89
Guten Abend,
die Woche lief leider so überhaupt nicht wie geplant. Ich hatte leider nicht wirklich viel Zeit für das Projekt, deswegen melde ich mich erst heute wieder.
Die Werte der open Loop fahrt habe ich aufgezeichnet,
die Position in Schritten des Encoders und die
die Zeit in Mikrosekunden
Jetzt habe ich leider den Code dazu nicht mit hier her genommen. Auf jeden Fall habe ich pwm.duty auf 100 gesetzt und dann in einer Schleife die Position des Encoders und die Zeit in Mikrosekunden aufgenommen und das ganze im 0,01 Sekunden Takt. Also wie der Soll-Ist-Vergleich auch.
Nun habe ich mal die Beschleunigung ausgerechnet und die zwei Werte "T" und "L". Bin aber gerade erst fertig geworden und konnte es noch nicht testen.
Aber mein Gefühl sagt mir dass die Werte so nicht hinhauen, ich zeig euch trotzdem mal was ich gerechnet habe. Die Konstanten sind die verlinkten Werte als Listen.
Von der Programmierung her geht das ein oder andere sicherlich noch eleganter, aber darauf habe ich gerade keinen Wert gelegt, weil ich mich erst mal auf die Rechnungen konzentrieren wollte. Die Beschleunigung habe ich nur interessehalber berechnet.
Mal noch etwas zu meinen Gedanken dabei. Mit den Positionen und den dazugehörigen Zeitabschnitten kann ich den Weg wieder grafisch darstellen. Die Zeit in der beschleunig wird, wird parabellförmig aussehen und bei voller Drehzahl wird eine Gerade mit konstanter Steigung entstehen (wohl gemerkt, in einer Welt ohne Reibung etc.). Da ich keine mathematische Funktion habe, die den Weg darstellt, musste ich mir was anderes überlegen um den Wendepunkt und damit den Anfang der Gerade zu bestimmen. Also dachte ich mir, ich berechne für jede Position die Steigung und vergleiche sie mit der nächsten und wenn beide gleich sind, dann habe ich den Anfang meiner Geraden gefunden. Naja das hat dann erst funktioniert, nachdem ich das Runden auf 5 Stellen in den Vergleich einbezogen habe.
Für meine Werte "T" und "L" muss ich die Gerade verlängern, bis sie die x-Achse schneidet (das tut sie bei y=0) und einmal benötige ich den Wert der x-Achse wenn die Gerade die Endposition schneidet (y=Endposition). Da mir die Werte komisch vorkommen, habe ich das mir mal grafisch ausgeben lassen und man sieht, dass es keine konstante Steigung gibt, was zu erwarten war und man auch in früheren Aufzeichnungen schon gesehen hat.
Naja jetzt hier mal der Code:
Code: Alles auswählen
from matplotlib import pyplot as plt
def draw_graphics(straight_line):
plt.plot(TIME_STAMP, POSITIONS, color='r')
plt.plot(TIME_STAMP, straight_line, color='g')
plt.xlabel("Zeit")
plt.ylabel("Step")
plt.show()
def calculate_pitch():
pitches = [(POSITIONS[index + 1] - position) / (TIME_STAMP[index + 1] - TIME_STAMP[index]) for index, position in
enumerate(POSITIONS) if index + 1 < len(POSITIONS)]
for index in range(len(pitches)):
if index + 1 < len(pitches):
if round(pitches[index], 5) == round(pitches[index + 1], 5):
if not index == 0:
return pitches[index], index
def calculate_acceleration(end_acceleration):
# 10**6 -> microsecond in second
return 2 * POSITIONS[end_acceleration] / (TIME_STAMP[end_acceleration] * 10**-6)**2
def calculate_y_axis_section(end_acceleration, pitch):
# equation of a straight line: y(x) = pitch * x + y_axis_section
return POSITIONS[end_acceleration] - (pitch * TIME_STAMP[end_acceleration])
def calculate_constants(pitch, y_axis_section):
# equation of a straight line: y(x) = pitch * x + y_axis_section
# y(x) = 0
delay_time = -y_axis_section / pitch
# y(x) = Endposition
constant_time = (POSITIONS[-1] - y_axis_section) / pitch
return delay_time, constant_time
def calculate_straight_line(pitch, y_axis_section, end_acceleration):
return [(pitch * x) + y_axis_section if x > TIME_STAMP[end_acceleration] else None for x in TIME_STAMP]
def main():
pitch, end_acceleration = calculate_pitch()
print(f'Pitch: {pitch}')
print(f'Acceleration: {calculate_acceleration(end_acceleration):0.2f} 1/s²')
y_axis_section = calculate_y_axis_section(end_acceleration, pitch)
delay_time, constant_time = calculate_constants(pitch, y_axis_section)
print(f'L: {delay_time}')
print(f'T: {constant_time}')
straight_line = calculate_straight_line(pitch, y_axis_section, end_acceleration)
draw_graphics(straight_line)
if __name__ == '__main__':
main()
Soviel zu meinem aktuellen Stand. Vielleicht beurteilst du/ihr die Werte auch anders, aber für mich sieht es falsch aus. (Trotzdem wollte ich den Stand mal vorstellen, allein das aufschreiben hier, hat einen anderen Fehler zum Vorschein gebracht. Dafür hat es schon geholfen)
Grüße
Dennis
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Freitag 18. März 2022, 22:57
von __deets__
Ich bin im Harz und habe nur das Telefon, darum kann ich das nicht gut beurteilen. Aber wie sieht dann die Beschleunigungskurve aus?
Was die Analyse dann angeht: das kannst du doch von Hand machen, auch wenn eine automatische natürlich “cool” ist.
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Freitag 18. März 2022, 23:29
von Dennis89
Das eilt auch nicht, vor morgen Mittag komme ich eh nicht in die Werkstatt. Bitte keine Umstände wegen mir.
So sieht die Kurve aus
Wie meinst du das von Hand? Schon rechnerisch oder ausgedruckt mit Stift und Papier?
Danke und Grüße
Dennis
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Freitag 18. März 2022, 23:53
von __deets__
Zur Kurve: die sollte schon in die Sättigung der Drehzahl gehen. Das ist dann ja der Punkt ab dem die Antwort auf 100% erreicht ist.
Und zur Analyse: ich habe das Verfahren gerade aus genannten Gründen nicht vor den Augen. Aber die Gerade muss doch angelegt werden an eben den ja gut sichtbaren Geraden Teil. Und händisch würde dann doch reichen, dass du den Startzeitpunkt und Endzeitpunkt der Geraden via zweier Konstanten einfach Angibst. Der Positionswert kommt dann einfach aus der Aufzeichnung, und zwischen diesen beiden Punkten ziehst du die Gerade.
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Samstag 19. März 2022, 09:03
von __deets__
Ich habe einen Denkfehler gemacht: die Kurve der Position sieht natürlich nicht s-förmig aus, wenn man einfach nur Gas gibt. Das ist nur der Fall beim Auftrag von Geschwindigkeit auf Zeit! Nimm doch mal deine Daten & berechne pro Schritt die Geschwindigkeit, indem du die Differenz zweier aufeinanderfolgender Schritte durch deren time Delta teilst. Wie sieht das dann aus?
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Samstag 19. März 2022, 10:37
von Dennis89
Guten Morgen,
und danke für deine Antwort.
Du meinst sowas(?):
Code: Alles auswählen
def calculate_velocity():
return [(POSITIONS[index + 1] - position) / (TIME_STAMP[index + 1] - TIME_STAMP[index]) for index, position in
enumerate(POSITIONS) if index + 1 < len(POSITIONS)]
Das würde dann
so aussehen
Grüße
Dennis
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Samstag 19. März 2022, 12:32
von __deets__
Hm. Das sieht nicht so aus wie ich mir das gedacht hätte. Ich muss mal die Daten anschauen. Gegebenenfalls ist die Regelung durch die Schrittauflösung beschränkt. Falls dem so ist, müsste ggf nochmal untersetzen.
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Samstag 19. März 2022, 13:08
von Dennis89
Die Achse, die das Rohr dreht, wird über einen Riemen angetrieben, also eine Untersetzung wäre da kein Problem.
Wie hast du dir denn gedacht, wie das Diagramm aussehen sollte? Hätte ich einen Encoder mit höherer Auflösung benötigt?
Danke und Grüße
Dennis
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Samstag 19. März 2022, 14:30
von __deets__
Na wie in den Ziegler-Nichols Artikeln. Auch eine S-Kurve, die hier ja aber natürlich ist: es wird statische Reibung überwunden, dann linear beschleunigt, und dann asymptotisch gegen V max gegangen.
Und ja, encoder Auflösung ist kritisch. Da würde ich immer eher höher als niedriger gehen, im Rahmen des Budgets natürlich.
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Samstag 19. März 2022, 15:04
von Dennis89
Achso so war das gemein.
Siehst du denoch eine Chance, unabhängig von der Methode, den Regler sauber einzustellen oder wäre das jetzt vergebene Mühe und ich mache erst weiter, wenn der Motor an der Maschine angebaut ist und ich das Encoder-Signal an der Untersetzung abnehme?
Ich/wir haben uns für die 1000er Auflösung entschieden, weil der eigentlich nur dazu dienen sollte, die Endposition abzufrgaen. Das ich da einen Regler brauche, war mir nicht klar. Aber selbst wenn, hätte ich mangels Erfahung vielleicht trotzdem den falschen gewählt.
Vielen Dank und Grüße
Dennis
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Samstag 19. März 2022, 17:16
von __deets__
Also ich denke erstmal schon, dass da noch was geht. Soooo viel haben wir da ja noch nicht probiert. Du hast auch noch gar nicht den Code gezeigt, mit dem du die Daten für die Step Response aufzeichnest. Vielleicht ist da was schief.
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Samstag 19. März 2022, 19:26
von Dennis89
Stimmt, ich war gerade in der Werkstatt und habe den Code mal vom ESP kopiert.
In der 'boot.py' wird der Wlan-Access-Point ereitgestellt, nach
diesem Beispiel (das habe ich vergessen zu kopieren).
Dann läuft auf dem ESP folgender Code:
Code: Alles auswählen
from machine import Pin, ADC
from esp32 import MCPWM, PCNT
from time import sleep, ticks_us, ticks_diff
from LargeCounter import LargeCounter
from PathPlanner import PathPlanner
from PID import PID
try:
import usocket as socket
except:
import socket
import json
PWM_PINS = [[16, 17], [5, 23]]
ENCODER_PINS = [15, 2]
KP = 0.03
KI = 0
KD = 0
class WeldingControl:
def __init__(self):
encoder = PCNT(0, Pin(ENCODER_PINS[1]), Pin(ENCODER_PINS[0]))
encoder.filter(100)
self.count_angle = LargeCounter(encoder)
self.welding_axis = MCPWM(0)
self.welding_axis.bind(Pin(PWM_PINS[0][0]), Pin(PWM_PINS[0][1]))
self.welding_axis.duty(0)
self.path = PathPlanner(45, 180, 45, 0.1)
self.pid = PID(KP, KI, -KD)
self.actually_pos = []
self.should_pos = []
self.time_stamp = []
self.record_motor_conduct()
# self.open_loop()
def open_loop(self):
start = ticks_us()
while True:
sleep(0.01)
time_ = ticks_diff(ticks_us(), start)
actually_position = self.count_angle.counter()
self.welding_axis.duty(100)
if actually_position >= 500:
self.welding_axis.duty(0)
break
self.actually_pos.append(actually_position)
self.time_stamp.append(time_)
def record_motor_conduct(self):
start = ticks_us()
while True:
sleep(0.01)
time_ = ticks_diff(ticks_us(), start)
should_be_position = self.path(time_ / 1000)
actually_position = self.translate_into_angle(self.count_angle.counter())
new_pwm = self.pid(should_be_position - actually_position, time_)
self.welding_axis.duty(new_pwm)
if actually_position >= 270:
self.welding_axis.duty(0)
break
self.should_pos.append(int(should_be_position))
self.actually_pos.append(actually_position)
self.time_stamp.append(time_)
def translate_into_angle(self, value):
return 360 * value // 1000
def listen_and_connect(pid_values):
while True:
cl, addr = s.accept()
print("client connected from", addr)
cl_file = cl.makefile("rwb", 0)
while True:
line = cl_file.readline()
if not line or line == b"\r\n":
break
response = pid_values
cl.send("HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n")
cl.send(response)
cl.close()
def make_json(welding_control):
pid_values = [
welding_control.time_stamp,
welding_control.should_pos,
welding_control.actually_pos,
]
return json.dumps(pid_values)
def main():
welding_control = WeldingControl()
pid_values = make_json(welding_control)
listen_and_connect(pid_values)
if __name__ == "__main__":
main()
Auf meinem Laptop läuft dann dieser Code:
Code: Alles auswählen
#!/usr/bin/env python3
import requests
import matplotlib.pyplot as plt
def draw_graphics(time_stamp, should_be_position, actually_position):
plt.plot(time_stamp, actually_position, color="r", label="Ist-Wert")
plt.plot(time_stamp, should_be_position, color='g', label='Soll-Wert')
plt.xlabel("Zeit")
plt.ylabel("Winkel")
plt.title("Soll-Ist-Vergleich")
plt.legend()
plt.show()
def translate_into_list(content):
return content[0], content[1], content[2]
def main():
content = requests.get("http://192.168.4.1").json()
time_stamp, should_be_position, actually_position = translate_into_list(content)
draw_graphics(time_stamp, should_be_position, actually_position)
if __name__ == "__main__":
main()
Also mit diesen zwei Dateien entstehen meine hier gezeigten Diagramme.
Grüße
Dennis
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Sonntag 20. März 2022, 20:28
von __deets__
Ich hoffe mal den Test hast du auch im open loop gemacht? Im code oben ist das ja auskommentiert. Allerdings sehen die Daten “gut” bzw passend dazu aus. Zu dem Code: da lässt sich nichts pathologisches erkennen. Aber durchaus stilistisch verbessern. Zb andauern die PWM auf 100 statt einmal zu setzen. Und die Code dopplung der Zeiterfassung in beiden Ansteuerungen, statt das einmal zu machen un im Loop zb via callback eine der beiden Methoden zu nutzen. Aber natürlich nur kosmetisch das ganze. Und bei den Daten Links habe ich zweimal die Positionen gefunden, statt einmal Positionen und einmal Zeit.
Letztlich aber habe ich leider schlechte Nachrichten: wenn das die Encoder Positionen bei Vollgas sind, dann haben wir da ~6 Schritte pro Zeitschritt. Und mit 100 (eigentlich weniger, weil deine Zeitberechnung nicht optimal ist) schritten pro Sekunde ist das ein viel zu geringer wert aus meiner Sicht. Denn da ist ja ein Schritt gleichbedeutend mit 16% Geschwindigkeitsdifferenz. Wenn ich dir die Aufgabe gebe, Tempo 50 zu halten, und der Tacho schwankt zwischen 40 & 56 wild hin und her - da machst du auch nix.
Da kannst du aus meiner Sicht nur Vollgas fahren. Und das Gesamtsystem darauf auslegen. Oder wahlweise die Motorgeschwindigkeit oder Encoderauflösung deutlich erhöhen. Aber leider denke ich zu deutlich. Bzw was natürlich auch ginge: den Encoder an den Motor *vor* dem Getriebe zu hängen, wenn der das zulässt.
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Montag 21. März 2022, 00:08
von Dennis89
Guten Abend,
danke für deine ausführliche Antwort und für die Analyse meiner Positionsdaten.
Erst mal sorry, das ich zwei mal den gleichen Link gepostet habe.
Die Positionen und
die Zeiten
Ja das wurde im open loop gefahren. Auskommentiert wurde das nur, weil ich mit dem Regler nochmal etwas gespielt hatte.
Deine Anmerkungen zum Code werde ich mal einpflegen. Hoffentlich wird die kommende Woche etwas entspannter.
Das sind natürlich wirklich schlechte Nachrichten. Den Encoder kann ich so nicht direkt an den Motor anbauen. Das ist alles mehr oder weniger eine Einheit. Ich schau mir das noch mal an, aber so wie ich es in Erinnerung habe, sehe ich da schwarz.
Dann muss ich jetzt wohl warten bis die Maschine steht und das einfach mal laufen lassen und sehen wie sich das System verhält.
Jetzt ist es schon etwas spät, ich muss morgen noch mal über deine Antwort mit der Geschwindigkeiterhöung des Motors nachdenken. Spontan hätte ich gesagt, wenn meine Auflösung des Encoders zu gering ist, dann muss der Motor langsamer laufen um alles ordentlich aufzeichnen zu können. Das muss ich mir morgen in Ruhe noch mal durch den Kopf gehen lassen. Habe ehrlich gesagt deine Nachricht gerade erst gesehen und ich antworte jetzt noch, damit die richtigen Links zu den Messdaten vorhanden sind.
Grüße und gute Nacht
Dennis
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Montag 21. März 2022, 08:04
von __deets__
Wenn der Motor bei Vollgas 6 Schritte pro Zeitschritt macht, dann macht er bei langsamerer Fahrt noch weniger pro Zeitschritt. Das hilft nicht.
Es gibt zwei Stellschrauben, wenn alles sonst bleibt: Erhöhung der Encoder Geschwindigkeit. Oder Vergrößerung des Zeitintervalls. Ersteres geht nur mechanisch. Wenn das Ding nicht an den Motor angeflanscht werden kann, dann ginge ggf auch eine Übersetzung via Riemenscheiben. Um also die Reduktion der Geschwindigkeit zu kompensieren. Das ist normalerweise ungünstig, weil es die Genauigkeit verringert. Da du aber nur eine Fahrt in eine Richtung hast, und einen Endschalter, ist das wahrscheinlich ok.
Die Alternative mit dem verlängerten Zeitintervall hat natürlich potentiell katastrophale Nachteile: wenn du zb auf 1/25 gehst, also das interval vervierfachst, dann kann das System uU einfach nicht mehr schnell genug reagieren.
Zu guter letzt: du musst die geregelte Fahrt so ansetzen, dass die bei vielleicht 80% der maximalen Geschwindigkeit liegt. Sonst hast du ja gar keinen Spielraum. Das sind dann konkret schon wieder nur 5 statt 6 Schritten pro Zeitschritt. Das heißt bei Abweichung vom nur einem Schritt ist man wieder bei Vollgas. Das geht in meinen Augen nicht.
Probier mal ein doppelt so langes interval. Und dann ein vierfaches. Und auch dafür sollte übrigens diese Wartezeit eine Kosntante sein, statt die einfach im Code stehen zu haben.
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Montag 21. März 2022, 08:38
von Dennis89
So guten Morgen,
der folgende Text ist entstanden, bevor du deinen letzten Post geschrieben hast. Ich lasse den mal unverändert, dann siehst du, wieso ich meinte den Motor langsamer laufen zu lassen.
__deets__ hat geschrieben: ↑Sonntag 20. März 2022, 20:28
Aber durchaus stilistisch verbessern. Zb andauern die PWM auf 100 statt einmal zu setzen. Und die Code dopplung der Zeiterfassung in beiden Ansteuerungen, statt das einmal zu machen [/quote ]
Dass der PWM-Wert in der Schleife steckt, ist mir durch die Lappen gegangen. Für den Rest den du erwähnt hast, habe ich keine plausible Ausrede.
__deets__ hat geschrieben: ↑Sonntag 20. März 2022, 20:28
dann haben wir da ~6 Schritte pro Zeitschritt.
Okay ich verstehe, wir haben das Problem, dass wir nicht wissen was "innerhalb" der 6 Schritte passiert. Das sehe ich ein, dass ist schlecht bis scheisse.
__deets__ hat geschrieben: ↑Sonntag 20. März 2022, 20:28
Oder wahlweise die Motorgeschwindigkeit oder Encoderauflösung deutlich erhöhen.
Ich habe pro Umdrehung 1000 Messpunkte. Wenn ich Vollgas gebe und wie im Code alle 0,01 Sekunden messe, dann wird während der Zeit von 0,01 Sekunden 6 Messpunkte überfahren. Dann hätte ich rein theoretisch und rechnerisch zwei Möglichkeiten um jeden Messpunkt zu erfassen. Entweder ich muss öfters messen, in dem Fall alle 0,00167 Sekunden oder ich muss den Encoder so langsam drehen, damit er nur alle 0,01 Sekunden an einem Messpunkt "vorbeikommt". Sind die Gedanken falsch bzw. übersehe ich etwas? Mal abgesehen von der dritten Möglichkeit, die höhere Encoderauflösung.
__deets__ hat geschrieben: ↑Sonntag 20. März 2022, 20:28
weil deine Zeitberechnung nicht optimal ist
Der Punkt würde mich auch noch interessieren. Ich hatte 'ticks_diff' so verstanden, dass das dafür gut ist. Die Probleme mit dem Überlaufen und die Probleme mit dem zu langen warten zwischen den Messungen, die in der Doku erwähnt sind, treffen bei mir meiner Meinung nach nicht zu.
Aber hier beziehe ich mich auf deinen neusten Post.
Leider kann ich dazu gar nicht viel schreiben, weil ich gerade nicht erkennen kann, was ich davon habe, wenn ich pro Zeitinterval mehrere Schritte "überfahre". Kannst du mir bitte sagen, wo ich mich da wieder verrannt habe?
Vielen Dank und Grüße
Dennis
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Montag 21. März 2022, 09:29
von __deets__
Du hast da eine komische Vorstellung. Es geht nicht darum, jeden Schritt einzeln zu erfassen. Das der Encoder mit dieser PCNT-Klasse behandelt wird, die Ja Spezial-Hardware im ESP anspricht, die einen eben genau davon befreit, dass man per CPU jeden einzelnen Flankenwechsel erfassen muss.
Jede Regelung, die ich kenne, arbeitet immer in einem festen interval. Die Geschwindigkeit, die man fährt, sind die Anzahl der gezählten Schritte, geteilt durch die Zeit. Wenn du im Auto sitzt, schaust du doch auch auf den Tacho alle paar Sekunden, statt zu versuchen, jede Radumdrehung mitzubekommen.
Und ich verstehe nicht, wieso du denkst, das würde irgendwie helfen. Dein Ziel ist eine bestimmte Geschwindigkeit. Nicht, so langsam zu fahren, dass der Zähler auch garantiert immer einen Schritt gemacht hat. Und die Geschwindigkeit variiert doch auch, mindestens & geplant in den Rampenphasen, aber faktisch immer. Woher nimmst du denn dann eine Adaption deines Messintervals her? Du kennst das doch gar nicht, weil wenn du es kennen würdest, wüsstest du schon alles über das System. Und musst gar nix mehr messen.
Nun ist der hier vielleicht unterliegende Gedanke, der dich da verwirrt, nicht komplett falsch: man kann natürlich statt Schritten / Zeit auch Zeit / Schritt bestimmen, und aus dem Kehrwert die Geschwindigkeit berechnen. Und da reicht uns dann eigentlich auch ein geringerer aufgelöster Encoder, weil es ja letztlich egal ist, wie man die Geschwindigkeit ermittelt. Das dreht dann aber die Regelung auf den Kopf: du müsstest dazu die Pulse des encoders in einem Interrupt erfassen, und in dem Moment deine Regelung durchrechnen. Das ist aber Unsinn. Denn deine Regelung kostet Zeit. Und das immer gleich viel. Wenn man die jetzt also plötzlich von der Flanke triggers lässt, dann hat man diverse Probleme erzeugt:
1) die CPU Last steigt proportional mit der Geschwindigkeit an.
2) die maximale Geschwindigkeit ist dann beschränkt durch die Zeit, die deine Regelung dauert.
3) wenn dein Motor steht, läuft per Definition die Regelung nicht. Es muss also einen zweiten Mechanismus geben, der den anwirft, wenn du losfahren willst.
Summa summarum ist das also Quatsch. Theoretisch kann man einen hybriden Ansatz fahren: die Regelung läuft im interval, und die Geschwindigkeit wird im IRQ bestimmt. Aber das erlaubt immer noch nicht die Verwendung des PCNT (der befreit uns ja gerade davon!). Der ist aber kein Selbstzweck, nur bin ich skeptisch, dass man in micropython einen IRQ programmiert, der schnell & genau genug ist, um das zu schaffen. Das müsste dann schon C sein. Und wie gesagt: es ist ein Würgaround.
Zur Frage nach der Zeit: ticks_diff ist super. Das problem liegt woanders: du willst 100Hz erreichen. Aber was du machst ist
1) 0.01 Sekunden schlafen
2) wenn es gut geht, genau danach geweckt werden. Aber das OS garantiert das nicht, du hast also 0.01 + x geschlafen.
3) du tust Dinge, die auch Zeit kosten, y viel.
Summa summarum ist deine Frequenz also 1 /(0.01 + x + y). Also irgendwas kleiner als 100Hz.
Das ist ein Klassiker. Der Weg daraus besteht darin, die Wartezeit adaptiv zu machen: du berechnest einen zukünftigen Moment ausgehend vom Startzeitpunkt, und wartest so lange, bis der erreicht ist. Dann kommt zwar pro Schritt immer noch das x als Jitter dazu, aber x + y werden rausgerechnet.
Code: Alles auswählen
t = now()
while True:
tuwas() # y
t += interval
sleep(t - now()) # hier entsteht x, aber korrigiert sich ja wieder im nächsten sleep.
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Montag 21. März 2022, 09:40
von __deets__
Und noch ein Nachtrag: es ist nicht schlimm, nicht zu wissen, was in den 6 Schritten passiert. Das problem ist, dass es zu große Abweichung bedeutet, wenn ein schritt so viel Gewicht hat durch die geringe Auflösung. Wenn du 50% der maximalen Geschwindigkeit erreichen willst, dann sind das 3 Schritte/Interval. Beim nächsten Mal wirst du aber dann wahlweise 2, 3, oder 4 Schritte bekommen. Sprich: 34% oder 50% oder 66% der Geschwindigkeit. Keine Regelung der Welt kann vernünftig eingreifen, wenn eine Abweichung zwangsweise immer so groß ist. Entweder ist die so lax eingestellt, dass sie nicht hinterherkommt, wenn last aufkommt. Und beschleunigt auch nicht richtig. Oder so hart, das sie auf dem Gaspedal rumtanzt.
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Montag 21. März 2022, 12:16
von Dennis89
Vielen Dank für die sehr ausführliche Erklärung.
Erst mal was positives: Das mit 'sleep' habe ich verstanden.
Meine komische Vorstellung kam daher, da ich nicht begriffen habe, auf was du mit den 6 Schritten raus wolltest. Da habe ich mir dann etwas zusammengestrickt und eine Theorie überlegt, was du damit sagen hast wollen. Gut war Quatsch, aber immerhin habe ich es jetzt verstanden.
Deine ganze Erklärung plus folgender Satz:
Das problem ist, dass es zu große Abweichung bedeutet, wenn ein schritt so viel Gewicht hat durch die geringe Auflösung
hat mein Rätsel im Kopf gelöst.
Das ich 80% als maximale Geschwindigkeit ansehen soll, leuchtet mir auch ein.
Dann versuche ich das mit dem größeren Zeitinterval mal aus.
Hast du im Allgemeinen Erfahrungswerte was die Auflösung des Encoders angeht? Wie geht man bei der Auswahl vor? Was würdest du als maximale Gewichtung der einzelnen Schritte ansetzen?
Ich weis ja nicht wie sich das nachher im zusammengebauten Zustand verhält und wenn es gar nicht geht, dann wird man ja nicht drum herum kommen passende Hardware zu kaufen.
Vielen Dank und Grüße
Dennis
Re: Wie kompiliert man MicroPython vom Quellcode selbst?
Verfasst: Montag 21. März 2022, 12:45
von __deets__
. Ich hätte das alles durchgerechnet & dann das so abgeschätzt, dass ich im Rahmen einer von mir gesteckten Toleranz wäre, aber auch aus dem Bauch. Also etwa 1%. Sprich: eher 15000 Schritte. Deinen Encoder gibt’s ja auch mit 5000. Da sind 3% Schwankung, die in der Regelstrecke minimal auflaufen können. Wäre mir etwas zu hoch, aber vielleicht reicht es auch. Ich hatte mal einen Roboter aus einem Kunstprojekt zur Reparatur. Der war von Phillips Ingenieuren gebaut. Und hatte etwa 30K Schritte pro Umdrehung. Also ein halbes % auf deinen Fall umgerechnet. Das ging gut.