diff --git a/chassis/antenna_mount.scad b/chassis/antenna_mount.scad new file mode 100644 index 0000000..48af8d1 --- /dev/null +++ b/chassis/antenna_mount.scad @@ -0,0 +1,309 @@ +// ============================================================ +// antenna_mount.scad — LTE + GNSS Antenna Brackets Rev A +// 2026-03-01 sl-mechanical +// ============================================================ +// Stem-mounted brackets for the SIM7600X cellular/GPS system. +// +// lte_bracket() 25 mm stem clamp + arm with 2× SMA +// bulkhead holes (LTE main + diversity). +// Antennas point skyward. +// +// gnss_platform() 25 mm stem clamp + upward-facing tray +// for active GNSS patch antenna (≤40×40 mm). +// +// Recommended stem positions (above base plate): +// LTE bracket 500–600 mm (above battery carousel) +// GNSS platform 750–800 mm (below sensor head, clear sky) +// +// Both use the same split-collar design: +// M4 clamping bolts + M4 set screw (height lock). +// Cable-tie slot on rear half for u.FL pigtail management. +// +// u.FL → SMA pigtail cables route down stem to SIM7600X HAT. +// +// ⚠ VERIFY: MAWB_HOLE_X / MAWB_HOLE_Y for any M2.5 pattern +// SMA_D for your SMA bulkhead thread OD +// +// RENDER options: +// "lte_assembly" LTE bracket view (default) +// "lte_front" LTE collar front half for slicing +// "lte_rear" LTE collar rear half +// "lte_arm" LTE SMA arm for slicing (print flat) +// "gnss_assembly" GNSS platform view +// "gnss_front" GNSS collar front half +// "gnss_rear" GNSS collar rear half +// "gnss_tray" GNSS patch-antenna tray for slicing +// "full_stem" both brackets on 400 mm stem stub +// ============================================================ + +RENDER = "lte_assembly"; + +// ── Stem ───────────────────────────────────────────────────── +STEM_OD = 25.0; +STEM_BORE = 25.4; // +0.4 clearance + +// ── Collar (shared) ────────────────────────────────────────── +COL_OD = 52.0; +COL_H = 28.0; +COL_BOLT_X = 19.0; // M4 clamping bolt CL from stem axis +COL_BOLT_D = 4.5; // M4 clearance hole +COL_NUT_W = 7.0; // M4 hex nut A/F +COL_NUT_H = 3.4; + +// Cable-tie slot on rear half outer face (for pigtail routing) +TIE_W = 5.0; +TIE_D = 3.0; +TIE_Z1 = COL_H * 0.35; +TIE_Z2 = COL_H * 0.70; + +// ── LTE SMA arm ────────────────────────────────────────────── +// 2× SMA bulkhead connectors pointing skyward +SMA_D = 6.6; // SMA bulkhead clearance hole (6.35 mm thread) +SMA_NUT_AF = 10.2; // SMA hex-nut capture across-flats +SMA_NUT_H = 4.5; // hex-nut pocket depth (bottom of arm) +SMA_SPACING = 22.0; // centre-to-centre between 2 SMA positions +LTE_ARM_L = 40.0; // arm length (from collar OD to SMA CL) +LTE_ARM_W = SMA_SPACING + 18.0; // arm width +LTE_ARM_H = 9.0; // arm thickness +LTE_SMA_Y = LTE_ARM_L * 0.65; // SMA position along arm + +// Pigtail cable relief (semi-circular groove on arm underside) +PIGTAIL_D = 4.5; + +// M3 attachment bolts (arm → collar boss) +M3_D = 3.3; + +// ── GNSS patch-antenna tray ─────────────────────────────────── +GNSS_PATCH = 40.0; // maximum patch antenna side (fits 25, 35, 40 mm) +GNSS_LIP_T = 2.2; // lip wall thickness +GNSS_LIP_H = 3.0; // lip height above tray surface +GNSS_TRAY_T = 3.0; // tray base thickness + +// Optional M2 bolt-down pattern for larger patch antennas +GNSS_M2_SP = 30.0; // M2 spacing (verify with your patch antenna) +M2_D = 2.2; + +// Coax cable slot (centre of tray, through base) +GNSS_COAX_W = 5.5; + +// Arm connecting tray to collar +GNSS_ARM_L = 28.0; +GNSS_ARM_W = 22.0; +GNSS_ARM_H = 7.0; + +// Spacing between LTE and GNSS collars on stem +STEM_SPACING = 80.0; + +$fn = 64; +e = 0.01; + +// ───────────────────────────────────────────────────────────── +// collar_half(side, arm_type) +// arm_type: "lte" | "gnss" | "none" +// Print flat-face-down. +// ───────────────────────────────────────────────────────────── +module collar_half(side="front", arm_type="lte") { + y_front = (side == "front"); + has_arm = y_front && (arm_type != "none"); + + arm_w = (arm_type == "lte") ? LTE_ARM_W : GNSS_ARM_W; + arm_l = (arm_type == "lte") ? LTE_ARM_L : GNSS_ARM_L; + arm_h = (arm_type == "lte") ? LTE_ARM_H : GNSS_ARM_H; + arm_z = COL_H/2 - arm_h/2; + + difference() { + union() { + // D-shaped collar half + intersection() { + cylinder(d=COL_OD, h=COL_H); + translate([-COL_OD/2, y_front ? 0 : -COL_OD/2, 0]) + cube([COL_OD, COL_OD/2, COL_H]); + } + + // Arm boss integrated into front half + if (has_arm) + translate([-arm_w/2, COL_OD/2, arm_z]) + cube([arm_w, arm_l, arm_h]); + } + + // Stem bore + translate([0, 0, -e]) + cylinder(d=STEM_BORE, h=COL_H + 2*e); + + // M4 clamping bolt holes (Y direction) + for (bx=[-COL_BOLT_X, COL_BOLT_X]) + translate([bx, y_front ? COL_OD/2 : 0, COL_H/2]) + rotate([90,0,0]) + cylinder(d=COL_BOLT_D, h=COL_OD/2 + e); + + // M4 hex nut pockets (rear half only) + if (!y_front) + for (bx=[-COL_BOLT_X, COL_BOLT_X]) + translate([bx, -(COL_OD/4 + e), COL_H/2]) + rotate([90,0,0]) + cylinder(d=COL_NUT_W/cos(30), h=COL_NUT_H+e, + $fn=6); + + // M4 set screw (height lock, front half outer face) + if (y_front) + translate([0, COL_OD/2, COL_H * 0.75]) + rotate([90,0,0]) + cylinder(d=COL_BOLT_D, + h=COL_OD/2 - STEM_BORE/2 + e); + + // Cable-tie grooves on rear half outer surface (2×) + if (!y_front) + for (tz=[TIE_Z1, TIE_Z2]) + translate([-COL_OD/2 - e, -TIE_W/2, tz]) + cube([TIE_D + e, TIE_W, TIE_W]); + + // M3 attachment holes through arm boss (2×) + if (has_arm) + for (dx=[-arm_w/4, arm_w/4]) + translate([dx, COL_OD/2 + arm_l * 0.45, arm_z - e]) + cylinder(d=M3_D, h=arm_h + 2*e); + } +} + +// ───────────────────────────────────────────────────────────── +// lte_sma_arm() +// Separate arm piece bolts to collar front boss. +// 2× SMA bulkheads point upward. Pigtail grooves on underside. +// Print: lay flat on bottom face. +// ───────────────────────────────────────────────────────────── +module lte_sma_arm() { + difference() { + translate([-LTE_ARM_W/2, 0, 0]) + cube([LTE_ARM_W, LTE_ARM_L, LTE_ARM_H]); + + // 2× SMA bulkhead through-holes (vertical) + for (dx=[-SMA_SPACING/2, SMA_SPACING/2]) { + translate([dx, LTE_SMA_Y, -e]) + cylinder(d=SMA_D, h=LTE_ARM_H + 2*e); + // Hex-nut pocket from bottom face + translate([dx, LTE_SMA_Y, -e]) + cylinder(d=SMA_NUT_AF/cos(30), h=SMA_NUT_H + e, + $fn=6); + } + + // u.FL pigtail relief grooves on underside + for (dx=[-SMA_SPACING/2, SMA_SPACING/2]) + translate([dx, 0, -e]) + rotate([0, 0, 0]) + linear_extrude(PIGTAIL_D/2 + e) + translate([0, LTE_ARM_L/2]) + circle(d=PIGTAIL_D); + + // M3 attachment holes (collar boss) + for (dx=[-LTE_ARM_W/4, LTE_ARM_W/4]) + translate([dx, LTE_ARM_L * 0.45, -e]) + cylinder(d=M3_D, h=LTE_ARM_H + 2*e); + } +} + +// ───────────────────────────────────────────────────────────── +// gnss_tray() +// Horizontal tray faces skyward. Retention lip on all 4 sides. +// Central coax slot + optional M2 bolt holes. +// Print: top face on bed (tray upside-down → no supports needed). +// ───────────────────────────────────────────────────────────── +module gnss_tray() { + outer = GNSS_PATCH + 2 * GNSS_LIP_T; + + difference() { + union() { + // Base plate + translate([-outer/2, 0, 0]) + cube([outer, outer, GNSS_TRAY_T]); + // Retention lip (4 walls) + translate([-outer/2, 0, GNSS_TRAY_T]) + difference() { + cube([outer, outer, GNSS_LIP_H]); + translate([GNSS_LIP_T, GNSS_LIP_T, -e]) + cube([GNSS_PATCH, GNSS_PATCH, GNSS_LIP_H + 2*e]); + } + // Arm connecting to collar + translate([-GNSS_ARM_W/2, -GNSS_ARM_L, 0]) + cube([GNSS_ARM_W, GNSS_ARM_L, GNSS_ARM_H]); + } + + // GNSS coax cable slot (centre, through base) + translate([-GNSS_COAX_W/2, outer/2 - GNSS_COAX_W/2, -e]) + cube([GNSS_COAX_W, GNSS_COAX_W, GNSS_TRAY_T + 2*e]); + + // M2 bolt-down holes (30×30 mm pattern, centred in tray) + tray_cx = 0; + tray_cy = outer/2; + for (dx=[-GNSS_M2_SP/2, GNSS_M2_SP/2]) + for (dy=[-GNSS_M2_SP/2, GNSS_M2_SP/2]) + translate([tray_cx + dx, tray_cy + dy, -e]) + cylinder(d=M2_D, h=GNSS_TRAY_T + 2*e); + + // M3 bolt holes (arm → collar) + for (dx=[-GNSS_ARM_W/4, GNSS_ARM_W/4]) + translate([dx, -GNSS_ARM_L * 0.45, -e]) + cylinder(d=M3_D, h=GNSS_ARM_H + 2*e); + } +} + +// ───────────────────────────────────────────────────────────── +// lte_bracket_assembly() / gnss_bracket_assembly() +// ───────────────────────────────────────────────────────────── +module lte_bracket_assembly() { + color("SteelBlue", 0.9) collar_half("front", "lte"); + color("CornflowerBlue", 0.9) mirror([0,1,0]) collar_half("rear", "none"); + color("LightSteelBlue", 0.85) + translate([0, COL_OD/2, COL_H/2 - LTE_ARM_H/2]) + lte_sma_arm(); + // Phantom SMA stub antennas + for (dx=[-SMA_SPACING/2, SMA_SPACING/2]) + color("DimGray", 0.5) + translate([dx, COL_OD/2 + LTE_SMA_Y, + COL_H/2 + LTE_ARM_H/2]) + cylinder(d=7, h=60); +} + +module gnss_bracket_assembly() { + color("Teal", 0.9) collar_half("front", "gnss"); + color("DarkCyan", 0.9) mirror([0,1,0]) collar_half("rear", "none"); + // Tray: arm at Y−, tray faces +Z + color("LightCyan", 0.85) + translate([0, COL_OD/2 + GNSS_ARM_L, + COL_H/2 - GNSS_ARM_H/2]) + rotate([90, 0, 0]) + gnss_tray(); + // Phantom GNSS patch + color("Gold", 0.35) + translate([-GNSS_PATCH/2, + COL_OD/2 + GNSS_ARM_L + GNSS_LIP_T, + COL_H/2 + GNSS_ARM_H/2 + GNSS_TRAY_T]) + cube([GNSS_PATCH, GNSS_PATCH, 8]); +} + +// ───────────────────────────────────────────────────────────── +// Render selector +// ───────────────────────────────────────────────────────────── +if (RENDER == "lte_assembly") { + lte_bracket_assembly(); +} else if (RENDER == "lte_front") { + collar_half("front", "lte"); +} else if (RENDER == "lte_rear") { + collar_half("rear", "none"); +} else if (RENDER == "lte_arm") { + translate([0, 0, LTE_ARM_H]) rotate([180,0,0]) lte_sma_arm(); +} else if (RENDER == "gnss_assembly") { + gnss_bracket_assembly(); +} else if (RENDER == "gnss_front") { + collar_half("front", "gnss"); +} else if (RENDER == "gnss_rear") { + collar_half("rear", "none"); +} else if (RENDER == "gnss_tray") { + gnss_tray(); +} else if (RENDER == "full_stem") { + color("Silver", 0.2) + translate([0,0,-40]) + cylinder(d=STEM_OD, h=STEM_SPACING + COL_H + 80); + lte_bracket_assembly(); + translate([0, 0, STEM_SPACING]) + gnss_bracket_assembly(); +} diff --git a/chassis/sim7600x_mount.scad b/chassis/sim7600x_mount.scad new file mode 100644 index 0000000..f265bfa --- /dev/null +++ b/chassis/sim7600x_mount.scad @@ -0,0 +1,169 @@ +// ============================================================ +// sim7600x_mount.scad — Waveshare SIM7600X 4G HAT Bracket +// Rev A 2026-03-01 sl-mechanical +// ============================================================ +// Mounts the SIM7600X HAT near the Jetson Orin on the base plate. +// +// PCB: 65 × 56 mm, 4× M2.5 mounting holes (RPi HAT std pattern). +// +// SIM card access without disassembly: +// The Y− edge of the bracket platform is fully open — a notch +// in the floor plate is wider than the SIM tray so the card +// inserts / ejects with the board fully installed. +// +// Base plate attachment: 4× M3 flat-head countersunk holes at +// bracket corners. Drill M3 clearance holes in base plate and +// use M3 nyloc nuts underneath, or use captured M3 T-nuts. +// +// ⚠ VERIFY WITH CALIPERS BEFORE PRINTING: +// HAT_L, HAT_W PCB dimensions +// HAT_HOLE_X, HAT_HOLE_Y M2.5 hole spacing +// HAT_HOLE_OX, HAT_HOLE_OY hole inset from PCB corners +// SIM_X, SIM_W SIM slot centre & width on Y− edge +// USB_X, USB_W, USB_H USB port on Y− edge +// +// RENDER options: +// "assembly" bracket + phantom PCB (default) +// "bracket" print-ready bracket +// "bracket_2d" floor projection → DXF for base-plate layout +// ============================================================ + +RENDER = "assembly"; + +// ── ⚠ Verify before printing ───────────────────────────────── +// Waveshare SIM7600X-H 4G HAT +HAT_L = 65.0; // PCB length (X) +HAT_W = 56.0; // PCB width (Y) — SIM slot on Y=0 edge +HAT_H_BELOW = 3.0; // tallest component on PCB underside (verify) + +// RPi HAT standard M2.5 hole pattern +HAT_HOLE_X = 58.0; // X span between hole pairs +HAT_HOLE_Y = 49.0; // Y span between hole pairs +HAT_HOLE_OX = 3.5; // hole inset from X− edge of PCB +HAT_HOLE_OY = 3.5; // hole inset from Y− edge of PCB +M25_D = 2.7; // M2.5 clearance (loose, for alignment) +M25_OD = 5.0; // standoff post outer diameter + +// SIM card slot (Y− edge, verify position from left/X− corner) +SIM_X = 42.0; // SIM slot centre from PCB X− edge +SIM_W = 17.0; // SIM slot width +SIM_H_NOTCH = 4.5; // notch height for tray travel + eject pin + +// USB Micro-B port (Y− edge, verify — may differ by HAT version) +USB_X = 11.0; // USB port centre from PCB X− edge +USB_W = 10.5; // USB port width +USB_H = 7.0; // USB port height + +// u.FL pigtail exit slot (Y+ wall) +UFL_SLOT_W = 12.0; +UFL_SLOT_H = 5.0; + +// ── Bracket geometry ───────────────────────────────────────── +STNDFF_H = HAT_H_BELOW + 4.0; // standoff height (clears underside) +PLAT_T = 3.5; // floor plate thickness +WALL_T = 2.5; // side wall thickness + +PAD_X = 5.0; // platform extends PAD_X beyond PCB on X± sides +PAD_Y_PLUS = 8.0; // platform extends PAD_Y_PLUS beyond PCB on Y+ side +// Y− side: open (no wall, no floor overhang) — SIM/USB access + +PLAT_L = HAT_L + 2 * PAD_X; +PLAT_W = HAT_W + PAD_Y_PLUS; // Y− edge flush with PCB Y=0 + +// PCB sits with Y=0 edge flush with bracket Y=0 face +PCB_X0 = PAD_X; // X offset of PCB within bracket + +// M3 base-plate mounting holes +M3_D = 3.4; +M3_CS_D = 6.2; // flat-head countersink diameter +M3_CS_H = 3.0; // countersink depth (from bottom face) +M3_INSET = 5.0; // hole inset from bracket corner + +// Side wall height (for cable containment) +WALL_H = STNDFF_H + 4.0; + +$fn = 48; +e = 0.01; + +// ───────────────────────────────────────────────────────────── +module sim7600x_bracket() { + difference() { + union() { + // ── Floor plate ────────────────────────────────── + cube([PLAT_L, PLAT_W, PLAT_T]); + + // ── Side walls: X−, X+, Y+ only (Y− open) ─────── + translate([0, 0, 0]) + cube([WALL_T, PLAT_W, WALL_H]); + translate([PLAT_L - WALL_T, 0, 0]) + cube([WALL_T, PLAT_W, WALL_H]); + translate([0, PLAT_W - WALL_T, 0]) + cube([PLAT_L, WALL_T, WALL_H]); + + // ── M2.5 standoff posts (×4) ───────────────────── + for (hx=[0, HAT_HOLE_X], hy=[0, HAT_HOLE_Y]) + translate([PCB_X0 + HAT_HOLE_OX + hx, + HAT_HOLE_OY + hy, + PLAT_T]) + cylinder(d=M25_OD, h=STNDFF_H); + } + + // ── M2.5 clearance bores through standoffs ─────────── + for (hx=[0, HAT_HOLE_X], hy=[0, HAT_HOLE_Y]) + translate([PCB_X0 + HAT_HOLE_OX + hx, + HAT_HOLE_OY + hy, -e]) + cylinder(d=M25_D, h=PLAT_T + STNDFF_H + e); + + // ── SIM card access notch (Y− face of floor) ───────── + // Notch 4 mm wider than SIM slot each side + translate([PCB_X0 + SIM_X - SIM_W/2 - 4, -e, -e]) + cube([SIM_W + 8, WALL_T + e, PLAT_T + SIM_H_NOTCH + e]); + + // ── USB port access notch (Y− face of X− wall) ─────── + translate([PCB_X0 + USB_X - USB_W/2, -e, + PLAT_T + STNDFF_H/2 - USB_H/2]) + cube([USB_W, WALL_T + 2*e, USB_H]); + + // ── u.FL pigtail exit slot (Y+ wall, upper zone) ───── + translate([PLAT_L/2 - UFL_SLOT_W/2, + PLAT_W - WALL_T - e, + PLAT_T + STNDFF_H - UFL_SLOT_H]) + cube([UFL_SLOT_W, WALL_T + 2*e, UFL_SLOT_H + e]); + + // ── M3 base-plate mounting holes (×4, countersunk) ─── + for (cx=[M3_INSET, PLAT_L - M3_INSET]) + for (cy=[M3_INSET, PLAT_W - M3_INSET]) { + translate([cx, cy, -e]) + cylinder(d=M3_D, h=PLAT_T + 2*e); + // Countersink from bottom face + translate([cx, cy, -e]) + cylinder(d1=M3_CS_D, d2=M3_D, + h=M3_CS_H + e); + } + + // ── Cable relief notch in X+ wall ──────────────────── + translate([PLAT_L - WALL_T - e, PLAT_W * 0.35, PLAT_T + 2]) + cube([WALL_T + 2*e, 9, 5]); + } +} + +// ───────────────────────────────────────────────────────────── +if (RENDER == "assembly") { + color("DimGray", 0.92) sim7600x_bracket(); + // Phantom PCB + color("ForestGreen", 0.3) + translate([PCB_X0, 0, PLAT_T + STNDFF_H]) + cube([HAT_L, HAT_W, 1.6]); + // SIM access marker (yellow arrow zone) + color("Gold", 0.7) + translate([PCB_X0 + SIM_X - 10, -8, 0]) + cube([20, 8, 2]); + +} else if (RENDER == "bracket") { + sim7600x_bracket(); + +} else if (RENDER == "bracket_2d") { + projection(cut=true) + translate([0, 0, -PLAT_T/2]) + sim7600x_bracket(); +}