Skip to main content

easyeda-draw-checking

Schematic verification and quality checking for EasyEDA Pro. Invoke when verifying layout, checking for overlaps, validating designators, or running design rule checks.

Source facts

Repository
kukucaiCndy/embedded_ai_skills
Last source activity
July 30, 2026 at 08:53
Detected SKILL.md language
Chinese
Stars
60
Forks
12

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
easyeda-draw-checking
description
Schematic verification and quality checking for EasyEDA Pro. Invoke when verifying layout, checking for overlaps, validating designators, or running design rule checks.
# 原理图检查 布局验证、重叠检测、位号检查、DRC 的完整指南。 > **⚠️ 重要**:所有检查必须通过 CLI 执行,禁止使用 curl 直接调用 API。 --- ## 0. 快捷入口:CLI 一键检查 按绘制阶段使用不同的检查命令: ```bash # 摆放一个模块后(每个模块摆放完必须执行) ./scripts/draw_cli.py verify-placement # 连线一个模块后(每个模块连线完必须执行) ./scripts/draw_cli.py verify-wiring # 全部模块完成后(最终提交前必须执行) ./scripts/draw_cli.py check-all # DRC 不通过时查看逐项详情 ./scripts/draw_cli.py drc --show-ui ``` --- ## 1. DRC 检查(Design Rule Check) ### 1.0 DRC API 限制(重要) > **⚠️ EasyEDA SCH_Drc API 只返回聚合统计**: > ```javascript > // check(true, false, true) 返回的是: > [{ type: "fatalError", count: 1 }, { type: "warn", count: 11 }] > ``` > **不返回每个错误的具体信息**(器件名、引脚号、错误描述等)。 > > **查看逐项详细错误的唯一方式**: > ```bash > ./scripts/draw_cli.py drc --show-ui > ``` > 这会呼出 EasyEDA 底部的 DRC 面板,面板中可看到每个错误的器件、引脚、具体描述。 ### 1.1 基础 DRC ```javascript // 仅知道是否通过 const passed = await eda.sch_Drc.check(true, false, false); // passed: true = 通过, false = 有错误 // 获取详细错误统计 const errors = await eda.sch_Drc.check(true, false, true); // 返回数组:[{ type: "fatalError"|"warn", count: N }] ``` ### 1.2 DRC 问题排查流程 ``` DRC 不通过 │ ├─ fatalError(致命错误) │ ├─ 未连接引脚 → 补全连线 或 添加 NC 标记 │ ├─ 网络短路 → 检查同一网络是否有不该连接的引脚 │ └─ 缺失网络标签 → 添加 NetFlag / NetPort │ └─ warn(警告) ├─ 空网络导线 → 为导线设置网络名 ├─ 未使用引脚 → 确认是否需要 NC 标记 └─ 去耦电容缺失 → 在 IC 电源引脚附近补充 ``` ### 1.3 使用 easyeda-draw 函数 ```javascript import utils from './scripts/draw-utils.js'; // 运行 DRC 详细检查 const result = await utils.runDrc(); // { passed: boolean, fatalErrors: number, warnings: number, details: Array } ``` --- ## 2. 重复标签检测 ### 2.1 检测原理 遍历所有 NetFlag/NetPort 图元,按坐标分组,找出同一位置放置多次的图元。 ### 2.2 使用函数 ```javascript import utils from './scripts/draw-utils.js'; // 检测重复标签 const result = await utils.detectDuplicateLabels(); // { duplicates: [{ position, items: [{id, net, type}] }] } // 自动删除重复标签(每组保留第一个) const cleanup = await utils.cleanupDuplicateLabels(); // { deleted: N, details: [...] } ``` ### 2.3 手动检测 ```javascript const allComps = await eda.sch_PrimitiveComponent.getAll(); const posMap = new Map(); for (const c of allComps || []) { // 只检查 NetFlag/NetPort (designator 为空或 "?") if (c.designator && c.designator !== '?') continue; const key = `${c.x},${c.y}`; if (!posMap.has(key)) posMap.set(key, []); posMap.get(key).push({ id: c.primitiveId, type: c.net ? 'NetFlag' : 'NetPort', net: c.net, rotation: c.rotation, }); } const duplicates = []; for (const [pos, items] of posMap) { if (items.length > 1) duplicates.push({ position: pos, items }); } ``` --- ## 3. 导线网络名完整性检查 ### 3.1 检测原理 遍历所有导线,检查网络名是否为空。 ### 3.2 使用函数 ```javascript import utils from './scripts/draw-utils.js'; // 检测无网络名的导线 const result = await utils.checkWireNets(); // { total: N, noNet: M, wiresNoNet: [{id, line}] } ``` ### 3.3 修复导线网络名 ```javascript // 逐个修复:用 getPrimitiveByPrimitiveId 获取导线 → toAsync → setState_Net → done const w = await eda.sch_Primitive.getPrimitiveByPrimitiveId(wireId); const aw = w.toAsync(); aw.setState_Net("NET_NAME"); aw.done(); ``` --- ## 4. 未连接引脚检测 ### 4.1 检测原理 对每个真实器件(有设计位号的),检查各引脚是否被导线可达或连接了网络标签。 **改进点(与旧版本差异):** | 特性 | 旧版本 | 新版本 | |------|--------|--------| | 4PIN 轻触开关 | 所有引脚都检查 | PIN1↔PIN2 内部短接,PIN3↔PIN4 内部短接,只接一对即可 | | NC 标记 | 不识别 | 有 NC 标记的引脚不算未连接 | | 分级 | 全部报 error | 区分 error (应连接) 和 warning (4PIN 冗余引脚,正常) | ### 4.2 使用 CLI ```bash ./scripts/draw_cli.py check-unconnected # 返回: { errorCount, warningCount, errors: [...], warnings: [...] } # errors: 应连接但未连接的引脚 # warnings: 4PIN 开关内部短接的冗余引脚 (正常) ``` ### 4.3 输出解读 - `errorCount > 0` → 有引脚应连接但未连接,必须修复 - `warningCount > 0` 且 `errorCount = 0` → 4PIN 开关冗余引脚,正常无需修复 - 4PIN 开关判断: 器件有 4 个引脚且符号名包含 SWITCH/轻触/4PIN/SMD_4 --- ## 4.5 短路检测(NEW) ### 原理 用并查集 (union-find) 合并物理上相连的连接点,如果同一个连通分量中有 2+ 个不同网络名 → 短路。 ### 使用 CLI ```bash ./scripts/draw_cli.py check-shorts # 返回: { shortCount, shorts: [{nets, points, wireCount, wireIds}], passed } ``` ### 典型短路场景 - VCC 和 GND 通过导线直接连通 - ROW0 和 ROW1 通过同一连接点误连 - 两个不同信号通过 NetPort 标签放在同一坐标 ## 4.7 冗余导线检测(NEW) ### 原理 检查同两个物理点之间是否有多条导线。冗余导线不会引起电气错误,但让原理图凌乱。 ### 使用 CLI ```bash ./scripts/draw_cli.py check-redundant-wires # 返回: { redundantCount, redundant: [{endpoints, count, wires}], passed } ``` --- ## 5. 布局验证(重叠检测) ### 检测所有器件重叠 ```javascript import utils from './scripts/draw-utils.js'; const { overlaps } = await utils.checkOverlaps(); // overlaps: [{comp1, comp2}] ``` ### 手动检测 ```javascript const compIds = await eda.sch_PrimitiveComponent.getAllPrimitiveId(); const bboxes = []; for (const id of compIds) { const comps = await eda.sch_PrimitiveComponent.get([id]); if (!comps || comps.length === 0) continue; const c = comps[0]; const pins = await eda.sch_PrimitiveComponent.getAllPinsByPrimitiveId(id); if (pins && pins.length > 0) { let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity; for (const p of pins) { minX = Math.min(minX, p.x); maxX = Math.max(maxX, p.x); minY = Math.min(minY, p.y); maxY = Math.max(maxY, p.y); } bboxes.push({ id, designator: c.designator, name: c.name, bbox: [minX, minY, maxX, maxY], area: (maxX - minX) * (maxY - minY), }); } } // 检查重叠 const overlaps = []; for (let i = 0; i < bboxes.length; i++) { for (let j = i + 1; j < bboxes.length; j++) { const a = bboxes[i].bbox; const b = bboxes[j].bbox; if (a[0] < b[2] && a[2] > b[0] && a[1] < b[3] && a[3] > b[1]) { overlaps.push({ comp1: bboxes[i].designator, comp2: bboxes[j].designator, }); } } } ``` ### 间距检查 ```javascript const minSpacing = 40; // 最小间距 40 单位 (0.4 inch) const tooClose = []; for (let i = 0; i < bboxes.length; i++) { for (let j = i + 1; j < bboxes.length; j++) { const a = bboxes[i].bbox; const b = bboxes[j].bbox; const ax = (a[0] + a[2]) / 2; const ay = (a[1] + a[3]) / 2; const bx = (b[0] + b[2]) / 2; const by = (b[1] + b[3]) / 2; const dist = Math.sqrt((ax - bx) ** 2 + (ay - by) ** 2); if (dist < minSpacing) { tooClose.push({ comp1: bboxes[i].designator, comp2: bboxes[j].designator, distance: dist, minRequired: minSpacing, }); } } } ``` --- ## 6. 位号检查 ### 检查缺失或异常位号 ```javascript const compIds = await eda.sch_PrimitiveComponent.getAllPrimitiveId(); const issues = []; for (const id of compIds) { const comps = await eda.sch_PrimitiveComponent.get([id]); if (!comps || comps.length === 0) continue; const c = comps[0]; // 检查位号是否存在 if (!c.designator) { issues.push({ id, type: "missing_designator", name: c.name }); continue; } // 检查位号是否包含 ?(未分配) if (c.designator.includes("?")) { issues.push({ id, type: "unassigned_designator", designator: c.designator, name: c.name }); } // 检查位号格式(字母+数字) if (!/^[A-Z]+\d+$/.test(c.designator)) { issues.push({ id, type: "invalid_format", designator: c.designator, name: c.name }); } } ``` ### 位号重复检查 ```javascript const designatorMap = new Map(); const duplicates = []; for (const id of compIds) { const comps = await eda.sch_PrimitiveComponent.get([id]); const c = comps[0]; if (c.designator) { if (designatorMap.has(c.designator)) { duplicates.push({ designator: c.designator, ids: [designatorMap.get(c.designator), id], }); } else { designatorMap.set(c.designator, id); } } } ``` --- ## 7. 文本标注检查 ### 检测重复文本 ```javascript const textIds = await eda.sch_PrimitiveText.getAllPrimitiveId(); const textMap = new Map(); for (const tid of textIds) { const t = await eda.sch_PrimitiveText.get([tid]); if (t && t[0]) { const key = `${t[0].x},${t[0].y}`; if (!textMap.has(key)) textMap.set(key, []); textMap.get(key).push({ id: tid, content: t[0].content, fontSize: t[0].fontSize }); } } const duplicateTexts = []; for (const [pos, items] of textMap) { if (items.length > 1) duplicateTexts.push({ position: pos, items }); } ``` ### 检查文本位置是否合理 ```javascript // 检查文本是否与器件重叠 const textOverlaps = []; for (const t of texts) { for (const b of bboxes) { if (t.x > b.bbox[0] && t.x < b.bbox[2] && t.y > b.bbox[1] && t.y < b.bbox[3]) { textOverlaps.push({ text: t.content, component: b.designator, }); } } } ``` --- ## 8. 导线穿过器件检测(NEW) ### 8.1 检测原理 遍历所有导线的每个线段,与所有真实器件的 BBox(边界框)做交叉检测: - 若导线端点在器件 BBox 内部(排除 ±3 容差的引脚边缘)→ 报出 - 若线段与器件 BBox 相交,且交叉长度 > 5 单位 → 报出 这能发现像 R7、R8 被 ROW 网络导线直接穿过的问题。 ### 8.2 使用 CLI ```bash ./scripts/draw_cli.py check-wire-through ``` ### 8.3 使用函数 ```javascript import utils from './scripts/draw-utils.js'; const result = await utils.checkWireThroughComponent();
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub