BT410 5.3.67: pose_chase was upside down -- harness bug, wire exonerated

The operator caught it: the 5.3.65 image showed the mech hanging from its own
ground-shadow plate (-y is up in the bridge world).  The follow-up pinned down
what was and wasn't wrong, and the reconstruction survives untouched.

Right, by three independent wire-level proofs: MAD.SKL offsets are a coherent
Y-up model (hip +5.29, knees descending, torso ascending -- anatomical only
read +Y-up); the BGF vertex extents agree (foot meshes extend -1.0 below their
ankle to the sole, torso +3.8 up to the missile pods); and the SHIPPED pod's
wire carries the same signs (hip +6.21, knees negative, vehicle root a pure
yaw with det +1).  Our wire and shipped's are convention-identical -- no flip
exists between game and board in either game.

Wrong: the ad-hoc chase camera.  It borrowed the aerial up-hint from the
calibrated live-bridge world (where -y is up) and applied it to a raw
scene-space render of Y-up wire data; the symmetric checkerboard ground
disguised the inversion.  The shipped capture rendered upside-down through the
same harness, which is what cleared the wire.

Both conventions now documented in the roadmap: wire/scene space is Y-up in
both games; the live bridge presents -y-up via its calibrated mirror family
(FP_RIGHT_SIGN / CAGE_TWIST_SIGN, COCKPIT-CAGE-NOTES.md).

