Liebe Kollegen, vielleicht hat jemand die Geduld es mir zu erklären. Ich hab den genannten Beschleunigungssensor und mir aus den Messwerten die Beschleunigung in g errechnet. Bei Ruhelage waagrecht, wie im Bild, erhalte ich für x=0.0g, y=0.0g, z=1.0g Drehe ich den Sensor, erhalte ich dementsprechend die richtigen g Werte in allen Lagen. Nun möchte ich nach einer Rotation (wieder in Ruhelage angekommen) den Winkel von x,y bestimmen (rollen, nicken). Hab jetzt alle Artikel die ich hier finden konnte gelesen, mir den Euler Raum angesehen, versucht die Winkelfunktionen dazu zu verstehen, aber keine der Lösungen konnte ich nachvollziehen, geschweige denn eine funktionierenden Winkel errechnen (welcher Kathete weise den g-Wert zu, etc.). Können wir bitte von diesem Startpunkt über den Lösungsweg zum Winkel sprechen? Anwendung: Ich habe mir auf einer Platine einen 3D-Magnetfeldsensor und den Beschleunigungssensor verbaut. Verfahre mit einem Schrittmotor den Sensor an eine Postion und messe das Magnetfeld. Dazu möchte ich nun die Raumlage haben, um den Magentfeld Vektor im Raum zuweisen zu können. Ich weiß inzwischen, dass ein SCA3300-D01-1 von Murata die bessere Wahl gewesen wäre, der mir schon den Winkel ausgibt, möchte es aber mit der bestehenden Konfiguration versuchen.
:
Bearbeitet durch User
Diese App-Note erklärt das ganz verständlich: https://www.mikrocontroller.net/attachment/292888/AN4248.pdf
A. Z. schrieb: > Diese App-Note erklärt das ganz verständlich: Vielen Dank für den Link. Ich glaub ich hab es schlecht erklärt. Ich will keinen Kompaß machen. Ich will nur aus einem Beschleunigungssensor im Ruhezustand den Winkel aus den g Kräften berechnen.
Wie man einen Winkel aus zwei Werten berechnet lernt man in der siebten Klasse. Vielleicht hast Du ja schon mal was von Sinus und Cosinus gehört? Wenn nein, ist dein Vorhaben zum scheitern verurteilt.
Die AppNote ist schon ganz gut - es wird bei dem neigungskompensierten Kompass auch Roll und Pitch benötigt, was du ja auch bestimmen willst. Schau dir in der AppNote Eqn. 13 und Eqn. 15 auf Seite 7 an, bzw. den Code der Beispielimplementierung ab Seite 15.
Moin, - Du brauchst Beschleunigung und Drehmoment, aufintegriert. Kleines Google hilft (sogar auf deutsch): https://www.all-electronics.de/elektronik-entwicklung/beschleunigungsaufnehmer.html https://www.codetd.com/de/article/12560493 https://www.fzt.haw-hamburg.de/pers/Scholz/arbeiten/TextWoll.pdf http://www.starlino.com/dcm_tutorial.html https://www.youtube.com/watch?v=zDGvcHMSPm8 Ich weiss Deine Vorbildung nicht: Es koennte sein, dass due Dich etwas einlesen musst (Mathe, 1 - 3 Semester). Die App-Note ist schon recht gut. Gruesse Th.
Thomas W. schrieb: > Du brauchst Beschleunigung und Drehmoment, aufintegriert. Du verwechselst Gyro mit Beschleunigungssensor. An den vom ADXL335 ausgegebenen Beschleunigungswerte gibt es nichts aufzuintegrieren. Es geht darum, rein statisch die Lage im Raum durch zwei Winkel zu beschreiben.
Moin, - ich muss gestehen, der adxl335 ist ja herzerfrischend primitiv. atan2 und sqrt sollte ausreichen. Gruesse Th.
Das funktioniert eigentlich nur, wenn der Körper in Ruhe ist. Dann wirkt nur die Fallbeschleunigung auf den Körper (tatsächlich auch die Zentrifugalkraft, denn das Erdsystem ist kein Intertialsystem. Das ist aber in vielen Fällen vernachlässigbar). Aus der Fallbeschleunigung (du nennst es g-Vektor) kann man dann nur 2 Winkel eindeutig bestimmen, Nick und Roll. Die Mathematik ist einfach. Der G-Vektor wird im körperfesten Koordinatensystem gemessen. Stell dir vor du hast ein Koordinatensystem (x,y,z-Achsen) auf dem Sensor draufgeklebt die sich mit dem Sensor mitdrehen/mitbewegen. Du möchtest eine Beschreibung des Objekts im Intertialsystem (Erdkoordinatensystem). Die Rotationsreihenfolge ist z=Gier -> y'=Nick -> x''=Roll Dabei deutet der ' an, dass stets um das soeben durch die vorherige Rotation entstandene Koordinatensystem rotiert wird (intrinsische Drehungen). Mathematisch wird das so beschrieben: vektor Intertialsystem = ( rot_z(Gier) * rot_y(Nick) * rot_x(Roll) ) * vektor Körperfest wobei rot_z, rot_y, rot_x die Standard Drehmatrizen aus dem R^3 sind. Wichtig ist, dass dein Koordinatensystem ein rechtshändiges Koordinatensystem ist. Ist beim zweiten Bild bei dir oben nicht der Fall (rechte Hand Regel!), beim ersten schon. Nehmen wir an, dass der G-Vektor im Körperfesten Koordinatensystem so aussieht G=(0,0,g), mit g=-9.81 m/s^2. Sprich der Vektor zeigt im Intertialsystem entgegen der z-Achse (z-Achse zeigt nach oben in den Himmel). Damit ist vektor Intertialsystem = G = (0,0,g) Da die Matrizen orthogonal sind kann man durch Transponieren die Transformation umkehren: vektor Körperfest = ( rot_x(-Roll) * rot_y(-Nick) * rot_z(-Gier) ) * vektor Intertialsystem jetzt einsetzen... vektor Körperfest = ( rot_x(-Roll) * rot_y(-Nick) * rot_z(-Gier) ) * (0,0,g) = (-sin(Nick), sin(Roll)*cos(Nick), cos(Roll)*cos(Nick) ) * g vektor Körperfest = (a,b,c). Das ist das, was dein Beschleunigungssensor misst bzw. dir an Werten rausgibt. Jetzt nur noch etwas Algebra: b/c = (sin(Roll)*cos(Nick)) / (cos(Roll)*cos(Nick)) = sin(Roll) / cos(Roll) = tan(Roll) damit Roll=atan(b/c) Dann: sqrt( (b/g)^2+(c/g)^2 ) = cos(Nick) damit a/sqrt( (b/g)^2+(c/g)^2 ) = -sin(Nick)/cos(Nick) = -tan(Nick) Nick = atan( -a/sqrt( (b/g)^2+(c/g)^2 ) ) g=-9.81 m/s^2 Ingesamt: Roll=atan(b/c) Nick = atan( -a/sqrt( (b/g)^2+(c/g)^2 ) ) lol... Hoffe du kannst es verstehen.
:
Bearbeitet durch User
Dieter H. schrieb: > Roll=atan(b/c) Nur für liebhaber des "division by zero" absturzes. Pros nehmem atan2.
Pepe T. schrieb: > Dieter H. schrieb: >> Roll=atan(b/c) > > Nur für liebhaber des "division by zero" absturzes. > Pros nehmem atan2. Stimmt!
Hallo, ich habe einen ADXL345, also ähnlich zu deinem ADXL335, Prinzip ist gleich, nur das du analoge Werte ausliest und ich digital über I2C. Arduino ...
1 | // Bsp.
|
2 | int xAxis = analogRead(A0); // Rohwert X-Achse |
3 | int yAxis = analogRead(A1); // Rohwert Y-Achse |
4 | int zAxis = analogRead(A2); // Rohwert Z-Achse |
5 | |
6 | Serial.print(xAxis); Serial.print('\t'); |
7 | Serial.print(yAxis); Serial.print('\t'); |
8 | Serial.print(zAxis); Serial.print('\t'); |
9 | |
10 | // Roll & Pitch Equations
|
11 | float xTemp = 3.0*xAxis/1024; // [3g vom Sensor] |
12 | float yTemp = 3.0*yAxis/1024; // |
13 | float zTemp = 3.0*zAxis/1024; // |
14 | float roll = (atan2(-yTemp,zTemp)*180.0)/3.14; |
15 | float pitch = (atan2(xTemp,sqrt(yTemp*yTemp+zTemp*zTemp))*180.0)/3.14; |
16 | |
17 | Serial.print(roll); Serial.print('\t'); |
18 | Serial.print(pitch); Serial.println(); |
Was du noch anpassen musst ist die maximale Auflösung bzw. Skala in der Berechnung beim einlesen, weil bei dir analog. Entweder korrigierst du das gleich beim einlesen oder dann in der Formel "/1024". Weil ich mit dem ADXL345 alles digital einlese ist das unabhängig vom ADC und dessen Referenzspannung. 10Bit sind 10Bit. Ich denke das bekommst du hin.
Beitrag #7080500 wurde vom Autor gelöscht.
Dieter H. schrieb: > Roll=atan(b/c) > Nick = atan( -a/sqrt( (b/g)^2+(c/g)^2 ) ) > > lol... Hoffe du kannst es verstehen. Vielen, herzlichen Dank Dieter für die ausführliche Herleitung. Ich arbeite dran :-)
Servus Veit, > // Roll & Pitch Equations > float xTemp = 3.0*xAxis/1024; // [3g vom Sensor] ich hab meinen Messwert so in g umgerechnet: float gX = (2.0 / (gX_MAX_Wert - gX_MIN_Wert) * (gX_roh_Wert - gX_MIN_Wert)) - 1; Wobei der roh Wert der Messwert ist. Min und Max sind empirisch ermittelt. > float roll = (atan2(-yTemp,zTemp)*180.0)/3.14; > float pitch = (atan2(xTemp,sqrt(yTemp*yTemp+zTemp*zTemp))*180.0)/3.14; Um diese Formel kreise ich seit Tagen. Ich bekomm da z.B. jetzt nur den halben Winkel raus. Also, ich dreh um 90°, kommt 45° raus. Beispiel: g_print("%5.2f %5.2f %5.2f|%6.2f %6.2f\n", gX, gY, gZ, roll, pitch); 1.) 0.00 0.00 1,03|-0,27 0,27 2.) 1,00 -0,01 0,99| 0,83 45,31 Bei 1.) waagrecht liegend, passt. Bei 2.) um 90° gedreht, kommt 45° raus. Das macht er bei roll und bei pitch. Die Formel mit 2 zu multiplizieren bringt aber ganz falsche Ergebnisse. Mmhh...
Hallo, ich denke deine Formel stimmt so nicht.
1 | float gX = (2.0 / (gX_MAX_Wert - gX_MIN_Wert) * (gX_roh_Wert - |
2 | gX_MIN_Wert)) - 1; |
Der eingelesene analoge Wert entspricht einem Beschleunigungswert [g]. Du rechnest aber 2 / Quadrat. Also dein gX hat nicht die Einheit g sondern g^2. Kann nicht stimmen. Der analoge Wert entspricht irgendwas zwischen -3g und +3g. 0g entsprechen Ub/2 (3,3V/2). Hier wird vermutlich der Faktor 2 drin stecken der dir noch fehlt. Ich denke mal laut vor mich hin ... Dein ADXL335 arbeitet sicherlich mit 3,3V? In welcher Auflösung arbeitet dein ADC? Mit welcher Spannung arbeitet dein µC und mit welcher Referenzspannung arbeitet der ADC? Ich nehme an beides mit 5V? Lass mich einmal laut denken. :-) Beim ADXL345 habe ich immer den vollen Skalenwert abgedeckt, weil digital. Default 10Bit, 0...1023. Auslesewert mal g Faktor durch 1024 gleich Ergebnis [g]. Wir nehmen einmal an bei dir läuft alles mit 3,3V und dein ADC arbeitet auch mit 10Bit Auflösung. Dann entspricht dein Analogwert genau wie bei mir der vollen Skala. Du müßtest nichts ändern. Einlesewert mal g Faktor durch 1024 - fertig. Dein ADXL335 misst max. +/- 3g, deswegen Faktor 3. Falls dein Controller bzw. dein ADC mit 5V Vref misst, fehlt eigentlich nur der Faktor 5V/3,3V=1,515. Weil dann 3,3V von maximal möglichen 5V dein Endausschlag sind die auf 5V Messbereichsende skaliert werden müßten. Soweit meine Überlegungen wenn ich nicht ganz doof bin. Ihr dürft mich gern korrigieren. Also entweder
1 | float gX = 3.0 * analogWert / 1024; |
2 | oder
|
3 | float gX = 1.515 * 3.0 * analogWert / 1024; |
Den Wert lässt du dann auf die anderen Formeln los die unverändert bleiben.
Servus Veit,
vielen Dank für die Ausführliche Erklärung.
>
1 | > float gX = (2.0 / (gX_MAX_Wert - gX_MIN_Wert) * (gX_roh_Wert - |
2 | > gX_MIN_Wert)) - 1; |
3 | >
|
Damit bekomm ich aber die richtigen g-Werte, von 0 bis 1 in allen Achsen korrekt. Ich habe Deine Variante nun auch probiert. > Dein ADXL335 arbeitet sicherlich mit 3,3V? 3,0V > In welcher Auflösung arbeitet dein ADC? 10 Bit (ATMEGA644) > Mit welcher Spannung arbeitet dein µC und mit welcher Referenzspannung > arbeitet der ADC? µC 5V AREF 3,0V >
1 | > float gX = 3.0 * analogWert / 1024; |
2 | >
|
Dann kommt raus: gX = 3.0 * 500 / 1024 ca. 1,5g. Aber den Wert 500 bringt er bei 0g. Ich steh auf'm Schlauch ...
Chris B. schrieb: > Aber den Wert 500 bringt er bei 0g. Weil 0g in der Mitte des ADC-Messbereichs liegen. Daher erst den Offset abziehen und dann reskalieren. mfg mf
Veit D. schrieb: > float gX = 1.515 * 3.0 * analogWert / 1024; Solche theoretischen Ergüsse kann man sich guten Gewissens sparen. Die Empfindlichkeit der Kanäle des ADXL335 ist nicht genauer als 1%.
Hallo Achim, > Weil 0g in der Mitte des ADC-Messbereichs liegen. Daher erst den Offset > abziehen und dann reskalieren. Oh Gott, na klar - peinlich :-( Vielen Dank. Manchmal ist alleine basteln echt zeitintensiv, wenn man im Kreis rennt.
> Ich > weiß inzwischen, dass ein SCA3300-D01-1 von Murata die bessere Wahl > gewesen wäre, der mir schon den Winkel ausgibt, möchte es aber mit der > bestehenden Konfiguration versuchen. Das stimmt ganz genau, aber nicht unbedingt aufgrund der direkten Winkelausgabe. Welchen Winkelbereich möchtest Du überhaupt erfassen? Für kleinere Winkel sind diese Art von Beschleunigungssensoren mit ein paar g Messbereich schlechte Schätzeisen. Und dann noch mit 10bit, bzw. dem, was davon übrig bleibt. Je nach Messbereich sicher nicht mehr als 4..6bit + Rauschen, Drift. Zweite Problem ist die Dämpfung des Elements, besonders dann wenn Schwingungen ins Spiel kommen, die ca. die Resonanz des MEMS treffen (Motoren, Hydraulik, etc.). Die kann man nämlich nicht filtern. Weder analog noch digital.
:
Bearbeitet durch User
Servus Harald, > Welchen Winkelbereich möchtest Du überhaupt erfassen? Für kleinere > Winkel sind diese Art von Beschleunigungssensoren mit ein paar g > Messbereich schlechte Schätzeisen. Und dann noch mit 10bit, bzw. dem, > was davon übrig bleibt. Je nach Messbereich sicher nicht mehr als > 4..6bit + Rauschen, Drift. Genau, darauf bin ich auch gekommen. Ich brauch kleine Winkeländerungen in alle Richtungen. Ich hab mir einen 3D Magnetfeld-Sensor gebaut, der frei im Raum drehen kann. Um die Lage im Raum vom Sensor zu bestimmen, hatte ich mir den ADXL335 ausgesucht. Ich bleib bei jeder Messung stehen, daher dachte ich es würde ein einfacher Beschleunigungssensor ausreichend sein. Ist aber für diesen Zweck, aus Deinen genannten Gründen, nicht brauchbar. Werde die Platine nochmal machen und diesmal SCA3300-D01-1 verwenden. Außer es hat jemand noch eine bessere Idee.
Nimm den SCL3300, der hat für Neigungserfassung die geeignetere Dämpfung.
Harald A. schrieb: > Nimm den SCL3300, der hat für Neigungserfassung die geeignetere > Dämpfung. Vielen Dank für den Tipp, dann nehm ich den.
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.