sync: HP_BOWEI 2026-09-09
This commit is contained in:
@@ -0,0 +1,296 @@
|
||||
---
|
||||
name: altium-kicad
|
||||
description: >
|
||||
把 Altium Designer 的 PCB 设计工程整体搬到 KiCad,并验证搬完的板与原设计电气
|
||||
等价、制造等价。驱动 E:\LangGraph_Design\Altium-Kicad 里的 LangGraph 工作流
|
||||
(11 节点 / 4 个判定回环),进程内 + SQLite 持久化,不用 langgraph dev。图在每
|
||||
个需要 MCP、CLI 或人在 GUI 里点的地方 interrupt 回到 Claude 会话,由本 skill
|
||||
执行真实动作再回填结论推进。附带把两次真实迁移里反复重写的脚本通用化:ASCII
|
||||
转换脚本生成、BGA 平面焊盘网络回填、覆铜 zone clearance 批改、逐页网表
|
||||
partition 比对、走线/过孔矢量等价比对。
|
||||
|
||||
只要用户提到 Altium 转 KiCad、AD 转 KiCad、把 PrjPCB 导入 KiCad、迁移/搬移
|
||||
PCB 工程、altium-kicad 工作流、"Header already parsed"、原理图转 ASCII、
|
||||
导入后 DRC 一堆短路、BGA 焊盘丢网络、铺铜避让变大、网表比对、Gerber 比对、
|
||||
或者说 "启动 altium-kicad"、"跑迁移流程"、"继续上次那个迁移"、"convert my
|
||||
Altium project to KiCad"、"import PrjPCB into KiCad"、"migrate PCB from
|
||||
Altium",就必须用这个 skill —— 哪怕他们没说 skill、没提 LangGraph,只说了
|
||||
"把这块板转成 KiCad"、"这板子迁移到一半,接着弄"。
|
||||
---
|
||||
|
||||
# Altium → KiCad 工程迁移
|
||||
|
||||
## 这个 skill 是什么
|
||||
|
||||
一次完整迁移 = 5 个阶段:**桥接 → 转 ASCII 并导入 → 修 PCB → 网表对齐 → 几何对齐 → 验收**。
|
||||
这些步骤有严格的先后依赖、有失败要退回重做的回环、单次会话跑不完(用户要去
|
||||
Altium 和 KiCad 里手动点很多次)。所以状态由 LangGraph 图持久化在 SQLite 里,
|
||||
你负责把图停下来的每一步翻译成真实动作,做完回填结论让它往下走。
|
||||
|
||||
**MCP 边界(必须理解,否则会白折腾)**:eda-agent(altium MCP)和 KiCAD-MCP-Server
|
||||
跑在**你这个 Claude 会话进程里**,不在 LangGraph 的 Python 进程里。所以图不可能
|
||||
自己去 ping Altium、自己去数文件、自己去改板 —— 它只做编排,凡是要碰真实世界的
|
||||
地方一律 `interrupt()` 交回给你。这是设计,不是缺陷。
|
||||
|
||||
## 环境
|
||||
|
||||
| 项 | 值 |
|
||||
|---|---|
|
||||
| 图工程根 | `E:\LangGraph_Design\Altium-Kicad`(可用 `--project-root` 或 `AK_PROJECT_ROOT` 改) |
|
||||
| Python | conda env `langgraph`(`~\skills_env.md` 的 `CONDA_LANGGRAPH_PYTHON`) |
|
||||
| KiCad python | `~\skills_env.md` 的 `KICAD_PYTHON`,本机 `D:\KiCad\10.0\bin\python.exe` |
|
||||
| checkpoint | `<图工程根>\runs\skill_checkpoint.sqlite`,按 thread 隔离 |
|
||||
| thread 命名 | 由 target_dir 目录名推导,如 `E:\Kicad_design\XMOD_V1p0` → `ak-xmod-v1p0` |
|
||||
| 驱动脚本 | `%USERPROFILE%\.claude\skills\altium-kicad\scripts\ak_flow.py` |
|
||||
|
||||
需要的 MCP:**eda-agent**(Altium 侧取数)、**kicad**(可选,KiCad 侧大多走
|
||||
`kicad-cli` 和 pcbnew 更稳)。
|
||||
|
||||
## 驱动命令
|
||||
|
||||
统一用 `conda run -n langgraph python` 跑 `ak_flow.py`。**退出码 2 = 停在
|
||||
interrupt 等你回填**(不是错误),0 = 图跑完,1 = 出错。
|
||||
|
||||
```powershell
|
||||
$AK = "$env:USERPROFILE\.claude\skills\altium-kicad\scripts\ak_flow.py"
|
||||
|
||||
# 新建 / 续跑(同一个 target-dir 重复跑就是续跑,不会重置)
|
||||
conda run -n langgraph python $AK start `
|
||||
--source-prj "E:\Altium_design\FOO\FOO.PrjPCB" `
|
||||
--target-dir "E:\Kicad_design\FOO"
|
||||
|
||||
# 看现在停在哪
|
||||
conda run -n langgraph python $AK status --target-dir "E:\Kicad_design\FOO"
|
||||
|
||||
# 回填结论、推进(--set 免转义,true/false 转 bool,纯数字转 int)
|
||||
conda run -n langgraph python $AK resume --target-dir "E:\Kicad_design\FOO" `
|
||||
--set bridge_ok=true
|
||||
|
||||
# 列出所有迁移线程 / 清掉某个线程重来
|
||||
conda run -n langgraph python $AK list
|
||||
conda run -n langgraph python $AK reset --target-dir "E:\Kicad_design\FOO"
|
||||
```
|
||||
|
||||
`--set` 的值含空格要整体加引号:`--set "report_path=E:\My Board\report.md"`。
|
||||
`start` 还可以调回环的重试上限(默认 桥接/导入 3 次、网表/几何 5 次,超限走 safety_end):
|
||||
`--max-bridge-retry N` `--max-import-retry N` `--max-netlist-retry N` `--max-gerber-retry N`。
|
||||
|
||||
`[INTERRUPT]` 后面的 JSON 里 `action` 字段告诉你该做哪一步,下面逐个说。
|
||||
|
||||
> **回填不能是空的**。langgraph 把 falsy 的 resume 当作「没提供」,会在同一个
|
||||
> 节点再中断一次,看起来像卡住。至少给一个键。
|
||||
|
||||
---
|
||||
|
||||
## 逐步执行
|
||||
|
||||
开始之前先问清楚两件事(没有默认值,猜错了会把工程写到别处):
|
||||
**源 `.PrjPCB` 的绝对路径**、**目标 KiCad 目录的绝对路径**。
|
||||
|
||||
### `prompt_altium_mcp` — 让用户开启 Altium 桥接
|
||||
|
||||
告诉用户在 Altium 里:`DXP/Preferences → Scripting System → Global Projects →
|
||||
Install` 选 `Altium_API.PrjScr`,然后 `File → Run Script → Dispatcher.pas →
|
||||
StartMCPServer → Run`,状态窗显示 `MCP: idle` 即通。
|
||||
|
||||
提醒两条脾气:桥接**约 10 分钟空闲自停**,**一次只能跑一个脚本**。
|
||||
|
||||
用户确认后:`--set acknowledged=true`
|
||||
|
||||
### `check_altium_bridge` — 验证桥接
|
||||
|
||||
调 eda-agent 的 `app_ping`。通了 `--set bridge_ok=true`,不通就 `false`
|
||||
(图会回到上一步让用户重开,最多 3 次)。
|
||||
|
||||
### `convert_ascii` — 转 ASCII(顺带做基线快照)
|
||||
|
||||
**先做基线快照,趁桥接还活着。** 后面 `check_file_count` 要页数、`rebuild_rules`
|
||||
要设计规则、网表比对要真值网表,这些全都只能从 Altium 侧取;而转 ASCII 的第一步
|
||||
就是停掉 eda-agent,停了再想取就得重开桥接。所以顺序是:
|
||||
|
||||
1. 用 eda-agent 落盘基线到 `<target_dir>\_migration\altium_baseline\`:
|
||||
`proj_get_stats` `proj_get_nets` `proj_get_bom` `pcb_get_board_statistics`
|
||||
`pcb_get_layer_stackup` `pcb_get_design_rules`(存成 `pcb_design_rules.json`,
|
||||
后面查 InPolygon clearance 要用)
|
||||
2. `proj_export_netlist`(**tabular**)导到 `_migration\reference\netlist_tabular.csv`
|
||||
—— 这是后面回填焊盘网络和比网表的**唯一真值**,别漏
|
||||
3. 记下原理图页数和 PCB 数(`check_file_count` 要用)
|
||||
|
||||
然后转 ASCII:
|
||||
|
||||
```powershell
|
||||
python "$env:USERPROFILE\.claude\skills\altium-kicad\scripts\stage_ascii.py" stage `
|
||||
--source-prj "E:\Altium_design\FOO\FOO.PrjPCB" `
|
||||
--migration-dir "E:\Kicad_design\FOO\_migration"
|
||||
```
|
||||
|
||||
它把整个工程复制到 `<工程目录>_ascii` staging(**原始工程一个字节都不动**),
|
||||
枚举出实际的 `.SchDoc` 并生成 `convert_to_ascii.pas`。
|
||||
|
||||
接着让用户:**先停掉 eda-agent**(不停会和 StartMCPServer 脚本冲突挂起),再在
|
||||
Altium 里 `File → Run Script` → 选生成的 `.pas` → `ConvertSchToAscii` → Run。
|
||||
|
||||
跑完验证:
|
||||
|
||||
```powershell
|
||||
python ...\stage_ascii.py verify --staging-dir "E:\Altium_design\FOO_ascii"
|
||||
```
|
||||
|
||||
**verify 通过了再回填**:`--set ascii_ok=true --set ascii_staging_dir=E:\Altium_design\FOO_ascii`
|
||||
|
||||
> ⚠️ `convert_ascii` 后面没有判定回环,回填 `ascii_ok=false` 图照样往下走。
|
||||
> 没转干净就进 KiCad 导入必然报 `Header already parsed`,白跑一轮。
|
||||
|
||||
### `prompt_kicad_import` — 用户在 KiCad 里手动导入
|
||||
|
||||
这一步**没有任何 CLI/MCP 通道**,只能人点。给用户精确路径:
|
||||
|
||||
打开 **KiCad 主程序(工程管理器)** → `File → Import Non-KiCad Project →
|
||||
Altium Project...`
|
||||
- 源:staging 里的 **`_ascii` 版** `.PrjPCB`(选错成原始工程就前功尽弃)
|
||||
- 目标:target_dir
|
||||
- 点 OK 等待,十几页 + 多层 PCB 要几十秒到几分钟
|
||||
|
||||
导完常见现象:报告里只有 `IEEE_SYMBOL` 未处理记录(无害);结构是扁平的,
|
||||
可能多出重复的 `.kicad_sch`(确认无引用后删掉)。
|
||||
|
||||
用户确认导完:`--set imported=true`
|
||||
|
||||
### `check_file_count` — 文件数核对
|
||||
|
||||
Altium 侧基线(原理图页数 + 1 块 PCB)对比 target_dir 下
|
||||
`*.kicad_sch` + `*.kicad_pcb` 的计数。payload 里的 `kicad_glob_hint` 是图那侧
|
||||
glob 出来的预填值(`-1` 表示它数不到),你要自己核实。
|
||||
|
||||
`--set altium_count=16 --set kicad_count=16`
|
||||
|
||||
不一致会退回重导(最多 3 次)。不一致时先看是不是多了重复页,或者某页导入失败。
|
||||
|
||||
### `rebuild_rules` — 设计规则重建 + PCB 修复
|
||||
|
||||
三件事,顺序不能反:
|
||||
|
||||
**1) 改 `.kicad_pro` 的规则**:按基线 `pcb_design_rules.json` 设间隙/线宽/过孔/
|
||||
孔/网络类。导入只搬几何,规则用的是 KiCad 默认(比 Altium 严),不改的话 DRC
|
||||
会有几千条误报。
|
||||
|
||||
**2) 回填焊盘网络 + 批改 zone clearance**(先干跑看量):
|
||||
|
||||
```powershell
|
||||
$KP = "D:\KiCad\10.0\bin\python.exe" # ~\skills_env.md 的 KICAD_PYTHON
|
||||
& $KP "...\scripts\fix_pcb.py" --board "E:\Kicad_design\FOO\FOO.kicad_pcb" `
|
||||
--netlist-csv "E:\Kicad_design\FOO\_migration\reference\netlist_tabular.csv" `
|
||||
--zone-clearance-mm 0.254 --dry-run
|
||||
```
|
||||
|
||||
`--zone-clearance-mm` 要去基线 `pcb_design_rules.json` 查 **InPolygon 规则**的
|
||||
polygon clearance,别照抄 0.254。确认后去掉 `--dry-run` 真改(会自动备份板文件)。
|
||||
|
||||
**3) 重填铺铜**:让用户在 KiCad GUI 里按 `B`,或走 IPC 后端。
|
||||
**大板不要用 SWIG/pcbnew refill**,会超时甚至段错误。
|
||||
|
||||
跑一次 DRC 确认数字降下来了(`run_drc` 或 `kicad-cli pcb drc`),
|
||||
然后 `--set rules_ok=true`。
|
||||
|
||||
> 这两个坑的根因写在 `references/playbook.md` §4,值得先读:
|
||||
> **BGA 平面焊盘丢网络**(假短路的真凶,Altium 靠负片内电层隐式连接)、
|
||||
> **zone 本地 clearance 被写成 0.5mm 且会盖过网络类**(只改网络类完全无效)。
|
||||
> `rebuild_rules` 后面同样没有回环,别在没修好的时候回填 true。
|
||||
|
||||
### `compare_netlist` — 网表对齐(可回环 5 次)
|
||||
|
||||
```powershell
|
||||
conda run -n langgraph python "...\scripts\netcmp.py" `
|
||||
--kicad-dir "E:\Kicad_design\FOO" `
|
||||
--netlist-csv "E:\Kicad_design\FOO\_migration\reference\netlist_tabular.csv" `
|
||||
--out "E:\Kicad_design\FOO\_migration\netcmp"
|
||||
```
|
||||
|
||||
脚本会**逐页**导出 kicadxml(扁平结构下整体导出会漏页)、剥掉 KiCad 网名的前导
|
||||
`/`、去掉 Altium 的 `net=?` 重复行,然后按 **net partition** 比等价类 —— 不比
|
||||
网络名,两个工具命名规则不同,逐名比必然一片红。
|
||||
|
||||
一致(退出码 0)→ `--set netlist_identical=true`。
|
||||
不一致 → 看 `diff.json` 改 KiCad 对齐,`--set netlist_identical=false` 会回到这一步
|
||||
再来一轮。改不动的时候,节点级差异往往不是真错,先按 playbook §5 的三条归一化
|
||||
自查。超过 5 轮会走 safety_end。
|
||||
|
||||
> payload 里写的是「调 `/goal` 让 Claude Code 或 Codex 自主迭代」。愿意的话可以
|
||||
> 那样做;直接用 `netcmp.py` + 自己改板通常更快也更可控。
|
||||
|
||||
### `compare_gerber` — 几何等价(可回环 5 次)
|
||||
|
||||
判定基准先说死:**逐层制造几何等价**。离散铜(走线/过孔/焊盘/孔/板框)要零差异;
|
||||
铺铜纹理、丝印字形、负片内电层是**工具固有容差项,不是缺陷、修不掉**。
|
||||
|
||||
决定性证据走矢量比对,不是栅格 XOR:
|
||||
|
||||
```powershell
|
||||
& $KP "...\scripts\dump_kicad_vec.py" --board "...\FOO.kicad_pcb" `
|
||||
--out "...\_migration\gerber\kicad_vec"
|
||||
# Altium 侧用 eda-agent 导同名 JSON 到 altium_vec\(格式见 references\vector-compare.md)
|
||||
python "...\scripts\cmp_vec.py" --altium-vec ...\altium_vec --kicad-vec ...\kicad_vec `
|
||||
--layer-map ...\layer_map.json --report ...\vec_result.json
|
||||
```
|
||||
|
||||
`TOTAL unmatched primitives: 0` → `--set gerber_aligned=true`。
|
||||
|
||||
要出 Gerber 图片证据的话:KiCad 侧 `kicad-cli pcb export gerbers/drill`;
|
||||
**Altium 侧 eda-agent 生不了 Gerber**(工程没有 OutJob,`proj_run_output` 是空操作),
|
||||
必须让用户在 `File → Fabrication Outputs → Gerber Files` 手动导,参数见
|
||||
playbook §7。
|
||||
|
||||
### `acceptance_report` — 验收报告
|
||||
|
||||
写 `<migration_dir>\verification_report.md`,必须包含:
|
||||
|
||||
1. 各阶段 PASS/FAIL 与关键数字(页数、元件数、节点数、走线/过孔匹配数)
|
||||
2. **明确列出三项工具固有差异**(负片内电层 / 铺铜填充纹理 / 丝印字体)
|
||||
及其根因,注明是容差项不是缺陷 —— 不写清楚,后面看报告的人会当成没做完
|
||||
3. 证据文件索引
|
||||
|
||||
`--set report_path=E:\Kicad_design\FOO\_migration\verification_report.md`
|
||||
|
||||
回填后图结束,`ak_flow.py` 打印 `[DONE]`。
|
||||
|
||||
---
|
||||
|
||||
## 铁律速查
|
||||
|
||||
1. **原理图必须先转 ASCII**。AD26 二进制 `.SchDoc` 会让 KiCad 报
|
||||
`Header already parsed`。PCB 侧没这问题,只有原理图。
|
||||
2. **转 ASCII 之前先停 eda-agent**。Altium 一次只能跑一个脚本,桥接自己就是个脚本。
|
||||
3. **基线快照要趁桥接活着做完**,尤其 tabular 网表 —— 后面回填网络和比网表都靠它。
|
||||
4. **KiCad 导入只能人工点**,源必须选 `_ascii` 版。
|
||||
5. **`kicad-cli pcb import` 不能替换主板**,那会切断原理图↔PCB 关联,只能当参考。
|
||||
6. **zone 的本地 clearance 会盖过网络类**,只改 `.kicad_pro` 无效。
|
||||
7. **网表比 partition 不比网络名**,且必须逐页导 kicadxml。
|
||||
8. **跨工具像素级一致不可能**,判定基准是离散几何等价 + 三项固有容差。
|
||||
9. **原始 Altium 工程只读**,所有写操作只作用于 staging 副本和 target_dir。
|
||||
|
||||
## 排错
|
||||
|
||||
| 症状 | 处理 |
|
||||
|---|---|
|
||||
| resume 后又停在同一个节点 | 回填是空的或全 falsy。langgraph 把它当没提供。加一个非空键。 |
|
||||
| `app_ping` 突然不通 | 桥接空闲 10 分钟自停了。让用户重跑 `StartMCPServer`。 |
|
||||
| Altium 脚本跑起来卡死 | eda-agent 没停,两个脚本冲突。停掉再跑。 |
|
||||
| 导入报 `Header already parsed` | ASCII 没转干净,或者源选成了原始工程。`stage_ascii.py verify` 查。 |
|
||||
| 导入后 DRC 几千条 | 正常。先按基线改 `.kicad_pro` 规则,再回填焊盘网络、重填铺铜。 |
|
||||
| 一堆 "GND vs 空网络" 短路 | BGA 平面焊盘丢网络。`fix_pcb.py` 回填。playbook §4.1。 |
|
||||
| 改了网络类但铺铜避让没变 | zone 本地 clearance 盖过了。`fix_pcb.py --zone-clearance-mm`。playbook §4.2。 |
|
||||
| refill 超时/段错误 | 大板别用 SWIG。GUI 里按 `B`,或 IPC 后端。 |
|
||||
| 网表比对差一堆节点 | 多半是某页 kicadxml 没导出成功,看 `netcmp.py` 的 `[export] N/M`。 |
|
||||
| 矢量比对某层全 unmatched | `layer_map.json` 配错了。不带 `--layer-map` 跑一次看两侧每层走线数。 |
|
||||
| `[SAFETY-END]` | 某个回环超了重试上限,图优雅退出了。修好卡住的那步再 `start --restart` 重跑;确实需要更多轮次就加 `--max-netlist-retry 8` 这类参数。 |
|
||||
| kicad-cli 输出 `UnicodeDecodeError` | 别用 `text=True` 收 kicad-cli 的输出,中文 Windows 会按 GBK 解 UTF-8。`netcmp.py` 已处理。 |
|
||||
| `ModuleNotFoundError: langgraph` | `conda run -n langgraph pip install langgraph langgraph-checkpoint-sqlite` |
|
||||
| `ImportError: pcbnew` | `fix_pcb.py` / `dump_kicad_vec.py` 必须用 KiCad 自带 python 跑,不是 conda 的。 |
|
||||
|
||||
## 深入
|
||||
|
||||
- `references/playbook.md` — 每个坑的根因、XMOD/GQ 两次迁移的实测数字、
|
||||
各阶段该有的判定基准和证据目录约定。卡住了先读这个。
|
||||
- `references/vector-compare.md` — `altium_vec/` 各 JSON 的字段格式、
|
||||
`layer_map.json` 怎么定、结果怎么读。
|
||||
- 图的拓扑与 interrupt 契约:`E:\LangGraph_Design\Altium-Kicad\Notes\Task04.md`
|
||||
Reference in New Issue
Block a user