feat: 后置高刚性防倾翻测试台架与J1电机镂空散热防拉脱托架整合 (P01/P02/P03重构)
This commit is contained in:
+68
-4
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user