Parviz · Design docs

Mechanism fix ledger, mechanisms-finalize

Three review agents (geometry verifier / mechanical loads / assembly walk) audited commit fa13f64 and converged on ~20 verified defects. Four fix stages run sequentially (they all edit src/build.py); stage 4 is an independent re-verification. Status legend: [x] fixed+probed, [~] in progress, [ ] queued, (!) accepted-as-is with reason.

Stage 1, chassis + pan stack [DONE, all probes pass]

Stage 2, tilt drive + neck + Pi + axle [DONE, all probes pass]

Stage-2 side effects for Stage 3: the Pi is portrait at (x −56, y −16, z 192.5) → re-aim the back-cover I/O slot for ports exiting the board's ±X/±Z edges there; bezel↔back fastening is now 7 posts (M3×35 ×7, nuts +1); pivot bosses are 12 long (they still protrude past the outer wall, the Stage 3 trim item stands).

Stage 3, head/screen/camera + tracks [DONE: head/camera 3a, tracks/drive 3b]

Head/camera fixed by the Stage-3a agent (attempt 2). Combined screen+Pi model swap (user design change) done FIRST; several fixes below were re-scoped by what the new mesh + official CM3 data proved.

[x] RESOLVED (Stage 2R): combined screen+Pi stack vs the TILT MECHANISM. User call: keep the Pi on the display back, rework the tilt geometry. The tilt axle moved BACK 18 mm to (y −18, z 178) (tilt_axis_y new param; tilt_axis_z unchanged; screen anchored separately via screen_cz, it did not move). Everything keyed off the axle moved with it: cheeks, 695 seats, clamp tubes/hubs/grubs, wheel, axle, worm group. Consequential rework, all probe-driven: cheek boxes now stop AT the axle + a Ø19 bearing hoop (kills the pre-existing 260-sample cheek-top overshoot into the display back; worst cheektop→display gap now 3.12 mm @ −30°); worm group sits 4 mm further behind the axle (face offset 4→8) with the bracket plate shortened 46→36 tall (old top clipped the head back wall at +10..+25°); the outboard bushing post, which both crossed the −30° swept stack and clipped the wheel-tooth circle, became an open-top cradle (arm+riser+pad hugging the measured swept-stack profile; worm separation force presses the Ø5 tail stub down into the groove, so open-top is load-correct); gusset front pulled to y −20; column front-top notch (y −21..−13, z 94..112) clears the head bottom-wall arc at −30°. Probes (12k stack surface samples + manifold booleans): stack vs {neck, worm, motor, axle, wheel, head shell} intersection 0.000 mm³ at every tilt −30..+30 step 5; min gaps stack→neck 1.62 mm @ −30°, stack→worm 2.71, stack→motor 16.8, stack→axle 8.5, stack→wheel 11.0 (all ≥ the 1.0 mm target); real bezel+back sweep vs neck+worm+motor 0.000 at all 13 angles; worm cd = 11.500 exact; wheel|cheeks 0.000; Ø12.85 seat plugs 0.000 both sides; neck_clevis/head_back/head_bezel watertight, EXPORT=1 clean. Tracks/drive fixed by the Stage-3b agent. Measured-param corrections applied first (audit corr. 1/3/4/5 + reference/tt-motor-1079893/NOTES.md): sprocket_outer_d 42.0 → 37.6, track_wheel_r 19.0 → 19.32 (exact 12T × 10.0 polygon), pin bores Ø2.0 (new track_pin_bore_d), track_pitch comment fixed (reference pitch is 9.65; our 10.0 is a re-model by design).

Notes for stage 4 / buy list: - The tt-motor reference CAD is SINGLE-shaft; purchased TT motors are often dual-shaft. If the real unit has a rear shaft, the far pod side needs a Ø7.5+ clearance pocket mirrored about the gearbox (currently nothing is there, the pods have no outboard wall, so it only matters if a pod wall/cover is added). Verify the actual motor before closing that side. - body_z_top grew to 251 in stage 3a (head +8, CoM higher): size the chassis ballast for the taller head when the buy list is done, keep the mass in the chassis floor, wheelbase is 120.

Stage 4, independent re-verification [DONE: NOT READY, 2 blocking + 2 minor defects]

Independent probes (own scripts, scratchpad/stage4_*.py), nothing reused from stages 1-3b. Method note that invalidates several earlier "0.000" claims: the screen reference mesh is NOT watertight, and trimesh.boolean with engine=manifold RAISES on it. The earlier probes' ivol() caught that exception and returned 0.0, so every prior "stack vs X = 0.000 mm3" boolean was vacuous (their ProximityQuery gap numbers were real). Stage 4 re-tested all screen pairs by surface-sample containment (30k-400k samples) against the watertight partner.

Category results

# Category Verdict Numbers
1 Build health PASS* plain + EXPORT=1 exit 0, 20 parts; 10 STLs written; every body watertight. *neck_clevis exports as 5 DISJOINT bodies (defect D4)
2 Collision matrix (190 pairs, neutral) FAIL defects D1, D2, D3. Intended contacts confirmed: pan_balls tangency 0.030 mm3 total (18 balls, mesh discretization), worm/wheel placeholder gear mesh 19.8 mm3
3 Kinematic sweeps PASS tilt -30..+30 step 5: all solids 0.000, screen samples in others 0, all 13 angles. pan -90..+90 step 15: 0.000 except pan_platform vs the STATIC motor_pan shaft mesh (2.4..15.2 mm3 growing with angle; the shaft co-rotates in reality, model artifact) + the constant 0.03 ball tangency
4 Pan stack PASS ball tangent both grooves 0.0000; platform top z 52.0000 flush with deck 52.0000; race ring 37.0000..42.0000; clips 0.000 at rest and at +0.3 lift, 10.13 mm3 bite at +0.5 (0.4 shoulder clearance then retention), clip tops z 52.000; D-profile only in the flat zone; platform-motor_pan 0.0000 at pan=0. Note N1
5 Tilt drive PASS* worm_cd() 11.500 vs mesh axis distance 11.500, delta 0.0000; lead angle 9.46 deg (<10, self-locks); Ø12.85 seat plugs 0.0000 both cheeks; wheel+spacers span exactly x -18.00..+18.00; wheel-neck 0.0000; grub pilots at x=+-30 open (rod 0.0000); Ø5.20 axle plug bites the clamp bosses 9.44 mm3/side, outer walls loose 0.0000. *but the drive carries D2 + D3
6 Screen + camera FAIL mounts at (61.61/-64.59, y 25.03, z 146.15/211.80); Ø3.2 screw paths + Ø6.0 driver channels through head_back all 0.0000; glass 30.994 vs face 31.0 (flush); 75-deg FoV cone (Ø2.63 pupil 3 mm behind the face) vs bezel 0.0000; cam vs bezel/back/cover and cover vs bezel/back all 0.0000; M2 cover paths drilled, 5.22 mm3 self-tap bite into bezel pilots, pilots ~3.8 deep. FAIL because of D1: the screen cannot SEAT
7 Tracks PASS loop min z +0.0000 both pods; sprocket tip r 18.800 exact; sprocket-link, idler-link, roadwheel-link, and all 36 adjacent link pairs 0.0000 per pod; motor shaft vs sprocket axis delta (0.0000, 0.0000) both sides; motor-chassis, motor-pod, sprocket-chassis, pod-chassis 0.0000; idler bore r 7.9750 (F688ZZ Ø15.95), Ø18.5 flange-recess ring present both pods
8 Cable route PASS* deck pass at (12,-24) clear z 30.25..55 (platform 0.000, race 0.000); platform slot mouth at (0,-38) clear; Ø7 rod up the neck channel z 52..150 = 0.000; head bottom-rear slot clears a drape capsule vs bezel/back 0.000 at tilt -30/0/+30. Notes N2, N3
9 Docs drift FAIL 9 stale claims in CLAUDE.md, listed below
10 Renders PASS chk_iso/side/front/top/sec_* shot via port 8770, downscaled and inspected: assembly coherent, tracks on the ground line, screen framed, camera lens visible on the forehead, no floaters / z-fighting / missing parts

DEFECTS

Notes (no geometry change required)

Docs drift (CLAUDE.md; found, not fixed)

  1. "9 watertight per-part STLs" (l.11) and the "9 printed parts" list (l.178): now 10; pan_clips missing from both lists.
  2. Worm wheel "24T" at l.68, l.121, l.144: build uses worm_wheel_teeth = 12.
  3. Key numbers (l.114-117): screen "measured ... 193.0 x 25.0 x 110.8" + "Loaded live from ..._v12.stl": the build loads ..._-_Pins_Out_v8.stl (combined display+Pi, 192.96 x 38.01 x 110.76). PARAMS["screen_d"]=25.0 no longer matches the loaded mesh either.
  4. "Overall assembly bbox = 221 x 208 x 248" (l.117): measured 209 x 170.5 x 251 at neutral.
  5. "bezel<->back: 6 perimeter posts" (l.183): now 8 posts (stage 3a).
  6. "screen: 4x M3 bosses on the bezel" (l.184): retention moved to 4 rear standoffs on head_back with back-wall driver channels (stage 3a).
  7. "Pi 5: 4x M2.5 standoffs on the back cover (58x49)" (l.186): removed; the Pi rides the display's own standoffs inside the combined reference mesh.
  8. The stage-2R tilt-axle relocation to y=-18 (tilt_axis_y, screen_cz decoupling) is absent from Mechanical intent / Key numbers (only z=178 is stated).
  9. Stage-1 claim above, "D-profile now only over the flat zone (z 44.5..52)": effective D zone is 46.5..52 (see N1).

Verdict

NOT READY TO COMMIT. Blockers: D1 (screen seating), D2 (worm/cradle). D3 + D4 are small but should ride along; docs drift items 1-8 belong in the same pass.

Accepted findings (no geometry change)

Fastener BOM (from the assembly review; re-check after stage 3)

