Altium Designer交互式BOM生成:从数据导出到排错实战
2026/9/16 10:42:38 网站建设 项目流程

简介:InteractiveHtmlBomForAD 是一份面向 AD 设计人员的快速 BOM 生成前端工具包,基于 HTML、JavaScript 等技术实现,可在浏览器中直接解析 AD 设计数据,生成结构清晰、便于协作和审核的物料清单,解决手动编制 BOM 效率低、易出错的问题。压缩包共 30 个文件,以 js(17 个)、html(3 个)、css(2 个)等前端文件为主,辅以 bat 批处理脚本、ini 配置文件、prjscr 项目脚本及 md 说明文档,整体仅 139KB,核心逻辑集中在 core 与 modules-lite 目录,dist 目录则提供可直接运行的打包产物。工具支持通过 config.ini 自定义解析规则和输出格式,Initialize.bat/UnInitialize.bat 可快速初始化和清理环境,适合熟悉前端技术的 AD 用户集成到现有流程中。已有 1035 人学习下载,对于需要提升 BOM 编制效率和准确性的工程团队,是一份轻量而实用的参考实现。

1. 拆开 InteractiveHtmlBom 压缩包之前,先想清楚 BOM 为什么需要交互

解开这个 zip,里面是一套为 Altium Designer 准备的数据导出和 HTML 渲染脚本。熟悉 AD 的人都知道,传统 BOM 是一张静态表格,生产、贴片、维修时要拿着表格在板子上找位号,眼睛累不说还容易漏。InteractiveHtmlBom 做的事是把 PCB 的元件位置图直接嵌进 HTML,生成一个能点、能搜、能分层显示的交互式 BOM。这个工具解决的是“位号、坐标、封装和物料清单各在一处”的断档问题。适合正在做 PCB 评审、试产备料或文档归档的硬件工程师、工艺工程师和产线管理者。下面按数据从 AD 导出的顺序,把这条链路拆开讲。

2. InteractiveHtmlBom 的数据链路:AD 导出的位号、坐标与封装如何组成 HTML

2.1 从 AD 里正确导出三类文件

InteractiveHtmlBom 本身不解析 AD 的工程文件,它吃的是 AD 导出的纯文本数据。所以第一步不是写脚本,而是从 AD 里导出三样东西:坐标文件、BOM 表、板框信息。

坐标文件在 AD 里叫 Pick and Place 文件,路径是File -> Assembly Outputs -> Generates pick and place files。导出时需要确认单位选公制毫米,格式选 CSV 或制表符分隔的 TXT,这样后面用 Python 解析最省事。BOM 表的导出用Reports -> Bill of Materials,建议把 Designator、Comment、Footprint、Quantity 这几列固定带上,其余列按项目需要勾选。

板框信息较容易被忽略。坐标文件里有元件位置,但没有电路板外轮廓,生成的 HTML 里元件会散落在空白画布上,观感很差。常见做法是在 AD 的Keep-Out LayerMechanical Layer上画好板框,导出一份 DXF,再在脚本里读出来换算成 HTML 的板框路径。很多快速 BOM 生成工具的 zip 里已经写好了这步转换,但前提是板框层命名稳定,换板子时记得检查。

2.1.1 导出文件长什么样

坐标文件打开后大概是这样的结构:

Designator Footprint Mid X Mid Y Ref X Ref Y Pad X Pad Y Layer Rotation Comment R1 0603 1.2345 2.3456 1.2345 2.3456 1.2345 2.3456 Top 90 10k C1 0402 3.4567 4.5678 3.4567 4.5678 3.4567 4.5678 Bottom 270 100nF

BOM 文件则是一张行数很多的表,一个位号一行,同一物料在 AD 里可能拆成多行。标准的 InteractiveHtmlBom 流程要求 BOM 文件里至少有一列能唯一标识元件,通常是位号列。按 Tab 分隔时,行内不能有多余空格,否则解析器容易错位。

2.2 脚本怎么把坐标、位号和封装拼起来

拿到上面两个文件后,核心逻辑就一句话:以位号为键,把 BOM 的物料信息合并到坐标文件的每一行里。但这句话落地时有两个细节容易翻车。

