Guest User

control

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