No title

 #include <Wire.h>

#include <Adafruit_MPU6050.h>

#include <Adafruit_SSD1306.h>

#include <Adafruit_GFX.h>

#include <math.h>


#define SCREEN_WIDTH 128

#define SCREEN_HEIGHT 64

#define OLED_ADDR 0x3C


#define BUTTON_CALIBRATE 12


Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

Adafruit_MPU6050 mpu;


float accX, accY, accZ;

float pitch, roll;

float pitchOffset = 0.0;

float rollOffset = 0.0;


#define SAMPLES 8

float pitchSamples[SAMPLES];

float rollSamples[SAMPLES];

int sampleIndex = 0;

bool bufferFilled = false;


// Car icon 45x22

#define CAR_ICON_WIDTH 45

#define CAR_ICON_HEIGHT 22

const unsigned char carIcon[] PROGMEM = {

  0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x03,0xff,0xf0,0x00,0x00,

  0x00,0x0f,0xcc,0xf8,0x00,0x00,0x00,0x3e,0x0c,0x1e,0x00,0x00,

  0x00,0x78,0x0c,0x07,0x00,0x00,0x01,0xf8,0x0c,0x03,0x80,0x00,

  0x03,0xfe,0x0c,0x01,0xe0,0x00,0x07,0xff,0xff,0xff,0xfe,0x00,

  0x0f,0xff,0xff,0xff,0xff,0xc0,0x0f,0xff,0xff,0xff,0xff,0xe0,

  0x0f,0x83,0xff,0xff,0x87,0xe0,0x0f,0x3c,0xff,0xff,0x33,0xe0,

  0x0f,0x7e,0xff,0xfe,0x7d,0xf0,0x0e,0xfe,0x7f,0xfe,0xfc,0xf0,

  0x0e,0xff,0x7f,0xfc,0xfe,0xf0,0x06,0xfe,0x7f,0xfd,0xfe,0xe0,

  0x00,0x7e,0x4f,0xfc,0xfe,0xe0,0x00,0x7c,0x00,0x00,0xfc,0x00,

  0x00,0x18,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00

};


void setup() {

  Serial.begin(115200);

  pinMode(BUTTON_CALIBRATE, INPUT_PULLUP);


  if(!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {

    Serial.println("SSD1306 allocation failed");

    while(1);

  }

  display.clearDisplay();

  display.setTextColor(SSD1306_WHITE);

  display.setTextSize(1);

  display.setCursor(0,0);

  display.println("Initializing...");

  display.display();

  delay(1000);


  if(!mpu.begin()){

    Serial.println("MPU6050 not found");

    display.clearDisplay();

    display.setCursor(0,0);

    display.println("MPU6050 Error!");

    display.display();

    while(1);

  }


  mpu.setAccelerometerRange(MPU6050_RANGE_8_G);

  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);


  for(int i=0;i<SAMPLES;i++){

    pitchSamples[i]=0;

    rollSamples[i]=0;

  }


  display.clearDisplay();

  display.setCursor(0,0);

  display.println("MPU6050 Ready!");

  display.println("Press button to calibrate");

  display.display();

  delay(2000);

}


void loop() {

  if(digitalRead(BUTTON_CALIBRATE)==LOW){

    delay(50);

    if(digitalRead(BUTTON_CALIBRATE)==LOW){

      calibrateSensor();

      while(digitalRead(BUTTON_CALIBRATE)==LOW) delay(10);

    }

  }


  sensors_event_t a, g, temp;

  mpu.getEvent(&a, &g, &temp);


  accX = a.acceleration.x;

  accY = a.acceleration.y;

  accZ = a.acceleration.z;


  pitch = atan2(-accX, sqrt(accY*accY + accZ*accZ))*180/PI;

  roll = atan2(accY, accZ)*180/PI;


  pitch -= pitchOffset;

  roll -= rollOffset;


  pitchSamples[sampleIndex] = pitch;

  rollSamples[sampleIndex] = roll;

  sampleIndex = (sampleIndex+1)%SAMPLES;

  if(sampleIndex==0) bufferFilled=true;


  displayInclinometer();

  delay(50);

}


