Pico 4 VR Teleoperation on Unitree G1
Use this tutorial after Pico Sim2Sim is working. It deploys the same realtime Pico input path to a physical Unitree G1.
Pico headset -> Teleopit host -> retarget -> RL policy -> g1_bridge_sdk -> G1
There are two deployment styles:
| Deployment | Where Teleopit Runs | Main Difference |
|---|---|---|
| Wired PC-to-G1 | External workstation or laptop | Set real_robot.network_interface to the PC Ethernet interface connected to G1 |
| Onboard | G1 onboard computer | Install Teleopit on the onboard computer; eth0 is usually correct |
Both styles use Pico4InputProvider and the in-process pico-bridge receiver.
There is no separate onboard Pico input mode.
1. Install Runtime Dependencies
Install Pico and sim2real dependencies on the machine that will run Teleopit:
pip install -e '.[pico4]'
git submodule update --init --recursive
bash scripts/setup/setup_g1_bridge.sh
Verify Pico receiver import:
python -c "from pico_bridge import PicoBridge; print('OK')"
2. Choose The Network Interface
real_robot.network_interface is the Linux interface used for Unitree DDS
communication.
For wired PC-to-G1 deployment:
- Connect the PC to the G1 by Ethernet.
- Run
ifconfigon the PC. - Use the Ethernet interface connected to the robot, for example
enp130s0. - Keep the Pico headset on a network that can reach the PC running Teleopit.
For onboard deployment:
- Run Teleopit on the robot onboard computer.
- Keep the Pico headset on a network that can reach the onboard computer.
- Use
real_robot.network_interface=eth0unless your robot network differs. - Set
input.bridge_advertise_ip=<host-ip>if Pico discovery advertises the wrong address.
Onboard RealSense On Arm
The pico-bridge PC receiver supports Arm machines when the required Python
dependencies are available. On Arm onboard computers that need RealSense preview,
install pyrealsense2 from conda-forge in the active Conda environment instead
of relying on the pip package:
pip uninstall pyrealsense2
conda install -c conda-forge pyrealsense2
This only matters when using the optional RealSense preview path
(input.video.enabled=true). Pico tracking and robot control do not require
RealSense.
3. Run The Controller
Wired PC example:
python scripts/run/run_sim2real.py \
--config-name pico4_sim2real \
controller.policy_path=track.onnx \
real_robot.network_interface=enp130s0
Onboard example:
python scripts/run/run_sim2real.py \
--config-name pico4_sim2real \
controller.policy_path=track.onnx \
real_robot.network_interface=eth0
Operator Flow
Keep the Unitree remote in hand. L1+R1 is the emergency stop path into
DAMPING.
| Control | Action |
|---|---|
Unitree remote Start | Enter STANDING |
Unitree remote Y | Enter MOCAP |
Pico/controller A | Pause / resume live mocap |
Unitree remote X | Return to STANDING |
Unitree remote L1+R1 | Emergency stop (DAMPING) |
Enter MOCAP only after Pico tracking is stable. Teleopit validates consecutive
mocap frames before switching; if validation fails, the robot stays in
STANDING.
Runtime Behavior
Pico sim2real uses the shared realtime reference timeline:
Pico body frames -> retarget -> reference buffer -> observation -> policy -> G1 joints
When entering STANDING, Teleopit releases active Unitree modes, enters
debug/low-level control, locks the current joints briefly, resets policy state,
and ramps Kp to reduce startup spikes.
When entering MOCAP, Teleopit resets policy/reference state and blends the
reference from the current robot state into the live mocap command.
Pause / Resume
Pico pause/resume is a mocap-session control event.
ACTIVE: the pause button freezes the current reference pose.PAUSED: pressing it again clears policy/reference state, warms the realtime buffer, re-centers yaw/XY alignment, and resumes from live mocap.
Resume while standing still and close to the paused pose. This reduces sudden reference changes when live tracking resumes.
Optional RealSense Preview
Stream the G1 RealSense color camera back to the Pico headset:
python scripts/run/run_sim2real.py \
--config-name pico4_sim2real \
controller.policy_path=track.onnx \
real_robot.network_interface=enp130s0 \
input.video.enabled=true \
input.video.device=<optional-realsense-serial>
If video fails, control continues unless input.video.fail_on_error=true.
Common Parameters
# Real G1 DDS interface
real_robot.network_interface=enp130s0
# Pico timeout
input.pico4_timeout=30
# Override advertised Pico discovery IP
input.bridge_advertise_ip=192.168.1.20
# Consecutive valid mocap frames required before MOCAP
mocap_switch.check_frames=10
# Smooth transition into mocap reference
transition_duration=2.0
# Realtime frames to collect before resume
pause_resume_warmup_steps=2
# Change Pico pause button
input.pause_button=right_axis_click
# Enable headset video preview
input.video.enabled=true
Troubleshooting
| Symptom | Likely Cause | Fix |
|---|---|---|
| No LowState received | Wrong interface or G1 network not connected | Check Ethernet wiring and real_robot.network_interface |
TimeoutError: No Pico4 body data | Headset is not connected or tracking is inactive | Check headset app, network, and input.pico4_timeout |
| Cannot enter debug mode | Unitree mode release failed | Stop other robot modes and press Start again |
Robot enters STANDING but not MOCAP | Mocap validation failed | Keep tracking active and stable; check mocap_switch.check_frames logs |
Pico pause does not return to STANDING | Expected behavior | Pico pause freezes mocap; press remote X for STANDING |
| Video preview is unavailable | RealSense or video source failed | Check camera permissions, input.video.source, and logs |