M3×35 ×8 (bezel↔back, stage-3a layout) · M3 nut ×11 · M3×12 ×4 (screen, from behind through the Ø6.5 back-wall channels into the display's threaded pan holes) · M3×16 ×3 (platform→neck) · M3×8 ×2 (pan ears) · M3 grub ×4-5 · M4×10+nut ×2 (tilt ears) · M2.5×8+nut ×4 (Pi) · M2×8 self-tap ×2+2 (camera + cover) · 695-2RS ×2 (owned) · F688ZZ flanged bearing ×2 (8×16×5, flange Ø18) + Ø8 stub axle ×2 + M2×16 self-tap ×2 (sprocket retain) · 6 mm BB ×18 · Ø1.75 filament pins ×72 · Ø5×209 tube ×1 · 28BYJ-48 ×2 + ULN2003 ×2 (owned) · TT gearmotor ×2 (own 1, buy 1).

Stage 5, fix pass (D1-D4) + neck-on-platform [DONE]

Stage 5 results (fresh probes, scratchpad st5_*.py; screen checked by surface samples,

booleans raise on failure)

Stage 6, independent re-verification of stage 5 [DONE: READY TO COMMIT]

Same methodology as stage 4 (own probes, scratchpad/stage4_*.py + stage6_d123.py; screen mesh checked by surface-sample containment, booleans raise on failure, nothing reused from the stage-5 agent's scripts).

# Category Verdict Numbers
1 Full collision matrix (190 pairs, neutral) PASS only intended contacts: pan_balls tangency 0.030 mm3 (both grooves), worm/wheel placeholder gear mesh 32.9 mm3. D1/D2/D3 pairs all gone
2 D1 screen seating PASS 0/400k dense samples inside head_back at all 4 mounts (was 386/6.2k per site), 0/60k global in back AND bezel; standoff bearing face measured y=22.480 (= 25.03 - 2.5 lip - 0.05 seat, exact); glass front 30.9940 flush; Ø3.2 screw paths 0.0000 x4
3 D2 worm rotation PASS 40-slice revolved envelope (max thread r 5.344) vs neck 0.0000; static 0.0000; thread span y -32.00..-16.29; bare stub forward of y=-15.5 max r 2.500 vs groove r 2.7; envelope vs the tilting head (bezel+back+axle) 0.0000 at -30/0/+30
4 D3 bore clocking PASS worm vs motor_tilt 0.0000; negative control (worm rotated 90 deg about its axis) 17.36 mm3, proving the flats exist and are correctly clocked; worm_cd 11.500 vs mesh 11.500, delta 0.0000
5 D4 watertight / bodies PASS all 10 STLs, every body watertight; neck_clevis 1 body (was 5); multi-body only track_L/R (52) + pan_clips (3), by design
6 Neck footprint + pan/tilt sweeps PASS footprint max r 43.098 at z 52..55 (<= 44; also max r below z=60), neck vs platform/clips/chassis/race 0.0000; pan -90..+90 step 15 vs all fixed: 0.000 (constant 0.03 ball tangency + the known static motor_pan shaft artifact only); tilt -30..+30 step 5: solids 0.000, screen samples 0, all 13 angles
7 Bolt circle PASS holes at az 270/30/150, r-from-pan-axis 33.00/16.52/16.52, plate annulus 100/100 solid each, bores fully void, Ø2.3 rods through platform hole + neck pilot 0.000 x3 (aligned)
8 Cable route PASS Ø7 deck-pass rod (12,-24, z 30.5..55) vs chassis/platform/race 0.000; Ø7 channel rod (0,-26, z 45..150) vs neck/platform 0.000
9 Renders PASS st6_iso/side/sec_mid via port 8770: column lands on the platform, assembly coherent, tracks on the ground line, no floaters / z-fighting

Docs: CLAUDE.md drift from stage 4 is resolved (10 parts, 12T, Pins_Out_v8; the one remaining "24T" is a historical "was 24T" note, not a stale claim).

Verdict: READY TO COMMIT. No defects found. Standing model-only artifacts (not defects): static motor_pan shaft vs the swept platform D-bore (shaft co-rotates in reality), placeholder worm/wheel tooth interpenetration (regen in BOSL2 before printing), 0.03 mm3 ball-seat tangency.

Wallcheck gate findings (2026-07-13, skills fix campaign)

The new make wallcheck min-wall gate (src/wallcheck.py, in make all) surfaced and closed these on its first full runs:

Finding Verdict Fix
track_keeper_L/R tab rim 0.65 mm (Ø4.2 M2 counterbore on the 2.6x5.5 tab) DEFECT, fixed cb Ø4.2 -> Ø4.0 (M2 pan head Ø3.8 max) + tab 5.5 -> 5.7; rim now 0.85, slot-critical 1.9 bar untouched, keeper-wall clearance 1.35
head_back_frame_L/R exported STLs non-manifold (float32 write collapses near-equal float64 vertices at the cap-plane junctions; in-memory mesh passed is_watertight) DEFECT, fixed geo.export_stl(): float32-quantized watertight check on every export; guarded manifold3d repair (volume < 0.1%, bbox < 0.01 mm, asserts)
neck_clevis 0.12 mm feather wedges (cradle-pad underside vs Ø5.4 tail-stub groove bottoming 0.2 below it) DEFECT, fixed structurally cooler-clearance pass deleted the pad+groove; the new crest-riding half-groove bottoms 4 mm above the block bottom; p1 now 1.75
tilt_worm / worm_wheel / pan_gears sub-0.8 populations EXPECTED geometry, whitelisted probe-located to tooth tips, thread run-out feathers, and helical face-edge feathers; mesh probe-verified per docs/WORM.md; documented floors 0.2 / 0.4 / 0.75