본문 바로가기

NodeMCU

GY-88을 NodeMCU (ESP-12E) 모듈과 I2C로 연결해서 사용하기

GY-88을 NodeMCU (ESP-12E) 모듈과 I2C로 연결해서 사용하기


GY-88은 MPU-6050, HMC5883L, BMP085를 한 조그마한 보드에 모은 10DOF 항법조종용 센서모듈입니다.  가격은 대충 $12불정도. 


MPU-6050 :  3축 회전자이로(Gyro), 3축 가속측정(Acceleration) + 온도(Temp.)

HMC5883L : 3축 XYZ 전자나침반(Compass) (지축을 기준으로 방향측정)

BMP085 : 압력으로 고도 측정기능이 있은 칩.(Barometer)


(*) 비고 : 항법 조종용 센서를 NodeMCU에 다는 것은 통신거리를 감안할 경우 사실상 의미가 없습니다.  단지 I2C를 실험하려고, 단순히 실험용임.



뒷면 (여기서 사용할 핀은 3V3, GND, SCL, SDA)

앞면 : 저 위에 MPU-6050, HMC5883L, BMP085 세 칩이 몰려 있음.







윗 그림은 NodeMCU가 일반적으로 I2C로 다른 모듈을 연결하는 법.  윗 SCL, SDA라인에 다량의 I2C장비를 연결할수 있음.  각 I2C를 사용하는 모듈들은 고유 주소가 있어서 SCL / SDA 을 공유해서 연결해도 각 모듈들을 컨트롤러와 대화 가능.



동영상 Video


 

윗 동영상은 아직 조율이 완벽하지 않은 상태에 통신만 완성된 상태.

아래 코딩에는 BMP085에서 오는 정보는 막아놨음. (온도, 압력)

실제로 BMP085는 코딩만 복잡하고 별로 도움안됨.




아듀이노 코딩: (라이브러리는 각자 웹에서 알아서 설치)

Arduino Style Coding, (No Lua)



#include "I2Cdev.h"

#include "HMC5883L.h"

#include "MPU6050.h"

#include "Wire.h"


// list of the accel X/Y/Z and then gyro X/Y/Z values in decimal. Easy to read,

#define OUTPUT_READABLE_ACCELGYRO


// class default I2C address is 0x1E

// specific I2C addresses may be passed as a parameter here

// this device only supports one I2C address (0x1E)

HMC5883L Compass(0x1E);  // 3D Compass  (0x1E)

MPU6050  accelgyro(0x68);  // 6D Accel & Gyro & Temp  (0x69)


// From the datasheet the BMP module address LSB distinguishes

// between read (1) and write (0) operations, corresponding to 

// address 0xEF (read) and 0xEE (write).

// shift the address 1 bit right (0xEF or 0xEE), the Wire library only needs the 7

// most significant bits for the address 0xEF >> 1 = 0x77

// 0xEE >> 1 = 0x77


int I2C_ADDRESS = 0x77;  // sensor address


int16_t cmx, cmy, cmz;  // xyz for compass


int16_t ax, ay, az;

int16_t gx, gy, gz;


int16_t rawTemp;  // Temperature value from MPU6050 Module

float temp;       // Converted Value in Celcius degree


String  s;  // Temporary string

int i = 100;  // Simple Counter


// oversampling setting

// 0 = ultra low power

// 1 = standard

// 2 = high

// 3 = ultra high resolution

const unsigned char oversampling_setting = 0; //oversampling for measurement

const unsigned char pressure_conversiontime[4] = { 

  5, 8, 14, 26 };  // delays for oversampling settings 0, 1, 2 and 3   


// sensor registers from the BOSCH BMP085 datasheet

int ac1;

int ac2; 

int ac3; 

unsigned int ac4;

unsigned int ac5;

unsigned int ac6;

int b1; 

int b2;

int mb;

int mc;

int md;


// variables to keep the values

int temperature = 0;

long pressure = 0;



void setup()

{  

   Wire.begin();

   

   Serial.begin(38400);  


   Serial.println("Initializing I2C for COMPASS devices...");

   Compass.initialize();  // initialize device

    

   // verify connection

   Serial.println("Testing device connections...");

   Serial.println(Compass.testConnection() ? "HMC5883L connection successful" : "HMC5883L connection failed");


   Serial.println("Initializing I2C for 6DOF AccelGyro devices...");

   accelgyro.initialize();

    

   // verify connection

   Serial.println("Testing device connections...");

   Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");


   delay(2000);  // to see what has been done

   

   getCalibrationData();

}


void loop()