Tooling: pose_probe.py replaces the throwaway harness (updir=+1 scene space
default, -1 for the bridge sense).  pose_chase_upfixed.png is the corrected
milestone image: the MadCat right side up -- chicken-walker legs, purple knee
actuators, feet planted, shadow under the feet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-29 10:41:34 -05:00
co-authored by Claude Fable 5
parent 1233a1d5f6
commit f30acc6a94
3 changed files with 150 additions and 0 deletions
+37
View File
@@ -54,3 +54,40 @@ LOG: ISA Plug & Play BIOS enabled
LOG: VGA ROM BIOS init callback
LOG: pixratio 1.000, dw false, dh false
LOG: Aspect ratio: 640 x 480 xToY=1.333 yToX=0.750
LOG: WARNING: No translation support (to host) for code page 0
LOG: DOS keyboard layout loaded with main language code US for layout us
LOG: XMS: 50 handles allocated for use by the DOS environment
LOG: EMS page frame at 0xe000-0xefff
LOG: COMMAND.COM env size: 720 bytes
LOG: COMMAND.COM environment block: 0x0701 sz=0x002d
LOG: COMMAND.COM main body (PSP): 0x072f sz=0x009a
LOG: COMMAND.COM stack: 0x0749
LOG: pixratio 1.350, dw false, dh false
LOG: Aspect ratio: 720 x 540 xToY=1.333 yToX=0.750
LOG: SHELL:Redirect output to COM3
LOG: VPXLOG: fifosock client connected
VPX lights@f1: type6=0 typeE=0 decoded=0 dir=0 amb(0.00,0.00,0.00)
LOG: 237273074 ERROR MOUSE:Unhandled videomode 79 on reset
LOG: pixratio 1.000, dw false, dh false
LOG: Aspect ratio: 640 x 480 xToY=1.333 yToX=0.750
VPX lightnode t=6 nb=52: [8]00000000/0 [12]00000000/0 [16]00000001/1.4013e-45 [20]3f800000/1 [24]3f800000/1 [28]3f800000/1 [32]64078678/1e+22 [36]64078678/1e+22 [40]00311d60/4.51048e-39 [44]00326744/4.62882e-39 [48]ffffffff/nan
LOG: 684478479 ERROR INT10:PutPixel unhandled mode type 7
LOG: SHELL:Redirect output to RC.TXT
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:2 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:3 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:12 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:6 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:3 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:3 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:6 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:3 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:3 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:6 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:3 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:3 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:3 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:3 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:6 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:3 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:3 (IF0:0), TX:0, Break 0
LOG: Serial1: Errors: Framing 0, Parity 0, Overrun RX:6 (IF0:0), TX:0, Break 0
+72
View File
@@ -0,0 +1,72 @@
#!/usr/bin/env python3
"""pose_probe -- offline chase render of the articulated mech in a fifodump.
py pose_probe.py <capture.fifodump> <out.png> [updir]
Frames the camera on the LAST-articulated root (board.anim_abs), a chase
offset away, and renders one frame. The proof harness for any "is the mech
posed/assembled right?" question -- offline, against a copy of the live dump,
zero interference with a running pod.
UP SENSE (updir, default +1): the wire's model/scene data is Y-UP -- proven
three ways on 2026-07-29: MAD.SKL offsets are anatomically coherent only with
+Y up (hip +5.29 above ground, knees/ankles descending), the BGF vertex
extents agree (foot meshes extend -1.0 below their ankle joint, torso +3.8
above shakey), and the SHIPPED pod's wire carries the same signs (hip +6.2,
knees negative, yaw-only vehicle root -- no flip anywhere on the wire). So a
scene-space render wants screen-up = +Y, which is updir=+1 here.
The LIVE bridge world is the other way around -- "-y is up here" -- because
the calibrated live path (fp_cam / the mirrored det -1 root-basis family,
FP_RIGHT_SIGN, COCKPIT-CAGE-NOTES.md) maps the wire into Dave's GL
presentation. The first version of this harness copied the aerial camera's
up hint from that world and rendered the mech hanging from its own shadow;
the operator caught it. updir=-1 reproduces that view if you ever need it.
"""
import sys, os, struct
sys.path.insert(0, r'C:\VWE\TeslaRel410\dpl3-revive\patha')
os.environ.setdefault('SDL_VIDEODRIVER', 'dummy')
import numpy as np
from vrboard import VirtualBoard, Msg
from vrview import Renderer
cap = sys.argv[1]
out = sys.argv[2] if len(sys.argv) > 2 else "pose_probe.png"
updir = float(sys.argv[3]) if len(sys.argv) > 3 else 1.0
data = open(cap, "rb").read()
board = VirtualBoard()
off = 0
while off + 8 <= len(data):
if data[off:off+4] != b'VPXM':
off += 1; continue
ln = struct.unpack_from('<I', data, off+4)[0]
body = data[off+8:off+8+ln]
if len(body) >= 4:
a = struct.unpack_from('<I', body, 0)[0]
if a < 0x100:
try: board.handle(Msg(False, 0xff, a, body[4:]))
except Exception: pass
off += 8 + ln
if not board.anim_abs:
print("no articulated roots in this capture"); sys.exit(1)
r = Renderer(w=832, h=512); c = r.cache; c.maybe_rebuild(board)
root = max(board.anim_abs.values(),
key=lambda f: float(np.abs(np.array(f[9:12])).sum()))
target = np.array(root[9:12]); target[1] += updir * 6.0 # mid-body
eye = target + np.array([30.0, updir * 14.0, 40.0]) # above + beside
fwd = target - eye; fwd /= np.linalg.norm(fwd); back = -fwd
right = np.cross([0.0, updir, 0.0], back); right /= np.linalg.norm(right)
up = np.cross(back, right)
M = np.eye(4); M[0,:3], M[1,:3], M[2,:3], M[3,:3] = right, up, back, eye
r.cam_matrix = lambda _b, _M=M: _M
if c.view is not None and c.view in board.nodes:
vb = bytearray(board.nodes[c.view].get('body') or b'')
if len(vb) >= 56:
struct.pack_into('<f', vb, 52, 1.0e6)
board.nodes[c.view]['body'] = bytes(vb)
r.draw(board)
r.pygame.image.save(r.screen, out)
print("wrote %s root at %s updir=%+g" % (out, target.round(1), updir))