robot-keyframe-kit 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- robot_keyframe_kit-0.1.0/LICENSE +21 -0
- robot_keyframe_kit-0.1.0/MANIFEST.in +30 -0
- robot_keyframe_kit-0.1.0/PKG-INFO +300 -0
- robot_keyframe_kit-0.1.0/README.md +262 -0
- robot_keyframe_kit-0.1.0/pyproject.toml +76 -0
- robot_keyframe_kit-0.1.0/setup.cfg +4 -0
- robot_keyframe_kit-0.1.0/src/robot_keyframe_kit/__init__.py +11 -0
- robot_keyframe_kit-0.1.0/src/robot_keyframe_kit/config.py +242 -0
- robot_keyframe_kit-0.1.0/src/robot_keyframe_kit/editor.py +2514 -0
- robot_keyframe_kit-0.1.0/src/robot_keyframe_kit/keyframe.py +27 -0
- robot_keyframe_kit-0.1.0/src/robot_keyframe_kit/math_utils.py +108 -0
- robot_keyframe_kit-0.1.0/src/robot_keyframe_kit/sim_worker.py +642 -0
- robot_keyframe_kit-0.1.0/src/robot_keyframe_kit.egg-info/PKG-INFO +300 -0
- robot_keyframe_kit-0.1.0/src/robot_keyframe_kit.egg-info/SOURCES.txt +16 -0
- robot_keyframe_kit-0.1.0/src/robot_keyframe_kit.egg-info/dependency_links.txt +1 -0
- robot_keyframe_kit-0.1.0/src/robot_keyframe_kit.egg-info/entry_points.txt +2 -0
- robot_keyframe_kit-0.1.0/src/robot_keyframe_kit.egg-info/requires.txt +13 -0
- robot_keyframe_kit-0.1.0/src/robot_keyframe_kit.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 The Movement Lab @ Stanford
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Include essential files
|
|
2
|
+
include LICENSE
|
|
3
|
+
include README.md
|
|
4
|
+
include pyproject.toml
|
|
5
|
+
|
|
6
|
+
# Include source code
|
|
7
|
+
recursive-include src *.py
|
|
8
|
+
|
|
9
|
+
# Exclude examples (too large - contains mesh files)
|
|
10
|
+
prune examples
|
|
11
|
+
|
|
12
|
+
# Exclude saved keyframes
|
|
13
|
+
prune keyframes
|
|
14
|
+
|
|
15
|
+
# Exclude development files
|
|
16
|
+
exclude PLAN.md
|
|
17
|
+
exclude MUJOCO_LOG.TXT
|
|
18
|
+
prune .cursor
|
|
19
|
+
|
|
20
|
+
# Exclude common unwanted files
|
|
21
|
+
global-exclude *.pyc
|
|
22
|
+
global-exclude *.pyo
|
|
23
|
+
global-exclude __pycache__
|
|
24
|
+
global-exclude *.egg-info
|
|
25
|
+
global-exclude .DS_Store
|
|
26
|
+
global-exclude *.lz4
|
|
27
|
+
global-exclude *.stl
|
|
28
|
+
global-exclude *.dae
|
|
29
|
+
global-exclude *.blend
|
|
30
|
+
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: robot-keyframe-kit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A generalizable Viser-based keyframe editor for any MuJoCo robot
|
|
5
|
+
Author-email: Stanford TML <yuming29@stanford.edu>
|
|
6
|
+
Maintainer-email: Stanford TML <yuming29@stanford.edu>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/Stanford-TML/robot_keyframe_kit
|
|
9
|
+
Project-URL: Repository, https://github.com/Stanford-TML/robot_keyframe_kit
|
|
10
|
+
Keywords: robotics,mujoco,keyframe,animation,viser,motion-planning
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: mujoco>=3.0
|
|
26
|
+
Requires-Dist: viser-keyframe==1.0.18
|
|
27
|
+
Requires-Dist: numpy
|
|
28
|
+
Requires-Dist: scipy
|
|
29
|
+
Requires-Dist: joblib
|
|
30
|
+
Requires-Dist: trimesh
|
|
31
|
+
Requires-Dist: lz4
|
|
32
|
+
Requires-Dist: pyyaml
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: pytest; extra == "dev"
|
|
35
|
+
Requires-Dist: black; extra == "dev"
|
|
36
|
+
Requires-Dist: ruff; extra == "dev"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# Robot Keyframe Kit
|
|
40
|
+
|
|
41
|
+
[](https://pypi.org/project/robot-keyframe-kit/)
|
|
42
|
+
[](https://www.python.org/downloads/)
|
|
43
|
+
[](https://opensource.org/licenses/MIT)
|
|
44
|
+
|
|
45
|
+
A web-based keyframe editor for **any MuJoCo robot**. Design robot motions through an intuitive 3D interface—no robot-specific code required.
|
|
46
|
+
|
|
47
|
+
https://github.com/user-attachments/assets/demo-video-placeholder
|
|
48
|
+
|
|
49
|
+
## ✨ Features
|
|
50
|
+
|
|
51
|
+
- **Universal Compatibility** — Works with any MuJoCo XML model out of the box
|
|
52
|
+
- **Zero Configuration** — Auto-detects joints, actuators, end-effectors, and mirror pairs
|
|
53
|
+
- **Web-Based Interface** — 3D visualization powered by [Viser](https://github.com/nerfstudio-project/viser)
|
|
54
|
+
- **Mirror Mode** — Automatically synchronize left/right joint movements
|
|
55
|
+
- **Physics Simulation** — Test keyframes with full MuJoCo physics
|
|
56
|
+
- **Keyframe Sequencing** — Build timed motion sequences
|
|
57
|
+
- **Trajectory Recording** — Record and export motion data
|
|
58
|
+
- **YAML Configuration** — Optional per-robot config files for advanced customization
|
|
59
|
+
|
|
60
|
+
## 🚀 Installation
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install robot-keyframe-kit
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Or install from source:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
git clone https://github.com/Stanford-TML/robot_keyframe_kit.git
|
|
70
|
+
cd robot_keyframe_kit
|
|
71
|
+
pip install -e .
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## 📖 Quick Start
|
|
75
|
+
|
|
76
|
+
### Command Line
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Just provide your robot's MuJoCo XML file
|
|
80
|
+
keyframe-editor path/to/robot.xml
|
|
81
|
+
|
|
82
|
+
# With a custom name and save directory
|
|
83
|
+
keyframe-editor path/to/robot.xml --name my_robot --save-dir ./keyframes
|
|
84
|
+
|
|
85
|
+
# Using a YAML configuration file
|
|
86
|
+
keyframe-editor path/to/robot.xml --config robot_config.yaml
|
|
87
|
+
|
|
88
|
+
# Generate a config template for your robot
|
|
89
|
+
keyframe-editor path/to/robot.xml --generate-config
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Then open **http://localhost:8081** in your browser.
|
|
93
|
+
|
|
94
|
+
### Python API
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from robot_keyframe_kit import ViserKeyframeEditor, EditorConfig
|
|
98
|
+
|
|
99
|
+
# Minimal usage — just provide the XML path
|
|
100
|
+
editor = ViserKeyframeEditor("path/to/robot.xml")
|
|
101
|
+
|
|
102
|
+
# With configuration
|
|
103
|
+
config = EditorConfig(
|
|
104
|
+
name="my_robot",
|
|
105
|
+
root_body="base_link",
|
|
106
|
+
save_dir="my_keyframes",
|
|
107
|
+
)
|
|
108
|
+
editor = ViserKeyframeEditor("path/to/robot.xml", config=config)
|
|
109
|
+
|
|
110
|
+
# Keep the server running
|
|
111
|
+
import time
|
|
112
|
+
while True:
|
|
113
|
+
time.sleep(1.0)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Loading from YAML Config
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from robot_keyframe_kit import ViserKeyframeEditor, EditorConfig
|
|
120
|
+
|
|
121
|
+
# Load configuration from YAML
|
|
122
|
+
config = EditorConfig.from_yaml("robot_config.yaml")
|
|
123
|
+
editor = ViserKeyframeEditor("path/to/robot.xml", config=config)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## ⚙️ Configuration
|
|
127
|
+
|
|
128
|
+
### YAML Configuration File
|
|
129
|
+
|
|
130
|
+
Create a `robot_config.yaml` for robot-specific settings:
|
|
131
|
+
|
|
132
|
+
```yaml
|
|
133
|
+
name: my_robot
|
|
134
|
+
root_body: torso
|
|
135
|
+
|
|
136
|
+
# End-effector sites for pose tracking
|
|
137
|
+
end_effectors:
|
|
138
|
+
- left_hand
|
|
139
|
+
- right_hand
|
|
140
|
+
- left_foot
|
|
141
|
+
- right_foot
|
|
142
|
+
|
|
143
|
+
# Joint mirror pairs (left: right)
|
|
144
|
+
mirror_pairs:
|
|
145
|
+
left_shoulder: right_shoulder
|
|
146
|
+
left_elbow: right_elbow
|
|
147
|
+
left_hip: right_hip
|
|
148
|
+
left_knee: right_knee
|
|
149
|
+
|
|
150
|
+
# Mirror sign corrections (-1 to flip, 1 to keep same)
|
|
151
|
+
mirror_signs:
|
|
152
|
+
left_shoulder: 1
|
|
153
|
+
left_elbow: -1
|
|
154
|
+
left_hip: 1
|
|
155
|
+
left_knee: 1
|
|
156
|
+
|
|
157
|
+
# Output settings
|
|
158
|
+
save_dir: keyframes
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### EditorConfig Options
|
|
162
|
+
|
|
163
|
+
| Option | Type | Default | Description |
|
|
164
|
+
|--------|------|---------|-------------|
|
|
165
|
+
| `name` | str | `"robot"` | Project name for saved files |
|
|
166
|
+
| `root_body` | str | auto-detect | Body used for ground alignment |
|
|
167
|
+
| `end_effector_sites` | list | auto-detect | Sites for end-effector tracking |
|
|
168
|
+
| `mirror_pairs` | dict | auto-detect | Left-to-right joint mapping |
|
|
169
|
+
| `mirror_signs` | dict | auto-detect | Sign corrections for mirroring |
|
|
170
|
+
| `save_dir` | str | `"keyframes"` | Directory for saved keyframes |
|
|
171
|
+
| `dt` | float | `0.02` | Trajectory timestep (50 Hz) |
|
|
172
|
+
| `n_frames` | int | `20` | Physics substeps per control step |
|
|
173
|
+
| `physics_dt` | float | `0.001` | Physics simulation timestep |
|
|
174
|
+
| `show_com` | bool | `True` | Show center of mass marker |
|
|
175
|
+
| `show_grid` | bool | `True` | Show ground grid |
|
|
176
|
+
|
|
177
|
+
## 🎮 UI Guide
|
|
178
|
+
|
|
179
|
+
The editor interface has three main sections:
|
|
180
|
+
|
|
181
|
+
### Left Panel — Keyframe Controls
|
|
182
|
+
- **Save Motion** — Export keyframes to compressed `.lz4` files
|
|
183
|
+
- **Keyframe List** — Select, add, remove, and reorder keyframes
|
|
184
|
+
- **Keyframe Operations** — Update, Test (with physics), Ground (place on floor)
|
|
185
|
+
- **Sequence Builder** — Create timed motion sequences
|
|
186
|
+
|
|
187
|
+
### Center Panel — Left-Side Joints
|
|
188
|
+
- Joint sliders for left-side actuators
|
|
189
|
+
- **End Effector Poses** — Save and restore end-effector positions
|
|
190
|
+
|
|
191
|
+
### Right Panel — Right-Side Joints & Settings
|
|
192
|
+
- Joint sliders for right-side actuators
|
|
193
|
+
- **Mirror Mode** — Sync left/right movements
|
|
194
|
+
- **Reverse Mirror** — Invert the mirror direction
|
|
195
|
+
- **Physics Toggle** — Enable/disable simulation
|
|
196
|
+
- **Visualization Options** — Grid, COM marker, etc.
|
|
197
|
+
|
|
198
|
+
### Camera Controls
|
|
199
|
+
- **Scroll** — Zoom in/out
|
|
200
|
+
- **Left-click + Drag** — Rotate view
|
|
201
|
+
- **Right-click + Drag** — Pan view
|
|
202
|
+
|
|
203
|
+
## 📁 Output Format
|
|
204
|
+
|
|
205
|
+
Keyframe data is saved as compressed `.lz4` files:
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
{
|
|
209
|
+
"keyframes": [
|
|
210
|
+
{
|
|
211
|
+
"name": "stand",
|
|
212
|
+
"motor_pos": [...], # Actuator positions
|
|
213
|
+
"joint_pos": [...], # Joint positions
|
|
214
|
+
"qpos": [...], # Full MuJoCo qpos
|
|
215
|
+
},
|
|
216
|
+
...
|
|
217
|
+
],
|
|
218
|
+
"timed_sequence": [
|
|
219
|
+
("stand", 0.0),
|
|
220
|
+
("crouch", 0.5),
|
|
221
|
+
("jump", 1.0),
|
|
222
|
+
],
|
|
223
|
+
"time": [...], # Trajectory timestamps
|
|
224
|
+
"qpos": [...], # Full qpos trajectory
|
|
225
|
+
"body_pos": [...], # Body positions over time
|
|
226
|
+
"body_quat": [...], # Body orientations over time
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Loading Saved Keyframes
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
import lz4.frame
|
|
234
|
+
import pickle
|
|
235
|
+
|
|
236
|
+
with lz4.frame.open("keyframes/my_robot/motion.lz4", "rb") as f:
|
|
237
|
+
data = pickle.load(f)
|
|
238
|
+
|
|
239
|
+
print(data["keyframes"][0]["name"]) # First keyframe name
|
|
240
|
+
print(data["timed_sequence"]) # Motion sequence
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## 🤖 Tested Robots
|
|
244
|
+
|
|
245
|
+
Works with robots from [MuJoCo Menagerie](https://github.com/google-deepmind/mujoco_menagerie) and custom models:
|
|
246
|
+
|
|
247
|
+
- **Humanoids** — Unitree G1, H1, ToddlerBot, OP3
|
|
248
|
+
- **Quadrupeds** — Unitree A1, Go1, Boston Dynamics Spot
|
|
249
|
+
- **Arms** — Franka Panda, UR5, xArm
|
|
250
|
+
- **Hands** — Leap Hand, Shadow Hand
|
|
251
|
+
- **Custom Models** — Any valid MuJoCo XML
|
|
252
|
+
|
|
253
|
+
## 📋 Requirements
|
|
254
|
+
|
|
255
|
+
- Python ≥ 3.9
|
|
256
|
+
- MuJoCo ≥ 3.0
|
|
257
|
+
- Modern web browser (Chrome, Firefox, Safari, Edge)
|
|
258
|
+
|
|
259
|
+
## 🛠️ Troubleshooting
|
|
260
|
+
|
|
261
|
+
### Port Already in Use
|
|
262
|
+
```bash
|
|
263
|
+
# Use a different port
|
|
264
|
+
keyframe-editor robot.xml --port 8082
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Mirror Mode Not Working Correctly
|
|
268
|
+
Generate a config file and manually adjust `mirror_signs`:
|
|
269
|
+
```bash
|
|
270
|
+
keyframe-editor robot.xml --generate-config
|
|
271
|
+
# Edit the generated YAML, then:
|
|
272
|
+
keyframe-editor robot.xml --config robot_config.yaml
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Robot Floating in Air
|
|
276
|
+
The editor auto-detects `root_body` for grounding. If incorrect, specify it:
|
|
277
|
+
```bash
|
|
278
|
+
keyframe-editor robot.xml --root-body base_link
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## 📄 License
|
|
282
|
+
|
|
283
|
+
MIT License — see [LICENSE](LICENSE) for details.
|
|
284
|
+
|
|
285
|
+
## 🤝 Contributing
|
|
286
|
+
|
|
287
|
+
Contributions welcome! Please open an issue or pull request on GitHub.
|
|
288
|
+
|
|
289
|
+
## 📚 Citation
|
|
290
|
+
|
|
291
|
+
If you use this tool in your research, please cite:
|
|
292
|
+
|
|
293
|
+
```bibtex
|
|
294
|
+
@software{robot_keyframe_kit,
|
|
295
|
+
title = {Robot Keyframe Kit},
|
|
296
|
+
author = {Stanford TML},
|
|
297
|
+
year = {2024},
|
|
298
|
+
url = {https://github.com/Stanford-TML/robot_keyframe_kit}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# Robot Keyframe Kit
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/robot-keyframe-kit/)
|
|
4
|
+
[](https://www.python.org/downloads/)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
A web-based keyframe editor for **any MuJoCo robot**. Design robot motions through an intuitive 3D interface—no robot-specific code required.
|
|
8
|
+
|
|
9
|
+
https://github.com/user-attachments/assets/demo-video-placeholder
|
|
10
|
+
|
|
11
|
+
## ✨ Features
|
|
12
|
+
|
|
13
|
+
- **Universal Compatibility** — Works with any MuJoCo XML model out of the box
|
|
14
|
+
- **Zero Configuration** — Auto-detects joints, actuators, end-effectors, and mirror pairs
|
|
15
|
+
- **Web-Based Interface** — 3D visualization powered by [Viser](https://github.com/nerfstudio-project/viser)
|
|
16
|
+
- **Mirror Mode** — Automatically synchronize left/right joint movements
|
|
17
|
+
- **Physics Simulation** — Test keyframes with full MuJoCo physics
|
|
18
|
+
- **Keyframe Sequencing** — Build timed motion sequences
|
|
19
|
+
- **Trajectory Recording** — Record and export motion data
|
|
20
|
+
- **YAML Configuration** — Optional per-robot config files for advanced customization
|
|
21
|
+
|
|
22
|
+
## 🚀 Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install robot-keyframe-kit
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or install from source:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
git clone https://github.com/Stanford-TML/robot_keyframe_kit.git
|
|
32
|
+
cd robot_keyframe_kit
|
|
33
|
+
pip install -e .
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 📖 Quick Start
|
|
37
|
+
|
|
38
|
+
### Command Line
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Just provide your robot's MuJoCo XML file
|
|
42
|
+
keyframe-editor path/to/robot.xml
|
|
43
|
+
|
|
44
|
+
# With a custom name and save directory
|
|
45
|
+
keyframe-editor path/to/robot.xml --name my_robot --save-dir ./keyframes
|
|
46
|
+
|
|
47
|
+
# Using a YAML configuration file
|
|
48
|
+
keyframe-editor path/to/robot.xml --config robot_config.yaml
|
|
49
|
+
|
|
50
|
+
# Generate a config template for your robot
|
|
51
|
+
keyframe-editor path/to/robot.xml --generate-config
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Then open **http://localhost:8081** in your browser.
|
|
55
|
+
|
|
56
|
+
### Python API
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from robot_keyframe_kit import ViserKeyframeEditor, EditorConfig
|
|
60
|
+
|
|
61
|
+
# Minimal usage — just provide the XML path
|
|
62
|
+
editor = ViserKeyframeEditor("path/to/robot.xml")
|
|
63
|
+
|
|
64
|
+
# With configuration
|
|
65
|
+
config = EditorConfig(
|
|
66
|
+
name="my_robot",
|
|
67
|
+
root_body="base_link",
|
|
68
|
+
save_dir="my_keyframes",
|
|
69
|
+
)
|
|
70
|
+
editor = ViserKeyframeEditor("path/to/robot.xml", config=config)
|
|
71
|
+
|
|
72
|
+
# Keep the server running
|
|
73
|
+
import time
|
|
74
|
+
while True:
|
|
75
|
+
time.sleep(1.0)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Loading from YAML Config
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from robot_keyframe_kit import ViserKeyframeEditor, EditorConfig
|
|
82
|
+
|
|
83
|
+
# Load configuration from YAML
|
|
84
|
+
config = EditorConfig.from_yaml("robot_config.yaml")
|
|
85
|
+
editor = ViserKeyframeEditor("path/to/robot.xml", config=config)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## ⚙️ Configuration
|
|
89
|
+
|
|
90
|
+
### YAML Configuration File
|
|
91
|
+
|
|
92
|
+
Create a `robot_config.yaml` for robot-specific settings:
|
|
93
|
+
|
|
94
|
+
```yaml
|
|
95
|
+
name: my_robot
|
|
96
|
+
root_body: torso
|
|
97
|
+
|
|
98
|
+
# End-effector sites for pose tracking
|
|
99
|
+
end_effectors:
|
|
100
|
+
- left_hand
|
|
101
|
+
- right_hand
|
|
102
|
+
- left_foot
|
|
103
|
+
- right_foot
|
|
104
|
+
|
|
105
|
+
# Joint mirror pairs (left: right)
|
|
106
|
+
mirror_pairs:
|
|
107
|
+
left_shoulder: right_shoulder
|
|
108
|
+
left_elbow: right_elbow
|
|
109
|
+
left_hip: right_hip
|
|
110
|
+
left_knee: right_knee
|
|
111
|
+
|
|
112
|
+
# Mirror sign corrections (-1 to flip, 1 to keep same)
|
|
113
|
+
mirror_signs:
|
|
114
|
+
left_shoulder: 1
|
|
115
|
+
left_elbow: -1
|
|
116
|
+
left_hip: 1
|
|
117
|
+
left_knee: 1
|
|
118
|
+
|
|
119
|
+
# Output settings
|
|
120
|
+
save_dir: keyframes
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### EditorConfig Options
|
|
124
|
+
|
|
125
|
+
| Option | Type | Default | Description |
|
|
126
|
+
|--------|------|---------|-------------|
|
|
127
|
+
| `name` | str | `"robot"` | Project name for saved files |
|
|
128
|
+
| `root_body` | str | auto-detect | Body used for ground alignment |
|
|
129
|
+
| `end_effector_sites` | list | auto-detect | Sites for end-effector tracking |
|
|
130
|
+
| `mirror_pairs` | dict | auto-detect | Left-to-right joint mapping |
|
|
131
|
+
| `mirror_signs` | dict | auto-detect | Sign corrections for mirroring |
|
|
132
|
+
| `save_dir` | str | `"keyframes"` | Directory for saved keyframes |
|
|
133
|
+
| `dt` | float | `0.02` | Trajectory timestep (50 Hz) |
|
|
134
|
+
| `n_frames` | int | `20` | Physics substeps per control step |
|
|
135
|
+
| `physics_dt` | float | `0.001` | Physics simulation timestep |
|
|
136
|
+
| `show_com` | bool | `True` | Show center of mass marker |
|
|
137
|
+
| `show_grid` | bool | `True` | Show ground grid |
|
|
138
|
+
|
|
139
|
+
## 🎮 UI Guide
|
|
140
|
+
|
|
141
|
+
The editor interface has three main sections:
|
|
142
|
+
|
|
143
|
+
### Left Panel — Keyframe Controls
|
|
144
|
+
- **Save Motion** — Export keyframes to compressed `.lz4` files
|
|
145
|
+
- **Keyframe List** — Select, add, remove, and reorder keyframes
|
|
146
|
+
- **Keyframe Operations** — Update, Test (with physics), Ground (place on floor)
|
|
147
|
+
- **Sequence Builder** — Create timed motion sequences
|
|
148
|
+
|
|
149
|
+
### Center Panel — Left-Side Joints
|
|
150
|
+
- Joint sliders for left-side actuators
|
|
151
|
+
- **End Effector Poses** — Save and restore end-effector positions
|
|
152
|
+
|
|
153
|
+
### Right Panel — Right-Side Joints & Settings
|
|
154
|
+
- Joint sliders for right-side actuators
|
|
155
|
+
- **Mirror Mode** — Sync left/right movements
|
|
156
|
+
- **Reverse Mirror** — Invert the mirror direction
|
|
157
|
+
- **Physics Toggle** — Enable/disable simulation
|
|
158
|
+
- **Visualization Options** — Grid, COM marker, etc.
|
|
159
|
+
|
|
160
|
+
### Camera Controls
|
|
161
|
+
- **Scroll** — Zoom in/out
|
|
162
|
+
- **Left-click + Drag** — Rotate view
|
|
163
|
+
- **Right-click + Drag** — Pan view
|
|
164
|
+
|
|
165
|
+
## 📁 Output Format
|
|
166
|
+
|
|
167
|
+
Keyframe data is saved as compressed `.lz4` files:
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
{
|
|
171
|
+
"keyframes": [
|
|
172
|
+
{
|
|
173
|
+
"name": "stand",
|
|
174
|
+
"motor_pos": [...], # Actuator positions
|
|
175
|
+
"joint_pos": [...], # Joint positions
|
|
176
|
+
"qpos": [...], # Full MuJoCo qpos
|
|
177
|
+
},
|
|
178
|
+
...
|
|
179
|
+
],
|
|
180
|
+
"timed_sequence": [
|
|
181
|
+
("stand", 0.0),
|
|
182
|
+
("crouch", 0.5),
|
|
183
|
+
("jump", 1.0),
|
|
184
|
+
],
|
|
185
|
+
"time": [...], # Trajectory timestamps
|
|
186
|
+
"qpos": [...], # Full qpos trajectory
|
|
187
|
+
"body_pos": [...], # Body positions over time
|
|
188
|
+
"body_quat": [...], # Body orientations over time
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Loading Saved Keyframes
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
import lz4.frame
|
|
196
|
+
import pickle
|
|
197
|
+
|
|
198
|
+
with lz4.frame.open("keyframes/my_robot/motion.lz4", "rb") as f:
|
|
199
|
+
data = pickle.load(f)
|
|
200
|
+
|
|
201
|
+
print(data["keyframes"][0]["name"]) # First keyframe name
|
|
202
|
+
print(data["timed_sequence"]) # Motion sequence
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## 🤖 Tested Robots
|
|
206
|
+
|
|
207
|
+
Works with robots from [MuJoCo Menagerie](https://github.com/google-deepmind/mujoco_menagerie) and custom models:
|
|
208
|
+
|
|
209
|
+
- **Humanoids** — Unitree G1, H1, ToddlerBot, OP3
|
|
210
|
+
- **Quadrupeds** — Unitree A1, Go1, Boston Dynamics Spot
|
|
211
|
+
- **Arms** — Franka Panda, UR5, xArm
|
|
212
|
+
- **Hands** — Leap Hand, Shadow Hand
|
|
213
|
+
- **Custom Models** — Any valid MuJoCo XML
|
|
214
|
+
|
|
215
|
+
## 📋 Requirements
|
|
216
|
+
|
|
217
|
+
- Python ≥ 3.9
|
|
218
|
+
- MuJoCo ≥ 3.0
|
|
219
|
+
- Modern web browser (Chrome, Firefox, Safari, Edge)
|
|
220
|
+
|
|
221
|
+
## 🛠️ Troubleshooting
|
|
222
|
+
|
|
223
|
+
### Port Already in Use
|
|
224
|
+
```bash
|
|
225
|
+
# Use a different port
|
|
226
|
+
keyframe-editor robot.xml --port 8082
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Mirror Mode Not Working Correctly
|
|
230
|
+
Generate a config file and manually adjust `mirror_signs`:
|
|
231
|
+
```bash
|
|
232
|
+
keyframe-editor robot.xml --generate-config
|
|
233
|
+
# Edit the generated YAML, then:
|
|
234
|
+
keyframe-editor robot.xml --config robot_config.yaml
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Robot Floating in Air
|
|
238
|
+
The editor auto-detects `root_body` for grounding. If incorrect, specify it:
|
|
239
|
+
```bash
|
|
240
|
+
keyframe-editor robot.xml --root-body base_link
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## 📄 License
|
|
244
|
+
|
|
245
|
+
MIT License — see [LICENSE](LICENSE) for details.
|
|
246
|
+
|
|
247
|
+
## 🤝 Contributing
|
|
248
|
+
|
|
249
|
+
Contributions welcome! Please open an issue or pull request on GitHub.
|
|
250
|
+
|
|
251
|
+
## 📚 Citation
|
|
252
|
+
|
|
253
|
+
If you use this tool in your research, please cite:
|
|
254
|
+
|
|
255
|
+
```bibtex
|
|
256
|
+
@software{robot_keyframe_kit,
|
|
257
|
+
title = {Robot Keyframe Kit},
|
|
258
|
+
author = {Stanford TML},
|
|
259
|
+
year = {2024},
|
|
260
|
+
url = {https://github.com/Stanford-TML/robot_keyframe_kit}
|
|
261
|
+
}
|
|
262
|
+
```
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "robot-keyframe-kit"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A generalizable Viser-based keyframe editor for any MuJoCo robot"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Stanford TML", email = "yuming29@stanford.edu"}
|
|
14
|
+
]
|
|
15
|
+
maintainers = [
|
|
16
|
+
{name = "Stanford TML", email = "yuming29@stanford.edu"}
|
|
17
|
+
]
|
|
18
|
+
keywords = ["robotics", "mujoco", "keyframe", "animation", "viser", "motion-planning"]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 3 - Alpha",
|
|
21
|
+
"Intended Audience :: Science/Research",
|
|
22
|
+
"Intended Audience :: Developers",
|
|
23
|
+
"Operating System :: OS Independent",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.9",
|
|
26
|
+
"Programming Language :: Python :: 3.10",
|
|
27
|
+
"Programming Language :: Python :: 3.11",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Topic :: Scientific/Engineering",
|
|
30
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
dependencies = [
|
|
34
|
+
"mujoco>=3.0",
|
|
35
|
+
"viser-keyframe==1.0.18",
|
|
36
|
+
"numpy",
|
|
37
|
+
"scipy",
|
|
38
|
+
"joblib",
|
|
39
|
+
"trimesh",
|
|
40
|
+
"lz4",
|
|
41
|
+
"pyyaml",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.optional-dependencies]
|
|
45
|
+
dev = [
|
|
46
|
+
"pytest",
|
|
47
|
+
"black",
|
|
48
|
+
"ruff",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[project.urls]
|
|
52
|
+
Homepage = "https://github.com/Stanford-TML/robot_keyframe_kit"
|
|
53
|
+
Repository = "https://github.com/Stanford-TML/robot_keyframe_kit"
|
|
54
|
+
|
|
55
|
+
[project.scripts]
|
|
56
|
+
keyframe-editor = "robot_keyframe_kit.editor:main"
|
|
57
|
+
|
|
58
|
+
[tool.setuptools.packages.find]
|
|
59
|
+
where = ["src"]
|
|
60
|
+
|
|
61
|
+
[tool.setuptools.package-data]
|
|
62
|
+
robot_keyframe_kit = ["py.typed"]
|
|
63
|
+
|
|
64
|
+
# Exclude examples and keyframes from the distribution
|
|
65
|
+
[tool.setuptools.exclude-package-data]
|
|
66
|
+
"*" = ["examples/*", "keyframes/*", "*.lz4", "*.stl", "*.dae"]
|
|
67
|
+
|
|
68
|
+
[tool.black]
|
|
69
|
+
line-length = 88
|
|
70
|
+
target-version = ["py39", "py310", "py311", "py312"]
|
|
71
|
+
|
|
72
|
+
[tool.ruff]
|
|
73
|
+
line-length = 88
|
|
74
|
+
select = ["E", "F", "I"]
|
|
75
|
+
|
|
76
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Robot Keyframe Kit - A generalizable Viser-based keyframe editor for MuJoCo robots."""
|
|
2
|
+
|
|
3
|
+
from .config import EditorConfig
|
|
4
|
+
from .editor import ViserKeyframeEditor
|
|
5
|
+
from .keyframe import Keyframe
|
|
6
|
+
|
|
7
|
+
__version__ = "0.1.0"
|
|
8
|
+
__all__ = ["ViserKeyframeEditor", "EditorConfig", "Keyframe"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|