Hallo Leute! Die Situation: Ich habe hier einen Absolutwert- Drehwinkelgeber(MLX90316) der mir via SPI(Ü-Rate 142kBit/s) ca. alle 5ms einen 14 Bit Winkelwerte liefert. Der erregende Magnet sitzt auf einer Motorwelle. Ich möchte aus den Winkeldaten zusätzlich die momentane Drehzahl berechnen (max. 2000 U/min). Der Controller ist ein M16C(16MHz). Mein Ansatz ist folgender: Ich messe die genaue Zeit die eine Winkelmessung benötigt, bestimme die Änderung des Winkels in diesem Intervall und berechne: (delta_omega/(delta_t*360))*60 = Drehzahl. Richtig oder Falsch??? Mein Problem: Ich habe grosse Schwankungen bei der Berechnung der Winkeldifferenz. Ich schreibe jeden Winkelwert in einen Ringpuffer(array[0..3]) und subtrahiere immer den letzten vom aktuellen Wert. Das müsste doch eigentlich funktionieren, oder? Allerdings bin ich auch kein so toller programmierer und wäre froh wenn mir da jemand tips geben kann! Vielen Dank
Svente wrote: > Allerdings bin ich auch kein so toller programmierer und wäre froh wenn > mir da jemand tips geben kann! Der beste Tip ist immer noch: Wenn du denkst, dass du möglicherweise Fehler in dein Programm eingebaut hast, dann ist es ratsam, das Programm herzuzeigen. Ansonsten müssen wir raten, und das willst du ganz sicher nicht
wenn du die drehzahl berechnen willst, dann könntest du auch immer nach einer umdrehung, die zeit messen, die vergangen ist, um die drehzahl zu errechnen... immer wenn 0 grad überschritten wird - zeit nehmen... usw... d.
Deine Berechnung stimmt soweit, obwohl deine Namensgebung wahrscheinlich unglücklich ist: d_omega -> d_phi. Aber das nur als akademische Spitzfindigkeit ;) . Dein Geber gibt doch bestimmt einen Winkelwert in Grad, oder? In welcher Auflösung? Was meinst du mit Subtraktion vom vorherigen Wert; nimmst du am Anfang eine Startmessung und nach delta_t eine Endmessung vor um daraus per_Subtraktion ein delta_phi zu erhalten? Wenn ja: gut, aber dort können sich Fehlerchen einschleichen die vor allem bei kurzen delta_t zu ordentlichen Fehlern führen können. Poste doch mal Code oder Pseudocode. pumpkin
Nimm lieber ein Intervall von z.B. 1 Sekunde und miss wieviel Umdrehungen du da machst. Also zu Beginn der Sekunde den Encoder auslesen, dann zählen wie oft der Wert übersprungen wurde (sind die ganzen Umdrehungen). Zum Ende der Sekunde Encoder nochmal auslesen, Wert vom Anfangswert subtrahieren, dass ist dann ein Bruchteil einer Umdrehung. Du erhältst dann direkt ein Ergebnis von z.B. 7,42 U/s (*60 = Upm)
Oki, hier mal das relevante Stück Code: Daten empfangen und verarbeiten! Dataframe senden und empangene Daten in ein Array schreiben while(1) { ta2s = 0x //timer einschalten - zur messung der zeit die eine //winkelmessung benötigt(us) CHIP_SELECT = 0x00; wait_7us(); wert[0] = SPI_send_receive (0xAA); wait_13us(); wert[1] = SPI_send_receive (0xFF); wait_13us(); wert[2] = SPI_send_receive (0xFF); wait_13us(); wert[3] = SPI_send_receive (0xFF); wait_13us(); wert[4] = SPI_send_receive (0xFF); wait_13us(); wert[5] = SPI_send_receive (0xFF); wait_13us(); wert[6] = SPI_send_receive (0xFF); wait_13us(); wert[7] = SPI_send_receive (0xFF); wait_13us(); wert[8] = SPI_send_receive (0xFF); wait_13us(); wert[9] = SPI_send_receive (0xFF); wait_3us(); CHIP_SELECT = 0x01; wait_300us(); /******** relevante daten auswerten und ausgeben (3. und 4. Byte vom DATAFRAME) ***********/ angle = 0; angle = wert[2]; //MSB vom Sensor in 16Bit Variable schreiben angle = angle<<8;//um 8 STellen nach links schieben angle = angle + wert[3];//LSB vom Sensor in die Variable schreiben angle = angle>>2;//die letzten beiden Stellen, die die Gültigkeit des Messwertes anzeigen, löschen //in ringpuffer schreiben winkelbuffer[n] = angle; if (n == 0) winkeldif = winkelbuffer[n]-winkelbuffer[3]; else winkeldif = winkelbuffer[n]-winkelbuffer[n-1]; if (winkeldif < 0) winkeldif += 16383; //beim nulldurchgang delta_t = us_counter - t_old; //us_counter = aktueller Stand des Mikrosekundenzählers t_old = us_counter; //t_old = alter Stand des Mikrosekundenzählers temp1 = delta_t*0.00001; //zeit in sekunden temp2 = winkeldif*0.02197; temp = (temp2/(temp1*360))*60; sprintf(buf,"%.0f \n", temp); //für hyperterminal ausgabe len = 0; while(buf[len]) TerminalOut((char)buf[len++]); n += 1; //Pufferindex erhöhen n &= 0x03; //maskieren des array_indizes; es gibt nur 00,01,10,11 ...immer im zyklus! }
OK. Und welche Werte (nenn doch mal ein paar Beispiele) verursachen jetzt dein Problem. Was ich im Code so gesehen habe (Ich sags gleich: mit dem M16C hab ich nichts am Hut) Mittels ta2s = 0x startest du anscheinend den Timer. Die vielen Waits da drinnen schmecken mir nicht besonders. Sind wohl dazu da um das SPI Timing einzuhalten. Aber: Hier delta_t = us_counter - t_old; //us_counter = aktueller Stand des Mikrosekundenzählers greifst du anscheined das nächste mal auf den Timer zu. Nur: Was hast du eigentlich gemessen? Was du gemessen hast, ist die Zeitdauer, die vergeht bis der Code von ta2s=0 bis zum Abfragen des Timers kommt. Die ist aber reichlich ungenau. Da sind einige ifs drinnen, etc. D.h. deine Aussage: "Ich messe die genaue Zeit die eine Winkelmessung benötigt" mit der Betonung auf 'genaue' nehm ich dir so nicht ab. temp1 = delta_t*0.00001; //zeit in sekunden temp2 = winkeldif*0.02197; temp = (temp2/(temp1*360))*60; Diese ganzen floating Point Berechnungen (hast du echte double oder so wie beim gcc nur float zur Verfügung), sind problematisch. Versuche ohne floating point auszukommen.
Warum 13us Delays zwischen den Byte? Das Datenblatt sagt einddeutig auf Seite 23 Abs. 16.10.3 "There is no interframe time defined."
sooo, hier die mathematik:
(hmmm wird hier in LateX \Rightarrow nicht unterstützt?) pseudo: werte auslesen, mit alten werten delta werte bestimmen, f berechnen, ausgelesene werte als alte abspeichern.... bei dem fall, wie oben schon erwähnt, können schwankungen bei f auftreten, da
lieber timer_overflow_interrupt oder CTC, falls der µC das unterstützt,
noch besser, du speicherst die ausgelesenen werte über
einen bestimmten Zeitraum und mittelst diese,...
grüüüüüße da kai
________________________________
>Das war ein sinnfreier Beitrag :D
Hallo Der Sensor liefert den absoluten Winkel bezogen auf einen Fixpunkt und nicht die Winkelgeschwindigkeit. Das 1. Problem das dich darauf ergibt ist, das du nicht weißt in welche Richtung die Achse gedreht wurde. zb: Wert 1 : 50° Wert 2 : 150° mögliche Winkeländerung sind 0° ; 50° ; 150° ; 180° ; .... = delta (+)100° 50° ; 0° ; 270°; 180°; 150°;...... = delta (-)260° Welche der beiden Richtungen ein + oder - bekommt hängt alleine davon ab, wie du dein Koordinatensystem legen willst. Die Winkeldifferenz also wie weit hat sich die Achse zwischen 2 Meßwerten gedreht ist eine Subtraktion , Meßwert [n] - Meßwert [n-1]. Das 2. Problem ist wie oft hat sich die Achse gedreht, das heißt X * 360° . Es könnten ja auch mehrere Umdrehungen sein. Nach Datenblatt wird der Winkel je nach Konfiguration alle 1,5ms oder alle 350 µs von Sensor gemessen. Der letzte gemessene Wert wird festgehalten und bei Anforderung von SPI Master gesendet. Wenn du jetzt alle 5 ms Daten von Sensor anforderst, folgt daraus das der Zeitabstand zwischen 2 Messungen 3,5 bis 5 ms, bzw 4,65 bis 5 ms betragen kann. Die Zeit die du messen kannst ist von Beginn einer Datenaforderung bis zum Beginn der nächsten Anforderung. Den Zeitabstand zwischen 2 Messungen kannst du nicht messen. Das könnte dir nur der Sensor sagen. Also deine Berechnug muss lauten : Winkelgeschwindigkeit = (Meßwert [n] - Meßwert [n-1]) ---------------------------------------------------- (Anforderungszeitpunkt [n] - Anforderungszeitpunkt [n-1]) Winkelgeschwindigkeit in [°/ms] umrechnen in [n/min] Desweiteren solltest du die Winkelgschwindigkeiten filtern, zb ein Mittelwertfilter über die letzten n Meßwerte. Und erst diesen gefilterten Wert in die Drehzahl umrechnen.
Hi Leute! Viele Dank mal für die Beiträge! Ich werde das jetzt mal durcharbeiten. Zu der Bemerkung von dem Michael: Ich habe die 13us Delay´s aus meinem Data- Frame rausgenommen. Ergebnis: Ich bekomme ne Menge Peaks pro Umdrehung. Also, wenn mann sich die Messwerte in einer Exelgrafik anschaut, dann bekommt man quasi einen Sägezahn der ohne die 13us viele fiese Peaks hat! Ich denke schon , daß der Sensor diese "Inter-Byte- Zeit" braucht! Ich mach mich mal an die Arbeit...
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.