ASAP适配宇树H1机器人

🚀 ASAP适配宇树H1机器人

📋 简介

本文介绍如何使用ASAP技术对宇树H1机器人进行动作捕捉和数据转换。我们将重点关注从视频输入到SMPL格式数据输出的整个流程,特别是如何将人体姿态估计结果转换为可用于机器人控制的NPZ格式文件。

🔄 整体流程

整体流程分为以下几个步骤:

  1. 视频转SMPL数据 - 获取PBHC开源项目代码以及GVHMR开源项目代码,借用PBHC其中motion_source目录下的demo.py代码将其拷贝到GVHMR项目目录下的tools/demo目录下
  2. 机器人配置 - 编写对应的H1机器人的仿真配置yaml文件
  3. 形状参数拟合 - 使用ASAP项目对smpl动作文件进行形状参数拟合
  4. 运动数据重定向 - 将smpl运动数据重定向到人形机器人
  5. 动作效果预览 - 查看重定向后的机器人动作效果
  6. 强化学习训练 - 编写强化学习奖励函数使其学会在平面地形下的稳定行走能力
  7. 模型评估与转换 - 预览训练出来的模型效果并转化为onnx模型
  8. 复杂动作训练 - 训练自定义的复杂动作控制策略模型
  9. 仿真测试 - 在仿真中运行训练好的动作模型控制策略
  10. 真机部署 - 将模型部署到真实机器人上

🎬 步骤1: 视频转SMPL数据

此代码实现将视频转化为标准的smpl格式的npz动作文件,同时也会生成可视化的视频文件。

📄 demo_to_npz.py

import cv2
import torch
import pytorch_lightning as pl
import numpy as np
import argparse
from hmr4d.utils.pylogger import Log
import hydra
from hydra import initialize_config_module, compose
from pathlib import Path
from pytorch3d.transforms import quaternion_to_matrix

from hmr4d.configs import register_store_gvhmr
from hmr4d.utils.video_io_utils import (
    get_video_lwh,
    read_video_np,
    save_video,
    merge_videos_horizontal,
    get_writer,
    get_video_reader,
)
from hmr4d.utils.vis.cv2_utils import draw_bbx_xyxy_on_image_batch, draw_coco17_skeleton_batch

from hmr4d.utils.preproc import Tracker, Extractor, VitPoseExtractor, SimpleVO

from hmr4d.utils.geo.hmr_cam import get_bbx_xys_from_xyxy, estimate_K, convert_K_to_K4, create_camera_sensor
from hmr4d.utils.geo_transform import compute_cam_angvel
from hmr4d.model.gvhmr.gvhmr_pl_demo import DemoPL
from hmr4d.utils.net_utils import detach_to_cpu, to_cuda
from hmr4d.utils.smplx_utils import make_smplx
from hmr4d.utils.vis.renderer import Renderer, get_global_cameras_static, get_ground_params_from_points
from tqdm import tqdm
from hmr4d.utils.geo_transform import apply_T_on_points, compute_T_ayfz2ay
from einops import einsum, rearrange

from scipy.spatial.transform import Rotation as sRot

CRF = 23  # 17 is lossless, every +6 halves the mp4 size

