R2 刀片:金手指两侧开台阶(插不进插槽)+ 铺铜补齐并跟着台阶重画
⛔ 根因:禁布区 ≠ 板材。ZONES['finger'] 早写着「槽体 ~9mm 要让开」,但那只是 「别放件」,板框从来没开台阶 —— outline_pts() 第一段就是 (r,0)→(BW-r,0), 90 mm 宽的板材一直到 y=0。插槽塑料体只有 39 mm 且两端封闭 ⇒ 插不到底。 板框(用户拍板):舌头 36.0 mm(x 27~63)/ 台阶高 12.0 / 内凹角 R1.0,切掉 648 mm²(10.6%)。 放行核算:被切区里铜 0 / 孔 0 / 焊盘 0 / 器件 0(板上读回与缓存两种口径一致); 7 个定位孔最南 y=14.46 全在板材上;铣穿槽 y 56.86 不受影响。 代价:主板投影底边在舌头两侧悬空 1.0 mm,靠 7 个 M1.6 尼龙立柱压住,无害。 铺铜:抓板发现板上只有 11 块(L1/L4 的 GND 底填整层缺失,而记录写的是 25/25)。 补齐后按台阶重画成 31 块(L2 11 + L1 9 + L4 9 + L3 两岛),填充 31/31,DRC 间距 0 条。 +12V 岛改成阶梯形单环:舌头段仍下探 y=9.0 接 12V 三指 launch 孔,东段抬到 12.5, 断面 11.0 → 7.5 mm(1 oz 内层约 5.1 A,需求 1.5 A 峰值)。 两条判据上的坑: - 阶梯形多边形不能按包围盒判越界(+12V 岛会误报)⇒ 改成逐边 0.25 mm 采样。 - pcb_pour.inner_poly()/outer_poly() 是死函数,plan() 只用 gnd_tiles()。 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_0168Bu6SEx3cXXCJLkdnE6zB
这个提交包含在:
+88
-19
@@ -57,14 +57,34 @@ L_TOP, L_GND, L_PWR, L_BOT = 1, 15, 16, 2
|
||||
|
||||
INSET = 0.5 # 铜面离板边
|
||||
TOP_POUR_Y = 11.5 # 外层铜面的下沿(金手指区一点外层铜都不许有)
|
||||
# ⛔ 2026-09-12:板框开了台阶(`pcb_blade.STEP_H` / `TONGUE_X0/X1`)之后,**舌头两侧根本没有板材**
|
||||
# ⇒ 那两段的铜下沿必须抬到 `STEP_H + INSET`,否则铜会悬在被切掉的地方。
|
||||
# 舌头那一段仍按 TOP_POUR_Y / INSET 走(外层不进金手指区、内层绕缺口)。
|
||||
STEP_POUR_Y = round(B.STEP_H + INSET, 3)
|
||||
NOTCH_KEEP = 0.5 # 缺口周围再让 0.5
|
||||
|
||||
# L3 两个岛(x0, y0, x1, y1)—— y 段直接对着 pcb_place 的功能带切,见 --bands
|
||||
VO_ISLAND = (20.0, 11.5, 97.5, 28.8) # eFuse/检流带 + 服务带:VO_P 4 A 的主通道
|
||||
# 2026-09-09 M6:J5 / 阻尼组挪到电池槽北边(y 29~40)之后岛要跟过去 —— 往北伸一个
|
||||
# 叶(L 形单环,不是第二块铜)。东沿 46 让开尾插槽 46.58;电池槽本身由挖槽区域反焊盘让开。
|
||||
VO_LOBE = (20.0, 28.8, 46.0, 46.0)
|
||||
V12_ISLAND = (84.0, 55.0, 97.5, 74.0) # 12V 入口(F1 的 +12V 脚)及以上;新摆位后功率链上端只占 x 83~93
|
||||
# L3 两个岛(x0, y0, x1, y1)
|
||||
# ⛔⛔ 2026-09-11 晚(方案 §35):主板转 180°、功率链转 180° ⇒ 两个岛上下对调。
|
||||
# · `VO_P` 岛在**上半**:功率链顶上的 Rs1 / U3 → 西去 J5 / 阻尼组 / DIS → 两槽之间的 C60。
|
||||
# 电池槽是铣穿的,岛做成**绕开电池槽的 U 形单环**(三块矩形拼,`VO_RECTS`),不用带洞多边形。
|
||||
# · `+12V` 岛在**下半**:金手指 12V 三指的 launch 孔(x 28.5~30.5, y 11.75)→ 东去 F1 的 +12V 脚(功率链最底)。
|
||||
# 12V 从此**不在 L1 / L4 上走线**(原来那根 L4 x≈42.5 的竖线把整块板东西切成两半)。
|
||||
# 下沿 9.0:金手指地母线的孔在 y 7.0 / 8.2,孔 + 净距到 8.8;上沿 20:信号 launch 孔在 y 11.75 一字排开
|
||||
# (1 mm 一个,反焊盘把 11.25~12.25 那一条几乎切断),电流要从它上面 8 mm 宽的那条过。
|
||||
VO_Y0 = 38.0 # 岛主体下沿(DIS / 阻尼组最南到 ~39.8)
|
||||
VO_TOP_Y = round(B.SLOT_Y[0] - 0.56, 3) # 主体上沿:离电池槽底 0.56(槽边到铜 ≥ 0.5)
|
||||
_bat = B.flex_slots()['BAT']
|
||||
VO_RECTS = [
|
||||
(26.0, VO_Y0, B.BW - 0.5, VO_TOP_Y), # 主体:J5 / 阻尼组 / DIS / U2 以北
|
||||
(25.6, VO_TOP_Y, round(_bat[0] - 0.56, 3), B.BH - 0.5), # 两槽之间往上:C60
|
||||
(round(_bat[2] + 0.56, 3), VO_TOP_Y, B.BW - 0.5, B.BH - 0.5), # 电池槽以东往上:Rs1 / U3 / C13
|
||||
]
|
||||
VO_ISLAND, VO_LOBE = VO_RECTS[0], VO_RECTS[1] # 老名字留给别的脚本(board_check 等)
|
||||
# ⛔ 2026-09-12 台阶之后改成**阶梯形**:舌头那一段(x TONGUE_X0~TONGUE_X1)仍下探到 9.0 去接
|
||||
# 12V 三指的 launch 孔(x 28.5~30.5 / y 11.75,全在舌头内);舌头以东那一段抬到 STEP_POUR_Y
|
||||
# —— 那边的板材已经被台阶铣掉了。断面:东段由 11.0 收到 7.5 mm 宽(1 oz 内层,1.5 A 峰值远够)。
|
||||
V12_ISLAND = (27.0, 9.0, 84.0, 20.0) # 老名字留着(board_check 等按它取包围盒)
|
||||
V12_LOW_Y, V12_TOP_Y = 9.0, 20.0
|
||||
|
||||
|
||||
def mil(v):
|
||||
@@ -163,12 +183,14 @@ def gnd_tiles(y_lo):
|
||||
x0, x1 = d, B.BW - d
|
||||
y1 = B.BH - d
|
||||
cuts = [(a - INSET, b - INSET, c + INSET, e + INSET) for (a, b, c, e) in B.mill_cuts()]
|
||||
xs = sorted(set([x0, x1] + [v for c in cuts for v in (c[0], c[2])]))
|
||||
# ⛔ 台阶两端也是切分点:舌头外的竖条下沿要抬到 STEP_POUR_Y(那边没有板材)
|
||||
xs = sorted(set([x0, x1, B.TONGUE_X0, B.TONGUE_X1] + [v for c in cuts for v in (c[0], c[2])]))
|
||||
tiles = []
|
||||
for xa, xb in zip(xs, xs[1:]):
|
||||
if xb - xa < 0.6:
|
||||
continue
|
||||
ys = [y_lo]
|
||||
in_tongue = (xa >= B.TONGUE_X0 - 1e-9 and xb <= B.TONGUE_X1 + 1e-9)
|
||||
ys = [y_lo if in_tongue else max(y_lo, STEP_POUR_Y)]
|
||||
for c in sorted(cuts, key=lambda c: c[1]):
|
||||
if c[0] < xb - 1e-9 and xa < c[2] - 1e-9:
|
||||
ys += [c[1], c[3]]
|
||||
@@ -198,12 +220,32 @@ def gnd_tiles(y_lo):
|
||||
return tiles
|
||||
|
||||
|
||||
def v12_poly():
|
||||
u"""`+12V` 岛(L3):**阶梯形单环**。舌头段下探到 V12_LOW_Y 接金手指的 launch 孔,
|
||||
舌头以东抬到 STEP_POUR_Y(板框台阶把那块板材铣掉了)。
|
||||
|
||||
⛔ 一律单环(带洞的复杂多边形会把客户端挂死,见 `gnd_tiles` 的说明)。"""
|
||||
x0, x1 = V12_ISLAND[0], V12_ISLAND[2]
|
||||
xt = B.TONGUE_X1
|
||||
assert x0 >= B.TONGUE_X0 and xt < x1, u'+12V 岛的阶梯点跑到舌头外了'
|
||||
pts = [(x0, V12_LOW_Y), (xt, V12_LOW_Y), (xt, STEP_POUR_Y), (x1, STEP_POUR_Y),
|
||||
(x1, V12_TOP_Y), (x0, V12_TOP_Y)]
|
||||
out = [pts[0]]
|
||||
for q in pts[1:]:
|
||||
if abs(q[0] - out[-1][0]) > 1e-9 or abs(q[1] - out[-1][1]) > 1e-9:
|
||||
out.append(q)
|
||||
out.append(out[0])
|
||||
return out
|
||||
|
||||
|
||||
def vo_poly():
|
||||
u"""VO_P 岛:主体矩形 + 北叶,拼成一个 L 形**单环**(逆时针,显式闭合)。"""
|
||||
a, b = VO_ISLAND, VO_LOBE
|
||||
assert abs(a[3] - b[1]) < 1e-9 and a[0] <= b[0] and b[2] <= a[2], u'北叶必须骑在主体上沿'
|
||||
pts = [(a[0], a[1]), (a[2], a[1]), (a[2], a[3]), (b[2], a[3]),
|
||||
(b[2], b[3]), (b[0], b[3]), (b[0], a[3]), (a[0], a[3])]
|
||||
u"""VO_P 岛:主体 + 两个上叶(夹着电池槽),拼成一个 U 形**单环**(逆时针,显式闭合)。
|
||||
|
||||
2026-09-11 晚起(方案 §35)。上叶 w 骑在主体上沿、西沿可以比主体再往西一点(C60 的 VO_P 盘)。"""
|
||||
a, w, e = VO_RECTS
|
||||
assert abs(a[3] - w[1]) < 1e-9 and abs(a[3] - e[1]) < 1e-9 and e[2] == a[2] and w[2] < e[0], u'上叶必须骑在主体上沿'
|
||||
pts = [(a[0], a[1]), (a[2], a[1]), (e[2], e[3]), (e[0], e[3]), (e[0], a[3]),
|
||||
(w[2], a[3]), (w[2], w[3]), (w[0], w[3]), (w[0], a[3]), (a[0], a[3])]
|
||||
out = [pts[0]]
|
||||
for q in pts[1:]:
|
||||
if abs(q[0] - out[-1][0]) > 1e-9 or abs(q[1] - out[-1][1]) > 1e-9:
|
||||
@@ -216,7 +258,7 @@ def plan():
|
||||
u"""[(name, net, layer, [环...], priority)],priority 小的先铺、先占地盘。"""
|
||||
outs = []
|
||||
outs.append(('VO-L3', 'VO_P', L_PWR, [src(vo_poly())], 1))
|
||||
outs.append(('V12-L3', '+12V', L_PWR, [src(rrect(*V12_ISLAND))], 2))
|
||||
outs.append(('V12-L3', '+12V', L_PWR, [src(v12_poly())], 2))
|
||||
for tag, layer, y_lo in (('L2', L_GND, INSET), ('TOP', L_TOP, TOP_POUR_Y),
|
||||
('BOT', L_BOT, TOP_POUR_Y)):
|
||||
for k, (a, b, c, d2) in enumerate(gnd_tiles(y_lo)):
|
||||
@@ -225,6 +267,14 @@ def plan():
|
||||
return outs
|
||||
|
||||
|
||||
def _ring_pts(ring):
|
||||
u"""`src()` 生成的 [x, y, 'L', x, y, 'L', ...](mil)还原成 [(x, y)] 点列(mm)。"""
|
||||
pts = [(float(ring[0]) / MIL, float(ring[1]) / MIL)]
|
||||
for k in range(3, len(ring), 3):
|
||||
pts.append((float(ring[k]) / MIL, float(ring[k + 1]) / MIL))
|
||||
return pts
|
||||
|
||||
|
||||
def selfcheck(ps):
|
||||
bad = []
|
||||
for name, _net, _lay, rings, _p in ps:
|
||||
@@ -237,19 +287,38 @@ def selfcheck(ps):
|
||||
bad.append(u'外层铜下沿 %.2f 压到指顶 %.2f' % (TOP_POUR_Y, top))
|
||||
if TOP_POUR_Y <= fp_edge.NOTCH_D:
|
||||
bad.append(u'外层铜下沿 %.2f 低于缺口顶 %.2f' % (TOP_POUR_Y, fp_edge.NOTCH_D))
|
||||
# ⛔ 台阶:舌头两侧不许有任何铜低于 STEP_POUR_Y(那块板材已经铣掉了)。
|
||||
# ⚠ 判据必须**逐边**走,不能按整个环的包围盒判:`+12V` 岛是阶梯形,
|
||||
# 它的 y=9.0 那一段只在舌头内,按包围盒(min y 9.0 且 max x 84)会误报。
|
||||
for name, _net, _lay, rings, _p in ps:
|
||||
for ring in rings:
|
||||
pts = _ring_pts(ring)
|
||||
worst = None
|
||||
for (ax, ay), (bx, by) in zip(pts, pts[1:]):
|
||||
n = max(2, int(math.hypot(bx - ax, by - ay) / 0.25) + 1)
|
||||
for i in range(n + 1):
|
||||
t = i / float(n)
|
||||
x, y = ax + (bx - ax) * t, ay + (by - ay) * t
|
||||
if y < STEP_POUR_Y - 1e-6 and (x < B.TONGUE_X0 - 1e-6 or x > B.TONGUE_X1 + 1e-6):
|
||||
if worst is None or y < worst[1]:
|
||||
worst = (x, y)
|
||||
if worst:
|
||||
bad.append(u'%s 伸进台阶切掉的区域(最深处 x %.2f / y %.2f < %.2f)'
|
||||
% (name, worst[0], worst[1], STEP_POUR_Y))
|
||||
# 内层铜面必须绕开缺口
|
||||
nx0, _a, nx1, ny1 = notch_cut()
|
||||
if nx1 - nx0 < 2.9:
|
||||
if nx1 - nx0 < fp_edge.NOTCH_W + 2 * fp_edge.LEAD_IN:
|
||||
bad.append(u'缺口挖得比口部还窄')
|
||||
# 两个岛不许互相重叠(同层,优先级只有 1/2 之差,重叠就说不清谁裁谁)
|
||||
b = V12_ISLAND
|
||||
for a in (VO_ISLAND, VO_LOBE):
|
||||
for a in VO_RECTS:
|
||||
if a[0] < b[2] and b[0] < a[2] and a[1] < b[3] and b[1] < a[3]:
|
||||
bad.append(u'VO 岛和 +12V 岛在 L3 上重叠')
|
||||
# 北叶不许伸进尾插槽/车道
|
||||
# 岛不许压到铣穿的槽(含 0.5 净距)—— 客户端会自己让,但让出来的形状谁也没核过
|
||||
for (x0, y0, x1, y1) in B.mill_cuts():
|
||||
if x0 > VO_LOBE[0] + 1.0 and VO_LOBE[0] < x1 and x0 < VO_LOBE[2] and y0 < VO_LOBE[3] and VO_LOBE[1] < y1:
|
||||
bad.append(u'VO 北叶压到槽 (%.1f~%.1f)' % (x0, x1))
|
||||
for a in VO_RECTS + [b]:
|
||||
if a[0] < x1 + 0.5 and x0 - 0.5 < a[2] and a[1] < y1 + 0.5 and y0 - 0.5 < a[3]:
|
||||
bad.append(u'L3 岛 %s 压到槽 (%.1f~%.1f, %.1f~%.1f)' % (a, x0, x1, y0, y1))
|
||||
return bad
|
||||
|
||||
|
||||
|
||||
在新工单中引用
屏蔽一个用户