Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --------------------------------------------------------
- -- This program won’t work properly with a sodium
- -- cooled reactor as it won’t calculate the boiler,
- -- meaning the reactor will overheat and shutdown
- -- several times.
- --
- --
- -- By Alexmaster75
- --------------------------------------------------------
- -- peripherals
- local reactor = peripheral.find("fissionReactorLogicAdapter")
- local turbine = peripheral.find("turbineValve")
- local monitor = peripheral.find("monitor")
- -- variables
- local cfg_n = "cfg.txt"
- local log_n = "log.txt"
- local cfg, log
- local data = {}
- local reboot = 1
- local max_energy = 0.8
- local min_energy = 0.2
- local limit_rate = 1.0
- local deact_side = "left"
- local scram_side = "right"
- local power = true
- local max_burn_rate = 0
- local max_turbine_energy = 0
- local max_steam = 0
- local status = ""
- local x, y
- local N = 10 -- this is the number responsible for how many samples are required for the estimation
- local smpl = {} -- and this is the array that stores those values
- local S = 0
- local j = 0
- local k = 0
- -- this shit is for the different timings, you know, you don't want the screen being updated like 500 times per second
- local t = 0.0
- local t_max = 10.0
- local ta = 0.05 -- a brake to the program (if the value is <=0 the program just explodes as it either goes full power or just error)
- local t0 = tonumber(os.date("%S")) -- this variable is used for time estimation sector
- local td = 5 -- this regulates the delay between each estimation (seconds)
- local ts = 0 -- this variable is responsible to save the time elapsed since last execution
- -- all of these below are just functions, after the double space
- -- it just prints a divider
- local function divider(char)
- local w, h = term.getSize()
- for i=1,w do
- write(char)
- end
- print()
- end
- -- checks if the file exists
- local function file_exists(file)
- local f = io.open(file, "rb")
- if (f) then f:close() end
- return f ~= nil
- end
- -- gets real time (hh/mm/ss) and returns it as string
- local function rtime()
- local ts = os.date("%X")
- return ts
- end
- -- end of all functions
- -- =======================================
- -- ALL OF THIS BELOW IS THE MAIN PROGRAM
- -- =======================================
- -- this part regards the checks for the communication, it makes sure all required components are connected and working properly
- -- waits for a response from the peripherals
- term.clear()
- term.setCursorPos(1, 1)
- term.setBackgroundColor(colors.black)
- term.setTextColor(colors.yellow)
- print("MEKANISM AUTOMATED CONTROL SYSTEM")
- term.setTextColor(colors.white)
- divider("=")
- print(("[%s] Checking response from peripherals.."):format(rtime()))
- x, y = term.getCursorPos()
- while (not (reactor and turbine)) do
- if (t > t_max) then
- error("Too long without a response")
- end
- reactor = peripheral.find("fissionReactorLogicAdapter")
- turbine = peripheral.find("turbineValve")
- monitor = peripheral.find("monitor")
- term.setCursorPos(1, y)
- print(("T: %.1f"):format(t))
- t = t + 0.1
- os.sleep(0.1)
- end
- print(("[%s] Done!"):format(rtime()))
- -- if the program finds them, it checks if they actually work
- print(("[%s] Checking if they're formed.."):format(rtime()))
- x, y = term.getCursorPos()
- t = 0.0
- while (not (reactor.isFormed() and turbine.isFormed())) do
- if (t > t_max) then
- error("Too long without a response")
- end
- term.setCursorPos(1, y)
- print(("T: %.1f"):format(t))
- t = t + 0.1
- os.sleep(0.1)
- end
- print(("[%s] Done!"):format(rtime()))
- -- if the program has arrived at this point then all the components are working properly
- -- but there's still a chance of not being truly online, so it waits for a valid response
- print(("[%s] Checking if the systems are online.."):format(rtime()))
- x, y = term.getCursorPos()
- t = 0.0
- while (reactor.getMaxBurnRate() == nil and turbine.getMaxEnergy() == nil) do
- if (t > t_max) then
- error("Too long without a response")
- end
- term.setCursorPos(1, y)
- print(("T: %.1f"):format(t))
- t = t + 0.1
- os.sleep(0.1)
- end
- print(("[%s] Done!"):format(rtime()))
- print(("[%s] Checking the config file.."):format(rtime()))
- -- reads (or creates is it doesn't exist) the config file
- if (not file_exists(cfg_n)) then
- -- creates it
- print(("[%s] Config file didn't found"):format(rtime()))
- print(("[%s] Creating it.."):format(rtime()))
- cfg = fs.open(cfg_n, "w")
- data = {reboot, limit_rate, max_energy, min_energy, deact_side, scram_side, td, N}
- cfg.write(textutils.serialise(data))
- cfg.close()
- else
- -- reads it
- print(("[%s] Config file found"):format(rtime()))
- print(("[%s] Reading it.."):format(rtime()))
- cfg = fs.open(cfg_n, "r")
- data = textutils.unserialise(cfg.readAll())
- cfg.close()
- reboot = data[1]
- limit_rate = data[2]
- max_energy = data[3]
- min_energy = data[4]
- deact_side = data[5]
- scram_side = data[6]
- td = data[7]
- N = data[8]
- end
- print(("[%s] Done!"):format(rtime()))
- -- then it restarts the entire program if necessary
- if (reboot ~= 0) then
- cfg = fs.open(cfg_n, "r")
- data = textutils.unserialise(cfg.readAll())
- data[1] = 0
- cfg = fs.open(cfg_n, "w")
- cfg.write(textutils.serialise(data))
- cfg.close()
- os.reboot()
- end
- -- here all the constants regarding the external system are assigned
- max_burn_rate = reactor.getMaxBurnRate() * limit_rate -- this is a limit imposed to the burn rate, like if someone wants to operate at maximum 50%, the program multiplies the max rate times 0.5
- max_turbine_energy = turbine.getMaxEnergy()
- max_steam = turbine.getSteamCapacity()
- print(("[%s] All set!"):format(rtime()))
- print(("[%s] Program started"):format(rtime()))
- -- checks if a monitor is connected to the network/computer
- -- if so it redirects the terminal output to the monitor
- if (monitor) then
- term.redirect(monitor)
- end
- term.clear()
- term.setCursorPos(1, 1)
- term.setBackgroundColor(colors.black)
- term.setTextColor(colors.yellow)
- print("MEKANISM AUTOMATED CONTROL SYSTEM")
- term.setTextColor(colors.white)
- divider("=")
- print(("> Min - Max Turbine Energy: %d - %d%s"):format(min_energy*100, max_energy*100, "%"))
- divider("=")
- x, y = term.getCursorPos()
- term.setCursorPos(1, y+8)
- divider("-")
- -- resets the array to 0
- for i=1,N do
- smpl[i] = 0
- end
- -- saves the actual time (unix timestamp in seconds)
- ts = os.time(os.date("!*t"))
- -- MAIN CYCLE
- while (true) do
- -- just gets the reactor status
- -- safety conditions
- if (reactor.getTemperature() > 1200.0 or turbine.getEnergy() >= max_turbine_energy or reactor.getWasteFilledPercentage() > 0.8 or reactor.getCoolantFilledPercentage() < 0.5) then
- if (reactor.getStatus()) then
- reactor.scram()
- end
- break
- end
- -- the logic of this thing (smooth brain)
- -- if the side is activated the program first shutdowns the reactor, then the computer
- if (rs.getInput(scram_side)) then
- if (reactor.getStatus()) then
- reactor.scram()
- end
- break
- end
- -- this is for efficiency/safety. it basically makes the energy go in a range between the minimum & maximum energy in the turbine
- if (turbine.getEnergyFilledPercentage() < min_energy) then
- power = true
- end
- if (turbine.getEnergyFilledPercentage() > max_energy) then
- power = false
- end
- -- if the energy reserve is in range, then the logic can proceed
- if (power and not rs.getInput(deact_side)) then
- reactor.setBurnRate(max_burn_rate - (turbine.getEnergy() * max_burn_rate / max_turbine_energy))
- -- it activates the reactor if it appears ready for operation or it's just off
- if (not reactor.getStatus() and reactor.getCoolantFilledPercentage() > 0.5) then
- reactor.activate()
- end
- else
- if (reactor.getStatus()) then
- reactor.scram()
- end
- end
- -- program output
- term.setCursorPos(1, y)
- -- start big print: it gets the status of the reactor and decides weather to print ON in green or OFF in red
- write("> Status: ")
- if (reactor.getStatus()) then
- status = "ON"
- term.setTextColor(colors.lime)
- else
- status = "OFF"
- term.setTextColor(colors.red)
- end
- print(status, " ")
- term.setTextColor(colors.white)
- -- end big print
- print(("> Rods Percentage: %.1f%s "):format((100 - (reactor.getBurnRate() * 100 / max_burn_rate)), "%"))
- print(("> Reactor Temp.: %.2f °C "):format(reactor.getTemperature() - 273.15))
- print(("> Burn Rate: %.2f / %.2f mB/t "):format(reactor.getBurnRate(), max_burn_rate))
- print(("> Fuel: %.1f%s "):format(reactor.getFuelFilledPercentage()*100, "%"))
- print(("> Eta Fuel (HH/MM/SS): %2d:%2d:%2d "):format(S/3600, (S/60)%60, S%60))
- print(("> Heating Rate: %d mB/t "):format(reactor.getHeatingRate()))
- print(("> Coolant: %.1f%s "):format(reactor.getCoolantFilledPercentage()*100, "%"))
- term.setCursorPos(1, y+9)
- print(("> Turbine Energy: %.1f / %.1f MFE (%.1f%s) "):format((turbine.getEnergy()/2500000), (max_turbine_energy/2500000), turbine.getEnergyFilledPercentage()*100, "%"))
- print(("> Flow Rate: %d mB/t "):format(turbine.getFlowRate()))
- print(("> Turbine Prod.: %.1f kFE/t "):format(turbine.getProductionRate()/2500))
- print(("> Turbine Gas Cap.: %d B "):format(max_steam/1000))
- -- this sector of the cycle decides the time left for the
- if (math.abs(tonumber(os.date("%S")) - t0) > td) then
- t0 = tonumber(os.date("%S"))
- k = 0
- j = 0
- -- moves all the values forward, for example:
- -- { 23, 67, 12, 3 } -> { 0, 23, 67, 12 }
- for i=N,1,-1 do
- smpl[i] = smpl[i-1]
- end
- -- assigns the reactor's burn rate to the first value of the array
- smpl[1] = reactor.getActualBurnRate()
- -- cycles through the array picking up all the values that are different from 0, then it sums them toghether in the variable "k", also incrementing "j" by 1 each time
- for i=1,N do
- if (smpl[i] ~= 0) then
- k = k + smpl[i]
- j = j + 1
- end
- end
- -- because "j" is the divider for "k", there could be a problem if the array is empty (full of 0), resulting in "j" being 0 and you can't divide by 0
- -- therefore, it checks if it is anywhere near 0 and if so, assigns 1 to it
- if (j <= 0) then j = 1 end
- -- this is just an arithmetic average of all the values in the array
- -- *20 is for the burn rate (velocity) being in mB/t, we want it in seconds so because 1 second = 20 ticks we do that
- k = k*20 / j
- -- calculation of seconds
- S = math.floor(reactor.getFuel().amount / k)
- end
- os.sleep(ta)
- end
- -- saves the time elapsed since last execution (TESLE)
- ts = os.time(os.date("!*t")) - ts
- -- if for some reason the code encounters an exeption, it cuts to this point to make it smooth
- x, y = term.getCursorPos()
- while (x < 17) do
- x = x + 1
- end
- term.setCursorPos(1, y)
- divider("-")
- print(("> Saving in /%s..."):format(log_n))
- log = io.open(log_n, "w")
- log:write(("LOG OF THE %s\n"):format(os.date()))
- log:write(("========================\nTESLE (HH/MM/SS): %2d:%2d:%2d\n"):format(ts/3600, (ts/60)%60, ts%60))
- log:write("========================\nReactor stats:\n")
- log:write(("> Reactor Temp.: %.2f °C\n"):format(reactor.getTemperature() - 273.15))
- log:write(("> Burn Rate: %.2f / %.2f mB/t\n"):format(reactor.getBurnRate(), max_burn_rate))
- log:write(("> Heating Rate: %d mB/t\n"):format(reactor.getHeatingRate()))
- log:write(("> Coolant: %s (%.1f%s)\n"):format(reactor.getCoolant().name, reactor.getCoolantFilledPercentage()*100, "%"))
- log:write(("> Fuel: %s (%.1f%s)\n"):format(reactor.getFuel().name, reactor.getFuelFilledPercentage()*100, "%"))
- log:write(("> Waste: %s (%.1f%s)\n"):format(reactor.getWaste().name, reactor.getWasteFilledPercentage()*100, "%"))
- log:write("------------------------\nTurbine stats:\n")
- log:write(("> Turbine Energy: %.1f / %.1f MFE (%.1f%s)\n"):format((turbine.getEnergy()/2500000), (max_turbine_energy/2500000), turbine.getEnergyFilledPercentage()*100, "%"))
- log:write(("> Flow Rate: %d mB/t\n"):format(turbine.getFlowRate()))
- log:write(("> Turbine Prod.: %.1f kFE/t\n"):format(turbine.getProductionRate()/2500))
- log:write(("> Turbine Gas Cap.: %d B\n"):format(max_steam/1000))
- log:close()
- print("> Saved successfully")
- print("> Terminated")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement