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
这个提交包含在:
+105
-34
@@ -11,16 +11,23 @@ u"""R2 刀片 PCB(M4):板框 + 分区参考 + 摆位常量。
|
|||||||
**板左下角 = (0, 0),x 向右、y 向上**(EasyEDA PCB 里 y 向上为正,见方案 §22.5)。
|
**板左下角 = (0, 0),x 向右、y 向上**(EasyEDA PCB 里 y 向上为正,见方案 §22.5)。
|
||||||
这正好是方案 §3.1 那张分区图的坐标,图里的数可以直接抄。
|
这正好是方案 §3.1 那张分区图的坐标,图里的数可以直接抄。
|
||||||
|
|
||||||
|
⛔ **2026-09-11 用户拍板:98×76 → 90×68**(方案 §34)。
|
||||||
|
⛔⛔ **2026-09-11 晚 用户拍板:主板转 180°,两条排线槽挪到顶部**(方案 §35)。
|
||||||
|
接口边(J600 / J1401 / 侧键)朝**上**,服务带(C60 + 两条槽 + J3)在板子**顶部**,
|
||||||
|
手机远端边贴着金手指区上沿(y 11.0)。与手机绑定的一切(七个孔 / 两条槽 / J4 / J5 / K1~K4)
|
||||||
|
一律经 `phone_xy()` 从本体坐标 (u, v) 推,**不许写死、不许自己算旋转**。
|
||||||
|
|
||||||
```
|
```
|
||||||
y 76 ┬──────────────────────────────────┬──────────────┐
|
y 68.00 ┬──────────────────────────────────┬─────────────┐
|
||||||
│ │ 功率列 26mm │
|
│ 服务带 12.34 尾插槽 / C60 / 电池槽 │ 功率列 19.4 │
|
||||||
│ 小米8 主板 67.09 × 44.66 │ Buck/L/Cin │
|
y 55.66 ┼──── 接口边(朝上)─────────────────┤ U3/Rs1 (顶) │
|
||||||
y 29 ┼──── 接口边 ───────────────────────┤ eFuse/Rs │
|
│ │ eFuse │
|
||||||
│ 服务带 18mm C60/TP/EDL/BM24/K1~4 │ INA/PCA9555 │
|
│ 小米8 主板 67.09 × 44.66(转 180)│ L / Buck │
|
||||||
y 11 ┼──────────────────────────────────┴──────────────┤
|
│ │ Cin / F1(底)│
|
||||||
│ 金手指区 11mm(槽体 ~9mm 要让开,这一带不许放件) │
|
y 11.00 ┼──────────────────────────────────┴─────────────┤
|
||||||
y 0 ┴───────────────── 板边(卡边)─────────────────────┘
|
│ 金手指区 11mm(槽体 ~9mm 要让开,这一带不许放件) │
|
||||||
x 0 3 ──── 手机主板 ──── 70.09 72 ─ 功率列 ─ 98
|
y 0.00 ┴───────────────── 板边(卡边)──────────────────┘
|
||||||
|
x 0 1.5 ─── 手机主板 ─── 68.59 70.59 ─ 功率列 ─ 90
|
||||||
```
|
```
|
||||||
|
|
||||||
## 板框的底边是**断开**的
|
## 板框的底边是**断开**的
|
||||||
@@ -55,8 +62,20 @@ PCB = '3b9c4e39c8d164db' # BLADE-PCB
|
|||||||
MIL = fp_edge.MIL
|
MIL = fp_edge.MIL
|
||||||
|
|
||||||
# ── 板框(mm,出处 方案 §3.1)─────────────────────────────────────────
|
# ── 板框(mm,出处 方案 §3.1)─────────────────────────────────────────
|
||||||
BW, BH = 98.0, 76.0
|
BW, BH = 90.0, 68.0 # 2026-09-11 由 98×76 压缩(用户拍板)
|
||||||
CORNER_R = 2.0
|
CORNER_R = 2.0
|
||||||
|
# ── 金手指两侧的台阶(2026-09-12 用户指出「金手指两侧没有开槽,插不进插槽」)──────────
|
||||||
|
# PCI-E 卡在金手指那一段是「凸」字形:只有舌头伸进插槽,两侧板材必须收到槽体顶面以上。
|
||||||
|
# 刀片原来是一整块 90×68 的圆角矩形,底边一条直线 ⇒ 塑料体(39 mm,两端封闭)会顶住
|
||||||
|
# x<27 / x>63 的板材,**插不到底**。
|
||||||
|
# 舌头 36.0 宽(用户拍板,比金手指 33.70 两侧各多 1.15);台阶高 12.0(槽体 ~9,余 3)。
|
||||||
|
# 内凹角必须倒圆角:外形铣刀下不去直角,取 R1.0。
|
||||||
|
# ⚠ 台阶 12.0 > 手机主板落点 y0 = 11.0 ⇒ 主板投影底边在舌头两侧**悬空 1.0 mm**
|
||||||
|
# (左 x 1.50~27.00 / 右 x 63.00~68.59)。7 个定位孔最南 y=14.46 全在板材上、
|
||||||
|
# 主板靠 M1.6 尼龙立柱固定而不是靠边缘托住 ⇒ 无害,但 selfcheck 的分区断言要按舌头口径判。
|
||||||
|
TONGUE_X0, TONGUE_X1 = 27.0, 63.0
|
||||||
|
STEP_H = 12.0
|
||||||
|
STEP_R = 1.0 # 台阶内凹角(铣刀半径,嘉立创外形最小 R0.5,取 1.0 稳)
|
||||||
CORNER_SEG = 8 # 每个 R2 圆角用几段折线
|
CORNER_SEG = 8 # 每个 R2 圆角用几段折线
|
||||||
OUTLINE_W = 0.15
|
OUTLINE_W = 0.15
|
||||||
|
|
||||||
@@ -66,8 +85,26 @@ J1_X, J1_Y, J1_ROT = BW / 2.0, 0.0, 0
|
|||||||
|
|
||||||
# ── 小米8 主板的落点 + 定位孔(板级事实,摆位/布线/铺铜都从这里取)────────
|
# ── 小米8 主板的落点 + 定位孔(板级事实,摆位/布线/铺铜都从这里取)────────
|
||||||
# 主板 67.09 × 44.66,长边水平、**接口边(v=0,J600/J1401/侧键都在上面)朝下**。
|
# 主板 67.09 × 44.66,长边水平、**接口边(v=0,J600/J1401/侧键都在上面)朝下**。
|
||||||
PHONE_ORG = (3.0, 29.0)
|
# ⛔ 2026-09-11 晚:**主板转 180°**(接口边朝上,方案 §35)。`PHONE_ORG` 仍是手机投影矩形的
|
||||||
|
# **左下角**(板坐标),但本体 (u, v) → 板 (x, y) 要经 `phone_xy()`:u 从右往左、v 从上往下。
|
||||||
|
# y 的取法:手机远端边贴金手指区上沿 11.0(原来 C60 也是贴这条线放的,同一条禁布规则);
|
||||||
|
# 接口边 = 11 + 44.66 = 55.66,上面 12.34 的服务带放 C60(本体 11)+ 两条槽 + J3。
|
||||||
|
# x 不变(1.5):H6/H7(u≈64.7)转过来落在左边,螺钉头离板边 2.2 − 1.6 = 0.6 以上。
|
||||||
|
# ⚠ SIM 卡托在 u 大的那一端(mi8_mech 注释:轮廓 70.3 含卡托 3.3)⇒ 转过来在**左边**,
|
||||||
|
# 装着卡托的话会伸出板左沿 ~1.8 mm(机箱侧壁要让)。
|
||||||
|
PHONE_ORG = (1.5, 11.0)
|
||||||
PHONE_WH = (67.09, 44.66)
|
PHONE_WH = (67.09, 44.66)
|
||||||
|
PHONE_ROT = 180
|
||||||
|
IF_Y = round(PHONE_ORG[1] + PHONE_WH[1], 3) # 接口边(v=0)在板上的 y:55.66
|
||||||
|
|
||||||
|
|
||||||
|
def phone_xy(u, v):
|
||||||
|
u"""主板本体坐标 (u, v) → 刀片板坐标 (x, y)。**唯一的旋转实现**,别处不许自己算。
|
||||||
|
|
||||||
|
PHONE_ROT = 180:本体绕投影中心转半圈 ⇒ x = 右沿 − u,y = 上沿 − v(接口边 v=0 在上)。"""
|
||||||
|
if PHONE_ROT == 180:
|
||||||
|
return (round(PHONE_ORG[0] + PHONE_WH[0] - u, 3), round(PHONE_ORG[1] + PHONE_WH[1] - v, 3))
|
||||||
|
return (round(PHONE_ORG[0] + u, 3), round(PHONE_ORG[1] + v, 3))
|
||||||
|
|
||||||
# ⛔ **主板定位孔**。整个 §3.2 的高度预算 / §21.1 的槽距结论都建立在
|
# ⛔ **主板定位孔**。整个 §3.2 的高度预算 / §21.1 的槽距结论都建立在
|
||||||
# 「螺丝把主板压在刀片上、螺柱间隙 1.0 mm」(R1 §22.3e 的中框式焊盘)之上 ——
|
# 「螺丝把主板压在刀片上、螺柱间隙 1.0 mm」(R1 §22.3e 的中框式焊盘)之上 ——
|
||||||
@@ -87,8 +124,7 @@ def phone_holes():
|
|||||||
u"""{名字: (x, y)},刀片坐标。"""
|
u"""{名字: (x, y)},刀片坐标。"""
|
||||||
m = json.load(io.open(os.path.join(os.path.dirname(HERE), 'mi8_mech.json'),
|
m = json.load(io.open(os.path.join(os.path.dirname(HERE), 'mi8_mech.json'),
|
||||||
encoding='utf-8'))
|
encoding='utf-8'))
|
||||||
return {k: (round(PHONE_ORG[0] + u, 3), round(PHONE_ORG[1] + v, 3))
|
return {k: phone_xy(u, v) for k, (u, v) in m['holes'].items()}
|
||||||
for k, (u, v) in m['holes'].items()}
|
|
||||||
|
|
||||||
|
|
||||||
# ── 排线穿板槽(2026-09-09 用户拍板:屏蔽窗去掉、器件全到 B 面、给两条排线开槽)──
|
# ── 排线穿板槽(2026-09-09 用户拍板:屏蔽窗去掉、器件全到 B 面、给两条排线开槽)──
|
||||||
@@ -109,7 +145,11 @@ def phone_holes():
|
|||||||
# 按 53.58 定,尾插车道西沿 47.6 正好让开 H4 螺钉头 (44.9 + 2.2),与 R1 自洽。
|
# 按 53.58 定,尾插车道西沿 47.6 正好让开 H4 螺钉头 (44.9 + 2.2),与 R1 自洽。
|
||||||
J600_U = 23.77 # 电池座中心(两份数据一致;§22.3b 标 ±2,槽放宽到 12)
|
J600_U = 23.77 # 电池座中心(两份数据一致;§22.3b 标 ±2,槽放宽到 12)
|
||||||
J1401_U = 53.58 # 尾插座本体中心(§22.3b,±0.3)
|
J1401_U = 53.58 # 尾插座本体中心(§22.3b,±0.3)
|
||||||
SLOT_Y = (24.8, 27.8) # 槽的 y 区间:接口边外侧 1.2~4.2,中心离边 2.7(R1 同)
|
# 槽的 y 区间:接口边外侧 1.2~4.2,中心离边 2.7(R1 同)。**跟着接口边走**。
|
||||||
|
# ⛔ 2026-09-11 晚主板转 180°:接口边朝上 ⇒ 槽在接口边**以北**(顶部服务带里),
|
||||||
|
# 排线翻过接口边 → 穿槽 → 在 B 面 U 形折回、往 **−y** 走到 J5 / J4。
|
||||||
|
SLOT_Y = (round(IF_Y + 1.2, 3), round(IF_Y + 4.2, 3))
|
||||||
|
SLOT_RIB = 2.0 # 槽顶到板边留的肋(顶边导轨也咬在这条肋上)
|
||||||
SLOT_W = {'BAT': 12.0, 'TAIL': 20.0} # 排线 8 / 18,各留余量
|
SLOT_W = {'BAT': 12.0, 'TAIL': 20.0} # 排线 8 / 18,各留余量
|
||||||
FLEX_W = {'BAT': 8.0, 'TAIL': 18.0}
|
FLEX_W = {'BAT': 8.0, 'TAIL': 18.0}
|
||||||
SLOT_R = 1.0 # 槽内圆角(铣刀半径,嘉立创内槽最小 R0.5)
|
SLOT_R = 1.0 # 槽内圆角(铣刀半径,嘉立创内槽最小 R0.5)
|
||||||
@@ -117,7 +157,7 @@ SLOT_R = 1.0 # 槽内圆角(铣刀半径,嘉立创内槽
|
|||||||
|
|
||||||
def flex_x():
|
def flex_x():
|
||||||
u"""两条排线的中心 x(刀片坐标)。"""
|
u"""两条排线的中心 x(刀片坐标)。"""
|
||||||
return {'BAT': round(PHONE_ORG[0] + J600_U, 3), 'TAIL': round(PHONE_ORG[0] + J1401_U, 3)}
|
return {'BAT': phone_xy(J600_U, 0.0)[0], 'TAIL': phone_xy(J1401_U, 0.0)[0]}
|
||||||
|
|
||||||
|
|
||||||
def flex_slots():
|
def flex_slots():
|
||||||
@@ -143,23 +183,26 @@ def slot_check():
|
|||||||
dy = max(w[1] - hy, 0.0, hy - w[3])
|
dy = max(w[1] - hy, 0.0, hy - w[3])
|
||||||
if math.hypot(dx, dy) < HOLE_KEEP:
|
if math.hypot(dx, dy) < HOLE_KEEP:
|
||||||
bad.append(u'槽 %s 离螺钉孔 %s 只有 %.2f < %.1f' % (k, hn, math.hypot(dx, dy), HOLE_KEEP))
|
bad.append(u'槽 %s 离螺钉孔 %s 只有 %.2f < %.1f' % (k, hn, math.hypot(dx, dy), HOLE_KEEP))
|
||||||
if w[3] > PHONE_ORG[1]:
|
if w[1] < IF_Y:
|
||||||
bad.append(u'槽 %s 顶 %.1f 进了手机投影(接口边 %.1f)' % (k, w[3], PHONE_ORG[1]))
|
bad.append(u'槽 %s 底 %.1f 进了手机投影(接口边 %.1f)' % (k, w[1], IF_Y))
|
||||||
if w[1] < ZONES['finger'][3] + 1.0:
|
if w[3] > BH - SLOT_RIB:
|
||||||
bad.append(u'槽 %s 底 %.1f 压到金手指区' % (k, w[1]))
|
bad.append(u'槽 %s 顶 %.1f 离板边不到 %.1f 的肋' % (k, w[3], SLOT_RIB))
|
||||||
s = flex_slots()
|
s = flex_slots()
|
||||||
rib = s['TAIL'][0] - s['BAT'][2]
|
a, b = sorted(s.values())
|
||||||
|
rib = b[0] - a[2]
|
||||||
if rib < 3.0:
|
if rib < 3.0:
|
||||||
bad.append(u'两槽之间只剩 %.1f mm 肋(要 >= 3)' % rib)
|
bad.append(u'两槽之间只剩 %.1f mm 肋(要 >= 3)' % rib)
|
||||||
return bad
|
return bad
|
||||||
|
|
||||||
|
|
||||||
# 分区(只是参考矩形,画在文档层,摆位脚本从这里取)
|
# 分区(只是参考矩形,画在文档层,摆位脚本从这里取)
|
||||||
|
PHONE_X1 = round(PHONE_ORG[0] + PHONE_WH[0], 3) # 手机右沿 68.59
|
||||||
|
POWER_X0 = round(PHONE_X1 + 2.0, 3) # 功率列西沿 70.59(离手机 2 mm)
|
||||||
ZONES = {
|
ZONES = {
|
||||||
'finger': (0.0, 0.0, BW, 11.0), # 金手指区:不许放件(槽体 ~9mm)
|
'finger': (TONGUE_X0, 0.0, TONGUE_X1, STEP_H), # 舌头(唯一伸进插槽的那块):不许放件
|
||||||
'service': (0.0, 11.0, 72.0, 29.0), # 服务带:C60 / TP / EDL / BM24 / K1~K4
|
'service': (0.0, IF_Y, POWER_X0, BH), # 服务带(2026-09-11 晚起在顶部):C60 / 两条排线槽 / J3
|
||||||
'phone': (3.0, 29.0, 3 + 67.09, 29.0 + 44.66), # 小米8 主板投影
|
'phone': (PHONE_ORG[0], PHONE_ORG[1], PHONE_X1, round(PHONE_ORG[1] + PHONE_WH[1], 3)),
|
||||||
'power': (72.0, 11.0, BW, BH), # 功率列
|
'power': (POWER_X0, STEP_H, BW, BH), # 功率列
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -173,26 +216,37 @@ def corner(cx, cy, a0, a1):
|
|||||||
|
|
||||||
|
|
||||||
def outline_pts():
|
def outline_pts():
|
||||||
u"""板框点列(逆时针,从底边左端 (r,0) 起,回到 (r,0) 闭合)。
|
u"""板框点列(逆时针,从舌头左下角起,闭合)。**凸字形**:底边只剩舌头那一段。
|
||||||
|
|
||||||
⚠ 相邻重合点必须去掉:圆角的首点和前一条直边的终点是同一个点,留着就会生成
|
⚠ 相邻重合点必须去掉:圆角的首点和前一条直边的终点是同一个点,留着就会生成
|
||||||
一条**零长度线段**,编辑器会静默把它吃掉(下发 41 段读回 37 段),
|
一条**零长度线段**,编辑器会静默把它吃掉(下发 41 段读回 37 段),
|
||||||
于是「读回条数 != 期望」变成一个没完没了的假警报。这正是 CLAUDE.md 里
|
于是「读回条数 != 期望」变成一个没完没了的假警报。这正是 CLAUDE.md 里
|
||||||
原理图那条「零长度导线」坑的 PCB 版。
|
原理图那条「零长度导线」坑的 PCB 版。
|
||||||
|
|
||||||
|
⛔ 第一段必须仍是底边 `(TONGUE_X0, 0) -> (TONGUE_X1, 0)`:`segments()` 和
|
||||||
|
`outline_polygon()` 都按这个前提把防呆缺口插进去。
|
||||||
"""
|
"""
|
||||||
r = CORNER_R
|
r, ri, hs = CORNER_R, STEP_R, STEP_H
|
||||||
pts = [(r, 0.0), (BW - r, 0.0)]
|
pts = [(TONGUE_X0, 0.0), (TONGUE_X1, 0.0)] # 舌头底边(缺口在中间断开)
|
||||||
pts += corner(BW - r, r, 270, 360) # 右下
|
pts += [(TONGUE_X1, hs - ri)]
|
||||||
|
pts += corner(TONGUE_X1 + ri, hs - ri, 180, 90) # 右侧台阶内凹角
|
||||||
|
pts += [(BW - r, hs)]
|
||||||
|
pts += corner(BW - r, hs + r, 270, 360) # 右下外角
|
||||||
pts += [(BW, BH - r)]
|
pts += [(BW, BH - r)]
|
||||||
pts += corner(BW - r, BH - r, 0, 90) # 右上
|
pts += corner(BW - r, BH - r, 0, 90) # 右上
|
||||||
pts += [(r, BH)]
|
pts += [(r, BH)]
|
||||||
pts += corner(r, BH - r, 90, 180) # 左上
|
pts += corner(r, BH - r, 90, 180) # 左上
|
||||||
pts += [(0.0, r)]
|
pts += [(0.0, hs + r)]
|
||||||
pts += corner(r, r, 180, 270) # 左下,收回 (r,0)
|
pts += corner(r, hs + r, 180, 270) # 左下外角
|
||||||
|
pts += [(TONGUE_X0 - ri, hs)]
|
||||||
|
pts += corner(TONGUE_X0 - ri, hs - ri, 90, 0) # 左侧台阶内凹角
|
||||||
|
pts += [(TONGUE_X0, 0.0)]
|
||||||
out = [pts[0]]
|
out = [pts[0]]
|
||||||
for q in pts[1:]:
|
for q in pts[1:]:
|
||||||
if abs(q[0] - out[-1][0]) > 1e-9 or abs(q[1] - out[-1][1]) > 1e-9:
|
if abs(q[0] - out[-1][0]) > 1e-9 or abs(q[1] - out[-1][1]) > 1e-9:
|
||||||
out.append(q)
|
out.append(q)
|
||||||
|
if abs(out[0][0] - out[-1][0]) > 1e-9 or abs(out[0][1] - out[-1][1]) > 1e-9:
|
||||||
|
out.append(out[0])
|
||||||
assert abs(out[0][0] - out[-1][0]) < 1e-9 and abs(out[0][1] - out[-1][1]) < 1e-9, u'板框点列没有闭合'
|
assert abs(out[0][0] - out[-1][0]) < 1e-9 and abs(out[0][1] - out[-1][1]) < 1e-9, u'板框点列没有闭合'
|
||||||
return out
|
return out
|
||||||
|
|
||||||
@@ -283,7 +337,7 @@ def rrect_pts(x0, y0, x1, y1, r, seg=6):
|
|||||||
|
|
||||||
def selfcheck():
|
def selfcheck():
|
||||||
bl, br = notch_break()
|
bl, br = notch_break()
|
||||||
assert round(br - bl, 4) == 2.9, (bl, br)
|
assert round(br - bl, 4) == round(fp_edge.NOTCH_W + 2 * fp_edge.LEAD_IN, 4), (bl, br)
|
||||||
# 金手指必须整个落在板内,且不侵占服务带
|
# 金手指必须整个落在板内,且不侵占服务带
|
||||||
for pin in ('A1', 'A32'):
|
for pin in ('A1', 'A32'):
|
||||||
x, y, w, h = fp_edge.pad_geom(pin)
|
x, y, w, h = fp_edge.pad_geom(pin)
|
||||||
@@ -294,10 +348,27 @@ def selfcheck():
|
|||||||
assert fp_edge.NOTCH_D < ZONES['finger'][3], u'缺口比金手指区还深'
|
assert fp_edge.NOTCH_D < ZONES['finger'][3], u'缺口比金手指区还深'
|
||||||
# 分区不许互相重叠(除了 finger/service 只共边)
|
# 分区不许互相重叠(除了 finger/service 只共边)
|
||||||
z = ZONES
|
z = ZONES
|
||||||
assert z['service'][3] == z['phone'][1] == 29.0
|
assert z['service'][1] == z['phone'][3] == IF_Y
|
||||||
|
# ⚠ 台阶之后 finger 区只剩舌头那一块(x TONGUE_X0~TONGUE_X1)。手机投影 y0=11.0
|
||||||
|
# 低于台阶 12.0,但它在舌头正上方那一段是有板材的;两侧那 1 mm 是**有意的悬空**
|
||||||
|
# (定位孔最南 14.46 全在板材上,主板靠尼龙立柱固定)⇒ 只判「不压舌头」。
|
||||||
|
# 主板投影底边在舌头两侧的**悬空量**(有意为之,见 STEP_H 处的说明):只判别超标。
|
||||||
|
_hang = max(0.0, STEP_H - z['phone'][1])
|
||||||
|
assert _hang <= 1.5, u'主板投影底边悬空 %.2f mm 过多(台阶 %.1f vs 主板 y0 %.2f)' % (
|
||||||
|
_hang, STEP_H, z['phone'][1])
|
||||||
|
assert min(v[1] for v in phone_holes().values()) > STEP_H, u'有定位孔落进台阶切掉的区域'
|
||||||
|
assert fp_edge.EDGE_CLR + fp_edge.LONG_L < STEP_H, u'金手指比台阶还高'
|
||||||
assert z['phone'][2] <= z['power'][0], u'手机投影压进功率列'
|
assert z['phone'][2] <= z['power'][0], u'手机投影压进功率列'
|
||||||
assert z['service'][2] <= z['power'][0], u'服务带压进功率列'
|
assert z['service'][2] <= z['power'][0], u'服务带压进功率列'
|
||||||
assert z['phone'][3] <= BH, u'手机投影超出板顶'
|
assert z['phone'][3] <= BH, u'手机投影超出板顶'
|
||||||
|
# 台阶:金手指与防呆缺口必须整个落在舌头里,内凹角要铣得出来
|
||||||
|
_fx0 = J1_X + fp_edge.PIN_X['A1'] - fp_edge.FW / 2
|
||||||
|
_fx1 = J1_X + fp_edge.PIN_X['A32'] + fp_edge.FW / 2
|
||||||
|
assert TONGUE_X0 < _fx0 and _fx1 < TONGUE_X1, u'金手指 %.2f~%.2f 超出舌头 %.1f~%.1f' % (_fx0, _fx1, TONGUE_X0, TONGUE_X1)
|
||||||
|
_bl, _br = notch_break()
|
||||||
|
assert TONGUE_X0 < _bl < _br < TONGUE_X1, u'防呆缺口超出舌头'
|
||||||
|
assert STEP_R >= 0.5, u'台阶内凹角 R%.1f 铣刀下不去' % STEP_R
|
||||||
|
assert TONGUE_X1 - TONGUE_X0 < BW, u'舌头没窄于板宽,等于没开台阶'
|
||||||
bad = slot_check()
|
bad = slot_check()
|
||||||
assert not bad, u'排线槽校核不过: %s' % bad
|
assert not bad, u'排线槽校核不过: %s' % bad
|
||||||
return True
|
return True
|
||||||
|
|||||||
+88
-19
@@ -57,14 +57,34 @@ L_TOP, L_GND, L_PWR, L_BOT = 1, 15, 16, 2
|
|||||||
|
|
||||||
INSET = 0.5 # 铜面离板边
|
INSET = 0.5 # 铜面离板边
|
||||||
TOP_POUR_Y = 11.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
|
NOTCH_KEEP = 0.5 # 缺口周围再让 0.5
|
||||||
|
|
||||||
# L3 两个岛(x0, y0, x1, y1)—— y 段直接对着 pcb_place 的功能带切,见 --bands
|
# L3 两个岛(x0, y0, x1, y1)
|
||||||
VO_ISLAND = (20.0, 11.5, 97.5, 28.8) # eFuse/检流带 + 服务带:VO_P 4 A 的主通道
|
# ⛔⛔ 2026-09-11 晚(方案 §35):主板转 180°、功率链转 180° ⇒ 两个岛上下对调。
|
||||||
# 2026-09-09 M6:J5 / 阻尼组挪到电池槽北边(y 29~40)之后岛要跟过去 —— 往北伸一个
|
# · `VO_P` 岛在**上半**:功率链顶上的 Rs1 / U3 → 西去 J5 / 阻尼组 / DIS → 两槽之间的 C60。
|
||||||
# 叶(L 形单环,不是第二块铜)。东沿 46 让开尾插槽 46.58;电池槽本身由挖槽区域反焊盘让开。
|
# 电池槽是铣穿的,岛做成**绕开电池槽的 U 形单环**(三块矩形拼,`VO_RECTS`),不用带洞多边形。
|
||||||
VO_LOBE = (20.0, 28.8, 46.0, 46.0)
|
# · `+12V` 岛在**下半**:金手指 12V 三指的 launch 孔(x 28.5~30.5, y 11.75)→ 东去 F1 的 +12V 脚(功率链最底)。
|
||||||
V12_ISLAND = (84.0, 55.0, 97.5, 74.0) # 12V 入口(F1 的 +12V 脚)及以上;新摆位后功率链上端只占 x 83~93
|
# 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):
|
def mil(v):
|
||||||
@@ -163,12 +183,14 @@ def gnd_tiles(y_lo):
|
|||||||
x0, x1 = d, B.BW - d
|
x0, x1 = d, B.BW - d
|
||||||
y1 = B.BH - d
|
y1 = B.BH - d
|
||||||
cuts = [(a - INSET, b - INSET, c + INSET, e + INSET) for (a, b, c, e) in B.mill_cuts()]
|
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 = []
|
tiles = []
|
||||||
for xa, xb in zip(xs, xs[1:]):
|
for xa, xb in zip(xs, xs[1:]):
|
||||||
if xb - xa < 0.6:
|
if xb - xa < 0.6:
|
||||||
continue
|
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]):
|
for c in sorted(cuts, key=lambda c: c[1]):
|
||||||
if c[0] < xb - 1e-9 and xa < c[2] - 1e-9:
|
if c[0] < xb - 1e-9 and xa < c[2] - 1e-9:
|
||||||
ys += [c[1], c[3]]
|
ys += [c[1], c[3]]
|
||||||
@@ -198,12 +220,32 @@ def gnd_tiles(y_lo):
|
|||||||
return tiles
|
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():
|
def vo_poly():
|
||||||
u"""VO_P 岛:主体矩形 + 北叶,拼成一个 L 形**单环**(逆时针,显式闭合)。"""
|
u"""VO_P 岛:主体 + 两个上叶(夹着电池槽),拼成一个 U 形**单环**(逆时针,显式闭合)。
|
||||||
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'北叶必须骑在主体上沿'
|
2026-09-11 晚起(方案 §35)。上叶 w 骑在主体上沿、西沿可以比主体再往西一点(C60 的 VO_P 盘)。"""
|
||||||
pts = [(a[0], a[1]), (a[2], a[1]), (a[2], a[3]), (b[2], a[3]),
|
a, w, e = VO_RECTS
|
||||||
(b[2], b[3]), (b[0], b[3]), (b[0], a[3]), (a[0], a[3])]
|
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]]
|
out = [pts[0]]
|
||||||
for q in pts[1:]:
|
for q in pts[1:]:
|
||||||
if abs(q[0] - out[-1][0]) > 1e-9 or abs(q[1] - out[-1][1]) > 1e-9:
|
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 小的先铺、先占地盘。"""
|
u"""[(name, net, layer, [环...], priority)],priority 小的先铺、先占地盘。"""
|
||||||
outs = []
|
outs = []
|
||||||
outs.append(('VO-L3', 'VO_P', L_PWR, [src(vo_poly())], 1))
|
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),
|
for tag, layer, y_lo in (('L2', L_GND, INSET), ('TOP', L_TOP, TOP_POUR_Y),
|
||||||
('BOT', L_BOT, TOP_POUR_Y)):
|
('BOT', L_BOT, TOP_POUR_Y)):
|
||||||
for k, (a, b, c, d2) in enumerate(gnd_tiles(y_lo)):
|
for k, (a, b, c, d2) in enumerate(gnd_tiles(y_lo)):
|
||||||
@@ -225,6 +267,14 @@ def plan():
|
|||||||
return outs
|
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):
|
def selfcheck(ps):
|
||||||
bad = []
|
bad = []
|
||||||
for name, _net, _lay, rings, _p in ps:
|
for name, _net, _lay, rings, _p in ps:
|
||||||
@@ -237,19 +287,38 @@ def selfcheck(ps):
|
|||||||
bad.append(u'外层铜下沿 %.2f 压到指顶 %.2f' % (TOP_POUR_Y, top))
|
bad.append(u'外层铜下沿 %.2f 压到指顶 %.2f' % (TOP_POUR_Y, top))
|
||||||
if TOP_POUR_Y <= fp_edge.NOTCH_D:
|
if TOP_POUR_Y <= fp_edge.NOTCH_D:
|
||||||
bad.append(u'外层铜下沿 %.2f 低于缺口顶 %.2f' % (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()
|
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'缺口挖得比口部还窄')
|
bad.append(u'缺口挖得比口部还窄')
|
||||||
# 两个岛不许互相重叠(同层,优先级只有 1/2 之差,重叠就说不清谁裁谁)
|
# 两个岛不许互相重叠(同层,优先级只有 1/2 之差,重叠就说不清谁裁谁)
|
||||||
b = V12_ISLAND
|
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]:
|
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 上重叠')
|
bad.append(u'VO 岛和 +12V 岛在 L3 上重叠')
|
||||||
# 北叶不许伸进尾插槽/车道
|
# 岛不许压到铣穿的槽(含 0.5 净距)—— 客户端会自己让,但让出来的形状谁也没核过
|
||||||
for (x0, y0, x1, y1) in B.mill_cuts():
|
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:
|
for a in VO_RECTS + [b]:
|
||||||
bad.append(u'VO 北叶压到槽 (%.1f~%.1f)' % (x0, x1))
|
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
|
return bad
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+47
@@ -7,6 +7,53 @@
|
|||||||
- 底板入口为 `.claude/r2/remote_route.ps1`;`route_base.py` 已加本机硬阻断,避免新会话误跑。
|
- 底板入口为 `.claude/r2/remote_route.ps1`;`route_base.py` 已加本机硬阻断,避免新会话误跑。
|
||||||
- **刀片**入口为 `bash .claude/r2/remote_blade.sh ['变体' ...]`(2026-09-11 新加);`router.py --replan/--pf` 同样本机硬阻断。
|
- **刀片**入口为 `bash .claude/r2/remote_blade.sh ['变体' ...]`(2026-09-11 新加);`router.py --replan/--pf` 同样本机硬阻断。
|
||||||
|
|
||||||
|
## ⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐ 2026-09-12:刀片金手指两侧开台阶(**插不进插槽**)+ 铺铜补齐(都已下发)
|
||||||
|
|
||||||
|
用户:「解决刀片板与插槽干涉的问题,完善刀片板铺铜」→「金手指两侧没有开槽,应该会插不进插槽」。
|
||||||
|
|
||||||
|
### ⛔ 根因:禁布区 ≠ 板材
|
||||||
|
|
||||||
|
`ZONES['finger']` 早就写着「金手指区 11 mm(**槽体高度 ~9 mm 要让开**)」,
|
||||||
|
但那只是**禁布区**(别放件),**板框从来没开台阶** —— `outline_pts()` 第一段就是
|
||||||
|
`(r,0) → (BW-r,0)`,整块 90 mm 宽的板材一直到 y=0。而插槽塑料体只有 **39 mm 且两端封闭**
|
||||||
|
⇒ x<29.5 / x>68.5 的板材压在塑料体两端壁上,**插不到底**。PCI-E 卡在这一段必须是「凸」字形。
|
||||||
|
|
||||||
|
### 定稿(用户拍板)与放行核算
|
||||||
|
|
||||||
|
| 项 | 值 |
|
||||||
|
|---|---|
|
||||||
|
| 舌头 | **36.0 mm**(x 27.00~63.00);金手指本身跨 33.70,两侧各余 1.15 |
|
||||||
|
| 台阶高 | **12.0 mm**(槽体 ~9,余 3)|
|
||||||
|
| 内凹角 | **R1.0**(外形铣刀下不去直角)|
|
||||||
|
| 切掉 | **648 mm²**,占 10.6% |
|
||||||
|
|
||||||
|
被切区里 **铜 0 / 过孔 0 / 焊盘 0 / 器件 0**(板上读回 + `_blade_pads.json` 两种口径一致);
|
||||||
|
7 个定位孔最南 `H5` y=14.46 全在板材上;两条铣穿槽 y 56.86 起,不受影响。
|
||||||
|
|
||||||
|
⚠ **唯一代价**:手机主板投影底边(`PHONE_ORG.y = 11.0`)在舌头两侧悬空 **1.0 mm**
|
||||||
|
(左 x 1.50~27.00 / 右 x 63.00~68.59,合计 31.09 mm²)。主板靠 7 个 M1.6 尼龙立柱压住、
|
||||||
|
不靠边缘托 ⇒ 无害。`selfcheck` 已改成判「悬空量 ≤ 1.5」+「定位孔不许落进台阶区」。
|
||||||
|
|
||||||
|
### 铺铜:原本外层整层缺失,现已补齐并跟着台阶重画
|
||||||
|
|
||||||
|
抓板发现刀片上只有 **11 块**铺铜(L2 九块 + L3 两岛)——**L1 / L4 的 GND 底填全都不在板上**,
|
||||||
|
而交接记录写的是"铺铜 25/25"。先补齐到 25 块,开台阶后重画成 **31 块**
|
||||||
|
(L2 11 + L1 9 + L4 9 + L3 两岛),**填充 31/31**;刀片 **DRC 间距错误 0 条**。
|
||||||
|
|
||||||
|
- 新常量 `pcb_pour.STEP_POUR_Y = 12.5`(舌头两侧的铜下沿);`gnd_tiles()` 的竖条切分点加入舌头两端。
|
||||||
|
- **`+12V` 岛改成阶梯形单环**:舌头段仍下探 y=9.0 接 12V 三指的 launch 孔(x 28.5~30.5 / y 11.75,
|
||||||
|
全在舌头内),舌头以东抬到 12.5;断面 11.0 → **7.5 mm**(1 oz 内层 ≈ 5.1 A,需求 1.5 A 峰值)。
|
||||||
|
|
||||||
|
### 三条坑
|
||||||
|
|
||||||
|
1. **禁布区不等于板材** —— 见上,这次就是栽在这上面。
|
||||||
|
2. **阶梯形多边形不能按包围盒判**:给 `selfcheck` 加「铜不许伸进台阶区」时按环的包围盒判,
|
||||||
|
`+12V` 岛(min y 9.0、max x 84)直接误报 ⇒ 改成**逐边采样**(0.25 mm 步长)。
|
||||||
|
3. **`pcb_pour.inner_poly()` / `outer_poly()` 是死函数**,`plan()` 只用 `gnd_tiles()`。
|
||||||
|
改铺铜边界时改那两个不生效,看着像"改了没用"。
|
||||||
|
|
||||||
|
⬜ 待用户人眼确认台阶形状与铺铜(图已发)。
|
||||||
|
|
||||||
## ⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐ 2026-09-12(定版):底板以**用户自己布好的那版**定稿 + 位号丝印重排(已下发)
|
## ⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐ 2026-09-12(定版):底板以**用户自己布好的那版**定稿 + 位号丝印重排(已下发)
|
||||||
|
|
||||||
用户:「按当前 eda 中底板状态定版,优化丝印放置」「现在 eda 中是我已经布好了的」
|
用户:「按当前 eda 中底板状态定版,优化丝印放置」「现在 eda 中是我已经布好了的」
|
||||||
|
|||||||
+64
@@ -3325,3 +3325,67 @@ FAN_PWM_L (10.30, 83.90, 22.50, 87.30) 盖住 J27.4 与 Q6.3
|
|||||||
|
|
||||||
工具:**`silk_base.py`**(`--push` 走 `pcb_PrimitiveAttribute.modify(id, {x, y, rotation})`,
|
工具:**`silk_base.py`**(`--push` 走 `pcb_PrimitiveAttribute.modify(id, {x, y, rotation})`,
|
||||||
下发后读回逐个核对),快照 `_base_silk.json`、方案 `_base_silk_plan.json`。
|
下发后读回逐个核对),快照 `_base_silk.json`、方案 `_base_silk_plan.json`。
|
||||||
|
|
||||||
|
## 40. 刀片金手指两侧开台阶(2026-09-12 用户指出「插不进插槽」)+ 铺铜补齐
|
||||||
|
|
||||||
|
用户:「解决刀片板与插槽干涉的问题,完善刀片板铺铜」→「金手指两侧没有开槽,应该会插不进插槽」。
|
||||||
|
|
||||||
|
### 40.1 ⛔ 根因:刀片底边是一条直线,而 PCI-E 卡在这一段必须是「凸」字形
|
||||||
|
|
||||||
|
`outline_pts()` 原来第一段就是 `(r, 0) → (BW-r, 0)` —— 整块 90 mm 宽的板材一直到 y=0。
|
||||||
|
而插槽塑料体只有 **39 mm 长且两端封闭**(`PCIE-64P11L`,焊盘外框 42.0 × 9.2),
|
||||||
|
高度约 9 mm。卡插下去时,x < 29.5 / x > 68.5 的板材会压在塑料体两端壁上,**插不到底**。
|
||||||
|
|
||||||
|
⚠ 这一条 §3.1 的分区图里其实写着「金手指区 11 mm(**槽体高度 ~9 mm 要让开**)」,
|
||||||
|
但那只写进了 `ZONES['finger']`(禁布区),**板框没有跟着开台阶** —— 禁布区管的是"别放件",
|
||||||
|
不等于"这里没有板材"。两者是两回事,这次才暴露。
|
||||||
|
|
||||||
|
### 40.2 定稿尺寸(用户拍板)
|
||||||
|
|
||||||
|
| 项 | 值 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| 舌头宽 | **36.0 mm**(x 27.00~63.00)| 金手指本身跨 33.70(x 28.15~61.85),两侧各余 1.15 |
|
||||||
|
| 台阶高 | **12.0 mm** | 槽体 ~9,余 3 |
|
||||||
|
| 内凹角 | **R1.0** | 外形铣刀下不去直角(嘉立创外形最小 R0.5) |
|
||||||
|
| 切掉 | **648 mm²**(占 10.6%)| 左 27.0×12.0 + 右 27.0×12.0 |
|
||||||
|
|
||||||
|
常量在 `pcb_blade.TONGUE_X0/TONGUE_X1/STEP_H/STEP_R`;`outline_pts()` 改成凸字形,
|
||||||
|
**第一段仍是舌头底边**(`segments()` 与 `outline_polygon()` 都按这个前提把防呆缺口插进去)。
|
||||||
|
|
||||||
|
### 40.3 放行前逐项核过(两种口径交叉验证)
|
||||||
|
|
||||||
|
被切区(x<27 或 x>63 且 y<12)里:**铜 0 段 / 过孔 0 / 焊盘 0 / 器件本体框 0**
|
||||||
|
(板上读回 + `_blade_pads.json` 缓存两种口径一致)。
|
||||||
|
7 个定位孔最南 `H5` 在 y=14.46,全在板材上;两条铣穿槽在 y 56.86 起,都不受影响。
|
||||||
|
|
||||||
|
⚠ **唯一代价:手机主板投影底边在舌头两侧悬空 1.0 mm**
|
||||||
|
(`PHONE_ORG.y = 11.0` < 台阶 12.0;左 x 1.50~27.00、右 x 63.00~68.59,合计 31.09 mm²)。
|
||||||
|
主板是 7 个 **M1.6 尼龙立柱**压住的(§3.2 中框式焊盘,螺柱间隙 1.0),不靠边缘托 ⇒ 无害。
|
||||||
|
`selfcheck` 里改成判「悬空量 ≤ 1.5」+「定位孔不许落进台阶区」,不再用原来那条
|
||||||
|
`phone.y0 >= finger.y1`(台阶之后 finger 区只剩舌头,那条断言已经没有意义)。
|
||||||
|
|
||||||
|
### 40.4 铺铜跟着台阶改
|
||||||
|
|
||||||
|
- 新常量 `pcb_pour.STEP_POUR_Y = STEP_H + INSET = 12.5`:**舌头两侧的铜下沿**。
|
||||||
|
舌头那一段仍按 `TOP_POUR_Y`(外层 11.5) / `INSET`(内层 0.5) 走。
|
||||||
|
- `gnd_tiles()` 的竖条切分点加入舌头两端,舌头外的条 `y_lo` 抬到 12.5
|
||||||
|
⇒ 外层 L1/L4 每层 7 → **9 块**,内层 L2 由 9 → **11 块**(内层下沿是 0.5,被舌头切得更细)。
|
||||||
|
板上铺铜合计 **25 → 31 块**(L2 11 + L1 9 + L4 9 + L3 两岛)。
|
||||||
|
- **`+12V` 岛(L3)改成阶梯形单环**:舌头段仍下探到 y=9.0 去接 12V 三指的 launch 孔
|
||||||
|
(x 28.5~30.5 / y 11.75,全在舌头内;下沿 9.0 是为了避开地母线的孔 y 7.0/8.2),
|
||||||
|
舌头以东抬到 12.5。断面由 11.0 收到 **7.5 mm**(1 oz 内层 ≈ 5.1 A,需求 1.5 A 峰值)。
|
||||||
|
|
||||||
|
⚠ **`inner_poly()` / `outer_poly()` 是死函数** —— `plan()` 只用 `gnd_tiles()`。改铺铜边界时
|
||||||
|
别去改那两个(改了不生效,看着像"改了没用")。
|
||||||
|
|
||||||
|
### 40.5 一条判据上的坑:阶梯形多边形不能按包围盒判
|
||||||
|
|
||||||
|
给 `selfcheck` 加「铜不许伸进台阶切掉的区域」时,第一版按**整个环的包围盒**判:
|
||||||
|
`+12V` 岛 min(y)=9.0 且 max(x)=84 ⇒ 直接误报,而它 y=9.0 的那一段其实只在舌头内。
|
||||||
|
⇒ 改成**逐边采样**(0.25 mm 步长)判每个点。阶梯形/L 形铜面都要这么判。
|
||||||
|
|
||||||
|
### 40.6 顺带补齐:刀片外层铺铜原本整层缺失
|
||||||
|
|
||||||
|
抓板发现刀片上只有 **11 块铺铜**(L2 九块 GND + L3 两个岛),而 `plan()` 计划 25 块 ——
|
||||||
|
**L1 七块 + L4 七块 GND 底填全都不在板上**(交接记录写的"铺铜 25/25"与板上不符)。
|
||||||
|
已重建。台阶改动后每层 GND 由 7 → 9 块。
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户