Forum: Mikrocontroller und Digitale Elektronik acc/gyro winkel bestimmen


von Ray M. (ray_m)


Lesenswert?

Hi,

Ich hab jetzt 3 Tage das Netz durchsucht und leider
keine passende Antwort gefunden, deshalb hier mal eine Frage
zum Thema.

Vorweg, ich benutze aktuell ein MPU6050.

Ich berechne die Winkel mit dem angehängten Test-Code.
Soweit so gut.

Wenn ich den Sensor um  eine Achse kippe, hat das kurzzeitig
auch Auswirkungen auf die andere Achse.

Bsp.

In Ruhelage habe ich
  -0.0 : -0.1

Wenn ich den Sensor bewege kurzzeitig z.B.
  -3.1 : 15.4

Wenn ich den Sensor dann in dieser Lage halte pendelt sich
das ganze korrekt auf die erwarteten Werte ein
  -0.1 : 15.3

Ich würde gern den die Änderung (im Bsp. Pitch) unterdrücken
wenn ich den Sensor auf der anderen Achse (im Bsp. Roll) bewege.

Ist das möglich und wenn ja wie ?
1
#include "I2Cdev.h"
2
#include "MPU6050.h"
3
#include "Wire.h"
4
5
MPU6050 accelgyro1(0x68);
6
7
int16_t ax1, ay1, az1;
8
int16_t gx1, gy1, gz1;
9
float aPitch, aRoll;
10
float fx1, fy1, fz1;
11
float fPitch, fRoll;
12
float dt = 0.001;
13
14
const    long LOOP_DEF    = 100; // in ms
15
unsigned long LOOP_DEF_pM = 0;
16
17
void setup() {
18
  Wire.begin();
19
  delay(100);
20
  Serial.begin(115200);
21
  delay(100);
22
  accelgyro1.initialize();
23
  delay(100);
24
  pinMode(LED_BUILTIN, OUTPUT);
25
}
26
27
void loop() {
28
  unsigned long currentMillis = millis();
29
30
  accelgyro1.getMotion6(&ax1, &ay1, &az1, &gx1, &gy1, &gz1);
31
32
  aPitch  = -(atan2(ax1, sqrt(ay1*ay1 + az1*az1))*180.0)/M_PI;
33
  aRoll   = (atan2(ay1, az1)*180.0)/M_PI;
34
35
  fx1     = 0.98*(fx1+gx1*dt)+0.02*(ax1);
36
  fy1     = 0.98*(fy1+gy1*dt)+0.02*(ay1);
37
  fz1     = 0.98*(fz1+gz1*dt)+0.02*(az1);
38
  fPitch  = -(atan2(fx1, sqrt(fy1*fy1 + fz1*fz1))*180.0)/M_PI;
39
  fRoll   = (atan2(fy1, fz1)*180.0)/M_PI;
40
41
  if ( currentMillis - LOOP_DEF_pM >= LOOP_DEF ) {
42
    LOOP_DEF_pM = currentMillis;
43
44
    Serial.print(aPitch,1); Serial.print(" : "); Serial.print(aRoll,1);
45
    Serial.println();
46
    Serial.print(fPitch,1); Serial.print(" : "); Serial.print(fRoll,1);
47
    Serial.println();
48
    Serial.println("---------------\n");
49
    
50
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
51
  }
52
}

: Bearbeitet durch User
von DraconiX (Gast)


Lesenswert?

Auf was für einem µC betreibst du denn die Berechnung o.O

Bist du dir denn ganz sicher das du die Achse (Pitch) nicht scheinbar 
doch um 3° bewegst während du die andere Achse auf 15° drehst? Ich 
meine, so ruhig kann keine menschliche Hand drehen. Oder ist deine 
"Apparatur auf ein" genulltes Drehgestell montiert?

Ansonsten, nen Deadtimer für die jeweils anderen Achsen mit einfügen 
wenn du aktuell nur die eine Achse sehen willst.

Liest du das über das Gyro aus oder hast du am MPU6050 ein 3 Achsen 
Kompass angeschlossen?!

von RP6conrad (Gast)


Lesenswert?

Dieses Algoritme mache eine Mischung zwischen ACC und Gyro, wo das gyro 
anteil 98% betragt und ACC 2%. Daneben siehe ich auch die sample zeit dt 
= 0.001, oder 1 ms. Aber ich siehe in die loop nicht diese feste 
samplezeit zuruck. Wen das nicht stimmt, stimmt der Integration von gyro 
auch nicht !  Damit haben sie dan immer Fehler nach eine Bewegung, und 
bei Stillstand pendelt sich das wieder richting durch das 2% ACC Anteil. 
chnVersuch erst mal auf feste Zeiten den ACC und Gyro zu samplen, und 
auch ihre Berechnung durch zu fuhren. 1ms scheint mir ziemlich wenig, 
besser soll 10 ms sein.

von Ray M. (ray_m)


Lesenswert?

