- v1(2026-10-17 20:06,
40af3b4):模型一次生成整条 32 点路径,失败回落到原规划器("有老师部署")。- v1.1(20:25,
c51f8f9):加入后训练挖错循环。- v2(本稿):按用户决定改为 无老师部署 + 每个控制周期重算(闭环),删除全部"回落原规划器"设计; 加入具身智能领域主流做法的调研与对比(§1–§2),并据此调整模型输出、后训练方法和验收标准。
- v2.1(2026-10-17 20:58):训练机定为 RTX 3090 24 GB;near_column 验收改为 30/30,新增 §8.5「为什么会超时、无老师怎样做到 30/30」;新增 §8.6 控制周期业界调研与评估。
- 基于
main@3c7c814(贴立柱修复后的规划器)。本文只是方案,代码尚未编写。- 审查重点:§0 定位、§2 差异与优化、§5 输出表示、§7 后训练(APG)、§8 闭环部署与安全层、§9 验收。
| 项目 | 决定 |
|---|---|
| 部署形态 | 无老师:运行时只有「神经策略 + 碰撞安全层」,不加载
IK 大表、PRM 路网、A*/RRT,也不调用 solveDyn /
routeRT |
| 运行方式 | 闭环滚动重算(MPC 式):每个控制周期(默认 50 Hz,20 ms)读当前关节角和目标,重新推理一段短动作块,只执行最前面一小段,下一周期再算。某一周期算错,下一周期有机会纠正 |
| 碰撞安全层 | 保留。它不是老师:不做搜索,只对模型给出的下一小段做胶囊碰撞检查(已有
collideFree + 包围球预筛),不安全就换候选或刹停 |
| 老师的角色 | 只在离线训练时出现:生成预训练数据。后训练阶段用可微碰撞代价(§7),基本不再需要老师 |
| 不做的事 | 不学动力学(速度/加速度上限由插补器保证);不用相机/点云(环境固定:台架 + P01 立柱,几何已知) |
| 收益目标 | 冷启动(新目标到第一个动作)< 10 ms;每周期推理 + 安全检查 < 10 ms;拖拽重规划 P99(现状约 321 ms)不再存在 |
| 底线 | 实时拖拽碰撞帧 = 0(安全层保证);到达率、行程在 §9 的指标上不低于现有规划器 |
为什么安全层必须保留:调研里最好的神经运动策略在静态场景里仍有约 10% 的轨迹发生碰撞(§1 DRP 附录表 6、ELMP 表 I)。 我们的环境几何完全已知、检查只要几毫秒,保留它代价极小,却把"偶尔撞一下"变成"偶尔停一下"。
以下数据均来自论文原文(链接见 §13)。
| 工作 | 年份 / 会议 | 输入 | 输出 | 老师与数据量 | 关键做法 | 运行方式 |
|---|---|---|---|---|---|---|
| MπNets(NVIDIA) | 2022 CoRL | 点云 + 当前关节角 + 目标位姿 | 下一步关节位置 | 规划器生成 300 万+ 问题、50 万+ 环境;8×V100 训练一周 | 端到端行为克隆 | 闭环 9 Hz,每次执行约 70% 推出的路径,1 kHz PD 跟踪 |
| Neural MP(CMU) | 2024 / IROS 2025 | 点云 + 关节角 + 目标 | GMM(LSTM) | AIT* 等,100 万–300 万条 | 测试时优化(TTO):采样多条,选与场景穿透最少的 | 开环为主;冷启动约 2970 ms |
| MπFormer / Avoid Everything(NVIDIA) | 2024 CoRL WS | 点云 | 关节动作 | 规划器数据 | 师生微调 + 困难负样本挖掘 | 闭环 |
| DRP / IMPACT(CMU) | 2025 CoRL | 点云 + 当前关节角 + 目标关节角 | 动作块:10 步关节增量,MSE 回归 | cuRobo 生成 1000 万条;4090 训练 3 天 | ① 大规模预训练 ② 迭代师生微调(局部控制器 Geometric Fabrics 当老师,不用全局规划器,因为每步都规划太贵)③ 局部反应层 DCP-RMP 改写目标 ④ 加入"目标被挡→停在最近安全处"的数据 | 闭环;4.67 M 参数,300 Hz(4090),冷启动 3.48 ms |
| ELMP(ETH) | 2026 arXiv | 点云 + 关节角 + 目标位姿(12 维) | 关节增量 | AIT* 约 60 万条 | 行为克隆后做 APG 微调:可微运动学展开,碰撞/到达/平滑三项损失直接反传,不再需要老师数据 | MPC 式闭环 30 Hz;冷启动 7.8 ms |
| Diffusion Policy / ACT 一类 | 2023– | 视觉 + 本体 | 动作块(扩散 / CVAE) | 人类示教 | 动作块 + 滚动执行(receding horizon)+ 时间集成 | 闭环 |
几个关键数字:
行业共识:
| 条件 | 主流(DRP/ELMP 等) | 本项目 | 意味着 |
|---|---|---|---|
| 环境 | 未知、多变,靠点云感知 | 固定且精确已知(台架 + 立柱,1936 个胶囊) | 不需要点云编码器;模型可以小很多;碰撞检查是精确的 |
| 机器人 | Franka 7 轴 | 自研 6 轴,J1/J3/J6 连续转 | 需处理连续轴展开 |
| 碰撞模型 | SDF / 球近似,有感知噪声 | 胶囊解析距离,可微 | 可以直接做 APG;安全层可信 |
| 运行平台 | 台式 GPU | 浏览器(后续真机) | 模型要小,ONNX + WebGPU/wasm |
结论:我们的问题比主流窄得多也"干净"得多,主流用来对付感知噪声和环境泛化的大部分复杂度(点云、千万级数据、多环境)都可以省掉,资源应投在闭环稳定性、多解选择和安全层上。
| # | v1 做法 | 主流做法 | v2 调整 | 理由 |
|---|---|---|---|---|
| 1 | 一次生成整条 32 点路径,开环执行 | 闭环 + 短动作块滚动执行 | 改为动作块策略:每周期输出未来 16 步(320 ms),只执行前 2–4 步 | 用户要求每周期重算;可纠错、可应对拖拽目标变化 |
| 2 | 失败回落原规划器 | 无回落;靠后训练提升 + 局部反应/检查 | 删除回落,改为安全层:换候选 → 刹停保持 → 下周期重算 | 用户决定无老师部署 |
| 3 | 512 桶离散化 + 自回归 186 token | DRP 用 MSE 回归动作块;Neural MP 用 GMM | K 个模式的动作块头(K=4)+ 模式分类,非自回归一次前向 | 闭环下多峰主要出现在"刚出发选左绕还是右绕",K 模式足够;一次前向比 186 步自回归快一个数量级 |
| 4 | 以目标位姿为条件 | DRP 用目标关节角(IK 另算);ELMP 用目标位姿 | 用目标位姿(位置 + 6D 旋转 + 模式标志),末段可选局部牛顿精修 | 无老师就没有全量 IK;位姿条件让模型连 IK 一起学。局部牛顿精修只是梯度下降几步,不属于搜索 |
| 5 | 后训练:挖错 + 老师重标(每轮 1–2 小时老师计算) | DRP:便宜局部老师;ELMP:APG 无老师 | 主力换成 APG(可微胶囊碰撞),挖错循环保留但不再需要老师重标 | 我们的胶囊模型可微且精确,正好适合 APG;省掉绝大部分老师计算 |
| 6 | 拒判头(REJECT) | DRP:目标被挡时学会"停在最近安全处" | 改为"停靠"行为:目标不可达时,数据里老师路径停在离目标最近的安全位形 | 闭环下"停在最近处"比"拒绝"更有用(目标常在拖拽中短暂进入立柱区) |
| 7 | 20 万条老师数据 | 主流百万–千万条,但它们要泛化到任意环境 | 降到 5 万条(+ 切片增广),其余靠 APG | ELMP 显示 APG 下 1 万条已胜过 60 万条纯克隆;我们的环境固定,需求更小 |
| 8 | 无 | DRP 的 DCP-RMP 局部反应层 | 暂不做;安全层已覆盖静态环境。未来真机有人/动态障碍时再加 | 当前环境静态 |
segSegDist
的可微版本),训练和部署检查同一套几何,消除"训练用球、检查用网格"的口径差(ELMP
的做法有这个差)。| 阶段 | 在哪里跑 | 说明 |
|---|---|---|
| 预训练数据生成 | Hark 沙箱(2 vCPU / 7 GB,Node)或用户机器 | 纯 JS,无需 GPU |
| 预训练 + APG 微调 | 用户的 GPU 机器 | 沙箱无 GPU、无 PyTorch。已定:RTX 3090 24 GB(显存对 3–4 M 参数模型绰绰有余,可用 batch 1024–2048) |
| 部署推理 | 浏览器(onnxruntime-web,WebGPU 优先,wasm 兜底);后续真机控制器 | 与现有查看器同页 |
conda create -n armtf python=3.11 -y && conda activate armtf
pip install torch --index-url https://download.pytorch.org/whl/cu121 # 按本机 CUDA 版本选
pip install numpy pyarrow tqdm tensorboard onnx onnxruntime| 文件 | 作用 |
|---|---|
ml/gen/gen_dataset.cjs |
采样任务 → 调老师 → 校验 → 时间参数化 → 写分片 |
ml/gen/sampler.cjs |
起点/目标采样(4.3) |
ml/gen/run_parallel.sh |
多进程,不同种子 |
ml/data/shard_XXXX.jsonl |
原始样本(不入库) |
复用 tests/route_bench_setup.cjs
装配求解器(关节表、docs/travel.json、docs/collide.json)。
{
"id": "s0003_000127", "mode": "pos" | "pose",
"q0": [6], "T": [x,y,z], "R": [[3x3]] | null, "tool": 0,
"path": [[6], ...], // 老师折线 q0 → via... → q_end
"reached": true, // false = 目标不可达,q_end 为离目标最近的安全位形("停靠")
"travel_deg": 123.4, "plan_ms": 812.0,
"fp": "collide.json 指纹"
}关节限位(docs/travel.json):J1/J3/J6 连续 ±180°;J2
[−92, 9],J4 [−111, 16],J5 [−93, 34]。
| 类别 | 占比 | 采样方式 |
|---|---|---|
| A 均匀 | 45% | q0、目标位形 b 均匀采样且无干涉;目标 = fk(b)(pose
模式加 orient(b)) |
| B 直线被挡 | 30% | q0→b 关节直线 1° 细验有干涉(route_bench 口径) |
| C 贴立柱 | 15% | b 满足 nearColumn,q0 在立柱另一侧(near_column_bench
口径) |
| D 目标不可达 | 10% | 目标在立柱内/所有分支都撞/工作空间外;老师标签 = 停在离目标最近的安全位形 |
solveDyn(松手口径)。poseRelaxed 样本只当 pos 模式用。routeRT 1.5
倍的视为绕远(先统计,再定是否丢弃)。闭环策略学的是"在某个状态下,接下来 16 步怎么走",所以要把整条路径切成很多个"状态 → 动作块"样本:
animTo 的轴速比
VREL = [0.6, 0.6, 0.9, 0.9, 1.2, 1.8]
做时间参数化(与查看器动画同口径),控制周期 dt = 20
ms。solveDyn 约 0.7 s/条:5 万条在沙箱 2 进程约 5
小时;用户 8 核机器约 1.5 小时。文件 ml/prep/build_dataset.py →
train/val/test.parquet、norm.json。
| 量 | 维度 | 编码 |
|---|---|---|
| 当前 q_t | 6 | 每轴 (sin, cos) → 12;限位轴另加归一化值 → +3 |
| 当前 TCP 位置与姿态 | 3 + 6 | fk(q_t)、orient(q_t) 的 6D
表示(给模型笛卡尔线索) |
| 目标位置 T | 3 | /600 mm |
| 目标姿态 R | 6 | 6D 表示;pos 模式填 0 |
| 目标 − 当前 TCP | 3 | 位置差,/600 mm |
| 模式 | 2 | one-hot [pos, pose] |
| 上一周期选的模式 k_prev | K+1 | one-hot(含"无"),用于模式粘滞 |
| 关键胶囊对最小距离 | 8 | 当前位形下臂各段到立柱的胶囊距离(cheap,现成函数),给模型"离柱子多近"的直接信号 |
J1/J3/J6 统一用 unwrapTo
口径展开后再做增量;预处理和部署共用一份实现,§6.4 对拍时一并验证。
条件特征(约 60 维)──MLP──▶ 8 个条件 token (d=192)
│
4 层 Transformer encoder
│ (memory)
K×16 个可学习动作 token ──▶ 4 层 Transformer decoder(非自回归,一次前向)
│
├─ 动作头:每 token 输出 6 维 Δq
├─ 模式分类头:K=4
├─ 价值头(剩余时间/代价):1 ← v2.1,§8.5
└─ 子目标头:2 个关节空间途经点 + 是否需要(仅冷启动用)← v2.1,§8.5
| 超参 | 值 |
|---|---|
| d_model / 头数 / FFN | 192 / 8 / 768 |
| encoder / decoder 层数 | 4 / 4 |
| 参数量 | 约 3–4 M(DRP 为 4.67 M,含点云编码) |
| 推理 | 一次前向得到 4 条候选动作块 |
L = WTA-L1(动作块, 最近模式) 权重 1.0
+ CE(模式分类) 权重 0.5
+ FK 损失:预测与标签位形下各连杆胶囊端点的位置差 权重 0.5 ← 借鉴 ELMP
+ 平滑:二阶差分 权重 0.05
+ L1(剩余时间) 权重 0.1
| 项 | 值 |
|---|---|
| 优化器 | AdamW,β=(0.9, 0.95),wd 0.01 |
| 学习率 | 1e-3,预热 1000 步,余弦退火(同 DRP 量级) |
| batch | 1024(3090 24 GB) |
| 精度 | bf16 混合精度 |
| 步数 | 约 20 万步(300 万样本约 30 epoch),验证集闭环成功率不再上升即停 |
| 预计耗时 | RTX 3090 约 1.5–3 小时(估算;DRP 4.67 M 参数在 4090 上预训练 100 万步用 3 天,我们的样本少、无点云编码,步数约其 1/5,跑完首轮再校正) |
ml/eval/collide_torch.py:胶囊距离的 PyTorch
批量版(可微,§7 要用),先与 JS
collideFree 对拍 10 万个位形,判定 0 误差。不再请老师标注,直接让模型在可微仿真里闭环展开,用代价反传:
for 每个 batch(随机采样 q0 和目标,82 ms 级别的便宜采样,不需要老师):
q = q0
for t in 0..H-1 (H = 60 个周期 ≈ 1.2 s,长任务分段展开):
chunk, logits = π(obs(q, 目标))
Δq = chunk[选中模式][0:3] # 执行前 3 步,与部署一致
q = clamp(q + Δq) # 限位
累计 L_col(q), L_smooth(Δq)
L = w_tgt·L_target(q_H) + w_col·ΣL_col + w_smooth·ΣL_smooth (+ w_len·行程)
反传(BPTT),梯度裁剪 ≤ 1.0
collide.json 的 margin_mm
基础上再加 5 mm 训练余量;包含臂×立柱、臂×台架、臂×臂(非相邻段)。每轮:
对每个任务采样多条闭环轨迹(不同模式、不同温度),只保留验算通过且最短的一条做行为克隆标签——模型自己当老师。适合 APG 收敛后进一步缩短行程。
每 20 ms:
1. 读当前 q(真机读编码器;查看器读当前插补位形)和最新目标(拖拽时每周期都在变)
2. 推理一次:得到 K=4 条 16 步动作块 + 模式概率 ≈ 2–5 ms(估算)
3. 按"模式概率 − 切换代价"排序(§8.2)
4. 安全层依次检查候选的前 n=3 步(60 ms 的运动)+ 刹停段(§8.3)
第一个通过的 → 把这 3 步"提交"给插补器;记下 k_prev
(实际上 20 ms 后只走完第 1 步,第 2、3 步是已验证的"缓冲":
下一周期的新结果会覆盖它们;若下一周期推理超时或全部不安全,就沿缓冲 + 刹停段安全停下)
5. 全部不通过 → 进入刹停:按已验证的刹停轨迹减速停下,保持;下一周期继续推理
6. 到达判据:TCP 误差 < 1 mm(pose 另需 < 0.5°)且速度≈0 → 结束;
接近目标(< 5 mm)时可选做 1–3 次局部牛顿精修(solveTo 单步,不是全量 IK)
插补器在两个周期之间做平滑过渡(下一块与正在执行的块做时间集成/交叉淡入,ACT 的 temporal ensembling 思路),避免每 20 ms 一顿。
pathFine 同口径),外加关节限位。ik-glue.js
的"每帧碰撞守卫"保留,作为第二道保险。| 有 | 没有 |
|---|---|
traj_v2.onnx(fp16,约 7 MB)+
norm.json |
PRM 路网(collide.json.roadmap)、IK 候选大表 |
胶囊碰撞检查(现有
collideFree、包围球预筛、pair2d 表) |
solveDyn / routeRT / RRT / A* |
正运动学 fk / orient、局部牛顿精修
solveTo 单步 |
全量 IK 枚举 |
collide.json
指纹写进模型;不一致时前端拒绝运行并提示重训(不再回落旧规划器)。
超时不是算得慢。 模型每周期只要几毫秒,比原规划器快得多;"超时"指的是机械臂在规定时间内没走到目标,是决策错了,不是计算慢了。无老师闭环下有三种典型情形:
| 失效形态 | 现象 | 为什么更快的推理救不了 |
|---|---|---|
| 局部极小 / 活锁 | 目标在立柱背后,策略每周期都想"直着过去",安全层每周期都刹停,原地抖动 | 每周期都做同样的错误决定,算得再快也只是更快地重复 |
| 模式摇摆 | 这一周期选左绕、下一周期选右绕,来回切换,进度为零 | 同上 |
| 绕远 | 选了一条可行但很长的路,在时限内走不完 | 方向对了但路线差 |
原规划器不会这样,是因为它做全局搜索(PRM + A*)。去掉老师后,全局"想清楚往哪绕"这件事必须由模型自己承担。v2.1 用五个手段(全部在运行时不需要老师)把 near_column 要求提到 30/30:
验收相应改为(§9.2):near pos / near rt 都必须 30/30,且到达用时 ≤ 老师路径动画时长 × 1.3。
工业臂 / 研究臂的外部实时接口(伺服层)
| 产品 / 接口 | 周期 | 说明 |
|---|---|---|
| Franka FCI(libfranka) | 1 ms(1 kHz) | 关节位置/速度/力矩、笛卡尔位姿;每周期往返 + 计算必须 < 1 ms |
| Universal Robots e-Series RTDE | 2 ms(500 Hz) | servoj 默认 t = 0.002 |
| Universal Robots CB3 RTDE | 8 ms(125 Hz) | servoj 默认 t = 0.008 |
| ABB EGM | 4 ms(250 Hz),可设为 4 ms 的整数倍 | 控制滞后 10–20 ms(随机型) |
| KUKA RSI | 4 ms(Fast)或 12 ms(Normal) | |
| FANUC DPM | 约 8 ms | R-30iB 无 1–2 ms 通道 |
| MoveIt Servo(ROS 2) | 默认 10 ms(新版);旧版示例 34 ms | 常设为 ros2_control 更新频率的倒数(如 50 Hz → 20 ms) |
| 舵机(RC PWM) | 20 ms(50 Hz) 帧周期 | 数字舵机可到更高帧率 |
学习型策略的推理周期(策略层)
| 方法 | 策略频率 | 动作块 | 执行方式 |
|---|---|---|---|
| MπNets | 9 Hz | 单步 | 线性插值,1 kHz PD 跟踪 |
| Diffusion Policy | 10 Hz | 16 步 | 线性插值到 125 Hz 交给 UR5 |
| ELMP | 30 Hz(真机) | 单步 Δq | 每步 3 个航点线性插值给 Franka 位置控制器 |
| π0 | 50 Hz 动作,约每 0.5 s 推理一次 | 50 步(1 s) | 执行 25 步后重算 |
| ACT | 50 Hz | 100 步 | 时间集成 |
| DRP / IMPACT | 可跑 300 Hz(4090) | 10 步 | 闭环 |
结论:业界一律是"两层"结构——策略层 10–50 Hz(少数到 300 Hz)给出关节目标,伺服/插补层 125 Hz–1 kHz 负责平滑跟踪。没有人让神经网络直接跑 1 kHz 伺服环。
对本方案的评估:
requestAnimationFrame 是 60 Hz,50 Hz 也能稳定跑。dt(默认 20 ms)、提交步数
n(默认 3)、动作块长度 S(默认 16 = 320 ms)。训练数据按 dt = 20 ms
生成;若真机必须改到 10 ms(100 Hz),只需把动作块重采样,或用 dt = 10
ms 重造数据(约 5 小时)。| 集合 | 来源 |
|---|---|
| route_bench | tests/route_bench.cjs,60 例 |
| near_column_bench | tests/near_column_bench.cjs,30 例(pos / pose /
rt) |
| rt_drag_bench | tests/rt_drag_bench.cjs,12
例(改为模型在环逐周期运行) |
| held-out | §4.3 留出 2000 条 |
新增 tests/policy_bench.cjs:①现有规划器
②策略(关安全层)③策略 + 安全层(部署形态),输出对比表。
| 指标 | 要求 | 现状参考 |
|---|---|---|
| 实际执行的碰撞帧 | = 0 | rt_drag_bench 0 |
| 到达率 | route 60/60,near pos 30/30,near rt 30/30,held-out ≥ 98% | 60/60、30/30、30/30 |
| 到达用时 | ≤ 老师同任务路径动画时长 × 1.3 | — |
| 关节行程 | ≤ 现有规划器 × 1.10 | route 平均 467° |
| 冷启动(新目标→第一个动作) | < 10 ms | 首次全量 IK 最差约 2 s |
| 每周期耗时(推理+安全层)P99 | < 15 ms | 拖拽重规划 P99 约 321 ms |
| 刹停发生率 | < 2% 的周期 | — |
| 模式摇摆(≥3 次切换) | < 1% 的任务 | — |
| 策略单独(关安全层)碰撞率 | < 3%(参考:ELMP-APG 8.9%,DRP 10.16%) | — |
说明:v2 曾提议 near_column 允许 29/30,用户否决(2026-10-17)。为保证 30/30,部署侧加入子目标头、价值头、短前瞻和卡死换向(§8.5)。
ci27
姿态根枚举漏分支(姿态偏差约 97.5°)会进入预训练数据;APG
的姿态到达项可以部分纠正,必要时先修老师。ml/
gen/ gen_dataset.cjs sampler.cjs run_parallel.sh
data/ (不入库)shard_*.jsonl stats.json *.parquet norm.json
prep/ build_dataset.py
model/ policy_transformer.py
sim/ closed_loop.py # 闭环仿真(训练验证、挖错、APG 展开共用)
eval/ collide_torch.py # 可微胶囊距离,与 JS 对拍
apg/ apg_finetune.py
mining/ mine_round.py gate.py loop.sh
configs/ base.yaml apg.yaml
train.py export_onnx.py README.md
webapp/js/ik-policy.js # 闭环推理 + 模式粘滞 + 安全层 + 刹停
webapp/models/traj_v2.onnx traj_v2.norm.json
tests/policy_bench.cjs
| # | 内容 | 产出 | 在哪跑 |
|---|---|---|---|
| M1 | 数据生成器 + 时间参数化 + 1000 条试跑 | ml/gen/*、stats.json |
沙箱 |
| M2 | 可微胶囊距离(PyTorch)与 JS 对拍 | collide_torch.py,10 万位形 0 误差 |
沙箱(CPU 即可) |
| M3 | 5 万条老师数据 → 约 300 万闭环样本 | Parquet | 沙箱约 5 h 或用户机器 |
| M4 | 模型 + 训练工程 + 闭环仿真;小数据过拟合测试 | train.py、closed_loop.py |
沙箱 CPU 验证可跑 |
| M5 | 预训练(行为克隆) | checkpoint | 用户 GPU |
| M6 | APG 微调 + 挖错循环 3–6 轮 | 每轮 report.md | 用户 GPU |
| M7 | 导出 ONNX + ik-policy.js 闭环部署 + 安全层实测 +
policy_bench |
对比表 | 沙箱 + 浏览器 |
| M8 | 移除查看器里对
solveDyn/routeRT/路网的运行时依赖(保留在
ml/gen 离线使用) |
部署包瘦身 | 沙箱 |