第一个细节是位号一对多。AD 的 BOM 里元件按位号展开,但一个位号在坐标文件里只出现一行。如果直接按行合并,最后生成的 HTML 里元件数量对不上。正确做法是先用位号聚合 BOM 行,再按坐标文件的顺序输出。

第二个细节是顶层和底层方向。AD 的 Pick and Place 文件里,底层元件的坐标已经做了镜像换算,坐标值是成品板上从正面投影看到的位置,直接填入 HTML 即可,不要再额外做镜像。如果脚本里自己又乘了一次 -1,元件会全部翻到板框外面去。

import csv from collections import defaultdict def load_bom(path): bom = defaultdict(list) with open(path, encoding="utf-8-sig", newline="") as f: reader = csv.DictReader(f, delimiter="\t") for row in reader: des = row["Designator"].strip() bom[des].append({ "Value": row.get("Comment", ""), "Footprint": row.get("Footprint", ""), "Quantity": row.get("Quantity", "1"), }) return bom def merge_placement(pl_file, bom, out_file): with open(pl_file, encoding="utf-8-sig", newline="") as f, \ open(out_file, "w", encoding="utf-8", newline="") as g: reader = csv.DictReader(f, delimiter="\t") writer = csv.DictWriter(g, fieldnames=reader.fieldnames + ["Value", "Qty"]) writer.writeheader() for row in reader: rows = bom.get(row["Designator"].strip(), []) if rows: row["Value"] = rows[0]["Value"] row["Qty"] = len(rows) writer.writerow(row) merge_placement("pick_and_place.txt", "bom.tsv", "merged.txt")

这段代码先用encoding="utf-8-sig"读文件,是为了滤掉 Excel 或 AD 在 CSV 头部留下的 BOM 字节序标记,不加这个参数时第一列的列名会变成\ufeffDesignator,后面按列名取值全部取空。后面合并输出时用集合去重了同一个位号的多行 BOM 数据,Qty列反映的是这个位号实际占几个位置。如果你用的 AD 版本导出的坐标文件列名不是Designator而是RefDes,改一下DictReader取值即可,其余逻辑不用动。

3. AD 快速 BOM 生成工具本地跑通:最小命令与关键参数

3.1 先说最小可用的调用方式

如果你拿到的 zip 里只是脚本和模板,没有自带可执行文件,那就需要自己准备 Python 环境。先确认python --version是 3.8 以上,然后安装渲染依赖。常见做法是用 pip 安装interactivehtmlbom这个包,它会自带命令行入口。

python -m pip install interactivehtmlbom python -m interactivehtmlbom \ --layout merged.txt \ --bom bom.tsv \ --layer-view FB \ --dark-mode \ --output board_bom.html

--layout传入上一步合并后的坐标文件,--bom传入原始的 BOM 文件。这里要强调一个容易误解的点:--bom参数不是必须的,如果你只传--layout,生成的 HTML 里只有元件位置图而没有任何物料信息。对于只做位置确认的场景这够用,但既然目标是快速 BOM 生成工具,BOM 文件必须传。

--layer-view FB表示同时显示顶层和底层,后续在 HTML 界面里可以手动切换。--dark-mode只是改变底色,不影响坐标精度,喜欢浅色背景的删掉即可。--output指定输出 HTML 的路径,默认是ibom.html

3.1.1 输出失败时先看什么

命令行跑完没有任何报错,但生成的 HTML 里元件数量明显比板上少,这种情况几乎都是合并那一步出了问题。回到上一节的merge_placement.py,在两个csv.DictReader之间分别打印一列位号做对比。

python -c " import csv for p in ['pick_and_place.txt', 'bom.tsv']: with open(p, encoding='utf-8-sig') as f: r = csv.DictReader(f, delimiter='\t') print(p, len([x for x in r])) "

位号数量对不上时,去检查 AD 导出 BOM 时是否勾选了Export to Excel并设置成Tab Delimited。AD 默认导出为.xlsx,选成这个格式后脚本读不了,命令行会直接报KeyError: 'Designator',看到这个错误先回来改 AD 的导出选项。

3.2 决定 HTML 好不好用的参数表

参数名可选值作用备注
--layer-viewF/B/FB控制生成文件中包含顶层、底层还是双层默认FB,单面 PCB 可以改成F减小文件体量
--bom-viewgrouped/list左侧 BOM 面板显示方式grouped按物料合并,list按位号逐条显示
--show-fabrication显示助印层和丝印层加了之后丝印字符会压住焊盘,适合工艺检查
--extra-fields列名列表把 BOM 里额外的列带进 HTML 元件详情和搜索例如供应商、封装名
--group-fields列名列表多个列做分组时用到常见做法是"Value,Footprint"两个字段同时分组
--no-compression关闭 HTML 压缩生成速度慢但便于修改模板,调试时用

这张表是 InteractiveHtmlBom 在 AD 场景下最常用的几个。--extra-fields值得多说一句:如果你希望 HTML 里点某个元件能直接看到“厂家”“订货号”这些字段,忘了加这个参数,左侧 BOM 列表里就永远只显示位号、数值、封装三列,别等到产线发来反馈才想起来。

3.3 多板或拼板时怎么同时出图

拼板项目在 AD 里常把一个 PCB 文件复制多个原点拼在一起。直接导出再生成 HTML,会出现整板元件连成一大片、板框分不清的情况。处理办法是在 AD 里为每个小板分别设置原点,然后逐个导出 Pick and Place 文件。

for file in board_a.txt board_b.txt; do python -m interactivehtmlbom \ --layout "$file" \ --bom "${file%.txt}.tsv" \ --layer-view FB \ --output "${file%.txt}.html" done

这个循环每条命令的逻辑和单个文件完全一致,区别只在于用 shell 变量把三个文件名串起来。批处理跑完后,拼板的每块小板都有独立的 HTML,评审时逐块打开,比在一个文件里切换原点方便得多。

4. 坐标原点、镜像和编码:InteractiveHtmlBom 排错实战

4.1 元件整体偏移 2 毫米但相对位置没错

症状是生成的 HTML 里所有元件都落在板框外同一个方向,移动一下 HTML 画布能看到元件之间距离完全正确,就是整组位置不对。这说明坐标数据本身没问题,是坐标原点和 AD 里的原点没对齐。

AD 的坐标文件有一个不少工程师没注意的特性:导出的坐标是相对于用户原点,不是绝对原点。如果打开 PCB 文件后没有手动设置过原点,用户原点和机械坐标系的原点可能差出好几个毫米。

解决办法是在 AD 里用Edit -> Origin -> Set把原点重新设置到 PCB 板框左下角,再重新导出坐标文件。设置完成后在 PCB 编辑器左下角状态栏确认坐标显示为X: 0mm Y: 0mm,此时导出的文件才可以和 DXF 里板框坐标对齐。

提示:已经出过一版 HTML 给产线时,临时改原点再重新导出会造成新旧版本坐标不一致。建议项目一开始就约定原点固定在板框左下角,并写进评审检查清单。

4.2 元件旋转角度对不上板子

HTML 里元件位置正确,但角度全部转错,常见于底层元件。AD 坐标文件中 Rotation 列对顶层和底层用同一套规则,底层元件在 Pick and Place 文件里已经换算成从顶层俯视的角度。如果你在脚本里做了angle = 360 - angle之类的转换,底层元件反而会被转成 90 度倍数加一个斜角。

正确做法是角度直接透传,不做任何换算。只有一种情况需要手动处理:坐标文件来自某些第三方转换工具时,底层角度会保持 AD 内部值,这时候才需要补一个 180 度旋转。判断办法是找一个 0603 电阻对比它丝印的方向,HTML 里显示的方向和 AD 里一致就不用改。

row["Rotation"] = row["Rotation"].strip() if float(row["Rotation"]) < 0: row["Rotation"] = str(float(row["Rotation"]) + 360)

这段代码只做归一化,把 AD 偶尔导出的负角度统一到 0 到 360 度之间。float(row["Rotation"])支持带小数点的度数,有些封装会旋转到 12.5 度这种非直角角度,转换后依然保留精度。如果角度列出现了空字符串,说明这一行可能是板框或钻孔标记误入坐标文件,直接跳过不处理比强行补 0 更安全。