def parse_args_to_cfg():
    # Put all args to cfg
    parser = argparse.ArgumentParser()
    parser.add_argument("--video", type=str, default="inputs/demo/dance_3.mp4")
    parser.add_argument("--output_root", type=str, default=None, help="by default to outputs/demo")
    parser.add_argument("-s", "--static_cam", action="store_true", help="If true, skip DPVO")
    parser.add_argument("--use_dpvo", action="store_true", help="If true, use DPVO. By default not using DPVO.")
    parser.add_argument(
        "--f_mm",
        type=int,
        default=None,
        help="Focal length of fullframe camera in mm. Leave it as None to use default values."
             "For iPhone 15p, the [0.5x, 1x, 2x, 3x] lens have typical values [13, 24, 48, 77]."
             "If the camera zoom in a lot, you can try 135, 200 or even larger values.",
    )
    parser.add_argument("--verbose", action="store_true", help="If true, draw intermediate results")
    args = parser.parse_args()

    # Input
    video_path = Path(args.video)
    assert video_path.exists(), f"Video not found at {video_path}"
    length, width, height = get_video_lwh(video_path)
    Log.info(f"[Input]: {video_path}")
    Log.info(f"(L, W, H) = ({length}, {width}, {height})")
    
    # Cfg
    with initialize_config_module(version_base="1.3", config_module=f"hmr4d.configs"):
        overrides = [
            f"video_name={video_path.stem}",
            f"static_cam={args.static_cam}",
            f"verbose={args.verbose}",
            f"use_dpvo={args.use_dpvo}",
        ]
        if args.f_mm is not None:
            overrides.append(f"f_mm={args.f_mm}")

        # Allow to change output root
        if args.output_root is not None:
            overrides.append(f"output_root={args.output_root}")
        register_store_gvhmr()
        cfg = compose(config_name="demo", overrides=overrides)

    # Output
    Log.info(f"[Output Dir]: {cfg.output_dir}")
    Path(cfg.output_dir).mkdir(parents=True, exist_ok=True)
    Path(cfg.preprocess_dir).mkdir(parents=True, exist_ok=True)

    # Copy raw-input-video to video_path
    Log.info(f"[Copy Video] {video_path} -> {cfg.video_path}")
    if not Path(cfg.video_path).exists() or get_video_lwh(video_path)[0] != get_video_lwh(cfg.video_path)[0]:
        reader = get_video_reader(video_path)
        writer = get_writer(cfg.video_path, fps=30, crf=CRF)
        for img in tqdm(reader, total=get_video_lwh(video_path)[0], desc=f"Copy"):
            writer.write_frame(img)
        writer.close()
        reader.close()

    return cfg

🤖 步骤2: H1机器人配置

拉取ASAP项目源代码,将上一个生成的NPZ文件拷贝到humanoidverse/data/motion/raw_tairantestbed_smpl(也可以自己在motion目录下新建一个目录放进去),然后我们就需要编写对应的H1机器人的仿真配置yaml。

📄 humanoidverse/config/robot/h1/h1.yaml

# @package _global_

defaults:
  - robot_base

robot:
  # Observation parameters
  num_bodies: 20  # 根据H1的实际身体数量调整
  dof_obs_size: 19  # 根据H1的实际DOF数量调整
  actions_dim: 19  # 根据H1的实际DOF数量调整
  lower_body_actions_dim: 11  # 腿部动作维度
  upper_body_actions_dim: 8  # 上身动作维度
  policy_obs_dim: -1
  critic_obs_dim: -1
  
  key_bodies: ["left_ankle_link", "right_ankle_link"]
  contact_bodies: ["left_ankle_link", "right_ankle_link"]
  num_feet: 2
  right_foot_name: "right_ankle_link"
  left_foot_name: "left_ankle_link"
  foot_name: "ankle_link"
  knee_name: "knee_link"
  has_torso: True
  torso_name: "torso_link"
  has_upper_body_dof: True
  
  # 关节名称配置
  dof_names: [
    'left_hip_yaw_joint', 'left_hip_roll_joint', 'left_hip_pitch_joint', 'left_knee_joint', 'left_ankle_joint',
    'right_hip_yaw_joint', 'right_hip_roll_joint', 'right_hip_pitch_joint', 'right_knee_joint', 'right_ankle_joint',
    'torso_joint',
    'left_shoulder_pitch_joint', 'left_shoulder_roll_joint', 'left_shoulder_yaw_joint', 'left_elbow_joint', 
    'right_shoulder_pitch_joint', 'right_shoulder_roll_joint', 'right_shoulder_yaw_joint', 'right_elbow_joint'
  ]
  
  # 关节限制配置
  dof_pos_lower_limit_list: [
    -0.43, -0.43, -1.57, -0.26, -0.87,    # 左腿
    -0.43, -0.43, -1.57, -0.26, -0.87,    # 右腿
    -2.35,                                  # 躯干
    -2.87, -0.34, -1.3, -1.25,            # 左臂
    -2.87, -3.11, -4.45, -1.25             # 右臂
  ]
  
  dof_pos_upper_limit_list: [
    0.43, 0.43, 1.57, 2.05, 0.52,         # 左腿
    0.43, 0.43, 1.57, 2.05, 0.52,         # 右腿
    2.35,                                   # 躯干
    2.87, 3.11, 4.45, 2.61,               # 左臂
    2.87, 0.34, 1.3, 2.61                 # 右臂
  ]
  
  # 控制参数
  control:
    control_type: P
    stiffness:  # [N*m/rad]
      hip_yaw: 100
      hip_roll: 100
      hip_pitch: 100
      knee: 200
      ankle: 20
      torso: 400
      shoulder_pitch: 90
      shoulder_roll: 60
      shoulder_yaw: 20
      elbow: 60
    
    damping:  # [N*m*s/rad]
      hip_yaw: 2.5
      hip_roll: 2.5
      hip_pitch: 2.5
      knee: 5.0
      ankle: 0.2
      torso: 5.0
      shoulder_pitch: 2.0
      shoulder_roll: 1.0
      shoulder_yaw: 0.4
      elbow: 1.0
    
    action_scale: 0.25
    action_clip_value: 100.0
    clip_torques: True

