mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Drehwinkelgeber -> Drehzahl


Autor: Svente (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: pumpkin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: pumpkin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Edit: Okäse, 14 Bit. Habs überlesen.

pumpkin

Autor: Roland Praml (pram)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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)

Autor: Svente (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!
  }

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Michael Wolf (mictronics) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum 13us Delays zwischen den Byte?

Das Datenblatt sagt einddeutig auf Seite 23 Abs. 16.10.3
"There is no interframe time defined."

Autor: Kai Scheddin (zeusosc)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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



Autor: Ralph (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.





Autor: Svente (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.