BrainStone

Lua PID

Jan 31st, 2016
615
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 3.45 KB | None | 0 0
  1. -- Basic PID-library
  2. -- Version 1.3
  3.  
  4. -- Taken and adapted from
  5. -- https://github.com/OpenPrograms/Kubuxu-Programs/blob/master/pid/pid.lua
  6.  
  7. local function clamp(x, min, max)
  8.   if x > max then
  9.     return max
  10.   elseif x < min then
  11.     return min
  12.   else
  13.     return x
  14.   end
  15. end
  16.  
  17. local seconds = nil
  18. do
  19.   local done, socket = pcall(require, "socket")
  20.   if not done then
  21.     socket = nil
  22.   end
  23.   local done, computer = pcall(require, "computer")
  24.   if not done then
  25.     computer = nil
  26.   end
  27.   seconds = (socket and socket.gettime) or (computer and computer.uptime) or os.time
  28. end
  29.  
  30. -- Creates a new PID controller.
  31. -- Passing table as an argument will make it used as an object base.
  32. -- It allows for convinient saving and loading of adjusted PID controller.
  33. function new(save)
  34.   assert(save == nil or type(save) == "table", "If save is specified the it has to be table.")
  35.  
  36.   -- all values of the PID controller
  37.   -- values with '_' at beginning are considered private and should not be changed.
  38.   local pid = {
  39.     kp = 1,
  40.     ki = 1,
  41.     kd = 1,
  42.     input = nil,
  43.     target = nil,
  44.     output = nil,
  45.    
  46.     minout = -math.huge,
  47.     maxout = math.huge,
  48.    
  49.     _lasttime = nil,
  50.     _lastinput = nil,
  51.     _Iterm = 0
  52.   }
  53.  
  54.   -- Copy all values from save to pid
  55.   if save then
  56.     for key, value in pairs(save) do
  57.       if pid[key] then
  58.         pid[key] = value
  59.       end
  60.     end
  61.   end
  62.  
  63.   -- Exports calibration variables and targeted value.
  64.   function pid:save()
  65.     return {kp = self.kp, ki = self.ki, kd = self.kd, target = self.target, minout = self.minout, maxout = self.maxout}
  66.   end
  67.  
  68.   -- This is main method of PID controller.
  69.   -- After creation of controller you have to set 'target' value in controller table
  70.   -- then in loop you should regularly update 'input' value in controller table,
  71.   -- call c:compute() and set 'output' value to the execution system.
  72.   -- c.minout = 0
  73.   -- c.maxout = 100
  74.   -- while true do
  75.   --   c.input = getCurrentEnergyLevel()
  76.   --   c:compute()
  77.   --   reactorcontrol:setAllControlRods(100 - c.output) -- PID expects the increase of output value will cause increase of input
  78.   --   sleep(0.5)
  79.   -- end
  80.   -- You can limit output range by specifying 'minout' and 'maxout' values in controller table.
  81.   -- By passing 'true' to the 'compute' function you will cause controller to not to take any actions but only
  82.   -- refresh internal variables. It is most useful if PID controller was disconnected from the system.
  83.   function pid:compute(waspaused)
  84.     assert(self.input and self.target, "You have to sepecify current input and target before running compute()")
  85.    
  86.     -- reset values if PID was paused for prolonegd period of time
  87.     if waspaused or self._lasttime == nil or self._lastinput == nil then
  88.       self._lasttime = seconds()
  89.       self._lastinput = self.input
  90.       self._Iterm = self.output or 0
  91.       return
  92.     end
  93.    
  94.     local err = self.target - self.input
  95.     local dtime = seconds() - self._lasttime
  96.    
  97.     if dtime == 0 then
  98.       return
  99.     end
  100.  
  101.     self._Iterm = self._Iterm + self.ki * err * dtime
  102.     self._Iterm = clamp(self._Iterm, self.minout, self.maxout)
  103.    
  104.     local dinput = (self.input - self._lastinput) / dtime
  105.    
  106.     self.output = self.kp * err + self._Iterm - self.kd * dinput
  107.     self.output = clamp(self.output, self.minout, self.maxout)
  108.    
  109.     self._lasttime = seconds()
  110.     self._lastinput = self.input
  111.   end
  112.  
  113.   return pid
  114. end
Advertisement
Add Comment
Please, Sign In to add comment