Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- This script controls Big Reactors and Big Turbines.
- -- For passively cooled reactors, just run this script, no configuration neccessary.
- -- For actively cooled reactors, set target turbine RPM. Optimal RPM is multiples of 900.
- local _targetRPM = 1800
- -- Get the pid controller from:
- -- https://github.com/OpenPrograms/Kubuxu-Programs/blob/master/pid/pid.lua
- -- Put it in your libs.
- -- Optionally, configure reactor and turbine PID. Defaults should be fine.
- local _reactorKp = 0.000005
- local _reactorKi = 0.000001
- local _reactorKd = 0.00005
- local _turbineKp = 0.01
- local _turbineKi = 0.001
- local _turbineKd = 0.1
- -- Configuration ends here
- -- Import basic opencomputers libs
- local term = require("term")
- term.clear()
- term.setCursorBlink(false)
- local component = require("component")
- local keyboard = require("keyboard")
- local computer = require("computer")
- local pid = require("pid")
- -- Constants
- local _reactorMaxEnergy = 10000000
- local _turbineMaxEnergy = 1000000
- local _turbineSteamMax = 2000
- -- Check if component is active
- local function checkComponent(componentType)
- if component.isAvailable(componentType) then
- return true
- else
- return false
- end
- end
- -- Get components, return them as a table
- local function getComponents(componentType)
- local components = {}
- local i = 0
- for componentAddress, componentName in component.list() do
- if componentName == componentType then
- i = i + 1
- components[i] = component.proxy(componentAddress)
- end
- end
- return components
- end
- -- Get PIDs, return them as a table
- local function getControllers(n)
- local controller = {}
- for i=1,n do
- controller[i] = pid:new()
- end
- return controller
- end
- -- Start main program
- local function main()
- -- Check for present reactors
- if not checkComponent("br_reactor") then
- error("ERROR: No reactor connected!")
- end
- -- Populate reactors, reactor controllers
- local reactor = getComponents("br_reactor")
- local numReactors = #reactor
- local reactorCtrl = getControllers(numReactors)
- -- Iterate through reactors, check for any actively cooled reactors, configure PID values
- local activelyCooled = false
- for i=1,numReactors do
- if reactor[i].isActivelyCooled() then
- activelyCooled = true
- reactorCtrl[i].target = math.floor(reactor[i].getCoolantAmountMax()/2)
- reactorCtrl[i].minout = 0
- reactorCtrl[i].maxout = 100
- reactorCtrl[i].kp = _reactorKp
- reactorCtrl[i].ki = _reactorKi
- reactorCtrl[i].kd = _reactorKd
- end
- end
- -- Turbine vars
- local turbine = {}
- local numTurbines = 0
- local turbineCtrl = {}
- -- If an actively cooled reactor is present, check for turbines
- if activelyCooled then
- if not checkComponent("br_turbine") then
- error("ERROR: Reactor is actively cooled, but no turbine detected!")
- end
- -- Populate turbines
- turbine = getComponents("br_turbine")
- numTurbines = #turbine
- turbineCtrl = getControllers(numTurbines)
- -- Configure turbine controllers
- for i=1,numTurbines do
- turbineCtrl[i].target = _targetRPM
- turbineCtrl[i].minout = 0
- turbineCtrl[i].maxout = _turbineSteamMax
- turbineCtrl[i].kp = _turbineKp
- turbineCtrl[i].ki = _turbineKi
- turbineCtrl[i].kd = _turbineKd
- end
- end
- -- This variable is needed for rotating the display
- local display = 1
- while true do
- -- Main loop begins here
- -- Variables we'll need later
- local energyRate = 0
- local fuelRate = 0
- local steamRate = 0
- for i=1,numReactors do
- -- Iterate through reactors
- if not reactor[i].isActivelyCooled() then
- -- Reactor is passively cooled, this is super simple. Rod insertion equals stored energy.
- local storedPercent = math.floor((reactor[i].getEnergyStored()/_reactorMaxEnergy)*100)
- reactor[i].setAllControlRodLevels(storedPercent)
- energyRate = energyRate + reactor[i].getEnergyProducedLastTick()
- fuelRate = fuelRate + reactor[i].getFuelConsumedLastTick()
- else
- -- Reactor is actively cooled. Use the PID controller to keep steam at about half full
- reactorCtrl[i].input = reactor[i].getHotFluidAmount()
- reactorCtrl[i]:compute()
- if reactorCtrl[i].output then
- reactor[i].setAllControlRodLevels(100-math.floor(reactorCtrl[i].output))
- end
- steamRate = steamRate + reactor[i].getHotFluidProducedLastTick()
- end
- end
- -- Turbine specific variables
- local energyRatePerTurbine = {}
- local dutyCyclePerTurbine = {}
- local dutyCycle = 0
- if activelyCooled then
- -- Run if the reactor is actively cooled
- for tick=1,20 do
- -- PWM routine runs once per tick per turbine.
- for i=1,numTurbines do
- if not dutyCyclePerTurbine[i] then
- dutyCyclePerTurbine[i] = 0
- energyRatePerTurbine[i] = 0
- end
- local storedPercent = math.floor((turbine[i].getEnergyStored()/_turbineMaxEnergy)*100)
- -- Power stored shouldn't go over 80%, so RF (and thus fuel) doesn't get wasted.
- if storedPercent > 80 then
- turbine[i].setInductorEngaged(false)
- else
- turbine[i].setInductorEngaged(true)
- dutyCyclePerTurbine[i] = dutyCyclePerTurbine[i] + 5
- dutyCycle = dutyCycle+5
- end
- energyRatePerTurbine[i] = energyRatePerTurbine[i] + turbine[i].getEnergyProducedLastTick()
- end
- os.sleep(0.01)
- end
- -- Turbine RPM is controlled and kept at _targetRPM by the PID controller
- for i=1,numTurbines do
- local RPM = turbine[i].getRotorSpeed()
- if RPM > 1820 then
- -- Cut steam if overspeeding
- -- This shouldn't really happen, but safety first, right?
- turbine[i].setFluidFlowRateMax(0)
- turbineCtrl[i].input = RPM
- turbineCtrl[i]:compute()
- else
- -- Get the power setting from the PID controller
- turbineCtrl[i].input = RPM
- turbineCtrl[i]:compute()
- if turbineCtrl[i].output then
- turbine[i].setFluidFlowRateMax(math.floor(turbineCtrl[i].output))
- end
- end
- energyRate = energyRate + energyRatePerTurbine[i]/20
- end
- end
- os.sleep(1)
- RFpermB = math.floor(energyRate/1000/fuelRate)
- dutyCycle = math.floor(dutyCycle/numTurbines)
- term.clear()
- print([[
- Total power output: ]] .. energyRate .. [[ RF/t
- Fuel efficiency: ]] .. RFpermB .. " MRF/ingot")
- if activelyCooled then
- print(" Duty cycle:" .. dutyCycle .. "%")
- end
- -- View changes with space
- if keyboard.isKeyDown(keyboard.keys.space) then
- display = display + 1
- if display > numReactors+numTurbines then
- display = 1
- end
- end
- if display <= numReactors then
- local i = display
- local coreTemp = math.floor(reactor[i].getFuelTemperature())
- local energyRate = math.floor(reactor[i].getEnergyProducedLastTick())
- if not reactor[i].isActivelyCooled() then
- local storedPercent = math.floor((reactor[i].getEnergyStored()/_reactorMaxEnergy)*100)
- print([[
- Reactor ]] .. i .. [[
- Core temperature: ]] .. coreTemp .. [[
- Energy rate: ]] .. energyRate .. [[ RF/t
- Reactor power: ]] .. 100 - storedPercent .. "%")
- else
- local steamPercent = math.floor((reactor[i].getHotFluidAmount()/reactor[i].getHotFluidAmountMax())*100)
- local rodPercent = reactor[i].getControlRodLevel(0)
- print([[
- Reactor ]] .. i .. [[
- Core temperature: ]] .. coreTemp .. [[
- Steam rate: ]] .. energyRate .. [[ mB/t
- Steam percent: ]] .. steamPercent .. [[%
- Reactor power: ]] .. 100 - rodPercent .. "%")
- end
- elseif numTurbines > 0 then
- local i = display - numReactors
- local RPM = turbine[i].getRotorSpeed()
- local steamRate = math.floor(turbineCtrl[i].output)
- local dutyCycle = dutyCyclePerTurbine[i]/20*100
- local energyRate = energyRatePerTurbine[i]/20
- print([[
- Turbine ]] .. i .. string.format([[
- RPM: %.4f]], RPM) .. [[
- Duty cycle: ]] .. dutyCycle .. [[%
- Energy rate: ]] .. energyRate .. [[ RF/t
- Steam rate: ]] .. steamRate .. [[ mB/t
- ]])
- end
- if keyboard.isKeyDown(keyboard.keys.q) and keyboard.isControlDown() then
- for i=1,numReactors do
- reactor[i].setActive(false)
- print("\nReactor " .. i .. " shutting down.\n")
- os.sleep(3)
- term.clear()
- term.setCursorBlink(true)
- os.exit()
- end
- end
- if (computer.energy() < 100) then
- for i=1,numReactors do
- reactor[i].setActive(false)
- print("\nEnergy level critical\nShutting down reactor " .. i)
- os.sleep(3)
- computer.shutdown()
- end
- end
- if not activelyCooled then
- sleep(1)
- end
- end
- end
- main()
- term.clear()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement