Projekt "StarTracker" Frage zu Nachkommastellen und Möglichkeiten

Hallo liebes Forum, :grinning:

mein momentaner Wissensstand beschränkt sich leider darauf, einen Schrittmotor (in einfachster Form) ansteuern zu können. Trotzdem habe ich vor, einen kleinen Astrotracker zu bauen, auf dem ich die Erdrotation für Milchstraßen-Aufnahmen ausgleichen kann. Ein 3D Drucker und genug Kram zum zusammenbrutzeln einer Steuerung ist vorhanden.

Nun bin ich auf folgende Frage gestoßen: Wie viele Nachkommastellen kann ein Arduino Nano unter realen Bedingungen umsetzen und rechnen?

Grund dafür ist dies:
Zum Ausgleich der Erdrotation muss das "nachführende Element" des Trackers sich an einem Tag genau ein Mal um sich selbst drehen. Also muss, den siderischen Tag vorrausgesetzt, eine Umdrehung 86164,0905 sek dauern. Ich habe ein 1:3600er Vorgetriebe (2x 1:60 Schnecken/Stirnrad-Getriebe) vorgesehen, womit der Schrittmotor pro Umdrehung 23,934469583E sek benötigen muss. Bei 16tel Schritt und 200 Steps/PR komme ich auf 0,0074795217447917 sek pro uStep bzw. 0,1196723479166667 sek pro Vollschritt (bei 1.8°, Nema 17).

Nehme ich nun Vollschritte (Reicht bei dieser Übersetzung locker, falls es einfacher ist) oder 16tel Mikroschitte? Und noch viel wichtiger... Wie viele Stellen schafft der Arduino in diesem Fall (ich glaube das war auch von den "Zeilenmengen" und der "Lesegeschwindigkeit" abhängig, wenn ich das richtig sehe oder? Also wie lange der Arduino für die jeweilige Zeile "rechnen" muss, richtig (ganz grob gesagt)?

Ein weglassen von zu vielen Stellen würde bedeuten, dass sich der "Fehler" schnell addiert und dies würde das Projekt so gut wie unbrauchbar machen. Sollte man z.B. auf wenige Stellen begrenzt sein, würde das für mich bedeuten auch noch ein Guidingsystem zu integrieren.. hierrauf würde ich aber erstmal verzichten wollen.

Nun sind die Füchse und alten Hasen unter euch gefragt.. Ich hoffe ihr könnt mir helfen! :wink:

Besonders liebe Grüße,

Chris

Hallo,

ich kenne mich mit solchen Schrittmotor-Geschichten eher nicht so gut aus, aber ich kann dir sagen, dass, meines Wissens nach, ein Arduino für Fließkommazahlen maximal 8 Ziffern und einen Exponenten hat. Ich nehme an, dass es bei deinem Projekt nicht gerade darauf ankommt, dass die Milchstraße nicht um 0,000001° verrutscht. Ich würde volle Schritte nehmen, dann kommst du, glaube ich, auf genauere Ergebnisse, denn der Nano kann nur auf die µs genau warten. 0,119672 µs zwischen jedem Schritt ist genau genug, oder? Bei µSchritten hättest du 0,007479 µs, das ist ein ganzes Stück ungenauer. Aber ich vermute, den großen Unterschied macht's jetzt nicht.

Rechnen muss der Nano überhaupt nicht, wenn du ihm direkt diesen Wert verpasst oder nur einmal, wenn du ihn in einer variable speicherst.

Wenn du ganz genaue Ergebnisse haben willst, dann beachte, dass auch das simple digitalWrite 5 µs braucht. Meine ich gelesen zu haben.

Hoffentlich hilft's,
HTML-Fan

HTML-Fan:
meines Wissens nach, ein Arduino für Fließkommazahlen maximal 8 Ziffern und einen Exponenten hat.

Die realen 6-7 sind ja in gewisser Weise maximal 8. :wink:

Nachkommastellen sind egal, es gibtr Libraries für bliebige Genauigkeit. Aber Schrittmotoren soind nicht so die prickelnde Idee für Astrotracker, normalerweise nimmt man da getriebemotoren um möglicht keine Vibrationen ins System zu bekommen.

Hallo HTML-Fan,

vielen Dank für die schnelle und ausführliche Antwort, geht ja fix hier im Forum :grinning:

Danke für die interlektuelle Machete...! Das mit dem Vollschritt wegen dem weglassen der ganzen 0,000(...) macht natürlich jede Menge Sinn.

Also gebe ich dem Motor einfach einen Delay von 0,119672 sek mit.. Super. Vielen lieben Dank.

@Whandall: Wenn ich dich richtig verstehe, möchtest du darauf hinweisen, dass "komma" auch immer als "Ziffer" gilt? Oder gibt es eine klare Aussage, dass hier nur insgesamt 7 oder 6 Ziffern funktionieren?

@zwieblum: Erklär das mal meiner HEQ5 mit Nema Motoren und einem Übersetzungsverhältnis von 1:705, die werden von Werk aus so gebaut, da wackelt und vibriert nichts. Ebenso bei den 500€ teuren Trackern von Skywatcher, Bresser etc. :wink:

lieben Gruß,

Chris

Sechs signifikante Ziffern sind immer korrekt, sieben halt nicht immer
(für eine Konversion von dezimal nach float und wieder zurück).

Die Basis der Floats is binär, die der "normalen" Darstellung ist dezimal,
deshalb kann man die Genauigkeit (Ziffern bezogen) nicht direkt aufeinander abbilden.

Zusätzlich ist zu bedenken, dass Berechnungen mit Floats
die Genauigkeit der Ergebnisse verschlechtern können,
z.B. hat die Differenz zweier sehr nahe beieinanderliegender Werte nur wenige signifikante Stellen.

Chrizl89:
@zwieblum: Erklär das mal meiner HEQ5 mit Nema Motoren und einem Übersetzungsverhältnis von 1:705, die werden von Werk aus so gebaut, da wackelt und vibriert nichts. Ebenso bei den 500€ teuren Trackern von Skywatcher, Bresser etc. :wink:

Och, wenn du die Mechanik so sauber hinbekommst, dann ist's natürlich kein Problem. HEQ5 hat ja auch einen fetten Dämpfer :slight_smile:

Wenn du delayMicroseconds nutzt, dann ist auch die Kommageschichte vergessen, da muss ja 'ne Ganzzahl hin. Aber, da fällt mir gerade noch rechtzeitig ein, delayMicroseconds nutzt 16-Bit-Variablen, also ist die maximale Wartezeit 216 - 1 = 65535 µs. Stattdesen kannst du nutzen:

void loop(){
  uint64_t now = micros();
  Schritt();
  while((micros() - now) < 119672); //Warteschleife bis Wartezeit seit der Startmessung vergangen
}

Dann ist auch völlig egal, ob der Schritt 1000 oder 1 µs dauert.

Alternativ kannst du natürlich auch

delayMicroseconds(672);
delay(119);

nutzen, aber das macht nicht so viel Spaß.

Hallo Leute,

ihr seid echt der Hammer :slight_smile:

@Whandall: Könntest du das Anhand eines Beispiels mit Zahlen machen, irgendwie kann ich ehrlich gesagt nicht so ganz greifen, was das bedeuten soll. Also bekomme den Zusammenhang nicht so ganz, wann was gilt...

@zwieblum: Das wird schon. Ist ja nur ein Tracker für max. 50mm Brennweite (ca. 2Kg Equipment) für maximal 2min Belichtungszeit. Bei der Auflösung der 50mm gerechnet zu den 6.4um Pixel der EOS 6D sollte da ohnehin kaum bewegung drin sein (hartes undersampling). Ohne Tracking sind bei 50mm ca. 8 Sekunden mit runden Sternen drin. Die Sampleraten sind da schon gut gewappnet gegen eventuelles Vibrieren des bösen Nemas :slight_smile:

@HTML-Fan: Sogar direkt mit Code, vielen Dank :wink: Das würde aber auch bedeuten, das "wenn" ich über micros gehe, das mir dann (ohne Komma) eine weitere Ziffer zur Verfügung steht oder?
Also Gegenübergestellt:

0.119672 (8 Ziffern)
119672XX (8 Ziffern)

Richtig? Oder habe ich letztendlich zu viele Bäume für den Wald vor meinem Gesicht :stuck_out_tongue_closed_eyes:

Hallo,

wenn ich diese float-Geschichte richtig verstanden habe, hat man, wie gesagt, ein paar Ziffern und einen Exponenten, d.h. 0.119672 wird gespeichert als 119672e-6, also die 119672 um 6 Stellen nach rechts verschieben. Daher hat man immer eine Genauigkeit, die von der Zahl abhängig ist. Daher sollte die Genauigkeit gleich sein.

Außerdem geht micros() nur auf die 4 µs genau, liegt am Prozessortakt und so. Meine ich zumindest.

Gruß
HTML-Fan

HTML-Fan:
Hallo,

wenn ich diese float-Geschichte richtig verstanden habe, hat man, wie gesagt, ein paar Ziffern und einen Exponenten, d.h. 0.119672 wird gespeichert als 119672e-6, also die 119672 um 6 Stellen nach rechts verschieben. Daher hat man immer eine Genauigkeit, die von der Zahl abhängig ist. Daher sollte die Genauigkeit gleich sein.

Außerdem geht micros() nur auf die 4 µs genau, liegt am Prozessortakt und so. Meine ich zumindest.

Gruß
HTML-Fan

Das bedeutet dann aber auch, anhand deines Codes den du soeben eingestellt hast:

void loop(){
  uint64_t now = micros();
  Schritt();
  while((micros() - now) < 119672); //Warteschleife bis Wartezeit seit der Startmessung vergangen
}

Wenn ich das richtig deute, baust du sowas wie einen Schrittzähler ein, der sich immer selbst resetet, wenn 119672 erreicht ist. Das bedeutet aber auch, das ich hergehen könnte und:

2ten Zähler einbauen, der immer wenn der Zähler reset geht eins weiter zählt, ist der meinetwegen bei 10x (hier addiert sich immer der Fehler bzw. die fehlenden stellen). Daher könnte ich dann nach 10x Fehler "stapeln" einmal die zusätzlich "warten" um die Zahl wieder zu glätten.. oder? Somit gewinne ich bei jeder 1/20 Umdrehung der Schnecke an Genauigkeit zurück, richtig? :wink:

Chrizl89:
@Whandall: Könntest du das Anhand eines Beispiels mit Zahlen machen, irgendwie kann ich ehrlich gesagt nicht so ganz greifen, was das bedeuten soll. Also bekomme den Zusammenhang nicht so ganz, wann was gilt...

Die Fehleranalyse/Stabilitätsanalyse von Berechnungen ist ein Untergebiet der Numerischen Mathematik.

Wenn es dich interessiert, mach dich da schlau.

Ein einfaches Beispiel (Aufsummieren der Zahlen zwischen 1 und 10000).

void setup() {
  Serial.begin(250000);
  float sum1 = 0;
  long sum = 0;
  for (long i = 1; i <= 10000; i++) {
    sum1 += i;
    sum += i;
  }
  Serial.print(F(" korrekt      "));
  Serial.println(sum);
  Serial.print(F(" aufsteigend  "));
  Serial.println(sum1);
  float sum2 = 0;
  for (long i = 10000; i >= 1; i--) {
    sum2 += i;
  }
  Serial.print(F(" absteigend   "));
  Serial.println(sum2);
}
void loop() {}
 korrekt      50005000
 aufsteigend  50002896.00
 absteigend   50009072.00

Du kannst auch einfach ohne Umwandlung die Ziffern ab der ersten Nicht-Null zählen. z.B. 0,00051 hat 2 signifikante Stellen

Man könnte vielleicht auch die Nachkommatellen als Integer abspeichern

0.119672 (8 Ziffern)
119672XX (8 Ziffern)

Nein das sind 6 und 8 Ziffern.

Wenn Du's wissen willst dann summiere eine 1 zu einer float Zahl

float A = 838800.0;
loop(){
A = A + 1.0;
Serial.println(A);
}

Du wirst sehen daß ab einem gewissen Wert die Zahl gleich bleibt.

die 32 Bit der float Zahl wird in 23 Bit Mantisse und 8 Bit Exponent.

Also eine Zahl von +/- 0 bis 2^23-1 mal 2^(2^7-1)
das entspricht einer Zahl von +/- 0 bis 8.388.607 *2 ^ (-128 bis +127).

Als Beispiel nehmen wir mal an Du hast eine Floatig dezimalzahl mit der Matisse von 3 Stellen und den Exponenten von 2 Stellen.

Da kannst Du zwar Zahlen von ca 999 *10^99 darstellen aber wenn Du zu 999,0 dann 1 dazuzählst ergibt das keine größere Zahl.

Grüße Uwe

Whandall:
Die Fehleranalyse/Stabilitätsanalyse von Berechnungen ist ein Untergebiet der Numerischen Mathematik.

Wenn es dich interessiert, mach dich da schlau.

Danke dir. Mit Annäherungsrechnung hat es dann Klick gemacht :wink:

Serenifly:
Du kannst auch einfach ohne Umwandlung die Ziffern ab der ersten Nicht-Null zählen. z.B. 0,00051 hat 2 signifikante Stellen

Man könnte vielleicht auch die Nachkommatellen als Integer abspeichern

Ist aber nicht funktionsfähig für das was ich vor habe, oder? Oder gilt das prinzipiell für alle größen und anzahlen der signifikanten Stellen? Dies ist aber auch wieder nur zum annähern an den Originalwert, richtig?

Entschuldigt die ganzen fragen, absoluter "beginner" in diesem Bereich :smiley:

Aber ich denke so langsam verstehe ich worauf das hinausläuft. Ich verstehe nicht alles bzw. nicht überall "warum" das so ist, aber ich verstehe worauf ihr hinaus wollt.

Ich werde mal testen wie weit ich komme. Und ansonsten, sehe ich ja hier, sind hier ein paar wirklich kluge Köpfe, die mit Rat und Tat zur Seite stehen :wink:

Chrizl89:
2ten Zähler einbauen, der immer wenn der Zähler reset geht eins weiter zählt, ist der meinetwegen bei 10x (hier addiert sich immer der Fehler bzw. die fehlenden stellen). Daher könnte ich dann nach 10x Fehler "stapeln" einmal die zusätzlich "warten" um die Zahl wieder zu glätten.. oder? Somit gewinne ich bei jeder 1/20 Umdrehung der Schnecke an Genauigkeit zurück, richtig? :wink:

Jepp.

float delayTime = 0;
void loop(){
  Schritt();
  delayTime += 119672,3479166667;
  Warte(floor(delayTime));
  delayTime -= floot(delayTime);
}

Dass sollte gehen, aber habe ich nicht getestet.

geht nicht.

delayTime += 119672,3479166667;

Das Komma ist der Punkt und nicht der Beistrich.
Außer daß die Hälfte der Zahlen so ab der 3 oder 4 in der Rechnung nicht mitgerechnet werden werden.

Genauer wird es wenn man mit einer unsigned log Zahl die µS zählt.

Grüße Uwe

HTML-Fan:
Jepp.

float delayTime = 0;

void loop(){
  Schritt();
  delayTime += 119672,3479166667;
  Warte(floor(delayTime));
  delayTime -= floot(delayTime);
}



Dass sollte gehen, aber habe ich nicht getestet.

uwefed:
geht nicht.

delayTime += 119672,3479166667;

Das Komma ist der Punkt und nicht der Beistrich.
Außer daß die Hälfte der Zahlen so ab der 3 oder 4 in der Rechnung nicht mitgerechnet werden werden.

Genauer wird es wenn man mit einer unsigned log Zahl die µS zählt.

Grüße Uwe

Hallo ihr beiden, danke für die tollen Ideen.

Mein Ansatzpunkt wäre folgender gewesen:
0,1196723479166667 ist ja nicht voll aufzulösen (zumindest nicht so einfach wie ich mir das gedacht hatte). Angenommen ich arbeite mit den 0,119672 und erhalte somit einen Rest annähernd 0,0000003479166667 das sind bei 200steps (200*) 0,00006958333334 somit hätte ich, einen Zähler vorrausgesetzt, nach jeder 1* Drehung der Schnecke die Möglichkeit um +0,000069 Wartezeit zu korrigieren. Somit "nulle" ich den Fehler annähernd aus. Die Abweichungskorrektur würde dann den Fehler auf wenige Winkelsenkunden reduzieren, was bedingt durch Pixelgröße im Verhältnis zur Brennweite nichts mehr aus machen würde. Bei 120 Sekunden Belichtungszeit hätten wir somit annähernd 6 (je 23sek) Drehungen mit einer winzigen Korrektur. Bitte bedenkt die 1:3600 Übersetzung, das sollte tatsächlich an Genauigkeit voll ausreichen!

Wäre das so umsetzbar? Also... stimmt meine Überlegung soweit? Ich meine vielleicht habt ihr ja einen einfacheren oder kürzeren Weg, dafür fehlt mir die Programmier-Erfahrung :wink:

Vergiss die ganze Float-Berechnung. Damit kommst Du beim ATMega auf keine grünen Zweig.
Rechne mit Ganzzahlen - da bekommst Du erstmal keinen Rechenfehler rein. Du musst dann nur deine Einheit klein genug wählen. Gut - die zeitliche Auflösung ist begrenzt - Du kannst die Einheit nicht beliebig klein wählen. Da must Du mit Rest rechnen - wie ganz früher in der Schule, bevor die Dezimalzahlen mit Nachkommastellen drankamen. . D.h. Du berechnest die notwendige Zeit für einen Step in µsec. Da Du da auch noch Nachkommastellen hast, rechnest Du mit Rest, und korrigierst alle n Steps. D.h. alle n Steps wird deine Stepzeit etwas größer um den Fehler zu korrigieren. Letztendlich kannst Du das alles vorher ausrechnen, da braucht der Nano fast nichts machen. Nur den Rest mit jedem Step aufaddieren, bis wieder ein µs zusammenkommt, die Du dann auf den Step draufschlägst.
Das ist so ähnlich wie bei den Schaltjahren, um die Jahre an die ungerade Tageszahl/Jahr anzupassen :wink:
Als Beispiel:
Du hast 119672,3479166667 µs / Step. Wenn Du nun alle 119672µs einen Step ausführst, fehlen dir pro Step 347916666,7 * 10E-9 µs. Die 0,7 sind ein Problem, denn die bekommst Du auch mit 32Bit Genauigkleit nicht reingebacken. Die lassen wir also weg. Dein Fehler ist also 347916666 * 10E-9 µs die deine Stepzeit zu klein ist. Die addierst Du bei jedem Step in einer Fehlervariable auf, bis der Wert > 1000000000 ( = 1µs ) ist. Dann machst Du den Step 1µs länger, und ziehst diese µs ( 1000000000*E-9) wieder von deinem Fehler ab. Und so geht das immer weiter ...
Auf Dauer ist dann der Fehler durch die Basisfrequenz des Resonators größer als dein Rechenfehler :wink:

Edit: Das geht schon in die Richtung wie Du das vorhast, aber die Umdrehung an der Schnecke ist für die Korrektur vollkommen irrelevant. Das machst Du am besten alles auf Step-Ebene.
Für die Zeitmessung würde ich den Timer 1 nehmen, der kann das auch auf 1 µs genau ( so genau wie halt der Resonator oder Quarz auf deinem Arduino ist :wink: ). Den lässt Du einfach durchlaufen, so summieren sich keine Fehler. Über einen OCR-Interrupt kannst Du dann immer zu rechten Zeit einen Step auslösen.

MicroBahner:
Vergiss die ganze Float-Berechnung. Damit kommst Du beim ATMega auf keine grünen Zweig.
Rechne mit Ganzzahlen - da bekommst Du erstmal keinen Rechenfehler rein. Du musst dann nur deine Einheit klein genug wählen. Gut - die zeitliche Auflösung ist begrenzt - Du kannst die Einheit nicht beliebig klein wählen. Da must Du mit Rest rechnen - wie ganz früher in der Schule, bevor die Dezimalzahlen mit Nachkommastellen drankamen. . D.h. Du berechnest die notwendige Zeit für einen Step in µsec. Da Du da auch noch Nachkommastellen hast, rechnest Du mit Rest, und korrigierst alle n Steps. D.h. alle n Steps wird deine Stepzeit etwas größer um den Fehler zu korrigieren. Letztendlich kannst Du das alles vorher ausrechnen, da braucht der Nano fast nichts machen. Nur den Rest mit jedem Step aufaddieren, bis wieder ein µs zusammenkommt, die Du dann auf den Step draufschlägst.
Das ist so ähnlich wie bei den Schaltjahren, um die Jahre an die ungerade Tageszahl/Jahr anzupassen :wink:
Als Beispiel:
Du hast 119672,3479166667 µs / Step. Wenn Du nun alle 119672µs einen Step ausführst, fehlen dir pro Step 347916666,7 * 10E-9 µs. Die 0,7 sind ein Problem, denn die bekommst Du auch mit 32Bit Genauigkleit nicht reingebacken. Die lassen wir also weg. Dein Fehler ist also 347916666 * 10E-9 µs die deine Stepzeit zu klein ist. Die addierst Du bei jedem Step in einer Fehlervariable auf, bis der Wert > 1000000000 ( = 1µs ) ist. Dann machst Du den Step 1µs länger, und ziehst diese µs ( 1000000000*E-9) wieder von deinem Fehler ab. Und so geht das immer weiter ...

Hallo MicroBahner,

genau so meinte ich das in meinem Bsp. von soeben, nur das du jetzt auf 1µsek hochgerechnet hast. Man zählt quasi den fehler aus, dies sollte aber häufiger passieren (wie in meinem Bsp. mit den 0.000069) da sonst die Abweichung eventuell doch zu groß werden könnte. Also gäbe es über "Zählfunktionen" etc. eine Möglichkeit Fehler heraus zu "mitteln", das ist doch ne Aussage!!!

Der konkrete Plan wäre: Sobald strom anliegt, also sobald eine Powerbank oder andere ext. Stromversorgung angeschlossen wird, geht der eigentliche Betrieb los. dieser gleicht die Rotation aus. Dann sollen zwei Schalter an einer Steuerung für Schnelllauf vor- bzw. Rückwärts sorgen. Den Code dafür versuche ich mal selbst zu schreiben mit ein paar Vorlagen.

1000 Dank! :grin: :grin: :grin: :grin: