MPU6050のサンプルプログラム2

Dependencies:   ConfigFile SDFileSystem mbed

Fork of LAURUS_program by LAURUS

Files at this revision

API Documentation at this revision

Comitter:
ojan
Date:
Mon Jun 22 18:17:16 2015 +0000
Parent:
19:ad8ff2de68f5
Child:
21:d417708e84a8
Commit message:
LAURUS_Program_v2.2(beta); + some refactoring; + fix GPS bug

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/main.cpp	Mon Jun 22 15:23:37 2015 +0000
+++ b/main.cpp	Mon Jun 22 18:17:16 2015 +0000
@@ -48,13 +48,15 @@
 SDFileSystem    sd(PB_5, PB_4, PB_3, PB_10, "sd");  // microSD
 FILE *          fp;                                 // ログファイルのポインタ
 BufferedSerial  xbee(PA_9, PA_10, PC_1);            // Xbee
+//Serial          xbee(PA_9, PA_10);                  // XBee
+//DigitalIn       cts(PC_1);                          // ctsピン
 ConfigFile      cfg;                                // ConfigFile
 PwmOut          servoL(PB_6), servoR(PC_7);         // サーボ用PWM出力
 AnalogIn        optSensor(PC_0);                    // 照度センサ用アナログ入力
-AnalogIn        servoVcc(PA_1);                     // バッテリー電圧監視用アナログ入力(サーボ用)
-AnalogIn        logicVcc(PA_0);                     // バッテリー電圧監視用アナログ入力(ロジック用)
+AnalogIn        servoVcc(PA_0);                     // バッテリー電圧監視用アナログ入力(サーボ用)
+AnalogIn        logicVcc(PA_1);                     // バッテリー電圧監視用アナログ入力(ロジック用)
 DigitalIn       paraSensor(PB_0);                   // パラフォイルに繋がる(予定)の物理スイッチ
-Ticker          INT_timer;                          // 割り込みタイマー
+Ticker          ticker;                             // 割り込みタイマー
 Timer           timer;                              // 時間計測用タイマー
 
 int     lps_cnt = 0;            // 気圧センサ読み取りカウント
@@ -96,9 +98,10 @@
 float   vrt_acc = 0.0f;         // 鉛直方向の加速度成分(落下検知に使用)
 
 int     step = 0;               // シーケンス制御のステップ
-int     count = 0;              // 時間測定用カウンター
+int     count = 0;              // 安定滑空までの時間測定用カウンター
 int     dir = 0;                // 旋回方向(0:左 1:右)
-char    data[512] = {};         // 送信データ用配列
+char    data[512] = {};         // 送信データ用配
+int     loopTime = 0;           // 1ループに掛かる時間(デバッグ用
 
 /** config.txt **
 * #から始めるのはコメント行
@@ -141,10 +144,12 @@
 void    KalmanInit();                       // カルマンフィルタ初期化
 void    LoadConfig();                       // config読み取り
 int     Find_last();                        // SDカード初期化用関数
+void    DataProcessing();                   // データ処理関数
+void    ControlRoutine();                   // 制御ルーチン関数
 void    KalmanUpdate();                     // カルマンフィルタ更新
 float   Distance(Vector p1, Vector p2);     // 緯度・経度の差から2点間の距離を算出(m)
-bool    thrown();                           // 投下されたかどうかを判断する
-void    INT_func();                         // 割り込み用関数
+bool    Thrown();                           // 投下されたかどうかを判断する
+void    DataUpdate();                       // データ取得&更新関数
 void    toString(Matrix& m);                // デバッグ用
 void    toString(Vector& v);                // デバッグ用
 
@@ -174,8 +179,9 @@
 
     // 各種ベクトルの初期化
     VectorsInit();
-    
-    INT_timer.attach(&INT_func, dt);        // 割り込み有効化(Freq = 0.01fなので、10msおきの割り込み)
+
+    ticker.attach(&DataUpdate, dt);         // 割り込み有効化(Freq = 0.01fなので、10msおきの割り込み)
+    NVIC_SetPriority(TIM5_IRQn, 5);
     
     servoL.period(0.020f);                  // サーボの信号の周期は20ms
     servoR.period(0.020f);
@@ -187,195 +193,213 @@
         timer.reset();
         timer.start();
         myled = 1;                                          // LED is ON
-
-
+        
         /******************************* データ処理 *******************************/
-        {
-            INT_flag = FALSE;                               // 割り込みによる変数書き換えを阻止
-            gms.read();                                     // GPSデータ取得
-            UTC_t = (int)gms.time;
-
-            // 参照座標系の基底を求める
-            r_u = g;
-            r_f = geomag.GetPerpCompTo(g).Normalize();
-            r_l = Cross(r_u, r_f);
-
-            // 回転行列を経由してオイラー角を求める
-            // オイラー角はヨー・ピッチ・ロールの順に回転したものとする
-            // 各オイラー角を求めるのに回転行列の全成分は要らないので、一部だけ計算する。
-
-            float R_11 = r_f * b_f;                         // 回転行列の(1,1)成分
-            float R_12 = r_f * b_l;                         // 回転行列の(1,2)成分
-            float R_13 = r_f * b_u;                         // 回転行列の(1,3)成分
-            float R_23 = r_l * b_u;                         // 回転行列の(2,3)成分
-            float R_33 = r_u * b_u;                         // 回転行列の(3,3)成分
-
-#ifdef RULE3
-            yaw = atan2(-R_12, R_11) * RAD_TO_DEG + MAG_DECLINATION - Beta;
-#else
-            yaw = atan2(-R_12, R_11) * RAD_TO_DEG + MAG_DECLINATION;
-#endif
-            roll = atan2(-R_23, R_33) * RAD_TO_DEG;
-            pitch = asin(R_13) * RAD_TO_DEG;
-
-            if(yaw < -180.0f) yaw += 360.0f;                // ヨー角を[-π, π]に補正
-            if(yaw > 180.0f) yaw -= 360.0f;                 // ヨー角を[-π, π]に補正
-
-            if(UTC_t - pre_UTC_t >= 1) {                    // GPSデータが更新されていたら
-                p.SetComp(1, gms.longitude * DEG_TO_RAD);
-                p.SetComp(2, gms.latitude * DEG_TO_RAD);
-
-            } else {                                        // 更新されていなかったら
-                // GPSの補完処理を追加予定
-            }
-
-            pre_p = p;
-            pre_UTC_t = UTC_t;
-
-            float sv = (float)servoVcc.read_u16() * ADC_LSB_TO_V * 2.0f;    // サーボ電源電圧
-            float lv = (float)logicVcc.read_u16() * ADC_LSB_TO_V * 2.0f;    // ロジック電源電圧
-
-            // データをmicroSDに保存し、XBeeでPCへ送信する
-            sprintf(data, "%d, %.1f,%.1f,%.1f, %.3f,%.5f,%.5f, %.3f,%.3f,%.3f, %.3f,%d\r\n",
-                    UTC_t, yaw, pitch, roll,
-                    press, gms.longitude, gms.latitude, 
-                    sv, lv, vrt_acc,
-                    Distance(target_p, p), optSensor.read_u16());
-            fprintf(fp, data);
-            fflush(fp);
-            xbee.printf(data);      
-
-            INT_flag = TRUE;            // 割り込み許可
-        }
-
+        DataProcessing();
 
         /******************************* 制御ルーチン *******************************/
