0
点赞
收藏
分享

微信扫一扫

位置PID控制

婉殇成长笔记 2022-03-30 阅读 53
数据仓库

代码如下:

FUNCTION_BLOCK Positionc_PID_Cycle_Period_First_shock   (*   位置 PID带第一次冲击  液压滞后处理闭环系统  应用液压伺服控制 *)
(*   U(t)  =   KP(err(t) + Σ(t)*dt/TI+TD*derr(t)/dt )  ;
 err(t) = rin(t)-rout(t)   ;
 Σ(t) = err(t)+ err(t+1)+┈┈   ;
 derr(t) =  err(t)- err(t-1)   ;
 dt  =  采样 循环周期  S   
 Kp为比例带,TI为积分时间,TD为微分时间  ;
   *)
VAR_INPUT
    Set:REAL;   (*  设定值   *)
    Actual:REAL;    (*   实际值   *)
    Cycle_time:REAL;     (*  采样循环周期   单位:S  *)
       Blind_spot:REAL ; (*   死区  默认值转向角度1.0%  *)
    KP :REAL;     (*  比例带  单位:%   *)
    TI :REAL;      (*   积分时间   单位:S   *)
       Integral_limit :REAL;  (* 积分 累计值限幅  Σ(t)   默认绝对值为300  *)
    TD :REAL;      (*   微分时间   单位:S   *)
    OUT_Manual:REAL;  (* 手动 输出值 *)
    OUT_OFFSET:REAL;  (*  输出修正值 *)
    OUT_MIN:REAL;  (*  输出范围最小值  *)
    OUT_MAX:REAL;  (*  输出范围最大值  *)
    Manual:BOOL;  (* 手动 *)
    Reset:BOOL;  (* 复位 *)
END_VAR
VAR_OUTPUT
    OUT:REAL;(*  输出值   *)
    Direction:BOOL;(*  输出方向  *)
END_VAR
VAR
    Accuracy_Revise:  REAL:=0.0 ;   (*  死区   0 预设值  1 预估值  2    *)
    dRho:ARRAY[0..1] OF REAL;  (*  偏差 0 当前偏差 1 上一次偏差   *)
       SumdRho :REAL;  (*  积分累计值  *)
    PID_Y: REAL;        (*PID输出值*)
    Angle_Value_OUT,First_shock_OUT: REAL;        (*限幅后的输出值*)
    Value: ARRAY [0..1] OF REAL;        (*限下幅后的输出值*)
    ID: INT;
    ID0: INT := 0;
    ID1: INT := 1;
    TON_Accuracy_Revise_0,TON_Accuracy_Revise_1 : TON;
    TOF_First_shock :TOF;
    UP_R_First_shock,UP_R0,UP_R1:R_TRIG;  (* 每次运行启动前 初始化 一次  *)
    Min_Accuracy_Revise:  REAL:=0.15 ;   (*  最小死区  编码器1  = 0.17%  *)
    Offset_Accuracy_Revise :REAL:=0.4;  (*  最小死区偏移值   默认0.4% 延时0.6S   *)
    TOF_First_shock_time:TIME:=t#40ms;
END_VAR


(*  ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆    偏差值    ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆    *)
 dRho[1]  := dRho[0] ;     (*   上一次偏差    *)
 dRho[0]  := Set  -   Actual  ;
   (*  当前 偏差 : 目标 - 实际   *)

(*   ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆    第一次冲击     ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆    *)
UP_R_First_shock(CLK:=  NOT  Reset  AND  ABS( Accuracy_Revise )   <  ABS( dRho[0] )  AND NOT  Manual  , Q=> );
TOF_First_shock(IN:=UP_R_First_shock.Q , PT:= TOF_First_shock_time, Q=> , ET=> );
IF TOF_First_shock.Q  THEN
First_shock_OUT :=  (OUT_MAX - OUT_MIN )* 0.85 + OUT_MIN ;
ELSE
First_shock_OUT:=0.0;
END_IF

(*   ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆    定位     ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆    *)
IF  NOT  Reset  AND  ABS( Accuracy_Revise )   <  ABS( dRho[0] )  AND NOT  Manual AND NOT TOF_First_shock.Q  THEN

(*  &&&&&&&&&&&&&&&    积分限幅  300   &&&&&&&&&&&&&&&  *)
IF   SumdRho >Integral_limit   THEN  SumdRho :=Integral_limit ;  END_IF;
IF   SumdRho < -1.0*Integral_limit  THEN  SumdRho := -1.0*Integral_limit ;  END_IF;

