R2 底板改 4 层(D15):规则 / 几何 / 背面摆位 / 4 层布线与铺铜,已下发

- 规则:铜层 2→4,差分 0.28/0.18,间距 0.15,过孔 0.3/0.2(rules_base)
- 几何:98×98 板框 + 4×M3,槽阵居中,L1 12V 大铜 + 指头(pcb_base)
- 摆位:五插槽留 L1,其余 133 件翻到 L4;背面镜像规则实测;Hub 放走廊 2、
  东移 2.5 mm;扇出圈 / 小件间距 1.5(去耦例外)/ 9 A 过孔阵禁区(place_base)
- 叠层按用户决定改为 L1 槽面 / L2 整层 +3V3 / L3 整层 GND / L4 器件面
- 布线:D± 七对按构造布通(USB3 掉头、USB1/2 北去掉头、USB4/5 东绕、
  J23 桥),+3V3 / GND / +12V 平面网每脚一孔,0.125 网格 + PathFinder
  开关(route_base、remote_route.ps1);剩 37 个网待手工补
- 铺铜:4 层重写,入口链自南向北切段 + 断面校核(pour_base);
  已下发布线 / 缝合孔 / 铜面轮廓,填铜未成功(待查)
- 工具:plot_base / plot_routes / shot_base,board_check 通孔两层都算

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_0168Bu6SEx3cXXCJLkdnE6zB
这个提交包含在:
zhou yang
2026-09-10 21:02:10 +08:00
共同撰写人 Claude Opus 5
父节点 18d3d69856
当前提交 efcba30a0c
共修改 280 个文件,包含 92007 行新增和 15053 行删除
+94 -94
查看文件
@@ -1,94 +1,94 @@
# -*- coding: utf-8 -*-
u"""删掉指定矩形框里的**某个网络**的走线与过孔(板坐标或站内坐标)。
/c/Python314/python .claude/pcb2_del_box.py GND --site 54.9 36.8 56.5 37.5
/c/Python314/python .claude/pcb2_del_box.py GND --board 100 60 102 62
加 `--push` 才真删,不加只列出来。
## 为什么需要它
板上的铜是好几个脚本各画各的(`pcb2_dp_long` / `pcb2_fanout` / `pcb2_vo_vias` / `pcb2_route_sig`),
每个脚本的 `--push` 只删**自己上一轮**画的东西。挪了一个元件之后,
它那颗扇出孔就成了没人认领的孤儿 —— 谁的删除逻辑都不管,DRC 只报一条
「过孔没连上任何东西」,很容易被当成噪声放过去。
## 判据
- **完全落在框里**才删(导线两端都在框内、过孔中心在框内)。半进半出的一律不动,
免得把一条长线截断一半留在板上 —— 那比不删还糟。
- `--site` 是站内坐标,会自动展开到五个手机位(`pcb2_place.to_board`,4/5 站镜像)。
"""
import json
import os
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
from eda import run
from pcb2_place import SITES, to_board
PCB = 'f126ffb29c92f9b2'
MIL = 39.3700787401575
def boxes_from_argv():
if '--site' in sys.argv:
i = sys.argv.index('--site')
u0, v0, u1, v1 = [float(v) for v in sys.argv[i + 1:i + 5]]
out = []
for n in SITES:
ax, ay, _ = to_board(n, u0, v0)
bx, by, _ = to_board(n, u1, v1)
out.append((min(ax, bx), min(ay, by), max(ax, bx), max(ay, by)))
return out
i = sys.argv.index('--board')
x0, y0, x1, y1 = [float(v) for v in sys.argv[i + 1:i + 5]]
return [(min(x0, x1), min(y0, y1), max(x0, x1), max(y0, y1))]
JS = u"""
await eda.dmt_EditorControl.openDocument('%s');
await new Promise(r => setTimeout(r, 1500));
const M = 39.3700787401575, q = v => Math.round(v / M * 1e4) / 1e4;
const NET = %s, B = %s, DO = %s;
const inB = (x, y) => B.some(b => x >= b[0] && x <= b[2] && y >= b[1] && y <= b[3]);
const lines = [], vias = [];
for (const l of await eda.pcb_PrimitiveLine.getAll()) {
if ((l.net || '') !== NET) continue;
if (l.layer !== 1 && l.layer !== 2) continue;
if (inB(q(l.startX), q(l.startY)) && inB(q(l.endX), q(l.endY)))
lines.push([l.primitiveId, q(l.startX), q(l.startY), q(l.endX), q(l.endY), l.layer]);
}
for (const v of await eda.pcb_PrimitiveVia.getAll()) {
if ((v.net || '') !== NET) continue;
if (inB(q(v.x), q(v.y))) vias.push([v.primitiveId, q(v.x), q(v.y)]);
}
if (DO) {
if (lines.length) await eda.pcb_PrimitiveLine.delete(lines.map(l => l[0]));
if (vias.length) await eda.pcb_PrimitiveVia.delete(vias.map(v => v[0]));
await eda.pcb_Document.save();
}
return {lines: lines.map(l => l.slice(1)), vias: vias.map(v => v.slice(1)), did: DO};
"""
def main():
net = sys.argv[1]
boxes = boxes_from_argv()
do = '--push' in sys.argv
r = run(JS % (PCB, json.dumps(net), json.dumps(boxes), 'true' if do else 'false'),
timeout=600)
if not r.get('success'):
sys.exit(u'失败: ' + json.dumps(r, ensure_ascii=False)[:400])
x = r['result']
print(u'%s:%d 个框里有 %s 的导线 %d 条 / 过孔 %d 个'
% (u'已删' if do else u'(预览,加 --push 才删)', len(boxes), net,
len(x['lines']), len(x['vias'])))
for l in x['lines'][:20]:
print(u' 线 L%d (%.3f, %.3f) -> (%.3f, %.3f)' % (l[4], l[0], l[1], l[2], l[3]))
for v in x['vias'][:20]:
print(u' 孔 (%.3f, %.3f)' % (v[0], v[1]))
if __name__ == '__main__':
main()
# -*- coding: utf-8 -*-
u"""删掉指定矩形框里的**某个网络**的走线与过孔(板坐标或站内坐标)。
/c/Python314/python .claude/pcb2_del_box.py GND --site 54.9 36.8 56.5 37.5
/c/Python314/python .claude/pcb2_del_box.py GND --board 100 60 102 62
加 `--push` 才真删,不加只列出来。
## 为什么需要它
板上的铜是好几个脚本各画各的(`pcb2_dp_long` / `pcb2_fanout` / `pcb2_vo_vias` / `pcb2_route_sig`),
每个脚本的 `--push` 只删**自己上一轮**画的东西。挪了一个元件之后,
它那颗扇出孔就成了没人认领的孤儿 —— 谁的删除逻辑都不管,DRC 只报一条
「过孔没连上任何东西」,很容易被当成噪声放过去。
## 判据
- **完全落在框里**才删(导线两端都在框内、过孔中心在框内)。半进半出的一律不动,
免得把一条长线截断一半留在板上 —— 那比不删还糟。
- `--site` 是站内坐标,会自动展开到五个手机位(`pcb2_place.to_board`,4/5 站镜像)。
"""
import json
import os
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
from eda import run
from pcb2_place import SITES, to_board
PCB = '942ed1560d81c1e7'
MIL = 39.3700787401575
def boxes_from_argv():
if '--site' in sys.argv:
i = sys.argv.index('--site')
u0, v0, u1, v1 = [float(v) for v in sys.argv[i + 1:i + 5]]
out = []
for n in SITES:
ax, ay, _ = to_board(n, u0, v0)
bx, by, _ = to_board(n, u1, v1)
out.append((min(ax, bx), min(ay, by), max(ax, bx), max(ay, by)))
return out
i = sys.argv.index('--board')
x0, y0, x1, y1 = [float(v) for v in sys.argv[i + 1:i + 5]]
return [(min(x0, x1), min(y0, y1), max(x0, x1), max(y0, y1))]
JS = u"""
await eda.dmt_EditorControl.openDocument('%s');
await new Promise(r => setTimeout(r, 1500));
const M = 39.3700787401575, q = v => Math.round(v / M * 1e4) / 1e4;
const NET = %s, B = %s, DO = %s;
const inB = (x, y) => B.some(b => x >= b[0] && x <= b[2] && y >= b[1] && y <= b[3]);
const lines = [], vias = [];
for (const l of await eda.pcb_PrimitiveLine.getAll()) {
if ((l.net || '') !== NET) continue;
if (l.layer !== 1 && l.layer !== 2) continue;
if (inB(q(l.startX), q(l.startY)) && inB(q(l.endX), q(l.endY)))
lines.push([l.primitiveId, q(l.startX), q(l.startY), q(l.endX), q(l.endY), l.layer]);
}
for (const v of await eda.pcb_PrimitiveVia.getAll()) {
if ((v.net || '') !== NET) continue;
if (inB(q(v.x), q(v.y))) vias.push([v.primitiveId, q(v.x), q(v.y)]);
}
if (DO) {
if (lines.length) await eda.pcb_PrimitiveLine.delete(lines.map(l => l[0]));
if (vias.length) await eda.pcb_PrimitiveVia.delete(vias.map(v => v[0]));
await eda.pcb_Document.save();
}
return {lines: lines.map(l => l.slice(1)), vias: vias.map(v => v.slice(1)), did: DO};
"""
def main():
net = sys.argv[1]
boxes = boxes_from_argv()
do = '--push' in sys.argv
r = run(JS % (PCB, json.dumps(net), json.dumps(boxes), 'true' if do else 'false'),
timeout=600)
if not r.get('success'):
sys.exit(u'失败: ' + json.dumps(r, ensure_ascii=False)[:400])
x = r['result']
print(u'%s:%d 个框里有 %s 的导线 %d 条 / 过孔 %d 个'
% (u'已删' if do else u'(预览,加 --push 才删)', len(boxes), net,
len(x['lines']), len(x['vias'])))
for l in x['lines'][:20]:
print(u' 线 L%d (%.3f, %.3f) -> (%.3f, %.3f)' % (l[4], l[0], l[1], l[2], l[3]))
for v in x['vias'][:20]:
print(u' 孔 (%.3f, %.3f)' % (v[0], v[1]))
if __name__ == '__main__':
main()