XLeRobot · hardware · 2026-09-10

3D 设计规范

这份文档是给下一次设计当输入用的。每一条都来自这套模型上真实踩过的坑,带证据和行号 —— 不是通用的 3D 打印常识。

第一原则

实测的几何 > 源码的常量。两者冲突时,永远以导出的网格为准。

源码说的是「设计想要什么」,STL 说的是「文件里真的有什么」。这两件事在本项目中已经被证实会不一致,而且那次差点让一整块件白打。
推论:任何数字进入文档、页面或采购单之前,必须从 STL 量一遍。

一、六条最贵的教训

1assert 只证明常量合规,不证明几何存在
assert(EYE_PORT_W >= 20 && EYE_PORT_H >= 10,
       "中央走线口小于操作者要求的 20x10");   // 这条 assert 是【通过】的

而导出的 STL 里那个走线口根本不存在 —— 连同显示窗、屏幕沉槽、两个 ∅8 穿线孔一起,整块 ∅48 中央区是空气。布尔实测:本该 9.048 cm³ 的区域只有 0.024。

规则:assert 用来挡住「参数写错」,挡不住「几何被后续布尔吃掉」。要断言几何,必须用布尔求交去量体积。

2连通性 ≠ 完整性

check_parts.py 检查「每个件是不是一个连通体」。上面那块背板整个消失的件,它照样放行 —— 因为剩下的那个圆环是完美连通的。

规则:连通性检查抓的是「碎片」,抓不了「缺失」。点名的特征必须单独写探针断言它存在。

3零厚度面接触 = 悬空碎片

眼睛托架第一版:主体 y 17..20.2,凸耳 y 16..17,两者只在 y=17 这个面相接。导出后是 2 个连通体,凸耳整个悬空。渲染图上完全看不出来。

规则:union 的两部分必须有实体重叠,共面不算。重叠 ≥ 0.5 mm。每个件导出后必须跑连通体计数。

4union 里的实心体会填平之前挖好的开口
module eye_solid() { union() { eye_ring(); eye_barrel(); eye_backplate(); } }
                                          ↑ ∅60 x 23 的【实心】柱

eye_backplate() 内部辛苦 difference 出来的窗/槽/孔,在 union 的那一刻全部被填回去。

规则:开口要在最终 union 之后再 difference。写成独立 module,在顶层件里减。

5rotate() 的方向要算,不要凭直觉

rotate([-90,0,0]) 把局部 +y 映射到全局 −z。源码里「屏幕沉槽正下方」的走线口用了负 y,实际跑到了眼睛上方。

规则:每次 rotate 之后手算一个特征点的全局坐标,或导出后切片实测。注释写的方向不能当证据。

6. 洞比料宽 = 豁口,不是孔

领结翅膀厚 BOW_T = 9,出线口 FR_PORT_W = 24 宽。24 > 9,所以那个「孔」必然从翅膀的前后两面同时切穿,导出的是一个外部可见的缺口,不是通孔。渲染图上看着像个凹槽,很容易当成设计意图放过去。

判据是一行算术,不需要建模:

封闭通孔的充分必要条件: 料厚 ≥ 开口宽 + 2 × 最小壁厚
                        30  ≥   24    + 2 × 3

规则:在任何薄壁件上开孔之前,先拿这条不等式核一遍。不满足只有三条路,按优先级:①加厚这个件(本项目选的,配合薄壳打印 —— 耗材由切片参数解决,不由尺寸解决)②在开口处做局部凸台 ③把开口转 90° 用较小的那一边。不要靠改小开口来凑 —— 开口尺寸通常是被接插件锁死的。

验证方法:沿厚度方向逐点打射线,孔的全长上每个位置都必须读到「料 / 空 / 料」三段。只在一个截面上量会漏掉根部或尖端被切穿的情况。

二、开口不能骑在分缝上

皮肤分缝相位skin0skin1skin2skin3
0° / 90° / 180° / 270°3/63/66/66/6
45° / 135° / 225° / 315°4/64/66/64/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 数引用点 ② 改之后重导所有受影响的件并比对体积 ③ 体积没变 = 那个件确实没被影响,这是最省事的回归判据。

四、配合公差(全部实测自 STL)

配合处实测值
四块拼缝定位销∅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 量一遍确认。

五、每个可打印件的验收清单

六、打印与材质

部位材质理由
内部骨架、相机框、承力链普通白色 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 33590×25×30当前在用,已验证
Orbbec Gemini 290×25×30零改动替代;孔位同为 1/4-20 + 2×M3,支持 UVC
Orbbec Astra Mini Pro84.9×20×19.9装得下且富余;34 g,深度/RGB 均 640×480@30fps
Intel RealSense D43590×25×25更宽松;lerobot 原生支持
Orbbec Astra Pro160×30×40长 68.5、高 13.5,装不进
Orbbec Gemini 335L / 336L124×29×27太长;孔位是 M4

教训:同一品牌同一系列的尺寸可以差一个数量级 Astra Pro 是 160 mm 的长条,Astra Mini Pro 是 84.9 mm 的裸模组。名字只差两个字,一个装不进一个富余。按型号查规格书,不要按系列推断。

换相机的三层代价:①机械(腔+视锥+孔位,头壳重打)②数据(已录数据集的视角和内参失效)③软件(V4L2/UVC 或专用 SDK,必须有 Linux aarch64 支持)。

九、改动流程(固定动作,不要跳步)

  1. 改之前:grep 所有引用点,列出受影响件
  2. 改:新增参数写 assert,把「为什么」连同实测数字写进注释
  3. 导出:受影响的件全部重导
  4. 验收:跑第五节的清单
  5. 回归:不该变的件,体积必须一字不差
  6. 推送:三个入口同步
  7. 验证线上:curl 下来数 U+FFFD,零命中才算发布成功

第 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。