R2:底板 / 刀片布局布线脚本、快照、截图与规划文档更新(含外壳、打印件、布线归档)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
zhou yang
2026-10-04 19:24:45 +08:00
共同撰写人 Claude Opus 5.5
父节点 cd01640c40
当前提交 cf7cc9cf90
共修改 759 个文件,包含 76962 行新增和 5299 行删除
+245
查看文件
@@ -0,0 +1,245 @@
# -*- coding: utf-8 -*-
u"""**底盖 v4**(2026-09-13 外观美化 A + E)。
与 v3 的差别:
A 四边**内缩 0.5**:外形 x −24.3~115.4、y −3.555~106.245(顶盖外沿 −24.8~115.9 / −4.055~106.745),
接缝处形成一圈 0.5 阴影缝,藏住两件的打印公差;四角圆角用 R2.5(与顶盖 R3 同心)——圆角由 add_fillets 后做。
E **加厚 2.4 → 3.6**(向下长,底盖顶面仍在 z=−10,机内尺寸不变;整机高 +1.2):
· 四角 M3 过孔下方挖**沉头 Ø6.5 深 2.0**,螺丝头不外露,头下还剩 1.6(2.4 厚时只剩 0.4,会压裂)
· 4 个**脚垫窝 Ø10 深 1.0**(贴 Ø10 硅胶脚垫),放在螺丝内侧、不盖住螺丝 ⇒ 拆盖不用撕脚垫
PCB 立柱、柱顶螺母孔、四角过孔位置与 v3 相同。
本地坐标:板 z −3.6~0、立柱 0~10;装配 dz = −10 ⇒ 板 z −13.6~−10。
面上切除沿用 NOTES §37:进草图后读 ModelToSketchTransform 验平面,再按变换精确画。
"""
import io
import math
import os
import sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', write_through=True)
import pythoncom
import win32com.client as wc
DST = u'D:\\DCDC\\新建文件夹\\5blades\\BottomPlate_v4.SLDPRT'
EMPTY = wc.VARIANT(pythoncom.VT_DISPATCH, None)
INSET = 0.5
X0, X1, Y0, Y1 = -24.8 + INSET, 115.9 - INSET, -4.055 + INSET, 106.745 - INSET
T = 3.6
CORNER_HOLES = [(-11.0, 3.345), (-11.0, 99.345), (108.5, 3.345), (108.5, 99.345)]
R_THRU = 1.7
CB_R, CB_D = 3.25, 2.0 # 沉头 Ø6.5 深 2
PCB_POSTS = [(4.0, 4.0), (94.0, 4.0), (4.0, 94.0), (94.0, 94.0)]
POST_R, POST_H, R_INS = 4.0, 10.0, 2.1
FOOT_R, FOOT_D = 5.0, 1.0 # 脚垫窝 Ø10 深 1
_XC, _YC = (X0 + X1) / 2.0, 51.345
FEET = [(_XC - 45.0, _YC - 43.0), (_XC + 45.0, _YC - 43.0), (_XC - 45.0, _YC + 43.0), (_XC + 45.0, _YC + 43.0)]
def prop(o, n):
v = getattr(o, n)
return v() if type(v).__name__ in ('method', 'function', 'builtin_function_or_method') else v
def D(x):
return x if hasattr(x, '_oleobj_') else wc.Dispatch(x)
def P(*a):
print(*a)
def M(v):
return v / 1000.0
app = wc.GetActiveObject('SldWorks.Application')
for d in list(app.GetDocuments or []):
try:
t = prop(d, 'GetTitle') or ''
if 'BOTTOMPLATE_V4' in t.upper():
app.CloseDoc(t)
except Exception:
pass
app.NewDocument(app.GetUserPreferenceStringValue(8), 0, 0.0, 0.0)
part = app.ActiveDoc
P(u'新建零件 %s' % prop(part, 'GetTitle'))
sm, fm = part.SketchManager, part.FeatureManager
def last_sketch():
nm, f = None, prop(part, 'FirstFeature')
while f:
if prop(f, 'GetTypeName2') == 'ProfileFeature':
nm = prop(f, 'Name')
f = prop(f, 'GetNextFeature')
return nm
def pick(name, typ):
part.ClearSelection2(True)
part.Extension.SelectByID2(name, typ, 0, 0, 0, False, 0, EMPTY, 0)
return part.SelectionManager.GetSelectedObjectCount2(-1)
def boss(depth, rev):
if pick(last_sketch(), 'SKETCH') != 1:
raise RuntimeError(u'草图没选中')
return fm.FeatureExtrusion3(True, False, rev, 0, 0, M(depth), 0.0,
False, False, False, False, 0.0, 0.0,
False, False, False, False, True, True, True, 0, 0.0, False)
def bodies():
return part.GetBodies2(0, True) or []
def faces():
b = bodies()
return prop(D(b[0]), 'GetFaces') if b else []
def bbox():
b = bodies()
if not b:
return None
xs = [[round(v * 1000, 3) for v in prop(D(x), 'GetBodyBox')] for x in b]
return [min(v[0] for v in xs), min(v[1] for v in xs), min(v[2] for v in xs),
max(v[3] for v in xs), max(v[4] for v in xs), max(v[5] for v in xs)]
def cyls():
out = []
for f in faces():
fc = D(f)
s = prop(fc, 'GetSurface')
if prop(s, 'IsCylinder'):
fb = [v * 1000 for v in prop(fc, 'GetBox')]
out.append((round(list(prop(s, 'CylinderParams'))[6] * 1000, 2), fb))
return out
def planes():
out = []
for f in faces():
fc = D(f)
s = prop(fc, 'GetSurface')
if not prop(s, 'IsPlane'):
continue
n = list(prop(s, 'PlaneParams'))[:3]
if prop(fc, 'FaceInSurfaceSense'):
n = [-v for v in n]
ax = max(range(3), key=lambda i: abs(n[i]))
out.append((ax, 1 if n[ax] > 0 else -1, [v * 1000 for v in prop(fc, 'GetBox')], prop(fc, 'GetArea') * 1e6, fc))
return out
def open_face_sketch(ax, sign, coord, tag):
for attempt in range(1, 4):
best, ba = None, -1.0
for a_, s_, fb, area, fc in planes():
if a_ == ax and s_ == sign and abs(fb[ax] - coord) < 0.02 and abs(fb[ax + 3] - coord) < 0.02 and area > ba:
best, ba = fc, area
if best is None:
P(u' ⛔ %s 选不到面' % tag); sys.exit(4)
part.ClearSelection2(True)
best.Select4(False, EMPTY)
sm.InsertSketch(True)
sk = prop(sm, 'ActiveSketch')
if sk:
arr = list(prop(D(sk), 'ModelToSketchTransform').ArrayData)
Mx = [[arr[3 * c + r] for c in range(3)] for r in range(3)]
X = (Mx, arr[9:12])
nax = max(range(3), key=lambda i: abs(Mx[2][i]))
probe = [0.0, 0.0, 0.0]
probe[ax] = coord / 1000.0
sz = (sum(Mx[2][i] * probe[i] for i in range(3)) + arr[11]) * 1000
ok = nax == ax and abs(sz) < 0.01
P(u' %s 进草图 第 %d 次:法线轴 %s、面上点草图 z=%.4f %s'
% (tag, attempt, 'xyz'[nax], sz, u'✅' if ok else u'✗ 退出重进'))
if ok:
return X
sm.InsertSketch(True)
P(u' ⛔ %s 进不到目标面' % tag); sys.exit(4)
def to_sketch(X, p):
Mx, t = X
q = [v / 1000.0 for v in p]
return [sum(Mx[r][c] * q[c] for c in range(3)) + t[r] for r in range(3)]
def cut(depth):
if pick(last_sketch(), 'SKETCH') != 1:
return None
return fm.FeatureCut4(True, False, False, 0, 0, M(depth), 0.0,
False, False, False, False, 0.0, 0.0,
False, False, False, False, False,
True, True, False, False, False, 0, 0.0, False, False)
P(u'\n[1] 平板 %.1f × %.1f × %.1f(四边内缩 %.1f)+ 四角 Ø%.1f 过孔' % (X1 - X0, Y1 - Y0, T, INSET, 2 * R_THRU))
pick(u'前视基准面', 'PLANE')
sm.InsertSketch(True)
sm.AddToDB = True
sm.CreateCornerRectangle(M(X0), M(Y0), 0.0, M(X1), M(Y1), 0.0)
for hx, hy in CORNER_HOLES:
sm.CreateCircleByRadius(M(hx), M(hy), 0.0, M(R_THRU))
sm.AddToDB = False
sm.InsertSketch(True)
boss(T, True)
P(u' box %s' % bbox())
P(u'\n[2] PCB 立柱 Ø%.0f × %.0f + 柱顶 Ø%.1f 螺母孔' % (2 * POST_R, POST_H, 2 * R_INS))
pick(u'前视基准面', 'PLANE')
sm.InsertSketch(True)
sm.AddToDB = True
for hx, hy in PCB_POSTS:
sm.CreateCircleByRadius(M(hx), M(hy), 0.0, M(POST_R))
sm.CreateCircleByRadius(M(hx), M(hy), 0.0, M(R_INS))
sm.AddToDB = False
sm.InsertSketch(True)
boss(POST_H, False)
b = bbox()
P(u' box %s(期望 x %.1f~%.1f y %.3f~%.3f z %.1f~%.1f)' % (b, X0, X1, Y0, Y1, -T, POST_H))
if b is None or any(abs(b[i] - w) > 0.02 for i, w in enumerate([X0, Y0, -T, X1, Y1, POST_H])):
P(u'⛔ 停手'); sys.exit(2)
for tag, pts, r, dep in ((u'沉头', CORNER_HOLES, CB_R, CB_D), (u'脚垫窝', FEET, FOOT_R, FOOT_D)):
P(u'\n[3] 底面 %s ×4:Ø%.1f 深 %.1f' % (tag, 2 * r, dep))
X = open_face_sketch(2, -1, -T, tag)
sm.AddToDB = True
for hx, hy in pts:
q = to_sketch(X, (hx, hy, -T))
sm.CreateCircleByRadius(q[0], q[1], 0.0, M(r))
sm.AddToDB = False
sm.InsertSketch(True)
c = cut(dep)
got = [fb for rr, fb in cyls() if abs(rr - r) < 0.01]
okp = len(got) == 4 and all(abs(fb[2] + T) < 0.05 and abs(fb[5] - (-T + dep)) < 0.05 for fb in got) and \
all(any(abs((fb[0] + fb[3]) / 2 - hx) < 0.05 and abs((fb[1] + fb[4]) / 2 - hy) < 0.05 for fb in got) for hx, hy in pts)
P(u' 切除 → %r;R%.2f 圆柱面 %d 个,z %.1f~%.1f、圆心在位 %s'
% (prop(c, 'Name') if c else c, r, len(got), -T, -T + dep, u'✅' if okp else u'⛔'))
if not okp:
P(u'⛔ 不存盘'); sys.exit(3)
h = {}
for rr, fb in cyls():
h[rr] = h.get(rr, 0) + 1
thru = [fb for rr, fb in cyls() if abs(rr - R_THRU) < 0.01]
ins = [fb for rr, fb in cyls() if abs(rr - R_INS) < 0.01]
P(u'\n[4] 验收 直方图 %s(期望 {1.7: 4, 2.1: 4, 3.25: 4, 4.0: 4, 5.0: 4})' % dict(sorted(h.items())))
ok_thru = len(thru) == 4 and all(abs(fb[2] - (-T + CB_D)) < 0.05 and abs(fb[5]) < 0.05 for fb in thru)
ok_ins = len(ins) == 4 and all(abs(fb[2]) < 0.05 and abs(fb[5] - POST_H) < 0.05 for fb in ins)
P(u' 过孔 z %.1f~0(沉头以上 1.6 实体)%s;柱顶螺母孔 z 0~10 盲孔 %s'
% (-T + CB_D, u'✅' if ok_thru else u'⛔', u'✅' if ok_ins else u'⛔'))
want = {1.7: 4, 2.1: 4, 3.25: 4, 4.0: 4, 5.0: 4}
if not (ok_thru and ok_ins) or any(h.get(k, 0) != v for k, v in want.items()):
P(u'⛔ 不存盘'); sys.exit(3)
e1 = wc.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0)
w1 = wc.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_I4, 0)
part.Extension.SaveAs3(DST, 0, 1, EMPTY, EMPTY, e1, w1)
P(u'\n另存 err=%s 存在=%s %.0f KB'
% (e1.value, os.path.exists(DST), os.path.getsize(DST) / 1024.0 if os.path.exists(DST) else 0))