diff --git a/README.md b/README.md index bbe09f1..696238e 100644 --- a/README.md +++ b/README.md @@ -91,3 +91,4 @@ README.md # 本文档 | 2026-10-17 | 增加浏览器 Three.js STL 预览页 `cad/viewer.html` | | 2026-10-17 | 预览增强:合盖/开盖、分解、装配动画、剖切/线框等 | | 2026-10-17 | 外壳改定:DHT11 后盖卡位微突出;前后盖止口合盖 | +| 2026-10-17 | 去掉旁侧多余凸块;修复合盖对齐;DHT 改为后盖平面卡位 | diff --git a/cad/README.md b/cad/README.md index bfaddf5..e95b16b 100644 --- a/cad/README.md +++ b/cad/README.md @@ -1,13 +1,21 @@ # CYD 温湿度仪表盘 3D 外壳 -桌面斜立分体外壳,适配 **ESP32-2432S028R(CYD)** + **DHT11**。 +## 结构说明(当前版) -## 设计要点(当前) +只有两件:**前框** + **后盖**。 -- **DHT11 在后盖外侧**:卡位槽 + 左右卡舌 + 前端止挡,模块从背面按入 -- **传感器微突出**约 **1.8 mm**(通风口/探头露出后盖平面) -- **前后盖合盖**:前框公止口落入后盖母槽;可用 `4×M3×10` 辅助固定 -- USB 侧孔、BOOT/RST 开孔、桌面支脚 +| 部位 | 作用 | +|------|------| +| 前框 | 屏窗;公止口,合盖时插入后盖 | +| 后盖 | 装板子;母止口;**背面中心 DHT11 卡位通风口**(探头微突出约 1.6mm) | +| DHT 示意 | 预览里蓝色/灰块,表示传感器装在后盖背面卡位里 | + +**没有**外壳旁边的大“格子”。旧版里那两块是:侧向支脚块、外挂 DHT 仓——已删除,避免误解。 + +## 合盖 + +前框止口落入后盖槽;预览默认合盖(开合度 0%)。 +对齐数据在 `export/mate.json`。 ## 浏览器预览 @@ -15,41 +23,19 @@ python -m http.server 8765 --directory cad ``` -打开:**http://localhost:8765/viewer.html** +打开 http://localhost:8765/viewer.html (请 **Ctrl+F5** 强制刷新) -| 操作 | 说明 | -|------|------| -| 合盖 / 开盖 | 前框相对后盖开合 | -| 开合度 / 分解 | 拖动查看止口与 DHT 仓 | -| 看后盖 | 快速转到背面看 DHT 突出 | -| 模拟屏板 / DHT11模块 | 示意件开关 | -| 快捷键 | `C` 合盖 · `O` 开盖 · `空格` 播放装配 | +- `C` 合盖 · `O` 开盖 · `空格` 播放 +- 「看后盖/DHT」查看背面微凸通风口 -## 零件 - -| 文件 | 说明 | -|------|------| -| `export/front.stl` | 前框(屏窗 + 公止口) | -| `export/back.stl` | 后盖(母止口 + DHT 卡位仓 + 支脚) | -| `generate_stl.py` | Python 生成 STL | -| `cyd_climate_case.scad` | OpenSCAD 参数源 | -| `viewer.html` | 交互预览 | - -## 重新导出 +## 导出 STL ```bash pip install trimesh manifold3d numpy python cad/generate_stl.py ``` -## 打印 - -PLA/PETG,0.2 mm,墙 2–3 圈,填充 15–20%,一般无需支撑。 -后盖建议 **外底朝下**(DHT 仓朝上或按切片预览,必要时对 DHT 卡舌加少量支撑)。 - ## 装配 -1. 将 DHT11 模块从 **后盖背面** 按入卡位,探头朝外微突出;线经仓内小孔接到 CN1(GPIO22) -2. CYD 放入后盖腔体,USB 对齐 -3. 前框止口对准后盖槽 **合盖**,四角螺丝固定 -4. 桌面斜立使用 +1. DHT11 从**后盖背面**按入中心卡位,探头朝外略突出,线进腔内接 CN1/GPIO22 +2. CYD 放入后盖,前框合盖,四角 M3×10 可选固定 diff --git a/cad/export/back.stl b/cad/export/back.stl index 3bb6f18..6d61b39 100644 Binary files a/cad/export/back.stl and b/cad/export/back.stl differ diff --git a/cad/export/front.stl b/cad/export/front.stl index bfdb986..654522b 100644 Binary files a/cad/export/front.stl and b/cad/export/front.stl differ diff --git a/cad/export/mate.json b/cad/export/mate.json new file mode 100644 index 0000000..fe8bfe0 --- /dev/null +++ b/cad/export/mate.json @@ -0,0 +1,8 @@ +{ + "outer_l": 91.5, + "outer_w": 55.5, + "front_body_h": 7.2, + "back_body_h": 10.4, + "lip_h": 2.2, + "dht_proud": 1.6 +} diff --git a/cad/generate_stl.py b/cad/generate_stl.py index c76a900..8ef61ce 100644 --- a/cad/generate_stl.py +++ b/cad/generate_stl.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 """ -CYD climate case STL generator. +CYD climate case — clean clamshell. -Design intent: - - DHT11 on the BACK cover, held by snap/clip posts (卡位), tip slightly proud of back face - - Front + back close with a interlocking lip (合盖) +- Front: screen bezel + male lip +- Back: cavity + female groove + DHT11 snap pocket flush in back wall (tip proud ~1.6mm) +- No side “boxes”: removed bulky stand block and external DHT hang-on bay """ from __future__ import annotations @@ -12,32 +12,31 @@ from __future__ import annotations from pathlib import Path import trimesh -from trimesh.creation import box, cylinder # noqa: F401 — cylinder used for holes/bosses +from trimesh.creation import box, cylinder -# ---- mm ---- PCB_L, PCB_W = 86.0, 50.0 MH_INSET = 4.0 DISP_X, DISP_L, DISP_W, DISP_H = 8.0, 69.0, 50.0, 4.0 VIEW_L, VIEW_W, VIEW_IX, VIEW_IY = 59.5, 45.0, 7.0, 2.5 WALL, GAP = 2.4, 0.35 -BEZEL_T, CAVITY = 2.2, 7.5 -LIP_H, LIP_T = 2.4, 1.15 # front male / back female for 合盖 +BEZEL_T = 2.2 +CAVITY = 8.0 +LIP_H, LIP_CLEAR = 2.2, 0.2 USB_W, USB_H, USB_Y = 15.0, 9.0, 30.5 -STAND_FOOT = 16.0 -SCREW = 3.3 -BOSS_OD, BOSS_ID = 7.0, 2.5 +SCREW, BOSS_OD, BOSS_ID = 3.3, 7.0, 2.5 -# DHT11 module (common PCB module ~15.5 x 12 x 7.5 + pins) -DHT_MOD_L, DHT_MOD_W, DHT_MOD_H = 16.0, 12.5, 8.0 -DHT_PROUD = 1.8 # how much grill/tip sticks out past back outer face -DHT_CLIP = 1.1 # undercut lip thickness for 卡位 +# DHT11 module pocket (from OUTSIDE of back face z=0) +DHT_L, DHT_W, DHT_H = 16.0, 12.5, 7.5 +DHT_PROUD = 1.6 INNER_L = PCB_L + 2 * GAP INNER_W = PCB_W + 2 * GAP OUTER_L = INNER_L + 2 * WALL OUTER_W = INNER_W + 2 * WALL -SHELL_H = CAVITY + WALL -SKIRT_H = DISP_H + 1.0 +SKIRT = DISP_H + 1.0 +# Back total height to mating plane (top of female groove floor) +BACK_BODY_H = WALL + CAVITY # rim starts here +FRONT_BODY_H = BEZEL_T + SKIRT MH = [ (MH_INSET, MH_INSET), @@ -52,256 +51,182 @@ def aabb(x0, y0, z0, x1, y1, z1) -> trimesh.Trimesh: ya, yb = sorted((float(y0), float(y1))) za, zb = sorted((float(z0), float(z1))) dx, dy, dz = xb - xa, yb - ya, zb - za - if dx < 1e-6 or dy < 1e-6 or dz < 1e-6: - raise ValueError(f"degenerate box {[xa,ya,za,xb,yb,zb]}") + if min(dx, dy, dz) < 1e-6: + raise ValueError(f"degenerate {[xa, ya, za, xb, yb, zb]}") m = box(extents=[dx, dy, dz]) m.apply_translation([xa + dx / 2, ya + dy / 2, za + dz / 2]) return m -def u(*meshes: trimesh.Trimesh) -> trimesh.Trimesh: - r = meshes[0] - for m in meshes[1:]: +def U(*ms: trimesh.Trimesh) -> trimesh.Trimesh: + r = ms[0] + for m in ms[1:]: r = r.union(m, engine="manifold") return r -def d(a: trimesh.Trimesh, *subs: trimesh.Trimesh) -> trimesh.Trimesh: +def D(a: trimesh.Trimesh, *ss: trimesh.Trimesh) -> trimesh.Trimesh: r = a - for s in subs: + for s in ss: r = r.difference(s, engine="manifold") return r def make_front() -> trimesh.Trimesh: - """Front bezel: screen window + skirt + male lip for closing onto back.""" - z1 = BEZEL_T + SKIRT_H + LIP_H - - body = aabb(0, 0, 0, OUTER_L, OUTER_W, BEZEL_T + SKIRT_H) - # hollow skirt - cavity = aabb(WALL, WALL, BEZEL_T, OUTER_L - WALL, OUTER_W - WALL, BEZEL_T + SKIRT_H + 1) + """ + Z=0: outer screen face + Z=FRONT_BODY_H: open rim with male lip extending to FRONT_BODY_H+LIP_H + """ + body = aabb(0, 0, 0, OUTER_L, OUTER_W, FRONT_BODY_H) + hollow = aabb(WALL, WALL, BEZEL_T, OUTER_L - WALL, OUTER_W - WALL, FRONT_BODY_H + 1) vx = WALL + GAP + DISP_X + VIEW_IX vy = WALL + GAP + VIEW_IY - view = aabb(vx - 0.25, vy - 0.25, -0.5, vx + VIEW_L + 0.25, vy + VIEW_W + 0.25, BEZEL_T + 0.6) + view = aabb(vx - 0.2, vy - 0.2, -0.5, vx + VIEW_L + 0.2, vy + VIEW_W + 0.2, BEZEL_T + 0.5) - sx = WALL + GAP + DISP_X - 0.25 + sx = WALL + GAP + DISP_X - 0.2 pocket = aabb( - sx, WALL + GAP - 0.15, BEZEL_T - 0.05, - sx + DISP_L + 0.5, WALL + GAP + DISP_W + 0.15, BEZEL_T + DISP_H + 0.8, + sx, WALL + GAP - 0.1, BEZEL_T - 0.05, + sx + DISP_L + 0.4, WALL + GAP + DISP_W + 0.1, BEZEL_T + DISP_H + 0.6, ) + out = D(body, hollow, view, pocket) - out = d(body, cavity, view, pocket) - - # male lip (inserts into back female groove) - lip_outer = aabb( - WALL - LIP_T, WALL - LIP_T, BEZEL_T + SKIRT_H - 0.05, - OUTER_L - (WALL - LIP_T), OUTER_W - (WALL - LIP_T), BEZEL_T + SKIRT_H + LIP_H, + # male lip: thin wall ring protruding past rim + lip_out = aabb( + WALL - 1.0, WALL - 1.0, FRONT_BODY_H - 0.05, + OUTER_L - (WALL - 1.0), OUTER_W - (WALL - 1.0), FRONT_BODY_H + LIP_H, ) - lip_inner = aabb( - WALL + 0.15, WALL + 0.15, BEZEL_T + SKIRT_H - 0.1, - OUTER_L - WALL - 0.15, OUTER_W - WALL - 0.15, BEZEL_T + SKIRT_H + LIP_H + 0.5, + lip_in = aabb( + WALL + LIP_CLEAR, WALL + LIP_CLEAR, FRONT_BODY_H - 0.2, + OUTER_L - WALL - LIP_CLEAR, OUTER_W - WALL - LIP_CLEAR, FRONT_BODY_H + LIP_H + 0.5, ) - lip = d(lip_outer, lip_inner) - out = u(out, lip) + out = U(out, D(lip_out, lip_in)) - # screw clearance through bezel for px, py in MH: - x = WALL + GAP + px - y = WALL + GAP + py - hole = cylinder(radius=SCREW / 2 + 0.1, height=z1 + 4, sections=28) - hole.apply_translation([x, y, (BEZEL_T + SKIRT_H) / 2]) - out = d(out, hole) + hole = cylinder(radius=SCREW / 2 + 0.1, height=FRONT_BODY_H + LIP_H + 4, sections=28) + hole.apply_translation([WALL + GAP + px, WALL + GAP + py, FRONT_BODY_H / 2]) + out = D(out, hole) out.merge_vertices() return out -def dht_pocket_on_back() -> trimesh.Trimesh: - """ - Pocket on outer back face (z=0 side is exterior bottom of shell). - Module inserts from outside; clips hold it; grill protrudes DHT_PROUD. - Coordinate: back shell sits z=0 exterior, z=SHELL_H toward PCB. - Pocket carved into floor from outside, clips on the outer face. - """ - # center DHT on back wall area away from USB (right-ish of board back) - cx = WALL + GAP + 62 - cy = WALL + GAP + PCB_W / 2 - - # outer boss that contains the module (sits mostly outside z<=0) - bay_l = DHT_MOD_L + 3.2 - bay_w = DHT_MOD_W + 3.2 - bay_h = DHT_MOD_H + WALL * 0.6 + DHT_PROUD - - # bay extends below z=0 (outside) and a bit into floor - bay = aabb( - cx - bay_l / 2, cy - bay_w / 2, -bay_h + WALL * 0.35, - cx + bay_l / 2, cy + bay_w / 2, WALL + 0.2, - ) - - # cavity for module (from outside) - cav = aabb( - cx - DHT_MOD_L / 2 - 0.25, cy - DHT_MOD_W / 2 - 0.25, -bay_h + WALL * 0.35 + 1.0, - cx + DHT_MOD_L / 2 + 0.25, cy + DHT_MOD_W / 2 + 0.25, WALL - 0.3, - ) - - # window through back wall into interior for wires (small) - wire = aabb( - cx - 3.5, cy - 4.0, WALL - 0.5, - cx + 3.5, cy + 4.0, WALL + 2.5, - ) - - # front face of bay: grill opening, leaving rim so tip is proud - grill = aabb( - cx - DHT_MOD_L / 2 + 1.2, cy - DHT_MOD_W / 2 + 1.2, -bay_h - 0.2, - cx + DHT_MOD_L / 2 - 1.2, cy + DHT_MOD_W / 2 - 1.2, -bay_h + WALL + DHT_PROUD + 0.5, - ) - - # side vent slots - vents = [] - for i in range(3): - vents.append(aabb( - cx - DHT_MOD_L / 2 - 2, cy - 4 + i * 3.2, -bay_h + 3, - cx - DHT_MOD_L / 2 + 0.2, cy - 4 + i * 3.2 + 1.4, -bay_h + 8, - )) - vents.append(aabb( - cx + DHT_MOD_L / 2 - 0.2, cy - 4 + i * 3.2, -bay_h + 3, - cx + DHT_MOD_L / 2 + 2, cy - 4 + i * 3.2 + 1.4, -bay_h + 8, - )) - - # 卡位: L/R snap ledges + end stops (press-fit module from outside) - z_base = -bay_h + WALL * 0.35 + 1.2 - left_clip = aabb( - cx - DHT_MOD_L / 2 - 1.2, cy - 3.5, z_base, - cx - DHT_MOD_L / 2 + DHT_CLIP, cy + 3.5, z_base + 3.2, - ) - right_clip = aabb( - cx + DHT_MOD_L / 2 - DHT_CLIP, cy - 3.5, z_base, - cx + DHT_MOD_L / 2 + 1.2, cy + 3.5, z_base + 3.2, - ) - # end stop ledge near grill (prevents module falling out front) - stop = aabb( - cx - DHT_MOD_L / 2 + 1.5, cy - DHT_MOD_W / 2 + 0.8, -bay_h + WALL * 0.35 + 0.8, - cx + DHT_MOD_L / 2 - 1.5, cy + DHT_MOD_W / 2 - 0.8, -bay_h + WALL * 0.35 + 0.8 + 1.0, - ) - # rear retention bar (卡入后沿) - retain = aabb( - cx - 5.0, cy - DHT_MOD_W / 2 - 0.2, WALL - 2.2, - cx + 5.0, cy + DHT_MOD_W / 2 + 0.2, WALL - 0.4, - ) - - bay = d(bay, cav, grill, wire, *vents) - bay = u(bay, left_clip, right_clip, stop, retain) - return bay - - def make_back() -> trimesh.Trimesh: - """Back shell: cavity, female lip, screw bosses, stand, DHT snap bay on outer back.""" - body = aabb(0, 0, 0, OUTER_L, OUTER_W, SHELL_H + LIP_H) - cavity = aabb(WALL, WALL, WALL, OUTER_L - WALL, OUTER_W - WALL, SHELL_H + LIP_H + 1) + """ + Z=0: exterior back face (DHT grill here, slightly proud) + Z=BACK_BODY_H: mating plane; female groove from BACK_BODY_H to BACK_BODY_H+LIP_H + """ + total_h = BACK_BODY_H + LIP_H + body = aabb(0, 0, 0, OUTER_L, OUTER_W, total_h) + cavity = aabb(WALL, WALL, WALL, OUTER_L - WALL, OUTER_W - WALL, total_h + 1) + out = D(body, cavity) - # female groove for front lip (near top rim) + # female groove: cut a channel in the top rim for the male lip + # outer wall of groove groove = aabb( - WALL - LIP_T - 0.15, WALL - LIP_T - 0.15, SHELL_H, - OUTER_L - (WALL - LIP_T - 0.15), OUTER_W - (WALL - LIP_T - 0.15), SHELL_H + LIP_H + 0.2, + WALL - 1.0 - LIP_CLEAR, WALL - 1.0 - LIP_CLEAR, BACK_BODY_H + 0.1, + OUTER_L - (WALL - 1.0 - LIP_CLEAR), OUTER_W - (WALL - 1.0 - LIP_CLEAR), total_h + 0.2, ) - # keep inner wall so groove is a channel, not open to cavity fully - # actually: cut a U-channel from the top rim - groove_cut = aabb( - WALL - LIP_T - 0.1, WALL - LIP_T - 0.1, SHELL_H - 0.05, - OUTER_L - (WALL - LIP_T - 0.1), OUTER_W - (WALL - LIP_T - 0.1), SHELL_H + LIP_H + 0.3, + groove_keep = aabb( + WALL + 0.05, WALL + 0.05, BACK_BODY_H - 0.1, + OUTER_L - WALL - 0.05, OUTER_W - WALL - 0.05, total_h + 0.3, ) - keep_inner = aabb( - WALL + 0.05, WALL + 0.05, SHELL_H - 0.2, - OUTER_L - WALL - 0.05, OUTER_W - WALL - 0.05, SHELL_H + LIP_H + 0.5, - ) - # rim solid then groove: start from body, remove cavity, then remove groove channel between lip walls - out = d(body, cavity) - - # Add rim collar then cut female slot - collar = aabb(0, 0, SHELL_H - 0.05, OUTER_L, OUTER_W, SHELL_H + LIP_H) - collar_in = aabb(WALL + 0.2, WALL + 0.2, SHELL_H - 0.2, OUTER_L - WALL - 0.2, OUTER_W - WALL - 0.2, SHELL_H + LIP_H + 0.5) - collar = d(collar, collar_in) - out = u(out, collar) - - # female slot (accepts front male lip) - slot = aabb( - WALL - LIP_T - 0.12, WALL - LIP_T - 0.12, SHELL_H + 0.15, - OUTER_L - (WALL - LIP_T - 0.12), OUTER_W - (WALL - LIP_T - 0.12), SHELL_H + LIP_H - 0.15, - ) - slot_keep = aabb( - WALL + 0.05, WALL + 0.05, SHELL_H, - OUTER_L - WALL - 0.05, OUTER_W - WALL - 0.05, SHELL_H + LIP_H + 0.2, - ) - # slot is the ring between slot outer and slot_keep — cut only the ring - slot_ring = d(slot, slot_keep) - out = d(out, slot_ring) + out = D(out, D(groove, groove_keep)) # USB - usb_y0 = WALL + GAP + USB_Y - USB_W / 2 - usb = aabb(-1, usb_y0, WALL + 1.2, WALL + 1.2, usb_y0 + USB_W, WALL + 1.2 + USB_H) - out = d(out, usb) + uy0 = WALL + GAP + USB_Y - USB_W / 2 + out = D(out, aabb(-0.5, uy0, WALL + 1.0, WALL + 1.0, uy0 + USB_W, WALL + 1.0 + USB_H)) - # SD optional slit - sd = aabb(WALL + GAP + 28, OUTER_W - WALL - 1, WALL + 2, WALL + GAP + 44, OUTER_W + 1, WALL + 5) - out = d(out, sd) - - # BOOT/RST access - for y in (12, 22): + # button holes + for y in (12.0, 22.0): btn = cylinder(radius=2.2, height=WALL + 2, sections=20) btn.apply_translation([WALL + GAP + 10, WALL + GAP + y, WALL / 2]) - out = d(out, btn) - - # floor vents (not under DHT) - vents = [] - for i in range(4): - vents.append(aabb(WALL + 10 + i * 12, WALL + 8, -0.5, WALL + 12 + i * 12, WALL + 16, WALL + 0.5)) - out = d(out, *vents) + out = D(out, btn) # screw bosses bosses = [] for px, py in MH: - x = WALL + GAP + px - y = WALL + GAP + py - boss = cylinder(radius=BOSS_OD / 2, height=CAVITY - 0.4, sections=28) - boss.apply_translation([x, y, WALL + (CAVITY - 0.4) / 2]) + x, y = WALL + GAP + px, WALL + GAP + py + boss = cylinder(radius=BOSS_OD / 2, height=CAVITY - 0.5, sections=28) + boss.apply_translation([x, y, WALL + (CAVITY - 0.5) / 2]) hole = cylinder(radius=BOSS_ID / 2, height=CAVITY + 1, sections=20) hole.apply_translation([x, y, WALL + CAVITY / 2]) - bosses.append(d(boss, hole)) - out = u(out, *bosses) + bosses.append(D(boss, hole)) + out = U(out, *bosses) - # stand foot (desk) - stand_len = OUTER_L * 0.7 - sx = (OUTER_L - stand_len) / 2 - foot = aabb(sx, -STAND_FOOT + 0.4, 0, sx + stand_len, WALL, SHELL_H * 0.85) - foot_in = aabb(sx + 2, -STAND_FOOT + 2.2, WALL, sx + stand_len - 2, WALL - 0.15, SHELL_H) - foot = d(foot, foot_in) - rib = aabb(OUTER_L / 2 - 1.2, -STAND_FOOT + 1, WALL, OUTER_L / 2 + 1.2, WALL, SHELL_H * 0.8) - out = u(out, foot, rib) + # ---- DHT11 flush pocket in back wall (NOT a side box) ---- + # Center on back face + cx = OUTER_L * 0.5 + cy = OUTER_W * 0.5 + # Pocket carved from outside into wall+cavity enough for module + pocket = aabb( + cx - DHT_L / 2 - 0.3, cy - DHT_W / 2 - 0.3, -0.05, + cx + DHT_L / 2 + 0.3, cy + DHT_W / 2 + 0.3, WALL + DHT_H - 1.0, + ) + out = D(out, pocket) - # DHT11 snap bay on outer back (protruding) - out = u(out, dht_pocket_on_back()) + # Snap rails (卡位) left/right inside pocket — thin ledges + rail_z0, rail_z1 = 1.2, 1.2 + 2.2 + left = aabb(cx - DHT_L / 2 - 0.3, cy - 3.2, rail_z0, cx - DHT_L / 2 + 1.0, cy + 3.2, rail_z1) + right = aabb(cx + DHT_L / 2 - 1.0, cy - 3.2, rail_z0, cx + DHT_L / 2 + 0.3, cy + 3.2, rail_z1) + # bottom stop (prevents falling inward) + stop = aabb(cx - 5, cy - DHT_W / 2 + 0.5, WALL + DHT_H - 2.2, cx + 5, cy + DHT_W / 2 - 0.5, WALL + DHT_H - 1.0) + out = U(out, left, right, stop) + + # Proud grill ring on exterior (the only intentional protrusion) + grill_ring = aabb( + cx - DHT_L / 2 - 1.0, cy - DHT_W / 2 - 1.0, -DHT_PROUD, + cx + DHT_L / 2 + 1.0, cy + DHT_W / 2 + 1.0, 0.05, + ) + grill_hole = aabb( + cx - DHT_L / 2 + 1.5, cy - DHT_W / 2 + 1.5, -DHT_PROUD - 0.2, + cx + DHT_L / 2 - 1.5, cy + DHT_W / 2 - 1.5, 0.2, + ) + # slot vents in proud face + slots = [] + for i in range(4): + slots.append(aabb( + cx - 5 + i * 2.8, cy - 4.5, -DHT_PROUD - 0.2, + cx - 5 + i * 2.8 + 1.2, cy + 4.5, 0.2, + )) + out = U(out, D(grill_ring, grill_hole, *slots)) + + # tiny wire path already open via pocket into cavity + + # Simple thin kickstand rib (not a hollow “格子”) — optional small triangle + # Skip bulky stand entirely per user feedback. out.merge_vertices() return out def main() -> None: - out_dir = Path(__file__).resolve().parent / "export" - out_dir.mkdir(parents=True, exist_ok=True) - - print("Building front (合盖公止口)…") + out = Path(__file__).resolve().parent / "export" + out.mkdir(parents=True, exist_ok=True) + print("front…") front = make_front() - print("Building back (DHT后盖卡位 + 母止口)…") + print("back…") back = make_back() + front.export(out / "front.stl") + back.export(out / "back.stl") - front.export(out_dir / "front.stl") - back.export(out_dir / "back.stl") - print(f"front watertight={front.is_watertight} faces={len(front.faces)}") - print(f"back watertight={back.is_watertight} faces={len(back.faces)}") - print(f"Wrote {out_dir / 'front.stl'}") - print(f"Wrote {out_dir / 'back.stl'}") - print(f"Outer ~ {OUTER_L:.1f} x {OUTER_W:.1f} mm; DHT proud ~{DHT_PROUD} mm") + # write mate info for viewer + meta = out / "mate.json" + meta.write_text( + "{\n" + f' "outer_l": {OUTER_L},\n' + f' "outer_w": {OUTER_W},\n' + f' "front_body_h": {FRONT_BODY_H},\n' + f' "back_body_h": {BACK_BODY_H},\n' + f' "lip_h": {LIP_H},\n' + f' "dht_proud": {DHT_PROUD}\n' + "}\n", + encoding="utf-8", + ) + print(f"front {front.extents} watertight={front.is_watertight}") + print(f"back {back.extents} watertight={back.is_watertight}") + print("closed stack height ≈", BACK_BODY_H + FRONT_BODY_H, "mm (lips nest, not add full)") + print("Wrote STLs + mate.json") if __name__ == "__main__": diff --git a/cad/viewer.html b/cad/viewer.html index 9437581..0e912ae 100644 --- a/cad/viewer.html +++ b/cad/viewer.html @@ -3,113 +3,77 @@ - CYD Case — 合盖 / DHT后盖卡位 + CYD Case — 合盖预览
-

CYD Case Preview

-

DHT11 在后盖外侧卡位,微微突出 · 前后盖止口合盖

+

CYD 外壳预览

+

左键旋转 · 滚轮缩放 · 右键平移

-
合盖
+
合盖
- - -
-
- 开合度 - - 0% -
-
- 分解 - - 0 +
+
开合度0%
+
分解0
-
部件
+
部件
- - - - + + + +
-
显示
+
视角
- - - - - + + + +
-
-
视角
-
- - - - - - -
-
- -

合盖=0%:前框止口落入后盖槽。DHT 从后盖背面卡入并突出约 1.8mm。

+

+ 后盖中心微凸的是 DHT11 卡位通风口(传感器按入后盖背面,探头略突出)。
+ 已去掉旁边多余的大“格子”(旧版支脚块 / 外挂仓)。 +

加载中…