单文件约束取消后,Python 侧没必要再靠 16 处 sys.path.insert 维持扁平模块互认。
现在按职责分包:
arm/paths.py 路径唯一来源(含新增 CACHE、TPL)
arm/constants.py 实测接口数值(原 armcore 的 M/C/CLR/FIT/MOTOR_TOL 段)
arm/cad/{helpers,arm_build,part_tools,parts/} 几何与装配
arm/kinematics.py(原 human_layout.py,唯一运动学事实源)
arm/analysis/{sweep_v2,strength_check,torque_balance,finalize_travel,ws_sweep,gen_env_mesh}
arm/dataio/{screw_mesh,draw_sheet} arm/viewer/{build_viewer,shot}
arm/build_model.py(原 arm_model.py)
顺带修掉的既有缺陷(都是实测撞出来的,不是预防性改动):
- arm_model 第二次 sys.path 跳到 gitignore 的 scratch/ 去 import 构建必需的包络脚本:
ws_sweep/gen_env_mesh 提升进 arm/analysis/,缓存挪到 data/cache/(gitignore,可重生成)。
- finalize_travel / draw_sheet 顶层就是"算完写文件",一次 importlib 冒烟测试就把
docs/travel.json 重写了一遍;现在被 import 直接抛错。
- strength_check 用 OUT.replace("/out","/web") 靠字符串形状推路径,改成直接用 WEB。
- build_viewer 里 WORKSPACE 使用点漏改导致 NameError —— 已由构建关卡抓到并修掉。
os._exit 的处置与计划里的假设相反:实测光是 `python -c "import arm.cad.helpers"`
就会在解释器退出时段错误(exit 139,OCC 静态析构),全流程跑完也一样。所以入口
脚本尾部保留 flush + os._exit,并把原因写进注释;被 import 时不生效。
关卡(tests/):
- verify.py 一条命令跑三层:产物 md5、IK 数值 exact 段、截图。
- 截图基线重做并分级:同一构建连跑两轮实测 102 张逐字节可复现(要求 md5 相同),
3 张线束 x-ray 不可复现(mean<=0.0017、无像素差>8)改为与参考像素比容差;
这 3 张不再入库,免得每次跑关卡都脏 git。
- 新增 ?view=sheet / ?sheet=N / ?theme / ?guide=N 四个 URL 参数:工程图与装配向导
占了约一半 CSS 和 700 行 JS,原先没有任何截图覆盖,拆它们等于没有关卡。
- 关卡灵敏度已验:改坏 IK 基线一个数 -> FAIL;换旧版求解器 -> 5 处 exact 差异。
实测:python -m arm.build_model 退出码 0,全部产物 md5 与基线一致,
105 视图截图全过,IK exact 段逐字节一致。
199 lines
14 KiB
Python
199 lines
14 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""P07 小臂骨架:J4 -> J5 的 L 型结构 + 顶板减重槽。"""
|
||
from arm.cad import arm_build as AB
|
||
import cadquery as cq
|
||
from arm import kinematics as HL
|
||
import math
|
||
from arm.cad.helpers import cyl
|
||
from arm.cad.arm_build import Ycyl, bx
|
||
from arm.kinematics import PLATE_T, X_ARM, Y_COVER, Y_HUB, Y_REAR, Z_EL, Z_WR
|
||
from arm.cad.part_tools import (
|
||
FILLET_SMALL, cut_motor_fence, hollow_channel, hub_m2_holes,
|
||
make_surface_tie_bridge_neg_x, motor_front_clamp,
|
||
)
|
||
|
||
|
||
P07_CH = dict(x0=-3.0, x1=43.0, y0=103.0, y1=153.0, z_floor=255.0) # 小臂顶板
|
||
|
||
|
||
def p_forearm_bone(j4, j5, half=None):
|
||
"""P07_小臂骨架_螺旋体30%_墙5底5_竖打 L型高刚度无干涉版(深度圆角优化版)
|
||
设计要点:
|
||
1. 改为与 P05/P08 统一的 L 型结构(L-bracket):
|
||
- +Y侧垂直背脊立柱(Y: y_hub_in..y_out),避开上级大臂骨架 P06(Y <= 155.5)
|
||
- 彻底消除原全深S弯在J4轴下方向两边突出的干涉结构(两边突出的结构全部去除)
|
||
- 垂直立柱与下方 M5 电机水平座之间采用规则折角(Corner Chamfer/Gusset)刚性连接
|
||
2. 下方 M5 电机实行半包散热结构,底部与内腔开窗散热
|
||
3. J4 轴俯仰动态行程从受限的 ±54° 大幅释放至无死角大范围摆动(零干涉)
|
||
4. 满足单实体 (solids=1) 与装配零碰撞。
|
||
5.【2026-10-02】M5 前端压盖(4xM3x8 BCD55)消除"电机只被后端板单面锁死"的倾斜隐患;
|
||
J4 从动侧整体让位:y_hub_in 由 158.5 后移到 J4_CLEAR=162.0,让出 P06 的 M4 前端压盖
|
||
(前端面 Y=161.0),留 1.0mm 动间隙。J4 直连凸台同步加长,3xS01 输出螺钉咬合量不变。
|
||
6.【2026-10-09】−X 侧线束走廊加一座外凸扎带拱桥 (y=102.5, Z=235):站出 3.2mm、桥下
|
||
3.2×1.8 穿带隧道沿 Y 贯通(与 P06/P03/P04 同配方)。走廊线心随之由 x=-17.5 提到 -20.7:
|
||
原线皮离本件 −X 面只剩 0.2mm,扎带没有容身处。
|
||
"""
|
||
y_out = Y_HUB + PLATE_T # 174.0
|
||
# J4 从动侧让位基准:必须 >= P06 的 M4 前端压盖前端面(Y_COVER+5.0=161.0) + 1.0mm
|
||
J4_CLEAR = Y_COVER + 6.0 # 162.0
|
||
y_hub_in = J4_CLEAR
|
||
y_front = Y_COVER - 0.5 # 155.5
|
||
y_rear = Y_REAR - 8.0 # 92.0
|
||
z_top_housing = Z_WR + 39.0 # 261.0 (顶面加厚 4.0mm,消除过薄破面问题)
|
||
z_roof_top = z_top_housing + 19.0 # 280.0 (顶板整条加高 19mm,用户确认方案4)
|
||
|
||
# 1. J5 电机前后安装环
|
||
collar_front = Ycyl(35.0, HL.Y_COVER - 6.0, HL.Y_COVER - 0.5, X_ARM, Z_WR)
|
||
rear_plate = Ycyl(35.0, HL.Y_REAR - 8.0, HL.Y_REAR, X_ARM, Z_WR)
|
||
s = collar_front.fuse(rear_plate)
|
||
|
||
# 2. J4 顶部从动法兰盘 (Y: y_hub_in..y_out, R=35mm, Z: Z_EL)
|
||
disc = Ycyl(35.0, y_hub_in, y_out, X_ARM, Z_EL)
|
||
s = s.fuse(disc)
|
||
|
||
# 3. M5 电机壳体水平顶部顶板 (Z: Z_WR..z_top_housing, Y: y_rear..y_front)
|
||
roof_w = (cq.Workplane("YZ", origin=(X_ARM, 0, 0))
|
||
.moveTo(y_rear, Z_WR)
|
||
.lineTo(y_rear, z_roof_top)
|
||
.lineTo(y_front - 3.0, z_roof_top)
|
||
.threePointArc((y_front - 3.0 + 3.0 * math.cos(math.pi / 4),
|
||
z_roof_top - 3.0 + 3.0 * math.sin(math.pi / 4)),
|
||
(y_front, z_roof_top - 3.0))
|
||
.lineTo(y_front, Z_WR)
|
||
.close()
|
||
.extrude(35.0, both=True))
|
||
s = s.fuse(roof_w.val())
|
||
|
||
# 4. L型垂直立柱臂 (+Y侧,Y: y_hub_in..y_out,从 Z_EL 顶端延伸至下方电机座)
|
||
vert_leg = (cq.Workplane("YZ", origin=(X_ARM, 0, 0))
|
||
.moveTo(y_hub_in, z_top_housing)
|
||
.lineTo(y_out, z_top_housing)
|
||
.lineTo(y_out, Z_EL)
|
||
.lineTo(y_hub_in, Z_EL)
|
||
.close()
|
||
.extrude(35.0, both=True))
|
||
s = s.fuse(vert_leg.val())
|
||
|
||
# 5. L型内侧圆弧加强过渡(Circular Arc Gusset,用户要求"改成圆弧而不是折角,消掉悬空小块")
|
||
# 彻底取代直角折角与直斜线折角,采用与顶面和立柱双相切的平滑内凹大圆弧 (R=28.0mm)
|
||
# 起点在顶板平整面 (y_arc_start, z_roof_top),精确相切至立柱内侧面 (y_hub_in, z_arc_end)
|
||
# 严控全域 Z >= z_top_housing,彻底消除侵入下方旋转副的悬空小方块与多余突起!
|
||
# 注:顶板整条加高19mm(z_roof_top=280)后,R28改R14使弧仍与顶板面光滑相切,不出现折角
|
||
R_arc = 14.0 # 随顶板加高联动重定:相切起点(144.5,280)->终点(158.5,294),避开P06环底z=297留3mm
|
||
y_arc_start = y_hub_in - R_arc
|
||
z_arc_end = z_roof_top + R_arc
|
||
p_mid_arc = (y_arc_start + R_arc * math.cos(math.pi / 4),
|
||
z_arc_end - R_arc * math.sin(math.pi / 4))
|
||
|
||
gusset_w = (cq.Workplane("YZ", origin=(X_ARM, 0, 0))
|
||
.moveTo(y_arc_start, z_roof_top)
|
||
.threePointArc(p_mid_arc, (y_hub_in, z_arc_end))
|
||
.lineTo(y_out, z_arc_end)
|
||
.lineTo(y_out, z_top_housing)
|
||
.lineTo(y_arc_start, z_top_housing)
|
||
.close()
|
||
.extrude(35.0, both=True))
|
||
s = s.fuse(gusset_w.val())
|
||
|
||
# 6. 下级 P08 旋转圆盘动态避让切除(R=35.5mm,预留 0.5mm 间隙)
|
||
p08_clearance = Ycyl(35.5, 156.0, y_out + 2.0, X_ARM, Z_WR)
|
||
s = s.cut(p08_clearance)
|
||
|
||
# 6b. 【2026-10-02 新增】顶板根部减重槽(见 hollow_channel)。
|
||
# 顶板在 Z255..280 一整段是壁厚最深 15mm 的实心料,而 J4 在 z=245 的安全系数
|
||
# 高达 122、z=195 也有 24。挖成朝上敞开的 U 形槽,顶板变成槽钢:
|
||
# 槽底 Z255 以下保留整块实心到电机座,抗弯的两片 X 向腹板(X-15..-7 / X47..55)
|
||
# 留在弯矩拉压区。Y 上限取 156 而非核心的 166,是为了避开 y_hub_in=158.5 起的
|
||
# 竖直立柱本体(立柱是 J4 从动法兰的承力柱,不能掏)。
|
||
# 槽顶 Z280 就是顶板上表面,敞口向上,免支撑、非封闭腔。
|
||
s = s.cut(hollow_channel(P07_CH["x0"], P07_CH["x1"], P07_CH["y0"], P07_CH["y1"],
|
||
P07_CH["z_floor"], 300.0, tag="P07顶板"))
|
||
|
||
# 7. M5 电机安装接口与定子空腔
|
||
# 【2026-10-05f 接缝整改】本件原先是全机唯一给腔径加 CLEARANCE_GAP(2.0) 的地方:
|
||
# front_collar_pocket(r_bore=32.25) + 一刀 Ycyl(32.5, Y_REAR-0.5, y_front-6)。
|
||
# 结果内壁是 35 -> 32.5 -> 30.2 -> 32.3 -> 30.2,比兄弟件多两道台阶
|
||
# (实测 scratch/bay_step_profile.py:z=5.5 处 32.5、z=49.5 处掉到 30.2、
|
||
# z=50.25 又回到 32.3)。
|
||
# 这 2.0mm 是「关节间隙」,但关节间隙是**轴向**让位(见 hub_gap / CLAMP_CLR),
|
||
# 径向把腔径撑大 2mm 只会让电机在腔里晃,且与 P05/P06/P08 不一致。
|
||
# 现统一走 BAY_R(30.50),与兄弟件同径,接缝归零。
|
||
# 【2026-10-03i】front_collar_pocket 随之删除:它切 cyl(BAY_R, 50.0..56.5),
|
||
# 是 Joint.pocket 那根 cyl(BAY_R, -2.6..61.6) 的子集,同半径重复相减
|
||
# 只会在腔壁上多出一条 s=50.0 的零宽棱。
|
||
s = j5.rear_mount_holes(s, t_plate=8.0, hole_d=2.8, cb_d=5.5, cb_depth=4.0)
|
||
s = j5.pocket(s)
|
||
# 【2026-10-07 修复:仅切除敞口侧承压面环墙,消除用户圈出的围挡】
|
||
# 仿照 P05 设计,只在敞口半侧(局部 y>=0)将承压面段(z: -REAR_SEAT..0)切平,
|
||
# 彻底消除用户红圈指出的承压面凸起围挡;顶板背脊侧(局部 y<0)绝对不动,杜绝切穿本体!
|
||
s = s.cut(j5.L(bx(-40.0, 40.0, 0.0, 40.0, -AB.REAR_SEAT, 0.0)))
|
||
# 【2026-10-05f】原 Ycyl(30.5+CLEARANCE_GAP=32.5, ...) 整刀删除:
|
||
# 它既撑大了腔径(接缝主因),又已被主腔 BAY_R 完全覆盖(纯冗余)。
|
||
|
||
# 半包散热设计:-Z底部电机定子通风口
|
||
vent_cut = bx(X_ARM - 40.0, X_ARM + 40.0, y_rear + 8.0, y_front - 6.0, Z_WR - 40.0, Z_WR - 25.0)
|
||
s = s.cut(vent_cut)
|
||
|
||
# 7b. 【2026-10-02 新增】M5 前端压盖 4xM3x8(BCD55):M5 原来只被后端板单面锁死,
|
||
# 大扭矩下会绕 J5 轴在座孔里点头。现在前端也面压夹一次(见 motor_front_clamp)。
|
||
# 必须在第 6 步 p08_clearance(R35.5 让位孔,Y>=156)之后熔接,否则压盖会被削掉。
|
||
# P08 的 J5 从动侧已相应后移到 Y>=162(make_pitch_to_roll_bracket 的 hub_gap=6.0)。
|
||
s = s.fuse(motor_front_clamp(X_ARM, Z_WR, tag="P07/M5"))
|
||
|
||
# 7c2.【2026-10-05e / 2026-10-07 修复】删掉前端"围挡"在敞口侧的那半圈环墙(见 FENCE_OPEN_CUT)。
|
||
s = cut_motor_fence(s, j5, "P07/M5", "P07")
|
||
|
||
# 8. J4 直连法兰结构(凸台延伸到法兰盘背面之后 2.0mm 跨过间隙与法兰盘牢固熔接,
|
||
# 保持单实体)。凸台长度跟着 y_hub_in 走:法兰盘后移时凸台同步加长,
|
||
# 3xS01 输出螺钉的头面台阶(局部 z=58)、杆长、咬合量与改前完全一致。
|
||
boss = cyl(17.8, 54.942, (y_hub_in - HL.Y_REAR) + 2.0)
|
||
s = s.fuse(j4.L(boss))
|
||
s = s.cut(j4.L(cyl(3.5, 54.0, 74.0 + 30.0)))
|
||
s = hub_m2_holes(s, j4, cb_z1=74.0 + 30.0)
|
||
|
||
# ========== 关键圆角优化 ==========
|
||
try:
|
||
# 后侧顶板外边缘圆角(平滑消除水平顶板与后部垂直端面交汇处的 90° 尖角,用户要求倒角改圆角)
|
||
wp_s = cq.Workplane(obj=s)
|
||
sel_rear = cq.selectors.BoxSelector(
|
||
(X_ARM - 40, y_rear - 1.0, z_roof_top - 1.0),
|
||
(X_ARM + 40, y_rear + 1.0, z_roof_top + 1.0)
|
||
)
|
||
s = wp_s.edges(sel_rear).fillet(FILLET_SMALL).val()
|
||
except Exception as e:
|
||
print(f"P07 顶板后边缘圆角异常: {e}")
|
||
|
||
try:
|
||
# 垂直立柱下部外缘圆角(消除立柱垂直外壁与下方悬空水平底面交汇处的 90° 尖角,用户截图红圈指定)
|
||
wp_s = cq.Workplane(obj=s)
|
||
sel_leg_bot = cq.selectors.BoxSelector(
|
||
(X_ARM - 40, y_out - 1.0, z_top_housing - 1.0),
|
||
(X_ARM + 40, y_out + 1.0, z_top_housing + 1.0)
|
||
)
|
||
s = wp_s.edges(sel_leg_bot).fillet(FILLET_SMALL).val()
|
||
except Exception as e:
|
||
print(f"P07 立柱下底外缘圆角异常: {e}")
|
||
|
||
# 9. −X 侧线束走廊扎带拱桥(与 P06/P03/P04 同一配方:站出 3.2mm、桥下 3.2×1.8 隧道、孔沿 Y)
|
||
# 线心随桥由 x=-17.5 改到 -20.5(桥顶 -18.7 + 线半径 1.8);本件 −X 面离走廊同样只有
|
||
# 2.0mm,原来线皮净空 0.2mm,扎带无从下手。
|
||
# 落点 Z=235 在 M5 壳体顶板的 −X 平面 (x=-15.5, Z222..280) 上:足迹 Z231..239 离顶板下缘
|
||
# 9.0mm、Y97.5..107.5 离 Y 边 5.5mm,实测平面度 0.00mm、背后 10.35mm 整实料;顶板减重槽
|
||
# 在 X≥-3 / Z≥255,与本桥不相交。
|
||
s = s.fuse(make_surface_tie_bridge_neg_x(X_ARM - 35.0, 102.5, 235.0,
|
||
w_y=10.0, l_z=8.0, h_x=3.2))
|
||
return s
|
||
|
||
|
||
JOINT = 'J4'
|
||
|
||
|
||
def specs(JS):
|
||
"""本件的 (件号, 中文名, 构建 thunk, 配色, 说明) 清单;顺序即 BOM 顺序。"""
|
||
j4 = JS["J4"]
|
||
j5 = JS["J5"]
|
||
return [
|
||
("P07_小臂骨架_螺旋体30%_墙5底5_竖打", "小臂骨架", lambda: p_forearm_bone(j4, j5, None), 0x7c3aed,
|
||
"V2 L型结构 + 顶板减重槽:+Y侧背脊立柱避让大臂骨架,过渡区采用与顶板和立柱双相切的R=28mm平滑内凹大圆弧,彻底消除直斜线折角与悬空阶梯小块,顶板前后外缘2mm倒角改R3圆角,立柱底端外下缘90°直棱倒R3圆角(平滑消除立柱外壁与水平底面交汇处直角尖角);顶板整条加高19mm(z261->280)加强连接且gusset弧R28->R14重定相切融入,J4圆盘外沿与立柱外棱不倒圆保持原始尖角,下方M5电机半包散热,俯仰大范围自由运动零干涉;【2026-10-02】顶板根部Z255~280开朝上敞开的减重槽(X-3~43 / Y103~153, Y上限取153避开y_hub_in=158.5起的竖直立柱本体):顶板由实心变槽钢,288->230cm3(-20%),槽底以下保留整块实心到电机座,抗弯靠两侧各10mm的X向腹板;槽底水平朝上、侧壁竖直、顶部敞开故零支撑且非封闭腔;开度按「减重区最差安全系数 >= 无槽基线 95%」选定(X-3~43 比最初的 X-7~47 收窄 4mm,强度从 88% 回到 96%);【2026-10-05 承压面让位腔改为 R35 圆腔、凸台与围挡一并消除】电机尾端垫片位(REAR_SEAT=2.6)用圆腔掏出承压面。**刀半径必须等于外壁 R35**(arm_build.SEAT_R):取小于 R35(曾试 32.2 = 64.4 方腔内切圆)时,刀半径与外壁之间那圈 2.8mm 环墙完整保留,而承压面只挖到刀半径,于是该环墙相对承压面【凸起】并把电机尾端面围住 —— 这就是用户截图里的一圈围挡(P08 实测 1536.9mm3)。它不是残留,而是 SEAT_R<R35 的必然产物。现 SEAT_R=35.0、SEAT_TOP=+1.0(越过尾端面 1mm,吃掉半包开口处那截0.052cm3 残片):承压面段整圈挖到外壁,承压面成为完整 R35 平圆盘,凸台与围挡一起消失,电机尾端面与承压面之间再无凸起。承力改由臂身本体承担(band 段 r36..58 有料方位 P04 10/36、其余各 15/36,其余方位靠 z>+1.0 杯体连接,无整圈通槽)。沉孔 z 区间(-8..-4)与圆腔(-2.6..+1.0)不重叠,S02 完好。连带:承压环由「方腔内切 32.2 − 沉孔外缘 30.25 = 1.95mm 窄环」变为「完整 R35 圆环 4.75mm」,受压面积 383->974mm²(2.5 倍)。【2026-10-04 承压面让位腔改为 32.2 圆腔】电机尾端垫片位(REAR_SEAT=2.6)之前用 64.4 **方**腔掏出来,方腔壁以外 z=-2.6..0 那圈料相对新承压面凸起 2.6mm,打印时是悬空薄壁(用户反馈:难打印、需支撑、公差差)。现承压面段改用**SEAT_R=32.2 圆腔**(= 64.4 方腔的内切圆半径,z=-2.6..0 与方腔平接)把整圈挖到承压面高度,凸台零残留;z=0 以上 PCBA 腔仍保持 64.4 方(PCB 是方的必须方腔)。**关键:刀半径必须取 32.2 而不是 R35** —— 中间试过 R35,结果把 r=32.2..35 的连接壁整圈切断:实测 P04 在 z=-2.6..+1.0 只剩 240~320° 方位有料,其余 360° 全掏空,后端法兰与杯壁之间出现 3.6mm 宽通槽 + 225° 一片 0.5mm 孤立薄片(用户截图:肩叉顶部「没连上」)。取 32.2 后 r=32.2..35 这圈 2.8mm 厚壁完整保留,360° 连续,既无凸台又与上方臂身连成一体(实测 5/5 件连接壁整圈连续、单实体)"),
|
||
]
|