saltylab-firmware/chassis/prototype_baseplate.scad
sl-mechanical 6ea4b56471 fix: base plate dimensions 270x240mm per spec (issue #18)
Both chassis files corrected. Previous dimensions were wrong:
  prototype_baseplate.scad: was 680x130mm → now 270x240mm
  chassis_frame.scad:       was 640x220mm → now 270x240mm

Geometry recalculated for 270x240mm envelope:

  PLATE_W = 270mm (axle direction)
  PLATE_D = 240mm (front-to-rear)
  PLATE_X_HALF = 135mm (plate edge / axle entry)
  FORK_SLOT_D = 50mm → AXLE_X = 85mm from plate centre
  Axle-to-axle = 170mm (2 × 85mm)

  Wheels extend beyond plate edges as expected:
  Tire at X = ±(85 ± 27) = ±58–112mm, plate edge at ±135mm ✓

Mount positions recalculated for smaller plate:
  Dropout clamp bolt holes: X = ±(85±22) = ±63 and ±107mm ✓ (all within ±135mm)
  Stem flange bolts: r=33mm BC, at (±33,0) and (0,±33) ✓
  FC mount: X = -40mm offset, holes at ±15mm ✓
  Wiring slots: Y = ±55mm (clear of stem flange bolts at ±33mm)
  Lightening ovals: Y = ±80mm in open front/rear corridors
  Bumper length: 300mm (was 660mm, now PLATE_D + 60)
  Longitudinal ribs: 270mm long (was 600mm)

chassis_frame.scad also updated:
  AXLE_HEIGHT corrected: 310mm → 127mm (TIRE_OD/2)
  Axle dimensions: 14mm → 16.11mm, flat 10mm → 13.00mm
  AXLE_X for fork bracket positioning
  Motor fork bracket logic cleaned up (no more negative cube dimensions)

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

331 lines
15 KiB
OpenSCAD
Raw 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.

// =============================================================================
// SaltyBot — Prototype Base Plate (Rev D — correct 270 × 240 mm envelope)
// Agent: sl-mechanical | 2026-02-28 | Fixes issue #18
//
// Laser-cut or CNC-routed flat plate (6 mm Al / 8 mm acrylic).
//
// PLATE DIMENSIONS (per spec, issue #18)
// Width (axle direction, X): 270 mm
// Depth (front-to-rear, Y): 240 mm
// Wheels extend beyond plate edges — expected.
//
// MOTOR AXLE GEOMETRY
// Plate edge = axle entry point (X = ±135 mm from plate centre)
// Fork slot depth = 50 mm inward → axle C/L seated at X = ±85 mm
// Axle-to-axle distance = 170 mm
// Tires (Ø254 mm, 54 mm wide) at X = ±(85 ± 27) = ±58 112 mm ← clear of ±135 edge
//
// VERIFIED AXLE PROFILE (caliper)
// Base section: Ø 16.11 mm, 15 mm long
// D-cut zone: Ø 15.95 mm, 13 mm flat chord, 43.35 mm long
// Tip: 3 mm
// Total: 65.5 mm from hub face
// Bearing seat collar: Ø 37.8 mm
// =============================================================================
$fn = 128;
// =============================================================================
// PLATE DIMENSIONS ← primary parameters for issue #18 fix
// =============================================================================
PLATE_W = 270.0; // mm width (axle / left-right direction)
PLATE_D = 240.0; // mm depth (front-to-rear)
PLATE_THICK = 6.0; // mm stock thickness
// Derived
PLATE_X_HALF = PLATE_W / 2; // 135 mm — plate edge
FORK_DEPTH = 50.0; // mm fork slot depth (inward from edge)
AXLE_X = PLATE_X_HALF - FORK_DEPTH; // 85 mm — axle C/L from plate centre
// =============================================================================
// 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; // 10" × 25.4 mm
// =============================================================================
// DROPOUT CLAMP PARAMETERS
// =============================================================================
FORK_W = AXLE_BASE_DIA + 0.4; // 16.51 mm fork slot width
CLAMP_L = 80.0; // mm clamp length along axle axis
// outer end at AXLE_X + CLAMP_L/2 = 85+40 = 125 mm
// plate edge at 135 mm → 10 mm margin ✓
CLAMP_H = 60.0; // mm clamp height (front-to-rear, in Y)
CLAMP_THICK = 8.0; // mm each clamp layer
CLAMP_BOLT_D = 5.3; // M5 clearance
CLAMP_BOLT_DX = 22.0; // mm bolt offset ±X from axle C/L
// inner bolt at AXLE_X - 22 = 63 mm ✓
// outer bolt at AXLE_X + 22 = 107 mm < 135 mm ✓
CLAMP_BOLT_DY = 22.0; // mm bolt offset ±Y from axle C/L
CLAMP_ALIGN_D = 4.1; // Ø4 alignment pin clearance
DCUT_CL = 0.3; // mm D-cut bore clearance (all-round)
DCUT_R = (AXLE_DCUT_DIA + 2*DCUT_CL) / 2;
DCUT_FC = AXLE_DCUT_FLAT + 2*DCUT_CL;
// =============================================================================
// STEM SOCKET
// =============================================================================
STEM_OD = 38.1; // mm 1.5" EMT conduit OD
STEM_BORE = STEM_OD + 0.5;
STEM_FLANGE_OD = 82.0; // mm flange ring OD
STEM_FLANGE_BC = 66.0; // mm M5 bolt circle diameter (r = 33 mm)
STEM_FLANGE_T = 6.0; // mm = PLATE_THICK
// Verify flange bolts clear all other holes:
// Flange bolts at (±33, 0) and (0, ±33)
// Clamp bolts at (±63, ±22) and (±107, ±22)
// FC holes centred at (-40, 0) spanning X = ±55.25, Y = ±15.25
// All separations are adequate ✓
// =============================================================================
// FC MOUNT — MAMBA F722S 30.5 × 30.5 mm M3
// =============================================================================
FC_PITCH = 30.5;
FC_HOLE_D = 3.2;
FC_X_OFFSET = -40.0; // mm front of plate (X); FC at (40, 0) within ±135 ✓
// =============================================================================
// UTILITIES
// =============================================================================
M3 = 3.2; M4 = 4.3; M5 = 5.3;
// =============================================================================
// 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)
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 * AXLE_X, 0, PLATE_THICK])
clamp_lower();
color("CornflowerBlue", 0.80)
translate([side * AXLE_X, 0, PLATE_THICK + CLAMP_THICK])
clamp_upper();
}
// Stem flanges (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();
// Ghosts — not exported
%color("Orange", 0.25)
translate([0, 0, PLATE_THICK + STEM_FLANGE_T])
cylinder(d=STEM_OD, h=900);
%for (side = [-1, 1])
color("Tomato", 0.20)
translate([side * PLATE_X_HALF, 0, 0])
rotate([0, side * (-90), 0]) // axle projects inward from plate edge
axle_ghost();
}
// =============================================================================
// BASE PLATE (Part A — 270 × 240 mm)
// =============================================================================
module base_plate() {
R = 10; // corner radius
difference() {
// ── Outer profile (minkowski rounded corners) ──────────────────────
linear_extrude(PLATE_THICK)
minkowski() {
square([PLATE_W - 2*R, PLATE_D - 2*R], center=true);
circle(r=R);
}
// ── Fork slots (open at ±X plate edges, semicircular tip) ──────────
// Slot width FORK_W, depth FORK_DEPTH inward from plate edge.
// Axle seats in the semicircle at X = ±(PLATE_X_HALF FORK_DEPTH) = ±85 mm.
for (side = [-1, 1]) {
// Rectangular slot body
translate([side * (PLATE_X_HALF - FORK_DEPTH), -FORK_W/2, -1])
cube([side > 0 ? FORK_DEPTH + 1 : FORK_DEPTH + 1,
FORK_W, PLATE_THICK + 2]);
// Semicircular slot tip (axle seat)
translate([side * (PLATE_X_HALF - FORK_DEPTH), 0, -1])
cylinder(d=FORK_W, h=PLATE_THICK + 2);
}
// ── Bearing seat relief (prevents Ø37.8 mm hub collar contacting edge) ─
for (side = [-1, 1])
translate([side * (PLATE_X_HALF - 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 * AXLE_X + dx, dy, -1])
cylinder(d=CLAMP_BOLT_D, h=PLATE_THICK + 2);
// ── Alignment pin holes (Ø4 × 2 per clamp) ─────────────────────────
for (side = [-1, 1])
for (dy = [-CLAMP_BOLT_DY + 8, CLAMP_BOLT_DY - 8])
translate([side * AXLE_X, 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 at 90° on Ø66 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 holes (MAMBA F722S 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 (flanking stem) ───────────────
// Placed at Y = ±55 mm (clear of stem flange bolts at ±33 mm and clamp at ±22 mm)
for (dy = [-55, 55])
hull() {
translate([ 12, dy, -1]) cylinder(d=12, h=PLATE_THICK + 2);
translate([-12, dy, -1]) cylinder(d=12, h=PLATE_THICK + 2);
}
// ── Lightening holes (2× in open areas between stem and clamp zones) ─
// At X = 0, Y = ±80 mm (front/rear open corridor)
for (dy = [-80, 80])
hull() {
translate([ 20, dy, -1]) cylinder(d=20, h=PLATE_THICK + 2);
translate([-20, dy, -1]) cylinder(d=20, h=PLATE_THICK + 2);
}
}
}
// =============================================================================
// STEM FLANGE RING (laser-cut, qty 2)
// =============================================================================
module stem_flange() {
difference() {
cylinder(d=STEM_FLANGE_OD, h=STEM_FLANGE_T);
translate([0, 0, -1]) cylinder(d=STEM_BORE, h=STEM_FLANGE_T + 2);
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)
// =============================================================================
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);
}
translate([0,0,-1]) cylinder(d=AXLE_BASE_DIA + 0.4, h=CLAMP_THICK + 2);
// Open entry slot (axle slides in from plate edge)
translate([-CLAMP_L/2 - 1, -FORK_W/2, -1])
cube([CLAMP_L/2 + 1, FORK_W, CLAMP_THICK + 2]);
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);
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_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);
}
translate([0,0,-1])
linear_extrude(CLAMP_THICK + 2) dcut_profile_2d(DCUT_R, dcut_d);
translate([-CLAMP_L/2 - 1, -FORK_W/2, -1])
cube([CLAMP_L/2 + 1, FORK_W, CLAMP_THICK + 2]);
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);
for (dy = [-CLAMP_BOLT_DY + 8, CLAMP_BOLT_DY - 8])
translate([0, dy, -1]) cylinder(d=CLAMP_ALIGN_D, h=CLAMP_THICK + 2);
// Orientation marker (triangle pointing toward flat)
translate([0, dcut_d + 1.5, CLAMP_THICK - 0.8])
linear_extrude(1) polygon([[0,0],[-3,-5],[3,-5]]);
}
}
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 COMMANDS
// =============================================================================
//
// Base plate (270 × 240 mm, 6 mm Al or 8 mm acrylic):
// openscad prototype_baseplate.scad -D 'RENDER="plate_2d"' -o baseplate.dxf
//
// Dropout clamp lower (× 2):
// openscad prototype_baseplate.scad -D 'RENDER="clamp_lower_2d"' -o clamp_lower.dxf
//
// Dropout clamp upper (× 2):
// openscad prototype_baseplate.scad -D 'RENDER="clamp_upper_2d"' -o clamp_upper.dxf
//
// Stem flange ring (× 2):
// openscad prototype_baseplate.scad -D 'RENDER="stem_flange_2d"' -o stem_flange.dxf
//
// PLATE BLANK: 280 × 250 mm (10 mm oversized each side for datum + clamping)
// CLAMP BLANKS: 90 × 70 mm each
// FLANGE BLANKS: Ø90 mm disc each
// =============================================================================