disturbance observer

Dependencies:   mbed MATSUbed USBDevice

Revision:
7:49afd76d633d
Parent:
6:238d52235a29
Child:
8:2ae2483893f0
diff -r 238d52235a29 -r 49afd76d633d main.cpp
--- a/main.cpp	Sun Dec 02 18:08:02 2018 +0000
+++ b/main.cpp	Tue Nov 10 08:36:16 2020 +0000
@@ -1,38 +1,394 @@
+/* 
+外乱推定→走行面の検出を行う
+やること
+・100Hzで離散化したプラントの逆モデルの実装
+・推定外乱から磁気吸着力変化の検出
+リビジョン
+mbed 127:25aea2a3f4e3
+*/
+
 #include "mbed.h"
 #include "USBSerial.h"
-#include "MATSUbed.h"
+#include "math.h"
+
+// Board settings
+#define LED1 P0_29
+#define LED2 P0_28
+#define LED3 P0_27
+#define LED4 P0_26
+
+// CANopen settings
+#define RxPDO1 0x220
+#define RxPDO2 0x320
+#define RxPDO3 0x420
+#define Halt 1
+#define QuickStop 2
+#define ShutDown 3
+#define SYNC_Enable 0
+#define SYNC_Disable 1
+#define node 2
+
+// Disturbance Observer settings
+#define tfA 0.9981         
+#define tfB 0.7529          
+#define tfC 0.002457    
+#define tfD 0.000004588
+
+// 定数
+#define Kv 0.092421
+#define Km  0.0092
+#define samplimgrate 0.01
+#define bodylength 550.0
+#define startdetect 10.0
+#define Kn  116
+
+USBSerial pc;           //PCとのシリアル通信
+char Serialdata;
+CANMessage canmsgTx;    //送信データ処理用
+CANMessage canmsgRxR;    //受信データ処理用
+CANMessage canmsgRxL;    //受信データ処理用
+Ticker flipper;         //汎用タイマー
 
-USBSerial pc(0x1f00,0x2012, 0x0001,false);
+DigitalOut ENsig(P0_10);
+BusOut myled(LED1, LED2, LED3,LED4);
+CAN canPort(P0_13, P0_18);  //CAN name(PinName rd, PinName td)
 
-BusOut myled(LED1, LED2, LED3, LED4);
+//グローバル変数
+//char Serialdata;    //シリアル受信データ
+float Current_demand_L=0, Current_demand_R=0, Velocity_actual=0;  //電流入力値,速度出力値
+float Torque_estimate_tf=0;                    //トルク入力推定値
+float Distterbance_estimate_tf=0;              //外乱トルク推定値
+float Velocity_estimate_z1;                 //推定時保持データ
+float Velocity_estimate=0;                  //推定時現在速度
+float Current_estimate_R=0, Current_estimate_L=0;                   //推定時現在電流
+int Velocity_Trend=0, Current_Trend_R=0, Current_Trend_L=0;      //除去するトレンド
+float distance = 0;                         //走行距離[mm]
+float Velocity_meter;                       // 走行速度[mm/s]
+float Distterbance_estimate_tf_abs = 0;      // 外乱推定値nの絶対値
+float Dist_error = 0;
+float baseDist = 0;                         // 判別基準値
+int cnt_ditect = 0;                         // しきい値を超えてからのカウント
+int cnt_find = 0;                            // 非磁性面の検出からのカウント
+int findnonmagnet =0;                       // 非磁性面検出信号
+int cnt_run = 0;                           // 走行時間カウント
+int beforecnt = 0;
+short firstid, secondid;
+short beforeID = 0x4a1;
+bool run_eternal = false;
+int check = 0;
+
+//プロトタイプ宣言
+// CANopen関連
+void NMTPreOpn(void);       //NMT PreOperationalへ移行
+void NMTOpn(void);          //NMT Operationalへ移行
+void CtrlWord(int);         //RxPDO1
+void ModesOfOperation(void);//RxPDO2
+void TgtVelCtrl(int);       //RxPDO3
+void sendCtrlRS(int);       //SDO Reset
+void sendCtrlSD(int);       //SDO Shutdown
+void sendCtrlEN(int);       //SDO Enable
+//-------------------その他--------------------
+void init(void);            //マイコン初期化
+void CANinit(void);         //CANノード初期化
+void SerialRX(void);        //Serial受信処理
+void flip(void);            //タイマー割り込み
+void printPlantData(void);  //速度指令値、出力値をPCに表示
+void EstimateDisterbance(void);//指令値を推定
+void detectNonmagnet(void);
 
