A Python toolkit for recording and replaying motor joint trajectories on the Unitree G1 robot.
By default, all operations are limited to ARMS ONLY (joints 15-28).
- ✅ Record: Only arm motors set to passive (legs stay firm)
- ✅ Replay: Only arm motors commanded (legs don't move)
⚠️ To control other joints: Must explicitly specify--joint-group all/legs/waist
See ARMS_ONLY_SAFETY.md for complete safety documentation.
- Calibrate: Discover and save joint limits by manually moving the robot
- Record: Capture joint trajectories with motors in passive mode
- Replay: Execute recorded trajectories on the robot
- Python >= 3.8
- Unitree SDK2 Python (requires cyclonedds)
- Network connection to G1 robot
uvpackage manager (recommended)
cd ~/projects/g1-piano/g1-record-and-replay
./setup_dependencies.shThis script will:
- Install cyclonedds (if not present)
- Install unitree_sdk2_python
- Install g1-record-and-replay
- Test all imports
- Setup cyclonedds (required by unitree SDK):
cd ~
git clone https://github.com/eclipse-cyclonedds/cyclonedds -b releases/0.10.x
cd cyclonedds && mkdir -p build install && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=../install
cmake --build . --target install
export CYCLONEDDS_HOME="$HOME/cyclonedds/install"- Install unitree SDK:
cd ~/projects/g1-piano/unitree_sdk2_python
uv pip install -e .- Install g1-record-and-replay:
cd ~/projects/g1-piano/g1-record-and-replay
uv pip install -e .Note: Add export CYCLONEDDS_HOME="$HOME/cyclonedds/install" to your ~/.bashrc or ~/.zshrc
Before using the robot, verify the connection:
python scripts/check_g1_connection.pyThis script will:
- ✅ Detect active network interfaces
- ✅ Check if robot is reachable (ping test)
- ✅ Test SDK connection
- ✅ Show which interface to use
Manually move the robot joints to their limits while the system records min/max positions:
python scripts/calibrate.py --network-interface enp2s0 --joint-group armsOptions:
--network-interface: Network interface connected to robot (e.g., enp2s0)--joint-group: Which joints to calibrate:all,arms,legs,waist(default: all)
Controls:
R: Reset min/max valuesS: Save calibration to fileQ: Quit without saving
Record robot movements with motors in passive mode (freely movable):
# SAFE: Records arms only (default)
python scripts/record.py --network-interface enp2s0 --name "arm_motion"
# With custom frequency (still arms only)
python scripts/record.py --network-interface enp2s0 --name "pick_cup" --frequency 50Options:
--network-interface: Network interface connected to robot--name: Episode name/description--frequency: Recording frequency in Hz (default: 50)--joint-group: Which joints to record (default: arms - SAFE)
Controls:
S: Stop and save recordingC: Cancel without saving
Replay a recorded episode on the robot:
python scripts/replay.py --network-interface enp2s0 --episode data/episodes/episode_001.h5 --speed 1.0Options:
--network-interface: Network interface connected to robot--episode: Path to episode file--speed: Playback speed multiplier (default: 1.0)
Controls:
P: Pause/resumeQ: Quit safely
Plot joint trajectories from a recorded episode:
python scripts/visualize_episode.py --episode data/episodes/episode_001.h5 --joints "left_shoulder_pitch,left_elbow"- Calibrate: Read-only mode, no commands sent to motors
- Record: Motors in passive mode, no active control
- Replay:
- Warning prompt before execution
- 3-second smooth transition to start position
- Emergency stop with Ctrl+C
- Position/velocity limits enforced
g1-record-and-replay/
├── config/ # Configuration and calibration data
├── data/episodes/ # Recorded episodes
├── g1_record_replay/ # Main package
│ ├── core/ # Core functionality
│ ├── calibrate.py # Calibration logic
│ ├── record.py # Recording logic
│ └── replay.py # Replay logic
└── scripts/ # CLI entry points
Episodes are stored in HDF5 format with the following structure:
joint_positions: (num_frames, 29) array of joint anglesjoint_velocities: (num_frames, 29) array of joint velocitiestimestamps: (num_frames,) array of timestamps- Metadata: episode_id, duration, frequency, description
MIT License