summaryrefslogblamecommitdiff
path: root/exp/FB_PID.EXP
blob: da3b92c2aa33d7618696b06a1e643c13252c5cb5 (plain) (tree)





































































































                                                                                           
(* @NESTEDCOMMENTS := 'Yes' *)
(* @PATH := '' *)
(* @OBJECTFLAGS := '0, 8' *)
(* @SYMFILEFLAGS := '2048' *)
FUNCTION_BLOCK FB_PID
VAR_INPUT				(* ex.: positioning *)
	IN_xEnable	: BOOL := TRUE;
	IN_xReset	: BOOL;
	IN_rW		: REAL; (* ex -> target position *)
	IN_rX		: REAL; (* ex -> actual position *)

	IN_rKp		: REAL := 1.0;
	IN_rKi		: REAL := 1.0;
	IN_rKd		: REAL := 1.0;

	IN_xLimit	: BOOL := FALSE;
	IN_rLimit 	: REAL := 1024;

	IN_rTa		: REAL; (* sampling rate in s *)
END_VAR
VAR_OUTPUT
	OUT_rY		: REAL;	(* ex. -> set speed *)
END_VAR
VAR
	rESum			: REAL;
	rE_old			: REAL;
	rE				: REAL;
	xWithinLimits	: BOOL;
	rY_tmp			: REAL;
	dwReset: DWORD;
END_VAR

(*

PID CONTROLLER
Author: mo
Date: 2019-02
                              |z
  w      e               y    v
  -->( )--->[controller]---->[system]---->
      ^x                               |
      |                                |
      ----------------------------------

Set up PID using Ziegler-Nichols-Method:

1) Ki = 0, Kd = 0
2) increase Kp until periodic oscillation occurs (and never stops swinging)
3) this value is Kp_crit
4) measured period length is T_crit
5) use this table

   Kp = 0.6 * Kp_crit
   Tn = 0.5 * T_crit
   Tv = 0.12 * T_crit

   -> with  [Ki = Kp / Tn]  and  [Kd = Kp * Tv]:

   Kp = 0.6 * Kp_crit
   Ki = Kp / (0.5 * T_crit)
   Kd = Kp * (0.12 * T_crit)

e.g.
Kp_crit = 25
T_crit = 2s

Kp = 0.6 * 25 = 15
Ki = 15 / (0.5 * 2s) = 15
Kd = 15 * (0.12 * 2s) = 3,6

*)

(* @END_DECLARATION := '0' *)
IF IN_xEnable
	AND NOT IN_xReset
THEN
	rE := IN_rW - IN_rX;

	xWithinLimits := NOT IN_xLimit
		OR (IN_xLimit AND rY_tmp >= -IN_rLimit AND rY_tmp < IN_rLimit);

	IF xWithinLimits THEN
		rESum := rEsum + rE;
	END_IF

	rY_tmp := (IN_rKp*rE) + (IN_rKi*IN_rTa*rEsum) + (IN_rKd*(rE-rE_old)/IN_rTa);
	OUT_rY := rY_tmp;

	IF NOT xWithinLimits THEN
		IF OUT_rY >= 0 THEN OUT_rY := IN_rLimit; ELSE OUT_rY := -IN_rLimit; END_IF
	END_IF

	rE_old := rE;
END_IF

IF IN_xReset THEN
	rESum := 0;
	rE_old := 0;
	dwReset := dwReset + 1;
END_IF
END_FUNCTION_BLOCK
in each repos: see "about"-tab (if existing) for more details / README.
mailto contact at omeckman dot net
all timestamps in UTC (German winter time: UTC+01:00, summer time: UTC+02:00)
dark theme is a modded version of: https://gist.github.com/Yoplitein/f4b671a2ec70c9e743fa