Repository navigation
Feat/g1 flip - #117
Feat/g1 flip#117
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a dedicated G1 flip motion-tracking task/profile and expands the motion-tracking pipeline to better support multi-clip datasets (clip-aware sampling + truncation at clip boundaries), alongside quaternion utilities to make orientation/velocity computations robust to quaternion sign flips.
Changes:
- Add
g1_flip_trackingtask (Hydra + registry) with flip-specific defaults and training budgets. - Update motion loading/sampling to support multiple NPZ clips and add clip-boundary truncation behavior in the env.
- Add quaternion helpers (
canonicalize,ensure_continuity,angular_velocity) and update CSV→NPZ scripts/tests accordingly; pin Torch version in project deps/lock.
Reviewed changes
Copilot reviewed 23 out of 27 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
uv.lock |
Updates locked dependencies (Torch/Triton/TorchVision and CUDA/NVIDIA wheels layout). |
pyproject.toml |
Pins torch==2.7.0. |
src/unilab/base/np_env.py |
Adds _compute_truncated hook + scratch buffer; integrates truncation into step() flow. |
src/unilab/utils/math_utils.py |
Adds quaternion canonicalization/continuity + angular velocity helper; reuses canonicalize in error magnitude. |
src/unilab/envs/motion_tracking/g1/motion_loader.py |
Supports multi-clip NPZ loading; adds clip-aware sampling mode and clip-end detection. |
src/unilab/envs/motion_tracking/g1/tracking.py |
Supports list-valued motion_file; adds clip_start sampling mode; truncates episodes at clip end. |
src/unilab/envs/motion_tracking/g1/flip_tracking.py |
New flip-specific config/profile + env registration (G1FlipTracking). |
src/unilab/envs/motion_tracking/g1/__init__.py |
Exports flip-tracking symbols. |
src/unilab/envs/motion_tracking/__init__.py |
Re-exports flip-tracking symbols at package level. |
conf/ppo/task/g1_flip_tracking.yaml |
Adds PPO Hydra task config for flip tracking. |
conf/appo/task/g1_flip_tracking.yaml |
Adds APPO Hydra task config for flip tracking. |
docs/05-g1-motion-tracking.md |
Documents new flip task and multi-clip semantics. |
tests/utils/test_math_utils.py |
Adds coverage for sign-flip invariance and angular-velocity robustness. |
tests/envs/test_motion_loader.py |
New tests for multi-clip loader + sampler modes and clip-end behavior. |
tests/envs/test_env_configs.py |
Adds tests for legacy defaults, flip profile defaults, and clip-end truncation behavior. |
tests/base/test_np_env.py |
Adds tests for truncation hook behavior + scratch-buffer reuse. |
tests/config/test_locomotion_params.py |
Adds PPO config assertions for motion/flip tracking tasks. |
tests/config/test_config_system.py |
Includes g1_flip_tracking in task composition matrix. |
tests/scripts/test_train_script_configs.py |
Ensures train script configs load for the new task. |
scripts/motion/csv_to_npz.py |
Uses shared quaternion continuity + angular velocity utilities. |
scripts/motion/replay_bones_seed_csv.py |
New tool to replay BONES-SEED CSV motions in MuJoCo viewer. |
scripts/motion/bones_seed_csv_to_npz.py |
New converter from BONES-SEED CSV to NPZ with FK + velocities. |
scripts/motion/README.md |
Documents the new replay/conversion scripts and formats. |
src/unilab/assets/robots/g1/scene_flat_with_wall.xml |
Adds a MuJoCo scene variant including a wall. |
.gitignore |
Ignores flip CSV/NPZ asset directories. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def np_quat_canonicalize(q: np.ndarray) -> np.ndarray: | ||
| """Flip quaternion signs so the real part is non-negative.""" | ||
| q_was_1d = q.ndim == 1 | ||
| if q_was_1d: | ||
| q = q[None, :] | ||
|
|
||
| sign = np.where(q[:, 0:1] < 0.0, -1.0, 1.0) | ||
| result = q * sign | ||
| return np.asarray(result[0] if q_was_1d else result) |
There was a problem hiding this comment.
np_quat_canonicalize assumes an input shaped like (N, 4) (or (4,)) but doesn’t validate this; for other shapes it will raise a confusing IndexError when slicing q[:, 0:1]. Consider adding explicit shape/ndim checks consistent with np_quat_ensure_continuity (e.g., require q.ndim in {1,2} and last dim == 4) and raise a clear ValueError when violated.
| def step(self): | ||
| """Advance all frames by one step.""" | ||
| self.current_frames += 1 | ||
|
|
||
| # Find environments that reached end of motion | ||
| done_mask = self.current_frames >= self.motion_loader.num_frames | ||
| # Find environments that reached the end of their current clip. | ||
| done_mask = self.current_frames > self.current_clip_end_frames | ||
| return np.where(done_mask)[0] |
There was a problem hiding this comment.
MotionSampler.step() advances current_frames past current_clip_end_frames for done envs (and for the last clip this can become num_frames, i.e. out of bounds). Since get_current_motion() indexes directly with current_frames, calling it after step() can return frames from the next clip or raise an IndexError. Consider clamping indices for done envs, or having get_current_motion() use np.minimum(current_frames, current_clip_end_frames) so the sampler remains safe to use even if callers don’t immediately resample/reset.
No description provided.