refactor(model): 重构P03为轻量化板式桁架并统一M4×16自攻螺钉连接方案

This commit is contained in:
cbb
2026-10-02 04:39:12 +08:00
parent 208b37048b
commit 6fe97fc643
29 changed files with 139069 additions and 1296 deletions
+320 -94
View File
@@ -23,7 +23,7 @@ from OCP.BRepAlgoAPI import BRepAlgoAPI_Common
from human_layout import (HUB, PLATE_T, R_MOT, Z_TIP, Z_WR, Z_EI, Z_SH, Z_RL, Z_R1,
Z_R3, Z_HUB3, Z_EL, Z_R6, Z_HUB6,
Z_R4, Z_CAP, Z_M6, Z_CHEST0, Z_CHEST1, X_J1_HUB, X_ARM, L1,
X_FORK_GAP,
X_FORK_GAP, X_BAY_EXT,
Y_AXIS, Y_HUB, Y_REAR, Y_COVER, Y_H, Y_R_IN, Y_R_OUT,
Y_M6, Y_CHEST, X_CHEST, FOOT_H)
@@ -80,12 +80,14 @@ def make_direct_hub(shape, j, r_disc=35.0, z_out=74.0):
# ========== 躯干/测试台架部分 (后置防倾翻高刚性机架) ==========
X_COL = -115.0
Y_COL = Y_AXIS # 128.0
Z_LOCK = 463.0 # 横向防脱锁紧螺钉高度(立柱后壁 → 榫头,M4x16 自攻)
def p_chest():
"""P01_胸腔支撑立柱 (High-Rigidity Box Mast Tower - 后置台架立柱):
1. 66x66mm 封闭中空厚壁箱型柱(壁厚 11mm,内腔 44x44),中心在 (-115.0, 128.0),位于手臂正后方;
2. 顶部接收 P03 48x48x15mm 榫头插槽与 4x M5 安装螺栓;
2. 顶部接收 P03 43.4x43.4x15mm 定位榫头(44x44 R4 内腔)、4x 竖向安装孔 + 1x 横向防脱锁紧孔
(全部 Ø3.9 直孔:M4x16 从外部直接拧入自攻成型,无过孔/无沉孔/无预埋);
3. 底部 50x50x12mm 阶梯榫头插入 P02 榫座:环形台肩(66->50)面承载轴向力,槽壁全周承载剪切;
4. 前向开设两组大圆角走线工艺窗口(Z=60~150mm 与 Z=330~420mm);
5. 外棱角全部采用 R=6mm 圆角。
@@ -115,9 +117,13 @@ def p_chest():
for xx in (X_COL - 20.0, X_COL + 16.0):
for yy in (Y_COL - 18.0, Y_COL + 18.0):
s = s.cut(cyl(2.75, 9.99, z_bot + 15.0, xx, yy))
for xx in (X_COL - 21.0, X_COL + 21.0):
for yy in (Y_COL - 21.0, Y_COL + 21.0):
s = s.cut(cyl(2.75, z_top - 20.0, z_top + 0.01, xx, yy))
# 顶部 4x 安装孔:统一 Ø3.9 直孔(M4x16 直接拧入自攻成型;只打这一个孔,无过孔/无沉孔),深 20mm
# 位于 66x66 顶环 11mm 实体壁内(内腔 22 → 外壁 33),避开 44x44 内腔与 R4 内腔圆角;
for xx in (X_COL - 27.5, X_COL + 27.5):
for yy in (Y_COL - 13.5, Y_COL + 13.5):
s = s.cut(cyl(1.95, z_top - 20.0, z_top + 0.01, xx, yy))
# 横向防脱锁紧孔(后壁 → 榫头):Ø3.9 贯穿 11mm 后壁 + 榫头同径(M4x16 拧入自攻)
s = s.cut(Xcyl(1.95, X_COL - 34.0, X_COL - 20.0, Y_COL, Z_LOCK))
w_bot = (cq.Workplane("YZ", origin=(X_COL + 33.5, Y_COL, 105.0))
.rect(34.0, 70.0)
@@ -134,7 +140,9 @@ def p_chest():
def split_p01_poka_yoke(p01):
"""拆分 P01 为 A/B/C 三段(严格适配 200x200mm 打印机,竖直免支撑打印):
带 16mm 阶梯互锁榫卯(外套筒壁 3.6 + 公榫壁 6.9,内腔收窄 51->44 换取双厚壁,
单边配合间隙 0.5)、非对称 M4 横向对锁穿钉孔(物理防反装防呆)、以及本体 3D 凹刻朝向标识。
单边配合间隙 0.5)、以及统一 Ø3.9 直孔的分段对锁孔(M4x16 从外面直接拧入自攻成型,
母口壁与公榫壁同径,无过孔/沉孔/预埋,前后两面对称各一颗);
孔位相对立柱中心 −16 / +22 非对称(物理防反装防呆);本体 3D 凹刻朝向标识。
"""
z_bot = 22.0
z_s1 = 172.0
@@ -144,6 +152,14 @@ def split_p01_poka_yoke(p01):
# 非对称对锁孔位(相对立柱中心偏心 -16mm 与 +22mm,偏心差 6mm,反装无法穿入螺栓)
xx_bolts = (X_COL - 16.0, X_COL + 22.0)
# 分段对锁孔:统一 Ø3.9 直孔(M4x16 从外面直接拧入自攻成型;母口壁与公榫壁同径,
# 没有过孔/沉孔等其它孔),前后两面对称;杆尖伸过榫壁的一段在内腔侧留 Ø4.5 让位。
def _seam_holes(part, xx, z):
return (part.cut(Ycyl(1.95, Y_COL - 33.6, Y_COL - 21.4, xx, z))
.cut(Ycyl(1.95, Y_COL + 21.4, Y_COL + 33.6, xx, z))
.cut(Ycyl(2.25, Y_COL - 21.7, Y_COL - 15.5, xx, z))
.cut(Ycyl(2.25, Y_COL + 15.5, Y_COL + 21.7, xx, z)))
# --- P01_A (下段) ---
cut_above_s1 = bx(X_COL - 50.0, X_COL + 50.0, Y_COL - 50.0, Y_COL + 50.0, z_s1, z_top + 10.0)
@@ -158,7 +174,7 @@ def split_p01_poka_yoke(p01):
z_bolt1 = z_s1 + h_lap / 2.0 # 180.0
for xx in xx_bolts:
p01_a = p01_a.cut(Ycyl(2.2, Y_COL - 40.0, Y_COL + 40.0, xx, z_bolt1))
p01_a = _seam_holes(p01_a, xx, z_bolt1) # A-B 缝对锁孔(Ø3.9,前后两面)
# Engrave the front (-Y) flat face, reading VERTICALLY bottom-to-top along
# the column (user request): local +X = world +Z, local +Y = world -X, so
@@ -189,8 +205,8 @@ def split_p01_poka_yoke(p01):
z_bolt2 = z_s2 + h_lap / 2.0 # 329.0
for xx in xx_bolts:
p01_b = p01_b.cut(Ycyl(2.2, Y_COL - 40.0, Y_COL + 40.0, xx, z_bolt1))
p01_b = p01_b.cut(Ycyl(2.2, Y_COL - 40.0, Y_COL + 40.0, xx, z_bolt2))
p01_b = _seam_holes(p01_b, xx, z_bolt1) # A-B 缝对锁孔(Ø3.9,前后两面)
p01_b = _seam_holes(p01_b, xx, z_bolt2) # B-C 缝对锁孔(Ø3.9,前后两面)
front_label_plane_b = cq.Plane(
origin=(X_COL, Y_COL - 33.0, 240.0),
@@ -207,7 +223,7 @@ def split_p01_poka_yoke(p01):
.rect(58.8, 58.8).extrude(h_lap + 0.6).edges("|Z").fillet(3.9)).val()
p01_c = p01_c_base.cut(pocket2)
for xx in xx_bolts:
p01_c = p01_c.cut(Ycyl(2.2, Y_COL - 40.0, Y_COL + 40.0, xx, z_bolt2))
p01_c = _seam_holes(p01_c, xx, z_bolt2) # B-C 缝对锁孔(Ø3.9,前后两面)
front_label_plane_c = cq.Plane(
origin=(X_COL, Y_COL - 33.0, 390.0),
@@ -492,111 +508,308 @@ def p_base_foot():
def p_girdle(j1):
"""P03_肩关节安装悬臂 (高强受力多筋桁架 + 侧开式电机托架与前置止脱锁紧法兰):
"""P03_肩关节安装悬臂 (轻量化板式桁架版 + 侧开式电机托架):
1. 10mm 后端重载法兰盘 (X: -61.0..-51.0, 74x74mm);
2. 双侧大截面三角加强筋 (8mm 厚,Y = Y_ARM ± 28mm);
3. 下腹部纵向大受力龙骨筋 (12mm 厚);
4. 顶部横向锁紧环抱筋 (60x10x10mm);
5. 侧开式电机托架 (+Y侧全开, X: -51.0..8.5),M1 电机可从侧方滑入装配,由后端法兰 4xM3 与前置止脱锁紧法兰 4xM3 双向锁死;
6. 端面 4x Ø3.2mm 沉头通孔直连 M1 定子端面螺纹孔 (BCD=55mm),彻底消除轴向拉脱风险;
7. 两侧大面积散热舷窗 (34x20mm) + 顶部双斜向对流排热槽 (30x6.5mm),确保散热畅通;
8. 4x 直通式螺丝刀安装通道 (Ø8.5mm) 与 Ø26mm 中央走线孔。
2. 主干由 66mm 实心块改为双侧 6mm 桁架竖板 (Y = Y_ARM ± 27..33),外轮廓保持旧版
"主干 ∪ 侧筋"并集不变 —— 只减材料不加体积,零新增干涉风险;实心 728 -> 286 cm³ (-61%);
3. 竖板帐篷形减重窗 (顶/底斜面 ≥52°,自支撑;仅 20mm 平顶可桥接);
4. 底部 9mm 承力鞍座 + 43.4x43.4 定位榫头 (配 P01_C 44x44 内腔,单边 0.3mm 间隙);
鞍座底面 66x66 与立柱顶环带承压面积 2403mm² —— 竖向载荷走面压,螺栓只防上抬/防滑;
5. 4x 安装孔 (X_COL±27.5, Y_COL±13.5):Ø3.9 直孔,M4x16 从上方直接拧入自攻成型
(鞍座与立柱顶环同径,无过孔/沉孔/预埋),可拆装;
6. 下腹中央龙骨筋 (12mm 中位腹板,自鞍座斜拉至法兰下缘) + 顶部横向锁紧环抱筋 (66x9x10mm,
与两侧竖板外面齐平、顶面压在筋板脊线上,仅顶前棱一道 2mm 倒角);
7. 侧开式电机托架 (+Y侧全开, X: -51.0..11.5,前端随 X_BAY_EXT 前延 3mm),
M1 电机可从侧方斜插卡入装配(插槽比电机长 3mm),由后端法兰 4xM3x16 锁死;
电机舱 Ø60.7 从后端直通到前端面(2026-10-02 用户裁定"去掉台阶改成平的":无环形台阶、
无喇叭锥;原前置止脱锁紧法兰 4xM3 随之取消,电机轴向由后端 4xM3x16 约束);
9. 两侧大面积散热舷窗 (34x20mm) + 顶部双斜向对流排热槽 (30x6.5mm),确保散热畅通;
10. Ø26mm 中央走线孔;竖板间为开放腔体(无封闭空腔),M3 螺丝刀通道直接走腔体,拧紧更顺手。
"""
X_MOUNT = Z_R1 # -51.0 (Rear face of M1)
T_FLANGE = 10.0 # 10mm thick high-strength mounting flange
X_BACK = X_MOUNT - T_FLANGE # -61.0
Y_ARM = Y_AXIS # 128.0
Z_ARM = Z_RL # 610.0
Y_P_IN = 27.0 # 桁架竖板内表面 (Y_ARM ± 27)
Y_P_OUT = 33.0 # 桁架竖板外表面 (与旧主干齐平)
T_SADDLE = 9.0 # 底部鞍座厚度
TENON = 43.4 # 定位榫头边长(P01_C 内腔 44x44 R4,单边留 0.3mm)
WIN_R = 4.0 # 竖板减重窗内角圆角(消除内尖角应力集中,Kt 由 ~2.5 降到 ~1.2)
BOLT_DX, BOLT_DY = 27.5, 13.5 # 4x 安装孔相对立柱中心偏移:落在顶环 11mm 实体壁内
# 1. 主安装法兰盘 (74x74mm, 倒圆角 R=8mm)
# 1. 主安装法兰盘 (74x74mm, 四角倒圆 R=8mm)
# 背面那圈 2mm 倒角已去掉:板料只伸进法兰 0.1mm,倒角面与板背面相交会在
# Z≈574.9 挤出一批 2mm 短棱,正是这批短棱让整条交接内棱网络倒不出圆角;
# 同时它跨过 R8 角部圆弧,就是角上那道"卷起来"的怪倒角。
flange = (cq.Workplane("YZ", origin=(X_BACK, Y_ARM, Z_ARM))
.rect(74.0, 74.0)
.extrude(T_FLANGE)
.edges("|X").fillet(8.0)
.edges("<X").chamfer(2.0)).val()
.edges("|X").fillet(8.0)).val()
s = cq.Shape(flange.wrapped)
# 2. 斜挑支撑主干 (Central Arch Backbone)
# 2. 双侧桁架竖板 (6mm):旧"斜挑支撑主干"与"大三角加强筋"轮廓同段挤出 → 自动并集成单块侧板
# 主干的后缘两点取在加强筋斜边的延长线上,使外轮廓顶部成为一整条直线
# (否则后缘 (-148,550) 处有 5° 折点、留下 5mm 台阶)。
# Z_CREST = 侧筋脊线高度,同时是顶筋 2mm 顶前倒角的下沿:倒角从 (X-71,Z_CREST)
# 斜上到 (X-69,Z_CREST+2) = 顶筋顶面,斜坡面与倒角面几乎相切,顶部读起来是一整张面。
Z_CREST = Z_ARM + 33.0 # 643(初版 642;顶筋整体上移 3mm 让出扳手空间后跟着抬)
RIB_SLOPE = (Z_CREST - 575.0) / ((X_BACK - 10.0) - (X_COL - 15.0))
def rib_line_z(x):
return Z_CREST + RIB_SLOPE * (x - (X_BACK - 10.0))
trunk_pts = [
(X_COL - 33.0, Z_CHEST1),
(X_COL + 33.0, Z_CHEST1),
(X_COL + 33.0, 505.0),
(X_BACK + 0.1, 565.0),
(X_BACK + 0.1, Z_ARM - 5.0),
(X_COL - 10.0, 580.0),
(X_COL - 33.0, 550.0),
(X_COL - 10.0, rib_line_z(X_COL - 10.0)),
(X_COL - 33.0, rib_line_z(X_COL - 33.0)),
]
rib_pts = [
(X_COL - 33.0, Z_CHEST1), # 底边两端与主干/鞍座对齐 (±33):原来收进 3mm,
(X_COL + 33.0, Z_CHEST1), # 会在鞍座顶面上留下 0.7/3mm 短棱,卡住整条底棱圆角
(X_BACK + 0.1, 565.0),
(X_BACK + 0.1, Z_CREST),
(X_BACK - 10.0, Z_CREST), # 脊线 (-71,643):正好落在顶筋前面与 2mm 倒角下沿的交点
(X_COL - 15.0, 575.0),
(X_COL - 30.0, 530.0),
]
trunk = (cq.Workplane("XZ", origin=(0, Y_ARM, 0))
.polyline(trunk_pts).close()
.extrude(33.0, both=True)).val()
s = s.fuse(cq.Shape(trunk.wrapped))
# 3. 左右两侧主抗弯抗扭大三角加强筋 (厚度 8mm)
for sign in (-1, 1):
y_rib = Y_ARM + sign * 28.0
rib_pts = [
(X_COL - 30.0, Z_CHEST1),
(X_COL + 30.0, Z_CHEST1),
(X_BACK + 0.1, 565.0),
(X_BACK + 0.1, Z_ARM + 32.0),
(X_BACK - 15.0, Z_ARM + 32.0),
(X_COL - 15.0, 575.0),
(X_COL - 30.0, 530.0),
]
side_rib = (cq.Workplane("XZ", origin=(0, y_rib, 0))
.polyline(rib_pts).close()
.extrude(5.0, both=True)).val()
s = s.fuse(cq.Shape(side_rib.wrapped))
# 4. 下腹部纵向抗弯龙骨筋 (厚度 12mm)
keel_pts = [
(X_COL + 33.0, Z_CHEST1),
(X_COL + 33.0, 495.0),
(X_BACK + 0.1, 570.0),
(X_BACK + 0.1, 555.0),
(X_COL + 20.0, 480.0),
(X_COL + 20.0, Z_CHEST1),
ya = Y_ARM + sign * Y_P_IN
yb = Y_ARM + sign * Y_P_OUT
y0, y1 = min(ya, yb), max(ya, yb)
for prof in (trunk_pts, rib_pts):
s = s.fuse(cq.Shape(Yplate(prof, y0, y1).wrapped))
# 3. 竖板减重窗 (帐篷形:斜面 ≥52° 自支撑、仅 20mm 平顶可桥接;避开鞍座与 M5 螺母柱)
# 6 个内角全部 R4 圆角:把内尖角应力集中 (Kt≈2.5) 降到 ≈1.2,同时圆角面仍是竖直/自支撑面
win_pts = [
(X_COL - 24.0, 498.0), (X_COL + 23.0, 498.0), (X_COL + 25.0, 522.0),
(X_COL + 10.0, 545.0), (X_COL - 10.0, 545.0), (X_COL - 25.0, 524.0),
]
keel = (cq.Workplane("XZ", origin=(0, Y_ARM, 0))
.polyline(keel_pts).close()
.extrude(12.0, both=True)).val()
s = s.fuse(cq.Shape(keel.wrapped))
for sign in (-1, 1):
yc = Y_ARM + sign * 0.5 * (Y_P_IN + Y_P_OUT)
tool = (cq.Workplane("XZ", origin=(0, yc, 0)).polyline(win_pts).close()
.extrude(Y_P_OUT - Y_P_IN + 1.0, both=True)
.edges("|Y").fillet(WIN_R).val())
s = s.cut(cq.Shape(tool.wrapped))
# 4. 底部承力鞍座:坐实立柱顶面,把两竖板、龙骨与榫头连成整体
s = s.fuse(bx(X_COL - 33.0, X_COL + 33.0, Y_ARM - Y_P_OUT, Y_ARM + Y_P_OUT,
Z_CHEST1, Z_CHEST1 + T_SADDLE))
# 5. 下腹部纵向抗弯龙骨筋 (12mm 中位腹板,自鞍座斜拉至法兰背面;交接内棱在融合后做真 3D 圆角)
keel_pts = [
(X_COL + 33.0, Z_CHEST1), # (-82, 470)
(X_COL + 33.0, 495.0), # (-82, 495)
(X_BACK + 0.1, 573.0), # (-60.9, 573) 斜拉至法兰背面
(X_BACK + 0.1, 594.4), # (-60.9, 594.4) 顶端贴法兰
(X_COL + 42.1, 585.0), # (-72.9, 585)
(X_COL + 20.0, Z_CHEST1), # (-95, 470) 背面一路斜到底:原来在 (-95,480) 有个折点,
] # 折点离鞍座顶面只 1mm,R2.5 圆角爬不上去 → 龙骨底棱整组倒不出
s = s.fuse(cq.Shape(Yplate(keel_pts, Y_ARM - 6.0, Y_ARM + 6.0).wrapped))
# 5. 顶部横向锁紧环抱横筋
tie_rib = (cq.Workplane("YZ", origin=(X_BACK - 10.0, Y_ARM, Z_ARM + 28.0))
.rect(60.0, 10.0)
# 7. 顶部横向锁紧环抱横筋:Y 向与两竖板外面齐平 (Y_ARM±33)、前面与筋板脊线共面 (X=-71)、
# 顶面 Z=645 压住脊线 (Z=643) 并与 2mm 顶前倒角相切 → 顶筋与两侧脊线合成一整块。
# 整体比初版抬高 3mm (底面 633→636):4x M3 后端沉孔 Ø6.5 跨在 Z 627.2..633.7 上,
# 底面 633 会压住孔口上沿 0.7mm、扳手让位只剩负间隙;抬到 636 后退到孔口上方 2.3mm、
# 离螺钉轴线 5.55mm。顶面 645 不越过法兰 R8 角部圆弧在 Y=95 处的 645.9 上界。
tie_rib = (cq.Workplane("YZ", origin=(X_BACK - 10.0, Y_ARM, Z_ARM + 30.5))
.rect(66.0, 9.0)
.extrude(10.0)
.edges("|X").fillet(3.0)).val()
.edges(cq.selectors.BoxSelector((X_BACK - 10.5, Y_ARM - 34.0, Z_ARM + 34.5),
(X_BACK - 9.5, Y_ARM + 34.0, Z_ARM + 35.5)))
.chamfer(2.0)).val()
s = s.fuse(cq.Shape(tie_rib.wrapped))
# 与立柱顶部配合的榫头 (48x48x15mm)
# 6.y 体-体交接凹棱:融合完成后对"凹棱"直接做真 3D 圆角。
# 原先这里是手工沿棱 fuse 的 10 条"正方形−四分之一圆"焊珠小体(_cove),已整体删除:
# 焊珠端面是平的、悬在半空,两条互相垂直的焊珠在角上互不搭接 → 圆角"缺一块",
# 并与相邻体的棱互相穿插留 1~3mm² 碎面。真圆角在面边界自然收口、多棱相交处由 OCC
# 生成角部补片。
from cadquery import selectors as _sel
from OCP.BRepAdaptor import BRepAdaptor_Surface
from OCP.GeomAbs import GeomAbs_Plane
from OCP.TopAbs import TopAbs_REVERSED
def _outward(f, sh):
"""平面面的外法向:先按 Orientation 修正,再用"面中心外移 1mm 是否仍在实体内"兜方向。"""
ad = BRepAdaptor_Surface(f.wrapped)
if ad.GetType() != GeomAbs_Plane:
return None
ax = ad.Plane().Axis().Direction()
n = cq.Vector(ax.X(), ax.Y(), ax.Z())
if f.wrapped.Orientation() == TopAbs_REVERSED:
n = n * -1.0
c = f.Center()
if cq.Solid(sh.wrapped).isInside(cq.Vector(c.x + n.x, c.y + n.y, c.z + n.z), 1e-6):
n = n * -1.0
return n
def _fillet_reflex(lo, hi, radii, tag, eps=0.9):
"""倒出 lo~hi 区域内的凹棱(两面夹 270° 材料)。判据:从棱中点沿 (n1-n2) 外探 eps,
落在实体内 = 凹、落在外 = 凸。区域内凹棱先整批一次倒(半径逐级降级,且倒完验拓扑:
OCC 会给出"没抛异常但面已坏"的结果),建不出时按相连棱分组逐组倒。"""
nonlocal s
def _pick(sh):
edges = sh.Edges()
idx = {}
for i, e in enumerate(edges):
idx[e.hashCode()] = i
adj = [[] for _ in edges]
for f in sh.Faces():
for ee in f.Edges():
k = idx.get(ee.hashCode())
if k is not None:
adj[k].append(f)
box = _sel.BoxSelector(lo, hi)
out = []
for i, e in enumerate(edges):
if e.Length() <= 6.0 or len(adj[i]) != 2 or not box.filter([e]):
continue
n1 = _outward(adj[i][0], sh)
n2 = _outward(adj[i][1], sh)
if n1 is None or n2 is None:
continue
dx, dy, dz = n1.x - n2.x, n1.y - n2.y, n1.z - n2.z
ln = math.sqrt(dx * dx + dy * dy + dz * dz)
if ln < 1e-6:
continue
p = e.Center()
if cq.Solid(sh.wrapped).isInside(
cq.Vector(p.x + dx / ln * eps, p.y + dy / ln * eps,
p.z + dz / ln * eps), 1e-6):
out.append(e)
return out
es0 = _pick(s)
if not es0:
print(" [P03 真圆角] %-14s 区域内无凹棱,跳过" % tag, flush=True)
return
def _groups(ee):
"""按共端点把凹棱连成链/网络:一组一次倒,OCC 才能在交汇处生成角部补片;
逐条倒会在交汇处留下断口(看着就像圆角倒一半停了)。"""
pts = [e.Vertices() or [e.Center()] for e in ee]
par = list(range(len(ee)))
def find(a):
while par[a] != a:
par[a] = par[par[a]]
a = par[a]
return a
for i in range(len(ee)):
for j in range(i + 1, len(ee)):
if any(pi.distance(pj) < 0.05 for pi in pts[i] for pj in pts[j]):
par[find(i)] = find(j)
g = {}
for i in range(len(ee)):
g.setdefault(find(i), []).append(ee[i])
return list(g.values())
def _do(edges_, rr):
"""倒完立刻验拓扑:OCC 会给出"没抛异常但面已坏"的结果,必须挡下来。"""
try:
ns = cq.Shape(cq.Solid(s.wrapped).fillet(rr, edges_).wrapped)
except Exception:
return None
return ns if cq.Solid(ns.wrapped).isValid() else None
# 先试"区域内全部凹棱一次倒"(探针实测这样能整批成型,且只重建一次,
# 不会像分批那样把同一张面反复重算坏掉);不行再按相连棱分组逐组倒。
for rr in radii:
ns = _do(es0, rr)
if ns is not None:
s = ns
print(" [P03 真圆角] %-14s %d 条凹棱 R%.1f ✓ 整批一次成型"
% (tag, len(es0), rr), flush=True)
return
n_ok, n_grp, left = 0, 0, len(es0)
for _ in range(24):
es = _pick(s)
if not es:
break
got = False
for g in sorted(_groups(es), key=lambda g: -sum(e.Length() for e in g)):
for rr in radii:
ns = _do(g, rr)
if ns is None:
continue
s = ns
n_ok += len(g)
n_grp += 1
print(" [P03 真圆角] %-14s 第%d组 %d 条 R%.1f ✓"
% (tag, n_grp, len(g), rr), flush=True)
got = True
break
if got:
break
if not got:
left = len(es)
break
print(" [P03 真圆角] %-14s 共 %d 组 %d 条凹棱倒圆,剩 %d 条保持尖棱"
% (tag, n_grp, n_ok, left), flush=True)
XR, YC, ZS = X_BACK, Y_ARM, Z_CHEST1 + T_SADDLE # -61, 128, 479
# —— 鞍座顶面 (Z=479) 上的交接内棱:龙骨三条 + 两竖板内侧两条,一次真圆角 ——
# 半径上限 2.0:龙骨侧面 Y=122 与 M5 螺钉头外缘 Y=118.75 只隔 3.25mm,
# 原来的 R3 焊珠会顶到螺帽承压边,R2.0 留 1.25mm。
_fillet_reflex((X_COL - 34.0, Y_ARM - 40.0, ZS - 3.0),
(X_COL + 34.0, Y_ARM + 40.0, ZS + 7.0),
(2.0, 1.5), "鞍座顶面交接")
# —— 法兰背面 (X=-61) 上的交接内棱:只倒竖板/龙骨的竖直棱 ——
# 顶筋底面那条水平棱 (Z=636) 不倒:4x M3 沉孔 Ø6.5 在 Z 627.2..633.7,
# 倒上 R2.5 会把螺钉上方 5.55mm 的扳手让位吃掉 2.5mm。
# 上界取 631:竖板内棱被顶筋底面切成 573..636 / 636..643 两段,只倒下面长的那段
# ——把 636..643 的 7mm 短段并进来,整批就从"一次成型"退化成逐组、且少倒 6 条。
_fillet_reflex((X_BACK - 3.0, Y_ARM - 40.0, 570.0),
(X_BACK + 3.0, Y_ARM + 40.0, 631.0),
(2.5, 2.0, 1.5), "竖板/龙骨↔法兰")
_fillet_reflex((X_BACK - 3.0, Y_ARM - 40.0, Z_ARM + 34.5),
(X_BACK + 3.0, Y_ARM + 40.0, Z_ARM + 35.5),
(1.5, 1.0), "顶筋顶↔法兰")
# 与立柱顶部配合的定位榫头 (43.4x43.4x15mm):配 P01_C 44x44 R4 内腔,单边 0.3mm 滑配
boss = (cq.Workplane("XY", origin=(X_COL, Y_COL, Z_CHEST1 - 15.0))
.rect(48.0, 48.0)
.rect(TENON, TENON)
.extrude(15.0)
.edges("|Z").fillet(4.0)).val()
.edges("|Z").fillet(4.2)).val()
s = s.fuse(cq.Shape(boss.wrapped))
# 4x 安装孔:统一 Ø3.9 直孔(M4x16 从腔体正上方拧入自攻成型;鞍座与立柱顶环同径、无沉孔)
# 孔位 (X_COL±27.5, Y_COL±13.5) 同时满足:①在立柱顶环实体壁内(内腔 22 → 外壁 33);
# ②在 P03 两竖板之间、避开中间龙骨,从腔体正上方用扳手可直接拧紧。
for xx in (X_COL - BOLT_DX, X_COL + BOLT_DX):
for yy in (Y_COL - BOLT_DY, Y_COL + BOLT_DY):
s = s.cut(cyl(1.95, Z_CHEST1 - 0.5, Z_CHEST1 + T_SADDLE + 0.5, xx, yy))
# 4x M5 连接螺栓孔
for xx in (X_COL - 21.0, X_COL + 21.0):
for yy in (Y_COL - 21.0, Y_COL + 21.0):
s = s.cut(cyl(2.75, Z_CHEST1 - 16.0, Z_CHEST1 + 25.0, xx, yy))
# 1x 横向防脱锁紧:榫头 −X 侧向内 Ø3.9x14 直孔(与立柱后壁 Ø3.9 孔同轴,M4x16 拧入自攻)
s = s.cut(Xcyl(1.95, X_COL - TENON / 2.0 - 1.0, X_COL - TENON / 2.0 + 14.0, Y_COL, Z_LOCK))
# 4x M3 连接螺孔与直通螺丝刀通道
# 4x M3 连接螺孔(螺丝刀通道直接走两竖板之间的开放腔体,无需再钻 Ø8.5 直通隧道)
for dy in (-17.55, 17.55):
for dz in (-20.46, 20.46):
py = Y_ARM + dy
pz = Z_ARM + dz
th = Xcyl(1.7, X_BACK - 0.5, X_MOUNT + 4.0, py, pz)
cb = Xcyl(3.25, X_BACK - 0.5, X_BACK + 4.5, py, pz)
access_tunnel = Xcyl(4.25, X_COL - 40.0, X_BACK + 0.1, py, pz)
s = s.cut(th).cut(cb).cut(access_tunnel)
s = s.cut(th).cut(cb)
# 中央走线孔 (Ø26mm)
wire_hole = Xcyl(13.0, X_COL - 40.0, X_MOUNT + 2.0, Y_ARM, Z_ARM)
s = s.cut(wire_hole)
# 6. 前向电机全包托架与前置止脱锁紧法兰 (X: -51.0..8.5)
X_FRONT = 8.5
# 6. 前向电机全包托架 (X: -51.0..8.5+X_BAY_EXT=11.5,Ø60.7 舱孔平直贯通到端面)
# 端面随插槽加长前延 X_BAY_EXT;叉板背面(10.5+X_FORK_GAP=11.5)与端面 0.0 硬贴平
# (用户两次要求"搞成平的";J1 转动摩擦由用户知悉,发涩时可微松 M2)
X_FRONT = 8.5 + X_BAY_EXT
R_POD = 36.5
R_BORE = 30.35
@@ -606,28 +819,38 @@ def p_girdle(j1):
.edges(">X").chamfer(1.5)).val()
s = s.fuse(cq.Shape(cradle_outer.wrapped))
# 电机定子配合内腔 (精密滑配至 X=5.05)
motor_pocket = Xcyl(R_BORE, X_MOUNT - 0.2, 5.05, Y_ARM, Z_ARM)
# 电机定子配合内腔(最终状态,2026-10-02 用户裁定"去掉台阶改成平的+保留固定电机的面"):
# Ø60.7 圆柱孔壁从前端面平直贯通到舱底(无窄颈、无台阶、无喇叭锥);
# 舱底 = 一个完整的平坦环面(X=5.06+X_BAY_EXT=8.06,与插槽末端墙共面,中开 Ø39 凸台过孔)
# ——即电机前限位面。电机轴向由后端法兰 4xM3x16 约束;
# 前端锁紧由 4 个 Ø10 局部凸台上的 M3 沉头螺钉承担(见下方凸台段)。
motor_pocket = Xcyl(R_BORE, X_MOUNT - 0.2, 5.06 + X_BAY_EXT, Y_ARM, Z_ARM)
s = s.cut(motor_pocket)
# 前端中心避让孔 (避让 J1 输出轴旋转凸台)
hub_clearance = Xcyl(19.5, 4.8, X_FRONT + 0.5, Y_ARM, Z_ARM)
s = s.cut(hub_clearance)
# 4x 前置 M3 锁紧螺钉通孔与沉头 (BCD=55mm, R=27.5mm, 角度 17.8°, 107.8°, 197.8°, 287.8°)
# 4x 前置 M3 锁紧螺钉凸台(BCD=55mm,17.8°/107.8°/197.8°/287.8°):
# 平直舱孔的沉头座位由 4 个 Ø10 局部凸台承载——凸台位于舱孔前段 8.06..11.5,
# 电机前端面(5.0)之前 3mm,电机斜插路径不经过;M3x10 沉头从凸台端面旋入
# 电机前端面,咬合 3.5mm,兼作电机前端防转定位。
for deg in (17.8, 107.8, 197.8, 287.8):
rad = math.radians(deg)
fy = Y_ARM + 27.5 * math.cos(rad)
fz = Z_ARM + 27.5 * math.sin(rad)
th = Xcyl(1.6, 4.5, X_FRONT + 0.5, fy, fz)
cb = Xcyl(3.0, 6.5, X_FRONT + 0.5, fy, fz)
s = s.fuse(Xcyl(5.0, 5.06 + X_BAY_EXT, X_FRONT, fy, fz))
th = Xcyl(1.6, 5.06 + X_BAY_EXT, X_FRONT, fy, fz)
cb = Xcyl(3.0, X_FRONT - 2.0, X_FRONT, fy, fz)
s = s.cut(th).cut(cb)
# J1 输出凸台过孔 (Ø39 × 3.44——J1 凸台与 3xM2 输出螺钉的必经孔,非台阶;
# 原 6.7mm 长颈与半圆台肩已随舱底前移一并消除)
hub_clearance = Xcyl(19.5, 4.8, X_FRONT + 0.5, Y_ARM, Z_ARM)
s = s.cut(hub_clearance)
# 8. 电机托架 +Y 侧全开(侧开式半包,替代原封闭全包筒):
# M1 电机可从 +Y 侧方直线滑入托架完成装配——原封闭筒电机物理上无法装入。
# 轴向约束:后端法兰 4xM3(电机尾端面)+ 前置止脱法兰 4xM3(电机前端面)双向锁死;
# 径向约束:Ø60.7 精密滑配托架底 + 重力贴底。开口前端至 5.06 保留完整止脱法兰环。
s = s.cut(bx(X_MOUNT, 5.06, Y_ARM, Y_ARM + 60.0, Z_ARM - 60.0, Z_ARM + 60.0))
# 轴向约束:后端法兰 4xM3(电机尾端面)单向锁死(前置止脱法兰随平直舱孔要求取消);
# 径向约束:Ø60.7 精密滑配托架底 + 重力贴底。开口前端至 5.06+X_BAY_EXT=8.06
# (比电机前端面多 3mm 斜插余量,电机可倾斜卡入),止脱法兰环随之前移、环宽保持 3.44mm。
s = s.cut(bx(X_MOUNT, 5.06 + X_BAY_EXT, Y_ARM, Y_ARM + 60.0, Z_ARM - 60.0, Z_ARM + 60.0))
# 7. 散热系统:双侧大视窗 + 顶部斜向对流排热槽
for sign in (-1, 1):
@@ -654,8 +877,9 @@ def p_girdle(j1):
def p_fork(j1, j2):
"""P04_肩叉_螺旋体30%_墙5底5_竖打 (Shoulder Fork / L-Bracket) - 加长避让顺滑流线版:
1. 头部与身子起点自 X=5.5 前移加长至 X=10.5,与 P03 前置锁紧法兰 (X=8.5) 保持 2.0mm 均匀轴向安全间隙
(X_FORK_GAP=0:不做整体前移,保持 J1 输出端最短悬伸力臂,避免额外弯矩负荷);
1. 头部与身子起点自 X=5.5 前移加长至 X=10.5+X_FORK_GAP=11.5,叉板背面与 P03 托架端面
(X=8.5+X_BAY_EXT=11.5) 0.0 硬贴平(2026-10-02 用户两次要求"搞成平的";
P03 侧插槽独立加长 3mm 便于 M1 电机斜插卡入);
2. J1 从动法兰圆盘已删除(盘面在 column 前缘形成鼓楞):J1 由 boss(Ø35.6)贯通 P03 前盖中心孔直连电机输出盘;column 顶边保持 Z=646.5 与 P03 环齐高,R=18mm 大圆弧顺滑过渡;
3. 头部转接凸台加长贯通 P03 前盖中心孔 (R=19.5mm),直连 J1 旋转法兰盘;
4. M2 保留后端安装板(R=35mm, 带 rear_mount_holes 螺钉孔),前端定位环鼓出圆盘已删除(前端定位由 column 端面 pocket 承担),中间镂空散热;
@@ -744,7 +968,9 @@ def p_fork(j1, j2):
u = AB.M['m2_bcd'] / 2.0 * math.cos(a * AB.D2R)
v = AB.M['m2_bcd'] / 2.0 * math.sin(a * AB.D2R)
th = cyl(1.4, 54.0, 63.0 + X_FORK_GAP, u, v)
cb = cyl(2.8, 63.0 + X_FORK_GAP, 74.0 + 40.0 + X_FORK_GAP, u, v)
# 沉孔台阶固定在 63.0(不随前移):M2x10 旋入电机输出毂的咬合量与改前一致;
# 螺钉头(63..65)相对叉板背面(64.5)外露 0.5mm,位于 2mm 叉缝空隙内,无干涉。
cb = cyl(2.8, 63.0, 74.0 + 40.0 + X_FORK_GAP, u, v)
s = s.cut(j1.L(th)).cut(j1.L(cb))
return s
@@ -1154,11 +1380,11 @@ def build():
parts_to_build = [
("P01_A_立柱下段_三角形30%_墙4底5_竖打", "立柱下段", lambda: p01_a, 0x0284c7,
"200mm适配分段A:高166mm+16mm阶梯公榫+非对称M4防反装通孔+底部50x50x12榫头+P01-A 竖排TOP刻字"),
"200mm适配分段A:高166mm+16mm阶梯公榫+顶端 2x Ø3.9 对锁孔(M4x16 自攻)+底部50x50x12榫头+P01-A 竖排TOP刻字"),
("P01_B_立柱中段_三角形30%_墙4底5_竖打", "立柱中段", lambda: p01_b, 0x2563eb,
"200mm适配分段B:高165mm+双端公母榫+非对称M4防反装通孔+P01-B 竖排TOP刻字"),
"200mm适配分段B:高165mm+双端公母榫+两端各 2x Ø3.9 对锁孔(M4x16 自攻,非对称孔位防反装)+P01-B 竖排TOP刻字"),
("P01_C_立柱上段_三角形30%_墙4底5_竖打", "立柱上段", lambda: p01_c, 0x1d4ed8,
"200mm适配分段C:高149mm+底端母榫+非对称M4防反装通孔+顶面P03安装台+P01-C 竖排TOP刻字"),
"200mm适配分段C:高149mm+底端母榫+底端 2x Ø3.9 对锁孔(非对称孔位防反装)+顶面P03安装台(4x Ø3.9 安装孔 + 1x Ø3.9 横向锁紧孔)+P01-C 竖排TOP刻字"),
("P02_Center_底座中核心_螺旋体30%_墙5底6_平打", "底座核心承力座", lambda: p02_c, 0x475569,
"200mm适配中座:195x190mm核心承力座+48mm套筒+12mm阶梯榫座(轴向面承载)+前后三角加强筋+前后非对称防呆母榫槽+刻字"),
("P02_Front_前向防翻力臂_螺旋体30%_墙4底5_平打", "前向防翻力臂", lambda: p02_f, 0xe11d48,
@@ -1166,9 +1392,9 @@ def build():
("P02_Rear_后向防翻力臂_螺旋体30%_墙4底5_平打", "后向防翻力臂", lambda: p02_r, 0xd97706,
"200mm适配后臂:45x190mm扩展力臂+80mm窄跨距双公榫+底部M5预埋螺母沉槽+P02-REAR刻字"),
("P03_肩吊臂_螺旋体35%_墙5底5_竖打", "肩关节安装悬臂", lambda: p_girdle(j1), 0x4b5563,
"高强多肋机架:10mm后置法兰+双侧8mm大三角加强筋+下腹12mm抗弯龙骨筋+侧开式电机托架(M1从+Y侧滑入装配,前后法兰8xM3双向锁死)+前置止脱锁紧法兰(4xM3止脱螺孔)+大散热窗与对流槽"),
"轻量化板式桁架版:主干由 66mm 实心块改为双侧 6mm 桁架竖板+帐篷减重窗(斜面≥52°自支撑)+R4内角,外轮廓与旧版并集完全一致,实心 728->286cm³;底部 9mm 承力鞍座(Ø3.9 安装孔)+12mm 中位龙骨筋(自鞍座斜拉至法兰下缘)+40~45°外扩斜撑;保留 10mm 后置法兰、侧开式电机托架、Ø60.7 直通电机舱(平孔无台阶)(M1 从+Y滑入,后端 4xM3x16 锁死)、大散热窗与对流槽;无封闭空腔、免支撑"),
("P04_肩叉_螺旋体30%_墙5底5_竖打", "肩叉", lambda: p_fork(j1, j2), 0x2563eb,
"加长避让版:头部与身子前移加长至X=10.5,与P03锁紧法兰保持2.0mm轴向安全间隙(不做前移,保持输出端最短悬伸力臂),J1输出凸台贯通直连电机,J1从动法兰圆盘鼓楞已删(接缝区与P03止脱环齐径齐高R36.5/顶646.5),单实体全角度零干涉"),
"齐平插槽版:叉板背面与P03托架端面(11.5)0.0硬贴平(用户要求外观齐平),P03侧插槽独立加长3mm,M1电机可倾斜卡入,J1输出凸台贯通直连电机,J1从动法兰圆盘鼓楞已删(接缝区与P03止脱环齐径齐高R36.5/顶646.5),单实体全角度零干涉"),
("P05_大臂旋转座_螺旋体30%_墙4底5_竖打", "大臂旋转座", lambda: p_shoulder_roll_base(j2, j3, None), 0x059669,
"V3圆角:Loft外轮廓R=10mm,L型转角内部2mm倒角,后缘凸包两角90°竖棱磨R2圆角(结构/后缘高度不变,打印无悬挂),保证J2全角度0干涉"),
("P06_大臂骨架_螺旋体25%_墙4底5_竖打", "大臂骨架", lambda: p_humerus_bone(j3, j4), 0x0d9488,