DraconiX schrieb:

[...]

> Liest du das über das Gyro aus oder hast du am MPU6050 ein 3 Achsen
> Kompass angeschlossen?!

Kein Kompass, nur acc/gyro vom MPU6050

von Ray M. (ray_m)


Lesenswert?

RP6conrad schrieb:
> Dieses Algoritme mache eine Mischung zwischen ACC und Gyro, wo das gyro
> anteil 98% betragt und ACC 2%. Daneben siehe ich auch die sample zeit dt
> = 0.001, oder 1 ms. Aber ich siehe in die loop nicht diese feste
> samplezeit zuruck. Wen das nicht stimmt, stimmt der Integration von gyro
> auch nicht !  Damit haben sie dan immer Fehler nach eine Bewegung, und
> bei Stillstand pendelt sich das wieder richting durch das 2% ACC Anteil.
> chnVersuch erst mal auf feste Zeiten den ACC und Gyro zu samplen, und
> auch ihre Berechnung durch zu fuhren. 1ms scheint mir ziemlich wenig,
> besser soll 10 ms sein.

ist es das was du meinst ?
es scheint mit dem folgendem code auch etwas besser zu werden
1
include "I2Cdev.h"
2
#include "MPU6050.h"
3
#include "Wire.h"
4
5
MPU6050 accelgyro1(0x68);
6
7
int16_t ax1, ay1, az1;
8
int16_t gx1, gy1, gz1;
9
float aPitch, aRoll;
10
float fx1, fy1, fz1;
11
float fPitch, fRoll;
12
float dt = 0.001;
13
14
const    long LOOP_DEF    = 100; // in ms
15
unsigned long LOOP_DEF_pM = 0;
16
unsigned long LAST_LOOP_TIME = 0;
17
18
void setup() {
19
  Wire.begin();
20
  delay(100);
21
  Serial.begin(115200);
22
  delay(100);
23
  accelgyro1.initialize();
24
  delay(100);
25
  pinMode(LED_BUILTIN, OUTPUT);
26
}
27
28
void loop() {
29
  unsigned long currentMillis = millis();
30
31
  accelgyro1.getMotion6(&ax1, &ay1, &az1, &gx1, &gy1, &gz1);
32
33
  dt = (currentMillis - LAST_LOOP_TIME) / 1000;
34
  LAST_LOOP_TIME = currentMillis;
35
36
  aPitch  = -(atan2(ax1, sqrt(ay1*ay1 + az1*az1))*180.0)/M_PI;
37
  aRoll   = (atan2(ay1, az1)*180.0)/M_PI;
38
39
  fx1     = 0.98*(fx1+gx1*dt)+0.02*(ax1);
40
  fy1     = 0.98*(fy1+gy1*dt)+0.02*(ay1);
41
  fz1     = 0.98*(fz1+gz1*dt)+0.02*(az1);
42
  fPitch  = -(atan2(fx1, sqrt(fy1*fy1 + fz1*fz1))*180.0)/M_PI;
43
  fRoll   = (atan2(fy1, fz1)*180.0)/M_PI;
44
45
  if ( currentMillis - LOOP_DEF_pM >= LOOP_DEF ) {
46
    LOOP_DEF_pM = currentMillis;
47
48
    Serial.print(aPitch,1); Serial.print(" : "); Serial.print(aRoll,1);
49
    Serial.println();
50
    Serial.print(fPitch,1); Serial.print(" : "); Serial.print(fRoll,1);
51
    Serial.println();
52
    Serial.println("---------------\n");
53
    
54
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
55
  }
56
}

: Bearbeitet durch User
von Ray M. (ray_m)


Lesenswert?

das war mist, dt ist in meinem code immer 0 ;)

aber wenn ich dt auf 0 stelle scheint der effect zu verschwinden,
ich versteh nur noch bahnhof ...

von Ray M. (ray_m)


Lesenswert?

so funktioniert es auch nicht
1
#include "I2Cdev.h"
2
#include "MPU6050.h"
3
#include "Wire.h"
4
5
MPU6050 accelgyro1(0x68);
6
7
int16_t ax1, ay1, az1;
8
int16_t gx1, gy1, gz1;
9
float aPitch, aRoll;
10
float fx1, fy1, fz1;
11
float fPitch, fRoll;
12
13
uint32_t timer;
14
15
const    long LOOP_DEF    = 100; // in ms
16
unsigned long LOOP_DEF_pM = 0;
17
18
void setup() {
19
  Wire.begin();
20
  delay(100);
21
  Serial.begin(115200);
22
  delay(100);
23
  accelgyro1.initialize();
24
  delay(100);
25
  pinMode(LED_BUILTIN, OUTPUT);
26
  timer = micros();
27
}
28
29
void loop() {
30
  unsigned long currentMillis = millis();
31
32
  accelgyro1.getMotion6(&ax1, &ay1, &az1, &gx1, &gy1, &gz1);
33
34
  double dt = (double)(micros() - timer) / 1000000;
35
  timer = micros();
36
37
  aPitch  = -(atan2(ax1, sqrt(ay1*ay1 + az1*az1))*180.0)/M_PI;
38
  aRoll   = (atan2(ay1, az1)*180.0)/M_PI;
39
40
  fx1     = 0.98*(fx1+gx1*dt)+0.02*(ax1);
41
  fy1     = 0.98*(fy1+gy1*dt)+0.02*(ay1);
42
  fz1     = 0.98*(fz1+gz1*dt)+0.02*(az1);
43
  fPitch  = -(atan2(fx1, sqrt(fy1*fy1 + fz1*fz1))*180.0)/M_PI;
44
  fRoll   = (atan2(fy1, fz1)*180.0)/M_PI;
45
46
  if ( currentMillis - LOOP_DEF_pM >= LOOP_DEF ) {
47
    LOOP_DEF_pM = currentMillis;
48
49
    Serial.print(aPitch,1); Serial.print(" : "); Serial.print(aRoll,1);
50
    Serial.println();
51
    Serial.print(dt,10); Serial.print(" : ");
52
    Serial.print(fPitch,1); Serial.print(" : "); Serial.print(fRoll,1);
53
    Serial.println();
54
    Serial.println("---------------\n");
55
    
56
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
57
  }
58
}

nur wenn ich dt = 0 setze scheint es in etwa hin zu kommen,
dass versteh ich leider garnicht

von RP6conrad (Gast)


Lesenswert?

Wan dt 0 ist, wird nur noch den ACC ausgewertet, damit scheint es besser 
zu functionieren. Aber ACC hat das Nachteil das alle Beschleunigungnen 
mit verrechtnet werden, und damit nur bei Stillstand eine gute 
Auswertung gibt. Versuch mal die gyro-integration separat auszuwerten :
10ms loop {fx1=gx1*dt+fx1;Serial.print(fx1);}
Damit sollen sie einen Winkel bekommen die langzam wegdriftet, aber bei 
Drehungen soll er auch richtig reagieren.
Sehr wichtig bei einen gyro ist die drift-kompensierung ! Sie vermessen 
die gyro ausgabe bei Stillstand uber einige Secunden, das ist dan die 
offset. Dieses offset wird dan immer verrechtnet, so das die Drift 
minimiert wird.

von Ray M. (ray_m)


Lesenswert?

RP6conrad schrieb:
> Wan dt 0 ist, wird nur noch den ACC ausgewertet, damit scheint es besser
> zu functionieren. Aber ACC hat das Nachteil das alle Beschleunigungnen
> mit verrechtnet werden, und damit nur bei Stillstand eine gute
> Auswertung gibt. Versuch mal die gyro-integration separat auszuwerten :
> 10ms loop {fx1=gx1*dt+fx1;Serial.print(fx1);}
> Damit sollen sie einen Winkel bekommen die langzam wegdriftet, aber bei
> Drehungen soll er auch richtig reagieren.
> Sehr wichtig bei einen gyro ist die drift-kompensierung ! Sie vermessen
> die gyro ausgabe bei Stillstand uber einige Secunden, das ist dan die
> offset. Dieses offset wird dan immer verrechtnet, so das die Drift
> minimiert wird.

ich verstehe das so leider nicht, hast du ein bsp.

von RP6conrad (Gast)


Lesenswert?

ACC vermesst direct die erdbeschleunigung (g). Das wird berechtnet aus 
die X und Z komponente mit hilfe von Atan2(X,Z). Das gibt dan ein Winkel 
gegenueber die Senkrechte.
Ein gyro gibt eine Drehrate aus (°/s).Bei Stillstand sollen alle gyro 
achse 0°/s ausgeben. Wen sie einen Winkel hieraus berechnen wollen, 
mussen sie diese Drehrate integrieren (= aufaddieren). Beispiel : gyro 
gibt ein Drehrate von 10°/s, dan ist die Winkelaenderung nach 5 s 50°. 
Auf diese art ist eine continuerliche Messung von Winkel moglich. 
Einfach immer diese Drehrate integrieren. Davon kommt diese Berechnung : 
fx1=gx1*dt+fx1. fx1 ist die forherige Winkel, gx1 ist die Drehrate, dt 
ist die Zeit zwischen eine Durchlauf. Nachteil von gyro : Er hat keine 
"nullposition", das bedeutet das bei Anfang steht die Winkel immer auf 
0. Daneben gibt eine "offset", bei Stillstand gibt er noch immer eine 
kleine Drehgeschwindigkeit an. Damit sehen sie diese Winkel langsam 
"wegdriften".
Um die richtige "sensorfusion" zu machen, muss du erst sicher stellen 
das ACC und Gyro berechnungen stimmen ! Darum separat auswerten.

von Ray M. (ray_m)


Lesenswert?

ok, ich werde nich mal versuchen ... danke

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.