-        {
-
-            switch(step) {
-
-                // 投下&安定滑空シーケンス
-                case 0:
-                    if(thrown() || count != 0) {
-                        count++;
-                        // 投下直後に紐を引く場合はコメントアウトをはずす
-                        // pull_L = 15;
-                        // pull_R = 15;
-                        if(count >= WaitTime*5) {
-                            pull_L = 0;
-                            pull_R = 0;
-                            step = 1;
-                        }
-                    }
-                    break;
-
-                // 制御シーケンス
-                case 1:
-                    if(fabs(roll) > BorderSpiral) {
-                        // スパイラル回避行動
-                        if(roll > 0) {
-                            pull_L = PullMax;
-                            pull_R = 0;
-                        } else {
-                            pull_L = 0;
-                            pull_R = PullMax;
-                        }
-                    } else {
-
-                        /* いずれも地球を完全球体と仮定 */
-                        float target_lng = target_x * DEG_TO_RAD;
-                        float target_lat = target_y * DEG_TO_RAD;
-                        /* 北から西回りで目標方向の角度を出力 */
-                        float targetY = cos( target_lat ) * sin( target_lng - p.GetComp(1) );
-                        float targetX = cos( p.GetComp(2) ) * sin( target_lat ) - sin( p.GetComp(2) ) * cos( target_lat ) * cos( target_lng - p.GetComp(1) );
-                        float theta = -atan2f( targetY, targetX );
-                        float delta_theta = 0.0f;
-
-                        if(yaw >= 0.0f) {                                       // ヨー角が正
-                            if(theta >= 0.0f) {                                 // 目標角も正ならば、
-                                if(theta - yaw > Alpha) dir = 0;                // 単純に差を取って閾値αと比べる
-                                else if(theta - yaw < -Alpha) dir = 1;
-                            } else {                                            // 目標角が負であれば
-                                theta += 360.0f;                                // 360°足して正の値に変換してから
-                                delta_theta = theta - yaw;                      // 差を取る(yawから左回りに見たthetaとの差分)
-                                if(delta_theta < 180.0f) {                      // 差が180°より小さければ左旋回
-                                    if(delta_theta > Alpha) dir = 0;
-                                } else {                                        // 180°より大きければ右旋回
-                                    if(360.0f - delta_theta > Alpha) dir = 1;
-                                }
-                            }
-                        } else {                                                // ヨー角が負
-                            if(theta <= 0.0f) {                                 // 目標角も負ならば、
-                                if(theta - yaw > Alpha) dir = 0;                // 単純に差を取って閾値αと比べる
-                                else if(theta - yaw < -Alpha) dir = 1;
-                            } else {                                            // 目標角が正であれば、
-                                delta_theta = theta - yaw;                      // 差を取る(yawから左回りに見たthetaとの差分)
-                                if(delta_theta < 180.0f) {                      // 差が180°より小さければ左旋回
-                                    if(delta_theta > Alpha) dir = 0;
-                                } else {                                        // 180°より大きければ右旋回
-                                    if(360.0f - delta_theta > Alpha) dir = 1;
-                                }
-                            }
-                        }
-
-                        if(dir == 0) {           //目標は左方向
-
-                            pull_L = 20;
-                            pull_R = 0;
-
-                        } else if (dir == 1) {   //目標は右方向
-
-                            pull_L = 0;
-                            pull_R = 20;
-
-                        }
-                    }
-                    
-#ifdef RULE2
-                    // 目標地点との距離が閾値以下だった場合、落下シーケンスへと移行する
-                    if(Distance(target_p, p) < BorderDistance) step = 2;
-#endif
-
-                    break;
-
-#ifdef RULE2
-                // 落下シーケンス
-                case 2:
-                    pull_L = PullMax;
-                    pull_R = 0;
-
-                    // もし落下中に目標値から離れてしまった場合は、体勢を立て直して再び滑空
-                    // 境界で制御が不安定にならないよう閾値にマージンを取る
-                    if(Distance(target_p, p) > BorderDistance+5.0f) step = 1;
-                    break;
-#endif
-            }
-
-            // 指定された引っ張り量だけ紐を引っ張る
-            if(pull_L < 0) pull_L = 0;
-            else if(pull_L > PullMax) pull_L = PullMax;
-            if(pull_R < 0) pull_R = 0;
-            else if(pull_R > PullMax) pull_R = PullMax;
-
-            servoL.pulsewidth((ServoMax - ServoMin) * pull_L / PullMax + ServoMin);
-            servoR.pulsewidth((ServoMax - ServoMin) * pull_R / PullMax + ServoMin);
-
-        }
+        ControlRoutine();
 
         myled = 0; // LED is OFF
 
+        loopTime = timer.read_ms();
+
         // ループはきっかり0.2秒ごと
         while(timer.read_ms() < 200);
-        
+
     }
 
     /* ------------------------------ ↑↑↑ ここまでメインループ ↑↑↑ ------------------------------ */
 }
 
