Advertisement
IanosStefanCristian

mpu6050 electronic level

Dec 21st, 2020
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.64 KB | None | 0 0
  1. /*
  2. Electronic Level
  3. mpu-6050-level.ino
  4. Uses MPU-6050 IMU
  5. Displays on 128x64 OLED and LED
  6.  
  7. DroneBot Workshop 2019
  8. https://dronebotworkshop.com
  9. */
  10.  
  11. // Include Wire Library for I2C
  12. #include <Wire.h>
  13.  
  14. // Include NewLiquidCrystal Library for I2C
  15. #include <LiquidCrystal_I2C.h>
  16.  
  17. // Define LCD pinout
  18. const int en = 2, rw = 1, rs = 0, d4 = 4, d5 = 5, d6 = 6, d7 = 7, bl = 3;
  19.  
  20. // Define I2C Address - change if reqiuired
  21. const int i2c_addr = 0x3F;
  22.  
  23. LiquidCrystal_I2C lcd(i2c_addr, en, rw, rs, d4, d5, d6, d7, bl, POSITIVE);
  24.  
  25. // Level LEDs
  26. int levelLED_neg1 = 9;
  27. int levelLED_neg0 = 10;
  28. int levelLED_level = 11;
  29. int levelLED_pos0 = 12;
  30. int levelLED_pos1 = 13;
  31.  
  32.  
  33.  
  34. //Variables for Gyroscope
  35. int gyro_x, gyro_y, gyro_z;
  36. long gyro_x_cal, gyro_y_cal, gyro_z_cal;
  37. boolean set_gyro_angles;
  38.  
  39. long acc_x, acc_y, acc_z, acc_total_vector;
  40. float angle_roll_acc, angle_pitch_acc;
  41.  
  42. float angle_pitch, angle_roll;
  43. int angle_pitch_buffer, angle_roll_buffer;
  44. float angle_pitch_output, angle_roll_output;
  45.  
  46. // Setup timers and temp variables
  47. long loop_timer;
  48. int temp;
  49.  
  50. // Display counter
  51. int displaycount = 0;
  52.  
  53. void setup() {
  54.  
  55. //Start I2C
  56. Wire.begin();
  57.  
  58. // Set display type as 16 char, 2 rows
  59. lcd.begin(16,2);
  60.  
  61. // Set Level LEDs as outputs
  62. pinMode(levelLED_neg1, OUTPUT);
  63. pinMode(levelLED_neg0, OUTPUT);
  64. pinMode(levelLED_level, OUTPUT);
  65. pinMode(levelLED_pos0, OUTPUT);
  66. pinMode(levelLED_pos1, OUTPUT);
  67.  
  68.  
  69. //Setup the registers of the MPU-6050
  70. setup_mpu_6050_registers();
  71.  
  72. //Read the raw acc and gyro data from the MPU-6050 1000 times
  73. for (int cal_int = 0; cal_int < 1000 ; cal_int ++){
  74. read_mpu_6050_data();
  75. //Add the gyro x offset to the gyro_x_cal variable
  76. gyro_x_cal += gyro_x;
  77. //Add the gyro y offset to the gyro_y_cal variable
  78. gyro_y_cal += gyro_y;
  79. //Add the gyro z offset to the gyro_z_cal variable
  80. gyro_z_cal += gyro_z;
  81. //Delay 3us to have 250Hz for-loop
  82. delay(3);
  83. }
  84.  
  85. // Divide all results by 1000 to get average offset
  86. gyro_x_cal /= 1000;
  87. gyro_y_cal /= 1000;
  88. gyro_z_cal /= 1000;
  89.  
  90. // Start Serial Monitor
  91. Serial.begin(115200);
  92.  
  93. // Init Timer
  94. loop_timer = micros();
  95. }
  96.  
  97. void loop(){
  98.  
  99. // Get data from MPU-6050
  100. read_mpu_6050_data();
  101.  
  102. //Subtract the offset values from the raw gyro values
  103. gyro_x -= gyro_x_cal;
  104. gyro_y -= gyro_y_cal;
  105. gyro_z -= gyro_z_cal;
  106.  
  107. //Gyro angle calculations . Note 0.0000611 = 1 / (250Hz x 65.5)
  108.  
  109. //Calculate the traveled pitch angle and add this to the angle_pitch variable
  110. angle_pitch += gyro_x * 0.0000611;
  111. //Calculate the traveled roll angle and add this to the angle_roll variable
  112. //0.000001066 = 0.0000611 * (3.142(PI) / 180degr) The Arduino sin function is in radians
  113. angle_roll += gyro_y * 0.0000611;
  114.  
  115. //If the IMU has yawed transfer the roll angle to the pitch angle
  116. angle_pitch += angle_roll * sin(gyro_z * 0.000001066);
  117. //If the IMU has yawed transfer the pitch angle to the roll angle
  118. angle_roll -= angle_pitch * sin(gyro_z * 0.000001066);
  119.  
  120. //Accelerometer angle calculations
  121.  
  122. //Calculate the total accelerometer vector
  123. acc_total_vector = sqrt((acc_x*acc_x)+(acc_y*acc_y)+(acc_z*acc_z));
  124.  
  125. //57.296 = 1 / (3.142 / 180) The Arduino asin function is in radians
  126. //Calculate the pitch angle
  127. angle_pitch_acc = asin((float)acc_y/acc_total_vector)* 57.296;
  128. //Calculate the roll angle
  129. angle_roll_acc = asin((float)acc_x/acc_total_vector)* -57.296;
  130.  
  131. //Accelerometer calibration value for pitch
  132. angle_pitch_acc -= 0.0;
  133. //Accelerometer calibration value for roll
  134. angle_roll_acc -= 0.0;
  135.  
  136. if(set_gyro_angles){
  137.  
  138. //If the IMU has been running
  139. //Correct the drift of the gyro pitch angle with the accelerometer pitch angle
  140. angle_pitch = angle_pitch * 0.9996 + angle_pitch_acc * 0.0004;
  141. //Correct the drift of the gyro roll angle with the accelerometer roll angle
  142. angle_roll = angle_roll * 0.9996 + angle_roll_acc * 0.0004;
  143. }
  144. else{
  145. //IMU has just started
  146. //Set the gyro pitch angle equal to the accelerometer pitch angle
  147. angle_pitch = angle_pitch_acc;
  148. //Set the gyro roll angle equal to the accelerometer roll angle
  149. angle_roll = angle_roll_acc;
  150. //Set the IMU started flag
  151. set_gyro_angles = true;
  152. }
  153.  
  154. //To dampen the pitch and roll angles a complementary filter is used
  155. //Take 90% of the output pitch value and add 10% of the raw pitch value
  156. angle_pitch_output = angle_pitch_output * 0.9 + angle_pitch * 0.1;
  157. //Take 90% of the output roll value and add 10% of the raw roll value
  158. angle_roll_output = angle_roll_output * 0.9 + angle_roll * 0.1;
  159. //Wait until the loop_timer reaches 4000us (250Hz) before starting the next loop
  160.  
  161. // Print to Serial Monitor
  162. //Serial.print(" | Angle = "); Serial.println(angle_pitch_output);
  163.  
  164.  
  165. // Increment the display counter
  166. displaycount = displaycount +1;
  167.  
  168. if (displaycount > 100) {
  169.  
  170. lcd.clear();
  171. // Print on first row of LCD
  172. lcd.setCursor(0,0);
  173. lcd.print("Pitch: ");
  174. lcd.print(angle_pitch_output);
  175. lcd.setCursor(0,1);
  176. lcd.print("Roll: ");
  177. lcd.print(angle_roll_output);
  178.  
  179.  
  180. // Check Angle for Level LEDs
  181.  
  182. if (angle_pitch_output < -2.01) {
  183. // Turn on Level LED
  184. digitalWrite(levelLED_neg1, HIGH);
  185. digitalWrite(levelLED_neg0, LOW);
  186. digitalWrite(levelLED_level, LOW);
  187. digitalWrite(levelLED_pos0, LOW);
  188. digitalWrite(levelLED_pos1, LOW);
  189.  
  190. } else if ((angle_pitch_output > -2.00) && (angle_pitch_output < -1.01)) {
  191. // Turn on Level LED
  192. digitalWrite(levelLED_neg1, LOW);
  193. digitalWrite(levelLED_neg0, HIGH);
  194. digitalWrite(levelLED_level, LOW);
  195. digitalWrite(levelLED_pos0, LOW);
  196. digitalWrite(levelLED_pos1, LOW);
  197.  
  198. } else if ((angle_pitch_output < 1.00) && (angle_pitch_output > -1.00)) {
  199. // Turn on Level LED
  200. digitalWrite(levelLED_neg1, LOW);
  201. digitalWrite(levelLED_neg0, LOW);
  202. digitalWrite(levelLED_level, HIGH);
  203. digitalWrite(levelLED_pos0, LOW);
  204. digitalWrite(levelLED_pos1, LOW);
  205.  
  206. } else if ((angle_pitch_output > 1.01) && (angle_pitch_output < 2.00)) {
  207. // Turn on Level LED
  208. digitalWrite(levelLED_neg1, LOW);
  209. digitalWrite(levelLED_neg0, LOW);
  210. digitalWrite(levelLED_level, LOW);
  211. digitalWrite(levelLED_pos0, HIGH);
  212. digitalWrite(levelLED_pos1, LOW);
  213.  
  214. } else if (angle_pitch_output > 2.01) {
  215. // Turn on Level LED
  216. digitalWrite(levelLED_neg1, LOW);
  217. digitalWrite(levelLED_neg0, LOW);
  218. digitalWrite(levelLED_level, LOW);
  219. digitalWrite(levelLED_pos0, LOW);
  220. digitalWrite(levelLED_pos1, HIGH);
  221.  
  222. }
  223.  
  224. displaycount = 0;
  225.  
  226. }
  227.  
  228.  
  229. while(micros() - loop_timer < 4000);
  230. //Reset the loop timer
  231. loop_timer = micros();
  232.  
  233. }
  234.  
  235. void setup_mpu_6050_registers(){
  236.  
  237. //Activate the MPU-6050
  238.  
  239. //Start communicating with the MPU-6050
  240. Wire.beginTransmission(0x68);
  241. //Send the requested starting register
  242. Wire.write(0x6B);
  243. //Set the requested starting register
  244. Wire.write(0x00);
  245. //End the transmission
  246. Wire.endTransmission();
  247.  
  248. //Configure the accelerometer (+/-8g)
  249.  
  250. //Start communicating with the MPU-6050
  251. Wire.beginTransmission(0x68);
  252. //Send the requested starting register
  253. Wire.write(0x1C);
  254. //Set the requested starting register
  255. Wire.write(0x10);
  256. //End the transmission
  257. Wire.endTransmission();
  258.  
  259. //Configure the gyro (500dps full scale)
  260.  
  261. //Start communicating with the MPU-6050
  262. Wire.beginTransmission(0x68);
  263. //Send the requested starting register
  264. Wire.write(0x1B);
  265. //Set the requested starting register
  266. Wire.write(0x08);
  267. //End the transmission
  268. Wire.endTransmission();
  269.  
  270. }
  271.  
  272.  
  273. void read_mpu_6050_data(){
  274.  
  275. //Read the raw gyro and accelerometer data
  276.  
  277. //Start communicating with the MPU-6050
  278. Wire.beginTransmission(0x68);
  279. //Send the requested starting register
  280. Wire.write(0x3B);
  281. //End the transmission
  282. Wire.endTransmission();
  283. //Request 14 bytes from the MPU-6050
  284. Wire.requestFrom(0x68,14);
  285. //Wait until all the bytes are received
  286. while(Wire.available() < 14);
  287.  
  288. //Following statements left shift 8 bits, then bitwise OR.
  289. //Turns two 8-bit values into one 16-bit value
  290. acc_x = Wire.read()<<8|Wire.read();
  291. acc_y = Wire.read()<<8|Wire.read();
  292. acc_z = Wire.read()<<8|Wire.read();
  293. temp = Wire.read()<<8|Wire.read();
  294. gyro_x = Wire.read()<<8|Wire.read();
  295. gyro_y = Wire.read()<<8|Wire.read();
  296. gyro_z = Wire.read()<<8|Wire.read();
  297. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement