SHOW:
|
|
- or go back to the newest paste.
| 1 | -- | |
| 2 | -- Control turbines of a active cooled Big Reactor (http://big-reactors.com/). | |
| 3 | -- | |
| 4 | -- Author: kla_sch | |
| 5 | -- | |
| 6 | -- History: | |
| 7 | -- v0.1, 2014-12-29: | |
| 8 | -- - first version | |
| 9 | -- | |
| 10 | -- v0.2, 2015-01-02: | |
| 11 | -- - Big Reactor since 0.3.4A: Feature to disengage coil to | |
| 12 | -- startup faster (see config value useDisengageCoils). | |
| 13 | -- - minor bugfixes | |
| 14 | -- - some code improvments (thanks to wieselkatze) | |
| 15 | -- | |
| 16 | -- Save as "startup" | |
| 17 | ||
| 18 | ||
| 19 | -- | |
| 20 | -- Constant values (configuration) | |
| 21 | -- =============================== | |
| 22 | ||
| 23 | ||
| 24 | -- Maximum loop time of controller (default: 0.5s) | |
| 25 | local loopT=0.5 | |
| 26 | ||
| 27 | -- Display loop time, of controller has been switched off (default: 1s). | |
| 28 | local displayT=1 | |
| 29 | ||
| 30 | -- Modem channel to listen for status requests. If it is set to 0, | |
| 31 | -- the remote status requests are disabled. | |
| 32 | -- The sender sould simply send "BR_turbine_get_state" to this channel. The | |
| 33 | -- turbine replies with status informations to the replay channel. | |
| 34 | local stateRequestChannel = 32768 -- Broadcast channel. | |
| 35 | ||
| 36 | -- | |
| 37 | -- Enable remote control. | |
| 38 | -- Set to "true" if you want to enable this feature. | |
| 39 | -- | |
| 40 | local remoteControl = false | |
| 41 | ||
| 42 | -- | |
| 43 | -- Use disengaged coil for faster speedup. (Big Reactor >= 0.3.4A). | |
| 44 | -- Set this to "false" if you want to disable this feature. | |
| 45 | -- | |
| 46 | local useDisengageCoils = true | |
| 47 | ||
| 48 | ||
| 49 | -- | |
| 50 | -- Internal values: | |
| 51 | -- ================ | |
| 52 | ||
| 53 | -- File to save last known controller state: | |
| 54 | local saveFilename = "turbine_crtl.save" | |
| 55 | ||
| 56 | local Kp, Kd, Ki, errSum, errOld -- global PID controller values | |
| 57 | local tSpeed -- target speed | |
| 58 | local turbine -- wraped turbine | |
| 59 | local maxFRate -- maximum float rate of turbine | |
| 60 | local floatRateChanged = false -- flag: true on float rate change | |
| 61 | ||
| 62 | ||
| 63 | -- | |
| 64 | -- Find the first connected big turbine and return the wraped handle. | |
| 65 | -- | |
| 66 | -- If no turbine was found this function terminate the program. | |
| 67 | -- | |
| 68 | -- Return: | |
| 69 | -- Handle of first connected turbine found. | |
| 70 | -- | |
| 71 | local function getTurbineHandle() | |
| 72 | local pList = peripheral.getNames() | |
| 73 | local i, name | |
| 74 | for i, name in pairs(pList) do | |
| 75 | if peripheral.getType(name) == "BigReactors-Turbine" then | |
| 76 | return peripheral.wrap(name) | |
| 77 | end | |
| 78 | end | |
| 79 | ||
| 80 | error("No turbine connected: Exit program")
| |
| 81 | end | |
| 82 | ||
| 83 | ||
| 84 | -- | |
| 85 | -- Search for any modem and open it to recieve modem requests. | |
| 86 | -- | |
| 87 | local function searchAndOpenModems() | |
| 88 | if stateRequestChannel <= 0 then | |
| 89 | return -- feature disabled | |
| 90 | end | |
| 91 | ||
| 92 | local pList = peripheral.getNames() | |
| 93 | local i, name | |
| 94 | for i, name in pairs(pList) do | |
| 95 | if peripheral.getType(name) == "modem" then | |
| 96 | peripheral.call(name, "open", stateRequestChannel) | |
| 97 | peripheral.call(name, "open", os.getComputerID()) | |
| 98 | end | |
| 99 | end | |
| 100 | end | |
| 101 | ||
| 102 | ||
| 103 | -- | |
| 104 | -- Saves current controller state | |
| 105 | -- | |
| 106 | local function saveControllerState() | |
| 107 | local tmpFilename = saveFilename .. ".tmp" | |
| 108 | ||
| 109 | fs.delete(tmpFilename) | |
| 110 | local sFile = fs.open(tmpFilename, "w") | |
| 111 | if sFile == nil then | |
| 112 | error("cannot open status file for writing.")
| |
| 113 | end | |
| 114 | ||
| 115 | sFile.writeLine("V0.1")
| |
| 116 | sFile.writeLine(tostring(tSpeed)) | |
| 117 | sFile.writeLine(tostring(loopT)) | |
| 118 | sFile.writeLine(tostring(Kp)) | |
| 119 | sFile.writeLine(tostring(errSum)) | |
| 120 | sFile.writeLine(tostring(errOld)) | |
| 121 | sFile.writeLine("EOF")
| |
| 122 | sFile.close() | |
| 123 | ||
| 124 | fs.delete(saveFilename) | |
| 125 | fs.move(tmpFilename, saveFilename) | |
| 126 | end | |
| 127 | ||
| 128 | ||
| 129 | -- | |
| 130 | -- Initialize basic PID controller values | |
| 131 | -- | |
| 132 | local function initControllerValues() | |
| 133 | local Tn = loopT | |
| 134 | local Tv = loopT * 10 | |
| 135 | ||
| 136 | Ki = Kp / Tn | |
| 137 | Kd = Kp * Tv | |
| 138 | end | |
| 139 | ||
| 140 | ||
| 141 | -- | |
| 142 | -- Read number from file | |
| 143 | -- | |
| 144 | -- Parameters: | |
| 145 | -- sFile - opened file to read from | |
| 146 | -- | |
| 147 | -- Return | |
| 148 | -- the number of nil, if an error has occurred | |
| 149 | -- | |
| 150 | local function readNumber(sFile) | |
| 151 | local s = sFile.readLine() | |
| 152 | if s == nil then | |
| 153 | return nil | |
| 154 | end | |
| 155 | return tonumber(s) | |
| 156 | end | |
| 157 | ||
| 158 | -- | |
| 159 | -- Restore last known controller state | |
| 160 | -- | |
| 161 | -- Returns: | |
| 162 | -- true, if the last saved state has successfully readed. | |
| 163 | local function restoreControllerState() | |
| 164 | local tmpFilename = saveFilename .. ".tmp" | |
| 165 | local sFile = fs.open(saveFilename, "r") | |
| 166 | if sFile == nil and fs.exists(tmpFilename) then | |
| 167 | fs.move(tmpFilename, saveFilename) | |
| 168 | sFile = fs.open(saveFilename) | |
| 169 | end | |
| 170 | ||
| 171 | if sFile == nil then | |
| 172 | return false -- cannot read any file | |
| 173 | end | |
| 174 | ||
| 175 | local version = sFile.readLine() | |
| 176 | if version == nil then | |
| 177 | sFile.close() | |
| 178 | return false -- empty file | |
| 179 | end | |
| 180 | if version ~= "V0.1" then | |
| 181 | sFile.close() | |
| 182 | return false -- unknown version | |
| 183 | end | |
| 184 | ||
| 185 | local tSpeedNum = readNumber(sFile) | |
| 186 | if tSpeedNum == nil then | |
| 187 | sFile.close() | |
| 188 | return false -- cannot read target speed | |
| 189 | end | |
| 190 | ||
| 191 | local loopTNum = readNumber(sFile) | |
| 192 | if loopTNum == nil then | |
| 193 | sFile.close() | |
| 194 | return false -- cannot read loop speed | |
| 195 | end | |
| 196 | ||
| 197 | local KpNum = readNumber(sFile) | |
| 198 | if KpNum == nil then | |
| 199 | sFile.close() | |
| 200 | return false -- cannot read Kp | |
| 201 | end | |
| 202 | ||
| 203 | local errSumNum = readNumber(sFile) | |
| 204 | if errSumNum == nil then | |
| 205 | sFile.close() | |
| 206 | return false -- cannot read error sum | |
| 207 | end | |
| 208 | ||
| 209 | local errOldNum = readNumber(sFile) | |
| 210 | if errOldNum == nil then | |
| 211 | sFile.close() | |
| 212 | return false -- cannot read last error | |
| 213 | end | |
| 214 | ||
| 215 | local eofStr = sFile.readLine() | |
| 216 | if eofStr == nil or eofStr ~= "EOF" then | |
| 217 | sFile.close() | |
| 218 | return false -- EOF marker not found. File corrupted? | |
| 219 | end | |
| 220 | ||
| 221 | sFile.close() | |
| 222 | ||
| 223 | -- Restore saved values | |
| 224 | tSpeed = tSpeedNum | |
| 225 | loopT = loopTNum | |
| 226 | Kp = KpNum | |
| 227 | errSum = errSumNum | |
| 228 | errOld = errOldNum | |
| 229 | ||
| 230 | initControllerValues() | |
| 231 | ||
| 232 | if tSpeed == 0 then | |
| 233 | turbine.setActive(false) | |
| 234 | else | |
| 235 | turbine.setActive(true) | |
| 236 | end | |
| 237 | ||
| 238 | return true | |
| 239 | end | |
| 240 | ||
| 241 | ||
| 242 | -- | |
| 243 | -- Write text with colors, if possible (advance monitor) | |
| 244 | -- | |
| 245 | -- Parameters: | |
| 246 | -- mon - handle of monitor | |
| 247 | -- color - text color | |
| 248 | -- text - text to write | |
| 249 | -- | |
| 250 | local function writeColor(mon, color, text) | |
| 251 | if mon.isColor() then | |
| 252 | mon.setTextColor(color) | |
| 253 | end | |
| 254 | mon.write(text) | |
| 255 | if mon.isColor() then | |
| 256 | mon.setTextColor(colors.white) | |
| 257 | end | |
| 258 | end | |
| 259 | ||
| 260 | ||
| 261 | -- | |
| 262 | -- Scale the monitor text size to needed size of output text. | |
| 263 | -- | |
| 264 | -- This function try to scale the monitor text size, so that it is enoth for | |
| 265 | -- "optHeight" lines with "optWidth" characters. If it is not possible | |
| 266 | -- (text scale is not supported or the connected monitor is too small), | |
| 267 | -- it also accept "minHeight" lines and "minWidth" characters. | |
| 268 | -- | |
| 269 | -- Parameters: | |
| 270 | -- mon - handle of monitor. | |
| 271 | -- minWidth - Minimum number of columns needed. | |
| 272 | -- optWidth - Optimal number of columns desired. | |
| 273 | -- minHeight - Minimum number of rows needed. | |
| 274 | -- optHeight - Optimal number of rows desired. | |
| 275 | -- | |
| 276 | -- Return: | |
| 277 | -- Size of monitor after scaling: width, height. | |
| 278 | -- If the monitor is too small, it returns nul,nil. | |
| 279 | -- | |
| 280 | local function scaleMonitor(mon, minWidth, optWidth, minHeight, optHeight) | |
| 281 | if mon.setTextScale ~= nil then | |
| 282 | mon.setTextScale(1) | |
| 283 | end | |
| 284 | ||
| 285 | local width, height = mon.getSize() | |
| 286 | ||
| 287 | if mon.setTextScale == nil then | |
| 288 | -- Scale not available | |
| 289 | if width < minWidth or height < minHeight then | |
| 290 | return nil, nil -- too small | |
| 291 | else | |
| 292 | return width, height | |
| 293 | end | |
| 294 | end | |
| 295 | ||
| 296 | if width < optWidth or height < optHeight then | |
| 297 | -- too small: try to scale down. | |
| 298 | mon.setTextScale(0.5) | |
| 299 | ||
| 300 | width, height = mon.getSize() | |
| 301 | if width < minWidth or height < minHeight then | |
| 302 | return nil, nil -- still too small | |
| 303 | end | |
| 304 | else | |
| 305 | -- Huge monitors? Try to scale up, if possible (max scale=5). | |
| 306 | local scale = math.min(width / optWidth, height / optHeight, 5) | |
| 307 | scale = math.floor(scale * 2) / 2 -- multiple of 0.5 | |
| 308 | ||
| 309 | if scale > 1 then | |
| 310 | mon.setTextScale(scale) | |
| 311 | width, height = mon.getSize() | |
| 312 | end | |
| 313 | end | |
| 314 | ||
| 315 | return width, height | |
| 316 | end | |
| 317 | ||
| 318 | ||
| 319 | -- Display turbine status to a monitor | |
| 320 | -- | |
| 321 | -- Parameters: | |
| 322 | -- mon - Wraped handle of monitor | |
| 323 | -- turbine - Wraped handle of turbine. | |
| 324 | -- tSpeed - Target speed. | |
| 325 | -- | |
| 326 | local function displayStateOnMonitor(mon, turbine, tSpeed) | |
| 327 | ||
| 328 | -- scale it, if possible. | |
| 329 | local width, height = scaleMonitor(mon, 15, 16, 5, 5) | |
| 330 | ||
| 331 | if width == nil or height == nil then | |
| 332 | return -- Montitor is too small | |
| 333 | end | |
| 334 | ||
| 335 | mon.clear() | |
| 336 | ||
| 337 | mon.setCursorPos(1,1) | |
| 338 | mon.write("Turbine: ")
| |
| 339 | if tSpeed == 0 then | |
| 340 | writeColor(mon, colors.red, "off") | |
| 341 | else | |
| 342 | writeColor(mon, colors.green, string.format("%d", tSpeed))
| |
| 343 | if width > 16 then | |
| 344 | mon.write(" RPM")
| |
| 345 | end | |
| 346 | end | |
| 347 | ||
| 348 | mon.setCursorPos(1,3) | |
| 349 | local speed = math.floor(turbine.getRotorSpeed()*10+0.5)/10 | |
| 350 | mon.write("Speed: ")
| |
| 351 | if (speed == tSpeed) then | |
| 352 | writeColor(mon, colors.green, speed) | |
| 353 | else | |
| 354 | writeColor(mon, colors.orange, speed) | |
| 355 | end | |
| 356 | if width > 16 then | |
| 357 | mon.write(" RPM")
| |
| 358 | end | |
| 359 | ||
| 360 | local maxFlow = turbine.getFluidFlowRateMax() | |
| 361 | local actFlow = turbine.getFluidFlowRate() | |
| 362 | if width >= 16 then | |
| 363 | -- bigger monitor | |
| 364 | mon.setCursorPos(1,4) | |
| 365 | mon.write("MFlow: " .. string.format("%d", maxFlow) .. " mB/t")
| |
| 366 | ||
| 367 | mon.setCursorPos(1,5) | |
| 368 | mon.write("AFlow: ")
| |
| 369 | if actFlow < maxFlow then | |
| 370 | writeColor(mon, colors.red, string.format("%d", actFlow))
| |
| 371 | else | |
| 372 | writeColor(mon, colors.green, string.format("%d", actFlow))
| |
| 373 | end | |
| 374 | mon.write(" mB/t")
| |
| 375 | else | |
| 376 | -- 1x1 monitor | |
| 377 | mon.setCursorPos(1,4) | |
| 378 | mon.write("Flow (act/max):")
| |
| 379 | mon.setCursorPos(1,5) | |
| 380 | mon.write("(")
| |
| 381 | ||
| 382 | if actFlow < maxFlow then | |
| 383 | writeColor(mon, colors.red, string.format("%d",actFlow))
| |
| 384 | else | |
| 385 | writeColor(mon, colors.green, string.format("%d",actFlow))
| |
| 386 | end | |
| 387 | ||
| 388 | mon.write("/")
| |
| 389 | mon.write(string.format("%d", maxFlow))
| |
| 390 | mon.write(" mB/t)")
| |
| 391 | end | |
| 392 | ||
| 393 | end | |
| 394 | ||
| 395 | ||
| 396 | -- Display turbine status to any connected monitor and also to console. | |
| 397 | -- | |
| 398 | -- Parameters: | |
| 399 | -- turbine - Wraped handle of turbine. | |
| 400 | -- tSpeed - Target speed. | |
| 401 | -- | |
| 402 | function displayState(turbine, tSpeed) | |
| 403 | displayStateOnMonitor(term, turbine, tSpeed) | |
| 404 | term.setCursorPos(1,7) | |
| 405 | term.write("* Keys: [o]ff, [m]edium (900), [f]ast (1800)")
| |
| 406 | term.setCursorPos(1,8) | |
| 407 | ||
| 408 | local pList = peripheral.getNames() | |
| 409 | local i, name | |
| 410 | for i, name in pairs(pList) do | |
| 411 | if peripheral.getType(name) == "monitor" then | |
| 412 | -- found monitor as peripheral | |
| 413 | displayStateOnMonitor(peripheral.wrap(name), turbine, tSpeed) | |
| 414 | end | |
| 415 | end | |
| 416 | end | |
| 417 | ||
| 418 | -- | |
| 419 | -- Test the speedup time of the turbine. | |
| 420 | -- | |
| 421 | -- Parameters: | |
| 422 | -- turbine - Wraped handle of turbine. | |
| 423 | -- loopT - Loop timer. | |
| 424 | -- tSpeed - Target speed | |
| 425 | local function testSpeedup(turbine, loopT, tSpeed) | |
| 426 | turbine.setFluidFlowRateMax(maxFRate) | |
| 427 | ||
| 428 | if turbine.setInductorEngaged then | |
| 429 | -- always engage coil | |
| 430 | turbine.setInductorEngaged(true) | |
| 431 | end | |
| 432 | ||
| 433 | local KpSum=0 | |
| 434 | local nKp=0 | |
| 435 | local oldSpeed=-1 | |
| 436 | ||
| 437 | for i=0,5 do | |
| 438 | displayState(turbine, tSpeed) | |
| 439 | speed = turbine.getRotorSpeed() | |
| 440 | if oldSpeed >= 0 then | |
| 441 | KpSum = KpSum + (speed-oldSpeed) | |
| 442 | nKp = nKp + 1 | |
| 443 | end | |
| 444 | oldSpeed = speed | |
| 445 | sleep(loopT) | |
| 446 | end | |
| 447 | ||
| 448 | if KpSum * loopT / nKp > 5 then | |
| 449 | -- Too fast: increase loop speed | |
| 450 | loopT = 5 * nKp / KpSum | |
| 451 | return 5, loopT | |
| 452 | else | |
| 453 | return (KpSum / nKp), loopT | |
| 454 | end | |
| 455 | end | |
| 456 | ||
| 457 | ||
| 458 | -- | |
| 459 | -- Main program | |
| 460 | -- | |
| 461 | ||
| 462 | sleep(2) -- wait for 2s | |
| 463 | ||
| 464 | -- wrap turbine | |
| 465 | turbine = getTurbineHandle() | |
| 466 | ||
| 467 | searchAndOpenModems() -- search and open any modem. | |
| 468 | ||
| 469 | if restoreControllerState() == false then | |
| 470 | -- restore of old values failed. | |
| 471 | tSpeed = 0 | |
| 472 | Kp=0 | |
| 473 | end | |
| 474 | ||
| 475 | ||
| 476 | maxFRate = turbine.getFluidFlowRateMaxMax() | |
| 477 | while true do | |
| 478 | displayState(turbine, tSpeed) | |
| 479 | ||
| 480 | if tSpeed ~= 0 then | |
| 481 | -- calculate PID controller | |
| 482 | local speed = turbine.getRotorSpeed() | |
| 483 | ||
| 484 | err = tSpeed - speed | |
| 485 | local errSumOld = errSum | |
| 486 | errSum = errSum + err | |
| 487 | ||
| 488 | if useDisengageCoils | |
| 489 | and floatRateChanged | |
| 490 | and err > 0 | |
| 491 | and turbine.setInductorEngaged | |
| 492 | then | |
| 493 | -- Turbine startup: disengage coils | |
| 494 | turbine.setInductorEngaged(false) | |
| 495 | end | |
| 496 | ||
| 497 | if turbine.setInductorEngaged and err < 0 then | |
| 498 | -- speed too fast: engage coils | |
| 499 | turbine.setInductorEngaged(true) | |
| 500 | end | |
| 501 | ||
| 502 | local p = Kp * err | |
| 503 | local i = Ki * loopT * errSum | |
| 504 | local d = Kd * (err - errOld) * loopT | |
| 505 | ||
| 506 | if i < 0 or i > maxFRate then | |
| 507 | errSum=errSumOld -- error too heavy => reset to old value. | |
| 508 | i = Ki * loopT * errSum | |
| 509 | end | |
| 510 | ||
| 511 | local fRate = p + i + d | |
| 512 | errOld = err | |
| 513 | ||
| 514 | ||
| 515 | -- cut extreme flow rates. | |
| 516 | if fRate < 0 then | |
| 517 | fRate = 0 | |
| 518 | elseif fRate > maxFRate then | |
| 519 | fRate = maxFRate | |
| 520 | end | |
| 521 | ||
| 522 | turbine.setFluidFlowRateMax(fRate) | |
| 523 | ||
| 524 | tID = os.startTimer(loopT) -- Wait for loopT secounds. | |
| 525 | else | |
| 526 | -- Turbine switched off: | |
| 527 | tID = os.startTimer(displayT) -- Wait for displayT secounds. | |
| 528 | end | |
| 529 | ||
| 530 | saveControllerState() | |
| 531 | floatRateChanged = false | |
| 532 | repeat | |
| 533 | -- Event loop | |
| 534 | local evt, p1, p2, p3, p4, p5 = os.pullEvent() | |
| 535 | if evt == "char" then | |
| 536 | -- character typed | |
| 537 | local oldTSpeed = tSpeed | |
| 538 | if p1 == "o" then -- off | |
| 539 | tSpeed = 0 | |
| 540 | turbine.setActive(false) | |
| 541 | saveControllerState() | |
| 542 | elseif p1 == "m" then -- medium speed = 900 RPM | |
| 543 | turbine.setActive(true) | |
| 544 | tSpeed = 900 | |
| 545 | floatRateChanged=true | |
| 546 | elseif p1 == "f" then -- fast speed = 1800 RPM | |
| 547 | turbine.setActive(true) | |
| 548 | tSpeed = 1800 | |
| 549 | floatRateChanged=true | |
| 550 | end | |
| 551 | ||
| 552 | if turbine.setInductorEngaged then | |
| 553 | -- engage coil by default | |
| 554 | turbine.setInductorEngaged(true) | |
| 555 | end | |
| 556 | ||
| 557 | ||
| 558 | if (p1 == "m" or p1 == "f") and tSpeed ~= oldTSpeed then | |
| 559 | -- Initialize PID controller values | |
| 560 | if Kp == 0 then | |
| 561 | Kp, loopT = testSpeedup(turbine, loopT, tSpeed) | |
| 562 | end | |
| 563 | ||
| 564 | initControllerValues() | |
| 565 | ||
| 566 | errSum = 0 | |
| 567 | errOld = 0 | |
| 568 | ||
| 569 | saveControllerState() | |
| 570 | end | |
| 571 | elseif evt == "modem_message" | |
| 572 | and stateRequestChannel >= 0 | |
| 573 | and stateRequestChannel == p2 | |
| 574 | and tostring(p4) == "BR_turbine_get_state" | |
| 575 | then | |
| 576 | -- Send status informations | |
| 577 | local cLabel = os.getComputerLabel() | |
| 578 | if cLabel == nil then | |
| 579 | -- No label: use coputer number (ID) as tio create a name | |
| 580 | cLabel = "ComputerID:" .. tostring(os.getComputerID()) | |
| 581 | end | |
| 582 | ||
| 583 | if turbine.getInductorEngaged ~= nil then | |
| 584 | inductorEngaged = turbine.getInductorEngaged() | |
| 585 | else | |
| 586 | inductorEngaged = nil | |
| 587 | end | |
| 588 | ||
| 589 | -- State structure | |
| 590 | local rState = {
| |
| 591 | version = "Turbine V0.1", -- Version of data structure | |
| 592 | label = cLabel, | |
| 593 | computerId = os.getComputerID(), | |
| 594 | remoteControl = remoteControl, | |
| 595 | active = turbine.getActive(), | |
| 596 | tSpeed = tSpeed, | |
| 597 | energyStored = turbine.getEnergyStored(), | |
| 598 | rotorSpeed = turbine.getRotorSpeed(), | |
| 599 | inputAmount = turbine.getInputAmount(), | |
| 600 | inputType = turbine.getInputType(), | |
| 601 | outputAmount = turbine.getOutputAmount(), | |
| 602 | outputType = turbine.getOutputType(), | |
| 603 | fluidAmountMax = turbine.getFluidAmountMax(), | |
| 604 | fluidFlowRate = turbine.getFluidFlowRate(), | |
| 605 | fluidFlowRateMax = turbine.getFluidFlowRateMax(), | |
| 606 | fluidFlowRateMaxMax = turbine.getFluidFlowRateMaxMax(), | |
| 607 | energyProducedLastTick = turbine.getEnergyProducedLastTick(), | |
| 608 | inductorEngaged = inductorEngaged | |
| 609 | } | |
| 610 | ||
| 611 | peripheral.call(p1, "transmit", p3, stateRequestChannel, | |
| 612 | textutils.serialize(rState)) | |
| 613 | elseif evt == "modem_message" | |
| 614 | and remoteControl | |
| 615 | and p2 == os.getComputerID() | |
| 616 | and string.sub(tostring(p4), 1, 21) == "BR_turbine_set_speed:" | |
| 617 | then | |
| 618 | -- Remote Request: Speed change | |
| 619 | local oldTSpeed = tSpeed | |
| 620 | tSpeed = tonumber(string.sub(tostring(p4), 22)) | |
| 621 | if (tSpeed == 0) then | |
| 622 | turbine.setActive(false) | |
| 623 | saveControllerState() | |
| 624 | else | |
| 625 | turbine.setActive(true) | |
| 626 | floatRateChanged=true | |
| 627 | end | |
| 628 | ||
| 629 | if tSpeed ~= 0 and tSpeed ~= oldTSpeed then | |
| 630 | -- Initialize PID controller values | |
| 631 | if Kp == 0 then | |
| 632 | Kp = testSpeedup(turbine, loopT, tSpeed) | |
| 633 | end | |
| 634 | ||
| 635 | initControllerValues() | |
| 636 | ||
| 637 | errSum = 0 | |
| 638 | errOld = 0 | |
| 639 | ||
| 640 | saveControllerState() | |
| 641 | end | |
| 642 | ||
| 643 | if turbine.setInductorEngaged then | |
| 644 | -- engage coil by default | |
| 645 | turbine.setInductorEngaged(true) | |
| 646 | end | |
| 647 | elseif evt == "peripheral" | |
| 648 | and peripheral.getType(p1) == "modem" | |
| 649 | and stateRequestChannel >= 0 | |
| 650 | then | |
| 651 | -- new modem connected | |
| 652 | peripheral.call(p1, "open", stateRequestChannel) | |
| 653 | peripheral.call(p1, "open", os.getComputerID()) | |
| 654 | end | |
| 655 | ||
| 656 | -- exit loop on timer event or float rate change | |
| 657 | until (evt == "timer" and p1 == tID) or floatRateChanged | |
| 658 | end | |
| 659 | ||
| 660 | -- | |
| 661 | -- EOF | |
| 662 | -- |