💡 注意: 此yaml中有用到h1机器人对应的urdf、usd、xml等文件可以从官方开源项目中获取,我本人是借鉴PHC开源项目中的phc/data/robot/unitree_h1的文件内容。


📊 步骤3: 形状参数拟合

使用ASAP项目目录下的scripts/data_process/fit_smpl_shape.py代码对smpl动作文件进行形状参数拟合:

python scripts/data_process/fit_smpl_shape.py +robot=h1/h1

🎯 步骤4: 运动数据重定向

使用ASAP项目目录下的scripts/data_process/fit_smpl_motion.py代码对将smpl运动数据重定向到人形机器人:

python scripts/data_process/fit_smpl_motion.py +robot=h1/h1

👁️ 步骤5: 动作效果预览

使用ASAP项目目录下的scripts/vis/vis_q_mj.py代码查看重定向后的机器人动作效果:

python scripts/vis/vis_q_mj.py +robot=h1/h1 +visualize_motion_file="humanoidverse/data/motions/h1/TairanTestbed/singles/0-motions_raw_tairantestbed_smpl_video_side_jump_level4_filter_amass.pkl"

🧠 步骤6: 强化学习训练

编写强化学习奖励函数使其学会在平面地形下的稳定行走能力,训练一个优化后的控制策略模型,此模型即为后面会使用到的loco_model。

📄 奖励函数配置

# @package _global_

rewards:
  set_reward: Unitree_RL GYM EXACT REWARD
  set_reward_date: 20241008
  only_positive_rewards: False
  
  reward_scales:
    tracking_lin_vel: 1.0
    tracking_ang_vel: 0.5
    penalty_lin_vel_z: -2.0
    penalty_ang_vel_xy: -1.0
    penalty_orientation: -1.0
    penalty_torques: -0.00001
    penalty_dof_acc: -3.5e-8
    penalty_action_rate: -0.01
    penalty_feet_ori: -2.0
    limits_dof_pos: -10.0
    feet_air_time: 1.0
    base_height: -100.0
    penalty_feet_height: -5.0
  
  reward_tracking_sigma:
    lin_vel: 0.25
    ang_vel: 0.25
  
  # 其他配置...
  feet_height_target: 0.2
  locomotion_max_contact_force: 200.0
  desired_feet_max_height_for_this_air: 0.2
  desired_base_height: 0.98

🔍 步骤7: 模型评估与转换

使用humanoidverse/eval_agent.py预览我们训练出来的模型效果,同时将这个模型输出转化为onnx模型供后面使用:

python humanoidverse/eval_agent.py +checkpoint=logs/TestIsaacGymInstallation/20260120_172220-h1_loco-locomotion-h1/model_800.pt

🎭 步骤8: 复杂动作训练

使用第4步代码生成的pkl动作文件,训练我们自定义的复杂动作控制策略模型:

