#include "Wire.h" #include "I2Cdev.h" #include "MPU9150.h" #define N_SAMPLE 256 #define WAIT_TIME 50 #define N_DIM 4 #define EPS 1e-8 // ライブラリ内で定義されたセンサーの値を取得するクラスのインスタンス MPU9150 sensor; // 磁気センサの値を保存する変数 float mx, my, mz; // 連立方程式 float A[4][4]; float B[4]; void setup() { Serial.begin(9600); // センサーの初期化 Wire.begin(); Serial.println("Initializing I2C devices..."); sensor.initialize(); Serial.println("Testing device connections..."); Serial.println(sensor.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed"); } void loop() { // 動かさないと値が取れないので動かして!!!って表示する Serial.println("calculating mag offset..."); Serial.println("move sensor..."); // ちょっと待ってあげる delay(500); init_data(); // 初期化して calc_offset(); // オフセットを計算・表示する delay(2000); } void calc_offset() { float a, b, c, r; for (int i = 0 ; i < N_SAMPLE ; i++ ) { // センサーの値を読み取る get_mag(); // 左辺(係数行列) A[0][0] += 2.0 * mx * mx; A[0][1] += 2.0 * mx * my; A[0][2] += 2.0 * mx * mz; A[0][3] += 2.0 * mx; A[1][0] += 2.0 * my * mx; A[1][1] += 2.0 * my * my; A[1][2] += 2.0 * my * mz; A[1][3] += 2.0 * my; A[2][0] += 2.0 * mz * mx; A[2][1] += 2.0 * mz * my; A[2][2] += 2.0 * mz * mz; A[2][3] += 2.0 * mz; A[3][0] += 2.0 * mx; A[3][1] += 2.0 * my; A[3][2] += 2.0 * mz; A[3][3] += 2.0 * 1.0; // 右辺 B[0] += mx * (mx * mx + my * my + mz * mz); B[1] += my * (mx * mx + my * my + mz * mz); B[2] += mz * (mx * mx + my * my + mz * mz); B[3] += mx * mx + my * my + mz * mz; Serial.print(mx);Serial.print("\t"); Serial.print(my);Serial.print("\t"); Serial.print(mz);Serial.print("\n"); delay(WAIT_TIME); } solve(A, B); // 連立方程式を計算 // a,b,c,dのパラメータがB[0],B[1],B[2],B[3]に代入されているので // a,b,c,rを代入して関数を終わる a = B[0]; b = B[1]; c = B[2]; r = sqrt(B[0] * B[0] + B[1] * B[1] + B[2] * B[2] + 2 * B[3]); Serial.print("(x,y,z,r) = "); Serial.print("("); Serial.print(a); Serial.print("\t"); Serial.print(b); Serial.print("\t"); Serial.print(c); Serial.print("\t"); Serial.print(r); Serial.print("\t"); Serial.println(")"); } void init_data() { // A,Bを初期化する関数 A[0][0] = 0.0; A[0][1] = 0.0; A[0][2] = 0.0; A[0][3] = 0.0; A[1][0] = 0.0; A[1][1] = 0.0; A[1][2] = 0.0; A[1][3] = 0.0; A[2][0] = 0.0; A[2][1] = 0.0; A[2][2] = 0.0; A[2][3] = 0.0; A[3][0] = 0.0; A[3][1] = 0.0; A[3][2] = 0.0; A[3][3] = 0.0; B[0] = B[1] = B[2] = B[3] = 0.0; } void get_mag() { // センサーの値を一時的に格納する変数 int16_t raw_ax, raw_ay, raw_az; int16_t raw_gx, raw_gy, raw_gz; int16_t raw_mx, raw_my, raw_mz; // センサーの値を読み取る sensor.getMotion9( &raw_ax, &raw_ay, &raw_az, &raw_gx, &raw_gy, &raw_gz, &raw_mx, &raw_my, &raw_mz); // スケールを調整 mx = ((float)raw_mx) / 4096.0; my = ((float)raw_my) / 4096.0; mz = ((float)raw_mz) / 4096.0; } // 連立方程式を求める関数 void solve(float A[N_DIM][N_DIM], float B[N_DIM]) { float temp; for (int i = 0 ; i < N_DIM ; i++ ) { // ピボット選択的みたいな処理 for (int j = i + 1 ; j < N_DIM ; j++ ) { if ( is_zero(A[i][j]) == false ) break; for (int k = 0 ; k < N_DIM ; k++ ) A[i][k] += A[j][k]; B[i] += B[j]; } // 対角成分を1に temp = A[i][i]; for (int j = i ; j < N_DIM ; j++ ) A[i][j] /= temp; B[i] /= temp; // 前進消去 for (int j = i + 1 ; j < N_DIM ; j++ ) { temp = A[j][i]; for (int k = i ; k < N_DIM ; k++ ) A[j][k] -= temp * A[i][k]; B[j] -= temp * B[i]; } } // 後進消去 for (int i = N_DIM - 1 ; i >= 0 ; i-- ) for (int j = i - 1 ; j >= 0 ; j-- ) B[j] -= A[j][i] * B[i]; } // ほぼ0ならtrueを返す関数 bool is_zero(float val){ return -EPS < val && val < EPS; }