Clarify Enclosure Labels And Validate Clearance

This commit is contained in:
2026-09-28 12:13:46 +02:00
parent c5bf3e32f5
commit 26ed569fcb
8 changed files with 90704 additions and 18349 deletions
+2
View File
@@ -10,6 +10,8 @@ Working memory, not an implementation timeline. Source is authoritative; begin w
## Parametric enclosure — initial concept, physical validation pending
- Label-only follow-up: removed DISPLAY, grouped `USB: UART0 / CDC` (local wiring/measurement evidence does not establish physical left/right roles), and raised `ESP32 / Serial Swiss / Army Knife` on the blank roof left of the display. Shared labels export retained; unlabeled lid CSG exactly matches the pre-change source. Lid STL and three previews refreshed; base/plungers and PCB unchanged. CGAL simple lid/labels exports, source/datum/mesh checks and actual-glyph roof clearance >=1 mm passed; no physical print/test. Lid detail now views readable branding from the USB side.
- `hardware/case/` corrected per user: 5 mm base insert bosses directly support carrier underside Z7.4/top Z9; two M3 RS-232 and four M2 OLED brass male/female bodies ABOVE carrier span 10 mm to module underside Z19. Studs cross actual 1.6 mm carrier holes into respective inserts; four separate carrier holes take direct M3 screws. ESP32 has no supplied mounting holes and remains header-supported. No under-carrier brass or printable spacers remain. Shell now **106 × 86.8 × 37.4 mm**, roof underside Z35 (10 mm lower); ports/display/DB9 panel/hangers/buttons follow the corrected datums. Red RF overlay/enclosure reserve restriction removed; physical antenna retained, no Wi-Fi guarantee and no PCB/schematic/copper/reserve/layout/export changes.
- Superseding DB9 change: separate plate/export/mode and M3 insert hangers removed. Cover now has integral nominal 48 mm-wide × 2.4 mm-thick connector panel at Y−0.47…1.93, Z21.07…35, continuous roof connection and two nominal 6 mm forward ribs outside flange bounds, extended into the wall to close former 1 mm side slits. Bottom-open 18.078 mm shell slot and closed Ø3.6 post holes at real 25 mm spacing permit straight vertical lowering **after removing both screw posts and all cables**; front-wall recess also opens to seam. Panel clears PCB by 0.5 mm and anchors by 3.10 mm in Y. No horizontal-slide claim. Insert count now 10 M3 + 4 M2, all base. Added forward-only base closure Y−3.4…−0.5: shoulders Z20.82, 17.578038-wide tongue Z21.69762024, 0.25 mm seams, 0.6 below STEP shell, 0.5 forward of module PCB. PCB files untouched.
- Three default CGAL exports, native registration (including flange plane, hole diameters/no ESP32 NPTH), evaluated stack/connector/stud/web fixtures, edge-manifold meshes, three parameter CGAL smoke tests and continuous 60 mm vertical envelope sweeps passed; restored-post negative control detects blockage. Thicker-panel sweep caught and fixed residual inner-wall strip; default and raised/thicker variant now pass. Closure follow-up regenerated base/lid and all three previews (unchanged plungers revalidated); default plus two variant sweeps include per-step upstand/lid travel, base/lid seating and electronics insertion. Four parameter mesh tests pass; closure guards and STEP shell-minimum registration added. Three regenerated previews visually inspected, including bare-lid detail. This is selected-envelope CAD clearance, not complete hardware or strength qualification.
+5 -3
View File
@@ -71,7 +71,7 @@ Measured shell centres **X15.23 and 26.63**, widths **8.87**, mouth plane **Y77.
A single joined bay spans **X9.595…32.265**, **Z19.6…26.6** (22.67 × 7), through the bottom-end wall. It admits both plug overmoulds instead of adding fragile individual webs. There are no internal bosses or tunnels between the wall and mouths. Mouth-to-exterior-wall distance is **5.695**: the plug must reach through that recess. The opening is deliberately generous relative to measured *widths*; shell height/depth and both plug overmoulds still need measurement. `usb_below_module_top`, `usb_above_module_top`, `usb_extra_width` are cutout controls; `usb_reference_depth/h` affect only the approximate preview. Enlarge for the actual plugs rather than moving U1 or growing Y without justification.
Signage says **USB**, not a guessed left/right native-USB vs USB-UART mapping. Both connections remain physically available independent of networking.
One grouped two-line label, **USB** above **CDC | UART0**, spans the combined bay; it does **not** assign left/right ports. The [wiring guide](../../docs/wiring.md#administration-and-native-usb-connectors) establishes bridge/UART0 and native/CDC roles, but neither it nor the measured HW678 mouth geometry establishes physical connector-to-role order. Seller labels are not used as mapping evidence. Both connections remain physically available independent of networking.
### DB9: external flange retention, not a guessed thread
@@ -117,6 +117,8 @@ Reseating a same-length **4.8 mm** post body puts its mouth at **Y−5.270**, **
8. Insert verified stock or replacement post studs from outside through the two closed cover holes into the connector. Check clamp contact, engagement and bottoming independently; do not use them to pull a misaligned flange/PCB into position. Tighten case/post hardware cautiously to verified values. Test full USB/DB9 mating and cable locks, particularly the changed post-mouth reach; perform a restrained cable-load test before trusting retention.
9. To remove the cover, unplug every cable, unscrew both connector posts completely out of the cover holes and remove the four case screws; lift vertically, retaining the plungers. The electronics remain secured by their independent carrier/daughterboard fasteners.
The roof prominently carries the README project name on three lines, **ESP32 / Serial Swiss / Army Knife**, left of the display and readable from the USB end. The former DISPLAY caption is removed; RS-232 and button captions are unchanged. All text comes from the shared `labels()` module, including `part="labels"`; `emboss=false` omits it only from the lid.
Raised labels are positive **0.6 mm emboss**, not engraving. Single-colour is the default; roof-up printing allows a filament change just above the roof for contrasting text (check actual sliced layers). For a separate material export `labels`, and export the lid with `emboss=false`. In a multi-object slicer, preserve XY origin and translate the flat text object up **22.13 mm** relative to the default lid export (its initial 0.02 overlaps the roof). Do not auto-centre individual letters; STL carries neither colour nor assembly transforms. Changes to stack require recalculating that offset: `top_z - eps - split_z - seam_clearance`.
## Regeneration and checks
@@ -133,10 +135,10 @@ python3 validate.py
/usr/bin/python3 -B validate.py --source --installation --variants
QT_QPA_PLATFORM=offscreen openscad -o assembly-preview.png --imgsize=1200,1000 --viewall --autocenter --projection=o --camera=0,0,0,55,0,25,200 -D 'part="exploded"' enclosure.scad
QT_QPA_PLATFORM=offscreen openscad -o db9-preview.png --imgsize=1200,900 --viewall --autocenter --projection=o --camera=0,0,0,80,0,180,200 -D 'part="assembly"' enclosure.scad
QT_QPA_PLATFORM=offscreen openscad -o lid-detail.png --render --imgsize=1200,900 --viewall --autocenter --projection=o --camera=0,0,0,100,0,155,200 -D 'part="lid"' enclosure.scad
QT_QPA_PLATFORM=offscreen openscad -o lid-detail.png --render --imgsize=1200,900 --viewall --autocenter --projection=o --colorscheme=Metallic --camera=0,0,0,55,0,25,200 -D 'part="lid"' enclosure.scad
```
`validate.py` uses Python's standard library and installed OpenSCAD for evaluated datum, stud-engagement and nozzle-web fixtures, plus ASCII STL checks; `--source` additionally uses the **already installed system KiCad `pcbnew` binding**, read-only. It verifies current outline/holes/placements, measured U1 USB mouth graphics and STEP-derived lock/shell data against case constants. It is a drift tripwire, not a full source parser for every SCAD expression. It checks each STL has two oppositely directed uses of every triangle edge, nonzero triangle area, the expected connected component count (1 base, 1 lid, 3 plungers), positive total signed volume and minimum Z≈0. It does **not** prove vertex-manifoldness, absence of self-intersections, full component collision clearance or physical fit.
`validate.py` uses Python's standard library and installed OpenSCAD for evaluated datum, stud-engagement and nozzle-web fixtures, plus ASCII STL checks; `--source` additionally uses the **already installed system KiCad `pcbnew` binding**, read-only. It verifies current outline/holes/placements, measured U1 USB mouth graphics and STEP-derived lock/shell data against case constants. The default checks also project the actual label glyphs against the roof, requiring at least 1 mm clearance from its edges, display/button openings and screw-head recesses. It is a drift tripwire, not a full source parser for every SCAD expression. It checks each STL has two oppositely directed uses of every triangle edge, nonzero triangle area, the expected connected component count (1 base, 1 lid, 3 plungers), positive total signed volume and minimum Z≈0. It does **not** prove vertex-manifoldness, absence of self-intersections, full component collision clearance or physical fit.
Validation results and bounded parameter/sweep tests are recorded in [checks.md](checks.md). The remaining exports are base, integral lid and three plungers; the corrected 37.4 mm shell / 7.4–9–19 mm stack is unchanged. No slicer, physical print, screw-fit, cable-load, hardware/firmware, thermal or RF acceptance is implied.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 22 KiB

+6 -2
View File
@@ -303,8 +303,12 @@ module label_at(x,y,s,size=2.5) {
}
module labels() {
label_at(module_cx,7,"RS-232",3);
label_at(20.93,74,"USB",3); // native vs UART left/right NOT established
label_at(module_cx,35,"DISPLAY",2.4);
// One grouped bay label: physical UART0/CDC left/right is not established.
label_at(20.93,71,"USB",3);
label_at(20.93,76,"CDC | UART0",2.4);
label_at(20.93,32,"ESP32",5);
label_at(20.93,41,"Serial Swiss",4);
label_at(20.93,50,"Army Knife",4);
for(i=[0:2]) label_at(button_centres[i][0],77,["BACK","SELECT","NEXT"][i],2.1);
}
module lid() {
+90668 -18344
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 32 KiB

+23
View File
@@ -235,6 +235,28 @@ def variant_check():
print('PASS parameter CGAL mesh', part, defines)
def label_check():
"""Actual glyph solids must stay on roof, 1 mm clear of all roof openings."""
with tempfile.TemporaryDirectory(prefix="case-labels-") as temp:
wrapper = Path(temp)/"labels.scad"
wrapper.write_text(
f'include <{ROOT / "enclosure.scad"}>\n'
'cube(1);\n'
'translate([0,0,80]) linear_extrude(1) difference() {\n'
' projection() labels();\n'
' offset(delta=-1) projection(cut=true)\n'
' translate([0,0,-top_z+eps/2]) lid_body();\n'
'}\n')
path = Path(temp)/"clearance.stl"
result = subprocess.run(
["openscad", "-o", str(path), "-D", 'part="check"', str(wrapper)],
env={**os.environ, "QT_QPA_PLATFORM": "offscreen"},
capture_output=True, text=True, timeout=180)
assert result.returncode == 0 and "ERROR:" not in result.stderr, result.stderr
near([mesh_check(path, 1)["volume_mm3"]], [1])
print("PASS actual label glyphs within roof, >=1 mm from edges, display, buttons and screw-head openings")
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--source", action="store_true", help="also check saved KiCad/STEP registration")
@@ -246,6 +268,7 @@ def main():
if args.installation:
installation_check()
geometry_check()
label_check()
if args.source:
source_check()
reports = [mesh_check(ROOT / name, n) for name, n in [