系列: 2026 机器人工程实例 环境: Windows 11、WSL2 / WSLg、Ubuntu 26.04、Python 3.12、MuJoCo 3.3.6 机器人模型: Allegro Hand V3 右手 项目名称: 05-dexterous-hand 完整代码: zephastra/robotics:05-dexterous-hand 关键词: 灵巧手、Allegro Hand、MuJoCo、接触抓取、状态机、物理仿真、抓取验证
前言
让灵巧手的手指动起来并不难。
给 16 个关节设置一组目标角度,模型很快就能摆出张开、握拳或捏合的姿态。但“手指已经合拢”和“物体已经被可靠抓住”是两件完全不同的事情。
一次可以验收的抓取至少要回答下面几个问题:
- 手指是否真的与物体建立了接触?
- 接触是否来自相对的多个方向,而不是单根手指碰了一下?
- 物体是否已经脱离原来的支座?
- 抬升和转移过程中有没有滑落?
- 释放之后,物体是否由目标托盘独立支撑?
- 程序如何区分“抓取完成”“物体掉落”和“放置不稳定”?
因此,本工程没有把目标停留在“播放一段手指动画”,而是把抓取拆成一条由仿真测量值驱动的闭环:
张开与稳定
↓
手指渐进合拢
↓
多指接触确认
↓
抬升并脱离源支座
↓
稳定保持
↓
水平转移
↓
下降、张开与撤手
↓
目标托盘放置验收
本文将完整介绍这套抓取实验台的结构、状态机、接触力测量、成功判据、失败复盘以及可以诚实声称的能力边界。
一、工程五解决了什么问题?
工程五是一个独立的 MuJoCo + Allegro Hand V3 灵巧手动作与接触抓取实验台。
系统使用四指、16 关节的 Allegro Hand,通过一个具有明确关节和驱动器的两轴手腕夹具完成竖直抬升与横向转移。自动任务从源支座上的球体开始,依次完成手指合拢、接触确认、抬升、保持、横移、下降、释放和托盘放置验收。
整个过程中,球体始终是自由物体。项目不使用吸附、绑定、焊接约束,也不会在运行中直接修改球体坐标。物体能不能被带起来,由手指碰撞、接触力、摩擦、重力以及夹具运动共同决定。
项目同时提供:
- 16 个手指关节的独立滑块;
- 张开、多指包络和两指动作预设;
- Y 方向横移与 Z 方向抬升控制;
- 自动抓取任务状态机;
- 分手指接触力显示;
- 任务取消、物理暂停与人工接管;
- 失败原因记录;
- JSON 报告与 CSV 轨迹;
- 无界面测试、批量扰动测试和图形验证。
需要提前说明:当前工程是一个四指灵巧手实验台,不是完整机械臂或人形机器人。两轴夹具只负责移动手腕,不代表已经实现机械臂运动规划、全身平衡或真实硬件控制。
二、为什么不能只看“手有没有闭合”?
最简单的抓取演示通常采用固定时间轴:
0 秒:张开
2 秒:合拢
5 秒:抬起
8 秒:移动
10 秒:松开
这种流程只能证明控制命令被发出,不能证明任务完成。
例如,手指可能没有碰到物体,但程序仍然进入抬升阶段;球可能在移动途中已经滑落,但动画仍然继续;物体也可能被手指带到托盘附近,却没有真正脱离手掌。
工程五采用的是“命令 + 测量 + 判定”的方式:
关节与夹具目标
↓
速度限制和平滑下发
↓
MuJoCo 位置驱动器
↓
碰撞、摩擦、重力与接触
↓
物体位置 / 速度 / 支撑关系 / 分指接触力
↓
状态机决定继续、完成或失败
时间只用于控制动作持续时间和超时,阶段切换还必须满足实际测量条件。
这也是本工程最重要的设计原则:动作脚本负责提出意图,物理测量负责决定结果。
三、实验台由哪些部分组成?
1. Allegro Hand V3
本项目使用 Allegro Hand V3 右手模型,包含四根手指:
- 食指 ff;
- 中指 mf;
- 无名指 rf;
- 拇指 th。
每根手指包含 4 个独立关节,总计 16 个手指关节。关节范围、质量、碰撞几何和位置驱动器来自固定版本的上游模型,项目没有为了让球更容易抓住而扩大手指关节范围。
2. 两轴手腕夹具
为了把注意力集中在接触抓取和任务验收上,手腕安装在一个两轴定位夹具上:
- Y transfer:沿 Y 方向移动 20 cm;
- Z lift:沿 Z 方向抬升 12 cm。
夹具不是通过修改模型根坐标实现瞬移,而是拥有自己的关节和驱动器。它可以完成本次抓取实验所需的抬升与转移,但不应被描述成机械臂。
3. 自由球体
当前抓取物体是一颗球:
| 半径 | 35 mm |
| 质量 | 50 g |
| 自由度 | 六自由度自由关节 |
| 接触模型 | 六维接触 |
| 初始位置 | 源支座上方 |
球体在任务初始化时可以加入有限的 X/Y 位置偏差。仿真开始后,程序不再直接写入它的位姿。
4. 源支座与目标托盘
球体最初位于源支座,任务结束时需要落在绿色目标托盘上。托盘带有挡边,并使用明确设定的接触与滚动摩擦参数。
这些参数用于构建本次名义接收垫,并没有经过真实材料实验标定。因此文章中的结果属于仿真工程验证,不是实物摩擦性能结论。
四、工程目录
克隆项目后,工程五的主要目录如下:
05-dexterous-hand/
├── README.md
├── LICENSE
├── THIRD_PARTY_NOTICES.md
├── requirements.txt
├── run_demo.sh
├── scripts/
│ ├── setup.sh
│ ├── doctor.sh
│ ├── test.sh
│ ├── batch.py
│ ├── prepare_assets.py
│ ├── probe_grasp.py
│ └── verify_gui.py
├── src/hand005/
│ ├── app.py
│ ├── core.py
│ ├── model.py
│ └── panel.py
├── tests/
│ ├── test_core.py
│ └── test_physics.py
└── docs/
├── images/
│ ├── first-lift-calibration.png
│ ├── grasp-hold.png
│ └── placed.png
└── evidence/
├── nominal-report.json
├── batch-final.json
├── gui-verification.json
├── gui-report.json
├── batch-before-release-fix.json
└── batch-pad-only.json
各模块的职责比较清楚:
- core.py:动作目标、平滑控制和抓取状态机;
- model.py:加载模型、校验资源和读取接触测量;
- app.py:仿真主循环、报告、轨迹和截图;
- panel.py:独立 Tk 控制面板;
- tests/:状态机逻辑与完整物理任务测试;
- docs/evidence/:成功结果和开发过程中的失败证据。
五、从 GitHub 安装
完整代码已经上传到 GitHub:
https://github.com/zephastra/robotics/tree/main/projects/05-dexterous-hand
在 Linux 或 WSL 中执行:
git clone https://github.com/zephastra/robotics.git
cd robotics/projects/05-dexterous-hand
bash scripts/setup.sh
bash scripts/doctor.sh
本机验证环境为:
Windows 11
WSL2 / WSLg
Ubuntu 26.04
Python 3.12.13
MuJoCo 3.3.6
NumPy 2.2.6
pytest 8.4.2
Pillow 11.3.0
安装脚本会完成以下工作:
运行前会再次检查资源哈希。如果文件缺失或被意外修改,程序会直接报错,不会在资源状态不明的情况下继续运行。
目前已经在上述本机环境中验证,但全新机器的完整复现仍待独立验收。这一点不应省略。
六、运行自动抓取任务
执行:
bash run_demo.sh –mode demo
程序会打开 MuJoCo 窗口,并自动运行一轮完整任务:
SETTLE
→ CLOSE
→ VERIFY_GRASP
→ LIFT
→ HOLD
→ TRANSFER
→ LOWER
→ RELEASE
→ VERIFY_PLACE
→ COMPLETED / FAILED
如果希望任务结束后保留窗口:
bash run_demo.sh –mode demo –keep-open
如果只进行无界面验收:
bash run_demo.sh –mode demo –headless
需要保存关键阶段截图时,可以在支持 EGL 的环境中执行:
MUJOCO_GL=egl bash run_demo.sh –mode demo –headless –snapshot
WSLg 下如果图形渲染存在兼容问题,还可以切换到软件渲染:
H005_RENDERER=software bash run_demo.sh
七、抓取状态机是如何工作的?
1. SETTLE:张开并等待稳定
任务开始后,手指保持张开姿态,球体在源支座上稳定 1 秒。
这一步可以避免初始化瞬间的接触抖动直接影响后续判断。
2. CLOSE:渐进合拢
手指不会一步跳到最终包络姿态,而是在约 2 秒内从 OPEN 插值到 GRASP,随后留出额外稳定时间。
核心形式可以写成:
hand = OPEN + np.clip(age / 2.0, 0, 1) * (GRASP – OPEN)
主循环还会对所有关节目标进行速度限制:
def slew(current, target, rates, dt):
delta = np.clip(target – current, –rates * dt, rates * dt)
return current + delta
这样可以避免关节目标突变造成不必要的冲击。
3. VERIFY_GRASP:确认多指对向接触
工程没有把“任意一次碰撞”当成抓取成功,而是要求:
- 拇指法向接触力大于 0.02 N;
- 食指、中指、无名指中至少两根的法向接触力大于 0.02 N;
- 上述条件连续保持 0.5 s。
对应的判断逻辑为:
def supported_grasp(obs):
forces = obs["finger_forces"]
thumb_ok = forces["th"] > 0.02
other_count = sum(forces[k] > 0.02 for k in ("ff", "mf", "rf"))
return thumb_ok and other_count >= 2
这不是严格的力闭合分析,但比“手指角度到了,所以抓住了”更可靠。若 3 秒内无法建立满足条件的接触,任务以 NO_OPPOSED_GRASP 失败。
4. LIFT:抬升并脱离源支座
接触确认后,Z 轴夹具命令抬升 12 cm。状态机不会仅根据夹具目标判断成功,而是检查球体:
- 相对初始位置至少上升 9 cm;
- 已经失去与源支座的接触。
如果夹具已经完成动作,而球体没有满足条件,任务记录为 INSUFFICIENT_LIFT。

