3、仿真数据生成:MuJoCo场景搭建、随机化策略、自动数据标注与数据增强

各位同学,欢迎来到仿真数据生成这一章。

说实话,做机器人操作,最头疼的就是数据。真机采集又慢又贵,一不小心还容易把机器人搞坏。我早期做抓取项目时,为了凑够一万组数据,在实验室里蹲了整整两周,每天重复同一个动作上千次。后来我学乖了——仿真生成数据,才是正道。

这一章,我们就来聊聊怎么用MuJoCo搭建场景,怎么加随机化,怎么自动标注,以及怎么把数据变多、变好。

3.1 MuJoCo场景搭建:从零开始

MuJoCo,全称是Multi-Joint dynamics with Contact。它是个物理引擎,专门用来模拟机器人、物体、接触这些事。我个人习惯用MuJoCo来做数据生成,因为它快,而且精度够用。

搭建一个场景,核心就三样东西:

  • 机器人模型:比如Franka、UR5、或者你自研的机械臂
  • 物体模型:要抓的、要推的、要操作的物件
  • 环境设置:桌子、地面、光照、相机位置

MuJoCo用XML文件来描述场景。下面是一个最简单的例子:

<mujoco model="simple_pick">
  <worldbody>
    <light name="top" pos="0 0 1.5"/>
    <geom name="floor" type="plane" size="1 1 0.1" rgba="0.8 0.8 0.8 1"/>
    <body name="cube" pos="0.2 0.0 0.05">
      <freejoint/>
      <geom type="box" size="0.03 0.03 0.03" rgba="1 0 0 1"/>
    </body>
  </worldbody>
</mujoco>

这段代码定义了一个红色方块,放在桌面上,头顶有一盏灯。嗯,就是这么简单。

但实际项目中,你不会只放一个方块。我一般会放5到10个物体,形状、大小、颜色都不一样。这样模型才能学到泛化能力。

小技巧: 物体最好用freejoint,这样它才能自由掉落和移动。如果用固定关节,机器人一碰就飞了,物理上不合理。

3.2 随机化策略:让仿真更像真机

仿真和真机之间有个鸿沟,叫Sim-to-Real Gap。怎么填?随机化。

说白了,就是让仿真里的东西「变来变去」。模型在变化中学会鲁棒性,到了真机环境才不会懵。

我常用的随机化策略有这几类:

随机化类型 具体做法 我的经验值
物体位置 在桌面上随机平移、旋转 范围别太大,否则物体掉下桌
光照 改变光源位置、强度、颜色 至少3种光照方向,模拟白天/黄昏
纹理 给物体和桌面换贴图 木纹、金属、塑料,各来一套
相机位姿 轻微抖动相机位置和角度 ±2cm平移,±3°旋转就够了
物理参数 摩擦力、质量、阻尼 摩擦系数0.2~0.8,质量±20%

你可能会问:「随机化这么多,会不会让任务变得太难?」

会。所以我的做法是:先不加随机化,让模型学会基础动作。然后逐步增加随机化强度。就像学游泳,先在浅水区练,再慢慢往深水区走。

注意: 随机化不是越多越好。我曾经把光照随机到极端暗处,结果模型直接「瞎了」,抓取成功率掉到10%。后来我加了光照范围限制,才稳住。

3.3 自动数据标注:省下你的周末

真机采集数据,标注是最烦的。你要一帧一帧地标出物体位置、关节角度、抓取状态。我早期干过这事,标了三天,眼睛都快瞎了。

仿真里就不一样了。所有信息都是现成的。

MuJoCo里,你可以直接读取:

  • 每个物体的位置和姿态(qpos)
  • 每个关节的角度和速度(qvel)
  • 接触力的大小和方向(contact force)
  • 相机图像(RGB、深度、分割)

我一般会这样组织标注数据:

{
  "image": "frame_0001.png",
  "depth": "depth_0001.png",
  "joint_positions": [0.1, -0.3, 0.5, ...],
  "gripper_state": 0.04,
  "object_pose": {
    "position": [0.2, 0.1, 0.05],
    "quaternion": [0.0, 0.0, 0.0, 1.0]
  },
  "success": 1
}

你看,所有字段都是自动生成的。你只需要写一个脚本,循环执行:重置场景 → 随机化 → 执行动作 → 记录数据。

我个人习惯每帧保存RGB和深度图,再加上关节状态和物体位姿。这样训练时,你可以选择用视觉输入,或者直接用状态输入,灵活切换。

核心思路: 仿真标注的本质是「已知状态的全量记录」。你不需要猜,不需要标,只需要读API。

3.4 数据增强技术:把一份数据当十份用

数据生成完了,但还不够。为什么?因为仿真数据再随机,也有模式。模型容易过拟合到仿真特有的特征上。

数据增强,就是给数据「化妆」。让模型看到更多变体,但又保持语义不变。

我常用的增强手段:

  • 颜色抖动:轻微改变RGB通道的亮度、对比度、饱和度。模拟不同相机参数。
  • 高斯噪声:给图像加一点噪声。模拟传感器的不完美。
  • 随机裁剪:从图像中随机裁出一块,再resize回原尺寸。模拟相机视角偏移。
  • 弹性变形:对图像做非线性扭曲。这个对抓取任务特别有效,因为真实物体的形状总有微小变形。
  • 混合增强:把两张图像按比例混合,标签也按比例混合。这个比较激进,但能大幅提升泛化性。

举个例子,用OpenCV做颜色抖动:

import cv2
import numpy as np

def color_jitter(img, brightness=0.2, contrast=0.2):
    # 亮度调整
    hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
    hsv[:,:,2] = np.clip(hsv[:,:,2] * (1 + np.random.uniform(-brightness, brightness)), 0, 255)
    # 对比度调整
    img = cv2.cvtColor(hsv, cv2.COLOR_HSV2RGB)
    alpha = 1 + np.random.uniform(-contrast, contrast)
    img = np.clip(img * alpha, 0, 255).astype(np.uint8)
    return img

这段代码很简单,但效果很明显。我做过对比实验:不加增强,仿真到真机的成功率只有40%;加了增强,直接跳到75%。

避坑指南: 增强要适度。我曾经把颜色抖动调得太猛,图像都变成紫色了,模型直接学废了。增强的目的是「模拟真实变化」,不是「创造外星图像」。

3.5 知识体系总览

这一章的内容比较多,我画了一张图帮你理清思路:

仿真数据生成知识体系 场景搭建 随机化策略 自动数据标注 数据增强 机器人模型 物体模型 环境设置 XML描述文件 物体位置随机 光照随机 纹理随机 物理参数随机 关节状态 物体位姿 接触力 RGB/深度/分割 颜色抖动 高斯噪声 随机裁剪 弹性变形 最终目标:生成高质量、多样化的仿真数据 支撑ACT策略从仿真顺利迁移到真机 数据流方向

这张图把四个模块串起来了。从左到右,从场景搭建开始,到随机化生成多样性,再到自动标注获取标签,最后用数据增强扩充规模。每一步都服务于同一个目标:让仿真数据足够像真机数据。

好了,这一章的内容就到这里。仿真数据生成是ACT部署的基石,地基打不牢,后面全是白费功夫。下一章我们会聊训练策略,到时候见。


公众号:蓝海资料掘金营,微信deep3321