-
Notifications
You must be signed in to change notification settings - Fork 0
/
lib_pid.ks
98 lines (82 loc) · 3.16 KB
/
lib_pid.ks
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// This file is distributed under the terms of the MIT license, (c) the KSLib team
@LAZYGLOBAL off.
function PID_init {
parameter
Kp, // gain of position
Ki, // gain of integral
Kd, // gain of derivative
cMin, // the bottom limit of the control range (to protect against integral windup)
cMax. // the the upper limit of the control range (to protect against integral windup)
local SeekP is 0. // desired value for P (will get set later).
local P is 0. // phenomenon P being affected.
local I is 0. // crude approximation of Integral of P.
local D is 0. // crude approximation of Derivative of P.
local oldT is -1. // (old time) start value flags the fact that it hasn't been calculated
local oldInput is 0. // previous return value of PID controller.
// Because we don't have proper user structures in kOS (yet?)
// I'll store the PID tracking values in a list like so:
//
local PID_array is list(Kp, Ki, Kd, cMin, cMax, SeekP, P, I, D, oldT, oldInput).
return PID_array.
}.
function PID_seek {
parameter
PID_array, // array built with PID_init.
seekVal, // value we want.
curVal. // value we currently have.
// Using LIST() as a poor-man's struct.
local Kp is PID_array[0].
local Ki is PID_array[1].
local Kd is PID_array[2].
local cMin is PID_array[3].
local cMax is PID_array[4].
local oldS is PID_array[5].
local oldP is PID_array[6].
local oldI is PID_array[7].
local oldD is PID_array[8].
local oldT is PID_array[9]. // Old Time
local oldInput is PID_array[10]. // prev return value, just in case we have to do nothing and return it again.
local P is seekVal - curVal.
local D is oldD. // default if we do no work this time.
local I is oldI. // default if we do no work this time.
local newInput is oldInput. // default if we do no work this time.
local t is time:seconds.
local dT is t - oldT.
if oldT < 0 {
// I have never been called yet - so don't trust any
// of the settings yet.
} else {
if dT > 0 { // Do nothing if no physics tick has passed from prev call to now.
set D to (P - oldP)/dT. // crude fake derivative of P
local onlyPD is Kp*P + Kd*D.
if (oldI > 0 or onlyPD > cMin) and (oldI < 0 or onlyPD < cMax) { // only do the I turm when within the control range
set I to oldI + P*dT. // crude fake integral of P
}.
set newInput to onlyPD + Ki*I.
}.
}.
set newInput to max(cMin,min(cMax,newInput)).
// remember old values for next time.
set PID_array[5] to seekVal.
set PID_array[6] to P.
set PID_array[7] to I.
set PID_array[8] to D.
set PID_array[9] to t.
set PID_array[10] to newInput.
return newInput.
}.
function PID_update {
parameter
PID_array,
Kp, // gain of position
Ki, // gain of integral
Kd, // gain of derivative
cMin, // the bottom limit of the control range (to protect against integral windup)
cMax. // the the upper limit of the control range (to protect against integral windup)
set PID_array[0] to Kp.
set PID_array[1] to Ki.
set PID_array[2] to Kd.
set PID_array[3] to cMin.
set PID_array[4] to cMax.
return PID_array.
}.