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));
}
'NodeMCU' 카테고리의 다른 글
Wireless 바코드 스캔 피드백 (0) | 2016.04.11 |
---|---|
NodeMCU w/ Motor Sheild 예문의 실제 실험 사진들 (0) | 2015.11.09 |
NodeMCU V.1.0 을 Motor Shield 와 함께 사용한 프로그램 예) (0) | 2015.11.09 |