機械工学実験1作業用

Dependencies:   PID QEI USBHost mbed

Files at this revision

API Documentation at this revision

Comitter:
neoqased
Date:
Mon Oct 20 11:15:26 2014 +0000
Child:
1:36385b59d183
Commit message:
??????1???

Changed in this revision

PID.lib Show annotated file Show diff for this revision Revisions of this file
QEI.lib Show annotated file Show diff for this revision Revisions of this file
USBHost.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
setting.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PID.lib	Mon Oct 20 11:15:26 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/aberk/code/PID/#6e12a3e5af19
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QEI.lib	Mon Oct 20 11:15:26 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/aberk/code/QEI/#5c2ad81551aa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost.lib	Mon Oct 20 11:15:26 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/USBHost/#45dcbf2ba11d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Oct 20 11:15:26 2014 +0000
@@ -0,0 +1,463 @@
+//※重要※  日本語コメントアウトはmbedのBeta-japaneseに登録すると使えるようになる(2014年現在)
+//めんどくさいからファイル分割しないよ.熱意がある人はやって頂戴 by小林2014-9-12
+#include "mbed.h"           //updateのマークが出ていてもupdateしないように.なんか仕様が変わってるっぽいからエラー吐くようになる
+#include "QEI.h"
+//#include "USBHostMSD.h"     //updateのマークが出ていてもupdateしないように.なんか仕様が変わってるっぽいからエラー吐くようになる
+#include "PID.h"
+#include "setting.h"
+
+//1回転あたりのパルス
+#define PULSE_PER_REVOLUTION 200
+//PIDのウェイト ミリ秒
+#define PID_RATE 10
+
+/**************************入出力ポート設定**************************/
+DigitalOut led1(LED1);      //mbed上LED出力4つ
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+DigitalIn dip1(p5);         //DIPスイッチの入力4つ
+DigitalIn dip2(p6);
+DigitalIn dip3(p7);
+DigitalIn dip4(p8);
+DigitalIn startsw(p9);      //スタートスイッチ入力
+DigitalOut buzzer(p18);     //電子ブザー用デジタル出力
+AnalogIn volume(p20);       //ポテンショメータ入力(アナログ)
+PwmOut pwm(p25);            //モータへのPWM出力
+
+Serial pc(USBTX, USBRX);    //PCとのシリアル通信設定
+QEI encoder(p30, p29, NC, PULSE_PER_REVOLUTION, QEI::X2_ENCODING);        //QEIの設定.
+Timer timer;                //タイマー
+
+typedef struct{             //時間tとその時のrpmを記録するための構造体
+    float t;
+    float rpm;
+} result;
+
+/**************************プロトタイプ宣言**************************/
+int Init();
+int DipLed();
+int GetDipValue();
+int SW();
+int Buzzer(int buzvar);
+int find_header(FILE *fp, char keyword[]);
+void rm_right_space(char str[]);
+
+/**************************main文**************************/
+int main() {
+    //初期化
+    Buzzer(2);
+    //USBHostMSD msd("usb");
+    LocalFileSystem local("local");
+    Init();             //初期化関数
+    int flag = 0;       //フラグ用変数
+    //float vol = 0;      //ポテンショメータからの入力値を受け取る変数
+    //float rpm = 0;      //rpmを格納するための変数
+    //float t = 0;        //時間計測のための変数
+    //result exp2[(int)(15*1000/PID_RATE+1)] = {};  //モード2用の構造体
+    //result exp3[(int)(15*1000/PID_RATE+1)] = {};  //モード3用の構造体
+    result exp[(int)(15*1000/PID_RATE+1)] = {};
+    //メインループ
+    while(1){
+        Init();
+        for(int i = 0; i <= 15*1000/PID_RATE; i++){
+            exp[i].t = 0;
+            exp[i].rpm = 0;
+        }
+        SW();           //スタートスイッチの入力を待つ
+        flag = GetDipValue();   //DIPスイッチの入力を見る
+        DipLed();               //DIPスイッチのHLでLEDを光らせる
+        Buzzer(1);      //ブザーを鳴らす.
+        switch (flag){      //実験モード切り替えのswitch文.ここにcase0~15を書き足せばモードが追加できる.
+            case 0:     //DIPスイッチの入力なしで何もしない
+                break;
+            case 1:{        //モード1はポテンショメータからの入力で直接PWMのデューティ比を変更する.約1秒ごとにPCに値を出力する.このモードは時間で終了せず永遠に続く.終了するにはmbedのresetボタンを押す.
+                //初期化
+                float vol = 0;      //ポテンショメータからの入力値を受け取る変数
+                float rpm = 0;      //rpmを格納するための変数
+                float t = 0;        //時間計測のための変数
+                int i1 = 0;
+                encoder.reset();
+                timer.reset();
+                timer.start();
+                //ループ(抜け出せない)
+                while(1){
+                    vol = 1 - volume;
+                    pwm = vol;
+                    if(i1 >= 20){
+                        t = timer.read();
+                        rpm = (float)encoder.getPulses() / 2 / PULSE_PER_REVOLUTION * 60 / t * 2;  //減速比2
+                        pc.printf("Duty Ratio = %.3f , %6d RPM\n", vol, (int)rpm);
+                        encoder.reset();
+                        i1 = 0;
+                        timer.reset();
+                    }
+                    wait_ms(50);
+                    i1++;
+                }
+                break;
+            }
+            case 2:{         //モード2はモータの応答を調べる.デューティ比1でモータを回転させ,100msごとの経過時間とRPMをUSBメモリのcsvファイルに出力する.約15秒で終了する.
+                //result exp2[(int)(15*1000/PID_RATE+1)] = {};
+                //初期化
+                exp[0].t = 0;
+                exp[0].rpm = 0;
+                encoder.reset();
+                timer.reset();
+                timer.start();
+                pwm = 1;        //モータ回転開始!!
+                //ループ(約15秒で終了)
+                for(int i = 0; i < 15*1000/PID_RATE; i++){       //10msごとに時間とrpmの取得
+                    wait_ms(PID_RATE);
+                    exp[i+1].t = timer.read();
+                    exp[i+1].rpm = (float)encoder.getPulses() / 2 / PULSE_PER_REVOLUTION * 60 / (exp[i+1].t - exp[i].t) * 2;        //減速比2
+                    encoder.reset();
+                }
+                for(int i = 100; i >= 0; i--){      //ゆるやかに減速
+                    pwm = (float)i / 100;
+                    wait_ms(20);
+                }
+                pwm = 0;                            //回転を止める
+                wait(1);
+                FILE * fp = fopen("/local/exp2.csv","w");
+                if(fp == NULL){     //ファイルオープンエラー
+                    Buzzer(-1);     //エラーコード-1のブザーを鳴らす
+                    break;          //終了
+                }
+                fprintf(fp,"Time , RPM\n");
+                for(int i = 0; i <= 15*1000/PID_RATE; i++){
+                    fprintf(fp,"%f , %f\n", exp[i].t, exp[i].rpm);        //ファイルに実験データの書き込み
+                }
+                fclose(fp);
+                Buzzer(4);          //終了を知らせる
+                break;
+            }
+            case 3:{         //モード3はモータの応答を調べる.PID制御をかけ,経過時間とRPMをUSBメモリのcsvファイルに出力する.約15秒で終了する.
+                //result exp3[(int)(15*1000/PID_RATE+1)] = {};
+                float kp = 0, ki = 0, kd = 0, max_rpm = 0, target_rpm = 0, reduction = 0;
+                //int pulse[15*1000/PID_RATE+2] = {};
+                //int j = 0;
+                //float times = 0;
+                encoder.reset();
+                timer.reset();
+                /*
+                -----PID制御の係数設定ファイルpid.txtの書き方-----
+                #kp
+                1.0
+                
+                #ki
+                1.0
+                
+                #kd
+                0.0
+                
+                #max_rpm
+                10000
+                エンコーダで読めるモータのrpmの最大値.これを超えないように制御を行う.
+                
+                #target_rpm
+                3000
+                http://denki.nara-edu.ac.jp/~yabu/soft/header.htmlを参考にしました
+                */
+                
+                /*FILE *fppid = fopen("/local/pid.txt","r");
+                if(fppid == NULL){
+                    Buzzer(-2);
+                    break;
+                }*/
+                //fscanf(fppid,"%f %f %f %f %f", &kp, &ki, &kd, &max_rpm, &target_rpm);
+                //fclose(fppid);
+                //find_header(fppid,"# kp");       //PID制御用の係数の読み込み
+                //fscanf(fppid,"%f",&kp);
+                //find_header(fppid,"# ki");
+                //fscanf(fppid,"%f",&ki);
+                //find_header(fppid,"# kd");
+                //fscanf(fppid,"%f",&kd);
+                //find_header(fppid,"# max_rpm");
+                //fscanf(fppid,"%f",&max_rpm);
+                //find_header(fppid,"# target_rpm");
+                //fscanf(fppid,"%f",&target_rpm);
+                //fclose(fppid);
+                
+                kp = KP;
+                ki = KI;
+                kd = KD;
+                max_rpm = MAX_RPM;
+                target_rpm = TARGET_RPM;
+                
+                PID pid(kp, ki, kd, PID_RATE);      //PIDの設定
+                pid.setInputLimits(0.0, max_rpm);
+                pid.setOutputLimits(0.0, 1.0);
+                pid.setMode(AUTO_MODE);
+                pid.setSetPoint(target_rpm);
+                
+                exp[0].t = 0;
+                exp[0].rpm = 0;
+                timer.start();
+                for(int i = 0; i < 15*1000/PID_RATE; i++){        //15秒間実行する
+                    exp[i+1].t = timer.read();
+                    exp[i+1].rpm = (float)encoder.getPulses() / 2 / PULSE_PER_REVOLUTION * 60 / (exp[i+1].t - exp[i].t) * 2;
+                    pid.setProcessValue(exp[i+1].rpm);
+                    pwm = pid.compute();
+                    encoder.reset();
+                    //pulse[i+1] = encoder.getPulses() / 2.0;
+                    //pid.setProcessValue((float)(pulse[i+1] - pulse[i]) / PULSE_PER_REVOLUTION * 60 / (timer.read() - times) * 2);
+                    //times = timer.read();
+                    //if((i % (int)(100 / PID_RATE) == 0) && (i != 0)){   //100ms毎に時間とrpmを読み込む
+                        //j++;
+                        //exp3[j].t = timer.read();
+                        //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;
+                    //}
+                    wait_ms(PID_RATE);
+                }
+                reduction = pwm.read();
+                for(int i = 0; i <= 100; i++){
+                    pwm = pwm.read() - reduction / 100;
+                    wait_ms(20);
+                }
+                pwm = 0;
+                wait(1);
+                FILE *fp = fopen("/local/exp3.csv","w");
+                if(fp == NULL){     //ファイルオープンエラー
+                    Buzzer(-1);     //エラーコード-1のブザーを鳴らす
+                    break;          //終了
+                }
+                fprintf(fp,"kp = %f  ki = %f  kd = %f\n",kp, ki, kd);
+                fprintf(fp,"Time , RPM\n");
+                for(int i = 0; i <= 15*1000/PID_RATE; i++){
+                    fprintf(fp,"%f , %f\n", exp[i].t, exp[i].rpm);        //ファイルに実験データの書き込み
+                }
+                fclose(fp);
+                Buzzer(5);          //終了を知らせる
+                break;
+            }
+            default:        //0と上記以外でなにもなし
+                break;
+        }
+    }
+}
+
+/**************************関数たち**************************/
+int Init(){         //初期化関数
+    pwm = 0;
+    led1 = 0;
+    led2 = 0;
+    led3 = 0;
+    led4 = 0;
+    buzzer = 0;
+    pc.baud(9600);
+    encoder.reset();
+    timer.reset();
+    pwm.period_us(25);      //40kHz
+    DipLed();
+    return 0;
+}
+
+int DipLed(){       //DIPスイッチの状態によってledを光らせる関数
+    if(dip1 == 1) led1 = 1; else led1 = 0;     //DIPスイッチの1がHならLEDを光らせる,Lなら光らせない
+    if(dip2 == 1) led2 = 1; else led2 = 0;
+    if(dip3 == 1) led3 = 1; else led3 = 0;
+    if(dip4 == 1) led4 = 1; else led4 = 0;
+    return 0;
+}
+
+int GetDipValue(){  //DIPスイッチの値を取得し,値を返す関数
+    int Dip1 = dip1, Dip2 = dip2, Dip3 = dip3, Dip4 = dip4; //DIPスイッチの値を取得
+    if(Dip1 == 0){
+        if(Dip2 == 0){
+            if(Dip3 == 0){
+                if(Dip4 == 0) return 0; else return 1;      //DIPスイッチが0000の場合0を返す.0001なら1
+            }else{
+                if(Dip4 == 0) return 2; else return 3;
+            }
+        }else{
+            if(Dip3 == 0){
+                if(Dip4 == 0) return 4; else return 5;
+            }else{
+                if(Dip4 == 0) return 6; else return 7;
+            }
+        }
+    }else{
+        if(Dip2 == 0){
+            if(Dip3 == 0){
+                if(Dip4 == 0) return 8; else return 9;
+            }else{
+                if(Dip4 == 0) return 10; else return 11;
+            }
+        }else{
+            if(Dip3 == 0){
+                if(Dip4 == 0) return 12; else return 13;
+            }else{
+                if(Dip4 == 0) return 14; else return 15;
+            }
+        }
+    }
+}
+
+int SW(){        //スタートスイッチ用関数,押して離したらスタート
+    int i = 0, j = 0;
+    while(i < 3){       //チャタリング除去,15msにわたってスタートスイッチが押されていればbreak
+        if(startsw == 1) i++;
+        else i = 0;
+        DipLed();
+        wait_ms(5);
+    }
+    while(j < 3){       //上に同じ,スタートスイッチが離されたことを検知
+        if(startsw == 0) j++;
+        else j = 0;
+        DipLed();
+        wait_ms(5);
+    }
+    return 0;
+}
+
+int Buzzer(int buzvar){     //電子ブザーを鳴らす関数
+    switch (buzvar){
+        /**************エラーを知らせるbeep**************/
+        case -3:        //error * - -
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1);
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
+            break;
+        case -2:        //error * - - -
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1);
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
+            break;
+        case -1:        //error * - - - -
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1);
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
+            break;
+        /**************エラーここまで**************/
+        case 0:         //サウンドなし
+            buzzer = 0;
+            break;
+        /**************状態を知らせるためのbeep**************/
+        case 1:         // *(短)
+            buzzer = 1; wait(0.1); buzzer = 0;
+            break;
+        case 2:         // * *
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.05);
+            buzzer = 1; wait(0.1); buzzer = 0;
+            break;
+        case 3:         // -(長)
+            buzzer = 1; wait(0.3); buzzer = 0;
+            break;
+        case 4:         // - -
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.3);
+            buzzer = 1; wait(0.3); buzzer = 0;
+            break;
+        case 5:         // ---
+            buzzer = 1; wait(0.9); buzzer = 0;
+            break;
+        case 6:         // * * *  * * *  * * *  *
+            for(int i = 0; i < 3; i++){
+                for(int j = 0; j < 3; j++){
+                    buzzer = 1; wait(0.1); buzzer = 0; wait(0.1);
+                }
+                wait(0.2);
+            }
+            buzzer = 1; wait(0.1); buzzer = 0;
+            break;
+        case 7:         // **-* ** -* ** *** **** "finish"
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            wait(0.2);
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            wait(0.2);
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            wait(0.2);
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            wait(0.2);
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            wait(0.2);
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.1); buzzer = 0;
+            break;
+        case 8:         // *-*** -*- --* "オワリ"
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1);
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.1);
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            wait(0.2);
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.1); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.1); 
+            wait(0.2);
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.3); buzzer = 0; wait(0.1); 
+            buzzer = 1; wait(0.1); buzzer = 0;
+            break;
+        /**************状態を知らせるためのbeepここまで**************/
+        default:        //no sound
+            buzzer = 0;
+            break;
+    }
+    return 0;
+}
+
+
+int find_header(FILE *fp, char keyword[])
+/*
+    入力     fp        ファイルポインタ
+             keyword   キーワード
+    戻り値             1 : ヘッダを見つけた   0 ヘッダが見つからなかった
+*/
+{
+    char char_buf[256];
+    char keyword_buf[256];
+    char *condition;
+    int  len,i;
+
+    strcpy(keyword_buf,keyword);
+    rm_right_space(keyword_buf);  /* 右側の空白を取り除く */
+
+    rewind(fp);
+    for(;;){
+        condition = fgets(char_buf,BUFSIZ,fp);
+        if ( condition == NULL ) break;
+        rm_right_space(char_buf);       /* 右側の空白と改行記号を取り除く */
+        len = strlen(char_buf);
+        if ( len == 0 ) continue;       /* この文はなくてもよい */
+        for ( i = 0 ; i < len ; i++ ){  /* 左側の空白を取り除く */
+            if ( char_buf[i] != ' ' ) break;
+        }
+        if ( strcmp(&char_buf[i],keyword_buf)==0){
+            return(1);
+            break;
+        }
+    }
+    fprintf(stderr,"cannot find header.  key word : |%s|\n",keyword);
+    Buzzer(-3);
+    return(0);
+}
+
+/* 文字列の右側の空白を削除する    改行記号がある場合はそれも除去する */
+
+void rm_right_space(char str[])
+{
+    int i;
+    
+    i = strlen(str)-1;
+    if ( str[i] == '\n' ) i--;
+
+    while(i>=0){
+        if ( str[i] != ' ')  break;
+        i--;
+    }
+    str[i+1] = '\0';
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Oct 20 11:15:26 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/5e5da4a5990b
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setting.h	Mon Oct 20 11:15:26 2014 +0000
@@ -0,0 +1,10 @@
+#ifndef _SETTING_H
+#define _SETTING_H
+
+#define KP 0.00135
+#define KI 0.00962
+#define KD 0.0
+#define TARGET_RPM 4000
+#define MAX_RPM 10000
+
+#endif
\ No newline at end of file