+/** データ処理関数
+ *
+ */
+void DataProcessing()
+{
+    INT_flag = FALSE;                               // 割り込みによる変数書き換えを阻止
+    gms.read();                                     // GPSデータ取得
+    UTC_t = (int)gms.time;
+
+    // 参照座標系の基底を求める
+    r_u = g;
+    r_f = geomag.GetPerpCompTo(g).Normalize();
+    r_l = Cross(r_u, r_f);
+
+    // 回転行列を経由してオイラー角を求める
+    // オイラー角はヨー・ピッチ・ロールの順に回転したものとする
+    // 各オイラー角を求めるのに回転行列の全成分は要らないので、一部だけ計算する。
+
+    float R_11 = r_f * b_f;                         // 回転行列の(1,1)成分
+    float R_12 = r_f * b_l;                         // 回転行列の(1,2)成分
+    float R_13 = r_f * b_u;                         // 回転行列の(1,3)成分
+    float R_23 = r_l * b_u;                         // 回転行列の(2,3)成分
+    float R_33 = r_u * b_u;                         // 回転行列の(3,3)成分
+
+#ifdef RULE3
+    yaw = atan2(-R_12, R_11) * RAD_TO_DEG + MAG_DECLINATION - Beta;
+#else
+    yaw = atan2(-R_12, R_11) * RAD_TO_DEG + MAG_DECLINATION;
+#endif
+    roll = atan2(-R_23, R_33) * RAD_TO_DEG;
+    pitch = asin(R_13) * RAD_TO_DEG;
+
+    if(yaw < -180.0f) yaw += 360.0f;                // ヨー角を[-π, π]に補正
+    if(yaw > 180.0f) yaw -= 360.0f;                 // ヨー角を[-π, π]に補正
+
+    if(UTC_t - pre_UTC_t >= 1) {                    // GPSデータが更新されていたら
+        p.SetComp(1, gms.longitude * DEG_TO_RAD);
+        p.SetComp(2, gms.latitude * DEG_TO_RAD);
+
+    } else {                                        // 更新されていなかったら
+        // GPSの補完処理を追加予定
+    }
+
+    pre_p = p;
+    pre_UTC_t = UTC_t;
+
+    float sv = (float)servoVcc.read_u16() * ADC_LSB_TO_V * 2.0f;    // サーボ電源電圧
+    float lv = (float)logicVcc.read_u16() * ADC_LSB_TO_V * 2.0f;    // ロジック電源電圧
+
+    // データをmicroSDに保存し、XBeeでPCへ送信する
+    sprintf(data, "%d, %.1f,%.1f,%.1f, %.3f,%.5f,%.5f, %.3f,%.3f,%d, %.3f,%d\r\n",
+            UTC_t, yaw, pitch, roll,
+            press, gms.longitude, gms.latitude,
+            lv, vrt_acc, loopTime, 
+            Distance(target_p, p), optSensor.read_u16());
+    fprintf(fp, data);
+    fflush(fp);
+    xbee.printf(data);
+    /*
+    int dataLength = strlen(data);
+    for(int i=0; i<dataLength; i++) {
+        while(cts);
+        xbee.putc(data[i]);
+    }
+    */
+    INT_flag = TRUE;            // 割り込み許可
+
+}
+
+/** 制御ルーチン関数
+ *
+ */
+void ControlRoutine()
+{
+    switch(step) {
+
+            // 投下&安定滑空シーケンス
+        case 0:
+            if(Thrown() || count != 0) {
+                count++;
+                // 投下直後に紐を引く場合はコメントアウトをはずす
+                // pull_L = 15;
+                // pull_R = 15;
+                if(count >= WaitTime*5) {
+                    pull_L = 0;
+                    pull_R = 0;
+                    step = 1;
+                }
+            }
+            break;
+
+            // 制御シーケンス
+        case 1:
+            if(fabs(roll) > BorderSpiral) {
+                // スパイラル回避行動
+                if(roll > 0) {
+                    pull_L = PullMax;
+                    pull_R = 0;
+                } else {
+                    pull_L = 0;
+                    pull_R = PullMax;
+                }
+            } else {
+
+                /* いずれも地球を完全球体と仮定 */
+                float target_lng = target_x * DEG_TO_RAD;
+                float target_lat = target_y * DEG_TO_RAD;
+                /* 北から西回りで目標方向の角度を出力 */
+                float targetY = cos( target_lat ) * sin( target_lng - p.GetComp(1) );
+                float targetX = cos( p.GetComp(2) ) * sin( target_lat ) - sin( p.GetComp(2) ) * cos( target_lat ) * cos( target_lng - p.GetComp(1) );
+                float theta = -atan2f( targetY, targetX );
+                float delta_theta = 0.0f;
+
+                if(yaw >= 0.0f) {                                       // ヨー角が正
+                    if(theta >= 0.0f) {                                 // 目標角も正ならば、
+                        if(theta - yaw > Alpha) dir = 0;                // 単純に差を取って閾値αと比べる
+                        else if(theta - yaw < -Alpha) dir = 1;
+                    } else {                                            // 目標角が負であれば
+                        theta += 360.0f;                                // 360°足して正の値に変換してから
+                        delta_theta = theta - yaw;                      // 差を取る(yawから左回りに見たthetaとの差分)
+                        if(delta_theta < 180.0f) {                      // 差が180°より小さければ左旋回
+                            if(delta_theta > Alpha) dir = 0;
+                        } else {                                        // 180°より大きければ右旋回
+                            if(360.0f - delta_theta > Alpha) dir = 1;
+                        }
+                    }
+                } else {                                                // ヨー角が負
+                    if(theta <= 0.0f) {                                 // 目標角も負ならば、
+                        if(theta - yaw > Alpha) dir = 0;                // 単純に差を取って閾値αと比べる
+                        else if(theta - yaw < -Alpha) dir = 1;
+                    } else {                                            // 目標角が正であれば、
+                        delta_theta = theta - yaw;                      // 差を取る(yawから左回りに見たthetaとの差分)
+                        if(delta_theta < 180.0f) {                      // 差が180°より小さければ左旋回
+                            if(delta_theta > Alpha) dir = 0;
+                        } else {                                        // 180°より大きければ右旋回
+                            if(360.0f - delta_theta > Alpha) dir = 1;
+                        }
+                    }
+                }
+
+                if(dir == 0) {           //目標は左方向
+
+                    pull_L = 20;
+                    pull_R = 0;
+
+                } else if (dir == 1) {   //目標は右方向
+
+                    pull_L = 0;
+                    pull_R = 20;
+
+                }
+            }
+
+#ifdef RULE2
+            // 目標地点との距離が閾値以下だった場合、落下シーケンスへと移行する
+            if(Distance(target_p, p) < BorderDistance) step = 2;
+#endif
+
+            break;
+
+#ifdef RULE2
+            // 落下シーケンス
+        case 2:
+            pull_L = PullMax;
+            pull_R = 0;
+
+            // もし落下中に目標値から離れてしまった場合は、体勢を立て直して再び滑空
+            // 境界で制御が不安定にならないよう閾値にマージンを取る
+            if(Distance(target_p, p) > BorderDistance+5.0f) step = 1;
+            break;
+#endif
+    }
+
+    // 指定された引っ張り量だけ紐を引っ張る
+    if(pull_L < 0) pull_L = 0;
+    else if(pull_L > PullMax) pull_L = PullMax;
+    if(pull_R < 0) pull_R = 0;
+    else if(pull_R > PullMax) pull_R = PullMax;
+
+    servoL.pulsewidth((ServoMax - ServoMin) * pull_L / PullMax + ServoMin);
+    servoR.pulsewidth((ServoMax - ServoMin) * pull_R / PullMax + ServoMin);
+}
+
 /** 各種ベクトルの初期化を行う関数
  *
  */
