Fopicon

modified reactor control try 2

Jul 16th, 2015
226
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 15.96 KB | None | 0 0
  1. os.loadAPI("button")
  2.    
  3. --Based on the PID Controller first posted by Copper280z on Reddit:
  4. --http://www.reddit.com/r/feedthebeast/comments/2pxwzo/big_reactors_like_br_turbines_but_dont_like/
  5. --Heavily Modified by LezChap for use with Multiple Turbines and Turbine Control
  6. --Turbine Graphic Code used from Direwolf20's Reactor Controler (youtube.com/watch?v=l7ZwSFVYITU)
  7. --Button API modified from Direwolf20 (youtube link above)
  8.  
  9. local turbines = {peripheral.find("BigReactors-Turbine")}
  10. local reactor = peripheral.find("BigReactors-Reactor")
  11. local mon = peripheral.find("monitor")
  12. local totalTurbines = #turbines
  13. local capacitors = peripheral.find("tile_blockcapacitorbank_name")
  14.  
  15.      
  16. --Change number below for your setup
  17. local rodsPerTurbine = 5.5  --how much Control Rod needed to produce >2000mb of steam in your reactor, helps prevent reactor from jumping between on/off quickly
  18. local goalRPM = 1804  --all RPM-based settings based on this number
  19. local shutdownPower = 2300000000
  20. --capacitors.getMaxEnergyStored() * totalCapacitors
  21. --make sure this is less then max Capacitor capacity
  22. --Change number below to total capacitors in the multiblock below the computer
  23. local totalCapacitors = 102
  24. --Change side below to input for redstone signal from Power Monitor
  25. --local powerMonitorInput = "front"
  26.    
  27. --Tweak these numbers if needed, as per Copper280z's post on Reddit (linked in header)
  28. local P = .2
  29. local I = .000001
  30. local D = 12
  31.  
  32. --initiating variables
  33. local integral = 0
  34. local derivative = 0
  35.  
  36. local error = 0
  37. local prevError = 0
  38.  
  39. local capInfo = {}
  40. local needEngaged = false
  41. local needShutdown = false
  42. local turbineSpeed = 0
  43.  
  44. local slowdown = {}
  45. for k,v in ipairs(turbines) do
  46.     slowdown[k] = false
  47.     v.setActive(true)
  48.     v.setInductorEngaged(false)
  49.     v.setVentOverflow(true)
  50.     v.setFluidFlowRateMax(0)
  51. end
  52.      
  53. local reactorCooldown = false
  54.  
  55. local prevControlRod = 0
  56. local ControlRod = 0  
  57.  
  58. local CRchange = 0
  59. local newCR = 0
  60. local lastPower = 0
  61.  
  62. reactor.setAllControlRodLevels(100)
  63. reactor.setActive(true)
  64.  
  65. local turbinePage = 0
  66. local lastPage = 1
  67. local pages = math.ceil(totalTurbines / 4)
  68. mon.clear()
  69.  
  70. local turbineSpeed = 0
  71. local countTurbines = 0
  72. local timerCounter = 0
  73.  
  74. function PID()
  75.     turbineSpeed = 0
  76.     local turbineNeedSteam = false
  77.     for k,v in pairs(turbines) do
  78.         local tempSpeed = v.getRotorSpeed()
  79.         turbineSpeed = turbineSpeed + tempSpeed
  80.         --if one turbine is too low, make sure steam is produced
  81.         if tempSpeed < (goalRPM - 6) then
  82.             turbineNeedSteam = true
  83.         end
  84.     end
  85.     turbineSpeed = turbineSpeed / totalTurbines
  86.     error = goalRPM - turbineSpeed
  87.      
  88.     ControlRod = reactor.getControlRodLevel(0)
  89.     local reactorTemp = reactor.getFuelTemperature()
  90.      
  91.     integral = integral + error
  92.      
  93.     derivative = error - prevError
  94.      
  95.     if integral > 1000 then
  96.         integral = 1000
  97.     end
  98.      
  99.     if integral < -1000 then
  100.         integral = -1000
  101.     end
  102.      
  103.     CRchange = P*error + I*integral + D*derivative
  104.      
  105.     prevError = error
  106.      
  107.     newCR = ControlRod - CRchange
  108.      
  109.     --check how many Turbines are using steam, only make enough for that # of Turbines
  110.     countTurbines = 0
  111.     for k,v in ipairs(slowdown) do
  112.         if not v then
  113.             countTurbines = countTurbines + 1
  114.         end
  115.     end
  116.     local maxControlRods = 100-(countTurbines * rodsPerTurbine)
  117.      
  118.       if newCR < maxControlRods then
  119.         newCR = maxControlRods
  120.       end
  121.      
  122.       if newCR > 100 then
  123.         newCR = 100
  124.       end
  125.      
  126.       if turbineNeedSteam then
  127.         newCR = maxControlRods
  128.       end
  129.      
  130.       --prevents fuel waste from too-hot reactors - normally used during turbine Spin-up
  131.       if reactorTemp < 200 and reactorCooldown then
  132.         reactorCooldown = false
  133.       end
  134.         if reactorTemp > 1000 or reactorCooldown then
  135.         newCR = 100
  136.         reactorCooldown = true
  137.       end
  138.      
  139.       reactor.setAllControlRodLevels(newCR)
  140.       --print("Control Rods: "..newCR.." Error: "..error)
  141.       --write("...")
  142.       --write("P: "..P*error)
  143.       --write("...")
  144.       --write("  I: "..I*integral)
  145.       --write("...")
  146.       --print("  D: "..D*derivative)
  147.       --print(newCR)
  148.     end
  149.      
  150.     function doTurbineLogic()
  151.       for k,v in ipairs(turbines) do
  152.         local turbSpeed = v.getRotorSpeed()
  153.         local flowRate = v.getFluidFlowRateMax()
  154.         local maxFlowRate = v.getFluidFlowRateMaxMax()
  155.         local safeShutdown = false
  156.         local tooSlow = false
  157.         local coils = v.getInductorEngaged()
  158.      
  159.         --Failsafes for turbines running too fast at shutdown (shouldn't happen)
  160.         --or running too slow (during spin-up) to make sure coils engage/disengage at optimum range
  161.         if turbSpeed > goalRPM + 50 then
  162.           safeShutdown = false
  163.         elseif turbSpeed < goalRPM - 10 then
  164.           tooSlow = true
  165.         else
  166.           tooSlow = false
  167.           safeShutdown = true
  168.         end
  169.      
  170.         --does the system need power, or have too much?
  171.         if capInfo.currPower < 1900000000 then
  172.           needEngaged = true
  173.           needShutdown = false
  174.         elseif capInfo.currPower > shutdownPower then
  175.             print("CurrPower = ", capInfo.currPower)
  176.             needEngaged = false
  177.             needShutdown = true
  178.         end
  179.      
  180.         --Adjust Steam Usage based on goalRPM (to make sure multiple-turbine setups split steam more evenly)
  181.         if turbSpeed > goalRPM + 5 then
  182.           slowdown[k] = true
  183.         end
  184.         if turbSpeed < goalRPM then
  185.           slowdown[k] = false
  186.         end
  187.      
  188.         --turn coils on/off based on conditions above
  189.         if needEngaged and not tooSlow and not coils then
  190.           v.setInductorEngaged(true)
  191.           print("Engaging Turbines")
  192.         elseif needShutdown and safeShutdown and coils then
  193.           v.setInductorEngaged(false)
  194.           print("Turbines Off")
  195.         elseif tooSlow and coils then
  196.           v.setInductorEngaged(false)
  197.         end
  198.      
  199.         --turn flowrate for steam usage on/off based on goalRPM (helps keep RPMs even in multiple-turbine setups)
  200.         if slowdown[k] then
  201.           if flowRate ~= 0 then
  202.             v.setFluidFlowRateMax(0)
  203.           end
  204.         else
  205.           if flowRate ~= 2000 then
  206.             local setRate = math.min(2000, maxFlowRate)
  207.             v.setFluidFlowRateMax(setRate)
  208.           end
  209.         end
  210.       end
  211.     end
  212.      
  213.     function toint(num)  --removes decimals from strings
  214.       return string.format("%d", tostring(num))
  215.     end  
  216.      
  217.     function commaformat(num)  --puts a comma every 3 digits in a number (From Direwolf20)
  218.       local formatted = num
  219.       local neg = false
  220.       if formatted < 0 then
  221.         formatted = math.abs(formatted)
  222.         neg = true
  223.       end
  224.       while true do
  225.         formatted, k = string.gsub(formatted, "^(%d+)(%d%d%d)", '%1,%2')
  226.         if k == 0 then
  227.           break
  228.         end
  229.       end
  230.       if neg then
  231.         formatted = "-"..formatted
  232.       end
  233.      
  234.       return formatted
  235.     end
  236.        
  237.      
  238.     function displayHeader()
  239.       mon.setTextScale(1)
  240.       mon.setBackgroundColor(colors.black)
  241.       mon.setTextColor(colors.white)
  242.       mon.setCursorPos(1,1)
  243.       mon.clearLine()
  244.      
  245.       --Start First Line of Header
  246.       mon.write("Average RPM: ")
  247.       if error > 4 or error < -4 then
  248.         mon.setTextColor(colors.red)
  249.       else
  250.         mon.setTextColor(colors.green)
  251.       end
  252.       mon.write(toint(turbineSpeed))
  253.       local x, y = mon.getSize()
  254.       local middle = (x/2) + 3
  255.       mon.setTextColor(colors.white)
  256.       mon.setCursorPos(middle, 1)
  257.       mon.write("Control Rods: ")
  258.       if math.ceil(newCR) == 100 then
  259.         mon.setTextColor(colors.green)
  260.       else
  261.         mon.setTextColor(colors.red)
  262.       end
  263.       mon.write(toint(math.ceil(newCR)))
  264.       mon.write("%")
  265.      
  266.       --start second line of Header
  267.       mon.setTextColor(colors.white)
  268.       mon.setCursorPos(1,2)
  269.       mon.clearLine()
  270.       mon.write("Goal RPM: "..goalRPM)
  271.       mon.setCursorPos(middle, 2)
  272.       mon.write("Fuel Usage: ")
  273.       local fuelUse = reactor.getFuelConsumedLastTick()
  274.       fuelUse = math.floor(fuelUse*100)
  275.       fuelUse = fuelUse/100
  276.       if fuelUse > 0 then
  277.         mon.setTextColor(colors.red)
  278.       else
  279.         mon.setTextColor(colors.green)
  280.       end
  281.       mon.write(fuelUse.."mb/t")
  282.      
  283.       --start third line of Header
  284.       mon.setTextColor(colors.white)
  285.       mon.setCursorPos(1,3)
  286.       mon.clearLine()
  287.       mon.write("Turbines Active: ")
  288.       mon.write(toint(countTurbines).." of "..totalTurbines)
  289.       mon.setTextColor(colors.white)
  290.       mon.setCursorPos(middle, 3)
  291.       mon.write("Fuel Level: ")
  292.       local fuelLevel = (reactor.getFuelAmount() / reactor.getFuelAmountMax()) * 100
  293.       if fuelLevel > 99 then
  294.         mon.setTextColor(colors.green)
  295.       else
  296.         mon.setTextColor(colors.red)
  297.       end
  298.       mon.write(fuelLevel.."%")
  299.      
  300.       --start fourth line of Header
  301.       mon.setTextColor(colors.white)
  302.       mon.setCursorPos(1,4)
  303.       mon.clearLine()
  304.       mon.write("Power Produced: ")
  305.       local totalEnergyProduced = 0
  306.       for k,v in ipairs(turbines) do
  307.         totalEnergyProduced = totalEnergyProduced + v.getEnergyProducedLastTick()
  308.       end
  309.       if totalEnergyProduced > (23500 * totalTurbines) then
  310.         mon.setTextColor(colors.green)
  311.       else
  312.         mon.setTextColor(colors.red)
  313.       end
  314.       totalEnergyProduced = toint(totalEnergyProduced)
  315.       totalEnergyProduced = tonumber(totalEnergyProduced)
  316.       mon.write(commaformat(totalEnergyProduced).."RF/t")
  317.       mon.setTextColor(colors.white)
  318.       mon.setCursorPos(middle, 4)
  319.       mon.write("Core Temp: ")
  320.       local coreTemp = reactor.getFuelTemperature()
  321.       if coreTemp > 750 then
  322.         mon.setTextColor(colors.red)
  323.       elseif coreTemp < 250 then
  324.         mon.setTextColor(colors.green)
  325.       else
  326.         mon.setTextColor(colors.orange)
  327.       end
  328.       mon.write(math.floor(coreTemp).."c")
  329.     end
  330.      
  331.     function displayTurbines(page)
  332.       local turbineStartNum = (page * 4) + 1
  333.       local turbinesOnPage = totalTurbines - turbineStartNum + 1
  334.       if turbinesOnPage > 4 then
  335.         turbinesOnPage = 4
  336.       end
  337.       if turbinesOnPage < 1 then
  338.         turbinesOnPage = 1
  339.       end
  340.       local x,y = mon.getSize()
  341.       local xInterval = math.floor(x/(turbinesOnPage + 1))
  342.       local turbinePagePeriph = {}
  343.       local temp = 1
  344.       for i = turbineStartNum, (turbineStartNum + turbinesOnPage - 1) do
  345.         turbinePagePeriph[temp] = turbines[i]
  346.         --print(i.." "..turbines[i])
  347.         temp = temp + 1
  348.       end
  349.       --clear text variables of Turbines
  350.       --mon.setCursorPos(1,5)
  351.       --mon.clearLine()
  352.       mon.setCursorPos(1,18)
  353.       mon.clearLine()
  354.       mon.setCursorPos(1,19)
  355.       mon.clearLine()
  356.      
  357.       for k,v in ipairs(turbinePagePeriph) do
  358.         --display Turbine info on Monitor
  359.         local xCenter = (k * xInterval)
  360.      
  361.         --display Turbine Title (Turbine #)
  362.         local turbineTitle = "Turbine "..tostring(k + turbineStartNum - 1)
  363.         local titleXStart = xCenter - math.floor(string.len(turbineTitle) / 2)
  364.         mon.setTextColor(colors.lightBlue)
  365.         mon.setCursorPos(titleXStart, 5)
  366.         mon.write(turbineTitle)
  367.      
  368.         --display individual turbine RPMs
  369.         local turbineRPM = toint(v.getRotorSpeed())
  370.         local RPMXStart = xCenter - math.floor(string.len(tostring(turbineRPM)) / 2)
  371.         mon.setCursorPos(RPMXStart, 18)
  372.         if goalRPM - turbineRPM > 4 or goalRPM - turbineRPM < -4 then
  373.           mon.setTextColor(colors.red)
  374.         else
  375.           mon.setTextColor(colors.green)
  376.         end
  377.         mon.write(turbineRPM)
  378.      
  379.         --display individual turbine power outputs
  380.         local powerMade = v.getEnergyProducedLastTick()
  381.         if powerMade > 0 then
  382.           mon.setTextColor(colors.green)
  383.         else
  384.           mon.setTextColor(colors.red)
  385.         end
  386.         powerMade = toint(powerMade)
  387.         powerMade = tonumber(powerMade)
  388.         powerMade = commaformat(powerMade).."RF"
  389.         local powerXStart = xCenter - math.floor(string.len(powerMade) / 2)
  390.         mon.setCursorPos(powerXStart, 19)
  391.         mon.write(powerMade)
  392.       end
  393.      
  394.       --display turbine graphics/coils
  395.       for k,v in ipairs(turbinePagePeriph) do
  396.         local xCenter = (k * xInterval)
  397.         local turbineXStart = xCenter - 3
  398.         local coilColor
  399.         if v.getInductorEngaged() then
  400.           coilColor = colors.red
  401.         else
  402.           coilColor = colors.blue
  403.         end
  404.         mon.setBackgroundColor(colors.gray)
  405.         mon.setCursorPos(turbineXStart, 6)
  406.         mon.write("       ")
  407.         for i=7,13 do
  408.           mon.setCursorPos(turbineXStart, i)
  409.           mon.setBackgroundColor(colors.gray)
  410.           mon.write(" ")
  411.           mon.setBackgroundColor(colors.lightGray)
  412.           mon.write(" ")
  413.           if i % 2 == 0 then
  414.             mon.setBackgroundColor(colors.gray)
  415.           end
  416.           mon.write(" ")
  417.           mon.setBackgroundColor(colors.gray)
  418.           mon.write(" ")
  419.           if i % 2 ~= 0 then
  420.             mon.setBackgroundColor(colors.lightGray)
  421.           end
  422.           mon.write(" ")
  423.           mon.setBackgroundColor(colors.lightGray)
  424.           mon.write(" ")
  425.           mon.setBackgroundColor(colors.gray)
  426.           mon.write(" ")
  427.         end
  428.         for i=14,16 do
  429.           mon.setCursorPos(turbineXStart, i)
  430.           mon.setBackgroundColor(colors.gray)
  431.           mon.write(" ")
  432.           mon.setBackgroundColor(colors.lightGray)
  433.           mon.write(" ")
  434.           mon.setBackgroundColor(coilColor)
  435.           mon.write(" ")
  436.           mon.setBackgroundColor(colors.gray)
  437.           mon.write(" ")
  438.           mon.setBackgroundColor(coilColor)
  439.           mon.write(" ")
  440.           mon.setBackgroundColor(colors.lightGray)
  441.           mon.write(" ")
  442.           mon.setBackgroundColor(colors.gray)
  443.           mon.write(" ")
  444.         end
  445.       mon.setCursorPos(turbineXStart, 17)
  446.       mon.write("       ")
  447.       mon.setBackgroundColor(colors.black)
  448.       end
  449.     end
  450.      
  451.     --change Turbine page
  452.     function turnPage(num)
  453.       turbinePage = num
  454.       mon.clear()
  455.       displayScreen()
  456.     end
  457.      
  458.     --show buttons to change pages
  459.     function displayPageButtons(page)
  460.       button.clearTable()
  461.       mon.setTextColor(colors.black)
  462.       if page > 0 then
  463.         local param = page - 1
  464.         button.setTable("<<", turnPage, param, 1, 3, 10, 12)
  465.       end
  466.       if page < (pages-1) then
  467.         local param = page + 1
  468.         button.setTable(">>", turnPage, param, 48, 50, 10, 12)
  469.       end
  470.       button.screen()
  471.     end
  472.      
  473.     function displayScreen()
  474.       displayHeader()
  475.       displayTurbines(turbinePage)
  476.       if pages > 1 and lastPage ~= turbinePage then  --only refresh buttons if page changes
  477.         displayPageButtons(turbinePage)
  478.         lastPage = turbinePage
  479.       end
  480.     end
  481.      
  482.     function pullPowerStatus()
  483.         capInfo.currPower = capacitors.getEnergyStored() * totalCapacitors
  484.         capInfo.maxPower = capacitors.getMaxEnergyStored() * totalCapacitors
  485.         capInfo.powerChange = capInfo.currPower - lastPower
  486.         lastPower = capInfo.currPower
  487.         capInfo.powerDelta = math.ceil(capInfo.powerChange/10)
  488.     end  
  489.      
  490.     displayScreen()
  491.     os.startTimer(.1)
  492.      
  493.     while true do
  494.       local event, param1, param2, param3 = os.pullEvent()
  495.       --import data from Capacitor
  496.       pullPowerStatus()
  497.       --do timed events, restart timer
  498.       if event == "timer" then
  499.         os.startTimer(.1)
  500.         PID()
  501.         doTurbineLogic()
  502.         timerCounter = timerCounter + 1
  503.         --update display every half second
  504.         if timerCounter % 5 == 0 then
  505.           timerCounter = 0
  506.           displayScreen()
  507.         end
  508.       end
  509.      
  510.  
  511.            
  512.       --parse monitor clicks to API
  513.       if event == "monitor_touch" then
  514.         button.checkxy(param2, param3)
  515.       end
  516.     end
Advertisement
Add Comment
Please, Sign In to add comment