refactor(layout): src/ 收成顶层包 arm/,入口统一 python -m;提升承担构建的 scratch 脚本
单文件约束取消后,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 段逐字节一致。
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""从 travel_detail.json 的单关节硬限位重新生成 docs/travel.json。
|
||||
|
||||
滑块范围 = 单关节硬限位(任意单关节推满零干涉,含 1° 安全余量);
|
||||
组合折叠约束保留在 travel_detail.json 的 combos 字段里,供报告引用。
|
||||
|
||||
注意 note 的措辞:单轴整周无干涉 **不等于** 任意组合姿态无干涉。sweep_v2 的组合扫描
|
||||
已经在 J1/J3/J6 上找到了真实卡死(工具法兰 P09 撞固定立柱 P01_A),例如 J3≈±162°。
|
||||
所以连续轴的 note 必须写明"单轴"并指向 combos,否则这份文件会误导人——查看器运行期
|
||||
另有胶囊碰撞模型按姿态夹取(ik-glue.js 的 dynLimit),但静态滑块范围按设计不压缩。
|
||||
"""
|
||||
import json
|
||||
import math
|
||||
|
||||
import os
|
||||
import sys
|
||||
from arm.analysis.sweep_v2 import CHAIN
|
||||
from arm.paths import DOCS
|
||||
|
||||
# 这两个脚本的顶层就是"算完并写文件",被 import 时会静默重写 travel/mesh 派生产物
|
||||
# (实测:一次 importlib 冒烟测试就把 docs/travel.json 重写了一遍)。这里改成直接炸。
|
||||
if __name__ != "__main__":
|
||||
raise RuntimeError(
|
||||
"finalize_travel 是脚本:顶层代码一执行就重写产物,不能 import。"
|
||||
"要用就跑 python -m arm.analysis.finalize_travel。")
|
||||
|
||||
d = json.load(open(DOCS + "/travel_detail.json", encoding="utf-8"))
|
||||
|
||||
# 组合扫描中,每个被扫轴真实出现卡死的最小绝对角
|
||||
combo_warn = {}
|
||||
for c in d.get("combos", []):
|
||||
if not c.get("jams"):
|
||||
continue
|
||||
ax = c["swept"]
|
||||
for a in c["jams"]:
|
||||
try:
|
||||
v = abs(float(a))
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
combo_warn[ax] = min(combo_warn.get(ax, 1e9), v)
|
||||
|
||||
out = []
|
||||
for t in CHAIN[1:]:
|
||||
s = d["singles"][t]
|
||||
lo, hi = s["lo"], s["hi"]
|
||||
warn = combo_warn.get(t)
|
||||
warn_txt = (";组合折叠姿态下(其余关节同时处于各自极限)约 ±%.0f° 起与躯干占位"
|
||||
"(台架 P01 立柱)干涉,见 travel_detail.combos,"
|
||||
"运行期由查看器碰撞模型按姿态夹取" % warn) if warn is not None else ""
|
||||
if lo <= -179.9 and hi >= 179.9:
|
||||
out.append(dict(axis=t, lo=-180.0, hi=180.0, continuous=True, zero=0.0,
|
||||
combo_warn_deg=warn,
|
||||
note="单轴整周无干涉(滑块按单轴限位给出)%s" % (warn_txt or
|
||||
";组合扫描未发现该轴卡死")))
|
||||
else:
|
||||
lo_out = float(math.ceil(lo + 1.0)) if lo < -0.5 else 0.0
|
||||
hi_out = float(math.floor(hi - 1.0)) if hi > 0.5 else 0.0
|
||||
out.append(dict(axis=t, lo=lo_out, hi=hi_out, continuous=False, zero=0.0,
|
||||
combo_warn_deg=warn,
|
||||
note="单轴正向 +%d° / 反向 %d°,总行程 %d°(单关节硬限位,含相邻件与电机)%s"
|
||||
% (hi_out, lo_out, hi_out - lo_out, warn_txt)))
|
||||
print("%-3s %7.1f .. %7.1f -> %s .. %s%s"
|
||||
% (t, lo, hi, out[-1]["lo"], out[-1]["hi"],
|
||||
(" 组合卡死阈值 ±%.0f°" % warn) if warn is not None else ""))
|
||||
|
||||
json.dump(out, open(DOCS + "/travel.json", "w", encoding="utf-8"),
|
||||
ensure_ascii=False, indent=1)
|
||||
d["final"] = out
|
||||
json.dump(d, open(DOCS + "/travel_detail.json", "w", encoding="utf-8"),
|
||||
ensure_ascii=False, indent=1)
|
||||
print("rewrote docs/travel.json (single-joint hard stops) + updated travel_detail.json")
|
||||
Reference in New Issue
Block a user