auto tracking car

Dependencies:   mbed-rtos mbed

Files at this revision

API Documentation at this revision

Comitter:
kosakaLab
Date:
Tue Jun 14 03:12:50 2016 +0000
Commit message:
ver 0.1;

Changed in this revision

controller.cpp Show annotated file Show diff for this revision Revisions of this file
controller.h 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-rtos.lib 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
diff -r 000000000000 -r 2af3980d8cc8 controller.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/controller.cpp	Tue Jun 14 03:12:50 2016 +0000
@@ -0,0 +1,185 @@
+//  controller.cpp: 制御器
+#include "mbed.h"   // mbedマイコンではstdio.hに相当
+//#include "QEI.h"    // エンコーダ用ライブラリを使用
+
+#include "controller.h" //  controller.cpp: モータ制御器(位置制御、電流制御)
+PwmOut pwm0p(p21);   // IN1 of TA7291P for right wheel
+PwmOut pwm0m(p22);   // IN2 of TA7291P for right wheel
+PwmOut pwm1p(p23);   // IN1 of TA7291P for left wheel
+PwmOut pwm1m(p24);   // IN2 of TA7291P for left wheel
+unsigned char   fReverse[2];  // モータ逆回転フラグ:回転方向が順方向のとき0、逆方向のとき1。[0]が現在の値、[1]はその前の値    reverse direction?
+
+Serial pc(USBTX, USBRX);    // PCのモニタ上のtera termに文字を表示する宣言
+
+controller_parameters    K[2];      // 速度制御メインループの定数、変数
+float                    volt[2];   // モータへの入力電圧
+AnalogOut   analog_out(DA_PORT);    // デバッグ用DA(アナログ信号をDA_PORTに出力)
+
+unsigned long _countTS0;   // TS0[s]ごとのカウント数
+float   _time;          // [s], プログラム開始時からの経過時間
+float   debug[20];      // デバッグ用変数
+DigitalOut  led1(LED1); // mbedマイコンのLED1を点灯
+DigitalOut  led2(LED2); // mbedマイコンのLED2を点灯
+DigitalOut  led3(LED3); // mbedマイコンのLED3を点灯
+DigitalOut  led4(LED4); // mbedマイコンのLED4を点灯
+
+
+float data[1000][5];    // PC上のmbed USB ディスクにセーブするデータ   memory to save data offline instead of "online fprintf".
+unsigned short _countTS3=0;
+
+DigitalOut  debug_p26(p26); // p17 for debug
+DigitalOut  debug_p25(p25); // p17 for debug
+
+// PIDゲイン
+float   Kp[2], Ki[2], Kd[2];
+#define vMAX   3.3       // [V], モータ入力電圧の最大値(超えるとこの値に制限する)
+
+void init_parameters(){
+// 制御器の初期値の設定
+//  親関数: main()
+//  子関数: なし
+    // 制御器0(人の距離)のPIDゲイン
+    Kp[0] = 1;
+    Ki[0] = 0;
+    Kd[0] = 0;
+    // 制御器1(人の向き)のPIDゲイン
+    Kp[1] = 1;
+    Ki[1] = 0;
+    Kd[1] = 0;
+
+    K[0].y = K[1].y = 0;        // K[1].yは人の距離[m]、K[1].yは人の向き[deg]
+    K[0].r = 1;                 // [m],   人の距離の目標値
+    K[0].r = 0;                 // [deg], 人の向きの目標値
+    K[0].u = K[1].u =0;         // 制御入力
+    K[0].eI= K[1].eI=0;         // eの積分値
+    K[0].e_old = K[1].e_old =0; // 1サンプル過去の偏差e
+    K[0].eI_old = K[1].eI_old =0; // 1サンプル過去の偏差の積分値eI
+    volt[0] = volt[1] = 0;      // [V], モータ入力電圧
+}
+
+
+void controller(){
+// 速度制御メインループ、サンプル時間TS1秒
+//      親関数: timerTS0()
+//      子関数: PID(), v2Hbridge0()
+    void PID(int i), v2Hbridge(int i);
+    int i, f_aw;
+
+    K[0].y = 1; // [m],   人の距離koko
+    K[1].y = 0; // [deg], 人の向きkoko
+
+    PID(0);    // 人の距離の制御器
+    PID(1);    // 人の向きの制御器
+
+    volt[0] = K[0].u + K[1].u;  // 右車輪のモータへの電圧
+    volt[1] = K[0].u - K[1].u;  // 左車輪のモータへの電圧
+
+    // アンチワインドアップ:制御入力が飽和したとき積分項eIを減衰させる   anti-windup: if u=v_ref is saturated, then reduce eI. 
+    f_aw = 0;
+    for(i=0;i<2;i++){
+        if( volt[i] > vMAX ){  // モータ入力電圧がvMAXを超えたとき
+            volt[i] = vMAX;        // 電圧をvMAXにする
+            f_aw = 1;
+        }else if( volt[i] < -vMAX ){  // モータ入力電圧が-vMAXを超えたとき
+            volt[1] = -vMAX;       // 電圧を-vMAXにする
+            f_aw = 1;
+        }
+    }
+    if( f_aw ){
+        K[0].eI = K[0].eI_old; // 積分しなかったことにする
+        K[1].eI = K[1].eI_old;
+    }
+
+    v2Hbridge(0);     // モータ0への入力電圧をPWMにしてHbridgeに出力 volt. to Hbridge
+    v2Hbridge(1);     // モータ1への入力電圧をPWMにしてHbridgeに出力 volt. to Hbridge
+}
+
+
+void PID(int i){
+//  制御器:偏差eが入力され、制御入力(モータ電圧)uを出力
+//      入力:出力 K[i].y, 目標値 K[i].r, PID制御積分項 K[i].eI, サンプル時間 TS1 [s]
+//      出力:制御入力(モータ電圧) K[i].u [V]
+    float  e, ed;
+
+    e = K[i].r - K[i].y;        // 偏差 e の計算
+
+    K[i].eI = K[i].eI + TS1*e;  // e の積分値の計算
+    K[i].eI_old = K[i].eI;      // eIの1サンプル過去の値を更新
+
+    ed = (e-K[i].e_old)/TS1;    // e の微分値の計算
+    K[i].e_old = e;             // e の1サンプル過去の値を更新
+
+    K[i].u = Kp[i]*e + Ki[i]*K[i].eI + Kd[i]*ed; // PID制御器の出力を計算
+}
+
+void    v2Hbridge(int i){
+// 指令電圧vより、PWM関数pwm_out()のパラメータ(dutyとフラグ)をセット。
+//      親関数: timerTS0()
+//      子関数: なし
+//      入力:電圧指令 p.v [V]
+//      出力:フルブリッジのfwdIN, rvsIN用duty,
+//            デッドタイムフラグfDeadtime, モータ逆回転フラグfReverse[i]
+    float           duty;      // 0-1, PWMデューティ    duty of H bridge
+
+    duty = volt[i]/vMAX;    // 指令電圧p.vの値を最大電圧vMAXで割って-1~1にしてdutyに代入
+    if( duty>=0 ){      // dutyがプラスでモータが順回転のとき
+        if( fReverse[i]==1 ){       // モータが逆回転から順回転に切り替ったとき
+            if( i==0 ){  pwm0p = 0;   pwm0m = 0;    // デッドタイム作成
+            }else{       pwm1p = 0;   pwm1m = 0;
+            }
+            wait(TS1/10);           // make デッドタイム
+        }
+        fReverse[i] = 0;            // 逆回転フラグをオフにする
+        if( i==0 ){    pwm0p = duty;    pwm0m = 0;   // dutyをPWM関数pwm_out()に渡す
+        }else{         pwm1p = duty;    pwm1m = 0;
+        }
+    }else{             // dutyがマイナスでモータが逆回転のとき
+        if( fReverse[i]==0 ){       // モータが順回転から逆回転に切り替ったとき
+            if( i==0 ){  pwm0p = 0;   pwm0m = 0;    // デッドタイム作成
+            }else{       pwm1p = 0;   pwm1m = 0;
+            }
+            wait(TS1/10);           // make デッドタイム
+        }
+        fReverse[i] = 1;            // 逆回転フラグをオンにする
+        if( i==0 ){    pwm0p = 0;    pwm0m = -duty;   // dutyをPWM関数pwm_out()に渡す
+        }else{         pwm1p = 0;    pwm1m = -duty;   // dutyをPWM関数pwm_out()に渡す
+        }
+    }
+}
+
+
+void data2mbedUSB(){    // PC上のmbed USB ディスクにセーブするためのデータをTS3[s]ごとに代入    save data to mbed USB drive 
+    if( _countTS3<1000 ){   // データ数が1,000の5種類のデータをメモリーに貯める
+        data[_countTS3][0]= debug[0];
+        data[_countTS3][1]= debug[1];
+        data[_countTS3][2]= K[0].y;
+        data[_countTS3][3]= K[1].y;
+        data[_countTS3][4]= _countTS0*TS0;
+        _countTS3++;
+    }
+}
+void timerTS0(){    // タイマーtimerTS0()はTS0[s]ごとにコールされる   timer called every TS0[s].
+//  debug_p26 = 1;
+    _countTS0++;    // カウンターに1足す
+    _time += TS0;   // 現在の時間にTS0[s]足す
+
+    controller();   // 制御器
+//  debug_p26 = 0;
+}
+
+void timerTS1(void const *argument){    // タイマーtimerTS1()はTS1[s]ごとにコールされる   
+}
+
+void display2PC(){  //  PCのモニタ上のtera termに諸量を表示 display to tera term on PC
+    pc.printf("%8.1f[s]\t%8.2f[V]\t%8.2f [Hz]\t%8.2f\t%8.2f\r\n",
+        _time, K[0].y, K[1].y, K[0].u, debug[0]);
+//    pc.printf("%8.1f[s]\t%8.5f[V]\t%4d [deg]\t%8.2f\r\n", _time, _u, (int)(_th/(2*PI)*360.0), _r);//debug[0]*3.3/R_SHUNT);  // print to tera term
+}
+void timerTS2(){    // タイマーtimerTS2()はTS2[s]ごとにコールされる   
+}
+void timerTS3(){    // タイマーtimerTS3()はTS3[s]ごとにコールされる   
+    data2mbedUSB();  // PC上のmbed USB ディスクにセーブするためのデータをTS3[s]ごとに代入   data2mbedUSB() is called every TS3[s].
+}
+void timerTS4(){    // タイマーtimerTS4()はTS4[s]ごとにコールされる   
+    display2PC();   //  PCのモニタ上のtera termに文字を表示 display to tera term on PC. display2PC() is called every TS4[s].
+}
diff -r 000000000000 -r 2af3980d8cc8 controller.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/controller.h	Tue Jun 14 03:12:50 2016 +0000
@@ -0,0 +1,46 @@
+#ifndef __controller_h
+#define __controller_h
+
+#define PI 3.14159265358979 // 円周率πの定義
+
+/*********** 使用するポート、サンプル時間、制御ゲインなどの設定 (ここから) ***************/
+    // タイマーのサンプル周期等
+#define TS0     0.002      // [s], timerTS0のサンプル時間(電流制御用)   sampling time (priority highest: Ticker IRQ) of motor current i control PID using timer interrupt
+#define TS1     0.002      // [s], timerTS1のサンプル時間(位置制御用)   sampling time (priority high: RtosTimer) of motor angle th PID using rtos-timer
+#define TS2     0.2        // [s], timerTS2のサンプル時間(不使用) sampling time (priority =main(): precision 4ms) to save data to PC using thread. But, max data length is 1000.
+#define TS3     0.002      // [s], timerTS3のサンプル時間(データセーブ用) sampling time (priority low: precision 4ms)
+#define TS4     0.2        // [s], timerTS4のサンプル時間(モニタ表示用)  sampling time (priority lowest: precision 4ms)  to display data to PC tera term
+#define TMAX    5.0          // [s], プログラム開始から終了までの時間   experiment starts from 0[s] to TMAX[s]
+#define N_DATA  1000        // PC上のmbed USB ディスクにセーブするデータの数
+
+#define DA_PORT p18         // デバッグ用DAポート   analog out (DA) port of mbed
+/*********** 使用するポートやサンプル時間、制御ゲインなどの設定 (ここから) ***************/
+
+    // 制御器 K(s) の定数、変数の宣言
+typedef struct struct_controller_parameters{
+    float  y;          // 出力(制御量)
+    float  r;          // 目標値
+    float  u;          // 制御入力
+    float  eI;         // 偏差eの積分値(積分項)
+    float  e_old;      // 偏差eの1サンプル過去の値
+    float  eI_old;     // 偏差eの積分値の1サンプル過去の値
+}controller_parameters;
+
+    // タイマー宣言
+extern void timerTS0();    // TS0[s]ごとにコールされるタイマー   timer called every TS0[s].
+extern void timerTS1(void const *argument);    // TS1[s]ごとにコールされるタイマー   timer called every TS1[s].
+extern void timerTS2();    // TS2[s]ごとにコールされるタイマー   timer called every TS2[s].
+extern void timerTS3();    // TS3[s]ごとにコールされるタイマー   timer called every TS3[s].
+extern void timerTS4();    // TS4[s]ごとにコールされるタイマー   timer called every TS4[s].
+
+extern void init_parameters();    // モータの機器定数等の設定, 制御器の初期化する関数の宣言
+
+extern unsigned long _countTS0;   // TS0[s]ごとのカウント数
+extern float   _time;          // [s], プログラム開始時からの経過時間
+
+extern controller_parameters    K[2]; // 制御器の定数、変数
+
+extern float data[][5];             // PC上のmbed USB ディスクにセーブするデータ   // memory to save data offline instead of "online fprintf".
+extern unsigned short _countTS3_data;  // data[i][5]のカウンタ
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r 2af3980d8cc8 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Jun 14 03:12:50 2016 +0000
@@ -0,0 +1,106 @@
+//  Auto tracking car
+//      ver. 160610 by Kosaka lab.
+//
+//  main.cpp: 優先度の異なるつぎのタイマー処理を生成。
+//  優先度|    コールされる関数名|  サンプル時間[s]| 割込み方法| 用途
+//  ---------------------------------------------------------
+//  最高  |   timerTS0()| TS0| ハードウェアタイマー | 電流制御
+//  2位  |   timerTS1()| TS1| RTOSタイマー   | 位置制御または速度制御
+//  3位  |   timerTS2()| TS2| RTOSスレッド   | 不使用 (main()と同じ優先度)
+//  4位  |   timerTS3()| TS3| RTOSスレッド   | データセーブ
+//  最低  |   timerTS4()| TS4| RTOSスレッド   | PCモニタ表示
+#include "mbed.h"   // mbedマイコンではstdio.hに相当
+#include "rtos.h"   // リアルタイムOS用
+
+#include "controller.h" // ブラシ付DCモータの位置制御器と電流制御器用
+
+
+Serial pc2(USBTX, USBRX);               // PCのモニタ上のtera termに文字を表示する宣言
+LocalFileSystem local("mbedUSBdrive");  // PCのmbed USB ディスク上にデータをセーブする宣言
+Ticker TickerTimerTS0;          // タイマー割込みを宣言。1ms以下もOK。RTOSよりも優先度が高い
+unsigned char   fTimerTS2ON=0, fTimerTS3ON=0, fTimerTS4ON=0;  // timerTS2, TS3, TS4のスタート・ストップ指定フラグ
+
+void CallTimerTS2(void const *argument) {   // タイマーtimerTS2()をTS2ごとにコール make sampling time TS3 timer (priority 3: precision 4ms)
+    int ms;             // [ms], 処理時間
+    unsigned long c;    // カウンタ
+    while (true) {      // 永遠に繰り返す
+        c = _countTS0;          // timerTS0()によるカウント数cを記憶
+        if( fTimerTS2ON ){  // タイマースタートフラグがオンのとき
+            timerTS2();         // timerTS2()をTS2[s]ごとにコールする is called every TS2[s].
+        }
+        if( (ms=(int)(TS2*1000-(_countTS0-c)*TS0*1000))<=0 ){    ms=1;} // c記憶時点から今まで時間を計算してTS2から引く。それが負なら1msに設定
+        Thread::wait(ms);   // while()内の処理がTS2[s]ごとに実行されるようにms[ms]待つ
+    }
+}
+void CallTimerTS3(void const *argument) {   // タイマーtimerTS3()をTS3ごとにコール make sampling time TS3 timer (priority 3: precision 4ms)
+    int ms;             // [ms], 処理時間
+    unsigned long c;    // カウンタ
+    while (true) {      // 永遠に繰り返す
+        c = _countTS0;          // timerTS0()によるカウント数cを記憶
+        if( fTimerTS3ON ){  // タイマースタートフラグがオンのとき
+            timerTS3();         // timerTS3()をTS3[s]ごとにコールする is called every TS3[s].
+        }
+        if( (ms=(int)(TS3*1000-(_countTS0-c)*TS0*1000))<=0 ){    ms=1;} // c記憶時点から今まで時間を計算してTS3から引く。それが負なら1msに設定
+        Thread::wait(ms);   // while()内の処理がTS3[s]ごとに実行されるようにms[ms]待つ
+    }
+}
+
+void CallTimerTS4(void const *argument) {   // タイマーtimerTS4()をTS4ごとにコール make sampling time TS4 timer (priority 4: precision 4ms)
+    int ms;             // [ms], 処理時間
+    unsigned long c;    // カウンタ
+    while (true) {      // 永遠に繰り返す
+        c = _countTS0;          // timerTS0()によるカウント数cを記憶
+        if( fTimerTS4ON ){  // タイマースタートフラグがオンのとき
+            timerTS4();         // timerTS4()をTS4[s]ごとにコールする is called every TS4[s].
+        }
+        if( (ms=(int)(TS4*1000-(_countTS0-c)*TS0*1000))<=0 ){    ms=1;} // c記憶時点から今まで時間を計算してTS4から引く。それが負なら1msに設定
+        Thread::wait(ms);   // while()内の処理がTS4[s]ごとに実行されるようにms[ms]待つ
+    }
+}
+
+int main(){ // モータ制御プログラム本体:マイコン起動時に最初にコールされる
+    unsigned short  i;
+    FILE *fp = fopen("/mbedUSBdrive/data.csv", "w");    // PC上のmbed USB ディスクにデータをセーブするためにディスクをオープン
+    RtosTimer RtosTimerTS1(timerTS1);                                 // timerTS1のためのRTOSタイマーを宣言
+    Thread ThreadTimerTS3(CallTimerTS3, NULL, osPriorityBelowNormal); // timerTS3のためのRTOSスレッドを宣言
+    Thread ThreadTimerTS4(CallTimerTS4, NULL, osPriorityLow);         // timerTS4のためのRTOSスレッドを宣言
+// Priority of Thread (RtosTimer is osPriorityAboveNormal)
+//  osPriorityIdle          = -3,          ///< priority: idle (lowest)--> then, mbed ERROR!!
+//  osPriorityLow           = -2,          ///< priority: low
+//  osPriorityBelowNormal   = -1,          ///< priority: below normal
+//  osPriorityNormal        =  0,          ///< priority: normal (default)
+//  osPriorityAboveNormal   = +1,          ///< priority: above normal
+//  osPriorityHigh          = +2,          ///< priority: high 
+//  osPriorityRealtime      = +3,          ///< priority: realtime (highest)
+//  osPriorityError         =  0x84        ///< system cannot determine priority or thread has illegal priority
+
+    init_parameters();  // モータの機器定数等の設定, 制御器の初期化
+
+    // シミュレーション開始
+    pc2.printf("Simulation start!!\r\n");   // PCのモニタ上のtera termに文字を表示
+    // PWMとすべてのタイマーをスタートする
+    TickerTimerTS0.attach(&timerTS0, TS0 );         // timerTS0スタート
+    RtosTimerTS1.start((unsigned int)(TS1*1000.));  // timerTS1スタート
+    fTimerTS3ON = 1;                                // timerTS3スタート
+    fTimerTS4ON = 1;                                // timerTS4スタート
+
+    while( (_countTS0*TS0) < TMAX ){    // 現在の時間tを見て、目標速度等を設定し、TMAX[s]に終了
+        Thread::wait(1);    // 1ms待つ(待つ間にtimerTS3とtimerTS4が実行される)
+    }
+    // PWMとすべてのタイマーをストップする
+//  stop_pwm();             // PWMストップ
+    TickerTimerTS0.detach();// timerTS0ストップ
+    RtosTimerTS1.stop();    // timerTS1ストップ
+    fTimerTS3ON=0;          // timerTS3ストップ
+    fTimerTS4ON=0;          // timerTS4ストップ
+
+    // PC上のmbed USB ディスクにデータをセーブする
+    for(i=0;i<N_DATA;i++){
+        fprintf( fp, "%f, %f, %f, %f, %f\r\n", 
+        data[i][0],data[i][1],data[i][2],data[i][3],data[i][4]);    // PCのmbed USB ディスク上にデータをセーブする
+    }
+    fclose( fp );       // PC上のmbed USB ディスクをリリース
+    Thread::wait(100);  // セーブ完了まで待つ
+
+    pc2.printf("Control completed!!\r\n\r\n");  // 制御実験終了をPCモニタ上に表示
+}
diff -r 000000000000 -r 2af3980d8cc8 mbed-rtos.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-rtos.lib	Tue Jun 14 03:12:50 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed-rtos/#4c105b8d7cae
diff -r 000000000000 -r 2af3980d8cc8 mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Jun 14 03:12:50 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/6c34061e7c34
\ No newline at end of file