// ============================================================================= // SaltyBot — Parametric Chassis Frame // Task: bd-1iy5 // Agent: sl-mechanical // Date: 2026-02-28 // // Self-balancing two-wheeled robot chassis // Requirements: // - 600mm wheelbase // - 2x hoverboard hub motors (170mm OD) // - ESP32-S3 ESP32-S3 BALANCE FC mount (30.5x30.5mm pattern) // - Battery tray (24V 4Ah — ~180x70x50mm pack) // - Jetson Orin Nano Super B01 mount plate (100x80mm, M3 holes) // - Front/rear bumper brackets // ============================================================================= // ─── RENDER QUALITY ────────────────────────────────────────────────────────── $fn = 64; // ============================================================================= // PARAMETERS — edit here to adjust the whole model // ============================================================================= // ── Wheelbase / overall geometry ───────────────────────────────────────────── WHEELBASE = 600; // mm, center-to-center axle distance (lateral) FRAME_WIDTH = 220; // mm, front-to-back depth of main deck DECK_THICKNESS = 6; // mm, main deck plate thickness WALL_T = 4; // mm, general wall thickness for brackets/ribs // ── Hub motor parameters ───────────────────────────────────────────────────── MOTOR_OD = 170; // mm, motor housing outer diameter MOTOR_AXLE_D = 14; // mm, axle bolt diameter MOTOR_AXLE_FLAT = 10; // mm, axle flat-to-flat (for anti-rotation) MOTOR_FORK_WIDTH = 24; // mm, dropout slot width (fits 10-14mm axle + spacers) MOTOR_FORK_DEPTH = 60; // mm, dropout slot depth from fork tip MOTOR_FORK_H = 80; // mm, total height of motor fork bracket MOTOR_FORK_T = 8; // mm, fork plate thickness AXLE_HEIGHT = 310; // mm, axle CL above ground (motor radius + clearance) // ── FC mount (ESP32-S3 BALANCE — 30.5 × 30.5 mm M3 pattern) ────────────────────── FC_MOUNT_SPACING = 30.5; // mm, hole pattern pitch FC_MOUNT_HOLE_D = 3.2; // mm, M3 clearance FC_STANDOFF_H = 6; // mm, standoff height FC_PAD_T = 3; // mm, mounting pad thickness // ── Battery tray (24V 4Ah LiPo / LiFePO4) ─────────────────────────────────── BATT_L = 185; // mm, cell pack length BATT_W = 72; // mm, cell pack width BATT_H = 52; // mm, cell pack height BATT_WALL = 3; // mm, tray wall thickness BATT_FLOOR = 4; // mm, tray floor thickness BATT_STRAP_W = 20; // mm, Velcro strap slot width BATT_STRAP_T = 2; // mm, strap slot depth // ── Jetson Orin Nano Super B01 mount plate ────────────────────────────────────────────── // B01 carrier board hole pattern: 58 x 58 mm M3 (inner) + corner pass-throughs JETSON_HOLE_PITCH = 58; // mm, M3 mounting hole pattern JETSON_HOLE_D = 3.2; // mm JETSON_PLATE_L = 105; // mm, plate length JETSON_PLATE_W = 90; // mm, plate width JETSON_PLATE_T = 4; // mm, plate thickness JETSON_STANDOFF_H = 8; // mm // ── Bumper bracket ──────────────────────────────────────────────────────────── BUMPER_L = WHEELBASE + 60; // mm, bumper rail length (overhangs wheel CL) BUMPER_H = 40; // mm, bracket vertical height BUMPER_T = 5; // mm, bracket plate thickness BUMPER_TUBE_OD = 22; // mm, 3/4" EMT conduit OD for bumper rail // ── Rib / gusset parameters ─────────────────────────────────────────────────── RIB_W = 20; // mm, longitudinal rib width RIB_H = 40; // mm, rib height below deck RIB_T = 4; // mm, rib plate thickness (laser/router cut) // ── Fastener helpers ───────────────────────────────────────────────────────── M3_D = 3.2; M4_D = 4.3; M5_D = 5.3; M6_D = 6.5; // ============================================================================= // MAIN ASSEMBLY — comment/uncomment parts as needed // ============================================================================= color("Silver", 0.9) main_deck(); color("DimGray") motor_fork(side= 1); // right (+X) color("DimGray") motor_fork(side=-1); // left (-X) color("SteelBlue") battery_tray(); color("OliveDrab") fc_mount_plate(); color("DarkOrange") jetson_mount_plate(); color("Tomato") bumper_bracket(front= 1); color("Tomato") bumper_bracket(front=-1); color("WhiteSmoke") longitudinal_ribs(); // ============================================================================= // MODULES // ============================================================================= // ─── Main deck plate ───────────────────────────────────────────────────────── module main_deck() { difference() { // Deck plate translate([-WHEELBASE/2 - MOTOR_FORK_T, -FRAME_WIDTH/2, 0]) cube([WHEELBASE + 2*MOTOR_FORK_T, FRAME_WIDTH, DECK_THICKNESS]); // Lightening holes — 3 rows × 4 cols for (x = [-WHEELBASE/3, 0, WHEELBASE/3]) for (y = [-FRAME_WIDTH/4, FRAME_WIDTH/4]) translate([x, y, -1]) cylinder(d=50, h=DECK_THICKNESS+2); // FC mount holes fc_mount_holes(z_offset=-1, depth=DECK_THICKNESS+2); // Battery tray floor cutout for wire pass-through translate([-BATT_L/2 + 40, -BATT_W/2 + 40, -1]) cube([BATT_L - 80, BATT_W - 80, DECK_THICKNESS+2]); // Cable routing slots for (x = [-60, 60]) translate([x, -FRAME_WIDTH/2 - 1, -1]) cube([14, 18, DECK_THICKNESS+2]); } } // ─── Longitudinal ribs (×2, symmetric F/R) ─────────────────────────────────── module longitudinal_ribs() { for (y = [-FRAME_WIDTH/2 + RIB_W/2 + WALL_T, FRAME_WIDTH/2 - RIB_W/2 - WALL_T]) translate([-WHEELBASE/2, y - RIB_T/2, -RIB_H]) cube([WHEELBASE, RIB_T, RIB_H]); } // ─── Motor fork dropout bracket ────────────────────────────────────────────── // Mounts to deck edge; provides a CNC-milled or FDM dropout slot for the axle. // `side` = +1 (right/+X) or -1 (left/-X) module motor_fork(side = 1) { x_pos = side * (WHEELBASE/2); translate([x_pos, 0, 0]) { difference() { union() { // Vertical fork body translate([side*(DECK_THICKNESS/2), -MOTOR_FORK_WIDTH/2 - 4, -MOTOR_FORK_H]) cube([side * MOTOR_FORK_T, MOTOR_FORK_WIDTH + 8, MOTOR_FORK_H + DECK_THICKNESS]); // Gusset triangles for (g = [-1, 1]) translate([side*(DECK_THICKNESS/2), g*(MOTOR_FORK_WIDTH/2 + 2), -MOTOR_FORK_H]) linear_extrude(height=MOTOR_FORK_T) polygon([[0,0],[0, g*20],[side*-30, 0]]); } // Axle dropout slot (open at bottom) translate([side*(DECK_THICKNESS/2) - 1, -MOTOR_AXLE_FLAT/2, -MOTOR_FORK_DEPTH - MOTOR_AXLE_D/2]) cube([MOTOR_FORK_T + 2, MOTOR_AXLE_FLAT, MOTOR_FORK_DEPTH + 1]); // Axle through-hole at slot top translate([side*(DECK_THICKNESS/2) - 1, 0, -MOTOR_FORK_DEPTH - MOTOR_AXLE_D/2]) rotate([0, 90, 0]) cylinder(d=MOTOR_AXLE_D + 1, h=MOTOR_FORK_T + 2); // Bolt holes for deck attachment (M5 × 4) for (y = [-20, 20]) for (z = [4, 12]) translate([side*(DECK_THICKNESS/2) - 1, y, z - MOTOR_FORK_H + MOTOR_FORK_H/2]) rotate([0, 90, 0]) cylinder(d=M5_D, h=MOTOR_FORK_T + 2); } } } // ─── Battery tray ───────────────────────────────────────────────────────────── // Positioned in centre of deck, recessed 10mm below deck surface module battery_tray() { z_base = -BATT_FLOOR - BATT_H - 5; // hang below deck translate([-BATT_L/2 - BATT_WALL, -BATT_W/2 - BATT_WALL, z_base]) { difference() { // Outer tray body cube([BATT_L + 2*BATT_WALL, BATT_W + 2*BATT_WALL, BATT_H + BATT_FLOOR]); // Inner cavity translate([BATT_WALL, BATT_WALL, BATT_FLOOR]) cube([BATT_L, BATT_W, BATT_H + 1]); // Strap slots (2× longitudinal) for (x = [BATT_L/2 - BATT_STRAP_W*2, BATT_L/2 + BATT_STRAP_W]) translate([x, -1, BATT_FLOOR + BATT_H/2 - BATT_STRAP_W/2]) cube([BATT_STRAP_W, BATT_W + 2*BATT_WALL + 2, BATT_STRAP_W]); // Ventilation slots bottom (3×) for (i = [0:2]) translate([BATT_WALL + 20 + i*50, BATT_WALL + 10, -1]) cube([30, BATT_W - 20, BATT_FLOOR + 2]); // Mount holes to deck (M4 × 4 corners) 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_D, h=BATT_FLOOR + 2); } } } // ─── FC mount holes helper ──────────────────────────────────────────────────── module fc_mount_holes(z_offset=0, depth=10) { // ESP32-S3 BALANCE: 30.5×30.5 mm M3 pattern, centred at origin for (x = [-FC_MOUNT_SPACING/2, FC_MOUNT_SPACING/2]) for (y = [-FC_MOUNT_SPACING/2, FC_MOUNT_SPACING/2]) translate([x, y, z_offset]) cylinder(d=FC_MOUNT_HOLE_D, h=depth); } // ─── FC mount plate (raised 40mm above deck centre) ────────────────────────── module fc_mount_plate() { fc_x = -50; // offset toward front from deck centre fc_y = 0; plate_z = DECK_THICKNESS + FC_STANDOFF_H; translate([fc_x, fc_y, 0]) { difference() { union() { // Mount pads with standoffs for (x = [-FC_MOUNT_SPACING/2, FC_MOUNT_SPACING/2]) for (y = [-FC_MOUNT_SPACING/2, FC_MOUNT_SPACING/2]) { translate([x, y, DECK_THICKNESS]) cylinder(d=8, h=FC_STANDOFF_H); // standoff column translate([x - 5, y - 5, DECK_THICKNESS]) cube([10, 10, FC_PAD_T]); // pad base } // Base plate translate([-FC_MOUNT_SPACING/2 - 8, -FC_MOUNT_SPACING/2 - 8, DECK_THICKNESS]) cube([FC_MOUNT_SPACING + 16, FC_MOUNT_SPACING + 16, FC_PAD_T]); } // M3 through-holes in standoffs fc_mount_holes(z_offset=DECK_THICKNESS - 1, depth=FC_STANDOFF_H + FC_PAD_T + 2); // Deck anchor holes fc_mount_holes(z_offset=-1, depth=DECK_THICKNESS + 2); } } } // ─── Jetson Orin Nano Super B01 mount plate ───────────────────────────────────────────── // Positioned rear of deck, elevated on standoffs module jetson_mount_plate() { jet_x = 60; // offset toward rear jet_y = 0; plate_z = DECK_THICKNESS + JETSON_STANDOFF_H; translate([jet_x, jet_y, 0]) { difference() { union() { // Mounting plate translate([-JETSON_PLATE_L/2, -JETSON_PLATE_W/2, DECK_THICKNESS + JETSON_STANDOFF_H]) cube([JETSON_PLATE_L, JETSON_PLATE_W, JETSON_PLATE_T]); // Four standoff columns for (x = [-JETSON_HOLE_PITCH/2, JETSON_HOLE_PITCH/2]) for (y = [-JETSON_HOLE_PITCH/2, JETSON_HOLE_PITCH/2]) translate([x, y, DECK_THICKNESS]) cylinder(d=6, h=JETSON_STANDOFF_H); } // B01 M3 hole pattern (58×58 mm) for (x = [-JETSON_HOLE_PITCH/2, JETSON_HOLE_PITCH/2]) for (y = [-JETSON_HOLE_PITCH/2, JETSON_HOLE_PITCH/2]) translate([x, y, DECK_THICKNESS - 1]) cylinder(d=JETSON_HOLE_D, h=JETSON_STANDOFF_H + JETSON_PLATE_T + 2); // Ventilation / cable routing slots in plate for (i = [-1, 0, 1]) translate([i*25 - 10, -JETSON_PLATE_W/2 + 10, DECK_THICKNESS + JETSON_STANDOFF_H - 1]) cube([20, JETSON_PLATE_W - 20, JETSON_PLATE_T + 2]); // Deck anchor holes (M3 × 4 corners of plate) for (x = [-JETSON_PLATE_L/2 + 8, JETSON_PLATE_L/2 - 8]) for (y = [-JETSON_PLATE_W/2 + 8, JETSON_PLATE_W/2 - 8]) translate([x, y, -1]) cylinder(d=M3_D, h=DECK_THICKNESS + 2); } } } // ─── Bumper bracket ─────────────────────────────────────────────────────────── // `front` = +1 (front) or -1 (rear) module bumper_bracket(front = 1) { y_pos = front * (FRAME_WIDTH/2); translate([0, y_pos, 0]) { difference() { union() { // Horizontal mounting rail plate translate([-BUMPER_L/2, front*(BUMPER_T/2), 0]) cube([BUMPER_L, BUMPER_T, BUMPER_H]); // Vertical gussets at ends for (x = [-BUMPER_L/2 + 5, BUMPER_L/2 - BUMPER_T - 5]) translate([x, front*(BUMPER_T), 0]) cube([BUMPER_T, 20, BUMPER_H]); // Bumper tube saddle clamps (×3 evenly spaced) for (x = [-BUMPER_L/3, 0, BUMPER_L/3]) translate([x - BUMPER_TUBE_OD/2 - 2, front*(BUMPER_T + 15), BUMPER_H - BUMPER_TUBE_OD/2 - 5]) 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); } } // Deck mounting holes (M5 × 6 along length) for (x = [-BUMPER_L/2 + 20, -BUMPER_L/6, BUMPER_L/6, BUMPER_L/2 - 20]) translate([x, y_pos * 0.001, -1]) cylinder(d=M5_D, h=BUMPER_H + 2); } } } // ============================================================================= // DIMENSIONS / ANNOTATIONS (2D cross-section reference) // ============================================================================= // Uncomment to render a side-view dimension guide: // // %translate([0, FRAME_WIDTH/2 + 30, 0]) { // color("Blue") { // cube([WHEELBASE, 1, 1]); // wheelbase span // translate([0,0,0]) text(str("Wheelbase: ", WHEELBASE, "mm"), size=12); // } // }