• 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となり、想定どおりに動作していることが確認できた