仿真到真机迁移(Sim-to-Real)基础

理解Sim-to-Real的核心挑战和解决方案,掌握Domain Randomization、System Identification等关键技术。

Sim-to-Real 仿真迁移 Domain Randomization ROS2
仿真到真机迁移(Sim-to-Real)基础

仿真到真机迁移(Sim-to-Real)基础

Sim-to-Real是Embodied AI的核心挑战之一。在仿真中训练的策略,直接部署到真实机器人时往往会失败。本文介绍主流的解决方案。

为什么Sim-to-Real很难?

仿真和现实之间存在Reality Gap

差异类型仿真现实
物理参数理想化摩擦、弹性、质量偏差
传感器完美数据噪声、延迟、漂移
执行器精确响应死区、饱和、非线性
环境可控光照变化、干扰

Domain Randomization(域随机化)

核心思想:在仿真中随机化环境参数,让策略学会适应各种情况。

import numpy as np

class DomainRandomizer:
    def __init__(self, world):
        self.world = world

    def randomize_physics(self):
        """随机化物理参数"""
        # 物体质量
        mass = np.random.uniform(0.1, 0.5)  # 100g-500g
        self.world.set_mass("/World/Target", mass)

        # 摩擦系数
        friction = np.random.uniform(0.3, 0.8)
        self.world.set_friction("/World/GroundPlane", friction)

    def randomize_visual(self):
        """随机化视觉外观"""
        # 物体颜色
        color = np.random.uniform(0, 1, 3)
        self.world.set_color("/World/Target", color)

        # 光照条件
        intensity = np.random.uniform(500, 2000)
        self.world.set_light_intensity("/World/Light", intensity)

    def randomize_sensors(self):
        """随机化传感器噪声"""
        # 相机噪声
        noise_std = np.random.uniform(0.01, 0.05)
        self.world.set_camera_noise("/World/Camera", noise_std)

    def apply_all(self):
        self.randomize_physics()
        self.randomize_visual()
        self.randomize_sensors()

训练时每个episode都应用新的随机化:

for episode in range(num_episodes):
    # 随机化环境
    randomizer.apply_all()
    world.reset()

    # 运行episode
    obs, _ = env.reset()
    done = False
    while not done:
        action = policy(obs)
        obs, reward, done, info = env.step(action)
        buffer.add(obs, action, reward, done)

    # 更新策略
    policy.update(buffer)

System Identification(系统辨识)

通过实验数据拟合仿真参数,缩小Reality Gap:

import numpy as np
from scipy.optimize import minimize

class SystemIdentifier:
    def __init__(self, robot):
        self.robot = robot

    def collect_data(self, num_trials=20):
        """在真实机器人上收集数据"""
        real_data = []
        for _ in range(num_trials):
            # 发送随机命令
            commands = np.random.uniform(-1, 1, (100, 6))
            states = []
            for cmd in commands:
                self.robot.send_command(cmd)
                state = self.robot.get_state()
                states.append(state)
            real_data.append((commands, states))
        return real_data

    def fit_parameters(self, real_data):
        """优化仿真参数以匹配真实数据"""
        def objective(params):
            # 设置仿真参数
            self.set_sim_params(params)

            # 运行仿真
            error = 0
            for commands, real_states in real_data:
                sim_states = self.run_simulation(commands)
                error += np.mean((sim_states - real_states) ** 2)
            return error

        # 初始参数猜测
        x0 = [0.5, 0.3, 0.1]  # 摩擦、阻尼、质量偏差

        result = minimize(objective, x0, method='Nelder-Mead')
        return result.x

渐进式迁移策略

  1. 先在仿真中充分训练
  2. 逐步增加域随机化强度
  3. 在真实机器人上微调
  4. 收集真实数据回灌仿真
class ProgressiveTransfer:
    def __init__(self, policy, env):
        self.policy = policy
        self.env = env
        self.randomization_level = 0.0

    def train_with_progressive_dr(self):
        for phase in range(5):
            # 增加随机化强度
            self.randomization_level = phase * 0.2
            self.env.set_randomization_scale(self.randomization_level)

            # 在当前强度下训练
            for episode in range(100):
                self.train_episode()

            # 评估
            success_rate = self.evaluate()
            print(f"Phase {phase}: DR={self.randomization_level:.1f}, Success={success_rate:.1%}")

            if success_rate > 0.9:
                break

FAQ

Sim-to-Real迁移成功率一般多少?

简单任务(如抓取)可以达到80-90%。复杂任务(如灵巧操作)可能只有50-60%。

必须用Domain Randomization吗?

不是必须,但它是目前最有效的方法之一。也可以结合System Identification使用。

迁移失败怎么排查?

检查传感器校准、执行器响应、物理参数匹配。建议用可视化工具对比仿真和现实的轨迹差异。