Forum: Mikrocontroller und Digitale Elektronik ADXL335 von g nach Winkel


von Chris B. (chrisberger)


Angehängte Dateien:

Lesenswert?

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
von A. Z. (donvido)


Lesenswert?

Diese App-Note erklärt das ganz verständlich:
https://www.mikrocontroller.net/attachment/292888/AN4248.pdf

von Chris B. (chrisberger)


Lesenswert?

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.

von Jan (Gast)


Lesenswert?

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.

von Pepe T. (honkler)


Lesenswert?

sin, cos, atan2 ?

von Peter C. (spacetec)


Lesenswert?

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.

von Thomas W. (Gast)


Lesenswert?

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.

von Wolfgang (Gast)


Lesenswert?

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.

von Thomas W. (Gast)


Lesenswert?

Moin, -

ich muss gestehen, der adxl335 ist ja herzerfrischend primitiv. atan2 
und sqrt sollte ausreichen.

Gruesse

Th.

von Dieter H. (kyblord)


Lesenswert?

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
von Pepe T. (honkler)


Lesenswert?

Dieter H. schrieb:
> Roll=atan(b/c)

Nur für liebhaber des "division by zero" absturzes.
Pros nehmem atan2.

von Dieter H. (kyblord)


Lesenswert?

Pepe T. schrieb:
> Dieter H. schrieb:
>> Roll=atan(b/c)
>
> Nur für liebhaber des "division by zero" absturzes.
> Pros nehmem atan2.

Stimmt!

von Veit D. (devil-elec)


Lesenswert?

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.
von Chris B. (chrisberger)


Lesenswert?

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 :-)

von Chris B. (chrisberger)


Lesenswert?

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...

von Veit D. (devil-elec)


Lesenswert?

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.

von Chris B. (chrisberger)


Lesenswert?

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 ...

von Achim M. (minifloat)


Lesenswert?

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

von Wolfgang (Gast)


Lesenswert?

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%.

von Chris B. (chrisberger)


Lesenswert?

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.

von Harald A. (embedded)


Lesenswert?

> 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
von Michael S. (captain-stone)


Angehängte Dateien:

Lesenswert?

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.

von Harald A. (embedded)


Lesenswert?

Nimm den SCL3300, der hat für Neigungserfassung die geeignetere 
Dämpfung.

von Michael S. (captain-stone)


Lesenswert?

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.

von Harald A. (embedded)


Lesenswert?

SCA für Accelerometer und SCL für Levelling.

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
Noch kein Account? Hier anmelden.