unitree_rl_gym 实物部署实战:在 Unitree G1 / H1 / H1_2 真机上运行强化学习策略
【免费下载链接】unitree_rl_gym项目地址: https://gitcode.com/GitHub_Trending/un/unitree_rl_gym
本文以仓库
deploy/deploy_real模块为主体,完整讲解如何把 legged_gym 训练好的网络策略部署到 Unitree G1、H1、H1_2 实物机器人上:从启动命令、网卡配置、遥控器操作流程,到 DDS 通信、状态机与观测构造的源码级原理。读完本文,你将掌握一套可直接照做的真机部署操作手册,并理解deploy_real.py内部"零力矩 → 默认位姿 → 运动控制 → 阻尼退出"的完整控制闭环。
一、部署模块概览:支持机型与目录结构
该模块的目标是把训练好的强化学习策略部署到实物机器人上,目前仓库明确支持的机型为 Unitree G1、H1、H1_2,对应三份预训练权重与三份部署配置:
| 机型 | 配置文件 | 预训练策略权重 | DDS 消息类型 | IMU 安装位置 |
|---|---|---|---|---|
| G1 | configs/g1.yaml | deploy/pre_train/g1/motion.pt | hg | pelvis(骨盆) |
| H1 | configs/h1.yaml | deploy/pre_train/h1/motion.pt | go | torso(躯干) |
| H1_2 | configs/h1_2.yaml | deploy/pre_train/h1_2/motion.pt | hg | torso(躯干) |
部署代码的核心入口为 deploy/deploy_real/deploy_real.py,其主要目录结构如下:
deploy/deploy_real/ ├── deploy_real.py # 主程序:状态机 + 策略推理 + 指令下发 ├── config.py # Config 类:加载并解析 yaml 配置 ├── configs/ # 三份机型配置 │ ├── g1.yaml │ ├── h1.yaml │ └── h1_2.yaml └── common/ ├── command_helper.py # 零力矩/阻尼指令、LowCmd 初始化、电机模式定义 ├── remote_controller.py # 遥控器按键/摇杆解码(KeyMap) └── rotation_helper.py # 重力朝向提取、IMU 坐标系变换配套的预训练权重位于 deploy/pre_train/ 下,每个机型一份motion.pt(TorchScript 格式,由torch.jit.load直接加载推理)。
仓库内还提供了基于 C++ 的部署实现
deploy/deploy_real/cpp_g1/,本文以官方文档对应的 Python 部署流程为主线展开。
二、启动用法:命令行参数说明
部署程序通过命令行传入两个位置参数启动,完整命令格式为:
python deploy_real.py {net_interface} {config_name}两个参数的含义(与 deploy_real.py 中的argparse定义一一对应):
| 参数 | 含义 | 示例 | 说明 |
|---|---|---|---|
net_interface | 与机器人直连的网卡名称 | enp3s0 | 用ifconfig命令查看;作为 DDS 通信的网卡绑定参数 |
config_name | 配置文件名 | g1.yaml | 程序会在deploy/deploy_real/configs/目录下查找该文件 |
以 G1 机器人为例(假设当前连接真机的网卡名为enp3s0):
python deploy_real.py enp3s0 g1.yaml程序内部会通过LEGGED_GYM_ROOT_DIR拼出配置文件完整路径{LEGGED_GYM_ROOT_DIR}/deploy/deploy_real/configs/{config_name},再由 config.py 中的Config类以yaml.FullLoader加载并解析(见 deploy_real.py)。也就是说,配置文件名必须与configs/目录下的文件名完全一致,否则会因文件不存在而启动失败。
三、配置文件逐项解读:以 g1.yaml 为例
三份配置的结构完全一致,差异仅在于具体数值。这里以 configs/g1.yaml 为蓝本逐项拆解,并指出各参数在源码中的消费位置:
control_dt: 0.02 # 控制周期(秒),即 50Hz 控制频率 msg_type: "hg" # DDS 消息类型:"hg" 或 "go" imu_type: "pelvis" # IMU 坐标系:"torso" 或 "pelvis" lowcmd_topic: "rt/lowcmd" # 指令发布主题 lowstate_topic: "rt/lowstate" # 状态订阅主题 policy_path: "{LEGGED_GYM_ROOT_DIR}/deploy/pre_train/g1/motion.pt" # 策略权重路径 # 腿部关节:电机索引 → 关节索引映射 leg_joint2motor_idx: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] kps: [100, 100, 100, 150, 40, 40, 100, 100, 100, 150, 40, 40] # 位置增益 kds: [2, 2, 2, 4, 2, 2, 2, 2, 2, 4, 2, 2] # 速度增益 default_angles: [-0.1, 0.0, 0.0, 0.3, -0.2, 0.0, -0.1, 0.0, 0.0, 0.3, -0.2, 0.0] # 默认关节角(rad) # 手臂与腰部关节:电机索引 → 关节索引映射 arm_waist_joint2motor_idx: [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28] arm_waist_kps: [300, 300, 300, 100, 100, 50, 50, 20, 20, 20, 100, 100, 50, 50, 20, 20, 20] arm_waist_kds: [3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1] arm_waist_target: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] # 手臂/腰部目标角 # 观测与动作缩放(对应训练时 sim 侧的配置) ang_vel_scale: 0.25 # 角速度观测缩放 dof_pos_scale: 1.0 # 关节位置观测缩放 dof_vel_scale: 0.05 # 关节速度观测缩放 action_scale: 0.25 # 策略输出 → 关节位置增量 的缩放 cmd_scale: [2.0, 2.0, 0.25] # 摇杆指令缩放 num_actions: 12 # 动作维度(腿部关节数) num_obs: 47 # 观测维度 max_cmd: [0.8, 0.5, 1.57] # 指令上限:[x 速度, y 速度, yaw 角速度]各参数的消费位置梳理如下(源码佐证):
msg_type:决定使用哪套 DDS 消息结构。"hg"使用unitree_hg_msg_dds__LowCmd_/LowState_(G1、H1_2),"go"使用unitree_go_msg_dds__LowCmd_/LowState_(H1),分支逻辑见 deploy_real.py,非法值会抛出ValueError("Invalid msg_type")。imu_type:决定是否需要对 IMU 数据做坐标系变换。"pelvis"直接使用;"torso"(H1、H1_2)需借助腰部偏航角把躯干 IMU 数据变换到骨盆坐标系,见 deploy_real.py 与 rotation_helper.py。weak_motor(仅 h1.yaml 存在):H1 使用go消息时,这些电机索引会被设置为弱控制模式(mode = 1),其余电机使用mode = 0x0A的位置模式,见 command_helper.py。policy_path:其中{LEGGED_GYM_ROOT_DIR}占位符会被替换为仓库根目录绝对路径,见 config.py。default_angles/kps/kds:既用于"默认位置状态"的位姿保持,也作为策略动作叠加的基准(target_dof_pos = default_angles + action * action_scale)。max_cmd:与cmd_scale共同决定摇杆指令的幅值——观测中的指令项为cmd * cmd_scale * max_cmd。
3.1 三份配置的差异速览
| 配置项 | g1.yaml | h1.yaml | h1_2.yaml |
|---|---|---|---|
msg_type | hg | go | hg |
imu_type | pelvis | torso | torso |
weak_motor | 无 | [10..19] | 无 |
num_actions | 12 | 10 | 12 |
num_obs | 47 | 41 | 47 |
| 腿关节映射 | 顺序 0–11 | 交叉映射[7,3,4,5,10,8,0,1,2,11] | 顺序 0–11 |
| 默认关节角 | [-0.1, 0, 0, 0.3, -0.2, 0]×2 | [0, 0, -0.1, 0.3, -0.2]×2 | [0, -0.16, 0, 0.36, -0.2, 0]×2 |
注意 H1 的leg_joint2motor_idx是非顺序的交叉映射(电机索引与关节索引不对应),部署时务必使用对应机型的配置,不可混用。
四、启动流程:四步实操指南
官方文档给出的启动流程分为四步,每一步都有明确的机器人状态要求与操作动作,下面按顺序展开。
4.1 第一步:启动机器人
将机器人置于吊装状态下启动,并等待机器人进入零力矩模式(关节完全放松、可自由活动)。吊装的意义在于:在正式控制前机器人的腿不承受自身重力,可避免误动作造成危险。
4.2 第二步:进入调试模式
确认机器人处于零力矩模式后,按下遥控器的L2 + R2组合键,机器人进入调试模式。在调试模式下,机器人关节处于阻尼状态(有阻尼力矩但无主动位置控制),方便人工掰动机器人腿并保持姿态。
4.3 第三步:连接机器人
使用网线将电脑与机器人机身上的网口直连,并修改电脑的网络配置为固定 IP(使电脑与机器人处于同一网段,具体配置可参考原文档插图)。随后执行:
ifconfig查看与机器人相连的网卡名称(例如enp3s0),记录该名称——它将作为启动命令的第一个参数传入。这一步是 DDS 通信的基础:程序启动时会调用ChannelFactoryInitialize(0, args.net)(见 deploy_real.py),把 DDS 通信绑定到该网卡上。
4.4 第四步:启动程序
以 G1 为例:
python deploy_real.py enp3s0 g1.yaml程序启动后会先通过wait_for_low_state()循环等待低层状态数据(deploy_real.py),直到low_state.tick != 0才打印Successfully connected to the robot.并继续,随后按以下四个阶段依次推进。
五、程序状态机与源码级原理
deploy_real.py的主流程是一个清晰的四阶段状态机,其执行顺序见 deploy_real.py:
zero_torque_state → move_to_default_pos → default_pos_state → run(循环) → create_damping_cmd → 退出5.1 零力矩状态(zero torque state)
启动后机器人所有关节处于零力矩状态(kp=0, kd=0, tau=0,见 command_helper.py 的create_zero_cmd)。程序在此阶段循环等待遥控器start按键,期间持续下发零力矩指令。可以用手晃动机器人关节确认零力矩生效。
5.2 默认位置状态(default pos state)
按下start键后,机器人会先平滑过渡到默认关节位置(move_to_default_pos,耗时 2 秒、按alpha线性插值,见 deploy_real.py),随后进入默认位置保持状态。此时机器人双腿由default_angles+ 腿部kps/kds支撑,手臂/腰部由arm_waist_target+arm_waist_kps/kds保持。
关键操作:在机器人运动到默认关节位置后,缓慢下放吊装机构,让机器人的脚与地面接触。这步要慢,让机器人逐步承重,观察其是否稳定。
5.3 运动控制模式(motion control)
默认位置状态下按下遥控器A键,机器人进入运动控制模式,开始原地踏步。在机器人状态稳定后,可逐渐降低吊装绳,给机器人留出活动空间。此时进入run()主循环(deploy_real.py),每个控制周期(control_dt=0.02s,即 50Hz)执行一轮"读取状态 → 构造观测 → 策略推理 → 下发指令"。
控制循环的核心调用链
- 读取关节状态:从
low_state.motor_state[leg_joint2motor_idx[i]]读取各腿关节位置q与速度dq; - 读取 IMU 数据:取四元数
quaternion(顺序w,x,y,z)与陀螺仪角速度;imu_type == "torso"时经transform_imu_data变换到骨盆系(见 rotation_helper.py); - 构造观测向量(
num_obs=47维,见 deploy_real.py):
| 观测槽位 | 内容 | 计算方式 |
|---|---|---|
| 0–2 | 角速度 | ang_vel * ang_vel_scale |
| 3–5 | 重力朝向 | get_gravity_orientation(quat),见 rotation_helper.py |
| 6–8 | 速度指令 | cmd * cmd_scale * max_cmd |
| 9–20 | 关节位置 | (qj - default_angles) * dof_pos_scale |
| 21–32 | 关节速度 | dqj * dof_vel_scale |
| 33–44 | 上一帧动作 | action |
| 45 | 相位正弦 | sin(2π·phase),周期0.8s |
| 46 | 相位余弦 | cos(2π·phase) |
- 策略推理:
torch.jit.load(config.policy_path)加载 TorchScript 模型(deploy_real.py),self.action = self.policy(obs_tensor)输出动作; - 动作 → 关节位置:
target_dof_pos = default_angles + action * action_scale; - 下发指令:
send_cmd中先计算 CRC 校验再lowcmd_publisher_.Write(cmd)(deploy_real.py),保证指令帧完整可靠。
遥控器摇杆映射
运动控制模式下,通过遥控器双摇杆控制机器人(代码见 deploy_real.py,按键/摇杆解码见 remote_controller.py):
| 操作 | 控制内容 | 源码映射 |
|---|---|---|
| 左摇杆前后 | x 方向运动速度 | cmd[0] = ly |
| 左摇杆左右 | y 方向运动速度 | cmd[1] = -lx |
| 右摇杆左右 | 偏航角 yaw 角速度 | cmd[2] = -rx |
5.4 退出控制(exit)
运动控制模式下,有两种退出方式:
- 按下遥控器
select键:主循环检测到KeyMap.select == 1后跳出循环(deploy_real.py); - 终端
Ctrl+C:捕获KeyboardInterrupt跳出循环。
无论哪种方式,退出前都会下发一次create_damping_cmd——将所有关节设置为阻尼模式(kd=8, kp=0, tau=0,见 command_helper.py),机器人会因失去主动支撑而自然倒下,随后程序打印Exit结束。
安全提示(原文重点):本示例部署并非稳定的控制程序,仅用于演示目的。控制过程中请尽量不要给机器人施加外部扰动;如果出现任何意外情况,请及时退出控制,以免发生危险。这也解释了为什么整个流程始终围绕吊装、阻尼、零力矩这些"软着陆"手段展开。
六、通信层原理:DDS 与两种消息协议
部署程序依赖unitree_sdk2py与机器人底层通过DDS(Data Distribution Service)通信,主题为rt/lowcmd(下行指令)与rt/lowstate(上行状态):
hg消息族(G1、H1_2):unitree_hg_msg_dds__LowCmd_/LowState_,初始化时需设置mode_machine与mode_pr(MotorMode.PR = 0对应俯仰/滚转关节串联控制,见 command_helper.py),所有电机mode = 1;go消息族(H1):unitree_go_msg_dds__LowCmd_/LowState_,初始化时写入帧头0xFE 0xEF、level_flag = 0xFF,位置/速度停止位使用大数值哨兵值PosStopF = 2.146e9、VelStopF = 16000.0,弱电机与普通电机使用不同mode(见 command_helper.py)。
低层状态通过订阅回调LowStateHgHandler/LowStateGoHandler更新(deploy_real.py),同一回调内还会把wireless_remote原始字节流喂给RemoteController.set()解码出 16 个按键位与 4 个摇杆轴值——这正是遥控器控制的底层数据来源。
七、视频教程与进一步阅读
原文档还提供了三个机型各自完整的部署演示视频(G1 / H1 / H1_2),视频链接收录于 deploy/deploy_real/README.md 末尾的 "Video tutorial" 一节,部署前建议先观看对应机型的完整操作过程。
若希望深入理解训练侧如何产出这些策略,可继续阅读:
- 训练入口 legged_gym/scripts/train.py 与推理入口 legged_gym/scripts/play.py;
- 环境配置 legged_gym/envs/g1/g1_config.py、legged_gym/envs/h1/h1_config.py、legged_gym/envs/h1_2/h1_2_config.py(其中观测维度、缩放系数与部署配置一一对应);
- 环境实现 legged_gym/envs/base/legged_robot.py(训练时观测/奖励的计算方式);
- 另外 deploy/deploy_real/README.md 提供了部署在 G1 上的 C++ 版本实现(
deploy/deploy_real/cpp_g1/),适合对实时性有更高要求的二次开发场景。
【免费下载链接】unitree_rl_gym项目地址: https://gitcode.com/GitHub_Trending/un/unitree_rl_gym
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考