legged_rl_deploy deploys learned policies on top of unitree_lowlevel for Unitree Go2 and G1 robots.
It provides:
- single-policy deployment from a single
config.yaml - multi-policy deployment with gamepad-triggered switching via
fsm - ONNX Runtime and LibTorch inference backends
- local-file and Redis-based mimic motion sources
- sample policies and deployment configs for Go2 and G1
This package inherits the low-level control loop, safety logic, and hardware adapters from unitree_lowlevel. The RL policy only becomes active after the low-level controller enters HighController.
The deployed config is passed directly to:
ros2 run legged_rl_deploy legged_rl_deploy_node <network-interface> <config-file>Two config styles are supported:
- Single-policy config: top-level
policy:section - Multi-policy config: top-level
fsm:section with multiple sub-policies and gamepad transitions
Video demo:
The repository already includes several example policies:
policies/
├── go2/
│ ├── My_unitree_go2_gym/
│ │ ├── trot/
│ │ ├── hop/
│ │ ├── handstand/
│ │ ├── legstand/
│ │ ├── spring_jump/
│ │ └── multi-policies.yaml
│ ├── mjlab/
│ │ ├── velocity/
│ │ ├── hop/
│ │ ├── mimic/
│ │ └── multi-policies.yaml
│ ├── unitree_rl_lab/
│ │ └── velocity/
│ └── aba/
│ └── velocity/
└── g1/
├── velocity/
│ ├── unitree_rl_mjlab/
│ └── mjlab/
├── mimic/
│ ├── unitree_rl_lab/
│ │ ├── dance_102/
│ │ └── gangnam_style/
│ ├── unitree_rl_mjlab/
│ │ └── dance1_subject2/
│ ├── mjlab/
│ │ └── dance1_subject1/
│ ├── whole_body_tracking/
│ │ └── jumps1_subject1/
│ └── TWIST2/
├── aba/
│ ├── velocity/
│ ├── dance102/
│ ├── jumps1_subject1/
│ └── multi-policies.yaml
└── multi-policies.yaml
Included policy sources referenced by this repo:
| Source | Link |
|---|---|
| unitree_rl_lab | github.com/unitreerobotics/unitree_rl_lab |
| My_unitree_go2_gym | github.com/yusongmin1/My_unitree_go2_gym |
| mjlab | github.com/mujocolab/mjlab |
| unitree_rl_mjlab | github.com/mujocolab/unitree_rl_mjlab |
Some configs in this repo are experiment-specific derivatives or internally retargeted motions.
unitree_lowlevelbuilt in the same workspace- ROS 2 workspace already initialized and buildable with
colcon
Most bundled policies use backend: ort, so ONNX Runtime is effectively required for the default examples:
cd $WORKSPACE/src/legged_rl_deploy
./scripts/get_ort.shThis downloads ONNX Runtime into thirdparty/onnxruntime.
Use LibTorch only if your policy config sets backend: libtorch or backend: torch.
Helper script:
cd $WORKSPACE/src/legged_rl_deploy
./scripts/get_torch.shPlatform-specific notes are in LibTorch.md.
Redis support is compiled in only when hiredis is available at build time:
sudo apt install -y libhiredis-dev redis-toolsThis is only needed for configs using mimic.params.source: redis, such as policies/g1/mimic/TWIST2/config.yaml.
Clone the repository into the workspace:
cd unitree_ws/src
git clone https://github.com/Renkunzhao/legged_rl_deploy.gitIf you plan to use:
- ONNX Runtime: run
./scripts/get_ort.shfirst - LibTorch: install it and set environment variables as described in LibTorch.md before building
- Redis mimic: install
libhiredis-devbefore building
Then build:
cd unitree_ws
source /opt/ros/<ros-distro>/setup.bash
colcon build --packages-up-to legged_rl_deploy --cmake-args -DPython3_EXECUTABLE=/usr/bin/python3
source install/setup.bashNote: The explicit
Python3_EXECUTABLEavoids clean-build failures whenpython3points to a Conda environment without the ROS build dependencies.
legged_rl_deploy still relies on the low-level controller setup from unitree_lowlevel.
For Go2 hardware, stop the default controller once after each boot:
source src/unitree_lowlevel/scripts/setup.sh <network-interface> <ros-distro>
$WORKSPACE/build/unitree_sdk2/bin/go2_stand_example <network-interface>For G1 hardware, enter Debug Mode first as described in the unitree_lowlevel documentation.
From the workspace root, use the helper wrapper:
./src/legged_rl_deploy/scripts/run.sh <network-interface> <ros-distro> ros2 run legged_rl_deploy legged_rl_deploy_node <network-interface> <config-file>The wrapper:
- sources
unitree_lowlevel/scripts/setup.sh - sets
CMAKE_PREFIX_PATHandLD_LIBRARY_PATHfor Torch on x86_64 - sets the corresponding Torch paths from Python on aarch64
The node inherits the same safety confirmation as unitree_lowlevel:
WARNING: Make sure the robot is hung up or lying on the ground.
Press Enter to continue...
In practice, the flow is:
- Start the node
- Confirm the safety prompt
- Use the low-level controller gamepad flow to reach
FixStand - Press
STARTto enterHighController - The RL policy then takes control
If you are using a multi-policy config, policy switching is handled by the fsm.policies.*.transitions entries in the YAML file.
Single-policy configs typically define:
llc_config_file: low-level config fromunitree_lowlevelll_dt: low-level timestep overridepolicy.backend:ort,onnxruntime,torch, orlibtorchpolicy.model_path: model file path relative to$WORKSPACEpolicy.observations: observation terms and assembly layoutpolicy.actions: output post-processingpolicy.commands: command preprocessing
Multi-policy configs additionally define:
clip_final_tau: optional torque-mode output instead of PD targetsfsm.default: policy activated when enteringHighControllerfsm.policies.<name>.config: sub-policy config pathfsm.policies.<name>.transitions: button mappings for switching
For Redis-based mimic motion:
sudo apt install -y libhiredis-dev redis-toolsRebuild legged_rl_deploy after installing hiredis, otherwise Redis support will remain disabled in the compiled binary.
You can inspect Redis keys with:
redis-cli -h 127.0.0.1 -p 6379 -n 0 --scanRun:
cd $WORKSPACE/src/legged_rl_deploy
./scripts/get_ort.shThen rebuild the package.
Install LibTorch, export the required paths from LibTorch.md, and rebuild the package.
Install libhiredis-dev, then rebuild the package so USE_HIREDIS is enabled.
If you see an error like:
Target "cmTC_xxxx" requires the language dialect "CUDA17", but CMake does not know the compile flags to use to enable it.
Update CMake to a newer version that supports CUDA17.