init basic

This commit is contained in:
2026-06-07 02:33:22 +03:00
commit f4e525b035
2 changed files with 371 additions and 0 deletions

258
AirlockRTL.lua Normal file
View File

@@ -0,0 +1,258 @@
-- Airlock control v2.0
-- Физическая раскладка шлюза:
-- Слева — большая внешняя дверь (наружу, под воду)
-- Справа (изнутри) — стеклянная внутренняя дверь (внутрь станции)
-- Кнопки внутри шлюза (слева направо):
-- Пин 3 = левая кнопка = внутренняя (вход 4)
-- Пин 4 = средняя кнопка = правая внутри (вход 3)
-- Пин 5 = наружная правая кнопка снаружи (вход 5)
-- === Состояния ===
-- IDLE — вода ~0%, обе двери закрыты. Ожидание команды.
-- FLOODING — насос качает воду внутрь (подготовка к выходу). "Затопление"
-- READY_OUT — вода ≥95%, внутр.дверь закрыта, внешн. закрыта. "Готов вых"
-- READY_IN — вода ≥95%, внутр.дверь закрыта, внешн. ОТКРЫТА. "Готов Вх"
-- DRAINING — насос откачивает воду (после входа снаружи). "Осушение"
-- FAULT — нештатная ситуация. "Неисправен"
-- === Входы ===
-- 1 — левая дверь (внешняя): 0=закрыта, 1=открыта
-- 2 — правая дверь (внутренняя): 0=закрыта, 1=открыта
-- 3 — правая кнопка (внутри, пин 4)
-- 4 — внутренняя кнопка (внутри, левая, пин 3)
-- 5 — наружная правая кнопка (снаружи, пин 5)
-- 6 — уровень воды в шлюзе (-100..100)
-- === Выходы ===
-- 1 — внешняя дверь: 1=открыть, 0=закрыть
-- 2 — внутренняя дверь: 1=открыть, 0=закрыть
-- 3 — насос: 1=вкл, 0=выкл
-- 4 — целевой уровень воды (-100 сухо, 100 заполнен)
-- 5 — текст статуса
-- 6 — цвет текста (rrr,ggg,bbb)
inp = {}
--out = {
--[1] = 0,
--[2] = 0,
--[3] = 0,
--[4] = 0,
--[5] = "",
--[6] = "100,180,100",
--}
-- Константы задержек (сек)
local MIN_FLOOD_TIME = 4.0
local MIN_DRAIN_TIME = 4.0
local INTERNAL_DOOR_DELAY = 4.0
local FAULT_HYSTERESIS = 2.0
local S = {
IDLE = 0,
FLOODING = 1,
READY_OUT = 2,
READY_IN = 3,
DRAINING = 4,
FAULT = 5,
}
local state = S.IDLE
local stateTimer = 0.0
local doorTimer = 0.0
local openIntDoor= false -- флаг: открыть внутреннюю дверь (пропустить человека)
-- Детекция фронта кнопок
local prevBtn = { [3] = 0, [4] = 0, [5] = 0 }
local btnEdge = { [3] = 0, [4] = 0, [5] = 0 }
local STATUS_TEXT = {
[S.IDLE] = "",
[S.FLOODING] = "Затопление",
[S.READY_OUT] = "Готов вых",
[S.READY_IN] = "Готов Вх",
[S.DRAINING] = "Осушение",
[S.FAULT] = "Неисправен",
}
local STATUS_COLOR = {
[S.IDLE] = "100,180,100",
[S.FLOODING] = "255,165,0",
[S.READY_OUT] = "0,200,50",
[S.READY_IN] = "0,200,200",
[S.DRAINING] = "0,100,255",
[S.FAULT] = "200,0,0",
}
local function setOutputs(d1, d2, pump, target)
out[1] = d1 and 1 or 0
out[2] = d2 and 1 or 0
out[3] = pump and 1 or 0
out[4] = target or 0
end
local function setStatus(s)
out[5] = STATUS_TEXT[s] or ""
out[6] = STATUS_COLOR[s] or STATUS_COLOR[S.FAULT]
end
local function gotoState(s)
if state == s then return end
state = s
stateTimer = 0.0
end
-- Аварийные условия
local function checkFault(water, leftDoor, rightDoor)
if rightDoor == 1 and water > 10 then return true end
if leftDoor == 1 and rightDoor == 1 then return true end
if leftDoor == 1 and water < 50 then return true end
return false
end
function upd(dt)
-- Чтение входов
local leftDoor = inp[1] or 0
local rightDoor = inp[2] or 0
local btnRight = inp[3] or 0
local btnInternal= inp[4] or 0
local btnExternal= inp[5] or 0
local water = inp[6] or 0
-- Детекция фронтов
for _, p in ipairs({3,4,5}) do
local v = inp[p] or 0
btnEdge[p] = (v == 1 and prevBtn[p] == 0) and 1 or 0
prevBtn[p] = v
end
stateTimer = stateTimer + dt
-- === Аварийный контроль (высший приоритет) ===
if checkFault(water, leftDoor, rightDoor) then
gotoState(S.FAULT)
end
if state == S.FAULT and not checkFault(water, leftDoor, rightDoor)
and stateTimer > FAULT_HYSTERESIS then
gotoState(S.IDLE)
end
-- === Логика состояний ===
-- IDLE
if state == S.IDLE then
-- Если дверь открывали для пропуска — закрыть по таймеру
if openIntDoor then
doorTimer = doorTimer + dt
openIntDoor = doorTimer < INTERNAL_DOOR_DELAY
end
if btnEdge[4] == 1 then
-- Внутренняя кнопка → подготовка к выходу (затопление)
setOutputs(false, false, true, 100)
gotoState(S.FLOODING)
elseif btnEdge[5] == 1 then
-- Наружная кнопка → открыть внешнюю дверь, впустить воду
setOutputs(true, false, false, 0)
gotoState(S.FLOODING)
elseif leftDoor == 1 then
-- Внешнюю открыли вручную — подтверждаем и начинаем заполнение
out[1] = 1
gotoState(S.FLOODING)
else
-- Ручное управление внутренней дверью (для пропуска)
setOutputs(false, openIntDoor, false, 0)
setStatus(S.IDLE)
end
-- FLOODING
-- Внешнюю дверь НЕ трогаем — она уже установлена при входе в состояние:
-- закрыта (выход — закачка насосом) или открыта (вход — естественное заполнение)
elseif state == S.FLOODING then
out[2] = 0
out[3] = 1
out[4] = 100
-- Если дверь открыли вручную — подтверждаем, иначе привод будет бороться
if leftDoor == 1 then out[1] = 1 end
setStatus(S.FLOODING)
if btnEdge[3] == 1 then
-- Правая кнопка → отмена, сброс
setOutputs(false, false, false, 0)
gotoState(S.IDLE)
end
if water >= 95 and stateTimer >= MIN_FLOOD_TIME then
if leftDoor == 1 then
-- Внешняя открыта, вода есть → готовность к входу
gotoState(S.READY_IN)
else
-- Внешняя закрыта, вода закачана насосом → готовность к выходу
gotoState(S.READY_OUT)
end
end
-- READY_OUT
-- Не перезаписываем out[1] — внешняя дверь открывается однократно по кнопке
elseif state == S.READY_OUT then
out[2] = 0
out[3] = 0
out[4] = 100
setStatus(S.READY_OUT)
if btnEdge[3] == 1 then
out[1] = 1 -- открыть внешнюю дверь (выход)
end
if leftDoor == 1 then
gotoState(S.READY_IN)
end
if btnEdge[4] == 1 then
out[1] = 0
out[3] = 1
out[4] = -100
gotoState(S.DRAINING)
end
-- READY_IN
elseif state == S.READY_IN then
setOutputs(true, false, false, 100)
setStatus(S.READY_IN)
if leftDoor == 0 then
-- Внешняя закрыта (человек зашёл) → осушение
setOutputs(false, false, true, -100)
gotoState(S.DRAINING)
elseif btnEdge[3] == 1 then
-- Правая кнопка → закрыть внешнюю дверь и начать осушение
setOutputs(false, false, true, -100)
gotoState(S.DRAINING)
end
-- DRAINING
elseif state == S.DRAINING then
setOutputs(false, false, true, -100)
setStatus(S.DRAINING)
if btnEdge[3] == 1 then
-- Правая кнопка → отмена осушения
setOutputs(false, false, false, 0)
gotoState(S.IDLE)
end
if water <= 5 and stateTimer >= MIN_DRAIN_TIME then
openIntDoor = true
doorTimer = 0.0
gotoState(S.IDLE)
end
-- FAULT
elseif state == S.FAULT then
setOutputs(false, false, false, 0)
setStatus(S.FAULT)
end
end