pre-bemis

This commit is contained in:
Marcelo
2026-04-22 05:04:19 +00:00
parent ac1a7900c8
commit 80d27f83b6
91 changed files with 11769 additions and 820 deletions

View File

@@ -0,0 +1,338 @@
// ============================================================
// 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();