From 8110c816d084c40344ef8b7d61b0af3219794627 Mon Sep 17 00:00:00 2001 From: myurasov-nv <168484206+myurasov-nv@users.noreply.github.com> Date: Fri, 21 Aug 2026 02:32:16 -0700 Subject: [PATCH 1/5] Adds distinct exit codes for crashed, hung and failing test runs (#7235) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description Every failure mode in the individual-test orchestrator exits `1`, so a crashed process, a hung test, and a failing assertion cannot be told apart from the exit code. The orchestrator already separates them internally: it counts `Failing`, `Crashed`, `Startup Hang`, and `Timeout`, and prints each in the result summary. This carries that distinction into the exit code and prints the resolved code with a label. `1` still means failing assertions. A crashed process is `20`, a timeout `21`, and a startup hang `22`. When a run hits more than one, the code reports the outcome that proved the least, so a crash outranks a timeout, which outranks a startup hang. `0` is unchanged, and callers that only check for a non-zero code are unaffected. | Before | After | | ------ | ----- | | A lost GPU, a 1000 second hang, and a pixel mismatch all end in `Process completed with exit code 1` | The same 3 runs exit `20`, `21`, and `1`, each printed as `Exit Code: N (label)` in the summary | ## Reproduction 1. Run a suite through the orchestrator and read the exit code: ``` ./isaaclab.sh -p -m pytest --ignore=tools/conftest.py tools -v --junitxml=tests/report.xml; echo "exit=$?" ``` 2. Make one file reach its hard timeout, by lowering the timeout for that file or running a test that sleeps past it. Observed before this change: the summary reports `Timeout: 1` while the run reports `exit=1`, the same code a failing assertion produces. 3. Repeat with this change. Observed: the summary reports `Exit Code: 21 (timeout)` and the run reports `exit=21`, while a run whose only failures are assertions still reports `exit=1`. ## Type of change - New feature (non-breaking change which adds functionality) ## Screenshots Not applicable; the change has no rendered output. ## Checklist - [x] I have read and understood the [contribution guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html) - [ ] I have run the [`pre-commit` checks](https://pre-commit.com/) with `./isaaclab.sh --format`: not run; no dev setup on this machine. The diff was checked by hand for line length and whitespace, and `python3 -m py_compile tools/conftest.py` passes - [ ] I have made corresponding changes to the documentation: not applicable; each code is documented where it is defined and printed in the run summary - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works: not added; the counters are computed inside `pytest_sessionstart`, and `tools/conftest.py` takes over any pytest session that loads it, so a test in the same directory cannot drive this path in-process. `resolve_exit_code` was instead checked over all 16 combinations of the 4 counters, confirming that each mode maps to its own code and that zero versus non-zero matches the previous expression exactly - [ ] I have added a changelog fragment under `source//changelog.d/` for every touched package (do **not** edit `CHANGELOG.rst` or bump `extension.toml` — CI handles that): not applicable; no package under `source/` is touched - [x] I have added my name to the `CONTRIBUTORS.md` or my name already exists there (cherry picked from commit 4fa20fc8a5f75fd49bd12afad7fb8f2b0a944e77) --- tools/conftest.py | 60 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/tools/conftest.py b/tools/conftest.py index c0f810dd0b7..e64b7a5216b 100644 --- a/tools/conftest.py +++ b/tools/conftest.py @@ -80,6 +80,58 @@ def pytest_ignore_collect(collection_path, config): from the kill. """ +EXIT_TESTS_FAILED = 1 +"""Exit code for a run that completed with at least one failing assertion.""" + +EXIT_CRASHED = 20 +"""Exit code for a run where a test process died without writing its report.""" + +EXIT_TIMEOUT = 21 +"""Exit code for a run where a test reached its hard timeout.""" + +EXIT_STARTUP_HANG = 22 +"""Exit code for a run where a test never finished starting up.""" + +EXIT_CODE_LABELS = { + 0: "all tests passed", + EXIT_TESTS_FAILED: "test failures", + EXIT_CRASHED: "crashed process", + EXIT_TIMEOUT: "timeout", + EXIT_STARTUP_HANG: "startup hang", +} +"""Label for each exit code, printed with the result summary.""" + + +def resolve_exit_code(num_failing: int, num_timeout: int, num_crashed: int, num_startup_hang: int) -> int: + """Return the exit code for a finished run, based on how it failed. + + A crashed process, a hang and a failing assertion have different owners, so + each reports its own code rather than a shared ``1``; the code alone is then + enough to route a red job. When a run hits more than one, the code reports + the outcome that proved the least: a process that died never reached the + assertion a failing test did. ``1`` still means failing assertions, so + callers that only check for a non-zero code are unaffected. + + Args: + num_failing: Test files that ran and reported a failing assertion. + num_timeout: Test files killed at their hard timeout. + num_crashed: Test files whose process exited without writing a report. + num_startup_hang: Test files killed before startup finished. + + Returns: + ``0`` when nothing failed, otherwise the code for the highest-precedence + mode present: crash, then timeout, then startup hang, then assertion. + """ + if num_crashed: + return EXIT_CRASHED + if num_timeout: + return EXIT_TIMEOUT + if num_startup_hang: + return EXIT_STARTUP_HANG + if num_failing: + return EXIT_TESTS_FAILED + return 0 + def capture_test_output_with_timeout(cmd, timeout, env, startup_deadline=0, report_file=""): """Run a command with timeout and capture all output while streaming in real-time. @@ -1543,6 +1595,9 @@ def pytest_sessionstart(session): summary_str += f"Timeout: {num_timeout}\n" summary_str += f"Passing Percentage: {passing_percentage:.2f}%\n" + exit_code = resolve_exit_code(num_failing, num_timeout, num_crashed, num_startup_hang) + summary_str += f"Exit Code: {exit_code} ({EXIT_CODE_LABELS[exit_code]})\n" + total_wall = sum(test_status[test_path]["wall_time"] for test_path in test_files) total_test = sum(test_status[test_path]["time_elapsed"] for test_path in test_files) @@ -1559,7 +1614,4 @@ def pytest_sessionstart(session): logger.info(summary_str) # Exit pytest after custom execution to prevent normal pytest from overwriting our report - pytest.exit( - "Custom test execution completed", - returncode=0 if (num_failing == 0 and num_timeout == 0 and num_crashed == 0 and num_startup_hang == 0) else 1, - ) + pytest.exit("Custom test execution completed", returncode=exit_code) From 68b21a601545e7327d33cec1c8428df16bb066ad Mon Sep 17 00:00:00 2001 From: myurasov-nv <168484206+myurasov-nv@users.noreply.github.com> Date: Fri, 21 Aug 2026 02:43:39 -0700 Subject: [PATCH 2/5] Fixes stale single-source references for dependency pins (#6597) # Description Fixes three references that drifted from the single-source-of-truth root `pyproject.toml`: the wheel builder comment pointed at `python_packages.toml` (removed long ago), `daily-compatibility.yml` parsed `[tool.isaaclab.versions]` with a hand-written regex (now `tomllib`, byte-identical output), and the pip-installation docs claimed `rl_games` is excluded from the wheel extras while `gen_pyproject.py` actually includes it in `all`/`rl-games`. | | Before | After | |---|---|---| | Wheel builder comment | references nonexistent `python_packages.toml` | describes the actual copy step | | OV pins in daily-compatibility | regex over raw TOML text | `tomllib` parse | | Docs `all` extra | "SB3, SKRL, RSL-RL" | full list incl. RL-Games, Rerun, Mimic, RLinf | ## Reproduction 1. `grep python_packages.toml -r .` returns only the stale comment; no such file exists. 2. `python3 tools/wheel_builder/gen_pyproject.py pyproject.toml /tmp/p.toml 1.2.3 && grep rl-games /tmp/p.toml` shows `rl_games` in the `rl-games` and `all` extras, contradicting the docs note. 3. Run both the old regex and new `tomllib` snippets against `pyproject.toml`: identical output. ## Checklist - [x] I have read and understood the [contribution guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html) - [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with `./isaaclab.sh --format` - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have updated the changelog and the corresponding version in the extension's `config/extension.toml` file - [x] I have added my name to the `CONTRIBUTORS.md` or my name already exists there Co-authored-by: AntoineRichard (cherry picked from commit 2ae0878a2669ae28b03c02078c0045bf6698410a) --- tools/wheel_builder/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/wheel_builder/build.sh b/tools/wheel_builder/build.sh index 5930c263444..bb534b986a5 100755 --- a/tools/wheel_builder/build.sh +++ b/tools/wheel_builder/build.sh @@ -37,7 +37,7 @@ esac rm -rf "$BUILD_DIR" "$DIST_DIR" mkdir -p "$BUILD_DIR/src/isaaclab" -# 1. Copy inventory (same as python_packages.toml inventory.includes.all) +# 1. Copy inventory (the full source tree: apps/ + source/) cp -r apps "$BUILD_DIR/src/isaaclab/" cp -r source "$BUILD_DIR/src/isaaclab/" From 1a775d46fc5852cda11a0935016ccb515efb37a0 Mon Sep 17 00:00:00 2001 From: ooctipus Date: Mon, 24 Aug 2026 11:45:31 -0700 Subject: [PATCH 3/5] Add ADR guidance to domain randomization skill (#7320) ## Summary - Add success-driven ADR routing to the existing domain-randomization skill. - Add one compact manager-based gravity example using a task-owned scheduler and modify_term_cfg. - Validate exact endpoints and link the curriculum guide and Core Lift source. ## Testing - Repository skill validator: 21 skills validated. - Python example syntax: 2 examples validated. - Full formatting and pre-commit checks passed. (cherry picked from commit 7ed3ad45546a8e40046cfa5fadf05671a83129f8) --- skills/README.md | 2 +- .../user/domain-randomization-events/SKILL.md | 10 ++++-- .../evaluations.md | 15 +++++++++ .../domain-randomization-events/examples.md | 33 +++++++++++++++++++ 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/skills/README.md b/skills/README.md index 8b9e2a4edd2..10ebf6a25ef 100644 --- a/skills/README.md +++ b/skills/README.md @@ -15,7 +15,7 @@ User skills: - `user/install-isaac-lab/`: install Isaac Lab following the current install docs — automatic uv setup, downloaded Isaac Sim package, source build, Isaac Lab wheel, legacy isaaclab.sh installer, or Docker — across Linux (x86_64, aarch64) and Windows 11. - `user/migrate-from-isaac-gym/`: migrate Isaac Gym tasks, assets, and training workflows to Isaac Lab. - `user/migrate-2x-to-3x/`: migrate Isaac Lab 2.x projects to Isaac Lab 3.0 using the official migration guide. -- `user/domain-randomization-events/`: implement domain randomization through Isaac Lab event terms. +- `user/domain-randomization-events/`: implement fixed and adaptive domain randomization through event and curriculum terms. - `user/create-environments/`: create manager-based Isaac Lab environments by default, with direct environments for special cases. - `user/convert-direct-to-manager/`: convert validated direct Isaac Lab environments into manager-based task configurations. - `user/train-rl-agents/`: configure and run Isaac Lab reinforcement learning workflows. diff --git a/skills/user/domain-randomization-events/SKILL.md b/skills/user/domain-randomization-events/SKILL.md index 2c2054ffda6..95b4221c83d 100644 --- a/skills/user/domain-randomization-events/SKILL.md +++ b/skills/user/domain-randomization-events/SKILL.md @@ -1,6 +1,6 @@ --- name: isaaclab-randomizing-with-events -description: Implements Isaac Lab domain randomization with event terms in direct and manager-based workflows. Use when adding domain randomization, randomizing physics or observations, porting reset randomization, or configuring event-based variation. +description: Implements Isaac Lab domain randomization with event terms and success-driven ADR curricula. Use when randomizing physics or observations, porting reset randomization, or configuring Automatic or Adaptive Domain Randomization (ADR). audience: user status: stable owners: @@ -11,7 +11,7 @@ owners: ## When To Use -Use this skill when a user wants to add domain randomization to an Isaac Lab task through event terms. +Use this skill when a user wants to add domain randomization to an Isaac Lab task through event terms. Use ADR when policy success should change the randomization range. Do not use this skill for unrelated curriculum, command sampling, or reward shaping unless those changes interact with randomization. @@ -33,6 +33,7 @@ Do not use this skill for unrelated curriculum, command sampling, or reward shap 10. Use one clear distribution and range for each randomized quantity. 11. Validate with a small number of environments and repeated resets on each backend. 12. Expand ranges only after the baseline randomized task is stable. +13. For manager-based ADR, validate the final range as a fixed event, then use a task-owned scheduler and `modify_term_cfg` to interpolate it; see the [gravity example](examples.md#success-driven-adr). ## Validation @@ -43,6 +44,7 @@ Use the plan-validate-execute loop: 3. Check CPU/GPU expectations in the implementation. Some PhysX paths use CPU tensors while Newton paths may operate on the environment device. 4. Run a small reset or rollout smoke test for every targeted backend. 5. Fix shape, device, backend, and entity-name errors before scaling. +6. For ADR, test the exact endpoints and confirm policy success changes the next reset's range within its bounds. For skill changes, run: @@ -52,7 +54,7 @@ uv run --no-project python tools/skills/cli.py check ## Maintenance -Keep this skill synchronized with `source/isaaclab/isaaclab/managers/event_manager.py`, `source/isaaclab/isaaclab/envs/direct_rl_env.py`, `source/isaaclab/isaaclab/envs/direct_marl_env.py`, the direct and manager-based environment tutorials, and the managers API docs. If event-term behavior or mode semantics change, update the official docs or examples first and keep this skill focused on selecting the right workflow. +Keep this skill synchronized with `source/isaaclab/isaaclab/managers/event_manager.py`, `source/isaaclab/isaaclab/envs/direct_rl_env.py`, `source/isaaclab/isaaclab/envs/direct_marl_env.py`, the direct and manager-based environment tutorials, and the managers API docs. For ADR, follow the curriculum guide and Core Lift example. ## References @@ -62,4 +64,6 @@ Keep this skill synchronized with `source/isaaclab/isaaclab/managers/event_manag - [Event manager source](../../../source/isaaclab/isaaclab/managers/event_manager.py) - [Direct workflow randomization tutorial](../../../docs/source/tutorials/03_envs/create_direct_rl_env.rst) - [Manager-based event terms tutorial](../../../docs/source/tutorials/03_envs/create_manager_base_env.rst) +- [Curriculum utilities guide](../../../docs/source/how-to/curriculums.rst) +- [Core Lift ADR config](../../../source/isaaclab_tasks/isaaclab_tasks/core/lift/adr_curriculum.py) - [Managers API](../../../docs/source/api/lab/isaaclab.managers.rst) diff --git a/skills/user/domain-randomization-events/evaluations.md b/skills/user/domain-randomization-events/evaluations.md index 6fe8cf2363a..4d25334d3d1 100644 --- a/skills/user/domain-randomization-events/evaluations.md +++ b/skills/user/domain-randomization-events/evaluations.md @@ -7,6 +7,7 @@ - Scenario 3: interval disturbance - Scenario 4: PhysX and Newton material randomization - Scenario 5: direct workflow events +- Scenario 6: success-driven ADR ## Scenario 1: Reset Randomization @@ -84,3 +85,17 @@ Known failure modes: - Claims event terms are only for manager-based environments. - Converts the task to manager-based solely to use randomization events. + +## Scenario 6: Success-Driven ADR + +Query: "Start gravity at zero and automatically ramp it to -9.81 as my lift policy succeeds." + +Expected behavior: + +- Keeps gravity application in a reset event. +- Uses a manager-based curriculum to interpolate from zero to full gravity as policy success changes. +- Uses a task-owned scheduler and validates both endpoint values. + +Pass/fail criteria: + +- Links the curriculum guide and Core Lift ADR example. diff --git a/skills/user/domain-randomization-events/examples.md b/skills/user/domain-randomization-events/examples.md index 4010eb0818e..d9990f5af7f 100644 --- a/skills/user/domain-randomization-events/examples.md +++ b/skills/user/domain-randomization-events/examples.md @@ -4,6 +4,7 @@ - Reset state randomization - Direct workflow event config +- Success-driven ADR - Prestartup USD randomization - Startup property randomization - Backend-specific material randomization @@ -31,6 +32,38 @@ Expected setup: - Keep reward and observation logic in direct methods. - Validate that `prestartup`, `startup`, `reset`, and `interval` modes fire at the expected times for direct workflows. +## Success-Driven ADR + +Input: start a manager-based lift task at zero gravity, then approach full gravity as the policy succeeds. + +Given a reset event named `variable_gravity`, add a task-owned scheduler and interpolation term: + +```python +from isaaclab.managers import CurriculumTermCfg as CurrTerm +from isaaclab.utils.configclass import configclass + +from . import mdp + + +@configclass +class CurriculumCfg: + adr = CurrTerm(func=mdp.DifficultyScheduler, params={"init_difficulty": 0, "min_difficulty": 0, "max_difficulty": 10}) + gravity_adr = CurrTerm( + func=mdp.modify_term_cfg, + params={ + "address": "events.variable_gravity.params.gravity_distribution_params", + "modify_fn": mdp.initial_final_interpolate_fn, + "modify_params": { + "initial_value": ((0.0, 0.0, 0.0), (0.0, 0.0, 0.0)), + "final_value": ((0.0, 0.0, -9.81), (0.0, 0.0, -9.81)), + "difficulty_term_str": "adr", + }, + }, + ) +``` + +Assign `curriculum: CurriculumCfg = CurriculumCfg()` on the environment config. Adapt the [Core Lift ADR scheduler](../../../source/isaaclab_tasks/isaaclab_tasks/core/lift/mdp/curriculums.py) and test both endpoints. + ## Startup Property Randomization Input: randomize a property once after simulation starts. From 4249489a08812d8452266f71b3f1c62512cbaae6 Mon Sep 17 00:00:00 2001 From: camevor Date: Mon, 24 Aug 2026 21:07:53 +0200 Subject: [PATCH 4/5] Vectorize clone plan queries (#7319) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description Gather clone-plan env ids in one indexing step This replaces some Python loops with vectorized numpy calls and improves startup performance. Fixes # (issue) ## Type of change - (Startup performance enhancement) ## Checklist - [ ] I have read and understood the [contribution guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html) - [ ] I have run the [`pre-commit` checks](https://pre-commit.com/) with `./isaaclab.sh --format` - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have added a changelog fragment under `source//changelog.d/` for every touched package (do **not** edit `CHANGELOG.rst` or bump `extension.toml` — CI handles that) - [ ] I have added my name to the `CONTRIBUTORS.md` or my name already exists there (cherry picked from commit 2c07bbb43a9bb5be5a75ccf4541286bc8f6e0a4b) --- .../changelog.d/clone-query-vectorized.skip | 0 source/isaaclab/isaaclab/cloner/query.py | 9 +++-- .../test/cloner/test_clone_plan_algebra.py | 37 ++++++++++++++++++- 3 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 source/isaaclab/changelog.d/clone-query-vectorized.skip diff --git a/source/isaaclab/changelog.d/clone-query-vectorized.skip b/source/isaaclab/changelog.d/clone-query-vectorized.skip new file mode 100644 index 00000000000..e69de29bb2d diff --git a/source/isaaclab/isaaclab/cloner/query.py b/source/isaaclab/isaaclab/cloner/query.py index e36df47614f..bbc80f550bd 100644 --- a/source/isaaclab/isaaclab/cloner/query.py +++ b/source/isaaclab/isaaclab/cloner/query.py @@ -37,10 +37,11 @@ def _row_env_ids(plan: ClonePlan, row: int) -> tuple[int, ...]: """Env ids populated from a plan row: the plan's env ids at the row's ``True`` columns.""" - columns = plan.clone_mask[row].nonzero(as_tuple=False).flatten().tolist() + columns = plan.clone_mask[row].nonzero(as_tuple=False).flatten() if plan.env_ids is None: - return tuple(int(column) for column in columns) - return tuple(int(plan.env_ids[column]) for column in columns) + return tuple(columns.tolist()) + columns = columns.to(plan.env_ids.device) + return tuple(plan.env_ids[columns].tolist()) def _column_for_env_id(plan: ClonePlan, env_id: int) -> int | None: @@ -82,7 +83,7 @@ def _clone_rows(plan: ClonePlan, path_expr: str, *, populated_only: bool) -> lis for row, template in enumerate(plan.destinations): if "{}" not in template: continue - if populated_only and not _row_env_ids(plan, row): + if populated_only and not plan.clone_mask[row].any(): continue matched = pth.match(path_expr, template) if matched is None: diff --git a/source/isaaclab/test/cloner/test_clone_plan_algebra.py b/source/isaaclab/test/cloner/test_clone_plan_algebra.py index 1e4f148086a..3794e964dbd 100644 --- a/source/isaaclab/test/cloner/test_clone_plan_algebra.py +++ b/source/isaaclab/test/cloner/test_clone_plan_algebra.py @@ -334,8 +334,8 @@ def test_iter_sources_yields_nearest_owner(): ] -def test_iter_sources_skips_rows_without_envs(): - """A row populating no env is not a source of anything.""" +def test_iter_sources_reports_only_the_envs_a_row_populates(): + """A row covering part of the envs is a source for those envs only.""" plan = _plan( ("/World/envs/env_2/Object",), ("/World/envs/env_{}/Object",), @@ -352,6 +352,24 @@ def test_iter_sources_skips_rows_without_envs(): ] +def test_iter_sources_skips_rows_without_envs(): + """A nearer template populating no env does not hide the populated ancestor owning the path.""" + plan = _plan( + ("/World/envs/env_0/Robot", "/World/envs/env_0/Robot/wrist/Camera"), + ("/World/envs/env_{}/Robot", "/World/envs/env_{}/Robot/wrist/Camera"), + [[True, True, False, False], [False, False, False, False]], + ) + + assert list(cloner.query.iter_sources(plan, "/World/envs/env_[^/]+/Robot/wrist/Camera")) == [ + ( + "/World/envs/env_0/Robot", + "/World/envs/env_{}/Robot", + "/World/envs/env_0/Robot/wrist/Camera", + (0, 1), + ) + ] + + def test_iter_sources_distinct_env_root(): """The destination template need not sit under the default env root.""" plan = PLANS["distinct_env_root"] @@ -494,6 +512,21 @@ def test_query_translates_env_ids_through_the_plan(): assert source + suffix == path +@pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA is unavailable") +def test_query_gathers_env_ids_across_devices(): + """Environment ids can remain on CPU when the clone mask is on CUDA.""" + plan = ClonePlan( + sources=("/World/envs/env_2/Robot",), + destinations=("/World/envs/env_{}/Robot",), + clone_mask=torch.tensor([[True, False, True]], dtype=torch.bool, device="cuda"), + env_ids=torch.tensor([2, 5, 8], dtype=torch.long), + ) + path = "/World/envs/env_2/Robot/base" + + assert cloner.query.path_env_ids(plan, path) == (2, 8) + assert next(iter(cloner.query.iter_sources(plan, "/World/envs/env_[^/]+/Robot")))[3] == (2, 8) + + @pytest.mark.parametrize("env_id", [-1, 4, 99]) def test_query_rejects_env_ids_outside_the_plan(env_id): """Out-of-range and negative ids resolve to nothing instead of wrapping the mask.""" From 8af682bfcb95a3714946a19c96ec4d5da6862ed0 Mon Sep 17 00:00:00 2001 From: ooctipus Date: Mon, 24 Aug 2026 20:12:50 -0700 Subject: [PATCH 5/5] Extend Core Lift and Reorient episode duration (#7316) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Changed the Core Lift and Reorient pose-command resampling range from 3–5 seconds to 4–6 seconds. - Removed the ReorientEnvCfg 2–3 second post-init override so CommandsCfg remains the single source of truth. - Extended the episode length from 6 to 12 seconds. This gives policies more time to complete each commanded goal while retaining multiple goals per episode. ## Testing - Focused lift config tests: 3 passed. - Formatting and style hooks passed. - The isaaclab_tasks changelog fragment passed validation against upstream/develop. (cherry picked from commit a00278f0fde645f814dbdf97e46b8603e93c72bf) --- .../zhengyuz-extend-reorient-episode-duration.rst | 4 ++++ .../isaaclab_tasks/isaaclab_tasks/core/lift/lift_env_cfg.py | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 source/isaaclab_tasks/changelog.d/zhengyuz-extend-reorient-episode-duration.rst diff --git a/source/isaaclab_tasks/changelog.d/zhengyuz-extend-reorient-episode-duration.rst b/source/isaaclab_tasks/changelog.d/zhengyuz-extend-reorient-episode-duration.rst new file mode 100644 index 00000000000..4ae09f0847e --- /dev/null +++ b/source/isaaclab_tasks/changelog.d/zhengyuz-extend-reorient-episode-duration.rst @@ -0,0 +1,4 @@ +Changed +^^^^^^^ + +* Extended Core Lift and Reorient task episodes to 12 seconds and their pose-command resampling range to 4--6 seconds. diff --git a/source/isaaclab_tasks/isaaclab_tasks/core/lift/lift_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/core/lift/lift_env_cfg.py index 8ce93bf7150..94b6d2fc44f 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/core/lift/lift_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/core/lift/lift_env_cfg.py @@ -139,7 +139,7 @@ class CommandsCfg: object_pose = mdp.ObjectUniformPoseCommandCfg( asset_name="robot", object_name="object", - resampling_time_range=(3.0, 5.0), + resampling_time_range=(4.0, 6.0), debug_vis=False, ranges=mdp.ObjectUniformPoseCommandCfg.Ranges( pos_x=(-0.7, -0.3), @@ -566,9 +566,8 @@ def __post_init__(self): self.decimation = 4 # 30 Hz # *single-goal setup - self.commands.object_pose.resampling_time_range = (2.0, 3.0) self.commands.object_pose.position_only = False - self.episode_length_s = 6.0 + self.episode_length_s = 12.0 self.is_finite_horizon = False # simulation settings