機械工学実験1作業用

Dependencies:   PID QEI USBHost mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 //※重要※  日本語コメントアウトはmbedのBeta-japaneseに登録すると使えるようになる(2014年現在)
00002 //めんどくさいからファイル分割しないよ.熱意がある人はやって頂戴 by小林2014-9-12
00003 #include "mbed.h"           //updateのマークが出ていてもupdateしないように.なんか仕様が変わってるっぽいからエラー吐くようになる
00004 #include "QEI.h"
00005 //#include "USBHostMSD.h"     //updateのマークが出ていてもupdateしないように.なんか仕様が変わってるっぽいからエラー吐くようになる
00006 #include "PID.h"
00007 #include "setting.h"
00008 
00009 //1回転あたりのパルス
00010 #define PULSE_PER_REVOLUTION 200
00011 //PIDのウェイト ミリ秒(制御周期)
00012 #define PID_RATE 10
00013 //ギア比
00014 #define GEAR_RATIO 2
00015 
00016 #define KP_SCALE 10
00017 #define TI_SCALE 20
00018 
00019 /**************************入出力ポート設定**************************/
00020 DigitalOut led1(LED1);      //mbed上LED出力4つ
00021 DigitalOut led2(LED2);
00022 DigitalOut led3(LED3);
00023 DigitalOut led4(LED4);
00024 DigitalIn dip1(p5);         //DIPスイッチの入力4つ
00025 DigitalIn dip2(p6);
00026 DigitalIn dip3(p7);
00027 DigitalIn dip4(p8);
00028 DigitalIn startsw(p9);      //スタートスイッチ入力
00029 DigitalOut buzzer(p18);     //電子ブザー用デジタル出力
00030 AnalogIn volume(p20);       //ポテンショメータ入力(アナログ)
00031 PwmOut pwm(p25);            //モータへのPWM出力
00032 
00033 Serial pc(USBTX, USBRX);    //PCとのシリアル通信設定
00034 QEI encoder(p30, p29, NC, PULSE_PER_REVOLUTION, QEI::X2_ENCODING);        //QEIの設定.
00035 Timer timer;                //タイマー
00036 
00037 typedef struct{             //時間tとその時のrpmを記録するための構造体
00038     unsigned short t;
00039     short rpm;
00040 } result;
00041 
00042 /**************************プロトタイプ宣言**************************/
00043 int Init();
00044 int DipLed();
00045 int GetDipValue();
00046 int SW();
00047 int Buzzer(int buzvar);
00048 int find_header(FILE *fp, char keyword[]);
00049 void rm_right_space(char str[]);
00050 
00051 /**************************main文**************************/
00052 int main() {
00053     //初期化
00054     Buzzer(2);
00055     //USBHostMSD msd("usb");
00056     LocalFileSystem local("local");
00057     Init();             //初期化関数
00058     int flag = 0;       //フラグ用変数
00059     //float vol = 0;      //ポテンショメータからの入力値を受け取る変数
00060     //float rpm = 0;      //rpmを格納するための変数
00061     //float t = 0;        //時間計測のための変数
00062     //result exp2[(int)(15*1000/PID_RATE+1)] = {};  //モード2用の構造体
00063     //result exp3[(int)(15*1000/PID_RATE+1)] = {};  //モード3用の構造体
00064     result exp[(int)(15*1000/PID_RATE+1)] = {};
00065     //メインループ
00066     while(1){
00067         Init();
00068         for(int i = 0; i <= 15*1000/PID_RATE; i++){
00069             exp[i].t = 0;
00070             exp[i].rpm = 0;
00071         }
00072         SW();           //スタートスイッチの入力を待つ
00073         flag = GetDipValue();   //DIPスイッチの入力を見る
00074         DipLed();               //DIPスイッチのHLでLEDを光らせる
00075         Buzzer(1);      //ブザーを鳴らす.
00076         switch (flag){      //実験モード切り替えのswitch文.ここにcase0~15を書き足せばモードが追加できる.
00077             case 0:     //DIPスイッチの入力なしで何もしない
00078                 break;
00079             case 1:{        //モード1はポテンショメータからの入力で直接PWMのデューティ比を変更する.約1秒ごとにPCに値を出力する.このモードは時間で終了せず永遠に続く.終了するにはmbedのresetボタンを押す.
00080                 //初期化
00081                 float vol = 0;      //ポテンショメータからの入力値を受け取る変数
00082                 float rpm = 0;      //rpmを格納するための変数
00083                 float t = 0;        //時間計測のための変数
00084                 int i1 = 0;
00085                 encoder.reset();
00086                 timer.reset();
00087                 timer.start();
00088                 //ループ(抜け出せない)
00089                 while(1){
00090                     vol = 1 - volume;
00091                     pwm = vol;
00092                     if(i1 >= 20){
00093                         t = timer.read();
00094                         rpm = (float)encoder.getPulses() / 2 / PULSE_PER_REVOLUTION * 60 / t * GEAR_RATIO;  //減速比2
00095                         pc.printf("Duty Ratio = %.3f , %6d RPM\n", vol, (int)rpm);
00096                         encoder.reset();
00097                         i1 = 0;
00098                         timer.reset();
00099                     }
00100                     wait_ms(50);
00101                     i1++;
00102                 }
00103                 break;
00104             }
00105             case 2:{         //モード2はモータの応答を調べる.デューティ比1でモータを回転させ,100msごとの経過時間とRPMをUSBメモリのcsvファイルに出力する.約15秒で終了する.
00106                 //result exp2[(int)(15*1000/PID_RATE+1)] = {};
00107                 float dt = 0, tnow = 0, tpre = 0;
00108                 //初期化
00109                 exp[0].t = 0;
00110                 exp[0].rpm = 0;
00111                 encoder.reset();
00112                 timer.reset();
00113                 timer.start();
00114                 pwm = 1;        //モータ回転開始!!
00115                 //ループ(約15秒で終了)
00116                 for(int i = 0; i < 15*1000/PID_RATE; i++){       //10msごとに時間とrpmの取得
00117                     wait_ms(PID_RATE);
00118                     tpre = tnow;
00119                     tnow = timer.read();
00120                     exp[i+1].t = (unsigned short)(tnow * 1000);
00121                     dt = tnow - tpre;
00122                     exp[i+1].rpm = (short)((float)encoder.getPulses() / 2 / PULSE_PER_REVOLUTION * 60 / dt * GEAR_RATIO);        //減速比2
00123                     encoder.reset();
00124                 }
00125                 for(int i = 100; i >= 0; i--){      //ゆるやかに減速
00126                     pwm = (float)i / 100;
00127                     wait_ms(20);
00128                 }
00129                 pwm = 0;                            //回転を止める
00130                 wait(1);
00131                 FILE * fp = fopen("/local/exp2.csv","w");
00132                 if(fp == NULL){     //ファイルオープンエラー
00133                     Buzzer(-1);     //エラーコード-1のブザーを鳴らす
00134                     break;          //終了
00135                 }
00136                 fprintf(fp,"Time , RPM\n");
00137                 for(int i = 0; i <= 15*1000/PID_RATE; i++){
00138                     fprintf(fp,"%f , %d\n", (float)exp[i].t / 1000.0, exp[i].rpm);        //ファイルに実験データの書き込み
00139                 }
00140                 fclose(fp);
00141                 Buzzer(4);          //終了を知らせる
00142                 break;
00143             }
00144             case 3:{         //モード3はモータの応答を調べる.PID制御をかけ,経過時間とRPMをUSBメモリのcsvファイルに出力する.約15秒で終了する.
00145                 //result exp3[(int)(15*1000/PID_RATE+1)] = {};
00146                 float kp = 0, ti = 0, td = 0, max_rpm = 0, target_rpm = 0, reduction = 0, dt = 0, tnow = 0, tpre = 0, rpmnow = 0;
00147                 //int pulse[15*1000/PID_RATE+2] = {};
00148                 //int j = 0;
00149                 //float times = 0;
00150                 encoder.reset();
00151                 timer.reset();
00152                 /*
00153                 -----PID制御の係数設定ファイルpid.txtの書き方-----
00154                 #kp
00155                 1.0
00156                 
00157                 #ki
00158                 1.0
00159                 
00160                 #kd
00161                 0.0
00162                 
00163                 #max_rpm
00164                 10000
00165                 エンコーダで読めるモータのrpmの最大値.これを超えないように制御を行う.
00166                 
00167                 #target_rpm
00168                 3000
00169                 http://denki.nara-edu.ac.jp/~yabu/soft/header.htmlを参考にしました
00170                 */
00171                 
00172                 /*FILE *fppid = fopen("/local/pid.txt","r");
00173                 if(fppid == NULL){
00174                     Buzzer(-2);
00175                     break;
00176                 }*/
00177                 //fscanf(fppid,"%f %f %f %f %f", &kp, &ki, &kd, &max_rpm, &target_rpm);
00178                 //fclose(fppid);
00179                 //find_header(fppid,"# kp");       //PID制御用の係数の読み込み
00180                 //fscanf(fppid,"%f",&kp);
00181                 //find_header(fppid,"# ki");
00182                 //fscanf(fppid,"%f",&ki);
00183                 //find_header(fppid,"# kd");
00184                 //fscanf(fppid,"%f",&kd);
00185                 //find_header(fppid,"# max_rpm");
00186                 //fscanf(fppid,"%f",&max_rpm);
00187                 //find_header(fppid,"# target_rpm");
00188                 //fscanf(fppid,"%f",&target_rpm);
00189                 //fclose(fppid);
00190                 
00191                 kp = KP / KP_SCALE;
00192                 ti = TI * TI_SCALE;
00193                 td = TD;
00194                 max_rpm = MAX_RPM;
00195                 target_rpm = TARGET_RPM;
00196                 
00197                 PID pid(kp, ti, td, PID_RATE);      //PIDの設定
00198                 pid.setInputLimits(0.0, max_rpm);
00199                 pid.setOutputLimits(0.0, 1.0);
00200                 pid.setMode(AUTO_MODE);
00201                 pid.setSetPoint(target_rpm);
00202                 
00203                 exp[0].t = 0;
00204                 exp[0].rpm = 0;
00205                 timer.start();
00206                 for(int i = 0; i < 15*1000/PID_RATE; i++){        //15秒間実行する
00207                     tpre = tnow;
00208                     tnow = timer.read();
00209                     exp[i+1].t = (unsigned short)(tnow * 1000);
00210                     dt = tnow - tpre;
00211                     rpmnow = (float)encoder.getPulses() / 2 / PULSE_PER_REVOLUTION * 60 / dt * GEAR_RATIO;
00212                     exp[i+1].rpm = (short)rpmnow;
00213                     pid.setProcessValue(rpmnow);
00214                     pwm = pid.compute();
00215                     encoder.reset();
00216                     //pulse[i+1] = encoder.getPulses() / 2.0;
00217                     //pid.setProcessValue((float)(pulse[i+1] - pulse[i]) / PULSE_PER_REVOLUTION * 60 / (timer.read() - times) * 2);
00218                     //times = timer.read();
00219                     //if((i % (int)(100 / PID_RATE) == 0) && (i != 0)){   //100ms毎に時間とrpmを読み込む
00220                         //j++;
00221                         //exp3[j].t = timer.read();
00222                         //exp3[j].rpm = (float)(pulse[i+1] - pulse[i+1-(int)(100/PID_RATE)]) / PULSE_PER_REVOLUTION * 60 / (exp3[j].t - exp3[j-1].t) * 2;
00223                     //}
00224                     wait_ms(PID_RATE);
00225                 }
00226                 reduction = pwm.read();
00227                 for(int i = 0; i <= 100; i++){
00228                     pwm = pwm.read() - reduction / 100;
00229                     wait_ms(20);
00230                 }
00231                 pwm = 0;
00232                 wait(1);
00233                 FILE *fp = fopen("/local/exp3.csv","w");
00234                 if(fp == NULL){     //ファイルオープンエラー
00235                     Buzzer(-1);     //エラーコード-1のブザーを鳴らす
00236                     break;          //終了
00237                 }
00238                 fprintf(fp,"kp = %.6f  ki = %.6f  kd = %.6f\n", (float)KP, (float)TI, (float)TD);
00239                 fprintf(fp,"Time , RPM\n");
00240                 for(int i = 0; i <= 15*1000/PID_RATE; i++){
00241                     fprintf(fp,"%f , %d\n", (float)exp[i].t / 1000.0, exp[i].rpm);        //ファイルに実験データの書き込み
00242                 }
00243                 fclose(fp);
00244                 Buzzer(5);          //終了を知らせる
00245                 break;
00246             }
00247             default:        //0と上記以外でなにもなし
00248                 break;
00249         }
00250     }
00251 }
00252 
00253 /**************************関数たち**************************/
00254 int Init(){         //初期化関数
00255     pwm = 0;
00256     led1 = 0;
00257     led2 = 0;
00258     led3 = 0;
00259     led4 = 0;
00260     buzzer = 0;
00261     pc.baud(9600);
00262     encoder.reset();
00263     timer.reset();
00264     pwm.period_us(25);      //40kHz
00265     DipLed();
00266     return 0;
00267 }
00268 
00269 int DipLed(){       //DIPスイッチの状態によってledを光らせる関数
00270     if(dip1 == 1) led1 = 1; else led1 = 0;     //DIPスイッチの1がHならLEDを光らせる,Lなら光らせない
00271     if(dip2 == 1) led2 = 1; else led2 = 0;
00272     if(dip3 == 1) led3 = 1; else led3 = 0;
00273     if(dip4 == 1) led4 = 1; else led4 = 0;
00274     return 0;
00275 }
00276 
00277 int GetDipValue(){  //DIPスイッチの値を取得し,値を返す関数
00278     int Dip1 = dip1, Dip2 = dip2, Dip3 = dip3, Dip4 = dip4; //DIPスイッチの値を取得
00279     if(Dip1 == 0){
00280         if(Dip2 == 0){
00281             if(Dip3 == 0){
00282                 if(Dip4 == 0) return 0; else return 1;      //DIPスイッチが0000の場合0を返す.0001なら1
00283             }else{
00284                 if(Dip4 == 0) return 2; else return 3;
00285             }
00286         }else{
00287             if(Dip3 == 0){
00288                 if(Dip4 == 0) return 4; else return 5;
00289             }else{
00290                 if(Dip4 == 0) return 6; else return 7;
00291             }
00292         }
00293     }else{
00294         if(Dip2 == 0){
00295             if(Dip3 == 0){
00296                 if(Dip4 == 0) return 8; else return 9;
00297             }else{
00298                 if(Dip4 == 0) return 10; else return 11;
00299             }
00300         }else{
00301             if(Dip3 == 0){
00302                 if(Dip4 == 0) return 12; else return 13;
00303             }else{
00304                 if(Dip4 == 0) return 14; else return 15;
00305             }
00306         }
00307     }
00308 }
00309 
00310 int SW(){        //スタートスイッチ用関数,押して離したらスタート
00311     int i = 0, j = 0;
00312     while(i < 3){       //チャタリング除去,15msにわたってスタートスイッチが押されていればbreak
00313         if(startsw == 1) i++;
00314         else i = 0;
00315         DipLed();
00316         wait_ms(5);
00317     }
00318     while(j < 3){       //上に同じ,スタートスイッチが離されたことを検知
00319         if(startsw == 0) j++;
00320         else j = 0;
00321         DipLed();
00322         wait_ms(5);
00323     }
00324     return 0;
00325 }
00326 
00327 int Buzzer(int buzvar){     //電子ブザーを鳴らす関数
00328     switch (buzvar){
00329         /**************エラーを知らせるbeep**************/
00330         case -3:        //error * - -
00331             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1);
00332             buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
00333             buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
00334             break;
00335         case -2:        //error * - - -
00336             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1);
00337             buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
00338             buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
00339             buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
00340             break;
00341         case -1:        //error * - - - -
00342             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1);
00343             buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
00344             buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
00345             buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
00346             buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
00347             break;
00348         /**************エラーここまで**************/
00349         case 0:         //サウンドなし
00350             buzzer = 0;
00351             break;
00352         /**************状態を知らせるためのbeep**************/
00353         case 1:         // *(短)
00354             buzzer = 1; wait(0.1); buzzer = 0;
00355             break;
00356         case 2:         // * *
00357             buzzer = 1; wait(0.1); buzzer = 0; wait(0.05);
00358             buzzer = 1; wait(0.1); buzzer = 0;
00359             break;
00360         case 3:         // -(長)
00361             buzzer = 1; wait(0.3); buzzer = 0;
00362             break;
00363         case 4:         // - -
00364             buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
00365             buzzer = 1; wait(0.3); buzzer = 0;
00366             break;
00367         case 5:         // ---
00368             buzzer = 1; wait(0.9); buzzer = 0;
00369             break;
00370         case 6:         // * * *  * * *  * * *  *
00371             for(int i = 0; i < 3; i++){
00372                 for(int j = 0; j < 3; j++){
00373                     buzzer = 1; wait(0.1); buzzer = 0; wait(0.1);
00374                 }
00375                 wait(0.2);
00376             }
00377             buzzer = 1; wait(0.1); buzzer = 0;
00378             break;
00379         case 7:         // **-* ** -* ** *** **** "finish"
00380             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00381             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00382             buzzer = 1; wait(0.3); buzzer = 0; wait(0.1); 
00383             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00384             wait(0.2);
00385             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00386             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00387             wait(0.2);
00388             buzzer = 1; wait(0.3); buzzer = 0; wait(0.1); 
00389             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00390             wait(0.2);
00391             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00392             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00393             wait(0.2);
00394             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00395             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00396             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00397             wait(0.2);
00398             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00399             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00400             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00401             buzzer = 1; wait(0.1); buzzer = 0;
00402             break;
00403         case 8:         // *-*** -*- --* "オワリ"
00404             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1);
00405             buzzer = 1; wait(0.3); buzzer = 0; wait(0.1);
00406             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00407             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00408             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00409             wait(0.2);
00410             buzzer = 1; wait(0.3); buzzer = 0; wait(0.1); 
00411             buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
00412             buzzer = 1; wait(0.3); buzzer = 0; wait(0.1); 
00413             wait(0.2);
00414             buzzer = 1; wait(0.3); buzzer = 0; wait(0.1); 
00415             buzzer = 1; wait(0.3); buzzer = 0; wait(0.1); 
00416             buzzer = 1; wait(0.1); buzzer = 0;
00417             break;
00418         /**************状態を知らせるためのbeepここまで**************/
00419         default:        //no sound
00420             buzzer = 0;
00421             break;
00422     }
00423     return 0;
00424 }
00425 
00426 
00427 int find_header(FILE *fp, char keyword[])
00428 /*
00429     入力     fp        ファイルポインタ
00430              keyword   キーワード
00431     戻り値             1 : ヘッダを見つけた   0 ヘッダが見つからなかった
00432 */
00433 {
00434     char char_buf[256];
00435     char keyword_buf[256];
00436     char *condition;
00437     int  len,i;
00438 
00439     strcpy(keyword_buf,keyword);
00440     rm_right_space(keyword_buf);  /* 右側の空白を取り除く */
00441 
00442     rewind(fp);
00443     for(;;){
00444         condition = fgets(char_buf,BUFSIZ,fp);
00445         if ( condition == NULL ) break;
00446         rm_right_space(char_buf);       /* 右側の空白と改行記号を取り除く */
00447         len = strlen(char_buf);
00448         if ( len == 0 ) continue;       /* この文はなくてもよい */
00449         for ( i = 0 ; i < len ; i++ ){  /* 左側の空白を取り除く */
00450             if ( char_buf[i] != ' ' ) break;
00451         }
00452         if ( strcmp(&char_buf[i],keyword_buf)==0){
00453             return(1);
00454             break;
00455         }
00456     }
00457     fprintf(stderr,"cannot find header.  key word : |%s|\n",keyword);
00458     Buzzer(-3);
00459     return(0);
00460 }
00461 
00462 /* 文字列の右側の空白を削除する    改行記号がある場合はそれも除去する */
00463 
00464 void rm_right_space(char str[])
00465 {
00466     int i;
00467     
00468     i = strlen(str)-1;
00469     if ( str[i] == '\n' ) i--;
00470 
00471     while(i>=0){
00472         if ( str[i] != ' ')  break;
00473         i--;
00474     }
00475     str[i+1] = '\0';
00476 }