New chassis design files for the SaltyRover rough-terrain variant: • saltyrover_chassis_r2.scad — Deck plate (500×480×6mm Al, laser-cut DXF), 4× M3-adjustable pivot brackets, 4× CSI corner camera mounts (45° outward, 20° down), D435i front bracket (8° tilt), stem collar. All RENDER modes for STL and DXF export included. • rover_spring_arm.scad — Trailing-arm spring suspension (×4). Pivot on M8 bolt; captured 14mm OD compression spring (50mm free, ~5 N/mm); open-end axle dropout slot with retainer cap. Provides 25mm bump + 15mm droop travel. Bearing-seat recess for caliper-verified 37.8mm collar OD. • rover_electronics_bay.scad — PETG electronics bay (240×200×80mm internal). FC standoffs 30.5×30.5mm M3 and Jetson Orin 58×49mm M3 — shared SaltyLab swappable pattern. Ventilation slots all 4 walls + lid. Lid integrates 100mm RPLIDAR A1M8 tower (58mm BC, matched to rplidar_mount.scad). Split-print halves for 220mm beds included. • rover_chassis_r2_BOM.md — Full BOM, mass estimate (frame ~2.15kg; reduce to <2kg by setting DECK_T=5), assembly sequence, critical dimensions. Sensor positions: RPLIDAR top-centre on bay lid, D435i front, 4× IMX219 at deck corners. Shares 30.5mm FC + 58mm Jetson + Ø25mm stem patterns with SaltyLab for swappable electronics. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
524 lines
22 KiB
OpenSCAD
524 lines
22 KiB
OpenSCAD
// ============================================================
|
||
// saltyrover_chassis_r2.scad — SaltyRover 4-Wheel Chassis Rev 2
|
||
// Issue: #109 Agent: sl-mechanical Date: 2026-03-01
|
||
// ============================================================
|
||
//
|
||
// Complete parametric chassis assembly for the SaltyRover 4-wheel
|
||
// rough-terrain variant. Designed to be printed (PETG), laser-cut
|
||
// (6 mm 5052-H32 Al), or CNC-routed.
|
||
//
|
||
// NEW vs Rev 1 (issue #73 / saltyrover_chassis.scad):
|
||
// • 4× trailing-arm spring-suspension corners
|
||
// • Enclosed electronics bay (rover_electronics_bay.scad)
|
||
// • M3-slot-adjustable pivot brackets (replaces fixed M5 flanges)
|
||
// • CSI camera corner brackets (4×, 45° outward tilt)
|
||
// • RPLIDAR tower stub on electronics bay lid
|
||
// • D435i front bracket arm
|
||
// • Weight target: <2 kg frame (excl. motors/electronics)
|
||
//
|
||
// Shared SaltyLab patterns (swappable electronics):
|
||
// FC : 30.5 × 30.5 mm M3 (MAMBA F722S / Pixhawk)
|
||
// Jetson: 58 × 49 mm M3 (Orin NX / Nano carrier board)
|
||
// Stem : Ø25 mm bore (sensor head unchanged)
|
||
//
|
||
// Coordinate convention (all modules):
|
||
// Z = 0 deck top face
|
||
// +Y forward
|
||
// +X right
|
||
// Ground at Z ≈ −(GND_CLR + BATT_PACK_H + BATT_FLOOR_T + DECK_T)
|
||
//
|
||
// RENDER options:
|
||
// "assembly" full 3D preview (default)
|
||
// "deck_2d" DXF — deck plate for waterjet / CNC
|
||
// "pivot_bracket_2d" DXF — pivot bracket for CNC / laser (×4)
|
||
// "pivot_bracket_stl" STL — pivot bracket (print 4×)
|
||
// "csi_mount_stl" STL — CSI corner bracket (print 4×)
|
||
// "d435i_mount_stl" STL — D435i front bracket (print 1×)
|
||
//
|
||
// ── Export commands ─────────────────────────────────────────
|
||
// Deck DXF:
|
||
// openscad saltyrover_chassis_r2.scad -D 'RENDER="deck_2d"' -o saltyrover_r2_deck.dxf
|
||
// Pivot bracket DXF (×4):
|
||
// openscad saltyrover_chassis_r2.scad -D 'RENDER="pivot_bracket_2d"' -o rover_pivot_bracket.dxf
|
||
// Pivot bracket STL (×4):
|
||
// openscad saltyrover_chassis_r2.scad -D 'RENDER="pivot_bracket_stl"' -o rover_pivot_bracket.stl
|
||
// CSI mount STL (×4):
|
||
// openscad saltyrover_chassis_r2.scad -D 'RENDER="csi_mount_stl"' -o rover_csi_mount.stl
|
||
// D435i mount STL (×1):
|
||
// openscad saltyrover_chassis_r2.scad -D 'RENDER="d435i_mount_stl"' -o rover_d435i_mount.stl
|
||
// ============================================================
|
||
|
||
$fn = 64;
|
||
e = 0.01;
|
||
|
||
// ── Deck footprint ────────────────────────────────────────────────────────────
|
||
ROVER_L = 500.0; // deck fore-aft (Y)
|
||
ROVER_W = 480.0; // deck left-right (X)
|
||
DECK_T = 6.0; // deck plate thickness (6 mm Al — weight-optimised)
|
||
DECK_R = 15.0; // corner fillet radius
|
||
|
||
// ── Drive geometry ────────────────────────────────────────────────────────────
|
||
// Hoverboard hub motors — caliper-verified (matches BOM.md / rover_motor_mount.scad)
|
||
TRACK_W = 540.0; // motor axle CL to CL, left-right (X)
|
||
AXLE_BASE = 340.0; // motor axle CL to CL, fore-aft (Y)
|
||
AXLE_H = 127.0; // axle CL above ground (10×2.125" tire, r=127mm)
|
||
AXLE_D = 16.11; // axle base section OD (caliper)
|
||
AXLE_FLAT = 13.00; // D-cut chord width (caliper)
|
||
BEARING_OD = 37.80; // bearing seat collar OD (caliper)
|
||
|
||
// ── Height stack ─────────────────────────────────────────────────────────────
|
||
GND_CLR = 55.0; // min ground clearance (at static suspension sag)
|
||
BATT_FLOOR_T = 3.0; // battery tray floor thickness
|
||
BATT_PACK_H = 56.0; // battery pack height (420×88×56mm, laid flat)
|
||
DECK_BOT_H = GND_CLR + BATT_FLOOR_T + BATT_PACK_H; // 114 mm
|
||
DECK_TOP_H = DECK_BOT_H + DECK_T; // 120 mm
|
||
// Axle above deck top (in chassis SCAD coords = positive Z):
|
||
// AXLE_H - DECK_TOP_H = 127 - 120 = +7 mm ← axle is 7 mm above deck top
|
||
|
||
// ── Battery packs (under-deck, laid flat) ────────────────────────────────────
|
||
BATT_X_DIM = 420.0; // pack long side (left-right)
|
||
BATT_Y_DIM = 88.0; // pack fore-aft per pack
|
||
BATT_N = 2; // number of packs fore-aft (2 = 176 mm; 4 = 352 mm)
|
||
TRAY_MARGIN = 5.0; // opening margin each side
|
||
|
||
// ── Stem socket (deck centre) ─────────────────────────────────────────────────
|
||
STEM_BORE = 25.5; // 25 mm tube + 0.5 mm FDM clearance
|
||
STEM_COLLAR_OD = 50.0;
|
||
STEM_COLLAR_H = 20.0; // raised boss height above deck top
|
||
STEM_FLANGE_BC = 40.0; // 4× M4 bolt circle for stem adapter
|
||
|
||
// ── FC mount — MAMBA F722S / Pixhawk (30.5 × 30.5 mm M3) ────────────────────
|
||
// Shared with SaltyLab — swappable electronics
|
||
FC_PITCH = 30.5;
|
||
FC_HOLE_D = 3.2;
|
||
FC_POS_Y = ROVER_L/2 - 65.0; // near front edge
|
||
|
||
// ── Jetson Orin NX / Nano mount (58 × 49 mm M3) ──────────────────────────────
|
||
// Shared with SaltyLab — swappable electronics
|
||
ORIN_HOLE_X = 58.0;
|
||
ORIN_HOLE_Y = 49.0;
|
||
ORIN_HOLE_D = 3.2;
|
||
ORIN_POS_Y = -(ROVER_L/2 - 60.0); // near rear edge
|
||
|
||
// ── Pivot bracket (motor corner mount, adjustable) ───────────────────────────
|
||
// Each corner: one pivot bracket bolted to deck top at motor CL fore-aft.
|
||
// M3 slotted holes allow ±15 mm fore-aft and ±10 mm lateral adjustment.
|
||
PBK_L = 80.0; // bracket plate length (fore-aft / Y)
|
||
PBK_W = 55.0; // bracket plate width (lateral / X from deck edge)
|
||
PBK_T = 8.0; // bracket plate thickness
|
||
PBK_FLANGE_H = 20.0; // vertical flange height below deck bottom face
|
||
|
||
// M3 adjustment slots (4× per bracket on the deck-top flange)
|
||
ADJ_SLOT_L = 25.0; // slot length (allows ±12 mm adjustment)
|
||
ADJ_M3_D = 3.3; // M3 clearance
|
||
ADJ_INSET_X = 12.0; // slot CL from lateral edge of bracket
|
||
ADJ_INSET_Y = 16.0; // slot CL from fore/aft ends
|
||
|
||
// Pivot pin (M8 through-bolt; arm swings around this)
|
||
PIV_D = 8.5; // M8 clearance bore
|
||
PIV_POS_X = ROVER_W/2 + 5.0; // pivot CL from deck centre (just at edge)
|
||
// Pivot fore-aft at each motor corner (±AXLE_BASE/2)
|
||
|
||
// Spring guide boss on bracket underside
|
||
SPG_GUIDE_OD = 14.0; // spring guide boss OD (spring slides over this)
|
||
SPG_GUIDE_H = 15.0; // guide boss height below bracket bottom
|
||
|
||
// ── CSI camera corner brackets ────────────────────────────────────────────────
|
||
CSI_PCB = 25.0; // IMX219 / CSI module PCB width (square)
|
||
CSI_M2_SPC = 15.0; // M2 hole pitch (±7.5 mm from centre)
|
||
CSI_TILT = 20.0; // downward tilt (degrees) for terrain view
|
||
CSI_ANGLE = 45.0; // outward rotation at each corner
|
||
|
||
// ── D435i front bracket ───────────────────────────────────────────────────────
|
||
RS_TILT = 8.0; // nose-down tilt (degrees)
|
||
RS_ARM_LEN = 65.0; // arm length from deck front edge to camera CL
|
||
RS_BASE_W = 40.0; // base width (left-right)
|
||
|
||
// ── Fasteners ─────────────────────────────────────────────────────────────────
|
||
M2_D = 2.3;
|
||
M3_D = 3.3;
|
||
M4_D = 4.3;
|
||
M5_D = 5.3;
|
||
M8_D = 8.5;
|
||
|
||
// ============================================================
|
||
// RENDER DISPATCH
|
||
// ============================================================
|
||
RENDER = "assembly";
|
||
|
||
if (RENDER == "assembly") {
|
||
assembly();
|
||
} else if (RENDER == "deck_2d") {
|
||
projection(cut = true)
|
||
translate([0, 0, -DECK_T / 2])
|
||
deck_plate();
|
||
} else if (RENDER == "pivot_bracket_2d") {
|
||
projection(cut = true)
|
||
translate([0, 0, -PBK_T / 2])
|
||
pivot_bracket_flat();
|
||
} else if (RENDER == "pivot_bracket_stl") {
|
||
pivot_bracket();
|
||
} else if (RENDER == "csi_mount_stl") {
|
||
csi_corner_bracket();
|
||
} else if (RENDER == "d435i_mount_stl") {
|
||
d435i_front_bracket();
|
||
}
|
||
|
||
// ============================================================
|
||
// FULL ASSEMBLY
|
||
// ============================================================
|
||
module assembly() {
|
||
color("Silver", 0.90) deck_plate();
|
||
color("DimGray", 0.85) stem_collar();
|
||
|
||
// 4× pivot brackets at motor corners
|
||
for (sx = [-1, 1])
|
||
for (sy = [-1, 1])
|
||
color("SteelBlue", 0.85)
|
||
translate([sx * TRACK_W/2, sy * AXLE_BASE/2, 0])
|
||
rotate([0, 0, sx > 0 ? 0 : 180])
|
||
pivot_bracket();
|
||
|
||
// 4× CSI corner brackets
|
||
for (sx = [-1, 1])
|
||
for (sy = [-1, 1])
|
||
color("Teal", 0.85)
|
||
csi_bracket_placed(sx, sy);
|
||
|
||
// D435i front bracket
|
||
color("DarkSlateGray", 0.85)
|
||
d435i_bracket_placed();
|
||
|
||
// Electronics bay reference ghost (from rover_electronics_bay.scad)
|
||
%color("OliveDrab", 0.30)
|
||
translate([0, 0, DECK_T + 0.5])
|
||
cube([240, 200, 80], center = true);
|
||
|
||
// Ghost motor axle positions
|
||
for (sx = [-1, 1])
|
||
for (sy = [-1, 1])
|
||
%color("Tomato", 0.25)
|
||
translate([sx * TRACK_W/2, sy * AXLE_BASE/2,
|
||
AXLE_H - DECK_TOP_H])
|
||
rotate([90, 0, 0])
|
||
cylinder(d = AXLE_D, h = 80, center = true);
|
||
|
||
// Ghost tyre outlines
|
||
for (sx = [-1, 1])
|
||
for (sy = [-1, 1])
|
||
%color("Black", 0.15)
|
||
translate([sx * TRACK_W/2, sy * AXLE_BASE/2,
|
||
-(DECK_TOP_H - AXLE_H)])
|
||
rotate([90, 0, 0])
|
||
cylinder(d = 254, h = 55, center = true);
|
||
}
|
||
|
||
// ============================================================
|
||
// DECK PLATE (Part A — laser-cut 6 mm 5052-H32 aluminium)
|
||
// ============================================================
|
||
// Weight estimate: 480×500×6 mm Al, ~50% lightened ≈ 1.35 kg
|
||
module deck_plate() {
|
||
difference() {
|
||
// ── Outer profile — rounded rectangle ─────────────────────────
|
||
linear_extrude(DECK_T)
|
||
minkowski() {
|
||
square([ROVER_L - 2*DECK_R, ROVER_W - 2*DECK_R], center = true);
|
||
circle(r = DECK_R);
|
||
}
|
||
|
||
// ── Battery tray opening (under-deck, centred) ─────────────────
|
||
batt_open_x = BATT_X_DIM + 2*TRAY_MARGIN;
|
||
batt_open_y = BATT_Y_DIM * BATT_N + 2*TRAY_MARGIN;
|
||
translate([0, 0, -e])
|
||
cube([batt_open_x, batt_open_y, DECK_T + 2*e], center = true);
|
||
|
||
// ── Stem bore ─────────────────────────────────────────────────
|
||
translate([0, 0, -e])
|
||
cylinder(d = STEM_BORE, h = DECK_T + 2*e);
|
||
|
||
// ── Stem collar bolt circle (4× M4 at 90°) ────────────────────
|
||
for (a = [0, 90, 180, 270])
|
||
rotate([0, 0, a])
|
||
translate([STEM_FLANGE_BC/2, 0, -e])
|
||
cylinder(d = M4_D, h = DECK_T + 2*e);
|
||
|
||
// ── FC mount holes — 30.5×30.5 M3 (shared SaltyLab pattern) ──
|
||
for (dx = [-FC_PITCH/2, FC_PITCH/2])
|
||
for (dy = [-FC_PITCH/2, FC_PITCH/2])
|
||
translate([dx, FC_POS_Y + dy, -e])
|
||
cylinder(d = FC_HOLE_D, h = DECK_T + 2*e);
|
||
|
||
// ── Jetson Orin mount holes — 58×49 M3 ───────────────────────
|
||
for (dx = [-ORIN_HOLE_X/2, ORIN_HOLE_X/2])
|
||
for (dy = [-ORIN_HOLE_Y/2, ORIN_HOLE_Y/2])
|
||
translate([dx, ORIN_POS_Y + dy, -e])
|
||
cylinder(d = ORIN_HOLE_D, h = DECK_T + 2*e);
|
||
|
||
// ── Pivot bracket M3 attachment slots (4× corners) ────────────
|
||
// Two slotted holes per corner at the deck attachment flange
|
||
for (sx = [-1, 1])
|
||
for (sy = [-1, 1]) {
|
||
bx = sx * (ROVER_W/2 - ADJ_INSET_X);
|
||
by = sy * AXLE_BASE/2;
|
||
for (offset = [-ADJ_INSET_Y, ADJ_INSET_Y])
|
||
hull() {
|
||
translate([bx, by + offset - ADJ_SLOT_L/2, -e])
|
||
cylinder(d = ADJ_M3_D, h = DECK_T + 2*e);
|
||
translate([bx, by + offset + ADJ_SLOT_L/2, -e])
|
||
cylinder(d = ADJ_M3_D, h = DECK_T + 2*e);
|
||
}
|
||
}
|
||
|
||
// ── Lightening holes — 55 mm dia, in structural corridors ─────
|
||
// Row between battery opening and pivot brackets
|
||
for (sx = [-1, 1])
|
||
for (sy = [-1, 1]) {
|
||
lx = sx * (ROVER_W/4 + 20);
|
||
ly = sy * (ROVER_L/4 + 15);
|
||
translate([lx, ly, -e])
|
||
cylinder(d = 55, h = DECK_T + 2*e);
|
||
}
|
||
// Additional pair flanking stem
|
||
for (sx = [-1, 1])
|
||
translate([sx * 65, 0, -e])
|
||
cylinder(d = 40, h = DECK_T + 2*e);
|
||
|
||
// ── Cable routing slots (4× around electronics bay footprint) ──
|
||
for (sy = [-1, 1])
|
||
hull() {
|
||
translate([-20, sy * 105, -e]) cylinder(d = 14, h = DECK_T+2*e);
|
||
translate([ 20, sy * 105, -e]) cylinder(d = 14, h = DECK_T+2*e);
|
||
}
|
||
for (sx = [-1, 1])
|
||
hull() {
|
||
translate([sx * 125, -18, -e]) cylinder(d = 14, h = DECK_T+2*e);
|
||
translate([sx * 125, 18, -e]) cylinder(d = 14, h = DECK_T+2*e);
|
||
}
|
||
|
||
// ── Motor phase cable pass-throughs at each corner ────────────
|
||
for (sx = [-1, 1])
|
||
for (sy = [-1, 1])
|
||
translate([sx * (ROVER_W/2 - 25),
|
||
sy * (ROVER_L/2 - 25), -e])
|
||
cylinder(d = 18, h = DECK_T + 2*e);
|
||
}
|
||
}
|
||
|
||
// ── Deck-top stem collar (raised boss, 25 mm bore) ─────────────────────────
|
||
module stem_collar() {
|
||
translate([0, 0, DECK_T])
|
||
difference() {
|
||
cylinder(d = STEM_COLLAR_OD, h = STEM_COLLAR_H);
|
||
// Bore
|
||
translate([0, 0, -e])
|
||
cylinder(d = STEM_BORE, h = STEM_COLLAR_H + 2*e);
|
||
// Flange bolt holes
|
||
for (a = [0, 90, 180, 270])
|
||
rotate([0, 0, a])
|
||
translate([STEM_FLANGE_BC/2, 0, -e])
|
||
cylinder(d = M4_D, h = STEM_COLLAR_H + 2*e);
|
||
}
|
||
}
|
||
|
||
// ============================================================
|
||
// PIVOT BRACKET (Part B — M3-adjustable motor corner mount)
|
||
// ============================================================
|
||
// One per corner (×4). Mounts to deck top face via 2× M3 SHCS
|
||
// through slotted deck holes (allows ±12 mm fore/aft adjustment).
|
||
// Provides:
|
||
// • M8 pivot pin bore for suspension trailing arm
|
||
// • Spring upper seat (captured spring guide boss, 14 mm OD)
|
||
// • Vertical flange to deck edge for lateral stiffness
|
||
//
|
||
// Print: PETG 5 perims 60% infill, flat base down.
|
||
// Alt : CNC 8 mm 6061-T6 Al from pivot_bracket_2d DXF.
|
||
//
|
||
// Coordinate: bracket centred at motor corner (sx*TRACK_W/2, sy*AXLE_BASE/2)
|
||
// The deck-edge flange is on the -X side (inner face toward deck centre).
|
||
// ============================================================
|
||
module pivot_bracket() {
|
||
// Deck-top flat base plate
|
||
translate([-PBK_W/2, -PBK_L/2, 0])
|
||
difference() {
|
||
cube([PBK_W, PBK_L, PBK_T]);
|
||
|
||
// 2× M3 adjustment slots (fore-aft direction)
|
||
for (s = [-1, 1])
|
||
hull() {
|
||
translate([ADJ_INSET_X,
|
||
PBK_L/2 + s*ADJ_INSET_Y - ADJ_SLOT_L/2,
|
||
-e])
|
||
cylinder(d = ADJ_M3_D, h = PBK_T + 2*e);
|
||
translate([ADJ_INSET_X,
|
||
PBK_L/2 + s*ADJ_INSET_Y + ADJ_SLOT_L/2,
|
||
-e])
|
||
cylinder(d = ADJ_M3_D, h = PBK_T + 2*e);
|
||
}
|
||
|
||
// Lightening slot (centre of bracket base)
|
||
translate([ADJ_INSET_X + 8, PBK_L/2 - 18, -e])
|
||
cube([PBK_W - ADJ_INSET_X - 14, 36, PBK_T + 2*e]);
|
||
}
|
||
|
||
// Outer vertical flange (at +X edge — outboard side, toward motor)
|
||
// This flange drops below the deck to form the suspension pivot clevis.
|
||
translate([PBK_W/2 - PBK_T, -PBK_L/2, -(PBK_FLANGE_H)])
|
||
difference() {
|
||
cube([PBK_T, PBK_L, PBK_FLANGE_H + PBK_T]);
|
||
|
||
// M8 pivot pin bore — at mid-height of flange, centred fore-aft
|
||
// The trailing arm will pivot on an M8 bolt through this hole.
|
||
pivot_z = PBK_FLANGE_H / 2;
|
||
translate([-e, PBK_L/2, pivot_z])
|
||
rotate([0, 90, 0])
|
||
cylinder(d = PIV_D, h = PBK_T + 2*e);
|
||
}
|
||
|
||
// Spring upper seat boss (below bracket base, outboard side)
|
||
// Compression spring (Ø14 OD) slides over this guide boss.
|
||
// When arm swings up (bump), spring is compressed between this boss
|
||
// and the matching pocket in the trailing arm.
|
||
translate([PBK_W/2 - PBK_T/2, 0, -e])
|
||
cylinder(d = SPG_GUIDE_OD, h = SPG_GUIDE_H + e);
|
||
}
|
||
|
||
// Flat (2D projection source) version of pivot bracket — same profile
|
||
module pivot_bracket_flat() {
|
||
difference() {
|
||
cube([PBK_W, PBK_L, PBK_T], center = true);
|
||
// M3 slots
|
||
for (s = [-1, 1])
|
||
hull() {
|
||
translate([0, s*ADJ_INSET_Y - ADJ_SLOT_L/2, 0])
|
||
cylinder(d = ADJ_M3_D, h = PBK_T + 2*e, center = true);
|
||
translate([0, s*ADJ_INSET_Y + ADJ_SLOT_L/2, 0])
|
||
cylinder(d = ADJ_M3_D, h = PBK_T + 2*e, center = true);
|
||
}
|
||
// M8 pivot bore
|
||
cylinder(d = PIV_D, h = PBK_T + 2*e, center = true);
|
||
}
|
||
}
|
||
|
||
// ── Place pivot brackets at correct corners ───────────────────────────────────
|
||
// Called from assembly() with (sx, sy) = (±1, ±1)
|
||
|
||
// ============================================================
|
||
// CSI CAMERA CORNER BRACKET (Part C — 4× corners)
|
||
// ============================================================
|
||
// Mounts an IMX219 / Arducam CSI module at each deck corner,
|
||
// angled 45° outward and CSI_TILT° downward for terrain coverage.
|
||
// 2× M2 bolts hold camera PCB (15 mm square hole pattern).
|
||
// 2× M3 bolts mount bracket to deck top.
|
||
//
|
||
// Print: PETG 4 perims 30% infill, flat base down.
|
||
// ============================================================
|
||
module csi_corner_bracket() {
|
||
base_l = 40;
|
||
base_w = 30;
|
||
base_t = 5;
|
||
arm_l = 30;
|
||
|
||
difference() {
|
||
union() {
|
||
// Deck-top base plate
|
||
cube([base_l, base_w, base_t]);
|
||
|
||
// Angled arm + camera face plate
|
||
translate([base_l / 2, base_w / 2, base_t])
|
||
rotate([0, CSI_TILT, 0])
|
||
translate([-CSI_PCB/2, -CSI_PCB/2, 0])
|
||
cube([CSI_PCB + 6, CSI_PCB + 6, base_t]);
|
||
}
|
||
|
||
// 2× M3 base attachment holes
|
||
for (dx = [8, base_l - 8])
|
||
translate([dx, base_w / 2, -e])
|
||
cylinder(d = M3_D, h = base_t + 2*e);
|
||
|
||
// CSI camera M2 mounting holes (15 × 15 mm pattern)
|
||
translate([base_l / 2, base_w / 2, base_t])
|
||
rotate([0, CSI_TILT, 0])
|
||
for (cx = [-CSI_M2_SPC/2, CSI_M2_SPC/2])
|
||
for (cy = [-CSI_M2_SPC/2, CSI_M2_SPC/2])
|
||
translate([cx, cy, -e])
|
||
cylinder(d = M2_D, h = base_t + 2*e);
|
||
|
||
// CSI ribbon cable slot (3 mm wide, 12 mm long, centred)
|
||
translate([base_l/2 - 6, base_w/2 - 1.5, -e])
|
||
cube([12, 3, base_t + 2*e]);
|
||
}
|
||
}
|
||
|
||
module csi_bracket_placed(sx, sy) {
|
||
// Corner position
|
||
cx = sx * (ROVER_W/2 - 25);
|
||
cy = sy * (ROVER_L/2 - 25);
|
||
// Rotate so camera faces outward from corner
|
||
rot = atan2(sy, sx) * 180 / 3.14159 - 45;
|
||
translate([cx, cy, DECK_T])
|
||
rotate([0, 0, rot])
|
||
translate([-20, -15, 0])
|
||
csi_corner_bracket();
|
||
}
|
||
|
||
// ============================================================
|
||
// D435i FRONT BRACKET (Part D — 1× front mount)
|
||
// ============================================================
|
||
// Arm extends forward from deck front edge.
|
||
// Camera face tilted RS_TILT° nose-down.
|
||
// 1/4-20 UNC captured hex nut for D435i tripod socket.
|
||
// 2× M4 bolts mount base to deck front face.
|
||
//
|
||
// Print: PETG 5 perims 40% infill, arm flat on bed.
|
||
// ============================================================
|
||
module d435i_front_bracket() {
|
||
base_d = 22; // base depth (Y direction, into deck)
|
||
base_h = 8; // base/arm thickness
|
||
arm_len = RS_ARM_LEN;
|
||
|
||
// 1/4-20 UNC geometry
|
||
nut14_af = 11.1; // across-flats
|
||
nut14_h = 5.6; // nut thickness
|
||
nut14_cl = 6.5; // bolt clearance bore
|
||
|
||
difference() {
|
||
union() {
|
||
// Rear base plate (bolts to deck front face)
|
||
translate([-RS_BASE_W/2, 0, 0])
|
||
cube([RS_BASE_W, base_d, base_h]);
|
||
|
||
// Forward arm (+ direction is forward / +Y)
|
||
translate([-12, base_d, 0])
|
||
cube([24, arm_len, base_h]);
|
||
|
||
// Camera face plate (tilted RS_TILT° downward)
|
||
translate([0, base_d + arm_len, base_h / 2])
|
||
rotate([0, RS_TILT, 0])
|
||
translate([-15, 0, -base_h / 2])
|
||
cube([30, 14, base_h]);
|
||
}
|
||
|
||
// 2× M4 base attachment holes
|
||
for (dx = [-RS_BASE_W/2 + 10, RS_BASE_W/2 - 10])
|
||
translate([dx, base_d / 2, -e])
|
||
cylinder(d = M4_D, h = base_h + 2*e);
|
||
|
||
// 1/4-20 captured nut pocket in face plate
|
||
translate([0, base_d + arm_len + 12, base_h / 2])
|
||
rotate([0, 90, 0]) {
|
||
// Hex nut pocket (from back)
|
||
translate([0, 0, -nut14_h - 1])
|
||
cylinder(d = nut14_af / cos(30), h = nut14_h + 1, $fn = 6);
|
||
// Camera bolt clearance bore
|
||
cylinder(d = nut14_cl, h = 20);
|
||
}
|
||
}
|
||
}
|
||
|
||
module d435i_bracket_placed() {
|
||
// Mount to deck front edge, centred left-right, at deck level
|
||
translate([0, ROVER_L/2 + 10, DECK_T])
|
||
rotate([0, 0, 180])
|
||
d435i_front_bracket();
|
||
}
|