Public Access
Compare commits
2
Commits
main
...
enclosure-frame
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b28ee2892a | ||
|
|
ab5844ce98 |
No files matched your search
@@ -99,6 +99,7 @@ home_assistant/packages/ el512_panel.yaml: helper sensors for the ESPHome pages
|
|||||||
tools/ import_still_alive.py, konosuba_sprites.py, steins_sprites.py,
|
tools/ import_still_alive.py, konosuba_sprites.py, steins_sprites.py,
|
||||||
trek_sprites.py, yourname_sprites.py, render_pages.py
|
trek_sprites.py, yourname_sprites.py, render_pages.py
|
||||||
(+ render/: PC renderer)
|
(+ render/: PC renderer)
|
||||||
|
enclosure/ el512_frame.scad: 3D-printed insert for a 250x200x30 photo frame
|
||||||
test/ unit tests (placeholder)
|
test/ unit tests (placeholder)
|
||||||
docs/ datasheet and notes
|
docs/ datasheet and notes
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -0,0 +1,280 @@
|
|||||||
|
// Skeleton insert for a 250 x 200 x 30 mm photo frame: holds the Planar EL512.256-H
|
||||||
|
// near the top and a Wemos D1 mini ESP32 below it, visible through the glass.
|
||||||
|
//
|
||||||
|
// Panel dimensions are from the datasheet (docs/datasheet, Table 9, Fig. 7), which wins
|
||||||
|
// over anything else here: PCB 233 x 136 mm, depth 16.5 mm, four M3 insert nuts
|
||||||
|
// (2.5 mm deep) on a 222.4 x 124.0 mm grid, insert nut tops 8.5 mm behind the front.
|
||||||
|
// The panel is the bare version (no FRA/FRB mounting frame).
|
||||||
|
//
|
||||||
|
// Coordinates: X to the right and Y up as seen from the front, Z towards the viewer.
|
||||||
|
// The part prints as modelled: back face (z = 0) on the bed, no supports.
|
||||||
|
//
|
||||||
|
// Stack inside the photo frame, front to back:
|
||||||
|
// photo glass | gap | panel (16.5) | >= 5 mm air gap | truss plate | backboard
|
||||||
|
// The rim touches the glass and the plate touches the backboard, so the backboard
|
||||||
|
// clamps the whole insert in place.
|
||||||
|
|
||||||
|
/* [Photo frame] */
|
||||||
|
frame_w = 245; // inside width of the photo frame
|
||||||
|
frame_h = 194; // inside height
|
||||||
|
frame_depth = 30; // inside depth, glass included
|
||||||
|
glass_t = 2; // photo glass thickness
|
||||||
|
backboard_t = 3; // backboard thickness (keep it, but drill vent holes)
|
||||||
|
fit = 0.6; // total clearance per axis against the frame
|
||||||
|
|
||||||
|
/* [Panel, datasheet Table 9 / Fig. 7] */
|
||||||
|
pcb_w = 233;
|
||||||
|
pcb_h = 136;
|
||||||
|
panel_d = 16.5; // front of panel glass to tallest part on the back
|
||||||
|
hole_dx = 222.4; // insert nut grid
|
||||||
|
hole_dy = 124.0;
|
||||||
|
nut_top = 8.5; // front of panel to top of the insert nuts
|
||||||
|
insert_depth = 2.5; // M3 thread depth in the nuts
|
||||||
|
air_gap = 5; // recommended free space behind the panel
|
||||||
|
glass_gap = 0.5; // photo glass to panel front, so the EL glass is not pressed
|
||||||
|
top_margin = 10; // frame inside top edge to panel PCB top edge
|
||||||
|
|
||||||
|
/* [Screws] */
|
||||||
|
// The heads sit below the back face, so the back stays flat against the backboard.
|
||||||
|
head_type = "socket"; // [countersunk:ISO 10642 / DIN 7991 90 degree, socket:ISO 4762]
|
||||||
|
screw_len = 0; // nominal length (countersunk: overall, head included); 0 = longest that fits
|
||||||
|
screw_engage = 2; // thread engagement in the insert nut, < insert_depth
|
||||||
|
m3_clear = 3.4;
|
||||||
|
csk_d = 6.9; // countersink diameter (M3 head 6.72 max)
|
||||||
|
socket_d = 6.2; // counterbore for a socket head (5.5 max)
|
||||||
|
socket_h = 3.0; // socket head height
|
||||||
|
hole_slot = 1.5; // extra hole length in X to absorb measuring differences
|
||||||
|
|
||||||
|
/* [Truss] */
|
||||||
|
plate_t = 3; // plate thickness
|
||||||
|
wall = 2; // rim wall thickness
|
||||||
|
border = 7; // solid band around the edge, rim included
|
||||||
|
cell = 26; // triangle side length
|
||||||
|
strut = 3.5; // strut width
|
||||||
|
fillet = 1.2; // corner rounding inside the cells
|
||||||
|
standoff_d = 9;
|
||||||
|
|
||||||
|
/* [D1 mini ESP32] */
|
||||||
|
d1_l = 39.0; // along the USB axis
|
||||||
|
d1_w = 31.4;
|
||||||
|
d1_t = 1.2; // PCB thickness
|
||||||
|
d1_glass_gap = 7; // photo glass to the board's top face (ESP32 module is ~3.2 high)
|
||||||
|
d1_rot = 0; // 0: USB to the right, 180: USB to the left
|
||||||
|
d1_clear = 0.3; // clearance around the board
|
||||||
|
d1_ledge = 2; // seat width under the short ends (the pin rows run along the long sides)
|
||||||
|
d1_arm_t = 0.8; // snap arm thickness (two 0.4 mm perimeters)
|
||||||
|
d1_arm_l = 12; // snap arm free length, root to tip
|
||||||
|
d1_arm_gap = 0.5; // snap arm to the end of the pocket
|
||||||
|
d1_lip = 0.8; // how far the snap lip reaches over the board
|
||||||
|
d1_lip_w = 3; // snap lip length along the arm
|
||||||
|
d1_usb_w = 11; // kept free between the arms at each end for the USB plug
|
||||||
|
d1_wall = 1.6;
|
||||||
|
|
||||||
|
/* [Preview] */
|
||||||
|
show_parts = true; // ghosts of the panel and the D1 mini (preview only)
|
||||||
|
|
||||||
|
$fn = 48;
|
||||||
|
eps = 0.01;
|
||||||
|
|
||||||
|
// ---------- derived ----------
|
||||||
|
W = frame_w - fit;
|
||||||
|
H = frame_h - fit;
|
||||||
|
part_d = frame_depth - glass_t - backboard_t; // total insert depth
|
||||||
|
|
||||||
|
panel_front = part_d - glass_gap; // z of the panel front
|
||||||
|
nut_z = panel_front - nut_top; // z of the insert nut tops
|
||||||
|
panel_back = panel_front - panel_d; // z of the tallest panel part
|
||||||
|
csk = head_type == "countersunk";
|
||||||
|
// longest standard M3 length whose head stays below the back face
|
||||||
|
std_len = [6, 8, 10, 12, 14, 16, 18, 20, 25, 30];
|
||||||
|
max_len = nut_z + screw_engage - (csk ? 0.3 : socket_h + 0.2);
|
||||||
|
fits = [for (l = std_len) if (l <= max_len) l];
|
||||||
|
screw = screw_len > 0 ? screw_len : fits[len(fits) - 1];
|
||||||
|
head_sink = nut_z + screw_engage - screw; // back face to the top of the screw head
|
||||||
|
|
||||||
|
pcb_x0 = (W - pcb_w) / 2;
|
||||||
|
pcb_y1 = H - top_margin;
|
||||||
|
pcb_y0 = pcb_y1 - pcb_h;
|
||||||
|
pcb_cx = W / 2;
|
||||||
|
pcb_cy = (pcb_y0 + pcb_y1) / 2;
|
||||||
|
|
||||||
|
holes = [for (sx = [-1, 1], sy = [-1, 1]) [pcb_cx + sx * hole_dx / 2, pcb_cy + sy * hole_dy / 2]];
|
||||||
|
|
||||||
|
d1_cx = W / 2;
|
||||||
|
d1_cy = (border + pcb_y0) / 2;
|
||||||
|
d1_top = part_d - d1_glass_gap; // z of the board's top face
|
||||||
|
d1_seat = d1_top - d1_t; // z of the board's bottom face
|
||||||
|
d1_in_l = d1_l + 2 * d1_clear;
|
||||||
|
d1_in_w = d1_w + 2 * d1_clear;
|
||||||
|
d1_flex = d1_clear + d1_lip; // worst-case arm deflection while snapping in
|
||||||
|
d1_arm_x = d1_in_l / 2 + d1_arm_gap; // inner face of the snap arms
|
||||||
|
d1_x_out = d1_arm_x + d1_arm_t + d1_flex + 0.4; // outer edge of the slot the arms flex into
|
||||||
|
d1_root = d1_in_w / 2 + d1_wall; // y of the arm roots
|
||||||
|
d1_tip = d1_root - d1_arm_l; // y of the arm tips
|
||||||
|
d1_catch = d1_top + 0.1; // z of the underside of the lips
|
||||||
|
// bending strain at the arm root with the lip pushed fully out
|
||||||
|
d1_strain = 1.5 * d1_arm_t * d1_flex / pow(d1_arm_l - d1_lip_w / 2, 2);
|
||||||
|
|
||||||
|
assert(pcb_x0 >= wall + 1, "panel does not fit the frame width");
|
||||||
|
assert(pcb_y0 - border >= 2 * (d1_root + d1_wall) + 2, "no room below the panel for the D1 mini");
|
||||||
|
assert(d1_tip >= d1_usb_w / 2, "snap arms reach into the USB plug's way: shorten d1_arm_l");
|
||||||
|
assert(d1_strain <= 0.015, str("snap arms strained ", d1_strain * 100, " %, too much for PLA"));
|
||||||
|
assert(panel_back - plate_t >= air_gap, "less than the recommended air gap behind the panel");
|
||||||
|
assert(screw_engage < insert_depth, "screw would bottom out in the insert nut");
|
||||||
|
assert(head_sink >= (csk ? 0.3 : socket_h + 0.2),
|
||||||
|
str("screw head would stick out of the back: use M3x", floor(max_len), " or shorter"));
|
||||||
|
assert(head_sink <= nut_z - 4, "screw_len too short for this stack");
|
||||||
|
|
||||||
|
echo(str("Insert depth ", part_d, " mm, air gap behind panel ", panel_back - plate_t,
|
||||||
|
" mm, standoff height ", nut_z - plate_t, " mm, use M3x", screw, " ", head_type,
|
||||||
|
" (head ", head_sink, " mm below the back face), snap arm strain ",
|
||||||
|
round(d1_strain * 1000) / 10, " %"));
|
||||||
|
|
||||||
|
// ---------- 2D ----------
|
||||||
|
module outline() square([W, H]);
|
||||||
|
|
||||||
|
module d1_footprint(grow = 0) {
|
||||||
|
translate([d1_cx, d1_cy]) rotate(d1_rot)
|
||||||
|
square([2 * (d1_x_out + 1 + grow), 2 * (d1_root + d1_wall + grow)], center = true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triangle cells; a horizontal strut runs along the panel's bottom edge and a vertex
|
||||||
|
// sits on the centre line, so the pattern is symmetric.
|
||||||
|
module tri_cells() {
|
||||||
|
h = cell * sqrt(3) / 2;
|
||||||
|
x0 = W / 2 - cell * ceil(W / 2 / cell) - cell;
|
||||||
|
y0 = pcb_y0 - h * ceil(pcb_y0 / h) - h;
|
||||||
|
for (j = [0 : ceil(H / h) + 2], k = [0 : 2 * ceil(W / cell) + 4]) {
|
||||||
|
x = x0 + k * cell / 2;
|
||||||
|
y = y0 + j * h;
|
||||||
|
up = (k + j) % 2 == 0;
|
||||||
|
pts = up ? [[x, y], [x + cell, y], [x + cell / 2, y + h]]
|
||||||
|
: [[x, y + h], [x + cell, y + h], [x + cell / 2, y]];
|
||||||
|
offset(r = fillet) offset(delta = -(strut / 2 + fillet)) polygon(pts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module plate_2d() {
|
||||||
|
difference() {
|
||||||
|
outline();
|
||||||
|
// the opening drops slivers of cells clipped by the border and the pads
|
||||||
|
offset(r = 1.5) offset(delta = -1.5) difference() {
|
||||||
|
intersection() {
|
||||||
|
offset(delta = -border) outline();
|
||||||
|
tri_cells();
|
||||||
|
}
|
||||||
|
// solid pads under the standoffs and the D1 mini cradle
|
||||||
|
for (p = holes) translate(p) circle(d = standoff_d + 8);
|
||||||
|
d1_footprint(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- 3D ----------
|
||||||
|
module rim() {
|
||||||
|
linear_extrude(part_d) difference() {
|
||||||
|
outline();
|
||||||
|
offset(delta = -wall) outline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module standoff(p) {
|
||||||
|
translate(p) {
|
||||||
|
cylinder(d = standoff_d, h = nut_z);
|
||||||
|
cylinder(d1 = standoff_d + 6, d2 = standoff_d, h = plate_t + 3); // base fillet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module slot() hull() for (s = [-1, 1]) translate([s * hole_slot / 2, 0, 0]) children();
|
||||||
|
|
||||||
|
// Slotted screw hole. Countersunk: the head's top face sits head_sink below the back
|
||||||
|
// face. Socket head: its bearing face sits head_sink deep, the head in a counterbore.
|
||||||
|
module screw_cut(p) translate(p) {
|
||||||
|
slot() translate([0, 0, -1]) cylinder(d = m3_clear, h = nut_z + 2);
|
||||||
|
if (csk) {
|
||||||
|
slot() translate([0, 0, -1]) cylinder(d = csk_d, h = head_sink + 1);
|
||||||
|
slot() translate([0, 0, head_sink - eps])
|
||||||
|
cylinder(d1 = csk_d, d2 = m3_clear, h = (csk_d - m3_clear) / 2); // 90 degrees
|
||||||
|
} else {
|
||||||
|
slot() translate([0, 0, -1]) cylinder(d = socket_d, h = head_sink + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cradle for the D1 mini, board face up towards the glass. It rests on ledges under its
|
||||||
|
// short ends and four snap arms hold it down; the pin rows hang free over the hollow
|
||||||
|
// inside. The upper long wall has a slot for the wires to the panel.
|
||||||
|
//
|
||||||
|
// The snap arms run along the short ends, anchored at the corners with the lip at the
|
||||||
|
// free end, and bend sideways: the strain runs along the printed perimeters instead of
|
||||||
|
// across the layers, so they hold up in PLA. Each arm stands on the bed in a slot through
|
||||||
|
// the plate. The arms leave d1_usb_w free in the middle of each end for the USB plug.
|
||||||
|
module d1_place() translate([d1_cx, d1_cy, 0]) rotate(d1_rot) children();
|
||||||
|
module d1_quadrants() for (mx = [0, 1], my = [0, 1]) mirror([mx, 0, 0]) mirror([0, my, 0]) children();
|
||||||
|
|
||||||
|
module d1_cradle() d1_place() {
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
// long walls, flush with the board's top face
|
||||||
|
for (s = [-1, 1]) translate([-d1_in_l / 2, s > 0 ? d1_in_w / 2 : -d1_in_w / 2 - d1_wall, 0])
|
||||||
|
cube([d1_in_l, d1_wall, d1_top]);
|
||||||
|
// seat ledges under the short ends
|
||||||
|
for (s = [-1, 1]) translate([s > 0 ? d1_in_l / 2 - d1_ledge : -d1_in_l / 2, -d1_in_w / 2, 0])
|
||||||
|
cube([d1_ledge, d1_in_w, d1_seat]);
|
||||||
|
// arm anchors, outside the long walls at the corners
|
||||||
|
d1_quadrants() translate([d1_in_l / 2 - 2, d1_root - eps, 0])
|
||||||
|
cube([d1_x_out + 1 - (d1_in_l / 2 - 2), d1_wall + eps, d1_top]);
|
||||||
|
}
|
||||||
|
// wire slot towards the panel
|
||||||
|
translate([-10, d1_in_w / 2 - eps, plate_t]) cube([20, d1_wall + 2 * eps, d1_seat - plate_t - 2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slots through the plate that free the arms from everything but their anchors.
|
||||||
|
module d1_arm_slots() d1_place() d1_quadrants()
|
||||||
|
translate([d1_in_l / 2, d1_tip - 0.6, -1]) cube([d1_x_out - d1_in_l / 2, d1_root - d1_tip + 0.6, plate_t + 2]);
|
||||||
|
|
||||||
|
// The lip has a 45 degree chamfer underneath across the gap to the pocket, so only the
|
||||||
|
// catch itself (clearance + d1_lip) is a flat overhang, and a blunt tip.
|
||||||
|
module d1_arms() d1_place() d1_quadrants() {
|
||||||
|
t = d1_arm_t;
|
||||||
|
g = d1_arm_gap;
|
||||||
|
reach = g + d1_clear + d1_lip; // arm face to lip tip
|
||||||
|
tip_h = 0.6;
|
||||||
|
translate([d1_arm_x, d1_tip, 0]) cube([t, d1_arm_l + eps, d1_catch]);
|
||||||
|
translate([d1_arm_x + t, d1_tip + d1_lip_w, d1_catch]) rotate([90, 0, 0])
|
||||||
|
linear_extrude(d1_lip_w) polygon([
|
||||||
|
[0, -g], [-t, -g], // chamfer starts on the arm face
|
||||||
|
[-t - g, 0], // 45 degrees across the gap
|
||||||
|
[-t - reach, 0], // flat catch over the board
|
||||||
|
[-t - reach, tip_h], // blunt tip
|
||||||
|
[-t, tip_h + reach], // 45 degree lead-in
|
||||||
|
[0, tip_h + reach]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
module frame() {
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
linear_extrude(plate_t) plate_2d();
|
||||||
|
rim();
|
||||||
|
for (p = holes) standoff(p);
|
||||||
|
d1_cradle();
|
||||||
|
}
|
||||||
|
for (p = holes) screw_cut(p);
|
||||||
|
d1_arm_slots();
|
||||||
|
}
|
||||||
|
d1_arms();
|
||||||
|
}
|
||||||
|
|
||||||
|
module ghosts() {
|
||||||
|
// panel: PCB and glass block, front at panel_front
|
||||||
|
color("dimgray", 0.35) translate([pcb_x0, pcb_y0, panel_back]) cube([pcb_w, pcb_h, panel_d]);
|
||||||
|
color("orange", 0.5) translate([pcb_cx - 97.55, pcb_cy - 48.75, panel_front - 0.2]) cube([195.1, 97.5, 0.2]);
|
||||||
|
// D1 mini
|
||||||
|
color("royalblue", 0.5) translate([d1_cx, d1_cy, d1_seat]) rotate(d1_rot)
|
||||||
|
translate([-d1_l / 2, -d1_w / 2, 0]) cube([d1_l, d1_w, d1_t]);
|
||||||
|
// photo glass
|
||||||
|
color("lightblue", 0.15) translate([0, 0, part_d]) cube([W, H, glass_t]);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame();
|
||||||
|
if (show_parts && $preview) %ghosts();
|
||||||
Reference in new issue
Block a user