diff --git a/enclosure/lib/params.scad b/enclosure/lib/params.scad index 1dbe1c1..4656a0f 100644 --- a/enclosure/lib/params.scad +++ b/enclosure/lib/params.scad @@ -46,6 +46,15 @@ plunger_clearance = 1; plunger_d = button_cap_w - 2 * plunger_clearance; // 8 mm — base diameter plunger_tip_d = 3; // tapered tip — more precise contact, more lateral tolerance +// Plunger extends this far past the nominal z_atom_top. Compensates +// for accumulated stack-up tolerance (header pins seat shorter than +// their 6 mm nominal, etc.) so the plunger tip firmly contacts the +// Atom button with the cap at its rest position. The Atom's switch +// has ~0.4 mm of travel — the extra length is taken up by the cap +// floating slightly higher than its theoretical rest position, not +// by depressing the switch. +plunger_preload = 2.3; + // ============================================================ // MAX98357A I2S amp breakout // ============================================================ @@ -224,17 +233,25 @@ slot_total_h = slot_base_h + slot_chamfer_h; // 23 // ============================================================ // Snap-fit join between halves. // -// Lower half: 4 flexible cantilever tabs at 90° intervals, sticking -// up from the wall's inner face beyond z_split. Each tab has an -// outward-facing bump near its tip. Upper half: 4 matching recesses -// on its inner wall at the bottom. The tabs flex inward as the upper -// half slides over them, then snap outward into the recesses with a -// definite click. Disassembly is by pulling the upper half firmly -// upward (tabs flex inward to release). +// Lower half: 4 tabs at 90° intervals fused to the wall's inner face. +// Each tab extends from z_split - snap_tab_root_h (root, fused to +// the wall) up to z_split + snap_tab_h (free cantilever tip). The +// portion below z_split is the structural root — it gives the tab a +// real attachment area to the wall instead of just one print layer. +// A 45° chamfer at the bottom of the root lets it grow inward at 45° +// during the print, self-supporting. The portion above z_split is +// the flexible cantilever and carries the bump near its tip. +// +// Upper half: 4 matching recesses on its inner wall at the bottom. +// The tabs flex inward as the upper half slides over them, then +// snap outward into the recesses with a definite click. Disassembly +// is by pulling the upper half firmly upward (tabs flex inward to +// release). // ============================================================ snap_tab_w = 12; // angular width of each tab (chord at the wall's inner radius) -snap_tab_h = 8; // vertical height of the cantilever +snap_tab_h = 8; // vertical height of the free cantilever above z_split +snap_tab_root_h = 4; // vertical height of the fused root below z_split snap_tab_t = 1.5; // radial thickness of the tab (thinner than wall_t for flex) snap_bump_h = 1; // radial protrusion of the bump beyond the tab's outer face snap_bump_inset = 1.5; // distance from tab tip down to the bump center diff --git a/enclosure/parts/chassis-lower.scad b/enclosure/parts/chassis-lower.scad index bf1e262..20c56a0 100644 --- a/enclosure/parts/chassis-lower.scad +++ b/enclosure/parts/chassis-lower.scad @@ -102,21 +102,39 @@ module snap_tabs() { snap_tab(); } -// One tab on the +X side. Body is a rectangular cantilever on the -// inner face of the wall, with a hemisphere bump on its outer face -// near the top. +// One tab on the +X side. Cross-section is a pentagon in the (r, z) +// plane, extruded along the chord direction (y). The pentagon has: +// - a tall outer face (at r=r_outer, flush with the wall's inner +// surface), from z_root_bot up to z_tab_top +// - a vertical inner face (at r=r_inner) from z_tab_top down to +// z_chamfer_top +// - a 45° chamfer from (r_inner, z_chamfer_top) down to +// (r_outer, z_root_bot) — self-supporting in the feet-down print +// +// The portion below z_split is fused to the wall's inner face, +// providing a solid attachment root. The portion above z_split is +// the free cantilever that flexes during assembly. +// +// A hemisphere bump sits on the tab's outer face near the tip, +// half embedded in the tab body, half protruding outward into where +// the upper half's recess will sit. module snap_tab() { - r_outer = cylinder_id / 2; // tab's outer face flush with cylinder ID - r_inner = r_outer - snap_tab_t; // tab's inner face - chord_y = snap_tab_w; // approximate as straight chord (small angle) + r_outer = cylinder_id / 2; + r_inner = r_outer - snap_tab_t; + + z_root_bot = z_split - snap_tab_root_h; + z_chamfer_top = z_root_bot + snap_tab_t; // 45° chamfer height = tab thickness + z_tab_top = z_split + snap_tab_h; - // Tab body — rectangular cantilever. - translate([r_inner, -chord_y / 2, z_split]) - cube([snap_tab_t, chord_y, snap_tab_h]); + rotate([90, 0, 0]) + linear_extrude(height = snap_tab_w, center = true) + polygon([ + [r_outer, z_root_bot], + [r_outer, z_tab_top], + [r_inner, z_tab_top], + [r_inner, z_chamfer_top], + ]); - // Bump — hemisphere on the tab's outer face. Half embedded in the - // tab body, half protruding outward into where the upper half's - // recess will sit. translate([r_outer, 0, z_split + z_snap_bump_offset]) sphere(r = snap_bump_h); } diff --git a/enclosure/parts/snooze-cap.scad b/enclosure/parts/snooze-cap.scad index 96a5efd..5df17ea 100644 --- a/enclosure/parts/snooze-cap.scad +++ b/enclosure/parts/snooze-cap.scad @@ -9,9 +9,13 @@ // - Flange: 22 mm disc, 2 mm thick. At rest, the flange's top face // touches the disc's underside (held there by the Atom button's // spring pushing on the plunger from below). -// - Plunger: 8 mm tapering to 3 mm tip, 3.2 mm long. Offset from +// - Plunger: 8 mm tapering to 3 mm tip, 5.5 mm long. Offset from // the cap's center to (button_offset_x, button_offset_y) so it -// lands precisely on the Atom's button cap. +// lands precisely on the Atom's button cap. The plunger extends +// plunger_preload (2.3 mm) past the nominal z_atom_top: real +// stack-up runs short of the math (pin headers seat shorter than +// 6 mm, etc.), and this preload ensures firm contact with the +// cap at its rest position. // // Mass ~3 g. Atom button's ~50 g spring lifts it easily. // @@ -37,12 +41,13 @@ $fs = 0.4; EPS = 0.05; module snooze_cap() { - z_flange_top = z_rim_bottom; // 122 — touches disc underside at rest - z_flange_bot = z_flange_top - flange_h; // 120 - z_crown_top = z_top + snooze_cap_h_above; // 128 — visible above disc - crown_h = z_crown_top - z_flange_top; // 6 + z_flange_top = z_rim_bottom; // 122 — touches disc underside at rest + z_flange_bot = z_flange_top - flange_h; // 120 + z_crown_top = z_top + snooze_cap_h_above; // 128 — visible above disc + crown_h = z_crown_top - z_flange_top; // 6 - plunger_h = z_flange_bot - z_atom_top; // 3.2 + plunger_bottom = z_atom_top - plunger_preload; // 114.5 — tip extends past nominal z_atom_top + plunger_h = z_flange_bot - plunger_bottom; // 5.5 union() { // Crown — visible above the disc, passes through the disc hole. @@ -56,7 +61,7 @@ module snooze_cap() { // Plunger — offset to land over the Atom button. Tapers from // plunger_d at the base (top, against flange) down to // plunger_tip_d at the tip (touching the Atom button at rest). - translate([button_offset_x, button_offset_y, z_atom_top]) + translate([button_offset_x, button_offset_y, plunger_bottom]) cylinder(h = plunger_h, d1 = plunger_tip_d, d2 = plunger_d); } }