re(flight): port the roll probe to the file pad, and drive fly_stage.sh to flight
roll_axis.py was written last session to re-measure roll ABOUT THE FORWARD AXIS -- the fix for the withdrawn result, whose defect was the MEASUREMENT (a non-forward matrix row sees any rotation that moves it, and pitch moves it as much as roll) and not the input device. It was never run, and it still drove vgamepad, which is retired for leaking to the host. Ported to the file pad. The important difference is not the device but the shape: the file pad is a SNAPSHOT, not independent channels -- each write replaces the whole state -- so holding a trigger while deflecting a stick has to be one write. pad_state(**kw) does that. The values are also exact rather than whatever a virtual stick quantises to, which is what makes a single-axis hold (lx=32767 with everything else exactly 0) trustworthy for an axis-separation question. fly_stage.sh now drives the rest of the route it previously stopped short of: briefing (A: Continue) -> READY ROOM -> up to TAKE OFF -> flight, and notes why it must get there at all (a snapshot at the briefing yields zero unit-definition objects; they are instantiated at stage load proper).
This commit is contained in:
@@ -76,12 +76,20 @@ sleep 1; shot 03-selected
|
|||||||
pad tap A 0.20; sleep 3; shot 04-after-A
|
pad tap A 0.20; sleep 3; shot 04-after-A
|
||||||
pad tap A 0.20; sleep 3; shot 05-after-A2
|
pad tap A 0.20; sleep 3; shot 05-after-A2
|
||||||
|
|
||||||
say "waiting for flight (up to 240s) — snapshotting when the guest settles"
|
# Selecting a stage lands on the mission BRIEFING (A: Continue), which leads to the
|
||||||
for i in $(seq 1 240); do
|
# READY ROOM (TAKE OFF / BRIEFINGS / HANGAR / ...) with BRIEFINGS pre-highlighted.
|
||||||
sleep 1
|
# A snapshot taken at the briefing yields ZERO unit-definition objects — they are
|
||||||
[ $((i % 30)) -eq 0 ] && shot "06-wait-$i"
|
# instantiated at stage load proper — so the run has to reach flight.
|
||||||
done
|
say "clearing the briefing"
|
||||||
shot 07-final
|
for _ in $(seq 1 10); do pad tap A 0.20; sleep 2.5; done
|
||||||
|
shot 06-readyroom
|
||||||
|
say "READY ROOM -> TAKE OFF (one up from the pre-highlighted BRIEFINGS)"
|
||||||
|
pad dpad up 0.06; sleep 1; shot 07-takeoff-hl
|
||||||
|
pad tap A 0.20; sleep 8
|
||||||
|
for _ in $(seq 1 6); do pad tap A 0.20; sleep 4; done
|
||||||
|
say "waiting for flight to settle"
|
||||||
|
sleep 30
|
||||||
|
shot 08-flight
|
||||||
SHM=$(ls /dev/shm/xenia_memory_* 2>/dev/null | head -1)
|
SHM=$(ls /dev/shm/xenia_memory_* 2>/dev/null | head -1)
|
||||||
if [ -n "$SHM" ]; then
|
if [ -n "$SHM" ]; then
|
||||||
OUT="$HOME/snap-stage$STAGE.bin"
|
OUT="$HOME/snap-stage$STAGE.bin"
|
||||||
|
|||||||
@@ -18,8 +18,27 @@ import json, math, os, struct, subprocess, sys, time
|
|||||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||||
import speed_law
|
import speed_law
|
||||||
|
|
||||||
def pad(*a):
|
PAD_FILE = os.environ.get("XENIA_PAD_FILE", "/tmp/xenia_pad.txt")
|
||||||
subprocess.run(["vgamepad", *a], capture_output=True)
|
|
||||||
|
|
||||||
|
def pad_state(**kw):
|
||||||
|
"""Write the WHOLE pad state at once.
|
||||||
|
|
||||||
|
The file pad is a snapshot, not a set of independent channels: each write
|
||||||
|
replaces everything, so holding a trigger *while* deflecting a stick has to be
|
||||||
|
one write. (`vgamepad`'s per-channel calls are what this replaces; that device
|
||||||
|
also leaked to the host, see the driver header.) Values are exact — no virtual
|
||||||
|
stick quantisation — which is what makes a single-axis roll hold trustworthy.
|
||||||
|
"""
|
||||||
|
parts = [f"{k}={v}" for k, v in kw.items() if v is not None]
|
||||||
|
tmp = PAD_FILE + ".tmp"
|
||||||
|
with open(tmp, "w") as f:
|
||||||
|
f.write(" ".join(parts))
|
||||||
|
os.replace(tmp, PAD_FILE)
|
||||||
|
|
||||||
|
|
||||||
|
def pad_neutral():
|
||||||
|
pad_state()
|
||||||
|
|
||||||
def shot(n):
|
def shot(n):
|
||||||
subprocess.run(["screenshot", f"/sylph-home/re/shots/{n}.png"], capture_output=True)
|
subprocess.run(["screenshot", f"/sylph-home/re/shots/{n}.png"], capture_output=True)
|
||||||
@@ -48,11 +67,13 @@ def main():
|
|||||||
u_i, w_i = [r for r in (0, 1, 2) if r != f_i]
|
u_i, w_i = [r for r in (0, 1, 2) if r != f_i]
|
||||||
rows = []
|
rows = []
|
||||||
for label, (trig, tv) in (("slow", ("LT", 1.0)), ("fast", ("RT", 1.0))):
|
for label, (trig, tv) in (("slow", ("LT", 1.0)), ("fast", ("RT", 1.0))):
|
||||||
pad("trig", "RT", "0.0"); pad("trig", "LT", "0.0"); pad("axis", "LX", "0.0")
|
# settle at the target speed with the stick CENTRED (5 s: 2 s was shown
|
||||||
pad("trig", trig, str(tv))
|
# wrong twice this session)
|
||||||
|
pad_state(**{trig.lower(): 255})
|
||||||
time.sleep(5.0)
|
time.sleep(5.0)
|
||||||
shot(f"rollax_{label}_a")
|
shot(f"rollax_{label}_a")
|
||||||
pad("axis", "LX", "1.0")
|
# full left-stick X, everything else exactly zero, trigger still held
|
||||||
|
pad_state(**{trig.lower(): 255, "lx": 32767})
|
||||||
t0, prev, swept = time.time(), rows_at(w.fd, off, cfg), 0.0
|
t0, prev, swept = time.time(), rows_at(w.fd, off, cfg), 0.0
|
||||||
seq = []
|
seq = []
|
||||||
while time.time() - t0 < dwell:
|
while time.time() - t0 < dwell:
|
||||||
@@ -63,13 +84,13 @@ def main():
|
|||||||
swept += abs(d)
|
swept += abs(d)
|
||||||
seq.append((round(time.time() - t0, 3), round(d, 4)))
|
seq.append((round(time.time() - t0, 3), round(d, 4)))
|
||||||
prev = cur
|
prev = cur
|
||||||
pad("axis", "LX", "0.0")
|
pad_state(**{trig.lower(): 255})
|
||||||
wall = seq[-1][0]
|
wall = seq[-1][0]
|
||||||
shot(f"rollax_{label}_b")
|
shot(f"rollax_{label}_b")
|
||||||
rows += [(label, *s) for s in seq]
|
rows += [(label, *s) for s in seq]
|
||||||
print(f"# {label:<5} wall {wall:5.2f}s roll swept {swept:7.1f}deg "
|
print(f"# {label:<5} wall {wall:5.2f}s roll swept {swept:7.1f}deg "
|
||||||
f"rate {swept / wall:6.1f} deg/wall-s")
|
f"rate {swept / wall:6.1f} deg/wall-s")
|
||||||
pad("trig", "RT", "0.0"); pad("trig", "LT", "0.0"); pad("reset")
|
pad_neutral()
|
||||||
with open(out_csv, "w") as f:
|
with open(out_csv, "w") as f:
|
||||||
f.write("phase,t,droll_deg\n")
|
f.write("phase,t,droll_deg\n")
|
||||||
for r in rows:
|
for r in rows:
|
||||||
|
|||||||
Reference in New Issue
Block a user