はじめに
- 作成したクラシックマウスの各パーツの解説。
- 今回は「Gyroセンサー MPU6050」。
- 機体写真、動画などは「その1」をご参照。
Gyroセンサー MPU6050
ステッピングモーターを使っていても、進むにつれて車体は斜めになっていき、いずれ壁に激突してしまう。距離センサーは精度が足りず、なかなか機体を制御するのが難しかった。
Gyroセンサーは、安価なのに精度が高く、機体の向きの制御が格段に容易になりました。
- BNO055との比較
- BNO055も試してみましたが、MPU6050の方が精度が高い気がしました。
- BNO055は9軸なので、向き(yaw)の絶対値が求まります。一方MPU6050は6軸なので、相対的な向きが出てきます。迷路探索においては、相対的な向きで十分なので、MPU6050を使っています。
- 取付位置
- 機体の写真で上に飛び出しているのがMPU6050です。マイコンやモーターからのノイズを減らす目的で離して取り付けています。ミニブレボ上に取り付けるより良くなった気がします。
- 使い方
- スタート時に向きを測定し、その測定数字をもとに機体の向きを修正しています。
- 90度回転 → 向き測定 → ずれた分を微調整 のような感じで利用しています。
- "yaw" 4元数?
- 本モジュールはマイコン(DMP)を内蔵していて、いろいろな数字を出力してくれますが、ここでは"yaw"しか使っていません。Sampleスケッチによると、"yaw"は4元数から計算されているようなので、精度は十分と考えました。
- 正直、4元数は難しすぎます。ドローン制御には必須なのでしょうか…
- 精度、調整
- 精度はかなり高いように思います。いろいろ回転させてみても、1~2°程度の誤差に収まっているようなので、機体制御には十分です。
- 自作の4×4迷路では、移動を繰り返した後でも、十分な精度を保っているように見えます。16x16ではどうなるでしょうか。
- 電源を入れてから、しばらく数字が安定しません。10秒程度(?)経つと安定するので、それから利用しています。
- ライブラリ
- ElectronicCatsのMPU6050を使いました。
- MPU6050_DMP6_using_DMP_V6v12.ino を適宜修正、削除して、"yaw"を利用しています。
- このSampleスケッチは割込みピンを利用する形になっていますが、ここでは利用していません。計測頻度が高くないので大丈夫なのでしょう。
- Calibrationは良くわからないので、Sampleスケッチにおまかせです。間違いがあるかもしれません。
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps612.h"
MPU6050 mpu;
#define OUTPUT_READABLE_YAWPITCHROLL
// MPU control/status vars
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
// orientation/motion vars
Quaternion q; // [w, x, y, z] quaternion container
VectorFloat gravity; // [x, y, z] gravity vector
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
///// 以下SETUP内 ////////////
//6050初期化
// initialize device
mpu.initialize();
// load and configure the DMP
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(51);
mpu.setYGyroOffset(8);
mpu.setZGyroOffset(21);
mpu.setXAccelOffset(1150);
mpu.setYAccelOffset(-50);
mpu.setZAccelOffset(1060);
// make sure it worked (returns 0 if so)
if (devStatus == 0) {
// Calibration Time: generate offsets and calibrate our MPU6050
mpu.CalibrateAccel(6);
mpu.CalibrateGyro(6);
mpu.PrintActiveOffsets();
// turn on the DMP, now that it's ready
mpu.setDMPEnabled(true);
// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
oled.print(F("DMP Initialization failed (code "));
oled.print(devStatus);
}
///// 以下yaw取得のための関数 ////////////
float get_y_6050(){
// read a packet from FIFO
mpu.dmpGetCurrentFIFOPacket(fifoBuffer);
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
return ypr[0] * 180 / M_PI;
}
以上