5. HOLD:验证稳定保持
进入保持阶段时,程序记录球体相对手掌的位置:
hold_reference = object_position – palm_position
随后连续保持 2 秒。如果球体相对手掌的位移超过 2 cm,则判定发生滑移:
OBJECT_SLIPPED
这一步用来区分“短暂带起来”和“能够稳定持有”。

6. TRANSFER:横向转移
保持通过后,两轴夹具维持抬升高度,同时沿 Y 方向移动 20 cm。
在 LIFT、HOLD、TRANSFER 和 LOWER 阶段,程序持续检查多指接触。如果接触条件连续丢失超过 0.5 秒,任务立即记录:
LOST_FINGER_CONTACT
短暂接触波动不会马上失败,持续失去接触才会触发终止。
7. LOWER:下降到释放高度
到达托盘上方后,夹具下降。手指此时仍保持包络姿态,防止球体提前滚落。
释放高度不是越低越好。如果手掌和手指过度压向托盘,张开时可能继续支撑或拨动物体,反而造成放置失败。
8. RELEASE:张开并主动撤手
释放阶段同时执行两个动作:
“撤手”非常关键。只有手指离开物体之后,才能确认球体是由托盘独立支撑,而不是仍然卡在指尖之间。
9. VERIFY_PLACE:连续验证放置结果
最终成功需要同时满足:
- 球心位于目标中心 X/Y 各 ±3.5 cm 内;
- 球心高度约为 20.5 cm ± 1.2 cm;
- 球体与目标托盘接触;
- 所有手指接触力之和低于 0.02 N;
- 球体速度低于 0.02 m/s;
- 上述条件连续保持 1 秒。
任何一项短暂满足都不够。5 秒内不能完成稳定验收时,任务返回:
PLACEMENT_NOT_STABLE

