// ============================================================================= // SaltyBot — Prototype Base Plate (Rev C — compact, stem-mount) // Agent: sl-mechanical | 2026-02-28 // // Laser-cut or CNC-routed flat plate (6 mm Al / 8 mm acrylic). // Uses CALIPER-VERIFIED hub motor axle measurements (see PR #7 / #11). // // ARCHITECTURE CHANGE (Rev C): // Batteries are NO LONGER on the base plate. // They stand vertically on a central stem via stem_battery_clamp.scad. // The base plate is now compact — only axle dropouts + stem socket + FC mount. // // ── AXLE PROFILE (stepped D-cut, caliper-verified) ─────────────────────────── // Zone │ Feature │ Ø / Width │ Length // ───────┼──────────────────┼────────────────────┼────────── // Base │ Round (near hub) │ Ø 16.11 mm │ 15.00 mm // D-cut │ Round OD │ Ø 15.95 mm │ 43.35 mm // │ Flat chord │ 13.00 mm │ // Tip │ Shoulder/end │ — │ 3.00 mm // Total │ Hub face → tip │ — │ 65.50 mm // Bearing seat collar: Ø 37.8 mm // Tire: 10 × 2.125" pneumatic (Ø 254 mm, 35 PSI) // ============================================================================= $fn = 128; // ============================================================================= // AXLE PARAMETERS — caliper-verified // ============================================================================= AXLE_BASE_DIA = 16.11; AXLE_BASE_LEN = 15.00; AXLE_DCUT_DIA = 15.95; AXLE_DCUT_FLAT = 13.00; AXLE_DCUT_LEN = 43.35; AXLE_TIP_LEN = 3.00; AXLE_TOTAL = 65.50; BEARING_SEAT_OD = 37.80; TIRE_OD = 254.0; AXLE_CL_HEIGHT = TIRE_OD / 2; // 127 mm above ground // ============================================================================= // PLATE PARAMETERS // ============================================================================= WHEELBASE = 600.0; // mm axle C/L to axle C/L // Plate depth now driven only by structural + FC needs (no battery footprint). PLATE_DEPTH = 130.0; // mm front-to-rear PLATE_OVERHANG = 40.0; // mm plate past axle C/L each side PLATE_THICK = 6.0; // mm // Fork slot FORK_W = AXLE_BASE_DIA + 0.4; // 16.51 mm FORK_DEPTH = 50.0; // Dropout clamp (two-piece sandwich) CLAMP_L = 80.0; CLAMP_H = 60.0; CLAMP_THICK = 8.0; CLAMP_BOLT_D = 5.3; // M5 CLAMP_BOLT_DX = 22.0; CLAMP_BOLT_DY = 22.0; CLAMP_ALIGN_D = 4.1; // Ø4 pin // D-cut bore clearance DCUT_CL = 0.3; // FC mount — ESP32-S3 BALANCE 30.5 × 30.5 mm M3 FC_PITCH = 30.5; FC_HOLE_D = 3.2; // FC is offset toward front of plate (away from stem) FC_X_OFFSET = -40.0; // mm from plate centre (negative = front/motor side) // ============================================================================= // STEM SOCKET PARAMETERS // ============================================================================= STEM_OD = 38.1; // mm 1.5" EMT conduit OD STEM_BORE = STEM_OD + 0.5; // 38.6 mm with clearance // Flange ring (laser-cut, bolts above + below plate to grip tube): STEM_FLANGE_OD = 82.0; // mm flange outer diameter STEM_FLANGE_BC = 66.0; // mm bolt circle diameter (4× M5 at 90°) STEM_FLANGE_T = 6.0; // mm = PLATE_THICK (flush-mount) // Stem position: at plate centre (X=0, Y=0) // ============================================================================= // UTILITIES // ============================================================================= M3 = 3.2; M4 = 4.3; M5 = 5.3; PLATE_X_HALF = WHEELBASE/2 + PLATE_OVERHANG; // ± 340 mm DCUT_R = (AXLE_DCUT_DIA + 2*DCUT_CL) / 2; DCUT_FC = AXLE_DCUT_FLAT + 2*DCUT_CL; // ============================================================================= // RENDER CONTROL // ============================================================================= // // "assembly" full 3-D preview // "plate_2d" DXF — base plate // "clamp_lower_2d" DXF — lower dropout clamp (× 2) // "clamp_upper_2d" DXF — upper dropout clamp (× 2) // "stem_flange_2d" DXF — stem flange ring (× 2, one above + one below plate) RENDER = "assembly"; if (RENDER == "assembly") { assembly(); } else if (RENDER == "plate_2d") { projection(cut=true) translate([0,0,-PLATE_THICK/2]) base_plate(); } else if (RENDER == "clamp_lower_2d") { projection(cut=true) translate([0,0,-CLAMP_THICK/2]) clamp_lower(); } else if (RENDER == "clamp_upper_2d") { projection(cut=true) translate([0,0,-CLAMP_THICK/2]) clamp_upper(); } else if (RENDER == "stem_flange_2d") { projection(cut=true) translate([0,0,-STEM_FLANGE_T/2]) stem_flange(); } // ============================================================================= // ASSEMBLY // ============================================================================= module assembly() { color("Silver", 0.85) base_plate(); for (side = [-1, 1]) { color("SteelBlue", 0.80) translate([side * WHEELBASE/2, 0, PLATE_THICK]) clamp_lower(); color("CornflowerBlue", 0.80) translate([side * WHEELBASE/2, 0, PLATE_THICK + CLAMP_THICK]) clamp_upper(); } // Stem flange rings (above and below plate) color("DimGray", 0.70) translate([0, 0, -STEM_FLANGE_T]) stem_flange(); color("DimGray", 0.70) translate([0, 0, PLATE_THICK]) stem_flange(); // Reference ghosts %color("Orange", 0.25) translate([0, 0, PLATE_THICK + STEM_FLANGE_T]) cylinder(d=STEM_OD, h=800); // vertical stem %for (side = [-1, 1]) color("Tomato", 0.2) translate([side * WHEELBASE/2, 0, 0]) rotate([0, side*90, 0]) axle_ghost(); } // ============================================================================= // BASE PLATE (Part A — compact) // ============================================================================= module base_plate() { R = 12; // corner radius difference() { // ── Outer profile ── linear_extrude(PLATE_THICK) minkowski() { square([2*(PLATE_X_HALF - R), PLATE_DEPTH - 2*R], center=true); circle(r=R); } // ── Fork slots (open at ±X edges, semicircular tip) ────────────── for (side = [-1, 1]) { translate([side*(PLATE_X_HALF - FORK_DEPTH), -FORK_W/2, -1]) cube([FORK_DEPTH + 1, FORK_W, PLATE_THICK + 2]); translate([side*(PLATE_X_HALF - FORK_DEPTH), 0, -1]) cylinder(d=FORK_W, h=PLATE_THICK + 2); } // ── Bearing seat relief (prevents Ø37.8 mm collar binding on edge) ─ for (side = [-1, 1]) translate([side*PLATE_X_HALF - side*(BEARING_SEAT_OD/2 + 1), -BEARING_SEAT_OD/2, -1]) cube([BEARING_SEAT_OD/2 + 2, BEARING_SEAT_OD, PLATE_THICK + 2]); // ── Dropout clamp bolt through-holes ───────────────────────────── for (side = [-1, 1]) for (dx = [-CLAMP_BOLT_DX, CLAMP_BOLT_DX]) for (dy = [-CLAMP_BOLT_DY, CLAMP_BOLT_DY]) translate([side*WHEELBASE/2 + dx, dy, -1]) cylinder(d=CLAMP_BOLT_D, h=PLATE_THICK + 2); // ── Alignment pin holes (Ø4) ────────────────────────────────────── for (side = [-1, 1]) for (dy = [-CLAMP_BOLT_DY + 8, CLAMP_BOLT_DY - 8]) translate([side*WHEELBASE/2, dy, -1]) cylinder(d=CLAMP_ALIGN_D, h=PLATE_THICK + 2); // ── Stem socket bore ────────────────────────────────────────────── translate([0, 0, -1]) cylinder(d=STEM_BORE, h=PLATE_THICK + 2); // ── Stem flange bolt holes (4× M5, 90° pattern on STEM_FLANGE_BC) ─ for (a = [0, 90, 180, 270]) rotate([0, 0, a]) translate([STEM_FLANGE_BC/2, 0, -1]) cylinder(d=M5, h=PLATE_THICK + 2); // ── FC mount (ESP32-S3 BALANCE 30.5 × 30.5 M3) ──────────────────────── for (x = [FC_X_OFFSET - FC_PITCH/2, FC_X_OFFSET + FC_PITCH/2]) for (y = [-FC_PITCH/2, FC_PITCH/2]) translate([x, y, -1]) cylinder(d=FC_HOLE_D, h=PLATE_THICK + 2); // ── Wiring / cable pass-through slots (2×, flanking stem) ───────── for (dy = [-30, 30]) hull() { translate([15, dy, -1]) cylinder(d=14, h=PLATE_THICK + 2); translate([-15, dy, -1]) cylinder(d=14, h=PLATE_THICK + 2); } // ── Lightening slots (between FC zone and dropout zones) ────────── for (sx = [-1, 1]) { // One slot each side of stem, in the structural corridor lx = sx * (WHEELBASE/4); hull() { translate([lx, -(PLATE_DEPTH/2 - 22), -1]) cylinder(d=18, h=PLATE_THICK+2); translate([lx, (PLATE_DEPTH/2 - 22), -1]) cylinder(d=18, h=PLATE_THICK+2); } } } } // ============================================================================= // STEM FLANGE RING (laser-cut, qty 2 — one above, one below plate) // ============================================================================= module stem_flange() { difference() { cylinder(d=STEM_FLANGE_OD, h=STEM_FLANGE_T); // Stem bore (tight fit — tube presses into flange) translate([0, 0, -1]) cylinder(d=STEM_BORE, h=STEM_FLANGE_T + 2); // 4× M5 flange bolts for (a = [0, 90, 180, 270]) rotate([0, 0, a]) translate([STEM_FLANGE_BC/2, 0, -1]) cylinder(d=M5, h=STEM_FLANGE_T + 2); } } // ============================================================================= // DROPOUT CLAMP — LOWER (round bore, base-section diameter) // ============================================================================= module clamp_lower() { difference() { hull() { translate([-CLAMP_L/2 + CLAMP_H/2, 0, 0]) cylinder(d=CLAMP_H, h=CLAMP_THICK); translate([ CLAMP_L/2 - CLAMP_H/2, 0, 0]) cylinder(d=CLAMP_H, h=CLAMP_THICK); } // Round bore (base zone) translate([0, 0, -1]) cylinder(d=AXLE_BASE_DIA + 0.4, h=CLAMP_THICK + 2); // Slide-in slot (open toward wheel side) translate([-CLAMP_L/2 - 1, -FORK_W/2, -1]) cube([CLAMP_L/2 + 1, FORK_W, CLAMP_THICK + 2]); // Clamp bolts for (dx = [-CLAMP_BOLT_DX, CLAMP_BOLT_DX]) for (dy = [-CLAMP_BOLT_DY, CLAMP_BOLT_DY]) translate([dx, dy, -1]) cylinder(d=CLAMP_BOLT_D, h=CLAMP_THICK + 2); // Alignment pins for (dy = [-CLAMP_BOLT_DY + 8, CLAMP_BOLT_DY - 8]) translate([0, dy, -1]) cylinder(d=CLAMP_ALIGN_D, h=CLAMP_THICK + 2); } } // ============================================================================= // DROPOUT CLAMP — UPPER (D-cut bore, anti-rotation) // ============================================================================= module clamp_upper() { dcut_r = DCUT_R; dcut_d = sqrt(pow(dcut_r, 2) - pow(DCUT_FC/2, 2)); difference() { hull() { translate([-CLAMP_L/2 + CLAMP_H/2, 0, 0]) cylinder(d=CLAMP_H, h=CLAMP_THICK); translate([ CLAMP_L/2 - CLAMP_H/2, 0, 0]) cylinder(d=CLAMP_H, h=CLAMP_THICK); } // D-cut bore translate([0, 0, -1]) linear_extrude(CLAMP_THICK + 2) dcut_profile_2d(dcut_r, dcut_d); // Slide-in slot translate([-CLAMP_L/2 - 1, -FORK_W/2, -1]) cube([CLAMP_L/2 + 1, FORK_W, CLAMP_THICK + 2]); // Clamp bolts for (dx = [-CLAMP_BOLT_DX, CLAMP_BOLT_DX]) for (dy = [-CLAMP_BOLT_DY, CLAMP_BOLT_DY]) translate([dx, dy, -1]) cylinder(d=CLAMP_BOLT_D, h=CLAMP_THICK + 2); // Alignment pins for (dy = [-CLAMP_BOLT_DY + 8, CLAMP_BOLT_DY - 8]) translate([0, dy, -1]) cylinder(d=CLAMP_ALIGN_D, h=CLAMP_THICK + 2); // Orientation emboss translate([0, dcut_d + 1.5, CLAMP_THICK - 0.8]) linear_extrude(1) polygon([[0,0],[-3,-5],[3,-5]]); } } // ── D-cut 2D profile helper ─────────────────────────────────────────────────── module dcut_profile_2d(r, flat_d) { intersection() { circle(r=r); translate([-r - 1, -r - 1]) square([2*(r+1), r + 1 + flat_d]); } } // ============================================================================= // AXLE GHOST (visualisation only) // ============================================================================= module axle_ghost() { cylinder(d=BEARING_SEAT_OD, h=12); translate([0,0,12]) cylinder(d=AXLE_BASE_DIA, h=AXLE_BASE_LEN); translate([0,0,12+AXLE_BASE_LEN]) cylinder(d=AXLE_DCUT_DIA, h=AXLE_DCUT_LEN); } // ============================================================================= // DXF EXPORT // ============================================================================= // // Part 1 — Base plate: // openscad prototype_baseplate.scad -D 'RENDER="plate_2d"' -o baseplate.dxf // // Part 2 — Dropout clamp, lower (× 2): // openscad prototype_baseplate.scad -D 'RENDER="clamp_lower_2d"' -o clamp_lower.dxf // // Part 3 — Dropout clamp, upper (× 2): // openscad prototype_baseplate.scad -D 'RENDER="clamp_upper_2d"' -o clamp_upper.dxf // // Part 4 — Stem flange ring (× 2, one each side of plate): // openscad prototype_baseplate.scad -D 'RENDER="stem_flange_2d"' -o stem_flange.dxf // // Materials: // Plate + flanges : 6 mm 5052-H32 aluminium (preferred) // 8 mm clear acrylic (quick proto) // Dropout clamps : 8 mm 6061-T6 aluminium // Stem tube : 38.1 mm OD × 1.5 mm wall 6061-T6 (or 1.5" EMT) // Cut stem to ~1050 mm — allows batteries from ~100 mm to ~950 mm height. // =============================================================================