Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- os.loadAPI("button")
- --Based on the PID Controller first posted by Copper280z on Reddit:
- --http://www.reddit.com/r/feedthebeast/comments/2pxwzo/big_reactors_like_br_turbines_but_dont_like/
- --Heavily Modified by LezChap for use with Multiple Turbines and Turbine Control
- --Turbine Graphic Code used from Direwolf20's Reactor Controler (youtube.com/watch?v=l7ZwSFVYITU)
- --Button API modified from Direwolf20 (youtube link above)
- local turbines = {peripheral.find("BigReactors-Turbine")}
- local reactor = peripheral.find("BigReactors-Reactor")
- local mon = peripheral.find("monitor")
- local totalTurbines = #turbines
- --Change number below for your setup
- rednet.open("bottom") --modem connected to Capacitor Relay Computer
- 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
- local goalRPM = 1792 --all RPM-based settings based on this number
- local shutdownPower = 200000000 --make sure this is less then max Capacitor capacity
- --Tweak these numbers if needed, as per Copper280z's post on Reddit (linked in header)
- local P = .4
- local I = .000001
- local D = 12
- --initiating variables
- local integral = 0
- local derivative = 0
- local error = 0
- local prevError = 0
- local table = {}
- local needEngaged = false
- local needShutdown = false
- local turbineSpeed = 0
- local slowdown = {}
- for k,v in ipairs(turbines) do
- slowdown[k] = false
- v.setActive(true)
- v.setInductorEngaged(false)
- v.setVentOverflow(true)
- v.setFluidFlowRateMax(0)
- end
- local reactorCooldown = false
- local prevControlRod = 0
- local ControlRod = 0
- local CRchange = 0
- local newCR = 0
- reactor.setAllControlRodLevels(100)
- reactor.setActive(true)
- local turbinePage = 0
- local lastPage = 1
- local pages = math.ceil(totalTurbines / 4)
- mon.clear()
- local turbineSpeed = 0
- local countTurbines = 0
- local timerCounter = 0
- function PID()
- turbineSpeed = 0
- local turbineNeedSteam = false
- for k,v in pairs(turbines) do
- local tempSpeed = v.getRotorSpeed()
- turbineSpeed = turbineSpeed + tempSpeed
- --if one turbine is too low, make sure steam is produced
- if tempSpeed < (goalRPM - 6) then
- turbineNeedSteam = true
- end
- end
- turbineSpeed = turbineSpeed / totalTurbines
- error = goalRPM - turbineSpeed
- ControlRod = reactor.getControlRodLevel(0)
- local reactorTemp = reactor.getFuelTemperature()
- integral = integral + error
- derivative = error - prevError
- if integral > 1000 then
- integral = 1000
- end
- if integral < -1000 then
- integral = -1000
- end
- CRchange = P*error + I*integral + D*derivative
- prevError = error
- newCR = ControlRod - CRchange
- --check how many Turbines are using steam, only make enough for that # of Turbines
- countTurbines = 0
- for k,v in ipairs(slowdown) do
- if not v then
- countTurbines = countTurbines + 1
- end
- end
- local maxControlRods = 100-(countTurbines * rodsPerTurbine)
- if newCR < maxControlRods then
- newCR = maxControlRods
- end
- if newCR > 100 then
- newCR = 100
- end
- if turbineNeedSteam then
- newCR = maxControlRods
- end
- --prevents fuel waste from too-hot reactors - normally used during turbine Spin-up
- if reactorTemp < 200 and reactorCooldown then
- reactorCooldown = false
- end
- if reactorTemp > 1000 or reactorCooldown then
- newCR = 100
- reactorCooldown = true
- end
- reactor.setAllControlRodLevels(newCR)
- print("Control Rods: "..newCR.." Error: "..error)
- --write("...")
- --write("P: "..P*error)
- --write("...")
- --write(" I: "..I*integral)
- --write("...")
- --print(" D: "..D*derivative)
- --print(newCR)
- end
- function doTurbineLogic()
- for k,v in ipairs(turbines) do
- local turbSpeed = v.getRotorSpeed()
- local flowRate = v.getFluidFlowRateMax()
- local maxFlowRate = v.getFluidFlowRateMaxMax()
- local safeShutdown = false
- local tooSlow = false
- local coils = v.getInductorEngaged()
- --Failsafes for turbines running too fast at shutdown (shouldn't happen)
- --or running too slow (during spin-up) to make sure coils engage/disengage at optimum range
- if turbSpeed > goalRPM + 50 then
- safeShutdown = false
- elseif turbSpeed < goalRPM - 10 then
- tooSlow = true
- else
- tooSlow = false
- safeShutdown = true
- end
- needEngaged = false
- needShutdown = false
- --does the system need power, or have too much?
- if table.monitor and table.currPower < 10000000 then
- needEngaged = true
- needShutdown = false
- elseif not table.montitor and table.currPower > shutdownPower then
- needEngaged = false
- needShutdown = true
- end
- --Adjust Steam Usage based on goalRPM (to make sure multiple-turbine setups split steam more evenly)
- if turbSpeed > goalRPM + 5 then
- slowdown[k] = true
- end
- if turbSpeed < goalRPM then
- slowdown[k] = false
- end
- --turn coils on/off based on conditions above
- if needEngaged and not tooSlow and not coils then
- v.setInductorEngaged(true)
- elseif needShutdown and safeShutdown and coils then
- v.setInductorEngaged(false)
- elseif tooSlow and coils then
- v.setInductorEngaged(false)
- end
- --turn flowrate for steam usage on/off based on goalRPM (helps keep RPMs even in multiple-turbine setups)
- if slowdown[k] then
- if flowRate ~= 0 then
- v.setFluidFlowRateMax(0)
- end
- else
- if flowRate ~= 2000 then
- local setRate = math.min(2000, maxFlowRate)
- v.setFluidFlowRateMax(setRate)
- end
- end
- end
- end
- function toint(num) --removes decimals from strings
- return string.format("%d", tostring(num))
- end
- function commaformat(num) --puts a comma every 3 digits in a number (From Direwolf20)
- local formatted = num
- local neg = false
- if formatted < 0 then
- formatted = math.abs(formatted)
- neg = true
- end
- while true do
- formatted, k = string.gsub(formatted, "^(%d+)(%d%d%d)", '%1,%2')
- if k == 0 then
- break
- end
- end
- if neg then
- formatted = "-"..formatted
- end
- return formatted
- end
- function displayHeader()
- mon.setTextScale(1)
- mon.setBackgroundColor(colors.black)
- mon.setTextColor(colors.white)
- mon.setCursorPos(1,1)
- mon.clearLine()
- --Start First Line of Header
- mon.write("Average RPM: ")
- if error > 4 or error < -4 then
- mon.setTextColor(colors.red)
- else
- mon.setTextColor(colors.green)
- end
- mon.write(toint(turbineSpeed))
- local x, y = mon.getSize()
- local middle = (x/2) + 3
- mon.setTextColor(colors.white)
- mon.setCursorPos(middle, 1)
- mon.write("Control Rods: ")
- if math.ceil(newCR) == 100 then
- mon.setTextColor(colors.green)
- else
- mon.setTextColor(colors.red)
- end
- mon.write(toint(math.ceil(newCR)))
- mon.write("%")
- --start second line of Header
- mon.setTextColor(colors.white)
- mon.setCursorPos(1,2)
- mon.clearLine()
- mon.write("Goal RPM: "..goalRPM)
- mon.setCursorPos(middle, 2)
- mon.write("Fuel Usage: ")
- local fuelUse = reactor.getFuelConsumedLastTick()
- fuelUse = math.floor(fuelUse*100)
- fuelUse = fuelUse/100
- if fuelUse > 0 then
- mon.setTextColor(colors.red)
- else
- mon.setTextColor(colors.green)
- end
- mon.write(fuelUse.."mb/t")
- --start third line of Header
- mon.setTextColor(colors.white)
- mon.setCursorPos(1,3)
- mon.clearLine()
- mon.write("Turbines Active: ")
- mon.write(toint(countTurbines).." of "..totalTurbines)
- mon.setTextColor(colors.white)
- mon.setCursorPos(middle, 3)
- mon.write("Fuel Level: ")
- local fuelLevel = (reactor.getFuelAmount() / reactor.getFuelAmountMax()) * 100
- if fuelLevel > 99 then
- mon.setTextColor(colors.green)
- else
- mon.setTextColor(colors.red)
- end
- mon.write(fuelLevel.."%")
- --start fourth line of Header
- mon.setTextColor(colors.white)
- mon.setCursorPos(1,4)
- mon.clearLine()
- mon.write("Power Produced: ")
- local totalEnergyProduced = 0
- for k,v in ipairs(turbines) do
- totalEnergyProduced = totalEnergyProduced + v.getEnergyProducedLastTick()
- end
- if totalEnergyProduced > (23500 * totalTurbines) then
- mon.setTextColor(colors.green)
- else
- mon.setTextColor(colors.red)
- end
- totalEnergyProduced = toint(totalEnergyProduced)
- totalEnergyProduced = tonumber(totalEnergyProduced)
- mon.write(commaformat(totalEnergyProduced).."RF/t")
- mon.setTextColor(colors.white)
- mon.setCursorPos(middle, 4)
- mon.write("Core Temp: ")
- local coreTemp = reactor.getFuelTemperature()
- if coreTemp > 750 then
- mon.setTextColor(colors.red)
- elseif coreTemp < 250 then
- mon.setTextColor(colors.green)
- else
- mon.setTextColor(colors.orange)
- end
- mon.write(math.floor(coreTemp).."c")
- end
- function displayTurbines(page)
- local turbineStartNum = (page * 4) + 1
- local turbinesOnPage = totalTurbines - turbineStartNum + 1
- if turbinesOnPage > 4 then
- turbinesOnPage = 4
- end
- if turbinesOnPage < 1 then
- turbinesOnPage = 1
- end
- local x,y = mon.getSize()
- local xInterval = math.floor(x/(turbinesOnPage + 1))
- local turbinePagePeriph = {}
- local temp = 1
- for i = turbineStartNum, (turbineStartNum + turbinesOnPage - 1) do
- turbinePagePeriph[temp] = turbines[i]
- --print(i.." "..turbines[i])
- temp = temp + 1
- end
- --clear text variables of Turbines
- --mon.setCursorPos(1,5)
- --mon.clearLine()
- mon.setCursorPos(1,18)
- mon.clearLine()
- mon.setCursorPos(1,19)
- mon.clearLine()
- for k,v in ipairs(turbinePagePeriph) do
- --display Turbine info on Monitor
- local xCenter = (k * xInterval)
- --display Turbine Title (Turbine #)
- local turbineTitle = "Turbine "..tostring(k + turbineStartNum - 1)
- local titleXStart = xCenter - math.floor(string.len(turbineTitle) / 2)
- mon.setTextColor(colors.lightBlue)
- mon.setCursorPos(titleXStart, 5)
- mon.write(turbineTitle)
- --display individual turbine RPMs
- local turbineRPM = toint(v.getRotorSpeed())
- local RPMXStart = xCenter - math.floor(string.len(tostring(turbineRPM)) / 2)
- mon.setCursorPos(RPMXStart, 18)
- if goalRPM - turbineRPM > 4 or goalRPM - turbineRPM < -4 then
- mon.setTextColor(colors.red)
- else
- mon.setTextColor(colors.green)
- end
- mon.write(turbineRPM)
- --display individual turbine power outputs
- local powerMade = v.getEnergyProducedLastTick()
- if powerMade > 0 then
- mon.setTextColor(colors.green)
- else
- mon.setTextColor(colors.red)
- end
- powerMade = toint(powerMade)
- powerMade = tonumber(powerMade)
- powerMade = commaformat(powerMade).."RF"
- local powerXStart = xCenter - math.floor(string.len(powerMade) / 2)
- mon.setCursorPos(powerXStart, 19)
- mon.write(powerMade)
- end
- --display turbine graphics/coils
- for k,v in ipairs(turbinePagePeriph) do
- local xCenter = (k * xInterval)
- local turbineXStart = xCenter - 3
- local coilColor
- if v.getInductorEngaged() then
- coilColor = colors.red
- else
- coilColor = colors.blue
- end
- mon.setBackgroundColor(colors.gray)
- mon.setCursorPos(turbineXStart, 6)
- mon.write(" ")
- for i=7,13 do
- mon.setCursorPos(turbineXStart, i)
- mon.setBackgroundColor(colors.gray)
- mon.write(" ")
- mon.setBackgroundColor(colors.lightGray)
- mon.write(" ")
- if i % 2 == 0 then
- mon.setBackgroundColor(colors.gray)
- end
- mon.write(" ")
- mon.setBackgroundColor(colors.gray)
- mon.write(" ")
- if i % 2 ~= 0 then
- mon.setBackgroundColor(colors.lightGray)
- end
- mon.write(" ")
- mon.setBackgroundColor(colors.lightGray)
- mon.write(" ")
- mon.setBackgroundColor(colors.gray)
- mon.write(" ")
- end
- for i=14,16 do
- mon.setCursorPos(turbineXStart, i)
- mon.setBackgroundColor(colors.gray)
- mon.write(" ")
- mon.setBackgroundColor(colors.lightGray)
- mon.write(" ")
- mon.setBackgroundColor(coilColor)
- mon.write(" ")
- mon.setBackgroundColor(colors.gray)
- mon.write(" ")
- mon.setBackgroundColor(coilColor)
- mon.write(" ")
- mon.setBackgroundColor(colors.lightGray)
- mon.write(" ")
- mon.setBackgroundColor(colors.gray)
- mon.write(" ")
- end
- mon.setCursorPos(turbineXStart, 17)
- mon.write(" ")
- mon.setBackgroundColor(colors.black)
- end
- end
- --change Turbine page
- function turnPage(num)
- turbinePage = num
- mon.clear()
- displayScreen()
- end
- --show buttons to change pages
- function displayPageButtons(page)
- button.clearTable()
- mon.setTextColor(colors.black)
- if page > 0 then
- local param = page - 1
- button.setTable("<<", turnPage, param, 1, 3, 10, 12)
- end
- if page < (pages-1) then
- local param = page + 1
- button.setTable(">>", turnPage, param, 48, 50, 10, 12)
- end
- button.screen()
- end
- function displayScreen()
- displayHeader()
- displayTurbines(turbinePage)
- if pages > 1 and lastPage ~= turbinePage then --only refresh buttons if page changes
- displayPageButtons(turbinePage)
- lastPage = turbinePage
- end
- end
- displayScreen()
- os.startTimer(.1)
- while true do
- local event, param1, param2, param3 = os.pullEvent()
- --do timed events, restart timer
- if event == "timer" then
- os.startTimer(.1)
- PID()
- if not (table.monitor == nil) then
- doTurbineLogic()
- end
- timerCounter = timerCounter + 1
- --update display every half second
- if timerCounter % 5 == 0 then
- timerCounter = 0
- displayScreen()
- end
- end
- --import data from Capacitor Relay Computer
- if event == "rednet_message" then
- table = textutils.unserialize(param2)
- end
- --parse monitor clicks to API
- if event == "monitor_touch" then
- button.checkxy(param2, param3)
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement