Forum: Mikrocontroller und Digitale Elektronik MPU6050 - Hilfe bei Winkelbestimmung


von Hanswurst (Gast)


Lesenswert?

Hallo allerseits. Ich versuche aus dem Gyroskop und Accelerometer im 
MPU6050 die Winkel abzuleiten. Habe dazu folgendes Programm aus dem 
Netz:
1
#include <Wire.h>
2
3
int gyro_x, gyro_y, gyro_z;
4
int angle_pitch_buffer, angle_roll_buffer;
5
int temp;
6
int count = 0;
7
8
long gyro_x_cal, gyro_y_cal, gyro_z_cal;
9
long acc_x, acc_y, acc_z, acc_total_vector;
10
long loop_timer;
11
long acc_x_average, acc_y_average, acc_z_average;
12
13
long gyro_x_offset = 0;
14
long gyro_y_offset = 0;
15
long gyro_z_offset = 0;
16
17
long acc_x_offset = 0; // 10
18
long acc_y_offset = 0; // 180
19
long acc_z_offset = 0; // -225
20
21
boolean set_gyro_angles;
22
boolean toggle;
23
24
float angle_roll_acc, angle_pitch_acc;
25
float angle_pitch, angle_roll;
26
float angle_pitch_output, angle_roll_output;
27
28
void setup() 
29
{
30
  Wire.begin();                                                        //Start I2C as master
31
32
  Serial.begin(115200);
33
  
34
  setup_mpu_6050_registers();                                          //Setup the registers of the MPU-6050 
35
36
  Serial.println("Calibrating gyro");
37
  
38
  for(int cal_int = 0; cal_int < 500 ; cal_int ++)
39
  {                                                                    //Read the raw acc and gyro data from the MPU-6050 for 500 times
40
    read_mpu_6050_data();                                             
41
    gyro_x_cal += gyro_x;                                              //Add the gyro x offset to the gyro_x_cal variable
42
    gyro_y_cal += gyro_y;                                              //Add the gyro y offset to the gyro_y_cal variable
43
    gyro_z_cal += gyro_z;                                              //Add the gyro z offset to the gyro_z_cal variable
44
    delay(3);                                                          //Delay 3us to have 250Hz for-loop
45
  }
46
47
  pinMode(8, OUTPUT);
48
  pinMode(9, OUTPUT);
49
  pinMode(10, OUTPUT);
50
    
51
  // divide by 500 to get avarage offset
52
  gyro_x_cal /= 500;                                                 
53
  gyro_y_cal /= 500;                                                 
54
  gyro_z_cal /= 500;                                                 
55
  
56
  Serial.begin(115200);
57
  
58
  loop_timer = micros();                                               //Reset the loop timer
59
}
60
61
void loop(){
62
63
  read_mpu_6050_data();   
64
  
65
  //Subtract the offset values from the raw gyro values
66
  gyro_x -= gyro_x_cal;                                                
67
  gyro_y -= gyro_y_cal;                                                
68
  gyro_z -= gyro_z_cal;
69
  acc_x += acc_x_offset;
70
  acc_y += acc_y_offset; 
71
  acc_z += acc_z_offset;                                               
72
         
73
  //Gyro angle calculations . Note 0.0000611 = 1 / (250Hz x 65.5)
74
  angle_pitch += gyro_x * 0.0000611;                                   //Calculate the traveled pitch angle and add this to the angle_pitch variable
75
  angle_roll += gyro_y * 0.0000611;                                    //Calculate the traveled roll angle and add this to the angle_roll variable
76
  
77
  //0.000001066 = 0.0000611 * (3.142(PI) / 180degr) The Arduino sin function is in radians
78
  angle_pitch += angle_roll * sin(gyro_z * 0.000001066);               //If the IMU has yawed transfer the roll angle to the pitch angel
79
  angle_roll -= angle_pitch * sin(gyro_z * 0.000001066);               //If the IMU has yawed transfer the pitch angle to the roll angel
80
  
81
  //Accelerometer angle calculations
82
  acc_total_vector = sqrt((acc_x*acc_x)+(acc_y*acc_y)+(acc_z*acc_z));  //Calculate the total accelerometer vector
83
  
84
  //57.296 = 1 / (3.142 / 180) The Arduino asin function is in radians
85
  angle_pitch_acc = asin((float)acc_y/acc_total_vector)* 57.296;       //Calculate the pitch angle
86
  angle_roll_acc = asin((float)acc_x/acc_total_vector)* -57.296;       //Calculate the roll angle
87
  
88
  angle_pitch_acc -= -2.04;                                            //Accelerometer calibration value for pitch
89
  angle_roll_acc -= 0.38;                                              //Accelerometer calibration value for roll
90
91
  if(set_gyro_angles)
92
  {                                                                    //If the IMU is already started
93
    angle_pitch = angle_pitch * 0.9996 + angle_pitch_acc * 0.0004;     //Correct the drift of the gyro pitch angle with the accelerometer pitch angle
94
    angle_roll = angle_roll * 0.9996 + angle_roll_acc * 0.0004;        //Correct the drift of the gyro roll angle with the accelerometer roll angle
95
  }
96
  
97
  else
98
  {                                                                    //At first start
99
    angle_pitch = angle_pitch_acc;                                     //Set the gyro pitch angle equal to the accelerometer pitch angle 
100
    angle_roll = angle_roll_acc;                                       //Set the gyro roll angle equal to the accelerometer roll angle 
101
    set_gyro_angles = true;                                            //Set the IMU started flag
102
  }
103
  
104
  //To dampen the pitch and roll angles a complementary filter is used
105
  angle_pitch_output = angle_pitch_output * 0.9 + angle_pitch * 0.1;   //Take 90% of the output pitch value and add 10% of the raw pitch value
106
  angle_roll_output = angle_roll_output * 0.9 + angle_roll * 0.1;      //Take 90% of the output roll value and add 10% of the raw roll value
107
108
  acc_x_average += acc_x;
109
  acc_y_average += acc_y;
110
  acc_z_average += acc_z;
111
  count++;
112
  
113
  if(count == 100)
114
  {  
115
  Serial.print(acc_x_average/100);
116
  Serial.print("\t");
117
  Serial.print(acc_y_average/100);
118
  Serial.print("\t");
119
  Serial.print(acc_z_average/100);
120
  Serial.print("\t\t");
121
  Serial.print(angle_pitch_output);
122
  Serial.print("\t");
123
  Serial.println(angle_roll_output);
124
  count = 0;
125
  acc_x_average = 0;
126
  acc_y_average = 0;
127
  acc_z_average = 0;
128
  }
129
  
130
  
131
  // half frequency output
132
  toggle = !toggle; if(!toggle) { PORTB |= (1 << PB2); } else { PORTB &= ~(1 << PB2); }
133
134
  if(angle_pitch_output <= 90.1 && angle_pitch_output >= 89.9) { digitalWrite(8, HIGH); } else { digitalWrite(8, LOW); }
135
  if(angle_roll_output <= 90.1 && angle_roll_output >= 89.9) { digitalWrite(9, HIGH); } else { digitalWrite(9, LOW); }
136
137
  while(micros() - loop_timer < 4000);                                 //Wait until the loop_timer reaches 4000us (250Hz) before starting the next loop
138
  
139
  loop_timer = micros();//Reset the loop timer 
140
}
141
142
143
144
145
void setup_mpu_6050_registers()
146
{
147
  //Activate the MPU-6050
148
  Wire.beginTransmission(0x68);                                        //Start communicating with the MPU-6050
149
  Wire.write(0x6B);                                                    //Send the requested starting register
150
  Wire.write(0x00);                                                    //Set the requested starting register
151
  Wire.endTransmission();                                             
152
  //Configure the accelerometer (+/-8g)
153
  Wire.beginTransmission(0x68);                                        //Start communicating with the MPU-6050
154
  Wire.write(0x1C);                                                    //Send the requested starting register
155
  Wire.write(0x10);                                                    //Set the requested starting register
156
  Wire.endTransmission();                                             
157
  //Configure the gyro (500dps full scale)
158
  Wire.beginTransmission(0x68);                                        //Start communicating with the MPU-6050
159
  Wire.write(0x1B);                                                    //Send the requested starting register
160
  Wire.write(0x08);                                                    //Set the requested starting register
161
  Wire.endTransmission();                                             
162
}
163
164
void read_mpu_6050_data()
165
{                                                                       //Subroutine for reading the raw gyro and accelerometer data
166
  Wire.beginTransmission(0x68);                                        //Start communicating with the MPU-6050
167
  Wire.write(0x3B);                                                    //Send the requested starting register
168
  Wire.endTransmission();                                              //End the transmission
169
  Wire.requestFrom(0x68,14);                                           //Request 14 bytes from the MPU-6050
170
  while(Wire.available() < 14);                                        //Wait until all the bytes are received
171
  acc_x = Wire.read()<<8|Wire.read();                                  
172
  acc_y = Wire.read()<<8|Wire.read();                                  
173
  acc_z = Wire.read()<<8|Wire.read();                                  
174
  temp = Wire.read()<<8|Wire.read();                                   
175
  gyro_x = Wire.read()<<8|Wire.read();                                 
176
  gyro_y = Wire.read()<<8|Wire.read();                                 
177
  gyro_z = Wire.read()<<8|Wire.read();                                 
178
}

Der MPU6050 liegt flach auf meinem Schreibtisch (Werte driften kaum) und 
nach einer kurzen Zeit kippe ich die Y-Achse um 90 °:

GyX GyY  GyZ    X    Y
-33 -174 4349  -0.04 0.14
-32 -174 4353  -0.05 0.13
-33 -173 4350  -0.06 0.14
-31 -175 4354  -0.06 0.14
-31 -173 4355  -0.07 0.14
-31 -173 4349  -0.08 0.14
-32 -174 4352  -0.08 0.14
-33 -173 4349  -0.08 0.13
-32 -174 4353  -0.09 0.13
-33 -175 4354  -0.10 0.13
-33 -178 4351  -0.11 0.13
-31 -173 4351  -0.12 0.12
-33 -172 4353  -0.12 0.13
-33 -173 4355  -0.12 0.14
-31 -173 4354  -0.13 0.14
-34 -173 4350  -0.12 0.16
-95 -168 4365  0.00 4.45
-1750 -184 3795  -0.97 42.07
-3658 -260 1730  -1.08 79.78
-4082 -287 431  -1.35 88.81
-4057 -270 56  -1.50 89.84
-4055 -270 30  -1.35 89.83
-4056 -272 14  -1.40 90.09 << ab hier 90 Grad gedreht
-4055 -272 -8  -1.41 89.91
-4056 -278 -3  -1.41 89.45
-4058 -267 28  -1.38 89.19
-4055 -269 32  -1.33 89.04
-4060 -267 27  -1.34 88.89
-4054 -266 32  -1.36 88.77
-4058 -264 32  -1.37 88.65
-4056 -266 32  -1.38 88.55
-4053 -263 34  -1.40 88.44
-4055 -265 36  -1.43 88.33
-4052 -268 40  -1.45 88.21
-4058 -265 40  -1.45 88.12
-4056 -264 34  -1.46 88.04
-4056 -267 34  -1.47 87.93
-4057 -266 36  -1.49 87.86
-4057 -266 36  -1.49 87.79
-4058 -265 37  -1.51 87.71
-4056 -267 37  -1.53 87.65
-4056 -269 34  -1.56 87.58
-4057 -268 36  -1.57 87.52
-4055 -269 37  -1.58 87.46
-4056 -267 35  -1.58 87.40
-4055 -267 38  -1.58 87.33
-4054 -267 37  -1.58 87.28
-4057 -266 40  -1.58 87.24
-4059 -266 40  -1.60 87.19
-4057 -266 37  -1.59 87.14
-4058 -264 34  -1.59 87.09
-4056 -266 37  -1.58 87.05
-4058 -265 33  -1.60 87.01
-4056 -263 36  -1.61 86.97
-4057 -265 39  -1.60 86.93
-4057 -265 37  -1.61 86.89
-4056 -266 36  -1.61 86.85
-4059 -264 37  -1.62 86.81
-4056 -266 32  -1.62 86.76
-4058 -265 41  -1.61 86.73
-4057 -267 41  -1.60 86.69
-4058 -267 39  -1.61 86.65
-4056 -266 40  -1.62 86.61

Mein Problem ist, dass ein gekippter Sensor sofort anfängt zu driften 
(siehe Messwerte). Weiß jemand, an welcher Stelle der Drift zustande 
kommt?

von Forist (Gast)


Lesenswert?

Hanswurst schrieb:
> Habe dazu folgendes Programm aus dem
> Netz:
> #include <Wire.h>
> ...
Verwende doch bitte die Code-Tage für C-Code, wenn du schon so langen 
Code direkt einbindest. Mit den automatischen Zeilenumbrüchen des 
Fließtextes ist das so mehr als unleserlich.

von RP6conrad (Gast)


Lesenswert?

Gyro offset acc offset und mag offset muss erst kalibriert werden.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Die Werte des Beschleunigungssensors sehen recht stabil aus. Lass doch 
mal den Gyro aus der Berechnung raus...

: Wiederhergestellt durch Moderator
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.