- ESP32を使って、MPU-6050から加速度とジャイロの検出値を取り出す(DMPは使用しない)
- 約10ms間隔のサンプルレートに設定する(手などの動きのトレースを意図)
使用機器
- MPU-6050 Amazonで購入した基板 GY-521
- ESP32-WROOM-32E 秋月電子で購入した基板
- 自作の基板
- ESPダウンローダー シリアル出力により結果を確認する
ESP32のソフトについて
- PlatformIOで、Arduinoフレームワークを使用
- Wireのライブラリのみを使用(MPU-6050のライブラリは使用しない)
MPU-6050のレジスタ設定
setupで一度だけ設定するもの
PWR_MGMT_1(0x6A)
- 電源ON後にまずスリープの解除が必須 他のレジスタ設定を受け付けてくれないため
- クロックをジャイロのクロックに切り替える より正確らしい
MPU_CONFIG(0x1A)
- LPFの設定
- サンプルレート(100Hzに設定する)の半分程度にする
- この設定で加速度・ジャイロともにベースのサンプルレートが1kHzになる
SMPLRT_DIV(0x19)
- サンプルレートの設定
- 入力デバイスを想定して100Hzにする
#include <Wire.h>
#define MPU_ADDRESS 0x68
#define MPU_SMPLRT_DIV 0x19
#define MPU_CONFIG 0x1A
#define MPU_INT_STATUS 0x3A
#define MPU_ACCEL_XOUT 0x3B
#define MPU_PWR_MGMT_1 0x6B
#define MPU_WHO_AM_I 0x75
#define DLPF_44HZ_42HZ 0x03
#define SMPLRT_100 0x09
#define SLEEP_OFF 0x00
#define SLEEP_ON 0x40
#define CLKSEL_PLLX 0x01
#define DATA_RDY_INT 0x01
#define MPU_DATA_NUM 7
unsigned char mpuReadByte( int address, int reg ){
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(address,1);
unsigned char ret = Wire.read();
return ret;
}
int mpuReadBlock( int address, int reg, int len, unsigned char *data ){
int i = 0;
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(address,len);
while (Wire.available()){
if (i==len){
return 0;
}
*(data+i) = Wire.read();
i++;
}
return i;
}
void mpuWriteReg( int address, int reg, unsigned char val ){
Wire.beginTransmission(address);
Wire.write(reg);
Wire.write(val);
Wire.endTransmission(true);
}
void setup() {
Serial.begin(115200);
Wire.begin(I2C_SDA,I2C_SCL);
Wire.setClock(400000);
int clk = Wire.getClock();
Serial.printf("I2C clock %d\n", clk);
delay(100);
int id = mpuReadByte(MPU_ADDRESS, MPU_WHO_AM_I);
Serial.printf("ID:0x%02X\n", id);
mpuWriteReg(MPU_ADDRESS, MPU_PWR_MGMT_1, SLEEP_OFF+CLKSEL_PLLX);
mpuWriteReg(MPU_ADDRESS, MPU_CONFIG, DLPF_44HZ_42HZ);
mpuWriteReg(MPU_ADDRESS, MPU_SMPLRT_DIV, SMPLRT_100);
}
MPU-6050からのデータ読み出し
データの更新待ち
- INT_STATUS(0x3A)を見て、新しいデータが入るのを待つ
- 新しいデータが入るとDATA_RDY_INT(Bit0)が1になる
- 一度読むとクリアされる
データの読み出し
- ACCEL_XOUT_H(0x3B)から14バイトを読み出す
- 各データはH、Lの順で読み出されるので、符号付き16ビットデータに戻す
void loop() {
unsigned char tData[MPU_DATA_NUM*2];
short dataBuf[MPU_DATA_NUM];
int mStatus = mpuReadByte(MPU_ADDRESS, MPU_INT_STATUS);
if ((mStatus&DATA_RDY_INT)!=0){
mpuReadBlock(MPU_ADDRESS, MPU_ACCEL_XOUT, MPU_DATA_NUM*2, tData);
for (int i=0; i<MPU_DATA_NUM; i++){
unsigned short s = (tData[2*i] << 8) + tData[2*i+1];
dataBuf[i] = (short)s;
}
}
}
テスト結果
- 200回分を取得するまでの時間を計測してシリアル出力
1回あたり約10msとなり、想定どおりに動作していることが確認できた