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

355 lines
15 KiB
OpenSCAD
Raw 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 — 7" Capacitive Touchscreen
// Version: 005
//
// ASSEMBLY LOGIC (read before printing):
//
// THREE separate printed parts:
//
// 1. REAR COVER — the main box. Open face points toward screen.
// Four corner TOWERS rise from the open front face; each tower
// has a self-tapping M3 pilot hole that opens toward the screen.
// The kickstand prong columns rise from the inner bottom face.
//
// 2. FRONT BEZEL — the display frame. Four countersunk M3 holes at
// the corners align with the rear cover's tower holes.
// Assembly: lay screen face-down, place rear cover over it,
// lay bezel over the front, drive 4× M3×30 self-tapping screws
// from the bezel face through into the corner towers.
//
// 3. KICKSTAND — separate wedge plate. Slide its 3 prongs upward
// into the 3 slots in the case bottom wall. The prong guide
// columns inside the case prevent the prongs from falling into
// the main cavity and give a solid 14 mm engagement.
//
// Changes vs 004:
// - Screen resized to 164.9 × 124.27 mm (7" 1024×600 capacitive)
// - Corner towers replace insert bosses: visible M3 holes on the
// OPEN front face of the rear cover — no hidden geometry
// - Prong guide columns (nested-difference CSG) give the slots a
// closed ceiling so the kickstand prongs cannot fall through
// - Left-wall USB-C touch cutout permanently removed
// - Wall 4 mm retained
// ============================================================
// ── SCREEN PARAMETERS ───────────────────────────────────────
scr_w = 164.9; // screen outer width (mm)
scr_h = 124.27; // screen outer height (mm)
scr_d = 12; // screen body depth (mm) ← confirm with calipers
scr_active_w = 154; // active display width (mm) ← confirm
scr_active_h = 90; // active display height (mm) ← confirm
scr_mount_x = 75; // rear M2.5 hole pattern X (mm) ← verify
scr_mount_y = 75; // 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: screen rear → Pi PCB (mm)
pi_offset_x = 0; // Pi centre X offset from screen centre (mm)
pi_offset_y = 0; // Pi centre Y offset from screen centre (mm)
// ── ENCLOSURE PARAMETERS ─────────────────────────────────────
wall = 4.0; // wall thickness (mm)
chamfer = 1.5; // external edge chamfer (mm)
recess = 1.0; // screen recess depth in front bezel (mm)
// ── VENT PARAMETERS ──────────────────────────────────────────
vent_w = 3; // slot width (mm)
vent_l = 18; // slot length (mm)
vent_sp = 4; // gap edge-to-edge (mm)
soc_vent_sz = 28; // SoC vent zone (mm, square)
// ── CABLE GLAND PARAMETERS ───────────────────────────────────
gland_count = 2; // number of M16 cable glands
gland_dia = 16.5; // M16 clearance hole diameter (mm)
gland_spacing= 36; // gland centre-to-centre (mm)
// ── KICKSTAND PARAMETERS ─────────────────────────────────────
ks_tilt = 75; // screen angle from horizontal when standing (deg)
ks_depth = 60; // plate reach behind rear face (mm)
ks_thick = 5; // plate thickness at thin (prong) end (mm)
ks_prong_n = 3; // number of prongs
ks_prong_w = 12; // prong width in X (mm)
ks_prong_h = 14; // prong engagement height (mm) — guided inside column
ks_prong_t = 5; // prong thickness in Z (mm)
ks_prong_clr = 0.25; // clearance per side for slide fit (mm)
// ── ASSEMBLY PARAMETERS ──────────────────────────────────────
m3_dia = 3.4; // M3 clearance hole (mm)
m3_pilot = 2.5; // M3 self-tapping pilot hole (mm)
m3_cs_dia = 6.5; // M3 countersink OD (mm)
m3_cs_depth = 3.5; // countersink depth (mm)
// Corner tower — a full-depth solid pillar at each inner corner.
// The M3 pilot hole is drilled from the open front face of the rear cover.
tower_w = 10; // tower footprint width and depth (mm)
tower_hole_d = 12; // M3 pilot hole depth from front face (mm)
// ── DERIVED DIMENSIONS ───────────────────────────────────────
rear_d = pi_standoff + pi_d + 10; // rear cavity depth = 32 mm
enc_w = scr_w + 2*wall; // outer width = 172.9 mm
enc_h = scr_h + 2*wall; // outer height = 132.27 mm
enc_d = rear_d + wall; // rear cover depth = 36 mm
// Pi centre in enclosure coordinates
pi_enc_cx = wall + scr_w/2 + pi_offset_x;
pi_enc_cy = wall + scr_h/2 + pi_offset_y;
pi_z = wall + pi_standoff; // Pi PCB Z from rear face
// Corner tower position — inset so tower is entirely within the wall zone
// (tower must NOT overlap the screen footprint X=wall..wall+scr_w)
tower_cx = wall/2; // tower centre offset from outer edge
// Four tower centre positions
tower_xs = [tower_cx, enc_w - tower_cx];
tower_ys = [tower_cx, enc_h - tower_cx];
// Kickstand wedge geometry
ks_drop = ks_depth * tan(90 - ks_tilt); // tip drop ≈ 16 mm
// Prong column Z extent (guide column behind and into cavity)
col_z_size = ks_prong_t + 2*wall; // = 13 mm
col_y_size = ks_prong_h; // = 14 mm (above inner bottom face)
col_x_size = ks_prong_w + wall; // = 16 mm (centred on prong)
$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);
}
// Countersunk M3 through-hole for bezel face
module m3_countersunk(total_depth) {
cylinder(d=m3_dia, h=total_depth+0.1);
cylinder(d1=m3_cs_dia, d2=m3_dia, h=m3_cs_depth+0.1);
}
// Prong slot cutter — used in both the rear cover and the guide column
// Origin at the prong centre-X, outer bottom face (Y=0), prong-Z start
module prong_slot_cut() {
translate([-ks_prong_w/2 - ks_prong_clr,
-0.1,
-ks_prong_clr])
cube([ks_prong_w + 2*ks_prong_clr,
wall + ks_prong_h + 0.2,
ks_prong_t + 2*ks_prong_clr]);
}
// ============================================================
// KICKSTAND (separate removable piece, print separately)
// ============================================================
module kickstand() {
ks_front_h = ks_thick + ks_drop; // height at the thick/front end
// Wedge plate — thin at prong end (Z=0), thick at desk end (Z=-ks_depth)
hull() {
translate([0, -ks_thick, 0])
cube([enc_w, ks_thick, wall]);
translate([0, -ks_front_h, -ks_depth])
cube([enc_w, ks_front_h, wall]);
}
// Three tapered prongs on the top edge (rear/thin end)
for(i = [0:ks_prong_n-1]) {
px = enc_w * (i+1) / (ks_prong_n+1);
translate([px - ks_prong_w/2, 0, 0]) {
// Body of prong
cube([ks_prong_w, ks_prong_h - 2, ks_prong_t]);
// Tapered tip (last 2 mm, narrowed 1 mm per side)
translate([0, ks_prong_h - 2, 0])
hull() {
cube([ks_prong_w, 0.01, ks_prong_t]);
translate([1, 2, 0])
cube([ks_prong_w - 2, 0.01, ks_prong_t]);
}
}
}
}
// ============================================================
// FRONT BEZEL (removable — 4× M3 countersunk screws)
// ============================================================
module front_bezel() {
difference() {
cbox(enc_w, enc_h, wall + recess);
// 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, aligned to corner towers
for(x = tower_xs) for(y = tower_ys)
translate([x, y, 0])
m3_countersunk(wall + recess);
}
}
// ============================================================
// REAR COVER
// ============================================================
//
// CORNER TOWER DESIGN — replaces hidden insert bosses:
// Each corner has a solid square tower (tower_w × tower_w) that
// runs the FULL DEPTH of the cavity (from inner rear face to the
// open front at Z=enc_d). An M3 pilot hole enters from the front
// face (Z=enc_d) and goes tower_hole_d into the tower body.
// Because the tower reaches the front opening, the holes are
// plainly visible from the front of the assembled unit — no
// hidden geometry.
//
// PRONG COLUMN DESIGN — prevents prongs falling into cavity:
// A solid rectangular column rises from the inner bottom face at
// each prong position. The prong slot cuts through the bottom wall
// AND the column. The column ceiling is at Y=wall+ks_prong_h,
// which acts as the hard stop for the prong — it cannot travel
// beyond that height. The column is added AFTER the main interior
// hollow is subtracted (nested-difference CSG), so the hollow
// does not remove it.
//
module rear_cover() {
n_vent = 5;
vent_block_w = n_vent*(vent_w+vent_sp) - vent_sp;
difference() {
// ── SOLID GEOMETRY ────────────────────────────────────
union() {
// 1. Main shell with interior already removed
// (nested so subsequent additions are NOT removed by hollow)
difference() {
cbox(enc_w, enc_h, enc_d);
// Interior hollow — from rear inner face to front opening
translate([wall, wall, wall])
cube([scr_w, scr_h, enc_d]);
}
// 2. Corner towers — full cavity height, clearly visible from front
for(x = tower_xs) for(y = tower_ys)
translate([x - tower_w/2, y - tower_w/2, wall])
cube([tower_w, tower_w, enc_d - wall]);
// 3. Prong guide columns — solid pillars on inner bottom face
// One per prong, gives 14 mm of guided engagement
for(i = [0:ks_prong_n-1]) {
px = enc_w * (i+1) / (ks_prong_n+1);
translate([px - col_x_size/2,
wall,
0])
cube([col_x_size, col_y_size, col_z_size]);
}
}
// ── ALL CUTOUTS ───────────────────────────────────────
// Corner tower M3 pilot holes (from front/open face, going inward)
for(x = tower_xs) for(y = tower_ys)
translate([x, y, enc_d + 0.1])
rotate([180, 0, 0])
cylinder(d=m3_pilot, h=tower_hole_d);
// ── PORT CUTOUTS ──────────────────────────────────────
pi_bot = pi_enc_cy - pi_h/2;
pi_top = pi_enc_cy + pi_h/2;
// LEFT WALL — USB-C power + HDMI ×2
translate([-0.1, pi_bot + 3, pi_z + 2]) cube([wall+0.2, 11, 11]);
translate([-0.1, pi_bot + 16, pi_z + 2]) cube([wall+0.2, 17, 9]);
translate([-0.1, pi_bot + 35, pi_z + 2]) cube([wall+0.2, 17, 9]);
// RIGHT WALL — RJ45 + USB-A ×4
translate([enc_w-wall-0.1, pi_top - 24, pi_z + 1])
cube([wall+0.2, 22, 16]);
translate([enc_w-wall-0.1, pi_bot + 2, pi_z + 1])
cube([wall+0.2, 50, 15]);
// ── COOLING VENTS ─────────────────────────────────────
// Bottom intake
translate([enc_w/2 - vent_block_w/2, -0.1, wall + 6])
rotate([-90, 0, 0])
vent_row(n_vent, vent_l, vent_w, vent_sp, wall+0.2);
// Top exhaust
translate([enc_w/2 - vent_block_w/2, enc_h - wall + 0.1, wall + 6])
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 face ────────────────────
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 ─────────────────────────────
// Each slot cuts through the outer bottom wall AND the guide
// column above it. The column ceiling at Y=wall+ks_prong_h
// is the hard stop — the prong cannot fall through.
for(i = [0:ks_prong_n-1]) {
px = enc_w * (i+1) / (ks_prong_n+1);
translate([px, 0, 0])
prong_slot_cut();
}
}
}
// ============================================================
// SCENE — three parts exploded for visual clarity
// ============================================================
// FRONT BEZEL — floated forward (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 — floated below the case to show it is a separate piece
color("DimGray", 0.85)
translate([0, -(ks_thick + ks_drop + 20), 0])
kickstand();