-//DigitalIn sw1(ISP0);
-//DigitalIn sw2(ISP1);
-
-InterruptIn USB_ISP_bt(ISP0);
+int main(){
+    init();
+    myled = 0b0101;
+    while(1){
+        if(Serialdata == 's'){
+            run_eternal = false;
+            break;
+        }else if(Serialdata == 'e'){
+            run_eternal = true;
+            break;
+        }
+        myled=~myled;
+        wait(1);
+    }
+    Serialdata = 0;
+    //node初期化
+    CANinit();
+    int count=0;
+    myled=0;
+    while(1){
+        if(!ENsig){
+            myled=count;
+            count++;
+        }
+        else{
+            myled =~ myled;
+        }
+        wait(0.5);
+    }
+}
+//マイコン初期化
+void init(void){
+    //I/O設定
+    ENsig=SYNC_Disable;
+    //CAN設定
+    canPort.frequency(1000000); //Bit Rate:1Mbps
+    //割り込み設定
+    flipper.attach_us(&flip,5000);  //汎用タイマー割り込み周期:5ms(5*10^3 us)
+    pc.attach(SerialRX);        //Serial受信割り込み開始
+}
+//can node初期化
+void CANinit(void){
+    //SDOコマンドで各nodeをリセット
+    for(int nodeID=1;nodeID <= node;nodeID++){
+        sendCtrlRS(nodeID);
+        sendCtrlSD(nodeID);
+        sendCtrlEN(nodeID);
+    }
+    //NMTコマンドで全nodeをオペレーショナルに
+    NMTPreOpn();
+    NMTOpn();
+}
+//Serial受信割り込み処理
+void SerialRX(void){
+    Serialdata = pc.getc();
+    //-------------送信コマンドを選択--------------
+    if(Serialdata == 'q'){
+        //Haltコマンド送信
+        ENsig = SYNC_Disable;
+        CtrlWord(QuickStop);
+        Serialdata = 0;
+    }
+    else if(Serialdata == '1'){
+        Velocity_Trend = 1000;
+        TgtVelCtrl(Velocity_Trend);
+        ENsig = SYNC_Enable;
+        Serialdata = 0;
+    }
+    else if(Serialdata == '2'){
+        Velocity_Trend = 2000;
+        TgtVelCtrl(Velocity_Trend);
+        ENsig = SYNC_Enable;
+        Serialdata = 0;
+    }
+    else if(Serialdata == '3'){
+        Velocity_Trend = 3000;
+        TgtVelCtrl(Velocity_Trend);
+        ENsig = SYNC_Enable;
+        Serialdata = 0;
+    }
+    else if(Serialdata == '4'){
+        Velocity_Trend = 4000;
+        TgtVelCtrl(Velocity_Trend);
+        ENsig = SYNC_Enable;
+        Serialdata = 0;
+    }
+    else if(Serialdata == 'h'){
+        //Haltコマンド送信
+        ENsig = SYNC_Disable;
+        CtrlWord(Halt);
+        Serialdata = 0;
+    }
+    else if(Serialdata == 'm'){
+        ENsig = SYNC_Disable;
+        ModesOfOperation();
+        Serialdata = 0;
+    }
 
-// ISP0ボタンを押すとUSB ISPモードに入る設定
-void enter_USB_ISP(){
-    pc.printf("enter ISP\n");
-    NVIC_SystemReset();
+}
+//汎用タイマー
+void flip(void){
+    short Current_raw_R, Current_raw_L;
+    
+    if (ENsig == SYNC_Enable) { 
+        cnt_run++;
+        if(canPort.read(canmsgRxR)){
+            if(canmsgRxR.id == 0x4a0) {
+                pc.printf("%d\r\n",cnt_run-beforecnt);
+                //pc.printf("%x ",canmsgRxR.id);
+                beforecnt = cnt_run;
+            }
+            /*
+            if(canPort.read(canmsgRxL)){
+                if(canmsgRxL.id == 0x4a1) {
+                    pc.printf("%x\r\n",canmsgRxL.id);
+                }
+            }*/
+            /*
+            Current_raw_L = canmsgRx.data[1]*0x100+canmsgRx.data[0];   //指令値の取得(電流)
+            if (Current_raw_L > 10000) Current_demand_L = ((Current_raw_L - 1) ^ 0xffff) * -1;
+            else Current_demand_L = Current_raw_L;
+            */
+            //if(canPort.read(canmsgRx)){
+                //if(canmsgRx.id == 0x4a1) {
+                //pc.printf("%x\r\n",canmsgRx.id);
+                /*
+                Current_raw_R = canmsgRx.data[1]*0x100+canmsgRx.data[0];   //指令値の取得(電流)
+                if (Current_raw_R > 10000) Current_demand_R = ((Current_raw_R - 1) ^ 0xffff) * -1;
+                else Current_demand_R = Current_raw_R;
+                */
+                //printPlantData();
+                
+                //}
+        }
+    }
+    // 走行2分後に停止
+    if (cnt_run >= 12000 && run_eternal == false) {
+        //Haltコマンド送信
+        ENsig = SYNC_Disable;
+        CtrlWord(QuickStop);
+    }
+    
+    
+    
+}
+//速度出力値、指令値の表示
+void printPlantData(void){
+    Velocity_actual = canmsgRxR.data[5]*0x100+canmsgRxR.data[4];  //出力値の取得(速度)
+    
+    EstimateDisterbance();  //外乱の推定
+    detectNonmagnet();      //非磁性面の判別
+    pc.printf("%f,%f,%f,%f,%f,%f,%d\r\n",Current_demand_L,Current_demand_R,Torque_estimate_tf,Distterbance_estimate_tf,baseDist,Dist_error,findnonmagnet);
+    /*if ( findnonmagnet == 1 && run_eternal == false) {
+        cnt_find++;
+        if (cnt_find >= 200) {
+            //Haltコマンド送信
+            ENsig = SYNC_Disable;
+            CtrlWord(QuickStop);
+        }
+    }*/
+    findnonmagnet = 0;
 }
 
-int main() {
-    USB_ISP_bt.mode(PullUp);
-    USB_ISP_bt.fall(&enter_USB_ISP);
-    
-    myled = 0b0001;
-    
-    while(1){
-        if(myled < 0b1000){
-            wait(0.5);
-            myled = myled << 1;
-        }else{
-            while(myled != 0b0001) {
-                wait(0.5);
-                myled = myled >> 1;
+void EstimateDisterbance(void){
+    //出力値のトレンド除去
+    Velocity_estimate = (Velocity_actual-Velocity_Trend)/Kn;
+    //電流値トレンドの計算
+    Current_Trend_R = int((Current_Trend_R + Current_demand_R)/2);
+    Current_estimate_R = (Current_demand_R-Current_Trend_R)*Km;
+    /*
+    伝達関数
+              (tfAz - tfB)
+        tf = ------------
+             (tfCz - tfD)
+    */
+    Torque_estimate_tf = (tfA*Velocity_estimate - tfB*Velocity_estimate_z1 + tfD*Torque_estimate_tf)/tfC;
+    Velocity_estimate_z1 = Velocity_estimate;
+    Distterbance_estimate_tf = Torque_estimate_tf - Current_estimate_R;
+}
+
+void detectNonmagnet(void) {
+    Velocity_meter = Velocity_actual * Kv;    //回転数から速度に変換[m/s]
+    distance += Velocity_meter * samplimgrate;  //走行距離を計算
+    Distterbance_estimate_tf_abs = fabsf(Distterbance_estimate_tf);
+    if (distance <= bodylength && distance >= startdetect) {
+        check = 0;
+        //外乱推定値の最大値を確認
+        if(Distterbance_estimate_tf_abs > baseDist) baseDist = Distterbance_estimate_tf_abs;
+    } else if (distance > bodylength) {
+        Dist_error = Distterbance_estimate_tf_abs / baseDist;
+        if (Dist_error < 0.3) {
+            check = 1;
+            cnt_ditect++;
+            if(cnt_ditect >= 150) {
+                findnonmagnet = 1;
             }
+        } else {
+            cnt_ditect = 0;
         }
-        pc.printf("hello world \r\n");
+    }
+
+}
+//NMT
+void NMTPreOpn(void){
+    //COB-ID:0 0x01-00-//-//-//-//-//-//
+    canmsgTx.id = 0x0;
+    canmsgTx.len = 2;
+    canmsgTx.data[0] = 0x80;//0x01:enter NMT state "PreOperational"
+    canmsgTx.data[1] = 0x00;//send All nodes
+    canPort.write(canmsgTx);
+    wait(0.2);
+}
+void NMTOpn(void){
+    //COB-ID:0 0x01-00-//-//-//-//-//-//
+    canmsgTx.id = 0x0;
+    canmsgTx.len = 2;
+    canmsgTx.data[0] = 0x01;//0x01:enter NMT state "Operational"
+    canmsgTx.data[1] = 0x00;//send All nodes
+    canPort.write(canmsgTx);
+    wait(0.2);
+}
+//PDO
+void CtrlWord(int type){
+    canmsgTx.id = RxPDO1;
+    canmsgTx.len = 2;       //Data Length
+    if(type==Halt){
+        canmsgTx.data[0] = 0x0F;//data:0x01"0F"
+        canmsgTx.data[1] = 0x01;//data:0x"01"0F
+    }
+    else if(type==QuickStop){
+        canmsgTx.data[0] = 0x0B;//data:0x00"0B"
+        canmsgTx.data[1] = 0x00;//data:0x"00"0B
+    }
+    else if(type==ShutDown){
+        canmsgTx.data[0] = 0x06;//data:0x00"06"
+        canmsgTx.data[1] = 0x00;//data:0x"00"06
     }
+    canPort.write(canmsgTx);//CANでデータ送信
 }
+void ModesOfOperation(void){
+    canmsgTx.id = RxPDO2;
+    canmsgTx.len = 1;       //Data Length
+    canmsgTx.data[0] = 0x03;//data:0x03 = "Profile Velocity Mode"
+    canPort.write(canmsgTx);//CANでデータ送信
+}
+void TgtVelCtrl(int rpm){
+    //pc.printf("%drpm|0x%08x\r\n",rpm,rpm);
+    canmsgTx.id = RxPDO3;
+    canmsgTx.len = 6;       //Data Length
+    //Target Velocity
+    for(char cnt=0;cnt<4;cnt++){
+        canmsgTx.data[cnt] = rpm % 256;
+        rpm = rpm / 256;
+    }
+    //CtrlWord Enable
+    canmsgTx.data[4] = 0x0F;//data:0x00"0F"
+    canmsgTx.data[5] = 0x00;//data:0x"00"0F
+    canPort.write(canmsgTx);//CANでデータ送信
+}
+//SDO
+void sendCtrlRS(int nodeID){
+    canmsgTx.id = 0x600+nodeID;
+    canmsgTx.len = 6;       //Data Length
+    canmsgTx.data[0] = 0x2B;//|0Byte:40|1Byte:2F|2Byte:2B|4Byte:23|other:22|
+    canmsgTx.data[1] = 0x40;//Index LowByte
+    canmsgTx.data[2] = 0x60;//Index HighByte
+    canmsgTx.data[3] = 0x00;//sub-Index
+    canmsgTx.data[4] = 0x80;//data:0x00"80" = "Controlword(Reset)"
+    canmsgTx.data[5] = 0x00;//data:0x"00"80
+    canPort.write(canmsgTx);//CANでデータ送信
+    wait(0.2);
+}
+void sendCtrlSD(int nodeID){
+    canmsgTx.id = 0x600+nodeID;
+    canmsgTx.len = 6;       //Data Length
+    canmsgTx.data[0] = 0x2B;//|0Byte:40|1Byte:2F|2Byte:2B|4Byte:23|other:22|
+    canmsgTx.data[1] = 0x40;//Index LowByte
+    canmsgTx.data[2] = 0x60;//Index HighByte
+    canmsgTx.data[3] = 0x00;//sub-Index
+    canmsgTx.data[4] = 0x06;//data:0x00"06" = "Controlword(Shutdown)"
+    canmsgTx.data[5] = 0x00;//data:0x"00"06
+    canPort.write(canmsgTx);//CANでデータ送信
+    wait(0.2);
+}
+void sendCtrlEN(int nodeID){
+    canmsgTx.id = 0x600+nodeID;
+    canmsgTx.len = 6;       //Data Length
+    canmsgTx.data[0] = 0x2B;//|0Byte:40|1Byte:2F|2Byte:2B|4Byte:23|other:22|
+    canmsgTx.data[1] = 0x40;//Index LowByte
+    canmsgTx.data[2] = 0x60;//Index HighByte
+    canmsgTx.data[3] = 0x00;//sub-Index
+    canmsgTx.data[4] = 0x0F;//data:0x00"0F" = "Controlword(Enable)"
+    canmsgTx.data[5] = 0x00;//data:0x"00"0F
+    canPort.write(canmsgTx);//CANでデータ送信
+    wait(0.2);
+}