原理图/PCB 已在 EasyEDA 里做到 12 页跨页 0 漏接,固件刚完成骨架包 A1。 这次是把已有的一切一次性纳入版本控制,没有改动任何设计内容。 纳入: - 设计与需求文档、PROGRESS.md、小米8 参考原理图 PDF 与追脚脚本 - .claude/ 下的 EasyEDA 桥接工具链与几何/网表缓存(eda-parts.json、 pcb-parts.json、pcb-pads.json、p2-ch1.json 等,是重画各页的唯一事实来源) - 117 张验证截图(本项目所有方向问题都是靠人眼看截图发现的,属于证据不是垃圾) - firmware/ 的 A1 骨架与 site/ 文档站源码 .gitignore 排除:构建产物(firmware/build、host/build、sdkconfig)、 site/node_modules、__pycache__、桥接日志 _bridge.log、脚本自标的 *.stale。 .gitattributes 默认 `* -text`:现有 .py/.json 大多是 CRLF,原样存, 不让 git 重写行尾。唯一例外是 *.sh 强制 LF —— 带 \r 的 shell 脚本 bash 跑不了。 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01QYuExfgyYa6DzRRcUso8M8
78 行
2.5 KiB
Python
78 行
2.5 KiB
Python
# -*- coding: utf-8 -*-
|
||
u"""在载板中央走廊里找两个中跨 M3 孔的位置(2026-09-05 用户拍板要加)。
|
||
|
||
判据:孔中心到**任何**已有焊盘 / 电解罐体的净间距 >= CLR。
|
||
孔按 NPTH Ø3.2 **无焊盘**算 —— 有焊盘的话 Ø6 塞不进走廊(见输出)。
|
||
罐体半径来自 pcb2_place.py 的 C801_BODY_R(Ø12.5 含余量)。
|
||
"""
|
||
import json
|
||
import math
|
||
import os
|
||
import sys
|
||
|
||
sys.stdout.reconfigure(encoding='utf-8')
|
||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||
MIL = 39.3700787401575
|
||
|
||
pads = json.load(open(os.path.join(HERE, '_pcb2_pads.json'), encoding='utf-8'))
|
||
|
||
|
||
def box(shape, rot, x, y):
|
||
kind = shape[0]
|
||
if kind == 'POLYGON':
|
||
pts = [v for v in shape[1] if isinstance(v, (int, float))]
|
||
xs, ys = pts[0::2], pts[1::2]
|
||
return ((min(xs) + max(xs)) / 2 / MIL, (min(ys) + max(ys)) / 2 / MIL,
|
||
(max(xs) - min(xs)) / 2 / MIL, (max(ys) - min(ys)) / 2 / MIL)
|
||
w, h = float(shape[1]) / MIL, float(shape[2]) / MIL
|
||
d = rot * 180.0 / math.pi if abs(rot) <= 2 * math.pi + 1e-6 else rot
|
||
if round(d) % 180 == 90:
|
||
w, h = h, w
|
||
return x / MIL, y / MIL, w / 2.0, h / 2.0
|
||
|
||
|
||
P = [box(s, r, x, y) for lay, x, y, r, s, net, num in pads]
|
||
|
||
# 五个 Ø10 电解罐(顶层,按 Ø12.5 留),中心从 pcb2_place.py 的 BAND['c1'] 折算
|
||
CANS = [(17.0, 74.5), (88.5, 74.5), (160.0, 74.5), (95.84, 60.66), (167.34, 60.66)]
|
||
CAN_R = 6.25
|
||
|
||
HOLE_R = 1.6 # NPTH Ø3.2
|
||
CLR = 0.5 # 到任何铜/罐体的净间距
|
||
|
||
|
||
def clearance(cx, cy):
|
||
best = 1e9
|
||
for px, py, hw, hh in P:
|
||
d = max(abs(cx - px) - hw, abs(cy - py) - hh) - HOLE_R
|
||
best = min(best, d)
|
||
for qx, qy in CANS:
|
||
best = min(best, math.hypot(cx - qx, cy - qy) - CAN_R - HOLE_R)
|
||
return best
|
||
|
||
|
||
# 走廊:两排手机本体之间(CH4/CH5 顶 49.66,CH1~3 底 85.5)
|
||
best = []
|
||
x = 20.0
|
||
while x <= 200.0:
|
||
y = 51.0
|
||
while y <= 84.0:
|
||
c = clearance(x, y)
|
||
if c >= CLR:
|
||
best.append((round(c, 2), round(x, 1), round(y, 1)))
|
||
y += 0.25
|
||
x += 0.25
|
||
|
||
print(u'走廊里净间距 >= %.1f mm 的候选点 %d 个' % (CLR, len(best)))
|
||
# 按 x 分簇,报出每一簇里最宽敞的一个
|
||
best.sort(key=lambda t: -t[0])
|
||
picked = []
|
||
for c, x, y in best:
|
||
if all(math.hypot(x - a[1], y - a[2]) > 12 for a in picked):
|
||
picked.append((c, x, y))
|
||
if len(picked) >= 12:
|
||
break
|
||
print(u'%-8s %-8s %-8s' % (u'净间距', 'x', 'y'))
|
||
for c, x, y in sorted(picked, key=lambda t: t[1]):
|
||
print(u'%8.2f %8.2f %8.2f' % (c, x, y))
|