Advertisement
Cr1spyBacon8r

Bigger Reactors ComputerCraft Control Software

Sep 27th, 2022 (edited)
1,987
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.02 KB | Software | 0 0
  1. Reactor = {
  2.     name = "",
  3.     id = {},
  4.     side = "",
  5.     type = "",
  6.     controlRodPID = {}
  7. }
  8.  
  9. function Reactor:new(o, name)
  10.     o = o or {}
  11.     setmetatable(o, self)
  12.     self.__index = self
  13.     o.id = peripheral.wrap(name)
  14.     o.name = "Reactor " .. (turbineCount + 1)
  15.     o.controlRodPID = PIDController:new(nil, .00000001, 0, 0)
  16.     reactorCount = reactorCount + 1
  17.     return o
  18. end
  19.  
  20. function Reactor:active()
  21.     return self.id.active()
  22. end
  23.  
  24. function Reactor:setActive(active)
  25.     return self.id.setActive(active)
  26. end
  27.  
  28. function Reactor:controlRodLevel()
  29.     return self.id.getControlRod(0).level()
  30. end
  31.  
  32. function Reactor:controlRodCount()
  33.     return self.id.getNumberOfControlRods()
  34. end
  35.  
  36. function Reactor:fuel()
  37.     return self.id.fuelTank().fuel()
  38. end
  39.  
  40. function Reactor:maxFuel()
  41.     return self.id.fuelTank().capacity()
  42. end
  43.  
  44. function Reactor:fuelPercentage()
  45.     return math.floor(self:fuel() / self:maxFuel() * 100)
  46. end
  47.  
  48. function Reactor:setControlRodLevels(level)
  49.     return self.id.setAllControlRodLevels(level)
  50. end
  51.  
  52. function Reactor:steamExported()
  53.     return self.id.coolantTank().transitionedLastTick()
  54. end
  55.  
  56. function Reactor:steamGenerated()
  57.     return self.id.coolantTank().maxTransitionedLastTick()
  58. end
  59.  
  60. Turbine = {
  61.     name = "",
  62.     id = {},
  63.     side = "",
  64.     type = "",
  65.     steamInputPID = {}
  66. }
  67.  
  68. turbineCount = 0
  69.  
  70. function Turbine:new(o, name)
  71.     o = o or {}
  72.     setmetatable(o, self)
  73.     self.__index = self
  74.     o.name = "Turbine " .. (turbineCount + 1)
  75.     o.side = name
  76.     o.id = peripheral.wrap(name)
  77.     o.steamInputPID = PIDController:new(nil, .5, 0, 0)
  78.     o.steamInputPID:setSetpoint(targetTurbineRPM)
  79.     turbineCount = turbineCount + 1
  80.     return o
  81. end
  82.  
  83. function Turbine:active()
  84.     return self.id.active()
  85. end
  86.  
  87. function Turbine:setActive(active)
  88.     return self.id.setActive(active)
  89. end
  90.  
  91. function Turbine:battery()
  92.     return self.id.battery().stored()
  93. end
  94.  
  95. function Turbine:maxBattery()
  96.     return self.id.battery().capacity()
  97. end
  98.  
  99. function Turbine:batteryProducedLastTick()
  100.     return self.id.battery().producedLastTick()
  101. end
  102.  
  103. function Turbine:batteryPercentage()
  104.     return math.floor(self:battery() / self:maxBattery() * 100)
  105. end
  106.  
  107. function Turbine:rpm()
  108.     return self.id.rotor().RPM()
  109. end
  110.  
  111. function Turbine:efficiency()
  112.     return self.id.rotor().efficiencyLastTick()
  113. end
  114.  
  115. function Turbine:flowRate()
  116.     return self.id.fluidTank().nominalFlowRate()
  117. end
  118.  
  119. function Turbine:setFlowRate(rate)
  120.     return self.id.fluidTank().setNominalFlowRate(rate)
  121. end
  122.  
  123. PIDController = {
  124.     kP = 1,
  125.     kI = 0,
  126.     kD = 0,
  127.     setpoint = 0,
  128.     previousError = 0,
  129.     integral = 0
  130. }
  131.  
  132. function PIDController:new(o, kP, kI, kD)
  133.     o = o or {}
  134.     setmetatable(o, self)
  135.     self.__index = self
  136.  
  137.     self.kP = kP
  138.     self.kI = kI
  139.     self.kD = kD
  140.     self.previousError = 0
  141.     self.setpoint = 0
  142.     self.integral = 0
  143.     return o
  144. end
  145.  
  146. function PIDController:setSetpoint(setpoint)
  147.     self.setpoint = setpoint
  148. end
  149.  
  150. function PIDController:calculate(currentValue)
  151.     error = self.setpoint - currentValue
  152.     self.integral = self.integral + (error)
  153.     derivative = (error - self.previousError)
  154.     self.previousError = error
  155.     rcw = self.kP * error + self.kI * self.integral + self.kD * derivative
  156.     -- print(rcw)
  157.     return rcw
  158. end
  159.  
  160. reactorCount = 0
  161. reactors = {}
  162. turbineCount = 0
  163. turbines = {}
  164.  
  165. -- Config
  166.  
  167. targetPowerStorage = 70
  168. targetTurbineRPM = 1800
  169.  
  170. -- Communication variables
  171. targetSteam = 0
  172. controlRodOutput = 0
  173.  
  174. monitor = {}
  175. energyCube = {}
  176.  
  177. -- Discover devices
  178. for i, v in pairs(peripheral.getNames()) do
  179.     print(v)
  180.     type = peripheral.getType(v)
  181.     if type == "BiggerReactors_Reactor" then
  182.         reactor = Reactor:new(nil, v)
  183.         reactors[reactorCount] = reactor
  184.     end
  185.     if type == "BiggerReactors_Turbine" then
  186.         turbine = Turbine:new(nil, v)
  187.         turbines[turbineCount] = turbine
  188.     end
  189.     if type == "eliteEnergyCube" then
  190.         energyCube = peripheral.wrap(v)
  191.     end
  192.     if type == "monitor" then
  193.         monitor = peripheral.wrap("monitor_0")
  194.     end
  195. end
  196.  
  197. for i = 1, turbineCount, 1 do
  198.     print(turbines[i])
  199. end
  200.  
  201. local function reactorControl()
  202.     if energyCube.getEnergyFilledPercentage() < .5 then
  203.  
  204.         for i = 1, reactorCount, 1 do
  205.             local reactor = reactors[i]
  206.             reactor:setActive(true)
  207.             reactor.controlRodPID:setSetpoint(targetSteam)
  208.             local pidValue = reactor.controlRodPID:calculate(reactor:steamGenerated())
  209.             local currentControlRod = reactor:controlRodLevel()
  210.             controlRodOutput = 100 -
  211.                                    math.max(0,
  212.                     math.min(currentControlRod + math.max(-100, math.min(100, pidValue * .01))))
  213.             reactor:setControlRodLevels(reactor:controlRodLevel() + controlRodOutput)
  214.         end
  215.     else
  216.         for i = 1, reactorCount, 1 do
  217.             local reactor = reactors[i]
  218.             reactor:setActive(false)
  219.         end
  220.     end
  221. end
  222.  
  223. local function turbineControl()
  224.     targetSteam = 0
  225.     for i = 1, turbineCount, 1 do
  226.         local turbine = turbines[i]
  227.         turbine:setActive(true)
  228.         local rpm = turbine:rpm()
  229.         local steamLevel = turbine.steamInputPID:calculate(rpm)
  230.         local totalSteam = turbine:flowRate() + steamLevel
  231.         targetSteam = targetSteam + totalSteam
  232.         turbine:setFlowRate(totalSteam)
  233.     end
  234. end
  235.  
  236. local function log()
  237.     print("ControlRod: " .. controlRodOutput .. " - Steam: " .. targetSteam)
  238. end
  239.  
  240. local function graphTurbineSpeed(turbine, offset)
  241.     term.setCursorPos(5, 1 + offset)
  242.     term.setTextColor(colors.white)
  243.     term.setBackgroundColor(colors.black)
  244.     term.write("Turbine RPM")
  245.     paintutils.drawFilledBox(5, 2 + offset, 50, 3 + offset, colors.gray)
  246.     local percentage = turbine:rpm() / targetTurbineRPM * 100
  247.     paintutils.drawFilledBox(5, 2 + offset, (percentage / 2) + 5, 3 + offset, colors.green)
  248.     term.setCursorPos(7, 2 + offset)
  249.     term.setTextColor(colors.white)
  250.     term.write(math.floor(turbine:rpm()) .. " RPM")
  251. end
  252.  
  253. local function graphControlRodLevel(reactor, offset)
  254.     term.setCursorPos(5, 1 + offset)
  255.     term.setTextColor(colors.white)
  256.     term.setBackgroundColor(colors.black)
  257.     term.write("Control Rod Level")
  258.     paintutils.drawFilledBox(5, 2 + offset, 50, 3 + offset, colors.gray)
  259.     local percentage = reactor:controlRodLevel()
  260.     paintutils.drawFilledBox(5, 2 + offset, (percentage / 2) + 5, 3 + offset, colors.green)
  261.     term.setCursorPos(7, 2 + offset)
  262.     term.setTextColor(colors.white)
  263.  
  264.     term.write(math.floor(reactor:controlRodLevel()) .. "%")
  265. end
  266.  
  267. local function graphSteamOutput(reactor, offset)
  268.     term.setCursorPos(5, 1 + offset)
  269.     term.setTextColor(colors.white)
  270.     term.setBackgroundColor(colors.black)
  271.     term.write("Steam Output")
  272.     paintutils.drawFilledBox(5, 2 + offset, 50, 3 + offset, colors.gray)
  273.     local percentage = reactor:steamExported() / targetSteam * 100
  274.     paintutils.drawFilledBox(5, 2 + offset, (percentage / 2) + 5, 3 + offset, colors.green)
  275.     term.setCursorPos(7, 2 + offset)
  276.     term.setTextColor(colors.white)
  277.     term.write(math.floor(reactor:steamExported()) .. "mB")
  278. end
  279.  
  280. local function graphEnergyGeneration(offset)
  281.     term.setCursorPos(5, 1 + offset)
  282.     term.setTextColor(colors.white)
  283.     term.setBackgroundColor(colors.black)
  284.     local energyPerTick = 0
  285.     for i = 1, turbineCount, 1 do
  286.         turbine = turbines[i]
  287.         energyPerTick = energyPerTick + turbine:batteryProducedLastTick()
  288.     end
  289.     term.write("Energy Generation RF/t")
  290.     term.setCursorPos(7, 2 + offset)
  291.     term.setTextColor(colors.white)
  292.     term.write(math.floor(energyPerTick) .. " RF/t")
  293. end
  294.  
  295. local function graphPowerLevel(offset)
  296.     term.setCursorPos(5, 1 + offset)
  297.     term.setTextColor(colors.white)
  298.     term.setBackgroundColor(colors.black)
  299.     term.write("Power Cube Level")
  300.     paintutils.drawFilledBox(5, 2 + offset, 50, 3 + offset, colors.gray)
  301.     local percentage = energyCube.getEnergyFilledPercentage()
  302.     paintutils.drawFilledBox(5, 2 + offset, (percentage / 2) + 5, 3 + offset, colors.green)
  303.     term.setCursorPos(7, 2 + offset)
  304.     term.setTextColor(colors.white)
  305.  
  306.     term.write(math.floor(energyCube.getEnergy()) .. " RF")
  307. end
  308.  
  309. local function graph()
  310.     regularMonitor = term.redirect(monitor)
  311.     graphTurbineSpeed(turbines[1], 0)
  312.     graphControlRodLevel(reactors[1], 4)
  313.     graphSteamOutput(reactors[1], 8)
  314.     graphEnergyGeneration(12)
  315.     term.redirect(regularMonitor)
  316. end
  317.  
  318. local function clearMonitor()
  319.     regularMonitor = term.redirect(monitor)
  320.     local w, h = monitor.getSize()
  321.     paintutils.drawFilledBox(1, 1, w, h, colors.black)
  322.     term.redirect(regularMonitor)
  323. end
  324.  
  325. print("Starting reactor control with " .. turbineCount .. " turbines and " .. reactorCount .. " reactors...")
  326.  
  327. while true do
  328.     os.sleep(1)
  329.     -- Run reactors
  330.     reactorControl()
  331.     -- Run turbines
  332.     turbineControl()
  333.  
  334.     -- log()
  335.     clearMonitor()
  336.     graph()
  337. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement