Forum: Mikrocontroller und Digitale Elektronik MPU6050 - Raw-, gravity- and bodyacceleration


von Niklas S. (nicklarrs)


Lesenswert?

Hi,

Ich versuche mit dem MPU6050 Sensor menschliche Bewegungen zu erkennen. 
Ich bin schon sowei, die Sensordaten aus den Registern auszulesen.

In einem, zu meinem Thema sehr ähnlichen, Artikel schreibt der Autor 
davon wie er aus den Rohen Sensordaten (ax, ay, az) die "gravity 
acceleration" (gx,gy,gz) und die "body acceleration" (bx, by, bz) 
berechnet.

Was sind die einzelnen Beschleunigungen (Rohdaten, graivty acceleration 
und body acceleration)?
Was ist der genaue Unterschied zwischen ihnen?
Wie berechne ich die einzelnen Werte (BA, GA und RD)?

Im Moment verwende ich einen im Internet gefunden Code in dem ich die 
Register auslese und dann die "gForce" berechne (ist dies schon die 
besagt gravity acceleration?):
1
void recordAccelRegisters() {
2
  Wire.beginTransmission(MPU);
3
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
4
  Wire.endTransmission(false);
5
  Wire.requestFrom(MPU,14,true);  // request a total of 14 registers
6
  AcX=Wire.read()<<8|Wire.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)    
7
  AcY=Wire.read()<<8|Wire.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
8
  AcZ=Wire.read()<<8|Wire.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
9
  Tmp=Wire.read()<<8|Wire.read();  // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
10
  gForceX = AcX / 16384.0;
11
  gForceY = AcY / 16384.0;
12
  gForceZ = AcZ / 16384.0;
13
}

edit:
Dazu sollte ich noch sagen, dass ich einen NodeMcu und die Arduino IDE 
verwende.w

Danke, mfG
Niklas

: Bearbeitet durch User
von Wolfgang (Gast)


Lesenswert?

Niklas S. schrieb:
> In einem, zu meinem Thema sehr ähnlichen, Artikel schreibt der Autor
> davon wie er aus den Rohen Sensordaten (ax, ay, az) die "gravity
> acceleration" (gx,gy,gz) und die "body acceleration" (bx, by, bz)
> berechnet.

Und? Was schreibt er, wie er das macht?

von Niklas S. (nicklarrs)


Lesenswert?

Das kann ich/man so nicht rauslesen, hier der Wortlaut:
"The measurements from tri-axial accelerometers, known as raw data (RD, 
ax, ay, az), can be decomposed into gravity acceleration (G) - due to 
each gravity, gx, gy , gz and body acceleration (BA) - which is due to 
the human movement bx, by, bz", aus Improving Human Activity Recognition 
von Jose Villar, Internation Journal of Neural Systems.

von Joachim S. (oyo)


Lesenswert?

Ich würde mal vermuten, dass die Raw-Werte die Rohdaten sind, die Du vom 
Sensor bekommst (also vermutlich irgendwelche Integer-Werte), diese für 
die gravity-Werte dann bereits in float-Werte umgewandelt/skaliert sind, 
dass die Werte sozusagen in G sind, also der Wert 1.0 bspw. genau der 
Beschleunigung durch die Gravitation entspricht.

Und für die "body-acceleration" wird aus den gravity-acceleration-Werten 
vermutlich gleich noch die Erdanziehungskraft herausgerechnet - also so, 
dass in völliger Ruheposition der Beschleunigungswert sämtlicher Achsen 
0 beträgt.

Von daher würde ich vermuten:
AcX/Y/Z sind die Rohdaten
und
gForceX/Y/Z sind in der Tat bereits die "gravity acceleration"-Daten

von Jonas G. (jstjst)


Lesenswert?

Hallo,

also ich verstehe das so, dass die gemessenen rohwerte in die 
Erdbeschleunigung und die eigentliche Bewegung aufgeteilt werden.

Gruß Jonas

von Niklas S. (nicklarrs)


Lesenswert?

Danke für die Antworten.

Blöde frage, aber wie rechne ich die gravitation aus der ganzen 
beschleunigung raus?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Niklas S. schrieb:
> Wire.read()<<8|Wire.read()

Die Reihenfolge, in welcher der linke und der rechte Operand von | 
bestimmt werden, ist in C/C++ nicht festgelegt:

"Unlike the bitwise | operator, the || operator guarantees left-to-right 
evaluation [...]"

M.a.W: | wird nicht notwendig von links nach rechts ausgewertet — 
übrigens hat das nix mit der Kommutativität von | zu tun; gleiches gilt 
sinngemaß etwa auch für - (minus).

: Bearbeitet durch User
von Niklas S. (nicklarrs)


Lesenswert?

Johann L. schrieb:
> Niklas S. schrieb:
>> Wire.read()<<8|Wire.read()
>
> Die Reihenfolge, in welcher der linke und der rechte Operand von |
> bestimmt werden, ist in C/C++ nicht festgelegt:
>
> "Unlike the bitwise | operator, the || operator guarantees left-to-right
> evaluation [...]"
>
> M.a.W: | wird nicht notwendig von links nach rechts ausgewertet —
> übrigens hat das nix mit der Kommutativität von | zu tun; gleiches gilt
> sinngemaß etwa auch für - (minus).

