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 36:94dc027e05cd, committed 2015-12-07
- Comitter:
- taurin
- Date:
- Mon Dec 07 02:11:56 2015 +0000
- Parent:
- 35:e490f3de2cde
- Commit message:
- MPU?HMC??????ver
Changed in this revision
| main.cpp | Show annotated file Show diff for this revision Revisions of this file |
--- a/main.cpp Tue Nov 24 05:43:09 2015 +0000
+++ b/main.cpp Mon Dec 07 02:11:56 2015 +0000
@@ -11,45 +11,7 @@
#include "BufferedSerial.h"
#include "ConfigFile.h"
-/****************************** private define ******************************/
-//#define RULE1
-//#define RULE2
-//#define RULE3
-//#define RULE4
-//#define RULE3_1
-#define SERVO_DEBUG
-//#define DIRECTION_DEBUG
-//#define SPIRAL_DEBUG
-
-#ifdef DIRECTION_DEBUG
-const float TargetDirection = -179.0f; // 指定方向に飛ぶ
-
-#elif RULE3_1
-const float BetaMin = 0.2f * RAD_TO_DEG; // β最小値
-const float BetaVar = 0.3f * RAD_TO_DEG; // β変化量
-const float BetaMax = 1.0f * RAD_TO_DEG; // β最大値
-const float Span = 10.0f; // βの値が変わる距離間隔(Span[m]ごとにβの値がBetaVarだけ変化)
-
-#elif RULE4
-const float BorderHeight = 10.0f; // 制御則3と2を切り替える高度の閾値(m)
-#endif
-
const float dt = 0.01f; // 割り込み周期(s)
-const float ServoMax = 0.0046f; // サーボの最大パルス長(s)
-const float ServoMin = 0.0012f; // サーボの最小パルス長(s)
-const float Stabilize = 0.0f; // 滑空安定時の引っ張り量
-const float Turn = 25.0f; // 旋回時の引っ張り量
-const float PullRate = 7.5f; // 紐の引っ張り速度
-const float PullMax = 25.0f; // 引っ張れる紐の最大量(mm)
-const float BorderSpiral = 40.0f; // スパイラル検知角度
-const short BorderOpt = 30000; // 光センサーの閾値
-const float BorderGravity = 0.3f; // 無重力状態の閾値
-const int BorderParafoil = 0; // 物理スイッチのOFF出力
-const int MaxCount = 3; // 投下シグナルを何回連続で検知したら投下と判断するか(×0.2[s])
-const int WaitTime = 6; // 投下後、安定するまで何秒滑空するか
-const float Alpha = 30.0f; // 目標方向と自分の進行方向との差の閾値(deg)(制御則1&2&3の定数
-const float Beta = 60.0f; // 目標方向と自分の進行方向との間に取るべき角度差(deg)(制御則3の定数
-const float BorderDistance = 5.0f; // 落下制御に入るための目標値との距離の閾値(m)(制御則2の定数
enum Direction {LEFT, RIGHT, NEUTRAL};
@@ -57,22 +19,13 @@
/****************************** private typedef ******************************/
/****************************** private variables ******************************/
DigitalOut myled(LED1); // デバッグ用LEDのためのデジタル出力
-I2C i2c(PB_9, PB_8); // I2Cポート
+I2C i2c(p9, p8); // I2Cポート
MPU6050 mpu(&i2c); // 加速度・角速度センサ
HMC5883L hmc(&i2c); // 地磁気センサ
LPS25H lps(&i2c); // 気圧センサ
-Serial gps(PA_11, PA_12); // GPS通信用シリアルポート
-Serial pc(SERIAL_TX, SERIAL_RX); // PC通信用シリアルポート
-GMS6_CR6 gms(&gps, &pc); // GPS
-SDFileSystem sd(PB_5, PB_4, PB_3, PB_10, "sd"); // microSD
+Serial pc(USBTX,USBRX); // PC通信用シリアルポート
FILE * fp; // ログファイルのポインタ
-BufferedSerial xbee(PA_9, PA_10, PC_1, 256, 16); // Xbee
ConfigFile cfg; // ConfigFile
-PwmOut servoL(PB_6), servoR(PC_7); // サーボ用PWM出力
-AnalogIn optSensor(PC_0); // 照度センサ用アナログ入力
-AnalogIn servoVcc(PA_1); // バッテリー電圧監視用アナログ入力(サーボ用)
-AnalogIn logicVcc(PA_0); // バッテリー電圧監視用アナログ入力(ロジック用)
-DigitalIn paraSensor(PB_0); // パラフォイルに繋がる(予定)の物理スイッチ
Ticker ticker; // 割り込みタイマー
Timer timer; // 時間計測用タイマー
Direction dir = NEUTRAL; // 旋回方向
@@ -166,24 +119,16 @@
/****************************** private functions ******************************/
-bool SD_Init(); // SDカード初期化
void SensorsInit(); // 各種センサーの初期化
void KalmanInit(); // カルマンフィルタ初期化
-bool LoadConfig(); // config読み取り
-int Find_last(); // SDカード初期化用関数
void DataProcessing(); // データ処理関数
-void ControlRoutine(); // 制御ルーチン関数
void KalmanUpdate(); // カルマンフィルタ更新
-float Distance(Vector p1, Vector p2); // 緯度・経度の差から2点間の距離を算出(m)
-bool Thrown(); // 投下されたかどうかを判断する
void DataUpdate(); // データ取得&更新関数
-void toString(Matrix& m); // デバッグ用
-void toString(Vector& v); // デバッグ用
/** 小さい値を返す関数
* @param a: 1つ目の入力値
* @param b: 2つ目の入力値
- *
+ *
* @return a,bのうち、小さい方の値
*/
inline float min(float a, float b)
@@ -191,52 +136,17 @@
return ((a > b) ? b : a);
}
-/** 気圧の変化から高度を計算する関数
- * @param press: 現在の気圧
- *
- * @return height: 現在の基準点からの高度
- */
-inline float Height(float press) {
- return (153.8f * (pow((p0/press),0.1902f)-1.0f)*(25.0f+273.15f));
-}
-
/****************************** main function ******************************/
int main()
{
i2c.frequency(400000); // I2Cの通信速度を400kHzに設定
-
- //Config読み取り
- xbee.printf("load...");
- while(!LoadConfig()) {
- wait(0.1f);
- xbee.printf(".");
- }
- xbee.printf("complete\r\n");
- xbee.printf("target(%.5f, %.5f)\r\n", target_x, target_y);
-
- // SDカード初期化
- xbee.printf("SD Init...");
- while(!SD_Init()) {
- wait(0.1f);
- xbee.printf(".");
- }
- xbee.printf("complete\r\n");
-
- // センサー関連の初期化
- xbee.printf("Sensors Init...");
- SensorsInit();
- xbee.printf("complete\r\n");
-
//カルマンフィルタ初期化
KalmanInit();
- NVIC_SetPriority(TIM5_IRQn, 5);
ticker.attach(&DataUpdate, dt); // 割り込み有効化(Freq = 0.01fなので、10msおきの割り込み)
-
- servoL.period(0.020f); // サーボの信号の周期は20ms
- servoR.period(0.020f);
+
/* ------------------------------ ↓↓↓ ここからメインループ ↓↓↓ ------------------------------ */
@@ -245,61 +155,12 @@
timer.reset();
timer.start();
myled = 1; // LED is ON
-
+
INT_flag = false; // 割り込みによる変数書き換えを阻止
/******************************* データ処理 *******************************/
DataProcessing();
-
- /******************************* 制御ルーチン *******************************/
-#ifdef SERVO_DEBUG
- if(xbee.readable()) {
- char cmd = xbee.getc();
- if(cmd == 'w') {
- pull_R = 20.0f;
- pull_L = 0.0f;
- } else if(cmd == 's'){
- pull_R = 10.0f;
- pull_L = 10.0f;
- } else if(cmd == 'a'){
- pull_R = 0.0f;
- pull_L = 20.0f;
- } else if(cmd == 'd'){
- pull_R = 10.0f;
- pull_L = 10.0f;
- }
- }
-#else
- ControlRoutine();
-#endif
-
- sv = (float)servoVcc.read_u16() * ADC_LSB_TO_V * 2.0f; // サーボ電源電圧
- lv = (float)logicVcc.read_u16() * ADC_LSB_TO_V * 2.0f; // ロジック電源電圧
-
-
-
- // データをmicroSDに保存し、XBeeでPCへ送信する
- sprintf(data, "%d.%d, %.1f,%.1f,%.1f, %.3f,%.6f,%.6f, %.3f,%.3f,%.1f, %d, %.1f,%.1f\r\n",
- UTC_t, ss, yaw, pitch, roll,
- press, gms.longitude, gms.latitude,
- vrt_acc, height, Distance(target_p, p),
- optSensor.read_u16(), pull_R, pull_L);
-
- INT_flag = true; // 割り込み許可
-
- fprintf(fp, data);
- fflush(fp);
- xbee.printf(data);
-
-
- myled = 0; // LED is OFF
-
- loopTime = timer.read_ms();
-
- // ループはきっかり0.2秒ごと
- while(timer.read_ms() < 200);
-
+ INT_flag = true;
}
-
/* ------------------------------ ↑↑↑ ここまでメインループ ↑↑↑ ------------------------------ */
}
@@ -314,9 +175,7 @@
static float r_sin; // ロール角のsin値
static float p_cos; // ピッチ角のcos値
static float p_sin; // ピッチ角のsin値
-
- gms.read(); // GPSデータ取得
- UTC_t = (int)gms.time + 90000;
+
// 参照座標系の基底を求める
r_u = g;
@@ -337,7 +196,7 @@
} else {
roll = -acos(r_cos) * RAD_TO_DEG;
}
-
+
p_cos = g.GetPerpCompTo(b_l).Normalize() * b_u;
p_sin = Cross(g.GetPerpCompTo(b_l).Normalize(), b_u) * b_l;
if(p_sin > 0.0f) {
@@ -348,196 +207,18 @@
if(yaw > 180.0f) yaw -= 360.0f; // ヨー角を[-π, π]に補正
else if(yaw < -180.0f) yaw += 360.0f; // ヨー角を[-π, π]に補正
-
- if(UTC_t - pre_UTC_t >= 1) { // GPSデータが更新されていたら
- pre_p = new_p;
- new_p.SetComp(1, gms.longitude * DEG_TO_RAD);
- new_p.SetComp(2, gms.latitude * DEG_TO_RAD);
- p = new_p;
- pre_UTC_t = UTC_t;
- ss = 0;
- } else { // 更新されていなかったら
- p += 0.2f * (new_p - pre_p);
- ss += 2;
- }
-
- height = Height(press);
-
-
-
}
-/** 制御ルーチン関数
- *
- */
-void ControlRoutine()
-{
- volatile static int count = 0;
- static float target_lng;
- static float target_lat;
- static float target_X;
- static float target_Y;
- static float theta;
- static float delta_theta;
-
- switch(step) {
-
- // 投下&安定滑空シーケンス
- case 0:
- if(Thrown() || count != 0) {
- count++;
- pull_L = Stabilize;
- pull_R = Stabilize;
- if(count >= WaitTime*5) {
- pull_L = 0.0f;
- pull_R = 0.0f;
-#ifdef SPIRAL_DEBUG
- step = 2;
-#else
- step = 1;
-#endif
- }
- }
- break;
-
- // 制御シーケンス
- case 1:
- if(fabs(roll) > BorderSpiral) {
- // スパイラル回避行動
- /*if(roll > 0) {
- pull_L = PullMax;
- pull_R = 0.0f;
- } else {
- pull_L = 0.0f;
- pull_R = PullMax;
- }*/
-
- } else {
-
- /* いずれも地球を完全球体と仮定 */
- target_lng = target_x * DEG_TO_RAD;
- target_lat = target_y * DEG_TO_RAD;
- /* 北から西回りで目標方向の角度を出力 */
- target_Y = cos( target_lat ) * sin( target_lng - p.GetComp(1) );
- target_X = cos( p.GetComp(2) ) * sin( target_lat ) - sin( p.GetComp(2) ) * cos( target_lat ) * cos( target_lng - p.GetComp(1) );
-
-#ifdef RULE4
- if(height > BorderHeight) {
- theta = -atan2f( target_Y, target_X ) * RAD_TO_DEG + Beta;
- if(theta > 180.0f) theta -= 360.0f;
- } else {
- theta = -atan2f( target_Y, target_X ) * RAD_TO_DEG;
- }
-#elif RULE3
- theta = -atan2f( target_Y, target_X ) * RAD_TO_DEG + Beta;
-
- if(theta > 180.0f) theta -= 360.0f;
- else if(theta < -180.0f) theta += 360.0f;
-#elif RULE3_1
- float d = Distance(target_p, p);
- beta = BetaMax - BetaVar * (int)(d / Span);
- if(beta < BetaMin) beta = BetaMin;
-
- theta = -atan2f( target_Y, target_X ) * RAD_TO_DEG + beta;
-
- if(theta > 180.0f) theta -= 360.0f;
- else if(theta < -180.0f) theta += 360.0f;
-
-#else
- theta = -atan2f( target_Y, target_X ) * RAD_TO_DEG;
-#endif
-
-#ifdef DIRECTION_DEBUG
- theta = TargetDirection;
-#endif
-
- if(yaw >= 0.0f) { // ヨー角が正
- if(theta >= 0.0f) { // 目標角も正ならば、
- if(theta - yaw > Alpha) dir = LEFT; // 単純に差を取って閾値αと比べる
- else if(theta - yaw < -Alpha) dir = RIGHT;
- else dir = NEUTRAL;
- } else { // 目標角が負であれば
- theta += 360.0f; // 360°足して正の値に変換してから
- delta_theta = theta - yaw; // 差を取る(yawから左回りに見たthetaとの差分)
- if(delta_theta < 180.0f) { // 差が180°より小さければ左旋回
- if(delta_theta > Alpha) dir = LEFT;
- else dir = NEUTRAL;
- } else { // 180°より大きければ右旋回
- if(360.0f - delta_theta > Alpha) dir = RIGHT;
- else dir = NEUTRAL;
- }
- }
- } else { // ヨー角が負
- if(theta <= 0.0f) { // 目標角も負ならば、
- if(theta - yaw > Alpha) dir = LEFT; // 単純に差を取って閾値αと比べる
- else if(theta - yaw < -Alpha) dir = RIGHT;
- else dir = NEUTRAL;
- } else { // 目標角が正であれば、
- delta_theta = theta - yaw; // 差を取る(yawから左回りに見たthetaとの差分)
- if(delta_theta < 180.0f) { // 差が180°より小さければ左旋回
- if(delta_theta > Alpha) dir = LEFT;
- else dir = NEUTRAL;
- } else { // 180°より大きければ右旋回
- if(360.0f - delta_theta > Alpha) dir = RIGHT;
- else dir = NEUTRAL;
- }
- }
- }
-
- if(dir == LEFT) { //目標は左方向
-
- pull_L = Turn;
- pull_R = 0.0f;
-
- } else if (dir == RIGHT) { //目標は右方向
-
- pull_L = 0.0f;
- pull_R = Turn;
-
- } else if (dir == NEUTRAL) {
- pull_L = 0.0f;
- pull_R = 0.0f;
- }
- }
-#ifdef RULE4
- if(height <= BorderHeight) {
- // 目標地点との距離が閾値以下だった場合、落下シーケンスへと移行する
- if(Distance(target_p, p) < BorderDistance) step = 2;
- }
-#else
-#ifdef RULE2
- // 目標地点との距離が閾値以下だった場合、落下シーケンスへと移行する
- if(Distance(target_p, p) < BorderDistance) step = 2;
-#endif
-#endif
-
- break;
-
-#if defined(RULE2) || defined(RULE4) || defined(SPIRAL_DEBUG)
- // 落下シーケンス
- case 2:
- pull_L = 0.0f;
- pull_R = PullMax;
-
-#ifndef SPIRAL_DEBUG
- // もし落下中に目標値から離れてしまった場合は、体勢を立て直して再び滑空
- // 境界で制御が不安定にならないよう閾値にマージンを取る
- if(Distance(target_p, p) > BorderDistance+3.0f) step = 1;
-#endif
- break;
-#endif
- }
-}
/** 各種センサーの初期化を行う関数
*
*/
void SensorsInit()
{
-
+
if(!mpu.init()) error("mpu6050 Initialize Error !!"); // mpu6050初期化
if(!hmc.init()) error("hmc5883l Initialize Error !!"); // hmc5883l初期化
-
+
//重力ベクトルの初期化
raw_g.SetComp(1, 0.0f);
raw_g.SetComp(2, 0.0f);
@@ -555,91 +236,8 @@
// 目標座標をベクトルに代入
target_p.SetComp(1, target_x * DEG_TO_RAD);
target_p.SetComp(2, target_y * DEG_TO_RAD);
-
- // 地表の気圧を取得
- p0 = 0.0f;
- for(int i=0; i<10; i++) {
- p0 += (float)lps.pressure() * PRES_LSB_TO_HPA;
- wait(0.1f);
- }
- p0 /= 10.0f;
-
- xbee.printf(".");
-}
-
-/** マイクロSDカードの初期化を行う関数
- *
- */
-bool SD_Init()
-{
- //SDカード初期化
- char filename[15];
- int n = Find_last();
- if(n < 0) {
- pc.printf("Could not read a SD Card.\n");
- return false;
- }
- sprintf(filename, "/sd/log%03d.csv", n+1);
- fp = fopen(filename, "w");
- fprintf(fp, "log data\r\n");
- xbee.printf("log data\r\n");
-
- return true;
}
-/** コンフィグファイルを読み込む関数
- *
- */
-bool LoadConfig()
-{
- char value[20];
- //Read a configuration file from a mbed.
- if (!cfg.read("/sd/config.txt")) {
- pc.printf("Config file does not exist\n");
- return false;
- } else {
- //Get values
- if (cfg.getValue("target_x", &value[0], sizeof(value))) target_x = atof(value);
- else {
- pc.printf("Failed to get value for target_x\n");
- return false;
- }
- if (cfg.getValue("target_y", &value[0], sizeof(value))) target_y = atof(value);
- else {
- pc.printf("Failed to get value for target_y\n");
- return false;
- }
- }
- return true;
-}
-
-/** ログファイルの番号の最大値を得る関数
- *
- * @return マイクロSD内に存在するログファイル番号の最大値
- */
-int Find_last()
-{
- int i, n = 0;
- char c;
- DIR *dp;
- struct dirent *dirst;
- dp = opendir("/sd/");
- if (!dp) {
- pc.printf("Could not open directry.\n");
- return -1;
- }
- while((dirst = readdir(dp)) != NULL) {
- if(sscanf(dirst->d_name, "log%03d.csv%c", &i, &c) == 1 && i>n) {
- n = i;
- }
- }
- closedir(dp);
- return n;
-}
-
-/** カルマンフィルタの初期化を行う関数
- *
- */
void KalmanInit()
{
// 重力
@@ -778,63 +376,6 @@
}
}
-/** GPS座標から距離を算出
- * @param 座標1(経度、緯度)(rad)
- * @param 座標2(経度、緯度)(rad)
- *
- * @return 2点間の距離(m)
- */
-float Distance(Vector p1, Vector p2)
-{
- static float mu_y;
- static float s_mu_y;
- static float w;
- static float m;
- static float n;
- static float d1;
- static float d2;
-
- if(p1.GetDim() != p2.GetDim()) return 0.0f;
-
- mu_y = (p1.GetComp(2) + p2.GetComp(2)) * 0.5f;
- s_mu_y = sin(mu_y);
- w = sqrt(1 - GPS_SQ_E * s_mu_y * s_mu_y);
- m = GPS_A * (1 - GPS_SQ_E) / (w * w * w);
- n = GPS_A / w;
- d1 = m * (p1.GetComp(2) - p2.GetComp(2));
- d2 = n * cos(mu_y) * (p1.GetComp(1) - p2.GetComp(1));
-
- return sqrt(d1 * d1 + d2 * d2);
-}
-
-/** 投下を検知する関数
- *
- * @return 投下されたかどうか(true=投下 false=未投下
- *
- */
-bool Thrown()
-{
- volatile static int opt_count = 0;
- volatile static int g_count = 0;
- volatile static int para_count = 0;
-
-#ifndef SPIRAL_DEBUG
- /*if(optSensor.read_u16() > BorderOpt) opt_count++;
- else opt_count = 0;
- if(vrt_acc < BorderGravity) g_count++;
- else g_count = 0;*/
-#endif
- if((int)paraSensor == BorderParafoil) para_count++;
- else para_count = 0;
-
- if(opt_count >= MaxCount || g_count >= MaxCount || para_count >= MaxCount) {
- return true;
- }
-
- return false;
-
-}
-
/* ------------------------------ 割り込み関数 ------------------------------ */
/** データ取得&更新関数
@@ -842,32 +383,6 @@
*/
void DataUpdate()
{
- // サーボ用変数(引き量)
- static float pL = 0.0f;
- static float pR = 0.0f;
-
- // 引き量が目標値から一定以上離れていれば、引き量を一定の速度で更新する
- if(pull_L - pL > PullRate * dt) {
- pL += PullRate * dt;
- } else if(pull_L - pL < -PullRate * dt) {
- pL -= PullRate * dt;
- }
-
- if(pull_R - pR > PullRate * dt) {
- pR += PullRate * dt;
- } else if(pull_R - pR < -PullRate * dt) {
- pR -= PullRate * dt;
- }
-
- // 指定された引っ張り量だけ紐を引っ張る
- if(pL < 0.0f) pL = 0.0f;
- else if(pL > PullMax) pL = PullMax;
- if(pR < 0.0f) pR = 0.0f;
- else if(pR > PullMax) pR = PullMax;
-
- servoL.pulsewidth((ServoMax - ServoMin) * (PullMax - pL) / PullMax + ServoMin);
- servoR.pulsewidth((ServoMax - ServoMin) * pR / PullMax + ServoMin);
-
// センサーの値を更新
mpu.read();
hmc.read();
@@ -884,13 +399,6 @@
KalmanUpdate();
- // LPS25Hによる気圧の取得は10Hz
- lps_cnt = (lps_cnt+1)%10;
- if(lps_cnt == 0) {
- raw_press = (float)lps.pressure() * PRES_LSB_TO_HPA;
- raw_temp = TempLsbToDeg(lps.temperature());
- }
-
if(INT_flag) {
g = raw_g;
for(int i=0; i<3; i++) {
@@ -902,30 +410,5 @@
temp = raw_temp;
vrt_acc = raw_acc * raw_g;
-
}
}
-
-/* ------------------------------ デバッグ用関数 ------------------------------ */
-
-void toString(Matrix& m)
-{
-
- for(int i=0; i<m.GetRow(); i++) {
- for(int j=0; j<m.GetCol(); j++) {
- pc.printf("%.6f\t", m.GetComp(i+1, j+1));
- }
- pc.printf("\r\n");
- }
-
-}
-
-void toString(Vector& v)
-{
-
- for(int i=0; i<v.GetDim(); i++) {
- pc.printf("%.6f\t", v.GetComp(i+1));
- }
- pc.printf("\r\n");
-
-}
\ No newline at end of file
