Grabette:用开放系统采集可复现的机器人操作数据

2026-07-21 37 预计阅读时间: 1 分钟
来源: huggingface.co AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:8 分钟

机器人操作模型不仅需要大量数据,还要求动作、传感器观测和任务上下文能够准确对齐。Grabette 将重点放在一个明确的问题上:以开放系统记录机器人操作数据。由于现有材料只提供了项目标题,下面不假定其具体硬件接口或文件格式,而是分析这类系统需要解决的工程问题,并给出一套可以直接改造的最小采集方案。

记录的不只是机械臂轨迹

一条可用于训练或回放的操作数据,通常至少包含四类信息:

  • 观测:相机图像、深度图、关节位置、末端执行器位姿和夹爪状态。
  • 动作:关节目标、速度指令、末端位姿增量或控制器实际执行的命令。
  • 任务上下文:任务名称、物体信息、操作者、场景配置和成功标记。
  • 时间信息:单调时钟时间戳、传感器采样时间和控制周期序号。

其中最容易被低估的是时间同步。相机以 30 Hz 输出图像,机械臂控制器可能以 100 Hz 或更高频率运行。如果采集程序只在收到数据时写入文件,却没有保留原始时间戳,后续很难判断某个动作究竟对应哪一帧图像。

开放采集系统的价值也不只是“代码可见”。真正可复用的数据还需要公开或固定数据模式、坐标系定义、单位、设备参数和版本信息。否则,同名字段可能分别表示角度、弧度或归一化控制量,数据在跨实验室使用时会迅速失真。

用 episode 组织一次完整操作

机器人模仿学习数据通常适合按 episode 管理。一次抓取、放置或装配尝试构成一个 episode,其中包含连续步骤以及最终结果。推荐将大文件和结构化元数据分开:图像或视频单独保存,JSONL、Parquet 或数据库记录动作与索引。

一个便于检查和迁移的目录可以这样设计:

dataset/
├── manifest.yaml
└── episodes/
    └── pick-cube-000001/
        ├── metadata.json
        ├── steps.jsonl
        └── camera_front/
            ├── 000000.jpg
            └── 000001.jpg

manifest.yaml 应明确声明模式版本,而不是依赖采集代码的 Git 提交记录来猜测字段含义:

schema_version: "1.0"
dataset_name: "tabletop-pick-demo"
robot:
  model: "replace-with-your-robot"
  control_mode: "joint_position"
  joint_unit: "radian"
frames:
  world: "table_origin"
  end_effector: "tool0"
sensors:
  camera_front:
    type: "rgb"
    rate_hz: 30
    resolution: [640, 480]
policy_rate_hz: 10

运行前需要替换机器人型号、控制模式、坐标系名称和实际采样率。模式文件一旦用于正式数据集,就应通过增加版本号演进,避免直接改变已有字段语义。

一个可运行的最小记录器

下面是独立于具体机器人 SDK 的示例。它从标准输入接收每一步的 JSON,补充单调时钟和序号,然后写入 JSONL。这里明确假设上游适配器已经把机器人状态与动作转换成统一字段。

将代码保存为 record_episode.py,Python 3.9 及以上版本可直接运行:

#!/usr/bin/env python3
import argparse
import json
import time
from pathlib import Path


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--episode", required=True)
    parser.add_argument("--output", default="dataset/episodes")
    args = parser.parse_args()

    episode_dir = Path(args.output) / args.episode
    episode_dir.mkdir(parents=True, exist_ok=False)
    output_file = episode_dir / "steps.jsonl"

    with output_file.open("w", encoding="utf-8") as stream:
        for sequence, line in enumerate(iter(input, "")):
            sample = json.loads(line)
            record = {
                "sequence": sequence,
                "monotonic_ns": time.monotonic_ns(),
                "observation": sample["observation"],
                "action": sample["action"],
            }
            stream.write(json.dumps(record, separators=(",", ":")) + "\n")
            stream.flush()

    print(f"recorded {sequence + 1 if 'sequence' in locals() else 0} steps")


if __name__ == "__main__":
    main()

可以用以下命令生成一段两步测试数据:

printf '%s\n' \
  '{"observation":{"joint_position":[0.0,0.2],"gripper":0.8},"action":{"joint_target":[0.1,0.2]}}' \
  '{"observation":{"joint_position":[0.1,0.2],"gripper":0.7},"action":{"joint_target":[0.2,0.2]}}' \
  | python3 record_episode.py --episode pick-cube-000001

python3 -m json.tool < dataset/episodes/pick-cube-000001/steps.jsonl

接入真实设备时,可以让 ROS 2 节点、机器人 SDK 适配器或遥操作进程向该记录器输出 JSON。生产实现还应加入图像索引、数据队列、磁盘空间检测和异常终止标记,避免慢速磁盘阻塞控制线程。

开放数据仍然需要严格边界

采集系统开放,并不意味着所有记录都适合直接发布。相机可能拍到操作者、人脸、屏幕或实验室标识;遥操作日志也可能包含账户和设备信息。发布前应执行隐私检查,并在元数据中标明许可证、允许用途和删除流程。

采用 Grabette 或同类系统时,可以重点检查以下项目:

  • 时间戳是否来自稳定时钟,跨设备时钟如何校准。
  • 动作记录的是目标命令、控制器输出,还是机器人实际状态。
  • 坐标系、单位和夹爪数值范围是否写入模式文件。
  • episode 中断、失败和人工重置是否有明确标记。
  • 数据能否由独立程序读取,而不依赖采集机器上的私有环境。
  • 模式升级后,旧数据是否仍可解析和验证。

开放系统降低了接入和审计门槛,但数据质量最终取决于时间同步、模式治理和故障处理。先用少量 episode 完成采集、回放与校验闭环,再扩大到长时间、多设备录制,通常比一开始追求数据规模更稳妥。


相关推荐