Also gehört in meinem Fall ||?

von Leo C. (rapid)


Lesenswert?

Niklas S. schrieb:
> Also gehört in meinem Fall ||?

Nein, z.B so:
1
AcX =  Wire.read()<<8;
2
AcX |= Wire.read();

von Niklas S. (nicklarrs)


Lesenswert?

Hatte so spät mit keiner Antwort mehr gerechnet, danke dir vielmals :)

von Wolfgang (Gast)


Lesenswert?

Niklas S. schrieb:
> aus Improving Human Activity Recognition
> von Jose Villar, Internation Journal of Neural Systems.

Dann meinst du wahrscheinlich den Artikel:
José R. Villar et al, Int. J. Neur. Syst. 25, 1450036 (2015)
/Improving human activity recognition and its application in early 
stroke diagnosis/

http://di002.edv.uniovi.es/~villar/Jose_R._Villar/Journal_papers_files/villarIJNSfinal.pdf

Der von dir genannte lapidare Satz am Anfang vom Abschnitt 2.1 müsste 
IMHO eine Trivialität ausdrücken, sonst hätte er dort irgendetwas 
zitieren (müssen). Vielleicht findet man in einer vorhergehenden 
Veröffentlichung mehr Details zu seiner Vorgehensweise.

von Niklas S. (nicklarrs)


Lesenswert?

Hi Leute,

bin jetzt, da ich ja auch die Beschleunigung ohne Gravitation brauche 
auf die i2cdevlib umgestiegen um die Beschleunigungsdaten zu erlangen.

Soweit funktioniert alles sehr gut, jedoch bekomme ich nach einigen 
Sekunden immer öfters FIFO Overflows und dann stürzt das Programm ab.


Mein Code:
1
    // if programming failed, don't try to do anything
2
    if (!dmpReady) return;
3
4
    // wait for MPU interrupt or extra packet(s) available
5
    while (!mpuInterrupt && fifoCount < packetSize) {
6
        // other program behavior stuff here
7
        // .
8
        // .
9
        // .
10
        // if you are really paranoid you can frequently test in between other
11
        // stuff to see if mpuInterrupt is true, and if so, "break;" from the
12
        // while() loop to immediately process the MPU data
13
        // .
14
        // .
15
        // .
16
    }
17
18
    // reset interrupt flag and get INT_STATUS byte
19
    mpuInterrupt = false;
20
    mpuIntStatus = mpu.getIntStatus();
21
22
    // get current FIFO count
23
    fifoCount = mpu.getFIFOCount();
24
25
    // check for overflow (this should never happen unless our code is too inefficient)
26
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
27
        // reset so we can continue cleanly
28
        mpu.resetFIFO();
29
        Serial.println(F("FIFO overflow!"));
30
31
    // otherwise, check for DMP data ready interrupt (this should happen frequently)
