Files
MIS-Contro-Tower/rpi-case/rpi5_industrial_case_004.scad
2026-04-22 05:04:19 +00:00

339 lines
14 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.
// ============================================================
// RPi5 Industrial Enclosure — Luckfox DHX-10.1" Touchscreen
// Version: 004
// Changes vs 003:
// 1. KICKSTAND is now a separate, removable piece (own module + color)
// - Full enc_w width (no shorter ks_width param)
// - 3 prongs on rear edge that slide into slots in case bottom wall
// - Tapered prong tips for easy insertion
// 2. Prong slots added to rear cover bottom wall
// 3. USB-C touch cutout on left wall REMOVED (per user request)
// 4. Wall thickness increased 2.5 → 4 mm for rigidity
// 5. Bezel screw holes now countersunk + clearly sized
// 6. Insert bosses on rear cover made taller and more prominent
// so the two-piece (bezel + rear cover) joint is obvious in renders
// 7. Render shows THREE separate bodies: bezel / rear cover / kickstand
// ============================================================
// ── SCREEN PARAMETERS ───────────────────────────────────────
scr_w = 236; // screen outer width (mm)
scr_h = 144; // screen outer height (mm)
scr_d = 19; // screen outer depth (mm)
scr_active_w = 222; // active display area width (mm) ← confirm
scr_active_h = 130; // active display area height (mm) ← confirm
scr_mount_x = 75; // screen rear M2.5 hole pattern X (mm) ← verify
scr_mount_y = 75; // screen rear M2.5 hole pattern Y (mm) ← verify
// ── RASPBERRY PI 5 PARAMETERS ────────────────────────────────
pi_w = 85; // Pi board width (mm)
pi_h = 56; // Pi board height (mm)
pi_d = 17; // Pi board + tallest component (mm)
pi_mnt_x = 58; // Pi mount hole pattern X (mm)
pi_mnt_y = 49; // Pi mount hole pattern Y (mm)
pi_standoff = 5; // standoff height screen-rear → Pi PCB (mm)
pi_offset_x = 0; // Pi centre X offset from screen centre (mm)
pi_offset_y = 5; // Pi centre Y offset upward from screen centre (mm)
// ── ENCLOSURE PARAMETERS ─────────────────────────────────────
wall = 4.0; // wall thickness — increased for rigidity (mm)
chamfer = 1.5; // external edge chamfer (mm)
recess = 1.0; // screen recess in front bezel (mm)
gap = 0.3; // bezel ↔ rear cover fit clearance (mm)
// ── VENT PARAMETERS ──────────────────────────────────────────
vent_w = 3; // vent slot width (mm)
vent_l = 20; // vent slot length (mm)
vent_sp = 4; // slot gap edge-to-edge (mm)
soc_vent_sz = 30; // SoC direct-vent area size (mm)
// ── CABLE GLAND PARAMETERS ───────────────────────────────────
gland_count = 2; // number of M16 cable glands
gland_dia = 16.5; // M16 clearance hole diameter (mm)
gland_spacing= 40; // gland centre-to-centre (mm)
// ── KICKSTAND PARAMETERS ─────────────────────────────────────
// Separate removable piece — slides onto case bottom via 3 prongs.
// Wedge shape: thin at rear (prong end), thick at front desk-contact end.
// When flat on desk the screen sits at ks_tilt degrees from horizontal.
ks_tilt = 75; // screen angle from horizontal when standing (deg)
// 75° from horiz ≈ 15° lean-back from vertical
ks_depth = 60; // plate reach in -Z from case rear face (mm)
ks_thick = 5; // plate thickness at thin (rear) end (mm)
// Prong dimensions — 3 prongs slide into 3 slots in case bottom wall
ks_prong_n = 3; // number of prongs
ks_prong_w = 12; // prong width (X, mm)
ks_prong_h = 14; // prong insertion height into cavity (mm)
ks_prong_t = 5; // prong depth (Z, mm) — same as slot depth
ks_prong_clr = 0.25; // diametral clearance for fit (mm)
// ── ASSEMBLY PARAMETERS ──────────────────────────────────────
m3_dia = 3.4; // M3 clearance hole (mm)
m3_cs_dia = 6.5; // M3 countersink diameter (mm)
m3_cs_depth = 3.0; // countersink depth (mm)
insert_dia = 4.2; // M3 heat-set insert OD (mm)
insert_h = 6; // heat-set insert depth (mm)
boss_od = 10; // insert boss outer diameter — prominent (mm)
boss_h = insert_h + 5; // boss total height from inner face (mm)
// ── DERIVED DIMENSIONS ───────────────────────────────────────
rear_d = pi_standoff + pi_d + 10; // cavity depth = 32 mm
enc_w = scr_w + 2*wall; // outer width = 244 mm
enc_h = scr_h + 2*wall; // outer height = 152 mm
enc_d = rear_d + wall; // rear cover depth = 36 mm
// Corner inset for boss/screw centres (keeps them inside the wall)
corner_inset = wall + boss_od/2 + 0.5; // ≈ 9.5 mm
// Pi centre in enclosure coordinates
pi_enc_cx = wall + scr_w/2 + pi_offset_x; // 122 mm
pi_enc_cy = wall + scr_h/2 + pi_offset_y; // 81 mm
pi_z = wall + pi_standoff; // 9 mm (Pi PCB Z from rear face)
// Kickstand geometry
ks_drop = ks_depth * tan(90 - ks_tilt); // ≈ 16 mm tip drop
// Prong slot Z position — prongs sit right at the case rear face
ks_prong_z = 0; // prong rear face flush with case Z=0
$fn = 48;
// ============================================================
// PRIMITIVES
// ============================================================
module cbox(w, h, d, c=chamfer) {
hull() {
translate([c, c, 0]) cube([w-2*c, h-2*c, d ]);
translate([0, c, c]) cube([w, h-2*c, d-2*c]);
translate([c, 0, c]) cube([w-2*c, h, d-2*c]);
}
}
module slot(len, w, d) {
r = w/2;
hull() {
translate([0, -len/2+r, 0]) cylinder(r=r, h=d);
translate([0, len/2-r, 0]) cylinder(r=r, h=d);
}
}
module vent_row(n, len, w, spacing, depth) {
for(i = [0:n-1])
translate([i*(w+spacing), 0, 0])
slot(len, w, depth);
}
// Heat-set insert boss
module insert_boss() {
difference() {
cylinder(d=boss_od, h=boss_h);
cylinder(d=insert_dia, h=insert_h);
translate([0,0,insert_h]) cylinder(d=m3_dia, h=boss_h);
}
}
// Countersunk M3 hole (for bezel face)
module m3_countersunk(depth) {
cylinder(d=m3_dia, h=depth+0.1);
translate([0, 0, depth - m3_cs_depth])
cylinder(d1=m3_dia, d2=m3_cs_dia, h=m3_cs_depth+0.1);
}
// Prong slot — cut from bottom wall, prong inserts up into cavity
module prong_slot() {
translate([-ks_prong_w/2 - ks_prong_clr,
-0.1,
ks_prong_z - ks_prong_clr])
cube([ks_prong_w + 2*ks_prong_clr,
ks_prong_h + wall + 0.2,
ks_prong_t + 2*ks_prong_clr]);
}
// ============================================================
// KICKSTAND (separate removable piece)
// ============================================================
//
// Side view (Y-Z plane, unit standing on kickstand):
//
// Y=0 (case bottom) ─────────────────────────────
// │↑↑↑ prongs (insert into case)
// Y=-ks_thick ─────┼─────────────────────────────────┐
// \ wedge plate (bottom surface │
// \ angled so it lies flat when │
// Y=-(ks_thick+ks_drop)\ screen tilts to ks_tilt) │
// └──────────────────────────────┘
// Z=0 Z=-ks_depth
//
module kickstand() {
ks_front_h = ks_thick + ks_drop; // total height at the front (desk-contact) edge
// Main wedge plate
hull() {
// Rear (thin) edge, at Z=0 — where prongs attach
translate([0, -ks_thick, 0])
cube([enc_w, ks_thick, wall]);
// Front (thick) edge, at Z=-ks_depth — rests on desk
translate([0, -ks_front_h, -ks_depth])
cube([enc_w, ks_front_h, wall]);
}
// Three prongs — evenly spaced, rise from Y=0 into case cavity
for(i = [0:ks_prong_n-1]) {
px = enc_w * (i+1) / (ks_prong_n+1);
translate([px - ks_prong_w/2, 0, ks_prong_z]) {
// Tapered tip so prong slides in easily
hull() {
// Base: full-width prong up to the tapered section
cube([ks_prong_w,
ks_prong_h - 2,
ks_prong_t]);
// Tip: narrowed 1 mm per side for 45° insertion chamfer
translate([1, ks_prong_h - 2, 0])
cube([ks_prong_w - 2, 2, ks_prong_t]);
}
}
}
}
// ============================================================
// FRONT BEZEL
// ============================================================
// Removable front frame — held to rear cover by 4× M3 screws
// through countersunk holes at each corner, threading into
// heat-set inserts pressed into the rear cover's corner bosses.
module front_bezel() {
difference() {
cbox(enc_w, enc_h, wall + recess);
// Active display window
translate([(enc_w - scr_active_w)/2,
(enc_h - scr_active_h)/2,
-0.1])
cube([scr_active_w, scr_active_h, wall+recess+0.2]);
// 1 mm recess pocket — bezel lip grips screen edge
translate([(enc_w - scr_w)/2,
(enc_h - scr_h)/2,
wall])
cube([scr_w, scr_h, recess+0.1]);
// 4× M3 countersunk screw holes at corners
for(x = [corner_inset, enc_w - corner_inset])
for(y = [corner_inset, enc_h - corner_inset])
translate([x, y, 0])
m3_countersunk(wall + recess);
}
}
// ============================================================
// REAR COVER
// ============================================================
module rear_cover() {
n_vent = 6;
vent_block_w = n_vent*(vent_w+vent_sp) - vent_sp;
difference() {
union() {
cbox(enc_w, enc_h, enc_d);
// ── Insert bosses: 4 corners, proud on inner rear face ──
// These are clearly visible tall cylinders that receive the
// heat-set inserts; M3 screws from the bezel thread into them.
for(x = [corner_inset, enc_w - corner_inset])
for(y = [corner_inset, enc_h - corner_inset])
translate([x, y, enc_d])
rotate([180, 0, 0])
insert_boss();
}
// ── HOLLOW INTERIOR ───────────────────────────────────
translate([wall, wall, wall])
cube([scr_w, scr_h, enc_d]);
// ── PORT CUTOUTS ──────────────────────────────────────
// LEFT WALL — USB-C power + HDMI ×2 (Pi left short-edge ports)
pi_bot = pi_enc_cy - pi_h/2;
// USB-C power
translate([-0.1, pi_bot + 3, pi_z + 2]) cube([wall+0.2, 11, 11]);
// HDMI 0
translate([-0.1, pi_bot + 16, pi_z + 2]) cube([wall+0.2, 17, 9]);
// HDMI 1
translate([-0.1, pi_bot + 35, pi_z + 2]) cube([wall+0.2, 17, 9]);
// RIGHT WALL — RJ45 + USB-A ×4 (Pi right short-edge ports)
pi_top = pi_enc_cy + pi_h/2;
// RJ45
translate([enc_w-wall-0.1, pi_top - 24, pi_z + 1])
cube([wall+0.2, 22, 16]);
// USB-A ×4
translate([enc_w-wall-0.1, pi_bot + 2, pi_z + 1])
cube([wall+0.2, 50, 15]);
// NOTE: USB-C touch cutout (screen side) REMOVED per v004 request.
// GPIO header is internal — access by removing bezel + rear cover.
// ── COOLING VENTS ─────────────────────────────────────
// Bottom intake slots (through bottom wall)
translate([enc_w/2 - vent_block_w/2, -0.1, wall + 8])
rotate([-90, 0, 0])
vent_row(n_vent, vent_l, vent_w, vent_sp, wall+0.2);
// Top exhaust slots (through top wall)
translate([enc_w/2 - vent_block_w/2,
enc_h - wall + 0.1,
wall + 8])
rotate([90, 0, 0])
vent_row(n_vent, vent_l, vent_w, vent_sp, wall+0.2);
// SoC direct-vent on rear panel
translate([pi_enc_cx - soc_vent_sz/2,
pi_enc_cy - soc_vent_sz/2,
enc_d - wall - 0.1]) {
n_soc = floor(soc_vent_sz / (vent_w + vent_sp));
for(i = [0:n_soc-1])
translate([i*(vent_w+vent_sp),
soc_vent_sz/2 - vent_l/2,
0])
slot(vent_l, vent_w, wall+0.2);
}
// ── CABLE GLANDS — rear panel, bottom area ────────────
for(i = [0:gland_count-1]) {
cx = enc_w/2 + (i - (gland_count-1)/2) * gland_spacing;
translate([cx, wall + gland_dia/2 + 4, -0.1])
cylinder(d=gland_dia, h=wall+0.2);
}
// ── KICKSTAND PRONG SLOTS — bottom wall ───────────────
// 3 slots matching kickstand prong positions and sizes.
// Slots pass through the bottom wall into the cavity so prongs
// engage wall + (ks_prong_h - wall) mm inside the cavity.
for(i = [0:ks_prong_n-1]) {
px = enc_w * (i+1) / (ks_prong_n+1);
translate([px, 0, ks_prong_z])
prong_slot();
}
}
}
// ============================================================
// SCENE — three separate bodies, exploded for clarity
// ============================================================
// Front bezel — exploded up, face toward viewer
color("DarkSlateGray", 0.92)
translate([0, 0, enc_d + 14])
front_bezel();
// Rear cover — at origin
color("SlateGray", 0.88)
rear_cover();
// Kickstand — exploded below, separate piece
color("DimGray", 0.85)
translate([0, -(ks_thick + ks_drop + 20), 0])
kickstand();