ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

KiCad PCB文件格式深度拆解:从s-expression到脚本化实战

KiCad PCB文件格式深度拆解:从s-expression到脚本化实战 前两天有人问我“KiCad的PCB文件怎么全是括号和英文标签我想直接改个封装名非得打开PCBnew不可吗”这个问题问到点子上了。作为一个常年跟KiCad打交道、偶尔还要翻源码看格式定义的人我确实积累了不少关于.kicad_pcb文件格式的笔记。这个文件就是KiCad PCB设计里最核心的ASCII文本文件围绕它你能做Git差异对比、脚本批量修改、自动审查、格式互转甚至在没有GUI的服务器上直接生成Gerber。这篇文章就把我读代码和格式定义时的随记整理出来从文件头一路拆到焊盘和覆铜再补几个直接用文本/脚本改PCB的实战姿势。适合正在学KiCad、想把PCB设计流程自动化或者被Altium/EasyEDA格式束缚想转出来的朋友。看完你会发现PCB文件格式并不可怕它甚至比想象中更有趣。1. 为什么值得读PCB文件格式不是炫技是真的有用很多人觉得“我会画板就行了文件格式是工具干的事”。这话在只用GUI画板时成立但一旦你遇到下面这些场景不懂文件结构就会非常难受。1.1 纯文本文件带来的三大红利KiCad从6.0版本以后PCB文件基本统一为.kicad_pcb这个文件本质是一段结构化文本。相比某些EDA导出的二进制或私有加密格式文本格式有三大直接好处。Git友好你可以把PCB文件放进版本库里每次改动都能通过diff看到哪条走线变了、哪个焊盘挪了。我在团队里就是用这种方式做原理图和PCB审查比人肉看图靠谱太多。可脚本化批量改网络名、批量替换封装、检查所有走线是否满足最小线宽这些用一段Python或sed就能完成。对于几十上百个电阻电容的板子这个优势是压倒性的。可自动生成很多参数化、重复性的PCB完全可以用Python输出合法格式交给KiCad打开。这也是很多自动布线、PCB生成器的底层原理。再加上KiCad另外提供了命令行工具kicad-cli你可以不打开界面直接完成DRC检查、Gerber导出等操作。这些功能能成立前提就是文件格式是公开、可读的。1.2 它不是XML而是s-expression第一次打开.kicad_pcb文件的人通常会被满屏括号吓到。它既不是JSON也不是XML而是Lisp风格的s-expression符号表达式。结构上它跟JSON是远房亲戚JSON用大括号和冒号描述对象KiCad用圆括号和缩进描述嵌套结构。你可以把它想成一套“俄罗斯套娃”。最外面一层叫kicad_pcb包住板子的全部信息里面一层是general、nets、footprint、segment这些块每个块里又继续嵌套属性比如坐标、尺寸、层名。比如(kicad_pcb (general (thickness 1.6) ) )thickness 1.6表示板厚1.6mm单位默认是毫米坐标系统原点是图纸上的某个参考点。简单说这个文件就是把PCB的全部物理信息用“对象参数”的形式原样写出来。理解了这套规则后面拆结构就轻松了。1.3 动手之前先记住两条底线在开始改文件之前有两条底线必须刻在脑子里。先备份KiCad保存时会自动生成.kicad_pcb-bak文件但你自己动手改文件前最好再手动复制一份。我踩过一次坑用脚本批量替换时正则是写错的结果把几个关键括号删掉了整个文件打不开最后只能从半小时前的备份恢复。理解“引用关系”PCB里的网络不是靠名字直接关联而是靠“网络编号”关联。一个名叫GND的net可能编号是57那么所有走线、焊盘、过孔里都要写net 57。如果只改了网络名却忘了改引用编号就会出现大面积断连。这个后面会展开说。也就是说读PCB文件格式本质上是在读一张由编号串联起来的连接网表加上一堆几何对象。把这条主线抓住剩下的都是细节。2. 逐段拆解从文件头一路读到布线现在进入正题。我按照一个真实.kicad_pcb文件的顺序从头到尾拆给你看。2.1 文件头版本号是最先要确认的东西打开文件前几行长这样(kicad_pcb (version 20240108) (generator pcbnew) (generator_version 8.0.0) (general (thickness 1.6) ) )version是文件格式版本号不是KiCad软件版本号。generator和generator_version记录这个文件是哪个程序、哪个版本生成的。看到generator pcbnew就说明是PCB编辑器保存的。这里最容易踩的坑是版本兼容。KiCad 6.x通常读不了KiCad 8.x保存的高版本文件轻则弹警告重则直接拒绝打开。所以如果你拿到别人发来的工程先看这个version字段再确认自己安装的KiCad支不支持。我把日常遇到的文件版本和常见KiCad版本对应关系整理了一张表仅供参考具体以官方Release Notes为准格式版本号version字段常见于KiCad版本说明202111276.0前后老一批工程常见202208316.99/7.0开发与发布期7.0早期的文件202401088.0系列目前最主流更高版本号8.99/9.0开发版建议升级软件后再打开看到比你自己KiCad版本更新的version号最稳妥的做法是让对方另存为兼容格式或直接升级KiCad千万别硬开。2.2 net区段一张全网通讯录继续往下翻会看到一组net定义(net 0 ) (net 1 GND) (net 2 3V3) (net 3 NET_CLK_USB)net后面第一个数字是网络编号第二个是网络名。编号表示“身份”名字方便人读。排在第0位的通常是空网络供不连接网络的焊盘或图形使用。为什么编号和名字要分开因为PCBnew内部处理连接关系时走线、焊盘、过孔都只记录编号查询编号再去net表里翻名字。这样处理效率高而且允许两个不同编号的网络恰好同名虽然不推荐。我看过不少新手改文件时只把(net 1 GND)改成(net 1 GND_MAIN)却没有更新其它对象里的net 1。结果打开后图面上名字是新的但连接关系跟原设计没变容易造成误解。正确的做法是“名录和引用一起改”后面第4章我会给一个完整的脚本示例。2.3 segment与via铜线是这样躺进板子里的网络定义之后就是物理布线对象。最典型的是segment(segment (start 100.5 78.2) (end 103.8 78.2) (width 0.25) (layer F.Cu) (net 1) )segment就是一段直线铜皮。start和end是起点和终点坐标width是线宽layer是所在层net是对应的网络编号。整块板的走线就是成百上千个这样的segment首尾相接拼出来的。看到这里你就明白为什么说PCB文件本质是“几何对象网络关系表”。它不像原理图那样有“器件”概念而是一堆线段、圆弧、焊盘、覆铜、文字按层摆放。过孔via的结构类似(via (at 102.1 78.2) (size 0.6) (drill 0.3) (layers F.Cu B.Cu) (net 1) )at是过孔中心坐标size是外径drill是钻孔直径layers是贯穿的两层。这里注意字段名是layers而不是layer因为过孔至少跨越两层而且还可能是盲埋孔或背钻结构。如果你写脚本解析文件这个细节必须区分清楚。另外KiCad布线时还会写(arc ...)表示圆弧走线(gr_line ...)表示辅助线或板框图形(text ...)表示丝印文本。它们的共同特征是都有坐标、层、净对象或图形类型解析逻辑大同小异。3. footprint、焊盘与覆铜封装是怎么嵌进文件里的网络和走线讲完接下来是PCB里最容易让人看花眼的部分footprint。3.1 footprint实例的层层嵌套PCB里的每一个元件实例都以footprint开头里面嵌套一大堆子块(footprint Resistor_SMD:R_0603 (layer F.Cu) (uuid 2f9a5e1f-...) (at 45.6 30.2 90) (fp_text reference R1 (at 0 -1.2) (layer F.SilkS) (effects (font (size 1 1) (thickness 0.15))) ) (fp_text value 10k (at 0 1.2) (layer F.Fab) (effects (font (size 1 1) (thickness 0.15))) ) (pad 1 smd roundrect (at -0.5 0) (size 0.8 0.9) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.2) ) )第一行是封装库名比如Resistor_SMD:R_0603告诉你这个封装来自哪个库。layer表示封装放在哪一面最常见是F.Cu顶层或B.Cu底层。uuid是唯一标识符。这个字段特别关键因为KiCad通过uuid把PCB上的封装实例和原理图中的符号对应起来。如果你用脚本复制一个footprint却忘了生成新uuid同步更新时大概率会出乱子。fp_text reference R1是位号fp_text value 10k是标称值或型号。你是不是觉得奇怪标称值为什么要写进PCB文件因为KiCad允许PCB里存储元件属性这样即使原理图不在也能从PCB上识别出元件信息。3.2 pad字段逐项拆解焊盘是元件和铜箔之间的桥梁字段看似复杂其实拆开就几个点(pad 1 smd roundrect (at -0.5 0) (size 0.8 0.9) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.2) )1是焊盘编号对应原理图引脚号。smd指表贴焊盘如果是通孔封装则是thru_hole。roundrect是焊盘形状其它还有circle、rect、oval等。at -0.5 0是焊盘相对封装原点的坐标注意是“相对”不是绝对坐标。size是焊盘尺寸。layers决定这个焊盘覆盖哪些层F.Cu表示焊盘铜层F.Paste表示钢网层F.Mask表示阻焊开窗。做封装时如果漏了钢网层贴片时就刷不上锡膏这是很隐蔽的坑。roundrect_rratio是圆角矩形焊盘的圆角比例数值越大越接近椭圆。如果是通孔焊盘还会有drill字段定义钻孔直径。有些焊盘还带(net 1 GND)表示它连接到了哪个网络。这是PCB上物理连接关系的一个重要来源做网表检查时绝对不能忽略。3.3 zone覆铜与Keepout再往下翻会看到zone块这就是覆铜区域(zone (net 1) (layer F.Cu) (polygon (pts (xy 10 10) (xy 20 10) (xy 20 20) (xy 10 20) ) ) (fill (thermal_gap 0.25) ) )zone同样要写网络编号和层然后用多边形顶点定义覆铜范围。KiCad保存时会附带填充参数但铜箔实际形状是打开软件时重新计算的所以直接看文本时你看到的是多边形边界和规则参数而不是每一小块铜。与此相对的还有keepout区域相当于“禁布区”。这类区域没有网络编号只用来划定不能在哪些地方走线或放元件。做板时如果发现某个区域怎么都布不进线去文件里搜keepout基本上能找到原因。4. 用文本和脚本改PCB的实战姿势格式看懂了接下来就是实践。我不推荐你永远靠图形界面来改板有些批量操作用文本和脚本真的是秒杀级效率。4.1 改板名与日期一条sed命令就够了最常见的需求是改板名。在PCB文件里板名存在title_block下(title_block (title My_Board_V1) (date 2025-03-15) )要改名字一条sed命令就行sed -i s/(title My_Board_V1)/(title My_Board_V2)/ project.kicad_pcb这里要提醒一句sed的-i命令是直接改写原文件的如果正则写错改完就找不回原内容了。我建议先复制一份再操作cp project.kicad_pcb project.kicad_pcb.bak sed -i s/(title My_Board_V1)/(title My_Board_V2)/ project.kicad_pcb改完以后用PCBnew打开在“图纸设置”里就能看到新板名。这个方法在批量出多个版本板子时特别好用省去一个个打开工程手动改标题的功夫。4.2 批量替换网络名先改名录再改引用假设你有一块板子所有标着3V3的网络要统一改名为VCC_3V3。如果网络名出现在多个位置用GUI一个个改会疯掉。用脚本更快。我的策略分三步第一步用grep看看网络名出现在哪些位置grep -n 3V3 project.kicad_pcb第二步确认网络编号。找到(net 5 3V3)这个定义记下编号5。注意3V3可能不止一个net定义需要把每个相关的编号都收集起来。第三步写一个Python脚本先改(net 编号 名字)再把所有对象里的(net 编号)一并处理import re content open(project.kicad_pcb, encodingutf-8).read() # 假设我们要把网络编号 5 的名字从 3V3 改为 VCC_3V3 # 1. 改定义处的名字 content re.sub(r\(net 5 3V3\), (net 5 VCC_3V3), content) # 2. 不需要改引用因为编号5没变 # 但如果要连编号一起改必须同步处理所有 segment/via/pad/zone 里的引用 open(project.kicad_pcb, w, encodingutf-8).write(content)脚本里那句注释就是核心概念如果只改名字、编号不变连接关系是不受影响的。但如果有一天你连编号也想换就必须把所有引用旧编号的对象全部替换掉否则文件里会出现“悬空网络”。这里多说一句Python处理文本时一定要指定encodingutf-8。KiCad的PCB文件默认UTF-8但如果你用记事本在Windows上保存过可能变成带BOM的格式导致脚本解析出第一行多了几个不可见字符。我遇到过这个问题当时调试了半小时才发现是BOM在作怪。4.3 用Python检查文件有没有被改坏文本文件最怕括号不配对。s-expression要求每个开括号都有对应的闭括号一个不匹配整个文件就废了。所以我每次批量改完都要跑一个括号配平检查。写个简单脚本from pathlib import Path text Path(project.kicad_pcb).read_text(encodingutf-8) balance 0 for i, ch in enumerate(text): if ch (: balance 1 elif ch ): balance - 1 if balance 0: print(f第 {i} 个字符处出现多余右括号) break else: print(括号配平OK最终深度:, balance)这只是最基础的防线不是万能的。括号配平不代表结构合法字段拼写错误、层名不存在、net编号悬空都是括号配平看不出来的。但作为快速检查它已经能拦住80%的“打不开”问题。更靠谱的验证方式是把改好的文件用kicad-cli做一次DRCkicad-cli pcb drc project.kicad_pcb如果命令行能正常跑完并输出结果说明文件结构基本没问题。这一步比打开GUI更快适合放脚本流水线里做自动回归。4.4 与EasyEDA/其他格式互转的启示现在很多人是从嘉立创EDA或其它工具转过来的听到KiCad文件格式纯文本第一反应都是“那我能不能把EasyEDA的PCB转成KiCad”思路其实一样。EasyEDA的工程文件本质上也是JSON格式里面同样有EDA层、封装、走线等描述。转格式的核心工作就是把这些JSON对象映射成.kicad_pcb里的s-expression。你不需要一步到位写完美转换器可以先把你常用的几种对象焊盘、segment、via映射出来跑通一个小板子再逐步扩展。这也是我强烈建议你读懂.kicad_pcb的原因。转换工具的背后就是对格式的深度理解。你读懂了KiCad这一端再看其它格式时就有对照系遇到转换问题能自己动手改文件而不是干等工具更新。5. 常见问题与排查实录格式玩多了必然碰到各种奇葩问题。我把频率最高的几个记下来相当于一个速查表。5.1 文件打不开多半是这三个原因现象常见原因处理方法打开提示“格式版本过高”文件的version比你安装的KiCad新换新版KiCad或让对方降版本保存打开闪退/报解析错误括号不配对或字段被改坏用括号配平脚本检查从.kicad_pcb-bak恢复中文字符变乱码或无名错误文件编码被改成非UTF-8统一用UTF-8保存不要用记事本乱存排第一名的永远是版本兼容。好多人从网上找工程解压出来一看打不开第一反应是“文件损坏”。其实只要看看version是多少基本就能定位。第二名的括号问题是手动编辑导致。我喜欢用s-expression做批量修改但每次改完都必须跑括号检查这是习惯动作。真正危险的是用“替换全部”这种粗暴操作一个正则没写好就把成片括号吃掉了。5.2 网络改错了为什么鼠线一片乱我之前说过的“网络编号与名字分离”这里再展开一次。有次我批量改名时脚本写得不对把不同网络定义里的编号搞串了结果打开PCBnew后整板鼠线疯狂刷新明明应该连GND的焊盘全部显示为未连接。排查过程是这样的先打开.kicad_pcbgrep出所有(net定义发现有一个编号在名录里消失了但很多segment仍然引用它。也就是说出现了“悬空引用”。修这个问题的思路很简单要么补回一个同名编号的网络定义要么把那些segment的引用改成正确编号。用脚本处理也很快关键是你得知道“名单”和“引用”是两码事。这个认知能帮你少走大量弯路。5.3 用kicad-cli做文件体检最后再安利一个工具链上的组合拳。每次改完文件我会依次执行三件事kicad-cli pcb export gerbers --layers F.Cu,B.Cu,Edge.Cuts project.kicad_pcb kicad-cli pcb drc project.kicad_pcb kicad-cli pcb export pdf project.kicad_pcb如果这三条命令都能成功跑完基本可以确认PCB文件结构是健康的。Gerber能导出说明几何对象都能被正确解析DRC能跑说明网络关系合法PDF能出说明显示层面没有明显异常。这套流程完全可以做成脚本放进CI每天晚上自动跑一次。我个人在实际操作中的体会是读.kicad_pcb文件格式这件事最初可能只是出于好奇但不知不觉就变成了工作流的一部分。它让你从“被工具的GUI牵着走”变成“自己掌握板子的数据”。如果你手头正好有一块改起来很痛苦的老板子不妨把它另存为.kicad_pcb打开文本编辑器从头到尾刷一遍按这篇文章的顺序读下去。我敢打赌下次再遇到批量调整、格式转换问题你心里会比现在踏实得多。
返回列表