Files
2026-09-09 09:51:06 +08:00

15 KiB
Raw Permalink Blame History

name, description
name description
altium-kicad 把 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 = 出错。

$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:

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。

跑完验证:

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(先干跑看量):

$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 次)

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:

& $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