saltylab-firmware/chassis/antenna_mount.scad
sl-mechanical 0daac970c3 feat: SIM7600X mount + LTE/GNSS antenna brackets
chassis/sim7600x_mount.scad
  Platform bracket for Waveshare SIM7600X-H 4G HAT (65×56 mm,
  RPi HAT M2.5 pattern 58×49 mm). Standoffs height = HAT underside
  component clearance + 4 mm. Three walls (X−, X+, Y+); Y− edge
  fully open for SIM card tray access without disassembly. Floor-plate
  notch wider than SIM slot so card inserts/ejects with board in situ.
  USB port notch same open edge. u.FL pigtail exit slot in Y+ wall.
  4× M3 flat-head countersunk holes for base plate bolt-down.
  RENDER: bracket / assembly / bracket_2d (DXF for base plate layout).

chassis/antenna_mount.scad
  Two bracket types on shared 25 mm stem split-collar (M4 bolts,
  set screw height lock, cable-tie grooves on rear half):

  lte_bracket() — arm with 2× SMA bulkhead holes (6.6 mm clearance,
  hex-nut capture on underside). u.FL pigtail relief grooves on arm
  underside. Antennas point skyward. Recommended: 500–600 mm stem.

  gnss_platform() — upward-facing tray (≤40×40 mm patch antenna),
  4-sided retention lip, central GNSS coax slot, optional M2 bolt-down
  holes at 30×30 mm. Mount as high as practical for clear sky view:
  750–800 mm stem height. Recommended: active 35×35 mm patch antenna.

  RENDER "full_stem" shows both at 80 mm spacing on stem stub.
  Individual RENDER modes for each printable piece.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 00:59:47 -05:00

310 lines
13 KiB
OpenSCAD
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ============================================================
// 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 500600 mm (above battery carousel)
// GNSS platform 750800 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();
}