python humanoidverse/train_agent.py \
  +simulator=isaacgym \
  +exp=motion_tracking \
  +domain_rand=NO_domain_rand \
  +rewards=motion_tracking/reward_motion_tracking_dm_2real \
  +robot=h1/h1 \
  +terrain=terrain_locomotion_plane \
  +obs=motion_tracking/deepmimic_a2c_nolinvel_LARGEnoise_history \
  num_envs=4096 \
  project_name=MotionTracking \
  experiment_name=MotionTracking_CR7 \
  robot.motion.motion_file="humanoidverse/data/motions/h1/TairanTestbed/singles/0-TairanTestbed_TairanTestbed_CR7_video_CR7_level1_filter_amass.pkl" \
  rewards.reward_penalty_curriculum=True \
  rewards.reward_penalty_degree=0.00001 \
  env.config.resample_motion_when_training=False \
  env.config.termination.terminate_when_motion_far=True \
  env.config.termination_curriculum.terminate_when_motion_far_curriculum=True \
  env.config.termination_curriculum.terminate_when_motion_far_threshold_min=0.3 \
  env.config.termination_curriculum.terminate_when_motion_far_curriculum_degree=0.000025 \
  robot.asset.self_collisions=0

🎮 步骤9: 模型评估

训练完成后,我们可以使用humanoidverse/eval_agent.py预览我们训练出来的模型效果,同时将这个模型输出转化为onnx模型供后面使用:

python humanoidverse/eval_agent.py \
  +checkpoint=logs/MotionTracking/xxxxxxxx_xxxxxxx-MotionTracking_CR7-motion_tracking-h1/model_5800.pt

🔬 步骤10: Sim2Sim仿真测试

sim2sim在仿真中运行训练好的动作模型控制策略,进入sim2real目录:

python sim_env/base_sim.py --config=config/h1_hist.yaml

📄 h1_hist.yaml配置

# 机器人配置
ROBOT_TYPE: 'h1'  # Robot name
ROBOT_SCENE: "../humanoidverse/data/robots/h1/scene_h1.xml"  # Robot scene
ROBOT: "../humanoidverse/data/robots/h1/h1.urdf"  # Robot URDF file
ASSET_ROOT: "../humanoidverse/data/robots/h1"  # Robot Asset Root
ASSET_FILE: "h1.urdf"  # Robot Asset File

# 网络配置
DOMAIN_ID: 0  # Domain id
INTERFACE: "lo"  # Yuanhang: in simulation, lo0 for mac, lo for linux

# 控制参数
USE_JOYSTICK: 0  # Simulate Unitree WirelessController
FREE_BASE: False
PRINT_SCENE_INFORMATION: True  # Print link, joint and sensors information
ENABLE_ELASTIC_BAND: True  # Virtual spring band, used for lifting h1

# 时间参数
SIMULATE_DT: 0.005   # Need to be larger than the runtime of viewer.sync()
VIEWER_DT: 0.02      # Viewer update time

# 历史配置
USE_SENSOR: False
USE_HISTORY: True
USE_HISTORY_LOCO: True
USE_HISTORY_MIMIC: True

# 控制增益
JOINT_KP: [
  100, 100, 100, 200, 20,   # Left leg
  100, 100, 100, 200, 20,   # Right leg
  400,                        # Torso
  90, 60, 20, 60,            # Left arm
  90, 60, 20, 60             # Right arm
]

JOINT_KD: [
  2.5, 2.5, 2.5, 5, 0.2,   # Left leg
  2.5, 2.5, 2.5, 5, 0.2,   # Right leg
  5.0,                       # Torso
  2.0, 1.0, 0.4, 1.0,      # Left arm
  2.0, 1.0, 0.4, 1.0       # Right arm
]

🎮 控制说明

然后在另一个终端中启动控制策略:

python rl_policy/deepmimic_dec_loco_height.py --config=config/h1_hist.yaml --loco_model_path=./models/dec_loco/20250109_231507-noDR_rand_history_loco_stand_height_noise-decoupled_locomotion-g1_29dof/model_6600.onnx --mimic_model_paths=./models/mimic

键盘控制