{

//  readSensor();  // BMP085

//  Serial.print("Temperature: ");

//  temperature = ((temperature/16)-32)*5/9;

//  Serial.print(temperature,DEC);

//  Serial.print(" Celcius,  Pressure: ");

//  pressure = pressure / 1000;

//  Serial.print(pressure,DEC);

//  Serial.println(" kPA");


   // Get temporature for every 100 cycle, no need fast change of temp.

   if (i == 100) {  // with delay(100), it will be every 10 sec.

      i = 0;  // reset counter

      rawTemp = accelgyro.getTemperature();  // get value from machine

      temp=(rawTemp/340.)+36.53;  // conver to tempature in C

 

      s = "<R=TEMP:";

      s += temp;

      s += ">";

      Serial.println(s);

   }

   i++;

   // read raw accel/gyro measurements from device

   accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

   // these methods (and a few others) are also available

   //accelgyro.getAcceleration(&ax, &ay, &az);

   //accelgyro.getRotation(&gx, &gy, &gz);

   s = "<R=6DOF-AXYZ-GXYZ:";

   s += ax;

   s += ",";

   s += ay;         

   s += ",";    

   s += az;         

   s += ","; 

   s += gx;

   s += ",";

   s += gy;         

   s += ",";    

   s += gz;         

   s += ">";

   Serial.println(s);

   

   Compass.getHeading(&cmx, &cmy, &cmz);  // read raw heading measurements from device


   // display , separated gyro x/y/z values + Heading value

   s = "<R=COMPASS-XYZH:";  

   s += cmx;

   s += ",";

   s += cmy;         

   s += ",";    

   s += cmz;         

   s += ",";    

    

   // To calculate heading in degrees. 0 degree indicates North

   float heading = atan2(cmy, cmx);

   if(heading < 0)

      heading += 2 * M_PI;

   s += (heading * 180/M_PI);         

   s += ">";       

   Serial.println(s);

  

   delay(100);

}


// Below there are the utility functions to get data from the sensor.

// read temperature and pressure from sensor

void readSensor() {

  int  ut= readUT();

  long up = readUP();

  long x1, x2, x3, b3, b5, b6, p;

  unsigned long b4, b7;


  //calculate true temperature

  x1 = ((long)ut - ac6) * ac5 >> 15;

  x2 = ((long) mc << 11) / (x1 + md);

  b5 = x1 + x2;

  temperature = (b5 + 8) >> 4;


  //calculate true pressure

  b6 = b5 - 4000;

  x1 = (b2 * (b6 * b6 >> 12)) >> 11; 

  x2 = ac2 * b6 >> 11;

  x3 = x1 + x2;

  b3 = (((int32_t) ac1 * 4 + x3)<<oversampling_setting + 2) >> 2;

  x1 = ac3 * b6 >> 13;

  x2 = (b1 * (b6 * b6 >> 12)) >> 16;

  x3 = ((x1 + x2) + 2) >> 2;

  b4 = (ac4 * (uint32_t) (x3 + 32768)) >> 15;

  b7 = ((uint32_t) up - b3) * (50000 >> oversampling_setting);

  p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;


  x1 = (p >> 8) * (p >> 8);

  x1 = (x1 * 3038) >> 16;

  x2 = (-7357 * p) >> 16;

  pressure = p + ((x1 + x2 + 3791) >> 4);

}


// read uncompensated temperature value

unsigned int readUT() {

  writeRegister(0xf4,0x2e);

  delay(5); // the datasheet suggests 4.5 ms

  return readIntRegister(0xf6);

}


// read uncompensated pressure value

long readUP() {

  writeRegister(0xf4,0x34+(oversampling_setting<<6));

  delay(pressure_conversiontime[oversampling_setting]);


  unsigned char msb, lsb, xlsb;

  Wire.beginTransmission(I2C_ADDRESS);

  Wire.write(0xf6);  // register to read

  Wire.endTransmission();


  Wire.requestFrom(I2C_ADDRESS, 3); // request three bytes

  while(!Wire.available()); // wait until data available

  msb = Wire.read();

  while(!Wire.available()); // wait until data available

  lsb |= Wire.read();

  while(!Wire.available()); // wait until data available

  xlsb |= Wire.read();

  return (((long)msb<<16) | ((long)lsb<<8) | ((long)xlsb)) >>(8-oversampling_setting);

}


void  getCalibrationData() {

  Serial.println("Reading Calibration Data");

  ac1 = readIntRegister(0xAA);

  Serial.print("AC1: ");

  Serial.println(ac1,DEC);

  ac2 = readIntRegister(0xAC);

  Serial.print("AC2: ");

  Serial.println(ac2,DEC);

  ac3 = readIntRegister(0xAE);

  Serial.print("AC3: ");

  Serial.println(ac3,DEC);

  ac4 = readIntRegister(0xB0);

  Serial.print("AC4: ");

  Serial.println(ac4,DEC);

  ac5 = readIntRegister(0xB2);

  Serial.print("AC5: ");

  Serial.println(ac5,DEC);

  ac6 = readIntRegister(0xB4);

  Serial.print("AC6: ");

  Serial.println(ac6,DEC);

  b1 = readIntRegister(0xB6);

  Serial.print("B1: ");

  Serial.println(b1,DEC);

  b2 = readIntRegister(0xB8);

  Serial.print("B2: ");

  Serial.println(b1,DEC);

  mb = readIntRegister(0xBA);

  Serial.print("MB: ");

  Serial.println(mb,DEC);

  mc = readIntRegister(0xBC);

  Serial.print("MC: ");

  Serial.println(mc,DEC);

  md = readIntRegister(0xBE);

  Serial.print("MD: ");

  Serial.println(md,DEC);

}


void writeRegister(unsigned char r, unsigned char v)

{

  Wire.beginTransmission(I2C_ADDRESS);

  Wire.write(r);

  Wire.write(v);

  Wire.endTransmission();

}


// read a 16 bit register

int readIntRegister(unsigned char r)

{

  unsigned char msb, lsb;

  Wire.beginTransmission(I2C_ADDRESS);

  Wire.write(r);  // register to read

  Wire.endTransmission();


  Wire.requestFrom(I2C_ADDRESS, 2); // request two bytes

  while(!Wire.available()); // wait until data available

  msb = Wire.read();

  while(!Wire.available()); // wait until data available

  lsb = Wire.read();

  return (((int)msb<<8) | ((int)lsb));

}