Provide OpenSCAD source, watertight front/back STLs, and print/assembly docs. Co-authored-by: Cursor <cursoragent@cursor.com>
301 lines
8.5 KiB
OpenSCAD
301 lines
8.5 KiB
OpenSCAD
/*
|
||
* CYD ESP32-2432S028R + DHT11 桌面斜立外壳
|
||
* Climate Dashboard Case — parametric OpenSCAD
|
||
*
|
||
* 零件:
|
||
* part = "front" 前框(屏窗)
|
||
* part = "back" 后盖 + 斜立支架 + DHT 通风仓
|
||
* part = "assembly" 装配预览(半透明板子)
|
||
*
|
||
* 导出 STL(本机安装 OpenSCAD 后):
|
||
* openscad -o export/front.stl -D part=\"front\" cyd_climate_case.scad
|
||
* openscad -o export/back.stl -D part=\"back\" cyd_climate_case.scad
|
||
*/
|
||
|
||
/* [Which part] */
|
||
part = "assembly"; // ["front", "back", "assembly"]
|
||
|
||
/* [PCB / CYD] */
|
||
pcb_l = 86.0;
|
||
pcb_w = 50.0;
|
||
pcb_t = 1.6;
|
||
pcb_corner_r = 4.0;
|
||
mh_inset = 4.0; // 安装孔距角边中心
|
||
mh_dia = 3.2; // PCB 孔
|
||
|
||
/* [Display] */
|
||
disp_l = 69.0;
|
||
disp_w = 50.0;
|
||
disp_h = 4.0;
|
||
disp_x = 8.0; // 屏相对 PCB 左边偏移
|
||
view_l = 59.5;
|
||
view_w = 45.0;
|
||
view_inset_x = 7.0; // 相对屏模组
|
||
view_inset_y = 2.5;
|
||
|
||
/* [Case shell] */
|
||
wall = 2.4;
|
||
gap = 0.4; // 板与壳间隙
|
||
front_lip = 1.2; // 屏边压边宽度
|
||
bezel_front_t = 2.0; // 前框面板厚度
|
||
cavity_back = 7.0; // 背面元件净空
|
||
stand_angle = 60; // 桌面倾角(度,相对水平)
|
||
stand_foot = 18; // 支脚接触深度
|
||
|
||
/* [USB dual cutout] */
|
||
usb_dual = true;
|
||
usb_w = 14.0; // 双口合并开孔宽
|
||
usb_h = 8.5;
|
||
usb_y = 30.5; // 相对 PCB 原点(短边为 X=0 侧)
|
||
|
||
/* [Buttons] */
|
||
btn_enable = true;
|
||
btn_dia = 4.5;
|
||
|
||
/* [DHT11 bay] */
|
||
dht_enable = true;
|
||
dht_bay_l = 22;
|
||
dht_bay_w = 18;
|
||
dht_bay_h = 14;
|
||
dht_vent_slot = 1.6;
|
||
dht_vent_gap = 2.8;
|
||
|
||
/* [Screws] */
|
||
screw_m3 = 3.2;
|
||
boss_od = 7.2;
|
||
boss_id = 2.6; // 自攻进塑料
|
||
$fn = 48;
|
||
|
||
// ---- derived ----
|
||
inner_l = pcb_l + 2 * gap;
|
||
inner_w = pcb_w + 2 * gap;
|
||
outer_l = inner_l + 2 * wall;
|
||
outer_w = inner_w + 2 * wall;
|
||
case_h = bezel_front_t + disp_h + pcb_t + cavity_back + wall;
|
||
|
||
mh_pts = [
|
||
[mh_inset, mh_inset],
|
||
[pcb_l - mh_inset, mh_inset],
|
||
[pcb_l - mh_inset, pcb_w - mh_inset],
|
||
[mh_inset, pcb_w - mh_inset]
|
||
];
|
||
|
||
module rounded_rect(l, w, h, r) {
|
||
hull() {
|
||
for (x = [r, l - r], y = [r, w - r])
|
||
translate([x, y, 0]) cylinder(h = h, r = r);
|
||
}
|
||
}
|
||
|
||
module cyd_mock() {
|
||
color("gold")
|
||
difference() {
|
||
rounded_rect(pcb_l, pcb_w, pcb_t, pcb_corner_r);
|
||
for (p = mh_pts)
|
||
translate([p[0], p[1], -0.1])
|
||
cylinder(d = mh_dia, h = pcb_t + 0.2);
|
||
}
|
||
color("black")
|
||
translate([disp_x, 0, pcb_t])
|
||
cube([disp_l, disp_w, disp_h]);
|
||
color("navy")
|
||
translate([disp_x + view_inset_x, view_inset_y, pcb_t + disp_h])
|
||
cube([view_l, view_w, 0.2]);
|
||
}
|
||
|
||
// 前框:从屏面方向看,Z=0 为最前表面
|
||
module front_bezel() {
|
||
view_x = wall + gap + disp_x + view_inset_x;
|
||
view_y = wall + gap + view_inset_y;
|
||
|
||
difference() {
|
||
union() {
|
||
// 前表面
|
||
rounded_rect(outer_l, outer_w, bezel_front_t, 3);
|
||
// 侧壁向下包住屏+PCB 前半
|
||
translate([0, 0, bezel_front_t])
|
||
difference() {
|
||
rounded_rect(outer_l, outer_w, disp_h + pcb_t * 0.5, 3);
|
||
translate([wall, wall, -0.1])
|
||
rounded_rect(inner_l, inner_w, disp_h + pcb_t + 1, 2);
|
||
}
|
||
// 止口(与后盖搭接)
|
||
translate([wall * 0.45, wall * 0.45, bezel_front_t + disp_h + pcb_t * 0.5 - 0.01])
|
||
difference() {
|
||
rounded_rect(outer_l - wall * 0.9, outer_w - wall * 0.9, 2.2, 2.4);
|
||
translate([wall * 0.55, wall * 0.55, -0.1])
|
||
rounded_rect(outer_l - wall * 2.0, outer_w - wall * 2.0, 3, 1.6);
|
||
}
|
||
}
|
||
|
||
// 可视窗
|
||
translate([view_x - 0.3, view_y - 0.3, -0.1])
|
||
cube([view_l + 0.6, view_w + 0.6, bezel_front_t + 1]);
|
||
|
||
// 屏模组沉台(背面)
|
||
translate([wall + gap + disp_x - 0.3, wall + gap - 0.2, bezel_front_t - 0.05])
|
||
cube([disp_l + 0.6, disp_w + 0.4, disp_h + 0.5]);
|
||
|
||
// 螺丝通孔
|
||
for (p = mh_pts)
|
||
translate([wall + gap + p[0], wall + gap + p[1], -0.1])
|
||
cylinder(d = screw_m3 + 0.2, h = case_h);
|
||
}
|
||
|
||
// 压屏边框内侧(窄边)
|
||
difference() {
|
||
translate([wall + gap + disp_x, wall + gap, bezel_front_t])
|
||
cube([disp_l, disp_w, 0.8]);
|
||
translate([view_x - 0.2, view_y - 0.2, bezel_front_t - 0.1])
|
||
cube([view_l + 0.4, view_w + 0.4, 2]);
|
||
}
|
||
}
|
||
|
||
// 后盖主体(不含支架倾转);本地坐标:PCB 底面朝上放置时的壳
|
||
module back_shell_body() {
|
||
shell_h = cavity_back + wall;
|
||
pcb_z = wall + cavity_back; // PCB 底面高度(元件朝下进腔)
|
||
|
||
difference() {
|
||
union() {
|
||
rounded_rect(outer_l, outer_w, shell_h, 3);
|
||
|
||
// 止口凹槽配合前框(外壳顶部一圈台阶)
|
||
translate([0, 0, shell_h - 0.01])
|
||
difference() {
|
||
rounded_rect(outer_l, outer_w, 2.0, 3);
|
||
translate([wall * 0.5, wall * 0.5, -0.05])
|
||
rounded_rect(outer_l - wall, outer_w - wall, 2.5, 2.4);
|
||
}
|
||
|
||
// 螺丝柱
|
||
for (p = mh_pts) {
|
||
translate([wall + gap + p[0], wall + gap + p[1], wall])
|
||
difference() {
|
||
cylinder(d = boss_od, h = cavity_back - 0.2);
|
||
translate([0, 0, 1])
|
||
cylinder(d = boss_id, h = cavity_back);
|
||
}
|
||
}
|
||
|
||
// DHT 通风仓(PCB 长边外侧,靠近 CN1:x≈51)
|
||
if (dht_enable) {
|
||
dht_x = wall + gap + 48;
|
||
dht_y = outer_w - wall * 0.2;
|
||
translate([dht_x, dht_y, wall])
|
||
dht_bay();
|
||
}
|
||
}
|
||
|
||
// 内腔
|
||
translate([wall, wall, wall])
|
||
rounded_rect(inner_l, inner_w, shell_h, 1.8);
|
||
|
||
// USB 开孔(短边 x=0 侧)
|
||
usb_cut_y = wall + gap + usb_y - usb_w / 2;
|
||
translate([-0.1, usb_cut_y, wall + 1.5])
|
||
cube([wall + 1.2, usb_w, usb_h]);
|
||
|
||
// SD 卡槽(可选宽缝)
|
||
translate([wall + gap + 28, outer_w - wall - 0.1, wall + 2])
|
||
cube([16, wall + 1, 3.2]);
|
||
|
||
// BOOT / RST 软按开孔(背面)
|
||
if (btn_enable) {
|
||
translate([wall + gap + 10, wall + gap + 12, -0.1])
|
||
cylinder(d = btn_dia, h = wall + 0.3);
|
||
translate([wall + gap + 10, wall + gap + 22, -0.1])
|
||
cylinder(d = btn_dia, h = wall + 0.3);
|
||
}
|
||
|
||
// 散热缝
|
||
for (i = [0:4])
|
||
translate([wall + 12 + i * 12, wall + 8, -0.1])
|
||
hull() {
|
||
cylinder(d = 2.2, h = wall + 0.3);
|
||
translate([0, 10, 0]) cylinder(d = 2.2, h = wall + 0.3);
|
||
}
|
||
|
||
// DHT 线槽通向 CN1
|
||
if (dht_enable) {
|
||
translate([wall + gap + 48, outer_w - wall - 2, wall + 2])
|
||
cube([8, wall + 4, 4]);
|
||
}
|
||
}
|
||
}
|
||
|
||
module dht_bay() {
|
||
// 局部:仓体贴在 outer 长边外侧
|
||
difference() {
|
||
translate([0, 0, 0])
|
||
rounded_rect(dht_bay_l, dht_bay_w + wall, dht_bay_h, 2);
|
||
translate([wall * 0.6, wall * 0.6, wall * 0.6])
|
||
cube([dht_bay_l - wall * 1.2, dht_bay_w, dht_bay_h]);
|
||
|
||
// 顶面百叶通风
|
||
for (i = [0:4])
|
||
translate([3 + i * dht_vent_gap, dht_bay_w * 0.3, dht_bay_h - wall - 0.1])
|
||
cube([dht_vent_slot, dht_bay_w * 0.55, wall + 0.3]);
|
||
|
||
// 侧面通风
|
||
for (i = [0:2])
|
||
translate([4 + i * 5.5, dht_bay_w + wall - 0.2, 3 + i * 0.2])
|
||
cube([dht_vent_slot, wall + 0.4, 6]);
|
||
}
|
||
}
|
||
|
||
// 带斜立支架的后盖(打印时支脚朝下)
|
||
module back_with_stand() {
|
||
shell_h = cavity_back + wall;
|
||
|
||
// 后盖:PCB 元件朝下;支架使屏幕斜立
|
||
// 组装时:屏幕朝向 -Z 转 stand_angle
|
||
union() {
|
||
back_shell_body();
|
||
|
||
// 三角形支脚(沿 PCB 长边下方)
|
||
stand_len = outer_l * 0.72;
|
||
stand_x = (outer_l - stand_len) / 2;
|
||
// 支脚从后盖底面向后延伸
|
||
translate([stand_x, -stand_foot + 0.5, 0])
|
||
difference() {
|
||
cube([stand_len, stand_foot, shell_h]);
|
||
// 挖空减料
|
||
translate([2, 2, wall])
|
||
cube([stand_len - 4, stand_foot - 2, shell_h]);
|
||
// 斜切贴合桌面视觉(打印可平放)
|
||
translate([-0.1, 0, shell_h])
|
||
rotate([-stand_angle + 90, 0, 0])
|
||
cube([stand_len + 0.2, 40, 40]);
|
||
}
|
||
|
||
// 后支撑肋
|
||
translate([outer_l * 0.5 - 1.2, -stand_foot + 1, wall])
|
||
cube([2.4, stand_foot - 1, shell_h - wall - 1]);
|
||
}
|
||
}
|
||
|
||
module assembly() {
|
||
// 后盖在下
|
||
color("SteelBlue", 0.85) back_with_stand();
|
||
|
||
// PCB:元件朝下坐在腔顶
|
||
translate([wall + gap, wall + gap, wall + cavity_back])
|
||
rotate([180, 0, 0])
|
||
translate([0, -pcb_w, -pcb_t])
|
||
%cyd_mock();
|
||
|
||
// 前框盖上
|
||
translate([0, 0, wall + cavity_back + pcb_t + disp_h + bezel_front_t])
|
||
rotate([180, 0, 0])
|
||
translate([0, -outer_w, 0])
|
||
color("SlateGray", 0.7) front_bezel();
|
||
}
|
||
|
||
if (part == "front")
|
||
front_bezel();
|
||
else if (part == "back")
|
||
back_with_stand();
|
||
else
|
||
assembly();
|