// ============================================================ // saltyrover_chassis.scad — SaltyRover 4-Wheel Base Plate // Rev A 2026-03-01 sl-mechanical // ============================================================ // Parametric deck plate for the stable 4-wheel SaltyRover. // Low/wide/stable design — reuses sensor head + 25 mm stem. // // Coordinate convention: // Z = 0 deck top face // +Y forward // +X right (motor side) // // Battery orientation: // Packs laid FLAT (56 mm tall, 420 mm running left-right, // 88 mm per pack fore-aft). N packs arranged fore-aft. // 2-pack tray: 430 × 186 mm opening. // 4-pack tray: 430 × 362 mm opening. // // Motor positions are at ±TRACK_W/2 (X), ±AXLE_BASE/2 (Y). // Motor brackets (rover_motor_mount.scad) bolt to deck edge // and extend BRKT_REACH mm outward to hold axle at AXLE_H. // // RENDER options: // "assembly" full deck + phantom batteries + stem stub // "deck" deck plate only (review) // "deck_2d" floor projection → DXF for waterjet/CNC // ============================================================ RENDER = "assembly"; // ── Deck footprint ──────────────────────────────────────── ROVER_L = 500.0; // fore-aft (Y) ROVER_W = 480.0; // left-right (X) — sized around battery width DECK_T = 8.0; // deck thickness DECK_R = 15.0; // corner fillet radius // ── Drive geometry (caliper-verified motor data from BOM.md) ── TRACK_W = 540.0; // motor axle CL to CL, left-right AXLE_BASE = 340.0; // motor axle CL to CL, fore-aft AXLE_H = 127.0; // axle CL above ground (10×2.125" wheel, caliper) GND_CLR = 50.0; // minimum chassis ground clearance // Height of deck bottom above ground: // GND_CLR + battery_tray_floor + battery_height BATT_FLOOR_T = 3.0; BATT_PACK_H = 56.0; // flat-laid pack height DECK_BOT_H = GND_CLR + BATT_FLOOR_T + BATT_PACK_H; // 109 mm // Axle above deck top = AXLE_H - (DECK_BOT_H + DECK_T) ≈ +10 mm // ── Battery packs (BOM.md caliper-verified: 420×88×56 mm) ── // Laid flat, 420 mm running left-right (X), 88 mm per pack (Y), // 56 mm tall (Z). BATT_N packs arranged side-by-side fore-aft. BATT_X_DIM = 420.0; BATT_Y_DIM = 88.0; // per-pack fore-aft depth BATT_N = 2; // packs fore-aft (2 = 176 mm; 4 = 352 mm) TRAY_MARGIN = 5.0; // extra margin on each side of tray opening // ── Stem socket (deck centre) ───────────────────────────── STEM_BORE = 25.5; // 25 mm tube + 0.5 clearance STEM_COLLAR_OD = 50.0; STEM_COLLAR_H = 22.0; // raised boss height above deck top // ── FC mount (MAMBA F722S, 30.5×30.5 M3) ───────────────── FC_SPACING = 30.5; FC_HOLE_D = 3.2; FC_STANDOFF_H= 6.0; // FC centred forward of battery tray FC_X = 0.0; FC_Y = ROVER_L/2 - 60.0; // near front edge // ── Jetson Orin NX mount ───────────────────────────────── // ⚠ Verify hole pattern against your carrier board. // Default: 58×49 mm M3 (same as RPi HAT pattern used on Orin NX cards). ORIN_HOLE_X = 58.0; ORIN_HOLE_Y = 49.0; ORIN_HOLE_D = 3.2; ORIN_STANDOFF = 8.0; ORIN_X = 0.0; ORIN_Y = -(ROVER_L/2 - 55.0); // near rear edge // ── Motor bracket attachment bolt pattern ──────────────── // 2× M5 bolts through deck edge at each motor corner. MOT_BOLT_D = 5.3; // M5 clearance MOT_BOLT_SPC = 30.0; // bolt spacing fore-aft at each motor position // ── Lightening holes ────────────────────────────────────── LH_D = 55.0; // ── Fasteners ───────────────────────────────────────────── M3_D = 3.2; M4_D = 4.3; M5_D = 5.3; $fn = 64; e = 0.01; // ───────────────────────────────────────────────────────── // rounded_plate_2d() // ───────────────────────────────────────────────────────── module rounded_plate_2d(l, w, r) { offset(r=r, $fn=32) offset(r=-r) square([l, w], center=true); } // ───────────────────────────────────────────────────────── // rover_deck() // ───────────────────────────────────────────────────────── module rover_deck() { tray_w = BATT_X_DIM + 2*TRAY_MARGIN; // 430 mm tray_l = BATT_Y_DIM * BATT_N + 2*TRAY_MARGIN; // 186 or 362 mm difference() { // ── Deck plate ──────────────────────────────── translate([0, 0, -DECK_T]) linear_extrude(DECK_T) rounded_plate_2d(ROVER_W, ROVER_L, DECK_R); // ── Battery tray opening (centred, through deck) ── translate([-tray_w/2, -tray_l/2, -DECK_T - e]) cube([tray_w, tray_l, DECK_T + 2*e]); // ── Lightening holes ────────────────────────── // 3 columns × 2 rows, outside battery opening for (hx = [-ROVER_W/4, 0, ROVER_W/4]) for (hy = [-(tray_l/2 + LH_D/2 + 20), (tray_l/2 + LH_D/2 + 20)]) if (abs(hy) < ROVER_L/2 - LH_D/2 - 10) translate([hx, hy, -DECK_T - e]) cylinder(d=LH_D, h=DECK_T + 2*e); // ── FC mount holes ──────────────────────────── for (fx=[-FC_SPACING/2, FC_SPACING/2]) for (fy=[-FC_SPACING/2, FC_SPACING/2]) translate([FC_X + fx, FC_Y + fy, -DECK_T - e]) cylinder(d=FC_HOLE_D, h=DECK_T + 2*e); // ── Orin mount holes ────────────────────────── for (ox=[-ORIN_HOLE_X/2, ORIN_HOLE_X/2]) for (oy=[-ORIN_HOLE_Y/2, ORIN_HOLE_Y/2]) translate([ORIN_X + ox, ORIN_Y + oy, -DECK_T - e]) cylinder(d=ORIN_HOLE_D, h=DECK_T + 2*e); // ── Motor bracket bolt holes (4 corners × 2 bolts) ── for (sx=[-1,1], sy=[-1,1]) for (by=[-MOT_BOLT_SPC/2, MOT_BOLT_SPC/2]) translate([sx*ROVER_W/2 - sx*(DECK_T/2 + e), sy*AXLE_BASE/2 + by, -DECK_T - e]) rotate([0, 90, 0]) cylinder(d=MOT_BOLT_D, h=DECK_T + 2*e); // ── Stem bore through deck ──────────────────── translate([0, 0, -DECK_T - e]) cylinder(d=STEM_BORE, h=DECK_T + 2*e); // ── Cable routing slots (×2 per side, fore and aft) ── for (cy=[-ROVER_L/2 - e, ROVER_L/2 - 16]) for (cx=[-55, 55]) translate([cx - 7, cy, -DECK_T - e]) cube([14, 16, DECK_T + 2*e]); } // ── Stem collar (raised boss) ───────────────────── difference() { cylinder(d=STEM_COLLAR_OD, h=STEM_COLLAR_H); translate([0, 0, -e]) cylinder(d=STEM_BORE, h=STEM_COLLAR_H + 2*e); } // ── FC standoff posts (×4) ──────────────────────── for (fx=[-FC_SPACING/2, FC_SPACING/2]) for (fy=[-FC_SPACING/2, FC_SPACING/2]) translate([FC_X + fx, FC_Y + fy, 0]) cylinder(d=6, h=FC_STANDOFF_H); // ── Orin standoff posts (×4) ────────────────────── for (ox=[-ORIN_HOLE_X/2, ORIN_HOLE_X/2]) for (oy=[-ORIN_HOLE_Y/2, ORIN_HOLE_Y/2]) translate([ORIN_X + ox, ORIN_Y + oy, 0]) cylinder(d=6, h=ORIN_STANDOFF); } // ───────────────────────────────────────────────────────── // Render selector // ───────────────────────────────────────────────────────── if (RENDER == "assembly") { color("Silver", 0.90) rover_deck(); // Phantom battery packs (2 × laid flat) tray_w = BATT_X_DIM + 2*TRAY_MARGIN; tray_l = BATT_Y_DIM * BATT_N + 2*TRAY_MARGIN; for (pn = [0 : BATT_N - 1]) color("Gold", 0.30) translate([-BATT_X_DIM/2, -BATT_Y_DIM*BATT_N/2 + pn*BATT_Y_DIM, -(DECK_T + BATT_FLOOR_T + BATT_PACK_H)]) cube([BATT_X_DIM, BATT_Y_DIM, BATT_PACK_H]); // Phantom stem stub color("Silver", 0.25) translate([0, 0, STEM_COLLAR_H]) cylinder(d=25, h=400); // Motor position markers (spheres at axle CLs) axle_z = AXLE_H - (DECK_BOT_H + DECK_T); // above deck top for (sx=[-1,1], sy=[-1,1]) color("Tomato", 0.5) translate([sx*TRACK_W/2, sy*AXLE_BASE/2, axle_z]) sphere(d=20); } else if (RENDER == "deck") { rover_deck(); } else if (RENDER == "deck_2d") { projection(cut=true) translate([0, 0, -DECK_T/2]) rover_deck(); }