// ============================================================ // Jetson Orin Nano Carrier Board Mount — Issue #612 // Agent : sl-mechanical // Date : 2026-03-15 // Part catalogue: // 1. tnut_base — 2020 T-slot rail interface plate, M5 T-nut captive pockets // 2. standoff_post — M2.5 captive-nut standoff post (×4), 10 mm airflow gap // 3. side_brace — lateral stiffening brace with port-access cutouts (×2) // 4. duct_shroud — optional top heatsink duct / fan-exhaust channel // 5. cable_clip — snap-on cable management clip for brace edge // // BOM: // 4 × M5×10 BHCS + M5 T-nuts (tnut_base to rail, 2 per rail) // 4 × M2.5×20 SHCS (board to standoff posts) // 4 × M2.5 hex nuts (captured in standoff posts) // 4 × M3×8 SHCS + washers (side_brace to tnut_base) // 2 × M3×16 SHCS (duct_shroud to side_brace tops) // // Jetson Orin Nano carrier board (Seeed reComputer / official dev kit): // Board dims : 100 × 80 mm // Mounting hole pattern : 86 × 58 mm (centre-to-centre), M2.5, Ø3.5 pad // PCB thickness: 1.6 mm // Connector side: -Y (USB-A, USB-C, HDMI, DP, GbE, SD on one long edge) // Fan header & PWM header: +X short edge // M.2 / NVMe: bottom face // // Print settings (PETG): // tnut_base / standoff_post / side_brace / duct_shroud : 5 perimeters, 40 % gyroid, no supports // cable_clip : 3 perimeters, 30 % gyroid, no supports // // Export commands: // openscad -D 'RENDER="tnut_base"' -o tnut_base.stl jetson_orin_mount.scad // openscad -D 'RENDER="standoff_post"' -o standoff_post.stl jetson_orin_mount.scad // openscad -D 'RENDER="side_brace"' -o side_brace.stl jetson_orin_mount.scad // openscad -D 'RENDER="duct_shroud"' -o duct_shroud.stl jetson_orin_mount.scad // openscad -D 'RENDER="cable_clip"' -o cable_clip.stl jetson_orin_mount.scad // openscad -D 'RENDER="assembly"' -o assembly.png jetson_orin_mount.scad // ============================================================ // ── Render selector ───────────────────────────────────────── RENDER = "assembly"; // tnut_base | standoff_post | side_brace | duct_shroud | cable_clip | assembly // ── Global constants ──────────────────────────────────────── $fn = 64; EPS = 0.01; // 2020 rail RAIL_W = 20.0; SLOT_NECK_H = 3.2; TNUT_W = 9.8; TNUT_H = 5.5; TNUT_L = 12.0; M5_D = 5.2; M5_HEAD_D = 9.5; M5_HEAD_H = 4.0; // Jetson Orin Nano carrier board BOARD_L = 100.0; // board X BOARD_W = 80.0; // board Y BOARD_T = 1.6; // PCB thickness MH_SX = 86.0; // mounting hole span X (centre-to-centre) MH_SY = 58.0; // mounting hole span Y M25_D = 2.7; // M2.5 clearance bore M25_NUT_W = 5.0; // M2.5 hex nut across-flats M25_NUT_H = 2.0; // M2.5 hex nut height M25_HEAD_D = 5.0; // M2.5 SHCS head diameter M25_HEAD_H = 2.5; // Base plate BASE_L = 120.0; // length along X (covers board + overhang for braces) BASE_W = 50.0; // width along Y (rail mount footprint) BASE_T = 6.0; // plate thickness BOLT_PITCH = 40.0; // M5 rail bolt pitch (per rail, 2 rails at Y=0 & Y=BASE_W) M3_D = 3.2; M3_HEAD_D = 6.0; M3_HEAD_H = 3.0; // Standoff posts POST_H = 12.0; // airflow gap + PCB seating (>= 10 mm clearance spec) POST_OD = 8.0; // outer diameter POST_BASE_D = 11.0; // flange diameter POST_BASE_H = 3.0; // flange height NUT_TRAP_H = M25_NUT_H + 0.3; NUT_TRAP_W = M25_NUT_W + 0.4; // Side braces BRACE_T = 5.0; // brace thickness (X) BRACE_H = POST_H + POST_BASE_H + BOARD_T + 4.0; // full height BRACE_W = BASE_W; // same width as base // Port-access cutouts (connector side -Y) USB_CUT_W = 60.0; // wide cutout for USB-A stack + HDMI + DP USB_CUT_H = 22.0; GBE_CUT_W = 20.0; // GbE jack GBE_CUT_H = 18.0; // Duct shroud DUCT_T = 3.0; // wall thickness DUCT_FLANGE = 6.0; // side tab width for M3 attachment FAN_W = 40.0; // standard 40 mm blower clearance cutout FAN_H = 10.0; // duct outlet height // Cable clip CLIP_OD = 12.0; CLIP_ID = 7.0; CLIP_GAP = 7.5; CLIP_W = 10.0; SNAP_T = 1.8; // ── Utilities ─────────────────────────────────────────────── module chamfer_cube(size, ch=1.0) { hull() { translate([ch, ch, 0]) cube([size[0]-2*ch, size[1]-2*ch, EPS]); translate([0, 0, ch]) cube(size - [0, 0, ch]); } } module hex_pocket(af, depth) { cylinder(d=af/cos(30), h=depth, $fn=6); } // ── Part 1: tnut_base ─────────────────────────────────────── module tnut_base() { difference() { union() { chamfer_cube([BASE_L, BASE_W, BASE_T], ch=1.5); // Raised mounting bosses for M3 brace attachment (4 corners) for (x = [8, BASE_L-8]) for (y = [8, BASE_W-8]) translate([x, y, BASE_T]) cylinder(d=10, h=2.5); } // T-nut pockets and M5 bolts — front rail (y = BASE_W/4) for (x = [BASE_L/2 - BOLT_PITCH/2, BASE_L/2 + BOLT_PITCH/2]) { translate([x, BASE_W/4, -EPS]) { cylinder(d=M5_D, h=BASE_T + 2*EPS); cylinder(d=M5_HEAD_D, h=M5_HEAD_H + EPS); } translate([x - TNUT_L/2, BASE_W/4 - TNUT_W/2, BASE_T - TNUT_H]) cube([TNUT_L, TNUT_W, TNUT_H + EPS]); } // T-nut pockets and M5 bolts — rear rail (y = 3*BASE_W/4) for (x = [BASE_L/2 - BOLT_PITCH/2, BASE_L/2 + BOLT_PITCH/2]) { translate([x, 3*BASE_W/4, -EPS]) { cylinder(d=M5_D, h=BASE_T + 2*EPS); cylinder(d=M5_HEAD_D, h=M5_HEAD_H + EPS); } translate([x - TNUT_L/2, 3*BASE_W/4 - TNUT_W/2, BASE_T - TNUT_H]) cube([TNUT_L, TNUT_W, TNUT_H + EPS]); } // M3 boss bolt holes (corner braces) for (x = [8, BASE_L-8]) for (y = [8, BASE_W-8]) translate([x, y, -EPS]) cylinder(d=M3_D, h=BASE_T + 2.5 + 2*EPS); // M3 boss counterbores (head from bottom) for (x = [8, BASE_L-8]) for (y = [8, BASE_W-8]) translate([x, y, -EPS]) cylinder(d=M3_HEAD_D, h=M3_HEAD_H + EPS); // Standoff post seating holes (board hole pattern, centred on plate) bx0 = BASE_L/2 - MH_SX/2; by0 = BASE_W/2 - MH_SY/2; for (dx = [0, MH_SX]) for (dy = [0, MH_SY]) translate([bx0+dx, by0+dy, -EPS]) cylinder(d=POST_BASE_D + 0.4, h=BASE_T + 2*EPS); // Weight relief grid (2 pockets) translate([20, 12, -EPS]) cube([30, BASE_W-24, BASE_T/2]); translate([BASE_L-50, 12, -EPS]) cube([30, BASE_W-24, BASE_T/2]); // Cable pass-through slot translate([BASE_L/2 - 8, BASE_W/2 - 3, -EPS]) cube([16, 6, BASE_T + 2*EPS]); } } // ── Part 2: standoff_post ─────────────────────────────────── module standoff_post() { difference() { union() { // Flange cylinder(d=POST_BASE_D, h=POST_BASE_H); // Post body translate([0, 0, POST_BASE_H]) cylinder(d=POST_OD, h=POST_H); } // M2.5 through bore translate([0, 0, -EPS]) cylinder(d=M25_D, h=POST_BASE_H + POST_H + 2*EPS); // Captured hex nut trap (from top) translate([0, 0, POST_BASE_H + POST_H - NUT_TRAP_H]) hex_pocket(NUT_TRAP_W, NUT_TRAP_H + EPS); // Anti-rotation flat on nut pocket translate([-M25_NUT_W/2 - 0.2, -POST_OD/2 - EPS, POST_BASE_H + POST_H - NUT_TRAP_H]) cube([M25_NUT_W + 0.4, 2.0, NUT_TRAP_H + EPS]); } } // ── Part 3: side_brace ────────────────────────────────────── // Printed as +X face. Mirror for -X side. module side_brace() { difference() { union() { chamfer_cube([BRACE_T, BRACE_W, BRACE_H], ch=1.0); // Top lip to retain board edge translate([0, 0, BRACE_H]) cube([BRACE_T + 8.0, BRACE_W, 2.5]); } // M3 bolt holes at base (attach to tnut_base bosses) for (y = [8, BRACE_W-8]) translate([-EPS, y, 4]) rotate([0, 90, 0]) cylinder(d=M3_D, h=BRACE_T + 2*EPS); // M3 counterbore from outer face for (y = [8, BRACE_W-8]) translate([-EPS, y, 4]) rotate([0, 90, 0]) cylinder(d=M3_HEAD_D, h=M3_HEAD_H + EPS); // Port-access cutout — USB/HDMI/DP cluster (centred on brace face) translate([-EPS, BRACE_W/2 - USB_CUT_W/2, POST_BASE_H + 2.0]) cube([BRACE_T + 2*EPS, USB_CUT_W, USB_CUT_H]); // GbE cutout (offset toward +Y) translate([-EPS, BRACE_W/2 + USB_CUT_W/2 - GBE_CUT_W - 2, POST_BASE_H + 2.0]) cube([BRACE_T + 2*EPS, GBE_CUT_W, GBE_CUT_H]); // M3 duct attachment holes (top edge) for (y = [BRACE_W/4, 3*BRACE_W/4]) translate([BRACE_T/2, y, BRACE_H - 2]) cylinder(d=M3_D, h=10); // Ventilation slots (3 tall slots for airflow) for (i = [0:2]) translate([-EPS, (BRACE_W - 3*8 - 2*4) / 2 + i*(8+4), POST_BASE_H + USB_CUT_H + 6]) cube([BRACE_T + 2*EPS, 8, BRACE_H - POST_BASE_H - USB_CUT_H - 10]); } } // ── Part 4: duct_shroud ───────────────────────────────────── // Top cap that channels fan exhaust away from board; optional print. module duct_shroud() { duct_l = BASE_L - 2*BRACE_T - 1.0; // span between inner brace faces duct_w = BRACE_W; difference() { union() { // Top plate cube([duct_l, duct_w, DUCT_T]); // Front wall (fan inlet side) translate([0, 0, -FAN_H]) cube([DUCT_T, duct_w, FAN_H + DUCT_T]); // Rear wall (exhaust side — open centre) translate([duct_l - DUCT_T, 0, -FAN_H]) cube([DUCT_T, duct_w, FAN_H + DUCT_T]); // Side flanges for M3 attachment translate([-DUCT_FLANGE, 0, -FAN_H]) cube([DUCT_FLANGE, duct_w, FAN_H + DUCT_T]); translate([duct_l, 0, -FAN_H]) cube([DUCT_FLANGE, duct_w, FAN_H + DUCT_T]); } // Fan cutout on top plate (centred) translate([duct_l/2 - FAN_W/2, duct_w/2 - FAN_W/2, -EPS]) cube([FAN_W, FAN_W, DUCT_T + 2*EPS]); // Fan screw holes (40 mm fan, Ø3.2 at 32 mm BC) for (dx = [-16, 16]) for (dy = [-16, 16]) translate([duct_l/2 + dx, duct_w/2 + dy, -EPS]) cylinder(d=M3_D, h=DUCT_T + 2*EPS); // Exhaust slot on rear wall (full width minus corners) translate([duct_l - DUCT_T - EPS, 4, -FAN_H + 2]) cube([DUCT_T + 2*EPS, duct_w - 8, FAN_H - 2]); // M3 flange attachment holes for (y = [duct_w/4, 3*duct_w/4]) { translate([-DUCT_FLANGE - EPS, y, -FAN_H/2]) rotate([0, 90, 0]) cylinder(d=M3_D, h=DUCT_FLANGE + 2*EPS); translate([duct_l + DUCT_T - EPS, y, -FAN_H/2]) rotate([0, 90, 0]) cylinder(d=M3_D, h=DUCT_FLANGE + 2*EPS); } } } // ── Part 5: cable_clip ────────────────────────────────────── module cable_clip() { difference() { union() { // Snap-wrap body difference() { cylinder(d=CLIP_OD + 2*SNAP_T, h=CLIP_W); translate([0, 0, -EPS]) cylinder(d=CLIP_ID, h=CLIP_W + 2*EPS); // Front gap translate([-CLIP_GAP/2, 0, -EPS]) cube([CLIP_GAP, CLIP_OD, CLIP_W + 2*EPS]); } // Mounting tab for brace edge translate([CLIP_OD/2 + SNAP_T - EPS, -SNAP_T, 0]) cube([8, SNAP_T*2, CLIP_W]); } // Tab screw hole translate([CLIP_OD/2 + SNAP_T + 4, 0, CLIP_W/2]) rotate([90, 0, 0]) cylinder(d=M3_D, h=SNAP_T*2 + 2*EPS, center=true); } } // ── Assembly ──────────────────────────────────────────────── module assembly() { // Base plate color("SteelBlue") tnut_base(); // Standoff posts (board hole pattern) bx0 = BASE_L/2 - MH_SX/2; by0 = BASE_W/2 - MH_SY/2; for (dx = [0, MH_SX]) for (dy = [0, MH_SY]) color("DodgerBlue") translate([bx0+dx, by0+dy, BASE_T]) standoff_post(); // Side braces (left and right) color("CornflowerBlue") translate([0, 0, BASE_T]) side_brace(); color("CornflowerBlue") translate([BASE_L, BRACE_W, BASE_T]) mirror([1, 0, 0]) mirror([0, 1, 0]) side_brace(); // Board silhouette (translucent, for clearance visualisation) color("ForestGreen", 0.25) translate([BASE_L/2 - BOARD_L/2, BASE_W/2 - BOARD_W/2, BASE_T + POST_BASE_H + POST_H]) cube([BOARD_L, BOARD_W, BOARD_T]); // Duct shroud (above board) color("LightSteelBlue", 0.7) translate([BRACE_T + 0.5, 0, BASE_T + POST_BASE_H + POST_H + BOARD_T + 2.0]) duct_shroud(); // Cable clips (on brace edge, 2×) for (y = [BRACE_W/3, 2*BRACE_W/3]) color("SlateGray") translate([BASE_L + 2, y, BASE_T + BRACE_H/2 - CLIP_W/2]) rotate([0, 90, 0]) cable_clip(); } // ── Dispatch ──────────────────────────────────────────────── if (RENDER == "tnut_base") tnut_base(); else if (RENDER == "standoff_post") standoff_post(); else if (RENDER == "side_brace") side_brace(); else if (RENDER == "duct_shroud") duct_shroud(); else if (RENDER == "cable_clip") cable_clip(); else assembly();