Add parametric OpenSCAD designs for the SaltyRover stable 4-wheel variant. Reuses existing 25mm stem, sensor head, and all SaltyLab sensor mounts without modification. Files: - saltyrover_chassis.scad 480×500mm deck, stem collar, FC+Orin standoffs, motor attachment holes, battery tray opening; RENDER deck_2d for waterjet/CNC DXF - rover_motor_mount.scad L-bracket + axle clamp plate per motor; uses caliper-verified axle dims from BOM.md; dropout slot for tool-free motor swap; RENDER bracket_2d for CNC DXF - rover_battery_tray.scad Slide-out tray for 2-4 × 420×88×56mm packs laid flat (low CG); T-slot rails, spring latch - rover_stem_adapter.scad Flange + split clamp locks 25mm stem to deck collar; 550mm stem option for rover height - rover_BOM.md Assembly sequence, fastener table, mass estimate (~13.4kg), height stack diagram Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
256 lines
11 KiB
OpenSCAD
256 lines
11 KiB
OpenSCAD
// ============================================================
|
||
// rover_battery_tray.scad — SaltyRover Flat Battery Tray
|
||
// Rev A 2026-03-01 sl-mechanical
|
||
// ============================================================
|
||
// Slide-out tray for 2–4 × 420×88×56 mm battery packs
|
||
// laid FLAT below the rover deck plate.
|
||
//
|
||
// Packs orient with 420 mm left-right (X), 88 mm fore-aft
|
||
// per pack (Y), 56 mm tall (Z). BATT_N packs stack fore-aft.
|
||
//
|
||
// Tray slides out to the RIGHT (+X) for battery swap.
|
||
// Two slide rails (T-slot profile) run fore-aft inside
|
||
// the deck opening. Tray body rides on these rails.
|
||
// A spring-clip latch on the +X end retains the tray.
|
||
//
|
||
// Base plate attachment:
|
||
// Rail mounts bolt to deck underside (4× M4 per rail,
|
||
// counter-sunk flat-head).
|
||
//
|
||
// ⚠ VERIFY:
|
||
// BATT_PACK_L / W / H from caliper.
|
||
// RAIL_SLOT_W / H from your chosen extrusion or print.
|
||
//
|
||
// RENDER options:
|
||
// "assembly" tray + phantom packs (default)
|
||
// "tray" tray body for printing
|
||
// "rail" one T-slot slide rail (print 2×)
|
||
// "latch" spring latch for tray end (print 1×)
|
||
// "tray_2d" floor projection → DXF
|
||
// ============================================================
|
||
|
||
RENDER = "assembly";
|
||
|
||
// ── Battery packs (BOM.md caliper-verified) ───────────────
|
||
BATT_PACK_L = 420.0; // left-right (X)
|
||
BATT_PACK_W = 88.0; // fore-aft per pack (Y)
|
||
BATT_PACK_H = 56.0; // height when flat (Z)
|
||
BATT_N = 2; // packs arranged fore-aft (2 or 4)
|
||
|
||
// ── Tray geometry ─────────────────────────────────────────
|
||
TRAY_WALL = 2.5; // wall thickness
|
||
TRAY_FLOOR = 3.0; // floor thickness
|
||
TRAY_PAD = 2.0; // per-side clearance inside tray (pack-to-wall)
|
||
|
||
// Inner cavity
|
||
TRAY_INN_W = BATT_PACK_L + 2*TRAY_PAD;
|
||
TRAY_INN_D = BATT_PACK_W * BATT_N + 2*TRAY_PAD;
|
||
TRAY_INN_H = BATT_PACK_H + TRAY_PAD; // open top
|
||
|
||
// Outer tray body
|
||
TRAY_OUT_W = TRAY_INN_W + 2*TRAY_WALL;
|
||
TRAY_OUT_D = TRAY_INN_D + 2*TRAY_WALL;
|
||
TRAY_OUT_H = TRAY_INN_H + TRAY_FLOOR;
|
||
|
||
// ── Slide rail ────────────────────────────────────────────
|
||
// T-profile rail runs fore-aft (Y), mounts to deck underside.
|
||
// Tray has matching T-slots on its side walls.
|
||
RAIL_L = TRAY_OUT_D + 40.0; // rail longer than tray for stop
|
||
RAIL_W = 14.0; // rail body width
|
||
RAIL_H = 8.0; // rail height below deck
|
||
RAIL_T_W = 10.0; // T-slot head width on tray side
|
||
RAIL_T_H = 4.0; // T-slot head height (captured in tray slot)
|
||
RAIL_CL = 0.3; // running clearance
|
||
RAIL_M4_SPC = 80.0; // M4 deck attachment bolt spacing along rail
|
||
|
||
// Tray T-slot channel (cut into tray outer wall)
|
||
SLOT_W = RAIL_T_W + 2*RAIL_CL;
|
||
SLOT_H = RAIL_T_H + RAIL_CL;
|
||
|
||
// Rail Y-spacing: rails at ±RAIL_Y from tray centre (fore-aft)
|
||
RAIL_Y_SPC = TRAY_INN_W - 20.0; // rails near X edges of tray
|
||
// Note: rails run in Y, so RAIL_Y_SPC is the X spread between them
|
||
|
||
// ── Strap slots ───────────────────────────────────────────
|
||
STRAP_W = 20.0; // Velcro strap width
|
||
STRAP_T = 3.0; // slot depth
|
||
|
||
// ── Latch ─────────────────────────────────────────────────
|
||
LATCH_L = 40.0; // latch body length
|
||
LATCH_W = 20.0;
|
||
LATCH_T = 4.0; // plate thickness
|
||
LATCH_FLEX = 25.0; // spring arm length
|
||
LATCH_TAB_H = 5.0; // retention tab height (hooks over deck edge)
|
||
LATCH_BOLT_D= 3.3; // M3 attachment bolt
|
||
|
||
// ── Fasteners ─────────────────────────────────────────────
|
||
M3_D = 3.2;
|
||
M4_D = 4.3;
|
||
M4_CS_D = 7.0; // flat-head countersink diam
|
||
|
||
$fn = 48;
|
||
e = 0.01;
|
||
|
||
// ─────────────────────────────────────────────────────────
|
||
// battery_tray()
|
||
// Z=0 at tray bottom face. Slides in +X direction.
|
||
// Inner cavity origin at (TRAY_WALL, TRAY_WALL, TRAY_FLOOR).
|
||
// ─────────────────────────────────────────────────────────
|
||
module battery_tray() {
|
||
difference() {
|
||
union() {
|
||
// ── Outer tray body ────────────────────────
|
||
cube([TRAY_OUT_W, TRAY_OUT_D, TRAY_OUT_H]);
|
||
|
||
// ── Pull tab on +X face ────────────────────
|
||
translate([TRAY_OUT_W, TRAY_OUT_D/2 - 15, TRAY_FLOOR])
|
||
cube([18, 30, TRAY_OUT_H - TRAY_FLOOR]);
|
||
}
|
||
|
||
// ── Inner cavity (open top) ────────────────────
|
||
translate([TRAY_WALL, TRAY_WALL, TRAY_FLOOR])
|
||
cube([TRAY_INN_W, TRAY_INN_D, TRAY_INN_H + e]);
|
||
|
||
// ── Pack divider slot (for multi-pack separation) ──
|
||
if (BATT_N > 1)
|
||
for (pn = [1 : BATT_N - 1])
|
||
translate([TRAY_WALL - e,
|
||
TRAY_WALL + BATT_PACK_W * pn - 1,
|
||
TRAY_FLOOR])
|
||
cube([TRAY_INN_W + 2*e, 2, TRAY_INN_H + e]);
|
||
|
||
// ── Strap slots through floor (×2 per pack) ───
|
||
for (pn = [0 : BATT_N - 1])
|
||
for (sx = [TRAY_WALL + TRAY_INN_W*0.25,
|
||
TRAY_WALL + TRAY_INN_W*0.75])
|
||
translate([sx - STRAP_W/2,
|
||
TRAY_WALL + BATT_PACK_W * pn + 10,
|
||
-e])
|
||
cube([STRAP_W, BATT_PACK_W - 20, TRAY_FLOOR + 2*e]);
|
||
|
||
// ── T-slot channels on left (+Y) and right (-Y) faces ──
|
||
// Tray left wall: Y+ face — rail rides in from -X end
|
||
for (face_y=[TRAY_OUT_D - TRAY_WALL - e, -e]) {
|
||
translate([TRAY_OUT_W*0.2 - SLOT_W/2, face_y,
|
||
TRAY_FLOOR + TRAY_INN_H/2 - SLOT_H/2])
|
||
cube([TRAY_OUT_W*0.6, TRAY_WALL + 2*e, SLOT_H]);
|
||
// T-head channel
|
||
translate([TRAY_OUT_W*0.2 - RAIL_T_W/2 - RAIL_CL,
|
||
face_y,
|
||
TRAY_FLOOR + TRAY_INN_H/2 - SLOT_H/2 - RAIL_CL])
|
||
cube([RAIL_T_W + 2*RAIL_CL,
|
||
TRAY_WALL + 2*e,
|
||
SLOT_H + 2*RAIL_CL]);
|
||
}
|
||
|
||
// ── Ventilation / weight-save holes in floor (×4) ──
|
||
for (vx=[TRAY_OUT_W*0.25, TRAY_OUT_W*0.75])
|
||
for (vy=[TRAY_WALL + TRAY_INN_D*0.25,
|
||
TRAY_WALL + TRAY_INN_D*0.75])
|
||
translate([vx, vy, -e])
|
||
cylinder(d=25, h=TRAY_FLOOR + 2*e);
|
||
}
|
||
}
|
||
|
||
// ─────────────────────────────────────────────────────────
|
||
// slide_rail()
|
||
// Mounts to deck underside. Runs fore-aft (Y).
|
||
// T-head protrudes inward (X direction) into tray slot.
|
||
// ─────────────────────────────────────────────────────────
|
||
module slide_rail() {
|
||
difference() {
|
||
union() {
|
||
// Rail body
|
||
translate([-RAIL_W/2, 0, 0])
|
||
cube([RAIL_W, RAIL_L, RAIL_H]);
|
||
// T-head flange (protrudes toward tray)
|
||
translate([-RAIL_T_W/2, 0, RAIL_H - RAIL_T_H])
|
||
cube([RAIL_T_W, RAIL_L, RAIL_T_H]);
|
||
}
|
||
|
||
// M4 countersunk attachment holes to deck (×3 along rail)
|
||
for (ry = [15, RAIL_L/2, RAIL_L - 15])
|
||
translate([0, ry, RAIL_H + e])
|
||
rotate([180, 0, 0]) {
|
||
cylinder(d=M4_D, h=RAIL_H + 2*e);
|
||
cylinder(d1=M4_CS_D, d2=M4_D, h=3.5 + e);
|
||
}
|
||
|
||
// Rail end stop slot (tray cannot slide past rail end)
|
||
translate([-RAIL_W/2 - e, RAIL_L - 8, -e])
|
||
cube([RAIL_W + 2*e, 8 + e, RAIL_H - RAIL_T_H + e]);
|
||
}
|
||
}
|
||
|
||
// ─────────────────────────────────────────────────────────
|
||
// spring_latch()
|
||
// Clips to tray +X end face. Spring arm hooks over
|
||
// deck opening edge to retain tray. Squeeze tab to release.
|
||
// ─────────────────────────────────────────────────────────
|
||
module spring_latch() {
|
||
difference() {
|
||
union() {
|
||
// Base plate (bolts to tray end face)
|
||
cube([LATCH_W, LATCH_T, LATCH_L]);
|
||
// Spring arm
|
||
translate([LATCH_W/2 - 4, LATCH_T, LATCH_L - LATCH_FLEX])
|
||
cube([8, LATCH_T + LATCH_TAB_H, LATCH_FLEX + LATCH_TAB_H]);
|
||
// Retention tab
|
||
translate([LATCH_W/2 - 6, LATCH_T, LATCH_L - 2])
|
||
cube([12, LATCH_T + LATCH_TAB_H + 4, LATCH_TAB_H + 2]);
|
||
}
|
||
// M3 attachment holes (×2)
|
||
for (lz=[10, LATCH_L - 20])
|
||
translate([LATCH_W/2, -e, lz])
|
||
rotate([-90,0,0])
|
||
cylinder(d=LATCH_BOLT_D, h=LATCH_T + 2*e);
|
||
}
|
||
}
|
||
|
||
// ─────────────────────────────────────────────────────────
|
||
// Render selector
|
||
// ─────────────────────────────────────────────────────────
|
||
if (RENDER == "assembly") {
|
||
color("SteelBlue", 0.88) battery_tray();
|
||
|
||
// Phantom battery packs inside tray
|
||
for (pn = [0 : BATT_N - 1])
|
||
color("Gold", 0.35)
|
||
translate([TRAY_WALL + TRAY_PAD,
|
||
TRAY_WALL + TRAY_PAD + pn * BATT_PACK_W,
|
||
TRAY_FLOOR])
|
||
cube([BATT_PACK_L, BATT_PACK_W, BATT_PACK_H]);
|
||
|
||
// Slide rails
|
||
color("Silver", 0.80) {
|
||
translate([0, -20, TRAY_OUT_H])
|
||
rotate([0, 90, 0])
|
||
slide_rail();
|
||
translate([0, TRAY_OUT_D + 20 - RAIL_L, TRAY_OUT_H])
|
||
rotate([0, 90, 0])
|
||
slide_rail();
|
||
}
|
||
|
||
// Latch at +X end
|
||
color("OrangeRed", 0.85)
|
||
translate([TRAY_OUT_W + 18,
|
||
TRAY_OUT_D/2 - LATCH_W/2,
|
||
TRAY_OUT_H/2 - LATCH_L/2])
|
||
rotate([0, -90, 0])
|
||
spring_latch();
|
||
|
||
} else if (RENDER == "tray") {
|
||
battery_tray();
|
||
|
||
} else if (RENDER == "rail") {
|
||
slide_rail();
|
||
|
||
} else if (RENDER == "latch") {
|
||
spring_latch();
|
||
|
||
} else if (RENDER == "tray_2d") {
|
||
projection(cut=true)
|
||
translate([0, 0, -TRAY_FLOOR/2])
|
||
battery_tray();
|
||
}
|