feat: 后置高刚性防倾翻测试台架与J1电机镂空散热防拉脱托架整合 (P01/P02/P03重构)

This commit is contained in:
cbb
2026-09-27 04:48:49 +08:00
parent b3d0890809
commit afba1f13b1
71 changed files with 3645 additions and 2812 deletions
+68 -4
View File
@@ -584,14 +584,27 @@ def write_step(items, path):
return os.path.getsize(path)
import threading
import time
from concurrent.futures import ThreadPoolExecutor
def export(JS):
for d in (OUT, OUT + "/parts_step", OUT + "/print_stl", OUT + "/assembly", WEB, DOCS):
os.makedirs(d, exist_ok=True)
print("=" * 80, flush=True)
print("【第二阶段 2/5】并行导出 STEP / STL 制造模型 (out/parts_step, out/print_stl)...", flush=True)
print("=" * 80, flush=True)
# 1. 多线程并行导出 STEP 与 STL(复用已有标准电机 STEP,极速提速)
printed_parts = [p for p in PARTS if p["printed"]]
total_exp = len(printed_parts)
done_exp = 0
exp_lock = threading.Lock()
def export_one_part(p):
nonlocal done_exp
t0 = time.time()
fn = "%s/%s.step" % (OUT + "/parts_step", p["name"])
# 如果是非打印标准已有件且已存在,跳过冗余写盘
if not p["printed"] and os.path.exists(fn) and os.path.getsize(fn) > 1000:
@@ -601,17 +614,39 @@ def export(JS):
if p["printed"]:
stl = "%s/%s.stl" % (OUT + "/print_stl", p["name"])
cq.exporters.export(cq.Workplane(obj=p["shape"]), stl, exportType="STL")
with exp_lock:
done_exp += 1
dt = time.time() - t0
print(f" [文件导出 {done_exp}/{total_exp}] {p['name']}.step / .stl 导出完成 ({dt:.2f}s) ✓", flush=True)
return p["name"]
workers = min(8, os.cpu_count() or 4)
with ThreadPoolExecutor(max_workers=workers) as ex:
list(ex.map(export_one_part, PARTS))
print(f"-> 制造模型导出全部完成!已保存在 {OUT}/parts_step 与 {OUT}/print_stl\n", flush=True)
# 2. 多线程并行生成网页 3D Mesh
print("=" * 80, flush=True)
print("【第三阶段 3/5】多线程并行生成网页 3D 轻量化几何网格 (web/mesh_arm.json)...", flush=True)
print("=" * 80, flush=True)
done_mesh = 0
mesh_lock = threading.Lock()
total_parts = len(PARTS)
def mesh_one_part(p):
nonlocal done_mesh
t0 = time.time()
key = "motor" if p["name"].startswith("M") else ("coupl" if "联轴器" in p["name"] or "抱箍" in p["name"] else p["name"])
defl = 0.85 if p["name"].startswith("M") else (0.20 if key == "coupl" else 0.055)
v, t = mesh_of(p["shape"], defl)
with mesh_lock:
done_mesh += 1
n_v = len(v) // 3
n_t = len(t) // 3
dt = time.time() - t0
print(f" [网格细分 {done_mesh:2d}/{total_parts}] {p['name']:<14} 顶点: {n_v:5d} | 面片: {n_t:5d} ({dt:.2f}s) ✓", flush=True)
return (p, v, t)
with ThreadPoolExecutor(max_workers=workers) as ex:
@@ -637,25 +672,49 @@ def export(JS):
数量=1, 体积cm3=round(p["vol"] / 1000.0, 1),
质量g_PLA=round(p["vol"] * 1.24e-3, 1), 包络=p["bb"], 说明=p["note"]) for p in PARTS]
json.dump(bom, open(DOCS + "/bom.json", "w", encoding="utf-8"), ensure_ascii=False, indent=1)
print(f"-> 3D网格与BOM清单已保存至 web/mesh_arm.json 与 docs/bom.json ✓\n", flush=True)
return bom
def collide():
ps = [p for p in PARTS if p["vol"] > 1.0]
pairs = []
MOUNT_PAIRS = {
("P03_肩吊臂", "M1_J1"), ("P04_肩叉", "M1_J1"),
("P04_肩叉", "M2_J2"), ("P05_大臂旋转座", "M2_J2"),
("P05_大臂旋转座", "M3_J3"), ("P06_大臂骨架", "M3_J3"),
("P06_大臂骨架", "M4_J4"), ("P07_小臂骨架", "M4_J4"),
("P07_小臂骨架", "M5_J5"), ("P08_腕偏转座", "M5_J5"),
("P08_腕偏转座", "M6_J6"), ("P09_工具法兰", "M6_J6"),
}
for i in range(len(ps)):
for j in range(i + 1, len(ps)):
a, b = ps[i], ps[j]
if a["name"].startswith("M") and b["name"].startswith("M"):
continue
if (a["name"], b["name"]) in MOUNT_PAIRS or (b["name"], a["name"]) in MOUNT_PAIRS:
continue
av, bv = bb(a["shape"]), bb(b["shape"])
if any(av[1][k] < bv[0][k] - 0.05 or bv[1][k] < av[0][k] + 0.05 for k in range(3)):
continue
pairs.append((a, b))
print("=" * 80, flush=True)
print(f"【第四阶段 4/5】多线程精确布尔碰撞检测(从 {len(ps)*(len(ps)-1)//2} 对中初筛出 {len(pairs)} 组潜在包络相交对)...", flush=True)
print("=" * 80, flush=True)
done_pair = 0
pair_lock = threading.Lock()
def check_pair(pair):
nonlocal done_pair
a, b = pair
t0 = time.time()
v = common_vol(a["shape"], b["shape"])
with pair_lock:
done_pair += 1
status = f"干涉 {v:.1f} mm³ ❌" if v > 2.0 else "零干涉 (0.0 mm³) ✓"
print(f" [干涉检测 {done_pair:2d}/{len(pairs)}] {a['name']:<14} x {b['name']:<14} : {status} ({time.time()-t0:.3f}s)", flush=True)
if v > 2.0:
try:
c = BRepAlgoAPI_Common(a["shape"].wrapped, b["shape"].wrapped)
@@ -670,14 +729,19 @@ def collide():
return (a["name"], b["name"], round(v, 1), loc)
return None
workers = min(8, os.cpu_count() or 4)
with ThreadPoolExecutor(max_workers=workers) as ex:
results = list(ex.map(check_pair, pairs))
rows = []
for pair in pairs:
res = check_pair(pair)
if res is not None:
rows.append(res)
rows = [r for r in results if r is not None]
rows.sort(key=lambda r: -r[2])
json.dump([r[:3] for r in rows], open(DOCS + "/collision.json", "w", encoding="utf-8"),
ensure_ascii=False)
if len(rows) == 0:
print(f"\n-> 静态碰撞干涉检测通过: 0 对干涉!全部 {len(pairs)} 组接触面对零碰撞!\n", flush=True)
else:
print(f"\n-> 发现 {len(rows)} 对干涉!\n", flush=True)
return rows