Arduino Digital Spirit Level Using MPU9250 & OLED

Posted on

MPU9250 Accelerometer

In this article, I will share the Arduino digital spirit level program code using the MPU9250 and OLED I2C SSD1306 with the u8g2 library. The program code will run by reading the X and Y coordinates from the accelerometer and will display them in the form of coordinate lines.

This is one of the features of the compass that is used to read a flat position. If you want to make your own compass, I have prepared the program code in the article Make a Compass with Arduino and MPU9250.

Before you upload the program code, it would be nice for you to see the wiring between Arduino, MPU-9250, and OLED below.


Wiring

It should be noted that the MPU-9250 uses VCC with a voltage of 3.3V. Do not connect it to 5V !!! because it will damage the MPU9250.

Whereas OLED is fine for 5V, therefore, connect the VCC of OLED to 5V. Next, connect the modules with the same path, namely SDA to SDA and SCL to SCL. Look at the picture below.

Arduino Digital Spirit Level Using MPU9250 & OLED

Code Program

After the circuit is complete, please copy the following program code and upload it to your Arduino. After that, please take a look at your OLED.

#include "quaternionFilters.h"
#include "MPU9250.h"
#include <U8g2lib.h>


#define I2Cclock 400000
#define I2Cport Wire
#define MPU9250_ADDRESS MPU9250_ADDRESS_AD0   // Use either this line or the next to select which I2C address your device is using
//#define MPU9250_ADDRESS MPU9250_ADDRESS_AD1

MPU9250 myIMU(MPU9250_ADDRESS, I2Cport, I2Cclock);
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);

float xAccel, yAccel = 0;

void setup() {
  Wire.begin();
  u8g2.begin();
  Serial.begin(9600);

  byte c = myIMU.readByte(MPU9250_ADDRESS, WHO_AM_I_MPU9250);

  u8g2.firstPage();
  do {
    u8g2.setFont(u8g2_font_5x7_tr);
    u8g2.setCursor(0, 10);

    if (c == 0x71) {
      u8g2.print("MPU-9250 Connected!");
    } else {
      u8g2.print("MPU-9250 Failed!");
    }
  } while (u8g2.nextPage());
  
  delay(1500);
  
  // Start by performing self test and reporting values
  myIMU.MPU9250SelfTest(myIMU.selfTest);

  // myIMU.calibrateMPU9250(myIMU.gyroBias, myIMU.accelBias);

  myIMU.initMPU9250();

  // Get sensor resolutions, only need to do this once
  myIMU.getAres();
}

void loop() {
  getAccData();

  if (xAccel > 0) {
    xAccel = f_map(xAccel, 0, 104, 0, 90);
  } else xAccel = f_map(xAccel, -97.0, 0, -90, 0);

  if (yAccel > 0) {
    yAccel = f_map(yAccel, 9.25, 107.86, 0, 90);
  } else yAccel = f_map(yAccel, -92.52, 9.10, -90, 0);

  showOLED();
}

float f_map(float x, float x1, float x2, float y1, float y2) {
  return (x - x1) * (y2 - y1) / (x2 - x1) + y1;
}

void getAccData() {
  myIMU.readAccelData(myIMU.accelCount);  // Read the x/y/z adc values

  // Now we'll calculate the accleration value into actual g's
  // This depends on scale being set
  myIMU.ax = (float)myIMU.accelCount[0] * myIMU.aRes;   
  myIMU.ay = (float)myIMU.accelCount[1] * myIMU.aRes;  

  xAccel = (100 * myIMU.ax);
  yAccel = (100 * myIMU.ay);
}

void showOLED() {
  u8g2.firstPage();
  do {
    //Draw Frame 64x64 px
    u8g2.drawFrame(0, 0, 64, 64);

    //Draw X Line
    u8g2.drawLine(0, 32, 64, 32);

    //Draw Y Line
    u8g2.drawLine(32, 0, 32, 64);

    //Show Label x & y near coordinat line
    u8g2.setFont(u8g2_font_5x7_tr);
    u8g2.drawStr(32 - 6, 7, "y");
    u8g2.drawStr(2, 32 + 7, "x");

    //Show value of X & Y Accelerometer
    u8g2.setFont(u8g2_font_6x13_tr);
    u8g2.setCursor(75, 45);
    u8g2.print((String) "X: " + xAccel);
    u8g2.setCursor(75, 58);
    u8g2.print((String) "Y: " + yAccel);

    //Accelerometer will be between -90 to 90
    //Map it to 0 - 64
    int xMap = map(xAccel, -90, 90, 0, 64);
    int yMap = map(yAccel, 90, -90, 0, 64);

    //Draw a round object
    u8g2.setFont(u8g2_font_unifont_t_symbols);
    u8g2.drawGlyph(xMap - 7, yMap + 6, 0x23fa);

    //if the device is exactly halfway between x and y
    if (((xAccel < 1) && (xAccel > -1)) && (yAccel < 1) && (yAccel > -1)) {

      // Draw a circle replacing a round object
      u8g2.setFont(u8g2_font_unifont_t_symbols);
      u8g2.drawGlyph(xMap - 7, yMap + 6, 0x25ef);

      //And show "PASS" text
      u8g2.drawBox(80, 0, 42, 15);
      u8g2.setDrawColor(0);
      u8g2.drawStr(85, 13, "PASS");
      u8g2.setDrawColor(1);
    }
  } while (u8g2.nextPage());
}

Explanation

In the program code above, there are lines that I need to explain, namely the following line:

if (xAccel > 0) {
    xAccel = f_map(xAccel, 0, 104, 0, 90);
  } else xAccel = f_map(xAccel, -97.0, 0, -90, 0);

  if (yAccel > 0) {
    yAccel = f_map(yAccel, 9.25, 107.86, 0, 90);
  } else yAccel = f_map(yAccel, -92.52, 9.10, -90, 0);

The xAccel or yAccel values based on the library that I use SparkFun MPU-9250, are not the same. For example, when I place the accelerometer parallel to the earth, the reading is 0, but when I turn right 90 degrees to the side, the value is not 90 but 104. Therefore, I need to map this value from 0-140 to 0-90 in order to give the corresponding result, and from 0 to -90.

So, please replace the map value with the value you get.


Result

If the upload is successful, you will be able to see the results as in the following video:

Hopefully, this Arduino Digital Spirit Level Using MPU9250 & OLED article can help you in developing other projects.


Keywords with the same search:

1 comment

Leave a Reply

Your email address will not be published. Required fields are marked *