# Go1 RL-Gym 45 维部署说明 本目录包含: - `policy_15k.onnx`:RoboGauge Go1 RL-Gym 的 ONNX 策略 - `deploy_go1_onnx_mujoco.py`:MuJoCo 调试脚本 - `deploy_go1_rlgym_pro_sdk.py`:真机 Go1 PRO 低层部署脚本 该 ONNX 策略使用 45 维单帧观测,以及 5 帧、共 225 维的历史输入,按观测项分组堆叠: ```text [角速度历史, 重力投影历史, 指令历史, 关节位置历史, 关节速度历史, 上一动作历史] ``` 关节顺序为 `FR, FL, RR, RL`,与 `go1_pro_sdk` 的电机顺序一致。 ## 安全说明 直接低层控电机是危险操作。 - 第一次测试必须悬空 - 低层控制前先杀掉 sport 进程 - sport 被杀后,要保留拔电池作为最终停机手段 - 真机状态机中,`L2` 会返回 `IDLE` 阻尼 - `Ctrl+C` 会通过 `safe_stop()` 退出 - 只有显式加 `--enable-rl` 才允许真正进入 RL 发电机目标 - 脚本启动连接 MCU 前会自动检查 SDK 电机顺序是否为 `FR, FL, RR, RL` - 遥控器速度指令默认只保留 deadzone,不再做低通和变化率限制;日志中仍会同时保存原始 `commands_raw` 和实际输入策略的 `commands` - RL 刚进入时会先 warmup,只预热观测历史和动作历史;warmup 期间仍保持默认站姿,结束后再按 `max_target_step` 从默认站姿逐步进入 RL 目标 ## 环境准备 ```bash cd /Users/chenyouyuan/cyy_ws/deploy_go1_pro conda activate free_dog_sdk ``` 杀掉机器人上的 sport 进程: ```bash ssh pi@192.168.123.161 "sudo pkill -9 -f keep_sport_alive; sudo pkill -9 -f Legged_sport; sudo pkill -9 -f appTransit" ``` 或者在部署脚本里直接加 `--kill-sport`。 脚本执行 `--kill-sport` 时,会打印并执行等价的 SSH 命令。如果不加 `--kill-sport`,请务必手动执行上面的命令。 ## 启动前电机顺序检查 真机脚本启动连接 MCU 前会自动检查: ```text SDK 顺序必须是: FR_0 FR_1 FR_2 FL_0 FL_1 FL_2 RR_0 RR_1 RR_2 RL_0 RL_1 RL_2 策略顺序对应: FR_hip FR_thigh FR_calf FL_hip FL_thigh FL_calf RR_hip RR_thigh RR_calf RL_hip RL_thigh RL_calf ``` 如果 SDK 顺序不一致,脚本会直接报错并停止,不会继续连接机器人。 检查通过时会打印类似: ```text [INFO] Joint order check passed: SDK and policy both use FR, FL, RR, RL. [00] FR_0 -> FR_hip default=-0.100 [01] FR_1 -> FR_thigh default=+0.800 [02] FR_2 -> FR_calf default=-1.500 ... [11] RL_2 -> RL_calf default=-1.500 ``` 连接成功后,脚本还会逐项打印当前电机角度和默认角度: ```text [INFO] Initial joint positions (rad): [00] FR_0: q=..., default=-0.100 ... [11] RL_2: q=..., default=-1.500 ``` ## 第 1 步:只取数据 只读 LowState、IMU、关节和遥控器数据,不发任何电机命令。 ```bash mjpython deploy_45dim_rl_gym/deploy_go1_rlgym_pro_sdk.py \ --monitor \ --kill-sport \ --log-dir logs ``` 检查: - 电量正常 - 机器人姿态变化时,RPY 会跟着变化 - 12 个关节位置不是全 0 - 遥控器按键和摇杆变化能正常打印 ## 第 2 步:测试遥控器 继续用 `--monitor`,依次测试: - 按 `R2` - 按 `L2` - 左摇杆前后、左右 - 右摇杆左右 期望结果: - `pressed`、`rising`、`falling` 会正确变化 - `lx`、`ly`、`rx` 会正确变化 - 不会有任何电机动作 ## 第 3 步:测试观测构建 只构建 45 维观测和 225 维 ONNX 历史输入,不做 RL 控制。 ```bash mjpython deploy_45dim_rl_gym/deploy_go1_rlgym_pro_sdk.py \ --obs-check \ --kill-sport \ --log-dir logs ``` 检查: - 站立时重力投影接近 `[0, 0, -1]` - 指令观测会随遥控器变化 - `q-qd max` 在合理范围内 - ONNX 输入形状是 `(1, 225)` ## 第 4 步:只测试 ONNX 推理 只跑 ONNX 推理,不发 RL 电机目标。 ```bash mjpython deploy_45dim_rl_gym/deploy_go1_rlgym_pro_sdk.py \ --infer-check \ --kill-sport \ --log-dir logs ``` 检查: - `action_raw max` 不会突然爆大 - 零指令时动作应比较稳定 - 长时间给 yaw 指令时,动作不应持续发散 ## 第 5 步:测试状态机和退出 不加 `--enable-rl`,这样只会走校准、保持、观测和推理层,不会真正进入 RL 电机控制。 ```bash mjpython deploy_45dim_rl_gym/deploy_go1_rlgym_pro_sdk.py \ --kill-sport \ --log-dir logs ``` ### 遥控器操作步骤 先把机器人悬空,四条腿下方不要站人,手指始终放在 `L2` 上。每按一次 `R2` 后都要等终端打印出对应状态,并观察 5 到 10 秒再按下一次。 ```text 启动后: 状态应为 IDLE 电机处于阻尼/空闲,不应主动站立 第 1 次按 R2: IDLE -> CALIBRATE -> HOLD 机器人会缓慢回到默认站姿 等终端打印 [STATE] HOLD 第 2 次按 R2: HOLD -> OBS_TEST 电机仍保持默认站姿 只构建观测,不使用 ONNX 动作控制电机 第 3 次按 R2: OBS_TEST -> INFER_TEST 电机仍保持默认站姿 只运行 ONNX 推理,动作只写日志,不控制电机 第 4 次按 R2: 未加 --enable-rl 时会被守卫拦住 终端应打印 RL blocked 任意激活状态按 L2: 立即回到 IDLE 阻尼 Ctrl+C: 调用 safe_stop() 并退出脚本 ``` 必须确认: ```text R2 每次只前进一层 L2 在 HOLD / OBS_TEST / INFER_TEST 都能回到 IDLE 松开 R2/L2 后,日志里 rising/falling 不应连续乱跳 摇杆不动时,lx/ly/rx/ry 应接近 0 ``` 检查: - 校准会缓慢回到默认站姿 - `HOLD` 会保持默认站姿 - `L2` 能回到 `IDLE` - `Ctrl+C` 会正常打印 `Safe stopping...` 并退出 ## 第 6 步:悬空 RL 测试 只有前 1 到 5 步都稳定后,才加 `--enable-rl` 进行悬空 RL。第一轮必须先隔离遥控器摇杆输入,用 `--no-rc` 固定零指令,只用遥控器按键切状态: ```bash mjpython deploy_45dim_rl_gym/deploy_go1_rlgym_pro_sdk.py \ --kill-sport \ --enable-rl \ --no-rc \ --cmd-x 0 --cmd-y 0 --cmd-yaw 0 \ --log-dir logs \ --kp 60 --kd 1.0 \ --kp-cal 20 --kd-cal 1.0 \ --power-factor 6 \ --position-protect-limit 0.8 \ --action-clip 2.5 \ --action-trip-limit 8.0 \ --max-target-step 0.04 \ --max-roll-deg 25 \ --max-pitch-deg 25 ``` ### RL 遥控器操作步骤 第一轮带 `--no-rc`,摇杆不会进入策略,只用 `R2` 和 `L2` 切状态。每一步都等终端状态确认后再继续。 ```text 启动后: 状态应为 IDLE 第 1 次按 R2: IDLE -> CALIBRATE -> HOLD 等站姿稳定 第 2 次按 R2: HOLD -> OBS_TEST 等 5 到 10 秒,确认 RPY、q 和 dq 稳定 第 3 次按 R2: OBS_TEST -> INFER_TEST 等 5 到 10 秒,确认 action_raw_max 不突然变大 第 4 次按 R2: INFER_TEST -> RL 先只观察 10 到 20 秒,不推摇杆 RL 中再按 R2: RL -> HOLD 用来从 RL 平稳退回保持站姿 任意异常立即按 L2: 回到 IDLE 阻尼 需要退出脚本: 先按 L2 回 IDLE 再 Ctrl+C ``` 悬空 RL 时: - 先用 `--no-rc` 保持零指令 - 零指令稳定后,再取消 `--no-rc` 并用很小的摇杆比例 - 观察 `action_raw_max`、`action_safe_max`、RPY 和关节目标 - 刚进入 RL 的前 `warmup_steps` 帧不会真正发送 RL 目标,之后目标应按 `max_target_step` 平滑变化 - 一旦动作或姿态不对,立刻按 `L2` ## 参数逐层强化 建议先用小参数,再逐层加到当前目标值。前一层如果还不稳定,不要跳层。每层至少稳定 1 到 2 分钟再升级。 ### 第 0 层:完全不控电机 先跑: ```bash mjpython deploy_45dim_rl_gym/deploy_go1_rlgym_pro_sdk.py --monitor --kill-sport --log-dir logs mjpython deploy_45dim_rl_gym/deploy_go1_rlgym_pro_sdk.py --obs-check --kill-sport --log-dir logs mjpython deploy_45dim_rl_gym/deploy_go1_rlgym_pro_sdk.py --infer-check --kill-sport --log-dir logs ``` 只有在状态、遥控、观测和动作日志都正常时,才进入下一层。 ### 第 1 层:弱校准和保持 先不进 RL,只测试起立、保持、`R2`、`L2` 和 `Ctrl+C`。 ```bash mjpython deploy_45dim_rl_gym/deploy_go1_rlgym_pro_sdk.py \ --kill-sport \ --log-dir logs \ --kp 20 --kd 0.7 \ --kp-cal 10 --kd-cal 0.7 \ --power-factor 3 \ --position-protect-limit 0.4 ``` 只有在校准平滑、能稳定保持、`L2` 能可靠回到 `IDLE` 时才升级。 ### 第 2 层:中等校准和保持 仍然不进 RL。 ```bash mjpython deploy_45dim_rl_gym/deploy_go1_rlgym_pro_sdk.py \ --kill-sport \ --log-dir logs \ --kp 40 --kd 0.8 \ --kp-cal 15 --kd-cal 0.8 \ --power-factor 5 \ --position-protect-limit 0.6 ``` 只有在保持姿态稳定、关节不抖时才继续。 ### 第 3 层:保守悬空 RL,固定零指令 开始允许 RL,但固定零指令,先确认策略本体能悬空稳定,不测试摇杆速度指令。 ```bash mjpython deploy_45dim_rl_gym/deploy_go1_rlgym_pro_sdk.py \ --kill-sport \ --enable-rl \ --no-rc \ --cmd-x 0 --cmd-y 0 --cmd-yaw 0 \ --log-dir logs \ --kp 60 --kd 1.0 \ --kp-cal 20 --kd-cal 1.0 \ --power-factor 6 \ --position-protect-limit 0.8 \ --action-clip 2.5 \ --action-trip-limit 8.0 \ --max-target-step 0.04 \ --max-roll-deg 25 \ --max-pitch-deg 25 ``` 只有在悬空 RL 零指令稳定时才进入下一层。 ### 第 3.5 层:保守悬空 RL,小遥控比例 取消 `--no-rc`,但先把摇杆比例限制到小范围。脚本默认还会对遥控器命令做 deadzone、低通和变化率限制。 如果加 `--swap-vy-yaw`,遥控映射会变成: ```text 左摇杆前后 ly -> vx 左摇杆左右 lx -> yaw 右摇杆左右 rx -> vy ``` ```bash mjpython deploy_45dim_rl_gym/deploy_go1_rlgym_pro_sdk.py \ --kill-sport \ --enable-rl \ --log-dir logs \ --kp 60 --kd 1.0 \ --kp-cal 20 --kd-cal 1.0 \ --power-factor 6 \ --position-protect-limit 0.8 \ --action-clip 2.5 \ --action-trip-limit 8.0 \ --max-target-step 0.06 \ --max-roll-deg 25 \ --max-pitch-deg 25 \ --swap-vy-yaw \ --rc-vx-scale 0.3 \ --rc-vy-scale 0.15 \ --rc-wz-scale 0.5 ``` 这一层不要直接长时间满杆。建议按下面顺序测,每次给很短的摇杆脉冲,松杆回中后等姿态稳定再继续: ```text 进入 RL 后先零摇杆观察 10 秒 左摇杆前后: ly 轻推到约 1/3 行程,保持 0.5 到 1 秒,松开 观察 roll/pitch、qvel、action_raw_max 左摇杆左右: 加 --swap-vy-yaw 后控制 yaw lx 轻推到约 1/3 行程,保持 0.5 到 1 秒,松开 如果 yaw 仍慢,可以逐步把 --rc-wz-scale 从 0.5 提到 0.7 右摇杆左右: 加 --swap-vy-yaw 后控制 vy rx 轻推到约 1/3 行程,保持 0.5 到 1 秒,松开 观察横向动作是否明显发散 任何时候: action_raw_max 接近 2.0、qvel 明显变大、roll/pitch 持续变大,立即按 L2 ``` 这一层重点检查 `commands_raw` 和 `commands`:默认无命令滤波时两者应基本一致。如果手动启用了 `--cmd-ema-alpha` 或 `--max-cmd-step-*`,则 `commands` 会比 `commands_raw` 更慢变化。 ### 第 4 层:当前目标参数 这是当前想要的正式参数。只有第 3 层和第 3.5 层都稳定后再用。 ```bash mjpython deploy_45dim_rl_gym/deploy_go1_rlgym_pro_sdk.py \ --kill-sport \ --enable-rl \ --log-dir logs \ --kp 80 --kd 1.0 \ --kp-cal 20 --kd-cal 1.0 \ --power-factor 7 \ --position-protect-limit 1.0 \ --action-clip 4.0 \ --action-trip-limit 12.0 \ --max-target-step 0.08 \ --swap-vy-yaw \ --rc-vx-scale 0.5 \ --rc-vy-scale 0.25 \ --rc-wz-scale 0.7 ``` 这些值仍低于全遥控比例,用来逐步靠近正式测试;不要直接用满 `1.0/0.5/1.0`。 ## 第 7 步:上地面测试 只有悬空 RL 稳定后,才能落地。 1. 把机器人放到平地上 2. 零指令进入 RL 3. 先让它站稳 4. 再给小指令 建议起始范围: ```text ly <= 0.2 lx <= 0.1 rx <= 0.2 ``` 如果出现以下情况,立即按 `L2`: - 动作越来越大 - roll 或 pitch 持续变大 - 腿乱甩 - 机器人开始摔倒或打滑 ### 15 cm 台阶测试参数 `stairs_3.xml` 的单级高度约 `0.14 m`。从 MuJoCo 采样和真机日志看,上台阶时 pitch 到 `25 deg` 以上、roll 短时超过 `35 deg` 都可能出现。台阶测试不要继续用平地/悬空的 `25 deg` 或 `35 deg` 姿态保护。 建议台阶第一轮用下面这组。它比平地测试放开姿态和动作幅度,但仍保留目标位置变化率限制,避免单帧目标跳变太大: ```bash mjpython deploy_45dim_rl_gym/deploy_go1_rlgym_pro_sdk.py \ --kill-sport \ --enable-rl \ --log-dir logs \ --kp 36 --kd 1.0 \ --kp-cal 20 --kd-cal 1.0 \ --power-factor 9 \ --position-protect-limit 0.0 \ --action-clip 5.0 \ --action-trip-limit 8.0 \ --max-target-step 0.0 \ --max-roll-deg 50 \ --max-pitch-deg 50 \ --swap-vy-yaw \ --rc-vx-scale 0.5 \ --rc-vy-scale 0.5 \ --rc-wz-scale 1.0 ``` 如果动作幅度仍明显不够,再把 `--max-target-step` 从 `0.15` 加到 `0.20`。只有确认目标变化率限制确实挡住抬腿时,才短时间对照测试 `--max-target-step 0`。 `--action-trip-limit 9.0` 只是把 raw action 的异常停机阈值从 `8.0` 放宽到 `9.0`;实际发给关节目标的动作仍会先被 `--action-clip 4.0` 裁剪,所以它不会直接增加腿部动作幅度。如果 raw action 经常超过 `9.0`,说明观测或姿态已经明显偏离训练分布,应按 `L2` 退回而不是继续放大阈值。 `--max-target-step 0` 的意思是关闭单步目标变化率限制,不是关闭关节硬限位、action clip 或 SDK 安全保护。真机日志 `rlgym_go1_deploy_20260724_172122` 里,`max_target_step=0`、`position_protect_limit=1.5`、`power_factor=9` 时触发的是实测扭矩保护:`tauEst` 已超过 SDK 的 `TAU_MAX`,所以脚本会进入 `FAULT` 并阻尼停机。 这只是放宽姿态保护,不是关闭全部安全保护。`action_trip_limit`、`max_dof_vel`、`max_gyro`、`position_protect_limit`、实测扭矩保护和 `L2` 急停仍然保留。 注意:`--power-factor` 主要限制命令力矩 `tau` 的比例;这个部署脚本发送的是位置控制,命令 `tau=0`。实测 `tauEst` 超过 SDK `TAU_MAX` 时,即使 `power_factor=9` 也会停机。遇到这种停机,优先减小瞬时目标跳变或速度指令,不要继续只增大 `power_factor`。 目前台阶实测后的建议顺序: ```text 第一轮: position_protect_limit=1.2, max_target_step=0.15, power_factor=6 第二轮: position_protect_limit=1.2, max_target_step=0.20, power_factor=6 第三轮: position_protect_limit=1.5, max_target_step=0.20, power_factor=6 或 7 短时对照: position_protect_limit=1.5, max_target_step=0, power_factor=6 或 7 ``` 如果出现 `PowerProtectViolation`,说明已经是实测扭矩过载边缘。下一轮建议回退到上一层参数,或者降低 `--rc-vx-scale` / 避免连续满前进杆。 ## MuJoCo 键盘 sim2sim 键盘控制测试直接用本目录的 `deploy_go1_onnx_mujoco.py`。它加载同一个 `policy_15k.onnx`,使用 45 维观测和 5 帧 ONNX 历史,在 MuJoCo 里做位置 PD 控制。 平地启动: ```bash cd /Users/chenyouyuan/cyy_ws/deploy_go1_pro conda activate free_dog_sdk mjpython deploy_45dim_rl_gym/deploy_go1_onnx_mujoco.py \ --clip-actions 4.0 \ --max-target-step 0.15 ``` 楼梯 level 3 启动: ```bash cd /Users/chenyouyuan/cyy_ws/deploy_go1_pro conda activate free_dog_sdk mjpython deploy_45dim_rl_gym/deploy_go1_onnx_mujoco.py \ --terrain terrains/stairs/stairs_3.xml \ --spawn-x -0.6 \ --spawn-z 0.34 \ --clip-actions 4.0 \ --max-target-step 0.15 ``` 如果你想对照策略原始动作能力,可以短时间把 `--max-target-step` 改成 `0.0`: ```bash mjpython deploy_45dim_rl_gym/deploy_go1_onnx_mujoco.py \ --terrain terrains/stairs/stairs_3.xml \ --spawn-x -0.6 \ --spawn-z 0.34 \ --clip-actions 4.0 \ --max-target-step 0.0 ``` 键盘控制: ```text 方向键 ↑ / ↓ : 前进 / 后退 方向键 ← / → : 左转 / 右转 yaw , / . : 左移 / 右移 vy K : 零速度指令 R : 重置机器人 Esc : 退出 ``` 如果键盘没有响应,先点一下 MuJoCo 窗口或终端,让当前窗口获得焦点。macOS 第一次使用 `pynput` 可能需要给终端或 Python 辅助功能权限。 ## MuJoCo 楼梯采样 可以先在 MuJoCo 里固定前进指令采样楼梯 level 3。`stairs_3.xml` 的单级高度约 `0.14 m`,接近 `15 cm` 台阶。 默认前进速度、真机放开动作幅度、但保留较严格目标步长限制: ```bash conda activate free_dog_sdk mjpython deploy_45dim_rl_gym/deploy_go1_onnx_mujoco.py \ --sample-stairs-level 3 \ --sample-seconds 10 \ --sample-cmd-x 1.0 \ --sample-cmd-y 0 \ --sample-cmd-yaw 0 \ --clip-actions 4.0 \ --max-target-step 0.08 \ --sample-log-dir logs ``` 如果 `0.08` 在楼梯上动作太小,可以用下面这个对照测试策略原始能力: ```bash mjpython deploy_45dim_rl_gym/deploy_go1_onnx_mujoco.py \ --sample-stairs-level 3 \ --sample-seconds 10 \ --sample-cmd-x 1.0 \ --sample-cmd-y 0 \ --sample-cmd-yaw 0 \ --clip-actions 4.0 \ --max-target-step 0.0 \ --sample-log-dir logs ``` 采样日志会保存: ```text logs/mujoco_stairs_sample_YYYYMMDD_HHMMSS/ metadata.json steps.jsonl summary.json ``` 重点看: - `fallen` - `base_x_progress` - `rpy_min_deg` / `rpy_max_deg` - `action_raw_maxabs` - `action_applied_maxabs` - `target_offset_maxabs` - `dof_vel_maxabs` ## 日志 日志会保存在: ```text logs/rlgym_go1_deploy_YYYYMMDD_HHMMSS/ metadata.json steps.jsonl ``` 常看字段: - `commands` - `commands_raw` - `obs_single` - `action_raw` - `action_safe` - `joint_targets` - `dof_pos` - `dof_vel` - `base_ang_vel` - `projected_gravity` - `imu_rpy_deg` - `state_reason` ## 常用默认值 真机部署脚本使用的默认值如下: ```text kp = 80.0 kd = 1.0 kp_cal = 20.0 kd_cal = 1.0 power_factor = 7 position_protect_limit = 1.0 action_ema_alpha = 0.0 rc_deadzone = 0.05 cmd_ema_alpha = 1.0 max_cmd_step_x = 0.0 max_cmd_step_y = 0.0 max_cmd_step_yaw = 0.0 rate_hz = 50.0 ``` 这些值来自之前成功的 Go1 PRO 低层部署经验。`rlgym_go1_deploy_20260724_193128` 和 `rlgym_go1_deploy_20260724_193318` 对照显示,当前 45 维策略在真机上关闭遥控器命令低通/变化率限制更稳定;如需重新启用滤波,应只作为单独变量短时对照测试。 RoboGauge 策略自己的参数不要照搬旧的 57 维策略: ```text action_scale = 0.25 default_dof_pos = FR, FL, RR, RL 顺序下的 [-0.1/0.1, 0.8/1.0, -1.5] history_len = 5 onnx_input_dim = 225 ```