added seperate input and working on http / sockets
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
--:Minify:--
|
||||
|
||||
local pid = {}
|
||||
pid.__index = pid
|
||||
|
||||
local function clamp(value, minimum, maximum)
|
||||
if minimum and value < minimum then
|
||||
return minimum
|
||||
end
|
||||
if maximum and value > maximum then
|
||||
return maximum
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
local function assertNumber(value, name)
|
||||
if type(value) ~= "number" then
|
||||
error("pid: " .. name .. " must be a number")
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
function pid.new(kp, ki, kd, options)
|
||||
assertNumber(kp, "kp")
|
||||
assertNumber(ki, "ki")
|
||||
assertNumber(kd, "kd")
|
||||
|
||||
options = options or {}
|
||||
|
||||
local controller = setmetatable({
|
||||
kp = kp,
|
||||
ki = ki,
|
||||
kd = kd,
|
||||
setpoint = options.setpoint or 0,
|
||||
outputMin = options.outputMin,
|
||||
outputMax = options.outputMax,
|
||||
integralMin = options.integralMin,
|
||||
integralMax = options.integralMax,
|
||||
lastError = 0,
|
||||
integral = 0,
|
||||
lastMeasurement = nil,
|
||||
lastOutput = 0,
|
||||
lastTime = nil,
|
||||
}, pid)
|
||||
|
||||
return controller
|
||||
end
|
||||
|
||||
function pid:reset()
|
||||
self.lastError = 0
|
||||
self.integral = 0
|
||||
self.lastMeasurement = nil
|
||||
self.lastOutput = 0
|
||||
self.lastTime = nil
|
||||
end
|
||||
|
||||
function pid:setSetpoint(setpoint)
|
||||
assertNumber(setpoint, "setpoint")
|
||||
self.setpoint = setpoint
|
||||
end
|
||||
|
||||
function pid:setCoefficients(kp, ki, kd)
|
||||
assertNumber(kp, "kp")
|
||||
assertNumber(ki, "ki")
|
||||
assertNumber(kd, "kd")
|
||||
self.kp = kp
|
||||
self.ki = ki
|
||||
self.kd = kd
|
||||
end
|
||||
|
||||
function pid:setOutputLimits(minimum, maximum)
|
||||
if minimum ~= nil then assertNumber(minimum, "outputMin") end
|
||||
if maximum ~= nil then assertNumber(maximum, "outputMax") end
|
||||
if minimum and maximum and minimum > maximum then
|
||||
error("pid: outputMin must be <= outputMax")
|
||||
end
|
||||
self.outputMin = minimum
|
||||
self.outputMax = maximum
|
||||
end
|
||||
|
||||
function pid:setIntegralLimits(minimum, maximum)
|
||||
if minimum ~= nil then assertNumber(minimum, "integralMin") end
|
||||
if maximum ~= nil then assertNumber(maximum, "integralMax") end
|
||||
if minimum and maximum and minimum > maximum then
|
||||
error("pid: integralMin must be <= integralMax")
|
||||
end
|
||||
self.integralMin = minimum
|
||||
self.integralMax = maximum
|
||||
end
|
||||
|
||||
function pid:update(measurement, dt)
|
||||
assertNumber(measurement, "measurement")
|
||||
assertNumber(dt, "dt")
|
||||
if dt <= 0 then
|
||||
error("pid: dt must be greater than zero")
|
||||
end
|
||||
|
||||
local errorValue = self.setpoint - measurement
|
||||
self.integral = clamp(self.integral + errorValue * dt, self.integralMin, self.integralMax)
|
||||
local derivative = 0
|
||||
if self.lastTime ~= nil then
|
||||
derivative = (errorValue - self.lastError) / dt
|
||||
end
|
||||
|
||||
local output = self.kp * errorValue + self.ki * self.integral + self.kd * derivative
|
||||
output = clamp(output, self.outputMin, self.outputMax)
|
||||
|
||||
self.lastError = errorValue
|
||||
self.lastMeasurement = measurement
|
||||
self.lastOutput = output
|
||||
self.lastTime = (self.lastTime or 0) + dt
|
||||
|
||||
return output
|
||||
end
|
||||
|
||||
function pid:compute(measurement, dt)
|
||||
return self:update(measurement, dt)
|
||||
end
|
||||
|
||||
function pid:getState()
|
||||
return {
|
||||
setpoint = self.setpoint,
|
||||
kp = self.kp,
|
||||
ki = self.ki,
|
||||
kd = self.kd,
|
||||
integral = self.integral,
|
||||
lastError = self.lastError,
|
||||
lastOutput = self.lastOutput,
|
||||
}
|
||||
end
|
||||
|
||||
function pid:resetIntegral()
|
||||
self.integral = 0
|
||||
end
|
||||
|
||||
return pid
|
||||
Reference in New Issue
Block a user