// ============================================================================= // SaltyBot — Full Chassis Frame (Rev B — correct 270 × 240 mm envelope) // Agent: sl-mechanical | 2026-02-28 | Fixes issue #18 // // Parametric OpenSCAD model. Plate geometry corrected per issue #18: // Width (axle direction, X): 270 mm ← was wrong 640 mm // Depth (front-to-rear, Y): 240 mm ← was wrong 220 mm // Wheels extend beyond plate edges — expected. // // Motor axle dimensions updated to caliper-verified values (see PR #7 / #11). // // NOTE: For the prototype, use prototype_baseplate.scad + stem_battery_clamp.scad. // This file models the full machined chassis for production reference. // ============================================================================= $fn = 64; // ============================================================================= // PLATE DIMENSIONS ← primary parameters fixed for issue #18 // ============================================================================= PLATE_W = 270.0; // mm width (axle / left-right direction) PLATE_D = 240.0; // mm depth (front-to-rear) DECK_THICK = 6.0; // mm deck plate thickness WALL_T = 4.0; // mm general wall / rib thickness // Fork slot geometry — slot opens at plate edge, axle seats at bottom FORK_SLOT_D = 50.0; // mm fork slot depth (inward from plate edge) PLATE_X_HALF = PLATE_W / 2; // 135 mm — plate half-width / edge AXLE_X = PLATE_X_HALF - FORK_SLOT_D; // 85 mm — axle C/L from plate centre // ============================================================================= // HUB MOTOR — VERIFIED AXLE DIMENSIONS (caliper) // ============================================================================= AXLE_BASE_DIA = 16.11; // mm round section near hub AXLE_BASE_LEN = 15.00; AXLE_DCUT_DIA = 15.95; // mm D-cut round OD AXLE_DCUT_FLAT = 13.00; // mm flat chord AXLE_DCUT_LEN = 43.35; AXLE_TOTAL = 65.50; // mm protrusion from hub face BEARING_SEAT_OD = 37.80; // mm hub centre collar OD TIRE_OD = 254.0; // mm 10 × 2.125" pneumatic TIRE_WIDTH = 54.0; // mm AXLE_HEIGHT = TIRE_OD / 2; // 127 mm — axle C/L above ground // Fork slot width (base section + clearance) FORK_SLOT_W = AXLE_BASE_DIA + 0.4; // 16.51 mm // Vertical motor fork bracket FORK_BKT_H = 100.0; // mm bracket height below deck to axle level FORK_BKT_T = 8.0; // mm bracket plate thickness FORK_BKT_W = 28.0; // mm bracket width (Y) // ============================================================================= // FC MOUNT — MAMBA F722S 30.5 × 30.5 mm M3 // ============================================================================= FC_PITCH = 30.5; FC_HOLE_D = 3.2; FC_STANDOFF = 6.0; FC_X = -40.0; // mm from plate centre (front of plate) // ============================================================================= // BATTERY TRAY (legacy flat — superseded by stem carousel architecture) // ============================================================================= BATT_L = 185.0; BATT_W = 72.0; BATT_H = 52.0; BATT_WALL = 3.0; BATT_FLOOR = 4.0; // ============================================================================= // JETSON NANO B01 MOUNT // ============================================================================= JETSON_PITCH = 58.0; JETSON_HOLE_D = 3.2; JETSON_PL = 100.0; JETSON_PW = 86.0; JETSON_PT = 4.0; JETSON_STOFF = 8.0; JETSON_X = 50.0; // mm from plate centre (rear) // ============================================================================= // BUMPER BRACKETS // ============================================================================= BUMPER_L = PLATE_D + 60; // 300 mm — spans plate depth + 30 mm each end BUMPER_H = 40.0; BUMPER_T = 5.0; BUMPER_TUBE_OD = 22.0; // 3/4" EMT // ============================================================================= // LONGITUDINAL RIBS // ============================================================================= RIB_T = 4.0; RIB_H = 40.0; // ============================================================================= // FASTENERS // ============================================================================= M3 = 3.2; M4 = 4.3; M5 = 5.3; // ============================================================================= // ASSEMBLY // ============================================================================= color("Silver", 0.90) main_deck(); color("DimGray", 1.00) motor_fork_bracket(side= 1); color("DimGray", 1.00) motor_fork_bracket(side=-1); color("SteelBlue", 1.00) battery_tray(); color("OliveDrab", 1.00) fc_mount_plate(); color("DarkOrange", 1.00) jetson_mount_plate(); color("Tomato", 1.00) bumper_bracket(front= 1); color("Tomato", 1.00) bumper_bracket(front=-1); color("WhiteSmoke", 1.00) longitudinal_ribs(); // ============================================================================= // MAIN DECK (270 × 240 mm) // ============================================================================= module main_deck() { R = 10; difference() { linear_extrude(DECK_THICK) minkowski() { square([PLATE_W - 2*R, PLATE_D - 2*R], center=true); circle(r=R); } // Fork slots (open at ±X plate edges) for (side = [-1, 1]) { translate([side*(PLATE_X_HALF - FORK_SLOT_D), -FORK_SLOT_W/2, -1]) cube([FORK_SLOT_D + 1, FORK_SLOT_W, DECK_THICK + 2]); translate([side*(PLATE_X_HALF - FORK_SLOT_D), 0, -1]) cylinder(d=FORK_SLOT_W, h=DECK_THICK + 2); } // Bearing seat relief 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, DECK_THICK + 2]); // Fork bracket bolt holes (M5 × 4 per side) for (side = [-1, 1]) for (dx = [-15, 15]) for (dy = [-12, 12]) translate([side * AXLE_X + dx, dy, -1]) cylinder(d=M5, h=DECK_THICK + 2); // FC mount holes fc_holes(z=-1, h=DECK_THICK+2); // Battery tray anchor holes for (x = [-BATT_L/2 + 12, BATT_L/2 - 12]) for (y = [-BATT_W/2 + 10, BATT_W/2 - 10]) translate([x, y, -1]) cylinder(d=M4, h=DECK_THICK+2); // Lightening ovals (front/rear open zones) for (dy = [-80, 80]) hull() { translate([ 25, dy, -1]) cylinder(d=22, h=DECK_THICK+2); translate([-25, dy, -1]) cylinder(d=22, h=DECK_THICK+2); } // Cable routing slots for (dy = [-55, 55]) hull() { translate([ 12, dy, -1]) cylinder(d=12, h=DECK_THICK+2); translate([-12, dy, -1]) cylinder(d=12, h=DECK_THICK+2); } } } // ============================================================================= // LONGITUDINAL RIBS (×2) // ============================================================================= module longitudinal_ribs() { rib_y = PLATE_D/2 - WALL_T - RIB_T/2; for (y = [-rib_y, rib_y]) translate([-PLATE_W/2, y - RIB_T/2, -RIB_H]) cube([PLATE_W, RIB_T, RIB_H]); } // ============================================================================= // MOTOR FORK BRACKET (vertical, bolts to deck edge at ±PLATE_X_HALF) // ============================================================================= module motor_fork_bracket(side = 1) { translate([side * PLATE_X_HALF, 0, 0]) { s = side; difference() { union() { // Main bracket plate (extends below deck) translate([s > 0 ? 0 : -FORK_BKT_T, -FORK_BKT_W/2, -FORK_BKT_H]) cube([FORK_BKT_T, FORK_BKT_W, FORK_BKT_H + DECK_THICK]); // Diagonal gussets for (gy = [-1, 1]) translate([s > 0 ? 0 : -FORK_BKT_T, gy * FORK_BKT_W/2, -FORK_BKT_H/2]) linear_extrude(FORK_BKT_T) polygon([[0,0],[0, gy*20],[s * -25, 0]]); } // Axle dropout slot (open at bracket bottom) translate([s > 0 ? -1 : -FORK_BKT_T - 1, -AXLE_BASE_DIA/2 - 0.2, -FORK_BKT_H]) cube([FORK_BKT_T + 2, AXLE_BASE_DIA + 0.4, FORK_SLOT_D + 1]); translate([s > 0 ? -1 : -FORK_BKT_T - 1, 0, -FORK_BKT_H + FORK_SLOT_D]) rotate([-90, 0, 0]) cylinder(d=AXLE_BASE_DIA + 0.4, h=FORK_BKT_T + 2, center=true); // Deck attachment bolts (M5 × 4) for (dy = [-12, 12]) for (dz = [DECK_THICK * 0.3, DECK_THICK * 0.7]) translate([s > 0 ? -1 : -FORK_BKT_T - 1, dy, dz]) rotate([0, 90, 0]) cylinder(d=M5, h=FORK_BKT_T + 2); } } } // ============================================================================= // FC MOUNT HELPERS // ============================================================================= module fc_holes(z=0, h=10) { for (x = [FC_X - FC_PITCH/2, FC_X + FC_PITCH/2]) for (y = [-FC_PITCH/2, FC_PITCH/2]) translate([x, y, z]) cylinder(d=FC_HOLE_D, h=h); } module fc_mount_plate() { translate([FC_X, 0, 0]) { difference() { union() { for (x = [-FC_PITCH/2, FC_PITCH/2]) for (y = [-FC_PITCH/2, FC_PITCH/2]) translate([x, y, DECK_THICK]) cylinder(d=8, h=FC_STANDOFF); translate([-(FC_PITCH/2+8), -(FC_PITCH/2+8), DECK_THICK]) cube([FC_PITCH+16, FC_PITCH+16, 3]); } fc_holes(z=DECK_THICK-1, h=FC_STANDOFF+4); fc_holes(z=-1, h=DECK_THICK+2); } } } // ============================================================================= // BATTERY TRAY // ============================================================================= module battery_tray() { z_base = -BATT_FLOOR - BATT_H - 5; translate([-BATT_L/2 - BATT_WALL, -BATT_W/2 - BATT_WALL, z_base]) { difference() { cube([BATT_L+2*BATT_WALL, BATT_W+2*BATT_WALL, BATT_H+BATT_FLOOR]); translate([BATT_WALL, BATT_WALL, BATT_FLOOR]) cube([BATT_L, BATT_W, BATT_H+1]); for (x = [BATT_L/2-30, BATT_L/2+8]) translate([x, -1, BATT_FLOOR+BATT_H/2-10]) cube([20, BATT_W+2*BATT_WALL+2, 20]); for (i = [0:1]) translate([BATT_WALL+12+i*68, BATT_WALL+8, -1]) cube([38, BATT_W-16, BATT_FLOOR+2]); for (x=[10,BATT_L+BATT_WALL-2]) for (y=[10,BATT_W+BATT_WALL-2]) translate([x,y,BATT_H+BATT_FLOOR-1]) cylinder(d=M4,h=BATT_FLOOR+2); } } } // ============================================================================= // JETSON NANO B01 MOUNT PLATE // ============================================================================= module jetson_mount_plate() { translate([JETSON_X, 0, 0]) { difference() { union() { translate([-JETSON_PL/2, -JETSON_PW/2, DECK_THICK+JETSON_STOFF]) cube([JETSON_PL, JETSON_PW, JETSON_PT]); for (x=[-JETSON_PITCH/2, JETSON_PITCH/2]) for (y=[-JETSON_PITCH/2, JETSON_PITCH/2]) translate([x,y,DECK_THICK]) cylinder(d=6, h=JETSON_STOFF); } for (x=[-JETSON_PITCH/2, JETSON_PITCH/2]) for (y=[-JETSON_PITCH/2, JETSON_PITCH/2]) translate([x,y,DECK_THICK-1]) cylinder(d=JETSON_HOLE_D, h=JETSON_STOFF+JETSON_PT+2); for (i=[-1,0,1]) translate([i*22-8,-JETSON_PW/2+8,DECK_THICK+JETSON_STOFF-1]) cube([16, JETSON_PW-16, JETSON_PT+2]); for (x=[-JETSON_PL/2+8, JETSON_PL/2-8]) for (y=[-JETSON_PW/2+8, JETSON_PW/2-8]) translate([x,y,-1]) cylinder(d=M3, h=DECK_THICK+2); } } } // ============================================================================= // BUMPER BRACKETS (front / rear) // ============================================================================= module bumper_bracket(front = 1) { yp = front * PLATE_D/2; translate([0, yp, 0]) { difference() { union() { translate([-BUMPER_L/2, front*(BUMPER_T/2), 0]) cube([BUMPER_L, BUMPER_T, BUMPER_H]); for (x=[-BUMPER_L/2+4, BUMPER_L/2-BUMPER_T-4]) translate([x, front*BUMPER_T, 0]) cube([BUMPER_T, 16, BUMPER_H]); for (x=[-BUMPER_L/3, 0, BUMPER_L/3]) translate([x-BUMPER_TUBE_OD/2-2, front*(BUMPER_T+10), BUMPER_H-BUMPER_TUBE_OD/2-4]) difference() { cube([BUMPER_TUBE_OD+4, BUMPER_TUBE_OD/2+4, BUMPER_TUBE_OD+4]); translate([BUMPER_TUBE_OD/2+2,-1,BUMPER_TUBE_OD/2+2]) rotate([-90,0,0]) cylinder(d=BUMPER_TUBE_OD, h=BUMPER_TUBE_OD/2+6); } } for (x=[-BUMPER_L/2+16, -BUMPER_L/6, BUMPER_L/6, BUMPER_L/2-16]) translate([x, yp*0.001, -1]) cylinder(d=M5, h=BUMPER_H+2); } } }