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