saltylab-firmware/chassis/stem_protector.scad
sl-mechanical beb0af7ce6 feat: bumper + frame crash protection for SaltyBot
Protects expensive sensors when robot tips over during testing.

Files added:
  chassis/bumper_frame.scad   — roll cage (25 mm stem collar + 4 inclined
                                posts + crown ring + TPU snap pad). Posts at
                                45/135/225/315° between cameras. Crown at
                                Z=148 mm above cage collar, 18 mm above RPLIDAR
                                top. RPLIDAR FOV unobstructed.
  chassis/base_bumper.scad    — clip-on bumper ring for 270×240 mm base plate.
                                50 mm tall, 15 mm standoff, rounded corners.
                                4× corner + 4× side clip brackets. TPU snap
                                edge caps. FC status LEDs remain visible.
  chassis/stem_protector.scad — split TPU sleeve for 25 mm stem. Snap-fit
                                closure (no hardware). Install 3–4 sleeves
                                along stem at ~200 mm intervals.
  chassis/bumper_BOM.md       — full BOM, print settings, install heights,
                                mass estimate (~500 g total, balanced).

All parts print without supports. Fully removable (clip/snap/clamp).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 23:30:06 -05:00

120 lines
5.3 KiB
OpenSCAD
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ============================================================
// 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 34 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");
}