按键 功能
] 激活locomotion策略
[ 激活asap策略(基于相位的动作跟踪策略)
; 切换到asap策略
i 使机器人回到初始位置
o 紧急停止机器人
9 在mujoco查看器中释放机器人栈
= 在locomotion策略中切换轻敲和行走
w/a/s/d 控制线速度
q/e 控制角速度
z 将所有命令设置为零

🔧 步骤11-12: Sim2Real真机部署

🚀 进入底层控制模式

  1. 开机启动人形机器人,等待头部蓝灯常亮
  2. 按下 L2+R2 组合键
  3. 按下 L2+A 组合键
  4. 按下 L2+B 组合键
  5. 通过网线将电脑与G1机器人连接,并按照这份文档配置网络

⚙️ 启动前准备

修改配置文件 config/h1_hist.yaml,将 INTERFACE 参数设置为 eth0(若使用Linux系统)—— 本质上就是你电脑中用于连接机器人、且在ifconfig中显示IP为192.168.123.xxx格式的网络接口名称。

🚀 启动策略程序

python rl_policy/deepmimic_dec_loco_height.py --config=config/h1_hist.yaml --loco_model_path=./models/dec_loco/20250109_231507-noDR_rand_history_loco_stand_height_noise-decoupled_locomotion-h1/model_6600.onnx --mimic_model_paths=./models/mimic

📈 步骤13-15: 模型微调与优化

📊 数据收集

如果需要微调动作策略使其动作更好、更稳定,就需要收集真机数据然后训练delta增量动作模型:

python rl_policy/listener_deltaa.py --config config/h1.yaml --exp_name delta_a_real_data

数据将保存在:./../humanoidverse/logs/delta_a_realdata/{exp_name}/{时间戳}/motion_{episode编号}.npz

🎯 Delta模型训练

使用收集的数据来训练delta增量动作模型:

python humanoidverse/train_agent.py \
  +simulator=isaacgym \
  +exp=train_delta_a_open_loop \
  +domain_rand=NO_domain_rand \
  +rewards=motion_tracking/delta_a/reward_delta_a_openloop \
  +robot=h1/h1 \
  +terrain=terrain_locomotion_plane \
  +obs=delta_a/open_loop \
  num_envs=5000 \
  project_name=DeltaA_Training \
  experiment_name=openloopDeltaA_training \
  robot.motion.motion_file="<PATH_TO_YOUR_MOTION_FILE_WITH_ACTION_KEYNAME>" \
  env.config.max_episode_length_s=1.0 \
  rewards.reward_scales.penalty_minimal_action_norm=-0.1 \
  +device=cuda:0 \
  env.config.resample_motion_when_training=True \
  env.config.resample_time_interval_s=10000

🔧 策略微调

使用delta增量动作模型来对我们的动作控制策略进行微调:

HYDRA_FULL_ERROR=1 \
python humanoidverse/train_agent.py \
  +simulator=isaacgym \
  +exp=train_delta_a_closed_loop \
  algo.config.policy_checkpoint='<PATH_TO_YOUR_DELTA_A_MODEL>' \
  +domain_rand=NO_domain_rand_finetune_with_deltaA \
  +rewards=motion_tracking/reward_motion_tracking_dm_simfinetuning \
  +robot=g1/g1_29dof_anneal_23dof \
  +terrain=terrain_locomotion_plane \
  +obs=delta_a/train_policy_with_delta_a \
  num_envs=4096 \
  project_name=DeltaA_Finetune \
  experiment_name=finetune_with_deltaA \
  robot.motion.motion_file="<PATH_TO_YOUR_MOTION_FILE>" \
  +opt=wandb \
  env.config.add_extra_action=True \
  +checkpoint="<PATH_TO_YOUR_POLICY_TO_BE_FINETUNED>" \
  domain_rand.push_robots=False \
  env.config.noise_to_initial_level=1 \
  rewards.reward_penalty_curriculum=True \
  +device=cuda:0 \
  algo.config.save_interval=5 \
  algo.config.num_learning_iterations=1000

✅ 总结

最后可以使用第10-12步骤进行模型的真机部署或者仿真环境下的测试。

通过这个完整的流程,你可以:

  • 🎥 将视频转换为SMPL格式的动作数据
  • 🤖 配置宇树H1机器人的仿真环境
  • 🎯 训练稳定的行走控制策略
  • 🎭 实现复杂的动作跟踪
  • 🔧 完成Sim2Real的部署
  • 📈 通过数据收集和微调优化模型性能

希望这个指南对你有所帮助!🚀

posted @ 2026-01-21 15:17  星光不问赶路人  阅读(1)  评论(0)    收藏  举报