(*  积分累计运算    *)
 SumdRho := SumdRho + dRho[0];   (*   累计积分 :积分 当前偏差 +  *)

(*   U(t)  =   KP(err(t) + Σ(t) * dt/TI+TD*derr(t)/dt )    ;
 err(t) = rin(t)-rout(t)   ;
 Σ(t) = err(t)+ err(t+1)+┈┈   ;
 derr(t) =  err(t)- err(t-1)    ;
 dt  =  采样 循环周期  S
 Kp为比例带,TI为积分时间,TD为微分时间  ;
   *)
IF   TI  =0  THEN  TI := 10000.0; END_IF;
IF   Cycle_time  =0  THEN  Cycle_time := 0.02; END_IF;

PID_Y  := KP *( dRho[0]  + SumdRho * Cycle_time / TI      (*  PI  控制  *)
+  TD * (dRho[0] - dRho[1] ) / Cycle_time ) ;
    (*   D 控制  *)

(*    输出限幅   *)
IF  PID_Y > ( OUT_MAX - OUT_MIN ) THEN
Angle_Value_OUT  :=  OUT_MAX - OUT_MIN ; END_IF;   (* 限制输出 上限限幅     *)
IF  PID_Y < (( OUT_MAX - OUT_MIN )  *-1.0 ) THEN
Angle_Value_OUT  := ( OUT_MAX - OUT_MIN ) *-1.0; END_IF;   (*  限制输出下限限幅    *)
IF  PID_Y >=  (( OUT_MAX - OUT_MIN ) *-1.0 )  AND    PID_Y <= ( OUT_MAX - OUT_MIN ) THEN
Angle_Value_OUT  := PID_Y ;
END_IF

ELSE
SumdRho := 0.0;

Angle_Value_OUT  := 0.0;

END_IF;

(*   ◆◆◆◆◆◆ ◆◆◆◆◆◆◆◆◆◆◆     自动回中 方向判断 电流 输出     ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆    *)
ID:=ID0;
IF      Angle_Value_OUT  > 0      THEN
Value[ID]   :=  ABS(Angle_Value_OUT) + OUT_MIN  ;
ELSE  Value[ID]:=0;  END_IF;

ID:=ID1;
IF   Angle_Value_OUT   < 0      THEN
Value[ID]   :=  ABS(Angle_Value_OUT ) + OUT_MIN  ;
ELSE  Value[ID]:=0;  END_IF;

(*   ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆     输出    ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆    *)
   IF  NOT Manual   THEN
      OUT :=  Value[0] + Value[1] + First_shock_OUT  + OUT_OFFSET;
ELSE
      OUT :=   OUT_Manual  + OUT_OFFSET ;
   END_IF;

IF  Value[0] >0 THEN
Direction :=TRUE;
ELSE
Direction :=FALSE;
END_IF

(*   ◆◆◆◆◆◆ ◆◆◆◆◆◆◆◆◆◆◆     死区判断 : 输出电流 接近 电流 最小值  and   连续运行时间大于 0.5S   and    转向 角度小于1 %  =  暂停 转向 1 S 转向      ◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆    *)
TON_Accuracy_Revise_0(IN:=
 ABS(OUT)  <  OUT_MIN +5+OUT_OFFSET  AND
ABS( dRho[0])  < Blind_spot  + Offset_Accuracy_Revise
, PT:=t#0.5S , Q=> , ET=> );

IF  TON_Accuracy_Revise_0.Q  THEN
Accuracy_Revise :=ABS(Blind_spot);
END_IF;

(*   死区初始化  自动修正 死区值  *)
TON_Accuracy_Revise_1(IN:=
 ABS(dRho[0] ) > Min_Accuracy_Revise  AND  Angle_Value_OUT=0 AND
 NOT  Reset   AND NOT  Manual
, PT:=t#0.8S , Q=> , ET=> );
(*   死区初始化  *)
UP_R0(CLK:= ABS(dRho[0] ) > Min_Accuracy_Revise  , Q=> );
UP_R1(CLK:= TON_Accuracy_Revise_1.Q   , Q=> );

IF  UP_R1.Q  THEN
Offset_Accuracy_Revise := 0.4 - 0.25 ;
Accuracy_Revise:=0.0;
END_IF;

IF  ABS( dRho[0] )  =0   OR   Reset OR  UP_R0.Q   OR Manual  THEN
Accuracy_Revise:=0.0;
Offset_Accuracy_Revise := 0.4 ;
END_IF;
 

举报

相关推荐

0 条评论