八、MuJoCo 接触力如何读取?
状态机需要知道哪根手指正在接触球体,以及法向接触力有多大。
程序首先遍历当前接触对,只保留包含球体碰撞几何的接触;然后识别另一侧几何所属的手指,使用 MuJoCo 的接触力接口读取六维接触量:
force = np.zeros(6)
mujoco.mj_contactForce(model, data, contact_id, force)
normal_force = max(0.0, float(force[0]))
同一根手指可能通过多个几何或多个接触点同时接触球体,所以程序会按手指累计法向力:
ff:食指接触力之和
mf:中指接触力之和
rf:无名指接触力之和
th:拇指接触力之和
同时,程序还会识别:
- source_contact:球体是否仍由源支座支撑;
- tray_contact:球体是否已经落在目标托盘上;
- speed:球体线速度;
- relative_object:球体相对手掌的位置。
需要注意,这些接触力是 MuJoCo 接触求解器给出的仿真量,不是真实灵巧手的触觉传感器读数。
九、失败关闭:条件不满足就不能算成功
本工程采用 fail-closed 思路:无法证明成功时,不把任务标记为成功。
| NO_OPPOSED_GRASP | 没有形成拇指与至少两根其他手指的持续接触 |
| INSUFFICIENT_LIFT | 球体没有达到最低抬升高度或仍接触源支座 |
| LOST_FINGER_CONTACT | 搬运阶段持续失去要求的多指接触 |
| OBJECT_SLIPPED | 保持阶段球体相对手掌移动超过 2 cm |
| OBJECT_DROPPED | 球体高度低于 10 cm |
| PLACEMENT_NOT_STABLE | 托盘位置、支撑、速度或撤手条件未连续满足 |
| NONFINITE_STATE | 仿真状态出现非有限值 |
| EXTERNAL_TIME_RESET | 运行期间检测到外部仿真时钟重置 |
| TIMEOUT | 在规定时间内没有完成任务 |
这些失败不是“难看的红色结果”,而是工程信息。只有知道在哪个阶段失败,才能判断问题来自接触姿态、摩擦参数、抬升轨迹、释放高度还是验收逻辑。
十、手动控制面板
不带参数执行:
bash run_demo.sh
程序会打开 MuJoCo 仿真窗口和独立的 005 Hand Controls 控制窗口。
操作时应点击控制面板,而不是在 MuJoCo 窗口中按键。
| Index / Middle / Ring / Thumb 的 J0~J3 | 设置 16 个手指关节目标,单位 rad |
| 1 Open | 张开手指 |
| 2 Power pose | 多指包络姿态 |
| 3 Pinch pose | 拇指与食指动作预设 |
| Y transfer | 设置横移夹具位置 |
| Z lift | 设置抬升夹具位置 |
| Run grasp demo | 从源位置启动自动任务 |
| Cancel demo / hold | 中止任务并保持当前关节位置 |
| Pause / resume | 暂停或恢复物理仿真 |
| Quit | 结束会话并保存报告 |
滑块表达的是持续位置目标,不是需要按住的速度按钮。失去窗口焦点后,目标不会被自动清空。
如果在自动任务运行期间操作滑块或姿态按钮,程序会:
另外,Pinch pose 目前只是拇指和食指的动作预设,尚未通过独立两指捏取任务验收,不能把它描述成已经实现稳定捏取。
十一、这次最值得记录的三个坑
坑一:抓住并不等于“关节到位”
早期最容易犯的错误,是只检查关节目标是否执行完成。
但手指角度相同,不代表物体位置、接触组合和支撑状态相同。最终方案改为使用拇指与至少两根其他手指的持续法向接触作为最低抓取条件,并在抬升后继续检查接触是否丢失。
坑二:提高托盘摩擦不能代替正确释放
开发过程中曾尝试只改变接收垫的摩擦参数。五次有限偏差试验结果为:
0 / 5 通过
这说明问题不只是球体落地后滚动。若手指在释放过程中仍然支撑或拨动球体,单纯增加摩擦并不能建立稳定放置。
正确修复是重新设计释放轨迹:降低到合适高度,逐渐张开,并在张开过程中向上撤手,让球体明确转移到托盘支撑。
坑三:一次成功不能证明流程稳定
修改释放轨迹前,五次有限初始偏差试验只有:
3 / 5 通过
失败原因均为:
PLACEMENT_NOT_STABLE
这类问题在单次演示中很容易被遗漏。加入不同随机种子的有限偏差批量测试后,才能暴露释放轨迹对初始位置的敏感性。
修复后,同一测试范围达到 5/5。这里仍然只能说明当前固定球体和有限偏差范围内通过,不能外推为通用成功率。
十二、测试与验证结果
1. 自动化测试
执行:
bash scripts/test.sh
当前共有 14 项测试通过,覆盖:
- 每个关节目标的速度限制;
- 抓取必须包含拇指和至少两根其他手指;
- 接触不足时必须失败;
- 物体掉落检测;
- 转移过程接触丢失检测;
- 抬升不足检测;
- 放置需要托盘支撑、手指撤离和低速度;
- 连续稳定计时器的重置逻辑;
- 状态机不应修改观测数据;
- 模型具有自由物体且不存在附着约束;
- 初始扰动可复现;
- 完整接触抓取物理任务。
2. 名义任务结果
归档的名义任务报告显示:
| 最终状态 | COMPLETED |
| 完成原因 | LIFT_HOLD_TRANSFER_RELEASE_VERIFIED |
| 仿真时间 | 约 19.64 s |
| 最大抬升 | 约 12.37 cm |
| 最终托盘接触 | 是 |
| 最终手指接触力 | 四根手指均为 0 |
| 最终球体速度 | 约 1.62 × 10⁻⁷ m/s |
各阶段进入时间如下:
| SETTLE | 0.00 s |
| CLOSE | 1.00 s |
| VERIFY_GRASP | 4.02 s |
| LIFT | 4.56 s |
| HOLD | 7.58 s |
| TRANSFER | 9.58 s |
| LOWER | 13.08 s |
| RELEASE | 16.08 s |
| VERIFY_PLACE | 18.60 s |
| COMPLETED | 19.64 s |
3. 五次有限初始偏差试验
执行:
.venv/bin/python scripts/batch.py –count 5 –offset 0.002
测试使用 5 个独立随机种子,球体初始 X/Y 位置各自在 ±2 mm 范围内变化。
最终结果为:
5 / 5 COMPLETED
但这个数字只覆盖:
- 同一种球体;
- 50 g 固定质量;
- 固定姿态;
- 名义摩擦参数;
- X/Y 各 ±2 mm 的有限初始偏差。
它不代表不同形状、质量、材质或大范围位置误差下的抓取成功率。
4. 图形界面验证
项目还运行了真实 Tk 控件与 MuJoCo Viewer 的程序化图形测试,验证结果包括:
widgets = true
demo_button = true
completed = true
这可以证明窗口、按钮和仿真流程能够协同运行,但不等于已经由独立用户在全新机器上完成鼠标操作验收。
十三、JSON 报告和 CSV 轨迹
每次运行都会在下面的目录生成单独记录:
reports/<UTC时间编号>/
├── report.json
└── trajectory.csv
如果启用了 –snapshot,还会根据任务阶段保存图片。
report.json 包含:
- 会话最终状态和失败原因;
- 运行模式、随机种子和初始偏差;
- 球体质量;
- MuJoCo 版本;
- 上游资源提交版本;
- 资源 SHA-256;
- 状态机事件时间线;
- 最大抬升高度;
- 最终物体位置、速度和接触状态;
- 当前源代码 SHA-256;
- 项目能力限制。
trajectory.csv 持续记录:
time, phase, x, y, z, speed,
source_contact, tray_contact,
ff, mf, rf, th
这些数据让一次演示从“我看到它好像成功了”,变成可追踪、可复查的工程记录。
仓库中同时保留:
- 当前名义任务成功报告;
- 当前 5/5 有限偏差报告;
- 图形测试记录;
- 修改释放轨迹前的 3/5 报告;
- 只调整托盘摩擦时的 0/5 报告。
保留失败证据非常重要。否则读者只能看到最终参数,却不知道为什么需要撤手轨迹、连续判定和批量测试。
十四、常见问题
1. 提示资源缺失或校验失败
重新执行:
bash scripts/setup.sh
bash scripts/doctor.sh
项目会检查 assets/manifest.json 中的文件哈希。不要直接绕过资源校验,否则模型和代码版本可能不匹配。
2. MuJoCo 窗口无法显示
确认 WSLg/OpenGL 环境可用。也可以尝试软件渲染:
H005_RENDERER=software bash run_demo.sh
如果只想验证物理任务,可以运行:
bash run_demo.sh –mode demo –headless
3. 点击 Run grasp demo 被拒绝
自动任务只接受位于源支座、速度足够低且接触状态正确的初始球体。
如果手动操作已经让球体离开源位置,程序不会偷偷把球放回去。关闭并重新启动仿真即可开始新一轮。
4. 手动操作后任务显示 CANCELLED
这是预期行为。自动任务期间调整滑块或姿态按钮属于人工接管,程序不会把干预后的结果继续算作自动成功。
5. 使用 Pinch pose 后为什么没有完成抓取?
Pinch pose 只是两指动作预设。目前通过完整验收的是多指包络抓取,两指捏取仍属于下一阶段工作。
6. 球已经落在托盘附近,为什么仍然失败?
放置成功不是只看位置。程序还要求:
- 托盘接触成立;
- 手指已经撤离;
- 球体速度足够低;
- 所有条件连续保持 1 秒。
缺少任何一项,都可能返回 PLACEMENT_NOT_STABLE。
十五、当前能力边界
工程实例最重要的不只是展示完成了什么,也要明确没有完成什么。
当前项目的边界如下:
所以,准确的描述是:
本项目在固定仿真场景中,完成了 Allegro Hand 对已知球体的多指接触抓取、稳定抬升、横向转移、受控释放和结果验收。
而不是:
已经实现能够抓取任意物体的通用灵巧手系统。
十六、下一步可以怎么扩展?
在当前闭环基础上,后续可以沿四个方向继续推进。
1. 两指捏取验收
为小尺寸物体单独建立捏取任务,重新定义:
- 拇指—食指对向接触;
- 最小抬升高度;
- 捏取滑移判定;
- 小物体稳定放置标准。
2. 多物体测试矩阵
逐步加入:
- 不同直径球体;
- 圆柱体;
- 方块;
- 不同质量;
- 不同摩擦参数;
- 更大范围的初始位置和姿态偏差。
这时应报告每个测试范围,而不是只给出一个笼统的成功率。
3. 反馈式自适应合拢
当前采用预先标定的包络姿态。下一步可以根据接触顺序和接触力动态调整各手指闭合速度,减少对固定物体位置的依赖。
4. 与机械臂或人形躯干集成
当灵巧手自身的接触抓取足够稳定后,再把目标位姿、机械臂规划和抓取状态机连接起来。这样可以清楚地区分:
- 手臂负责把手送到哪里;
- 灵巧手负责如何建立和保持接触;
- 任务层负责何时抓取、何时搬运、何时释放。
这比一开始就把所有模块堆在一起更容易调试和验收。
十七、总结
工程五真正完成的,不只是让 Allegro Hand 做出一个握拳动作,而是建立了一条可以检查结果的物理抓取链路:
关节目标
↓
平滑执行
↓
多指接触
↓
抬升脱离
↓
稳定保持
↓
横向搬运
↓
张开撤手
↓
托盘支撑与静止验收
其中最关键的工程经验有三点:
从人形机器人行走到灵巧手抓取,问题看起来从“脚”转移到了“手”,但核心方法没有改变:不要只验证命令是否发出,而要验证物理世界中的目标是否真正达成。
完整代码:
https://github.com/zephastra/robotics/tree/main/projects/05-dexterous-hand
网硕互联帮助中心




评论前必须登录!
注册