PAPER DEEP DIVE
盲装配:只靠关节编码器完成轴孔插入、齿轮啮合与螺母攻丝
精密装配通常被当成视觉问题:孔在哪、零件在指间怎么转、间隙多大,都得由相机或力/扭矩传感器告诉策略。MIT 的这篇工作把外部传感全部掐断——策略每步只观测最近 0.6 秒的关节位置、关节速度、由正运动学算出的夹爪位姿与速度,以及自己上一步的动作;没有相机、没有力/扭矩传感器、没有触觉,也不知道孔位、零件尺寸与间隙大小。作者在三个接触密集的精密任务上检验本体感知究竟够不够:轴孔插入(训练时每侧间隙 1.0–1.5 mm,5 秒限时)、齿轮啮合(每个锚齿齿侧间隙 0.2–0.6 mm,10 秒)、螺母攻丝(M24–M42,螺纹侧面间隙 0.05–0.2 mm,15 秒)。训练完全在仿真里完成:PPO 跑 12,288 个并行 MuJoCo 世界,随机化零件形状、尺寸、间隙、孔位与抓取偏置,并用特权仿真状态给出辅助接触监督——去掉这项监督,三个任务分别需要 2.7 / 3.8 / 5.1 倍的环境步数。时序卷积把 30 步历史压成 32 维 latent,线性探针能从 latent 解出七种接触模式(准确率 61–73%,只看当前观测是 41–64%,随机基线 14%),把不同模式的 latent 互换会让动作整体改道(变化量是同模式互换的 1.3–3.0 倍)——说明策略是在做反应式接触搜索,而不是背一套固定螺旋图案;同样的起点,它入孔前中位只走 37 mm,乐观的脚本螺旋要走 95 mm。轴孔策略 zero-shot 迁到 Flexiv Rizon 4S 真机(50 Hz,无真实数据、无微调),237 次试验成功 173 次(73%),其中三个销完全在训练分布之外;对未见零件,盲策略也明显比参数匹配的 RGB 视觉策略稳(螺母尺寸外推 98.4% 对 1.6%,销的新形状 93.8–97.1% 对 40.1–62.7%)。为让这种规模的训练跑得起来,作者还开源了 mjfit:从任意平面轮廓程序化生成「间隙精确保持」的凸棱柱装配体,在 20 µm 级间隙上比 CoACD/V-HACD 凸分解与 MuJoCo 自带 SDF 碰撞既准又快一个数量级。结论很直接:每台机器人本来就自带高分辨率接触传感器——它自己的关节。
原文标题:Blind Precise Assembly: Proprioceptive Sim-to-Real Peg-in-Hole for Diverse Parts
作者:Antonia Bronars*、Younghyo Park*(* 共同一作)、Kushal Kedia、Pulkit Agrawal —— 麻省理工学院(MIT)
论文链接:https://arxiv.org/abs/2610.23849(arXiv:2610.23849v1 [cs.RO],2026 年 10 月 16 日,CC BY 4.0)
项目主页:https://younghyopark.me/blind-proprioceptive-assembly/(视频与可交互仿真)
代码状态:已开源。mjfit(精确凸碰撞几何的 MuJoCo 装配体生成器)在 github.com/younghyopark/mjfit,MIT 许可,pip install git+https://github.com/younghyopark/mjfit 即可安装,需要 Python 3.10+ 与 MuJoCo 3.3+。本解读的「方法 ↔ 源码」对应基于 2026-10-19 克隆的 commit eee986c;策略训练代码论文未一并公开,训练细节以正文与附录 A 为准。
真机平台:Flexiv Rizon 4S 七自由度臂 + Robotiq 2F-85 平行夹爪,50 Hz 部署,无真实世界数据、无微调。
一句话总结
只看 0.6 秒的关节位置、关节速度与自身上一动作(没有相机、没有力/扭矩传感器、没有触觉、不知道夹具位姿也不知道零件在指间的位姿),在 MuJoCo 的 12,288 个并行世界里纯仿真强化学习训练出的盲策略,学会了轴孔插入、齿轮啮合与螺母攻丝;轴孔策略 zero-shot 上真机,237 次试验成功 173 次(73%),其中三个销完全在训练分布之外。为喂饱这种训练,作者还开源了 mjfit:从任意平面轮廓程序化生成「间隙精确保持」的凸棱柱装配体,在 20 µm 级间隙上比凸分解与 MuJoCo 自带 SDF 碰撞既准又快一个数量级。
图 1(论文 Figure 1):盲插入。一个只在仿真里训练的策略,在真实世界上仅凭关节编码器与上一动作插入不同形状、不同尺寸的销。
研究背景与动机
施加在机器人身体任意位置的力都会经连杆传到关节,关节因此偏离「仅由指令决定」的运动,而编码器把这个偏差记录了下来 —— 所以每条机械臂、每条腿的关节都同时兼任接触传感器。腿式机器人已经把这个本体感知信号用到了极致:不看地形也能走、跑、上下楼梯,人形机器人靠它做全身动作跟踪。但这些场景有一个共同前提:接触是大而猛的,关节在记录到可测偏差之前往往已经明显柔顺变形。
机械臂上的精密装配处在完全相反的一端。机器人要在毫米甚至更小间隙里找到开口、把齿轮齿带进啮合、让螺纹咬住,靠的是轻接触 —— 它对关节的影响很容易被忽略。这篇论文要回答的就是这个「反端」问题:本体感知里到底有没有足够信息,支撑接触密集的精密装配?作者用三个任务把它做实:轴孔插入、齿轮啮合、螺母攻丝。在真实世界里,他们的插入策略插入了八个不同横截面、不同尺寸的销,其中三个在训练分布之外,每侧间隙 0.5–1.5 mm,237 次试验成功率 73%,而且策略没有被告知孔的位置、销在抓取中的位姿、零件尺寸或间隙大小。按作者的说法,这是这类演示的第一例。
已有的插入工作大体走三条路。经典轴孔装配把柔顺与搜索图案(螺旋、光栅、倾摆)组合起来,某些实现甚至不用力反馈,但它们都假设抓取已知、孔落在图案覆盖范围内,并且要为每个零件调参。学习型插入策略通常额外挂上力/扭矩传感、腕部视觉,或两者都用;软腕 + 腕部力/扭矩已能让策略容忍 10 mm 的孔位误差与未见过的销形状,指尖触觉也支撑过盲灵巧插入。还有一批工作观测关节状态,同时从感知或标定拿到一个误差几毫米的目标位姿。本文的策略只用本体感知:不给孔位、不给零件模型、不给力信号,孔要靠接触去找,而销在指间的位姿还是未知的。
要把这种鲁棒性训出来,需要上千个各不相同的装配体,而且每一个都必须在仿真里保住自己的毫米级间隙。这里撞上了 MuJoCo 的一个硬约束:它只按凸包做网格碰撞,所以凹的孔要么给 SDF,要么用凸块手工搭 —— 现有仿真基准正是用盒子手工搭孔的,这对随机形状无法扩展。自动替代方案在这些间隙上又不够用:近似凸分解(CoACD、V-HACD)容许的凹度是相对网格尺寸的,远大于一个装配体的间隙,于是壁材被留在孔里;网格 SDF 会漏接触、把孔口磨圆。论文的图 5 把这件事拍在了台面上 —— 同样的零件,三种分解方式,CoACD 与 V-HACD 都把材料放进了孔内,把螺母 0.1 mm 的螺纹间隙直接填满。
于是这篇论文的贡献是三件事叠起来的:一是纯仿真训练、只靠本体感知的盲策略,学会三个精密装配任务,并且用探针与 latent 替换实验证明它们是在对接触状态做反应式搜索,而不是背一套固定图案,同时证明它们对未见零件形状与尺寸的泛化远好于匹配的视觉策略;二是首个「只用本体感知做精密插入」的 sim-to-real 策略,zero-shot 上真机并能插训练分布外的销;三是 mjfit —— 面向 MuJoCo 的开源程序化装配体生成器(销与孔、螺纹、齿轮),碰撞几何是精确凸块,配套一个对照解析真值的基准,在这些间隙上比凸分解与 MuJoCo 的 SDF 碰撞更准也更快。
预备知识:观测、控制器与 MuJoCo 的碰撞设置
观测与动作。策略每步观测 33 个量:7 个关节位置、7 个关节速度、由正向运动学从它们算出的夹爪位姿与速度(12 个),以及上一动作(7 个)。螺母策略把夹爪姿态编码为旋转矩阵的两列而不是欧拉角,因此是 36 维 —— 因为攻丝时腕关节要转过半圈,欧拉角会奇异。动作是 7 个关节位置增量,按任务的动作尺度缩放后加到实测关节位置上,再由关节阻抗控制器跟踪:$\tau=k_p(q_d-q)-k_d\dot{q}$。销任务用 $k_p/k_d=80/20$、动作尺度 0.02 rad;齿轮与螺母用 $40/20$、动作尺度 0.04 rad(螺母的腕关节 0.2 rad)。物理以 1 kHz 运行,策略 50 Hz。臂模型的电枢惯量、阻尼与摩擦都是从真实机器测量辨识出来的,这一点是 zero-shot 迁移能成立的前提之一。
时序编码。一个时序卷积编码器把最近 30 步(0.6 s)的观测压成 32 维 latent $z_t$;一个 MLP(256, 256, 128 单元)把 $z_t$ 与当前观测 $o_t$ 一起映射到关节目标。actor 关于过去的全部知识都必须经过 $z_t$ 这个瓶颈 —— 这正是后面探针实验能成立的原因:如果 $z_t$ 里没有接触状态,策略就不可能在用它。
仿真设置。基准里所有场景都用 1 ms 步长、implicit-fast 积分器、Newton 求解器、$\mathrm{solref}=(2\,\mathrm{ms},1)$、$\mathrm{solimp}=(0.99,0.999,0.001)$、摩擦 $\mu=1$、零 margin。基线拿到的是精确水密的板网格(圆按 1,024 段离散,矢高 0.04 µm),真值用解析圆,所以 mjfit 自己的弦误差也被计入 —— 它没有享受任何记账上的优待。销始终是一个精确的 MuJoCo 原生 primitive,因此方法之间的所有差别都来自孔那一侧。
方法详解
一、mjfit:把「间隙」当成一等公民的凸几何生成器
mjfit 把基准里那些「用盒子手工搭孔」的做法自动化了,并推广到任意轮廓。给定一个孔的平面轮廓(可以带 islands,例如连接器的针脚),它直接吐出一个可仿真的 MJCF 模型,其中每一个接触面都是 MuJoCo 原生 primitive 或一个凸棱柱。构造分三步:孔周围的板被切成凸多边形并拉伸成棱柱;销就是「孔轮廓向内偏移一个间隙」,于是每条销边到对应的孔边都精确等于间隙;islands 变成空心销里的 pocket。同一套思路的配套生成器负责螺栓–螺母副与直齿轮,再加一个采样器随机抽轮廓、islands 与尺寸 —— 于是一次训练里可以装下上千个互不相同的装配体。
图 2(论文 Figure 4):mjfit 生成的装配体,每种颜色是碰撞几何的一个凸块。标注给出凸块数(pcs)与零件处于接触状态时每物理步的 CPU 时间 —— 一个销和它的孔只需要几十个凸块。
向内偏移是斜接(mitred)的,不是简单平移。源码里 offset_inward 把每条边沿其法向移动距离 $d$,角点用斜接求交,因此输出与输入有相同的顶点数与拓扑,且每条输出边到对应输入边精确等于 $d$:
$$\mathbf{v}'_i=\mathbf{v}_i+d\,\mathbf{n}_{i-1}+t\,\mathbf{d}_{i-1},\qquad \begin{bmatrix}\mathbf{d}_{i-1} & -\mathbf{d}_{i}\end{bmatrix}\begin{bmatrix}t\\ s\end{bmatrix}=d\,(\mathbf{n}_{i}-\mathbf{n}_{i-1})$$
其中 $\mathbf{d}_i$ 是第 $i$ 条边的单位方向、$\mathbf{n}_i$ 是其内法向。两条边共线时行列式退化,直接取 $\mathbf{v}_i+d\,\mathbf{n}_{i-1}$。这一步的工程价值在于「精确」二字是有保证的:偏移量超过局部特征尺寸会翻边、会让轮廓自交,offset_is_valid 专门检测这两种情况并抛错,而不是静默生成一个几何错误的销。
# src/mjfit/_polygon.py — offset_inward(斜接向内偏移)
for i in range(len(poly)):
d_prev, d_curr = dirs[i - 1], dirs[i]
a = np.column_stack([d_prev, -d_curr])
b = distance * (inward[i] - inward[i - 1])
if abs(np.linalg.det(a)) < TOL:
out[i] = poly[i] + distance * inward[i - 1] # collinear edges
else:
t, _ = np.linalg.solve(a, b)
out[i] = poly[i] + distance * inward[i - 1] + t * d_prev
销与孔的配对在 _peg.py 里就是「孔轮廓向内偏移一个间隙」,islands 则向外偏移同样的间隙变成 pocket,并且逐项校验:island 必须在孔内、pocket 必须落在销内、两个 pocket 之间必须不相交(否则两个 island 的间距小于两倍间隙)。这些 _check 报错的措辞值得留意 —— 它们直接把「间隙对这个孔太大了」翻译成几何语言:
# src/mjfit/_peg.py — 销 = 孔向内偏移间隙;islands → pockets
hole_poly = source
insert = pg.offset_inward(hole_poly, c)
_check(pg.offset_is_valid(hole_poly, insert),
f"clearance {clearance:g} m is too large for this hole: offsetting it inward "
"by the clearance leaves no valid peg.")
for k, island in enumerate(isl):
_check(pg.contains(hole_poly, island), f"Island {k} is not inside the hole.")
pocket = pg.offset_outward(island, c)
_check(pg.offset_is_valid(island, pocket), ...)
_check(pg.contains(insert, pocket), ...)
for j, other in enumerate(pockets):
_check(pg.disjoint(pocket, other),
f"Islands {j} and {k} are closer than twice the clearance.")
板是「每条孔边一个凸楔」。radial_wedges 要求孔对其顶点均值是星形的,然后每条孔边生成一个楔形:边界由这条孔边、从均值穿过两端点的两条射线、以及板边界(含落在两条射线之间的板角)围成。这比通用多边形三角剖分给出的块数少得多,也解释了图 2 里「一个销加一个孔只要几十块」的量级 —— 而块数直接决定每步碰撞开销。
曲线用外接多边形,误差方向被刻意选定。圆与圆弧被离散成外接(circumscribed)正多边形,半径 $R$ 的圆用 $n$ 边时顶点落在
$$r_n=\frac{R}{\cos(\pi/n)}$$
上,于是壁永远不会侵入真实孔内 —— 这与用盒子环内接圆的做法(会侵入)方向相反。唯一的误差是角上多出来的余隙,径向间隙为 $c$ 的 $n$ 边圆孔为
$$e_n=c\left(\frac{1}{\cos(\pi/n)}-1\right)$$
边数由用户给的误差上限反解:$n=\max\!\left(6,\left\lceil \pi/\arccos\!\frac{R}{R+\varepsilon}\right\rceil\right)$。这个「只朝多给余量的方向出错」的设计选择,配合「构造本身知道哪块区域必须留空,所以用户直接指定间隙,而不是去调一个凹度容差再检查结果」,是 mjfit 与近似凸分解最本质的区别。
# src/mjfit/shapes.py — 外接多边形:边数与半径
def _sides(radius: float, max_error: float, minimum: int = 6) -> int:
"""Fewest sides whose circumscribed polygon stays within max_error."""
if not max_error > 0:
raise ValueError(f"max_error must be positive, got {max_error!r}.")
half_angle = math.acos(radius / (radius + max_error))
return max(minimum, math.ceil(math.pi / half_angle))
def circle(radius, *, n=None, max_error=MAX_ERROR, center=(0.0, 0.0), rotate=0.0):
"""Regular n-gon circumscribing a circle (first vertex on +x)."""
n = _sides(radius, max_error) if n is None else int(n)
a = np.linspace(0.0, 2 * np.pi, n, endpoint=False)
r = radius / math.cos(math.pi / n)
return _place(np.column_stack([r * np.cos(a), r * np.sin(a)]), center, rotate)
flowchart TD A["Planar outline of the hole
(optional islands: connector pins)"] --> B["Curves tessellated by
CIRCUMSCRIBED polygon
r = R / cos(pi/n)"] B --> C["Plate: radial_wedges
one convex wedge per hole edge
star-shaped from vertex mean"] B --> D["Peg: offset_inward by clearance c
mitred, same vertex count
every peg edge exactly c from its hole edge"] B --> E["Islands: offset_outward by c
become pockets in a hollow peg"] C --> F["Extrude to convex prisms"] D --> F E --> F F --> G{"offset_is_valid /
contains / disjoint checks"} G -->|fail| H["Raise: clearance too large,
islands closer than 2c"] G -->|pass| I["Ready-to-simulate MJCF
every contact face is a MuJoCo
primitive or convex prism"] I --> J["Sampler: random outlines,
islands, dimensions"] J --> K["12,288 parallel Warp worlds,
each holding a different assembly"]
图 3:根据论文 2.2 节与 mjfit 源码(_peg.py / _polygon.py / shapes.py)绘制的生成流程。关键点是「误差只朝多给余量的方向出」,以及所有几何校验都在生成时抛错,而不是留到仿真里表现为莫名的卡死。
二、碰撞基准:用有解析答案的被动探针量「间隙保真度」
论文没有停在「我们的几何更准」这种定性说法上,而是给了一个对照解析真值的基准。对照对象是给 MuJoCo 一个凹孔的三条自动路线:CoACD、V-HACD、MuJoCo 原生 mesh SDF,每条都把它自己的粒度设置扫一遍,画出速度–精度 Pareto 前沿。测试体是 16 mm 的圆孔与方孔(15 mm 厚的板),径向间隙 $c$ 从 200 µm 一路收到 20 µm —— 在 $c=20\,\mu\mathrm{m}$ 处相对间隙 $2c/D=0.0025$;螺纹用 M10 × 1.5 的螺栓螺母副,翼面间隙 20 与 100 µm。误差以壁面位置的微米数计,负值表示「幻影材料提前挡住了销」。
五个被动探针各有精确答案:壁面偏移(从孔轴发出 720 个角度 × 11 个高度的射线,不跑解算器,真值是解析轮廓上的壁)、S0 接触起始(把对齐的销放在已知间隙上,只跑碰撞,真值是「间隙为 0 时出现接触」)、S1 落销(居中的自由销从 1 mm 高落下,$c$ 从 +1 mm 扫到 −500 µm,真值是「当且仅当 $c>0$ 时零壁接触通过」)、S2 横向余隙(平面滑动,24 个方向各推 0.1 N,真值是可行平移集的支撑)、S3 倾摆余隙(滑动加一个铰,1.5 mN·m 扭矩,真值是两面都能容下的最大倾角)、S4 偏摆余隙(滑动加一个竖直铰,方孔,真值 $\arcsin\!\big(a/(s\sqrt{2})\big)-\pi/4$)。这里有一条很诚实的负面结果:在 2 ms 接触时间常数下做无摩擦落销,最高 20 µm 超尺寸的销对所有方法都能滑进去,包括精确几何 —— 所以 S1 分辨不了 20 µm 以下的几何误差,必须靠余隙类探针。把测量方法的分辨极限写清楚,是这个基准可信的原因。
图 4(论文 Figure 5):同样的零件、三种分解,每种颜色一个凸块(Ø16 mm 板;M10 螺母剖开)。mjfit 只会朝「多余隙」的方向出错;CoACD 与 V-HACD 把材料放进了孔内,并把螺母 0.1 mm 的螺纹间隙填满。
图 5(论文 Figure 6):16 mm 圆销、100 µm 间隙下的速度–精度权衡。(a) CPU,一个环境一个线程;(b) GPU,256 个 MuJoCo Warp 世界的单环境步时间,误差也在 Warp 上测。每条线是一种方法在其全部设置上的 Pareto 前沿,左下更好;空心标记表示「把间隙填掉了」(虚线)。
结果汇总在论文 Table 4(1 ms 步长、销压着壁时的实时率;GPU 数字是一块 RTX 5090 上 512 个 MuJoCo Warp 世界的总和;最后一列是 $c=20\,\mu\mathrm{m}$ 时最差的稳定误差):
| 碰撞表示 | CPU(1 线程)实时率 | GPU(512 worlds)实时率 | $c=20\,\mu$m 时的误差 |
|---|---|---|---|
mjfit,方孔 | 93× | 970× | 0.2 µm |
mjfit,圆孔 7–32 边 | 82–29× | 1120–1070× | $\leq$ 2.6 µm |
mjfit,圆孔 63–281 边 | 16–4.9× | 875–442× | $\leq$ 0.4 µm |
| Mesh SDF,octree 深度 5–8 | 2.9–2.2× | 590–840× | 填满,或 23–79 µm |
| CoACD,阈值 0.01(839 个凸包) | 1.8× | 254× | 填满 |
| 其他 CoACD / V-HACD 设置 | 3.3–70× | 680–1900× | 填满 |
表 1:论文 Table 4 的碰撞基准。读法:在 CPU 上 mjfit 与 mesh SDF 精度相当或更好的同时快一个数量级(93× 对 2.9×);在 GPU 上它的速度–精度权衡最好。所有凸分解设置的误差列都写着「填满」—— 它们把 20 µm 的间隙本身吃掉了,这时再谈实时率没有意义。
这些误差不只是数字,它改变结论:一个居中且对齐的销,从 1 mm 高处落到每种基线的默认板上,都会停在孔口或者卡住,而在 mjfit 的板上干净地落下去(论文 Figure 6c)。每个装配体只有几十个凸块,因此 12,288 个并行训练世界里的每一个都能装一个不同的装配体 —— 这一句是「训练分布多样性」与「碰撞几何精确性」能同时成立的原因。
三、三个任务与它们的随机化范围
三个任务共用一个设定:七自由度臂配平行夹爪,夹着零件,要把它与一个几乎可以放在工作空间任意位置、而且可以倾斜的夹具装配起来(论文 Figure 3)。零件几何、它在抓取中的位姿、接触属性都被随机化,且策略都观测不到。每个回合都从「零件已经碰到夹具但错位」开始,成功判据是「完全装配好」。这就要求策略同时做两件事:通过接触搜索对齐,然后完成装配 —— 而它唯一的依据是关节位置反馈。
图 6(论文 Figure 2):三个任务。(a–c) 每个任务的起始状态(淡出)与同一抓取下的成功状态:销入座、齿轮坐到轴上并与两个 anchor 齿轮啮合、螺母转到螺纹咬住。(d–f) mjfit 生成、用于训练的 stadium 销、齿轮组与螺母螺栓,按真实比例绘制。
| 任务 | 零件与间隙 | 起始状态 | 成功判据 / 回合上限 |
|---|---|---|---|
| 轴孔插入 | stadium 棱柱销,横截面尺寸、长宽比、质量、长度均随机;每侧间隙 1.0–1.5 mm(部署策略 0.5–1.5 mm) | 销已触到板面,离孔心中位 1 cm(部署 2 cm),倾角远超间隙所能容纳 | 销底面完全入座 / 5 s |
| 齿轮啮合 | 渐开线直齿轮,模数 2.375–3.125 mm、16–24 齿;每个 anchor 背隙 0.4–0.6 mm,孔径间隙 0.75–1.0 mm | 齿轮靠在轴端但偏离轴心,齿与 anchor 的相位不对 | 孔包住轴且齿轮距轴肩 1 mm 内(只有啮合才可能达到)/ 10 s |
| 螺母攻丝 | ISO 米制螺母螺栓 M24–M42,粗牙与细牙;翼面间隙 0.1–0.2 mm(全范围 0.05–0.2 mm) | 螺母搁在螺栓尖端,偏心且倾斜,还差 87.5–142.5° 转角才咬住螺纹 | 螺纹咬住后再转 1/4 圈,且螺母在螺栓轴 1 mm 内 / 15 s |
表 2:三个任务的定义(论文 2.1 节与附录 A.1)。夹具中心相对机器人基座在 $x$ 0.54–0.76 m、$y$ −0.29–0.17 m、$z$ −0.20–0.29 m 内随机,姿态 roll/pitch/yaw ±5°(部署策略 ±10°);抓取沿指垫 ±5.5 mm、绕指轴倾 ±10°(部署 ±7 mm / ±20°);板摩擦 0.5–2.0、接触时间常数 3.5–7.1 ms、指摩擦尺度 1.41–2.0、夹持力上限尺度 1.41–2.83,均按对数均匀采样。几何每个 world 抽一次,位姿与接触参数每次 reset 抽;不加观测噪声。
图 7(论文 Figure 3):训练用的夹具位姿与抓取分布。齿轮与螺栓夹具覆盖销任务的同一范围 —— 三个任务面对的位置不确定性是同一量级的。
奖励是稀疏的:成功给一次 bonus,中间里程碑各给一次性 bonus。销的里程碑是「第一次被孔口捕获」与成功(各 +1);齿轮是「第一次捕获轴」「与每个 anchor 第一次啮合」与成功;螺母是「入座」「捕获」「每新增一段转角」与成功。零件远离夹具时回合提前结束,螺母脱手时也结束。
四、PPO 配方与非对称评论家
训练用 PPO,超参是这一类大规模并行仿真的标准配置但每一项都写清楚了:12,288 个 world、32 步 rollout、每次更新 5 个 epoch × 20 个 minibatch(齿轮与螺母 24 个)、固定学习率 $3\times10^{-4}$、裁剪 $\varepsilon=0.2$、$\gamma=0.98$、$\lambda=0.95$、熵系数 0.003、值损失系数 1(带裁剪)、梯度范数裁到 1、初始动作标准差 0.5。裁剪目标与优势估计分别是
$$L^{\mathrm{CLIP}}(\theta)=\mathbb{E}_t\Big[\min\big(r_t(\theta)\hat{A}_t,\ \mathrm{clip}(r_t(\theta),1-\varepsilon,1+\varepsilon)\hat{A}_t\big)\Big],\qquad \hat{A}_t=\sum_{l\geq 0}(\gamma\lambda)^{l}\delta_{t+l}$$
加速稀疏奖励学习的第一个手段是非对称评论家:critic 额外看到零件相对夹具的位姿、真实接触标签,螺母任务还看到螺纹几何,因此输入维度是 240(销)/ 434(齿轮)/ 317(螺母),而 actor 只有 33 或 36 维。特权信息只进 critic,不进 actor,这是标准的 asymmetric actor-critic 做法。部署用的销策略还多了两项:一个分阶段引入的安全惩罚(先在无限制下把任务学会,再惩罚超过硬件极限六分之一的关节速度与指令扭矩),以及探索退火 —— 学习率自适应到目标 KL 0.01。
五、接触监督:把看不见的接触状态压进 latent,但不喂给 actor
盲策略必须从「臂怎么动」反推接触。为了给这个反推一个稠密的训练信号,作者用它观测不到的接触状态去监督 actor 的 latent。每一步,仿真器在零件与夹具的配对特征上采样点并打标签:free(自由)、touching but misaligned(接触但未对齐)、aligned(已对齐)。销任务标底边上的 64 个点:高于板面 1 mm 以上为 free,落在孔口或板面 1 mm 内为 contact,进入开口内为 inside。齿轮任务标轴缘 64 点(free / 在齿轮上 / 在孔内)与齿顶 64 点(free / 在 anchor 上 / 已啮合)。螺母任务标孔缘 64 点(free / 在螺栓尖端 / 绕着螺栓 / 被螺纹咬住,咬住判定带宽 0.29 个螺距,M30 × 3.5 时是 1 mm)。
一个小的接触解码器(两层 128 单元)从 $z_t$ 预测这些标签,它的类加权交叉熵被加进 PPO 损失:
$$\mathcal{L}_{\mathrm{contact}}=-\frac{1}{64}\sum_{p=1}^{64}\sum_{k} w_k\,\mathbf{1}\!\left[c_{t,p}=k\right]\log \hat{p}_{t,p,k},\qquad (w_{\mathrm{free}},w_{\mathrm{contact}},w_{\mathrm{inside}})=(0.25,\,3.0,\,2.0)$$
类权重的取法说明作者清楚这里的类别不平衡:绝大多数采样点在绝大多数时间里都是 free,真正决定动作的是少数接触点与咬合点,所以 free 被压到 0.25、contact 抬到 3.0。这个损失的梯度只训练编码器,预测值 $\hat{c}_t$ 永远不进入策略 —— 所以没有任何特权信息到达 actor,部署时解码器直接丢掉。
图 8(论文 Figure 7):策略架构。时序卷积把最近 $H=30$ 步本体感知观测 $o_t$(关节位置 $q$、速度 $\dot{q}$、夹爪位姿 $x$ 与速度 $\dot{x}$、上一动作 $a_{t-1}$)压成 latent $z_t$,MLP 把 $z_t$ 与 $o_t$ 映射到关节目标 $q_d$,交给关节阻抗控制器。训练时接触解码器(琥珀色)从 $z_t$ 预测接触状态 $\hat{c}_t$,它与仿真器标签 $c_t$ 的交叉熵训练编码器,但 $\hat{c}_t$ 从不进入策略。
flowchart LR
subgraph TRAIN["Training only (dropped at deployment)"]
P["Privileged simulator state
part pose relative to fixture
64-point contact labels c_t"]
DEC["Contact decoder
2 x 128 units"]
LOSS["Class-weighted cross-entropy
w = 0.25 / 3.0 / 2.0
gradient trains the ENCODER only"]
CRIT["Asymmetric critic
inputs: 240 peg / 434 gear / 317 nut"]
end
O["Observation o_t (33 values)
q, q_dot, gripper pose x and twist,
previous action a_t-1"] --> ENC["Temporal convolution
last H = 30 steps (0.6 s)"]
ENC --> Z["Latent z_t (32-dim)
the only path from past to actor"]
Z --> MLP["MLP 256 - 256 - 128"]
O --> MLP
MLP --> ACT["7 joint-position increments
scaled by action scale"]
ACT --> IMP["Joint impedance controller
tau = kp (q_d - q) - kd q_dot
physics 1 kHz, policy 50 Hz"]
IMP --> ROBOT["Arm model with identified
armature, damping, friction"]
Z --> DEC
P --> DEC
DEC --> LOSS
P --> CRIT
ROBOT --> P
ACT -->|"50 Hz, encoders only
no camera / F-T / tactile"| DEPLOY["Flexiv Rizon 4S + Robotiq 2F-85
frozen policy, zero-shot"]
图 9:按论文 2.3 节、附录 A.1 与 Figure 7 绘制的训练–部署数据流。要点是两条特权通道(非对称评论家、接触解码器)都只在训练期存在,部署时 actor 的输入仍然只有编码器导出的 33 个量。
第二个加速手段的效果是可量化的(论文 Figure 14):去掉接触损失,三个任务仍然都学得会,但达到 90% 训练成功率所需的环境步数分别是 2.7 倍(销)、3.8 倍(齿轮)、5.1 倍(螺母);无监督的销策略在 4.86 亿步后到 97.8%,有监督的在 2.42 亿步就过了 99%。
图 10(论文 Figure 14):接触监督加速学习。蓝色是带接触损失的盲 study 策略,灰色是同一策略去掉接触损失后的训练成功率曲线 —— 任务越精细(螺母最甚),这条辅助损失的收益越大。
六、视觉对照策略与表征分析方法
为了把「传感模态」这一个变量单独隔离出来,视觉对照策略与盲策略在任务、reset 分布、随机化、奖励、动作空间与成功判据上完全一致,唯一区别是输入:一个刚性装在腕部的相机渲染 64 × 64 的 RGB 图像(拍到手持零件与夹具),视觉策略只看图像,同样取 0.6 s 历史,经一个紧凑 CNN。两者都带 30 步历史,因此比较的不是「有没有记忆」,而是「记忆的内容来自关节还是来自像素」。
表征分析用两把工具。线性探针:在仿真里 rollout 策略,用特权零件位姿给每个状态打上该任务的 7 个模式之一,然后拟合一个从 $z_t$ 预测模式的线性探针 $\hat{m}_t=\operatorname*{arg\,max}_k\left(W^\top z_t+b\right)_k$。销的 7 个模式是 lifted、beside the plate、searching far、searching near(以距开口 5 mm 分界)、partly engaged、inside moving、inside stuck(已在孔内但 0.2 s 内推进不足 0.5 mm);齿轮与螺母按各自任务阶段定义类似模式。探针在偶数编号的 world 上训练、奇数 world 上测试:销用部署策略在 1,536 个 world 上 rollout 得 115 万个状态,齿轮与螺母用全范围策略得 13.3 万与 8.5 万个状态。latent 替换:保留一个状态自己的当前观测,把它的 $z_t$ 换成另一个模式的状态的 $z_t$,度量动作相对「同模式内互换」的变化倍数。探针只能说明 latent 里含有模式信息,替换才说明策略真的在用它。
实验结果
1. 本体感知确实够用,但更慢
三个任务在分布内几何上都达到接近完美的成功率:盲销策略 99.4%,视觉策略 97.2%;齿轮与螺母的盲策略分别是 >99.9% 与 99.7%(论文 Table 7 的「In dist.」列)。也就是说,仅凭关节历史就足以找到开口、把齿带进啮合、让螺纹咬住。
图 11(论文 Figure 8):仅本体感知就足以学会三个任务。盲策略(只感知自己的关节)达到与带腕部相机的视觉策略同样的近满成功率。曲线是两个训练种子的均值。
代价在速度上。销任务里盲策略必须通过接触去找开口,路径更绕、入座更晚(论文 Figure 9a, b)。附录 C 的 Table 5 把这笔账算得很细:
| 分布内行为指标(销插入) | 盲本体感知(本文) | 视觉(腕部 RGB) |
|---|---|---|
| 成功率(%) | 99.4 | 97.2 |
| 入座时间中位数(s) | 0.80 | 0.44 |
| 每分钟插入次数 | 65 | 82 |
| 入座前横向移动(mm) | 37 | 20 |
| 部分啮合状态时长(s) | 0.38 | 0.22 |
| 部分啮合 / 入座时倾角(°) | 6.7 / 1.1 | 5.2 / 1.1 |
表 3:论文 Table 5 的分布内行为对比。成功率、时间、速率来自每个种子 8,192 个回合并对两个种子取平均;移动距离、啮合与倾角来自 4,096 个配对起点中两个种子 1 策略都成功的 3,964 个。除注明外均为中位数;「每分钟插入次数」把每次尝试都计入,失败按其完整 5 s 计。起点离孔心中位 10 mm。盲策略在 99% 的配对起点上走得比视觉策略更远。
但在另外两个任务上差距明显缩小,齿轮甚至反转:盲齿轮策略入座中位 0.58 s,视觉策略 0.64 s,只在两者都成功的 8,059 个起点中的 43% 上更慢;盲螺母策略 0.76 s 对 0.64 s,在 8,139 个共同成功起点中的 98% 上更慢,中位只慢 0.10 s。作者给的解释很物理:被夹持的零件挡住了腕部相机对配对零件的视线,所以视觉策略在齿轮与螺母上也不得不搜索。这提示「盲的慢多少」高度依赖任务里遮挡有多严重。
2. 盲而不愚:latent 里确实编码了接触模式,而且策略真的在用
探针结果一致地指向同一个结论。三个任务的平衡准确率(7 个模式,随机基线 14%)分别是:销 70%(从当前观测单独预测 56%,从随机初始化的编码器 33%)、齿轮 61%(41% / 29%)、螺母 73%(64% / 46%)。历史 latent 全面优于当前观测,说明信息主要来自 0.6 s 的时间窗而不是单帧。销的历史 latent 对 lifted、moving、stuck 三类召回率 84–90%;它的典型错误是把「远搜索」解成「近搜索」19%、把「近搜索」解成「远搜索」26% —— 这两类需要的动作本来就相似(都是继续扫),混淆的代价小。
| 任务 | 从历史 latent $z_t$ | 从当前观测 $o_t$ | 从随机初始化编码器 | 随机基线 |
|---|---|---|---|---|
| 轴孔插入(部署策略,115 万状态) | 70% | 56% | 33% | 14% |
| 齿轮啮合(全范围策略,13.3 万状态) | 61% | 41% | 29% | 14% |
| 螺母攻丝(全范围策略,8.5 万状态) | 73% | 64% | 46% | 14% |
表 4:论文附录 C「Probe details」的线性探针平衡准确率。探针只在仿真里拟合;偶数 world 训练、奇数 world 测试。
图 12(论文 Figure 10):盲策略的关节历史编码了任务模式,仿真与真机都如此。只在仿真里拟合的线性探针从每个策略的历史 latent 读模式;每个矩阵给出混淆率(%),旁边是一个起始状态在每一步的解码结果(T:真实模式,D:解码模式)。三个任务上探针都干净地区分了需要不同动作的模式,例如 lifted、engaged、stuck。(a) 在真机上,它解码出的销插入模式序列与仿真一致。
latent 替换给出了因果一侧的证据:把搜索状态与已入孔状态的 latent 互换,动作变化是同模式内互换的 1.4–1.9 倍;而把「近搜索」与「远搜索」互换只有 0.99–1.11 倍。齿轮是 1.3–1.6 倍(跨「搜索 ↔ 已啮合」)对 0.97–1.04 倍(近 ↔ 远),螺母是 1.4–3.0 倍对 0.94–1.18 倍。换句话说,latent 编码的不是「所有状态差别」,而是恰好那些需要换一套动作的差别 —— 这正是「反应式搜索」而非「固定图案」的定义。
图 13(论文 Figure 15):latent 替换测试。每个状态保留自己的当前观测,但接收另一个模式的 $z_t$;每格是相对于「在接收状态自己模式内互换」的平均动作变化量。跨模式的对角块明显更热,同模式(近 ↔ 远)接近 1。
反应式搜索还让盲装配更省路程。固定图案不管臂感觉到什么都扫同一条路,而反应式策略能用接触获得的信息(例如销被孔口挂住)来引导搜索。作者在销插入上对照了工业装配里标准的脚本化盲基线 —— 螺旋搜索:从同样的起点出发,盲策略入座前中位只走 37 mm,而一个「乐观版」螺旋(起点与孔口齐平、还被告知销的朝向与最佳起始方向)要走 95 mm。
真机上的探针同样成立,但暴露了 sim-to-real 的缝隙:在 peg I3 上再跑 30 次试验,用记录的观测重算动作,与记录的动作吻合到 $2\times10^{-5}$ 以内(说明部署管线本身没有偏差);成功试验结束时,由关节编码器与计划抓取估出的销位姿离真正入座位姿中位差 6.6 mm(10–90 分位 2.6–17.4 mm),因为销在指间滑动和转动,这些估计只把 3% 的状态判为「完全在孔内」。探针把 62% 的 inside 状态标对(仿真中同样起点是 100%),并把 24 次成功试验中的 17 次的末态标为 inside。图 12a 里展示的那个起始状态,仿真中真实模式与解码模式在 74% 的步上一致(30 个起点的中位数是 65%)。
3. 对未见零件,盲策略的泛化远好于视觉策略
这是全文最有分量的一组对照。评测方式是每次只把一个零件属性推到训练范围之外,其余范围保持 study 值:更紧的间隙、长宽比/齿高/螺纹深度的温和与强烈变化、尺寸在训练范围两侧的温和与极端变化、以及新形状(销是随机凸轮廓、齿轮是随机齿形四边形、螺母是 5–8 边的随机凸轮廓)。
| 任务 / 传感 | 分布内 | 更紧间隙 | 比例·温和 | 比例·强烈 | 尺寸·温和 | 尺寸·极端 | 新形状 |
|---|---|---|---|---|---|---|---|
| 轴孔插入 · 本体感知(盲) | 99.4 | 93.8 | 97.1 | 93.3 | 97.1 | 91.9 | 36.2 |
| 轴孔插入 · RGB(视觉) | 97.2 | 54.1 | 62.7 | 40.1 | 57.7 | 16.4 | 3.9 |
| 齿轮啮合 · 本体感知(盲) | >99.9 | >99.9 | >99.9 | >99.9 | >99.9 | >99.9 | >99.9 |
| 齿轮啮合 · RGB(视觉) | 98.4 | 98.0 | 98.6 | 98.5 | 96.5 | 90.2 | 87.9 |
| 螺母攻丝 · 本体感知(盲) | 99.7 | 99.2 | 99.2 | 98.2 | 98.8 | 98.4 | 99.7 |
| 螺母攻丝 · RGB(视觉) | 99.7 | 98.7 | 99.1 | 98.8 | 25.5 | 1.6 | 57.1 |
表 5:论文 Table 7,未见零件上的成功率(%),对应 Figure 11 的每一根柱子。销插入是两个训练种子的均值,齿轮与螺母是一个种子;两种策略都带 30 步历史。最刺眼的两格是螺母的尺寸列(视觉 25.5% 与 1.6%,盲 98.8% 与 98.4%)和销的新形状列(视觉 3.9%,盲 36.2%)。
解释很直接:视觉策略学的是对齐视觉特征,而这些特征在 held-out 装配体上可能根本不出现;盲策略学的是搜索策略,它只通过接触依赖零件,因此可迁移得多。要注意的是,盲策略在「新形状」上也不是免疫的 —— 36.2% 对 99.4% 同样是断崖,只是比 3.9% 高一个量级;这些随机凸销的面积中位数只有匹配 stadium 的 53%。全范围策略在分布内的未见实例上仍然可靠:确定性动作下,齿轮策略在 4,096 组未见齿轮组的 8,192 个回合上成功 98%,螺母策略在 512 组未见螺母螺栓对的 8,192 个回合上成功 93%。
4. Zero-shot 上真机:237 次试验成功 173 次
冻结的盲策略部署在 Flexiv Rizon 4S + Robotiq 2F-85 上,50 Hz,没有真实世界数据、没有微调,输入只有编码器导出的关节与夹爪状态 —— 没有相机、没有力/扭矩传感器、没有孔位姿进入策略。部署用的是在「随机凸、光滑、混合横截面 + 一个手柄」下训练的那一版策略。测试八个 3D 打印销:五个分布内,三个来自训练分布之外(更紧的 0.5 mm 每侧间隙、更大的横截面、更高的手柄)。每次试验的起点从仿真 reset 分布里抽,销以随机位置与倾斜被夹住、并触到孔附近的夹具;操作员在销入座时判成功。
| 销 | 类别 | 几何与间隙 | 成功率 |
|---|---|---|---|
| I1–I5 | 分布内 | 从部署策略训练分布抽出的横截面(多边形、光滑、混合),每侧间隙 1.11–1.49 mm,80 × 44 mm stadium 手柄高 40 mm | 各 73–80% |
| C | 分布外:更紧间隙 | 多边形销,每侧间隙 0.5 mm(训练下限是 1.0 mm 量级) | 66% |
| L | 分布外:更大横截面 | 把训练轮廓放大 1.28 × 1.09,孔 101 × 37 mm | 66% |
| H | 分布外:更高手柄 | 混合轮廓,手柄高 70 mm(其余 40 mm) | 72% |
| 合计 | 八个销重 147–164 g,所有孔深 20 mm;每销 30 个计划 reset,每个 reset 只按第一次给出裁决的尝试计(操作员判成功/失败,或 20 s 到时算失败) | 173 / 237 = 73% | |
表 6:真机结果(论文 3.4 节、Figure 12 与附录 C「Real-world pegs」)。仿真对照是同一策略在该销几何上跑 2,048 个 world、同样 20 s horizon、确定性动作;误差条是 95% Wilson 区间。真机上策略的行为与仿真一致:压住表面、扫掠,开口到了销下方就掉进去。
值得注意的是三个分布外销(66%、66%、72%)与五个分布内销(73–80%)之间只差几个百分点 —— 在「没有孔位、没有零件模型、抓取还是随机的」条件下,这个差距比表 5 里视觉策略的崩塌温和得多,与仿真里得到的结论方向一致。
局限性
作者自述之一:它是一个「最后一公里」技能,假设起始已经在接触中。每个训练回合都从销已经触到夹具、离孔几厘米开始,所以必须有另一个动作(脚本化的或视觉的)把它带到那里。这条限制划定了方法的适用边界:它解决的是「已经摸到板面之后怎么找到孔并插进去」,不是「怎么从料箱里拿起销并对准板子」。
作者自述之二:行为是局部的。策略在起始点附近搜索表面、纠正它在训练中遇到过的那些错位,但处理不了需要非局部纠正的事件 —— 例如销从抓取中滑出、落在远离孔的地方。
解读补充之一:真机评测的裁决方式与覆盖面。真机成功由操作员判定,horizon 20 s,而且真机演示只覆盖销插入一个任务;齿轮啮合与螺母攻丝的 sim-to-real 没有做,表 5 里那组最漂亮的泛化对比全部是在仿真中测得的。真机的每销 30 个 reset、以第一次裁决计数,样本量下 66% 与 73% 的差别不足以支撑「分布外与分布内一样好」的强结论。
解读补充之二:吞吐代价没有与融合方案对照。每分钟 65 次对 82 次插入、入座 0.80 s 对 0.44 s,在产线节拍上不是中性的。论文用这个代价换来了对未见几何的鲁棒性,但没有给出「视觉负责粗对准 + 本体感知负责最后几毫米」这类融合方案的对照,而这恰恰是工程上最可能落地的形态。
解读补充之三:真机上的探针读数是间接的。真机 inside 召回率 62%(仿真 100%),末态销位姿估计离入座位姿中位差 6.6 mm、只有 3% 的状态被判为完全在孔内。这说明真机上的「模式解码」在很大程度上依赖对抓取滑移的估计,探针在真机上给出的是相关性证据,而 latent 替换那种因果证据只在仿真里做过。
解读补充之四:mjfit 的余量方向与速度代价。外接多边形只会朝「多给余隙」的方向出错,这对训练是安全的,但对研究 20 µm 级配合时意味着实际间隙略大于名义值($e_n$ 可由边数控制)。同时精度与速度仍在用户手里权衡:圆孔从 7–32 边到 63–281 边,CPU 实时率从 82–29× 掉到 16–4.9×,而误差从 ≤2.6 µm 收到 ≤0.4 µm。
总结与展望
这篇论文的价值不在「又一个插入策略」,而在它把一个长期被默认的前提推翻了:精密装配不必依赖视觉或力/扭矩传感。关节编码器在轻接触下携带的信息,配合足够宽的随机化与一个 32 维的时间瓶颈,就足以支撑毫米级开口搜索、齿相位对齐与螺纹咬合。更实用的一点是它给出了「怎么证明这不是背图案」的方法论:线性探针说明 latent 里有接触模式,latent 替换说明策略在用这些模式,两者合起来才构成「反应式搜索」的证据链 —— 这套手法可以直接搬到任何声称学到了接触技能的策略上。
对做仿真的团队,mjfit 是立刻可用的东西:pip install git+https://github.com/younghyopark/mjfit,命令行有 mjfit peg --shape star、mjfit peg --config usb_c(自带 USB-C 与舌片)、mjfit thread --config m10、mjfit gear --teeth 18 24,Python 侧每个生成器返回 MJCF 字符串。它解决的问题很具体:当你需要几千个「间隙精确」的装配体来训练时,凸分解会把间隙吃掉,mesh SDF 会漏接触而且慢一个数量级。它对间隙的处理方式 —— 让用户直接指定间隙、把销定义为孔的内偏移、把曲线做成外接多边形 —— 也提供了一个可复用的设计原则:在精密装配仿真里,几何误差的方向比大小更重要,只朝「多给余量」出错的方法可以安全地用于训练。
顺着作者划出的边界,接下来几步很自然:给「最后一公里」技能配一个把零件带到板面的 approach 策略(视觉或脚本),组成完整的装配管线;把接触监督这套「不给 actor 特权信息也能加速稀疏奖励」的辅助损失迁移到其它接触密集任务(连接器插拔、卡扣、线束);把探针当成部署期的接触状态监视器 —— 它在真机上已经能解出与仿真一致的模式序列,而 62% 的 inside 召回率也正好提示了 sim-to-real 需要补的地方;以及把齿轮与螺母策略也推上真机,检验表 5 里那组 >99.9% 与 98% 的仿真泛化在真实螺纹上还剩多少。
金句
「每台机器人身上都早已装着高分辨率的接触传感器:它自己的关节。」
原文:Every robot already carries high-resolution contact sensors: its own joints. —— 论文摘要第一句。腿式机器人与人体机器人靠它走路、跑步、跟踪全身动作,但那里的接触又大又猛;这篇论文要问的是:轻接触下的精密装配,够不够?



