--[[
神龙反应堆控制器(ComputerCraft: Tweaked 版)
作者:ChatGPT
结构:双PID + 预测辅助安全限幅
依赖接口:
reactor: activateReactor(), chargeReactor(), getReactorInfo(), stopReactor(), toggleFailSafe()
flow_gate: getFlow(), setFlowOverride(), setOverrideEnabled(), getOverrideEnabled()
--]]
-- ===== 手动 peripheral 配置 =====
local reactor = peripheral.wrap("reactor_0")
local inGate = peripheral.wrap("flow_gate_in")
local outGate = peripheral.wrap("flow_gate_out")
local monitor = peripheral.wrap("monitor_0") -- 可选
-- ===== 参数配置 =====
local TARGET_TEMP = 8000
local TARGET_FIELD = 0.05
local SAFETY_TEMP = 8300
local MIN_FIELD = 0.02
local CHARGE_INPUT_MAX = 64000000
local MAIN_SLEEP = 0.2
local GUI_UPDATE_INTERVAL = 0.5
local PREDICT_STEPS = 10
local ALLOW_TOUCH_START = true
-- ===== 反应堆信息封装 =====
local function info() return reactor.getReactorInfo() end
local function temp() return info().temperature or 0 end
local function field() return info().fieldStrength or 0 end
local function fieldMax() return info().maxFieldStrength or 1 end
local function energy() return info().energySaturation or 0 end
local function energyMax() return info().maxEnergySaturation or 1 end
local function genRate() return info().generationRate or 0 end
local function status() return tostring(info().status) end
-- ===== PID 控制 =====
local function newPID(kp,ki,kd)
return {kp=kp,ki=ki,kd=kd,lastErr=0,int=0,step=function(self,target,cur,dt)
local e=target-cur
self.int=self.int+e*dt
local d=(e-self.lastErr)/dt
self.lastErr=e
return self.kp*e+self.ki*self.int+self.kd*d
end}
end
-- 主PID(温控基于能空率)
local pidTemp = newPID(0.5,0.02,0.3)
-- 次PID(场强维持)
local pidField = newPID(20000000,10000,0)
-- ===== 预测模块(辅助限幅) =====
local function predict(steps)
local t=temp()
local f=field()
local e=energy()
local fmax=fieldMax()
local emax=energyMax()
for _=1,steps do
local erate=(1-e/emax)*99
local trate=(t/20000)*50
local upIndex=(erate^3)/(100-erate+1e-9)+444.7
local upResist=(trate^4)/(100-trate+1e-9)
local rise=(upIndex+upResist*(0.5-1))/1000+0.5
t=t+rise
f=f-(1-e/emax)
e=e+(1-(e/emax))*5000
end
return t,f
end
-- ===== 控制函数 =====
local function setIn(v)
if not inGate then return end
if v<0 then v=0 end
if v>CHARGE_INPUT_MAX then v=CHARGE_INPUT_MAX end
inGate.setFlowOverride(v)
inGate.setOverrideEnabled(true)
end
local function setOut(v)
if not outGate then return end
if v<0 then v=0 end
if v>CHARGE_INPUT_MAX then v=CHARGE_INPUT_MAX end
outGate.setFlowOverride(v)
outGate.setOverrideEnabled(true)
end
-- ===== 状态机 =====
local function emergency(reason)
print("!!! 紧急停机: "..reason)
setOut(0)
setIn(CHARGE_INPUT_MAX)
reactor.stopReactor()
end
local function tryActivate()
local fi=field()/fieldMax()
local ei=energy()/energyMax()
if fi>=0.5 and ei>=0.5 and temp()>=2500 then
reactor.activateReactor()
return true
end
end
-- ===== GUI =====
local function draw()
if not monitor then return end
monitor.setTextScale(1)
monitor.clear()
monitor.setCursorPos(1,1)
monitor.write("神龙反应堆控制")
monitor.setCursorPos(1,2)
monitor.write("状态: "..status())
monitor.setCursorPos(1,3)
monitor.write(string.format("温度: %.1fC",temp()))
monitor.setCursorPos(1,4)
monitor.write(string.format("场强: %.2f%%",(field()/fieldMax())*100))
monitor.setCursorPos(1,5)
monitor.write(string.format("能量: %.2f%%",(energy()/energyMax())*100))
monitor.setCursorPos(1,7)
monitor.write("[触摸底部启动/停止]")
end
-- ===== 主循环 =====
local manualStart, manualStop=false,false
local function monitorTouch()
if not monitor then return end
while true do
local _,side,x,y=os.pullEvent("monitor_touch")
if y>=7 then
if status()=="running" then manualStop=true else manualStart=true end
end
end
end
local function main()
local running=false
while true do
draw()
local st=status()
local T=temp()
local fRatio=field()/fieldMax()
local eRatio=energy()/energyMax()
-- 安全检查
if st=="running" and (T>=SAFETY_TEMP or fRatio=SAFETY_TEMP)
local outAdj=pidTemp:step(TARGET_TEMP,T,MAIN_SLEEP)
if predictedOverheat then
outAdj=outAdj*0.2 -- 限幅抑制
end
local outFlow=math.max(0,math.min(CHARGE_INPUT_MAX,genRate()+outAdj*1000))
setOut(outFlow)
-- 次PID:控制场强维持
local inAdj=pidField:step(TARGET_FIELD,fRatio,MAIN_SLEEP)
if predF/fieldMax()