UVW 3 phases Brushless DC motor control
Dependencies: QEI mbed-rtos mbed
Fork of DCmotor by
Diff: controller.cpp
- Revision:
- 13:791e20f1af43
- Parent:
- 12:a4b17bb682eb
--- a/controller.cpp Fri Dec 21 22:06:56 2012 +0000 +++ b/controller.cpp Sun Mar 03 09:09:34 2013 +0000 @@ -1,5 +1,5 @@ -// BLDCmotor.cpp: 各種3相同期モータに対するセンサあり運転のシミュレーション -// Kosaka Lab. 121215 +// controller.cpp: 各種3相同期モータに対するセンサあり運転のシミュレーション +// Kosaka Lab. 130214 #include "mbed.h" #include "QEI.h" @@ -31,25 +31,9 @@ /*********** User setting for control parameters (end) ***************/ AnalogOut analog_out(DA_PORT); -AnalogIn VshuntR_Uplus(p19); // *3.3 [V], Volt of shunt R_SHUNT[Ohm]. The motor current i = v_shunt_r/R_SHUNT [A] -AnalogIn VshuntR_Uminus(p20); // *3.3 [V], Volt of shunt R_SHUNT[Ohm]. The motor current i = v_shunt_r/R_SHUNT [A] -AnalogIn VshuntR_Vplus(p16); // *3.3 [V], Volt of shunt R_SHUNT[Ohm]. The motor current i = v_shunt_r/R_SHUNT [A] -AnalogIn VshuntR_Vminus(p17); // *3.3 [V], Volt of shunt R_SHUNT[Ohm]. The motor current i = v_shunt_r/R_SHUNT [A] unsigned long _count; // sampling number float _time; // time[s] -float _r; // reference signal -float _th=0; // [rad], motor angle, control output of angle controller -float _i=0; // [A], motor current, control output of current controller -float _e=0; // e=r-y for PID controller -float _eI=0; // integral of e for PID controller -float _iref; // reference current iref [A], output of angle th_contorller -float _u; // control input[V], motor input volt. -float _ei=0; // e=r-y for current PID controller -float _eiI=0; // integral of e for current PID controller -unsigned char _f_u_plus=1;// sign(u) -unsigned char _f_umax=0;// flag showing u is max or not -unsigned char _f_imax=0;// flag showing i is max or not float debug[20]; // for debug float disp[10]; // for printf to avoid interrupted by quicker process DigitalOut led1(LED1); @@ -57,15 +41,14 @@ DigitalOut led3(LED3); DigitalOut led4(LED4); -#ifdef GOOD_DATA float data[1000][5]; // memory to save data offline instead of "online fprintf". unsigned int count3; // unsigned int count2=(int)(TS2/TS0); // unsigned short _count_data=0; -#endif -DigitalOut debug_p26(p26); // p17 for debug -DigitalOut debug_p25(p25); // p17 for debug -DigitalOut debug_p24(p24); // p17 for debug + +//DigitalOut debug_p26(p26); // p17 for debug +//DigitalOut debug_p25(p25); // p17 for debug +//DigitalOut debug_p24(p24); // p17 for debug //AnalogIn VCC(p19); // *3.3 [V], Volt of VCC for motor //AnalogIn VCC2(p20); // *3.3 [V], Volt of (VCC-R i), R=2.5[Ohm]. R is for preventing too much i when deadtime is failed. @@ -101,13 +84,12 @@ p.R = 0.143; // Ω p.phi = 0.176; // V s p.Jm = 0.00018; // Nms^2 + p.p = 2; // 極対数 #endif - p.th[0] = 0; - p.th[1] = 0; + p.th[0] = p.th[1] = 0; p.w = 0; p.iab[0] =0; p.iab[1] = 0; // iab = [iα;iβ]; p.vab[0] =0; p.vab[1] = 0; // vab = [vα;vβ]; - p.p = 2; // 極対数 // UVW座標からαβ座標への変換行列Cuvwの設定 r2 = sqrt(2.);//1.414213562373095;//2^(1/2); r3 = sqrt(3.);//1.732050807568877;//3^(1/2); @@ -121,22 +103,23 @@ // 制御器の初期化 vl.iq_ref=0; // q軸電流指令[A] vl.w_lpf = 0; // 検出した速度[rad/s] - vl.eI_w = 0; // 速度制御用偏差の積分値(積分項) - il.eI_idq[0] = 0; // 電流制御用偏差の積分値(積分項) - il.eI_idq[1] = 0; // 電流制御用偏差の積分値(積分項) + vl.eI = 0; // 速度制御用偏差の積分値(積分項) + il.eI_idq[0] = 0; // d軸電流制御用偏差の積分値(積分項) + il.eI_idq[1] = 0; // q軸電流制御用偏差の積分値(積分項) + il.e_old[0] = 0; // d軸電流制御用偏差の1サンプル過去の値 + il.e_old[1] = 0; // q軸電流制御用偏差の1サンプル過去の値 +#ifndef SIMULATION + encoder.reset(); // set encoder counter zero + p.th[0] = p.th[1] = (float)encoder.getPulses()/(float)N_ENC*2.0*PI; // get angle [rad] from encoder +#endif } void idq_control(float idq_act[2]){ // dq座標電流PID制御器(電流マイナーループのフィードバック制御) -// 入力:指令dq座標電流 idq_ref [A], 実dq座標電流 idq_act [A], PI制御積分項 eI, サンプル時間 ts [s] -// 出力:αβ軸電圧指令 vdq_ref [A] +// 入力:指令dq座標電流 idq_ref [A], 実dq座標電流 idq_act [A], PI制御積分項 eI, サンプル時間 TS0 [s] +// 出力:dq軸電圧指令 vdq_ref [A] // [vdq_ref,eI_idq] = idq_control(idq_ref,idq_act,eI_idq,ts); - float Kp_d, Kp_q, Ki_d, Ki_q, e[2]; - // 電流制御ゲイン - Kp_d = iKPd; // P gain (d-axis) - Ki_d = iKId; // I gain (d-axis) - Kp_q = iKPq; // P gain (q-axis) - Ki_q = iKIq; // I gain (q-axis) + float e[2], ed[2]; // dq電流偏差の計算 e[0] = il.idq_ref[0] - idq_act[0]; @@ -146,23 +129,24 @@ il.eI_idq[0] = il.eI_idq[0] + TS0*e[0]; il.eI_idq[1] = il.eI_idq[1] + TS0*e[1]; - // PI制御 + + // dq電流偏差の微分値の計算 + ed[0] = (e[0]-il.e_old[0])/TS0; + ed[1] = (e[1]-il.e_old[1])/TS0; + il.e_old[0] = e[0]; // 電流偏差の1サンプル過去の値を更新 + il.e_old[1] = e[1]; // 電流偏差の1サンプル過去の値を更新 + + // PID制御 // vdq_ref = [Kp_d 0;0 Kp_q]*e + [Ki_d 0;0 Ki_q]*eI; - il.vdq_ref[0] = Kp_d*e[0] + Ki_d*il.eI_idq[0]; - il.vdq_ref[1] = Kp_q*e[1] + Ki_q*il.eI_idq[1]; - -// koko anti-windup + il.vdq_ref[0] = iKPd*e[0] + iKId*il.eI_idq[0] + iKDd*ed[0]; + il.vdq_ref[1] = iKPq*e[1] + iKIq*il.eI_idq[1] + iKDq*ed[0]; } void current_loop(){ // 電流制御マイナーループ - float th, c, s, Cdq[2][2], iu, iv, iab[2], idq_act[2], vab_ref[2],tmp; + float th, c, s, Cdq[2][2], iu, iv, iab[2], idq_act[2], vab_ref[2], tmp, prev[2]; if( f_find_origin==1 ){ th = 0; }else{ - // 位置θをセンサで検出 -#ifndef SIMULATION - p.th[0] = (float)encoder.getPulses()/(float)N_ENC*2.0*PI; // get angle [rad] from encoder -#endif th = p.th[0]; } @@ -177,11 +161,6 @@ Cdq[0][0]= c; Cdq[0][1]=s; //Cdq ={{ c, s} Cdq[1][0]=-s; Cdq[1][1]=c; // {-s, c]}; - // 電流センサによってiu, iv を検出 -#ifndef SIMULATION - p.iuvw[0] = (VshuntR_Uplus - VshuntR_Uminus) /R_SHUNT; // get iu [A] from shunt resistance; - p.iuvw[1] = (VshuntR_Vplus - VshuntR_Vminus) /R_SHUNT; // get iv [A] from shunt resistance; -#endif iu = p.iuvw[0]; iv = p.iuvw[1]; // iw = -(iu + iv); // iu+iv+iw=0であることを利用してiw を計算 @@ -204,18 +183,30 @@ #ifdef USE_CURRENT_CONTROL idq_control(idq_act); #else - il.vdq_ref[0] = il.idq_ref[0]; - il.vdq_ref[1] = il.idq_ref[1]; + il.vdq_ref[0] = il.idq_ref[0]/iqMAX*vdqMAX; + il.vdq_ref[1] = il.idq_ref[1]/iqMAX*vdqMAX; #endif - // dq軸電圧指令ベクトルの大きさをMAX制限(コンバータ出力電圧値に設定) + // dq軸電圧指令ベクトルの大きさをMAX制限してアンチワインドアップ対策 // if( norm(vdq_ref) > vdqmax ){ vdq_ref= vdqmax/norm(vdq_ref)*vdq_ref} - if( (tmp=il.vdq_ref[0]*il.vdq_ref[0]+il.vdq_ref[1]*il.vdq_ref[1])>SQRvdqMAX ){ - tmp = sqrt2(SQRvdqMAX/tmp); - il.vdq_ref[0] = tmp*il.vdq_ref[0]; //= vdqmax/norm(vdq_ref)*vdq_ref - il.vdq_ref[1] = tmp*il.vdq_ref[1]; -// koko anti-windup + // anti-windup: if u=v_ref is saturated, then reduce eI. + //電圧振幅の2乗 vd^2+vq^2 を計算 + tmp=il.vdq_ref[0]*il.vdq_ref[0]+il.vdq_ref[1]*il.vdq_ref[1]; + if( tmp > SQRvdqMAX ){ // 電圧振幅の2乗がVMAXより大きいとき + prev[0] = il.vdq_ref[0]; // vdを記憶 + prev[1] = il.vdq_ref[1]; // vqを記憶 + tmp = sqrt2(SQRvdqMAX/tmp); // 振幅をVMAXまで小さくする比を求める + il.vdq_ref[0] = tmp*il.vdq_ref[0]; // vdにその比をかける + il.vdq_ref[1] = tmp*il.vdq_ref[1]; // vqにその比をかける + il.eI_idq[0] -= (prev[0]-il.vdq_ref[0])/iKId; // 振幅を小さくした分、 + if( il.eI_idq[0]<0 ){ il.eI_idq[0]=0;} // I項を小さくする + il.eI_idq[1] -= (prev[1]-il.vdq_ref[1])/iKIq; // q軸にも同じ処理 + if( il.eI_idq[1]<0 ){ il.eI_idq[1]=0;} } - +//#define DOUKI +#ifdef DOUKI +il.vdq_ref[0]=0; +il.vdq_ref[1]=vdqMAX; +#endif // dq座標指令電圧 vd_ref, vq_refからiα, iβを計算 // vab_ref = Cdq'*vdq_ref; vab_ref[0] = Cdq[0][0]*il.vdq_ref[0] + Cdq[1][0]*il.vdq_ref[1]; @@ -233,8 +224,6 @@ p.vuvw[2] = -p.vuvw[0] - p.vuvw[1]; // p.vuvw[0] = p.Cuvw[0][0]*vab_ref[0] + p.Cuvw[1][0]*vab_ref[1]; // p.vuvw[2] = p.Cuvw[0][2]*vab_ref[0] + p.Cuvw[1][2]*vab_ref[1]; - - p.th[1] = p.th[0]; // thを更新 } @@ -242,21 +231,20 @@ // 速度制御器:速度偏差が入力され、q軸電流指令を出力。 // 入力:指令速度 w_ref [rad/s], 実速度 w_lpf [rad/s], PI制御積分項 eI, サンプル時間 TS1 [s] // 出力:q軸電流指令 iq_ref [A] -// [iq_ref,eI_w] = vel_control(w_ref,w_lpf,eI_w,ts); - float Kp, Ki, e; - // 速度制御PIDゲイン - Kp = wKp; // 速度制御PIDのPゲイン - Ki = wKi; // 速度制御PIDのIゲイン +// [iq_ref,eI] = vel_control(w_ref,w_lpf,eI,ts); + float e, ed; // 速度偏差の計算 e = vl.w_ref - vl.w_lpf; // 速度偏差の積分値の計算 - vl.eI_w = vl.eI_w + TS1*e; + vl.eI = vl.eI + TS1*e; + + ed = (e-vl.e_old)/TS1; // 速度偏差の微分値の計算 + vl.e_old = e; // 速度偏差の1サンプル過去の値を更新 // PI制御 - vl.iq_ref = Kp*e + Ki*vl.eI_w; -// koko anti-windup + vl.iq_ref = wKp*e + wKi*vl.eI + wKd*ed; // PID制御器の出力を計算 } void velocity_loop(){ // 速度制御メインループ(w_ref&beta_ref to idq_ref) @@ -266,16 +254,19 @@ tmp = p.th[0]-p.th[1]; while( tmp> PI ){ tmp -= 2*PI;} while( tmp<-PI ){ tmp += 2*PI;} - vl.w_lpf = (1-iLPF)*vl.w_lpf + tmp/TS0 *iLPF; + vl.w_lpf = iLPF*vl.w_lpf + tmp/TS0 *(1-iLPF); // 速度制御:速度偏差が入力され、q軸電流指令を出力。 -// [iq_ref,eI_w] = vel_control(w_ref,w_act,eI_w,ts); +// [iq_ref,eI] = vel_control(w_ref,w_act,eI,ts); vel_control(); // q軸電流指令のMAX制限(異常に大きい指令値を制限する) + // anti-windup: if u=i_ref is saturated, then reduce eI. if( vl.iq_ref > iqMAX ){ + vl.eI -= (vl.iq_ref - iqMAX)/wKi; if( vl.eI<0 ){ vl.eI=0;} vl.iq_ref = iqMAX; }else if( vl.iq_ref < -iqMAX ){ + vl.eI -= (vl.iq_ref + iqMAX)/wKi; if( vl.eI>0 ){ vl.eI=0;} vl.iq_ref = -iqMAX; } @@ -293,12 +284,12 @@ void vuvw2pwm(){ // vu, vv, vwより、UVW相の上アームPWMを発生 float duty_u, duty_v, duty_w; - duty_u = (p.vuvw[0]/vdqMAX+1)*0.5; - duty_v = (p.vuvw[1]/vdqMAX+1)*0.5; - duty_w = (p.vuvw[2]/vdqMAX+1)*0.5; - uvw[0].duty = duty_u; - uvw[1].duty = duty_v; - uvw[2].duty = duty_w; + duty_u = p.vuvw[0]/vdqMAX+0.5; // dutyを計算 + duty_v = p.vuvw[1]/vdqMAX+0.5; // dutyを計算 + duty_w = p.vuvw[2]/vdqMAX+0.5; // dutyを計算 + uvw[0].duty = duty_u; // dutyをPWM発生関数に渡す + uvw[1].duty = duty_v; // dutyをPWM発生関数に渡す + uvw[2].duty = duty_w; // dutyをPWM発生関数に渡す } #ifdef SIMULATION @@ -419,26 +410,38 @@ #endif } void timerTS0(){ // timer called every TS0[s]. - debug_p26 = 1; +// debug_p26 = 1; _count++; _time += TS0; - current_loop(); // 電流制御マイナーループ(idq_ref to vuvw) - vuvw2pwm(); // vuvw to pwm + p.th[1] = p.th[0]; // thを更新 #ifdef SIMULATION // モータシミュレータ sim_motor(); // IPM, dq座標 + #else +//koko p.th[0] = (float)encoder.getPulses()/(float)N_ENC*2.0*PI; // get angle [rad] from encoder + // 位置θをセンサで検出 +#ifdef DOUKI +led1=1; +p.th[0] += 2*PI*TS0 * 1; if(p.th[0]>4*PI){ p.th[0]-=4*PI;} +debug[0]=p.th[0]/PI*180; +analog_out=debug[0]/180*PI/4/PI; +led1=0; +#endif #endif - debug_p26 = 0; + current_loop(); // 電流制御マイナーループ(idq_ref to vuvw) + vuvw2pwm(); // vuvw to pwm +// debug_p26 = 0; } void timerTS1(void const *argument){ - debug_p25 = 1; +// debug_p25 = 1; velocity_loop(); // 速度制御メインループ(w_ref&beta_ref to idq_ref) - debug_p25 = 0; +// debug_p25 = 0; } void display2PC(){ // display to tera term on PC - pc.printf("%8.1f[s]\t%8.5f[V]\t%4d [Hz]\t%d\r\n", _time, il.vdq_ref[0], (int)(vl.w_lpf/(2*PI)+0.5), (int)(vl.w_ref/(2*PI)+0.5)); // print to tera term + pc.printf("%8.1f[s]\t%8.5f[V]\t%8.2f [Hz]\t%8.2f\t%8.2f\r\n", + _time, il.vdq_ref[1], vl.w_lpf/(2*PI), vl.w_ref/(2*PI), debug[0]); // print to tera term // 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(){