Components and supplies
Breadboard (generic)
Arduino UNO
SparkFun Triple Axis Accelerometer and Gyro Breakout - MPU-6050
Jumper wires (generic)
Tools and machines
Soldering iron (generic)
Project description
Code
Code version 1.2.1
arduino
The code now adds data to the gyroscope and accelerometer saved data arrays. This will allow the Kalman filter to make its predictions based on past data. very important! There are also some other small fixes. the filter will probably be added soon, but when is unknown. We're doing our best to implement the math.
1/** 2 _ 3 _ _ \\_\ _ 4 |_| /_\\_\| |_ 5 \\_\\ 6version 1.2.1 (filter still in progress, but data gets saved) . this work is free to use by anyone, but please credit it if you are using it. 7**/ 8 9 10#include<Wire.h> 11/** 12 * the #include 's are to tell the program to import the two libraries instead of writing them all out. 13 * wire lets the gyroscope and the arduino communicate over the ic^2 connection. 14 */ 15#define gyro_address 0x68 16/* change this number to the ic^2 adress of your gyroscope (in Hexidecimal, so find that column and add a 0x if there isn't one), 17 * though if you don't have one already, an Invenesense MPU-6050 will make the code work without edits. 18*/ 19int16_t accel_x, accel_y, accel_z, temp, gyro_x, gyro_y, gyro_z; 20/**the int16_t defines 16 bits per variable. 15 can be used, but computers prefer 8, 16, 32, etc. change the number 21 * to change the bits. these are left blank because the first thing to happen in the loop is them being filled with 22 * the gyroscope's value. the math used has to be altered though, so some gyroscopes may use more bits. at this point, 23 * you really need the documentation for the gyroscope. 24 */ 25array gyro_data = []; //this stores the past data from the sensor, giving the kalman filter some of its neccasary data. 26array accel_data = []; //this stores the past data from the sensor, giving the kalman filter some of its neccasary data. 27array gyro_current = []; //this feeds into the main variable, but it's here just to better orginize the X, Y. & Z values. 28array accel_current = []; //this feeds into the main variable, but it's here just to better orginize the X, Y. & Z values. 29 30void setup() { 31 Wire.begin(); 32 Wire.beginTransmission(gyro_address); 33 Wire.write(0x6B); // PWR_MGMT_1 register 34 Wire.write(0); // set to zero (wakes up the MPU-6050) 35 Wire.endTransmission(true); //set this to false, and it doesn't end. simple enough, right? 36 37 Wire.beginTransmission(gyro_address); 38 Wire.write(0x6a); 39 Wire.requestFrom(gyro_address, 1, true); 40 int usercontrol = Wire.read(); 41 Wire.endTransmission(true); 42 Serial.begin(9600); 43 /**initiate 'Serial' library. most arduinos use 9600 baud (bits per second) but some use different amounts. 44 * again, check the documentation.*/ 45 double x_rotation = 0, y_rotation = 0, z_rotation = 0; 46 //these double variables have double the bits as others, so they can be longer and therefor more specific. 47} 48 49void loop() { 50 Wire.beginTransmission(gyro_address); 51 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H).this number may change depending on how the gyroscope transferrs data. 52 Wire.endTransmission(false); 53 Wire.requestFrom(gyro_address, 14, true); // request a total of 14 registers (again, it may be different for your gyroscope) 54 accel_x = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) 55 accel_y = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) 56 accel_z = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) 57 temp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) 58 gyro_x = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) 59 gyro_y = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) 60 gyro_z = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L) 61 /* 62 * these 7 variables look familiar? we defined them as nothing in setup(). these store the raw values of the gyroscope. 63 * once again, all these numbers may change. if you can, refer to a program someone else made with the same gyro to 64 * save a couple headaches. 65 */ 66 accel_current = [accel_x,accel_y,accel_z]; 67 gyro_current = [gyro_x,gyro_y,gyro_z]; 68 Serial.print(" | Accelerometer X:"); 69 Serial.print(accel_x); 70 Serial.print(" | Accelerometer Y:"); 71 Serial.print(accel_y); 72 Serial.print(" | Accelerometer Z:"); 73 Serial.print(accel_z); 74 Serial.print(" | Temperature:"); 75 Serial.print(temp / 340.00 + 36.53); 76 Serial.print(" | Gyro X:"); 77 Serial.print(gyro_x); 78 Serial.print(" | Gyro Y:"); 79 Serial.print(gyro_y); 80 Serial.print(" | Gyro Z:"); 81 Serial.println(gyro_z); 82 gyro_data[gyro_data.length()] = gyro_current; 83 accel_data[accel_data.length()] = accel_current; 84 /** 85 * these two top statements add the current data from the gyro and accel to the data arrays, using a neat trick: every array counts 86 * starting at 0, but the .length() function starts at one. this allows us to create new data in the arrays constantly! be warned: 87 * using a constantly adding array can be dangerous, especially with large amounts of data. 88 */ 89 delay(100);//this is important to make sure the board and arduino both aren't overloading. slower-operating gyros may need a bigger number. 90} 91
code version 1.3.2
arduino
hurrah! the math for the complimentary filter is done, meaning that there is one filter left, the kalman filter, and then the final conversion math can be completed.
1/** 2 _ 3 _ _ \\_\ _ 4 |_| /_\\_\| |_ 5 \\_\\ 6version 1.3.1 (filter 1 out of 2 done, one more still in progress, cleaned up the text a little) . this work is free to use by anyone, but please credit it if you are using it. 7**/ 8#include<Wire.h> 9#include<math.h> 10/** 11 * the #include 's are to tell the program to import the two libraries instead of writing them all out. wire lets the gyroscope and the arduino communicate over the ic^2 connection. 12 */ 13#define gyro_address 0x68 14/* change this number to the ic^2 adress of your gyroscope (in Hexidecimal, so find that column and add a 0x if there isn't one), though if you don't have one already, an Invenesense MPU-6050 will make the code work without edits. 15*/ 16#define ACCELEROMETER_SENSITIVITY 8192.0 17#define GYROSCOPE_SENSITIVITY 65.536 18/* these are used to account for the lack of perfectness in the gyroscope, they can help a little CURRENTLY NOT IN USE 19*/ 20int dataRate = 100; 21int16_t accelX, accelY, accelZ, temp, gyroX, gyroY, gyroZ,angleX,angleY,angleZ; 22/**the int16_t defines 16 bits per variable. 15 can be used, but computers prefer 8, 16, 32, etc. change the number to change the bits. these are left blank because the first thing to happen in the loop is them being filled with 23 * the gyroscope's value. the math used has to be altered though, so some gyroscopes may use more bits. at this point,you really need the documentation for the gyroscope. 24 */ 25 26void setup() { 27 Wire.begin(); 28 Wire.beginTransmission(gyro_address); 29 Wire.write(0x6B); // PWR_MGMT_1 register 30 Wire.write(0); // set to zero (wakes up the MPU-6050) 31 Wire.endTransmission(true); //set this to false, and it doesn't end. simple enough, right? 32 33 Wire.beginTransmission(gyro_address); 34 Wire.write(0x6a); 35 Wire.requestFrom(gyro_address, 1, true); 36 int usercontrol = Wire.read(); 37 Wire.endTransmission(true); 38 Serial.begin(9600); 39 /**initiate 'Serial' library. most arduinos use 9600 baud (bits per second) but some use different amounts. 40 * again, check the documentation.*/ 41 Serial.println("libraries loaded "); 42 //this is our message. please don't copy our code without mention. there's a lot of work here, and we wanted to share it with you as long as you respect our work. 43 44 double x_rotation = 0, y_rotation = 0, z_rotation = 0; 45 //these double variables have double the bits as others, so they can be longer and therefor more specific. 46} 47 48void loop() { 49 Wire.beginTransmission(gyro_address); 50 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H).this number may change depending on how the gyroscope transferrs data. 51 Wire.endTransmission(false); 52 Wire.requestFrom(gyro_address, 14, true); // request a total of 14 registers (again, it may be different for your gyroscope) 53 accelX = Wire.read() << 8 | Wire.read(); accelY = Wire.read() << 8 | Wire.read(); accelZ = Wire.read() << 8 | Wire.read(); //accelerometer data shift and variable update 54 temp = Wire.read() << 8 | Wire.read(); //temperature data shift and variable update 55 gyroX = Wire.read() << 8 | Wire.read(); gyroY = Wire.read() << 8 | Wire.read(); gyroZ = Wire.read() << 8 | Wire.read(); //gyroscope data shift and variable update 56 /* 57 * these 7 variables look familiar? we defined them as nothing in setup(). these store the raw values of the gyroscope. once again, all these numbers may change depending on 58 * gyroscope type. if you can, refer to a program someone else made with the same gyro to save a couple headaches. */ 59 //heavy math time: 60 accelX = atan2(accelY, accelZ) * 57.2957795131; 61 accelY = atan2(accelX, accelZ) * 57.2957795131; 62 //accelZ = atan2(accelX, accelY): //due to math problems, the z axis isn't avaible as yet. however, two axis (plural) should be fine 63 angleX = 0.98* (angleX + gyroX * dataRate) + 0.02 * accelX; 64 angleY = 0.98* (angleY + gyroY * dataRate) + 0.02 * accelY; 65 //angleZ = 0.98* (angleZ + gyroZ * dataRate) + 0.02 * accelZ; 66 67 //Serial.print(" | Accelerometer X:");Serial.print(accelX);Serial.print(" | Accelerometer Y:");Serial.print(accelY);Serial.print(" | Accelerometer Z:");Serial.print(accelZ);Serial.print(" | Temperature:");Serial.print(temp / 340.00 + 36.53);Serial.print(" | Gyro X:");Serial.print(gyroX);Serial.print(" | Gyro Y:");Serial.print(gyroY);Serial.print(" | Gyro Z:");Serial.println(gyroZ); 68 //there's our first data set, now retired. progress!. 69 Serial.print(" | AngleX: "); 70 Serial.print(angleX); 71 Serial.print(" | Angle Y: "); 72 Serial.print(angleY); 73 Serial.print(" | Angle Z: "); 74 Serial.println(angleZ); 75 //and here's the second, with the filter! 76 77 delay(dataRate);//this is important to make sure the board and arduino both aren't overloading. slower-operating gyros may need a bigger number. 78} 79
Code version 1.1.0
arduino
This is an updated version of the code, with a few improvements but no filter or math yet..
1/** 2 _ 3 _ _ \\_\ _ 4 |_| /_\\_\| |_ 5 \\_\\ 6version 1.1.0 . this work is free to use by anyone, but please credit it if you are using it. 7**/ 8 9 10#include<Wire.h> 11/** 12 * the #include 's are to tell the program to import the two libraries instead of writing them all out. 13 * wire lets the gyroscope and the arduino communicate over the ic^2 connection. 14 */ 15#define gyro_address 0x68 16/* change this number to the ic^2 adress of your gyroscope (in Hexidecimal, so find that column and add a 0x if there isn't one), 17 * though if you don't have one already, an Invenesense MPU-6050 will make the code work without edits. 18*/ 19int16_t accel_x, accel_y, accel_z, temp, gyro_x, gyro_y, gyro_z; 20/**the int16_t defines 16 bits per variable. 15 can be used, but computers prefer 8, 16, 32, etc. change the number 21 * to change the bits. these are left blank because the first thing to happen in the loop is them being filled with 22 * the gyroscope's value. the math used has to be altered though, so some gyroscopes may use more bits. at this point, 23 * you really need the documentation for the gyroscope. 24 */ 25 26void setup() { 27 Wire.begin(); 28 Wire.beginTransmission(gyro_address); 29 Wire.write(0x6B); // PWR_MGMT_1 register 30 Wire.write(0); // set to zero (wakes up the MPU-6050) 31 Wire.endTransmission(true); //set this to false, and it doesn't end. simple enough, right? 32 33 Wire.beginTransmission(gyro_address); 34 Wire.write(0x6a); 35 Wire.requestFrom(gyro_address, 1, true); 36 int usercontrol = Wire.read(); 37 Wire.endTransmission(true); 38 Serial.begin(9600); 39 /**initiate 'Serial' library. most arduinos use 9600 baud (bits per second) but some use different amounts. 40 * again, check the documentation.*/ 41 double x_rotation = 0, y_rotation = 0, z_rotation = 0; 42 //these double variables have double the bits as others, so they can be longer and therefor more specific. 43} 44 45void loop() { 46 Wire.beginTransmission(gyro_address); 47 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H).this number may change depending on how the gyroscope transferrs data. 48 Wire.endTransmission(false); 49 Wire.requestFrom(gyro_address, 14, true); // request a total of 14 registers (again, it may be different for your gyroscope) 50 accel_x = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) 51 accel_y = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) 52 accel_z = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) 53 temp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) 54 gyro_x = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) 55 gyro_y = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) 56 gyro_z = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L) 57 /* 58 * these 7 variables look familiar? we defined them as nothing in setup(). these store the raw values of the gyroscope. 59 * once again, all these numbers may change. if you can, refer to a program someone else made with the same gyro to 60 * save a couple headaches. 61 */ 62 Serial.print(" | Accelerometer X:"); 63 Serial.print(accel_x); 64 Serial.print(" | Accelerometer Y:"); 65 Serial.print(accel_y); 66 Serial.print(" | Accelerometer Z:"); 67 Serial.print(accel_z); 68 Serial.print(" | Temperature:"); 69 Serial.print(temp / 340.00 + 36.53); 70 Serial.print(" | Gyro X:"); 71 Serial.print(gyro_x); 72 Serial.print(" | Gyro Y:"); 73 Serial.print(gyro_y); 74 Serial.print(" | Gyro Z:"); 75 Serial.println(gyro_z); 76 delay(100);//this is important to make sure the board and arduino both aren't overloading. slower-operating gyros may need a bigger number. 77} 78
adaptive filter apha
arduino
here's a more active version of the complementary filter, making sure that the
1/* 2 * this code is a PROTOTYPE version of the adaptive filter for the MPU-6050 gyroscope unit. 3 * this is very akin to a complimentary filter, however it uses the gyroscope data to more 4 * accurately fluctuate between control of the gyroscope, accelerometer, and later compass. 5 * please use, change or edit this code to your own will. HOWEVER: this code has taken a lot 6 * of work and you MUST reference the creater of this code. 7 * 8 * Oscar Zingle and Flynn Meredith-Black, 2017 9 * 10 * OZTL. this code is released on HACKSTER.IO . please submit changes to hackster to support 11 * the open-sourced community! 12 * 13 * version 0.0.2 (very very alpha stage, not working perfectly) 14 */ 15#include<Wire.h> 16#define MPU_addr 0x68 17#define delay_value 0.01 //how long the program is delayed each time. please change this value, 18//DO NOT change the delay manually. it will break everything 19 20//variables 21int16_t AccelX_out, AccelY_out, AccelZ_out, Tmp, GyroX_out, GyroY_out, GyroZ_out; 22double AccelX, AccelY, AccelZ, GyroX, GyroY, GyroZ, AngleX, AngleY, AngleZ, xR, yR, zR; 23void setup() { 24 Wire.begin(); 25 Serial.begin(9600);//change depending on the data rate of your arduino. 26 Wire.beginTransmission(MPU_addr); 27 Wire.write(0x6B); // PWR_MGMT_1 register 28 Wire.write(0); // set to zero (wakes up the MPU-6050) 29 Wire.endTransmission(true); 30 31 Wire.beginTransmission(MPU_addr); 32 Wire.write(0x6A); 33 Wire.endTransmission(false); 34 Wire.requestFrom(MPU_addr, 1, true); 35 Wire.endTransmission(true); 36} 37 38void loop() { 39 Wire.beginTransmission(MPU_addr); 40 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) 41 Wire.endTransmission(false); 42 Wire.requestFrom(MPU_addr, 14, true); // request a total of 14 registers 43 AccelX_out = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) 44 AccelY_out = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) 45 AccelZ_out = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) 46 Tmp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) 47 GyroX_out = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) 48 GyroY_out = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) 49 GyroZ_out = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L) 50 AccelX = atan2(AccelY_out, AccelZ_out) * 57.2957795131; 51 AccelY = atan2(AccelX_out, AccelZ_out) * 57.2957795131; 52 //Serial.println(AccelX); 53 if (GyroX_out >= 0) { 54 GyroX = ((double(GyroX_out)) * 250 / 32767.0) * delay_value * 10; 55 } else if (GyroX_out < 0) { 56 GyroX = ((double(GyroX_out)) * 250 / 32768.0) * delay_value * 10; 57 } 58 59 if (GyroY_out >= 0) { 60 GyroY = ((double(GyroY_out)) * 250 / 32767.0) * delay_value * 10; 61 } else if (GyroX_out < 0) { 62 GyroY = ((double(GyroY_out)) * 250 / 32768.0) * delay_value * 10; 63 } 64 xR += GyroX; 65 yR += GyroY; 66 zR += GyroZ; 67 delay(delay_value * 1000); 68 if (GyroX > 10) { 69 AngleX = (0.97 * ((AngleX + xR) / 2) + 0.03 * (AccelX)); 70 Serial.print("option 1 "); 71 } else if (GyroX <= 10 && GyroX > 5) { 72 AngleX = (0.90 * ((AngleX + xR) / 2) + 0.10 * (AccelX)); 73 Serial.print("option 2 "); 74 } else if (GyroX <= 5 && GyroX > 2.5) { 75 AngleX = (0.80 * ((AngleX + xR) / 2) + 0.20 * (AccelX)); 76 Serial.print("option 2 "); 77 } else { 78 AngleX = (0.03 * ((AngleX + xR) / 2) + 0.97 * (AccelX)); 79 xR = AccelX; 80 Serial.print("option 3 "); 81 } 82 Serial.println(AngleX); 83} 84/*This product is meant for educational purposes only. Any resemblance to real persons, living or dead is 85purely coincidental. Void where prohibited. Batteries not included. 86*/ 87
adaptive filter version 0.8.2
arduino
the adaptive filter works! yay! it's not fluid, but values are set out. yay!
1/* 2 * this code is a PROTOTYPE version of the adaptive filter for the MPU-6050 gyroscope unit. 3 * this is very akin to a complimentary filter, however it uses the gyroscope data to more 4 * accurately fluctuate between control of the gyroscope, accelerometer, and later compass. 5 * please use, change or edit this code to your own will. HOWEVER: this code has taken a lot 6 * of work and you MUST reference the creater of this code. 7 * 8 * Oscar Zingle and Flynn Meredith-Black, 2017 9 * 10 * OZTL. this code is released on HACKSTER.IO . please submit changes to hackster to support 11 * the open-sourced community! 12 * 13 * version 0.0.2 (very very alpha stage, not working perfectly) 14 */ 15#include<Wire.h> 16#define MPU_addr 0x68 17#define delay_value 0.01 //how long the program is delayed each time. please change this value, 18//DO NOT change the delay manually. it will break everything 19 20//variables 21int16_t AccelX_out, AccelY_out, AccelZ_out, Tmp, GyroX_out, GyroY_out, GyroZ_out; 22double AccelX, AccelY, AccelZ, GyroX, GyroY, GyroZ, AngleX, AngleY, AngleZ, xR, yR, zR; 23void setup() { 24 Wire.begin(); 25 Serial.begin(9600);//change depending on the data rate of your arduino. 26 Wire.beginTransmission(MPU_addr); 27 Wire.write(0x6B); // PWR_MGMT_1 register 28 Wire.write(0); // set to zero (wakes up the MPU-6050) 29 Wire.endTransmission(true); 30 31 Wire.beginTransmission(MPU_addr); 32 Wire.write(0x6A); 33 Wire.endTransmission(false); 34 Wire.requestFrom(MPU_addr, 1, true); 35 Wire.endTransmission(true); 36} 37 38void loop() { 39 Wire.beginTransmission(MPU_addr); 40 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) 41 Wire.endTransmission(false); 42 Wire.requestFrom(MPU_addr, 14, true); // request a total of 14 registers 43 AccelX_out = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) 44 AccelY_out = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) 45 AccelZ_out = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) 46 Tmp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) 47 GyroX_out = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) 48 GyroY_out = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) 49 GyroZ_out = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L) 50 AccelX = atan2(AccelY_out, AccelZ_out) * 57.2957795131; 51 AccelY = atan2(AccelX_out, AccelZ_out) * 57.2957795131; 52 //Serial.println(AccelX); 53 if (GyroX_out >= 0) { 54 GyroX = ((double(GyroX_out)) * 250 / 32767.0) * delay_value * 10; 55 } else if (GyroX_out < 0) { 56 GyroX = ((double(GyroX_out)) * 250 / 32768.0) * delay_value * 10; 57 } 58 59 if (GyroY_out >= 0) { 60 GyroY = ((double(GyroY_out)) * 250 / 32767.0) * delay_value * 10; 61 } else if (GyroX_out < 0) { 62 GyroY = ((double(GyroY_out)) * 250 / 32768.0) * delay_value * 10; 63 } 64 xR += GyroX; 65 yR += GyroY; 66 zR += GyroZ; 67 delay(delay_value * 1000); 68 69 if (AccelX > 10) { 70 AngleX = (0.95 * ((AngleX + xR) / 2) + 0.05 * (AccelX)); 71 //Serial.print("option 1 "); 72 } else if (AccelX <= 10 && AccelX > 5) { 73 AngleX = (0.65 * ((AngleX + xR) / 2) + 0.35 * (AccelX)); 74 //Serial.print("option 2 "); 75 } else if (AccelX <= 5 && AccelX > 2.5) { 76 AngleX = (0.80 * ((AngleX + xR) / 2) + 0.20 * (AccelX)); 77 //Serial.print("option 2 "); 78 } else { 79 AngleX = (0.00 * ((AngleX + xR) / 2) + 1.00 * (AccelX)); 80 xR = AccelX; 81 //Serial.print("option 3 "); 82 } 83 Serial.print(AngleX); 84 Serial.print(" "); 85 Serial.print(GyroX); 86 Serial.print(" "); 87 Serial.print(AccelX); 88 Serial.println(); 89} 90/*This product is meant for educational purposes only. Any resemblance to real persons, living or dead is 91purely coincidental. Void where prohibited. Batteries not included. 92*/ 93
Adaptive filter version 1.1.2
arduino
Yay! its awful. --changelog-- -NEW! lots of random data to sort through! -FIXED! the data is relatively smooth -that's all
1/* 2 * this code is a PROTOTYPE version of the adaptive filter for the MPU-6050 gyroscope unit. 3 * this is very akin to a complimentary filter, however it uses the gyroscope data to more 4 * accurately fluctuate between control of the gyroscope, accelerometer, and later compass. 5 * please use, change or edit this code to your own will. HOWEVER: this code has taken a lot 6 * of work and you MUST reference the creater of this code. 7 * 8 * Oscar Zingle and Flynn Meredith-Black, 2017 9 * 10 * OZTL. this code is released on HACKSTER.IO . please submit changes to hackster to support 11 * the open-sourced community! 12 * 13 * version 1.1.2 (very very alpha stage, not working perfectly) 14 */ 15#include<Wire.h> 16#define MPU_addr 0x68 17#define delay_value 0.01 //how long the program is delayed each time. please change this value, 18//DO NOT change the delay manually. it will break everything 19 20//variables 21int Accel_old; 22int16_t AccelX_out, AccelY_out, AccelZ_out, Tmp, GyroX_out, GyroY_out, GyroZ_out; 23double AccelX, AccelY, AccelZ, GyroX, GyroY, GyroZ, AngleX, AngleY, AngleZ, xR, yR, zR; 24void setup() { 25 Wire.begin(); 26 Serial.begin(9600);//change depending on the data rate of your arduino. 27 Wire.beginTransmission(MPU_addr); 28 Wire.write(0x6B); // PWR_MGMT_1 register 29 Wire.write(0); // set to zero (wakes up the MPU-6050) 30 Wire.endTransmission(true); 31 32 Wire.beginTransmission(MPU_addr); 33 Wire.write(0x6A); 34 Wire.endTransmission(false); 35 Wire.requestFrom(MPU_addr, 1, true); 36 Wire.endTransmission(true); 37} 38 39void loop() { 40 Wire.beginTransmission(MPU_addr); 41 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) 42 Wire.endTransmission(false); 43 Wire.requestFrom(MPU_addr, 14, true); // request a total of 14 registers 44 AccelX_out = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) 45 AccelY_out = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) 46 AccelZ_out = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) 47 Tmp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) 48 GyroX_out = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) 49 GyroY_out = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) 50 GyroZ_out = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L) 51 AccelX = atan2(AccelY_out, AccelZ_out) * 57.2957795131; 52 AccelY = atan2(AccelX_out, AccelZ_out) * 57.2957795131; 53 AccelZ = atan2(AccelX_out, AccelY_out) * 57.2957795131; 54 //Serial.println(AccelX); 55 if (GyroX_out >= 0) { 56 GyroX = ((double(GyroX_out)) * 250 / 32767.0) * delay_value * 10; 57 } else if (GyroX_out < 0) { 58 GyroX = ((double(GyroX_out)) * 250 / 32768.0) * delay_value * 10; 59 } 60 61 if (GyroY_out >= 0) { 62 GyroY = ((double(GyroY_out)) * 250 / 32767.0) * delay_value * 10; 63 } else if (GyroX_out < 0) { 64 GyroY = ((double(GyroY_out)) * 250 / 32768.0) * delay_value * 10; 65 } 66 xR += GyroX; 67 yR += GyroY; 68 zR += GyroZ; 69 delay(delay_value * 1000); 70 if (((AccelX_out + AccelY_out + AccelZ_out) - Accel_old) < 100 and ((AccelX_out + AccelY_out + AccelZ_out) - Accel_old) > -100) { 71 AngleX = (0.10 * ((AngleX + xR) / 2) + 0.90 * (AccelX)); 72 xR = AccelX; 73 } else { 74 75 AngleX = ( 0.90 * ((AngleX + xR) / 2) + 0.10 * (AccelX)); 76 } 77 //AngleX = ( (((AccelX_out + AccelY_out + AccelZ_out) - 16383.75) - Accel_old) * ((AngleX + xR) / 2) + (1 -(((AccelX_out + AccelY_out + AccelZ_out) - 16383.75)) * (AccelX))) ; 78 Serial.print(AngleX); 79 Serial.print(" "); 80 Serial.print(AccelX); 81 Serial.print(" "); 82 Serial.print(AccelY); 83 Serial.print(" "); 84 Serial.print(Tmp/340.00+36.53); 85 Serial.print(" "); 86 Serial.print(GyroX); 87 Serial.print(" "); 88 Serial.print(GyroY); 89 Serial.println(); 90 Accel_old = (AccelX_out + AccelY_out + AccelZ_out); 91} 92/*This product is meant for educational purposes only. Any resemblance to real persons, living or dead is 93purely coincidental. Void where prohibited. Batteries not included. 94*/ 95
code version 1.4.2
arduino
complete revamp of the whole system. its now running an optimized version of the original code with an awesome complimentary filter! the data is still jumpy, however, and updates are sure to come soon. sorry it's been so long!
1#include<Wire.h> 2#define MPU_addr 0x68//0x means HEX (because I don't really understand these things yet) 3/** 4 _ 5 _ _ \\_\ _ 6 |_| /_\\_\| |_ 7 \\_\\ 8 Version 1.4.2 (2/ now 4 filters done) 9**/ 10//much of the original code was done by JonChi of the arduino community! 11//vars for stuff 12double AccelX, AccelY, AccelZ, GyroX, GyroY, GyroZ, AngleX, AngleY, AngleZ; 13int tOne = 0, tTwo = 0; 14int16_t AccelX_out, AccelY_out, AccelZ_out, Tmp, GyroX_out, GyroY_out, GyroZ_out; 15double xR = 0, yR = 0, zR = 0, OldXr = 0, xA = 0, yA = 0, zA = 0; 16double DegX, DegSX; 17double dFudgeGyroX = 0; 18 19//this loop just gets everything up and going 20void setup() { 21 22 Serial.begin(9600); 23 Wire.begin(); 24 Wire.beginTransmission(MPU_addr); 25 Wire.write(0x6B); // PWR_MGMT_1 register 26 Wire.write(0); // set to zero (wakes up the MPU-6050) 27 Wire.endTransmission(true); 28 29 Wire.beginTransmission(MPU_addr); 30 Wire.write(0x6A); 31 Wire.endTransmission(false); 32 Wire.requestFrom(MPU_addr, 1, true); 33 Wire.endTransmission(true); 34 35} 36 37void loop() { 38 //communication with sensor 39 Wire.beginTransmission(MPU_addr); 40 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) 41 Wire.endTransmission(false); 42 Wire.requestFrom(MPU_addr, 14, true); // request a total of 14 registers 43 AccelX_out = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) 44 AccelY_out = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) 45 AccelZ_out = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) 46 Tmp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) 47 GyroX_out = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) 48 GyroY_out = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) 49 GyroZ_out = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L) 50 int debugPin = digitalRead(13); 51 if (debugPin == 0) { 52 delay(1000); 53 xR = 0; 54 yR = 0; 55 zR = 0; 56 Serial.println("Variables reset!"); 57 } 58 59 //the stablization numbers 60 AccelX = atan2(AccelY_out, AccelZ_out) * 57.2957795131; 61 AccelY = atan2(AccelX_out, AccelZ_out) * 57.2957795131; 62 //AccelZ = atan2(AccelX, AccelY): //due to math problems, the z axis isn't avaible as yet. however, two axis (plural) should be fine 63 //TAccelX = SAccelX * ((double(tTwo - tOne)) / 1000.0); 64 65 if (GyroX_out >= 0) { 66 GyroX = (double(GyroX_out)) * 250 / 32767.0; 67 } else if (GyroX_out < 0) { 68 GyroX = (double(GyroX_out)) * 250 / 32768.0; 69 } 70 71 if (GyroY_out >= 0) { 72 GyroY = (double(GyroY_out)) * 250 / 32767.0; 73 } else if (GyroX_out < 0) { 74 GyroY = (double(GyroY_out)) * 250 / 32768.0; 75 } 76 //GyroX = nGyroX; 77 tTwo = millis(); 78 //SGyroX = GyroX * ((double(tTwo - tOne)) / 1000.0); 79 GyroX = GyroX * ((double(tTwo - tOne)) / 1000.0); 80 yR += GyroY; 81 xR += GyroX; 82 yR = (0.50 * yR) + (0.50 * AccelX); 83 xR = (0.50 * xR) + (0.50 * AccelX); 84 //if (nAccelX + nAccelY + nAccelZ < 32767) { 85 AngleX = (0.97 * ((AngleX + xR) / 2) + 0.03 * (AccelX / 2)); 86 AngleY = (0.97 * (AngleY + GyroY) + 0.03 * (AccelY / 2)); 87 AngleZ = (0.97 * (AngleZ + GyroZ) + 0.03 * ( 1/*compass*/)); 88 //} 89 /* 90 if (AngleX >= 0) { 91 xR = (double(AngleX)) * 250 / 32767.0; 92 } else if (AngleX < 0) { 93 xR = (double(AngleX)) * 250 / 32768.0; 94 } 95 //AngleX = 0; 96 //AngleX = xR * ((double(tTwo - tOne)) / 1000.0); 97 */ 98 //Serial.println(tTwo - tOne); 99 tOne = tTwo; 100 101 //GyroY = GyroY * 250 / 32767.5; 102 //GyroZ = GyroZ * 250 / 32767.5; 103 Serial.print(AngleX); 104 //Serial.print(" "); 105 //Serial.print(AngleY); 106 //Serial.print(GyroX_out); 107 //Serial.print(" "); 108 //Serial.print(AccelX); 109 //Serial.print(" "); 110 //Serial.print(nGyroX); 111 //Serial.print(" "); 112 //Serial.println(AccelZ); 113 //Serial.print(SGyroX); 114 Serial.println(); 115 116 OldXr = xR; 117 delay(10); 118} 119 120 121 122
Code version 1.3.1
arduino
Basically version 1.3.0, but we did some cleaning up, making this thing easier to follow. once the code is done, we can post a version that has no comments, for those of you who understand the code, and only want the program to copy. also, as a note: the program uses 22,940 bytes, which is close to the old uno's limit. a stripped-down version can be added later for those with this chip. NOTE: we've found out that the code is missing one piece, the atan2 conversion for the accelerometer data. do not use this code yet!
1/** 2 _ 3 _ _ \\_\ _ 4 |_| /_\\_\| |_ 5 \\_\\ 6version 1.3.1 (filter 1 out of 2 done, one more still in progress, cleaned up the text a little) . this work is free to use by anyone, but please credit it if you are using it. 7**/ 8#include<Wire.h> 9/** 10 * the #include 's are to tell the program to import the two libraries instead of writing them all out. wire lets the gyroscope and the arduino communicate over the ic^2 connection. 11 */ 12#define gyro_address 0x68 13/* change this number to the ic^2 adress of your gyroscope (in Hexidecimal, so find that column and add a 0x if there isn't one), though if you don't have one already, an Invenesense MPU-6050 will make the code work without edits. 14*/ 15#define ACCELEROMETER_SENSITIVITY 8192.0 16#define GYROSCOPE_SENSITIVITY 65.536 17/* these are used to account for the lack of perfectness in the gyroscope, they can help a little CURRENTLY NOT IN USE 18*/ 19int dataRate = 100; 20int16_t accelX, accelY, accelZ, temp, gyroX, gyroY, gyroZ,angleX,angleY,angleZ; 21/**the int16_t defines 16 bits per variable. 15 can be used, but computers prefer 8, 16, 32, etc. change the number to change the bits. these are left blank because the first thing to happen in the loop is them being filled with 22 * the gyroscope's value. the math used has to be altered though, so some gyroscopes may use more bits. at this point,you really need the documentation for the gyroscope. 23 */ 24 25void setup() { 26 Wire.begin(); 27 Wire.beginTransmission(gyro_address); 28 Wire.write(0x6B); // PWR_MGMT_1 register 29 Wire.write(0); // set to zero (wakes up the MPU-6050) 30 Wire.endTransmission(true); //set this to false, and it doesn't end. simple enough, right? 31 32 Wire.beginTransmission(gyro_address); 33 Wire.write(0x6a); 34 Wire.requestFrom(gyro_address, 1, true); 35 int usercontrol = Wire.read(); 36 Wire.endTransmission(true); 37 Serial.begin(9600); 38 /**initiate 'Serial' library. most arduinos use 9600 baud (bits per second) but some use different amounts. 39 * again, check the documentation.*/ 40 Serial.println("libraries loaded "); 41 Serial.println(); 42 Serial.println("+--------------------+");Serial.println("| _ |");Serial.println("| _ _ | | _ |");Serial.println("| |_| /_ | | | |_ |");Serial.println("| |_| |");Serial.println("|thank you for using |");Serial.println("|our code. mention us|");Serial.println("|if you use it! |");Serial.println("+--------------------+"); 43 delay(2500); 44 //this is our message. please don't copy our code without mention. there's a lot of work here, and we wanted to share it with you as long as you respect our work. 45 46 double x_rotation = 0, y_rotation = 0, z_rotation = 0; 47 //these double variables have double the bits as others, so they can be longer and therefor more specific. 48} 49 50void loop() { 51 Wire.beginTransmission(gyro_address); 52 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H).this number may change depending on how the gyroscope transferrs data. 53 Wire.endTransmission(false); 54 Wire.requestFrom(gyro_address, 14, true); // request a total of 14 registers (again, it may be different for your gyroscope) 55 accelX = Wire.read() << 8 | Wire.read(); accelY = Wire.read() << 8 | Wire.read(); accelZ = Wire.read() << 8 | Wire.read(); //accelerometer data shift and variable update 56 temp = Wire.read() << 8 | Wire.read(); //temperature data shift and variable update 57 gyroX = Wire.read() << 8 | Wire.read(); gyroY = Wire.read() << 8 | Wire.read(); gyroZ = Wire.read() << 8 | Wire.read(); //gyroscope data shift and variable update 58 /* 59 * these 7 variables look familiar? we defined them as nothing in setup(). these store the raw values of the gyroscope. once again, all these numbers may change depending on 60 * gyroscope type. if you can, refer to a program someone else made with the same gyro to save a couple headaches. */ 61 //heavy math time: 62 angleX = 0.98* (angleX + gyroX * dataRate) + 0.02 * accelX; 63 angleY = 0.98* (angleY + gyroY * dataRate) + 0.02 * accelY; 64 angleZ = 0.98* (angleZ + gyroZ * dataRate) + 0.02 * accelZ; 65 66 //Serial.print(" | Accelerometer X:");Serial.print(accelX);Serial.print(" | Accelerometer Y:");Serial.print(accelY);Serial.print(" | Accelerometer Z:");Serial.print(accelZ);Serial.print(" | Temperature:");Serial.print(temp / 340.00 + 36.53);Serial.print(" | Gyro X:");Serial.print(gyroX);Serial.print(" | Gyro Y:");Serial.print(gyroY);Serial.print(" | Gyro Z:");Serial.println(gyroZ); 67 //there's our first data set, now retired. progress!. 68 69 Serial.print(" | AngleX: "); 70 Serial.print(angleX); 71 Serial.print(" | Angle Y: "); 72 Serial.print(angleY); 73 Serial.print(" | Angle Z: "); 74 Serial.println(angleZ); 75 //and here's the second, with the filter! 76 77 delay(dataRate);//this is important to make sure the board and arduino both aren't overloading. slower-operating gyros may need a bigger number. 78} 79
WIP stablized gyroscope
arduino
Simply set up your gyroscope, plug the code in, and watch the fun on the serial monitor or serial plotter. Your numbers will be in degrees, but this is still WIP and may not work completely or at all.
1/** 2 _ 3 _ _ \\_\ _ 4 |_| /_\\_\| |_ 5 \\_\\ 6version 1.0.0 . this work is free to use by anyone, but please credit it if you are using it. 7**/ 8 9 10#include<Wire.h> 11#include<Serial.h> 12/** 13 * the #include 's are to tell the program to import the two libraries instead of writing them all out. 14 * wire lets the gyroscope and the arduino communicate over the ic^2 connection. 15 */ 16#define gyro_address 0x68 17/* change this number to the ic^2 adress of your gyroscope (in Hexidecimal, so find that column and ad a 0x if there isn't one), 18 * though if you don't have one already, an Invenesense MPU-6050 will make the code work without edits. 19*/ 20void setup() { 21 int16_t accel_x, accel_y, accel_z, temp, gyro_x, gyro_y, gyro_z; 22 /**the int16_t defines 16 bits per variable. 15 can be used, but computers prefer 8, 16, 32, etc. change the number 23 * to change the bits. these are left blank because the first thing to happen in the loop is them being filled with 24 * the gyroscope's value. the math used has to be altered though, so some gyroscopes may use more bits. at this point, 25 * you really need the documentation for the gyroscope. 26 */ 27 Wire.begin(); 28 Wire.beginTransmission(MPU_addr); 29 Wire.write(0x6B); // PWR_MGMT_1 register 30 Wire.write(0); // set to zero (wakes up the MPU-6050) 31 Wire.endTransmission(true); //set this to false, and it doesn't end. simple enough, right? 32 33 Wire.beginTransmission(gyro_address); 34 Wire.write(0x6a); 35 Wire.requestFrom(gyro_adress, 1, true); 36 int usercontrol = Wire.read(); 37 Wire.endTransmission(true); 38 Serial.begin(9600); 39 /**initiate 'Serial' library. most arduinos use 9600 baud (bits per second) but some use different amounts. 40 * again, check the documentation.*/ 41 double x_rotation = 0, y_rotation = 0, z_rotation = 0; 42 //these double variables have double the bits as others, so they can be longer and therefor more specific. 43} 44 45void loop() { 46 // put your main code here, to run repeatedly: 47 48} 49
code version 1.3.2
arduino
hurrah! the math for the complimentary filter is done, meaning that there is one filter left, the kalman filter, and then the final conversion math can be completed.
1/** 2 _ 3 _ _ \\_\ _ 4 |_| /_\\_\| |_ 5 \\_\\ 6version 1.3.1 (filter 1 out of 2 done, one more still in progress, cleaned up the text a little) . this work is free to use by anyone, but please credit it if you are using it. 7**/ 8#include<Wire.h> 9#include<math.h> 10/** 11 * the #include 's are to tell the program to import the two libraries instead of writing them all out. wire lets the gyroscope and the arduino communicate over the ic^2 connection. 12 */ 13#define gyro_address 0x68 14/* change this number to the ic^2 adress of your gyroscope (in Hexidecimal, so find that column and add a 0x if there isn't one), though if you don't have one already, an Invenesense MPU-6050 will make the code work without edits. 15*/ 16#define ACCELEROMETER_SENSITIVITY 8192.0 17#define GYROSCOPE_SENSITIVITY 65.536 18/* these are used to account for the lack of perfectness in the gyroscope, they can help a little CURRENTLY NOT IN USE 19*/ 20int dataRate = 100; 21int16_t accelX, accelY, accelZ, temp, gyroX, gyroY, gyroZ,angleX,angleY,angleZ; 22/**the int16_t defines 16 bits per variable. 15 can be used, but computers prefer 8, 16, 32, etc. change the number to change the bits. these are left blank because the first thing to happen in the loop is them being filled with 23 * the gyroscope's value. the math used has to be altered though, so some gyroscopes may use more bits. at this point,you really need the documentation for the gyroscope. 24 */ 25 26void setup() { 27 Wire.begin(); 28 Wire.beginTransmission(gyro_address); 29 Wire.write(0x6B); // PWR_MGMT_1 register 30 Wire.write(0); // set to zero (wakes up the MPU-6050) 31 Wire.endTransmission(true); //set this to false, and it doesn't end. simple enough, right? 32 33 Wire.beginTransmission(gyro_address); 34 Wire.write(0x6a); 35 Wire.requestFrom(gyro_address, 1, true); 36 int usercontrol = Wire.read(); 37 Wire.endTransmission(true); 38 Serial.begin(9600); 39 /**initiate 'Serial' library. most arduinos use 9600 baud (bits per second) but some use different amounts. 40 * again, check the documentation.*/ 41 Serial.println("libraries loaded "); 42 //this is our message. please don't copy our code without mention. there's a lot of work here, and we wanted to share it with you as long as you respect our work. 43 44 double x_rotation = 0, y_rotation = 0, z_rotation = 0; 45 //these double variables have double the bits as others, so they can be longer and therefor more specific. 46} 47 48void loop() { 49 Wire.beginTransmission(gyro_address); 50 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H).this number may change depending on how the gyroscope transferrs data. 51 Wire.endTransmission(false); 52 Wire.requestFrom(gyro_address, 14, true); // request a total of 14 registers (again, it may be different for your gyroscope) 53 accelX = Wire.read() << 8 | Wire.read(); accelY = Wire.read() << 8 | Wire.read(); accelZ = Wire.read() << 8 | Wire.read(); //accelerometer data shift and variable update 54 temp = Wire.read() << 8 | Wire.read(); //temperature data shift and variable update 55 gyroX = Wire.read() << 8 | Wire.read(); gyroY = Wire.read() << 8 | Wire.read(); gyroZ = Wire.read() << 8 | Wire.read(); //gyroscope data shift and variable update 56 /* 57 * these 7 variables look familiar? we defined them as nothing in setup(). these store the raw values of the gyroscope. once again, all these numbers may change depending on 58 * gyroscope type. if you can, refer to a program someone else made with the same gyro to save a couple headaches. */ 59 //heavy math time: 60 accelX = atan2(accelY, accelZ) * 57.2957795131; 61 accelY = atan2(accelX, accelZ) * 57.2957795131; 62 //accelZ = atan2(accelX, accelY): //due to math problems, the z axis isn't avaible as yet. however, two axis (plural) should be fine 63 angleX = 0.98* (angleX + gyroX * dataRate) + 0.02 * accelX; 64 angleY = 0.98* (angleY + gyroY * dataRate) + 0.02 * accelY; 65 //angleZ = 0.98* (angleZ + gyroZ * dataRate) + 0.02 * accelZ; 66 67 //Serial.print(" | Accelerometer X:");Serial.print(accelX);Serial.print(" | Accelerometer Y:");Serial.print(accelY);Serial.print(" | Accelerometer Z:");Serial.print(accelZ);Serial.print(" | Temperature:");Serial.print(temp / 340.00 + 36.53);Serial.print(" | Gyro X:");Serial.print(gyroX);Serial.print(" | Gyro Y:");Serial.print(gyroY);Serial.print(" | Gyro Z:");Serial.println(gyroZ); 68 //there's our first data set, now retired. progress!. 69 Serial.print(" | AngleX: "); 70 Serial.print(angleX); 71 Serial.print(" | Angle Y: "); 72 Serial.print(angleY); 73 Serial.print(" | Angle Z: "); 74 Serial.println(angleZ); 75 //and here's the second, with the filter! 76 77 delay(dataRate);//this is important to make sure the board and arduino both aren't overloading. slower-operating gyros may need a bigger number. 78} 79
Adaptive filter version 1.1.2
arduino
Yay! its awful. --changelog-- -NEW! lots of random data to sort through! -FIXED! the data is relatively smooth -that's all
1/* 2 * this code is a PROTOTYPE version of the adaptive filter for 3 the MPU-6050 gyroscope unit. 4 * this is very akin to a complimentary filter, 5 however it uses the gyroscope data to more 6 * accurately fluctuate between 7 control of the gyroscope, accelerometer, and later compass. 8 * please use, change 9 or edit this code to your own will. HOWEVER: this code has taken a lot 10 * of 11 work and you MUST reference the creater of this code. 12 * 13 * Oscar Zingle 14 and Flynn Meredith-Black, 2017 15 * 16 * OZTL. this code is released on HACKSTER.IO 17 . please submit changes to hackster to support 18 * the open-sourced community! 19 20 * 21 * version 1.1.2 (very very alpha stage, not working perfectly) 22 */ 23#include<Wire.h> 24#define 25 MPU_addr 0x68 26#define delay_value 0.01 //how long the program is delayed each 27 time. please change this value, 28//DO NOT change the delay manually. it will 29 break everything 30 31//variables 32int Accel_old; 33int16_t AccelX_out, AccelY_out, 34 AccelZ_out, Tmp, GyroX_out, GyroY_out, GyroZ_out; 35double AccelX, AccelY, AccelZ, 36 GyroX, GyroY, GyroZ, AngleX, AngleY, AngleZ, xR, yR, zR; 37void setup() { 38 Wire.begin(); 39 40 Serial.begin(9600);//change depending on the data rate of your arduino. 41 Wire.beginTransmission(MPU_addr); 42 43 Wire.write(0x6B); // PWR_MGMT_1 register 44 Wire.write(0); // set to zero 45 (wakes up the MPU-6050) 46 Wire.endTransmission(true); 47 48 Wire.beginTransmission(MPU_addr); 49 50 Wire.write(0x6A); 51 Wire.endTransmission(false); 52 Wire.requestFrom(MPU_addr, 53 1, true); 54 Wire.endTransmission(true); 55} 56 57void loop() { 58 Wire.beginTransmission(MPU_addr); 59 60 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) 61 Wire.endTransmission(false); 62 63 Wire.requestFrom(MPU_addr, 14, true); // request a total of 14 registers 64 AccelX_out 65 = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) 66 67 AccelY_out = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) 68 69 AccelZ_out = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) 70 71 Tmp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) 72 73 GyroX_out = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) 74 75 GyroY_out = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) 76 77 GyroZ_out = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L) 78 79 AccelX = atan2(AccelY_out, AccelZ_out) * 57.2957795131; 80 AccelY = atan2(AccelX_out, 81 AccelZ_out) * 57.2957795131; 82 AccelZ = atan2(AccelX_out, AccelY_out) * 57.2957795131; 83 84 //Serial.println(AccelX); 85 if (GyroX_out >= 0) { 86 GyroX = ((double(GyroX_out)) 87 * 250 / 32767.0) * delay_value * 10; 88 } else if (GyroX_out < 0) { 89 GyroX 90 = ((double(GyroX_out)) * 250 / 32768.0) * delay_value * 10; 91 } 92 93 if 94 (GyroY_out >= 0) { 95 GyroY = ((double(GyroY_out)) * 250 / 32767.0) * delay_value 96 * 10; 97 } else if (GyroX_out < 0) { 98 GyroY = ((double(GyroY_out)) * 250 99 / 32768.0) * delay_value * 10; 100 } 101 xR += GyroX; 102 yR += GyroY; 103 zR 104 += GyroZ; 105 delay(delay_value * 1000); 106 if (((AccelX_out + AccelY_out + AccelZ_out) 107 - Accel_old) < 100 and ((AccelX_out + AccelY_out + AccelZ_out) - Accel_old) > -100) 108 { 109 AngleX = (0.10 * ((AngleX + xR) / 2) + 0.90 * (AccelX)); 110 xR = AccelX; 111 112 } else { 113 114 AngleX = ( 0.90 * ((AngleX + xR) / 2) + 0.10 * (AccelX)); 115 116 } 117 //AngleX = ( (((AccelX_out + AccelY_out + AccelZ_out) - 16383.75) - Accel_old) 118 * ((AngleX + xR) / 2) + (1 -(((AccelX_out + AccelY_out + AccelZ_out) - 16383.75)) 119 * (AccelX))) ; 120 Serial.print(AngleX); 121 Serial.print(" "); 122 Serial.print(AccelX); 123 124 Serial.print(" "); 125 Serial.print(AccelY); 126 Serial.print(" "); 127 128 Serial.print(Tmp/340.00+36.53); 129 Serial.print(" "); 130 Serial.print(GyroX); 131 132 Serial.print(" "); 133 Serial.print(GyroY); 134 Serial.println(); 135 Accel_old 136 = (AccelX_out + AccelY_out + AccelZ_out); 137} 138/*This product is meant for educational 139 purposes only. Any resemblance to real persons, living or dead is 140purely coincidental. 141 Void where prohibited. Batteries not included. 142*/ 143
Code version 1.2.1
arduino
The code now adds data to the gyroscope and accelerometer saved data arrays. This will allow the Kalman filter to make its predictions based on past data. very important! There are also some other small fixes. the filter will probably be added soon, but when is unknown. We're doing our best to implement the math.
1/** 2 _ 3 _ _ \\_\ _ 4 |_| /_\\_\| |_ 5 \\_\\ 6version 1.2.1 (filter still in progress, but data gets saved) . this work is free to use by anyone, but please credit it if you are using it. 7**/ 8 9 10#include<Wire.h> 11/** 12 * the #include 's are to tell the program to import the two libraries instead of writing them all out. 13 * wire lets the gyroscope and the arduino communicate over the ic^2 connection. 14 */ 15#define gyro_address 0x68 16/* change this number to the ic^2 adress of your gyroscope (in Hexidecimal, so find that column and add a 0x if there isn't one), 17 * though if you don't have one already, an Invenesense MPU-6050 will make the code work without edits. 18*/ 19int16_t accel_x, accel_y, accel_z, temp, gyro_x, gyro_y, gyro_z; 20/**the int16_t defines 16 bits per variable. 15 can be used, but computers prefer 8, 16, 32, etc. change the number 21 * to change the bits. these are left blank because the first thing to happen in the loop is them being filled with 22 * the gyroscope's value. the math used has to be altered though, so some gyroscopes may use more bits. at this point, 23 * you really need the documentation for the gyroscope. 24 */ 25array gyro_data = []; //this stores the past data from the sensor, giving the kalman filter some of its neccasary data. 26array accel_data = []; //this stores the past data from the sensor, giving the kalman filter some of its neccasary data. 27array gyro_current = []; //this feeds into the main variable, but it's here just to better orginize the X, Y. & Z values. 28array accel_current = []; //this feeds into the main variable, but it's here just to better orginize the X, Y. & Z values. 29 30void setup() { 31 Wire.begin(); 32 Wire.beginTransmission(gyro_address); 33 Wire.write(0x6B); // PWR_MGMT_1 register 34 Wire.write(0); // set to zero (wakes up the MPU-6050) 35 Wire.endTransmission(true); //set this to false, and it doesn't end. simple enough, right? 36 37 Wire.beginTransmission(gyro_address); 38 Wire.write(0x6a); 39 Wire.requestFrom(gyro_address, 1, true); 40 int usercontrol = Wire.read(); 41 Wire.endTransmission(true); 42 Serial.begin(9600); 43 /**initiate 'Serial' library. most arduinos use 9600 baud (bits per second) but some use different amounts. 44 * again, check the documentation.*/ 45 double x_rotation = 0, y_rotation = 0, z_rotation = 0; 46 //these double variables have double the bits as others, so they can be longer and therefor more specific. 47} 48 49void loop() { 50 Wire.beginTransmission(gyro_address); 51 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H).this number may change depending on how the gyroscope transferrs data. 52 Wire.endTransmission(false); 53 Wire.requestFrom(gyro_address, 14, true); // request a total of 14 registers (again, it may be different for your gyroscope) 54 accel_x = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) 55 accel_y = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) 56 accel_z = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) 57 temp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) 58 gyro_x = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) 59 gyro_y = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) 60 gyro_z = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L) 61 /* 62 * these 7 variables look familiar? we defined them as nothing in setup(). these store the raw values of the gyroscope. 63 * once again, all these numbers may change. if you can, refer to a program someone else made with the same gyro to 64 * save a couple headaches. 65 */ 66 accel_current = [accel_x,accel_y,accel_z]; 67 gyro_current = [gyro_x,gyro_y,gyro_z]; 68 Serial.print(" | Accelerometer X:"); 69 Serial.print(accel_x); 70 Serial.print(" | Accelerometer Y:"); 71 Serial.print(accel_y); 72 Serial.print(" | Accelerometer Z:"); 73 Serial.print(accel_z); 74 Serial.print(" | Temperature:"); 75 Serial.print(temp / 340.00 + 36.53); 76 Serial.print(" | Gyro X:"); 77 Serial.print(gyro_x); 78 Serial.print(" | Gyro Y:"); 79 Serial.print(gyro_y); 80 Serial.print(" | Gyro Z:"); 81 Serial.println(gyro_z); 82 gyro_data[gyro_data.length()] = gyro_current; 83 accel_data[accel_data.length()] = accel_current; 84 /** 85 * these two top statements add the current data from the gyro and accel to the data arrays, using a neat trick: every array counts 86 * starting at 0, but the .length() function starts at one. this allows us to create new data in the arrays constantly! be warned: 87 * using a constantly adding array can be dangerous, especially with large amounts of data. 88 */ 89 delay(100);//this is important to make sure the board and arduino both aren't overloading. slower-operating gyros may need a bigger number. 90} 91
code version 1.4.2
arduino
complete revamp of the whole system. its now running an optimized version of the original code with an awesome complimentary filter! the data is still jumpy, however, and updates are sure to come soon. sorry it's been so long!
1#include<Wire.h> 2#define MPU_addr 0x68//0x means HEX (because I don't 3 really understand these things yet) 4/** 5 _ 6 _ _ \\_\ _ 7 8 |_| /_\\_\| |_ 9 \\_\\ 10 Version 1.4.2 (2/ now 4 filters done) 11**/ 12//much 13 of the original code was done by JonChi of the arduino community! 14//vars for 15 stuff 16double AccelX, AccelY, AccelZ, GyroX, GyroY, GyroZ, AngleX, AngleY, AngleZ; 17int 18 tOne = 0, tTwo = 0; 19int16_t AccelX_out, AccelY_out, AccelZ_out, Tmp, GyroX_out, 20 GyroY_out, GyroZ_out; 21double xR = 0, yR = 0, zR = 0, OldXr = 0, xA = 0, yA = 22 0, zA = 0; 23double DegX, DegSX; 24double dFudgeGyroX = 0; 25 26//this loop 27 just gets everything up and going 28void setup() { 29 30 Serial.begin(9600); 31 32 Wire.begin(); 33 Wire.beginTransmission(MPU_addr); 34 Wire.write(0x6B); // 35 PWR_MGMT_1 register 36 Wire.write(0); // set to zero (wakes up the MPU-6050) 37 38 Wire.endTransmission(true); 39 40 Wire.beginTransmission(MPU_addr); 41 Wire.write(0x6A); 42 43 Wire.endTransmission(false); 44 Wire.requestFrom(MPU_addr, 1, true); 45 Wire.endTransmission(true); 46 47} 48 49void 50 loop() { 51 //communication with sensor 52 Wire.beginTransmission(MPU_addr); 53 54 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) 55 Wire.endTransmission(false); 56 57 Wire.requestFrom(MPU_addr, 14, true); // request a total of 14 registers 58 AccelX_out 59 = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) 60 61 AccelY_out = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) 62 63 AccelZ_out = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) 64 65 Tmp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) 66 67 GyroX_out = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) 68 69 GyroY_out = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) 70 71 GyroZ_out = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L) 72 73 int debugPin = digitalRead(13); 74 if (debugPin == 0) { 75 delay(1000); 76 77 xR = 0; 78 yR = 0; 79 zR = 0; 80 Serial.println("Variables reset!"); 81 82 } 83 84 //the stablization numbers 85 AccelX = atan2(AccelY_out, AccelZ_out) 86 * 57.2957795131; 87 AccelY = atan2(AccelX_out, AccelZ_out) * 57.2957795131; 88 89 //AccelZ = atan2(AccelX, AccelY): //due to math problems, the z axis isn't avaible 90 as yet. however, two axis (plural) should be fine 91 //TAccelX = SAccelX * ((double(tTwo 92 - tOne)) / 1000.0); 93 94 if (GyroX_out >= 0) { 95 GyroX = (double(GyroX_out)) 96 * 250 / 32767.0; 97 } else if (GyroX_out < 0) { 98 GyroX = (double(GyroX_out)) 99 * 250 / 32768.0; 100 } 101 102 if (GyroY_out >= 0) { 103 GyroY = (double(GyroY_out)) 104 * 250 / 32767.0; 105 } else if (GyroX_out < 0) { 106 GyroY = (double(GyroY_out)) 107 * 250 / 32768.0; 108 } 109 //GyroX = nGyroX; 110 tTwo = millis(); 111 //SGyroX 112 = GyroX * ((double(tTwo - tOne)) / 1000.0); 113 GyroX = GyroX * ((double(tTwo - 114 tOne)) / 1000.0); 115 yR += GyroY; 116 xR += GyroX; 117 yR = (0.50 * yR) + (0.50 118 * AccelX); 119 xR = (0.50 * xR) + (0.50 * AccelX); 120 //if (nAccelX + nAccelY 121 + nAccelZ < 32767) { 122 AngleX = (0.97 * ((AngleX + xR) / 2) + 0.03 * (AccelX 123 / 2)); 124 AngleY = (0.97 * (AngleY + GyroY) + 0.03 * (AccelY / 2)); 125 AngleZ 126 = (0.97 * (AngleZ + GyroZ) + 0.03 * ( 1/*compass*/)); 127 //} 128 /* 129 if 130 (AngleX >= 0) { 131 xR = (double(AngleX)) * 250 / 32767.0; 132 } else if (AngleX 133 < 0) { 134 xR = (double(AngleX)) * 250 / 32768.0; 135 } 136 //AngleX = 137 0; 138 //AngleX = xR * ((double(tTwo - tOne)) / 1000.0); 139 */ 140 //Serial.println(tTwo 141 - tOne); 142 tOne = tTwo; 143 144 //GyroY = GyroY * 250 / 32767.5; 145 //GyroZ 146 = GyroZ * 250 / 32767.5; 147 Serial.print(AngleX); 148 //Serial.print(" "); 149 150 //Serial.print(AngleY); 151 //Serial.print(GyroX_out); 152 //Serial.print(" 153 "); 154 //Serial.print(AccelX); 155 //Serial.print(" "); 156 //Serial.print(nGyroX); 157 158 //Serial.print(" "); 159 //Serial.println(AccelZ); 160 //Serial.print(SGyroX); 161 162 Serial.println(); 163 164 OldXr = xR; 165 delay(10); 166} 167 168 169 170
Code version 1.1.0
arduino
This is an updated version of the code, with a few improvements but no filter or math yet..
1/** 2 _ 3 _ _ \\_\ _ 4 |_| /_\\_\| |_ 5 \\_\\ 6version 1.1.0 . this work is free to use by anyone, but please credit it if you are using it. 7**/ 8 9 10#include<Wire.h> 11/** 12 * the #include 's are to tell the program to import the two libraries instead of writing them all out. 13 * wire lets the gyroscope and the arduino communicate over the ic^2 connection. 14 */ 15#define gyro_address 0x68 16/* change this number to the ic^2 adress of your gyroscope (in Hexidecimal, so find that column and add a 0x if there isn't one), 17 * though if you don't have one already, an Invenesense MPU-6050 will make the code work without edits. 18*/ 19int16_t accel_x, accel_y, accel_z, temp, gyro_x, gyro_y, gyro_z; 20/**the int16_t defines 16 bits per variable. 15 can be used, but computers prefer 8, 16, 32, etc. change the number 21 * to change the bits. these are left blank because the first thing to happen in the loop is them being filled with 22 * the gyroscope's value. the math used has to be altered though, so some gyroscopes may use more bits. at this point, 23 * you really need the documentation for the gyroscope. 24 */ 25 26void setup() { 27 Wire.begin(); 28 Wire.beginTransmission(gyro_address); 29 Wire.write(0x6B); // PWR_MGMT_1 register 30 Wire.write(0); // set to zero (wakes up the MPU-6050) 31 Wire.endTransmission(true); //set this to false, and it doesn't end. simple enough, right? 32 33 Wire.beginTransmission(gyro_address); 34 Wire.write(0x6a); 35 Wire.requestFrom(gyro_address, 1, true); 36 int usercontrol = Wire.read(); 37 Wire.endTransmission(true); 38 Serial.begin(9600); 39 /**initiate 'Serial' library. most arduinos use 9600 baud (bits per second) but some use different amounts. 40 * again, check the documentation.*/ 41 double x_rotation = 0, y_rotation = 0, z_rotation = 0; 42 //these double variables have double the bits as others, so they can be longer and therefor more specific. 43} 44 45void loop() { 46 Wire.beginTransmission(gyro_address); 47 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H).this number may change depending on how the gyroscope transferrs data. 48 Wire.endTransmission(false); 49 Wire.requestFrom(gyro_address, 14, true); // request a total of 14 registers (again, it may be different for your gyroscope) 50 accel_x = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) 51 accel_y = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) 52 accel_z = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) 53 temp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) 54 gyro_x = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) 55 gyro_y = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) 56 gyro_z = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L) 57 /* 58 * these 7 variables look familiar? we defined them as nothing in setup(). these store the raw values of the gyroscope. 59 * once again, all these numbers may change. if you can, refer to a program someone else made with the same gyro to 60 * save a couple headaches. 61 */ 62 Serial.print(" | Accelerometer X:"); 63 Serial.print(accel_x); 64 Serial.print(" | Accelerometer Y:"); 65 Serial.print(accel_y); 66 Serial.print(" | Accelerometer Z:"); 67 Serial.print(accel_z); 68 Serial.print(" | Temperature:"); 69 Serial.print(temp / 340.00 + 36.53); 70 Serial.print(" | Gyro X:"); 71 Serial.print(gyro_x); 72 Serial.print(" | Gyro Y:"); 73 Serial.print(gyro_y); 74 Serial.print(" | Gyro Z:"); 75 Serial.println(gyro_z); 76 delay(100);//this is important to make sure the board and arduino both aren't overloading. slower-operating gyros may need a bigger number. 77} 78
Code version 1.3.1
arduino
Basically version 1.3.0, but we did some cleaning up, making this thing easier to follow. once the code is done, we can post a version that has no comments, for those of you who understand the code, and only want the program to copy. also, as a note: the program uses 22,940 bytes, which is close to the old uno's limit. a stripped-down version can be added later for those with this chip. NOTE: we've found out that the code is missing one piece, the atan2 conversion for the accelerometer data. do not use this code yet!
1/** 2 _ 3 _ _ \\_\ _ 4 |_| /_\\_\| |_ 5 \\_\\ 6version 7 1.3.1 (filter 1 out of 2 done, one more still in progress, cleaned up the text a 8 little) . this work is free to use by anyone, but please credit it if you are using 9 it. 10**/ 11#include<Wire.h> 12/** 13 * the #include 's are to tell the program 14 to import the two libraries instead of writing them all out. wire lets the gyroscope 15 and the arduino communicate over the ic^2 connection. 16 */ 17#define gyro_address 18 0x68 19/* change this number to the ic^2 adress of your gyroscope (in Hexidecimal, 20 so find that column and add a 0x if there isn't one), though if you don't have one 21 already, an Invenesense MPU-6050 will make the code work without edits. 22*/ 23#define 24 ACCELEROMETER_SENSITIVITY 8192.0 25#define GYROSCOPE_SENSITIVITY 65.536 26/* these 27 are used to account for the lack of perfectness in the gyroscope, they can help 28 a little CURRENTLY NOT IN USE 29*/ 30int dataRate = 100; 31int16_t accelX, accelY, 32 accelZ, temp, gyroX, gyroY, gyroZ,angleX,angleY,angleZ; 33/**the int16_t defines 34 16 bits per variable. 15 can be used, but computers prefer 8, 16, 32, etc. change 35 the number to change the bits. these are left blank because the first thing to happen 36 in the loop is them being filled with 37 * the gyroscope's value. the math used 38 has to be altered though, so some gyroscopes may use more bits. at this point,you 39 really need the documentation for the gyroscope. 40 */ 41 42void setup() { 43 44 Wire.begin(); 45 Wire.beginTransmission(gyro_address); 46 Wire.write(0x6B); 47 // PWR_MGMT_1 register 48 Wire.write(0); // set to zero (wakes up the MPU-6050) 49 50 Wire.endTransmission(true); //set this to false, and it doesn't end. simple enough, 51 right? 52 53 Wire.beginTransmission(gyro_address); 54 Wire.write(0x6a); 55 56 Wire.requestFrom(gyro_address, 1, true); 57 int usercontrol = Wire.read(); 58 59 Wire.endTransmission(true); 60 Serial.begin(9600); 61 /**initiate 'Serial' 62 library. most arduinos use 9600 baud (bits per second) but some use different amounts. 63 64 * again, check the documentation.*/ 65 Serial.println("libraries loaded 66 "); 67 Serial.println(); 68 Serial.println("+--------------------+");Serial.println("| 69 _ |");Serial.println("| _ _ | | _ |");Serial.println("| 70 |_| /_ | | | |_ |");Serial.println("| |_| |");Serial.println("|thank 71 you for using |");Serial.println("|our code. mention us|");Serial.println("|if 72 you use it! |");Serial.println("+--------------------+"); 73 delay(2500); 74 75 //this is our message. please don't copy our code without mention. there's 76 a lot of work here, and we wanted to share it with you as long as you respect our 77 work. 78 79 double x_rotation = 0, y_rotation = 0, z_rotation = 0; 80 //these 81 double variables have double the bits as others, so they can be longer and therefor 82 more specific. 83} 84 85void loop() { 86 Wire.beginTransmission(gyro_address); 87 88 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H).this number may 89 change depending on how the gyroscope transferrs data. 90 Wire.endTransmission(false); 91 92 Wire.requestFrom(gyro_address, 14, true); // request a total of 14 registers (again, 93 it may be different for your gyroscope) 94 accelX = Wire.read() << 8 | Wire.read(); 95 accelY = Wire.read() << 8 | Wire.read(); accelZ = Wire.read() << 8 | Wire.read(); 96 //accelerometer data shift and variable update 97 temp = Wire.read() << 8 | Wire.read(); 98 //temperature data shift and variable update 99 gyroX = Wire.read() << 8 | Wire.read(); 100 gyroY = Wire.read() << 8 | Wire.read(); gyroZ = Wire.read() << 8 | Wire.read(); 101 //gyroscope data shift and variable update 102 /* 103 * these 7 variables look 104 familiar? we defined them as nothing in setup(). these store the raw values of the 105 gyroscope. once again, all these numbers may change depending on 106 * gyroscope 107 type. if you can, refer to a program someone else made with the same gyro to save 108 a couple headaches. */ 109 //heavy math time: 110 angleX = 0.98* (angleX + gyroX 111 * dataRate) + 0.02 * accelX; 112 angleY = 0.98* (angleY + gyroY * dataRate) + 113 0.02 * accelY; 114 angleZ = 0.98* (angleZ + gyroZ * dataRate) + 0.02 * accelZ; 115 116 117 //Serial.print(" | Accelerometer X:");Serial.print(accelX);Serial.print(" 118 | Accelerometer Y:");Serial.print(accelY);Serial.print(" | Accelerometer Z:");Serial.print(accelZ);Serial.print(" 119 | Temperature:");Serial.print(temp / 340.00 + 36.53);Serial.print(" | Gyro X:");Serial.print(gyroX);Serial.print(" 120 | Gyro Y:");Serial.print(gyroY);Serial.print(" | Gyro Z:");Serial.println(gyroZ); 121 122 //there's our first data set, now retired. progress!. 123 124 Serial.print(" 125 | AngleX: "); 126 Serial.print(angleX); 127 Serial.print(" | Angle Y: "); 128 129 Serial.print(angleY); 130 Serial.print(" | Angle Z: "); 131 Serial.println(angleZ); 132 133 //and here's the second, with the filter! 134 135 delay(dataRate);//this 136 is important to make sure the board and arduino both aren't overloading. slower-operating 137 gyros may need a bigger number. 138} 139
Code version 1.3.0
arduino
Hurrah! now that we've found time, we've got a major update for you! the arrays didn't work, so they're gone, but now there is a complimentary filter, lots of thanks to Pieter-Jan of Pieter-jan.com for this math! next update should clean it up a little, it's getting long! NOTE: we've found out that the code is missing one piece, the atan2 conversion for the accelerometer data. do not use this code yet!
1/** 2 _ 3 _ _ \\_\ _ 4 |_| /_\\_\| |_ 5 \\_\\ 6version 1.3.0 (filter 1 out of 2 done, one more still in progress, no more data gets saved) . this work is free to use by anyone, but please credit it if you are using it. 7**/ 8 9 10#include<Wire.h> 11/** 12 * the #include 's are to tell the program to import the two libraries instead of writing them all out. 13 * wire lets the gyroscope and the arduino communicate over the ic^2 connection. 14 */ 15#define gyro_address 0x68 16/* change this number to the ic^2 adress of your gyroscope (in Hexidecimal, so find that column and add a 0x if there isn't one), 17 * though if you don't have one already, an Invenesense MPU-6050 will make the code work without edits. 18*/ 19#define ACCELEROMETER_SENSITIVITY 8192.0 20#define GYROSCOPE_SENSITIVITY 65.536 21/* these are used to account for the lack of perfectness in the gyroscope, they can help a little 22*/ 23int dataRate = 100; 24 25int16_t accelX, accelY, accelZ, temp, gyroX, gyroY, gyroZ,angleX,angleY,angleZ; 26/**the int16_t defines 16 bits per variable. 15 can be used, but computers prefer 8, 16, 32, etc. change the number 27 * to change the bits. these are left blank because the first thing to happen in the loop is them being filled with 28 * the gyroscope's value. the math used has to be altered though, so some gyroscopes may use more bits. at this point, 29 * you really need the documentation for the gyroscope. 30 */ 31 32 33void setup() { 34 Wire.begin(); 35 Wire.beginTransmission(gyro_address); 36 Wire.write(0x6B); // PWR_MGMT_1 register 37 Wire.write(0); // set to zero (wakes up the MPU-6050) 38 Wire.endTransmission(true); //set this to false, and it doesn't end. simple enough, right? 39 40 Wire.beginTransmission(gyro_address); 41 Wire.write(0x6a); 42 Wire.requestFrom(gyro_address, 1, true); 43 int usercontrol = Wire.read(); 44 Wire.endTransmission(true); 45 Serial.begin(9600); 46 /**initiate 'Serial' library. most arduinos use 9600 baud (bits per second) but some use different amounts. 47 * again, check the documentation.*/ 48 Serial.println("libraries loaded "); 49 Serial.println(); 50 Serial.println("+--------------------+"); 51 Serial.println("| _ |"); 52 Serial.println("| _ _ | | _ |"); 53 Serial.println("| |_| /_ | | | |_ |"); 54 Serial.println("| |_| |"); 55 Serial.println("|thank you for using |"); 56 Serial.println("|our code. mention us|"); 57 Serial.println("|if you use it! |"); 58 Serial.println("+--------------------+"); 59 delay(2500); 60 //this is our message. please don't copy our code without mention. there's a lot of work here, and we wanted to share it with you as long as you respect our work. 61 62 double x_rotation = 0, y_rotation = 0, z_rotation = 0; 63 //these double variables have double the bits as others, so they can be longer and therefor more specific. 64} 65 66void loop() { 67 Wire.beginTransmission(gyro_address); 68 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H).this number may change depending on how the gyroscope transferrs data. 69 Wire.endTransmission(false); 70 Wire.requestFrom(gyro_address, 14, true); // request a total of 14 registers (again, it may be different for your gyroscope) 71 accelX = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) 72 accelY = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) 73 accelZ = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) 74 temp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) 75 gyroX = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) 76 gyroY = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) 77 gyroZ = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L) 78 /* 79 * these 7 variables look familiar? we defined them as nothing in setup(). these store the raw values of the gyroscope. 80 * once again, all these numbers may change. if you can, refer to a program someone else made with the same gyro to 81 * save a couple headaches. 82 */ 83 //heavy math time: 84 angleX = 0.98* (angleX + gyroX * dataRate) + 0.02 * accelX; 85 angleY = 0.98* (angleY + gyroY * dataRate) + 0.02 * accelY; 86 angleZ = 0.98* (angleZ + gyroZ * dataRate) + 0.02 * accelZ; 87 88 Serial.print(" | Accelerometer X:"); 89 Serial.print(accelX); 90 Serial.print(" | Accelerometer Y:"); 91 Serial.print(accelY); 92 Serial.print(" | Accelerometer Z:"); 93 Serial.print(accelZ); 94 Serial.print(" | Temperature:"); 95 Serial.print(temp / 340.00 + 36.53); 96 Serial.print(" | Gyro X:"); 97 Serial.print(gyroX); 98 Serial.print(" | Gyro Y:"); 99 Serial.print(gyroY); 100 Serial.print(" | Gyro Z:"); 101 Serial.println(gyroZ); 102 //there's our first data sets. 103 104 Serial.print(" | AngleX: "); 105 Serial.print(angleX); 106 Serial.print(" | Angle Y: "); 107 Serial.print(angleY); 108 Serial.print(" | Angle Z: "); 109 Serial.println(angleZ); 110 //and here's the second, with the filter! 111 /** 112 * these two top statements add the current data from the gyro and accel to the data arrays, using a neat trick: every array counts 113 * starting at 0, but the .length() function starts at one. this allows us to create new data in the arrays constantly! be warned: 114 * using a constantly adding array can be dangerous, especially with large amounts of data. 115 */ 116 delay(dataRate);//this is important to make sure the board and arduino both aren't overloading. slower-operating gyros may need a bigger number. 117} 118
adaptive filter version 0.8.2
arduino
the adaptive filter works! yay! it's not fluid, but values are set out. yay!
1/* 2 * this code is a PROTOTYPE version of the adaptive filter for the MPU-6050 gyroscope unit. 3 * this is very akin to a complimentary filter, however it uses the gyroscope data to more 4 * accurately fluctuate between control of the gyroscope, accelerometer, and later compass. 5 * please use, change or edit this code to your own will. HOWEVER: this code has taken a lot 6 * of work and you MUST reference the creater of this code. 7 * 8 * Oscar Zingle and Flynn Meredith-Black, 2017 9 * 10 * OZTL. this code is released on HACKSTER.IO . please submit changes to hackster to support 11 * the open-sourced community! 12 * 13 * version 0.0.2 (very very alpha stage, not working perfectly) 14 */ 15#include<Wire.h> 16#define MPU_addr 0x68 17#define delay_value 0.01 //how long the program is delayed each time. please change this value, 18//DO NOT change the delay manually. it will break everything 19 20//variables 21int16_t AccelX_out, AccelY_out, AccelZ_out, Tmp, GyroX_out, GyroY_out, GyroZ_out; 22double AccelX, AccelY, AccelZ, GyroX, GyroY, GyroZ, AngleX, AngleY, AngleZ, xR, yR, zR; 23void setup() { 24 Wire.begin(); 25 Serial.begin(9600);//change depending on the data rate of your arduino. 26 Wire.beginTransmission(MPU_addr); 27 Wire.write(0x6B); // PWR_MGMT_1 register 28 Wire.write(0); // set to zero (wakes up the MPU-6050) 29 Wire.endTransmission(true); 30 31 Wire.beginTransmission(MPU_addr); 32 Wire.write(0x6A); 33 Wire.endTransmission(false); 34 Wire.requestFrom(MPU_addr, 1, true); 35 Wire.endTransmission(true); 36} 37 38void loop() { 39 Wire.beginTransmission(MPU_addr); 40 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) 41 Wire.endTransmission(false); 42 Wire.requestFrom(MPU_addr, 14, true); // request a total of 14 registers 43 AccelX_out = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) 44 AccelY_out = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) 45 AccelZ_out = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) 46 Tmp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) 47 GyroX_out = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) 48 GyroY_out = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) 49 GyroZ_out = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L) 50 AccelX = atan2(AccelY_out, AccelZ_out) * 57.2957795131; 51 AccelY = atan2(AccelX_out, AccelZ_out) * 57.2957795131; 52 //Serial.println(AccelX); 53 if (GyroX_out >= 0) { 54 GyroX = ((double(GyroX_out)) * 250 / 32767.0) * delay_value * 10; 55 } else if (GyroX_out < 0) { 56 GyroX = ((double(GyroX_out)) * 250 / 32768.0) * delay_value * 10; 57 } 58 59 if (GyroY_out >= 0) { 60 GyroY = ((double(GyroY_out)) * 250 / 32767.0) * delay_value * 10; 61 } else if (GyroX_out < 0) { 62 GyroY = ((double(GyroY_out)) * 250 / 32768.0) * delay_value * 10; 63 } 64 xR += GyroX; 65 yR += GyroY; 66 zR += GyroZ; 67 delay(delay_value * 1000); 68 69 if (AccelX > 10) { 70 AngleX = (0.95 * ((AngleX + xR) / 2) + 0.05 * (AccelX)); 71 //Serial.print("option 1 "); 72 } else if (AccelX <= 10 && AccelX > 5) { 73 AngleX = (0.65 * ((AngleX + xR) / 2) + 0.35 * (AccelX)); 74 //Serial.print("option 2 "); 75 } else if (AccelX <= 5 && AccelX > 2.5) { 76 AngleX = (0.80 * ((AngleX + xR) / 2) + 0.20 * (AccelX)); 77 //Serial.print("option 2 "); 78 } else { 79 AngleX = (0.00 * ((AngleX + xR) / 2) + 1.00 * (AccelX)); 80 xR = AccelX; 81 //Serial.print("option 3 "); 82 } 83 Serial.print(AngleX); 84 Serial.print(" "); 85 Serial.print(GyroX); 86 Serial.print(" "); 87 Serial.print(AccelX); 88 Serial.println(); 89} 90/*This product is meant for educational purposes only. Any resemblance to real persons, living or dead is 91purely coincidental. Void where prohibited. Batteries not included. 92*/ 93
adaptive filter apha
arduino
here's a more active version of the complementary filter, making sure that the
1/* 2 * this code is a PROTOTYPE version of the adaptive filter for the MPU-6050 gyroscope unit. 3 * this is very akin to a complimentary filter, however it uses the gyroscope data to more 4 * accurately fluctuate between control of the gyroscope, accelerometer, and later compass. 5 * please use, change or edit this code to your own will. HOWEVER: this code has taken a lot 6 * of work and you MUST reference the creater of this code. 7 * 8 * Oscar Zingle and Flynn Meredith-Black, 2017 9 * 10 * OZTL. this code is released on HACKSTER.IO . please submit changes to hackster to support 11 * the open-sourced community! 12 * 13 * version 0.0.2 (very very alpha stage, not working perfectly) 14 */ 15#include<Wire.h> 16#define MPU_addr 0x68 17#define delay_value 0.01 //how long the program is delayed each time. please change this value, 18//DO NOT change the delay manually. it will break everything 19 20//variables 21int16_t AccelX_out, AccelY_out, AccelZ_out, Tmp, GyroX_out, GyroY_out, GyroZ_out; 22double AccelX, AccelY, AccelZ, GyroX, GyroY, GyroZ, AngleX, AngleY, AngleZ, xR, yR, zR; 23void setup() { 24 Wire.begin(); 25 Serial.begin(9600);//change depending on the data rate of your arduino. 26 Wire.beginTransmission(MPU_addr); 27 Wire.write(0x6B); // PWR_MGMT_1 register 28 Wire.write(0); // set to zero (wakes up the MPU-6050) 29 Wire.endTransmission(true); 30 31 Wire.beginTransmission(MPU_addr); 32 Wire.write(0x6A); 33 Wire.endTransmission(false); 34 Wire.requestFrom(MPU_addr, 1, true); 35 Wire.endTransmission(true); 36} 37 38void loop() { 39 Wire.beginTransmission(MPU_addr); 40 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) 41 Wire.endTransmission(false); 42 Wire.requestFrom(MPU_addr, 14, true); // request a total of 14 registers 43 AccelX_out = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) 44 AccelY_out = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) 45 AccelZ_out = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) 46 Tmp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) 47 GyroX_out = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) 48 GyroY_out = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) 49 GyroZ_out = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L) 50 AccelX = atan2(AccelY_out, AccelZ_out) * 57.2957795131; 51 AccelY = atan2(AccelX_out, AccelZ_out) * 57.2957795131; 52 //Serial.println(AccelX); 53 if (GyroX_out >= 0) { 54 GyroX = ((double(GyroX_out)) * 250 / 32767.0) * delay_value * 10; 55 } else if (GyroX_out < 0) { 56 GyroX = ((double(GyroX_out)) * 250 / 32768.0) * delay_value * 10; 57 } 58 59 if (GyroY_out >= 0) { 60 GyroY = ((double(GyroY_out)) * 250 / 32767.0) * delay_value * 10; 61 } else if (GyroX_out < 0) { 62 GyroY = ((double(GyroY_out)) * 250 / 32768.0) * delay_value * 10; 63 } 64 xR += GyroX; 65 yR += GyroY; 66 zR += GyroZ; 67 delay(delay_value * 1000); 68 if (GyroX > 10) { 69 AngleX = (0.97 * ((AngleX + xR) / 2) + 0.03 * (AccelX)); 70 Serial.print("option 1 "); 71 } else if (GyroX <= 10 && GyroX > 5) { 72 AngleX = (0.90 * ((AngleX + xR) / 2) + 0.10 * (AccelX)); 73 Serial.print("option 2 "); 74 } else if (GyroX <= 5 && GyroX > 2.5) { 75 AngleX = (0.80 * ((AngleX + xR) / 2) + 0.20 * (AccelX)); 76 Serial.print("option 2 "); 77 } else { 78 AngleX = (0.03 * ((AngleX + xR) / 2) + 0.97 * (AccelX)); 79 xR = AccelX; 80 Serial.print("option 3 "); 81 } 82 Serial.println(AngleX); 83} 84/*This product is meant for educational purposes only. Any resemblance to real persons, living or dead is 85purely coincidental. Void where prohibited. Batteries not included. 86*/ 87
WIP stablized gyroscope
arduino
Simply set up your gyroscope, plug the code in, and watch the fun on the serial monitor or serial plotter. Your numbers will be in degrees, but this is still WIP and may not work completely or at all.
1/** 2 _ 3 _ _ \\_\ _ 4 |_| /_\\_\| |_ 5 \\_\\ 6version 1.0.0 . this work is free to use by anyone, but please credit it if you are using it. 7**/ 8 9 10#include<Wire.h> 11#include<Serial.h> 12/** 13 * the #include 's are to tell the program to import the two libraries instead of writing them all out. 14 * wire lets the gyroscope and the arduino communicate over the ic^2 connection. 15 */ 16#define gyro_address 0x68 17/* change this number to the ic^2 adress of your gyroscope (in Hexidecimal, so find that column and ad a 0x if there isn't one), 18 * though if you don't have one already, an Invenesense MPU-6050 will make the code work without edits. 19*/ 20void setup() { 21 int16_t accel_x, accel_y, accel_z, temp, gyro_x, gyro_y, gyro_z; 22 /**the int16_t defines 16 bits per variable. 15 can be used, but computers prefer 8, 16, 32, etc. change the number 23 * to change the bits. these are left blank because the first thing to happen in the loop is them being filled with 24 * the gyroscope's value. the math used has to be altered though, so some gyroscopes may use more bits. at this point, 25 * you really need the documentation for the gyroscope. 26 */ 27 Wire.begin(); 28 Wire.beginTransmission(MPU_addr); 29 Wire.write(0x6B); // PWR_MGMT_1 register 30 Wire.write(0); // set to zero (wakes up the MPU-6050) 31 Wire.endTransmission(true); //set this to false, and it doesn't end. simple enough, right? 32 33 Wire.beginTransmission(gyro_address); 34 Wire.write(0x6a); 35 Wire.requestFrom(gyro_adress, 1, true); 36 int usercontrol = Wire.read(); 37 Wire.endTransmission(true); 38 Serial.begin(9600); 39 /**initiate 'Serial' library. most arduinos use 9600 baud (bits per second) but some use different amounts. 40 * again, check the documentation.*/ 41 double x_rotation = 0, y_rotation = 0, z_rotation = 0; 42 //these double variables have double the bits as others, so they can be longer and therefor more specific. 43} 44 45void loop() { 46 // put your main code here, to run repeatedly: 47 48} 49
Downloadable files
Gyroscope wiring
This is a diagram of the wiring for this project. all 3 modes are filled in, so if you want you can use the breadboard, circuit or schematic view to wire your version!
Gyroscope wiring
Gyroscope wiring
This is a diagram of the wiring for this project. all 3 modes are filled in, so if you want you can use the breadboard, circuit or schematic view to wire your version!
Gyroscope wiring
Comments
Only logged in users can leave comments
oztechlab
0 Followers
•0 Projects
+3
Work attribution
Table of contents
Intro
16
0