这份文档是给下一次设计当输入用的。每一条都来自这套模型上真实踩过的坑,带证据和行号 —— 不是通用的 3D 打印常识。
第一原则
实测的几何 > 源码的常量。两者冲突时,永远以导出的网格为准。
源码说的是「设计想要什么」,STL 说的是「文件里真的有什么」。这两件事在本项目中已经被证实会不一致,而且那次差点让一整块件白打。
推论:任何数字进入文档、页面或采购单之前,必须从 STL 量一遍。
assert(EYE_PORT_W >= 20 && EYE_PORT_H >= 10,
"中央走线口小于操作者要求的 20x10"); // 这条 assert 是【通过】的
而导出的 STL 里那个走线口根本不存在 —— 连同显示窗、屏幕沉槽、两个 ∅8 穿线孔一起,整块 ∅48 中央区是空气。布尔实测:本该 9.048 cm³ 的区域只有 0.024。
规则:assert 用来挡住「参数写错」,挡不住「几何被后续布尔吃掉」。要断言几何,必须用布尔求交去量体积。
check_parts.py 检查「每个件是不是一个连通体」。上面那块背板整个消失的件,它照样放行 —— 因为剩下的那个圆环是完美连通的。
规则:连通性检查抓的是「碎片」,抓不了「缺失」。点名的特征必须单独写探针断言它存在。
眼睛托架第一版:主体 y 17..20.2,凸耳 y 16..17,两者只在 y=17 这个面相接。导出后是 2 个连通体,凸耳整个悬空。渲染图上完全看不出来。
规则:union 的两部分必须有实体重叠,共面不算。重叠 ≥ 0.5 mm。每个件导出后必须跑连通体计数。
module eye_solid() { union() { eye_ring(); eye_barrel(); eye_backplate(); } }
↑ ∅60 x 23 的【实心】柱
eye_backplate() 内部辛苦 difference 出来的窗/槽/孔,在 union 的那一刻全部被填回去。
规则:开口要在最终 union 之后再 difference。写成独立 module,在顶层件里减。
rotate([-90,0,0]) 把局部 +y 映射到全局 −z。源码里「屏幕沉槽正下方」的走线口用了负 y,实际跑到了眼睛上方。
规则:每次 rotate 之后手算一个特征点的全局坐标,或导出后切片实测。注释写的方向不能当证据。
6. 洞比料宽 = 豁口,不是孔
领结翅膀厚 BOW_T = 9,出线口 FR_PORT_W = 24 宽。24 > 9,所以那个「孔」必然从翅膀的前后两面同时切穿,导出的是一个外部可见的缺口,不是通孔。渲染图上看着像个凹槽,很容易当成设计意图放过去。
判据是一行算术,不需要建模:
封闭通孔的充分必要条件: 料厚 ≥ 开口宽 + 2 × 最小壁厚
30 ≥ 24 + 2 × 3
规则:在任何薄壁件上开孔之前,先拿这条不等式核一遍。不满足只有三条路,按优先级:①加厚这个件(本项目选的,配合薄壳打印 —— 耗材由切片参数解决,不由尺寸解决)②在开口处做局部凸台 ③把开口转 90° 用较小的那一边。不要靠改小开口来凑 —— 开口尺寸通常是被接插件锁死的。
验证方法:沿厚度方向逐点打射线,孔的全长上每个位置都必须读到「料 / 空 / 料」三段。只在一个截面上量会漏掉根部或尖端被切穿的情况。
| 皮肤分缝相位 | skin0 | skin1 | skin2 | skin3 |
|---|---|---|---|---|
| 0° / 90° / 180° / 270° | 3/6 | 3/6 | 6/6 | 6/6 |
| 45° / 135° / 225° / 315° | 4/6 | 4/6 | 6/6 | 4/6 |
眼睛在 90°、两个耳罩在 0° 和 180°。相位 0 时三个大开口全部骑在缝上,把两侧件的材料和螺丝位一起挖掉。
规则:先定开口方位,再定分缝方位。分缝必须避开所有大开口的中心线。
usb_window() 被 3 处引用。把 USB 口缩小连带改变了:
cam_frame 53.32 -> 58.47 cm³
frame 201.67 -> 202.31
quarter1 43.74 -> 44.38 ← USB 在 180°,正好这一块
skin1 32.05 -> 31.81
quarter0/2/3 · skin0/2/3 · core_link 完全没变
规则:① 改之前 grep 数引用点 ② 改之后重导所有受影响的件并比对体积 ③ 体积没变 = 那个件确实没被影响,这是最省事的回归判据。
| 配合处 | 实测值 |
|---|---|
| 四块拼缝定位销 | ∅3.400/∅4.000 → ∅4.350/∅4.850 = 0.425–0.475/边 |
| 皮肤内表面 | 0.35 mm/边 |
| 皮肤块之间 | 0.40 (2×0.20) |
| 装饰环 ↔ 镜筒 | 0.20 mm/边 |
| 屏幕托架 ↔ 通光孔 | 0.25 mm/边 |
| 相机 ↔ 相机腔 | 1.0 mm/边 |
销孔那条有历史。名义 0.35 mm(直径)在实物上插不进去(2026-08-24 试装反馈)。现在的 0.85–0.95 是那次的修复。FDM 上「销偏大、孔偏小」是系统性的。定位销宁松勿紧 —— 销只管对位,压紧靠螺丝。
规则:新增配合处,直径间隙 ≥ 0.4 mm(单边 0.2)起步,给完从 STL 量一遍确认。
intersection() 求体积,不是看渲染图)| 部位 | 材质 | 理由 |
|---|---|---|
| 内部骨架、相机框、承力链 | 普通白色 PLA | 装好后被皮肤盖住 |
| 外皮肤 | 金属质感料 | 整个外观 |
| 眼圈装饰环 | 银色/金属质感 | 唯一外露的金属细节,件小省料 |
| 用途 | 规格 | 注意 |
|---|---|---|
| 拧进塑料底孔 | 自攻(PT/三角牙) | 底孔 ∅2.5 配 M3;机牙会滑牙 |
| 拧进热熔螺母 | 机牙 | 自攻咬不住铜 |
| 热熔螺母 | OD 4.2 × L6 | 市面有 4.0/4.2/4.6,4.6 塞不进 |
| 沉头孔 | ∅7.1 / ∅6.2 | 不要圆头,会凸出顶到盖板 |
螺丝长度按板厚算,且不许拧穿。皮肤底孔 4.5 mm 深且明确「不许穿透到腔里」:3 mm 板 + 4 mm 拧入 = 8 mm 刚好,10 mm 顶穿。
腋尺寸 92.0 × 32.0 × 27.0 mm (= 相机 90×30×25 + 单边 1.0)
新相机上限 W ≤ 91.5 D ≤ 31.5 H ≤ 26.5
安装孔距 L_HOLE = 44.5 mm,2×M3,入深 ≤ 4 (展示件不承力时可放宽)
视锡 CONE_LEN = 130,cam_cone() 在 8 处挖头壳
| 相机 | 尺寸 | 判定 |
|---|---|---|
| Orbbec Gemini 335 | 90×25×30 | 当前在用,已验证 |
| Orbbec Gemini 2 | 90×25×30 | 零改动替代;孔位同为 1/4-20 + 2×M3,支持 UVC |
| Orbbec Astra Mini Pro | 84.9×20×19.9 | 装得下且富余;34 g,深度/RGB 均 640×480@30fps |
| Intel RealSense D435 | 90×25×25 | 更宽松;lerobot 原生支持 |
| Orbbec Astra Pro | 160×30×40 | 长 68.5、高 13.5,装不进 |
| Orbbec Gemini 335L / 336L | 124×29×27 | 太长;孔位是 M4 |
教训:同一品牌同一系列的尺寸可以差一个数量级 Astra Pro 是 160 mm 的长条,Astra Mini Pro 是 84.9 mm 的裸模组。名字只差两个字,一个装不进一个富余。按型号查规格书,不要按系列推断。
换相机的三层代价:①机械(腔+视锥+孔位,头壳重打)②数据(已录数据集的视角和内参失效)③软件(V4L2/UVC 或专用 SDK,必须有 Linux aarch64 支持)。
assert,把「为什么」连同实测数字写进注释第 5 步是最容易跳过也最容易出事的。「我觉得没影响」不算证据,体积相等才算。
每条结论必须标明属于哪一类,不许含糊:
| 跑测过 | 有脚本、有数字、可复现 |
| 没跑过 | 推断或标称值,明确标注 |
| 被挡住 | 想验但条件不具备(缺硬件、缺实物) |
尤其是尺寸类数字。「GC9A01 是 ∅37.5」这种从常见规格填的值,必须标 ★待实测★,因为量错的代价是整件报废。
源文件:02-hardware/3D-DESIGN-RULES.md。配套:EAR-POD-RULES.md、check_parts.py、measure*.py、check_mounts.py、check_skin.py、stlview.py。