One-command installer + guided setup: role detection, self-flying sign test v2

- install.lua: single entry point -- detects role from peripherals
  (flight sensors = autopilot, monitor = cockpit), installs, cleans
  legacy/removed files, then hands off straight into setup/standby.
  Ship state (sides/calib/target/settings) is never shipped; existing
  profiles can be kept or reset on re-install.
- Sign test v2: fully self-driving -- staircase power search (learns
  hover), closed-loop climb, both-direction verification with auto-
  escalating nudge, controlled descent. Never freefalls, also not on
  Ctrl+T or abort.
- Setup wizard (ap setup): wiring pulse-walk + sign test in one guided
  flow; offered automatically on first boot without a profile.
- New launcher 'ap' (stabilizeV2 kept as case-safe identical aliases;
  removes Windows-host case-collision recursion risk).
- build.sh: repo is source of truth; LC_ALL=C sorted manifests;
  optional --from-world/--to-world dev sync with exclude lists.
- Removed legacy v1 files and per-ship state from the repo/manifest
  (26 -> 17 files in the autopilot role).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 23:21:54 +02:00
parent 71e750bbe0
commit 54963e5b42
24 changed files with 617 additions and 1135 deletions

View File

@@ -1,19 +1,35 @@
-- install.lua -- role-based installer for the Create: Aeronautics airship autopilot.
-- Fetches every file for the chosen role over HTTP and writes it to this computer,
-- so it works on any server regardless of the computer's id. Re-run to update.
-- install.lua -- ETT entry-point for hele autopiloten. Samme kommando paa begge PC-er:
--
-- Usage on a CC computer:
-- wget run https://gt.zyon.no/Stian/airship-autopilot/raw/branch/main/install.lua
-- wget run https://gt.zyon.no/Stian/airship-autopilot/raw/branch/main/install.lua autopilot
-- wget run https://gt.zyon.no/Stian/airship-autopilot/raw/branch/main/install.lua cockpit
--
-- Installeren DETEKTERER selv hvilken PC den staar paa (flysensorer = autopilot,
-- monitor = cockpit), installerer riktig rolle, og gaar RETT videre i setup/oppstart --
-- ingen reboot, ingen rollenavn aa huske. Re-run samme kommando for aa oppdatere.
-- Eksplisitt rolle som argument overstyrer deteksjonen (avansert):
-- wget run .../install.lua autopilot | cockpit
--
-- Roles:
-- autopilot machine-room PC: full v3 observer autopilot (boots to standby)
-- cockpit pilot-house PC: control console
-- autopilot machine-room PC: full v3 observer autopilot (setup wizard / standby)
-- cockpit pilot-house PC: control console (monitor + modem)
--
-- Per-skip TILSTAND (sides/calib/target/settings) shippes ALDRI av installeren -- den maales
-- av setup-wizarden PAA skipet. Ved re-install kan profilen beholdes eller nullstilles.
-- Filer som er fjernet fra manifestet siden sist (eller kjente legacy-filer) ryddes bort.
local BASE = "https://gt.zyon.no/Stian/airship-autopilot/raw/branch/main"
local ROLES = { "autopilot", "cockpit" }
-- per-skip tilstand: roeres aldri automatisk, men tilbys nullstilt ved install
local STATE_FILES = { "sides.txt", "calib.txt", "target.txt", "settings.txt" }
-- kjente filer fra eldre versjoner som ikke lenger hoerer til rollen (engangs-rydding;
-- videre oppdateringer ryddes automatisk via installasjons-loggen .installed_<role>)
local LEGACY = {
autopilot = { "stabilize.lua", "diag.lua", "probe.lua", "scan.lua", "scan.txt",
"pid_gains.txt", "cockpit.lua", "pilot_startup.lua" },
cockpit = {},
}
local args = { ... }
-- ---- helpers ---------------------------------------------------------------
@@ -41,9 +57,17 @@ local function writeFile(path, data)
f.close()
end
local function inList(list, x)
for _, v in ipairs(list) do if v == x then return true end end
return false
end
local function chooseRole()
print("Select role to install:")
for i, r in ipairs(ROLES) do print((" %d) %s"):format(i, r)) end
print(" 1) autopilot (machine room -- has the")
print(" altitude + gimbal sensors)")
print(" 2) cockpit (pilot house -- has a")
print(" monitor + modem)")
write("> ")
local sel = read()
local n = tonumber(sel)
@@ -52,6 +76,18 @@ local function chooseRole()
die("Unknown role: " .. tostring(sel))
end
-- gjett rollen ut fra hva som er koblet til: flysensorer er det sterkeste signalet
-- (maskinrommet kan ogsaa ha monitor), deretter monitor -> cockpit
local function detectRole()
if peripheral.find("altitude_sensor") or peripheral.find("gimbal_sensor") then
return "autopilot", "flight sensors attached"
end
if peripheral.find("monitor") then
return "cockpit", "monitor attached, no flight sensors"
end
return nil
end
-- ---- preflight -------------------------------------------------------------
if not http then
@@ -61,12 +97,23 @@ if not http then
end
local role = args[1]
if not role then
role = chooseRole()
else
if role then
local ok = false
for _, r in ipairs(ROLES) do if r == role then ok = true end end
if not ok then die("Unknown role '" .. role .. "'. Valid: " .. table.concat(ROLES, ", ")) end
else
local guess, why = detectRole()
if guess then
print("This looks like the " ..
(guess == "autopilot" and "MACHINE-ROOM" or "PILOT-HOUSE") .. " PC")
print(" (" .. why .. ")")
write("Install '" .. guess .. "'? [Y/n] ")
role = (read():lower() == "n") and chooseRole() or guess
else
print("Could not auto-detect this PC's role")
print("(no flight sensors or monitor attached).")
role = chooseRole()
end
end
-- ---- fetch manifest --------------------------------------------------------
@@ -108,8 +155,57 @@ if #fail > 0 then
die("Install incomplete -- re-run after fixing the errors above.")
end
-- ---- rydd: legacy + filer fjernet fra manifestet siden forrige install ------
local removed = 0
for _, f in ipairs(LEGACY[role] or {}) do
if fs.exists(f) then fs.delete(f); removed = removed + 1; print("removed legacy: " .. f) end
end
local RECORD = ".installed_" .. role
if fs.exists(RECORD) then
local rf = fs.open(RECORD, "r"); local prev = rf.readAll(); rf.close()
for line in (prev or ""):gmatch("[^\r\n]+") do
local p = line:match("^%s*(.-)%s*$")
if p ~= "" and not inList(files, p) and not inList(STATE_FILES, p) and fs.exists(p) then
fs.delete(p); removed = removed + 1; print("removed obsolete: " .. p)
end
end
end
writeFile(RECORD, table.concat(files, "\n") .. "\n")
if removed > 0 then print(("Cleaned up %d old file(s)."):format(removed)) end
-- ---- skip-profil: behold eller nullstill (ETTER vellykket install, foer boot) ----
-- (kun autopilot-rollen har skip-tilstand; sletter aldri noe hvis nedlastingen feilet)
if role == "autopilot" then
local found = {}
for _, f in ipairs(STATE_FILES) do if fs.exists(f) then found[#found + 1] = f end end
if #found > 0 then
print("Existing ship profile found:")
print(" " .. table.concat(found, ", "))
write("Keep it? (n = new/rewired ship) [Y/n] ")
if read():lower() == "n" then
for _, f in ipairs(found) do fs.delete(f) end
print("Profile reset -- the setup wizard takes over.")
end
end
end
-- ---- ferdig: gaa RETT videre (ingen reboot noedvendig) ----------------------
-- startup.lua er installert, saa alt auto-starter ved fremtidige reboots; naa
-- fortsetter vi direkte inn i samme flyt som boot ville gitt.
term.setTextColor(colors.green)
print("Done. Reboot to auto-start (startup.lua).")
print("Done. (auto-starts on every reboot)")
term.setTextColor(colors.white)
write("Reboot now? [y/N] ")
if read():lower() == "y" then os.reboot() end
print("")
if role == "autopilot" then
print("Continuing into setup/standby...")
sleep(1.0)
shell.run("ap", "boot")
else
print("Starting the pilot console...")
sleep(1.0)
shell.run("cockpit")
end