// ============================================================ // saltytank_skid_plate.scad — SaltyTank Underside Skid Plate // Issue: #121 Agent: sl-mechanical Date: 2026-03-01 // ============================================================ // // Bolt-on underside protection panel for rough terrain. // Mounts to the underside of the deck plate, covering the hull // floor between the two track frames. // // Purpose: // • Protects electronics bay wiring + deck underside from rock strikes // • Sacrificial layer — replace without reworking deck plate // • Provides a smooth low-drag hull bottom for terrain sliding // • Four drain / inspection slots (water / mud egress) // // Material options: // Primary : 4 mm HDPE (high-density polyethylene) // — lightweight, impact resistant, low friction surface // Alternative: 2 mm 304 stainless steel // — heavier (+0.5 kg), extremely wear resistant // Prototype : 6 mm plywood (quick, cheap; not weatherproof) // // Dimensions: BODY_W × BODY_L × SKID_T // = 360 × 500 × 4 mm (fits between track inner faces) // // Mounting: // 8× M4 SHCS from below; nuts captured in deck plate M4 rivet-nuts // (see saltytank_chassis.scad skid plate attachment holes) // Countersunk (FHCS) variant available — set COUNTERSINK = true // // Coordinate: Z=0 at skid top face (= deck plate underside) // Ground contact surface at Z = -(FRAME_H) = -90 mm (in deck coords) // Skid sits immediately below deck: deck_bottom → skid_top // // RENDER options: // "skid_stl" STL for 3D printing (4 mm PETG, prototype) // "skid_2d" DXF for waterjet / CNC (HDPE or steel plate) // "assembly" preview with deck ghost // // Export commands: // DXF (HDPE / steel — recommended): // openscad saltytank_skid_plate.scad -D 'RENDER="skid_2d"' -o saltytank_skid.dxf // STL (3D print prototype): // openscad saltytank_skid_plate.scad -D 'RENDER="skid_stl"' -o saltytank_skid.stl // ============================================================ $fn = 64; e = 0.01; // ── Skid plate dimensions ──────────────────────────────────────────────────── // Must match saltytank_chassis.scad BODY_W and BODY_L exactly. BODY_L = 500.0; // fore-aft — copy from saltytank_chassis.scad BODY_W = 360.0; // left-right SKID_T = 4.0; // skid plate thickness (4 mm HDPE) SKID_R = 12.0; // corner radius (matches deck corners, ease of cleaning) FRAME_H = 90.0; // side frame height (from saltytank_chassis.scad) // ── Skid reinforcement ribs (under-surface, printed variant only) ───────────── // Ribs add stiffness to the printed skid without adding flat-surface area. // Ribs are omitted on the CNC/laser version (material stiffness is sufficient). RIB_H = 8.0; // rib height below skid top face RIB_T = 3.0; // rib wall thickness RIB_PRINT = false; // set true to add ribs (print only; skip for DXF) // ── Attachment bolt holes (M4) ─────────────────────────────────────────────── // Pattern must match saltytank_chassis.scad skid plate holes exactly. // 2 rows × 3 columns = 6 holes + 2 corners = 8 total BOLT_D = 4.3; // M4 clearance BOLT_INSET_X = 20.0; // CL inset from left/right edge BOLT_INSET_Y = 25.0; // CL inset from front/rear edge // Countersinking (flat-head bolts flush with skid surface — preferred for terrain) COUNTERSINK = true; CSINK_ANGLE = 82; // M4 FHCS countersink angle (82° for DIN 7991) CSINK_OD = 8.0; // M4 FHCS head diameter // ── Drain / inspection slots ───────────────────────────────────────────────── DRAIN_W = 20.0; // slot width DRAIN_L = 60.0; // slot length DRAIN_R = 10.0; // slot corner radius // ── Road-wheel axle pass-through slots ─────────────────────────────────────── // The road wheel axles sit OUTSIDE the skid plate (they're in the side frames), // so no axle holes are needed in the skid plate. // The skid plate is a solid panel between the track frames. // ── Fasteners ───────────────────────────────────────────────────────────────── M4_D = 4.3; // ============================================================ // RENDER DISPATCH // ============================================================ RENDER = "assembly"; if (RENDER == "skid_stl") { skid_plate(); } else if (RENDER == "skid_2d") { projection(cut = true) translate([0, 0, -SKID_T / 2]) skid_plate_flat_only(); } else if (RENDER == "assembly") { assembly(); } // ============================================================ // ASSEMBLY PREVIEW // ============================================================ module assembly() { color("Sienna", 0.85) skid_plate(); // Ghost deck plate above %color("Silver", 0.25) translate([0, 0, SKID_T]) linear_extrude(8) minkowski() { square([BODY_L - 24, BODY_W - 24], center = true); circle(r = 12); } // Ghost side frames (simplified) for (sx = [-1, 1]) %color("SteelBlue", 0.20) translate([sx * (BODY_W/2 + 3), 0, SKID_T]) cube([6, BODY_L, FRAME_H + 8], center = true); } // ============================================================ // SKID PLATE (3D print — includes optional ribs) // ============================================================ module skid_plate() { difference() { union() { // ── Base plate ───────────────────────────────────────────── linear_extrude(SKID_T) skid_profile_2d(); // ── Reinforcement ribs (printed version only) ────────────── if (RIB_PRINT) { // Longitudinal centre rib translate([0, 0, SKID_T]) cube([RIB_T, BODY_L - 40, RIB_H], center = true); // Lateral ribs (3× fore-aft) for (ry = [-BODY_L/4, 0, BODY_L/4]) translate([0, ry, SKID_T]) cube([BODY_W - 40, RIB_T, RIB_H], center = true); } } // ── Attachment bolt holes ────────────────────────────────────── for (bpos = bolt_positions()) translate([bpos[0], bpos[1], -e]) { cylinder(d = BOLT_D, h = SKID_T + 2*e); if (COUNTERSINK) // Countersink cone from top face translate([0, 0, SKID_T + e]) cylinder(d1 = CSINK_OD, d2 = BOLT_D, h = (CSINK_OD - BOLT_D) / (2 * tan(CSINK_ANGLE/2))); } // ── Drain / inspection slots (4×, one per quadrant) ─────────── for (sx = [-1, 1]) for (sy = [-1, 1]) { dx = sx * (BODY_W/4 + 15); dy = sy * (BODY_L/4 + 20); translate([dx - DRAIN_W/2 + DRAIN_R, dy - DRAIN_L/2 + DRAIN_R, -e]) linear_extrude(SKID_T + 2*e) minkowski() { square([DRAIN_W - 2*DRAIN_R, DRAIN_L - 2*DRAIN_R]); circle(r = DRAIN_R); } } } } // 2D profile of skid plate (shared by skid_plate and DXF export) module skid_profile_2d() { minkowski() { square([BODY_L - 2*SKID_R, BODY_W - 2*SKID_R], center = true); circle(r = SKID_R); } } // Flat-only version for DXF projection (no ribs) module skid_plate_flat_only() { difference() { linear_extrude(SKID_T) skid_profile_2d(); for (bpos = bolt_positions()) translate([bpos[0], bpos[1], -e]) cylinder(d = BOLT_D, h = SKID_T + 2*e); for (sx = [-1, 1]) for (sy = [-1, 1]) { dx = sx * (BODY_W/4 + 15); dy = sy * (BODY_L/4 + 20); translate([dx - DRAIN_W/2 + DRAIN_R, dy - DRAIN_L/2 + DRAIN_R, -e]) linear_extrude(SKID_T + 2*e) minkowski() { square([DRAIN_W - 2*DRAIN_R, DRAIN_L - 2*DRAIN_R]); circle(r = DRAIN_R); } } } } // ── Bolt position list (8 positions matching saltytank_chassis.scad) ────────── function bolt_positions() = [ // From saltytank_chassis.scad skid plate holes (sx × (BODY_W/2 - 20), sy × BODY_L/3) [-BODY_W/2 + BOLT_INSET_X, -BODY_L/3], [-BODY_W/2 + BOLT_INSET_X, 0], [-BODY_W/2 + BOLT_INSET_X, +BODY_L/3], [+BODY_W/2 - BOLT_INSET_X, -BODY_L/3], [+BODY_W/2 - BOLT_INSET_X, 0], [+BODY_W/2 - BOLT_INSET_X, +BODY_L/3] ];