4.3 中文注释变成乱码

BOM 里器件值写中文,生成的 HTML 里显示成乱码,原因几乎都出在读文件那一步的编码上。AD 导出 CSV/TXT 文件在中文 Windows 上默认是 ANSI 编码,即 GBK,而 Python 默认用 UTF-8 读取,自然乱码。

处理方式有两种。第一种是在代码读取时指定 GBK,如果你拿到的 zip 里脚本写的是 UTF-8,则需要改动打开文件的open()函数。第二种更稳妥,直接在 AD 导出 BOM 时把格式改成 CSV,并在 AD 的偏好设置里把默认编码改成 UTF-8,一劳永逸。

def load_bom(path): for enc in ("utf-8-sig", "gbk", "gb18030"): try: with open(path, encoding=enc, newline="") as f: reader = csv.DictReader(f, delimiter="\t") rows = [r for r in reader if any(r.values())] return rows except UnicodeDecodeError: continue

这段代码的逻辑是一次尝试三种编码直到成功,gb18030gbk覆盖字符更全,如果 BOM 里出现生僻字,GBK 会解码失败,GB18030 能兜住。any(r.values())是为了过滤掉行尾多余的空行,因为 AD 导出的文件结尾经常有一个只有分隔符的空行,不滤掉会在 HTML 中显示一个没有位号的幽灵元件。

4.4 元件数量对但点击后不跳转

HTML 里所有元件都在,但点左侧 BOM 列表里的某一项时,元件不高亮。这属于按钮和元件的关联 ID 对不上。InteractiveHtmlBom 的联动机制是给每个元件分配一个以位号为基础的 ID,如果 BOM 数据里有两个完全相同的位号,ID 会冲突,点其中一个时浏览器不知道该高亮哪个。

根治办法是在合并步骤为每个物理位置生成唯一 ID,而不是直接用位号。常见做法是在脚本输出时给位号加一个自增序号,例如R1_1R1_2。同时把原始位号放到extra-fields里,这样 BOM 界面仍能看到 R1,内部索引不会重复。

5. 让 HTML BOM 更顺手:批处理生成与内容验证

5.1 一个命令跑完整个项目

一个稍大的混合信号板卡,散热焊盘、去耦电容、连接器加起来轻轻松松上千个位置。逐个文件生成 HTML 的效率太低,zip 工具里通常会有个批处理脚本,没有就自己补一个。

@echo off set SCRIPT_DIR=%~dp0 for %%f in ("%SCRIPT_DIR%output\*.txt") do ( echo Processing %%f python -m interactivehtmlbom ^ --layout "%%f" ^ --bom "%SCRIPT_DIR%output\%%~nf.tsv" ^ --layer-view FB ^ --extra-fields "Manufacturer,Supplier_PartNumber" ^ --output "%SCRIPT_DIR%html\%%~nf.html" )

这个批处理遍历output目录下所有坐标文件,%%~nf取文件名不带后缀,用来匹配同名 BOM 文件。%~dp0取脚本自身所在目录,避免在别的盘符下运行时路径出错。执行前需要确认 BOM 文件名和坐标文件名完全一致,否则匹配失败会生成一个没有物料信息的空 HTML。

批处理场景下建议把--no-compression加上,调试时输出速度快很多。等确认所有板卡的 HTML 内容无误后,再重新跑一遍不带该参数的正式版。

5.2 用代码做一次坐标还原验证

生成 HTML 后花五分钟做一次自动化验证,能避免把带问题的 BOM 发给产线。思路是直接解析生成的 HTML,统计里面的元件数量,再和 AD 里的标注数对比。

import re html_text = open("board_bom.html", encoding="utf-8").read() ids = set(re.findall(r'id="([^"]+?)"', html_text)) has_ref = re.findall(r'data-ref="([^"]+?)"', html_text) print(f"元件 ID 数量: {len(ids)}") print(f"带位号数量: {len(has_ref)}") print("位号重复:", len(has_ref) != len(set(has_ref)))

这个验证段落里,id是元件唯一标识,style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;" />

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询