32
    } else if (mpuIntStatus & 0x02) {
33
        // wait for correct available data length, should be a VERY short wait
34
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
35
36
        // read a packet from FIFO
37
        mpu.getFIFOBytes(fifoBuffer, packetSize);
38
        
39
        // track FIFO count here in case there is > 1 packet available
40
        // (this lets us immediately read more without waiting for an interrupt)
41
        fifoCount -= packetSize;
42
43
        mpu.dmpGetAccel(&aa, fifoBuffer);
44
        tmp = String(aa.x) + " " + String(aa.y) + " " + String(aa.z) + " ";
45
        mpu.dmpGetAccel(&aa, fifoBuffer);
46
        gravityX = aa.x / 8192.0;
47
        gravityY = aa.y / 8192.0;
48
        gravityZ = aa.z / 8192.0;
49
        tmp = tmp + String(gravityX) + " " + String(gravityY) + " " + String(gravityZ) + " ";
50
51
        // display Euler angles in degrees
52
        mpu.dmpGetQuaternion(&q, fifoBuffer);
53
        mpu.dmpGetGravity(&gravity, &q);
54
        mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
55
        tmp = tmp + String(ypr[0] * 180/M_PI) + " " + String(ypr[1] * 180/M_PI) + " " + String(ypr[2] * 180/M_PI) + " ";
56
57
        mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
58
        tmp = tmp + String(aaReal.x) + " " + String(aaReal.y) + " " + String(aaReal.z) + "\r\n";
59
60
61
        Serial.print(tmp);
62
        client.print(tmp);

Der Overflow hat eindeutig etwas mit dem Senden (client.print(tmp)) zu 
tun, wenn ich es auskommentiere bekomme ich keinen Overflow.

Ich denke mal das Problem liegt dabei, dass der FIFO Buffer sich 
schneller füllt als ich ihn auslese, da das Senden sehr viel Zeit in 
anspruch nimmt. Liege ich da richtig?

Falls ja, wie kann ich das Problem umgehen?
Gibt es eine Möglichkeit den Buffer langsamer zu füllen, also einfach 
mehr Zeit zwischen den Messungen zu lassen?
Alternativ, gibt es eine Möglichkeit das Senden (client.print...) zu 
beschleunigen?

Danke, Niklas

von Niklas S. (nicklarrs)


Lesenswert?

Hi Leute,

ich habe nun den Code sehr abgeändert, habe das hier 
(http://www.i2cdevlib.com/forums/topic/27-fifo-overflow/#entry99) 
versucht und es hat sich auch einiges verbessert.
Jedoch stürzt das Programm trotz allem nach ca. 6 Minuten ab, vorher 
wirft es noch einige "Fifo Overflows" raus.

Ich denke aber inzwischen, dass das Problem nicht an dem Holen der Daten 
vom MPU liegt, sondern am Senden der Daten über den ESP. Sprich, dass 
der FIFO Overflow nur deshalb entsteht, weil ich das WLAN Modul mit dem 
Senden überfordere und es steckenbleibt.

Deshalb habe ich auch mal nach dem "clien.send(tmp)" ein delay(40) 
drangehängt und es hat auch was gebracht. Jedoch konnte ich so das 
Abstürzten des Programms wieder nur nach hinten verschieben, das Problem 
gelöst hat das nicht...

Ich denke also, dass beim Senden ein Flaschenhals entsteht, das 
Wlan-Modul kommt mit dem Senden nicht hinterher und stürzt dann nach zu 
vielen Sendeversuchen ab.

Könnte ich da richtig liegen?
Wenn ja, gibt es irgendeine Lösung für das Problem?
Kann ich die Geschwindigkeit in der das Modul sendet irgendwie erhöhen?

So sieht momentan mein Code aus:
1
 // wait for MPU interrupt or extra packet(s) available
2
    while (!mpuInterrupt && fifoCount < packetSize) {
3
      
4
      }
5
6
    // reset interrupt flag and get INT_STATUS byte
7
    mpuInterrupt = false;
8
    mpuIntStatus = mpu.getIntStatus();
9
10
    // get current FIFO count
11
    fifoCount = mpu.getFIFOCount();
12
13
    // check for overflow (this should never happen unless our code is too inefficient)
14
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
15
        // reset so we can continue cleanly
16
        mpu.resetFIFO();
17
        Serial.println("FiFO Overflow");
18
    // otherwise, check for DMP data ready interrupt (this should happen frequently)
19
    } else if (mpuIntStatus & 0x02) {
20
        // wait for correct available data length, should be a VERY short wait
21
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
22
23
        // read a packet from FIFO
24
        mpu.getFIFOBytes(fifoBuffer, packetSize);
25
        
26
        // track FIFO count here in case there is > 1 packet available
27
        // (this lets us immediately read more without waiting for an interrupt)
28
        fifoCount -= packetSize;
29
30
        mpu.dmpGetAccel(&aa, fifoBuffer);
31
        /*
32
        mpu.dmpGetAccel(&aa, fifoBuffer);
33
        gravityX = aa.x / 8192.0;
34
        gravityY = aa.y / 8192.0;
35
        gravityZ = aa.z / 8192.0;
36
        tmp = tmp + String(gravityX) + " " + String(gravityY) + " " + String(gravityZ) + " ";
37
        */
38
39
        // display Euler angles in degrees
40
        mpu.dmpGetQuaternion(&q, fifoBuffer);
41
        mpu.dmpGetGravity(&gravity, &q);
42
        mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
43
44
        mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
45
46
        //tmp = String(aa.x) + " " + String(aa.y) + " " + String(aa.z) + " " + String(ypr[0]) + " " + String(ypr[1]) + " " + String(ypr[2]) + " " + String(aaReal.x) + " " + String(aaReal.y) + " " + String(aaReal.z) + "\r\n";
47
        tmp = String(aa.x) + " " + String(aa.y) + " " + String(aa.z) + " " + String(aaReal.x) + " " + String(aaReal.y) + " " + String(aaReal.z) + "\r\n";
48
        //Senden der Daten über ESP
49
        client.print(tmp);
50
        delay(50);
51
        Serial.print(tmp);
52
    }
53
}


Und so sieht der Output auf der seriellen Console aus:
1
-6504 2399 4043 -102.56 -54.17 17.34 139 -42 -84 //Ca 7 Minuten bekomme ich alle ca. 50 mS den gewünschten Output
2
-6504 2399 4043 -102.56 -54.17 17.34 139 -42 -84
3
-6504 2399 4043 -102.56 -54.17 17.34 139 -42 -84//Dann stockt das Programm, alle ca 20 Sekunden gibt es einen Output und dazu den "Fifo Overflow"
4
FIFO overflow!
5
-6504 2399 4043 -102.56 -54.17 17.34 139 -42 -84
6
FIFO overflow!
7
-6506 2389 4040 -102.56 -54.16 17.35 135 -54 -87
8
FIFO overflow!
9
-6496 2389 4053 -102.54 -54.17 17.34 145 -52 -75
10
...

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.