-void VectorsInit() {
+void VectorsInit()
+{
     //重力ベクトルの初期化
     raw_g.SetComp(1, 0.0f);
     raw_g.SetComp(2, 0.0f);
@@ -389,7 +413,7 @@
     b_u.SetComp(2, 0.0f);
     b_u.SetComp(3, 0.0f);
     b_l = Cross(b_u, b_f);
-    
+
     // 目標座標をベクトルに代入
     target_p.SetComp(1, target_x * DEG_TO_RAD);
     target_p.SetComp(2, target_y * DEG_TO_RAD);
@@ -398,7 +422,8 @@
 /** マイクロSDカードの初期化を行う関数
  *
  */
-void SD_Init() {
+void SD_Init()
+{
     //SDカード初期化
     char filename[15];
     int n = Find_last();
@@ -625,7 +650,7 @@
  * @return 投下されたかどうか(true=投下 false=未投下
  *
  */
-bool thrown()
+bool Thrown()
 {
     static int opt_count = 0;
     static int g_count = 0;
@@ -646,9 +671,10 @@
 
 }
 
-/* ------------------------------ 割り込み関数 ------------------------------ */
-
-void INT_func()
+/** データ取得&更新関数
+ *
+ */
+void DataUpdate()
 {
     // センサーの値を更新
     mpu.read();
@@ -686,6 +712,8 @@
     }
 }
 
+/* ------------------------------ 割り込み関数 ------------------------------ */
+
 /* ------------------------------ デバッグ用関数 ------------------------------ */
 
 void toString(Matrix& m)