Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: ConfigFile SDFileSystem mbed
Fork of LAURUS_program by
Revision 20:00afba164688, committed 2015-06-22
- 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)
