--- name: solidworks-assembly description: 把 EasyEDA 的 PCB 导成 STEP、在本机 SOLIDWORKS 里装配并做干涉检查。用于「底板 + 刀片插在一起会不会撞」这类机械核对,也用于量插槽插入深度这类 EDA 侧算不出来的数。涉及 SolidWorks / STEP / 3D 装配 / 干涉检查 / 机械干涉 时触发。 --- # SolidWorks 装配与干涉检查(PhoneRail 专用) > ⚠ **动手前先读 `NOTES-probed.md`** —— 那是本机逐条实测出来的 API 口径与坑, > 每一条都踩过一次。不读会把同样的坑再踩一遍。 > 环境已实测:SOLIDWORKS 2025 SP01.1(`RevisionNumber` = `33.1.1`)、 > Python 3.14.3 **64 位** + pywin32(32 位 Python 连不上 64 位 SW,本机不存在这问题)。 ## 什么时候用 - 底板与刀片、刀片与刀片之间的**机械干涉**核对(EDA 侧只能算 2.5D 净距,算不了竖插后的三维关系) - 量 EDA 侧拿不到的机械数:插槽**插入深度**、塑料体内腔、刀片底边离底板多高 - ⚠ **但凡实物在手,优先用卡尺**。STEP 里的连接器是厂商**标称模型**,不含公差; 3D 能替代"按标称值推算",替代不了实测。 ## 整条链(每一步都已实测通过) ### 1. 从 EasyEDA 导出 STEP ```python # 桥有 30 s 硬超时,大板同步调用必断 ⇒ 异步启动 + 轮询 START = "window.__gen={state:'running'}; (async()=>{ ... get3DFile(name,'step',['Component Model'],'Outfit',true) ... })(); return {started:true};" # 再每 5 s 查 window.__gen.state,done 后用 4 MB 分块 base64 取回 ``` 实测:刀片 31.2 MB(生成 22.6 s + 取回 2 s)、底板 53.9 MB(生成 40 s + 取回 4 s)。 归档在 `.claude/r2/3d/`(已 `.gitignore`)。细节见 NOTES §6。 ### 2. 导入 SolidWorks ```python app = wc.GetActiveObject('SldWorks.Application') # 挂已开着的实例 data = app.GetImportFileData(step_path) err = wc.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0) app.LoadFile4(step_path, 'r', data, err) # err.value == 0 即成功 ``` 导进来是**带位号的装配树**(`R1~R0402~…`、`U4~TSSOP-24~…`),一块板 95 个文档。 ⛔ 第三参不能传 `None`(报"类型不匹配");⛔ `OpenDoc6` 导 STEP 返回 None。见 NOTES §3。 ### 3. 找到可插引用 + 装配 ```python # 导入后**不要关文档**,遍历 GetDocuments 找:有路径 + GetType==2 + .SLDASM p = ... # → %TEMP%\swx…\IC~~\PhoneRail_base.step.SLDASM c = asm.AddComponent4(p, '', 0.0, 0.0, 0.0) # ✅ 用 AddComponent4 ``` ⛔ **`AddComponent5`(8 参)在本机恒返回 `None`**,换参数没用,直接用 `AddComponent4`。 ⛔ 别走"另存再插":`SaveAs3` 出来的是废件、`CopyDocument` 返回 2、`OpenDoc7` 打不开 STEP。 见 NOTES §11/§12/§15。 ### 4. 干涉检查 ```python pc = wc.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_VARIANT, None) pf = wc.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_VARIANT, None) n = asm.ToolsCheckInterference2(0, EMPTY, False, pc, pf) # 5 参,少一个都报"非选择性的参数" ``` ⛔ 第 2 参只能传 `EMPTY`(`VARIANT(VT_DISPATCH, None)`),塞零部件元组会报"服务器出现意外情况"。 ### 5. 清理 ```python app.CloseAllDocuments(True) # 295 个文档 0.9 s 关完,SW 不退出 ``` ⛔ 一关就清空 `%TEMP%\swx…\IC~~\`,所以第 3 步必须在清理**之前**做完。 ## ⛔ 未完成的两步(别当成能用) 1. **刀片摆位**。变换矩阵算好了(NOTES §14),但 `CreateTransform` 卡在 pywin32 封送: `GetMathUtility` 要用 dispid 绕行才拿得到(NOTES §17),拿到后 `CreateTransform` **又**报"找不到成员"——同一个病一层套一层,未解。 2. **坐标系**:`AddComponent4` 插进总装后,两块板都被**重心归零** (刀片 `x -45~45 / y -34~34`、底板 `x -49~49 / y -49~49`), NOTES §14 那套"原点 = 板左下角"的平移量**不能直接用**,要按 `GetBox` 现算。 ⇒ 现状:能装、能查干涉,但**两块板都堆在原点**,查出来的干涉没有工程意义。 要么解掉上面两点,要么在 SolidWorks 里手工拖一次(更快)。 ## 调试时的通用招数 动态派发报"找不到成员"时,先确认名字在不在: ```python did = app._oleobj_.GetIDsOfNames('GetMathUtility') # 在 → 返回 dispid raw = app._oleobj_.Invoke(did, 0, pythoncom.DISPATCH_METHOD, 1) ``` 还有一条贯穿始终的规律:**无参成员基本都是属性**(`app.GetDocumentCount` / `doc.GetTitle` / `doc.EditRebuild3` 都不加括号),有参的才是方法。但**有例外**(`GetMathUtility`), 拿不准就去 `sldworks.tlb` 查 `invkind`(NOTES §8 给了读法)。