void calibrateSensor(){

  display.clearDisplay();

  display.setCursor(0,0);

  display.println("Calibrating...");

  display.println("Place flat");

  display.display();

  delay(3000);


  float pSum=0,rSum=0;

  int readings=20;

  for(int i=0;i<readings;i++){

    sensors_event_t a,g,t;

    mpu.getEvent(&a,&g,&t);

    float p = atan2(-a.acceleration.x, sqrt(a.acceleration.y*a.acceleration.y + a.acceleration.z*a.acceleration.z))*180/PI;

    float r = atan2(a.acceleration.y,a.acceleration.z)*180/PI;

    pSum += p; rSum += r;

    delay(50);

  }

  pitchOffset=pSum/readings;

  rollOffset=rSum/readings;


  for(int i=0;i<SAMPLES;i++){ pitchSamples[i]=0; rollSamples[i]=0; }

  sampleIndex=0; bufferFilled=false;


  display.clearDisplay();

  display.setCursor(0,0);

  display.println("Calibration Done!");

  display.print("Pitch: "); display.println(pitchOffset,1);

  display.print("Roll: "); display.println(rollOffset,1);

  display.display();

  delay(2000);

}


float getAveragePitch(){

  float sum=0; int cnt = bufferFilled? SAMPLES : sampleIndex;

  for(int i=0;i<cnt;i++) sum+=pitchSamples[i];

  return sum/cnt;

}

float getAverageRoll(){

  float sum=0; int cnt = bufferFilled? SAMPLES : sampleIndex;

  for(int i=0;i<cnt;i++) sum+=rollSamples[i];

  return sum/cnt;

}


void drawRotatedBitmap(int16_t x,int16_t y,const uint8_t *bmp,int16_t w,int16_t h,float angle){

  int16_t cx=w/2,cy=h/2;

  float c=cos(angle*PI/180.0), s=sin(angle*PI/180.0);

  int16_t bpr=(w+7)/8;

  int16_t bw=w*1.5,bh=h*1.5;

  int16_t bcx=bw/2,bcy=bh/2;

  display.fillRect(x-bw/4,y-bh/4,bw,bh,SSD1306_BLACK);

  for(int16_t j=0;j<h;j++){

    for(int16_t i=0;i<w;i++){

      uint8_t byteIndex = j*bpr + i/8;

      uint8_t bitMask = 0x80 >> (i%8);

      if(pgm_read_byte(&bmp[byteIndex]) & bitMask){

        int16_t rx = round((i-cx)*c-(j-cy)*s + bcx);

        int16_t ry = round((i-cx)*s+(j-cy)*c + bcy);

        display.drawPixel(x+rx-bcx, y+ry-bcy, SSD1306_WHITE);

      }

    }

  }

}


void drawRollGauge(int16_t x,int16_t y,int16_t w,float angle){

  float displayRoll = constrain(angle,-45,45);

  int16_t ind = map(displayRoll*10,-450,450,0,w);

  display.drawRect(x,y,w,8,SSD1306_WHITE);

  display.drawLine(x+w/2,y,x+w/2,y+8,SSD1306_WHITE);

  display.fillRect(x+ind-2,y+1,5,6,SSD1306_WHITE);

  for(int i=0;i<=4;i++){

    int t=map(i,0,4,0,w/2);

    display.drawLine(x+w/2-t,y,x+w/2-t,y+3,SSD1306_WHITE);

    display.drawLine(x+w/2+t,y,x+w/2+t,y+3,SSD1306_WHITE);

  }

}


void displayInclinometer(){

  float avgP=-getAveragePitch();

  float avgR=getAverageRoll();

  display.clearDisplay();


  display.setTextSize(2);

  display.setCursor(0,0);

  display.print(avgP,1); display.print((char)247);


  drawRotatedBitmap(90,20,carIcon,CAR_ICON_WIDTH,CAR_ICON_HEIGHT,-constrain(avgP,-45,45));


  display.setTextSize(1);

  display.setCursor(20,50);

  display.print("ROLL: "); display.print(avgR,1); display.print((char)247);

  drawRollGauge(10,58,display.width()-20,avgR);


  display.display();

}

Post a Comment

Previous Post Next Post

Contact Form