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