// ============================================================ // stem_protector.scad — Clip-on Stem Sleeve Rev A 2026-03-01 // Agent: sl-mechanical // ============================================================ // Split-sleeve impact protector for the 25 mm OD vertical stem. // Print in TPU (Shore 95A) for energy absorption. // Snap-fit closure — no tools, no hardware. // Install 3–4 sleeves along the stem at 200 mm spacing. // // RENDER options: // "assembly" both halves closed around stem (default) // "front" front half for slicing // "rear" rear half for slicing // ============================================================ RENDER = "assembly"; // ── Stem ───────────────────────────────────────────────────── STEM_OD = 25.0; STEM_BORE = 25.6; // +0.6 mm — TPU flexible, snaps closed // ── Sleeve ─────────────────────────────────────────────────── SLEEVE_OD = 38.0; // outer diameter SLEEVE_H = 80.0; // height (print and trim to taste) WALL = (SLEEVE_OD - STEM_BORE) / 2; // ~6.2 mm wall // ── Snap-fit ───────────────────────────────────────────────── // Tab on front half snaps into recess on rear half. // Placed at both Z = SLEEVE_H*0.25 and Z = SLEEVE_H*0.75. SNAP_W = 8.0; // snap tab width SNAP_H = 3.0; // snap tab height (protrusion) SNAP_T = 2.5; // snap tab thickness SNAP_CL = 0.3; // recess clearance for TPU flex // ── Ribbing ────────────────────────────────────────────────── // Optional radial ribs for grip and stiffness RIB_N = 8; // number of ribs around circumference RIB_H = 1.2; // rib height RIB_W = 2.0; // rib width $fn = 64; e = 0.01; // ───────────────────────────────────────────────────────────── // sleeve_half(side) // side = "front" (+Y) | "rear" (-Y) // Split at Y=0 plane. Print flat-face-down. // ───────────────────────────────────────────────────────────── module sleeve_half(side = "front") { y_front = (side == "front"); y_sign = y_front ? 1 : -1; difference() { union() { // Main D-shaped half cylinder intersection() { cylinder(d = SLEEVE_OD, h = SLEEVE_H); translate([-SLEEVE_OD/2, y_front ? 0 : -SLEEVE_OD/2, 0]) cube([SLEEVE_OD, SLEEVE_OD/2, SLEEVE_H]); } // Radial grip ribs on outer curved face for (i = [0 : RIB_N/2 - 1]) { ang = (i / (RIB_N/2 - 1)) * 150 - 75; // spread 150° on each half rotate([0, 0, y_sign * ang + (y_front ? 0 : 180)]) translate([SLEEVE_OD/2, -RIB_W/2, 0]) cube([RIB_H, RIB_W, SLEEVE_H]); } // Snap tab (front half) — 2 positions if (y_front) { for (zh = [SLEEVE_H * 0.25, SLEEVE_H * 0.75]) { translate([-SNAP_W/2, SLEEVE_OD/2 - SNAP_T, zh - SNAP_H/2]) cube([SNAP_W, SNAP_T + SNAP_H, SNAP_H]); } } } // Stem bore translate([0, 0, -e]) cylinder(d = STEM_BORE, h = SLEEVE_H + 2*e); // Snap tab recess in rear half if (!y_front) { for (zh = [SLEEVE_H * 0.25, SLEEVE_H * 0.75]) { translate([-(SNAP_W + SNAP_CL)/2, SLEEVE_OD/2 - (SNAP_T + SNAP_H + SNAP_CL + e), zh - (SNAP_H + SNAP_CL)/2]) cube([SNAP_W + SNAP_CL, SNAP_H + SNAP_CL + e, SNAP_H + SNAP_CL]); } } // Mating face: very small 0.2 mm chamfer to prevent elephant-foot binding translate([0, 0, -e]) rotate([0, 0, y_front ? 0 : 180]) translate([-SLEEVE_OD/2, -0.2, 0]) cube([SLEEVE_OD, 0.2, SLEEVE_H + 2*e]); } } // ───────────────────────────────────────────────────────────── // Render selector // ───────────────────────────────────────────────────────────── if (RENDER == "assembly") { color("OrangeRed", 0.85) sleeve_half("front"); color("Tomato", 0.85) mirror([0,1,0]) sleeve_half("rear"); // Reference stem color("Silver", 0.3) translate([0, 0, -10]) cylinder(d = STEM_OD, h = SLEEVE_H + 20); } else if (RENDER == "front") { sleeve_half("front"); } else if (RENDER == "rear") { sleeve_half("rear"); }