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>
120 lines
5.3 KiB
OpenSCAD
120 lines
5.3 KiB
OpenSCAD
// ============================================================
|
||
// 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");
|
||
}
|