初始提交:机械臂 CadQuery 建模源码、设计文档与 3D 查看器

This commit is contained in:
cbb
2026-09-26 18:05:21 +08:00
commit 1dfd48278b
172 changed files with 11116 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
"""Headless Edge screenshots of the viewer, for the visual self-check loop."""
import os
import subprocess
import sys
import shutil
import glob
try:
sys.stdout.reconfigure(encoding="utf-8")
except Exception:
pass
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from armcore import ROOT, WORKSPACE, WEB, DOCS
SHOTS = DOCS + "/shots"
HTML = WEB + "/机器人手臂3D查看器.html"
CAND = [r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe",
r"C:\Program Files\Microsoft\Edge\Application\msedge.exe"]
EDGE = next((c for c in CAND if os.path.exists(c)), None)
if not EDGE:
EDGE = glob.glob(r"C:\Users\*\AppData\Local\Microsoft\Edge\*\msedge.exe")
EDGE = EDGE[0] if EDGE else None
if not EDGE:
raise SystemExit("msedge not found")
VIEWS = {
"01_iso": "?cam=iso",
"zoom_user": "?cam=iso&az=-0.9&po=1.15&rd=470&tx=30&ty=320&tz=-80&xray=0",
"02_front": "?cam=front",
"03_side": "?cam=side",
"04_top": "?cam=top",
"05_exploded": "?cam=iso&expl=100",
"06_wrist": "?cam=wrist&xray=0",
"07_joint": "?cam=joint",
"08_pose": "?cam=iso&j2=35&j3=60&j4=-25&j1=25",
"09_sheet": "?sheet=1",
"10_solid": "?cam=iso&xray=0",
"11_tool_flange": "?cam=wrist&xray=0&j6=45",
"12_elbow_flare": "?cam=elbow&xray=0",
"13_forearm_side": "?cam=side&xray=0&rd=340&ty=245&tz=-135",
"user_target": "?cam=side&az=-1.5708&po=1.57&xray=0&rd=340&tx=100&ty=245&tz=-135",
"view_yz_pos_x": "?cam=side&az=0&po=1.57&xray=0&rd=340&tx=100&ty=245&tz=-135",
"view_yz_neg_x": "?cam=side&az=3.14159&po=1.57&xray=0&rd=340&tx=100&ty=245&tz=-135",
"view_iso_forearm": "?cam=side&az=-0.65&po=1.2&xray=0&rd=320&tx=100&ty=245&tz=-135",
"user_view1": "?cam=wrist&az=0.55&po=1.4&rd=310&xray=0",
"user_view2": "?cam=wrist&az=0.2&po=1.4&rd=290&xray=0",
"user_p04": "?cam=joint&az=-1.5708&po=1.57&rd=380&xray=0",
"user_p04_opp": "?cam=joint&az=1.5708&po=1.57&rd=380&xray=0",
"user_elbow_rear": "?az=1.5708&po=1.5708&rd=280&tx=95&ty=315&tz=-128&xray=0",
"user_p07_wrist": "?az=1.5708&po=1.5708&rd=240&tx=95&ty=235&tz=-128&xray=0",
"user_elbow_front": "?az=-1.5708&po=1.5708&rd=250&tx=18.5&ty=310&tz=-128&xray=0",
"user_p06_xz": "?az=1.5708&po=1.5708&rd=240&tx=18.5&ty=350&tz=-128&xray=0&hide=胸板,底脚,肩吊臂",
"user_p06_yz": "?az=0&po=1.5708&rd=260&tx=18.5&ty=350&tz=-110&xray=0",
"user_p06_iso": "?az=-0.65&po=1.25&rd=260&tx=-15&ty=350&tz=-128&xray=0",
"user_p07_creases": "?az=-0.65&po=1.25&rd=260&tx=30&ty=270&tz=-130&xray=0",
"user_p04_side": "?az=1.5708&po=1.5708&rd=300&tx=18.5&ty=520&tz=-128&xray=0&hide=胸板,底脚,肩吊臂",
"user_p04_bottom": "?az=0.5&po=2.0&rd=240&tx=18.5&ty=490&tz=-128&xray=0&hide=胸板,底脚,肩吊臂",
"user_p04_bottom2": "?az=1.2&po=2.0&rd=260&tx=18.5&ty=490&tz=-128&xray=0&hide=胸板,底脚,肩吊臂",
"svg_side": f"file:///{DOCS}/sheet_side.svg",
"svg_joint": f"file:///{DOCS}/sheet_joint.svg",
"svg_exploded": f"file:///{DOCS}/sheet_exploded.svg",
"svg_front": f"file:///{DOCS}/sheet_front.svg",
}
os.makedirs(SHOTS, exist_ok=True)
want = sys.argv[1:] or list(VIEWS)
def take_shot(nm):
q = VIEWS[nm]
out = "%s/%s.png" % (SHOTS, nm)
import time
t_bust = int(time.time() * 1000)
target = q if q.startswith("file://") else "file:///" + HTML.replace("\\", "/") + q + (
f"&still=1&_t={t_bust}" if "?" in q else f"?still=1&_t={t_bust}")
cmd = [EDGE, "--headless=new", "--use-gl=angle", "--use-angle=d3d11",
"--disable-cache", "--disable-application-cache", "--disk-cache-size=0",
"--enable-gpu-rasterization", "--ignore-gpu-blocklist",
"--hide-scrollbars", "--force-device-scale-factor=1",
"--window-size=1500,860", "--virtual-time-budget=20000",
"--screenshot=" + out, target]
r = subprocess.run(cmd, capture_output=True, timeout=180)
ok = os.path.exists(out) and os.path.getsize(out) > 20000
err = (r.stderr or b"").decode("utf-8", errors="ignore").strip()[:90].replace("\n", " ")
sz = os.path.getsize(out) if os.path.exists(out) else 0
print("%-12s %s %8s %s" % (nm, "OK " if ok else "FAIL", sz, err), flush=True)
return ok
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=min(4, os.cpu_count() or 2)) as executor:
results = list(executor.map(take_shot, want))
print("edge:", EDGE)
print("all shots ok:", all(results))
os._exit(0)