Advertisement
Putnam

PID Controller for reactor temp instead of powergen

Oct 17th, 2014 (edited)
1,552
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- keeps reactor working efficiently at all times; increases power load when necessary, goes idle at 90% power until below 10%
  2.  
  3. -- updated to Bigger Reactors; see earlier versions for the big reactors versions (they exist)
  4.  
  5. timer=nil
  6.  
  7. local timeOperationTable={
  8.   __sub=function(a,b)
  9.     if not a or not b then return false end
  10.     if b[2]>a[2] then
  11.           return setmetatable({(a[1]-1)-b[1],(a[2]-b[2])%24},timeOperationTable)
  12.         else
  13.           return setmetatable({a[1]-b[1],a[2]-b[2]},timeOperationTable)
  14.         end
  15.   end,
  16.   __tostring=function(t)
  17.     return t[1]..' in-game days, ' .. math.floor(t[2]) ..' hours'
  18.   end
  19. }
  20.  
  21. local function findPeripherals() --searches around for reactor so the computer doesn't have to be placed in a particular way
  22.   local reactor,terminal,monitor
  23.   for k,v in pairs(peripheral.getNames()) do
  24.     local t = peripheral.getType(v)
  25.     if (t == "BiggerReactors_Reactor") then
  26.       reactor = peripheral.wrap(v)
  27.       print('reactor found!')
  28.     elseif (peripheral.getType(v) == "openperipheral_glassesbridge") and (not terminal) then
  29.       terminal = peripheral.wrap(v)
  30.       print('terminal glasses terminal found!')
  31.     elseif (peripheral.getType(v) == 'monitor') then
  32.       monitor=peripheral.wrap(v)
  33.       local x,y=monitor.getSize()
  34.       monitor.setTextScale(math.min(5,math.max(x/60,0.5)))
  35.       print('monitor found!')
  36.     end
  37.   end
  38.   return reactor, terminal, monitor
  39. end
  40.  
  41.  
  42. local reactor,terminal,monitor=findPeripherals()
  43.  
  44. local controlRodLevel,powerMode,tickCount,showAdvancedSettings=0,50,0,0,false
  45.  
  46. local upTicks=0
  47.  
  48. local integral=0
  49.  
  50. local function powerPerc()
  51.     return reactor.battery().stored()/reactor.battery().capacity()
  52. end
  53.  
  54. local function reactivity()
  55.     return reactor.fuelTank().fuelReactivity()
  56. end
  57.  
  58. tempGuess = 1000
  59.  
  60. tempGuessChange = 2
  61.  
  62. reactivities = {}
  63.  
  64. lastReactivity = 1
  65.  
  66. bestFound = false
  67.  
  68. powerMode = powerPerc() < 0.1
  69.  
  70. local function reactorActivities()
  71.   term.clear()
  72.   tickCount=tickCount+1
  73.   if powerMode and powerPerc()>0.99 then
  74.     powerMode=false
  75.     timeStarted={os.day(),os.time()} --I keep repeating this because not doing it (using a function) makes setmetatable apparently completely and utterly fail to work and gives me a bunch of other stupid crap
  76.     setmetatable(timeStarted,timeOperationTable)
  77.   elseif not powerMode and powerPerc()<0.1 then
  78.     powerMode=true
  79.     timeStarted={os.day(),os.time()}
  80.     setmetatable(timeStarted,timeOperationTable)
  81.   elseif powerPerc() < 0.001 then
  82.     reactor.setActive(true)
  83.     reactor.setAllControlRodLevels(0)
  84.   end
  85.   if powerMode then
  86.     upTicks=upTicks+1
  87.     reactor.setActive(true)
  88.     local temperature = reactor.fuelTemperature()
  89.     oldError=curError or 0
  90.     curError = temperature - tempGuess or 0
  91.     integral=integral+curError or 0
  92.     derivative = tickCount>1 and curError - oldError or 0
  93.     term.setCursorPos(1,1)
  94.     term.write('Error: ' .. curError)
  95.     term.setCursorPos(1,2)
  96.     term.write('Integral: ' .. integral)
  97.     term.setCursorPos(1,3)
  98.     term.write('Derivative: ' .. derivative)
  99.     term.setCursorPos(1,4)
  100.     Kp=Kp or 0.1*interval
  101.     Ki=Ki or 0.001*interval
  102.     Kd=Kd or 0.001*interval
  103.     local deltaControlRodLevel=(Kp*curError)+(Ki*integral)+(Kd*derivative)
  104.     term.write('Control rod level change: ' .. deltaControlRodLevel)
  105.     controlRodLevel = controlRodLevel+deltaControlRodLevel
  106.     if controlRodLevel>100 or controlRodLevel<0 then
  107.      integral=0
  108.     end
  109.     controlRodLevel = controlRodLevel>100 and 100 or controlRodLevel<0 and 0 or controlRodLevel
  110.     term.setCursorPos(1,5)
  111.     term.write('Current control rod level: ' .. controlRodLevel)
  112.         term.setCursorPos(1,6)
  113.         term.write('Uptime: ' .. timeOperationTable.__tostring(setmetatable({os.day(),os.time()},timeOperationTable)-timeStarted)) --wow the normal tostring should really work here
  114.         term.setCursorPos(1,7)
  115.     term.write('Uptime percentage: ' ..(upTicks*100)/tickCount..'%')
  116.     if term.isColor() then
  117.       term.setCursorPos(1,8)
  118.       term.write('Error weight: ' .. Kp)
  119.       term.setCursorPos(1,9)
  120.       term.write('Integral weight: ' .. Ki)
  121.       term.setCursorPos(1,10)
  122.       term.write('Derivative weight: ' .. Kd)
  123.       term.setCursorPos(1,11)
  124.       term.write('Target temp: ' .. tempGuess)
  125.       for i=8,11,1 do
  126.         term.setCursorPos(30,i)
  127.         term.write('+-')
  128.       end
  129.     end
  130.     reactor.setAllControlRodLevels(controlRodLevel)
  131.   else
  132.     term.setCursorPos(1,1)
  133.     term.write("Reactor's nearly full.")
  134.     term.setCursorPos(1,2)
  135.     term.write("Current status: off.")
  136.     reactor.setActive(false)
  137.   end
  138. end
  139.  
  140. local function terminalActivities()
  141.   terminal.clear()
  142.   local fuel = reactor.fuelTank()
  143.   local wastePercent=fuel.waste()/fuel.capacity()
  144.   local fuelPercent=(fuel.waste()+fuel.fuel())/fuel.capacity()
  145.   terminal.addBox(5,5,100,10,0xcc0000,0.8)
  146.   terminal.addBox(5,5,math.floor(powerPerc()),10,0x00cc00,0.8)
  147.   terminal.addBox(105,5,10,100,0xcccccc,0.8)
  148.   terminal.addBox(105,5,10,controlRodLevel,0x303030,0.8)
  149.   terminal.addBox(5,20,100,10,0x303030,0.8)
  150.   terminal.addBox(5,20,math.min(math.floor(100*fuelPercent),100),10,0xcccc00,0.8)
  151.   terminal.addBox(5,20,math.min(math.floor(100*wastePercent),100),10,0x00cccc,0.8)
  152. end
  153.  
  154. local function monitorActivities()
  155.   monitor.clear()
  156.   monitor.setTextColor(colors.white)
  157.   monitor.setCursorPos(1,1)
  158.   monitor.write('Power mode: ')
  159.   if powerMode then
  160.    monitor.setTextColor(colors.green)
  161.    monitor.write('On')
  162.    monitor.setTextColor(colors.white)
  163.    monitor.setCursorPos(1,4)
  164.    monitor.write('Reactor working at ' .. 100-controlRodLevel .. '% capacity.')
  165.    monitor.setCursorPos(1,5)
  166.    monitor.write('Uptime: ' .. timeOperationTable.__tostring(setmetatable({os.day(),os.time()},timeOperationTable)-timeStarted))
  167.   else
  168.    monitor.setTextColor(colors.red)
  169.    monitor.write('Off')
  170.    monitor.setTextColor(colors.white)
  171.    monitor.setCursorPos(1,4)
  172.    monitor.write("Reactor's off.")
  173.    monitor.setCursorPos(1,5)
  174.    monitor.write('Downtime: ' .. timeOperationTable.__tostring(setmetatable({os.day(),os.time()},timeOperationTable)-timeStarted))
  175.   end
  176.   monitor.setCursorPos(1,2)
  177.   monitor.write('Current temperature: ')
  178.   monitor.setTextColor(curError>100 and colors.red or curError>10 and colors.orange or curError>-10 and colors.green or curError>-100 and colors.lightBlue or colors.cyan)
  179.   monitor.write(reactor.fuelTemperature())
  180.   monitor.setCursorPos(1,3)
  181.   monitor.setTextColor(colors.white)
  182.   monitor.write('Current energy storage: ' .. reactor.battery().stored())
  183.   monitor.setCursorPos(1,6)
  184.   monitor.write('Uptime percentage: ' ..(upTicks*100)/tickCount..'%')
  185.   if monitor.isColor() then
  186.     if showAdvancedSettings then
  187.      monitor.setCursorPos(1,7)
  188.          derweight='Derivative weight: ' .. Kd
  189.      monitor.write('Error weight: ' .. Kp)
  190.      monitor.setCursorPos(1,8)
  191.      monitor.write('Integral weight: ' .. Ki)
  192.      monitor.setCursorPos(1,9)
  193.      monitor.write(derweight)
  194.      monitor.setCursorPos(1,10)
  195.      monitor.write("Target temp:" .. tempGuess)
  196.      for i=7,10,1 do
  197.        monitor.setCursorPos(string.len(derweight)+2,i)
  198.        monitor.write('+-')
  199.      end
  200.      monitor.setCursorPos(1,11)--hate hardcoding hate hardcoding
  201.          monitor.setTextColor(colors.yellow)
  202.      monitor.write('Hide advanced settings')
  203.     else
  204.      monitor.setCursorPos(1,7)
  205.      monitor.setTextColor(colors.yellow)
  206.      monitor.write('Show advanced settings')
  207.     end
  208.   end
  209. end
  210.  
  211. function monitorTouch(x,y)
  212.   if showAdvancedSettings then -- all these global variables are going to make me sick
  213.     if x==(string.len(derweight)>23 and string.len(derweight)+3 or string.len(derweight)+2) then
  214.       if y==5 then
  215.         Kp=Kp+0.05
  216.       elseif y==6 then
  217.         Ki=Ki+(0.005*interval)
  218.       elseif y==7 then
  219.         Kd=Kd+0.01
  220.       elseif y==8 then
  221.         tempGuess = tempGuess + 10
  222.       end
  223.     elseif x==((string.len(derweight)>22) and string.len(derweight)+4 or string.len(derweight)+3) then --in case you're wondering, I have no idea either, but it's necessary
  224.       if y==5 then
  225.         Kp=Kp-0.05
  226.       elseif y==6 then
  227.         Ki=Ki-(0.005*interval)
  228.       elseif y==7 then
  229.         Kd=Kd-0.01
  230.       elseif y==8 then
  231.         tempGuess = tempGuess - 10
  232.         elseif y==9 then
  233.           showAdvancedSettings=false
  234.         end
  235.     end
  236.   else
  237.     if y==5 then
  238.       showAdvancedSettings=true
  239.     end
  240.   end
  241. end
  242.  
  243. local args = {...}
  244.  
  245. interval = args[1] or 0.5
  246.  
  247. interval=tonumber(interval)
  248.  
  249. if interval<0.5 then
  250.     interval=0.5
  251. end
  252.  
  253. local timeStarted={os.day(),os.time()}
  254.  
  255. setmetatable(timeStarted,timeOperationTable)
  256.  
  257. while reactor.connected() do
  258.   if not timer then timer=os.startTimer(interval) end
  259.   local event = {os.pullEvent()}
  260.   if event[1]=='timer' and event[2]==timer then
  261.    timer=nil
  262.    pcall(reactorActivities)
  263.    if terminal then
  264.     pcall(terminalActivities)
  265.    end
  266.    if monitor then
  267.     pcall(monitorActivities)
  268.    end
  269.   elseif event[1]=='mouse_click' then
  270.     if event[2]=='1' then
  271.      if event[3]==49 then
  272.       if event[4]==5 then
  273.        Kp=Kp+0.05
  274.       elseif event[4]==6 then
  275.        Ki=Ki+(0.005*interval)
  276.       elseif event[4]==7 then
  277.        Kd=Kd+0.01
  278.       elseif event[4]==8 then
  279.        tempGuess=tempGuess+10
  280.       end
  281.      elseif event[3]==50 then
  282.       if event[4]==5 then
  283.        Kp=Kp-0.05
  284.       elseif event[4]==6 then
  285.        Ki=Ki-(0.005*interval)
  286.       elseif event[4]==7 then
  287.        Kd=Kd-0.01
  288.       elseif event[4]==8 then
  289.         tempGuess=tempGuess-10
  290.       end
  291.      end
  292.     end
  293.   elseif event[1]=='monitor_touch' then
  294.    pcall(monitorTouch,event[3],event[4])
  295.    pcall(monitorActivities)
  296.   end
  297. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement