From e74397354b76d95cb49ee4afc8aee2b3ef809027 Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Sat, 25 Oct 2025 01:25:38 +0800 Subject: [PATCH 01/92] Initial commit --- LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. From 001437a7e1db18994cd57f4f384026adb0c04997 Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Fri, 21 Nov 2025 13:09:04 +0000 Subject: [PATCH 02/92] Init Project (#1) --- .github/ISSUE_TEMPLATE/bug.md | 46 + .github/ISSUE_TEMPLATE/proposal.md | 26 + .github/PULL_REQUEST_TEMPLATE.md | 54 + .gitignore | 222 ++ .readthedocs.yaml | 23 + README.md | 45 + VERSION | 1 + assets/imgs/teaser.jpg | Bin 0 -> 1148574 bytes configs/agents/rl/push_cube/gym_config.json | 129 + configs/agents/rl/push_cube/train_config.json | 64 + configs/gym/action_bank/conf.json | 237 ++ configs/gym/cobotmagic.json | 120 + configs/gym/dexforce_w1.json | 109 + configs/gym/pour_water/action_config.json | 938 +++++++ configs/gym/pour_water/gym_config.json | 459 ++++ .../reality_config_PourWaterW1Single_v3.json | 582 +++++ configs/gym/scoop_ice/gym_config.json | 254 ++ docs/Makefile | 21 + docs/make.bat | 35 + docs/requirements.txt | 9 + docs/source/_templates/module.rst | 58 + ...utils.warp.kernels.reshape_tiled_image.rst | 6 + .../embodichain.utils.warp.kernels.rst | 6 + ...chain.utils.warp.kinematics.opw_solver.rst | 6 + .../embodichain.utils.warp.kinematics.rst | 6 + ....utils.warp.kinematics.warp_trajectory.rst | 6 + .../embodichain/embodichain.agents.rst | 12 + .../embodichain.lab.gym.envs.managers.rst | 130 + .../embodichain/embodichain.lab.gym.envs.rst | 34 + .../embodichain/embodichain.lab.gym.rst | 153 ++ .../embodichain/embodichain.lab.gym.utils.rst | 48 + .../embodichain/embodichain.lab.rst | 29 + .../embodichain/embodichain.lab.sim.cfg.rst | 21 + .../embodichain.lab.sim.common.rst | 12 + .../embodichain.lab.sim.material.rst | 14 + .../embodichain.lab.sim.objects.rst | 111 + .../embodichain.lab.sim.robots.rst | 6 + .../embodichain/embodichain.lab.sim.rst | 101 + .../embodichain.lab.sim.sensors.rst | 54 + .../embodichain.lab.sim.shapes.rst | 16 + .../embodichain.lab.sim.sim_manager.rst | 13 + .../embodichain.lab.sim.solvers.rst | 95 + .../embodichain/embodichain.lab.sim.types.rst | 6 + .../embodichain.lab.sim.utility.rst | 31 + .../embodichain/embodichain.toolkits.rst | 29 + .../embodichain/embodichain.utils.rst | 100 + .../embodichain.utils.warp.kinematics.rst | 37 + .../embodichain/embodichain.utils.warp.rst | 27 + docs/source/api_reference/index.rst | 19 + docs/source/conf.py | 66 + docs/source/index.rst | 50 + docs/source/introduction.rst | 58 + docs/source/overview/gym/index.rst | 5 + docs/source/overview/rl/algorithm.md | 67 + docs/source/overview/rl/buffer.md | 65 + docs/source/overview/rl/config.md | 55 + docs/source/overview/rl/index.rst | 80 + docs/source/overview/rl/models.md | 50 + docs/source/overview/rl/train_script.md | 48 + docs/source/overview/rl/trainer.md | 53 + docs/source/overview/sim/index.rst | 23 + docs/source/overview/sim/planners/index.rst | 36 + .../overview/sim/planners/motion_generator.md | 142 ++ .../overview/sim/planners/toppra_planner.md | 58 + .../sim/planners/trajectory_sample_method.md | 17 + .../sim/solvers/differential_solver.md | 99 + docs/source/overview/sim/solvers/index.rst | 96 + .../source/overview/sim/solvers/opw_solver.md | 111 + .../overview/sim/solvers/pink_solver.md | 103 + .../overview/sim/solvers/pinocchio_solver.md | 94 + .../overview/sim/solvers/pytorch_solver.md | 112 + .../source/overview/sim/solvers/srs_solver.md | 133 + docs/source/overview/vla/index.rst | 2 + docs/source/quick_start/docs.md | 18 + docs/source/quick_start/install.md | 71 + docs/source/resources/roadmap.md | 25 + docs/source/resources/robot/cobotmagic.md | 112 + docs/source/resources/robot/dexforce_w1.md | 54 + docs/source/resources/robot/index.rst | 9 + docs/source/resources/task/index.rst | 7 + docs/source/resources/task/pour_water.md | 3 + docs/source/tutorial/basic_env.rst | 185 ++ docs/source/tutorial/create_scene.rst | 93 + docs/source/tutorial/create_softbody.rst | 68 + docs/source/tutorial/gizmo.rst | 270 ++ docs/source/tutorial/index.rst | 19 + docs/source/tutorial/modular_env.rst | 237 ++ docs/source/tutorial/motion_gen.rst | 134 + docs/source/tutorial/rigid_object_group.rst | 52 + docs/source/tutorial/rl.rst | 365 +++ docs/source/tutorial/robot.rst | 143 ++ docs/source/tutorial/sensor.rst | 118 + docs/source/tutorial/solver.rst | 114 + docs/sync_readme.py | 30 + embodichain/__init__.py | 32 + embodichain/agents/rl/algo/__init__.py | 52 + embodichain/agents/rl/algo/base.py | 52 + embodichain/agents/rl/algo/ppo.py | 184 ++ embodichain/agents/rl/buffer/__init__.py | 19 + .../agents/rl/buffer/rollout_buffer.py | 106 + embodichain/agents/rl/models/__init__.py | 101 + embodichain/agents/rl/models/actor_critic.py | 96 + embodichain/agents/rl/models/mlp.py | 121 + embodichain/agents/rl/models/policy.py | 94 + embodichain/agents/rl/train.py | 270 ++ embodichain/agents/rl/utils/__init__.py | 21 + embodichain/agents/rl/utils/config.py | 29 + embodichain/agents/rl/utils/trainer.py | 265 ++ embodichain/data/__init__.py | 35 + embodichain/data/assets/__init__.py | 23 + embodichain/data/assets/demo_assets.py | 46 + embodichain/data/assets/eef_assets.py | 264 ++ embodichain/data/assets/materials.py | 107 + embodichain/data/assets/obj_assets.py | 215 ++ embodichain/data/assets/robot_assets.py | 463 ++++ embodichain/data/assets/scene_assets.py | 63 + embodichain/data/assets/w1_assets.py | 210 ++ embodichain/data/constants.py | 21 + embodichain/data/data_engine/__init__.py | 15 + .../data/data_engine/data_dict_extractor.py | 1135 +++++++++ .../data/data_engine/datasets/vla_datasets.py | 521 ++++ embodichain/data/data_engine/online/engine.py | 525 ++++ embodichain/data/data_engine/online/enum.py | 34 + .../data_engine/online/online_generator.py | 191 ++ embodichain/data/data_engine/unified_state.py | 381 +++ embodichain/data/dataset.py | 170 ++ embodichain/data/enum.py | 349 +++ embodichain/data/global_indices.py | 132 + embodichain/data/global_mapping.py | 161 ++ embodichain/lab/__init__.py | 19 + embodichain/lab/devices/__init__.py | 17 + embodichain/lab/devices/device.py | 44 + embodichain/lab/gym/__init__.py | 18 + embodichain/lab/gym/envs/__init__.py | 31 + .../envs/action_bank/configurable_action.py | 1472 +++++++++++ embodichain/lab/gym/envs/action_bank/utils.py | 69 + embodichain/lab/gym/envs/base_env.py | 506 ++++ embodichain/lab/gym/envs/embodied_env.py | 506 ++++ embodichain/lab/gym/envs/managers/__init__.py | 20 + embodichain/lab/gym/envs/managers/cfg.py | 311 +++ .../lab/gym/envs/managers/event_manager.py | 353 +++ embodichain/lab/gym/envs/managers/events.py | 610 +++++ .../lab/gym/envs/managers/manager_base.py | 408 +++ .../gym/envs/managers/observation_manager.py | 213 ++ .../lab/gym/envs/managers/observations.py | 615 +++++ .../envs/managers/randomization/__init__.py | 22 + .../envs/managers/randomization/rendering.py | 469 ++++ .../envs/managers/randomization/spatial.py | 261 ++ embodichain/lab/gym/envs/managers/record.py | 237 ++ embodichain/lab/gym/envs/object/__init__.py | 17 + embodichain/lab/gym/envs/object/geometry.py | 138 + embodichain/lab/gym/envs/rl_env_cfg.py | 33 + embodichain/lab/gym/envs/tasks/rl/__init__.py | 32 + .../lab/gym/envs/tasks/rl/push_cube.py | 227 ++ .../lab/gym/envs/tasks/tableware/__init__.py | 0 .../tasks/tableware/pour_water/__init__.py | 0 .../tasks/tableware/pour_water/action_bank.py | 233 ++ .../tasks/tableware/pour_water/pour_water.py | 147 ++ .../lab/gym/envs/tasks/tableware/scoop_ice.py | 214 ++ embodichain/lab/gym/envs/wrapper/__init__.py | 17 + embodichain/lab/gym/envs/wrapper/no_fail.py | 31 + embodichain/lab/gym/utils/__init__.py | 15 + embodichain/lab/gym/utils/gym_utils.py | 617 +++++ embodichain/lab/gym/utils/misc.py | 1564 ++++++++++++ embodichain/lab/gym/utils/registration.py | 204 ++ embodichain/lab/scripts/generate_video.py | 162 ++ embodichain/lab/scripts/preview_env.py | 149 ++ embodichain/lab/scripts/run_env.py | 301 +++ embodichain/lab/sim/__init__.py | 19 + embodichain/lab/sim/cfg.py | 1051 ++++++++ embodichain/lab/sim/common.py | 105 + embodichain/lab/sim/material.py | 386 +++ embodichain/lab/sim/objects/__init__.py | 28 + embodichain/lab/sim/objects/articulation.py | 1487 +++++++++++ embodichain/lab/sim/objects/gizmo.py | 545 ++++ embodichain/lab/sim/objects/light.py | 281 ++ embodichain/lab/sim/objects/rigid_object.py | 667 +++++ .../lab/sim/objects/rigid_object_group.py | 513 ++++ embodichain/lab/sim/objects/robot.py | 653 +++++ embodichain/lab/sim/objects/soft_object.py | 376 +++ embodichain/lab/sim/planners/base_planner.py | 201 ++ .../lab/sim/planners/motion_generator.py | 604 +++++ .../lab/sim/planners/toppra_planner.py | 172 ++ embodichain/lab/sim/planners/utils.py | 54 + embodichain/lab/sim/robots/__init__.py | 18 + embodichain/lab/sim/robots/cobotmagic.py | 227 ++ .../lab/sim/robots/dexforce_w1/__init__.py | 17 + embodichain/lab/sim/robots/dexforce_w1/cfg.py | 341 +++ .../lab/sim/robots/dexforce_w1/params.py | 269 ++ .../lab/sim/robots/dexforce_w1/types.py | 66 + .../lab/sim/robots/dexforce_w1/utils.py | 746 ++++++ embodichain/lab/sim/sensors/__init__.py | 19 + embodichain/lab/sim/sensors/base_sensor.py | 175 ++ embodichain/lab/sim/sensors/camera.py | 537 ++++ embodichain/lab/sim/sensors/stereo.py | 538 ++++ embodichain/lab/sim/shapes.py | 144 ++ embodichain/lab/sim/sim_manager.py | 1486 +++++++++++ embodichain/lab/sim/solvers/__init__.py | 23 + embodichain/lab/sim/solvers/base_solver.py | 457 ++++ .../lab/sim/solvers/differential_solver.py | 424 +++ .../sim/solvers/null_space_posture_task.py | 270 ++ embodichain/lab/sim/solvers/opw_solver.py | 734 ++++++ embodichain/lab/sim/solvers/pink_solver.py | 417 +++ .../lab/sim/solvers/pinocchio_solver.py | 644 +++++ embodichain/lab/sim/solvers/pytorch_solver.py | 603 +++++ .../lab/sim/solvers/qpos_seed_sampler.py | 88 + embodichain/lab/sim/solvers/srs_solver.py | 1222 +++++++++ embodichain/lab/sim/types.py | 28 + embodichain/lab/sim/utility/__init__.py | 19 + embodichain/lab/sim/utility/action_utils.py | 337 +++ embodichain/lab/sim/utility/gizmo_utils.py | 46 + embodichain/lab/sim/utility/import_utils.py | 125 + embodichain/lab/sim/utility/io_utils.py | 26 + embodichain/lab/sim/utility/mesh_utils.py | 208 ++ embodichain/lab/sim/utility/sim_utils.py | 286 +++ embodichain/lab/sim/utility/solver_utils.py | 111 + embodichain/lab/sim/utility/tensor.py | 55 + embodichain/toolkits/__init__.py | 15 + .../toolkits/graspkit/pg_grasp/__init__.py | 21 + .../toolkits/graspkit/pg_grasp/antipodal.py | 671 +++++ .../graspkit/pg_grasp/cone_sampler.py | 121 + .../toolkits/urdf_assembly/__init__.py | 18 + .../toolkits/urdf_assembly/component.py | 342 +++ .../toolkits/urdf_assembly/connection.py | 212 ++ .../toolkits/urdf_assembly/file_writer.py | 211 ++ .../toolkits/urdf_assembly/logging_utils.py | 131 + embodichain/toolkits/urdf_assembly/mesh.py | 190 ++ embodichain/toolkits/urdf_assembly/sensor.py | 957 +++++++ .../toolkits/urdf_assembly/signature.py | 204 ++ .../urdf_assembly/urdf_assembly_manager.py | 783 ++++++ embodichain/toolkits/urdf_assembly/utils.py | 30 + embodichain/utils/__init__.py | 59 + embodichain/utils/cfg.py | 598 +++++ embodichain/utils/configclass.py | 616 +++++ embodichain/utils/device_utils.py | 39 + embodichain/utils/file.py | 54 + embodichain/utils/img_utils.py | 154 ++ embodichain/utils/logger.py | 74 + embodichain/utils/math.py | 2269 +++++++++++++++++ embodichain/utils/module_utils.py | 217 ++ embodichain/utils/string.py | 336 +++ embodichain/utils/utility.py | 650 +++++ embodichain/utils/visualizer.py | 568 +++++ embodichain/utils/warp/__init__.py | 32 + embodichain/utils/warp/kernels.py | 93 + embodichain/utils/warp/kinematics/__init__.py | 19 + .../utils/warp/kinematics/interpolate.py | 172 ++ .../utils/warp/kinematics/opw_solver.py | 500 ++++ .../utils/warp/kinematics/srs_solver.py | 789 ++++++ .../utils/warp/kinematics/warp_trajectory.py | 180 ++ examples/gym/pour_water.sh | 3 + examples/gym/run_scoop_ice.sh | 1 + examples/sim/demo/grasp_cup_to_caffe.py | 469 ++++ examples/sim/demo/press_softbody.py | 261 ++ examples/sim/demo/scoop_ice.py | 569 +++++ examples/sim/gizmo/gizmo_camera.py | 236 ++ examples/sim/gizmo/gizmo_object.py | 175 ++ examples/sim/gizmo/gizmo_robot.py | 158 ++ examples/sim/gizmo/gizmo_scene.py | 263 ++ examples/sim/gizmo/gizmo_w1.py | 188 ++ examples/sim/planners/motion_generator.py | 146 ++ examples/sim/scene/scene_demo.py | 195 ++ examples/sim/sensors/batch_camera.py | 145 ++ examples/sim/solvers/differential_solver.py | 250 ++ examples/sim/solvers/opw_solver.py | 195 ++ examples/sim/solvers/pink_solver.py | 177 ++ examples/sim/solvers/pinocchio_solver.py | 127 + examples/sim/solvers/pytorch_solver.py | 226 ++ examples/sim/solvers/srs_solver.py | 85 + pyproject.toml | 74 + scripts/benchmark/opw_solver.py | 155 ++ scripts/tutorials/gym/modular_env.py | 216 ++ scripts/tutorials/gym/random_reach.py | 170 ++ .../sim/create_rigid_object_group.py | 170 ++ scripts/tutorials/sim/create_robot.py | 218 ++ scripts/tutorials/sim/create_scene.py | 149 ++ scripts/tutorials/sim/create_sensor.py | 346 +++ scripts/tutorials/sim/create_softbody.py | 161 ++ scripts/tutorials/sim/gizmo_robot.py | 158 ++ setup.py | 123 + tests/common.py | 63 + tests/datasets/run_pourwater_env_offline.py | 107 + tests/datasets/test_configurable_action.py | 246 ++ tests/datasets/test_online_training.py | 102 + tests/gym/envs/test_base_env.py | 182 ++ tests/gym/envs/test_embodied_env.py | 163 ++ tests/sim/objects/test_articulation.py | 198 ++ tests/sim/objects/test_light.py | 155 ++ tests/sim/objects/test_rigid_object.py | 280 ++ tests/sim/objects/test_rigid_object_group.py | 132 + tests/sim/objects/test_robot.py | 264 ++ tests/sim/objects/test_soft_object.py | 105 + tests/sim/planners/test_motion_generator.py | 251 ++ tests/sim/sensors/test_camera.py | 153 ++ tests/sim/sensors/test_stereo.py | 155 ++ tests/sim/solvers/test_differential_solver.py | 142 ++ tests/sim/solvers/test_opw_solver.py | 139 + tests/sim/solvers/test_pink_solver.py | 146 ++ tests/sim/solvers/test_pinocchio_solver.py | 126 + tests/sim/solvers/test_pytorch_solver.py | 130 + tests/sim/solvers/test_srs_solver.py | 307 +++ tests/sim/test_sim_manager.py | 63 + tests/toolkits/test_pg_grasp.py | 96 + tests/unitest.sh | 93 + 304 files changed, 63895 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug.md create mode 100644 .github/ISSUE_TEMPLATE/proposal.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .gitignore create mode 100644 .readthedocs.yaml create mode 100644 README.md create mode 100644 VERSION create mode 100644 assets/imgs/teaser.jpg create mode 100644 configs/agents/rl/push_cube/gym_config.json create mode 100644 configs/agents/rl/push_cube/train_config.json create mode 100644 configs/gym/action_bank/conf.json create mode 100644 configs/gym/cobotmagic.json create mode 100644 configs/gym/dexforce_w1.json create mode 100644 configs/gym/pour_water/action_config.json create mode 100644 configs/gym/pour_water/gym_config.json create mode 100644 configs/gym/real2sim/reality_config_PourWaterW1Single_v3.json create mode 100644 configs/gym/scoop_ice/gym_config.json create mode 100644 docs/Makefile create mode 100644 docs/make.bat create mode 100644 docs/requirements.txt create mode 100644 docs/source/_templates/module.rst create mode 100644 docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kernels.reshape_tiled_image.rst create mode 100644 docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kernels.rst create mode 100644 docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kinematics.opw_solver.rst create mode 100644 docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kinematics.rst create mode 100644 docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kinematics.warp_trajectory.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.agents.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.gym.envs.managers.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.gym.envs.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.gym.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.gym.utils.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.sim.cfg.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.sim.common.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.sim.material.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.sim.objects.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.sim.robots.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.sim.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.sim.sensors.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.sim.shapes.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.sim.sim_manager.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.sim.solvers.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.sim.types.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.lab.sim.utility.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.toolkits.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.utils.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.utils.warp.kinematics.rst create mode 100644 docs/source/api_reference/embodichain/embodichain.utils.warp.rst create mode 100644 docs/source/api_reference/index.rst create mode 100644 docs/source/conf.py create mode 100644 docs/source/index.rst create mode 100644 docs/source/introduction.rst create mode 100644 docs/source/overview/gym/index.rst create mode 100644 docs/source/overview/rl/algorithm.md create mode 100644 docs/source/overview/rl/buffer.md create mode 100644 docs/source/overview/rl/config.md create mode 100644 docs/source/overview/rl/index.rst create mode 100644 docs/source/overview/rl/models.md create mode 100644 docs/source/overview/rl/train_script.md create mode 100644 docs/source/overview/rl/trainer.md create mode 100644 docs/source/overview/sim/index.rst create mode 100644 docs/source/overview/sim/planners/index.rst create mode 100644 docs/source/overview/sim/planners/motion_generator.md create mode 100644 docs/source/overview/sim/planners/toppra_planner.md create mode 100644 docs/source/overview/sim/planners/trajectory_sample_method.md create mode 100644 docs/source/overview/sim/solvers/differential_solver.md create mode 100644 docs/source/overview/sim/solvers/index.rst create mode 100644 docs/source/overview/sim/solvers/opw_solver.md create mode 100644 docs/source/overview/sim/solvers/pink_solver.md create mode 100644 docs/source/overview/sim/solvers/pinocchio_solver.md create mode 100644 docs/source/overview/sim/solvers/pytorch_solver.md create mode 100644 docs/source/overview/sim/solvers/srs_solver.md create mode 100644 docs/source/overview/vla/index.rst create mode 100644 docs/source/quick_start/docs.md create mode 100644 docs/source/quick_start/install.md create mode 100644 docs/source/resources/roadmap.md create mode 100644 docs/source/resources/robot/cobotmagic.md create mode 100644 docs/source/resources/robot/dexforce_w1.md create mode 100644 docs/source/resources/robot/index.rst create mode 100644 docs/source/resources/task/index.rst create mode 100644 docs/source/resources/task/pour_water.md create mode 100644 docs/source/tutorial/basic_env.rst create mode 100644 docs/source/tutorial/create_scene.rst create mode 100644 docs/source/tutorial/create_softbody.rst create mode 100644 docs/source/tutorial/gizmo.rst create mode 100644 docs/source/tutorial/index.rst create mode 100644 docs/source/tutorial/modular_env.rst create mode 100644 docs/source/tutorial/motion_gen.rst create mode 100644 docs/source/tutorial/rigid_object_group.rst create mode 100644 docs/source/tutorial/rl.rst create mode 100644 docs/source/tutorial/robot.rst create mode 100644 docs/source/tutorial/sensor.rst create mode 100644 docs/source/tutorial/solver.rst create mode 100644 docs/sync_readme.py create mode 100644 embodichain/__init__.py create mode 100644 embodichain/agents/rl/algo/__init__.py create mode 100644 embodichain/agents/rl/algo/base.py create mode 100644 embodichain/agents/rl/algo/ppo.py create mode 100644 embodichain/agents/rl/buffer/__init__.py create mode 100644 embodichain/agents/rl/buffer/rollout_buffer.py create mode 100644 embodichain/agents/rl/models/__init__.py create mode 100644 embodichain/agents/rl/models/actor_critic.py create mode 100644 embodichain/agents/rl/models/mlp.py create mode 100644 embodichain/agents/rl/models/policy.py create mode 100644 embodichain/agents/rl/train.py create mode 100644 embodichain/agents/rl/utils/__init__.py create mode 100644 embodichain/agents/rl/utils/config.py create mode 100644 embodichain/agents/rl/utils/trainer.py create mode 100644 embodichain/data/__init__.py create mode 100644 embodichain/data/assets/__init__.py create mode 100644 embodichain/data/assets/demo_assets.py create mode 100644 embodichain/data/assets/eef_assets.py create mode 100644 embodichain/data/assets/materials.py create mode 100644 embodichain/data/assets/obj_assets.py create mode 100644 embodichain/data/assets/robot_assets.py create mode 100644 embodichain/data/assets/scene_assets.py create mode 100644 embodichain/data/assets/w1_assets.py create mode 100644 embodichain/data/constants.py create mode 100644 embodichain/data/data_engine/__init__.py create mode 100644 embodichain/data/data_engine/data_dict_extractor.py create mode 100644 embodichain/data/data_engine/datasets/vla_datasets.py create mode 100644 embodichain/data/data_engine/online/engine.py create mode 100644 embodichain/data/data_engine/online/enum.py create mode 100644 embodichain/data/data_engine/online/online_generator.py create mode 100644 embodichain/data/data_engine/unified_state.py create mode 100644 embodichain/data/dataset.py create mode 100644 embodichain/data/enum.py create mode 100644 embodichain/data/global_indices.py create mode 100644 embodichain/data/global_mapping.py create mode 100644 embodichain/lab/__init__.py create mode 100644 embodichain/lab/devices/__init__.py create mode 100644 embodichain/lab/devices/device.py create mode 100644 embodichain/lab/gym/__init__.py create mode 100644 embodichain/lab/gym/envs/__init__.py create mode 100644 embodichain/lab/gym/envs/action_bank/configurable_action.py create mode 100644 embodichain/lab/gym/envs/action_bank/utils.py create mode 100644 embodichain/lab/gym/envs/base_env.py create mode 100644 embodichain/lab/gym/envs/embodied_env.py create mode 100644 embodichain/lab/gym/envs/managers/__init__.py create mode 100644 embodichain/lab/gym/envs/managers/cfg.py create mode 100644 embodichain/lab/gym/envs/managers/event_manager.py create mode 100644 embodichain/lab/gym/envs/managers/events.py create mode 100644 embodichain/lab/gym/envs/managers/manager_base.py create mode 100644 embodichain/lab/gym/envs/managers/observation_manager.py create mode 100644 embodichain/lab/gym/envs/managers/observations.py create mode 100644 embodichain/lab/gym/envs/managers/randomization/__init__.py create mode 100644 embodichain/lab/gym/envs/managers/randomization/rendering.py create mode 100644 embodichain/lab/gym/envs/managers/randomization/spatial.py create mode 100644 embodichain/lab/gym/envs/managers/record.py create mode 100644 embodichain/lab/gym/envs/object/__init__.py create mode 100644 embodichain/lab/gym/envs/object/geometry.py create mode 100644 embodichain/lab/gym/envs/rl_env_cfg.py create mode 100644 embodichain/lab/gym/envs/tasks/rl/__init__.py create mode 100644 embodichain/lab/gym/envs/tasks/rl/push_cube.py create mode 100644 embodichain/lab/gym/envs/tasks/tableware/__init__.py create mode 100644 embodichain/lab/gym/envs/tasks/tableware/pour_water/__init__.py create mode 100644 embodichain/lab/gym/envs/tasks/tableware/pour_water/action_bank.py create mode 100644 embodichain/lab/gym/envs/tasks/tableware/pour_water/pour_water.py create mode 100644 embodichain/lab/gym/envs/tasks/tableware/scoop_ice.py create mode 100644 embodichain/lab/gym/envs/wrapper/__init__.py create mode 100644 embodichain/lab/gym/envs/wrapper/no_fail.py create mode 100644 embodichain/lab/gym/utils/__init__.py create mode 100644 embodichain/lab/gym/utils/gym_utils.py create mode 100644 embodichain/lab/gym/utils/misc.py create mode 100644 embodichain/lab/gym/utils/registration.py create mode 100644 embodichain/lab/scripts/generate_video.py create mode 100644 embodichain/lab/scripts/preview_env.py create mode 100644 embodichain/lab/scripts/run_env.py create mode 100644 embodichain/lab/sim/__init__.py create mode 100644 embodichain/lab/sim/cfg.py create mode 100644 embodichain/lab/sim/common.py create mode 100644 embodichain/lab/sim/material.py create mode 100644 embodichain/lab/sim/objects/__init__.py create mode 100644 embodichain/lab/sim/objects/articulation.py create mode 100644 embodichain/lab/sim/objects/gizmo.py create mode 100644 embodichain/lab/sim/objects/light.py create mode 100644 embodichain/lab/sim/objects/rigid_object.py create mode 100644 embodichain/lab/sim/objects/rigid_object_group.py create mode 100644 embodichain/lab/sim/objects/robot.py create mode 100644 embodichain/lab/sim/objects/soft_object.py create mode 100644 embodichain/lab/sim/planners/base_planner.py create mode 100644 embodichain/lab/sim/planners/motion_generator.py create mode 100644 embodichain/lab/sim/planners/toppra_planner.py create mode 100644 embodichain/lab/sim/planners/utils.py create mode 100644 embodichain/lab/sim/robots/__init__.py create mode 100644 embodichain/lab/sim/robots/cobotmagic.py create mode 100644 embodichain/lab/sim/robots/dexforce_w1/__init__.py create mode 100644 embodichain/lab/sim/robots/dexforce_w1/cfg.py create mode 100644 embodichain/lab/sim/robots/dexforce_w1/params.py create mode 100644 embodichain/lab/sim/robots/dexforce_w1/types.py create mode 100644 embodichain/lab/sim/robots/dexforce_w1/utils.py create mode 100644 embodichain/lab/sim/sensors/__init__.py create mode 100644 embodichain/lab/sim/sensors/base_sensor.py create mode 100644 embodichain/lab/sim/sensors/camera.py create mode 100644 embodichain/lab/sim/sensors/stereo.py create mode 100644 embodichain/lab/sim/shapes.py create mode 100644 embodichain/lab/sim/sim_manager.py create mode 100644 embodichain/lab/sim/solvers/__init__.py create mode 100644 embodichain/lab/sim/solvers/base_solver.py create mode 100644 embodichain/lab/sim/solvers/differential_solver.py create mode 100644 embodichain/lab/sim/solvers/null_space_posture_task.py create mode 100644 embodichain/lab/sim/solvers/opw_solver.py create mode 100644 embodichain/lab/sim/solvers/pink_solver.py create mode 100644 embodichain/lab/sim/solvers/pinocchio_solver.py create mode 100644 embodichain/lab/sim/solvers/pytorch_solver.py create mode 100644 embodichain/lab/sim/solvers/qpos_seed_sampler.py create mode 100644 embodichain/lab/sim/solvers/srs_solver.py create mode 100644 embodichain/lab/sim/types.py create mode 100644 embodichain/lab/sim/utility/__init__.py create mode 100644 embodichain/lab/sim/utility/action_utils.py create mode 100644 embodichain/lab/sim/utility/gizmo_utils.py create mode 100644 embodichain/lab/sim/utility/import_utils.py create mode 100644 embodichain/lab/sim/utility/io_utils.py create mode 100644 embodichain/lab/sim/utility/mesh_utils.py create mode 100644 embodichain/lab/sim/utility/sim_utils.py create mode 100644 embodichain/lab/sim/utility/solver_utils.py create mode 100644 embodichain/lab/sim/utility/tensor.py create mode 100644 embodichain/toolkits/__init__.py create mode 100644 embodichain/toolkits/graspkit/pg_grasp/__init__.py create mode 100644 embodichain/toolkits/graspkit/pg_grasp/antipodal.py create mode 100644 embodichain/toolkits/graspkit/pg_grasp/cone_sampler.py create mode 100644 embodichain/toolkits/urdf_assembly/__init__.py create mode 100644 embodichain/toolkits/urdf_assembly/component.py create mode 100644 embodichain/toolkits/urdf_assembly/connection.py create mode 100644 embodichain/toolkits/urdf_assembly/file_writer.py create mode 100644 embodichain/toolkits/urdf_assembly/logging_utils.py create mode 100644 embodichain/toolkits/urdf_assembly/mesh.py create mode 100644 embodichain/toolkits/urdf_assembly/sensor.py create mode 100644 embodichain/toolkits/urdf_assembly/signature.py create mode 100644 embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py create mode 100644 embodichain/toolkits/urdf_assembly/utils.py create mode 100644 embodichain/utils/__init__.py create mode 100644 embodichain/utils/cfg.py create mode 100644 embodichain/utils/configclass.py create mode 100644 embodichain/utils/device_utils.py create mode 100644 embodichain/utils/file.py create mode 100644 embodichain/utils/img_utils.py create mode 100644 embodichain/utils/logger.py create mode 100644 embodichain/utils/math.py create mode 100644 embodichain/utils/module_utils.py create mode 100644 embodichain/utils/string.py create mode 100644 embodichain/utils/utility.py create mode 100644 embodichain/utils/visualizer.py create mode 100644 embodichain/utils/warp/__init__.py create mode 100644 embodichain/utils/warp/kernels.py create mode 100644 embodichain/utils/warp/kinematics/__init__.py create mode 100644 embodichain/utils/warp/kinematics/interpolate.py create mode 100644 embodichain/utils/warp/kinematics/opw_solver.py create mode 100644 embodichain/utils/warp/kinematics/srs_solver.py create mode 100644 embodichain/utils/warp/kinematics/warp_trajectory.py create mode 100755 examples/gym/pour_water.sh create mode 100755 examples/gym/run_scoop_ice.sh create mode 100644 examples/sim/demo/grasp_cup_to_caffe.py create mode 100644 examples/sim/demo/press_softbody.py create mode 100644 examples/sim/demo/scoop_ice.py create mode 100644 examples/sim/gizmo/gizmo_camera.py create mode 100644 examples/sim/gizmo/gizmo_object.py create mode 100644 examples/sim/gizmo/gizmo_robot.py create mode 100644 examples/sim/gizmo/gizmo_scene.py create mode 100644 examples/sim/gizmo/gizmo_w1.py create mode 100644 examples/sim/planners/motion_generator.py create mode 100644 examples/sim/scene/scene_demo.py create mode 100644 examples/sim/sensors/batch_camera.py create mode 100644 examples/sim/solvers/differential_solver.py create mode 100644 examples/sim/solvers/opw_solver.py create mode 100644 examples/sim/solvers/pink_solver.py create mode 100644 examples/sim/solvers/pinocchio_solver.py create mode 100644 examples/sim/solvers/pytorch_solver.py create mode 100644 examples/sim/solvers/srs_solver.py create mode 100644 pyproject.toml create mode 100644 scripts/benchmark/opw_solver.py create mode 100644 scripts/tutorials/gym/modular_env.py create mode 100644 scripts/tutorials/gym/random_reach.py create mode 100644 scripts/tutorials/sim/create_rigid_object_group.py create mode 100644 scripts/tutorials/sim/create_robot.py create mode 100644 scripts/tutorials/sim/create_scene.py create mode 100644 scripts/tutorials/sim/create_sensor.py create mode 100644 scripts/tutorials/sim/create_softbody.py create mode 100644 scripts/tutorials/sim/gizmo_robot.py create mode 100644 setup.py create mode 100644 tests/common.py create mode 100644 tests/datasets/run_pourwater_env_offline.py create mode 100644 tests/datasets/test_configurable_action.py create mode 100644 tests/datasets/test_online_training.py create mode 100644 tests/gym/envs/test_base_env.py create mode 100644 tests/gym/envs/test_embodied_env.py create mode 100644 tests/sim/objects/test_articulation.py create mode 100644 tests/sim/objects/test_light.py create mode 100644 tests/sim/objects/test_rigid_object.py create mode 100644 tests/sim/objects/test_rigid_object_group.py create mode 100644 tests/sim/objects/test_robot.py create mode 100644 tests/sim/objects/test_soft_object.py create mode 100644 tests/sim/planners/test_motion_generator.py create mode 100644 tests/sim/sensors/test_camera.py create mode 100644 tests/sim/sensors/test_stereo.py create mode 100644 tests/sim/solvers/test_differential_solver.py create mode 100644 tests/sim/solvers/test_opw_solver.py create mode 100644 tests/sim/solvers/test_pink_solver.py create mode 100644 tests/sim/solvers/test_pinocchio_solver.py create mode 100644 tests/sim/solvers/test_pytorch_solver.py create mode 100644 tests/sim/solvers/test_srs_solver.py create mode 100644 tests/sim/test_sim_manager.py create mode 100644 tests/toolkits/test_pg_grasp.py create mode 100755 tests/unitest.sh diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md new file mode 100644 index 00000000..1ed54bc4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -0,0 +1,46 @@ +--- +name: Bug Report +about: Submit a bug report +title: "[Bug Report] Bug title" + +--- + +If you are submitting a bug report, please fill in the following details and use the tag [bug]. + +### Describe the bug + +A clear and concise description of what the bug is. + +### Steps to reproduce + +Please try to provide a minimal example to reproduce the bug. Error messages and stack traces are also helpful. + + + +### System Info + +Describe the characteristic of your environment: + + +- Commit: [e.g. 8f3b9ca or main branch] +- OS: [e.g. Ubuntu 22.04] +- GPU: [e.g. RTX 3060] +- CUDA: [e.g. 12.8] +- GPU Driver: [e.g. 570.195.03, this can be seen by using `nvidia-smi` command.] + +### Additional context + +Add any other context about the problem here. + +### Checklist + +- [ ] I have checked that there is no similar issue in the repo (**required**) + diff --git a/.github/ISSUE_TEMPLATE/proposal.md b/.github/ISSUE_TEMPLATE/proposal.md new file mode 100644 index 00000000..8b7792a2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/proposal.md @@ -0,0 +1,26 @@ +--- +name: Proposal +about: Propose changes that are not bug fixes +title: "[Proposal] Proposal title" +--- + + +### Proposal + +A clear and concise description of the proposal. In a few sentences, describe the feature and its core capabilities. + +### Motivation + +Please outline the motivation for the proposal. Summarize the core use cases and user problems and needs you are trying to solve. + +Is your feature request related to a problem? e.g.,"I'm always frustrated when [...]". + +If this is related to another GitHub issue, please link here too. + +### Additional context + +Add any other context or screenshots about the feature request here. + +### Checklist + +- [ ] I have checked that there is no similar issue in the repo (**required**) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..bcdc2439 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,54 @@ +# Description + + + +Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. +List any dependencies that are required for this change. + +Fixes # (issue) + + + +## Type of change + + + +- Bug fix (non-breaking change which fixes an issue) +- New feature (non-breaking change which adds functionality) +- Breaking change (existing functionality will not work without user modification) +- Documentation update + +## Screenshots + +Please attach before and after screenshots of the change if applicable. + + + +## Checklist + +- [ ] I have run the `black .` command to format the code base. +- [ ] I have made corresponding changes to the documentation +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] Dependencies have been updated, if applicable. + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..4857c898 --- /dev/null +++ b/.gitignore @@ -0,0 +1,222 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +#python api built by docs +# docs/source/api + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# ignore file for vlac demo +cache + +*.filament +*.filamat +*.png +*.tiff +*.npy +*.pkl +*.hdf5 +*.pt +*.csv +materials + +!embodichain/agents/dexforce_vla/data/empty_lang_embed.pt +!resources/Arch.png +embodichain/toolkits/outputs/* +embodichain/toolkits/outputs/* + +embodichain/database/* + +3rdparty/ +Log/ +embodichain/deploy/h1/sim/unitree_h1 +embodichain/deploy/inspire/inspire_hand +embodichain/devices/camera/king_fisher/kingfisher + +# tensorboard logs +embodichain/agents/policy/runs/* +embodichain/agents/dexrdt/wandb +*.pth +outputs +test_configs/* + +wandb/ +embodichain/deploy/mobile_aloha/collect_data/data +*.mp4 + +# vscode settings +.vscode/ + +# web server backend +*/backend/datas/ +*/backend/logs/ +*/backend/__pycache__/ + +# web server frontend +*/backend/export_datas/ +*/backend/**/__pycache__/ + +# web server frontend +!web_server/frontend/**/* +!web_server/frontend/**/event* +*/frontend/node_modules +*/frontend/.DS_Store +*/frontend/*.local +*/frontend/.eslintcache +*/frontend/.stylelintcache diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000..17245082 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,23 @@ +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version, and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.10" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: docs/source/conf.py + +# Optionally, but recommended, +# declare the Python requirements required to build your documentation +# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +python: + install: + - requirements: docs/requirements.txt + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..61c352a4 --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# EmbodiChain + +![teaser](assets/imgs/teaser.jpg) +**📘 [Documentation](http://192.168.3.120/MixedAI/docs_dev/embodichain/index.html)** +--- + +EmbodiChain is an end-to-end, GPU-accelerated framework for Embodied AI. It streamlines research and development by unifying high-performance simulation, real-to-sim data pipelines, modular model architectures, and efficient training workflows. This integration enables rapid experimentation, seamless deployment of intelligent agents, and effective Sim2Real transfer for real-world robotic systems. + +> [!NOTE] +> EmbodiChain is in Alpha and under active development: +> * More features will be continually added in the coming months. +> * Since this is an early release, we welcome feedback (bug reports, feature requests, etc.) via GitHub Issues. + + +## Key Features + +- **High-Fidelity, GPU-Accelerated Simulation**: Combines realistic physics for both rigid and deformable objects with advanced ray-traced sensor modeling, all accelerated on the GPU for high-throughput batched simulations. +- **Unified Robot Learning Environment**: Offers standardized interfaces for a wide range of robot learning tasks, including Imitation Learning and Reinforcement Learning. +- **Scalable Data Pipeline**: Features a comprehensive toolkit for automated data collection, efficient processing, and large-scale data generation to fuel your models. +- **Efficient Training & Evaluation**: Supports modern training paradigms like online data streaming for Imitation Learning and massively parallel environment rollouts for Reinforcement Learning. +- **Modular and Extensible**: Designed with modularity in mind to easily integrate new robot platforms, environments, and learning algorithms. + + +## Getting Started + +To get started with EmbodiChain, follow these steps: + +- [Installation Guide](http://192.168.3.120/MixedAI/docs_dev/embodichain/quick_start/install.html) +- [Quick Start Tutorial](http://192.168.3.120/MixedAI/docs_dev/embodichain/tutorial/index.html) +- [API Reference](http://192.168.3.120/MixedAI/docs_dev/embodichain/api_reference/index.html) + + +## Citation + +If you use EmbodiChain in your research, please cite our work: + +```bibtex +@misc{EmbodiChain, + author = {EmbodiChain Developers}, + title = {EmbodiChain: An end-to-end, GPU-accelerated, and modular platform for building generalized Embodied Intelligence.}, + month = {November}, + year = {2025}, + url = {https://github.com/DexForce/EmbodiChain} +} +``` \ No newline at end of file diff --git a/VERSION b/VERSION new file mode 100644 index 00000000..8acdd82b --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.0.1 diff --git a/assets/imgs/teaser.jpg b/assets/imgs/teaser.jpg new file mode 100644 index 0000000000000000000000000000000000000000..59f12c3d70b7030d2146b17ecb22db2518d19dff GIT binary patch literal 1148574 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 z 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 Kz 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

oegHD2) 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 DUNP;~l!5pDw?zUOMBU#{Qi~ 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%0AmDTE56w5Jr5X~oxiwM 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

ZNWe zM3oScWF!OUoxkGsl{{?lW#vU33-oWcl$8ZM3yT6robDg;LfJLe;DjEwX?yE#^qdg`|-a>SNo$z)b?VSC1f2^a3&;pwYTB5!bPI7dqJAwEQO^;EI zG+r>3kYt6CBak4HY<{)`V>2RCm_Y<7Rwhq{L=I8T2G=pBAkU3y1A~#c>wvwa4BrGl%*qo@L+TV zWM{9-uLK?;FuShYj_D3J{h@*iSCR>F5{Duc389QJfO|TB!MIW;% z1vI+Tp*ahvKA^3}08tq4>ODA;-aOxWHzKHUv;OLskfXTWxWTmhrz8AX$9#`~43F7^ z1*O{+cN{uYBrQV&?`20;N$7Uzx%m#d^g}Hh=S;!>0FGb>#z(B_d}Y-TSbAc7AZ;?F z5fgKz$5CjLi34>I?a9p93C>eni5wi~Ary!y3G~@Y#^bh0@5N=dp)14%Ewi{4l=jF9 z4v~%iKbOGmW);P1sB<~wD+x{2Ja3Gsu^u}losKYD7~iJ-j}@n7NByVb779Xwvs^#~ zoQ>aD>Uxuqcj>==E2d3CdF5<%_fxNy`}v$+pa4>m1mB-g;}uqS3-ww$Ck}L^1h+d-+gdqU-uLtQLNP( zhV#y|0ol#eW4$swB(WLE=2WjJKKsg7vg!(q-w`#b4=49@n@%XyRB*|9V%$+Z0zpGN z^aKOkXOGX1?KkGJ=SPkXd|qNfkqz70vkIKBu(bZqi8bid;DVe0mg()qXbfx`0Yu|G zdGBu4gz)YX(Mk)eea8}|09J%0D@w~}RA$cDTzkoYbQtS95{DPZxPz%u!%a}7D}q8) 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

YnC+=$%?vVzkQA*Toh^V0jsPbeNXh6p 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 (SPI4Si9L&$>y#XZDOY|mlG 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 z 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 QE~7f;OW2Miw~P$9=&z^cm{pu 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%0DL52OtwQg{#zJgy58CDO<1fAt+WpNsD#YAzF?mLh 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 literal 0 HcmV?d00001 diff --git a/configs/agents/rl/push_cube/gym_config.json b/configs/agents/rl/push_cube/gym_config.json new file mode 100644 index 00000000..b78e7f37 --- /dev/null +++ b/configs/agents/rl/push_cube/gym_config.json @@ -0,0 +1,129 @@ +{ + "id": "PushCubeRL", + "max_episodes": 5, + "env": { + "num_envs": 128, + "sim_steps_per_control": 4, + "events": { + "randomize_cube": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cube"}, + "position_range": [[-0.2, -0.2, 0.0], [0.2, 0.2, 0.0]], + "relative_position": true + } + } + }, + "observations": {}, + "extensions": { + "obs_mode": "state", + "episode_length": 100, + "joint_limits": 0.5, + "action_scale": 0.1, + "success_threshold": 0.1, + "reaching_reward_weight": 0.1, + "place_reward_weight": 2.0, + "place_penalty_weight": 0.5, + "action_penalty_weight": 0.01, + "success_bonus_weight": 10.0 + } + }, + "robot": { + "uid": "Manipulator", + "urdf_cfg": { + "components": [ + { + "component_type": "arm", + "urdf_path": "UniversalRobots/UR10/UR10.urdf", + "transform": [ + [1.0, 0.0, 0.0, 0.0], + [0.0, 1.0, 0.0, 0.0], + [0.0, 0.0, 1.0, 0.0], + [0.0, 0.0, 0.0, 1.0] + ] + }, + { + "component_type": "hand", + "urdf_path": "DH_PGI_140_80/DH_PGI_140_80.urdf", + "transform": [ + [1.0, 0.0, 0.0, 0.0], + [0.0, 1.0, 0.0, 0.0], + [0.0, 0.0, 1.0, 0.0], + [0.0, 0.0, 0.0, 1.0] + ] + } + ] + }, + "init_pos": [0.0, 0.0, 0.0], + "init_rot": [0.0, 0.0, 0.0], + "init_qpos": [0.0, -1.57, 1.57, -1.57, -1.57, 0.0, 0.04, 0.04], + "drive_pros": { + "drive_type": "force", + "stiffness": 100000.0, + "damping": 1000.0, + "max_velocity": 2.0, + "max_effort": 500.0 + }, + "solver_cfg": { + "arm": { + "class_type": "PytorchSolver", + "end_link_name": "ee_link", + "root_link_name": "base_link", + "tcp": [ + [1.0, 0.0, 0.0, 0.0], + [0.0, 1.0, 0.0, 0.0], + [0.0, 0.0, 1.0, 0.16], + [0.0, 0.0, 0.0, 1.0] + ] + } + }, + "control_parts": { + "arm": ["JOINT[1-6]"] + } + }, + "sensor": [], + "light": { + }, + "background": [ + { + "uid": "goal_sphere", + "shape": { + "shape_type": "Sphere", + "radius": 0.02 + }, + "body_type": "kinematic", + "init_pos": [-0.9, -0.6, 0.05], + "attrs": { + "enable_collision": false, + "mass": 0.0 + } + } + ], + "rigid_object": [ + { + "uid": "cube", + "shape": { + "shape_type": "Cube", + "size": [0.1, 0.1, 0.1] + }, + "body_type": "dynamic", + "init_pos": [-0.6, -0.4, 0.05], + "attrs": { + "mass": 10.0, + "static_friction": 3.0, + "dynamic_friction": 2.0, + "linear_damping": 2.0, + "angular_damping": 2.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "restitution": 0.1, + "max_depenetration_velocity": 10.0, + "max_linear_velocity": 1.0, + "max_angular_velocity": 1.0 + } + } + ], + "rigid_object_group": [], + "articulation": [] +} diff --git a/configs/agents/rl/push_cube/train_config.json b/configs/agents/rl/push_cube/train_config.json new file mode 100644 index 00000000..f1558fda --- /dev/null +++ b/configs/agents/rl/push_cube/train_config.json @@ -0,0 +1,64 @@ +{ + "trainer": { + "exp_name": "push_cube_ppo", + "gym_config": "configs/agents/rl/push_cube/gym_config.json", + "seed": 42, + "device": "cuda:0", + "headless": true, + "iterations": 1000, + "rollout_steps": 1024, + "eval_freq": 2, + "save_freq": 200, + "use_wandb": false, + "wandb_project_name": "embodychain-push_cube", + "events": { + "eval": { + "record_camera": { + "func": "record_camera_data_async", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "main_cam", + "resolution": [640, 480], + "eye": [-1.4, 1.4, 2.0], + "target": [0, 0, 0], + "up": [0, 0, 1], + "intrinsics": [600, 600, 320, 240], + "save_path": "./outputs/videos/eval" + } + } + } + } + }, + "policy": { + "name": "actor_critic", + "actor": { + "type": "mlp", + "network_cfg": { + "hidden_sizes": [256, 256], + "activation": "relu" + } + }, + "critic": { + "type": "mlp", + "network_cfg": { + "hidden_sizes": [256, 256], + "activation": "relu" + } + } + }, + "algorithm": { + "name": "ppo", + "cfg": { + "learning_rate": 0.0001, + "n_epochs": 10, + "batch_size": 8192, + "gamma": 0.99, + "gae_lambda": 0.95, + "clip_coef": 0.2, + "ent_coef": 0.01, + "vf_coef": 0.5, + "max_grad_norm": 0.5 + } + } +} \ No newline at end of file diff --git a/configs/gym/action_bank/conf.json b/configs/gym/action_bank/conf.json new file mode 100644 index 00000000..3c5e9850 --- /dev/null +++ b/configs/gym/action_bank/conf.json @@ -0,0 +1,237 @@ +{ + "scope": { + "right_arm": { + "type": "DiGraph", + "dim": [ + 6 + ], + "init": { + "method": "given_qpos", + "kwargs": { + "given_qpos": [ + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "init_node_name": "" + }, + "dtype": "float32" + }, + "left_arm": { + "type": "DiGraph", + "dim": [ + 6 + ], + "init": { + "method": "given_qpos", + "kwargs": { + "given_qpos": [ + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + "init_node_name": "" + }, + "dtype": "float32" + }, + "left_eef": { + "type": "DiGraph", + "dim": [ + 2 + ], + "init": { + "method": "given_qpos", + "kwargs": { + "given_qpos": [ + 0, + 0 + ] + }, + "init_node_name": "" + }, + "dtype": "float32" + }, + "right_eef": { + "type": "DiGraph", + "dim": [ + 2 + ], + "init": { + "method": "given_qpos", + "kwargs": { + "given_qpos": [ + 0, + 0 + ] + }, + "init_node_name": "" + }, + "dtype": "float32" + } + }, + "node": { + "right_arm": [ + { + "home_qpos": { + "name": "A", + "kwargs": {} + } + }, + { + "bottle_grasp": { + "name": "B", + "kwargs": {} + } + }, + { + "bottle_pre1_pose": { + "name": "C", + "kwargs": {} + } + }, + { + "bottle_pre2_pose": { + "name": "C", + "kwargs": {} + } + }, + { + "bottle_place_pose": { + "name": "D", + "kwargs": {} + } + } + ], + "left_arm": [ + { + "lhome_qpos": { + "name": "a", + "kwargs": {} + } + }, + { + "cup_monitor_pose": { + "name": "b", + "kwargs": {} + } + } + ], + "left_eef": [ + { + "open": { + "name": "aa", + "kwargs": {} + } + }, + { + "close": { + "name": "bb", + "kwargs": {} + } + } + ], + "right_eef": [ + { + "ropen": { + "name": "cc", + "kwargs": {} + } + }, + { + "rclose": { + "name": "dd", + "kwargs": {} + } + } + ] + }, + "edge": { + "right_arm": [ + { + "init_to_pre1": { + "src": "home_qpos", + "sink": "bottle_pre1_pose", + "duration": 1, + "kwargs": {} + } + }, + { + "grasp_to_move": { + "src": "bottle_pre1_pose", + "sink": "bottle_grasp", + "duration": 2, + "kwargs": {} + } + }, + { + "move_to_rotation": { + "src": "bottle_grasp", + "sink": "bottle_pre2_pose", + "duration": 3, + "kwargs": {} + } + }, + { + "rotation_back_to_move": { + "src": "bottle_pre2_pose", + "sink": "bottle_place_pose", + "duration": 4, + "kwargs": {} + } + } + ], + "left_arm": [ + { + "init_to_monitor": { + "src": "lhome_qpos", + "sink": "cup_monitor_pose", + "duration": 1, + "kwargs": {} + } + }, + { + "left_arm_go_back": { + "src": "cup_monitor_pose", + "sink": "lhome_qpos", + "duration": 2, + "kwargs": {} + } + } + ], + "left_eef": [ + { + "lopen": { + "src": "close", + "sink": "open", + "duration": 10, + "kwargs": {} + } + } + ], + "right_eef": [ + { + "ropen": { + "src": "rclose", + "sink": "ropen", + "duration": 10, + "kwargs": {} + } + } + ] + }, + "sync": { + "grasp_to_move": { + "depend_tasks": [ + "init_to_monitor" + ] + } + } +} \ No newline at end of file diff --git a/configs/gym/cobotmagic.json b/configs/gym/cobotmagic.json new file mode 100644 index 00000000..6eef0718 --- /dev/null +++ b/configs/gym/cobotmagic.json @@ -0,0 +1,120 @@ +{ + "id": "EmbodiedEnv-v1", + "max_episodes": 10, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "random_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_robot": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 5, + "params": { + "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + }, + "replace_fork": { + "func": "replace_assets_from_group", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "fork"}, + "folder_path": "TableWare/tableware/fork/" + } + } + } + }, + "sensor": [ + { + "sensor_type": "Camera", + "width": 640, + "height": 480, + "enable_mask": true, + "enable_depth": true, + "extrinsics": { + "eye": [0.0, 0.0, 1.0], + "target": [0.0, 0.0, 0.0] + } + } + ], + "robot": { + "robot_type": "CobotMagic", + "init_pos": [0.0, 0.3, 1.2] + }, + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [0, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "ShopTableSimple/shop_table_simple.ply" + }, + "attrs" : { + "mass": 10.0 + }, + "body_scale": [2, 1.6, 1], + "body_type": "kinematic" + } + ], + "rigid_object": [ + { + "uid": "fork", + "shape": { + "shape_type": "Mesh", + "fpath": "TableWare/tableware/fork/standard_fork_scale.ply" + }, + "body_scale": [0.75, 0.75, 1.0], + "init_pos": [0.0, 0.0, 1.0] + } + ], + "articulation": [ + { + "fpath": "SlidingBoxDrawer/SlidingBoxDrawer.urdf", + "init_pos": [0.5, 0.0, 0.85] + } + ] +} diff --git a/configs/gym/dexforce_w1.json b/configs/gym/dexforce_w1.json new file mode 100644 index 00000000..42f0f073 --- /dev/null +++ b/configs/gym/dexforce_w1.json @@ -0,0 +1,109 @@ +{ + "id": "EmbodiedEnv-v1", + "max_episodes": 10, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "random_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + }, + "replace_fork": { + "func": "replace_assets_from_group", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "fork"}, + "folder_path": "TableWare/tableware/fork/" + } + } + } + }, + "sensor": [ + { + "sensor_type": "Camera", + "width": 640, + "height": 480, + "enable_mask": true, + "enable_depth": true, + "extrinsics": { + "eye": [0.0, 0.0, 1.0], + "target": [0.0, 0.0, 0.0] + } + } + ], + "robot": { + "robot_type": "DexforceW1", + "init_pos": [0.0, 1.0, 0] + }, + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [0, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "ShopTableSimple/shop_table_simple.ply" + }, + "attrs" : { + "mass": 10.0 + }, + "body_scale": [2, 1.6, 1], + "body_type": "kinematic" + } + ], + "rigid_object": [ + { + "uid": "fork", + "shape": { + "shape_type": "Mesh", + "fpath": "TableWare/tableware/fork/standard_fork_scale.ply" + }, + "body_scale": [0.75, 0.75, 1.0], + "init_pos": [0.0, 0.0, 1.0] + } + ], + "articulation": [ + { + "fpath": "SlidingBoxDrawer/SlidingBoxDrawer.urdf", + "init_pos": [0.5, 0.0, 0.85] + } + ] +} diff --git a/configs/gym/pour_water/action_config.json b/configs/gym/pour_water/action_config.json new file mode 100644 index 00000000..42f036a8 --- /dev/null +++ b/configs/gym/pour_water/action_config.json @@ -0,0 +1,938 @@ +{ + "scope": { + "right_arm": { + "type": "DiGraph", + "dim": [ + 6 + ], + "init": { + "method": "current_qpos", + "init_node_name": "right_arm_init_qpos" + }, + "dtype": "float32" + }, + "left_arm": { + "type": "DiGraph", + "dim": [ + 6 + ], + "init": { + "method": "current_qpos", + "init_node_name": "left_arm_init_qpos" + }, + "dtype": "float32" + }, + "left_eef": { + "type": "DiGraph", + "dim": [ + 1 + ], + "init": { + "method": "given_qpos", + "kwargs": { + "given_qpos": [ + 1 + ] + }, + "init_node_name": "" + }, + "dtype": "float32" + }, + "right_eef": { + "type": "DiGraph", + "dim": [ + 1 + ], + "init": { + "method": "given_qpos", + "kwargs": { + "given_qpos": [ + 1 + ] + }, + "init_node_name": "" + }, + "dtype": "float32" + } + }, + "node": { + "right_arm": [ + { + "right_arm_init_qpos": { + "name": "generate_affordances_from_src", + "kwargs": { + "affordance_infos": [ + { + "src_key": "right_arm_init_qpos", + "dst_key": "right_arm_init_pose", + "valid_funcs_name_kwargs_proc": [ + { + "name": "no_validation", + "kwargs": {}, + "pass_processes": [ + { + "name": "get_fk_xpos", + "kwargs": { + "control_part": "right_arm", + "fk_func": "env.robot.compute_fk" + } + } + ] + } + ] + } + ] + + } + } + }, + { + "right_arm_aim_qpos": { + "name": "generate_right_arm_aim_qpos", + "kwargs": {} + } + }, + { + "bottle_grasp": { + "name": "generate_affordances_from_src", + "kwargs": { + "affordance_infos": [ + { + "src_key": "bottle_pose", + "dst_key": "bottle_grasp_pose", + "valid_funcs_name_kwargs_proc": [ + { + "name": "no_validation", + "kwargs": {}, + "pass_processes": [ + { + "name": "get_rotation_replaced_pose", + "kwargs": { + "rotation_value": "env.affordance_datas['right_arm_aim_qpos'][0]", + "rot_axis": "z", + "mode": "intrinsic" + } + }, + { + "name": "get_frame_changed_pose", + "kwargs": { + "frame_change_matrix": "env.affordance_datas['bottle_pose']", + "mode": "intrinsic", + "inverse": true + } + }, + { + "name": "get_frame_changed_pose", + "kwargs": { + "frame_change_matrix": "env.affordance_datas['bottle_grasp_pose']", + "mode": "intrinsic" + } + } + ] + } + ] + }, + { + "src_key": "bottle_grasp_pose", + "dst_key": "bottle_pre1_pose", + "valid_funcs_name_kwargs_proc": [ + { + "name": "no_validation", + "kwargs": {}, + "pass_processes": [ + { + "name": "get_offset_pose", + "kwargs": { + "offset_value": -0.05, + "direction": "z", + "mode": "intrinsic" + } + } + ] + } + ] + }, + { + "src_key": "bottle_pre1_pose", + "dst_key": "bottle_pre2_pose", + "valid_funcs_name_kwargs_proc": [ + { + "name": "no_validation", + "kwargs": {}, + "pass_processes": [ + { + "name": "get_offset_pose", + "kwargs": { + "offset_value": -0.05, + "direction": "z", + "mode": "intrinsic" + } + } + ] + } + ] + } + ] + } + } + }, + { + "bottle_pre1_qpos": { + "name": "generate_affordances_from_src", + "kwargs": { + "affordance_infos": [ + { + "src_key": "bottle_pre1_pose", + "dst_key": "bottle_pre1_qpos", + "valid_funcs_name_kwargs_proc": [ + { + "name": "get_ik_ret", + "kwargs": { + "ik_func": "env.robot.compute_ik", + "qpos_seed": "env.affordance_datas['right_arm_init_qpos']", + "control_part": "right_arm" + }, + "pass_processes": [ + { + "name": "get_ik_qpos", + "kwargs": { + "ik_func": "env.robot.compute_ik", + "qpos_seed": "env.affordance_datas['right_arm_init_qpos']", + "control_part": "right_arm" + } + } + ] + }, + { + "name": "is_qpos_flip", + "kwargs": { + "qpos_ref": "env.affordance_datas['right_arm_init_qpos']", + "qpos_ids": [3, 4], + "threshold": 3.455751918948773, + "mode": "delta", + "return_inverse": true + } + } + ] + } + ] + } + } + }, + { + "bottle_grasp_qpos": { + "name": "generate_affordances_from_src", + "kwargs": { + "affordance_infos": [ + { + "src_key": "bottle_grasp_pose", + "dst_key": "bottle_grasp_qpos", + "valid_funcs_name_kwargs_proc": [ + { + "name": "get_ik_ret", + "kwargs": { + "ik_func": "env.robot.compute_ik", + "qpos_seed": "env.affordance_datas['bottle_pre1_qpos']", + "control_part": "right_arm" + }, + "pass_processes": [ + { + "name": "get_ik_qpos", + "kwargs": { + "ik_func": "env.robot.compute_ik", + "qpos_seed": "env.affordance_datas['bottle_pre1_qpos']", + "control_part": "right_arm" + } + } + ] + }, + { + "name": "is_qpos_flip", + "kwargs": { + "qpos_ref": "env.affordance_datas['right_arm_init_qpos']", + "qpos_ids": [3, 4], + "threshold": 3.455751918948773, + "mode": "delta", + "return_inverse": true + } + } + ] + } + ] + + } + } + }, + { + "bottle_up_qpos": { + "name": "generate_affordances_from_src", + "kwargs": { + "affordance_infos": [ + { + "src_key": "bottle_grasp_qpos", + "dst_key": "bottle_up_qpos", + "valid_funcs_name_kwargs_proc": [ + { + "name": "no_validation", + "kwargs": {}, + "pass_processes": [ + { + "name": "get_offset_qpos", + "kwargs": { + "offset_value": -0.05, + "joint_list_offset": [1] + } + } + ] + }, + { + "name": "is_qpos_exceed_new", + "kwargs": { + "robot": "env.robot", + "control_part": "right_arm" + } + }, + { + "name": "is_qpos_flip", + "kwargs": { + "qpos_ref": "env.affordance_datas['right_arm_init_qpos']", + "qpos_ids": [3, 4], + "threshold": 3.455751918948773, + "mode": "delta", + "return_inverse": true + } + } + ] + } + ] + } + } + }, + { + "pour_water_start_qpos": { + "name": "generate_affordances_from_src", + "kwargs": { + "affordance_infos": [ + { + "src_key": "bottle_grasp_pose", + "dst_key": "pour_water_start_pose", + "valid_funcs_name_kwargs_proc": [ + { + "name":"no_validation", + "kwargs": {}, + "pass_processes": [ + { + "name": "get_replaced_pose", + "kwargs": { + "pose_replace_value": "env.affordance_datas['cup_pose'][:2,3]", + "axis_str_replace": "xy" + } + }, + { + "name": "get_offset_pose", + "kwargs": { + "offset_value": 0.05, + "direction": "x", + "mode": "extrinsic" + } + }, + { + "name": "get_offset_pose", + "kwargs": { + "offset_value": -0.10, + "direction": "y", + "mode": "extrinsic" + } + }, + { + "name": "get_offset_pose", + "kwargs": { + "offset_value": 0.125, + "direction": "z", + "mode": "extrinsic" + } + } + ] + } + ] + }, + { + "src_key": "pour_water_start_pose", + "dst_key": "pour_water_start_qpos", + "valid_funcs_name_kwargs_proc": [ + { + "name": "get_ik_ret", + "kwargs": { + "ik_func": "env.robot.compute_ik", + "qpos_seed": "env.affordance_datas['bottle_up_qpos']", + "control_part": "right_arm" + }, + "pass_processes": [ + { + "name": "get_ik_qpos", + "kwargs": { + "ik_func": "env.robot.compute_ik", + "qpos_seed": "env.affordance_datas['bottle_up_qpos']", + "control_part": "right_arm" + } + } + ] + }, + { + "name": "is_qpos_flip", + "kwargs": { + "qpos_ref": "env.affordance_datas['right_arm_init_qpos']", + "qpos_ids": [3, 4], + "threshold": 3.455751918948773, + "mode": "delta", + "return_inverse": true + } + } + ] + } + ] + } + } + }, + { + "pour_water_stop_pose": { + "name": "generate_affordances_from_src", + "kwargs": { + "affordance_infos": [ + { + "src_key": "pour_water_start_qpos", + "dst_key": "bottle_rotation_qpos", + "valid_funcs_name_kwargs_proc": [ + { + "name": "no_validation", + "kwargs": {}, + "pass_processes": [ + { + "name": "get_offset_qpos", + "kwargs": { + "offset_value": -75, + "joint_list_offset": [5], + "degrees": true + } + } + ] + }, + { + "name": "is_qpos_exceed_new", + "kwargs": { + "robot": "env.robot", + "control_part": "right_arm" + } + }, + { + "name": "is_qpos_flip", + "kwargs": { + "qpos_ref": "env.affordance_datas['right_arm_init_qpos']", + "qpos_ids": [3, 4], + "threshold": 3.455751918948773, + "mode": "delta", + "return_inverse": true + } + } + ] + }, + { + "src_key": "bottle_rotation_qpos", + "dst_key": "pour_water_stop_pose", + "valid_funcs_name_kwargs_proc": [ + { + "name": "no_validation", + "kwargs": {}, + "pass_processes": [ + { + "name": "get_fk_xpos", + "kwargs": { + "control_part": "right_arm", + "fk_func": "env.robot.compute_fk" + } + } + ] + } + ] + } + ] + } + } + }, + { + "bottle_place_pose": { + "name": "generate_affordances_from_src", + "kwargs": { + "affordance_infos": [ + { + "src_key": "bottle_grasp_pose", + "dst_key": "bottle_place_pose", + "valid_funcs_name_kwargs_proc": [ + { + "name":"no_validation", + "kwargs": {}, + "pass_processes": [ + { + "name": "get_replaced_pose", + "kwargs": { + "pose_replace_value": [0.7, -0.1], + "axis_str_replace": "xy" + } + } + ] + } + ] + }, + { + "src_key": "bottle_place_pose", + "dst_key": "bottle_place_qpos", + "valid_funcs_name_kwargs_proc": [ + { + "name": "get_ik_ret", + "kwargs": { + "ik_func": "env.robot.compute_ik", + "qpos_seed": "env.affordance_datas['pour_water_start_qpos']", + "control_part": "right_arm" + }, + "pass_processes": [ + { + "name": "get_ik_qpos", + "kwargs": { + "ik_func": "env.robot.compute_ik", + "qpos_seed": "env.affordance_datas['pour_water_start_qpos']", + "control_part": "right_arm" + } + } + ] + }, + { + "name": "is_qpos_flip", + "kwargs": { + "qpos_ref": "env.affordance_datas['right_arm_init_qpos']", + "qpos_ids": [3, 4], + "threshold": 3.455751918948773, + "mode": "delta", + "return_inverse": true + } + } + ] + } + ] + } + } + }, + { + "bottle_pre_place_qpos": { + "name": "generate_affordances_from_src", + "kwargs": { + "affordance_infos": [ + { + "src_key": "bottle_place_qpos", + "dst_key": "bottle_pre_place_qpos", + "valid_funcs_name_kwargs_proc": [ + { + "name": "no_validation", + "kwargs": {}, + "pass_processes": [ + { + "name": "get_offset_qpos", + "kwargs":{ + "offset_value": -0.05, + "joint_list_offset": [1] + } + } + ] + }, + { + "name": "is_qpos_exceed_new", + "kwargs": { + "robot": "env.robot", + "control_part": "right_arm" + } + }, + { + "name": "is_qpos_flip", + "kwargs": { + "qpos_ref": "env.affordance_datas['right_arm_init_qpos']", + "qpos_ids": [3, 4], + "threshold": 3.455751918948773, + "mode": "delta", + "return_inverse": true + } + } + ] + } + ] + } + } + }, + { + "compute_unoffset_for_exp":{ + "name": "compute_unoffset_for_exp", + "kwargs": { + "pose_input_output_names_changes": { + "bottle_grasp_pose": { + "output_pose_name":"bottle_grasp_pose_object_unoffset", + "pose_changes": [ + ["framechange_extrinsic_inverse", "env.affordance_datas['bottle_pose']"], + ["rotation_z_intrinsic_degrees", 90], + ["offset_-z_intrinsic", 0.025], + ["rotation_z_intrinsic_degrees", -90] + ] + }, + "bottle_place_pose": { + "output_pose_name":"bottle_place_pose_unoffset", + "pose_changes": [ + ["rotation_z_intrinsic_degrees", 90], + ["offset_-z_intrinsic", 0.025], + ["rotation_z_intrinsic_degrees", -90] + ] + }, + "pour_water_start_pose": { + "output_pose_name":"pour_water_start_pose_unoffset", + "pose_changes": [ + ["rotation_z_intrinsic_degrees", 90], + ["offset_-z_intrinsic", 0.025], + ["rotation_z_intrinsic_degrees", -90] + ] + }, + "pour_water_stop_pose": { + "output_pose_name":"pour_water_stop_pose_unoffset", + "pose_changes": [ + ["rotation_z_intrinsic_degrees", 90], + ["offset_-z_intrinsic", 0.025], + ["rotation_z_intrinsic_degrees", -90] + ] + } + } + } + } + } + ], + "left_arm": [ + { + "left_arm_init_qpos": { + "name": "generate_affordances_from_src", + "kwargs": { + "affordance_infos": [ + { + "src_key": "left_arm_init_qpos", + "dst_key": "left_arm_init_pose", + "valid_funcs_name_kwargs_proc": [ + { + "name": "no_validation", + "kwargs": {}, + "pass_processes": [ + { + "name": "get_fk_xpos", + "kwargs": { + "control_part": "left_arm", + "fk_func": "env.robot.compute_fk" + } + } + ] + } + ] + } + ] + + } + } + }, + { + "left_monitor_qpos": { + "name": "generate_affordances_from_src", + "kwargs": { + "affordance_infos": [ + { + "src_key": "left_arm_init_qpos", + "dst_key": "left_arm_monitor_qpos", + "valid_funcs_name_kwargs_proc": [ + { + "name": "no_validation", + "kwargs": {}, + "pass_processes": [ + { + "name": "get_replaced_qpos", + "kwargs": { + "replace_value": [-0.6, 1.0, -1.2, 0.0, 0.58, 0.0], + "joint_list_replace": [0, 1, 2, 3, 4, 5] + } + } + ] + } + ] + } + ] + } + } + } + ], + "left_eef": [ + { + "open": { + "name": "execute_open", + "kwargs": {} + } + }, + { + "close": { + "name": "execute_close", + "kwargs": {} + } + } + ], + "right_eef": [ + { + "ropen": { + "name": "execute_open", + "kwargs": {} + } + }, + { + "rclose": { + "name": "execute_close", + "kwargs": {} + } + } + ] + }, + "edge": { + "right_arm": [ + { + "init_to_aim": { + "src": "right_arm_init_qpos", + "sink": "right_arm_aim_qpos", + "duration": 10, + "name": "plan_trajectory", + "kwargs": { + "agent_uid": "right_arm", + "keypose_names": [ + "right_arm_init_qpos", + "right_arm_aim_qpos" + ] + } + } + }, + { + "aim_to_pre1": { + "src": "right_arm_aim_qpos", + "sink": "bottle_pre1_qpos", + "duration": 24, + "name": "plan_trajectory", + "kwargs": { + "agent_uid": "right_arm", + "keypose_names": [ + "right_arm_aim_qpos", + "bottle_pre1_qpos" + ] + } + } + }, + { + "pre1_to_grasp": { + "src": "bottle_pre1_qpos", + "sink": "bottle_grasp_qpos", + "duration": 24, + "name": "plan_trajectory", + "kwargs": { + "agent_uid": "right_arm", + "keypose_names": [ + "bottle_pre1_qpos", + "bottle_grasp_qpos" + ] + } + } + }, + { + "grasp_to_up": { + "src": "bottle_grasp_qpos", + "sink": "bottle_up_qpos", + "duration": 4, + "name": "plan_trajectory", + "kwargs": { + "agent_uid": "right_arm", + "keypose_names": [ + "bottle_grasp_qpos", + "bottle_up_qpos" + ] + } + } + }, + { + "up_to_move": { + "src": "bottle_up_qpos", + "sink": "pour_water_start_qpos", + "duration": 20, + "name": "plan_trajectory", + "kwargs": { + "agent_uid": "right_arm", + "keypose_names": [ + "bottle_up_qpos", + "pour_water_start_qpos" + ] + } + } + }, + { + "move_to_rotation": { + "src": "pour_water_start_qpos", + "sink": "bottle_rotation_qpos", + "duration": 24, + "name": "plan_trajectory", + "kwargs": { + "agent_uid": "right_arm", + "keypose_names": [ + "pour_water_start_qpos", + "bottle_rotation_qpos" + ] + } + } + }, + { + "rotation_back_to_move": { + "src": "bottle_rotation_qpos", + "sink": "pour_water_start_qpos", + "duration": 24, + "name": "plan_trajectory", + "kwargs": { + "agent_uid": "right_arm", + "keypose_names": [ + "bottle_rotation_qpos", + "pour_water_start_qpos" + ] + } + } + }, + { + "move_back_to_pre_place": { + "src": "pour_water_start_qpos", + "sink": "bottle_pre_place_qpos", + "duration": 20, + "name": "plan_trajectory", + "kwargs": { + "agent_uid": "right_arm", + "keypose_names": [ + "pour_water_start_qpos", + "bottle_pre_place_qpos" + ] + } + } + }, + { + "pre_place_back_to_place": { + "src": "bottle_pre_place_qpos", + "sink": "bottle_place_qpos", + "duration": 4, + "name": "plan_trajectory", + "kwargs": { + "agent_uid": "right_arm", + "keypose_names": [ + "bottle_pre_place_qpos", + "bottle_place_qpos" + ] + } + } + }, + { + "place_back_to_init": { + "src": "bottle_place_qpos", + "sink": "right_arm_init_qpos", + "duration": 24, + "name": "plan_trajectory", + "kwargs": { + "agent_uid": "right_arm", + "keypose_names": [ + "bottle_place_qpos", + "right_arm_init_qpos" + ] + } + } + } + ], + "left_arm": [ + { + "left_init_to_monitor": { + "src": "left_arm_init_qpos", + "sink": "left_monitor_qpos", + "duration": 15, + "name": "plan_trajectory", + "kwargs": { + "agent_uid": "left_arm", + "keypose_names": [ + "left_arm_init_qpos", + "left_arm_monitor_qpos" + ] + } + } + }, + { + "left_arm_go_back": { + "src": "left_monitor_qpos", + "sink": "left_arm_init_qpos", + "duration": 15, + "kwargs": {} + } + } + ], + "left_eef": [], + "right_eef": [ + { + "rclose0": { + "src": "ropen", + "sink": "rclose", + "duration": 11, + "name": "execute_close", + "kwargs": { + "return_action": true, + "expand": true + } + } + }, + { + "ropen0": { + "src": "rclose", + "sink": "ropen", + "duration": 11, + "name": "execute_open", + "kwargs": { + "return_action": true, + "expand": true + } + } + } + ] + }, + "sync": { + "rclose0": { + "depend_tasks": [ + "pre1_to_grasp" + ] + }, + "grasp_to_up": { + "depend_tasks": [ + "rclose0" + ] + }, + "ropen0": { + "depend_tasks": [ + "pre_place_back_to_place" + ] + }, + "place_back_to_init": { + "depend_tasks": [ + "ropen0" + ] + }, + "left_arm_go_back": { + "depend_tasks": [ + "ropen0" + ] + } + }, + "misc": { + "vis_graph": false, + "vis_gantt": false, + "warpping": true + } +} diff --git a/configs/gym/pour_water/gym_config.json b/configs/gym/pour_water/gym_config.json new file mode 100644 index 00000000..4207f438 --- /dev/null +++ b/configs/gym/pour_water/gym_config.json @@ -0,0 +1,459 @@ +{ + "id": "PourWater-v3", + "max_episodes": 5, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "init_bottle_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "bottle"}, + "position_range": [[-0.08, -0.12, 0.0], [0.08, 0.04, 0.0]], + "relative_position": true + } + }, + "init_cup_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cup"}, + "position_range": [[-0.08, -0.04, 0.0], [0.08, 0.12, 0.0]], + "relative_position": true + } + }, + "prepare_extra_attr": { + "func": "prepare_extra_attr", + "mode": "reset", + "params": { + "attrs": [ + { + "name": "object_lengths", + "mode": "callable", + "entity_uids": "all_objects", + "func_name": "compute_object_length", + "func_kwargs": { + "is_svd_frame": true, + "sample_points": 5000 + } + }, + { + "name": "grasp_pose_object", + "mode": "static", + "entity_cfg": { + "uid": "bottle" + }, + "value": [[ + [0.32243, 0.03245, 0.94604, 0.025], + [0.00706, -0.99947, 0.03188, -0.0 ], + [0.94657, -0.0036 , -0.32249, 0.0 ], + [0.0 , 0.0 , 0.0 , 1.0 ] + ]] + }, + { + "name": "left_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "left_arm_base", + "to_matrix": true + } + }, + { + "name": "right_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "right_arm_base", + "to_matrix": true + } + } + ] + } + }, + "register_info_to_env": { + "func": "register_info_to_env", + "mode": "reset", + "params": { + "registry": [ + { + "entity_cfg": { + "uid": "bottle" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "cup" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["left_arm"] + }, + "attrs": ["left_arm_base_pose"], + "pose_register_params": { + "compute_relative": "cup", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["right_arm"] + }, + "attrs": ["right_arm_base_pose"], + "pose_register_params": { + "compute_relative": "bottle", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + } + ], + "registration": "affordance_datas", + "sim_update": true + } + }, + "random_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_robot_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 5, + "params": { + "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_camera_intrinsics": { + "func": "randomize_camera_intrinsics", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "focal_x_range": [-50, 50], + "focal_y_range": [-50, 50] + } + }, + "random_robot_init_eef_pose": { + "func": "randomize_robot_eef_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, + "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + } + }, + "observations": { + "norm_robot_eef_joint": { + "func": "normalize_robot_joint_data", + "mode": "modify", + "name": "robot/qpos", + "params": { + "joint_ids": [12, 13, 14, 15] + } + }, + "bottle_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "bottle_pose", + "params": { + "entity_cfg": {"uid": "bottle"} + } + }, + "cup_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "cup_pose", + "params": { + "entity_cfg": {"uid": "cup"} + } + }, + "cam_high_semantic_mask_l": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["bottle", "cup"] + } + }, + "cam_high_semantic_mask_r": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_r", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["bottle", "cup"], + "is_right": true + } + }, + "cam_left_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_left_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_left_wrist"}, + "foreground_uids": ["bottle", "cup"] + } + }, + "cam_right_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_right_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_right_wrist"}, + "foreground_uids": ["bottle", "cup"] + } + }, + "exteroception": { + "func": "compute_exteroception", + "mode": "add", + "name": "exteroception", + "params": { + "descriptor": { + "all_sensors": [ + { + "type": "robot", + "control_part": "left_arm", + "offset": [0.0, 0.0, 0.025], + "follow_eef": true + }, + { + "type": "robot", + "control_part": "right_arm", + "offset": [0.0, 0.0, 0.025], + "follow_eef": true + }, + { + "type": "affordance", + "obj_uid": "bottle", + "key": "bottle_grasp_pose_object_unoffset", + "is_arena_coord": false, + "follow_eef": "right_eef" + }, + { + "type": "affordance", + "obj_uid": "bottle", + "key": "pour_water_start_pose_unoffset", + "is_arena_coord": true, + "follow_eef": "right_eef" + }, + { + "type": "affordance", + "obj_uid": "bottle", + "key": "pour_water_stop_pose_unoffset", + "is_arena_coord": true, + "follow_eef": "right_eef" + }, + { + "type": "affordance", + "obj_uid": "bottle", + "key": "bottle_place_pose_unoffset", + "is_arena_coord": true + } + ] + }, + "x_interval": 0.02, + "y_interval": 0.05, + "kpnts_number": 2, + "groups": 6 + } + } + }, + "dataset": { + "instruction": { + "lang": "Pour water from the bottle into the mug." + }, + "robot_meta": { + "arm_dofs": 12, + "control_freq": 25, + "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], + "observation": { + "vision": { + "cam_high": ["mask", "exteroception"], + "cam_right_wrist": ["mask", "exteroception"], + "cam_left_wrist": ["mask", "exteroception"] + }, + "states": ["qpos"], + "exteroception": ["cam_high", "cam_right_wrist", "cam_left_wrist"] + }, + "min_len_steps": 5 + } + }, + "success_params": { + "strict": false + } + }, + "robot": { + "uid": "CobotMagic", + "robot_type": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] + }, + "sensor": [ + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "width": 960, + "height": 540, + "enable_mask": true, + "enable_depth": true, + "left_to_right_pos": [0.059684025824163614, 0, 0], + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "extrinsics": { + "eye": [0.35368482807598, 0.014695524383058989, 1.4517046071614774], + "target": [0.7186357573287919, -0.054534732904795505, 0.5232553674540066], + "up": [0.9306678549330372, -0.0005600064212467153, 0.3658647703553347] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "right_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "left_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + } + ], + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [2, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "CircleTableSimple/circle_table_simple.ply" + }, + "attrs" : { + "mass": 10.0, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.01 + }, + "body_scale": [1, 1, 1], + "body_type": "kinematic", + "init_pos": [0.725, 0.0, 0.825], + "init_rot": [0, 90, 0] + } + ], + "rigid_object": [ + { + "uid":"cup", + "shape": { + "shape_type": "Mesh", + "fpath": "PaperCup/paper_cup.ply" + }, + "attrs" : { + "mass": 0.01, + "contact_offset": 0.003, + "rest_offset": 0.001, + "restitution": 0.01, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters":8 + }, + "init_pos": [0.75, 0.1, 0.9], + "body_scale":[0.75, 0.75, 1.0], + "max_convex_hull_num": 8 + }, + { + "uid":"bottle", + "shape": { + "shape_type": "Mesh", + "fpath": "ScannedBottle/kashijia_processed.ply" + }, + "attrs" : { + "mass": 0.01, + "contact_offset": 0.003, + "rest_offset": 0.001, + "restitution": 0.01, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters":8 + }, + "init_pos": [0.75, -0.1, 0.932], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 8 + } + ] +} \ No newline at end of file diff --git a/configs/gym/real2sim/reality_config_PourWaterW1Single_v3.json b/configs/gym/real2sim/reality_config_PourWaterW1Single_v3.json new file mode 100644 index 00000000..e7801584 --- /dev/null +++ b/configs/gym/real2sim/reality_config_PourWaterW1Single_v3.json @@ -0,0 +1,582 @@ +{ + "id": "pour_water_single_real2sim", + "max_episodes": 10, + "env": { + "observations": { + "norm_robot_eef_joint": { + "func": "normalize_robot_joint_data", + "mode": "modify", + "name": "robot/qpos", + "params": { + "joint_ids": [7, 15] + } + }, + "bottle_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "bottle_pose", + "params": { + "entity_cfg": {"uid": "bottle"} + } + }, + "cup_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "cup_pose", + "params": { + "entity_cfg": {"uid": "cup"} + } + }, + "cam_high_semantic_mask_l": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["bottle", "cup"] + } + }, + "cam_high_semantic_mask_r": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_r", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["bottle", "cup"], + "is_right": true + } + }, + "cam_left_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_left_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_left_wrist"}, + "foreground_uids": ["bottle", "cup"] + } + }, + "cam_right_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_right_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_right_wrist"}, + "foreground_uids": ["bottle", "cup"] + } + }, + "exteroception": { + "func": "compute_exteroception", + "mode": "add", + "name": "exteroception", + "params": { + "descriptor": { + "cam_high": [ + { + "type": "robot", + "control_part": "left_arm" + }, + { + "type": "robot", + "control_part": "right_arm" + } + ] + }, + "x_interval": 0.02, + "y_interval": 0.05, + "kpnts_number": 2, + "groups": 2 + } + } + }, + "dataset": { + "dir_path": "", + "instruction": { + "lang": "Pour water from the bottle into the cup." + }, + "robot_meta": { + "arm_dofs": 14, + "control_freq": 25, + "qpos_to_control": [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14], + "observation": { + "vision": { + "cam_high": ["mask"], + "cam_right_wrist": ["mask"], + "cam_left_wrist": ["mask"] + }, + "proprioception": ["qpos"], + "exteroception": ["cam_high", "cam_right_wrist", "cam_left_wrist"] + }, + "action": "qpos_with_eef_pose", + "min_len_steps": 30 + } + }, + "success_params": { + "strict": false + } + }, + "robot": { + "uid": "dexforce_w1", + "init_pos": [0.14, 0.0, 0.04], + "init_qpos": [0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.57923,0.0,-1.57003,-1.2,0.4,0.0,0.0,0.57923,0.0,1.57003,1.2,-0.4,0.0,2.5,0.0,0.0,0.0,0.0,0.0,2.5,0.0,0.0,0.0,0.0,0.0], + "solver_cfg": { + "left_arm": { + "ik_nearest_weight": [5, 5, 1, 5, 1, 1, 1] + }, + "right_arm": { + "ik_nearest_weight": [5, 5, 1, 5, 1, 1, 1], + "tcp": [[ 1.0 , 0.0 , 0.0 , 0.0 ], + [ 0.0 , 0.0 , -1.0 , -0.04], + [ 0.0 , 1.0 , 0.0 , 0.14], + [ 0.0 , 0.0 , 0.0 , 1.0 ]] + } + } + }, + "sensor": [ + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "sensor_name": "cam_left_wrist", + "width": 640, + "height": 480, + "intrinsics": [487.39422607421875, 487.39422607421875, 320.3005676269531, 210.7530517578125], + "enable_mask": true, + "attach_link": "left_ee", + "attach_xpos": [ + [ 0.70711, -0.40558, 0.57923, 0.09 ], + [-0.0 , -0.81915, -0.57358, -0.05 ], + [ 0.70711, 0.40558, -0.57923, 0.04 ], + [ 0.0 , 0.0 , 0.0 , 1.0 ] + ], + "set_near": 0.005, + "set_far": 50 + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "sensor_name": "cam_right_wrist", + "width": 640, + "height": 480, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "enable_mask": true, + "attach_link": "right_ee", + "attach_xpos": [ + [-0.70711, -0.40558, 0.57923, 0.09 ], + [-0.0 , 0.81915, 0.57358, 0.05 ], + [-0.70711, 0.40558, -0.57923, 0.04 ], + [ 0.0 , 0.0 , 0.0 , 1.0 ] + ], + "set_near": 0.005, + "set_far": 50 + }, + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "sensor_name": "cam_high", + "width": 960, + "height": 540, + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "enable_mask": true, + "enable_depth": true, + "relativate_T": [ + [ + 0.99996440327, + 0.000856048544, + 0.008394008265, + 0.059684025824163614 + ], + [ + -0.00085599875, + 0.999999633588, + -9.524764e-06, + 1.064844737251626e-05 + ], + [ + -0.008394013343, + 2.339165e-06, + 0.999964769647, + 0.0002219304982263564 + ], + [ + 0, + 0, + 0, + 1 + ] + ], + "set_near": 0.005, + "set_far": 50, + "camera_position": [ + 0.35368482807598, + 0.014695524383058989, + 1.4517046071614774 + ], + "camera_look_at": [ + 0.7186357573287919, + -0.054534732904795505, + 0.5232553674540066 + ], + "up_vector": [ + 0.9306678549330372, + -0.0005600064212467153, + 0.3658647703553347 + ] + } + ], + "light": { + "direct": [ + { + "uid": "light1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 100, + "init_pos": [0, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { "shape_type": "Mesh", "fpath": "static_scenes/static_scene_3/circle_table_simple.ply", "compute_uv": false }, + "body_scale": [1.0, 0.8, 0.8], + "init_local_pose": [ + [2.220446049250313e-16, 0.0, 1.0, 0.7], + [0.0, 1.0, 0.0, 0.0], + [-1.0, 0.0, 2.220446049250313e-16, 0.92], + [0.0, 0.0, 0.0, 1.0] + ], + "body_type": "kinematic", + "max_convex_hull_num": 1 + } + ], + "rigid_object": [ + { + "uid": "bottle", + "shape": { "shape_type": "Mesh", "fpath": "objects/object_6/xingbake_processed.ply" }, + "attrs": { + "mass": 0.005, + "contact_offset": 0.003, + "rest_offset": 0.001, + "restitution": 0.1, + "max_depenetration_velocity": 1e1 + }, + "body_scale": [1, 1, 1], + "init_local_pose": [ + [1.0, 0.0, 0.0, 0.59013], + [0.0, 1.0, 0.0, -0.02475], + [0.0, 0.0, 1.0, 1.06664], + [0.0, 0.0, 0.0, 1.0] + ], + "max_convex_hull_num": 8 + }, + { + "uid": "cup", + "shape": { "shape_type": "Mesh", "fpath": "objects/object_7/paper_cup.ply" }, + "attrs": { + "mass": 0.005, + "contact_offset": 0.003, + "rest_offset": 0.001, + "restitution": 0.1, + "max_depenetration_velocity": 1e1 + }, + "body_scale": [0.75, 0.75, 1.0], + "init_local_pose": [ + [0.9986, -0.00476, 0.05268, 0.66128], + [0.01116, 0.99248, -0.12189, 0.1], + [-0.0517, 0.12231, 0.99114, 1.0], + [0.0, 0.0, 0.0, 1.0] + ], + "max_convex_hull_num": 8 + } + ], + "task": { + "name": "pour_water_single", + "data": { + "0": { + "trajectory": { + "path": "demo1", + "sample_ratio": 0.1, + "scope": { + "right_arm": [ + 8, + 9, + 10, + 11, + 12, + 13, + 14 + ], + "left_arm": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "left_eef": [ + 7 + ], + "right_eef": [ + 15 + ] + } + }, + "node": { + "right_arm": [ + { + "0": { + "affordance_name": "grasp_qpos", + "master": "", + "slaver": "bottle", + "timestep": 122, + "mimicable": true, + "trajectory": { + "name": "load_trajectory", + "kwargs": {} + } + }, + "1": { + "affordance_name": "after_pour_qpos", + "master": "bottle", + "slaver": "", + "timestep": 436, + "trajectory": { + "name": "load_trajectory", + "kwargs": {} + } + }, + "3": { + "affordance_name": "place_qpos", + "master": "bottle", + "slaver": "", + "timestep": 502, + "trajectory": { + "name": "load_trajectory", + "kwargs": {} + } + }, + "4": { + "affordance_name": "pour_qpos", + "master": "bottle", + "slaver": "cup", + "timestep": 327, + "trajectory": { + "name": "load_trajectory", + "kwargs": {} + } + }, + "5": { + "affordance_name": "before_pour_qpos", + "master": "bottle", + "slaver": "", + "timestep": 207, + "trajectory": { + "name": "load_trajectory", + "kwargs": {} + } + } + } + ], + "left_arm": [], + "right_eef": [ + { + "0": { + "affordance_name": "right_close", + "master": "", + "slaver": "bottle", + "timestep": 123, + "mimicable": false, + "duration": 20, + "trajectory": { + "name": "execute_close", + "kwargs": {} + } + }, + "1": { + "affordance_name": "right_open", + "master": "", + "slaver": "bottle", + "timestep": 502, + "mimicable": false, + "duration": 20, + "trajectory": { + "name": "execute_open", + "kwargs": {} + } + } + + } + ], + "left_eef": [] + }, + "sync": { + "right_eefhand_init_qpos": { + "depend_tasks": [ + "grasp_qpos" + ] + }, + "grasp_qpos": { + "depend_tasks": [ + "right_close" + ] + }, + "right_close": { + "depend_tasks": [ + "place_qpos" + ] + }, + "place_qpos": { + "depend_tasks": [ + "right_open" + ] + } + } + }, + "1": { + "trajectory": { + "path": "demo2", + "sample_ratio": 0.1, + "scope": { + "right_arm": [ + 8, + 9, + 10, + 11, + 12, + 13, + 14 + ], + "left_arm": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "left_eef": [ + 7 + ], + "right_eef": [ + 15 + ] + } + }, + "node": { + "right_arm": [ + { + "0": { + "affordance_name": "grasp_qpos", + "master": "", + "slaver": "bottle", + "timestep": 163, + "mimicable": true, + "trajectory": { + "name": "load_trajectory", + "kwargs": {} + } + }, + "1": { + "affordance_name": "pour_qpos", + "master": "bottle", + "slaver": "cup", + "timestep": 400, + "trajectory": { + "name": "load_trajectory", + "kwargs": {} + } + }, + "3": { + "affordance_name": "place_qpos", + "master": "bottle", + "slaver": "", + "timestep": 692, + "trajectory": { + "name": "load_trajectory", + "kwargs": {} + } + }, + "4": { + "affordance_name": "after_pour_qpos", + "master": "bottle", + "slaver": "", + "timestep": 532, + "trajectory": { + "name": "load_trajectory", + "kwargs": {} + } + }, + "5": { + "affordance_name": "before_pour_qpos", + "master": "bottle", + "slaver": "", + "timestep": 232, + "trajectory": { + "name": "load_trajectory", + "kwargs": {} + } + } + } + ], + "left_arm": [], + "right_eef": [ + { + "0": { + "affordance_name": "right_close", + "master": "", + "slaver": "bottle", + "timestep": 210, + "mimicable": false, + "duration": 20, + "trajectory": { + "name": "execute_close", + "kwargs": {} + } + }, + "1": { + "affordance_name": "right_open", + "master": "", + "slaver": "bottle", + "timestep": 692, + "mimicable": false, + "duration": 20, + "trajectory": { + "name": "execute_open", + "kwargs": {} + } + } + + } + ], + "left_eef": [] + }, + "sync": { + "right_eefhand_init_qpos": { + "depend_tasks": [ + "grasp_qpos" + ] + }, + "grasp_qpos": { + "depend_tasks": [ + "right_close" + ] + }, + "right_close": { + "depend_tasks": [ + "place_qpos" + ] + }, + "place_qpos": { + "depend_tasks": [ + "right_open" + ] + } + } + } + } + } +} diff --git a/configs/gym/scoop_ice/gym_config.json b/configs/gym/scoop_ice/gym_config.json new file mode 100644 index 00000000..eed397ac --- /dev/null +++ b/configs/gym/scoop_ice/gym_config.json @@ -0,0 +1,254 @@ +{ + "id": "ScoopIce-v1", + "max_episodes": 5, + "env": { + "events": { + "drop_ice":{ + "func": "drop_rigid_object_group_sequentially", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "ice_cubes"}, + "drop_position": [0.5, -0.05, 1.0], + "position_range": [[-0.12, -0.12, 0], [0.12, 0.12, 0]], + "physics_step": 10 + } + }, + "init_scoop_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "scoop"}, + "position_range": [[0.45, -0.27, 1.05], [0.45, -0.27, 1.05]], + "rotation_range": [[30, -25, 180], [30, -25, 180]], + "relative_position": false, + "relative_rotation": false + } + }, + "init_cup_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "paper_cup"}, + "position_range": [[0.455, 0.112, 1.05], [0.455, 0.112, 1.05]], + "rotation_range": [[0, 0, 0], [0, 0, 0]], + "relative_position": false, + "relative_rotation": false + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [0, -1, 2], + "target": [0.5, 0, 1] + } + } + }, + "dataset": { + "instruction": { + "lang": "Scoop ice." + }, + "robot_meta": { + "arm_dofs": 14, + "control_freq": 25, + "qpos_to_control": [6, 8, 10, 12, 14, 16, 18, 24, 7, 9, 11, 13, 15, 17, 19, 29], + "observation": { + "vision": { + "cam_high": [], + "cam_right_wrist": [], + "cam_left_wrist": [] + }, + "states": ["qpos"] + }, + "min_len_steps": 10 + } + } + }, + "robot": { + "robot_type": "DexforceW1", + "init_pos": [0.0, 0.0, 0], + "init_qpos":[ + 0.42241, -1.11061, 0.55116, 0.01815, 0.00002, -0.43273, + -0.30339, 0.2412 , -1.20074, 0.72621, 0.40264, -0.41044, + -1.34341, 1.27664, -0.42869, -0.30873, -0.23608, 0.54272, + -0.12095, -0.16959, 0.00011, 0.00002, 0.00009, 0.00003, + 1.50006, 0.30045, 0.30028, 0.30051, 0.30037, 0.90003, + 0.23262, 0.24298, 0.22003, 0.19901, -0 , 0.59305, + 0.6033 , 0.58056, 0.55942, 0.29999 + ], + "solver_cfg": { + "left_arm": { + "class_type": "PytorchSolver", + "end_link_name": "left_ee", + "root_link_name": "left_arm_base", + "tcp": + [ + [-1.0, 0.0, 0.0, 0.012], + [0.0, 0.0, 1.0, 0.0675], + [0.0, 1.0, 0.0, 0.127], + [0.0, 0.0, 0.0, 1.0] + ] + }, + "right_arm": { + "class_type": "PytorchSolver", + "end_link_name": "right_ee", + "root_link_name": "right_arm_base", + "tcp": + [ + [1.0, 0.0, 0.0, 0.012], + [0.0, 0.0, -1.0, -0.0675], + [0.0, 1.0, 0.0, 0.127], + [0.0, 0.0, 0.0, 1.0] + ] + } + } + }, + "sensor": [ + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "width": 960, + "height": 540, + "enable_mask": true, + "enable_depth": true, + "left_to_right_pos": [0.059684025824163614, 0, 0], + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "extrinsics": { + "parent": "eyes" + } + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "width": 640, + "height": 360, + "enable_mask": true, + "intrinsics": [337.0, 325.0, 320.0, 180.0], + "extrinsics": { + "parent": "right_ee", + "pos": [0.09, 0.05, 0.04], + "quat": [0.36497168, -0.11507513, 0.88111957, 0.27781593] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "width": 640, + "height": 360, + "enable_mask": true, + "intrinsics": [337.0, 325.0, 320.0, 180.0], + "extrinsics": { + "parent": "left_ee", + "pos": [0.09, -0.05, 0.04], + "quat": [0.27781593, 0.88111957, -0.11507513, 0.36497168] + } + } + ], + "light": { + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "CircleTableSimple/circle_table_simple.ply" + }, + "attrs" : { + "mass": 1.0, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.05 + }, + "body_type": "kinematic", + "init_pos": [0.80, 0, 0.54], + "init_rot": [0, 90, 0] + } + ], + "rigid_object": [ + { + "uid": "scoop", + "shape": { + "shape_type": "Mesh", + "fpath": "ScoopIceNewEnv/scoop.ply" + }, + "attrs" : { + "mass": 0.5, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.0, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "max_convex_hull_num": 8, + "init_pos": [0, 10, 10] + }, + { + "uid": "paper_cup", + "shape": { + "shape_type": "Mesh", + "fpath": "PaperCup/paper_cup.ply" + }, + "attrs" : { + "mass": 0.5, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.0, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "max_convex_hull_num": 16, + "init_pos": [0, 10, 10] + } + ], + "rigid_object_group": [ + { + "uid": "ice_cubes", + "max_num": 300, + "folder_path": "ScoopIceNewEnv/ice_mesh_small", + "ext": ".obj", + "rigid_objects": { + "obj": { + "attrs" : { + "mass": 0.004, + "contact_offset": 0.001, + "rest_offset": 0, + "dynamic_friction": 0.05, + "static_friction": 0.1, + "restitution": 0.00, + "min_position_iters": 32, + "min_velocity_iters": 8, + "max_depenetration_velocity": 1.0 + }, + "shape": { + "shape_type": "Mesh" + }, + "init_pos": [0, 0, 2], + "body_scale": [1.0, 1.0, 1.0] + } + } + } + ], + "articulation": [ + { + "uid": "container", + "fpath": "ScoopIceNewEnv/IceContainer/ice_container.urdf", + "init_pos": [0.635, -0.04, 0.94], + "init_rot": [0, 0, -80], + "attrs": { + "mass": 1.0, + "dynamic_friction": 0.05, + "static_friction": 0.1, + "max_depenetration_velocity": 1.0 + }, + "drive_pros": { + "stiffness": 1.0, + "damping": 0.1, + "max_effort": 100.0 + } + } + ] +} \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..864eb2a7 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,21 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @rm -rf "$(BUILDDIR)" + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..747ffb7b --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..cacbd083 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,9 @@ +sphinx>=4.0 +sphinx-book-theme>=0.3.0 +sphinx-tabs +sphinx-copybutton +myst-parser +sphinx-autosummary-accessors +sphinxcontrib-bibtex +sphinx-design +sphinx_autodoc_typehints diff --git a/docs/source/_templates/module.rst b/docs/source/_templates/module.rst new file mode 100644 index 00000000..b3160842 --- /dev/null +++ b/docs/source/_templates/module.rst @@ -0,0 +1,58 @@ +{{ fullname | escape | underline}} + +.. automodule:: {{ fullname }} + :members: + :undoc-members: + :show-inheritance: + + {% block modules %} + {% if modules %} + .. rubric:: Modules + + .. autosummary:: + :toctree: + :template: module.rst + {% for item in modules %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block classes %} + {% if classes %} + .. rubric:: Classes + + .. autosummary:: + :toctree: + :template: class.rst + {% for item in classes %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block functions %} + {% if functions %} + .. rubric:: Functions + + .. autosummary:: + :toctree: + :template: function.rst + {% for item in functions %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block exceptions %} + {% if exceptions %} + .. rubric:: Exceptions + + .. autosummary:: + :toctree: + :template: class.rst + {% for item in exceptions %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} diff --git a/docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kernels.reshape_tiled_image.rst b/docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kernels.reshape_tiled_image.rst new file mode 100644 index 00000000..510de4bd --- /dev/null +++ b/docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kernels.reshape_tiled_image.rst @@ -0,0 +1,6 @@ +embodichain.utils.warp.kernels.reshape\_tiled\_image +==================================================== + +.. currentmodule:: embodichain.utils.warp.kernels + +.. autodata:: reshape_tiled_image \ No newline at end of file diff --git a/docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kernels.rst b/docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kernels.rst new file mode 100644 index 00000000..fb1ba6ab --- /dev/null +++ b/docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kernels.rst @@ -0,0 +1,6 @@ +embodichain.utils.warp.kernels +============================== + +.. automodule:: embodichain.utils.warp.kernels + + \ No newline at end of file diff --git a/docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kinematics.opw_solver.rst b/docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kinematics.opw_solver.rst new file mode 100644 index 00000000..7fec8013 --- /dev/null +++ b/docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kinematics.opw_solver.rst @@ -0,0 +1,6 @@ +embodichain.utils.warp.kinematics.opw\_solver +============================================= + +.. automodule:: embodichain.utils.warp.kinematics.opw_solver + + \ No newline at end of file diff --git a/docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kinematics.rst b/docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kinematics.rst new file mode 100644 index 00000000..0e0f9b9c --- /dev/null +++ b/docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kinematics.rst @@ -0,0 +1,6 @@ +embodichain.utils.warp.kinematics +================================= + +.. automodule:: embodichain.utils.warp.kinematics + + \ No newline at end of file diff --git a/docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kinematics.warp_trajectory.rst b/docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kinematics.warp_trajectory.rst new file mode 100644 index 00000000..aa9760cd --- /dev/null +++ b/docs/source/api_reference/embodichain/_autosummary/embodichain.utils.warp.kinematics.warp_trajectory.rst @@ -0,0 +1,6 @@ +embodichain.utils.warp.kinematics.warp\_trajectory +================================================== + +.. automodule:: embodichain.utils.warp.kinematics.warp_trajectory + + \ No newline at end of file diff --git a/docs/source/api_reference/embodichain/embodichain.agents.rst b/docs/source/api_reference/embodichain/embodichain.agents.rst new file mode 100644 index 00000000..1db72b60 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.agents.rst @@ -0,0 +1,12 @@ +embodichain.agents +================== + +.. automodule:: embodichain.agents + + .. rubric:: Submodules + + .. autosummary:: + + dexforce_vla + rl + diff --git a/docs/source/api_reference/embodichain/embodichain.lab.gym.envs.managers.rst b/docs/source/api_reference/embodichain/embodichain.lab.gym.envs.managers.rst new file mode 100644 index 00000000..afc9df9a --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.gym.envs.managers.rst @@ -0,0 +1,130 @@ +embodichain.lab.gym.envs.managers +========================================== + +.. automodule:: embodichain.lab.gym.envs.managers + + .. rubric:: Submodules + + .. autosummary:: + + randomization + + .. rubric:: Classes + + .. autosummary:: + + FunctorCfg + SceneEntityCfg + EventCfg + ObservationCfg + Functor + ManagerBase + EventManager + ObservationManager + + .. rubric:: Functions + + .. autosummary:: + + observations.get_rigid_object_pose + observations.normalize_robot_joint_data + observations.compute_semantic_mask + observations.compute_exteroception + events.replace_assets_from_group + record.record_camera_data + randomization.rendering.randomize_light + randomization.rendering.randomize_camera_intrinsics + randomization.rendering.randomize_visual_material + randomization.spatial.get_random_pose + randomization.spatial.randomize_rigid_object_pose + randomization.spatial.randomize_robot_eef_pose + randomization.spatial.randomize_robot_qpos + +.. currentmodule:: embodichain.lab.gym.envs.managers + +Configuration Classes +--------------------- + +.. autoclass:: FunctorCfg + :members: + :exclude-members: __init__, class_type + +.. autoclass:: SceneEntityCfg + :members: + :exclude-members: __init__, class_type + +.. autoclass:: EventCfg + :members: + :exclude-members: __init__, class_type + +.. autoclass:: ObservationCfg + :members: + :exclude-members: __init__, class_type + +Base Classes +------------ + +.. autoclass:: Functor + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: ManagerBase + :members: + :inherited-members: + :show-inheritance: + +Managers +-------- + +.. autoclass:: EventManager + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: ObservationManager + :members: + :inherited-members: + :show-inheritance: + +Observation Functions +-------------------- + +.. automodule:: embodichain.lab.gym.envs.managers.observations + :members: + +Event Functions +-------------- + +.. automodule:: embodichain.lab.gym.envs.managers.events + :members: + +Recording Functions +------------------ + +.. automodule:: embodichain.lab.gym.envs.managers.record + :members: + +Randomization +------------- + +.. automodule:: embodichain.lab.gym.envs.managers.randomization + + .. rubric:: Submodules + + .. autosummary:: + + rendering + spatial + + Rendering + ~~~~~~~~~~~~~~~~~~~~~~~ + + .. automodule:: embodichain.lab.gym.envs.managers.randomization.rendering + :members: + + Spatial + ~~~~~~~~~~~~~~~~~~~~~ + + .. automodule:: embodichain.lab.gym.envs.managers.randomization.spatial + :members: diff --git a/docs/source/api_reference/embodichain/embodichain.lab.gym.envs.rst b/docs/source/api_reference/embodichain/embodichain.lab.gym.envs.rst new file mode 100644 index 00000000..24c568f9 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.gym.envs.rst @@ -0,0 +1,34 @@ +embodichain.lab.gym.envs +==================================== + +.. automodule:: embodichain.lab.gym.envs + + .. rubric:: Submodules + + .. autosummary:: + managers + +.. currentmodule:: embodichain.lab.gym.envs + +Environment Classes +------------------- + +.. currentmodule:: embodichain.lab.gym.envs + +.. autoclass:: BaseEnv + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: EnvCfg + :members: + :exclude-members: __init__, class_type + +.. autoclass:: EmbodiedEnv + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: EmbodiedEnvCfg + :members: + :exclude-members: __init__, class_type diff --git a/docs/source/api_reference/embodichain/embodichain.lab.gym.rst b/docs/source/api_reference/embodichain/embodichain.lab.gym.rst new file mode 100644 index 00000000..e788b8f7 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.gym.rst @@ -0,0 +1,153 @@ +embodichain.lab.gym +=============================== + +.. automodule:: embodichain.lab.gym + + .. rubric:: Submodules + + .. autosummary:: + :toctree: . + + envs + utils + +.. currentmodule:: embodichain.lab.gym + +Overview +-------- + +The ``gym`` module provides a comprehensive framework for creating robot learning environments. It extends the Gymnasium interface to support multi-environment parallel execution, +custom observations, and robotic-specific functionality. + +Key Features: + +* **Multi-Environment Support**: Run multiple environment instances in parallel for efficient training +* **Gymnasium Integration**: Full compatibility with the Gymnasium API and ecosystem +* **Robotic Focus**: Built-in support for robot control, sensors, and manipulation tasks +* **Extensible Architecture**: Easy to create custom environments and tasks +* **GPU Acceleration**: Leverage GPU computing for high-performance simulation + +Environments Module (envs) +--------------------------- + +.. currentmodule:: embodichain.lab.gym.envs + +Base Environment Classes +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: BaseEnv + :members: + :inherited-members: + :show-inheritance: + + The foundational environment class that provides the core functionality for all EmbodiChain RL environments. + This class extends the Gymnasium ``Env`` interface with multi-environment support and robotic-specific features. + +.. autoclass:: EnvCfg + :members: + :exclude-members: __init__, class_type + + Configuration class for basic environment settings including simulation parameters and environment count. + +Embodied Environment Classes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: EmbodiedEnv + :members: + :inherited-members: + :show-inheritance: + + An advanced environment class that provides additional features for embodied AI research, including + sophisticated observation management, event handling, and multi-modal sensor integration. + +.. autoclass:: EmbodiedEnvCfg + :members: + :exclude-members: __init__, class_type + + Configuration class for embodied environments with extended settings for lighting, observation management, + and advanced simulation features. + +Utilities Module (utils) +------------------------- + +.. currentmodule:: embodichain.lab.gym.utils + +Registration System +~~~~~~~~~~~~~~~~~~~ + +.. automodule:: embodichain.lab.gym.utils.registration + +.. autoclass:: EnvSpec + :members: + :show-inheritance: + + Specification class for environment registration, containing environment metadata and creation parameters. + +.. autofunction:: register + + Register a new environment class with the EmbodiChain environment registry. + + :param name: Unique identifier for the environment + :param cls: Environment class (must inherit from BaseEnv or BaseEnv) + :param max_episode_steps: Maximum steps per episode (optional) + :param default_kwargs: Default keyword arguments for environment creation + +.. autofunction:: register_env + + Decorator function for registering environment classes. This is the recommended way to register environments. + + :param uid: Unique identifier for the environment + :param max_episode_steps: Maximum steps per episode (optional) + :param override: Whether to override existing environment with same ID + :param kwargs: Additional registration parameters + + Example: + .. code-block:: python + + @register_env("MyEnv-v1", max_episode_steps=1000) + class MyCustomEnv(BaseEnv): + def __init__(self, **kwargs): + super().__init__(**kwargs) + +.. autofunction:: make + + Create an environment instance from a registered environment ID. + + :param env_id: Registered environment identifier + :param kwargs: Additional keyword arguments for environment creation + :returns: Environment instance + +.. autoclass:: TimeLimitWrapper + :members: + :show-inheritance: + + Gymnasium wrapper that adds episode time limits to environments. + +Action Conversion Utilities +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. automodule:: embodichain.lab.gym.utils.action_conversion + + Utilities for converting between different action representations in robotic environments. + +Gymnasium Utilities +~~~~~~~~~~~~~~~~~~ + +.. automodule:: embodichain.lab.gym.utils.gym_utils + + Helper functions and utilities for Gymnasium environment integration. + +Image Utilities +~~~~~~~~~~~~~~~ + +.. automodule:: embodichain.lab.gym.utils.img_utils + + Image processing utilities for visual observations and rendering. + +Miscellaneous Utilities +~~~~~~~~~~~~~~~~~~~~~~~ + +.. automodule:: embodichain.lab.gym.utils.misc + + Miscellaneous utility functions for environment development and debugging. + diff --git a/docs/source/api_reference/embodichain/embodichain.lab.gym.utils.rst b/docs/source/api_reference/embodichain/embodichain.lab.gym.utils.rst new file mode 100644 index 00000000..a0c9f265 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.gym.utils.rst @@ -0,0 +1,48 @@ +embodichain.lab.gym.utils +===================================== + +.. automodule:: embodichain.lab.gym.utils + +Registration System +------------------- + +.. currentmodule:: embodichain.lab.gym.utils.registration + +.. autoclass:: EnvSpec + :members: + :show-inheritance: + +.. autofunction:: register + +.. autofunction:: register_env + +.. autofunction:: make + +.. autoclass:: TimeLimitWrapper + :members: + :show-inheritance: + +Utility Modules +--------------- + +Action Conversion +~~~~~~~~~~~~~~~~~ + +.. automodule:: embodichain.lab.gym.utils.action_conversion + +Gymnasium Utilities +~~~~~~~~~~~~~~~~~~~ + +.. automodule:: embodichain.lab.gym.utils.gym_utils + +Image Utilities +~~~~~~~~~~~~~~~ + +.. automodule:: embodichain.lab.gym.utils.img_utils + +Miscellaneous +~~~~~~~~~~~~~ + +.. automodule:: embodichain.lab.gym.utils.misc + + \ No newline at end of file diff --git a/docs/source/api_reference/embodichain/embodichain.lab.rst b/docs/source/api_reference/embodichain/embodichain.lab.rst new file mode 100644 index 00000000..e8a7d565 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.rst @@ -0,0 +1,29 @@ +embodichain.lab +===================== + +.. automodule:: embodichain.lab + + .. rubric:: Submodules + + .. autosummary:: + + devices + gym + sim + utility + +Device Management +----------------- + +.. automodule:: embodichain.lab.devices + :members: + :undoc-members: + :show-inheritance: + +Utilities +--------- + +.. automodule:: embodichain.lab.utility + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api_reference/embodichain/embodichain.lab.sim.cfg.rst b/docs/source/api_reference/embodichain/embodichain.lab.sim.cfg.rst new file mode 100644 index 00000000..dacdae33 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.sim.cfg.rst @@ -0,0 +1,21 @@ +embodichain.lab.sim.cfg +=================================== + +.. automodule:: embodichain.lab.sim.cfg + + + .. rubric:: Classes + + .. autosummary:: + + ArticulationCfg + GPUMemoryCfg + JointDrivePropertiesCfg + LightCfg + ObjectBaseCfg + PhysicsCfg + RigidBodyAttributesCfg + RigidObjectCfg + RobotCfg + URDFCfg + \ No newline at end of file diff --git a/docs/source/api_reference/embodichain/embodichain.lab.sim.common.rst b/docs/source/api_reference/embodichain/embodichain.lab.sim.common.rst new file mode 100644 index 00000000..2d8ffc14 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.sim.common.rst @@ -0,0 +1,12 @@ +embodichain.lab.sim.common +====================================== + +.. automodule:: embodichain.lab.sim.common + + + .. rubric:: Classes + + .. autosummary:: + + BatchEntity + \ No newline at end of file diff --git a/docs/source/api_reference/embodichain/embodichain.lab.sim.material.rst b/docs/source/api_reference/embodichain/embodichain.lab.sim.material.rst new file mode 100644 index 00000000..61e7bbdf --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.sim.material.rst @@ -0,0 +1,14 @@ +embodichain.lab.sim.material +======================================== + +.. automodule:: embodichain.lab.sim.material + + + .. rubric:: Classes + + .. autosummary:: + + VisualMaterial + VisualMaterialCfg + VisualMaterialInst + \ No newline at end of file diff --git a/docs/source/api_reference/embodichain/embodichain.lab.sim.objects.rst b/docs/source/api_reference/embodichain/embodichain.lab.sim.objects.rst new file mode 100644 index 00000000..34928803 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.sim.objects.rst @@ -0,0 +1,111 @@ +embodichain.lab.sim.objects +========================================== + + +.. automodule:: embodichain.lab.sim.objects + + .. rubric:: Classes + + .. autosummary:: + + Light + LightCfg + RigidObject + RigidBodyData + RigidObjectCfg + RigidObjectGroup + RigidBodyGroupData + RigidObjectGroupCfg + Articulation + ArticulationData + ArticulationCfg + Robot + RobotCfg + +.. currentmodule:: embodichain.lab.sim.objects + +Light +----- + +.. autoclass:: Light + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: LightCfg + :members: + :inherited-members: + :show-inheritance: + :exclude-members: __init__, copy, replace, to_dict, validate + +Rigid Object +------------ + +.. autoclass:: RigidObject + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: RigidBodyData + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: RigidObjectCfg + :members: + :inherited-members: + :show-inheritance: + :exclude-members: __init__, copy, replace, to_dict, validate + +Rigid Object Group +------------------- + +.. autoclass:: RigidObjectGroup + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: RigidBodyGroupData + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: RigidObjectGroupCfg + :members: + :inherited-members: + :show-inheritance: + :exclude-members: __init__, copy, replace, to_dict, validate + +Articulation +------------ + +.. autoclass:: Articulation + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: ArticulationData + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: ArticulationCfg + :members: + :inherited-members: + :show-inheritance: + :exclude-members: __init__, copy, replace, to_dict, validate + +Robot +----- + +.. autoclass:: Robot + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: RobotCfg + :members: + :inherited-members: + :show-inheritance: + :exclude-members: __init__, copy, replace, to_dict, validate + \ No newline at end of file diff --git a/docs/source/api_reference/embodichain/embodichain.lab.sim.robots.rst b/docs/source/api_reference/embodichain/embodichain.lab.sim.robots.rst new file mode 100644 index 00000000..d6428af3 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.sim.robots.rst @@ -0,0 +1,6 @@ +embodichain.lab.sim.robots +====================================== + +.. automodule:: embodichain.lab.sim.robots + + \ No newline at end of file diff --git a/docs/source/api_reference/embodichain/embodichain.lab.sim.rst b/docs/source/api_reference/embodichain/embodichain.lab.sim.rst new file mode 100644 index 00000000..87b82a41 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.sim.rst @@ -0,0 +1,101 @@ +embodichain.lab.sim +===================== + +.. automodule:: embodichain.lab.sim + + .. rubric:: Submodules + + .. autosummary:: + :toctree: . + + sim_manager + cfg + common + material + shapes + objects + sensors + solvers + utility + +.. currentmodule:: embodichain.lab.sim + +Simulation Manager +------------------ + +.. autoclass:: SimulationManager + :members: + :undoc-members: + :show-inheritance: + +.. autoclass:: SimulationManagerCfg + :members: + :undoc-members: + :show-inheritance: + :exclude-members: __init__, copy, replace, to_dict, validate + +Configurations +------------------ + +.. automodule:: embodichain.lab.sim.cfg + :members: + :undoc-members: + :show-inheritance: + :exclude-members: __init__, copy, replace, to_dict, validate + +Common Conponents +------------------ + +.. automodule:: embodichain.lab.sim.common + :members: + :undoc-members: + :show-inheritance: + +Materials +------------------ + +.. automodule:: embodichain.lab.sim.material + :members: + :undoc-members: + :show-inheritance: + +Shapes +------------------ + +.. automodule:: embodichain.lab.sim.shapes + :members: + :undoc-members: + :show-inheritance: + :exclude-members: __init__, copy, replace, to_dict, validate + +Objects +------- + +.. toctree:: + :maxdepth: 1 + + embodichain.lab.sim.objects + +Sensors +------- + +.. toctree:: + :maxdepth: 1 + + embodichain.lab.sim.sensors + +Solvers +------- + +.. toctree:: + :maxdepth: 1 + + embodichain.lab.sim.solvers + +Utility +------- + +.. toctree:: + :maxdepth: 1 + + embodichain.lab.sim.utility \ No newline at end of file diff --git a/docs/source/api_reference/embodichain/embodichain.lab.sim.sensors.rst b/docs/source/api_reference/embodichain/embodichain.lab.sim.sensors.rst new file mode 100644 index 00000000..b52a9185 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.sim.sensors.rst @@ -0,0 +1,54 @@ +embodichain.lab.sim.sensors +========================================== + + +.. automodule:: embodichain.lab.sim.sensors + + .. rubric:: Classes + + .. autosummary:: + SensorCfg + BaseSensor + CameraCfg + Camera + StereoCameraCfg + StereoCamera + +.. currentmodule:: embodichain.lab.sim.sensors + +Sensor +------ +.. autoclass:: BaseSensor + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: SensorCfg + :members: + :exclude-members: __init__, copy, replace, to_dict, validate + +Camera +------ +.. autoclass:: Camera + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: CameraCfg + :members: + :inherited-members: + :show-inheritance: + :exclude-members: __init__, copy, replace, to_dict, validate + +Stereo Camera +------------- +.. autoclass:: StereoCamera + :members: + :inherited-members: + :show-inheritance: + +.. autoclass:: StereoCameraCfg + :members: + :inherited-members: + :show-inheritance: + :exclude-members: __init__, copy, replace, to_dict, validate diff --git a/docs/source/api_reference/embodichain/embodichain.lab.sim.shapes.rst b/docs/source/api_reference/embodichain/embodichain.lab.sim.shapes.rst new file mode 100644 index 00000000..724f5229 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.sim.shapes.rst @@ -0,0 +1,16 @@ +embodichain.lab.sim.shapes +====================================== + +.. automodule:: embodichain.lab.sim.shapes + + + .. rubric:: Classes + + .. autosummary:: + + CubeCfg + LoadOption + MeshCfg + ShapeCfg + SphereCfg + \ No newline at end of file diff --git a/docs/source/api_reference/embodichain/embodichain.lab.sim.sim_manager.rst b/docs/source/api_reference/embodichain/embodichain.lab.sim.sim_manager.rst new file mode 100644 index 00000000..e6f74aee --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.sim.sim_manager.rst @@ -0,0 +1,13 @@ +embodichain.lab.sim.sim_manager +========================================= + +.. automodule:: embodichain.lab.sim.sim_manager + + + .. rubric:: Classes + + .. autosummary:: + + SimulationManager + SimulationManagerCfg + \ No newline at end of file diff --git a/docs/source/api_reference/embodichain/embodichain.lab.sim.solvers.rst b/docs/source/api_reference/embodichain/embodichain.lab.sim.solvers.rst new file mode 100644 index 00000000..36fcdbe5 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.sim.solvers.rst @@ -0,0 +1,95 @@ +embodichain.lab.sim.solvers +========================================== + + +.. automodule:: embodichain.lab.sim.solvers + + .. rubric:: Classes + + .. autosummary:: + SolverCfg + BaseSolver + PytorchSolverCfg + PytorchSolver + PinocchioSolverCfg + PinocchioSolver + PinkSolverCfg + PinkSolver + DifferentialSolverCfg + DifferentialSolver + OPWSolverCfg + OPWSolver + +.. currentmodule:: embodichain.lab.sim.solvers + +Base Solver +----------- + +.. autoclass:: SolverCfg + :members: + :exclude-members: __init__, copy, replace, to_dict, validate + +.. autoclass:: BaseSolver + :members: + :inherited-members: + :show-inheritance: + +PyTorch Solver +-------------- + +.. autoclass:: PytorchSolverCfg + :members: + :exclude-members: __init__, copy, replace, to_dict, validate + +.. autoclass:: PytorchSolver + :members: + :inherited-members: + :show-inheritance: + +Pinocchio Solver +---------------- + +.. autoclass:: PinocchioSolverCfg + :members: + :exclude-members: __init__, copy, replace, to_dict, validate + +.. autoclass:: PinocchioSolver + :members: + :inherited-members: + :show-inheritance: + +Pink Solver +----------- + +.. autoclass:: PinkSolverCfg + :members: + :exclude-members: __init__, copy, replace, to_dict, validate + +.. autoclass:: PinkSolver + :members: + :inherited-members: + :show-inheritance: + +Differential Solver +------------------- + +.. autoclass:: DifferentialSolverCfg + :members: + :exclude-members: __init__, copy, replace, to_dict, validate + +.. autoclass:: DifferentialSolver + :members: + :inherited-members: + :show-inheritance: + +OPW Solver +---------- + +.. autoclass:: OPWSolverCfg + :members: + :exclude-members: __init__, copy, replace, to_dict, validate + +.. autoclass:: OPWSolver + :members: + :inherited-members: + :show-inheritance: diff --git a/docs/source/api_reference/embodichain/embodichain.lab.sim.types.rst b/docs/source/api_reference/embodichain/embodichain.lab.sim.types.rst new file mode 100644 index 00000000..5b1c4bd8 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.sim.types.rst @@ -0,0 +1,6 @@ +embodichain.lab.sim.types +===================================== + +.. automodule:: embodichain.lab.sim.types + + \ No newline at end of file diff --git a/docs/source/api_reference/embodichain/embodichain.lab.sim.utility.rst b/docs/source/api_reference/embodichain/embodichain.lab.sim.utility.rst new file mode 100644 index 00000000..f64d3ce3 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.lab.sim.utility.rst @@ -0,0 +1,31 @@ +embodichain.lab.sim.utility +========================================== + +.. automodule:: embodichain.lab.sim.utility + +Utility Functions +----------------- + +This module contains utility functions for simulation, mesh processing, and URDF handling. + +.. rubric:: Submodules + +.. autosummary:: + + sim_utils + mesh_utils + urdf_utils + +.. currentmodule:: embodichain.lab.sim.utility + +Simulation Utils +~~~~~~~~~~~~~~~~ + +.. automodule:: embodichain.lab.sim.utility.sim_utils + :members: + +Mesh Utils +~~~~~~~~~~ + +.. automodule:: embodichain.lab.sim.utility.mesh_utils + :members: diff --git a/docs/source/api_reference/embodichain/embodichain.toolkits.rst b/docs/source/api_reference/embodichain/embodichain.toolkits.rst new file mode 100644 index 00000000..cc2639d5 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.toolkits.rst @@ -0,0 +1,29 @@ +embodichain.toolkits +==================== + +.. automodule:: embodichain.toolkits + + .. rubric:: Submodules + + .. autosummary:: + + graspkit + urdf_assembly + + +GraspKit +-------- + +.. automodule:: embodichain.toolkits.graspkit + :members: + :undoc-members: + :show-inheritance: + + +URDF Assembly Tool +------------------- + +.. automodule:: embodichain.toolkits.urdf_assembly + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api_reference/embodichain/embodichain.utils.rst b/docs/source/api_reference/embodichain/embodichain.utils.rst new file mode 100644 index 00000000..52ad4a4f --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.utils.rst @@ -0,0 +1,100 @@ +embodichain.utils +================= + +.. automodule:: embodichain.utils + + .. Rubric:: Submodules + + .. autosummary:: + + warp + configclass + file + heat_map + logger + math + module_utils + string + utility + visualizer + + +High Performance Computing with Warp +--------------- + +.. toctree:: + :maxdepth: 1 + + embodichain.utils.warp + +Configuration Classes +--------------------- + +.. automodule:: embodichain.utils.configclass + :members: + :undoc-members: + :show-inheritance: + +File Operations +--------------- + +.. automodule:: embodichain.utils.file + :members: + :undoc-members: + :show-inheritance: + +Heat Map Utilities +------------------ + +.. automodule:: embodichain.utils.heat_map + :members: + :undoc-members: + :show-inheritance: + +Logging +------- + +.. automodule:: embodichain.utils.logger + :members: + :undoc-members: + :show-inheritance: + +Mathematical Operations +----------------------- + +.. automodule:: embodichain.utils.math + :members: + :undoc-members: + :show-inheritance: + +Module Utilities +----------------------- + +.. automodule:: embodichain.utils.module_utils + :members: + :undoc-members: + :show-inheritance: + +String Operations +----------------- + +.. automodule:: embodichain.utils.string + :members: + :undoc-members: + :show-inheritance: + +General Utilities +----------------- + +.. automodule:: embodichain.utils.utility + :members: + :undoc-members: + :show-inheritance: + +Visualization +------------- + +.. automodule:: embodichain.utils.visualizer + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api_reference/embodichain/embodichain.utils.warp.kinematics.rst b/docs/source/api_reference/embodichain/embodichain.utils.warp.kinematics.rst new file mode 100644 index 00000000..d6b6c286 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.utils.warp.kinematics.rst @@ -0,0 +1,37 @@ +embodichain.utils.warp.kinematics +================================= + +Utilities for kinematics implemented with Warp (high-performance kernels). + +This subpackage provides Warp kernels and helper functions for inverse/forward +kinematics and batched trajectory warping used across EmbodiChain. The modules +documented below are the main entry points: + +- ``opw_solver``: efficient OPW-based forward/inverse kinematics kernels. +- ``warp_trajectory``: kernels to compute, interpolate, and apply trajectory offsets. + +.. automodule:: embodichain.utils.warp.kinematics + + .. Rubric:: Submodules + + .. autosummary:: + + opw_solver + warp_trajectory + +OPW Kinematics Solver +----------------------- + +.. automodule:: embodichain.utils.warp.kinematics.opw_solver + :members: + :undoc-members: + :show-inheritance: + + +Trajectory Warping Utilities +---------------------------- +.. automodule:: embodichain.utils.warp.kinematics.warp_trajectory + :members: + :undoc-members: + :show-inheritance: + \ No newline at end of file diff --git a/docs/source/api_reference/embodichain/embodichain.utils.warp.rst b/docs/source/api_reference/embodichain/embodichain.utils.warp.rst new file mode 100644 index 00000000..cdc62d20 --- /dev/null +++ b/docs/source/api_reference/embodichain/embodichain.utils.warp.rst @@ -0,0 +1,27 @@ +embodichain.utils.warp +======================= + +High-performance Warp utilities used by EmbodiChain. + +This package exposes Warp kernels and helpers for various high-performance computing tasks: + +- Image processing. +- 3D spatial computating, +- Robotics kinematics and trajectory computating + +.. automodule:: embodichain.utils.warp + + .. Rubric:: Submodules + + .. autosummary:: + + kinematics + kernels + +kernel Operators +----------------------- + +.. automodule:: embodichain.utils.warp.kernels + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/api_reference/index.rst b/docs/source/api_reference/index.rst new file mode 100644 index 00000000..fa3112ae --- /dev/null +++ b/docs/source/api_reference/index.rst @@ -0,0 +1,19 @@ +API Reference +============= + +This page provides detailed documentation for all EmbodiChain modules and classes. + +Core Framework +-------------- + +The following modules are available in the core ``embodichain`` framework: + +.. currentmodule:: embodichain + +.. autosummary:: + :toctree: embodichain + + agents + lab + toolkits + utils diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..311ddbf4 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,66 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +import os +import sys + + +project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) +package_root = os.path.join(project_root, "embodichain") +sys.path.insert(0, package_root) + + +project = "EmbodiChain" +copyright = "2025, The EmbodiChain Project Developers" +author = "The EmbodiChain Project Developers" + +# Read version from VERSION file if it exists +with open(os.path.join(os.path.dirname(__file__), "..", "..", "VERSION")) as f: + full_version = f.read().strip() + version = ".".join(full_version.split(".")[:3]) + + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + + +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.napoleon", + "sphinx.ext.viewcode", + "sphinx_autodoc_typehints", # optional, shows type hints + "sphinx_design", + "myst_parser", # if you prefer Markdown pages +] +# Napoleon settings if using Google/NumPy docstring style: +napoleon_google_docstring = True +napoleon_numpy_docstring = True + +# generate autosummary even if no references +autosummary_generate = True +autosummary_generate_overwrite = False +# default autodoc settings +autodoc_default_options = { + "autosummary": True, +} + +# If using MyST and writing .md API stubs: +myst_enable_extensions = ["colon_fence", "deflist", "html_admonition"] + + +templates_path = ["_templates"] +exclude_patterns = [] + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "sphinx_book_theme" +html_static_path = ["_static"] +html_logo = "_static/logo_e.png" diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 00000000..2058a8ba --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,50 @@ +EmbodiChain Documentation +========================= + +Welcome to the EmbodiChain! + +Table of Contents +================= + +.. toctree:: + :maxdepth: 1 + :caption: Introduction + :glob: + + introduction + +.. toctree:: + :maxdepth: 1 + :caption: Getting Started + :glob: + + quick_start/install.md + tutorial/index + quick_start/docs.md + +.. toctree:: + :maxdepth: 1 + :caption: Overview + :glob: + + overview/sim/index + overview/gym/index + overview/vla/index + overview/rl/index + +.. toctree:: + :maxdepth: 1 + :caption: Resources + :glob: + + resources/robot/index* + resources/task/index* + resources/roadmap.md + +.. toctree:: + :maxdepth: 2 + :caption: API Reference + :titlesonly: + + api_reference/index + diff --git a/docs/source/introduction.rst b/docs/source/introduction.rst new file mode 100644 index 00000000..404541da --- /dev/null +++ b/docs/source/introduction.rst @@ -0,0 +1,58 @@ +.. EmbodiChain documentation master file, created by + sphinx-quickstart on Tue Nov 19 11:00:25 2024. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +EmbodiChain +====================================== + +.. image:: ../../assets/imgs/teaser.jpg + :alt: teaser + +📘 `Documentation `_ + +--- + +EmbodiChain is an end-to-end, GPU-accelerated framework for Embodied AI. It streamlines research and development by unifying high-performance simulation, real-to-sim data pipelines, modular model architectures, and efficient training workflows. This integration enables rapid experimentation, seamless deployment of intelligent agents, and effective Sim2Real transfer for real-world robotic systems. + +.. NOTE:: + EmbodiChain is in Alpha and under active development: + + * More features will be continually added in the coming months. + * Since this is an early release, we welcome feedback (bug reports, feature requests, etc.) via GitHub Issues. + + +Key Features +------------ + +* **High-Fidelity, GPU-Accelerated Simulation**: Combines realistic physics for both rigid and deformable objects with advanced ray-traced sensor modeling, all accelerated on the GPU for high-throughput batched simulations. +* **Unified Robot Learning Environment**: Offers standardized interfaces for a wide range of robot learning tasks, including Imitation Learning and Reinforcement Learning. +* **Scalable Data Pipeline**: Features a comprehensive toolkit for automated data collection, efficient processing, and large-scale data generation to fuel your models. +* **Efficient Training & Evaluation**: Supports modern training paradigms like online data streaming for Imitation Learning and massively parallel environment rollouts for Reinforcement Learning. +* **Modular and Extensible**: Designed with modularity in mind to easily integrate new robot platforms, environments, and learning algorithms. + + +Getting Started +--------------- + +To get started with EmbodiChain, follow these steps: + +* `Installation Guide `_ +* `Quick Start Tutorial `_ +* `API Reference `_ + + +Citation +-------- + +If you use EmbodiChain in your research, please cite our work: + +.. code-block:: bibtex + + @misc{EmbodiChain, + author = {EmbodiChain Developers}, + title = {EmbodiChain: An end-to-end, GPU-accelerated, and modular platform for building generalized Embodied Intelligence.}, + month = {November}, + year = {2025}, + url = {https://github.com/DexForce/EmbodiChain} + } diff --git a/docs/source/overview/gym/index.rst b/docs/source/overview/gym/index.rst new file mode 100644 index 00000000..7781adfb --- /dev/null +++ b/docs/source/overview/gym/index.rst @@ -0,0 +1,5 @@ +Embodied Environments +================== + +Overview of the Embodied Environments: + diff --git a/docs/source/overview/rl/algorithm.md b/docs/source/overview/rl/algorithm.md new file mode 100644 index 00000000..cfc92421 --- /dev/null +++ b/docs/source/overview/rl/algorithm.md @@ -0,0 +1,67 @@ +# RL Algorithms + +This module contains the core implementations of reinforcement learning algorithms, mainly including PPO (Proximal Policy Optimization). + +## Main Classes and Functions + +### BaseAlgorithm +- Abstract base class for RL algorithms, defining common interfaces such as buffer initialization, data collection, and update. +- Key methods: + - `initialize_buffer(num_steps, num_envs, obs_dim, action_dim)`: Initialize the trajectory buffer. + - `collect_rollout(env, policy, obs, num_steps, on_step_callback)`: Collect interaction data. + - `update()`: Update the policy based on collected data. +- Designed to be algorithm-agnostic; Trainer only depends on this interface to support various RL algorithms. +- Supports multi-environment parallel collection, compatible with Gymnasium/IsaacGym environments. + +### PPO +- Mainstream on-policy algorithm, supports Generalized Advantage Estimation (GAE), policy update, and hyperparameter configuration. +- Key methods: + - `_compute_gae(rewards, values, dones)`: Generalized Advantage Estimation. + - `collect_rollout`: Collect trajectories and compute advantages/returns. + - `update`: Multi-epoch minibatch optimization, including entropy, value, and policy loss, with gradient clipping. +- Supports custom callbacks, detailed logging, and GPU acceleration. +- Typical training flow: collect rollout → compute advantage/return → multi-epoch minibatch optimization. +- Supports advantage normalization, entropy regularization, value loss weighting, etc. + +### Config Classes +- `AlgorithmCfg`, `PPOCfg`: Centralized management of learning rate, batch size, clip_coef, ent_coef, vf_coef, and other parameters. +- Supports automatic loading from JSON config files for batch experiments and parameter tuning. +- Can be extended via inheritance for multiple algorithms and tasks. + +## Code Example +```python +class BaseAlgorithm: + def initialize_buffer(self, num_steps, num_envs, obs_dim, action_dim): + ... + def collect_rollout(self, env, policy, obs, num_steps, on_step_callback=None): + ... + def update(self): + ... + +class PPO(BaseAlgorithm): + def _compute_gae(self, rewards, values, dones): + ... + def collect_rollout(self, ...): + ... + def update(self): + ... +``` + +## Usage Recommendations +- It is recommended to manage all algorithm parameters via config classes and JSON config files for reproducibility and tuning. +- Supports multi-environment parallel collection to improve sampling efficiency. +- Custom algorithm classes can be implemented to extend new RL methods. + +## Extension Notes +- Users can inherit from `BaseAlgorithm` to implement custom algorithms and flexibly integrate them into the RL framework. +- Supports multi-environment parallelism and event-driven extension. +- Typical usage: +```python +algo = PPO(cfg, policy) +buffer = algo.initialize_buffer(...) +for _ in range(num_iterations): + algo.collect_rollout(...) + algo.update() +``` + +--- diff --git a/docs/source/overview/rl/buffer.md b/docs/source/overview/rl/buffer.md new file mode 100644 index 00000000..91852074 --- /dev/null +++ b/docs/source/overview/rl/buffer.md @@ -0,0 +1,65 @@ +# Rollout Buffer + +This module implements the data buffer for RL training, responsible for storing trajectory data from agent-environment interactions. + +## Main Classes and Structure + +### RolloutBuffer +- Used for on-policy algorithms (such as PPO), efficiently stores observations, actions, rewards, dones, values, and logprobs for each step. +- Supports multi-environment parallelism (shape: [T, N, ...]), all data allocated on GPU. +- Structure fields: + - `obs`: Observation tensor, float32, shape [T, N, obs_dim] + - `actions`: Action tensor, float32, shape [T, N, action_dim] + - `rewards`: Reward tensor, float32, shape [T, N] + - `dones`: Done flags, bool, shape [T, N] + - `values`: Value estimates, float32, shape [T, N] + - `logprobs`: Action log probabilities, float32, shape [T, N] + - `_extras`: Algorithm-specific fields (e.g., advantages, returns), dict[str, Tensor] + +## Main Methods +- `add(obs, action, reward, done, value, logprob)`: Add one step of data. +- `set_extras(extras)`: Attach algorithm-related tensors (e.g., advantages, returns). +- `iterate_minibatches(batch_size)`: Randomly sample minibatches, returns dict (including all fields and extras). +- Supports efficient GPU shuffle and indexing for large-scale training. + +## Usage Example +```python +buffer = RolloutBuffer(num_steps, num_envs, obs_dim, action_dim, device) +for t in range(num_steps): + buffer.add(obs, action, reward, done, value, logprob) +buffer.set_extras({"advantages": adv, "returns": ret}) +for batch in buffer.iterate_minibatches(batch_size): + # batch["obs"], batch["actions"], batch["advantages"] ... + pass +``` + +## Design and Extension +- Supports multi-environment parallel collection, compatible with Gymnasium/IsaacGym environments. +- All data is allocated on GPU to avoid frequent CPU-GPU copying. +- The extras field can be flexibly extended to meet different algorithm needs (e.g., GAE, TD-lambda, distributional advantages). +- The iterator automatically shuffles to improve training stability. +- Compatible with various RL algorithms (PPO, A2C, SAC, etc.), custom fields and sampling logic supported. + +## Code Example +```python +class RolloutBuffer: + def __init__(self, num_steps, num_envs, obs_dim, action_dim, device): + # Initialize tensors + ... + def add(self, obs, action, reward, done, value, logprob): + # Add data + ... + def set_extras(self, extras): + # Attach algorithm-related tensors + ... + def iterate_minibatches(self, batch_size): + # Random minibatch sampling + ... +``` + +## Practical Tips +- It is recommended to call set_extras after each rollout to ensure advantage/return tensors align with main data. +- When using iterate_minibatches, set batch_size appropriately for training stability. +- Extend the extras field as needed for custom sampling and statistics. + +--- diff --git a/docs/source/overview/rl/config.md b/docs/source/overview/rl/config.md new file mode 100644 index 00000000..bf5c04df --- /dev/null +++ b/docs/source/overview/rl/config.md @@ -0,0 +1,55 @@ +# Config + +This module defines configuration classes for RL algorithms, centralizing the management of training hyperparameters and supporting automatic loading and experiment reproducibility. + +## Main Classes and Structure + +### AlgorithmCfg +- Base parameter config class for RL algorithms, supports dataclass-based automation. +- Typical fields: + - `device`: Training device (e.g., "cuda", "cpu"). + - `learning_rate`: Learning rate. + - `batch_size`: Batch size per training epoch. + - `gamma`: Discount factor. + - `gae_lambda`: GAE advantage estimation parameter. + - `max_grad_norm`: Gradient clipping threshold. +- Supports inheritance and extension (e.g., PPOCfg adds clip_coef, ent_coef, vf_coef). + +### Automatic Loading +- Supports automatic parsing of JSON config files; the main training script injects parameters automatically. +- Decouples config from code, making batch experiments and parameter tuning easier. + +## Usage Example +```python +from embodichain.agents.rl.utils import AlgorithmCfg +cfg = AlgorithmCfg(learning_rate=1e-4, batch_size=8192, gamma=0.99) +``` +Or via config file: +```json +{ + "algorithm": { + "name": "ppo", + "cfg": { + "learning_rate": 0.0001, + "batch_size": 8192, + "gamma": 0.99, + "gae_lambda": 0.95, + "clip_coef": 0.2, + "ent_coef": 0.01, + "vf_coef": 0.5, + "max_grad_norm": 0.5 + } + } +} +``` + +## Extension and Customization +- Custom algorithm parameter classes are supported for multi-algorithm and multi-task experiments. +- Config classes are seamlessly integrated with the main training script for automated experiments and reproducibility. +- Supports parameter validation, default values, and type hints. + +## Practical Tips +- It is recommended to manage all experiment parameters via JSON config files for reproducibility and tuning. +- Supports multi-algorithm config for easy comparison and automation. + +--- diff --git a/docs/source/overview/rl/index.rst b/docs/source/overview/rl/index.rst new file mode 100644 index 00000000..2d78b85b --- /dev/null +++ b/docs/source/overview/rl/index.rst @@ -0,0 +1,80 @@ +Reinforcement Learning +====================== + +This section introduces the overall architecture and submodules of the embodychain RL (Reinforcement Learning) module. The RL framework supports mainstream algorithms (such as PPO) and provides flexible components for policy, buffer, trainer, etc., making it easy to extend and customize. + +.. contents:: Table of contents + :local: + :depth: 2 + +Overview +-------- + +The embodychain RL module is used to train agents to accomplish tasks in simulation environments. It mainly includes algorithm implementations, policy networks, data buffers, training processes, and utility tools. + +Architecture Diagram Example +--------------------------- + +.. code-block:: text + + +-------------------+ + | train.py | + +-------------------+ + | + v + +-------------------+ + | Trainer | + +-------------------+ + | | | | + v v v v + Algo Policy Buffer Env + +- train.py is responsible for entry, config parsing, and module initialization. +- Trainer coordinates algorithm, policy, buffer, and environment. +- Algo/Policy/Buffer/Env are independent, making extension easy. + +Module Categories +----------------- + +- Algorithm (`algo/`): RL algorithm implementations, including `BaseAlgorithm`, `PPO`, etc. +- Buffer (`buffer/`): Trajectory data buffer, such as `RolloutBuffer`. +- Models (`models/`): Policy network modules, including `Policy`, `ActorCritic`, `MLP`. +- Trainer (`utils/trainer.py`): Main training loop and logging management. +- Config (`utils/config.py`): Algorithm config class definitions. +- Train Script (`train.py`): RL training entry script. + +Extension and Customization +--------------------------- + +- Users can customize algorithms (by inheriting `BaseAlgorithm`), policies (by inheriting `Policy`), buffers, etc. +- Supports multi-environment parallelism, event-driven extension, and flexible config management. +- It is recommended to manage all parameters via config files for reproducibility and batch experiments. + +Common Issues and Best Practices +------------------------------- +- Config files are recommended to use JSON for easy management and reproducibility. +- Parallel environment sampling can significantly improve training efficiency. +- The event-driven mechanism allows flexible insertion of custom logic (such as evaluation, saving, callbacks). +- It is recommended to use WandB/TensorBoard for training process visualization. + +Example +------- + +.. code-block:: bash + + python train.py --config configs/agents/rl/push_cube/train_config.json + +For more details, please refer to the source code and API documentation of each submodule. + +See also +-------- + +.. toctree:: + :maxdepth: 1 + + algorithm.md + buffer.md + models.md + trainer.md + config.md + train_script.md diff --git a/docs/source/overview/rl/models.md b/docs/source/overview/rl/models.md new file mode 100644 index 00000000..8bf7986e --- /dev/null +++ b/docs/source/overview/rl/models.md @@ -0,0 +1,50 @@ +# Policy Models + +This module contains RL policy networks and related model implementations, supporting various architectures and distributional extensions. + +## Main Classes and Structure + +### Policy +- Abstract base class for RL policies; all policies must inherit from it. +- Unified interface: + - `get_action(obs, deterministic=False)`: Sample or output actions. + - `get_value(obs)`: Estimate state value. + - `evaluate_actions(obs, actions)`: Evaluate action probabilities, entropy, and value. +- Supports GPU deployment and distributed training. + +### ActorCritic +- Typical actor-critic policy, includes actor (action distribution) and critic (value function). +- Supports Gaussian action distributions, learnable log_std, suitable for continuous action spaces. +- Key methods: + - `get_action`: Actor network outputs mean, samples action, returns log_prob and critic value. + - `evaluate_actions`: Used for loss calculation in PPO/SAC algorithms. +- Custom actor/critic network architectures supported (e.g., MLP/CNN/Transformer). + +### MLP +- Multi-layer perceptron, supports custom number of layers, activation functions, LayerNorm, Dropout. +- Used to build actor/critic networks. +- Supports orthogonal initialization and output reshaping. + +### Factory Functions +- `build_policy(policy_block, obs_space, action_space, device, ...)`: Automatically build policy from config. +- `build_mlp_from_cfg(module_cfg, in_dim, out_dim)`: Automatically build MLP from config. + +## Usage Example +```python +actor = build_mlp_from_cfg(actor_cfg, obs_dim, action_dim) +critic = build_mlp_from_cfg(critic_cfg, obs_dim, 1) +policy = build_policy(policy_block, obs_space, action_space, device, actor=actor, critic=critic) +action, log_prob, value = policy.get_action(obs) +``` + +## Extension and Customization +- Supports custom network architectures (e.g., CNN, Transformer) by implementing the Policy interface. +- Can extend to multi-head policies, distributional actors, hybrid action spaces, etc. +- Factory functions facilitate config management and automated experiments. + +## Practical Tips +- It is recommended to configure all network architectures and hyperparameters for reproducibility. +- Supports multi-environment parallelism and distributed training to improve sampling efficiency. +- Extend the Policy interface as needed for multi-modal input, hierarchical policies, etc. + +--- diff --git a/docs/source/overview/rl/train_script.md b/docs/source/overview/rl/train_script.md new file mode 100644 index 00000000..cc7a1568 --- /dev/null +++ b/docs/source/overview/rl/train_script.md @@ -0,0 +1,48 @@ +# Train Script + +This module provides the RL training entry script, responsible for parsing configuration, initializing modules, and starting training. It supports multi-task and automated experiments. + +## Main Structure and Flow + +### train.py +- Main training script, supports command-line arguments (such as --config), automatically loads JSON config. +- Initializes device, random seed, output directory, and logging (TensorBoard/WandB). +- Loads environment config, supports multi-environment parallelism and evaluation environments. +- Builds policy (e.g., actor-critic), algorithm (e.g., PPO), and Trainer. +- Supports event management (e.g., environment randomization, data logging, evaluation events). +- Automatically saves model checkpoints and performs periodic evaluation. + +## Argument Parsing +- Supports command-line arguments: + - `--config`: Specify the path to the config file (JSON only). +- The config file includes parameters for trainer, policy, algorithm, events, and other modules. + +## Module Initialization +- Device selection (CPU/GPU), automatic detection and setup. +- Random seed setting to ensure experiment reproducibility. +- Output directory is automatically generated, log files are managed automatically. +- Supports TensorBoard/WandB logging, automatically records the training process. + +## Training Flow +1. Load the JSON config file and parse parameters for each module. +2. Initialize environment, policy, algorithm, and Trainer. +3. Enter the main training loop: collect data, update policy, record logs. +4. Periodically evaluate and save the model. +5. Supports graceful interruption and auto-saving with KeyboardInterrupt. + +## Usage Example +```bash +python train.py --config configs/agents/rl/push_cube/train_config.json +``` + +## Extension and Customization +- Supports custom event modules for flexible training flow extension. +- Can integrate multi-task and multi-environment training. +- Config-driven management for batch experiments and parameter tuning. + +## Practical Tips +- It is recommended to manage all experiment parameters via JSON config files for reproducibility and tuning. +- Supports multi-environment and event extension to improve training flexibility. +- Logging and checkpoint management help with experiment tracking and recovery. + +--- diff --git a/docs/source/overview/rl/trainer.md b/docs/source/overview/rl/trainer.md new file mode 100644 index 00000000..1a2b0fe3 --- /dev/null +++ b/docs/source/overview/rl/trainer.md @@ -0,0 +1,53 @@ +# Trainer + +This module implements the main RL training loop, logging management, and event-driven extension. + +## Main Classes and Structure + +### Trainer +- RL training coordinator, responsible for the interaction between algorithm, environment, and policy. +- Main responsibilities: + - Manage training loop, evaluation, and model saving. + - Event-driven extension (e.g., environment randomization, data logging, evaluation events). + - Logging output (TensorBoard/WandB/console), tracking rewards, episode length, loss, etc. +- Key fields: + - `policy`: RL policy object. + - `algorithm`: RL algorithm object. + - `env`/`eval_env`: Training and evaluation environments. + - `writer`: TensorBoard logger. + - `event_manager`/`eval_event_manager`: Event managers. + - `global_step`, `ret_window`, `len_window`: Training statistics. + +## Main Methods +- `train(total_timesteps)`: Main training loop, automatically collects data, updates policy, and logs. +- `_collect_rollout()`: Collect one rollout, supports custom callback statistics. +- `_log_train(losses)`: Log training loss, reward, sampling speed, etc. +- `_eval_once()`: Periodic evaluation, records evaluation metrics. +- `save_checkpoint()`: Save model parameters and training state. + +## Event Management +- Supports custom events (e.g., environment randomization, data logging) injected via EventManager. +- Events can be executed by interval/step/trigger, enabling flexible extension. + +## Logging and Monitoring +- Supports TensorBoard and WandB logging, automatically records reward, episode length, loss, sampling speed, etc. +- Console output for training progress and statistics. + +## Usage Example +```python +trainer = Trainer(policy, env, algorithm, num_steps, batch_size, writer, ...) +trainer.train(total_steps) +trainer.save_checkpoint() +``` + +## Extension and Customization +- Custom event modules can be implemented for environment reset, data collection, evaluation, etc. +- Supports multi-environment parallelism and distributed training. +- Training process can be flexibly adjusted via config files. + +## Practical Tips +- It is recommended to perform periodic evaluation and model saving to prevent loss of progress during training. +- The event mechanism can be used for automated experiments, data collection, and environment reset. +- Logging and monitoring help analyze training progress and tune hyperparameters. + +--- diff --git a/docs/source/overview/sim/index.rst b/docs/source/overview/sim/index.rst new file mode 100644 index 00000000..fd6e56fd --- /dev/null +++ b/docs/source/overview/sim/index.rst @@ -0,0 +1,23 @@ +Simulation Framework +================== + +Overview of the Simulation Framework: + +- Architecture + +- Components + + - Simulation Manager + - Simulation Object + - Material + - Virtual Sensor + - Kinematics Solver + - Motion Generation + + +.. toctree:: + :maxdepth: 1 + :glob: + + solvers/index + planners/index diff --git a/docs/source/overview/sim/planners/index.rst b/docs/source/overview/sim/planners/index.rst new file mode 100644 index 00000000..0347197a --- /dev/null +++ b/docs/source/overview/sim/planners/index.rst @@ -0,0 +1,36 @@ +Planners +================================= + +This section documents the planners provided by the project with a focus on +planners for robotic motion: path planning, trajectory generation, +collision avoidance, and practical considerations such as smoothness and +dynamic feasibility. + +The repository contains several planner implementations — each has a dedicated +page with implementation details and examples. Use the links at the bottom of +this page to jump to a specific planner. + +.. contents:: Table of contents + :local: + :depth: 2 + +Overview +-------- + +The `embodichain` project provides a unified interface for robot trajectory planning, supporting both joint space and Cartesian space interpolation. The main planners include: + +- **MotionGenerator**: A unified trajectory planning interface that supports joint/Cartesian interpolation, automatic constraint handling, flexible planner selection, and is easily extensible for collision checking and additional planners. +- **ToppraPlanner**: A time-optimal trajectory planner based on the TOPPRA library, supporting joint trajectory generation under velocity and acceleration constraints. +- **TrajectorySampleMethod**: An enumeration for trajectory sampling strategies, supporting sampling by time, quantity, or distance. + +These tools can be used to generate smooth and dynamically feasible robot trajectories, and are extensible for future collision checking and various sampling requirements. + +See also +-------- + +.. toctree:: + :maxdepth: 1 + + motion_generator.md + toppra_planner.md + trajectory_sample_method.md diff --git a/docs/source/overview/sim/planners/motion_generator.md b/docs/source/overview/sim/planners/motion_generator.md new file mode 100644 index 00000000..5aa75a0b --- /dev/null +++ b/docs/source/overview/sim/planners/motion_generator.md @@ -0,0 +1,142 @@ +# MotionGenerator + +`MotionGenerator` provides a unified interface for robot trajectory planning, supporting both joint space and Cartesian space interpolation. It is designed to work with different planners (such as ToppraPlanner) and can be extended to support collision checking in the future. + +## Features + +* **Unified planning interface**: Supports trajectory planning with or without collision checking (collision checking is reserved for future implementation). +* **Flexible planner selection**: Allows selection of different planners (currently supports TOPPRA for time-optimal planning). +* **Automatic constraint handling**: Retrieves velocity and acceleration limits from the robot or uses user-specified/default values. +* **Supports both joint and Cartesian interpolation**: Generates discrete trajectories using either joint space or Cartesian space interpolation. +* **Convenient sampling**: Supports various sampling strategies via `TrajectorySampleMethod`. + +## Usage + +### Initialization + +```python +from embodichain.data import get_data_path +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import ( + RobotCfg, + URDFCfg, + JointDrivePropertiesCfg, +) + +from embodichain.lab.sim.planners.motion_generator import MotionGenerator +from embodichain.lab.sim.objects.robot import Robot +from embodichain.lab.sim.solvers.pink_solver import PinkSolverCfg +from embodichain.lab.sim.planners.utils import TrajectorySampleMethod + +# Configure the simulation +sim_cfg = SimulationManagerCfg( + width=1920, + height=1080, + physics_dt=1.0 / 100.0, + sim_device="cpu", +) + +sim = SimulationManager(sim_cfg) +sim.set_manual_update(True) + +# Get UR10 URDF path +urdf_path = get_data_path("UniversalRobots/UR10/UR10.urdf") + +# Create UR10 robot +robot_cfg = RobotCfg( + uid="UR10_test", + urdf_cfg=URDFCfg( + components=[{"component_type": "arm", "urdf_path": urdf_path}] + ), + control_parts={"arm": ["Joint[1-6]"]}, + solver_cfg={ + "arm": PinkSolverCfg( + urdf_path=urdf_path, + end_link_name="ee_link", + root_link_name="base_link", + pos_eps=1e-2, + rot_eps=5e-2, + max_iterations=300, + dt=0.1, + ) + }, + drive_pros=JointDrivePropertiesCfg( + stiffness={"Joint[1-6]": 1e4}, + damping={"Joint[1-6]": 1e3}, + ), +) +robot = sim.add_robot(cfg=robot_cfg) + +motion_gen = MotionGenerator( + robot=robot, + uid="arm", + planner_type="toppra", + default_velocity=0.2, + default_acceleration=0.5 +) + +``` + +### Trajectory Planning + +#### Joint Space Planning + +```python +current_state = { + "position": [0, 0, 0, 0, 0, 0], + "velocity": [0, 0, 0, 0, 0, 0], + "acceleration": [0, 0, 0, 0, 0, 0] +} +target_states = [ + {"position": [1, 1, 1, 1, 1, 1]} +] +success, positions, velocities, accelerations, times, duration = motion_gen.plan( + current_state=current_state, + target_states=target_states, + sample_method=TrajectorySampleMethod.TIME, + sample_interval=0.01 +) +``` + +#### Cartesian or Joint Interpolation + +```python +# Using joint configurations (qpos_list) +qpos_list = [ + [0, 0, 0, 0, 0, 0], + [1, 1, 1, 1, 1, 1] +] +out_qpos_list, out_xpos_list = motion_gen.create_discrete_trajectory( + qpos_list=qpos_list, + is_linear=False, + sample_method=TrajectorySampleMethod.QUANTITY, + sample_num=20 +) +``` + +### Estimating Trajectory Sample Count + +You can estimate the number of sampling points required for a trajectory before generating it: + +```python +# Estimate based on joint configurations (qpos_list) +qpos_list = [ + [0, 0, 0, 0, 0, 0], + [0.5, 0.5, 0.5, 0.5, 0.5, 0.5], + [1, 1, 1, 1, 1, 1] +] +sample_count = motion_gen.estimate_trajectory_sample_count( + qpos_list=qpos_list, # List of joint positions + step_size=0.01, # unit: m + angle_step=0.05, # unit: rad +) +print(f"Estimated sample count: {sample_count}") +``` + +## Notes + +* The planner type can be specified as a string or `PlannerType` enum. +* If the robot provides its own joint limits, those will be used; otherwise, default or user-specified limits are applied. +* For Cartesian interpolation, inverse kinematics (IK) is used to compute joint configurations for each interpolated pose. +* The class is designed to be extensible for additional planners and collision checking in the future. +* The sample count estimation is useful for predicting computational load and memory requirements. diff --git a/docs/source/overview/sim/planners/toppra_planner.md b/docs/source/overview/sim/planners/toppra_planner.md new file mode 100644 index 00000000..3ff756fd --- /dev/null +++ b/docs/source/overview/sim/planners/toppra_planner.md @@ -0,0 +1,58 @@ +# ToppraPlanner + +`ToppraPlanner` is a trajectory planner based on the [TOPPRA](https://toppra.readthedocs.io/) (Time-Optimal Path Parameterization via Reachability Analysis) library. It generates time-optimal joint trajectories under velocity and acceleration constraints. + +## Features + +- **Time-optimal trajectory generation**: Computes the fastest possible trajectory between waypoints, given joint velocity and acceleration limits. +- **Flexible sampling**: Supports sampling by time interval or by number of points. +- **Constraint handling**: Automatically formats velocity and acceleration constraints for the TOPPRA solver. +- **Dense and sparse waypoints**: Supports both dense and sparse waypoint interpolation. + +## Usage + +### Initialization + +```python +from embodichain.lab.sim.planners.toppra_planner import ToppraPlanner +planner = ToppraPlanner( + dofs=6, + max_constraints={ + "velocity": [1.0, 1.0, 1.0, 1.0, 1.0, 1.0], + "acceleration": [2.0, 2.0, 2.0, 2.0, 2.0, 2.0] + } +) +``` + +### Planning + +```python +from embodichain.lab.sim.planners.utils import TrajectorySampleMethod +from embodichain.lab.sim.planners.toppra_planner import ToppraPlanner +success, positions, velocities, accelerations, times, duration = planner.plan( + current_state={ + "position": [0, 0, 0, 0, 0, 0], + "velocity": [0, 0, 0, 0, 0, 0], + "acceleration": [0, 0, 0, 0, 0, 0] + }, + target_states=[ + {"position": [1, 1, 1, 1, 1, 1]} + ], + sample_method=TrajectorySampleMethod.TIME, + sample_interval=0.01 +) +``` + +- `positions`, `velocities`, `accelerations` are arrays of sampled trajectory points. +- `times` is the array of time stamps. +- `duration` is the total trajectory time. + +## Notes + +- The planner requires the `toppra` library (`pip install toppra==0.6.3`). +- For dense waypoints, the default spline interpolation is used. For sparse waypoints, you may need to adjust the interpolation method. +- The number of grid points (`gridpt_min_nb_points`) is important for accurate acceleration constraint handling. + +## References + +- [TOPPRA Documentation](https://hungpham2511.github.io/toppra/index.html) diff --git a/docs/source/overview/sim/planners/trajectory_sample_method.md b/docs/source/overview/sim/planners/trajectory_sample_method.md new file mode 100644 index 00000000..0b8c16ff --- /dev/null +++ b/docs/source/overview/sim/planners/trajectory_sample_method.md @@ -0,0 +1,17 @@ +# TrajectorySampleMethod + +`TrajectorySampleMethod` is an enumeration that defines different strategies for sampling points along a trajectory. It provides meaningful names for various sampling methods, making trajectory planning code more readable and maintainable. + +## Enum Members + +- **TIME**: + Sample trajectory points based on fixed time intervals. + Example: Generate a point every 0.01 seconds. + +- **QUANTITY**: + Sample a specified number of points along the trajectory, regardless of the time interval. + Example: Generate exactly 100 points between start and end. + +- **DISTANCE**: + Sample points based on fixed distance intervals along the path. + Example: Generate a point every 1 cm along the trajectory. diff --git a/docs/source/overview/sim/solvers/differential_solver.md b/docs/source/overview/sim/solvers/differential_solver.md new file mode 100644 index 00000000..5f68cad6 --- /dev/null +++ b/docs/source/overview/sim/solvers/differential_solver.md @@ -0,0 +1,99 @@ +# DifferentialSolver + +The `DifferentialSolver` is a differential inverse kinematics (IK) controller designed for robot manipulators. It computes joint-space commands to achieve desired end-effector positions or poses using various Jacobian-based methods. + +## Key Features + +* Supports multiple IK methods: pseudo-inverse (`pinv`), singular value decomposition (`svd`), transpose (`trans`), and damped least squares (`dls`) +* Configurable for position or pose control, with absolute or relative modes +* Efficient batch computation for multiple environments +* Flexible configuration via `DifferentialSolverCfg` + +## Configuration Example + +```python +from embodichain.data import get_data_path +from embodichain.lab.sim.solvers.differential_solver import DifferentialSolver +from embodichain.lab.sim.solvers.differential_solver import DifferentialSolverCfg + +cfg = DifferentialSolverCfg( + urdf_path=get_data_path("UniversalRobots/UR5/UR5.urdf"), + joint_names=["joint1", "joint2", "joint3", "joint4", "joint5", "joint6"], + end_link_name="ee_link", + root_link_name="base_link", + command_type="pose", + use_relative_mode=False, + ik_method="pinv", + ik_params={"k_val": 1.0} +) + +solver = DifferentialSolver(cfg) +``` + +## Main Methods + +* `get_fk(self, qpos: torch.Tensor) -> torch.Tensor` + Computes the end-effector pose (homogeneous transformation matrix) for the given joint positions. + + **Parameters:** + + `qpos` (`torch.Tensor` or `list[float]`): Joint positions, shape `(num_envs, num_joints)` or `(num_joints,)`. + + **Returns:** + + `torch.Tensor`: End-effector pose(s), shape `(num_envs, 4, 4)`. + + **Example:** + +```python + fk = solver.get_fk(qpos=[0.0, 0.0, 0.0, 1.5708, 0.0, 0.0]) + print(fk) + # Output: + # tensor([[[ 0.0, -1.0, 0.0, -0.722600], + # [ 0.0, 0.0, -1.0, -0.191450], + # [ 1.0, 0.0, 0.0, 0.079159], + # [ 0.0, 0.0, 0.0, 1.0 ]]]) +``` + +* `get_ik(self, target_xpos: torch.Tensor, qpos_seed: torch.Tensor = None, return_all_solutions: bool = False, jacobian: torch.Tensor = None) -> Tuple[torch.Tensor, torch.Tensor]` + Computes joint positions (inverse kinematics) for the given target end-effector pose. + + **Parameters:** + + `target_xpos` (`torch.Tensor`): Target end-effector pose(s), shape `(num_envs, 4, 4)`. + + `qpos_seed` (`torch.Tensor`, optional): Initial guess for joint positions, shape `(num_envs, num_joints)`. If `None`, a default is used. + + `return_all_solutions` (`bool`, optional): If `True`, returns all possible solutions. Default is `False`. + + `jacobian` (`torch.Tensor`, optional): Custom Jacobian. Usually not required. + + **Returns:** + + `Tuple[torch.Tensor, torch.Tensor]`: + - First element: Joint positions, shape `(num_envs, num_joints)`. + - Second element: Convergence info or error for each environment. + + **Example:** + +```python + import torch + xpos = torch.tensor([[[ 0.0, -1.0, 0.0, -0.722600], + [ 0.0, 0.0, -1.0, -0.191450], + [ 1.0, 0.0, 0.0, 0.079159], + [ 0.0, 0.0, 0.0, 1.0 ]]]) + qpos_seed = torch.zeros((1, 6)) + qpos_sol, info = solver.get_ik(target_xpos=xpos) + print("IK solution:", qpos_sol) + print("Convergence info:", info) + # IK solution: tensor([True]) + # Convergence info: tensor([[0.0, -0.231429, 0.353367, 0.893100, 0.0, 0.555758]]) +``` + +> **Tip:** +> - `get_fk` is for forward kinematics (joint to end-effector), `get_ik` is for inverse kinematics (end-effector to joint). +> - For batch computation, the first dimension of `qpos` and `target_xpos` is the batch size. + +## IK Methods Supported + +* **pinv**: Jacobian pseudo-inverse +* **svd**: Singular value decomposition +* **trans**: Jacobian transpose +* **dls**: Damped least squares + +## References + +* [Isaac Sim Library](https://github.com/isaac-sim/IsaacLab) diff --git a/docs/source/overview/sim/solvers/index.rst b/docs/source/overview/sim/solvers/index.rst new file mode 100644 index 00000000..8ffa5570 --- /dev/null +++ b/docs/source/overview/sim/solvers/index.rst @@ -0,0 +1,96 @@ +Solvers +================================= + +This section documents the solvers provided by the project with a focus on +robotic kinematics: forward kinematics (FK), inverse kinematics (IK), +differential (velocity) kinematics, constraint handling and practical +considerations such as singularities and performance tuning. + +The repository contains several solver implementations — each has a dedicated +page with implementation details and examples. Use the links at the bottom of +this page to jump to a specific solver. + +.. contents:: Table of contents + :local: + :depth: 2 + +Overview +-------- + +Robotic kinematics solvers translate between joint-space and task-space. + +- Forward kinematics (FK) maps joint values q to an end-effector pose. +- Inverse kinematics (IK) finds joint values q that achieve a desired end-effector + pose. + + +Forward kinematics +------------------- + +Forward kinematics composes joint transforms according to the robot's +kinematic tree to produce the end-effector transform. Practical builders compute these transforms efficiently using the robot's +URDF or internal kinematic model. FK solvers in `embodichain` are +optimized for batch evaluation and for returning both pose and link frames. + +Inverse kinematics +------------------- + +Inverse kinematics is the core topic for robotics. There are two common +approaches implemented in the repository: + +- Analytical IK (closed-form): when the robot geometry admits a closed-form + solution (e.g., many 6-DOF industrial arms), these solvers return exact + solutions quickly and deterministically. +- Numerical IK: general-purpose methods based on the Jacobian or optimization + that work for arbitrary kinematic chains but may be slower and require + a good initial guess. + +Analytical IK +~~~~~~~~~~~~~ + +Analytical solvers (see the OPW) exploit kinematic +structure to derive algebraic inverse mappings. Benefits include: + +- very fast runtime +- exact solutions when they exist + +Limitations: + +- only available for specific robot families and joint arrangements + +Numerical IK (Jacobian-based and optimization) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Numerical IK methods iteratively update joint values q to reduce pose error. +Jacobian-based updates use the task Jacobian J(q) to relate changes in joint +space to end-effector motion. + + +Multi-chain and closed-loop kinematics +------------------------------------- + +Solvers can handle serial chains, branched kinematic trees and some closed-loop +mechanisms. Closed-loop systems commonly require constraint solvers and may +embed loop-closure constraints in the solver as equality constraints. + + +Choosing a solver +----------------- + +- Use analytic solvers (OPW for 6-DOF arms or SRS for 7-DOF arms) when available for speed and + determinism. +- Use numerical solvers (PyTorch/optimization, Differential) when you need + flexibility.. + +See also +-------- + +.. toctree:: + :maxdepth: 1 + + pytorch_solver.md + differential_solver.md + pink_solver.md + pinocchio_solver.md + opw_solver.md + srs_solver.md diff --git a/docs/source/overview/sim/solvers/opw_solver.md b/docs/source/overview/sim/solvers/opw_solver.md new file mode 100644 index 00000000..f4dd1bf1 --- /dev/null +++ b/docs/source/overview/sim/solvers/opw_solver.md @@ -0,0 +1,111 @@ +# OPWSolver + +`OPWSolver` is a specialized inverse kinematics (IK) solver for 6-DOF industrial robots using the OPW kinematic parameterization. It provides fast, analytical solutions for robots with parallel and offset axes, supporting both CPU and GPU acceleration. The solver is suitable for large-scale batch IK tasks and real-time control. + +## Key Features + +* Analytical IK for OPW-parameterized 6-DOF manipulators +* Supports both parallel and offset axes, with custom axis flipping +* Fast batch computation for multiple target poses +* Configurable for CPU (py_opw_kinematics) and GPU (warp) backends +* Flexible configuration via `OPWSolverCfg` +* Strict enforcement of joint limits +* Forward kinematics (FK) and multiple IK solution branches + +## Configuration + +The solver is configured using the `OPWSolverCfg` class, which defines OPW parameters and solver options. + +```python +import torch +import numpy as np +from embodichain.data import get_data_path +from embodichain.lab.sim.solvers.opw_solver import OPWSolver, OPWSolverCfg + +cfg = OPWSolverCfg( + urdf_path=get_data_path("CobotMagicArm/CobotMagicNoGripper.urdf"), + joint_names=["joint1", "joint2", "joint3", "joint4", "joint5", "joint6"], + end_link_name="link6", + root_link_name="arm_base", + a1 = 0.0, + a2 = -21.984, + b = 0.0, + c1 = 123.0, + c2 = 285.03, + c3 = 250.75, + c4 = 91.0, + offsets = ( + 0.0, + 82.21350356417211 * np.pi / 180.0, + -167.21710113148163 * np.pi / 180.0, + 0.0, + 0.0, + 0.0, + ), + flip_axes = (False, False, False, False, False, False), + has_parallelogram = False, +) + +solver = OPWSolver(cfg, device="cuda") +``` + +## Main Methods + +* `get_fk(self, qpos: torch.Tensor) -> torch.Tensor` + Computes the end-effector pose (homogeneous transformation matrix) for the given joint positions. + + **Parameters:** + + `qpos` (`torch.Tensor` or `list[float]`): Joint positions, shape `(num_envs, num_joints)` or `(num_joints,)`. + + **Returns:** + + `torch.Tensor`: End-effector pose(s), shape `(num_envs, 4, 4)`. + + **Example:** + +```python + fk = solver.get_fk(qpos=[0.0, 0.0, 0.0, 1.5708, 0.0, 0.0]) + print(fk) + # Output: + # tensor([[[ 0.0, 0.087093, 0.996200, 0.056135], + # [-1.0, 0.0 , -0.0 , -0.0 ], + # [ 0.0, -0.996200, 0.087093, 0.213281], + # [ 0.0, 0.0 , 0.0 , 1.0 ]]], device=solver.device) +``` + +* `get_ik(self, target_xpos: torch.Tensor, qpos_seed: torch.Tensor = None, return_all_solutions: bool = False, jacobian: torch.Tensor = None) -> Tuple[torch.Tensor, torch.Tensor]` + Computes joint positions (inverse kinematics) for the given target end-effector pose. + + **Parameters:** + + `target_xpos` (`torch.Tensor`): Target end-effector pose(s), shape `(num_envs, 4, 4)`. + + `qpos_seed` (`torch.Tensor`, optional): Initial guess for joint positions, shape `(num_envs, num_joints)`. If `None`, a default is used. + + `return_all_solutions` (`bool`, optional): If `True`, returns all possible solutions. Default is `False`. + + `jacobian` (`torch.Tensor`, optional): Custom Jacobian. Usually not required. + + **Returns:** + + `Tuple[torch.Tensor, torch.Tensor]`: + - First element: Joint positions, shape `(num_envs, num_joints)`. + - Second element: Convergence info or error for each environment. + + **Example:** + +```python + import torch + xpos = torch.tensor([[[ 0.0, 0.087093, 0.996200, 0.056135], + [-1.0, 0.0 , -0.0 , -0.0 ], + [ 0.0, -0.996200, 0.087093, 0.213281], + [ 0.0, 0.0 , 0.0 , 1.0 ]]], device=solver.device) + + qpos_seed = torch.zeros((1, 6)) + qpos_sol, info = solver.get_ik(target_xpos=xpos) + print("IK solution:", qpos_sol) + print("Convergence info:", info) + # IK solution: tensor([1], device='cuda:0', dtype=torch.int32) + # Convergence info: tensor([[-3.141593, 0.793811, 0.0, 0.0, 2.522188, 1.570792]], device='cuda:0') + +``` + +## References + +* [OPW Kinematics Paper](https://doi.org/10.1109/TRO.2017.2776312) +* [py_opw_kinematics Documentation](https://github.com/UM-ARM-Lab/py_opw_kinematics) +* [warp Documentation](https://github.com/NVIDIA/warp) diff --git a/docs/source/overview/sim/solvers/pink_solver.md b/docs/source/overview/sim/solvers/pink_solver.md new file mode 100644 index 00000000..c7de6d61 --- /dev/null +++ b/docs/source/overview/sim/solvers/pink_solver.md @@ -0,0 +1,103 @@ +# PinkSolver + +`PinkSolver` is an advanced inverse kinematics (IK) solver for robot manipulators, built on [Pinocchio](https://github.com/stack-of-tasks/pinocchio) and [Pink](https://github.com/stephane-caron/pink). It supports flexible task definitions, robust optimization, and null space posture control. + +## Key Features + +- Supports both position-only and full pose (position + orientation) constraints +- Configurable convergence tolerance (`pos_eps`, `rot_eps`), damping, and iteration limits +- Handles joint limits and safety checks during optimization +- Allows variable and fixed task definitions for flexible control (see `FrameTask`, `NullSpacePostureTask`) +- Integrates with Pinocchio robot models and Pink task framework +- Supports multiple solver backends: `osqp`, `clarabel`, `ecos`, `proxqp`, `scs`, `daqp` +- Provides joint mapping between simulation and solver for flexible robot integration +- Null space posture task for redundancy resolution and secondary objectives +- Torch and numpy compatible for seamless integration in simulation pipelines + +## Configuration Example + +```python +from embodichain.data import get_data_path +from embodichain.lab.sim.solvers.pink_solver import PinkSolver +from embodichain.lab.sim.solvers.pink_solver import PinkSolverCfg + +cfg = PinkSolverCfg( + urdf_path=get_data_path("UniversalRobots/UR5/UR5.urdf"), + joint_names=["joint1", "joint2", "joint3", "joint4", "joint5", "joint6"], + end_link_name="ee_link", + root_link_name="base_link", + max_iterations=500, + pos_eps=1e-4, + rot_eps=1e-4, + dt=0.05, + damp=1e-10, + is_only_position_constraint=False, + fail_on_joint_limit_violation=True, + solver_type="osqp", + variable_input_tasks=None, + fixed_input_tasks=None, +) + +solver = PinkSolver(cfg) +``` + + +## Main Methods + +* `get_fk(self, qpos: torch.Tensor) -> torch.Tensor` + Computes the end-effector pose (homogeneous transformation matrix) for the given joint positions. + + **Parameters:** + + `qpos` (`torch.Tensor` or `list[float]`): Joint positions, shape `(num_envs, num_joints)` or `(num_joints,)`. + + **Returns:** + + `torch.Tensor`: End-effector pose(s), shape `(num_envs, 4, 4)`. + + **Example:** + +```python + fk = solver.get_fk(qpos=[0.0, 0.0, 0.0, 1.5708, 0.0, 0.0]) + print(fk) + # Output: + # tensor([[[ 0.0, -1.0, 0.0, -0.722600], + # [ 0.0, 0.0, -1.0, -0.191450], + # [ 1.0, 0.0, 0.0, 0.079159], + # [ 0.0, 0.0, 0.0, 1.0 ]]]) +``` + +* `get_ik(self, target_xpos: torch.Tensor, qpos_seed: torch.Tensor = None, return_all_solutions: bool = False, jacobian: torch.Tensor = None) -> Tuple[torch.Tensor, torch.Tensor]` + Computes joint positions (inverse kinematics) for the given target end-effector pose. + + **Parameters:** + + `target_xpos` (`torch.Tensor`): Target end-effector pose(s), shape `(num_envs, 4, 4)`. + + `qpos_seed` (`torch.Tensor`, optional): Initial guess for joint positions, shape `(num_envs, num_joints)`. If `None`, a default is used. + + `return_all_solutions` (`bool`, optional): If `True`, returns all possible solutions. Default is `False`. + + `jacobian` (`torch.Tensor`, optional): Custom Jacobian. Usually not required. + + **Returns:** + + `Tuple[torch.Tensor, torch.Tensor]`: + - First element: Joint positions, shape `(num_envs, num_joints)`. + - Second element: Convergence info or error for each environment. + + **Example:** + +```python + import torch + xpos = torch.tensor([[[ 0.0, -1.0, 0.0, -0.722600], + [ 0.0, 0.0, -1.0, -0.191450], + [ 1.0, 0.0, 0.0, 0.079159], + [ 0.0, 0.0, 0.0, 1.0 ]]]) + qpos_seed = torch.zeros((1, 6)) + qpos_sol, info = solver.get_ik(target_xpos=xpos) + print("IK solution:", qpos_sol) + print("Convergence info:", info) + # IK solution: tensor([True]) + # Convergence info: tensor([[0.0, -0.231429, 0.353367, 0.893100, 0.0, 0.555758]]) +``` + + +## References + +- [Pinocchio Library](https://github.com/stack-of-tasks/pinocchio) +- [Pink Library](https://github.com/stephane-caron/pink) +- [Null Space Posture Task](https://github.com/stephane-caron/pink#null-space-posture-task) diff --git a/docs/source/overview/sim/solvers/pinocchio_solver.md b/docs/source/overview/sim/solvers/pinocchio_solver.md new file mode 100644 index 00000000..fa2f0dec --- /dev/null +++ b/docs/source/overview/sim/solvers/pinocchio_solver.md @@ -0,0 +1,94 @@ +# PinocchioSolver + +The `PinocchioSolver` is a high-precision inverse kinematics (IK) solver for robot manipulators, leveraging [Pinocchio](https://github.com/stack-of-tasks/pinocchio) and [CasADi](https://web.casadi.org/) for symbolic and numerical optimization. It supports both position and orientation constraints, joint limits, and smoothness regularization for robust and realistic IK solutions. + +## Key Features + +* Supports both position-only and full pose constraints +* Configurable convergence tolerance, damping, and iteration limits +* Enforces joint limits during optimization +* Uses CasADi for symbolic cost and constraint definition +* Integrates with Pinocchio robot models for accurate kinematics +* Batch sampling for robust IK seed initialization + +## Configuration Example + +```python +from embodichain.data import get_data_path +from embodichain.lab.sim.solvers.pinocchio_solver import PinocchioSolver +from embodichain.lab.sim.solvers.pinocchio_solver import PinocchioSolverCfg + +cfg = PinocchioSolverCfg( + urdf_path=get_data_path("UniversalRobots/UR5/UR5.urdf"), + joint_names=["joint1", "joint2", "joint3", "joint4", "joint5", "joint6"], + end_link_name="ee_link", + root_link_name="base_link", + max_iterations=1000, + pos_eps=1e-4, + rot_eps=1e-4, + dt=0.05, + damp=1e-6, + num_samples=30, + is_only_position_constraint=False, +) + +solver = PinocchioSolver(cfg) +``` + +## Main Methods + +* `get_fk(self, qpos: torch.Tensor) -> torch.Tensor` + Computes the end-effector pose (homogeneous transformation matrix) for the given joint positions. + + **Parameters:** + + `qpos` (`torch.Tensor` or `list[float]`): Joint positions, shape `(num_envs, num_joints)` or `(num_joints,)`. + + **Returns:** + + `torch.Tensor`: End-effector pose(s), shape `(num_envs, 4, 4)`. + + **Example:** + +```python + fk = solver.get_fk(qpos=[0.0, 0.0, 0.0, 1.5708, 0.0, 0.0]) + print(fk) + # Output: + # tensor([[[ 0.0, -1.0, 0.0, -0.722600], + # [ 0.0, 0.0, -1.0, -0.191450], + # [ 1.0, 0.0, 0.0, 0.079159], + # [ 0.0, 0.0, 0.0, 1.0 ]]]) +``` + +* `get_ik(self, target_xpos: torch.Tensor, qpos_seed: torch.Tensor = None, return_all_solutions: bool = False, jacobian: torch.Tensor = None) -> Tuple[torch.Tensor, torch.Tensor]` + Computes joint positions (inverse kinematics) for the given target end-effector pose. + + **Parameters:** + + `target_xpos` (`torch.Tensor`): Target end-effector pose(s), shape `(num_envs, 4, 4)`. + + `qpos_seed` (`torch.Tensor`, optional): Initial guess for joint positions, shape `(num_envs, num_joints)`. If `None`, a default is used. + + `return_all_solutions` (`bool`, optional): If `True`, returns all possible solutions. Default is `False`. + + `jacobian` (`torch.Tensor`, optional): Custom Jacobian. Usually not required. + + **Returns:** + + `Tuple[torch.Tensor, torch.Tensor]`: + - First element: Joint positions, shape `(num_envs, num_joints)`. + - Second element: Convergence info or error for each environment. + + **Example:** + +```python + import torch + xpos = torch.tensor([[[ 0.0, -1.0, 0.0, -0.722600], + [ 0.0, 0.0, -1.0, -0.191450], + [ 1.0, 0.0, 0.0, 0.079159], + [ 0.0, 0.0, 0.0, 1.0 ]]]) + qpos_seed = torch.zeros((1, 6)) + qpos_sol, info = solver.get_ik(target_xpos=xpos) + print("IK solution:", qpos_sol) + print("Convergence info:", info) + # IK solution: tensor([True]) + # Convergence info: tensor([[0.0, -0.231429, 0.353367, 0.893100, 0.0, 0.555758]]) +``` + +## References + +* [Pinocchio Documentation](https://stack-of-tasks.github.io/pinocchio/) +* [CasADi Documentation](https://web.casadi.org/) diff --git a/docs/source/overview/sim/solvers/pytorch_solver.md b/docs/source/overview/sim/solvers/pytorch_solver.md new file mode 100644 index 00000000..7677a3cb --- /dev/null +++ b/docs/source/overview/sim/solvers/pytorch_solver.md @@ -0,0 +1,112 @@ +# PytorchSolver + +`PytorchSolver` is a high-performance inverse kinematics (IK) solver for robot manipulators, leveraging [pytorch_kinematics](https://github.com/UM-ARM-Lab/pytorch_kinematics) for efficient computation and seamless integration with PyTorch workflows. It supports both position and orientation constraints, joint limits, batch sampling, and GPU acceleration, making it suitable for real-time and large-scale applications. + +## Key Features + +* Full support for position-only or full pose (position + orientation) constraints +* Configurable convergence tolerance, damping, and iteration limits +* Enforces joint limits during optimization +* Batch sampling for robust IK seed initialization and solution diversity +* Efficient batched computation for multiple target poses +* PyTorch integration for GPU acceleration and tensor-based workflows +* Flexible configuration via `PytorchSolverCfg` class + +## Configuration + +The solver is configured using the `PytorchSolverCfg` class, which allows detailed control over solver parameters and robot model setup. + +```python +from embodichain.data import get_data_path +from embodichain.lab.sim.solvers.pytorch_solver import PytorchSolver +from embodichain.lab.sim.solvers.pytorch_solver import PytorchSolverCfg +import torch + +cfg = PytorchSolverCfg( + urdf_path=get_data_path("UniversalRobots/UR5/UR5.urdf"), + joint_names=["joint1", "joint2", "joint3", "joint4", "joint5", "joint6"], + end_link_name="ee_link", + root_link_name="base_link", + max_iterations=1000, + pos_eps=1e-4, + rot_eps=1e-4, + dt=0.05, + damp=1e-6, + num_samples=30, + is_only_position_constraint=False, +) + +solver = PytorchSolver(cfg) +``` + +### Dynamic Parameter Adjustment + +Solver parameters can be updated at runtime using `set_iteration_params` : + +```python +solver.set_iteration_params( + pos_eps=1e-5, + rot_eps=1e-5, + max_iterations=500, + num_samples=50, + damp=1e-7, +) +``` + +## Main Methods + +* `get_fk(self, qpos: torch.Tensor) -> torch.Tensor` + Computes the end-effector pose (homogeneous transformation matrix) for the given joint positions. + + **Parameters:** + + `qpos` (`torch.Tensor` or `list[float]`): Joint positions, shape `(num_envs, num_joints)` or `(num_joints,)`. + + **Returns:** + + `torch.Tensor`: End-effector pose(s), shape `(num_envs, 4, 4)`. + + **Example:** + +```python + fk = solver.get_fk(qpos=[0.0, 0.0, 0.0, 1.5708, 0.0, 0.0]) + print(fk) + # Output: + # tensor([[[ 0.0, -1.0, 0.0, -0.722600], + # [ 0.0, 0.0, -1.0, -0.191450], + # [ 1.0, 0.0, 0.0, 0.079159], + # [ 0.0, 0.0, 0.0, 1.0 ]]]) +``` + +* `get_ik(self, target_xpos: torch.Tensor, qpos_seed: torch.Tensor = None, return_all_solutions: bool = False, jacobian: torch.Tensor = None) -> Tuple[torch.Tensor, torch.Tensor]` + Computes joint positions (inverse kinematics) for the given target end-effector pose. + + **Parameters:** + + `target_xpos` (`torch.Tensor`): Target end-effector pose(s), shape `(num_envs, 4, 4)`. + + `qpos_seed` (`torch.Tensor`, optional): Initial guess for joint positions, shape `(num_envs, num_joints)`. If `None`, a default is used. + + `return_all_solutions` (`bool`, optional): If `True`, returns all possible solutions. Default is `False`. + + `jacobian` (`torch.Tensor`, optional): Custom Jacobian. Usually not required. + + **Returns:** + + `Tuple[torch.Tensor, torch.Tensor]`: + - First element: Joint positions, shape `(num_envs, num_joints)`. + - Second element: Convergence info or error for each environment. + + **Example:** + +```python + import torch + xpos = torch.tensor([[[ 0.0, -1.0, 0.0, -0.722600], + [ 0.0, 0.0, -1.0, -0.191450], + [ 1.0, 0.0, 0.0, 0.079159], + [ 0.0, 0.0, 0.0, 1.0 ]]]) + qpos_seed = torch.zeros((1, 6)) + qpos_sol, info = solver.get_ik(target_xpos=xpos) + print("IK solution:", qpos_sol) + print("Convergence info:", info) + # IK solution: tensor([True], device='cuda:0') + # Convergence info: tensor([[0.0, -0.244575, 0.373442, 0.853886, 0.0, 0.588007]], device='cuda:0') + +``` + +## References + +* [pytorch_kinematics Documentation](https://github.com/UM-ARM-Lab/pytorch_kinematics) diff --git a/docs/source/overview/sim/solvers/srs_solver.md b/docs/source/overview/sim/solvers/srs_solver.md new file mode 100644 index 00000000..3cabb57e --- /dev/null +++ b/docs/source/overview/sim/solvers/srs_solver.md @@ -0,0 +1,133 @@ +# SRSSolver + +`SRSSolver` is a high-performance inverse kinematics (IK) solver specifically designed for 7-DOF manipulators with a Spherical-Rotational-Spherical (S-R-S) joint structure. This architecture is common in anthropomorphic and redundant industrial arms, providing high dexterity and redundancy for advanced manipulation tasks. SRSSolver supports batch computation, joint limits, GPU acceleration, and seamless integration with PyTorch workflows. + +## What is S-R-S Kinematics? + +The S-R-S (Spherical-Rotational-Spherical) structure refers to a 7-joint manipulator arrangement: + +* **Spherical (S)**: A 3-DOF spherical joint (often realized by three intersecting revolute joints), enabling arbitrary orientation in 3D space. +* **Rotational (R)**: A single revolute joint, typically located at the "elbow, " providing an extra degree of freedom for redundancy. +* **Spherical (S)**: Another 3-DOF spherical joint at the wrist, allowing full orientation control of the end-effector. + +This structure enables: +* **Redundancy**: The arm can reach the same pose with multiple joint configurations, useful for obstacle avoidance and singularity avoidance. +* **High Dexterity**: Suitable for tasks requiring complex manipulation and orientation. +* **Wide Application**: Common in humanoid robots and collaborative arms. + +## Key Features + +* Optimized for S-R-S 7-DOF kinematic chains +* Supports position and orientation constraints, joint limits +* Batch sampling and multi-solution output for robust IK +* GPU acceleration for large-scale or real-time applications +* Flexible configuration for DH parameters, joint limits, link lengths, and more + +## Configuration + +SRSSolver is configured via the `SRSSolverCfg` class, allowing detailed control over kinematic parameters and solver behavior. + +```python +from embodichain.data import get_data_path +from embodichain.lab.sim.robots.dexforce_w1.types import ( + DexforceW1ArmSide, + DexforceW1ArmKind, + DexforceW1Version, +) +from embodichain.lab.sim.robots.dexforce_w1.params import ( + W1ArmKineParams, +) +from embodichain.lab.sim.solvers.srs_solver import SRSSolver, SRSSolverCfg + +arm_params = W1ArmKineParams( + arm_side=DexforceW1ArmSide.RIGHT, + arm_kind=DexforceW1ArmKind.ANTHROPOMORPHIC, + version=DexforceW1Version.V021, +) + +cfg = SRSSolverCfg( + urdf_path=get_data_path("DexforceW1V021/DexforceW1_v02_1.urdf"), + joint_names=[f"{'RIGHT'}_J{i+1}" for i in range(7)], + end_link_name="left_ee", + root_link_name="left_arm_base", + dh_params=arm_params.dh_params, + qpos_limits=arm_params.qpos_limits, + T_e_oe=arm_params.T_e_oe, + T_b_ob=arm_params.T_b_ob, + link_lengths=arm_params.link_lengths, + rotation_directions=arm_params.rotation_directions, +) + +solver = SRSSolver(cfg, num_envs=1, device="cuda") +``` + +## Main Methods + +* `get_fk(self, qpos: torch.Tensor) -> torch.Tensor` + Computes the end-effector pose (homogeneous transformation matrix) for the given joint positions. + + **Parameters:** + + `qpos` (`torch.Tensor` or `list[float]`): Joint positions, shape `(num_envs, num_joints)` or `(num_joints,)`. + + **Returns:** + + `torch.Tensor`: End-effector pose(s), shape `(num_envs, 4, 4)`. + + **Example:** + +```python + fk = solver.get_fk(qpos=[0.0, 0.0, 0.0, 1.5708, 0.0, 0.0, 0.0]) + print(fk) + # Output: + # tensor([[[ 0.0, -1.0, 0.0, 0.0], + # [ 0.0, 0.0, -1.0, -0.33], + # [ 1.0, 0.0, 0.0, 0.3625], + # [ 0.0, 0.0, 0.0, 1.0]]]) +``` + +* `get_ik(self, target_xpos: torch.Tensor, qpos_seed: torch.Tensor = None, return_all_solutions: bool = False, jacobian: torch.Tensor = None) -> Tuple[torch.Tensor, torch.Tensor]` + Computes joint positions (inverse kinematics) for the given target end-effector pose. + + **Parameters:** + + `target_xpos` (`torch.Tensor`): Target end-effector pose(s), shape `(num_envs, 4, 4)`. + + `qpos_seed` (`torch.Tensor`, optional): Initial guess for joint positions, shape `(num_envs, num_joints)`. If `None`, a default is used. + + `return_all_solutions` (`bool`, optional): If `True`, returns all possible solutions. Default is `False`. + + `jacobian` (`torch.Tensor`, optional): Custom Jacobian. Usually not required. + + **Returns:** + + `Tuple[torch.Tensor, torch.Tensor]`: + - First element: Joint positions, shape `(num_envs, num_joints)`. + - Second element: Convergence info or error for each environment. + + **Example:** + +```python + import torch + xpos = torch.tensor([[[ 0.0, -1.0, 0.0, -0.0], + [ 0.0, 0.0, -1.0, -0.33], + [ 1.0, 0.0, 0.0, 0.3625], + [ 0.0, 0.0, 0.0, 1.0]]]) + qpos_seed = torch.zeros((1, 7)) + qpos_sol, info = solver.get_ik(target_xpos=xpos) + print("IK solution:", qpos_sol) + print("Convergence info:", info) + # IK solution: tensor([True], device='cuda:0') + # Convergence info: tensor([[[-0.022269, 0.045214, -0.022273, -1.570796, 0.045204, -0.001007, 0.044519]]], device='cuda:0') +``` + +## References + +The following key references provide the theoretical foundation and algorithmic background for this implementation: + +* **Analytical Inverse Kinematic Computation for 7-DOF Redundant Manipulators With Joint Limits and Its Application to Redundancy Resolution** + Masayuki Shimizu, Hiromu Kakuya, Woo-Keun Yoon, Kosei Kitagaki, Kazuhiro Kosuge + *IEEE Transactions on Robotics*, 2008 + [DOI: 10.1109/TRO.2008.2003266](https://doi.org/10.1109/TRO.2008.2003266) + This paper presents an analytical approach for solving the inverse kinematics of 7-DOF redundant manipulators, including joint limit handling and redundancy resolution strategies. + +* **Position-based kinematics for 7-DoF serial manipulators with global configuration control, joint limit, and singularity avoidance** + Carlos Faria, Flora Ferreira, Wolfram Erlhagen, Sérgio Monteiro, Estela Bicho + *Mechanism and Machine Theory*, 2018 + [DOI: 10.1016/j.mechmachtheory.2017.10.025](https://doi.org/10.1016/j.mechmachtheory.2017.10.025) + This work introduces position-based kinematic algorithms for 7-DOF manipulators, focusing on global configuration control, joint limit enforcement, and singularity avoidance. + +These publications provide the mathematical models and solution strategies that underpin the SRSSolver's design and functionality. diff --git a/docs/source/overview/vla/index.rst b/docs/source/overview/vla/index.rst new file mode 100644 index 00000000..dc775db1 --- /dev/null +++ b/docs/source/overview/vla/index.rst @@ -0,0 +1,2 @@ +Vision-Language-Action Models +================== diff --git a/docs/source/quick_start/docs.md b/docs/source/quick_start/docs.md new file mode 100644 index 00000000..c62a3d71 --- /dev/null +++ b/docs/source/quick_start/docs.md @@ -0,0 +1,18 @@ +# Build Documentation + +## 1. Install the documentation dependencies + +```bash +pip install -r docs/requirements.txt +``` + +> If you have issue like `locale.Error: unsupported locale setting`, please enter `export LC_ALL=C.UTF-8; export LANG=C.UTF-8` before build the API. + +## 2. Build the HTML site + +```bash +cd docs +make html +``` + +Then you can preview the documentation in your browser at `docs/build/html/index.html`. diff --git a/docs/source/quick_start/install.md b/docs/source/quick_start/install.md new file mode 100644 index 00000000..8a365939 --- /dev/null +++ b/docs/source/quick_start/install.md @@ -0,0 +1,71 @@ +# Installation + +## System Requirements + +The following minimum system requirements are recommended to run EmbodiChain reliably. These are the tested configurations during development — other Linux distributions and versions may work but are not officially supported. + +- Operating System: Linux (x86_64) + - Recommended distributions: Ubuntu 20.04 LTS or Ubuntu 22.04 LTS + +- NVIDIA GPU and drivers: + - Hardware: NVIDIA GPU with compute capability 7.0 or higher (e.g., RTX 20 series, RTX 30 series, A100, etc.) + - NVIDIA driver: 535 or higher (recommended 570) + - CUDA Toolkit: any of 11.8 — 12.8 (we test primarily with 11.8 and 12.x) + +- Python: + - Supported Python versions: + - Python 3.9 + - Python 3.10 + - Use a virtual environment (venv, virtualenv, or conda) to isolate dependencies + +Notes: + +- Ensure your NVIDIA driver and CUDA toolkit versions are compatible with your chosen PyTorch wheel. +- We recommend installing PyTorch from the official PyTorch instructions for your CUDA version: https://pytorch.org/get-started/locally/ + +--- + +### Recommended: Install with Docker + +We strongly recommend using our pre-configured Docker environment, which contains all necessary dependencies. + +```bash +docker pull dexforce/embodichain:ubuntu22.04-cuda12.8 +``` + +--- + + +### Install EmbodiChain + +> **We strongly recommend using a virtual environment to avoid dependency conflicts.** + +Install `DexSim` manually: +```bash +# If you are using Python 3.10 +pip install http://pyp.open3dv.site:2345/packages/dexsim_engine-0.3.6-cp310-cp310-manylinux_2_31_x86_64.whl +``` + +> We are working on uploading DexSim to PyPI for easier installation. Please stay tuned! + + +Clone the EmbodiChain repository: +```bash +git clone https://github.com/DexForce/EmbodiChain.git +``` + +Install the project in development mode: + +```bash +pip install -e . +``` + + +### Verify Installation +To verify that EmbodiChain is installed correctly, run a simple demo script to create a simulation scene: + +```bash + python scripts/tutorials/sim/create_scene.py +``` +--- + diff --git a/docs/source/resources/roadmap.md b/docs/source/resources/roadmap.md new file mode 100644 index 00000000..89bf504a --- /dev/null +++ b/docs/source/resources/roadmap.md @@ -0,0 +1,25 @@ +# Roadmap + +Currently, EmbodiChain is under active development. Our plan for the feature roadmap is as follows: + +- Simulation: + - Rendering: + - Improve ray-tracing backend performance and fix some konwn issues. + - Add a high performance Hybrid rendering backend for better visual quality and speed trade-off. + - Support a more efficient real-time denoiser. + - Add a new rasterization backend for basic rendering tasks. + - Support 3DGS rendering mode (If we have enough bandwidth). + - Physics: + - Improve soft body simulation stability and add more examples and tasks. + - We are also exploring how to integrate [newton physics](https://github.com/newton-physics/newton) into EmbodiChain as an alternative physics backend. + - Sensors: + - Add contact and force sensors with examples. + - Kinematics Solvers: + - Improve the existing IK solver performance and stability (especially SRSSolver and OPWSolver). + - Motion Generation: + - Add more advanced motion generation methods and examples. + - Useful Tools: + - Add a robot workspace analysis tool for better visualization and sampling of robot accessible workspace. + - We are working on USD support for EmbodiChain to enable better scene creation and asset management. + +- Models and Training Workflows: diff --git a/docs/source/resources/robot/cobotmagic.md b/docs/source/resources/robot/cobotmagic.md new file mode 100644 index 00000000..ac7a959f --- /dev/null +++ b/docs/source/resources/robot/cobotmagic.md @@ -0,0 +1,112 @@ +# CobotMagic + +CobotMagic is a versatile dual-arm collaborative robot developed by AgileX Robotics. It is widely used in simulation, education, industry, and service scenarios. All examples in this document are based on the latest PourWater task environment. + +## Key Features + +- **Dual-arm parallel structure** supporting multiple layouts (standard, face-to-face, custom) +- **Configurable gripper models** (V70/V100) and material types (NORMAL/NEW_UV/NO_MATERIAL) +- **Flexible URDF assembly** and simulation parameter configuration +- **Compatible with SimulationManager**, supporting multi-arena parallel simulation +- **High degree of freedom**: 16 axes (dual arms + grippers, each gripper includes 1 mimic joint) +- **Customizable control groups** for flexible task decomposition and extension + +--- + +## Robot Parameters + +| Parameter | Description | +|-----------------------|------------------------------------------------------------------| +| Number of joints | 16 (dual arms + grippers, each gripper includes a mimic joint) | +| Gripper models | V70 / V100 | +| Layout types | NORMAL (standard) / FACE_TO_FACE / CUSTOM | +| Initial base height | 0.7775m (adjustable) | +| Mobile base support | **Not supported** in the current version (fixed base only) | + +> **Note:** The current version of CobotMagic does **not** support a mobile base. All examples and environments assume a fixed base configuration. + + +--- + +## Quick Initialization Example + +```python +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.robots import CobotMagicCfg + +config = SimulationManagerCfg(headless=False, sim_device="cpu") +sim = SimulationManager(config) +sim.build_multiple_arenas(2) # Supports parallel simulation in multiple arenas +sim.set_manual_update(False) + +robot = sim.add_robot(cfg=CobotMagicCfg().from_dict({})) +``` + +--- + +## Configuration Parameters + +### 1. Main Configuration Items + +- **uid**: Unique identifier for the robot, default is "CobotMagic" +- **urdf_cfg**: URDF configuration, supports multi-component assembly (e.g., dual arms) +- **control_parts**: Control groups for independent control of each arm and gripper +- **solver_cfg**: Inverse kinematics solver configuration, customizable end-effector and base +- **drive_pros**: Joint drive properties (stiffness, damping, max effort, etc.) +- **attrs**: Rigid body physical attributes (mass, friction, damping, etc.) + +### 2. Custom Usage Example + +```python +from embodichain.lab.sim.robots import CobotMagicCfg + +custom_cfg = { + "init_pos": [0.0, 0.0, 1.0], # Initial position + # Add more custom parameters as needed +} +cfg = CobotMagicCfg.from_dict(custom_cfg) +robot = sim.add_robot(cfg=cfg) +``` + +### 3. Control Group Example + +```python +control_parts = { + "left_arm": ["LEFT_JOINT1", ..., "LEFT_JOINT6"], + "left_eef": ["LEFT_JOINT7", "LEFT_JOINT8"], + "right_arm": ["RIGHT_JOINT1", ..., "RIGHT_JOINT6"], + "right_eef": ["RIGHT_JOINT7", "RIGHT_JOINT8"], +} +``` + +--- + +## Common Issues & Notes + +- **URDF Path**: Ensure the corresponding URDF files exist in the data path (e.g., `CobotMagicArm/CobotMagicWithGripperV100.urdf`). +- **Simulation Device**: Supports CPU/GPU simulation. Set `sim_device` according to your hardware. +- **Multi-arena Simulation**: Use `build_multiple_arenas(n)` to quickly create n parallel simulation environments. +- **Gripper Model Switching**: To switch gripper models, modify the URDF path in `urdf_cfg`. +- **Mobile Base**: Not supported in the current version; related parameters will be ignored. + +--- + +## References + +- [AgileX CobotMagic Product Page](https://global.agilex.ai/products/cobot-magic) +- Related URDF file path: `CobotMagicArm/` + - CobotMagicWithGripperV70.urdf + - CobotMagicWithGripperV100.urdf + - CobotMagicNoGripper.urdf +- [embodichain Simulation Platform Documentation](https://github.com/dexforce/embodichain) + +--- + +## References + +- [AgileX CobotMagic Product Page](https://global.agilex.ai/products/cobot-magic) +- Related URDF file paths (located in `CobotMagicArm/`): + - `CobotMagicWithGripperV70.urdf` + - `CobotMagicWithGripperV100.urdf` + - `CobotMagicNoGripper.urdf` +- [embodichain Simulation Platform Documentation](https://github.com/dexforce/embodichain) diff --git a/docs/source/resources/robot/dexforce_w1.md b/docs/source/resources/robot/dexforce_w1.md new file mode 100644 index 00000000..69c4860e --- /dev/null +++ b/docs/source/resources/robot/dexforce_w1.md @@ -0,0 +1,54 @@ +# Dexforce W1 + +Dexforce W1 is a versatile robot developed by DexForce Technology Co., Ltd., supporting both industrial and anthropomorphic arm types. It is suitable for various simulation and real-world application scenarios. + +## Key Features + +- Supports multiple arm types (industrial, anthropomorphic) +- Configurable left/right hand brand and version +- Flexible URDF assembly and simulation configuration +- Compatible with SimulationManager simulation environment + + +## Usage in Simulation Environment + +""" +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.robots.dexforce_w1.types import ( + DexforceW1HandBrand, DexforceW1ArmSide, DexforceW1ArmKind, DexforceW1Version +) +from embodichain.lab.sim.robots.dexforce_w1.utils import build_dexforce_w1_cfg + +config = SimulationManagerCfg(headless=False, sim_device="cpu") +sim = SimulationManager(config) +sim.build_multiple_arenas(4) +sim.set_manual_update(True) + +hand_types = { + DexforceW1ArmSide.LEFT: DexforceW1HandBrand.BRAINCO_HAND, + DexforceW1ArmSide.RIGHT: DexforceW1HandBrand.BRAINCO_HAND, +} +hand_versions = { + DexforceW1ArmSide.LEFT: DexforceW1Version.V021, + DexforceW1ArmSide.RIGHT: DexforceW1Version.V021, +} + +cfg = build_dexforce_w1_cfg( + arm_kind=DexforceW1ArmKind.ANTHROPOMORPHIC, + hand_types=hand_types, + hand_versions=hand_versions, +) + +robot = sim.add_robot(cfg=cfg) +print("DexforceW1 robot added to the simulation.") +``` + +## Type Descriptions + + +| Type | Options / Values | Description | +|-------------------------|-------------------------------------------------------|------------------------------------| +| `DexforceW1ArmKind` | `ANTHROPOMORPHIC`, `INDUSTRIAL` | Arm type | +| `DexforceW1HandBrand` | `BRAINCO_HAND`, `DH_PGC_GRIPPER`, `DH_PGC_GRIPPER_M` | Hand brand | +| `DexforceW1Version` | `V021` | Release version | +| `DexforceW1ArmSide` | `LEFT`, `RIGHT` | Left/right hand identifier | diff --git a/docs/source/resources/robot/index.rst b/docs/source/resources/robot/index.rst new file mode 100644 index 00000000..621c5294 --- /dev/null +++ b/docs/source/resources/robot/index.rst @@ -0,0 +1,9 @@ +Supported Robots +====================== + +.. toctree:: + :maxdepth: 1 + + Dexforce W1 + CobotMagic + \ No newline at end of file diff --git a/docs/source/resources/task/index.rst b/docs/source/resources/task/index.rst new file mode 100644 index 00000000..7a83855d --- /dev/null +++ b/docs/source/resources/task/index.rst @@ -0,0 +1,7 @@ +Supported Tasks +====================== + +.. toctree:: + :maxdepth: 1 + + Pour Water \ No newline at end of file diff --git a/docs/source/resources/task/pour_water.md b/docs/source/resources/task/pour_water.md new file mode 100644 index 00000000..a5be3b73 --- /dev/null +++ b/docs/source/resources/task/pour_water.md @@ -0,0 +1,3 @@ +# Pour Water + +Zhao Runyi is pouring water now, please do not disturb him... \ No newline at end of file diff --git a/docs/source/tutorial/basic_env.rst b/docs/source/tutorial/basic_env.rst new file mode 100644 index 00000000..a0b8fabf --- /dev/null +++ b/docs/source/tutorial/basic_env.rst @@ -0,0 +1,185 @@ + +.. _tutorial_create_basic_env: + +Creating a Basic Environment +============================ + +.. currentmodule:: embodichain.lab.gym + +This tutorial shows you how to create a simple robot learning environment using EmbodiChain's Gym interface. You'll learn how to inherit from the base environment class, set up robots and objects, define actions and observations, and run training scenarios. + +The Code +~~~~~~~~ + +The tutorial corresponds to the ``random_reach.py`` script in the ``scripts/tutorials/gym`` directory. + +.. dropdown:: Code for random_reach.py + :icon: code + + .. literalinclude:: ../../../scripts/tutorials/gym/random_reach.py + :language: python + :linenos: + + +The Code Explained +~~~~~~~~~~~~~~~~~~ + +This tutorial demonstrates how to create a custom RL environment by inheriting from :class:`envs.BaseEnv`. The environment implements a simple reach task where a robot arm tries to reach randomly positioned targets. + +Environment Registration +------------------------- + +First, we register the environment with the Gymnasium registry using the :func:`utils.registration.register_env` decorator: + +.. literalinclude:: ../../../scripts/tutorials/gym/random_reach.py + :language: python + :start-at: @register_env("RandomReach-v1", max_episode_steps=100, override=True) + :end-at: class RandomReachEnv(BaseEnv): + +The decorator parameters define: + +- **Environment ID**: ``"RandomReach-v1"`` - unique identifier for the environment +- **max_episode_steps**: Maximum steps per episode (100 in this case) +- **override**: Whether to override existing environment with same ID + +Environment Initialization +--------------------------- + +The ``__init__`` method configures the simulation environment and calls the parent constructor: + +.. literalinclude:: ../../../scripts/tutorials/gym/random_reach.py + :language: python + :lines: 25-46 + +Key configuration options include: + +- **num_envs**: Number of parallel environments to run +- **headless**: Whether to run without GUI (useful for training) +- **device**: Computation device ("cpu" or "cuda") + +Robot Setup +------------ + +The `_setup_robot` method loads and configures the robot for the environment: + +.. literalinclude:: ../../../scripts/tutorials/gym/random_reach.py + :language: python + :start-at: def _setup_robot(self, **kwargs) -> Robot: + :end-at: return robot + +This method demonstrates: + +1. **URDF Loading**: Using data module to access robot URDF files +2. **Robot Configuration**: Setting initial position and joint configuration +3. **Action Space Definition**: Creating action space based on joint limits + +The action space is automatically derived from the robot's joint limits, ensuring actions stay within valid ranges. + +Scene Preparation +----------------- + +The :meth:`_prepare_scene` method adds additional objects to the simulation environment: + +.. literalinclude:: ../../../scripts/tutorials/gym/random_reach.py + :language: python + :lines: 72-84 + +In this example, we add a kinematic cube that serves as a visual target. The cube is configured with: + +- **No collision**: ``enable_collision=False`` for visualization only +- **Kinematic body**: Can be moved programmatically without physics +- **Custom size**: Small 3cm cube for target visualization +- **initial position**: Initially placed at a fixed location + +State Updates +------------- + +The `_update_sim_state` method is called at each simulation step to update object states: + +.. literalinclude:: ../../../scripts/tutorials/gym/random_reach.py + :language: python + :start-at: def _update_sim_state(self, **kwargs) -> None: + :end-at: self.cube.set_local_pose(pose=pose) + +This method randomizes the cube's position. The pose is updated for all parallel environments simultaneously. + +Note that this method is called after perform action execution and simulation update but before observation collection. For more details, see :meth:`envs.BaseEnv.step`. + +Action Execution +---------------- + +The `_step_action` method applies actions to the robot: + +.. literalinclude:: ../../../scripts/tutorials/gym/random_reach.py + :language: python + :start-at: def _step_action(self, action: EnvAction) -> EnvAction: + :end-at: return action + +In this simple environment, actions directly set joint positions. More complex environments might: + +- Convert actions to joint torques or velocities +- Apply action filtering or scaling +- Implement inverse kinematics for end-effector control + +Observation Extension +--------------------- + +The default observations include the following keys: + +- `robot`: Robot proprioception data (joint positions, velocities, efforts) +- `sensor` (optional): Data from any sensors (e.g., cameras) + +The `_extend_obs` method allows you to add custom observations: + +.. literalinclude:: ../../../scripts/tutorials/gym/random_reach.py + :language: python + :start-at: def _extend_obs(self, obs: EnvObs, **kwargs) -> EnvObs: + :end-at: return obs + +While commented out in this example, you can add custom data like: + +- Object positions and orientations +- Distance calculations +- Custom sensor readings +- Task-specific state information + +The Code Execution +~~~~~~~~~~~~~~~~~~ + +To run the environment: + +.. code-block:: bash + + cd /path/to/embodichain + python scripts/tutorials/gym/random_reach.py + +You can customize the execution with command-line options: + +.. code-block:: bash + + # Run multiple parallel environments + python scripts/tutorials/gym/random_reach.py --num_envs 4 + + # Run with GPU acceleration + python scripts/tutorials/gym/random_reach.py --device cuda + + # Run in headless mode (no GUI) + python scripts/tutorials/gym/random_reach.py --headless + +The script demonstrates: + +1. **Environment Creation**: Using ``gym.make()`` with custom parameters +2. **Episode Loop**: Running multiple episodes with random actions +3. **Performance Monitoring**: Calculating frames per second (FPS) + +Key Features Demonstrated +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This tutorial showcases several important features of EmbodiChain environments: + +1. **Gymnasium Integration**: Full compatibility with the Gymnasium API +2. **Parallel Environments**: Running multiple environments simultaneously for efficient training +3. **Robot Integration**: Easy loading and control of robotic systems +4. **Custom Objects**: Adding and manipulating scene objects +5. **Flexible Actions**: Customizable action spaces and execution methods +6. **Extensible Observations**: Adding task-specific observation data diff --git a/docs/source/tutorial/create_scene.rst b/docs/source/tutorial/create_scene.rst new file mode 100644 index 00000000..4f8dd314 --- /dev/null +++ b/docs/source/tutorial/create_scene.rst @@ -0,0 +1,93 @@ +Creating a simulation scene +========================== + +.. currentmodule:: embodichain.lab.sim + +This tutorial shows how to create a basic simulation scene using SimulationManager. It covers the setup of the simulation context, adding rigid objects, and running the simulation loop. + +The Code +~~~~~~~~ + +The tutorial corresponds to the ``create_scene.py`` script in the ``scripts/tutorials/sim`` directory. + +.. dropdown:: Code for create_scene.py + :icon: code + + .. literalinclude:: ../../../scripts/tutorials/sim/create_scene.py + :language: python + :linenos: + + +The Code Explained +~~~~~~~~~~~~~~~~~~ + +Configuring the simulation +-------------------------- + +The first step is to configure the simulation environment. This is done using the :class:`SimulationManagerCfg` data class, which allows you to specify various parameters like window dimensions, headless mode, physics timestep, simulation device (CPU/GPU), and rendering options like ray tracing. + +Command-line arguments are parsed using ``argparse`` to allow for easy customization of the simulation from the terminal. + +.. literalinclude:: ../../../scripts/tutorials/sim/create_scene.py + :language: python + :start-at: # Parse command line arguments + :end-at: sim.build_multiple_arenas(args.num_envs, space=3.0) + +There are two kinds of physics mode in :class:`SimulationManager`: + +- `manual`: The physics updates only when the user calls the :meth:`SimulationManager.update` function. This mode is used for robot learning tasks where precise control over simulation steps is required. Enabled by setting :meth:`SimulationManager.set_manual_update` to True. +- `auto`: The physics updates in a standalone thread, which enable asynchronous rendering and physics stepping. This mode is suitable for visualizations and demos for digital twins applications. This is the default mode. + +If `num_envs` is greater than 1, :meth:`SimulationManager.build_multiple_arenas` should be used to create multiple simulation arenas. + +Adding objects to the scene +--------------------------- + +With the simulation context created, we can add objects. This tutorial demonstrates adding a dynamic rigid cube to the scene using the :meth:`SimulationManager.add_rigid_object` method. The object's properties, such as its shape, initial position, and physics attributes (mass, friction, restitution), are defined through a configuration object, :class:`cfg.RigidObjectCfg`. + +.. literalinclude:: ../../../scripts/tutorials/sim/create_scene.py + :language: python + :start-at: # Add objects to the scene + :end-at: init_pos=[0.0, 0.0, 1.0], + +Running the simulation +---------------------- + +The simulation is advanced through a loop in the ``run_simulation`` function. Before starting the loop, GPU physics is initialized if a CUDA device is used. + +Inside the loop, :meth:`SimulationManager.update` is called to step the physics simulation forward. The script also includes logic to calculate and print the Frames Per Second (FPS) to monitor performance. The simulation runs until it's manually stopped with ``Ctrl+C``. + +.. literalinclude:: ../../../scripts/tutorials/sim/create_scene.py + :language: python + :start-at: def run_simulation(sim: SimulationManager): + :end-at: last_step = step_count + +Exiting the simulation +---------------------- + +Upon exiting the simulation loop (e.g., by a ``KeyboardInterrupt``), it's important to clean up resources. The :meth:`SimulationManager.destroy` method is called in a ``finally`` block to ensure that the simulation is properly terminated and all allocated resources are released. + +.. literalinclude:: ../../../scripts/tutorials/sim/create_scene.py + :language: python + :start-at: except KeyboardInterrupt: + :end-at: sim.destroy() + + +The Code Execution +~~~~~~~~~~~~~~~~~~ + +To run the script and see the result, execute the following command: + +.. code-block:: bash + + python scripts/tutorials/sim/create_scene.py + +A window should appear showing a cube dropping onto a flat plane. To stop the simulation, you can either close the window or press ``Ctrl+C`` in the terminal. + +You can also pass arguments to customize the simulation. For example, to run in headless mode with `n` parallel environments using specified device: + +.. code-block:: bash + + python scripts/tutorials/sim/create_scene.py --headless --num_envs --device + +Now that we have a basic understanding of how to create a scene, let's move on to more advanced topics. diff --git a/docs/source/tutorial/create_softbody.rst b/docs/source/tutorial/create_softbody.rst new file mode 100644 index 00000000..cfaf85c8 --- /dev/null +++ b/docs/source/tutorial/create_softbody.rst @@ -0,0 +1,68 @@ +Creating a soft-body simulation +=============================== + +.. currentmodule:: embodichain.lab.sim + +This tutorial shows how to create a soft-body simulation using ``SimulationManager``. It covers the setup of the simulation context, adding a deformable mesh (soft object), and running the simulation loop. + +The Code +~~~~~~~~ + +The tutorial corresponds to the ``create_softbody.py`` script in the ``scripts/tutorials/sim`` directory. + +.. dropdown:: Code for create_softbody.py + :icon: code + + .. literalinclude:: ../../../scripts/tutorials/sim/create_softbody.py + :language: python + :linenos: + + +The Code Explained +~~~~~~~~~~~~~~~~~~ + +Configuring the simulation +-------------------------- + +The first step is to configure the simulation environment. This is done using the :class:`SimulationManagerCfg` data class, which allows you to specify parameters like window dimensions, headless mode, physics timestep, simulation device (CPU/GPU), and rendering options like ray tracing. Reminded that soft body simulation can only run on cuda deive. + + +.. literalinclude:: ../../../scripts/tutorials/sim/create_softbody.py + :language: python + :start-at: # Configure the simulation + :end-at: print("[INFO]: Scene setup complete!") + +If ``num_envs`` is greater than 1, :meth:`SimulationManager.build_multiple_arenas` should be used to create multiple simulation arenas. + +Adding a soft body to the scene +------------------------------- + +With the simulation context created, we can add a soft (deformable) object. This tutorial demonstrates adding a soft-body cow mesh to the scene using the :meth:`SimulationManager.add_soft_object` method. The object's geometry and physical parameters are defined through configuration objects: + +- :class:`cfg.MeshCfg` for the mesh shape (``cow.obj``) +- :class:`cfg.SoftbodyVoxelAttributesCfg` for voxelization and simulation mesh resolution +- :class:`cfg.SoftbodyPhysicalAttributesCfg` for material properties (Young's modulus, Poisson's ratio, density, frictions, solver iterations) + +.. literalinclude:: ../../../scripts/tutorials/sim/create_softbody.py + :language: python + :start-at: # add softbody to the scene + :end-at: print("[INFO]: Add soft object complete!") + +The Code Execution +~~~~~~~~~~~~~~~~~~ + +To run the script and see the result, execute the following command: + +.. code-block:: bash + + python scripts/tutorials/sim/create_softbody.py + +A window should appear showing a soft-body cow mesh falling onto a ground plane. To stop the simulation, you can either close the window or press ``Ctrl+C`` in the terminal. + +You can also pass arguments to customize the simulation. For example, to run in headless mode with ``n`` parallel environments using the specified device: + +.. code-block:: bash + + python scripts/tutorials/sim/create_softbody.py --headless --num_envs --device + +Now that we have a basic understanding of how to create a soft-body scene, let's move on to more advanced topics. diff --git a/docs/source/tutorial/gizmo.rst b/docs/source/tutorial/gizmo.rst new file mode 100644 index 00000000..b0d39b2c --- /dev/null +++ b/docs/source/tutorial/gizmo.rst @@ -0,0 +1,270 @@ +.. _tutorial_gizmo_robot: + +Interactive Robot Control with Gizmo +===================================== + +.. currentmodule:: embodichain.lab.sim + +This tutorial demonstrates how to use the Gizmo class for interactive robot manipulation in SimulationManager. You'll learn how to create a gizmo attached to a robot's end-effector and use it for real-time inverse kinematics (IK) control, allowing intuitive manipulation of robot poses through visual interaction. + +The Code +~~~~~~~~ + +The tutorial corresponds to the ``gizmo_robot.py`` script in the ``scripts/tutorials/sim`` directory. + +.. dropdown:: Code for gizmo_robot.py + :icon: code + + .. literalinclude:: ../../../scripts/tutorials/sim/gizmo_robot.py + :language: python + :linenos: + + +The Code Explained +~~~~~~~~~~~~~~~~~~ + + +Similar to the previous tutorial on robot simulation, we use the :class:`SimulationManager` class to set up the simulation environment. If you haven't read that tutorial yet, please refer to :doc:`robot` first. + + + +**Important:** Gizmo only supports single environment mode (`num_envs=1`). Using multiple environments will raise an exception. + +All gizmo creation, visibility, and destruction operations must be managed via the SimulationManager API: + +.. code-block:: python + + # Toggle visibility for a gizmo + sim.toggle_gizmo_visibility("ur10_gizmo_test", control_part="arm") + + # Set visibility explicitly + sim.set_gizmo_visibility("ur10_gizmo_test", visible=False, control_part="arm") + +Always use the SimulationManager API to control gizmo visibility and lifecycle. Do not operate on the Gizmo instance directly. + +What is a Gizmo? +----------------- + +A Gizmo is an interactive visual tool that allows users to manipulate simulation objects in real-time through mouse interactions. In robotics applications, gizmos are particularly useful for: + +- **Interactive Robot Control**: Drag the robot's end-effector to desired positions +- **Inverse Kinematics**: Automatically solve joint angles to reach target poses +- **Real-time Manipulation**: Provide immediate visual feedback during robot motion planning +- **Debugging and Visualization**: Test robot reachability and workspace limits + +The :class:`objects.Gizmo` class provides a unified interface for interactive control of different simulation elements including robots, rigid objects, and cameras. + +Setting up Robot Configuration +------------------------------ + +First, we configure a UR10 robot with an IK solver for end-effector control: + +.. literalinclude:: ../../../scripts/tutorials/sim/gizmo_robot.py + :language: python + :start-at: # Create UR10 robot configuration + :end-at: robot = sim.add_robot(cfg=robot_cfg) + +Key components of the robot configuration: + +- **URDF Configuration**: Loads the robot's kinematic and visual model +- **Control Parts**: Defines which joints can be controlled (``"Joint[1-6]"`` for UR10) +- **IK Solver**: :class:`solvers.PinkSolverCfg` provides inverse kinematics capabilities +- **Drive Properties**: Sets stiffness and damping for joint control + +The IK solver is crucial for gizmo functionality, as it enables the robot to automatically calculate joint angles needed to reach gizmo target positions. + +Creating and Attaching a Gizmo +------------------------------- + + + +After configuring the robot, enable the gizmo for interactive control using the SimulationManager API (supports robot, rigid object, camera; key is `uid:control_part`): + +.. code-block:: python + + # Enable gizmo for the robot's arm + sim.enable_gizmo(uid="ur10_gizmo_test", control_part="arm") + if not sim.has_gizmo("ur10_gizmo_test", control_part="arm"): + logger.log_error("Failed to enable gizmo!") + return + + + +The Gizmo instance is managed internally by SimulationManager. If you need to access it: + +.. code-block:: python + + gizmo = sim.get_gizmo("ur10_gizmo_test", control_part="arm") + + + +The Gizmo system will automatically: + +1. **Detect Target Type**: Identify that the target is a robot (vs. rigid object or camera) +2. **Find End-Effector**: Locate the robot's end-effector link (``ee_link`` for UR10) +3. **Create Proxy Object**: Generate a small invisible cube at the end-effector position +4. **Set Up IK Callback**: Configure the gizmo to trigger IK solving when moved + +How Gizmo-Robot Interaction Works +---------------------------------- + + + +The gizmo-robot interaction follows this efficient workflow: + +1. **Gizmo Callback**: When the user drags the gizmo, a callback function updates the proxy object's transform +2. **Deferred IK Solving**: Instead of solving IK immediately in the callback (which causes UI lag), the target transform is stored +3. **Update Loop**: During each simulation step, ``gizmo.update()`` solves IK and applies joint commands +4. **Robot Motion**: The robot smoothly moves to follow the gizmo position + +This design separates UI responsiveness from computational IK solving, ensuring smooth interaction even with complex robots. + +The Simulation Loop +------------------- + + + +In the main loop, simply call `sim.update_gizmos()`. There is no need to manually update any Gizmo instance. + + + +.. code-block:: python + + def run_simulation(sim: SimulationManager): + step_count = 0 + try: + last_time = time.time() + last_step = 0 + while True: + time.sleep(0.033) # 30Hz + sim.update_gizmos() # Update all gizmos + step_count += 1 + # ...performance statistics, etc... + except KeyboardInterrupt: + logger.log_info("\nStopping simulation...") + finally: + sim.destroy() # Release all resources + logger.log_info("Simulation terminated successfully") + + + +Main loop highlights: + +- **Gizmo update**: Only `sim.update_gizmos()` is needed, no `gizmo.update()` +- **Performance monitoring**: Optional FPS statistics +- **Resource cleanup**: Only `sim.destroy()` is needed, no manual Gizmo destruction +- **Graceful shutdown**: Supports Ctrl+C interruption + +Gizmo Lifecycle Management +-------------------------- + + + + +Gizmo lifecycle is managed by SimulationManager: + +- Enable: `sim.enable_gizmo(...)` +- Update: Main loop automatically calls `sim.update_gizmos()` +- Destroy/disable: `sim.disable_gizmo(...)` or `sim.destroy()` (recommended) + +There is no need to manually create or destroy Gizmo instances. All resources are managed by SimulationManager. + +Available Gizmo Methods +----------------------- + + + + +If you need to access the underlying Gizmo instance (via `sim.get_gizmo`), you can use the following methods: + +**Transform Control:** + +- ``set_world_pose(pose)``: Set gizmo world position and orientation +- ``get_world_pose()``: Get current gizmo world transform +- ``set_local_pose(pose)``: Set gizmo local transform relative to parent +- ``get_local_pose()``: Get gizmo local transform + + + +**Visual properties (strongly recommend using SimulationManager API):** + +- ``sim.toggle_gizmo_visibility(uid, control_part=None)``: Toggle gizmo visibility +- ``sim.set_gizmo_visibility(uid, visible, control_part=None)``: Set gizmo visibility + +**Hierarchy Management:** + +- ``get_parent()``: Get gizmo's parent node in scene hierarchy +- ``get_name()``: Get gizmo node name for debugging +- ``detach()``: Disconnect gizmo from current target +- ``attach(target)``: Attach gizmo to a new simulation object + +Running the Tutorial +-------------------- + +To run the gizmo robot tutorial: + +.. code-block:: bash + + cd scripts/tutorials/sim + python gizmo_robot.py --device cpu + +Command-line options: + +- ``--device cpu|cuda``: Choose simulation device +- ``--num_envs N``: Number of parallel environments +- ``--headless``: Run without GUI for automated testing +- ``--enable_rt``: Enable ray tracing for better visuals + +Once running: + +1. **Mouse Interaction**: Click and drag the gizmo (colorful axes) to move the robot +2. **Real-time IK**: Watch the robot joints automatically adjust to follow the gizmo +3. **Workspace Limits**: Observe how the robot behaves at workspace boundaries +4. **Performance**: Monitor FPS in the console output + +Tips and Best Practices +------------------------ + + + +**Performance optimization:** + +- Only call ``sim.update_gizmos()`` in the main loop, no need for ``gizmo.update()`` +- Reduce IK solver iterations for better real-time performance if needed +- Use ``set_manual_update(False)`` for smoother interaction + + + +**Debugging tips:** + +- Check console output for IK solver success/failure messages +- Use ``get_world_pose()`` to check gizmo position (if needed) +- Monitor FPS to identify performance bottlenecks + + + +**Robot compatibility:** + +- Ensure your robot is configured with a correct IK solver +- Check the end-effector (EE) link name +- Test joint limits and workspace boundaries + + + +**Visualization customization:** + +- Adjust gizmo appearance via Gizmo config (e.g., ``set_line_width()``; requires access to the instance via `sim.get_gizmo`) +- Adjust gizmo scale according to robot size +- Enable collision for debugging if needed + +Next Steps +---------- + +After mastering basic gizmo usage, you can explore: + +- **Multi-robot Gizmos**: Attach gizmos to multiple robots simultaneously +- **Custom Gizmo Callbacks**: Implement application-specific interaction logic +- **Gizmo with Rigid Objects**: Use gizmos for interactive object manipulation +- **Advanced IK Configuration**: Fine-tune solver parameters for specific robots + +For more advanced robot control and simulation features, refer to the complete :doc:`robot` tutorial and the API documentation for :class:`objects.Gizmo` and :class:`solvers.PinkSolverCfg`. diff --git a/docs/source/tutorial/index.rst b/docs/source/tutorial/index.rst new file mode 100644 index 00000000..11eaf5d7 --- /dev/null +++ b/docs/source/tutorial/index.rst @@ -0,0 +1,19 @@ +Tutorials +========= + +.. toctree:: + :maxdepth: 1 + :hidden: + + create_scene + create_softbody + rigid_object_group + robot + solver + sensor + motion_gen + gizmo + basic_env + modular_env + rl + diff --git a/docs/source/tutorial/modular_env.rst b/docs/source/tutorial/modular_env.rst new file mode 100644 index 00000000..53175e97 --- /dev/null +++ b/docs/source/tutorial/modular_env.rst @@ -0,0 +1,237 @@ +.. _tutorial_modular_env: + +Creating a Modular Environment +============================== + +.. currentmodule:: embodichain.lab.gym + +This tutorial demonstrates how to create sophisticated robotic environments using EmbodiChain's modular architecture. You'll learn how to use the advanced :class:`envs.EmbodiedEnv` class with configuration-driven setup, event managers, observation managers, and randomization systems. + +The Code +~~~~~~~~ + +The tutorial corresponds to the ``modular_env.py`` script in the ``scripts/tutorials/gym`` directory. + +.. dropdown:: Code for modular_env.py + :icon: code + + .. literalinclude:: ../../../scripts/tutorials/gym/modular_env.py + :language: python + :linenos: + + +The Code Explained +~~~~~~~~~~~~~~~~~~ + +This tutorial showcases EmbodiChain's most powerful environment creation approach using the :class:`envs.EmbodiedEnv` class. Unlike the basic environment tutorial, this approach uses declarative configuration classes and manager systems for maximum flexibility and reusability. + +Event Configuration +------------------- + +Events define automated behaviors that occur during simulation. There are three types of supported modes: + +- `startup`: triggers once when the environment is initialized +- `reset`: triggers every time the environment is reset +- `interval`: triggers at fixed step intervals during simulation + +The :class:`ExampleEventCfg` demonstrates three types of events: + +.. literalinclude:: ../../../scripts/tutorials/gym/modular_env.py + :language: python + :lines: 36-76 + +**Asset Replacement Event** + +The ``replace_obj`` event demonstrates dynamic asset swapping: + +- **Function**: :func:`envs.managers.events.replace_assets_from_group` +- **Mode**: ``"reset"`` - triggers at environment reset +- **Purpose**: Randomly selects different fork models from a folder + +**Light Randomization Event** + +The ``randomize_light`` event creates dynamic lighting conditions: + +- **Function**: :func:`envs.managers.randomization.rendering.randomize_light` +- **Mode**: ``"interval"`` - triggers every 5 steps +- **Parameters**: Randomizes position, color, and intensity within specified ranges + +**Material Randomization Event** + +The ``randomize_table_mat`` event varies visual appearance: + +- **Function**: :func:`envs.managers.randomization.rendering.randomize_visual_material` +- **Mode**: ``"interval"`` - triggers every 10 steps +- **Features**: Random textures from COCO dataset and base color variations + +for more randomization events, please refer + +Observation Configuration +------------------------- + +The default observation from :class:`envs.EmbodiedEnv` includes: +- `robot`: robot proprioceptive data (joint positions, velocities, efforts) +- `sensor`: all available sensor data (images, depth, segmentation, etc.) + +However, users always need to define some custom observation for specified learning tasks. To handle this, the observation manager system allows users to declaratively specify additional observations. + +.. literalinclude:: ../../../scripts/tutorials/gym/modular_env.py + :language: python + :lines: 79-87 + +This configuration: + +- **Function**: :func:`envs.managers.observations.get_rigid_object_pose` +- **Mode**: ``"add"`` - appends data to observation dictionary +- **Name**: Custom key for the observation data +- **Target**: Tracks the fork object's pose in the scene + +For details documentation, see :class:`envs.managers.cfg.ObservationCfg`. + +Environment Configuration +------------------------- + +The main environment configuration inherits from :class:`envs.EmbodiedEnvCfg` and defines all scene components: + +**Robot Configuration** + +.. currentmodule:: embodichain.lab.sim.robots + +.. literalinclude:: ../../../scripts/tutorials/gym/modular_env.py + :language: python + :start-at: robot: RobotCfg = DexforceW1Cfg.from_dict( + :end-at: ) + +Uses the pre-configured :class:`DexforceW1Cfg` with customizations: + +- **Version**: Specific robot variant (v021) +- **Arm Type**: Anthropomorphic configuration +- **Position**: Initial placement in the scene + +**Sensor Configuration** + +.. literalinclude:: ../../../scripts/tutorials/gym/modular_env.py + :language: python + :lines: 104-118 + +.. currentmodule:: embodichain.lab.sim.sensors + +Configures a stereo camera system using :class:`StereoCameraCfg`: + +- **Resolution**: 960x540 pixels for realistic visual input +- **Features**: Depth sensing and segmentation masks enabled +- **Stereo Setup**: 6cm baseline between left and right cameras +- **Mounting**: Attached to robot's "eyes" frame + +**Lighting Configuration** + +.. literalinclude:: ../../../scripts/tutorials/gym/modular_env.py + :language: python + :lines: 120-130 + +Defines scene illumination with controllable point lights: + +- **Type**: Point light for realistic shadows +- **Properties**: Configurable color, intensity, and position +- **UID**: Named reference for event system manipulation + +**Rigid Objects** + +.. literalinclude:: ../../../scripts/tutorials/gym/modular_env.py + :language: python + :lines: 132-157 + +Multiple objects demonstrate different physics properties: + +*Table Configuration:* + +- **Shape**: Custom PLY mesh with UV mapping +- **Physics**: Kinematic body (movable but not affected by forces) +- **Material**: Friction and restitution properties for realistic contact + +*Fork Configuration:* + +- **Shape**: Detailed mesh from asset library +- **Scale**: Proportionally scaled for scene consistency +- **Physics**: Dynamic body affected by gravity and collisions + +**Articulated Objects** + +.. literalinclude:: ../../../scripts/tutorials/gym/modular_env.py + :language: python + :lines: 159-169 + +Demonstrates complex mechanisms with moving parts: + +- **URDF**: Sliding drawer with joints and constraints +- **Positioning**: Placed on table surface for interaction + +Environment Implementation +-------------------------- + +The actual environment class is remarkably simple due to the configuration-driven approach: + +.. literalinclude:: ../../../scripts/tutorials/gym/modular_env.py + :language: python + :start-at: @register_env("ModularEnv-v1", max_episode_steps=100, override=True) + :end-at: super().__init__(cfg, **kwargs) + +The :class:`envs.EmbodiedEnv` base class automatically: + +- Loads all configured scene components +- Sets up observation and action spaces +- Initializes event and observation managers +- Handles environment lifecycle (reset, step, etc.) + +The Code Execution +~~~~~~~~~~~~~~~~~~ + +To run the modular environment: + +.. code-block:: bash + + cd /path/to/embodichain + python scripts/tutorials/gym/modular_env.py + +The script demonstrates the complete workflow: + +1. **Configuration**: Creates an instance of ``ExampleCfg`` +2. **Registration**: Uses the registered environment ID +3. **Execution**: Runs episodes with zero actions to observe automatic behaviors + + +Manager System Benefits +~~~~~~~~~~~~~~~~~~~~~~~ + +The manager-based architecture provides several key advantages: + +**Event Managers** + +- **Modularity**: Reusable event functions across environments +- **Timing Control**: Flexible scheduling (reset, interval, condition-based) +- **Parameter Binding**: Type-safe configuration with validation +- **Extensibility**: Easy to add custom event behaviors + +**Observation Managers** + +- **Flexible Data**: Any simulation data can become an observation +- **Processing Pipeline**: Built-in normalization and transformation +- **Dynamic Composition**: Runtime observation space modification +- **Performance**: Efficient data collection and GPU acceleration + + +Key Features Demonstrated +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This tutorial showcases the most advanced features of EmbodiChain environments: + +1. **Configuration-Driven Design**: Declarative environment specification +2. **Manager Systems**: Modular event and observation handling +3. **Asset Management**: Dynamic loading and randomization +4. **Sensor Integration**: Realistic camera systems with stereo vision +5. **Physics Simulation**: Complex articulated and rigid body dynamics +6. **Visual Randomization**: Automated domain randomization +7. **Extensible Architecture**: Easy customization and extension points + + +This tutorial demonstrates the full power of EmbodiChain's modular environment system, providing the foundation for creating sophisticated robotic learning scenarios. diff --git a/docs/source/tutorial/motion_gen.rst b/docs/source/tutorial/motion_gen.rst new file mode 100644 index 00000000..712a314a --- /dev/null +++ b/docs/source/tutorial/motion_gen.rst @@ -0,0 +1,134 @@ + +.. _tutorial_motion_generator: + +Motion Generator +================ + +.. currentmodule:: embodichain.lab.sim.planners.motion_generator + +Overview +~~~~~~~~ + +The ``MotionGenerator`` class in EmbodiChain provides a unified and extensible interface for robot trajectory planning. It supports time-optimal trajectory generation (currently via TOPPRA), joint/Cartesian interpolation, and is designed for easy integration with RL, imitation learning, and classical control scenarios. + +Key Features +------------ + +- **Unified API**: One interface for multiple planning strategies (time-optimal, interpolation, etc.) +- **Constraint Support**: Velocity/acceleration constraints configurable per joint +- **Flexible Input**: Supports both joint space and Cartesian space waypoints +- **Extensible**: Easy to add new planners (RRT, PRM, etc.) +- **Integration Ready**: Can be used in RL, imitation learning, or classical pipelines + +Typical Usage +~~~~~~~~~~~~~ + +.. code-block:: python + + from embodichain.lab.sim.planners.motion_generator import MotionGenerator + + # Assume you have a robot instance and uid + motion_gen = MotionGenerator( + robot=robot, + uid="arm", + default_velocity=0.2, + default_acceleration=0.5 + ) + + # Plan a joint-space trajectory + current_state = {"position": [0, 0, 0, 0, 0, 0]} + target_states = [{"position": [0.5, 0.2, 0, 0, 0, 0]}] + success, positions, velocities, accelerations, times, duration = motion_gen.plan( + current_state=current_state, + target_states=target_states + ) + + # Generate a discrete trajectory (joint or Cartesian) + qpos_list, xpos_list = motion_gen.create_discrete_trajectory( + qpos_list=[[0,0,0,0,0,0],[0.5,0.2,0,0,0,0]], + sample_num=20 + ) + +API Reference +~~~~~~~~~~~~~ + +**Initialization** + +.. code-block:: python + + MotionGenerator( + robot: Robot, + uid: str, + sim=None, + planner_type="toppra", + default_velocity=0.2, + default_acceleration=0.5, + collision_margin=0.01, + **kwargs + ) + +- ``robot``: Robot instance, must support get_joint_ids, compute_fk, compute_ik +- ``uid``: Unique robot identifier (e.g., "arm") +- ``planner_type``: Planner type (default: "toppra") +- ``default_velocity``, ``default_acceleration``: Default joint constraints + +**plan** + +.. code-block:: python + + plan( + current_state: Dict, + target_states: List[Dict], + sample_method=TrajectorySampleMethod.TIME, + sample_interval=0.01, + **kwargs + ) -> Tuple[bool, positions, velocities, accelerations, times, duration] + +- Plans a time-optimal trajectory (joint space), returns trajectory arrays and duration. + +**create_discrete_trajectory** + +.. code-block:: python + + create_discrete_trajectory( + xpos_list=None, + qpos_list=None, + is_use_current_qpos=True, + is_linear=False, + sample_method=TrajectorySampleMethod.QUANTITY, + sample_num=20, + qpos_seed=None, + **kwargs + ) -> Tuple[List[np.ndarray], List[np.ndarray]] + +- Generates a discrete trajectory between waypoints (joint or Cartesian), auto-handles FK/IK. + +**estimate_trajectory_sample_count** + +.. code-block:: python + + estimate_trajectory_sample_count( + xpos_list=None, + qpos_list=None, + step_size=0.01, + angle_step=np.pi/90, + **kwargs + ) -> int + +- Estimates the number of samples needed for a trajectory. + +**plan_with_collision** + +.. code-block:: python + + plan_with_collision(...) + +- (Reserved) Plan trajectory with collision checking (not yet implemented). + +Notes & Best Practices +~~~~~~~~~~~~~~~~~~~~~ + +- Only collision-free planning is currently supported; collision checking is a placeholder. +- Input/outputs are numpy arrays or torch tensors; ensure type consistency. +- Robot instance must implement get_joint_ids, compute_fk, compute_ik, get_proprioception, etc. +- For custom planners, extend the PlannerType Enum and _create_planner methods. diff --git a/docs/source/tutorial/rigid_object_group.rst b/docs/source/tutorial/rigid_object_group.rst new file mode 100644 index 00000000..4ed5a3a1 --- /dev/null +++ b/docs/source/tutorial/rigid_object_group.rst @@ -0,0 +1,52 @@ +Rigid object group tutorial +========================== + +.. currentmodule:: embodichain.lab.sim + +This tutorial shows how to create and use a `RigidObjectGroup` in SimulationManager. +It follows the style used in the `create_scene` tutorial and references the +example script located in ``scripts/tutorials/sim/create_rigid_object_group.py``. + +The Code +~~~~~~~~ + +The tutorial corresponds to the ``create_rigid_object_group.py`` script in the +``scripts/tutorials/sim`` directory. + +.. dropdown:: Code for create_rigid_object_group.py + :icon: code + + .. literalinclude:: ../../../scripts/tutorials/sim/create_rigid_object_group.py + :language: python + :linenos: + + +The Code Explained +~~~~~~~~~~~~~~~~~~ + + +Adding a RigidObjectGroup +------------------------- + +The key part of the tutorial demonstrates creating a ``RigidObjectGroup`` via +``sim.add_rigid_object_group``. The group is configured with a mapping of +object UIDs to ``RigidObjectCfg`` entries. Each entry defines a shape +(here ``CubeCfg``), physics attributes, and initial pose. + +.. literalinclude:: ../../../scripts/tutorials/sim/create_rigid_object_group.py + :language: python + :start-at: obj_group: RigidObjectGroup = sim.add_rigid_object_group( + :end-at: print("[INFO]: Scene setup complete!") + + +Running the tutorial +~~~~~~~~~~~~~~~~~~~~ + +To run the script from the repository root: + +.. code-block:: bash + + python scripts/tutorials/sim/create_rigid_object_group.py + +You can pass flags such as ``--headless``, ``--num_envs ``, and +``--device `` to customize the run. diff --git a/docs/source/tutorial/rl.rst b/docs/source/tutorial/rl.rst new file mode 100644 index 00000000..d3c18883 --- /dev/null +++ b/docs/source/tutorial/rl.rst @@ -0,0 +1,365 @@ +.. _tutorial_rl: + +Reinforcement Learning Training +================================ + +.. currentmodule:: embodichain.agents.rl + +This tutorial shows you how to train reinforcement learning agents using EmbodiChain's RL framework. You'll learn how to configure training via JSON, set up environments, policies, and algorithms, and launch training sessions. + +Overview +~~~~~~~~ + +The RL framework provides a modular, extensible stack for robotics tasks: + +- **Trainer**: Orchestrates the training loop (calls algorithm for data collection and updates, handles logging/eval/save) +- **Algorithm**: Controls data collection process (interacts with environment, fills buffer, computes advantages/returns) and updates the policy (e.g., PPO) +- **Policy**: Neural network models implementing a unified interface (get_action/get_value/evaluate_actions) +- **Buffer**: On-policy rollout storage and minibatch iterator (managed by algorithm) +- **Env Factory**: Build environments from a JSON config via registry + +Architecture +~~~~~~~~~~~~ + +The framework follows a clean separation of concerns: + +- **Trainer**: Orchestrates the training loop (calls algorithm for data collection and updates, handles logging/eval/save) +- **Algorithm**: Controls data collection process (interacts with environment, fills buffer, computes advantages/returns) and updates the policy (e.g., PPO) +- **Policy**: Neural network models implementing a unified interface +- **Buffer**: On-policy rollout storage and minibatch iterator (managed by algorithm) +- **Env Factory**: Build environments from a JSON config via registry + +The core components and their relationships: + +- Trainer → Policy, Env, Algorithm (via callbacks for statistics) +- Algorithm → Policy, RolloutBuffer (algorithm manages its own buffer) + +Configuration via JSON +~~~~~~~~~~~~~~~~~~~~~~ + +Training is configured via a JSON file that defines runtime settings, environment, policy, and algorithm parameters. + +Example Configuration +--------------------- + +The configuration file (e.g., ``train_config.json``) is located in ``configs/agents/rl/push_cube``: + +.. dropdown:: Example: train_config.json + :icon: code + + .. literalinclude:: ../../../configs/agents/rl/push_cube/train_config.json + :language: json + :linenos: + +Configuration Sections +--------------------- + +Runtime Settings +^^^^^^^^^^^^^^^^ + +The ``runtime`` section controls experiment setup: + +- **exp_name**: Experiment name (used for output directories) +- **seed**: Random seed for reproducibility +- **cuda**: Whether to use GPU (default: true) +- **headless**: Whether to run simulation in headless mode +- **iterations**: Number of training iterations +- **rollout_steps**: Steps per rollout (e.g., 1024) +- **eval_freq**: Frequency of evaluation (in steps) +- **save_freq**: Frequency of checkpoint saving (in steps) +- **use_wandb**: Whether to enable Weights & Biases logging (set in JSON config) +- **wandb_project_name**: Weights & Biases project name + +Environment Configuration +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``env`` section defines the task environment: + +- **id**: Environment registry ID (e.g., "PushCubeRL") +- **cfg**: Environment-specific configuration parameters + +Example: + +.. code-block:: json + + "env": { + "id": "PushCubeRL", + "cfg": { + "num_envs": 4, + "obs_mode": "state", + "episode_length": 100, + "action_scale": 0.1, + "success_threshold": 0.1 + } + } + +Policy Configuration +^^^^^^^^^^^^^^^^^^^ + +The ``policy`` section defines the neural network policy: + +- **name**: Policy name (e.g., "actor_critic", "vla") +- **cfg**: Policy-specific hyperparameters (empty for actor_critic) +- **actor**: Actor network configuration (required for actor_critic) +- **critic**: Critic network configuration (required for actor_critic) + +Example: + +.. code-block:: json + + "policy": { + "name": "actor_critic", + "cfg": {}, + "actor": { + "type": "mlp", + "hidden_sizes": [256, 256], + "activation": "relu" + }, + "critic": { + "type": "mlp", + "hidden_sizes": [256, 256], + "activation": "relu" + } + } + +Algorithm Configuration +^^^^^^^^^^^^^^^^^^^^^^^ + +The ``algorithm`` section defines the RL algorithm: + +- **name**: Algorithm name (e.g., "ppo") +- **cfg**: Algorithm-specific hyperparameters + +Example: + +.. code-block:: json + + "algorithm": { + "name": "ppo", + "cfg": { + "learning_rate": 0.0001, + "n_epochs": 10, + "batch_size": 64, + "gamma": 0.99, + "gae_lambda": 0.95, + "clip_coef": 0.2, + "ent_coef": 0.01, + "vf_coef": 0.5, + "max_grad_norm": 0.5 + } + } + +Training Script +~~~~~~~~~~~~~~~ + +The training script (``train.py``) is located in ``embodichain/agents/rl/``: + +.. dropdown:: Code for train.py + :icon: code + + .. literalinclude:: ../../../embodichain/agents/rl/train.py + :language: python + :linenos: + +The Script Explained +-------------------- + +The training script performs the following steps: + +1. **Parse Configuration**: Loads JSON config and extracts runtime/env/policy/algorithm blocks +2. **Setup**: Initializes device, seeds, output directories, TensorBoard, and Weights & Biases +3. **Build Components**: + - Environment via ``build_env()`` factory + - Policy via ``build_policy()`` registry + - Algorithm via ``build_algo()`` factory +4. **Create Trainer**: Instantiates the ``Trainer`` with all components +5. **Train**: Runs the training loop until completion + +Launching Training +------------------ + +To start training, run: + +.. code-block:: bash + + python embodichain/agents/rl/train.py --config configs/agents/rl/push_cube/train_config.json + +Outputs +------- + +All outputs are written to ``./outputs/_/``: + +- **logs/**: TensorBoard logs +- **checkpoints/**: Model checkpoints + +Training Process +~~~~~~~~~~~~~~~ + +The training process follows this sequence: + +1. **Rollout Phase**: Algorithm collects trajectories by interacting with the environment (via ``collect_rollout``). During this phase, the trainer performs dense per-step logging of rewards and metrics from environment info. +2. **GAE Computation**: Algorithm computes advantages and returns using Generalized Advantage Estimation (internal to algorithm, stored in buffer extras) +3. **Update Phase**: Algorithm updates the policy using collected data (e.g., PPO) +4. **Logging**: Trainer logs training losses and aggregated metrics to TensorBoard and Weights & Biases +5. **Evaluation** (periodic): Trainer evaluates the current policy +6. **Checkpointing** (periodic): Trainer saves model checkpoints + +Policy Interface +~~~~~~~~~~~~~~~~ + +All policies must inherit from the ``Policy`` abstract base class: + +.. code-block:: python + + from abc import ABC, abstractmethod + import torch.nn as nn + + class Policy(nn.Module, ABC): + device: torch.device + + @abstractmethod + def get_action( + self, obs: torch.Tensor, deterministic: bool = False + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Returns (action, log_prob, value)""" + raise NotImplementedError + + @abstractmethod + def get_value(self, obs: torch.Tensor) -> torch.Tensor: + """Returns value estimate""" + raise NotImplementedError + + @abstractmethod + def evaluate_actions( + self, obs: torch.Tensor, actions: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Returns (log_prob, entropy, value)""" + raise NotImplementedError + +Available Policies +------------------ + +- **ActorCritic**: MLP-based Gaussian policy with learnable log_std. Requires external ``actor`` and ``critic`` modules to be provided (defined in JSON config). +- **VLAPlaceholderPolicy**: Placeholder for Vision-Language-Action policies + +Algorithms +~~~~~~~~~~ + +Available Algorithms +-------------------- + +- **PPO**: Proximal Policy Optimization with GAE + +Adding a New Algorithm +--------------------- + +To add a new algorithm: + +1. Create a new algorithm class in ``embodichain/agents/rl/algo/`` +2. Implement ``initialize_buffer()``, ``collect_rollout()``, and ``update()`` methods +3. Register in ``algo/__init__.py``: + +.. code-block:: python + + from embodichain.agents.rl.algo import BaseAlgorithm, register_algo + from embodichain.agents.rl.buffer import RolloutBuffer + + @register_algo("my_algo") + class MyAlgorithm(BaseAlgorithm): + def __init__(self, cfg, policy): + self.cfg = cfg + self.policy = policy + self.device = torch.device(cfg.device) + self.buffer = None + + def initialize_buffer(self, num_steps, num_envs, obs_dim, action_dim): + """Initialize the algorithm's buffer.""" + self.buffer = RolloutBuffer(num_steps, num_envs, obs_dim, action_dim, self.device) + + def collect_rollout(self, env, policy, obs, num_steps, on_step_callback=None): + """Control data collection process (interact with env, fill buffer, compute advantages/returns).""" + # Collect trajectories + # Compute advantages/returns (e.g., GAE for on-policy algorithms) + # Attach extras to buffer: self.buffer.set_extras({"advantages": adv, "returns": ret}) + # Return empty dict (dense logging handled in trainer) + return {} + + def update(self): + """Update the policy using collected data.""" + # Access extras from buffer: self.buffer._extras.get("advantages") + # Use self.buffer to update policy + return {"loss": 0.0} + +Adding a New Policy +-------------------- + +To add a new policy: + +1. Create a new policy class inheriting from the ``Policy`` abstract base class +2. Register in ``models/__init__.py``: + +.. code-block:: python + + from embodichain.agents.rl.models import register_policy, Policy + + @register_policy("my_policy") + class MyPolicy(Policy): + def __init__(self, obs_space, action_space, device, config): + super().__init__() + self.device = device + # Initialize your networks here + + def get_action(self, obs, deterministic=False): + ... + def get_value(self, obs): + ... + def evaluate_actions(self, obs, actions): + ... + +Adding a New Environment +------------------------ + +To add a new RL environment: + +1. Create an environment class inheriting from ``EmbodiedEnv`` +2. Register it with the Gymnasium registry: + +.. code-block:: python + + from embodichain.lab.gym.utils.registration import register_env + + @register_env("MyTaskRL", max_episode_steps=100, override=True) + class MyTaskEnv(EmbodiedEnv): + cfg: MyTaskEnvCfg + ... + +3. Use the environment ID in your JSON config: + +.. code-block:: json + + "env": { + "id": "MyTaskRL", + "cfg": { + ... + } + } + +Best Practices +~~~~~~~~~~~~~~ + +- **Device Management**: Device is single-sourced from ``runtime.cuda``. All components (trainer/algorithm/policy/env) share the same device. + +- **Action Scaling**: Keep action scaling in the environment, not in the policy. + +- **Observation Format**: Environments should provide consistent observation shape/types (torch.float32) and a single ``done = terminated | truncated``. + +- **Algorithm Interface**: Algorithms must implement ``initialize_buffer()``, ``collect_rollout()``, and ``update()`` methods. The algorithm completely controls data collection and buffer management. + +- **Reward Components**: Organize reward components in ``info["rewards"]`` dictionary and metrics in ``info["metrics"]`` dictionary. The trainer performs dense per-step logging directly from environment info. + +- **Configuration**: Use JSON for all hyperparameters. This makes experiments reproducible and easy to track. + +- **Logging**: Metrics are automatically logged to TensorBoard and Weights & Biases. Check ``outputs//logs/`` for TensorBoard logs. + +- **Checkpoints**: Regular checkpoints are saved to ``outputs//checkpoints/``. Use these to resume training or evaluate policies. + diff --git a/docs/source/tutorial/robot.rst b/docs/source/tutorial/robot.rst new file mode 100644 index 00000000..8312ad27 --- /dev/null +++ b/docs/source/tutorial/robot.rst @@ -0,0 +1,143 @@ +.. _tutorial_simulate_robot: + +Simulating a Robot +================ + +.. currentmodule:: embodichain.lab.sim + +This tutorial shows you how to create and simulate a robot using SimulationManager. You'll learn how to load a robot from URDF files, configure control systems, and run basic robot simulation with joint control. + +The Code +~~~~~~~~ + +The tutorial corresponds to the ``create_robot.py`` script in the ``scripts/tutorials/sim`` directory. + +.. dropdown:: Code for create_robot.py + :icon: code + + .. literalinclude:: ../../../scripts/tutorials/sim/create_robot.py + :language: python + :linenos: + + +The Code Explained +~~~~~~~~~~~~~~~~~~ + +Similar to the previous tutorial on creating a simulation scene, we use the :class:`SimulationManager` class to set up the simulation environment. If you haven't read that tutorial yet, please refer to :doc:`create_scene` first. + +Loading Robot URDF +------------------- + +SimulationManager supports loading robots from URDF (Unified Robot Description Format) files. You can load either a single URDF file or compose multiple URDF components into a complete robot system. + +For a simple two-component robot (arm + hand): + +.. literalinclude:: ../../../scripts/tutorials/sim/create_robot.py + :language: python + :start-at: sr5_urdf_path = get_data_path("Rokae/SR5/SR5.urdf") + :end-at: robot: Robot = sim.add_robot(cfg=cfg) + + +The :class:`cfg.URDFCfg` allows you to compose multiple URDF files with specific transformations, enabling complex robot assemblies. + + +Configuring Control Parts +-------------------------- + +Control parts define how the robot's joints are grouped for control purposes. This is useful for organizing complex robots with multiple subsystems. + +.. literalinclude:: ../../../scripts/tutorials/sim/create_robot.py + :language: python + :start-at: # Define control parts for the robot + :end-at: } + +Joint names in control parts can use regex patterns for flexible matching. For example: + +- ``"JOINT[1-6]"`` matches JOINT1, JOINT2, ..., JOINT6 +- ``"L_.*"`` matches all joints starting with `"L_"` + +Setting Drive Properties +------------------------ + +Drive properties control how the robot's joints behave during simulation, including stiffness, damping, and force limits. + +.. literalinclude:: ../../../scripts/tutorials/sim/create_robot.py + :language: python + :start-at: drive_pros=JointDrivePropertiesCfg( + :end-at: ) + +You can set different stiffness values for different joint groups using regex patterns. More details on drive properties can be found in :class:`cfg.JointDrivePropertiesCfg`. + +For more robot configuration options, refer to :class:`cfg.RobotCfg`. + +Robot Control +------------- + +For the basic control of robot joints, you can set position targets using :meth:`objects.Robot.set_qpos`. The control action should be created as a torch.Tensor with shape (num_envs, num_joints), where `num_joints` is the total number of joints in the robot or the number of joints in a specific control part. + +- If you can control all joints, use: + + .. code-block:: python + + robot.set_qpos(qpos=target_positions) + +- If you want to control a subset of joints, specify the joint IDs: + + .. code-block:: python + + robot.set_qpos(qpos=target_positions, joint_ids=subset_joint_ids) + +Getting Robot State +-------------------- + +You can query the robot's current joint positions and velocities via :meth:`objects.Robot.get_qpos` and :meth:`objects.Robot.get_qvel`. For more robot API details, see :class:`objects.Robot`. + +The Code Execution +~~~~~~~~~~~~~~~~~~ + +To run the robot simulation script: + +.. code-block:: bash + + cd /root/sources/embodichain + python scripts/tutorials/sim/create_robot.py + +You can customize the simulation with various command-line options: + +.. code-block:: bash + + # Run with GPU physics + python scripts/tutorials/sim/create_robot.py --device cuda + + # Run multiple environments + python scripts/tutorials/sim/create_robot.py --num_envs 4 + + # Run in headless mode + python scripts/tutorials/sim/create_robot.py --headless + + # Enable ray tracing rendering + python scripts/tutorials/sim/create_robot.py --enable_rt + +The simulation will show the robot moving through different poses, demonstrating basic joint control capabilities. + +Key Features Demonstrated +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This tutorial demonstrates several key features of robot simulation in SimulationManager: + +1. **URDF Loading**: Both single-file and multi-component robot loading +2. **Control Parts**: Organizing joints into logical control groups +3. **Drive Properties**: Configuring joint stiffness and control behavior +4. **Joint Control**: Setting position targets and reading joint states +5. **Multi-Environment**: Running multiple robot instances in parallel + +Next Steps +~~~~~~~~~~ + +After mastering basic robot simulation, you can explore: + +- End-effector control and inverse kinematics +- Sensor integration (cameras, force sensors) +- Robot-object interaction scenarios + +This tutorial provides the foundation for creating sophisticated robotic simulation scenarios with SimulationManager. \ No newline at end of file diff --git a/docs/source/tutorial/sensor.rst b/docs/source/tutorial/sensor.rst new file mode 100644 index 00000000..1d5c4dc9 --- /dev/null +++ b/docs/source/tutorial/sensor.rst @@ -0,0 +1,118 @@ +.. _tutorial_simulate_sensor: + +Simulating a Camera Sensor +========================= + +.. currentmodule:: embodichain.lab.sim + +This tutorial demonstrates how to create and simulate a camera sensor attached to a robot using SimulationManager. You will learn how to configure a camera, attach it to the robot's end-effector, and visualize the sensor's output during simulation. + +Source Code +~~~~~~~~~~~ + +The code for this tutorial is in ``scripts/tutorials/sim/create_sensor.py``. + +.. dropdown:: Show code for create_sensor.py + :icon: code + + .. literalinclude:: ../../../scripts/tutorials/sim/create_sensor.py + :language: python + :linenos: + +Overview +~~~~~~~~ + +This tutorial builds on the basic robot simulation example. If you are not familiar with robot simulation in SimulationManager, please read the :doc:`robot` tutorial first. + +1. **Sensor Creation and Attachment** +------------------------------------- + +The camera sensor is created using :class:`CameraCfg` and can be attached to the robot's end-effector or placed freely in the scene. The attachment is controlled by the ``--attach_sensor`` argument. + +.. literalinclude:: ../../../scripts/tutorials/sim/create_sensor.py + :language: python + :start-at: def create_sensor + :end-at: return camera + +- The camera's intrinsics (focal lengths and principal point) and resolution are set. +- The ``extrinsics`` specify the camera's pose relative to its parent (e.g., the robot's ``ee_link`` or the world). +- The camera is added to the simulation with :meth:`sim.add_sensor`. + +2. **Visualizing Sensor Output** +-------------------------------- + +The function ``get_sensor_image`` retrieves and visualizes the camera's color, depth, mask, and normal images. In GUI mode, images are shown in a 2x2 grid using OpenCV. In headless mode, images are saved to disk. + +.. literalinclude:: ../../../scripts/tutorials/sim/create_sensor.py + :language: python + :start-at: def get_sensor_image + :end-at: plt.close(fig) + +- The camera is updated to capture the latest data. +- Four types of images are visualized: color, depth, mask, and normals. +- Images are displayed in a window or saved as PNG files depending on the mode. + +3. **Simulation Loop** +---------------------- + +The simulation loop moves the robot through different arm poses and periodically updates and visualizes the sensor output. + +.. literalinclude:: ../../../scripts/tutorials/sim/create_sensor.py + :language: python + :start-at: def run_simulation + :end-at: sim.destroy() + +- The robot alternates between two arm positions. +- After each movement, the sensor image is refreshed and visualized. + +Running the Example +~~~~~~~~~~~~~~~~~~~ + +To run the sensor simulation script: + +.. code-block:: bash + + cd /home/dex/projects/yuanhaonan/embodichain + python scripts/tutorials/sim/create_sensor.py + +You can customize the simulation with the following command-line options: + +.. code-block:: bash + + # Use GPU physics + python scripts/tutorials/sim/create_sensor.py --device cuda + + # Simulate multiple environments + python scripts/tutorials/sim/create_sensor.py --num_envs 4 + + # Run in headless mode (no GUI, images saved to disk) + python scripts/tutorials/sim/create_sensor.py --headless + + # Enable ray tracing rendering + python scripts/tutorials/sim/create_sensor.py --enable_rt + + # Attach the camera to the robot end-effector + python scripts/tutorials/sim/create_sensor.py --attach_sensor + +Key Features Demonstrated +~~~~~~~~~~~~~~~~~~~~~~~~ + +This tutorial demonstrates: + +1. **Camera sensor creation** using :class:`CameraCfg` +2. **Sensor attachment** to a robot link or placement in the scene +3. **Camera configuration** (intrinsics, extrinsics, clipping planes) +4. **Real-time visualization** of color, depth, mask, and normal images +5. **Robot-sensor integration** in a simulation loop + +Next Steps +~~~~~~~~~~ + +After completing this tutorial, you can explore: + +- Using other sensor types (e.g., stereo cameras, force sensors) +- Recording sensor data for offline analysis +- Integrating sensor feedback into robot control or learning algorithms + +This tutorial provides a foundation for integrating perception into robotic simulation scenarios with SimulationManager. +This tutorial provides the foundation for integrating perception into robotic simulation scenarios with SimulationManager. \ No newline at end of file diff --git a/docs/source/tutorial/solver.rst b/docs/source/tutorial/solver.rst new file mode 100644 index 00000000..dd190f01 --- /dev/null +++ b/docs/source/tutorial/solver.rst @@ -0,0 +1,114 @@ + +.. _tutorial_solver: + +Create a solver +=============== + +.. currentmodule:: embodichain.lab.sim.solvers + +Overview +~~~~~~~~ + +The ``solver`` module in EmbodiChain provides a unified and extensible interface for robot kinematics computation, including forward kinematics (FK), inverse kinematics (IK), and Jacobian calculation. It supports multiple solver backends (e.g., Pinocchio, OPW, SRS, PINK, PyTorch) and is designed for both simulation and real-robot applications. + +Key Features +------------ +- **Unified API**: Abstract base class (`BaseSolver`) defines a common interface for all solvers. +- **Multiple Backends**: Supports Pinocchio, OPW, SRS, PINK, PyTorch, and differential solvers. +- **Flexible Configuration**: Easily switch solver type and parameters via configuration. +- **Batch and Single Query**: Supports both batch and single FK/IK/Jacobian queries. +- **Extensible**: New solvers can be added by subclassing `BaseSolver` and implementing required methods. + +Example: Using PinkSolver +~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. code-block:: python + + from embodichain.lab.sim.solvers import PinkSolverCfg + from embodichain.lab.sim.objects.robot import Robot + + # 1. Configure PinkSolver + pink_cfg = PinkSolverCfg( + urdf_path="/path/to/robot.urdf", + joint_names=[ + "shoulder_pan_joint", "shoulder_lift_joint", "elbow_joint", + "wrist_1_joint", "wrist_2_joint", "wrist_3_joint" + ], + end_link_name="ee_link", + root_link_name="base_link" + ) + # 2. Assign solver config to robot config + robot_cfg.solver_cfg = pink_cfg + # 3. Instantiate robot (solver will be initialized automatically) + robot = Robot(cfg=robot_cfg, entities=[], device="cpu") + + # 4. Use FK/IK/Jacobian + qpos = [0.0, -1.57, 1.57, 0.0, 1.57, 0.0] # 6-DOF joint angles (radians) + ee_pose = robot.compute_fk(qpos) # Forward kinematics, returns 4x4 matrix + print("End-effector pose (FK):\n", ee_pose) + + import numpy as np + target_pose = np.array([ + [0, -1, 0, 0.5], + [1, 0, 0, 0.2], + [0, 0, 1, 0.3], + [0, 0, 0, 1.0] + ]) + success, qpos_sol = robot.compute_ik(target_pose, joint_seed=qpos) + print("IK success:", success) + print("IK solution:", qpos_sol) + + J = robot.get_solver().get_jacobian(qpos) + print("Jacobian:\n", J) + +**Note** + +- robot.compute_fk(qpos) internally calls the bound solver's get_fk method. +- robot.compute_ik(target_pose, joint_seed) internally calls the solver's get_ik method. + +API Reference +~~~~~~~~~~~~~ + +**BaseSolver** + +.. code-block:: python + + class BaseSolver: + def get_fk(self, qpos, **kwargs) -> torch.Tensor: + """Compute forward kinematics for the end-effector.""" + + def get_ik(self, target_pose, joint_seed=None, num_samples=None, **kwargs) -> Tuple[torch.Tensor, torch.Tensor]: + """Compute inverse kinematics for a given pose.""" + + def get_jacobian(self, qpos, locations=None, jac_type="full") -> torch.Tensor: + """Compute the Jacobian matrix for the given joint positions.""" + +- **set_ik_nearst_weight**: Set weights for IK nearest neighbor search. +- **set_position_limits / get_position_limits**: Set or get joint position limits. +- **set_tcp / get_tcp**: Set or get the tool center point (TCP) transformation. + +**PinkSolver** + +- Implements all BaseSolver methods using the Pink library. +- Supports custom task lists, solver type selection, and joint limit handling. +- See PinkSolverCfg for all configuration options. + +Configuration +~~~~~~~~~~~~~ + +- All solvers are configured via a `SolverCfg` or its subclass (e.g., `PinkSolverCfg`). +- Key config fields: `urdf_path`, `joint_names`, `end_link_name`, `root_link_name`, `tcp`, and solver-specific parameters. +- Use `cfg.init_solver()` to instantiate the solver, or assign to `robot_cfg.solver_cfg` for automatic integration. + +Notes & Best Practices +~~~~~~~~~~~~~~~~~~~~~ +- Always ensure URDF and joint/link names match your robot model. +- For IK, providing a good `qpos_seed` improves convergence and solution quality. +- Use `set_iteration_params` (if available) to tune solver performance for your application. +- For custom robots or new algorithms, subclass `BaseSolver` and register your solver. + +See Also +~~~~~~~~ +- :ref:`tutorial_motion_generator` — Motion Generator +- :ref:`tutorial_basic_env` — Basic Environment Setup diff --git a/docs/sync_readme.py b/docs/sync_readme.py new file mode 100644 index 00000000..a3198b6e --- /dev/null +++ b/docs/sync_readme.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +"""Sync project README.md into docs/source/introduction.md. + +Idempotent copy. Exit code 0 on success. +""" +import shutil +from pathlib import Path +import sys + + +def main() -> int: + repo_root = Path(__file__).resolve().parents[1] + readme = repo_root / "README.md" + dest = repo_root / "docs" / "source" / "introduction.md" + + if not readme.exists(): + print(f"ERROR: README not found at {readme}") + return 2 + + # Ensure destination directory exists + dest.parent.mkdir(parents=True, exist_ok=True) + + # Copy file + shutil.copyfile(readme, dest) + print(f"Copied {readme} -> {dest}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/embodichain/__init__.py b/embodichain/__init__.py new file mode 100644 index 00000000..1b3998b6 --- /dev/null +++ b/embodichain/__init__.py @@ -0,0 +1,32 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os + +embodichain_dir = os.path.dirname(__file__) + +# Read version from VERSION file +def _get_version(): + version_file = os.path.join(os.path.dirname(embodichain_dir), "VERSION") + try: + with open(version_file, "r") as f: + return f.read().strip() + except FileNotFoundError: + print("VERSION file not found.") + return "unknown" + + +__version__ = _get_version() diff --git a/embodichain/agents/rl/algo/__init__.py b/embodichain/agents/rl/algo/__init__.py new file mode 100644 index 00000000..6aca3d5d --- /dev/null +++ b/embodichain/agents/rl/algo/__init__.py @@ -0,0 +1,52 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +from typing import Dict, Tuple, Type, Any +import torch + +from .base import BaseAlgorithm +from .ppo import PPOCfg, PPO + +# name -> (CfgClass, AlgoClass) +_ALGO_REGISTRY: Dict[str, Tuple[Type[Any], Type[Any]]] = { + "ppo": (PPOCfg, PPO), +} + + +def get_registered_algo_names() -> list[str]: + return list(_ALGO_REGISTRY.keys()) + + +def build_algo(name: str, cfg_kwargs: Dict[str, float], policy, device: torch.device): + key = name.lower() + if key not in _ALGO_REGISTRY: + raise ValueError( + f"Algorithm '{name}' not found. Available: {get_registered_algo_names()}" + ) + CfgCls, AlgoCls = _ALGO_REGISTRY[key] + cfg = CfgCls(device=str(device), **cfg_kwargs) + return AlgoCls(cfg, policy) + + +__all__ = [ + "BaseAlgorithm", + "PPOCfg", + "PPO", + "get_registered_algo_names", + "build_algo", +] diff --git a/embodichain/agents/rl/algo/base.py b/embodichain/agents/rl/algo/base.py new file mode 100644 index 00000000..1cb23309 --- /dev/null +++ b/embodichain/agents/rl/algo/base.py @@ -0,0 +1,52 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +from typing import Dict, Any, Optional, Callable +import torch + + +class BaseAlgorithm: + """Base class for RL algorithms. + + Algorithms must implement buffer initialization, rollout collection, and + policy update. Trainer depends only on this interface to remain + algorithm-agnostic. + """ + + device: torch.device + + def initialize_buffer( + self, num_steps: int, num_envs: int, obs_dim: int, action_dim: int + ) -> None: + """Initialize internal buffer(s) required by the algorithm.""" + raise NotImplementedError + + def collect_rollout( + self, + env, + policy, + obs: torch.Tensor, + num_steps: int, + on_step_callback: Optional[Callable] = None, + ) -> Dict[str, Any]: + """Collect trajectories and return logging info (e.g., reward components).""" + raise NotImplementedError + + def update(self) -> Dict[str, float]: + """Update policy using collected data and return training losses.""" + raise NotImplementedError diff --git a/embodichain/agents/rl/algo/ppo.py b/embodichain/agents/rl/algo/ppo.py new file mode 100644 index 00000000..2ecc195e --- /dev/null +++ b/embodichain/agents/rl/algo/ppo.py @@ -0,0 +1,184 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +from typing import Dict, Any, Tuple, Callable, Optional + +from embodichain.agents.rl.utils import AlgorithmCfg +from embodichain.agents.rl.buffer import RolloutBuffer +from embodichain.utils import configclass +from .base import BaseAlgorithm + + +@configclass +class PPOCfg(AlgorithmCfg): + """Configuration for the PPO algorithm.""" + + n_epochs: int = 10 + clip_coef: float = 0.2 + ent_coef: float = 0.01 + vf_coef: float = 0.5 + + +class PPO(BaseAlgorithm): + """PPO algorithm operating via Policy and RolloutBuffer (algo-agnostic design).""" + + def __init__(self, cfg: PPOCfg, policy): + self.cfg = cfg + self.policy = policy + self.device = torch.device(cfg.device) + self.optimizer = torch.optim.Adam(policy.parameters(), lr=cfg.learning_rate) + self.buffer: Optional[RolloutBuffer] = None + # no per-rollout aggregation for dense logging + + def _compute_gae( + self, rewards: torch.Tensor, values: torch.Tensor, dones: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + """Internal method to compute GAE. Only called by collect_rollout.""" + T, N = rewards.shape + advantages = torch.zeros_like(rewards, device=self.device) + last_adv = torch.zeros(N, device=self.device) + for t in reversed(range(T)): + next_value = values[t + 1] if t < T - 1 else torch.zeros_like(values[0]) + not_done = (~dones[t]).float() + delta = rewards[t] + self.cfg.gamma * next_value * not_done - values[t] + last_adv = ( + delta + self.cfg.gamma * self.cfg.gae_lambda * not_done * last_adv + ) + advantages[t] = last_adv + returns = advantages + values + return advantages, returns + + def initialize_buffer( + self, num_steps: int, num_envs: int, obs_dim: int, action_dim: int + ): + """Initialize the rollout buffer. Called by trainer before first rollout.""" + self.buffer = RolloutBuffer( + num_steps, num_envs, obs_dim, action_dim, self.device + ) + + def collect_rollout( + self, + env, + policy, + obs: torch.Tensor, + num_steps: int, + on_step_callback: Optional[Callable] = None, + ) -> Dict[str, Any]: + """Collect a rollout. Algorithm controls the data collection process.""" + if self.buffer is None: + raise RuntimeError( + "Buffer not initialized. Call initialize_buffer() first." + ) + + policy.train() + self.buffer.step = 0 + current_obs = obs + + for t in range(num_steps): + # Get action from policy + actions, log_prob, value = policy.get_action( + current_obs, deterministic=False + ) + + # Step environment + result = env.step(actions) + next_obs, reward, terminated, truncated, env_info = result + done = terminated | truncated + # Light dtype normalization + reward = reward.float() + done = done.bool() + + # Add to buffer + self.buffer.add(current_obs, actions, reward, done, value, log_prob) + + # Dense logging is handled in Trainer.on_step via info; no aggregation here + # Call callback for statistics and logging + if on_step_callback is not None: + on_step_callback(current_obs, actions, reward, done, env_info, next_obs) + + current_obs = next_obs + + # Compute advantages/returns and attach to buffer extras + adv, ret = self._compute_gae( + self.buffer.rewards, self.buffer.values, self.buffer.dones + ) + self.buffer.set_extras({"advantages": adv, "returns": ret}) + + # No aggregated logging results; Trainer performs dense per-step logging + return {} + + def update(self) -> dict: + """Update the policy using the collected rollout buffer.""" + if self.buffer is None: + raise RuntimeError("Buffer not initialized. Call collect_rollout() first.") + + # Normalize advantages (optional, common default) + adv = self.buffer._extras.get("advantages") + adv = (adv - adv.mean()) / (adv.std() + 1e-8) + + total_actor_loss = 0.0 + total_value_loss = 0.0 + total_entropy = 0.0 + total_steps = 0 + + for _ in range(self.cfg.n_epochs): + for batch in self.buffer.iterate_minibatches(self.cfg.batch_size): + obs = batch["obs"] + actions = batch["actions"] + old_logprobs = batch["logprobs"] + returns = batch["returns"] + advantages = ( + (batch["advantages"] - adv.mean()) / (adv.std() + 1e-8) + ).detach() + + logprobs, entropy, values = self.policy.evaluate_actions(obs, actions) + ratio = (logprobs - old_logprobs).exp() + surr1 = ratio * advantages + surr2 = ( + torch.clamp( + ratio, 1.0 - self.cfg.clip_coef, 1.0 + self.cfg.clip_coef + ) + * advantages + ) + actor_loss = -torch.min(surr1, surr2).mean() + value_loss = torch.nn.functional.mse_loss(values, returns) + entropy_loss = -entropy.mean() + + loss = ( + actor_loss + + self.cfg.vf_coef * value_loss + + self.cfg.ent_coef * entropy_loss + ) + + self.optimizer.zero_grad(set_to_none=True) + loss.backward() + torch.nn.utils.clip_grad_norm_( + self.policy.parameters(), self.cfg.max_grad_norm + ) + self.optimizer.step() + + bs = obs.shape[0] + total_actor_loss += actor_loss.item() * bs + total_value_loss += value_loss.item() * bs + total_entropy += (-entropy_loss.item()) * bs + total_steps += bs + + return { + "actor_loss": total_actor_loss / max(1, total_steps), + "value_loss": total_value_loss / max(1, total_steps), + "entropy": total_entropy / max(1, total_steps), + } diff --git a/embodichain/agents/rl/buffer/__init__.py b/embodichain/agents/rl/buffer/__init__.py new file mode 100644 index 00000000..8e6f6392 --- /dev/null +++ b/embodichain/agents/rl/buffer/__init__.py @@ -0,0 +1,19 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .rollout_buffer import RolloutBuffer + +__all__ = ["RolloutBuffer"] diff --git a/embodichain/agents/rl/buffer/rollout_buffer.py b/embodichain/agents/rl/buffer/rollout_buffer.py new file mode 100644 index 00000000..d99a8966 --- /dev/null +++ b/embodichain/agents/rl/buffer/rollout_buffer.py @@ -0,0 +1,106 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +from typing import Dict, Iterator + +import torch + + +class RolloutBuffer: + """On-device rollout buffer for on-policy algorithms. + + Stores (obs, actions, rewards, dones, values, logprobs) over time. + After finalize(), exposes advantages/returns and minibatch iteration. + """ + + def __init__( + self, + num_steps: int, + num_envs: int, + obs_dim: int, + action_dim: int, + device: torch.device, + ): + self.num_steps = num_steps + self.num_envs = num_envs + self.obs_dim = obs_dim + self.action_dim = action_dim + self.device = device + + T, N = num_steps, num_envs + self.obs = torch.zeros(T, N, obs_dim, dtype=torch.float32, device=device) + self.actions = torch.zeros(T, N, action_dim, dtype=torch.float32, device=device) + self.rewards = torch.zeros(T, N, dtype=torch.float32, device=device) + self.dones = torch.zeros(T, N, dtype=torch.bool, device=device) + self.values = torch.zeros(T, N, dtype=torch.float32, device=device) + self.logprobs = torch.zeros(T, N, dtype=torch.float32, device=device) + + self.step = 0 + # Container for algorithm-specific extra fields (e.g., advantages, returns) + self._extras: dict[str, torch.Tensor] = {} + + def add( + self, + obs: torch.Tensor, + action: torch.Tensor, + reward: torch.Tensor, + done: torch.Tensor, + value: torch.Tensor, + logprob: torch.Tensor, + ) -> None: + t = self.step + self.obs[t].copy_(obs) + self.actions[t].copy_(action) + self.rewards[t].copy_(reward) + self.dones[t].copy_(done) + self.values[t].copy_(value) + self.logprobs[t].copy_(logprob) + self.step += 1 + + def set_extras(self, extras: dict[str, torch.Tensor]) -> None: + """Attach algorithm-specific tensors (shape [T, N, ...]) for batching. + + Examples: + {"advantages": adv, "returns": ret} + """ + self._extras = extras or {} + + def iterate_minibatches(self, batch_size: int) -> Iterator[Dict[str, torch.Tensor]]: + T, N = self.num_steps, self.num_envs + total = T * N + indices = torch.randperm(total, device=self.device) + for start in range(0, total, batch_size): + idx = indices[start : start + batch_size] + t_idx = idx // N + n_idx = idx % N + batch = { + "obs": self.obs[t_idx, n_idx], + "actions": self.actions[t_idx, n_idx], + "rewards": self.rewards[t_idx, n_idx], + "dones": self.dones[t_idx, n_idx], + "values": self.values[t_idx, n_idx], + "logprobs": self.logprobs[t_idx, n_idx], + } + # Slice extras if present and shape aligned to [T, N, ...] + for name, tensor in self._extras.items(): + try: + batch[name] = tensor[t_idx, n_idx] + except Exception: + # Skip misaligned extras silently + continue + yield batch diff --git a/embodichain/agents/rl/models/__init__.py b/embodichain/agents/rl/models/__init__.py new file mode 100644 index 00000000..669e2b33 --- /dev/null +++ b/embodichain/agents/rl/models/__init__.py @@ -0,0 +1,101 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +from typing import Dict, Type +import torch +from gymnasium import spaces + +from .actor_critic import ActorCritic +from .policy import Policy +from .mlp import MLP + +# In-module policy registry +_POLICY_REGISTRY: Dict[str, Type[Policy]] = {} + + +def register_policy(name: str, policy_cls: Type[Policy]) -> None: + if name in _POLICY_REGISTRY: + raise ValueError(f"Policy '{name}' is already registered") + _POLICY_REGISTRY[name] = policy_cls + + +def get_registered_policy_names() -> list[str]: + return list(_POLICY_REGISTRY.keys()) + + +def get_policy_class(name: str) -> Type[Policy] | None: + return _POLICY_REGISTRY.get(name) + + +def build_policy( + policy_block: dict, + obs_space: spaces.Space, + action_space: spaces.Space, + device: torch.device, + actor: torch.nn.Module | None = None, + critic: torch.nn.Module | None = None, +) -> Policy: + """Build policy strictly from json-like block: { name: ..., cfg: {...} }""" + name = policy_block["name"].lower() + if name not in _POLICY_REGISTRY: + available = ", ".join(get_registered_policy_names()) + raise ValueError( + f"Policy '{name}' is not registered. Available policies: {available}" + ) + policy_cls = _POLICY_REGISTRY[name] + if name == "actor_critic": + if actor is None or critic is None: + raise ValueError( + "ActorCritic policy requires external 'actor' and 'critic' modules." + ) + return policy_cls(obs_space, action_space, device, actor=actor, critic=critic) + else: + return policy_cls(obs_space, action_space, device) + + +def build_mlp_from_cfg(module_cfg: Dict, in_dim: int, out_dim: int) -> MLP: + """Construct an MLP module from a minimal json-like config. + + Expected schema: + module_cfg = { + "type": "mlp", + "hidden_sizes": [256, 256], + "activation": "relu", + } + """ + if module_cfg.get("type", "").lower() != "mlp": + raise ValueError("Only 'mlp' type is supported for actor/critic in this setup.") + + hidden_sizes = module_cfg["network_cfg"]["hidden_sizes"] + activation = module_cfg["network_cfg"]["activation"] + return MLP(in_dim, out_dim, hidden_sizes, activation) + + +# default registrations +register_policy("actor_critic", ActorCritic) + +__all__ = [ + "ActorCritic", + "register_policy", + "get_registered_policy_names", + "build_policy", + "build_mlp_from_cfg", + "get_policy_class", + "Policy", + "MLP", +] diff --git a/embodichain/agents/rl/models/actor_critic.py b/embodichain/agents/rl/models/actor_critic.py new file mode 100644 index 00000000..1c40043a --- /dev/null +++ b/embodichain/agents/rl/models/actor_critic.py @@ -0,0 +1,96 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +from typing import Dict, Any, Tuple + +import torch +import torch.nn as nn +from torch.distributions.normal import Normal +from .mlp import MLP +from .policy import Policy + + +class ActorCritic(Policy): + """Actor-Critic with learnable log_std for Gaussian policy. + + This is a placeholder implementation of the Policy interface that: + - Encapsulates MLP networks (actor + critic) that need to be trained by RL algorithms + - Handles internal computation: MLP output → mean + learnable log_std → Normal distribution + - Provides a uniform interface for RL algorithms (PPO, SAC, etc.) + + This allows seamless swapping with other policy implementations (e.g., VLAPolicy) + without modifying RL algorithm code. + + Implements: + - get_action(obs, deterministic=False) -> (action, log_prob, value) + - get_value(obs) + - evaluate_actions(obs, actions) -> (log_prob, entropy, value) + """ + + def __init__( + self, + obs_space, + action_space, + device: torch.device, + actor: nn.Module, + critic: nn.Module, + ): + super().__init__() + self.obs_dim = obs_space.shape[-1] + self.action_dim = action_space.shape[-1] + self.device = device + + # Require external injection of actor and critic + self.actor = actor + self.critic = critic + self.actor.to(self.device) + self.critic.to(self.device) + + # learnable log_std per action dim + self.log_std = nn.Parameter(torch.zeros(self.action_dim, device=self.device)) + self.log_std_min = -5.0 + self.log_std_max = 2.0 + + @torch.no_grad() + def get_action( + self, obs: torch.Tensor, deterministic: bool = False + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + mean = self.actor(obs) + log_std = self.log_std.clamp(self.log_std_min, self.log_std_max) + std = log_std.exp().expand(mean.shape[0], -1) + dist = Normal(mean, std) + action = mean if deterministic else dist.sample() + log_prob = dist.log_prob(action).sum(dim=-1) + value = self.critic(obs).squeeze(-1) + return action, log_prob, value + + @torch.no_grad() + def get_value(self, obs: torch.Tensor) -> torch.Tensor: + return self.critic(obs).squeeze(-1) + + def evaluate_actions( + self, obs: torch.Tensor, actions: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + mean = self.actor(obs) + log_std = self.log_std.clamp(self.log_std_min, self.log_std_max) + std = log_std.exp().expand(mean.shape[0], -1) + dist = Normal(mean, std) + log_prob = dist.log_prob(actions).sum(dim=-1) + entropy = dist.entropy().sum(dim=-1) + value = self.critic(obs).squeeze(-1) + return log_prob, entropy, value diff --git a/embodichain/agents/rl/models/mlp.py b/embodichain/agents/rl/models/mlp.py new file mode 100644 index 00000000..d839f63d --- /dev/null +++ b/embodichain/agents/rl/models/mlp.py @@ -0,0 +1,121 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +from functools import reduce +from typing import Iterable, List, Optional, Sequence, Tuple, Union + +import torch +import torch.nn as nn + + +ActivationName = Union[str, None] + + +def _resolve_activation(name: ActivationName) -> nn.Module: + if name is None: + return nn.Identity() + name_l = str(name).lower() + if name_l in ("relu",): + return nn.ReLU() + if name_l in ("elu",): + return nn.ELU() + if name_l in ("tanh",): + return nn.Tanh() + if name_l in ("gelu",): + return nn.GELU() + if name_l in ("silu", "swish"): + return nn.SiLU() + # fallback + return nn.ReLU() + + +class MLP(nn.Sequential): + """General MLP supporting custom last activation, orthogonal init, and output reshape. + + Args: + - input_dim: input dimension + - output_dim: output dimension (int or shape tuple/list) + - hidden_dims: hidden layer sizes, e.g. [256, 256] + - activation: hidden layer activation name (relu/elu/tanh/gelu/silu) + - last_activation: last-layer activation name or None for linear + - use_layernorm: whether to add LayerNorm after each hidden linear layer + - dropout_p: dropout probability for hidden layers (0 disables) + """ + + def __init__( + self, + input_dim: int, + output_dim: Union[int, Sequence[int]], + hidden_dims: Sequence[int], + activation: ActivationName = "elu", + last_activation: ActivationName = None, + use_layernorm: bool = False, + dropout_p: float = 0.0, + ) -> None: + super().__init__() + + act = lambda: _resolve_activation(activation) + last_act = ( + _resolve_activation(last_activation) + if last_activation is not None + else None + ) + + layers: List[nn.Module] = [] + dims = [input_dim] + list(hidden_dims) + + for in_d, out_d in zip(dims[:-1], dims[1:]): + layers.append(nn.Linear(in_d, out_d)) + if use_layernorm: + layers.append(nn.LayerNorm(out_d)) + layers.append(act()) + if dropout_p and dropout_p > 0.0: + layers.append(nn.Dropout(p=dropout_p)) + + # Output layer + if isinstance(output_dim, int): + layers.append(nn.Linear(dims[-1], output_dim)) + else: + total_out = int(reduce(lambda a, b: a * b, output_dim)) + layers.append(nn.Linear(dims[-1], total_out)) + layers.append(nn.Unflatten(dim=-1, unflattened_size=tuple(output_dim))) + + if last_act is not None: + layers.append(last_act) + + for idx, layer in enumerate(layers): + self.add_module(str(idx), layer) + + def init_orthogonal(self, scales: Union[float, Sequence[float]] = 1.0) -> None: + """Orthogonal-initialize linear layers and zero the bias. + + scales: single gain value or a sequence with length equal to the + number of linear layers. + """ + + def get_scale(i: int) -> float: + if isinstance(scales, (list, tuple)): + return float(scales[i]) + return float(scales) + + lin_idx = 0 + for m in self.modules(): + if isinstance(m, nn.Linear): + nn.init.orthogonal_(m.weight, gain=get_scale(lin_idx)) + nn.init.zeros_(m.bias) + lin_idx += 1 diff --git a/embodichain/agents/rl/models/policy.py b/embodichain/agents/rl/models/policy.py new file mode 100644 index 00000000..cd21d0f7 --- /dev/null +++ b/embodichain/agents/rl/models/policy.py @@ -0,0 +1,94 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +"""Policy base class for RL algorithms. + +This module defines an abstract Policy base class that all RL policies must +inherit from. A Policy encapsulates the neural networks and exposes a uniform +interface for RL algorithms (e.g., PPO, SAC) to interact with. +""" + +from __future__ import annotations + +from typing import Tuple +from abc import ABC, abstractmethod +import torch.nn as nn + +import torch + + +class Policy(nn.Module, ABC): + """Abstract base class that all RL policies must implement. + + A Policy: + - Encapsulates neural networks that are trained by RL algorithms + - Handles internal computations (e.g., network output → distribution) + - Provides a uniform interface for algorithms (PPO, SAC, etc.) + """ + + device: torch.device + """Device where the policy parameters are located.""" + + def __init__(self) -> None: + super().__init__() + + @abstractmethod + def get_action( + self, obs: torch.Tensor, deterministic: bool = False + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Sample an action from the policy. + + Args: + obs: Observation tensor of shape (batch_size, obs_dim) + deterministic: If True, return the mean action; otherwise sample + + Returns: + Tuple of (action, log_prob, value): + - action: Sampled action tensor of shape (batch_size, action_dim) + - log_prob: Log probability of the action, shape (batch_size,) + - value: Value estimate, shape (batch_size,) + """ + raise NotImplementedError + + @abstractmethod + def get_value(self, obs: torch.Tensor) -> torch.Tensor: + """Get value estimate for given observations. + + Args: + obs: Observation tensor of shape (batch_size, obs_dim) + + Returns: + Value estimate tensor of shape (batch_size,) + """ + raise NotImplementedError + + @abstractmethod + def evaluate_actions( + self, obs: torch.Tensor, actions: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Evaluate actions and compute log probabilities, entropy, and values. + + Args: + obs: Observation tensor of shape (batch_size, obs_dim) + actions: Action tensor of shape (batch_size, action_dim) + + Returns: + Tuple of (log_prob, entropy, value): + - log_prob: Log probability of actions, shape (batch_size,) + - entropy: Entropy of the action distribution, shape (batch_size,) + - value: Value estimate, shape (batch_size,) + """ + raise NotImplementedError diff --git a/embodichain/agents/rl/train.py b/embodichain/agents/rl/train.py new file mode 100644 index 00000000..e87d4629 --- /dev/null +++ b/embodichain/agents/rl/train.py @@ -0,0 +1,270 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import argparse +import os +import time +from pathlib import Path + +import numpy as np +import torch +import wandb +import json +from torch.utils.tensorboard import SummaryWriter +from copy import deepcopy + +from embodichain.agents.rl.models import build_policy, get_registered_policy_names +from embodichain.agents.rl.models import build_mlp_from_cfg +from embodichain.agents.rl.algo import build_algo, get_registered_algo_names +from embodichain.agents.rl.utils.trainer import Trainer +from embodichain.utils import logger +from embodichain.lab.gym.envs.tasks.rl import build_env +from embodichain.lab.gym.utils.gym_utils import config_to_rl_cfg +from embodichain.utils.utility import load_json +from embodichain.utils.module_utils import find_function_from_modules +from embodichain.lab.sim import SimulationManagerCfg +from embodichain.lab.gym.envs.managers.cfg import EventCfg + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--config", type=str, required=True, help="Path to JSON config") + args = parser.parse_args() + + with open(args.config, "r") as f: + cfg_json = json.load(f) + + trainer_cfg = cfg_json["trainer"] + policy_block = cfg_json["policy"] + algo_block = cfg_json["algorithm"] + + # Runtime + exp_name = trainer_cfg.get("exp_name", "generic_exp") + seed = int(trainer_cfg.get("seed", 1)) + device_str = trainer_cfg.get("device", "cpu") + iterations = int(trainer_cfg.get("iterations", 250)) + rollout_steps = int(trainer_cfg.get("rollout_steps", 2048)) + eval_freq = int(trainer_cfg.get("eval_freq", 10000)) + save_freq = int(trainer_cfg.get("save_freq", 50000)) + headless = bool(trainer_cfg.get("headless", True)) + wandb_project_name = trainer_cfg.get("wandb_project_name", "embodychain-generic") + + # Device + if not isinstance(device_str, str): + raise ValueError( + f"runtime.device must be a string such as 'cpu' or 'cuda:0'. Got: {device_str!r}" + ) + try: + device = torch.device(device_str) + except RuntimeError as exc: + raise ValueError( + f"Failed to parse runtime.device='{device_str}': {exc}" + ) from exc + + if device.type == "cuda": + if not torch.cuda.is_available(): + raise ValueError( + "CUDA device requested but torch.cuda.is_available() is False." + ) + index = ( + device.index if device.index is not None else torch.cuda.current_device() + ) + device_count = torch.cuda.device_count() + if index < 0 or index >= device_count: + raise ValueError( + f"CUDA device index {index} is out of range (available devices: {device_count})." + ) + torch.cuda.set_device(index) + device = torch.device(f"cuda:{index}") + elif device.type != "cpu": + raise ValueError(f"Unsupported device type: {device}") + logger.log_info(f"Device: {device}") + + # Seeds + np.random.seed(seed) + torch.manual_seed(seed) + torch.backends.cudnn.deterministic = True + if device.type == "cuda": + torch.cuda.manual_seed_all(seed) + + # Outputs + run_stamp = time.strftime("%Y%m%d_%H%M%S") + run_base = os.path.join("outputs", f"{exp_name}_{run_stamp}") + log_dir = os.path.join(run_base, "logs") + checkpoint_dir = os.path.join(run_base, "checkpoints") + os.makedirs(log_dir, exist_ok=True) + os.makedirs(checkpoint_dir, exist_ok=True) + writer = SummaryWriter(f"{log_dir}/{exp_name}") + + # Initialize Weights & Biases (optional) + use_wandb = trainer_cfg.get("use_wandb", False) + + # Initialize Weights & Biases (optional) + if use_wandb: + wandb.init(project=wandb_project_name, name=exp_name, config=cfg_json) + + gym_config_path = Path(trainer_cfg["gym_config"]) + logger.log_info(f"Current working directory: {Path.cwd()}") + + gym_config_data = load_json(str(gym_config_path)) + gym_env_cfg = config_to_rl_cfg(gym_config_data) + + # Ensure sim configuration mirrors runtime overrides + if gym_env_cfg.sim_cfg is None: + gym_env_cfg.sim_cfg = SimulationManagerCfg() + if device.type == "cuda": + gpu_index = device.index + if gpu_index is None: + gpu_index = torch.cuda.current_device() + gym_env_cfg.sim_cfg.sim_device = torch.device(f"cuda:{gpu_index}") + if hasattr(gym_env_cfg.sim_cfg, "gpu_id"): + gym_env_cfg.sim_cfg.gpu_id = gpu_index + else: + gym_env_cfg.sim_cfg.sim_device = torch.device("cpu") + gym_env_cfg.sim_cfg.headless = headless + + logger.log_info( + f"Loaded gym_config from {gym_config_path} (env_id={gym_env_cfg.env_id}, headless={gym_env_cfg.sim_cfg.headless}, sim_device={gym_env_cfg.sim_cfg.sim_device})" + ) + + env = build_env(gym_env_cfg.env_id, base_env_cfg=gym_env_cfg) + + eval_gym_env_cfg = deepcopy(gym_env_cfg) + eval_gym_env_cfg.num_envs = 4 + eval_gym_env_cfg.sim_cfg.headless = True + + eval_env = build_env(eval_gym_env_cfg.env_id, base_env_cfg=eval_gym_env_cfg) + + # Build Policy via registry + policy_name = policy_block["name"] + # Build Policy via registry (actor/critic must be explicitly defined in JSON when using actor_critic) + if policy_name.lower() == "actor_critic": + obs_dim = env.observation_space.shape[-1] + action_dim = env.action_space.shape[-1] + + actor_cfg = policy_block.get("actor") + critic_cfg = policy_block.get("critic") + if actor_cfg is None or critic_cfg is None: + raise ValueError( + "ActorCritic requires 'actor' and 'critic' definitions in JSON (policy.actor / policy.critic)." + ) + + actor = build_mlp_from_cfg(actor_cfg, obs_dim, action_dim) + critic = build_mlp_from_cfg(critic_cfg, obs_dim, 1) + + policy = build_policy( + policy_block, + env.observation_space, + env.action_space, + device, + actor=actor, + critic=critic, + ) + else: + policy = build_policy( + policy_block, env.observation_space, env.action_space, device + ) + + # Build Algorithm via factory + algo_name = algo_block["name"].lower() + algo_cfg = algo_block["cfg"] + algo = build_algo(algo_name, algo_cfg, policy, device) + + # Build Trainer + event_modules = [ + "embodichain.lab.gym.envs.managers.randomization", + "embodichain.lab.gym.envs.managers.record", + "embodichain.lab.gym.envs.managers.events", + ] + events_dict = trainer_cfg.get("events", {}) + train_event_cfg = {} + eval_event_cfg = {} + # Parse train events + for event_name, event_info in events_dict.get("train", {}).items(): + event_func_str = event_info.get("func") + mode = event_info.get("mode", "interval") + params = event_info.get("params", {}) + interval_step = event_info.get("interval_step", 1) + event_func = find_function_from_modules( + event_func_str, event_modules, raise_if_not_found=True + ) + train_event_cfg[event_name] = EventCfg( + func=event_func, + mode=mode, + params=params, + interval_step=interval_step, + ) + # Parse eval events + for event_name, event_info in events_dict.get("eval", {}).items(): + event_func_str = event_info.get("func") + mode = event_info.get("mode", "interval") + params = event_info.get("params", {}) + interval_step = event_info.get("interval_step", 1) + event_func = find_function_from_modules( + event_func_str, event_modules, raise_if_not_found=True + ) + eval_event_cfg[event_name] = EventCfg( + func=event_func, + mode=mode, + params=params, + interval_step=interval_step, + ) + trainer = Trainer( + policy=policy, + env=env, + algorithm=algo, + num_steps=rollout_steps, + batch_size=algo_cfg["batch_size"], + writer=writer, + eval_freq=eval_freq, + save_freq=save_freq, + checkpoint_dir=checkpoint_dir, + exp_name=exp_name, + use_wandb=use_wandb, + eval_env=eval_env, + event_cfg=train_event_cfg, + eval_event_cfg=eval_event_cfg, + ) + + logger.log_info("Generic training initialized") + logger.log_info(f"Task: {type(env).__name__}") + logger.log_info( + f"Policy: {policy_name} (available: {get_registered_policy_names()})" + ) + logger.log_info( + f"Algorithm: {algo_name} (available: {get_registered_algo_names()})" + ) + + total_steps = int(iterations * rollout_steps * env.num_envs) + logger.log_info(f"Total steps: {total_steps} (iterations≈{iterations})") + + try: + trainer.train(total_steps) + except KeyboardInterrupt: + logger.log_info("Training interrupted by user") + finally: + trainer.save_checkpoint() + writer.close() + if use_wandb: + try: + wandb.finish() + except Exception: + pass + logger.log_info("Training finished") + + +if __name__ == "__main__": + main() diff --git a/embodichain/agents/rl/utils/__init__.py b/embodichain/agents/rl/utils/__init__.py new file mode 100644 index 00000000..f6f9f4f9 --- /dev/null +++ b/embodichain/agents/rl/utils/__init__.py @@ -0,0 +1,21 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .config import AlgorithmCfg + +__all__ = [ + "AlgorithmCfg", +] diff --git a/embodichain/agents/rl/utils/config.py b/embodichain/agents/rl/utils/config.py new file mode 100644 index 00000000..2a89e243 --- /dev/null +++ b/embodichain/agents/rl/utils/config.py @@ -0,0 +1,29 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from embodichain.utils import configclass + + +@configclass +class AlgorithmCfg: + """Minimal algorithm configuration shared across RL algorithms.""" + + device: str = "cuda" + learning_rate: float = 3e-4 + batch_size: int = 64 + gamma: float = 0.99 + gae_lambda: float = 0.95 + max_grad_norm: float = 0.5 diff --git a/embodichain/agents/rl/utils/trainer.py b/embodichain/agents/rl/utils/trainer.py new file mode 100644 index 00000000..0ae1fb1e --- /dev/null +++ b/embodichain/agents/rl/utils/trainer.py @@ -0,0 +1,265 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +from typing import Dict, Any, Tuple, Callable, Optional +import time +import numpy as np +import torch +from torch.utils.tensorboard import SummaryWriter +from collections import deque +import wandb + +from embodichain.lab.gym.envs.managers.event_manager import EventManager + + +class Trainer: + """Algorithm-agnostic trainer that coordinates training loop, logging, and evaluation.""" + + def __init__( + self, + policy, + env, + algorithm, + num_steps: int, + batch_size: int, + writer: SummaryWriter | None, + eval_freq: int, + save_freq: int, + checkpoint_dir: str, + exp_name: str, + use_wandb: bool = True, + eval_env=None, + event_cfg=None, + eval_event_cfg=None, + ): + self.policy = policy + self.env = env + self.eval_env = eval_env + self.algorithm = algorithm + self.num_steps = num_steps + self.batch_size = batch_size + self.writer = writer + self.eval_freq = eval_freq + self.save_freq = save_freq + self.checkpoint_dir = checkpoint_dir + self.exp_name = exp_name + self.use_wandb = use_wandb + + if event_cfg is not None: + self.event_manager = EventManager(event_cfg, env=self.env) + if eval_event_cfg is not None: + self.eval_event_manager = EventManager(eval_event_cfg, env=self.eval_env) + + # Get device from algorithm + self.device = self.algorithm.device + self.global_step = 0 + self.start_time = time.time() + self.ret_window = deque(maxlen=100) + self.len_window = deque(maxlen=100) + + # initial obs (assume env returns torch tensors already on target device) + obs, _ = self.env.reset() + self.obs = obs + + # Initialize algorithm's buffer + self.observation_space = getattr(self.env, "observation_space", None) + self.action_space = getattr(self.env, "action_space", None) + obs_dim = ( + self.observation_space.shape[-1] + if self.observation_space + else self.obs.shape[-1] + ) + action_dim = self.action_space.shape[-1] if self.action_space else None + if action_dim is None: + raise RuntimeError( + "Env must expose action_space with shape for buffer initialization." + ) + num_envs = self.obs.shape[0] if self.obs.ndim == 2 else 1 + + # Algorithm manages its own buffer + self.algorithm.initialize_buffer(num_steps, num_envs, obs_dim, action_dim) + + # episode stats tracked on device to avoid repeated CPU round-trips + self.curr_ret = torch.zeros(num_envs, dtype=torch.float32, device=self.device) + self.curr_len = torch.zeros(num_envs, dtype=torch.int32, device=self.device) + + # ---- lightweight helpers for dense logging ---- + @staticmethod + def _mean_scalar(x) -> float: + if hasattr(x, "detach"): + x = x.detach().cpu().numpy() + else: + x = np.asarray(x) + return float(np.mean(x)) + + def _log_scalar_dict(self, prefix: str, data: dict): + if not self.writer or not isinstance(data, dict): + return + for k, v in data.items(): + try: + self.writer.add_scalar( + f"{prefix}/{k}", self._mean_scalar(v), self.global_step + ) + except Exception: + continue + + def _pack_log_dict(self, prefix: str, data: dict) -> dict: + if not isinstance(data, dict): + return {} + out = {} + for k, v in data.items(): + try: + out[f"{prefix}/{k}"] = self._mean_scalar(v) + except Exception: + continue + return out + + def train(self, total_timesteps: int): + print(f"Start training, total steps: {total_timesteps}") + while self.global_step < total_timesteps: + self._collect_rollout() + losses = self.algorithm.update() + self._log_train(losses) + if self.global_step % self.eval_freq == 0: + self._eval_once() + if self.global_step % self.save_freq == 0: + self.save_checkpoint() + + @torch.no_grad() + def _collect_rollout(self): + """Collect a rollout. Algorithm controls the data collection process.""" + + # Callback function for statistics and logging + def on_step(obs, actions, reward, done, info, next_obs): + """Callback called at each step during rollout collection.""" + # Episode stats (stay on device; convert only when episode ends) + self.curr_ret += reward + self.curr_len += 1 + done_idx = torch.nonzero(done, as_tuple=False).squeeze(-1) + if done_idx.numel() > 0: + finished_ret = self.curr_ret[done_idx].detach().cpu().tolist() + finished_len = self.curr_len[done_idx].detach().cpu().tolist() + self.ret_window.extend(finished_ret) + self.len_window.extend(finished_len) + self.curr_ret[done_idx] = 0 + self.curr_len[done_idx] = 0 + + # Update global step and observation + self.obs = next_obs + self.global_step += next_obs.shape[0] if next_obs.ndim == 2 else 1 + + if isinstance(info, dict): + rewards_dict = info.get("rewards") + metrics_dict = info.get("metrics") + self._log_scalar_dict("rewards", rewards_dict) + self._log_scalar_dict("metrics", metrics_dict) + log_dict = {} + log_dict.update(self._pack_log_dict("rewards", rewards_dict)) + log_dict.update(self._pack_log_dict("metrics", metrics_dict)) + if log_dict and self.use_wandb: + wandb.log(log_dict, step=self.global_step) + + # Algorithm controls data collection + result = self.algorithm.collect_rollout( + env=self.env, + policy=self.policy, + obs=self.obs, + num_steps=self.num_steps, + on_step_callback=on_step, + ) + + def _log_train(self, losses: Dict[str, float]): + if self.writer: + for k, v in losses.items(): + self.writer.add_scalar(f"train/{k}", v, self.global_step) + elapsed = max(1e-6, time.time() - self.start_time) + sps = self.global_step / elapsed + self.writer.add_scalar("charts/SPS", sps, self.global_step) + if len(self.ret_window) > 0: + self.writer.add_scalar( + "charts/episode_reward_avg_100", + float(np.mean(self.ret_window)), + self.global_step, + ) + if len(self.len_window) > 0: + self.writer.add_scalar( + "charts/episode_length_avg_100", + float(np.mean(self.len_window)), + self.global_step, + ) + # console + sps = self.global_step / max(1e-6, time.time() - self.start_time) + avgR = np.mean(self.ret_window) if len(self.ret_window) > 0 else float("nan") + avgL = np.mean(self.len_window) if len(self.len_window) > 0 else float("nan") + print( + f"[train] step={self.global_step} sps={sps:.0f} avgReward(100)={avgR:.3f} avgLength(100)={avgL:.1f}" + ) + + # wandb (mirror TB logs) + if self.use_wandb: + log_dict = {f"train/{k}": v for k, v in losses.items()} + log_dict["charts/SPS"] = sps + if not np.isnan(avgR): + log_dict["charts/episode_reward_avg_100"] = float(avgR) + if not np.isnan(avgL): + log_dict["charts/episode_length_avg_100"] = float(avgL) + wandb.log(log_dict, step=self.global_step) + + @torch.no_grad() + def _eval_once(self, num_episodes: int = 5): + self.policy.eval() + returns = [] + for _ in range(num_episodes): + obs, _ = self.eval_env.reset() + done_any = torch.zeros( + obs.shape[0] if obs.ndim == 2 else 1, + dtype=torch.bool, + device=self.device, + ) + num_envs_eval = obs.shape[0] if obs.ndim == 2 else 1 + ep_ret = torch.zeros(num_envs_eval, dtype=torch.float32, device=self.device) + while not done_any.any(): + actions, _, _ = self.policy.get_action(obs, deterministic=True) + result = self.eval_env.step(actions) + obs, reward, terminated, truncated, info = result + done = terminated | truncated + reward = reward.float() + done_any = done + ep_ret += reward + + if hasattr(self, "eval_event_manager"): + if "interval" in self.eval_event_manager.available_modes: + self.eval_event_manager.apply(mode="interval") + + returns.extend(ep_ret.detach().cpu().tolist()) + if self.writer and len(returns) > 0: + self.writer.add_scalar( + "eval/avg_reward", float(np.mean(returns)), self.global_step + ) + + def save_checkpoint(self): + # minimal model-only checkpoint; trainer/algorithm states can be added + path = f"{self.checkpoint_dir}/{self.exp_name}_step_{self.global_step}.pt" + torch.save( + { + "global_step": self.global_step, + "policy": self.policy.state_dict(), + }, + path, + ) + print(f"Checkpoint saved: {path}") diff --git a/embodichain/data/__init__.py b/embodichain/data/__init__.py new file mode 100644 index 00000000..f97508ac --- /dev/null +++ b/embodichain/data/__init__.py @@ -0,0 +1,35 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os + +database_dir = os.path.dirname(os.path.abspath(__file__)).replace("data", "database") +video_dir = os.path.join(database_dir, "video") +weights_dir = os.path.join(database_dir, "weights") +database_2d_dir = os.path.join(database_dir, "2dasset") +database_lang_dir = os.path.join(database_dir, "lang") +database_demo_dir = os.path.join(database_dir, "demostration") +database_tmp_dir = os.path.join(database_dir, "tmp") +database_train_dir = os.path.join(database_dir, "train") + + +if not os.path.exists(database_tmp_dir): + os.makedirs(database_tmp_dir, exist_ok=True) +if not os.path.exists(database_train_dir): + os.makedirs(database_train_dir, exist_ok=True) + +from . import assets +from .dataset import * diff --git a/embodichain/data/assets/__init__.py b/embodichain/data/assets/__init__.py new file mode 100644 index 00000000..875628de --- /dev/null +++ b/embodichain/data/assets/__init__.py @@ -0,0 +1,23 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .materials import * +from .demo_assets import * +from .obj_assets import * +from .w1_assets import * +from .eef_assets import * +from .robot_assets import * +from .scene_assets import * diff --git a/embodichain/data/assets/demo_assets.py b/embodichain/data/assets/demo_assets.py new file mode 100644 index 00000000..8480d468 --- /dev/null +++ b/embodichain/data/assets/demo_assets.py @@ -0,0 +1,46 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import open3d as o3d +from pathlib import Path +from embodichain.data.dataset import EmbodiChainDataset +from embodichain.data.constants import ( + EMBODICHAIN_DOWNLOAD_PREFIX, + EMBODICHAIN_DEFAULT_DATA_ROOT, +) + + +class ScoopIceNewEnv(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/demo/ScoopIceNewEnv.zip", + "e92734a9de0f64be33a11fbda0fbd3b6", + ) + prefix = "ScoopIceNewEnv" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class MultiW1Data(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/demo/multi_w1_demo.zip", + "984e8fa3aa05cb36a1fd973a475183ed", + ) + prefix = "MultiW1Data" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + super().__init__(prefix, data_descriptor, path) diff --git a/embodichain/data/assets/eef_assets.py b/embodichain/data/assets/eef_assets.py new file mode 100644 index 00000000..fa1e9aae --- /dev/null +++ b/embodichain/data/assets/eef_assets.py @@ -0,0 +1,264 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + + +import open3d as o3d +from embodichain.data.dataset import EmbodiChainDataset +from embodichain.data.constants import ( + EMBODICHAIN_DOWNLOAD_PREFIX, + EMBODICHAIN_DEFAULT_DATA_ROOT, +) + + +class DH_PGC_140_50(EmbodiChainDataset): + """Dataset class for the DH Robotics PGC-140-50 end-effector gripper. + + Reference: + https://www.dh-robotics.com/product/pgc + + Directory structure: + DH_PGC_140_50/ + DH_PGC_140_50.urdf + + Example usage: + >>> from embodichain.data.eef_dataset import DH_PGC_140_50 + >>> dataset = DH_PGC_140_50() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("DH_PGC_140_50/DH_PGC_140_50.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/eef_assets/DH_PGC_140_50.zip", + "c2a642308a76e99b1b8b7cb3a11c5df3", + ) + prefix = "DH_PGC_140_50" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class DH_PGI_140_80(EmbodiChainDataset): + """Dataset class for the DH Robotics PGI-140-80 end-effector gripper. + + Reference: + https://www.dh-robotics.com/product/pgia### + + Directory structure: + DH_PGI_140_80/ + DH_PGI_140_80.urdf + + Example usage: + >>> from embodichain.data.eef_dataset import DH_PGI_140_80 + >>> dataset = DH_PGI_140_80() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("DH_PGI_140_80/DH_PGI_140_80.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/eef_assets/DH_PGI_140_80.zip", + "05a1a08b13c6250cc12affeeda3a08ba", + ) + prefix = "DH_PGI_140_80" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class DH_PGC_140_50_M(EmbodiChainDataset): + """Dataset class for the DH Robotics PGC-140-50 end-effector gripper. + DexForce modified connector and finger. + + Reference: + https://www.dh-robotics.com/product/pgc + + Directory structure: + DH_PGC_140_50_M/ + DH_PGC_140_50_M.urdf + + Example usage: + >>> from embodichain.data.eef_dataset import DH_PGC_140_50_M + >>> dataset = DH_PGC_140_50_M() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("DH_PGC_140_50_M/DH_PGC_140_50_M.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/eef_assets/DH_PGC_140_50_M.zip", + "3a9ab5f32639e03afb38dc033b44bb62", + ) + prefix = "DH_PGC_140_50_M" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class ZH_CTM2F110(EmbodiChainDataset): + """Dataset class for the Zhixing Robot Technology CTM2F110 end-effector gripper. + + Reference: + https://www.changingtek.com/service + + Directory structure: + ZH_CTM2F110/ + ZH_CTM2F110.urdf + + Example usage: + >>> from embodichain.data.eef_dataset import ZH_CTM2F110 + >>> dataset = ZH_CTM2F110() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("ZH_CTM2F110/ZH_CTM2F110.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/eef_assets/ZH_CTM2F110.zip", + "0e7c3310425609797fe010b2a76fe465", + ) + prefix = "ZH_CTM2F110" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class BrainCoHandRevo1(EmbodiChainDataset): + """Dataset class for the BrainCo Hand Revo 1 robotic hand. + + Reference: + https://www.brainco-hz.com/docs/revolimb-hand/revo1/parameters.html + + Directory structure: + BrainCoHandRevo1/ + BrainCoRightHand/BrainCoRightHand.urdf + BrainCoLeftHand/BrainCoLeftHand.urdf + + Example usage: + >>> from embodichain.data.eef_dataset import BrainCoHandRevo1 + >>> dataset = BrainCoHandRevo1() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("BrainCoHandRevo1/BrainCoRightHand/BrainCoRightHand.urdf")) + >>> print(get_data_path("BrainCoHandRevo1/BrainCoLeftHand/BrainCoLeftHand.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/eef_assets/BrainCoHandRevo01.zip", + "ff9ac77e7e1493fd32d40c87fecbee6c", + ) + prefix = "BrainCoHandRevo1" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class InspireHand(EmbodiChainDataset): + """Dataset class for the Inspire Hand robotic hand. + + Reference: + https://en.inspire-robots.com/product/rh56bfx + + Directory structure: + InspireHand/ + InspireLeftHand/InspireLeftHand.urdf + InspireRightHand/InspireRightHand.urdf + inspire_joint_data.csv + inspire_joint_data.npy + + Example usage: + >>> from embodichain.data.eef_dataset import InspireHand + >>> dataset = InspireHand() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("InspireHand/InspireLeftHand/InspireLeftHand.urdf")) + >>> print(get_data_path("InspireHand/InspireRightHand/InspireRightHand.urdf")) + >>> print(get_data_path("InspireHand/inspire_joint_data.csv")) + >>> print(get_data_path("InspireHand/inspire_joint_data.npy")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/eef_assets/InspireHand.zip", + "c60132a6f03866fb021cca5b6d72845e", + ) + prefix = "InspireHand" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class Robotiq2F85(EmbodiChainDataset): + """Dataset class for the Robotiq 2F85 robotic gripper. + + Reference: + https://robotiq.com/products/adaptive-grippers#Two-Finger-Gripper + + Directory structure: + Robotiq2F85/ + Robotiq2F85.urdf + + Example usage: + >>> from embodichain.data.eef_dataset import Robotiq2F85 + >>> dataset = Robotiq2F85() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("Robotiq2F85/Robotiq2F85.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/eef_assets/Robotiq2F85.zip", + "53ecbf2c953f43f1134aa7223e592292", + ) + prefix = "Robotiq2F85" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class WheelTecFA2F(EmbodiChainDataset): + """Dataset class for the WheelTec FA 2 fingers robotic gripper. + + Reference: + https://www.wheeltec.net/ + + Directory structure: + WheelTecFA2F/ + WheelTecFA2F.urdf + + Example usage: + >>> from embodichain.data.eef_dataset import WheelTecFA2F + >>> dataset = WheelTecFA2F() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("WheelTecFA2F/WheelTecFA2F.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/eef_assets/WheelTecFA2F.zip", + "feaf13f25b1c6ce58d011b1f2fa72f58", + ) + prefix = "WheelTecFA2F" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) diff --git a/embodichain/data/assets/materials.py b/embodichain/data/assets/materials.py new file mode 100644 index 00000000..784d6c6d --- /dev/null +++ b/embodichain/data/assets/materials.py @@ -0,0 +1,107 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import open3d as o3d + +from pathlib import Path +from typing import List + +from embodichain.data.dataset import EmbodiChainDataset +from embodichain.utils import logger +from embodichain.data.constants import ( + EMBODICHAIN_DOWNLOAD_PREFIX, + EMBODICHAIN_DEFAULT_DATA_ROOT, +) + + +class SimResources(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/materials/embodisim_resources.zip", + "53c054b3ae0857416dc52632eb562c12", + ) + prefix = "SimResources" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + def get_ibl_path(self, name: str) -> str: + """Get the path of the IBL resource. + + Args: + name (str): The name of the IBL resource. + + Returns: + str: The path to the IBL resource. + """ + ibl_names = self.get_ibl_list() + if name not in ibl_names: + logger.log_error( + f"Invalid IBL name: {name}. Available names are: {ibl_names}" + ) + return str(Path(self.extract_dir) / "embodysim_resources" / "IBL" / name) + + def get_ibl_list(self) -> List[str]: + """Get the names of all IBL resources. + + Returns: + List[str]: The names of all IBL resources. + """ + return [ + f.name + for f in Path(self.extract_dir).glob("embodysim_resources/IBL/*") + if f.is_dir() + ] + + def get_material_path(self, name: str) -> str: + """Get the path of the material resource. + + Args: + name (str): The name of the material resource. + + Returns: + str: The path to the material resource. + """ + material_names = self.get_material_list() + if name not in material_names: + logger.log_error( + f"Invalid material name: {name}. Available names are: {material_names}" + ) + return str(Path(self.extract_dir) / "embodysim_resources" / "materials" / name) + + def get_material_list(self) -> List[str]: + """Get the names of all material resources. + + Returns: + List[str]: The names of all material resources. + """ + return [ + f.name + for f in Path(self.extract_dir).glob("embodysim_resources/materials/*") + if f.is_dir() + ] + + +class CocoBackground(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/materials/CocoBackground.zip", + "fda82404a317281263bd5849e9eb31a1", + ) + prefix = "CocoBackground" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) diff --git a/embodichain/data/assets/obj_assets.py b/embodichain/data/assets/obj_assets.py new file mode 100644 index 00000000..6c2310f8 --- /dev/null +++ b/embodichain/data/assets/obj_assets.py @@ -0,0 +1,215 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + + +import open3d as o3d +from embodichain.data.dataset import EmbodiChainDataset +from embodichain.data.constants import ( + EMBODICHAIN_DOWNLOAD_PREFIX, + EMBODICHAIN_DEFAULT_DATA_ROOT, +) + + +class ShopTableSimple(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/shop_table_simple.zip", + "e3061ee024de7840f773b70140dcd43f", + ) + prefix = "ShopTableSimple" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class CircleTableSimple(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/circle_table_simple.zip", + "42ad2be8cd0caddcf9bfbf106b7783f3", + ) + prefix = "CircleTableSimple" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class PlasticBin(o3d.data.DownloadDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/plastic_bin.zip", + "21e00083689a4a3c4e4ae3fd89c61e55", + ) + prefix = "PlasticBin" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class Chair(o3d.data.DownloadDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/chair.zip", + "df3d7d1a05731d45fb2c678a40a39cd4", + ) + prefix = "Chair" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class ContainerMetal(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/container_metal.zip", + "ceafb87f8177609f87aaa6779fcbb9a3", + ) + prefix = "ContainerMetal" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class SimpleBoxDrawer(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/simple_box_drawer.zip", + "966b648bca16823ee91525847c183973", + ) + prefix = "SimpleBoxDrawer" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class AdrianoTable(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/adriano_table.zip", + "8453583a9a1a9d04d50268f8a3da554f", + ) + prefix = "AdrianoTable" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class CoffeeCup(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/CoffeeCup.zip", + "f05fce385826414c15e19df3b75dc886", + ) + prefix = "CoffeeCup" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class SlidingBoxDrawer(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/SlidingBoxDrawer.zip", + "b03d9006503d27b75ddeb06d31b2c7a5", + ) + prefix = "SlidingBoxDrawer" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class AiLiMu_BoxDrawer(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + EMBODICHAIN_DOWNLOAD_PREFIX + "AiLiMu_BoxDrawer_v3.zip", + "9a2889151a23d482f95f602cce9900c6", + ) + prefix = "AiLiMu_BoxDrawer" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class AluminumTable(o3d.data.DownloadDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + EMBODICHAIN_DOWNLOAD_PREFIX + "AluminumTable.glb", + "02991d36ca9b70f019ed330a61143aa9", + ) + prefix = "AluminumTable" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class ToyDuck(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + EMBODICHAIN_DOWNLOAD_PREFIX + "ToyDuck.zip", + "2f5c00ba487edf34ad668f7257c0264e", + ) + prefix = "ToyDuck" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class PaperCup(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + EMBODICHAIN_DOWNLOAD_PREFIX + "PaperCup.zip", + "359d13af8c5f31ad3226d8994a1a7198", + ) + prefix = "PaperCup" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class ChainRainSec(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/lianguijie.zip", + "2387589040a4d3f2676b622362452242", + ) + prefix = "ChainRainSec" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class TableWare(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/tableware.zip", + "403e340fc0e4996c002ee774f89cd236", + ) + prefix = "TableWare" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class ScannedBottle(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/ScannedBottle.zip", + "d2b2d4deb7b463a734af099f7624b4af", + ) + prefix = "ScannedBottle" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) diff --git a/embodichain/data/assets/robot_assets.py b/embodichain/data/assets/robot_assets.py new file mode 100644 index 00000000..60a33678 --- /dev/null +++ b/embodichain/data/assets/robot_assets.py @@ -0,0 +1,463 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + + +import open3d as o3d +from embodichain.data.dataset import EmbodiChainDataset +from embodichain.data.constants import ( + EMBODICHAIN_DOWNLOAD_PREFIX, + EMBODICHAIN_DEFAULT_DATA_ROOT, +) + + +class CobotMagicArm(EmbodiChainDataset): + """Dataset class for the Cobot Magic Arm robot. + + Reference: + https://global.agilex.ai/products/cobot-magic + + Directory structure: + CobotMagicArm/ + CobotMagicNoGripper.urdf + CobotMagicWithGripperV70.urdf + CobotMagicWithGripperV70NewUV.urdf + CobotMagicWithGripperV70NoMaterial.urdf + CobotMagicWithGripperV100.urdf + CobotMagicWithGripperV100NewUV.urdf + CobotMagicWithGripperV100NoMaterial.urdf + + Example usage: + >>> from embodichain.data.robot_dataset import CobotMagicArm + >>> dataset = CobotMagicArm() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("CobotMagicArm/CobotMagicWithGripperV100.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/CobotMagicArmV2.zip", + "14af3e84b74193680899a59fc74e8337", + ) + prefix = "CobotMagicArm" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class RidgeBack(EmbodiChainDataset): + """Dataset class for the RidgeBack wheeled robot. + + Reference: + https://clearpathrobotics.com/ridgeback-indoor-robot-platform/ + + Directory structure: + RidgeBack/ + RidgeBack.urdf + + Example usage: + >>> from embodichain.data.robot_dataset import RidgeBack + >>> dataset = RidgeBack() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("RidgeBack/RidgeBack.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/RidgeBack.zip", + "f03e1a6f4c781ad8957a88bdb010e9b6", + ) + prefix = "RidgeBack" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class UnitreeH1(EmbodiChainDataset): + """Dataset class for the Unitree H1 robot. + + Reference: + https://www.unitree.com/h1/ + + Directory structure: + UnitreeH1/ + UnitreeH1.urdf + UnitreeH1WithWrist.urdf + + Example usage: + >>> from embodichain.data.robot_dataset import UnitreeH1 + >>> dataset = UnitreeH1() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("UnitreeH1/UnitreeH1.urdf")) + >>> print(get_data_path("UnitreeH1/UnitreeH1WithWrist.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/UnitreeH1.zip", + "339417cef5051a912693f3c64d29dddc", + ) + prefix = "UnitreeH1" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class ABB(EmbodiChainDataset): + """Dataset class for the ABB robot. + + Reference: + https://global.abb/ + + Directory structure: + ABB/ + IRB1200_5_90/IRB1200_5_90.urdf + IRB2600_12_165/IRB2600_12_165.urdf + + Example usage: + >>> from embodichain.data.robot_dataset import ABB + >>> dataset = ABB() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("ABB/IRB1200_5_90/IRB1200_5_90.urdf")) + >>> print(get_data_path("ABB/IRB2600_12_165/IRB2600_12_165.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/ABB.zip", + "ea6df4983982606c43387783e5fb8c05", + ) + prefix = "ABB" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class Motoman(EmbodiChainDataset): + """Dataset class for the Motoman robot. + + Reference: + https://www.motoman.com/en-us + + Directory structure: + Motoman/ + GP7/GP7.urdf + GP12/GP12.urdf + + Example usage: + >>> from embodichain.data.robot_dataset import Motoman + >>> dataset = Motoman() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("Motoman/GP7/GP7.urdf")) + >>> print(get_data_path("Motoman/GP12/GP12.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/Motoman.zip", + "ee5f16cfce34d8e2cb996fcff8a25986", + ) + prefix = "Motoman" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class KUKA(EmbodiChainDataset): + """Dataset class for the KUKA robot. + + Reference: + https://www.kuka.com/ + + Directory structure: + KUKA/ + KUKA/KR6_R700_sixx/KR6_R700_sixx.urdf + KUKA/KR6_R900_sixx/KR6_R900_sixx.urdf + + Example usage: + >>> from embodichain.data.robot_dataset import ABB + >>> dataset = ABB() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("KUKA/KR6_R700_sixx/KR6_R700_sixx.urdf")) + >>> print(get_data_path("KUKA/KR6_R900_sixx/KR6_R900_sixx.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/KUKA.zip", + "da7a2dfd0db3f486e407f038d25c7537", + ) + prefix = "KUKA" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class Fanuc(EmbodiChainDataset): + """Dataset class for the Fanuc robot. + + Reference: + https://www.fanuc.com/ + + Directory structure: + Fanuc/ + M_20iA/M_20iA.urdf + R_2000iC_165F/R_2000iC_165F.urdf + + Example usage: + >>> from embodichain.data.robot_dataset import Fanuc + >>> dataset = Fanuc() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("Fanuc/KR6_R700_sixx/KR6_R700_sixx.urdf")) + >>> print(get_data_path("Fanuc/KR6_R900_sixx/KR6_R900_sixx.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/Fanuc.zip", + "0a1c562f4719f7cdc1b24545fec4a301", + ) + prefix = "Fanuc" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class UniversalRobots(EmbodiChainDataset): + """Dataset class for the Universal Robots. + + Reference: + https://www.universal-robots.com/products/ur-series/ + + Directory structure: + UniversalRobots/ + UR3/UR3.urdf + UR3e/UR3e.urdf + UR5/UR5.urdf + UR5e/UR5e.urdf + UR10/UR10.urdf + UR10e/UR10e.urdf + + Example usage: + >>> from embodichain.data.robot_dataset import UniversalRobots + >>> dataset = UniversalRobots() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("UniversalRobots/UR3/UR3.urdf")) + >>> print(get_data_path("UniversalRobots/UR3e/UR3e.urdf")) + >>> print(get_data_path("UniversalRobots/UR5/UR5.urdf")) + >>> print(get_data_path("UniversalRobots/UR5e/UR5e.urdf")) + >>> print(get_data_path("UniversalRobots/UR10/UR10.urdf")) + >>> print(get_data_path("UniversalRobots/UR10e/UR10e.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/UniversalRobots.zip", + "dbd12f7e36cef4e5025b82f748233b80", + ) + prefix = "UniversalRobots" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class Rokae(EmbodiChainDataset): + """Dataset class for the Rokae robots. + + Reference: + https://www.rokae.com/en/product/show/349/SR-Cobots.html + + Directory structure: + Rokae/ + SR3/SR3.urdf + SR5/SR5.urdf + + Example usage: + >>> from embodichain.data.robot_dataset import Rokae + >>> dataset = Rokae() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("Rokae/SR3/SR3.urdf")) + >>> print(get_data_path("Rokae/SR5/SR5.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/Rokae.zip", + "fbfb852d6139e94b7c422771542f988f", + ) + prefix = "Rokae" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class Franka(EmbodiChainDataset): + """Dataset class for the Franka robots. + + Reference: + https://franka.de/franka-research-3 + + Directory structure: + Franka/ + Panda/Panda.urdf + PandaHand/PandaHand.urdf + PandaWithHand/PandaWithHand.urdf + + Example usage: + >>> from embodichain.data.robot_dataset import Franka + >>> dataset = Franka() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("Franka/Panda/Panda.urdf")) + >>> print(get_data_path("Franka/PandaHand/PandaHand.urdf")) + >>> print(get_data_path("Franka/PandaWithHand/PandaWithHand.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/Franka.zip", + "c2de367fe1da02eeb45a8129f903d0b6", + ) + prefix = "Franka" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class Agile(EmbodiChainDataset): + """Dataset class for the Agile robots. + + Reference: + https://www.agile-robots.com/en/solutions/diana-7/ + + Directory structure: + Agile/ + Diana7/Diana7.urdf + + Example usage: + >>> from embodichain.data.robot_dataset import Agile + >>> dataset = Agile() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("Agile/Diana7/Diana7.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/Agile.zip", + "fd47d7ab8a4d13960fd76e59544ba836", + ) + prefix = "Agile" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class Hans(EmbodiChainDataset): + """Dataset class for the Hans robots. + + Reference: + https://www.huayan-robotics.com/elfin + + Directory structure: + Hans/ + E05/E05.urdf + E10/E10.urdf + + Example usage: + >>> from embodichain.data.robot_dataset import Hans + >>> dataset = Hans() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("Hans/E05/E05.urdf")) + >>> print(get_data_path("Hans/E10/E10.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/Hans.zip", + "c867c406e3dffd6982fd0a15e7dc7e29", + ) + prefix = "Hans" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class Aubo(EmbodiChainDataset): + """Dataset class for the Aubo robots. + + Reference: + https://www.aubo-robotics.cn/ + + Directory structure: + Aubo/ + i5/i5.urdf + + Example usage: + >>> from embodichain.data.robot_dataset import Aubo + >>> dataset = Aubo() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("Aubo/i5/i5.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/Aubo.zip", + "2574649cd199c11267cc0f4aeac65557", + ) + prefix = "Aubo" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class RainbowY1(EmbodiChainDataset): + """Dataset class for the Aubo robots. + + Reference: + https://www.rainbow-robotics.com/en_rby1 + + Directory structure: + RainbowY1/ + RainbowY1.urdf + + Example usage: + >>> from embodichain.data.robot_dataset import RainbowY1 + >>> dataset = RainbowY1() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("RainbowY1/RainbowY1.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/RainbowY1.zip", + "5979a3aaadb5de6488b13765d523564f", + ) + prefix = "RainbowY1" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) diff --git a/embodichain/data/assets/scene_assets.py b/embodichain/data/assets/scene_assets.py new file mode 100644 index 00000000..bd6e30a3 --- /dev/null +++ b/embodichain/data/assets/scene_assets.py @@ -0,0 +1,63 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import open3d as o3d +from pathlib import Path +from embodichain.data.dataset import EmbodiChainDataset +from embodichain.data.constants import ( + EMBODICHAIN_DOWNLOAD_PREFIX, + EMBODICHAIN_DEFAULT_DATA_ROOT, +) + + +class SceneData(EmbodiChainDataset): + """Dataset class for the Scene. + + Directory structure: + SceneData/ + factory.glb + kitchen.gltf + office.glb + + Example usage: + >>> from embodichain.data.assets.scene_assets import SceneData + >>> data = SceneData() + or + >>> from embodichain.data import get_data_path + >>> print(get_data_path("Scenedata/factory.glb")) + """ + + def __init__(self, data_root: str = None): + + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/scene_assets/SceneData.zip", + "fb46e4694cc88886fc785704e891a68a", + ) + prefix = "SceneData" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + super().__init__(prefix, data_descriptor, path) + + +class EmptyRoom(o3d.data.DownloadDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/scene_assets/empty_room.zip", + "612ffead4fac95114bec2e3812469f96", + ) + prefix = "EmptyRoom" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) diff --git a/embodichain/data/assets/w1_assets.py b/embodichain/data/assets/w1_assets.py new file mode 100644 index 00000000..b46e807f --- /dev/null +++ b/embodichain/data/assets/w1_assets.py @@ -0,0 +1,210 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import open3d as o3d +from embodichain.data.dataset import EmbodiChainDataset +from embodichain.data.constants import ( + EMBODICHAIN_DOWNLOAD_PREFIX, + EMBODICHAIN_DEFAULT_DATA_ROOT, +) + +# ================= Dexforce W1 Asset Dataset Overview ================= +# This file provides dataset classes for the Dexforce W1 humanoid robot +# and its individual components. +# +# Main Asset: +# - DexforceW1V021: +# Represents the complete humanoid robot asset, +# including both industrial arms and anthropomorphic arms. +# +# Component Assets: +# - DexforceW1ChassisV021: Chassis component +# - DexforceW1TorsoV021: Torso component +# - DexforceW1EyesV021: Eyes component +# - DexforceW1HeadV021: Head component +# +# Arm Assets: +# - DexforceW1LeftArm1V021 / DexforceW1RightArm1V021: +# Anthropomorphic (human-like) arms, left and right. +# - DexforceW1LeftArm2V021 / DexforceW1RightArm2V021: +# Industrial arms, left and right. +# +# All classes inherit from EmbodiChainDataset and are responsible for +# downloading and managing the data resources for their respective components. +# ====================================================================== + + +class DexforceW1V021(EmbodiChainDataset): + """Dataset class for the Dexforce W1 V021. + + Directory structure: + DexforceW1V021/DexforceW1V021.urdf + + Example usage: + >>> from embodichain.data import get_data_path + >>> print(get_data_path("DexforceW1V021/DexforceW1_v02_1.urdf")) + >>> print(get_data_path("DexforceW1V021/DexforceW1_v02_2.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/DexforceW1V021.zip", + "3cc3a0bfd1c50ebed5bee9dadeee6756", + ) + prefix = "DexforceW1V021" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class DexforceW1V021_INDUSTRIAL_DH_PGC_GRIPPER_M(EmbodiChainDataset): + """Dataset class for the industrial Dexforce W1 V021 with DH_PGC_gripper. + + Directory structure: + DexforceW1V021_INDUSTRIAL_DH_PGC_GRIPPER_M/DexforceW1V021.urdf + + Example usage: + >>> from embodichain.data import get_data_path + >>> print(get_data_path("DexforceW1V021_INDUSTRIAL_DH_PGC_GRIPPER_M/DexforceW1V021.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/DexforceW1V021_INDUSTRIAL_DH_PGC_GRIPPER_M.zip", + "06ec5dfa76dc69160d7ff9bc537a6a7b", + ) + prefix = "DexforceW1V021_INDUSTRIAL_DH_PGC_GRIPPER_M" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class DexforceW1V021_ANTHROPOMORPHIC_BRAINCO_HAND_REVO1(EmbodiChainDataset): + """Dataset class for the anthropomorphic Dexforce W1 V021 with BrainCo_hand_revo_1. + + Directory structure: + DexforceW1V021_ANTHROPOMORPHIC_BRAINCO_HAND_REVO1/DexforceW1V021.urdf + + Example usage: + >>> from embodichain.data import get_data_path + >>> print(get_data_path("DexforceW1V021_ANTHROPOMORPHIC_BRAINCO_HAND_REVO1/DexforceW1V021.urdf")) + """ + + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/DexforceW1V021_ANTHROPOMORPHIC_BRAINCO_HAND_REVO1.zip", + "ef19d247799e79233863b558c47b32cd", + ) + prefix = "DexforceW1V021_ANTHROPOMORPHIC_BRAINCO_HAND_REVO1" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class DexforceW1ChassisV021(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/W1_Chassis_v021.zip", + "6b0517a4d92a572988641d46269d063f", + ) + prefix = "DexforceW1ChassisV021" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class DexforceW1TorsoV021(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/W1_Torso_v021.zip", + "4f762a3ae6ef2acbe484c915cf80da7b", + ) + prefix = "DexforceW1TorsoV021" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class DexforceW1EyesV021(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/W1_Eyes_v021.zip", + "80e0b86ef2e934f439c99b79074f6f3c", + ) + prefix = "DexforceW1EyesV021" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class DexforceW1HeadV021(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/W1_Head_v021.zip", + "ba72805828c5fd62ad55d6a1458893d0", + ) + prefix = "DexforceW1HeadV021" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class DexforceW1LeftArm1V021(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/W1_LeftArm_1_v021.zip", + "c3cacda7bd36389ed98620047bff6216", + ) + prefix = "DexforceW1LeftArm1V021" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class DexforceW1RightArm1V021(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/W1_RightArm_1_v021.zip", + "456c9495748171003246a3f6626bb0db", + ) + prefix = "DexforceW1RightArm2V021" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class DexforceW1LeftArm2V021(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/W1_LeftArm_2_v021.zip", + "b99bd0587cc9a36fed3cdaa4f9fd62e7", + ) + prefix = "DexforceW1LeftArm2V021" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) + + +class DexforceW1RightArm2V021(EmbodiChainDataset): + def __init__(self, data_root: str = None): + data_descriptor = o3d.data.DataDescriptor( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/W1_RightArm_2_v021.zip", + "d9f25b2d5244ca5a859040327273a99e", + ) + prefix = "DexforceW1RightArm1V021" + path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root + + super().__init__(prefix, data_descriptor, path) diff --git a/embodichain/data/constants.py b/embodichain/data/constants.py new file mode 100644 index 00000000..3a4aa144 --- /dev/null +++ b/embodichain/data/constants.py @@ -0,0 +1,21 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + + +from pathlib import Path + +EMBODICHAIN_DOWNLOAD_PREFIX = "http://192.168.3.120/CoreEngine/Data/embodychain_data/" +EMBODICHAIN_DEFAULT_DATA_ROOT = str(Path.home() / ".cache" / "embodichain_data") diff --git a/embodichain/data/data_engine/__init__.py b/embodichain/data/data_engine/__init__.py new file mode 100644 index 00000000..e4655620 --- /dev/null +++ b/embodichain/data/data_engine/__init__.py @@ -0,0 +1,15 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- diff --git a/embodichain/data/data_engine/data_dict_extractor.py b/embodichain/data/data_engine/data_dict_extractor.py new file mode 100644 index 00000000..d56a5a94 --- /dev/null +++ b/embodichain/data/data_engine/data_dict_extractor.py @@ -0,0 +1,1135 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from embodichain.utils.logger import log_warning, log_error + +try: + import h5ffmpeg as hf + + has_h5ffmpeg = True +except Exception as e: + has_h5ffmpeg = False + log_warning("Fail to import h5ffmpeg.") + +import h5py +import os +import random +import torch +import numpy as np + +from functools import cached_property +from typing import Dict, Any, List, Union, Optional +from embodichain.data.enum import ( + Modality, + PrivilegeType, + JointType, +) +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim.sensors import StereoCamera +from embodichain.lab.gym.envs import BaseEnv, EmbodiedEnv +from embodichain.lab.gym.utils.gym_utils import map_qpos_to_eef_pose +from embodichain.utils.utility import get_right_name +from embodichain.lab.gym.utils.misc import _data_key_to_control_part +from embodichain.utils import logger +from embodichain.data.data_engine.unified_state import ( + StateUnifier, +) +from embodichain.data.enum import ( + SUPPORTED_PROPRIO_TYPES, + SUPPORTED_ACTION_TYPES, + SUPPORTED_EXTRA_VISION_TYPES, +) +from tqdm import tqdm +from copy import deepcopy + +SCALE_FACTOR = 4e3 # Scale factor for depth data +FAR_CLIP = 4.0 # m + +DATA_FORMATS = { + "observations": { + Modality.IMAGES.value: {}, + Modality.GEOMAP.value: {}, + PrivilegeType.MASK.value: {}, + PrivilegeType.EXTEROCEPTION.value: {}, + Modality.STATES.value: {}, + }, + Modality.ACTIONS.value: {}, +} + + +class CompressedVideoHDF5: + def __init__(self, save_path: str, chunks: int = 20) -> None: + """ + Initializes the data dictionary extractor with the specified save path and number of chunks. + Attempts to configure video encoding settings based on the detected GPU model using the h5ffmpeg library. + Supported GPUs include NVIDIA A800 and NVIDIA GeForce RTX 3060, with specific encoding configurations for each. + If the GPU is unsupported or an error occurs during initialization, a warning is logged and default configuration is used. + + Args: + save_path (str): Path where extracted data will be saved. + chunks (int, optional): Number of chunks to split the data into. Defaults to 20. + + Raises: + ValueError: If the detected GPU is not supported. + """ + self.save_path = save_path + self.chunks = chunks + + try: + import h5ffmpeg as hf + import torch + + name = torch.cuda.get_device_name() + + if "A800" in name or name == "NVIDIA A800-SXM4-80GB": + self.conf = { + Modality.GEOMAP.value: hf.x264( + preset="veryfast", tune="fastdecode" + ), + Modality.IMAGES.value: hf.x264( + preset="veryfast", tune="fastdecode" + ), + PrivilegeType.MASK.value: hf.x264( + preset="veryslow", tune="ssim", crf=0 + ), + } + elif "3060" in name or name == "NVIDIA GeForce RTX 3060": + self.conf = { + Modality.GEOMAP.value: hf.h264_nvenc(), + Modality.IMAGES.value: hf.h264_nvenc(), + PrivilegeType.MASK.value: hf.h264_nvenc(), + } + elif "3090" in name or name == "NVIDIA GeForce RTX 3090": + self.conf = { + Modality.GEOMAP.value: hf.x264( + preset="veryfast", tune="fastdecode" + ), + Modality.IMAGES.value: hf.x264( + preset="veryfast", tune="fastdecode" + ), + PrivilegeType.MASK.value: hf.x264( + preset="veryslow", tune="ssim", crf=0 + ), + } + elif "4090" in name or name == "NVIDIA GeForce RTX 4090": + self.conf = { + Modality.GEOMAP.value: hf.x264( + preset="veryfast", tune="fastdecode" + ), + Modality.IMAGES.value: hf.x264( + preset="veryfast", tune="fastdecode" + ), + PrivilegeType.MASK.value: hf.x264( + preset="veryslow", tune="ssim", crf=0 + ), + } + else: + raise ValueError("Unsupported GPU: {}".format(name)) + + except Exception as e: + log_warning( + "{}. Please make sure h5ffmpeg is successfully installed.".format(e) + ) + self.conf = {} + + @staticmethod + def is_compressed_hdf5(data: Dict) -> bool: + images_group = data.get("observations", {}).get(Modality.IMAGES.value, {}) + has_compressed_keys = any( + (isinstance(k, str) and ("index" in k or "start" in k)) + for k in images_group.keys() + ) + return has_compressed_keys + + @staticmethod + def get_chunk_name(name: str, id: Union[int, str]) -> str: + """ + Generates a chunk name by concatenating the given name with the provided id, separated by an underscore. + Args: + name (str): The base name for the chunk. + id (Union[int, str]): The identifier to append to the name. + Returns: + str: The resulting chunk name in the format 'name_id'. + """ + + return name + "_{}".format(id) + + @staticmethod + def video_save( + f, + chunks: int, + data: Dict[str, np.ndarray], + key: str, + dtype=np.uint8, + conf: Dict = None, + ): + """ + Saves video data from multiple cameras into an HDF5 file, splitting the data into chunks for efficient storage. + Args: + f: An open HDF5 file handle where the video data will be saved. + data (Dict[str, np.ndarray]): Dictionary mapping camera names to their corresponding video data arrays. + key (str): Key under "observations" group in the HDF5 file to store the video data. + dtype (type, optional): Data type to convert the video frames to before saving (default: np.uint8). + conf (Dict, optional): Additional configuration parameters for HDF5 dataset creation. + Notes: + - Video data for each camera is processed and split into the specified number of chunks. + - Index and start datasets are created for each camera to map frame indices to chunk IDs and chunk start indices. + - Uses CompressedVideoHDF5 utility functions for data formatting and conversion. + - Progress is displayed using tqdm for each chunk being saved. + """ + import h5ffmpeg as hf + + f_images = f["observations"].create_group(key) + + for cam_name in data.keys(): + data_ = data[cam_name] + if len(data_) != 0: + data_ = CompressedVideoHDF5.to_bhw(data_) + + if dtype == np.uint16: + data_ = CompressedVideoHDF5.uint16_depth(data_) + else: + data_ = data_.astype(dtype) + + data_chunks = np.array_split(data_, chunks, axis=0) + data_chunk_ids = np.arange(data_.shape[0]) + data_chunk_ids_ = np.array_split(data_chunk_ids, chunks) + idtochunkid = np.zeros((data_.shape[0])) + chunkid2startid = np.zeros((chunks,)) + for chunkid, temp in enumerate(data_chunk_ids_): + chunkid2startid[chunkid] = min(temp) + for tempi in temp: + idtochunkid[tempi] = chunkid + _ = f_images.create_dataset( + CompressedVideoHDF5.get_chunk_name(cam_name, "index"), + data=idtochunkid, + ) + _ = f_images.create_dataset( + CompressedVideoHDF5.get_chunk_name(cam_name, "start"), + data=chunkid2startid, + ) + + for t, data_chunk in enumerate(tqdm(data_chunks)): + _ = f_images.create_dataset( + "{}/{}".format(cam_name, t), + data=data_chunk, + chunks=data_chunk.shape, + **conf, + ) + + @staticmethod + def uint16_depth( + data: np.ndarray, scale_factor: float = SCALE_FACTOR, far_clip: float = FAR_CLIP + ) -> np.ndarray: + """ + Converts a depth data array to a uint16 format after applying scaling and clipping. + Args: + data (np.ndarray): The input depth data as a NumPy array. + scale_factor (float, optional): The factor by which to scale the depth data. + Defaults to SCALE_FACTOR. + far_clip (float, optional): The maximum depth value (far clipping plane) + before scaling. Defaults to FAR_CLIP. + Returns: + np.ndarray: The scaled and clipped depth data as a NumPy array of type uint16. + """ + return (np.clip(data * scale_factor, 0, far_clip * scale_factor)).astype( + np.uint16 + ) + + @staticmethod + def float32_depth( + data: np.ndarray, scale_factor: float = SCALE_FACTOR, far_clip: float = FAR_CLIP + ) -> np.ndarray: + """ + Converts depth data to float32 and scales it by the given scale factor. + Args: + data (np.ndarray): The input depth data array. + scale_factor (float, optional): The factor by which to scale the depth values. Defaults to SCALE_FACTOR. + far_clip (float, optional): The far clipping distance (unused in this function). Defaults to FAR_CLIP. + Returns: + np.ndarray: The scaled depth data as a float32 numpy array. + """ + + return data.astype(np.float32) / scale_factor + + @staticmethod + def to_bhw(data: np.ndarray) -> np.ndarray: + """ + Reshapes a 4D numpy array from (vdepth, height, width, channels) to (vdepth, height, width * channels). + If the input is already a 3D array, returns it unchanged. + Args: + data (np.ndarray): Input array of shape (vdepth, height, width, channels) or (vdepth, height, width). + Returns: + np.ndarray: Reshaped array of shape (vdepth, height, width * channels) or the original array if 3D. + Raises: + Logs an error if the input array does not have 3 or 4 dimensions. + """ + + if len(data.shape) == 4: + vdepth, h, w, channels = ( + data.shape[0], + data.shape[1], + data.shape[2], + data.shape[3], + ) + return data.reshape(vdepth, h, w * channels) + elif len(data.shape) == 3: + return data + else: + log_error("Unsupported data shape: {}".format(data.shape)) + + @staticmethod + def to_bhwc(data: np.ndarray): + """ + Converts a numpy array to BHWC (Batch, Height, Width, Channels) format. + If the input array has 3 dimensions, it reshapes the array to have a channel dimension of size 3. + If the input array already has 4 dimensions, it returns the array unchanged. + Otherwise, logs an error for unsupported shapes. + Args: + data (np.ndarray): Input numpy array to be converted. + Returns: + np.ndarray: Array in BHWC format. + Raises: + Logs an error if the input array shape is not supported. + """ + + if len(data.shape) == 3: + vdepth, h, w = data.shape + return data.reshape(vdepth, h, -1, 3) + elif len(data.shape) == 4: + return data + else: + log_error("Unsupported data shape: {}".format(data.shape)) + + def dump( + self, + ret: Dict, + video_names: List[str] = [ + Modality.IMAGES.value, + PrivilegeType.MASK.value, + Modality.GEOMAP.value, + ], + dtypes: List = [np.uint8, np.uint8, np.uint16], + ): + """ + Dumps the provided data into an HDF5 file, saving specific video data with + compression and specified data types. + Args: + ret (Dict): The data dictionary containing observations and other metadata. + video_names (List[str], optional): A list of video names to extract from + the observations. Defaults to [Modality.IMAGES.value, PrivilegeType.MASK.value, Modality.GEOMAP.value]. + dtypes (List, optional): A list of data types corresponding to each video + name. Defaults to [np.uint8, np.uint8, np.uint16]. + Raises: + AssertionError: If the lengths of `video_names` and `dtypes` are not equal. + RuntimeError: If the configuration (`self.conf`) is empty, indicating that + `h5ffmpeg` is not installed or configured properly. + Notes: + - The method modifies the `ret` dictionary by temporarily removing the + specified video data during the HDF5 file creation process and then + restoring it afterward. + - The `hdfdict.dump` function is used to save the remaining data in the + dictionary, while the `CompressedVideoHDF5.video_save` function handles + the saving of video data with compression. + """ + + assert len(video_names) == len( + dtypes + ), "Inequal length of video names {} and dtypes {}.".format(video_names, dtypes) + import hdfdict + + if self.conf == {}: + raise RuntimeError( + "Please make sure h5ffmpeg is successfully installed before using `dump`." + ) + + pop_ret = {} + for video_name, dtype in zip(video_names, dtypes): + video_data = ret["observations"].pop(video_name) + pop_ret[video_name] = video_data + + # Open the file once and pass the open file object to hdfdict.dump so + # h5py doesn't try to truncate the same path while it is already open. + with h5py.File(self.save_path, "w") as f: + hdfdict.dump(ret, f) + for video_name, dtype in zip(video_names, dtypes): + CompressedVideoHDF5.video_save( + f, + self.chunks, + pop_ret[video_name], + video_name, + dtype=dtype, + conf=self.conf[video_name], + ) + + ret["observations"].update(pop_ret) + + @staticmethod + def decode_resources( + f: Dict, + ret: Dict, + name: str, + slice_id: int, + condition: callable, + function: callable, + padding: bool = True, + chunk_id: int = None, + ): + """ + Decodes and processes resources from a hierarchical data structure, applying + a condition and transformation function to the data, and optionally adding + zero-padding. + Args: + f (Dict): The input data dictionary containing observations and metadata. + ret (Dict): The output data dictionary where processed data will be stored. + name (str): The key name under "observations" to access specific data. + slice_id (int): The slice index used to retrieve the corresponding chunk ID. + condition (callable): A function that takes the data as input and returns + a boolean indicating whether the transformation function should be applied. + function (callable): A function to transform the data if the condition is met. + padding (bool, optional): Whether to add zero-padding to the data. Defaults to True. + chunk_id (int, optional): The chunk ID to use instead of deriving it from the slice ID. + Defaults to None. + Returns: + None: The function modifies the `ret` dictionary in place. + """ + + import time + + images = f["observations"][name] + + for cam_name in images.keys(): + if "index" in cam_name: + continue + if "start" in cam_name: + continue + + start_time = time.time() + sliceid2chunkid = images[ + CompressedVideoHDF5.get_chunk_name(cam_name, "index") + ][:] + chunkid = int(sliceid2chunkid[slice_id]) if chunk_id is None else chunk_id + data_ = images[cam_name][str(chunkid)][:] + # log_warning("".format(time.time() - start_time) + if condition(data_): + data_ = function(data_) + + if padding: + chunkid2startid = images[ + CompressedVideoHDF5.get_chunk_name(cam_name, "start") + ][:] + start_idx = chunkid2startid[chunkid] + zero_padding = np.zeros_like(data_)[0:1] + zero_padding = np.repeat(zero_padding, repeats=start_idx, axis=0) + ret["observations"][name][cam_name] = np.concatenate( + [zero_padding, data_], 0 + ) + else: + if ret["observations"][name][cam_name] is None: + ret["observations"][name][cam_name] = data_ + else: + ret["observations"][name][cam_name] = np.concatenate( + [ret["observations"][name][cam_name], data_], 0 + ) + + def safe_filter(self, f: Dict, slice_id: int = None) -> Dict: + """ + Filters and processes the input data dictionary based on the configuration + and specified slice ID. + Args: + f (Dict): The input data dictionary containing observations, including + images, masks, and geomap. + slice_id (int, optional): The specific slice ID to process. If None, + processes all chunks. Defaults to None. + Returns: + Dict: The filtered and processed data dictionary with updated + observations for images, masks, and geomap. + Notes: + - The method filters out camera names containing "index" or "start". + - It initializes the return dictionary with None values for images, + masks, and geomap for the filtered camera names. + - Depending on the `slice_id`, it either processes all chunks or a + specific slice using the `CompressedVideoHDF5.decode_resources` + method. + - The processed observations are updated in the input dictionary `f`. + """ + + if self.conf is {}: + return f + + cam_names = [] + for cam_name in f["observations"][Modality.IMAGES.value].keys(): + if "index" in cam_name: + continue + if "start" in cam_name: + continue + cam_names.append(cam_name) + + # Only build return structure for actually present modalities, avoid errors when real data lacks mask/geomap + present_modalities = [] + if Modality.IMAGES.value in f["observations"]: + present_modalities.append(Modality.IMAGES.value) + if PrivilegeType.MASK.value in f["observations"]: + present_modalities.append(PrivilegeType.MASK.value) + if Modality.GEOMAP.value in f["observations"]: + present_modalities.append(Modality.GEOMAP.value) + + ret = {"observations": {}} + for modality_key in present_modalities: + ret["observations"][modality_key] = { + cam_name: None for cam_name in cam_names + } + + if slice_id == None: + # For all chunks + for chunk_id_ in range(self.chunks): + if Modality.IMAGES.value in present_modalities: + CompressedVideoHDF5.decode_resources( + f, + ret, + Modality.IMAGES.value, + None, + lambda x: len(x.shape) == 3, + self.to_bhwc, + chunk_id=chunk_id_, + padding=False, + ) + if PrivilegeType.MASK.value in present_modalities: + CompressedVideoHDF5.decode_resources( + f, + ret, + PrivilegeType.MASK.value, + None, + lambda x: len(x.shape) == 3, + self.to_bhwc, + chunk_id=chunk_id_, + padding=False, + ) + if Modality.GEOMAP.value in present_modalities: + CompressedVideoHDF5.decode_resources( + f, + ret, + Modality.GEOMAP.value, + None, + lambda x: x.dtype == np.uint16 and len(x) != 0, + self.float32_depth, + chunk_id=chunk_id_, + padding=False, + ) + + else: + if Modality.IMAGES.value in present_modalities: + CompressedVideoHDF5.decode_resources( + f, + ret, + Modality.IMAGES.value, + slice_id, + lambda x: len(x.shape) == 3, + self.to_bhwc, + ) + if PrivilegeType.MASK.value in present_modalities: + CompressedVideoHDF5.decode_resources( + f, + ret, + PrivilegeType.MASK.value, + slice_id, + lambda x: len(x.shape) == 3, + self.to_bhwc, + ) + if Modality.GEOMAP.value in present_modalities: + CompressedVideoHDF5.decode_resources( + f, + ret, + Modality.GEOMAP.value, + slice_id, + lambda x: x.dtype == np.uint16 and len(x) != 0, + self.float32_depth, + ) + if Modality.IMAGES.value in present_modalities: + f["observations"][Modality.IMAGES.value] = ret["observations"][ + Modality.IMAGES.value + ] + if PrivilegeType.MASK.value in present_modalities: + f["observations"][PrivilegeType.MASK.value] = ret["observations"][ + PrivilegeType.MASK.value + ] + if Modality.GEOMAP.value in present_modalities: + f["observations"][Modality.GEOMAP.value] = ret["observations"][ + Modality.GEOMAP.value + ] + + return f + + +class ActStateStatistic: + def __init__(self, data_dict: Dict, min_len_steps: int) -> None: + self.data_dict = data_dict + self.min_len_steps = min_len_steps + + def prepare_state_and_action( + self, + ): + proprio = self.data_dict["observations"][Modality.STATES.value][:] + num_steps = proprio.shape[0] + # [Optional] We drop too-short episode + if num_steps < self.min_len_steps: + return False, None + # [Optional] We skip the first few still steps + EPS = 1e-2 + # Get the idx of the first qpos whose delta exceeds the threshold + proprio_delta = np.abs(proprio - proprio[0:1]) + indices = np.where(np.any(proprio_delta > EPS, axis=1))[0] + if len(indices) > 0: + first_idx = indices[0] + else: + raise ValueError("Found no qpos that exceeds the threshold.") + target_actions = self.data_dict[Modality.ACTIONS.value][:] + # Parse the state and action + state = proprio[first_idx - 1 :] + action = target_actions[first_idx - 1 :] + # Return the resulting sample + + return True, {Modality.STATES.value: state, Modality.ACTIONS.value: action} + + def statistic( + self, + ) -> Dict: + EPS = 1e-8 + episode_cnt = 0 + state_sum = 0 + state_sum_sq = 0 + z_state_sum = 0 + z_state_sum_sq = 0 + state_cnt = 0 + nz_state_cnt = None + state_max = None + state_min = None + _, episode = self.prepare_state_and_action() + episode_cnt += 1 + + states = episode[Modality.STATES.value] + + # Zero the values that are close to zero + z_states = states.copy() + z_states[np.abs(states) <= EPS] = 0 + # Compute the non-zero count + if nz_state_cnt is None: + nz_state_cnt = np.zeros(states.shape[1]) + nz_state_cnt += np.sum(np.abs(states) > EPS, axis=0) + + # Update statistics + state_sum += np.sum(states, axis=0) + state_sum_sq += np.sum(states**2, axis=0) + z_state_sum += np.sum(z_states, axis=0) + z_state_sum_sq += np.sum(z_states**2, axis=0) + state_cnt += states.shape[0] + if state_max is None: + state_max = np.max(states, axis=0) + state_min = np.min(states, axis=0) + else: + state_max = np.maximum(state_max, np.max(states, axis=0)) + state_min = np.minimum(state_min, np.min(states, axis=0)) + + # Add one to avoid division by zero + nz_state_cnt = np.maximum(nz_state_cnt, np.ones_like(nz_state_cnt)) + + result = { + "state_mean": (state_sum / state_cnt).tolist(), + "state_std": np.sqrt( + np.maximum( + (z_state_sum_sq / nz_state_cnt) + - (z_state_sum / state_cnt) ** 2 * (state_cnt / nz_state_cnt), + np.zeros_like(state_sum_sq), + ) + ).tolist(), + "state_min": state_min.tolist(), + "state_max": state_max.tolist(), + } + + return result + + +class DataDictExtractor: + def __init__( + self, + env: Union[BaseEnv, EmbodiedEnv], + save_path: str = None, + compression_opts: int = 9, + ): + self.env = env + self.save_path = save_path + self.data = {} + + # save all supported proprio and action types. + robot_meta_config = deepcopy(self.env.metadata["dataset"]["robot_meta"]) + robot_meta_config["observation"][ + Modality.STATES.value + ] = SUPPORTED_PROPRIO_TYPES + robot_meta_config[Modality.ACTIONS.value] = SUPPORTED_ACTION_TYPES + + self.state_unifier = StateUnifier(robot_meta=robot_meta_config) + self.compression_opts = compression_opts + + @cached_property + def robot_control_parts(self) -> List[str]: + """Get the robot's control parts. + + Note: + If control_parts is specified in the robot metadata, return those parts. + Otherwise, return all control parts. + + Returns: + List[str]: The robot's control parts. + """ + robot_meta_config = self.env.metadata["dataset"]["robot_meta"] + control_parts = robot_meta_config.get("control_parts", None) + if control_parts is None: + return [] + else: + return control_parts + + def _get_arm_control_parts(self) -> List[str]: + control_parts = self.robot_control_parts + arm_control_parts = [] + for part in control_parts: + if "arm" in part: + arm_control_parts.append(part) + return arm_control_parts + + def _has_exteroception(self) -> bool: + robot_meta_config = self.env.metadata["dataset"]["robot_meta"] + return PrivilegeType.EXTEROCEPTION.value in robot_meta_config["observation"] + + def extract( + self, + obs_list: List[Dict[str, Any]], + action_list: List[Dict[str, Any]], + data_dict: Dict = DATA_FORMATS, + save: bool = True, + ): + if save: + assert ( + self.save_path is not None + ), "Please provide a save path for the dataset." + data_dict = deepcopy(data_dict) + + self._init_data(data_dict) + + ret = {} + robot_meta_config = self.env.metadata["dataset"]["robot_meta"] + + for i, (obs, action) in enumerate(zip(obs_list, action_list)): + self._extract_vision_obs(obs, data_dict) + self._extract_proprioception(obs, data_dict) + self._extract_action(action, data_dict) + + action = self._collate_action(data_dict) + proprio = self._collate_proprio(data_dict) + robot_meta = self._collate_metainfo() + + extra_vision_config = robot_meta_config["observation"]["vision"] + obs = {"observations": {}} + images = self.collate_sub_anns( + data_dict, extra_vision_config, Modality.IMAGES.value + ) + obs["observations"].update(proprio) + obs["observations"].update(images) + + extra_vision_names = list( + set([name for list in extra_vision_config.values() for name in list]) + ) + for extra_vision_name in extra_vision_names: + extra_vision_obs = self.collate_sub_anns( + data_dict, extra_vision_config, extra_vision_name + ) + obs["observations"].update(extra_vision_obs) + + ret.update(robot_meta) + ret.update(obs) + ret.update(action) + + statistics = ActStateStatistic( + ret, self.env.metadata["dataset"]["robot_meta"]["min_len_steps"] + ).statistic() + ret.update(statistics) + + if save: + if has_h5ffmpeg: + cvhdf5 = CompressedVideoHDF5(self.save_path) + all_video_names = [Modality.IMAGES.value] + [ + name + for name in extra_vision_names + if name != PrivilegeType.EXTEROCEPTION.value + ] + all_dtypes = [ + np.uint16 if name == Modality.GEOMAP.value else np.uint8 + for name in all_video_names + ] + cvhdf5.dump(ret, video_names=all_video_names, dtypes=all_dtypes) + else: + logger.log_info( + "h5ffmpeg is not installed, saving dataset without compression." + ) + import hdfdict + + # Open the file once and pass the file object to hdfdict.dump to + # avoid opening/truncating the same file path twice which causes + # "unable to truncate a file which is already open" errors on + # some platforms and HDF5 builds. + with h5py.File(self.save_path, "w") as f: + hdfdict.dump(ret, f) + + return ret + + def _init_data(self, data_dict: Dict): + robot_meta_config = self.env.metadata["dataset"]["robot_meta"] + extra_vision_config = robot_meta_config["observation"]["vision"] + + for proprio_name in SUPPORTED_PROPRIO_TYPES: + data_dict["observations"][Modality.STATES.value][proprio_name] = [] + for action_name in SUPPORTED_ACTION_TYPES: + data_dict[Modality.ACTIONS.value][action_name] = [] + + for camera_name, extra_vision_list in extra_vision_config.items(): + is_stereo = isinstance(self.env.get_sensor(camera_name), StereoCamera) + + data_dict["observations"][Modality.IMAGES.value][camera_name] = [] + if is_stereo: + data_dict["observations"][Modality.IMAGES.value][ + get_right_name(camera_name) + ] = [] + + for extra_vision_name in extra_vision_list: + if extra_vision_name in SUPPORTED_EXTRA_VISION_TYPES: + data_dict["observations"][extra_vision_name][camera_name] = [] + else: + log_error( + f"Extra vision observation name {extra_vision_name} is not in SUPPORTED_EXTRA_VISION_TYPES {SUPPORTED_EXTRA_VISION_TYPES}, please check again." + ) + if is_stereo: + data_dict["observations"][extra_vision_name][ + get_right_name(camera_name) + ] = [] + + def _extract_vision_obs(self, obs: Dict[str, Any], data_dict: Dict): + robot_meta_config = self.env.metadata["dataset"]["robot_meta"] + extra_vision_config = robot_meta_config["observation"]["vision"] + + for camera_name, extra_vision_list in extra_vision_config.items(): + if camera_name in obs["sensor"]: + is_stereo = isinstance(self.env.get_sensor(camera_name), StereoCamera) + + data_dict["observations"][Modality.IMAGES.value][camera_name].append( + obs["sensor"][camera_name]["color"] + .squeeze(0)[:, :, :3] + .cpu() + .numpy() + ) + if is_stereo: + # save rgb right + data_dict["observations"][Modality.IMAGES.value][ + get_right_name(camera_name) + ].append( + obs["sensor"][camera_name]["color_right"] + .squeeze_(0)[:, :, :3] + .cpu() + .numpy() + ) + + for extra_vision_name in extra_vision_list: + if extra_vision_name in SUPPORTED_EXTRA_VISION_TYPES: + if extra_vision_name == PrivilegeType.EXTEROCEPTION.value: + if is_stereo: + data_dict["observations"][extra_vision_name][ + camera_name + ].append( + obs[extra_vision_name][camera_name]["l"] + .cpu() + .numpy() + ) + data_dict["observations"][extra_vision_name][ + get_right_name(camera_name) + ].append( + obs[extra_vision_name][camera_name]["r"] + .cpu() + .numpy() + ) + elif camera_name in obs.get(extra_vision_name, {}): + data_dict["observations"][extra_vision_name][ + camera_name + ].append( + obs[extra_vision_name][camera_name].cpu().numpy() + ) + elif extra_vision_name == PrivilegeType.MASK.value: + # save semantic mask for monocular cameras + data_dict["observations"][extra_vision_name][ + camera_name + ].append( + obs["sensor"][camera_name]["semantic_mask_l"] + .squeeze_(0) + .numpy() + .astype(np.uint8) + ) + if is_stereo: + data_dict["observations"][extra_vision_name][ + get_right_name(camera_name) + ].append( + obs["sensor"][camera_name]["semantic_mask_r"] + .squeeze_(0) + .numpy() + .astype(np.uint8) + ) + elif extra_vision_name == Modality.GEOMAP.value: + if not is_stereo: + log_error( + f"Camera {camera_name} is not stereo, while '{extra_vision_name}' is in gym_config.dataset.robot_meta.vision, please check again." + ) + if "depth" in obs["sensor"][camera_name]: + data_dict["observations"][extra_vision_name][ + camera_name + ].append( + obs["sensor"][camera_name]["depth"] + .squeeze_() + .numpy() + ) + else: + log_error( + f"obs['sensor'][{camera_name}] has no key named 'depth' while it's required in gym_config.dataset.robot_meta.vision, please check again." + ) + else: + log_error( + f"Extra vision observation name {extra_vision_name} is not in SUPPORTED_EXTRA_VISION_TYPES {SUPPORTED_EXTRA_VISION_TYPES}, please check again." + ) + else: + logger.log_error( + f"Camera {camera_name} not found in observations, please check your sensor configuration in gym_config.json" + ) + + def _extract_action( + self, + action: torch.Tensor, + data_dict: Dict, + ): + robot: Robot = self.env.robot + + for key in data_dict[Modality.ACTIONS.value].keys(): + part = _data_key_to_control_part( + robot=robot, + control_parts=self.env.metadata["dataset"]["robot_meta"].get( + "control_parts", [] + ), + data_key=key, + ) + if part is None: + continue + indices = robot.get_joint_ids(part, remove_mimic=True) + data_dict[Modality.ACTIONS.value][key].append( + action[0, indices].cpu().numpy() + if isinstance(action, torch.Tensor) + else action[0, indices] + ) + + eef_pose_dict = map_qpos_to_eef_pose( + robot, action, control_parts=self._get_arm_control_parts() + ) + for key, val in eef_pose_dict.items(): + data_dict[Modality.ACTIONS.value][key].append( + val.squeeze_(0).cpu().numpy() + if isinstance(val, torch.Tensor) + else val.squeeze_(0) + ) + + def _extract_proprioception( + self, + obs: Dict[str, Any], + data_dict: Dict, + ): + robot: Robot = self.env.robot + + qpos = obs["robot"][JointType.QPOS.value] + for key in data_dict["observations"][Modality.STATES.value].keys(): + part = _data_key_to_control_part( + robot=robot, + control_parts=self.env.metadata["dataset"]["robot_meta"].get( + "control_parts", [] + ), + data_key=key, + ) + if part is None: + continue + indices = robot.get_joint_ids(part, remove_mimic=True) + data_dict["observations"][Modality.STATES.value][key].append( + qpos[0][indices].cpu().numpy() + ) + + eef_pose_dict = map_qpos_to_eef_pose( + robot, qpos, control_parts=self._get_arm_control_parts() + ) + for key, val in eef_pose_dict.items(): + data_dict["observations"][Modality.STATES.value][key].append( + val.squeeze_(0).cpu().numpy() + ) + + def _collate_proprio(self, data_dict: Dict) -> Dict: + proprio_dict = {} + for proprio_name in self.state_unifier.proprio_meta: + proprio = np.array( + data_dict["observations"][Modality.STATES.value][proprio_name] + ) + proprio_dict[proprio_name] = proprio + proprios = self.state_unifier.fill_in_state(proprio_dict) + return {Modality.STATES.value: proprios} + + def _collate_metainfo( + self, + ) -> Dict: + meta_info = { + "arm_dofs": self.env.metadata["dataset"]["robot_meta"].get("arm_dofs", 12), + "observation": self.env.metadata["dataset"]["robot_meta"].get( + "observation", {} + ), + "min_len_steps": self.env.metadata["dataset"]["robot_meta"].get( + "min_len_steps", 125 + ), + } + return { + "robot_meta": meta_info, + "instruction": { + "lang": self.env.metadata["dataset"]["instruction"].get("lang", "") + }, + } + + def _collate_action(self, data_dict: Dict) -> Dict: + action_data_dict = data_dict[Modality.ACTIONS.value] + for k, v in action_data_dict.items(): + action_data_dict[k] = np.array(v) + + action_dict = {} + action_dict.update(action_data_dict) + action = self.state_unifier.fill_in_action(action_dict) + return {Modality.ACTIONS.value: action} + + @staticmethod + def collate_sub_anns( + data_dict: Dict, + extra_vision_config: Dict, + key: str = Modality.IMAGES.value, + ) -> Dict: + ret = {key: {}} + for camera_name in extra_vision_config: + images_list = data_dict["observations"][key].pop(camera_name, None) + if images_list is None: + continue + if len(images_list) > 0: + ret[key][camera_name] = np.empty( + (len(images_list),) + images_list[0].shape, + dtype=images_list[0].dtype, + ) + for idx, image in enumerate(images_list): + ret[key][camera_name][idx] = image + else: + ret[key][camera_name] = np.array([]) + + del images_list + if get_right_name(camera_name) in data_dict["observations"][key]: + images_right_list = data_dict["observations"][key].pop( + get_right_name(camera_name), None + ) + if images_right_list is None: + continue + if len(images_right_list) > 0: + ret[key][get_right_name(camera_name)] = np.empty( + (len(images_right_list),) + images_right_list[0].shape, + dtype=images_right_list[0].dtype, + ) + for idx, image in enumerate(images_right_list): + ret[key][get_right_name(camera_name)][idx] = image + else: + ret[key][get_right_name(camera_name)] = np.array([]) + del images_right_list + + return ret + + +def fetch_imitation_dataset( + env: BaseEnv, + obs_list: List[Dict[str, Any]], + action_list: List[Dict[str, Any]], + id: str, + folder_name: str, +) -> Dict: + """ + Save imitation dataset for a single episode. + + Args: + env (BaseEnv): Environment instance. + obs_list (List[Dict]): List of observation dicts. + action_list (List[Dict]): List of action dicts. + id (str): Unique identifier for the episode. + folder_name (str): Folder name for saving the dataset. + + Returns: + dict: Contains data_path, id, current_episode, and extracted data. + """ + # Get dataset save path + dataset_path = env.metadata["dataset"].get("save_path", None) + if dataset_path is None: + from embodichain.data import database_demo_dir + + dataset_path = database_demo_dir + + # Create folder if first episode + dataset_save_path = os.path.join(dataset_path, folder_name) + if env.curr_episode == 0 and id: + os.makedirs(dataset_save_path, exist_ok=True) + + # Check robot dof validity + try: + robot: Robot = env.robot + assert ( + env.metadata["dataset"]["robot_meta"]["arm_dofs"] <= robot.dof + ), f"Control dof {env.metadata['dataset']['robot_meta']['arm_dofs']} must be less than {robot.dof}." + except Exception as e: + logger.log_error(f"Robot DOF check failed: {e}") + return None + + # Select data format + data_format = DATA_FORMATS + + # Extract and save data + if id is None: + ret = DataDictExtractor(env).extract( + obs_list, action_list, save=False, data_dict=data_format + ) + save_path = None + else: + save_path = os.path.join(dataset_save_path, id + ".hdf5") + logger.log_info(f"Save episode {env.curr_episode} to '{save_path}'") + ret = DataDictExtractor(env, save_path).extract( + obs_list, action_list, save=True, data_dict=data_format + ) + + # Update episode count + env.curr_episode += 1 + + # Return result dict + return { + "data_path": dataset_save_path, + "id": id, + "current_episode": env.curr_episode, + "data": ret, + "save_path": save_path, + } diff --git a/embodichain/data/data_engine/datasets/vla_datasets.py b/embodichain/data/data_engine/datasets/vla_datasets.py new file mode 100644 index 00000000..a3edb854 --- /dev/null +++ b/embodichain/data/data_engine/datasets/vla_datasets.py @@ -0,0 +1,521 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import fnmatch +from embodichain.utils.logger import log_warning, log_info + +try: + import h5ffmpeg as hf +except Exception as e: + log_warning("Fail to import h5ffmpeg.") +import h5py +import numpy as np +from typing import Dict, Callable, List, Tuple +from embodichain.utils.utility import get_right_name, pad_to_chunk, convert_bytes +from embodichain.utils.logger import log_warning, log_info +from embodichain.data.enum import Proprioception, Image, Exteroception, ModalInput +from copy import deepcopy +from typing import Dict +from embodichain.data.enum import ( + Modality, + PrivilegeType, + ActionMode, + JointType, + EefType, + CameraName, + TeleoperationData, +) +from embodichain.data.global_mapping import GlobalMapping +from scipy.ndimage import gaussian_filter1d +from embodichain.data.data_engine.unified_state import ActionIndicesGenerator + + +class VLADataset: + """ + This class is used to sample episodes from the embododiment dataset + stored in HDF5. + """ + + def __init__( + self, + data_path: str, + batch_size: int, + chunk_size: int, + state: List, + output: List, + img_history_size: int, + state_history_len: int, + precomp_lang_embed: bool = True, + online_config: Dict = None, + camera_used: List[str] = None, + indices_generator=None, + ) -> None: + # [Modify] The path to the HDF5 dataset directory + # Each HDF5 file contains one episode + + self.precomp_lang_embed = precomp_lang_embed + self.batch_size = batch_size + self.chunk_size = chunk_size + self.state = state + self.output = output + self.img_history_size = img_history_size + self.state_history_len = state_history_len + self.online_config = online_config + self.camera_used = camera_used + self.indices_generator = indices_generator + if self.camera_used is not None: + for cam in CameraName: + if cam.value not in camera_used: + log_warning( + "{} does not exist in {}".format(cam.value, camera_used) + ) + + if self.online_config is not None: + from embodichain.data.data_engine.online.engine import OnlineEngine + + log_info("Init online vla dataset.", color="purple") + self.engine = OnlineEngine(**self.online_config) + self.DATASET_NAME = "online_whatever" + else: + log_info("Init offline vla dataset.", color="purple") + self.engine = None + self.data_path = data_path + assert os.path.exists(self.data_path), "{} does not exist.".format( + self.data_path + ) + if os.path.isabs(self.data_path) is False: + self.data_path = os.path.join(os.getcwd(), self.data_path) + self.DATASET_NAME = os.path.basename(self.data_path) + self.file_paths = [] + for root, _, files in os.walk(self.data_path): + for filename in fnmatch.filter(files, "*.hdf5"): + file_path = os.path.join(root, filename) + self.file_paths.append(file_path) + log_info( + f"Init dataset with size of: {len(self.file_paths)}", color="purple" + ) + + def update_data_size(self): + """Interface for update validation dataset size generated on the fly.""" + self.file_paths = [] + for root, _, files in os.walk(self.data_path): + for filename in fnmatch.filter(files, "*.hdf5"): + file_path = os.path.join(root, filename) + self.file_paths.append(file_path) + log_info(f"Update dataset with size of: {len(self.file_paths)}", color="purple") + + def __len__(self): + return ( + len(self.file_paths) + if self.online_config is None + else np.maximum(self.engine.episode_limit, self.batch_size) + ) + + def get_item(self, index: int = None, chunk_size: int = None): + """Get a training sample at a random timestep. + + Args: + index (int, optional): the index of the episode. + If not provided, a random episode will be selected. + state_only (bool, optional): Whether to return only the state. + In this way, the sample will contain a complete trajectory rather + than a single timestep. Defaults to False. + + Returns: + sample (dict): a dictionary containing the training sample. + """ + chunk_size = self.chunk_size if chunk_size is None else chunk_size + while True: + if self.online_config is None: + # offline + if index is None: + file_path = np.random.choice(self.file_paths) + else: + file_path = self.file_paths[index] + valid, sample = self.parse_hdf5_file(file_path, chunk_size) + else: + data_dict = self.engine.sample_data() + valid, sample = self.parse_dict(data_dict, chunk_size) + + if valid: + return sample + else: + if self.online_config is None: + index = np.random.randint(0, len(self.file_paths)) + + @staticmethod + def parse_exteroception( + file: Dict, + step_id: int, + chunk_size: int, + camera_used: List[str] = [], + ) -> Exteroception: + exteroception = [] + for cam in camera_used: + exteroception_full = file["observations"][ + PrivilegeType.EXTEROCEPTION.value + ][cam] + exteroception.append(exteroception_full[step_id : step_id + chunk_size]) + + exteroception = np.concatenate(exteroception, 1) + _, cs, kn, _ = exteroception.shape + exteroception = pad_to_chunk(exteroception, chunk_size) + return Exteroception( + data=exteroception.reshape(chunk_size, cs, kn, 2).transpose( + 1, 0, 2, 3 + ) # cs, chunk_size, kn, 2 + ) + + @staticmethod + # Parse the images + def parse_img( + file: Dict, + step_id: int, + first_idx: int, + cam: str, + chunk_size: int, + key: str = Modality.IMAGES.value, + camera_used: List[str] = [], + np_ops: Callable = lambda x: x, + ) -> Image: + valid_len = min(step_id - (first_idx - 1) + 1, chunk_size) + cam_mask = np.array([False] * (chunk_size - valid_len) + [True] * valid_len) + if cam in camera_used: + temp = file["observations"][key][cam][0] + imgs = np.zeros((valid_len,) + temp.shape, dtype=temp.dtype) + for t, i in enumerate(range(max(step_id - chunk_size + 1, 0), step_id + 1)): + img = file["observations"][key][cam][i] + imgs[t] = img + imgs = np_ops(imgs) + imgs = pad_to_chunk(imgs, chunk_size=chunk_size) + mask = cam_mask.copy() + else: + imgs = np.zeros((chunk_size, 0, 0, 0)) + mask = np.zeros((chunk_size,), dtype=bool) + return Image(data=imgs, mask=mask, name=cam) + + def parse_hdf5_file(self, file_path, chunk_size: int) -> Dict[str, ModalInput]: + import hdfdict + from embodichain.data.data_engine.data_dict_extractor import ( + CompressedVideoHDF5, + ) + + with h5py.File(file_path, "r") as f: + data = hdfdict.load(f) + keyname = ( + JointType.QPOS.value + if VLADataset.is_real_datasets(data) + else Modality.STATES.value + ) + step_id = VLADataset.random_step_id(data, chunk_size, keyname) + if not VLADataset.is_real_datasets(data): + data = CompressedVideoHDF5(file_path, chunks=None).safe_filter( + data, step_id + ) + else: + # Real data: if compressed structure is detected (containing *_index/*_start), also perform decoding filtering + try: + if CompressedVideoHDF5.is_compressed_hdf5(data): + data = CompressedVideoHDF5(file_path, chunks=None).safe_filter( + data, step_id + ) + except Exception: + pass + + ret = self.parse_dict(data, chunk_size, step_id) + + return ret + + @staticmethod + def random_step_id( + f: Dict, chunk_size: int, key: str = Modality.STATES.value + ) -> int: + obs = f["observations"] + proprio = obs[key][:] + num_steps = proprio.shape[0] + # We randomly sample a timestep + first_idx = 1 + step_id = np.random.randint( + first_idx, np.maximum(first_idx + 1, num_steps - 1 - chunk_size) + ) + return step_id + + @staticmethod + def is_real_datasets(f: Dict): + return "robot_meta" not in f.keys() + + def parse_dict( + self, f: Dict, chunk_size: int, step_id: int = None + ) -> Dict[str, ModalInput]: + if not VLADataset.is_real_datasets(f): + log_warning("Using simulation hdf5 datasets.") + return self.parse_sim_dict(f, chunk_size, step_id) + else: + log_warning("Using real world offline hdf5 datasets.") + return self.parse_real_dict(f, chunk_size, step_id) + + def parse_real_dict( + self, f: Dict, chunk_size: int, step_id: int = None + ) -> Dict[str, ModalInput]: + + from embodichain.data.data_engine.unified_state import ( + StateUnifier, + ) + from embodichain.data.enum import ( + ControlParts, + EndEffector, + JointType, + ) + + if step_id is None: + step_id = VLADataset.random_step_id(f, chunk_size, "qpos") + obs = f["observations"] + first_idx = 1 + proprio = obs["qpos"][:] + num_steps = proprio.shape[0] + camera_used_in_real = list(obs[Modality.IMAGES.value].keys()) + camera_used_from_real_to_dualsys = { + "cam_hand_left": CameraName.LEFT_WRIST.value, + "cam_hand_right": CameraName.RIGHT_WRIST.value, + "cam_high_left": CameraName.HEAD.value, + } + camera_used_from_dualsys_to_real = { + val: key for key, val in camera_used_from_real_to_dualsys.items() + } + # Now assume it is from W1. + camera_used = [ + camera_used_from_real_to_dualsys[cam] + for cam in camera_used_in_real + if cam in camera_used_from_real_to_dualsys + ] + + # Assemble the meta + meta = { + "dataset_name": self.DATASET_NAME, + "#steps": num_steps, + "step_id": step_id, + "camera_used": camera_used, + "instruction": "", + } + # save all supported proprio and action types. + robot_meta_config = {"arm_dofs": 14, "observation": {}} + + REAL_SUPPORTED_PROPRIO_TYPES = [ + ControlParts.LEFT_ARM.value + JointType.QPOS.value, + ControlParts.RIGHT_ARM.value + JointType.QPOS.value, + ControlParts.HEAD.value + JointType.QPOS.value, + ControlParts.WAIST.value + JointType.QPOS.value, + ControlParts.LEFT_EEF.value + EndEffector.DEXTROUSHAND.value, + ControlParts.RIGHT_EEF.value + EndEffector.DEXTROUSHAND.value, + ] + REAL_SUPPORTED_ACTION_TYPES = REAL_SUPPORTED_PROPRIO_TYPES + + robot_meta_config["observation"][ + Modality.STATES.value + ] = REAL_SUPPORTED_PROPRIO_TYPES + robot_meta_config[Modality.ACTIONS.value] = REAL_SUPPORTED_ACTION_TYPES + state_unifier = StateUnifier(robot_meta=robot_meta_config) + + qpos_index_dict = { + ControlParts.LEFT_ARM.value + + JointType.QPOS.value: TeleoperationData.LEFT_ARM_QPOS_INDICES.value, + ControlParts.RIGHT_ARM.value + + JointType.QPOS.value: TeleoperationData.RIGHT_ARM_QPOS_INDICES.value, + ControlParts.LEFT_EEF.value + + EndEffector.DEXTROUSHAND.value: TeleoperationData.LEFT_EEF_DEXTROUSHAND_INDICES.value, + ControlParts.RIGHT_EEF.value + + EndEffector.DEXTROUSHAND.value: TeleoperationData.RIGHT_EEF_DEXTROUSHAND_INDICES.value, + ControlParts.HEAD.value + + JointType.QPOS.value: TeleoperationData.HEAD_QPOS_INDICES.value, + ControlParts.WAIST.value + + JointType.QPOS.value: TeleoperationData.WAIST_QPOS_INDICES.value, + } + qpos_dict = {} + for key, indices in qpos_index_dict.items(): + qpos_dict[key] = proprio[:, indices] + + actions = state_unifier.fill_in_action(qpos_dict) + proprio = state_unifier.fill_in_state(qpos_dict) + parse_dict = self.parse_core(proprio, actions, step_id, chunk_size) + parse_dict.update({"meta": meta}) + for cam in camera_used: + parse_dict[cam] = VLADataset.parse_img( + f, + step_id, + first_idx, + camera_used_from_dualsys_to_real[cam], + self.img_history_size, + Modality.IMAGES.value, + camera_used=camera_used_from_dualsys_to_real[cam], + ) + return True, parse_dict + + def parse_sim_dict( + self, f: Dict, chunk_size: int, step_id: int = None + ) -> Dict[str, ModalInput]: + + if step_id is None: + step_id = VLADataset.random_step_id(f, chunk_size) + + obs = f["observations"] + metadata = dict(f["robot_meta"]) + first_idx = 1 + + proprio = obs[Modality.STATES.value][:] + num_steps = proprio.shape[0] + min_len_step = metadata["min_len_steps"] + # [Optional] We drop too-short episode + if num_steps < min_len_step: + return False, None + + # We randomly sample a timestep + + camera_used = ( + convert_bytes(list(metadata["observation"]["vision"].keys())) + if self.camera_used is None + else self.camera_used + ) + + # Assemble the meta + meta = { + "dataset_name": self.DATASET_NAME, + "#steps": num_steps, + "step_id": step_id, + "instruction": "", + "camera_used": camera_used, + } + + assert ( + self.indices_generator.dof == metadata["arm_dofs"] + ), "Train dof {} but dataset dof {}.".format( + self.indices_generator.dof, metadata["arm_dofs"] + ) + parse_dict = self.parse_core( + proprio, f[Modality.ACTIONS.value], step_id, chunk_size + ) + parse_dict.update({"meta": meta}) + + for cam in camera_used: + cam_r = get_right_name(cam) + if cam_r in obs[Modality.IMAGES.value] and cam_r not in camera_used: + # insert camera name after cam + camera_used.insert(camera_used.index(cam) + 1, cam_r) + + for cam in camera_used: + parse_dict[cam] = VLADataset.parse_img( + f, + step_id, + first_idx, + cam, + self.img_history_size, + Modality.IMAGES.value, + camera_used=camera_used, + ) + + if PrivilegeType.MASK.value in obs: + parse_dict[ + cam + "_{}".format(PrivilegeType.MASK.value) + ] = VLADataset.parse_img( + f, + step_id, + first_idx, + cam, + self.img_history_size, + PrivilegeType.MASK.value, + camera_used=camera_used, + ) + if PrivilegeType.EXTEROCEPTION.value in obs: + if obs[PrivilegeType.EXTEROCEPTION.value][camera_used[0]].shape[0] != 0: + parse_dict[ + PrivilegeType.EXTEROCEPTION.value + ] = VLADataset.parse_exteroception( + f, + step_id, + chunk_size, + camera_used=camera_used, + ) + + if Modality.GEOMAP.value in obs: + if ( + hasattr(obs[Modality.GEOMAP.value][camera_used[0]], "shape") + and obs[Modality.GEOMAP.value][camera_used[0]].shape[0] != 0 + ): + parse_dict[Modality.GEOMAP.value] = VLADataset.parse_img( + f, + step_id, + first_idx, + CameraName.HEAD.value, + self.img_history_size, + Modality.GEOMAP.value, + camera_used=camera_used, + np_ops=lambda x: np.tile(np.expand_dims(x, -1), [1, 1, 1, 3]), + ) + + # Return the resulting sample + # For unavailable images, return zero-shape arrays, i.e., (IMG_HISORY_SIZE, 0, 0, 0) + # E.g., return np.zeros((self.img_history_size, 0, 0, 0)) for the key "cam_left_wrist", + # if the left-wrist camera is unavailable on your robot + return True, parse_dict + + def parse_core( + self, proprio: np.ndarray, actions: np.ndarray, step_id: int, chunk_size: int + ): + # Parse the state and action + state = proprio[np.maximum(step_id - self.state_history_len, 0) : step_id] + state = np.concatenate( + [np.tile(state[0:1], [self.state_history_len - state.shape[0], 1]), state], + 0, + ) + self.indices_generator: ActionIndicesGenerator + global_mapping = self.indices_generator.global_mapping + state_indices = global_mapping.get_indices( + convert_bytes(self.state), + ) + state_indicator = np.zeros_like(state, dtype=np.int8) + state_indicator[:, state_indices] = 1 + state *= state_indicator + proprio *= state_indicator[0:1] + state_std = np.std(proprio, axis=0) + state_mean = np.mean(proprio, axis=0) + state_norm = np.sqrt(np.mean(proprio**2, axis=0)) + action_indices = self.indices_generator.get( + self.output, + ) + actions = deepcopy(actions[step_id : step_id + chunk_size]) + # FIXME: handness injection + delta_qpos_indices = self.indices_generator.get_all_delta_qpos() + qpos_indices = self.indices_generator.get_all_qpos() + # NOTE: Ops `cumsum` equal to action[:horizon]-action[0:1]. + # TODO: action = action_chunk - current_obs. + actions[:, delta_qpos_indices] = ( + actions[:, qpos_indices] - state[-1:, qpos_indices] + ) + + actions = pad_to_chunk(actions, chunk_size=chunk_size) + action_indicator = np.zeros_like(actions, dtype=np.int8) + action_indicator[:, action_indices] = 1 + actions *= action_indicator[0:1] + + parse_dict = { + "state_std": state_std, + "state_mean": state_mean, + "state_norm": state_norm, + Modality.STATES.value: Proprioception(data=state, mask=state_indicator), + Modality.ACTIONS.value: Proprioception(data=actions, mask=action_indicator), + PrivilegeType.PROGRESS.value: step_id / proprio.shape[0], + } + return parse_dict diff --git a/embodichain/data/data_engine/online/engine.py b/embodichain/data/data_engine/online/engine.py new file mode 100644 index 00000000..8b49e391 --- /dev/null +++ b/embodichain/data/data_engine/online/engine.py @@ -0,0 +1,525 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import time +import sys +import numpy as np +from threading import Thread +from typing import Dict, Tuple, Any, List, Callable, Optional +from copy import deepcopy +import threading +from embodichain.data.data_engine.online.enum import ( + ConsumerTeleEnum, + ProducerTeleEnum, +) + +import torch +import torch.multiprocessing as mp +import copy +from embodichain.utils.logger import ( + log_info, + log_warning, + decorate_str_color, + log_debug, +) + +# Must call cuda init to prevent cuda error in subprocess. +torch._C._cuda_init() + +from dexsim.utility import NumpyRNG + +import threading +from multiprocessing import shared_memory +import pickle +from datetime import datetime +import zmq + +__all__ = ["MaiDataEngine"] + +rng = NumpyRNG.get_rng() + +log_info_produce = lambda x: log_info(decorate_str_color(x, "cyan")) +log_info_consume = lambda x: log_info(decorate_str_color(x, "orange")) + +MAX_LOOP_TIMES = 40000 + + +def init_context(port): + context = zmq.Context() + socket = context.socket(zmq.REQ) + socket.connect("tcp://localhost:{}".format(port)) + return socket + + +class DataPoolCont: + data: Any + count: int = 0 + tag: str + + @staticmethod + def from_list(data_pool: List[Dict]) -> List["DataPoolCont"]: + ret = [] + for data in data_pool: + dcnt = DataPoolCont() + dcnt.data = data + dcnt.count = 0 + dcnt.tag = str(datetime.now()).split(".")[0] + ret.append(dcnt) + return ret + + @staticmethod + def clean_data_pool_in_place( + data_pool: List["DataPoolCont"], clean_indices: List[int] + ): + if clean_indices is None: + data_pool = [] + else: + if len(clean_indices) > 0: + log_debug( + "Clean data pool with data indices {}, counts {}.".format( + clean_indices, + [data_pool[index].count for index in clean_indices], + ), + color="purple", + ) + for i in list(np.sort(clean_indices)[::-1]): + data_pool.pop(i) + + +def fetch_data( + queue_data: mp.Queue, data_pool: List[DataPoolCont], worker_info, debug: bool = True +) -> bool: + start_time = time.time() + try: + existing_shm = queue_data.get(timeout=5) + except Exception as error: + log_debug("Timeout! {}.".format(str(error)), color="red") + return False + log_debug( + "[Thread {}][Worker {}][Get] Cost {}s.".format( + threading.current_thread().ident, + worker_info.id, + time.time() - start_time, + ) + ) + start_time = time.time() + scene_data = pickle.loads(existing_shm.buf[:]) + log_debug( + "[Thread {}][Worker {}][Pickle] Cost {}s.".format( + threading.current_thread().ident, + worker_info.id, + time.time() - start_time, + ) + ) + + if np.random.random() > 0.5 or queue_data.qsize() == 0: + start_time = time.time() + queue_data.put(existing_shm) # put back + log_debug( + "[Thread {}][Worker {}][Put] Cost {}s.".format( + threading.current_thread().ident, + worker_info.id, + time.time() - start_time, + ) + ) + + assert isinstance(scene_data, list), "Invalid data format {}.".format( + type(scene_data) + ) + start_time = time.time() + data = DataPoolCont.from_list(scene_data) + data_pool.extend(data) + + log_debug( + "[Thread {}][Worker {}][Other] Cost {}s.".format( + threading.current_thread().ident, + worker_info.id, + time.time() - start_time, + ) + ) + return True + + +class RestockCriterion: + def __init__(self, data_pool_limit: int, buffer_size: int, max_sample_num: int): + self.data_pool_limit = data_pool_limit + self.buffer_size = buffer_size + self.max_sample_num = max_sample_num + + def restock_condition(self, data_pool: List, queue: mp.Queue) -> bool: + return len(data_pool) < self.data_pool_limit + + def expired_condition( + self, data_pool: List[DataPoolCont], inverse: bool = False + ) -> List[bool]: + + if len(data_pool) == 0: + return [] + + if inverse: + return [data.count <= self.max_sample_num for data in data_pool] + else: + return [data.count > self.max_sample_num for data in data_pool] + + +class OnlineEngine: + """Data manager for online data production and training. + + The objectives of this class are: + - Manage the fetch data in a separate thread. + - Perform data synchronization between the data production process and + the training process (main process). + - Provide data sampling interface for the training process, which is designed + to return a batch of synthetic data with the different scene id. + - Data lifecycle management. + + To achieve the above objectives, the following functions should be implemented: + - from_shm_thread (static method) + + Args: + insight_config (List[CfgNode]): The config of insight pipeline. + episode_limit (int, optional): The maximum number of frames in the data pool. Defaults to 24. + max_sample_num (int, optional): The maximum number of times that a data can be sampled. + Defaults to 2. + target_device (torch.device, optional): The target device of the data. Defaults to torch.device('cpu'). + annos_param (Dict[str, Any], optional): The parameters of the annotations. Defaults to None. + data_gen_func (Callable, optional): The data generation function. Defaults to None. + unique_scene_frame (int, optional): The number of unique scene frame to be sampled. Defaults to None. + port (int, optional): The ZeroMQ socket port. Defaults to 5555. + buffer_size(int, optional): The number of max data queue size. Defaults to 10. + """ + + def __init__( + self, + episode_limit: int = 24, + max_sample_num: int = 2, + port: int = 5555, + buffer_size: int = 10, + multiprocess: bool = False, + **kwargs, + ) -> None: + + self.episode_limit = episode_limit + self._max_sample_num = max_sample_num + self.port = port + + self._data_pool = [] + + self._duration = 0.01 + + self._context = mp.get_context("forkserver") + + self._queue_data = self._context.Queue() + self._queue_data.cancel_join_thread() + + self.buffer_size = buffer_size + + self._data_gen_proc = None + self._fetch_data_thread = None + self._restock_data_pool = None + + self._is_started = False + self._is_restocked = False + self._socket = init_context(port + 1 if multiprocess else port) + + self._restock_criterion = RestockCriterion( + data_pool_limit=episode_limit, + buffer_size=buffer_size, + max_sample_num=max_sample_num, + ) + self._lock = threading.RLock() + + def start( + self, + ) -> None: + """Start the data production process and the data synchronization thread. + + Args: + wait_for_limit (bool, optional): Whether to wait for the data pool to reach + the frame limit. Defaults to False. + """ + + self._signal_gen = self._context.Value("b", True) + self._signal_fetch = self._context.Value("b", True) + + self._fetch_data_thread = Thread( + target=self.from_shm_thread, + args=( + self._socket, + self._queue_data, + self._duration, + self.buffer_size, + ), + daemon=True, + ) + self._fetch_data_thread.start() + self._is_started = True + log_info( + "Now start the thread to fetch data from share memory.", color="purple" + ) + + def start_restock(self, static: bool = False): + if static: + self._restock_data_pool = Thread( + target=self.restock_data_pool_static, + args=( + self._data_pool, + self._queue_data, + self._duration, + self._restock_criterion, + self._context, + self._lock, + ), + daemon=True, + ) + else: + self._restock_data_pool = Thread( + target=self.restock_data_pool, + daemon=True, + ) + + self._restock_data_pool.start() + self._is_restocked = True + + def stop(self) -> None: + if self.is_started: + self._is_started = False + self._signal_fetch.value = 2 + self._fetch_data_thread.join() + self.empty_queue(self._queue_data, self._context) + self.clean_data_pool_in_place() + self._signal_gen.value = 2 + else: + log_info( + "The data generation process has not been started.", color="purple" + ) + + @property + def is_started(self) -> bool: + return self._is_started + + @property + def data_size(self) -> int: + with self._lock: + return len(self._data_pool) + + @property + def queue_size(self) -> int: + return self._queue.qsize() + + @property + def unique_scene_frame(self) -> int: + return self._unique_scene_frame + + @staticmethod + def empty_queue(queue: mp.Queue, context: mp) -> None: + while queue.qsize() > 0: + try: + queue.get() + except Exception as e: + log_info("queue put invaild data format") + queue.close() + queue.join_thread() + queue = context.Queue() + break + return queue + + @staticmethod + def empty_share_memory(queue: mp.Queue) -> None: + while queue.qsize() > 0: + shm_name = queue.get() + shm = shared_memory.SharedMemory(shm_name) + shm.close() + shm.unlink() + + def restock_data_pool(self): + return OnlineEngine.restock_data_pool_static( + self._data_pool, + self._queue_data, + self._duration, + self._restock_criterion, + self._context, + self._lock, + ) + + @staticmethod + def restock_data_pool_static( + data_pool: List[DataPoolCont], + queue_data: mp.Queue, + duration: float, + restock_criterion: RestockCriterion, + context, + thread_lock, + ): + counts = 0 + + worker_info = torch.utils.data.get_worker_info() + if worker_info is None: + + class FakeWorkerInfo: + num_workers = 1 + id = 0 + + worker_info = FakeWorkerInfo() + + while True: + time.sleep(duration) + # always clean the data pool first. + + start_time = time.time() + with thread_lock: + # delete + clean_indices = list( + np.argwhere(restock_criterion.expired_condition(data_pool)).reshape( + -1 + ) + ) + DataPoolCont.clean_data_pool_in_place( + data_pool, + clean_indices, + ) + if len(clean_indices) > 0: + log_debug( + "[Thread {}][Delete][Cost {}s]".format( + threading.current_thread().ident, time.time() - start_time + ) + ) + + # after clean, we check whether to restock data. + while restock_criterion.restock_condition(data_pool, queue_data): + + prev_data_size = len(data_pool) + should_fetch = False + for i in range(worker_info.num_workers): + if queue_data.qsize() > 0 and worker_info.id == i: + should_fetch = True + if should_fetch: + start_time = time.time() + with thread_lock: + # add + fetch_data( + data_pool=data_pool, + queue_data=queue_data, + worker_info=worker_info, + ) + log_debug( + "[Thread {}][Worker {}][ToDataPool] Produce data: {}->{}. Cost {}s.".format( + threading.current_thread().ident, + worker_info.id, + prev_data_size, + len(data_pool), + time.time() - start_time, + ) + ) + counts = 0 + else: + counts += 1 + + if counts % MAX_LOOP_TIMES == 0 and counts != 0: + log_info("Can not find the shm after {} times.".format(counts)) + # queue_data = OnlineEngine.empty_queue(queue_data, context) + + @staticmethod + def from_shm_thread( + socket, + queue_data: mp.Queue, + duration: float = 0.001, + buffer_size: int = 10, + ) -> None: + """The data fetching thread for data synchronization. + + The queue_data_size is used to control the data fetching thread. + If queue_data_size < buffer_size, the data fetching thread will fetch data from the queue. + If queue_data_size >= buffer_size, the data fetching thread will stop fetch data. + + Args: + socket (zmq.Context): The socket send signal for connect fetch and generator. + queue_data (mp.Queue): This queue contains information about shared memory. + duration (float, optional): _description_. Defaults to 0.001. + port (int, optional): The ZeroMQ socket port. Defaults to 5555. + buffer_size(int, optional): The number of max data queue size. Defaults to 10. + """ + counts = 0 + while True: + time.sleep(duration) + counts += 1 + if queue_data.qsize() < buffer_size: + socket.send_string(ConsumerTeleEnum.SHAKEHAND.value) + message = socket.recv() + try: + message_str = message.decode() + except Exception as e: + log_debug(str(e), color="red") + message_str = "" + if message_str != ProducerTeleEnum.NOREADY.value: + log_debug("Receive data.", color="purple") + shm_name = pickle.loads(message).popleft() + existing_shm = shared_memory.SharedMemory(name=shm_name) + queue_data.put(existing_shm) + log_debug( + "[FromShmThread] Produce queue: {}->{};".format( + queue_data.qsize() - 1, queue_data.qsize() + ) + ) + else: + if counts % MAX_LOOP_TIMES == 0: + log_debug("Queue is full. Skip this stage.", "purple") + + def sample_data( + self, + ): + + if self._is_restocked: + pass + else: + log_debug("Now start the thread to restock data.", color="purple") + self.start_restock(static=False) + + worker_info = torch.utils.data.get_worker_info() + if worker_info is None: + + class FakeWorkerInfo: + num_workers = 1 + id = 0 + + worker_info = FakeWorkerInfo() + + counts = 0 + while True: + time.sleep(self._duration) + if len(self._data_pool) > 0: + start_time = time.time() + with self._lock: + index = rng.integers(0, len(self._data_pool)) + data = self._data_pool[index] + self._data_pool[index].count += 1 + log_debug( + "[SampleData, worker {}] Consume data {}: index {}; times: {}->{}; Show queue size: {}; Cost time: {}s.".format( + worker_info.id, + data.tag, + index, + data.count, + data.count + 1, + self._queue_data.qsize(), + np.round(time.time() - start_time, 4), + ) + ) + counts = 0 + return data.data + else: + counts += 1 + if counts % MAX_LOOP_TIMES == 0: + log_info("Data pool is always empty after {} times.".format(counts)) diff --git a/embodichain/data/data_engine/online/enum.py b/embodichain/data/data_engine/online/enum.py new file mode 100644 index 00000000..a93b00d6 --- /dev/null +++ b/embodichain/data/data_engine/online/enum.py @@ -0,0 +1,34 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from enum import Enum + + +class ConsumerTeleEnum(Enum): + SHAKEHAND = "Data is ready?" + CONSUME = "Fetch data!" + NOCONSUME = "Data_pool is full." + GOTDATA = "Feched data!" + NOGOTDATA = "Not fetching data." + + +class ProducerTeleEnum(Enum): + READY = "Yes" + NOREADY = "No ready" + FULL = "Data_pool is full" + FAIL = "Failed" + SEND = "Send!" + EMPTYSTR = "Empty String." diff --git a/embodichain/data/data_engine/online/online_generator.py b/embodichain/data/data_engine/online/online_generator.py new file mode 100644 index 00000000..979f3543 --- /dev/null +++ b/embodichain/data/data_engine/online/online_generator.py @@ -0,0 +1,191 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import time +import zmq +import random +from multiprocessing import shared_memory +import pickle +from collections import deque +from typing import List +from threading import Thread +import multiprocessing as mp +import traceback +from embodichain.utils.logger import log_info, log_warning, log_error, log_debug +from embodichain.data.data_engine.online.enum import ( + ConsumerTeleEnum, + ProducerTeleEnum, +) + +torch._C._cuda_init() + + +class OnlineGenerator: + """Callback collection for online training mode.""" + + def __init__( + self, port: int, max_limit_gb: int = 50, multiprocess: bool = False, **kwargs + ) -> None: + self.shm_val = None + max_limit = max_limit_gb * 1024**3 + self._context = mp.get_context("forkserver") + self.port = port + self.socket = self.init_context(self.port, multiprocess) + self._duration = 0.01 + self.queue = deque() + self.queue_memroy = deque() + self.max_limit = max_limit + + self.validation_config = kwargs.get("validation", {}) + + def get_validation_config(self): + return self.validation_config + + def init_context(self, port, multiprocess: bool = False): + context = zmq.Context() + socket = context.socket(zmq.REP) + if multiprocess: + socket.connect(f"tcp://127.0.0.1:{port}") + else: + socket.bind(f"tcp://*:{port}") + + return socket + + def generator(self, generate_func, loop_times: int = -1, **kwargs): + self.signal = self._context.Value("b", True) + + self._zmq_send = Thread( + target=self.zmq_send, args=(self.queue, self.signal), daemon=True + ) + self._zmq_send.start() + log_debug("Start zmq sending.") + scene_id = 0 + + # -1 means infinite loop + while scene_id < loop_times or loop_times == -1: + if self.signal.value == 1: + first_time = True + try: + t0 = time.time() + return_list = generate_func( + time_id=scene_id, **self.validation_config + ) + + # TODO: support multiple trajectories for each scene. + if len(return_list) > 1: + log_error( + "Only support one trajectory for each scene in online generation mode." + ) + + data_dict_list = [return_list[0]["data"]] + + if ( + scene_id == 0 + and self.validation_config.get("num_samples", 0) > 0 + and "data_path" in return_list[0] + ): + # create shared memory to store the validation dataset path, which will be accessed by training process. + import sys + + data_path = return_list[0]["data_path"] + + shared_name = self.validation_config.get( + "dataset_name", "val_data_path" + ) + log_info( + f"Create shared memory for validation data path: {shared_name}", + color="green", + ) + self.shm_val = shared_memory.SharedMemory( + name=shared_name, + create=True, + size=len(data_path.encode()) + sys.getsizeof(""), + ) + self.shm_val.buf[: len(data_path.encode())] = data_path.encode() + log_info( + f"Craete shared memory for validation data path: {data_path}" + ) + + log_info( + f"Generate scene {scene_id + 1} time cost: {time.time() - t0}" + ) + serialized_data = pickle.dumps(data_dict_list) + shm = shared_memory.SharedMemory( + create=True, size=len(serialized_data) + ) + self.queue.append(shm.name) + self.queue_memroy.append( + {"name": shm.name, "size": len(serialized_data)} + ) + shm.buf[: len(serialized_data)] = serialized_data + except Exception as e: + log_error(f"Error in data generation process: {e}.") + traceback.print_exc() + self._zmq_send.join() + break + scene_id += 1 + self.empty_memory() + elif self.signal.value == 0: + if first_time: + log_warning("zmq recive full signal, wait generator signal") + first_time = False + log_warning("Signal value is 0.") + time.sleep(self._duration) + continue + else: + log_error("Unknown signal, data generator stop") + break + + def zmq_send(self, queue, signal): + while True: + try: + message = self.socket.recv_string() + if message == ConsumerTeleEnum.SHAKEHAND.value: + if len(queue) > 0: + log_warning( + "Recieve {} and send [data] to consumer.".format(message) + ) + self.socket.send(pickle.dumps(queue)) + queue.clear() + else: + self.socket.send(ProducerTeleEnum.NOREADY.value.encode()) + signal.value = 1 + except Exception as e: + print(e) + traceback.print_exc() + break + + def empty_memory(self): + total_size = sum([x["size"] for x in self.queue_memroy]) + log_info(f"share memory size is {total_size/(1024**3)} GB") + while total_size >= self.max_limit: + shm_name = self.queue_memroy.popleft() + if shm_name["name"] in self.queue: + log_info(f"remove {shm_name['name']} from queue") + self.queue.remove(shm_name["name"]) + try: + shm = shared_memory.SharedMemory(shm_name["name"]) + except: + continue + shm.close() + shm.unlink() + total_size = sum([x["size"] for x in self.queue_memroy]) + + def __del__(self): + if self.shm_val: + self.shm_val.close() + self.shm_val.unlink() diff --git a/embodichain/data/data_engine/unified_state.py b/embodichain/data/data_engine/unified_state.py new file mode 100644 index 00000000..fc430def --- /dev/null +++ b/embodichain/data/data_engine/unified_state.py @@ -0,0 +1,381 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from embodichain.data.global_indices import ( + GLOBAL_INDICES, + STATE_VEC_LEN, +) +from embodichain.data.global_mapping import GlobalMapping +import numpy as np +from typing import List, Dict, Tuple, Union +from embodichain.data.enum import ( + ArmEnum, + Modality, + JointType, + ActionMode, + EefType, + ControlParts, + EndEffector, + Modality, +) +from embodichain.utils.logger import log_info, log_warning + +DEFAULT_EMPTY_STATE = -1 + + +"""Unified state utilities for EmbodiChain. + +This module provides helpers to construct and query a unified state/action +vector representation used across EmbodiChain environments and agents. + +Classes: + StateUnifier: Fill sparse per-modality state/action dictionaries into a + fixed-length unified state vector where unspecified entries are set + to a sentinel value (DEFAULT_EMPTY_STATE). + + ActionIndicesGenerator: Query index ranges in the unified vector for + common action/state groups (e.g. qpos, delta qpos, end-effector pose). + +Constants: + DEFAULT_EMPTY_STATE (int): Sentinel value used to mark unspecified + entries in the unified vector. +""" + + +class StateUnifier: + """Convert per-modality state/action arrays into a unified vector. + + The StateUnifier is constructed with ``robot_meta`` (the robot's + metadata) which should contain an ``observation`` mapping with keys for + modalities (e.g. ``Modality.STATES``) and an ``actions`` specification. + + Attributes: + metadata (dict): Robot metadata passed at construction. + arm_dofs (int): Degrees of freedom for the arm (default: 12). + indices_generator (ActionIndicesGenerator): Helper for action indices. + proprio_meta: Metadata list for proprioceptive modalities. + global_mapping (GlobalMapping): Mapping from names to unified indices. + output: Action output specification from metadata. + state_dim (int): Fixed length of the unified state vector. + """ + + def __init__(self, robot_meta: Dict) -> None: + assert "arm_dofs" in robot_meta + assert "observation" in robot_meta + assert Modality.ACTIONS.value in robot_meta + + self.arm_dofs = robot_meta["arm_dofs"] + self.indices_generator = ActionIndicesGenerator(self.arm_dofs) + self.proprio_meta = robot_meta["observation"][Modality.STATES.value] + self.global_mapping = GlobalMapping(self.arm_dofs) + self.output = robot_meta[Modality.ACTIONS.value] + + self.state_dim = STATE_VEC_LEN + + def fill_in_state( + self, values: Union[np.ndarray, Dict[str, np.ndarray]] + ) -> np.ndarray: + """Fill a unified state vector from given values. + + Args: + values (np.ndarray or dict): If ``values`` is a numpy array it is + assumed to already be aligned to the unified layout and will + be placed into the output container. If it is a ``dict``, + keys should match entries from the robot metadata + ``observation[Modality.STATES]`` and values are numpy arrays + with a trailing dimension matching each state's width. + + Returns: + np.ndarray: An array with shape ``(..., STATE_VEC_LEN)`` containing + the unified state with unspecified entries set to + ``DEFAULT_EMPTY_STATE``. + """ + if isinstance(values, np.ndarray): + UNI_STATE_INDICES = self.global_mapping.get_indices(self.proprio_meta) + uni_vec = ( + np.ones(values.shape[:-1] + (self.state_dim,)) * DEFAULT_EMPTY_STATE + ) + uni_vec[..., UNI_STATE_INDICES] = values + return uni_vec + else: + shape_tuple_list = [] + for val in values.values(): + shape_tuple = val.shape[:-1] + if val.size != 0: + shape_tuple_list.append(shape_tuple) + + shape_tuple = list(set(shape_tuple_list)) + assert len(shape_tuple) == 1, "shape tuple {} is not unique.".format( + shape_tuple + ) + uni_vec = np.ones(shape_tuple[0] + (self.state_dim,)) * DEFAULT_EMPTY_STATE + for state_name in self.proprio_meta: + state_indices = self.global_mapping.get_indices([state_name]) + if values[state_name].size != 0: + uni_vec[..., state_indices] = values[state_name] + + return uni_vec + + def fill_in_action( + self, values: Union[np.ndarray, Dict[str, np.ndarray]] + ) -> np.ndarray: + """Fill a unified action vector from given action values. + + This mirrors :meth:`fill_in_state` but uses the metadata's action + output specification to determine which named outputs map into the + unified vector. + + Args: + values (np.ndarray or dict): Action values aligned to the unified + layout or a mapping from output names to numpy arrays. + + Returns: + np.ndarray: Unified vector shaped ``(..., STATE_VEC_LEN)`` with + unspecified entries filled with ``DEFAULT_EMPTY_STATE``. + """ + if isinstance(values, np.ndarray): + UNI_STATE_INDICES = self.indices_generator.get(self.output) + uni_vec = ( + np.ones(values.shape[:-1] + (self.state_dim,)) * DEFAULT_EMPTY_STATE + ) + uni_vec[..., UNI_STATE_INDICES] = values + return uni_vec + else: + shape_tuple_list = [] + for key, val in values.items(): + + shape_tuple = val.shape[:-1] + if val.size != 0: + shape_tuple_list.append(shape_tuple) + + shape_tuple = list(set(shape_tuple_list)) + assert len(shape_tuple) == 1, "shape tuple {} is not unique.".format( + shape_tuple + ) + + uni_vec = np.ones(shape_tuple[0] + (self.state_dim,)) * DEFAULT_EMPTY_STATE + for out_name in self.output: + state_indices = self.global_mapping.get_indices([out_name]) + if out_name in values and values[out_name].size != 0: + uni_vec[..., state_indices] = values[out_name] + return uni_vec + + +class ActionIndicesGenerator: + """Utility for generating index lists for action/state groups. + + The ActionIndicesGenerator wraps :class:`GlobalMapping` to provide + common queries like retrieving indices for all joint positions (qpos), + delta qpos (relative mode), end-effector transforms/poses, and + hand-specific selections (left/right/both). + + Args: + dof (int, optional): If provided, a :class:`GlobalMapping` is + constructed and reused for queries. + """ + + def __init__(self, dof: int = None): + self.global_mapping = None + self.dof = dof + if dof is not None: + self.global_mapping = GlobalMapping(dof) + + def get_all_qpos( + self, dof: int = None, handness: str = ArmEnum.DUAL_ARM.value + ) -> List[int]: + """Return indices covering all joint position entries. + + Args: + dof (int, optional): Degrees of freedom to construct a temporary + :class:`GlobalMapping` if the generator was not initialized + with a ``dof``. + handness (str): One of values from :class:`ArmEnum` specifying + which arm(s) to include. + + Returns: + List[int]: Ordered list of indices in the unified vector + corresponding to qpos entries for the requested arm + selection. + """ + qpos_name = JointType.QPOS.value + delta_qpos_name = ActionMode.RELATIVE.value + qpos_name + global_mapping = self.get_mapping(dof) + + all_names = list(global_mapping.mapping_from_name_to_indices.keys()) + if handness == ArmEnum.DUAL_ARM.value: + return self.get(all_names, dof, [qpos_name], [delta_qpos_name]) + elif handness == ArmEnum.LEFT_ARM_ONLY.value: + handness = ControlParts.LEFT_ARM.value + return self.get( + all_names, dof, [handness + qpos_name], [handness + delta_qpos_name] + ) + elif handness == ArmEnum.RIGHT_ARM_ONLY.value: + handness = ControlParts.RIGHT_ARM.value + return self.get( + all_names, dof, [handness + qpos_name], [handness + delta_qpos_name] + ) + + def get_all_delta_qpos( + self, dof: int = None, handness: str = ArmEnum.DUAL_ARM.value + ) -> List[int]: + """Return indices for delta (relative) joint position entries. + + Args and return are the same as :meth:`get_all_qpos` but select the + ``ActionMode.RELATIVE`` named entries. + """ + qpos_name = JointType.QPOS.value + delta_qpos_name = ActionMode.RELATIVE.value + qpos_name + global_mapping = self.get_mapping(dof) + + all_names = list(global_mapping.mapping_from_name_to_indices.keys()) + if handness == ArmEnum.DUAL_ARM.value: + return self.get(all_names, dof, [delta_qpos_name], []) + elif handness == ArmEnum.LEFT_ARM_ONLY.value: + handness = ControlParts.LEFT_ARM.value + return self.get(all_names, dof, [handness + delta_qpos_name], []) + elif handness == ArmEnum.RIGHT_ARM_ONLY.value: + handness = ControlParts.RIGHT_ARM.value + return self.get(all_names, dof, [handness + delta_qpos_name], []) + + def get_all_eef( + self, dof: int = None, handness: str = ArmEnum.DUAL_ARM.value + ) -> List[int]: + """Return indices covering end-effector (EEF) related entries. + + Args: + dof (int, optional): Degrees of freedom for mapping lookup. + handness (str): Which arm(s) to include (left/right/both). + + Returns: + List[int]: Indices corresponding to EEF-related entries. + """ + global_mapping = self.get_mapping(dof) + all_names = list(global_mapping.mapping_from_name_to_indices.keys()) + if handness == ArmEnum.DUAL_ARM.value: + return self.get( + all_names, + dof, + [ControlParts.LEFT_EEF.value, ControlParts.RIGHT_EEF.value], + [], + ) + elif handness == ArmEnum.LEFT_ARM_ONLY.value: + handness = ControlParts.LEFT_EEF.value + return self.get( + all_names, + dof, + [handness], + [], + ) + elif handness == ArmEnum.RIGHT_ARM_ONLY.value: + handness = ControlParts.RIGHT_EEF.value + return self.get( + all_names, + dof, + [handness], + [], + ) + + def get_all_eef_pose( + self, dof: int = None, handness: str = ArmEnum.DUAL_ARM.value + ) -> List[int]: + """Return indices specifically for EEF pose entries. + + Args: + dof (int, optional): Degrees of freedom for mapping lookup. + handness (str): Which arm(s) to include (left/right/both). + + Returns: + List[int]: Indices corresponding to EEF poses. + """ + global_mapping = self.get_mapping(dof) + all_names = list(global_mapping.mapping_from_name_to_indices.keys()) + + if handness == ArmEnum.DUAL_ARM.value: + return self.get(all_names, dof, [EefType.POSE.value], []) + elif handness == ArmEnum.LEFT_ARM_ONLY.value: + handness = ControlParts.LEFT_ARM.value + return self.get(all_names, dof, [handness + EefType.POSE.value], []) + elif handness == ArmEnum.RIGHT_ARM_ONLY.value: + handness = ControlParts.RIGHT_ARM.value + return self.get(all_names, dof, [handness + EefType.POSE.value], []) + + def get_mapping(self, dof: int = None): + """Return the :class:`GlobalMapping` used by this generator. + + If a mapping was created during initialization (because ``dof`` was + provided), ensure any provided ``dof`` argument matches it. Otherwise + construct and return a temporary :class:`GlobalMapping` for the + requested ``dof``. + + Args: + dof (int, optional): Degrees of freedom to construct a mapping + if one was not provided at initialization. + + Returns: + GlobalMapping: Mapping instance for name->index lookups. + """ + if self.global_mapping is not None: + assert dof is None or dof == self.dof + global_mapping = self.global_mapping + else: + assert ( + dof is not None + ), "Dof must be set when dof is not provided in initialization." + global_mapping = GlobalMapping(dof) + return global_mapping + + def get( + self, + output: List[str], + dof: int = None, + white_list: List[str] = None, + black_list: List[str] = None, + ) -> List[int]: + """Select and return indices from ``output`` names applying optional + white/black list filters. + + Args: + output (List[str]): Names (keys) in a :class:`GlobalMapping` + whose indices should be collected. + dof (int, optional): Degrees of freedom used to construct a + temporary :class:`GlobalMapping` if needed. + white_list (List[str], optional): If provided, only include names + that contain any of these substrings. + black_list (List[str], optional): If provided, exclude names + that contain any of these substrings. + + Returns: + List[int]: Ordered list of unified-vector indices for the + selected names. + """ + + action_indices = [] + global_mapping = self.get_mapping(dof) + + for action_type in output: + if isinstance(white_list, list) and isinstance(black_list, list): + if any([temp in action_type for temp in white_list]) and all( + [temp not in action_type for temp in black_list] + ): + action_indices += global_mapping.mapping_from_name_to_indices[ + action_type + ] + else: + action_indices += global_mapping.mapping_from_name_to_indices[ + action_type + ] + + return action_indices # keep order. diff --git a/embodichain/data/dataset.py b/embodichain/data/dataset.py new file mode 100644 index 00000000..f5c775fd --- /dev/null +++ b/embodichain/data/dataset.py @@ -0,0 +1,170 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import sys +import shutil +import hashlib +import open3d as o3d + + +from embodichain.utils import logger + + +class EmbodiChainDataset(o3d.data.DownloadDataset): + def __init__(self, prefix, data_descriptor, path): + # Perform the zip file and extracted contents check + # If the zip was not valid, the zip file would have been removed + # and the parent class would download and extract it again + self.check_zip(prefix, data_descriptor, path) + # Call the parent class constructor + super().__init__(prefix, data_descriptor, path) + + def check_zip(self, prefix, data_descriptor, path): + """Check the integrity of the zip file and its extracted contents.""" + # Path to the downloaded zip file + zip_file_name = os.path.split(data_descriptor.urls[0])[1] + zip_dir_path = os.path.join(path, "download", f"{prefix}") + zip_path = os.path.join(path, "download", f"{prefix}", f"{zip_file_name}") + # Path to the extracted directory + extracted_path = os.path.join(path, "extract", prefix) + + def is_safe_path(path_to_check): + """Verify if the path is within safe directory boundaries""" + return ( + "embodichain_data/download" in path_to_check + or "embodichain_data/extract" in path_to_check + ) + + def safe_remove_directory(dir_path): + """Safely remove a directory after path validation""" + if not is_safe_path(dir_path): + logger.log_warning( + f"Safety check failed, refusing to delete directory: {dir_path}" + ) + return False + + if os.path.exists(dir_path): + try: + shutil.rmtree(dir_path) + logger.log_info(f"Successfully removed directory: {dir_path}") + return True + except OSError as e: + logger.log_warning(f"Error while removing directory: {e}") + return False + return True + + # Check if the file already exists + if os.path.exists(zip_path): + # Calculate MD5 checksum of the existing file + md5_existing = self.calculate_md5(zip_path) + # Compare with the expected MD5 checksum + if md5_existing != data_descriptor.md5: + # If checksums do not match, delete the existing file + os.remove(zip_path) + # Ensure the extracted directory is removed if it exists + safe_remove_directory(extracted_path) + logger.log_warning( + f"Invalid MD5 checksum detected:\n" + f" - File: {zip_path}\n" + f" - Expected MD5: {data_descriptor.md5}\n" + f" - Actual MD5: {md5_existing}\n" + f"Cleaned up invalid files and directories for fresh download." + ) + return + else: + safe_remove_directory(zip_dir_path) + safe_remove_directory(extracted_path) + logger.log_info( + f"ZIP file not found at {zip_path}." + f"Cleaning up related directories for fresh download." + ) + return + + # Check if the extracted directory exists and is not empty + if not os.path.exists(extracted_path) or not os.listdir(extracted_path): + # Remove the zip file to trigger Open3D's automatic download mechanism + # Open3D will re-download and extract when the zip file is missing + if os.path.exists(zip_path): + os.remove(zip_path) + + # Clean up any existing empty extraction directory + # This ensures a clean state for the upcoming extraction process + safe_remove_directory(extracted_path) + logger.log_info( + f"Removed zip file {zip_path} and extracted path {extracted_path} to trigger Open3D download and extract. " + f"Reason: {'Missing extraction directory.' if not os.path.exists(extracted_path) else 'Empty extraction directory.'}" + ) + return + + def calculate_md5(self, file_path, chunk_size=8192): + """Calculate the MD5 checksum of a file.""" + hash_md5 = hashlib.md5() + with open(file_path, "rb") as f: + for chunk in iter(lambda: f.read(chunk_size), b""): + hash_md5.update(chunk) + return hash_md5.hexdigest() + + +def get_data_class(dataset_name: str): + """Retrieve the dataset class from the available modules. + + Args: + dataset_name (str): The name of the dataset class. + + Returns: + type: The dataset class. + + Raises: + AttributeError: If the dataset class is not found in any module. + """ + module_names = [ + "embodichain.data", + "embodichain.data.assets", + __name__, + ] + + for module_name in module_names: + try: + return getattr(sys.modules[module_name], dataset_name) + except AttributeError: + continue + + raise AttributeError(f"Dataset class '{dataset_name}' not found in any module.") + + +def get_data_path(data_path_in_config: str) -> str: + """Get the absolute path of the data file. + + Args: + data_path_in_config (str): The dataset path in the format "${dataset_name}/subpath". + + Returns: + str: The absolute path of the data file. + """ + if os.path.isabs(data_path_in_config): + return data_path_in_config + + split_str = data_path_in_config.split("/") + dataset_name = split_str[0] + sub_path = os.path.join(*split_str[1:]) + + # Use the optimized get_data_class function + data_class = get_data_class(dataset_name) + data_obj = data_class() + data_dir = data_obj.extract_dir + data_path = os.path.join(data_dir, sub_path) + return data_path diff --git a/embodichain/data/enum.py b/embodichain/data/enum.py new file mode 100644 index 00000000..5c31ed9e --- /dev/null +++ b/embodichain/data/enum.py @@ -0,0 +1,349 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + +from typing import List, Tuple, Union, Dict +from enum import Enum, IntEnum +from itertools import product +from aenum import Enum as AEnum +from aenum import NoAlias + +from embodichain.utils.utility import get_right_name + + +class ModalInput: + def __init__( + self, + data: Union[torch.Tensor, np.ndarray] = None, + mask: Union[torch.Tensor, np.ndarray] = None, + name: str = "", + ): + self.data = data + self.mask = mask # indicator mask for the data, e.g., which part is valid. + self.name = name + + +class Privilege: + def __init__( + self, + data: Union[torch.Tensor, np.ndarray] = None, + mask: Union[torch.Tensor, np.ndarray] = None, + name: str = "", + ): + self.data = data + self.mask = mask # indicator mask for the data, e.g., which part is valid. + self.name = name + + +class Mask(Privilege): + pass + + +class Exteroception(Privilege): + pass + + +class State(Privilege): + pass + + +class Proprioception(ModalInput): + pass + + +class Image(ModalInput): + pass + + +class GeoMap(ModalInput): + pass + + +class Lang(ModalInput): + pass + + +class Modality(Enum): + STATES = "states" + STATE_INDICATOR = "state_indicator" + ACTIONS = "actions" + ACTION_INDICATOR = "action_indicator" + IMAGES = "images" + LANG = "lang" + LANG_INDICATOR = "lang_indicator" + GEOMAP = "geomap" # e.g., depth, point cloud, etc. + VISION_LANGUAGE = "vision_language" # e.g., image + lang + + +class JointType(Enum): + QPOS = "qpos" + + +class EefType(Enum): + POSE = "eef_pose" + + +class ActionMode(Enum): + ABSOLUTE = "" + RELATIVE = "delta_" # This indicates the action is relative change with respect to last state. + + +class EndEffector(Enum): + GRIPPER = "gripper" + DEXTROUSHAND = "hand" + + +class EefExecute(Enum): + OPEN = "execute_open" + CLOSE = "execute_close" + + +class CameraName(Enum): + HEAD = "cam_high" + HEAD_RIGHT = get_right_name("cam_high") + RIGHT_WRIST = "cam_right_wrist" + LEFT_WRIST = "cam_left_wrist" + + +class ControlParts(Enum): + LEFT_ARM = "left_arm" + RIGHT_ARM = "right_arm" + LEFT_EEF = "left_eef" + RIGHT_EEF = "right_eef" + HEAD = "head" + WAIST = "waist" + + +class TeleoperationData(Enum): + """Enum for teleoperation data conversion script specific string constants""" + + # Camera types + HEAD_CAMERA = "head" + HAND_CAMERA = "hand" + + # Camera positions + LEFT_PLACE = "left" + RIGHT_PLACE = "right" + + # Camera name prefixes + CAM_HIGH_PREFIX = "cam_high" + CAM_HAND_PREFIX = "cam_hand" + + # File names and patterns + METADATA_FILE = "metadata.jsonl" + QPOS_PATTERN = "pose_record_*.json" + IMAGE_PATH_KEY = "image_path" + TIMESTAMP_KEY = "timestamp" + CAMERA_TYPE_KEY = "camera_type" + + # Data structure keys + OBSERVATIONS = "observations" + IMAGES = "images" + QPOS = "qpos" + ACTION = "action" + FRAMES = "frames" + DATA = "data" + + # Joint keys (common ones) + LEFT_GRIPPER = "LEFT_GRIPPER" + RIGHT_GRIPPER = "RIGHT_GRIPPER" + LEFT_HAND_PREFIX = "LEFT_HAND" + RIGHT_HAND_PREFIX = "RIGHT_HAND" + # Joint index mapping for real robot data + LEFT_ARM_QPOS_INDICES = [6, 7, 8, 9, 10, 11, 12] + RIGHT_ARM_QPOS_INDICES = [14, 15, 16, 17, 18, 19, 20] + LEFT_EEF_DEXTROUSHAND_INDICES = [22, 23, 24, 25, 26, 27] + RIGHT_EEF_DEXTROUSHAND_INDICES = [28, 29, 30, 31, 32, 33] + WAIST_QPOS_INDICES = [ + 3, + ] + HEAD_QPOS_INDICES = [4, 5] + + +class Hints(Enum): + EEF = ( + ControlParts.LEFT_EEF.value, + ControlParts.RIGHT_EEF.value, + EndEffector.GRIPPER.value, + EndEffector.DEXTROUSHAND.value, + ) + ARM = (ControlParts.LEFT_ARM.value, ControlParts.RIGHT_ARM.value) + + +class CameraLoc(AEnum): + # The difference between CameraLoc and CameraName is that CameraLoc allows duplicate values. + # And the value is used to indicate the sub-network ids, e.g. LEFT_WRIST and RIGHT_WRIST share the same sub-network feature extraction. + _settings_ = NoAlias + HEAD = 0 + RIGHT_WRIST = 1 + LEFT_WRIST = 1 + + +class CameraOrder(IntEnum): + # This is used to indicate the order of camera inputs, for both simulation and real deployment, training and inference. + # For dual system, the order is HEAD, RIGHT_WRIST, LEFT_WRIST. + HEAD = 0 + RIGHT_WRIST = 1 + LEFT_WRIST = 2 + + +DEFAULT_CAMERA_ORDER = {tmp.value: CameraName[tmp.name].value for tmp in CameraOrder} +DEFAULT_CAMERA_LOC = {CameraName[tmp.name].value: tmp.value for tmp in CameraLoc} + + +def link_type(*args) -> str: + l = len(args) + if l == 0: + return "" + elif l == 1: + return args[0] + elif l >= 2: + ret_str = "[{}]".format(args[0]) + for i in range(1, l): + ret_str += "_[{}]".format(args[i]) + return ret_str + + +combined_members = { + link_type(a.name + b.name, c.name + d.name, e.name): link_type( + a.value + b.value, c.value + d.value, e.value + ) + for a, b, c, d, e in product( + ActionMode, JointType, ActionMode, EefType, EndEffector + ) +} +ActionType = Enum("ActionType", combined_members) +combined_proprio_members = { + link_type(a.name, b.name, c.name): link_type(a.value, b.value, c.value) + for a, b, c in product(JointType, EefType, EndEffector) +} +ProprioType = Enum("ProprioType", combined_proprio_members) + + +def parse_action_type(action_type: str) -> Tuple[str, str, str]: + splits = action_type.split("[") + assert len(splits) == 3, "{} must contain 3-[].".format(action_type) + proprio_type = splits[0].split("]")[0] + eef_type = splits[1].split("]")[0] + end_effector = splits[2].split("]")[0] + return proprio_type, eef_type, end_effector + + +def parse_proprio_type(proprio_type: str) -> Tuple[str, str, str]: + return parse_action_type(proprio_type) + + +class PrivilegeType(Enum): + EXTEROCEPTION = "exteroception" + MASK = "mask" + STATE = "state" + PROGRESS = "progress" + + +SUPPORTED_PROPRIO_TYPES = [ + ControlParts.LEFT_ARM.value + EefType.POSE.value, + ControlParts.RIGHT_ARM.value + EefType.POSE.value, + ControlParts.LEFT_ARM.value + JointType.QPOS.value, + ControlParts.RIGHT_ARM.value + JointType.QPOS.value, + ControlParts.LEFT_EEF.value + EndEffector.DEXTROUSHAND.value, + ControlParts.RIGHT_EEF.value + EndEffector.DEXTROUSHAND.value, + ControlParts.LEFT_EEF.value + EndEffector.GRIPPER.value, + ControlParts.RIGHT_EEF.value + EndEffector.GRIPPER.value, +] +SUPPORTED_ACTION_TYPES = SUPPORTED_PROPRIO_TYPES + [ + ControlParts.LEFT_ARM.value + ActionMode.RELATIVE.value + JointType.QPOS.value, + ControlParts.RIGHT_ARM.value + ActionMode.RELATIVE.value + JointType.QPOS.value, +] +SUPPORTED_EXTRA_VISION_TYPES = [ + Modality.GEOMAP.value, + PrivilegeType.EXTEROCEPTION.value, + PrivilegeType.MASK.value, +] + + +def search_sub_str(sub_str: str, refs: List[str]): + ret = [False for _ in refs] + for i, ref in enumerate(refs): + ret[i] = sub_str in ref + return ret + + +class ArmEnum(IntEnum): + LEFT_ARM_ONLY = 1 + RIGHT_ARM_ONLY = 2 + DUAL_ARM = 3 + + +class ArmName(Enum): + LEFT_ARM_ONLY = "left_arm" + RIGHT_ARM_ONLY = "right_arm" + + +class SemanticMask(IntEnum): + BACKGROUND = 0 + FOREGROUND = 1 + ROBOT = 2 + + +def get_all_cond(suffix: str = "_cond") -> Dict[str, str]: + cond_dict = {} + for modality in Modality: + cond_dict[modality.value] = modality.value + suffix + for privilege in PrivilegeType: + cond_dict[privilege.value] = privilege.value + suffix + return cond_dict + + +def is_dual_arms(dofs: int) -> bool: + return dofs > 10 + + +from collections import deque + + +class HistoryChunks: + def __init__(self, history_len: int = 2) -> None: + self.deque = deque(maxlen=history_len) + self.history_len = history_len + + def inqueue(self, data: ModalInput) -> None: + self.deque.append(data) + + def __getitem__( + self, + index: int, + ) -> ModalInput: + return self.deque[index] + + def __len__( + self, + ) -> int: + return len(self.deque) + + def isfull( + self, + ) -> bool: + return len(self) == self.history_len + + def get_list( + self, + ) -> List[ModalInput]: + return list(self.deque) + + def clean(self) -> None: + self.deque.clear() diff --git a/embodichain/data/global_indices.py b/embodichain/data/global_indices.py new file mode 100644 index 00000000..518a2e4c --- /dev/null +++ b/embodichain/data/global_indices.py @@ -0,0 +1,132 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import numpy as np + +GLOBAL_INDICES = { + # [0, 10): right arm joint positions + **{"arm_joint_{}_pos".format(i): i for i in range(10)}, + **{"right_arm_joint_{}_pos".format(i): i for i in range(10)}, + # [10, 15): right gripper joint positions + **{"gripper_joint_{}_pos".format(i): i + 10 for i in range(5)}, + **{"right_gripper_joint_{}_pos".format(i): i + 10 for i in range(5)}, + "gripper_open": 10, # alias of right_gripper_joint_0_pos + "right_gripper_open": 10, + # [15, 25): right arm joint velocities + **{"arm_joint_{}_vel".format(i): i + 15 for i in range(10)}, + **{"right_arm_joint_{}_vel".format(i): i + 15 for i in range(10)}, + # [25, 30): right gripper joint velocities + **{"gripper_joint_{}_vel".format(i): i + 25 for i in range(5)}, + **{"right_gripper_joint_{}_vel".format(i): i + 25 for i in range(5)}, + "gripper_open_vel": 25, # alias of right_gripper_joint_0_vel + "right_gripper_open_vel": 25, + # [30, 33): right end effector positions + "eef_pos_x": 30, + "right_eef_pos_x": 30, + "eef_pos_y": 31, + "right_eef_pos_y": 31, + "eef_pos_z": 32, + "right_eef_pos_z": 32, + # [33, 39): right end effector 6D pose + "eef_angle_0": 33, + "right_eef_angle_0": 33, + "eef_angle_1": 34, + "right_eef_angle_1": 34, + "eef_angle_2": 35, + "right_eef_angle_2": 35, + "eef_angle_3": 36, + "right_eef_angle_3": 36, + "eef_angle_4": 37, + "right_eef_angle_4": 37, + "eef_angle_5": 38, + "right_eef_angle_5": 38, + # [39, 42): right end effector velocities + "eef_vel_x": 39, + "right_eef_vel_x": 39, + "eef_vel_y": 40, + "right_eef_vel_y": 40, + "eef_vel_z": 41, + "right_eef_vel_z": 41, + # [42, 45): right end effector angular velocities + "eef_angular_vel_roll": 42, + "right_eef_angular_vel_roll": 42, + "eef_angular_vel_pitch": 43, + "right_eef_angular_vel_pitch": 43, + "eef_angular_vel_yaw": 44, + "right_eef_angular_vel_yaw": 44, + # [45, 50): reserved + # [50, 60): left arm joint positions + **{"left_arm_joint_{}_pos".format(i): i + 50 for i in range(10)}, + # [60, 65): left gripper joint positions + **{"left_gripper_joint_{}_pos".format(i): i + 60 for i in range(5)}, + "left_gripper_open": 60, # alias of left_gripper_joint_0_pos + # [65, 75): left arm joint velocities + **{"left_arm_joint_{}_vel".format(i): i + 65 for i in range(10)}, + # [75, 80): left gripper joint velocities + **{"left_gripper_joint_{}_vel".format(i): i + 75 for i in range(5)}, + "left_gripper_open_vel": 75, # alias of left_gripper_joint_0_vel + # [80, 83): left end effector positions + "left_eef_pos_x": 80, + "left_eef_pos_y": 81, + "left_eef_pos_z": 82, + # [83, 89): left end effector 6D pose + "left_eef_angle_0": 83, + "left_eef_angle_1": 84, + "left_eef_angle_2": 85, + "left_eef_angle_3": 86, + "left_eef_angle_4": 87, + "left_eef_angle_5": 88, + # [89, 92): left end effector velocities + "left_eef_vel_x": 89, + "left_eef_vel_y": 90, + "left_eef_vel_z": 91, + # [92, 95): left end effector angular velocities + "left_eef_angular_vel_roll": 92, + "left_eef_angular_vel_pitch": 93, + "left_eef_angular_vel_yaw": 94, + # [95, 100): reserved + # [100, 102): base linear velocities + "base_vel_x": 100, + "base_vel_y": 101, + # [102, 103): base angular velocities + "base_angular_vel": 102, + # [103, 115): dextrous hand joint positions + **{"left_hand_joint_{}_pos".format(i): i + 103 for i in range(6)}, + **{"right_hand_joint_{}_pos".format(i): i + 109 for i in range(6)}, + # [115, 119): torso joint positions + **{"torso_joint_{}_pos".format(i): i + 115 for i in range(4)}, + # [119, 121): head joint positions + **{"head_joint_{}_pos".format(i): i + 119 for i in range(2)}, + "waist": 115, + # [121, 123): head joint velocities + **{"head_joint_{}_vel".format(i): i + 121 for i in range(2)}, + "waist_vel": 113, + # [124, 128): reserved +} + + +STATE_VEC_LEN = 128 + + +def get_all_left_related_indices(including_end: bool = True): + if including_end: + return np.arange(50, 128, step=1) + else: + return np.arange(50, 100) + + +def get_all_right_related_indices(): + return np.arange(0, 50) diff --git a/embodichain/data/global_mapping.py b/embodichain/data/global_mapping.py new file mode 100644 index 00000000..24ebcb34 --- /dev/null +++ b/embodichain/data/global_mapping.py @@ -0,0 +1,161 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from embodichain.data.enum import ( + ControlParts, + ActionMode, + EndEffector, + JointType, + EefType, + is_dual_arms, +) +from embodichain.data.global_indices import GLOBAL_INDICES +import numpy as np +from typing import List + + +class GlobalMapping: + def __init__(self, dof: int): + self_attrs = GlobalMapping.__dict__ + num_arm = 2 if is_dual_arms(dofs=dof) else 1 + single_dof = dof // num_arm + function_dict = {} + for k, v in self_attrs.items(): + if isinstance(v, staticmethod) and "__" not in k: + function_dict.update(v.__func__(dof=single_dof, num_arm=num_arm)) + self.mapping_from_name_to_indices = function_dict + + @staticmethod + def get_qpos_indices(dof: int, num_arm, **kwrags): + + return { + ControlParts.LEFT_ARM.value + + JointType.QPOS.value: [ + GLOBAL_INDICES[f"left_arm_joint_{i}_pos"] for i in range(dof) + ], + ControlParts.RIGHT_ARM.value + + JointType.QPOS.value: [ + GLOBAL_INDICES[f"right_arm_joint_{i}_pos"] for i in range(dof) + ], + ControlParts.HEAD.value + + JointType.QPOS.value: [ + GLOBAL_INDICES["head_joint_{}_pos".format(i)] for i in range(2) + ], + ControlParts.WAIST.value + JointType.QPOS.value: [GLOBAL_INDICES["waist"]], + } + + @staticmethod + def get_gripper_open_state_indices(num_arm, **kwrags): + return { + ControlParts.LEFT_EEF.value + + EndEffector.GRIPPER.value: [GLOBAL_INDICES["left_gripper_open"]], + ControlParts.RIGHT_EEF.value + + EndEffector.GRIPPER.value: [GLOBAL_INDICES["right_gripper_open"]], + } + + @staticmethod + def get_hand_qpos_indices(num_arm: int, hand_dof: int = 6, **kwrags): + return { + ControlParts.LEFT_EEF.value + + EndEffector.DEXTROUSHAND.value: [ + GLOBAL_INDICES[f"left_hand_joint_{i}_pos"] for i in range(hand_dof) + ], + ControlParts.RIGHT_EEF.value + + EndEffector.DEXTROUSHAND.value: [ + GLOBAL_INDICES[f"right_hand_joint_{i}_pos"] for i in range(hand_dof) + ], + } + + @staticmethod + def get_gripper_open_vel_indices(num_arm, **kwrags): + return { + ControlParts.LEFT_EEF.value + + ActionMode.RELATIVE.value + + EndEffector.GRIPPER.value: [GLOBAL_INDICES["left_gripper_open_vel"]], + ControlParts.RIGHT_EEF.value + + ActionMode.RELATIVE.value + + EndEffector.GRIPPER.value: [GLOBAL_INDICES["right_gripper_open_vel"]], + } + + @staticmethod + def get_delta_qpos_indices(dof: int, num_arm, **kwrags): + return { + ControlParts.LEFT_ARM.value + + ActionMode.RELATIVE.value + + JointType.QPOS.value: [ + GLOBAL_INDICES[f"left_arm_joint_{i}_vel"] for i in range(dof) + ], + ControlParts.RIGHT_ARM.value + + ActionMode.RELATIVE.value + + JointType.QPOS.value: [ + GLOBAL_INDICES[f"right_arm_joint_{i}_vel"] for i in range(dof) + ], + ControlParts.HEAD.value + + ActionMode.RELATIVE.value + + JointType.QPOS.value: [ + GLOBAL_INDICES["head_joint_{}_vel".format(i)] for i in range(2) + ], + ControlParts.WAIST.value + + ActionMode.RELATIVE.value + + JointType.QPOS.value: [GLOBAL_INDICES["waist_vel"]], + } + + @staticmethod + def get_eef_pose_indices(num_arm, **kwrags): + return { + ControlParts.LEFT_ARM.value + + EefType.POSE.value: [ + GLOBAL_INDICES["left_eef_pos_x"], + GLOBAL_INDICES["left_eef_pos_y"], + GLOBAL_INDICES["left_eef_pos_z"], + GLOBAL_INDICES["left_eef_angle_0"], + GLOBAL_INDICES["left_eef_angle_1"], + GLOBAL_INDICES["left_eef_angle_2"], + GLOBAL_INDICES["left_eef_angle_3"], + GLOBAL_INDICES["left_eef_angle_4"], + GLOBAL_INDICES["left_eef_angle_5"], + ], + ControlParts.RIGHT_ARM.value + + EefType.POSE.value: [ + GLOBAL_INDICES["right_eef_pos_x"], + GLOBAL_INDICES["right_eef_pos_y"], + GLOBAL_INDICES["right_eef_pos_z"], + GLOBAL_INDICES["right_eef_angle_0"], + GLOBAL_INDICES["right_eef_angle_1"], + GLOBAL_INDICES["right_eef_angle_2"], + GLOBAL_INDICES["right_eef_angle_3"], + GLOBAL_INDICES["right_eef_angle_4"], + GLOBAL_INDICES["right_eef_angle_5"], + ], + } + + def get_indices(self, state_meta: List[str]): + state_indices = [] + + for proprio_name in state_meta: + state_indices += self.mapping_from_name_to_indices[proprio_name] + + return state_indices + + def ret_all_state( + self, + ): + state_indices = [] + + for val in self.mapping_from_name_to_indices.values(): + state_indices += val + + return state_indices diff --git a/embodichain/lab/__init__.py b/embodichain/lab/__init__.py new file mode 100644 index 00000000..e66036ce --- /dev/null +++ b/embodichain/lab/__init__.py @@ -0,0 +1,19 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from . import sim +from . import gym +from . import devices diff --git a/embodichain/lab/devices/__init__.py b/embodichain/lab/devices/__init__.py new file mode 100644 index 00000000..29525240 --- /dev/null +++ b/embodichain/lab/devices/__init__.py @@ -0,0 +1,17 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .device import Device diff --git a/embodichain/lab/devices/device.py b/embodichain/lab/devices/device.py new file mode 100644 index 00000000..4e75cd9c --- /dev/null +++ b/embodichain/lab/devices/device.py @@ -0,0 +1,44 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import abc # for abstract base class definitions + + +class Device(metaclass=abc.ABCMeta): + """ + Base class for all robot controllers. + Defines basic interface for all controllers to adhere to. + """ + + @abc.abstractmethod + def start_control(self): + """ + Method that should be called externally before controller can + start receiving commands. + """ + raise NotImplementedError + + @abc.abstractmethod + def stop_control(self): + """ + Method that should be called externally to stop the controller. + """ + raise NotImplementedError + + @abc.abstractmethod + def get_controller_state(self): + """Returns the current state of the device, a dictionary of pos, orn, grasp, and reset.""" + raise NotImplementedError diff --git a/embodichain/lab/gym/__init__.py b/embodichain/lab/gym/__init__.py new file mode 100644 index 00000000..eae2638c --- /dev/null +++ b/embodichain/lab/gym/__init__.py @@ -0,0 +1,18 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from . import envs +from . import utils diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py new file mode 100644 index 00000000..286d7824 --- /dev/null +++ b/embodichain/lab/gym/envs/__init__.py @@ -0,0 +1,31 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .base_env import * +from .embodied_env import * +from .tasks import * +from .wrapper import * + +from embodichain.lab.gym.envs.embodied_env import EmbodiedEnv + +# Specific task environments +from embodichain.lab.gym.envs.tasks.tableware.pour_water.pour_water import ( + PourWaterEnv, +) +from embodichain.lab.gym.envs.tasks.tableware.scoop_ice import ScoopIce + +# Reinforcement learning environments +from embodichain.lab.gym.envs.tasks.rl.push_cube import PushCubeEnv diff --git a/embodichain/lab/gym/envs/action_bank/configurable_action.py b/embodichain/lab/gym/envs/action_bank/configurable_action.py new file mode 100644 index 00000000..9c285aa5 --- /dev/null +++ b/embodichain/lab/gym/envs/action_bank/configurable_action.py @@ -0,0 +1,1472 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import numpy as np +import networkx as nx +from copy import deepcopy +from typing import Dict, Tuple, Union, List, Callable, Any, Optional +from tqdm import tqdm + +import torch +import matplotlib.pyplot as plt +from functools import partial +from embodichain.utils.math import pose_inv +from embodichain.utils.logger import log_info, log_warning, log_error +from embodichain.lab.sim.cfg import MarkerCfg +from embodichain.lab.gym.utils.misc import resolve_env_params, _data_key_to_control_part +from embodichain.data.enum import Hints, EefExecute +from .utils import generate_affordance_from_src, get_init_affordance +import functools + + +# https://stackoverflow.com/questions/41834530/how-to-make-python-decorators-work-like-a-tag-to-make-function-calls-by-tag +class TagDecorator(object): + def __init__(self, tagName): + self.functions = {} + self.tagName = tagName + + def __str__(self): + return "".format(tagName=self.tagName) + + def __call__(self, f): + # class_key = f"{f.__module__}.{f.__qualname__.rsplit('.', 1)[0]}" + class_name = f.__qualname__.split(".")[0] + if class_name in self.functions.keys(): + self.functions[class_name].update({f.__name__: f}) + else: + self.functions.update({class_name: {f.__name__: f}}) + return f + + +@functools.lru_cache(maxsize=None) # memoization +def get_func_tag(tagName): + return TagDecorator(tagName) + + +tag_node = get_func_tag("node") +tag_edge = get_func_tag("edge") + + +class ActionBank: + _function_type: Dict[str, Callable] + + def __init__(self, conf: Dict): + # 轨迹可以是qpos或者xpos,不同方法检查一下shape,每个姿态qpos是1维(16维),xpos是2维(4x4的矩阵) + self.conf = conf + + @property + def vis_gantt(self): + return self.conf.get("misc", {}).get("vis_gantt", False) + + @property + def vis_graph(self): + return self.conf.get("misc", {}).get("vis_graph", False) + + @property + def warpping(self): + return self.conf.get("misc", {}).get("warpping", True) + + @staticmethod + def get_function_name(input: Dict) -> str: + """ + Retrieve the function name from the input dictionary. + + This method assumes that the input dictionary contains exactly one key, + which represents the function name. If the dictionary contains more than + one key, a ValueError is raised. + + Args: + input (Dict): A dictionary with a single key representing the function name. + + Returns: + str: The function name extracted from the dictionary. + + Raises: + ValueError: If the input dictionary contains zero or more than one key. + """ + if len(list(input.keys())) != 1: + raise ValueError( + "The input dict {} has invalid keys {}.".format( + input, list(input.keys()) + ) + ) + + return list(input.keys())[0] + + def get_scope_names( + self, + ) -> List[str]: + return list(self.conf["scope"].keys()) + + def get_node_names(self, bool_attr_name: str = None) -> Dict[str, List[str]]: + scopes = self.get_scope_names() + nodes = self.conf["node"] + node_names = {} + for scope in scopes: + node_names[scope] = [] + for node in nodes[scope]: + if bool_attr_name is not None: + if node[self.get_function_name(node)].get(bool_attr_name, False): + function_name = ActionBank.get_function_name(node) + node_names[scope].append(function_name) + return node_names + + def graph2id(self, type: str = "node") -> Dict[str, Dict[str, str]]: + scopes = self.get_scope_names() + nodes = self.conf[type] + graph_2_id = {} + for scope in scopes: + graph_2_id[scope] = {} + for i, node in enumerate(nodes[scope]): + function_name = ActionBank.get_function_name(node) + graph_2_id[scope].update({function_name: i}) + return graph_2_id + + def get_edge_names(self, node_name: str = None) -> Dict[str, List[Dict[str, str]]]: + scopes = self.get_scope_names() + edges = self.conf["edge"] + edge_names = {} + for i, key in enumerate(scopes): + edge_names[key] = [] + for edge in edges[key]: + function_name = ActionBank.get_function_name(edge) + src = edge[function_name]["src"] + sink = edge[function_name]["sink"] + temp = {"name": function_name, "src": src, "sink": sink} + edge_names[key].append(temp) + if node_name is None: + return edge_names + else: + filtered_edge_names = {} + for scope, edge_list in edge_names.items(): + filtered_edge_names[scope] = [ + edge + for edge in edge_list + if edge["src"] == node_name or edge["sink"] == node_name + ] + return filtered_edge_names + + def _infer_fill_type(self, scope: str, label: str, edge_cfg: Dict) -> str: + # 1) explicit in config + ft = edge_cfg.get("fill_type", None) + # 2) built-in eef rules + fn = edge_cfg.get("name", None) + if fn in {EefExecute.OPEN.value, EefExecute.CLOSE.value}: + return "still" + # 3) explicit wins; otherwise default + return ft if ft in ("still", "scalable") else "still" + + def _get_unit_pairs(self, legends: List[str]) -> Dict[str, str]: + """ + Return a symmetric map executor -> partner within the same unit (arm+eef). + Priority: + 1) explicit config: self.conf["misc"]["unit_pairs"] = [["right_arm","right_eefhand"], ["left_arm","left_eefhand"], ...] + 2) heuristic by side-prefix and name hints ('arm' vs 'eef'/'hand'/'gripper') + """ + pairs: Dict[str, str] = {} + + # 1) explicit mapping if provided + explicit = self.conf.get("misc", {}).get("unit_pairs", None) + if explicit: + for a, b in explicit: + if a in legends and b in legends: + pairs[a] = b + pairs[b] = a + + # 2) heuristic fallback + def side_key(name: str) -> str: + # prefer token before '_' or '-', else prefix match + if "_" in name: + return name.split("_", 1)[0] + if "-" in name: + return name.split("-", 1)[0] + for pref in ("left", "right", "L", "R"): + if name.lower().startswith(pref.lower()): + return pref + return "" + + eef_hints = Hints.EEF.value + arm_hints = Hints.ARM.value + + from collections import defaultdict + + by_side = defaultdict(list) + for n in legends: + by_side[side_key(n)].append(n) + + for _, names in by_side.items(): + arms = [n for n in names if any(h in n.lower() for h in arm_hints)] + eefs = [n for n in names if any(h in n.lower() for h in eef_hints)] + # pair the first unmatched arm with the first unmatched eef + for a in arms: + if a in pairs: + continue + partner = next((e for e in eefs if e not in pairs), None) + if partner: + pairs[a] = partner + pairs[partner] = a + + return pairs + + def _apply_bubble_filling(self, packages, taskkey2index): + from collections import defaultdict + + if not packages: + return packages + + # group by executor + per_legend = defaultdict(list) + for p in packages: + per_legend[p["legend"]].append(p) + for lg in per_legend: + per_legend[lg].sort(key=lambda x: (x["start"], x["end"])) + + legends = list(per_legend.keys()) + unit_pairs = self._get_unit_pairs(legends) + + # fill_type lookup + fill_type = {} + for scope, scope_edges in self.conf.get("edge", {}).items(): + for edge in scope_edges: + lbl = list(edge.keys())[0] + fill_type[lbl] = edge[lbl].get("fill_type", "still") + + label2pkg = {p["label"]: p for p in packages} + global_end = max(p["end"] for p in packages) + + def first_start_at_or_after(seq, t): + for pkg in seq: + if pkg["start"] >= t: + return pkg["start"] + return global_end + + # optional sync boundary (unchanged) + dep_of = defaultdict(list) + for e_label, s in self.conf.get("sync", {}).items(): + for d in s.get("depend_tasks", []): + dep_of[d].append(e_label) + + def sync_boundary_for(lbl): + deps = dep_of.get(lbl, []) + if not deps: + return None + starts = [label2pkg[d]["start"] for d in deps if d in label2pkg] + return max(starts) if starts else None + + # unit-aware filling + for lg, seq in per_legend.items(): + partner = unit_pairs.get(lg, None) + partner_seq = per_legend.get(partner, []) if partner else [] + + # middle gaps + for i in range(len(seq) - 1): + curr, nxt = seq[i], seq[i + 1] + if curr["end"] < nxt["start"]: + cap_local = nxt["start"] + cap_partner = ( + first_start_at_or_after(partner_seq, curr["end"]) + if partner_seq + else global_end + ) + cap_sync = sync_boundary_for(curr["label"]) + cap = ( + min(cap_local, cap_partner, cap_sync) + if cap_sync is not None + else min(cap_local, cap_partner) + ) + if cap > curr["end"]: + curr["end"] = cap + curr.setdefault( + "fill_type", fill_type.get(curr["label"], "still") + ) + + # tail gap: cap by partner’s next (≥ end), not global + if seq: + last = seq[-1] + cap_partner = ( + first_start_at_or_after(partner_seq, last["end"]) + if partner_seq + else last["end"] + ) + if cap_partner > last["end"]: + last["end"] = cap_partner + last.setdefault("fill_type", fill_type.get(last["label"], "still")) + + return packages + + def parse_network( + self, + node_functions: Dict[str, Callable], + edge_functions: Dict[str, Callable], + vis_graph: bool = False, + ) -> Tuple[nx.DiGraph, Dict[str, List], Dict[str, Tuple[int, int]]]: + """Construct a graph with self.conf["node"]&["edge"], and node_functions, edge_functions be its node generator and edge linker. + + Return the constructed nx.DiGraph graph_compose, + + and tasks_data = {"scope name" : [(scope_id=task_id, skill_duration_{i})]}, + + and taskkey2index = {"edge_name": (scope_id=task_id, edge_id=skill_id)} + + Args: + node_functions (Dict[str, Callable]): A Dict consists of key-value pair that key be all nodes (affordance) name and value be its generating functions + edge_functions (Dict[str, Callable]): A Dict consists of key-value pair that key be all edges (skill, a part of a trajectory) name and value be its linker functions + vis_graph (bool, optional): Whether to show the graph or not. Defaults to True. + + Returns: + graph_compose: A composed nx.DiGraph representing the graph defined in self.conf, while the node generators and edge linkers prepared, + tasks_data: A Dict consists of key-value pair that key be all scopes' names, and value be List(Tuple=(scope_id=task_id, skill_duration)) + taskkey2index: A Dict consists of key-value pair that key be all edges' names, and value be Tuple=(scope_id=task_id, edge_id=skill_id) + """ + nodes = self.conf.get("node", {}) + edges = self.conf.get("edge", {}) + graph_type = self.conf.get("scope", {}) + + graphs = {key: nx.DiGraph() for key in graph_type.keys()} + disjoint_names = {} + tasks_data = {} + taskkey2index = {} + + # key2index = {} + edges_flatten = {} + for i, key in enumerate(graphs.keys()): + # key2index[key] = i + for j, edge in enumerate(edges[key]): + edge = deepcopy(edge) + taskkey2index[ActionBank.get_function_name(edge)] = (i, j) + edge["type"] = key + edges_flatten.update(edge) + for i, key in enumerate(graphs.keys()): + tasks_data[key] = [] + for edge in edges[key]: + label = ActionBank.get_function_name(edge) # edge label in config + cfg = edge[label] + src = cfg["src"] + sink = cfg["sink"] + kwargs = cfg.get("kwargs", {}) + duration = cfg.get("duration", 0) + if not isinstance(duration, int): + raise TypeError("Duration must be an integer.") + + # function to call + fn_name = cfg.get("name", label) + # normalize and persist fill_type (default + built-in rules) + fill_type = self._infer_fill_type(key, label, cfg) + + graphs[key].add_edge( + src, + sink, + linker=partial( + edge_functions[fn_name], **kwargs, duration=duration + ), + duration=duration, + fill_type=fill_type, + edge_label=label, + scope=key, + ) + tasks_data[key].append((i, duration)) + + for node in nodes[key]: + function_name = ActionBank.get_function_name(node) + if function_name in disjoint_names.keys(): + error_msg = f"Function {function_name} is already defined in {disjoint_names[function_name]} but re-defined in {key} again." + log_error(error_msg) + disjoint_names.update({function_name: key}) + graphs[key].add_node( + function_name, + generator=partial( + node_functions[node[function_name]["name"]], + **node[function_name]["kwargs"], + ), + ) + + graph_compose = nx.DiGraph() + for key, graph in graphs.items(): + if self.vis_graph or vis_graph: + nx.draw(graph, with_labels=True) + plt.show() + if graph_type[key]["type"] == "tree": + assert nx.is_tree( + graph.to_undirected() + ), "{} graph is not tree.".format(key) + + graph_compose = nx.compose(graph_compose, graph) + + if self.vis_graph or vis_graph: + nx.draw(graph_compose, with_labels=True) + plt.show() + + return graph_compose, tasks_data, taskkey2index + + def gantt( + self, + tasks_data: Dict[str, List], + taskkey2index: Dict[str, int], + vis: bool = False, + ) -> Dict[str, Any]: + """Given tasks on different machines and skills within tasks that takes a specific duration, try to minimize the max length among task, while respecting: + Constraint 1: For skills of a same task, which occupied a same machine, do not overlap with each other. + Constraint 2: For skills of a same task, the start time of skill should not surpass the end time of the before skill + Constraint 3: For sync edges define in self.conf["sync"], which defined a skill, its start time should not surpass the end time of the depend skill. + with a set of start and end time of all skills. Then draw the gantt with the solution, return the solution packages with start and end time of each edge. + + Args: + tasks_data (Dict[str, List]): A Dict consists of key-value pair that key be all scopes' names, and value be List(Tuple=(scope_id=task_id, skill_duration)) + taskkey2index (Dict[str, int]): A Dict consists of key-value pair that key be all edges' names, and value be Tuple=(scope_id=task_id, edge_id=skill_id) + vis (bool, optional): Whether to visualize the gantt or not. Defaults to False. + + Returns: + packages Dict[str, Any]: + { + "total_num": int(solver.objective_value)=max length of a task (among tasks = scopes = machines = executors), + "packages": packages=List(Dict=assigned_task={ + "labels": edge_name, + "start" : edge.start + "end": edge.start + edge.duration + "legend": task_name + "color": color representing the task_id, the former the bluer + } + ) + } + """ + import collections + + # https://developers.google.com/optimization/scheduling/task_shop?hl=zh-cn + from ortools.sat.python import cp_model + + machines_count = len(list(tasks_data.keys())) + all_machines = range(machines_count) + # Computes horizon dynamically as the sum of all durations. + id2key = {i: key for i, key in enumerate(tasks_data.keys())} + tasks_data = list(tasks_data.values()) + + horizon = sum(skill[1] for task in tasks_data for skill in task) + model = cp_model.CpModel() + # Named tuple to store information about created variables. + skill_type = collections.namedtuple("skill_type", "start end interval") + + # Creates task intervals and add to the corresponding machine lists. + all_skills = {} + machine_to_intervals = collections.defaultdict(list) + + for task_id, task in enumerate(tasks_data): + for skill_id, skill in enumerate(task): + machine, duration = skill + suffix = f"_{task_id}_{skill_id}" + start_var = model.new_int_var(0, horizon, "start" + suffix) + end_var = model.new_int_var(0, horizon, "end" + suffix) + interval_var = model.new_interval_var( + start_var, duration, end_var, "interval" + suffix + ) + all_skills[task_id, skill_id] = skill_type( + start=start_var, end=end_var, interval=interval_var + ) + machine_to_intervals[machine].append(interval_var) + + # Create and add disjunctive constraints for each machine. + for machine in all_machines: + model.add_no_overlap(machine_to_intervals[machine]) + + # Precedences inside a task. + for task_id, task in enumerate(tasks_data): + for skill_id in range(len(task) - 1): + model.add( + all_skills[task_id, skill_id + 1].start + >= all_skills[task_id, skill_id].end + ) + + sync_edges = self.conf["sync"] + for edge_name in sync_edges.keys(): + task_id, skill_id = taskkey2index[edge_name] + for depend_task in sync_edges[edge_name]["depend_tasks"]: + before_task_id, before_skill_id = taskkey2index[depend_task] + model.add( + all_skills[task_id, skill_id].start + >= all_skills[before_task_id, before_skill_id].end + ) + + # Makespan objective. + obj_var = model.new_int_var(0, horizon, "makespan") + + max_equality = [] + for task_id, task in enumerate(tasks_data): + if len(task) != 0: + max_equality.append(all_skills[task_id, len(task) - 1].end) + + model.add_max_equality(obj_var, max_equality) + model.minimize(obj_var) + solver = cp_model.CpSolver() + status = solver.solve(model) + + packages = [] + if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE: + # Create one list of assigned skills per machine. + n = len(list(id2key.keys())) + color = [(1 - i / n, 0, i / n) for i in range(n)] + keys_ = list(taskkey2index.keys()) + values_ = list(taskkey2index.values()) + for task_id, task in enumerate(tasks_data): + for skill_id, skill in enumerate(task): + machine = skill[0] + duration = skill[1] + start = solver.value(all_skills[task_id, skill_id].start) + + assigned_task = {} + assigned_task["label"] = keys_[values_.index((task_id, skill_id))] + assigned_task["start"] = start + assigned_task["end"] = start + duration + assigned_task["legend"] = id2key[task_id] + assigned_task["color"] = color[task_id] + packages.append(assigned_task) + + # Finally print the solution found. + log_warning(f"Optimal Schedule Length: {solver.objective_value}") + else: + log_error("No solution found.") + + packages = self._apply_bubble_filling(packages, taskkey2index) + + new_total = max((p["end"] for p in packages), default=0) + + if self.vis_gantt or vis: + from embodichain.utils.visualizer import Gantt + + draw_gantt_data = { + "title": " Sample GANTT", + "xlabel": "Trajectory (steps)", + "packages": packages, + } + g = Gantt(draw_gantt_data) + g.render() + g.show() + + return {"total_num": int(new_total), "packages": packages} + + def initialize_action_list( + self, env, action_list, executor: str, executor_init_info: Dict + ) -> np.ndarray: + """ + Initialize the action list for a specific executor. + + This method initializes the action trajectory for the given executor based on the provided initialization information. + The initialization can be done using predefined qpos values or the current qpos of the executor. + + Args: + self (ActionBank): The ActionBank instance. + env (object): The environment instance containing executor and affordance data. + action_list (np.ndarray): A numpy array of shape (T, qpos_dim), representing the uninitialized action trajectory for the executor. + executor (str): The name of the executor (e.g., "left_arm", "right_arm"). + executor_init_info (Dict): A dictionary containing initialization information for the executor, such as method and parameters. + + Returns: + np.ndarray: The initialized action list for the executor. + """ + + def initialize_with_given_qpos(action_list, executor, executor_init_info, env): + given_qpos = executor_init_info.get("kwargs", {}).get("given_qpos", None) + if given_qpos is None: + log_warning( + "No given_qpos is provided for initialize_with_given_qpos. Using {}.".format( + get_init_affordance(executor) + ) + ) + given_qpos = env.affordance_datas[get_init_affordance(executor)] + + executor_qpos_dim = action_list[executor].shape[0] + given_qpos = np.asarray(given_qpos) + if len(given_qpos.shape) != 1: + log_warning( + f"Shape of given init qpos should be (1,), but got {given_qpos.shape} with length {len(given_qpos.shape)}. Using 0-th element with {given_qpos.shape[-1]}." + ) + last_ids = (0,) * (given_qpos.ndim - 1) + (Ellipsis,) + given_qpos = given_qpos[last_ids] + + if given_qpos.shape[0] != executor_qpos_dim: + log_error( + f"Shape of given init qpos should be {(executor_qpos_dim,)}, but got {given_qpos.shape[0]}." + ) + + init_node_name = executor_init_info.get( + "init_node_name", f"{executor}_init_qpos" + ) + if ( + len(init_node_name) > 0 + ): # so if you don't need to inject it, just assign the "init_node_name" to be "" in action_config + env.affordance_datas[init_node_name] = given_qpos + action_list[executor][:, 0] = given_qpos + + return action_list + + def initialize_with_current_qpos( + action_list, executor, executor_init_info, env + ): + # TODO: Hard to get current qpos for multi-agent env + current_qpos = env.robot.get_qpos() + joint_ids = env.robot.get_joint_ids(name=get_control_part(env, executor)) + if current_qpos.ndim == 2 and current_qpos.shape[0] == 1: + current_qpos = current_qpos[0] + current_qpos = current_qpos[joint_ids].cpu() + + executor_qpos_dim = action_list[executor].shape[0] + + # NOTE: hard code! + current_qpos = current_qpos[:executor_qpos_dim] + + if current_qpos.shape[0] != executor_qpos_dim: + log_error( + f"Shape of given init qpos should be {(executor_qpos_dim,)}, but got {current_qpos.shape[0]}." + ) + + init_node_name = executor_init_info.get( + "init_node_name", f"{executor}_init_qpos" + ) + if ( + len(init_node_name) > 0 + ): # so if you don't need to inject it, just assign the "init_node_name" to be "" in action_config + env.affordance_datas[init_node_name] = current_qpos + action_list[executor][:, 0] = current_qpos + + return action_list + + INIT_METHOD_MAPPING = { + "given_qpos": initialize_with_given_qpos, + "current_qpos": initialize_with_current_qpos, + } + + init_method = executor_init_info.get("method", "current_qpos") + + if init_method is None: + log_warning( + f"No init method provided in action config for executor {executor}, please check. Skipping.." + ) + return action_list + if init_method not in INIT_METHOD_MAPPING: + log_warning( + f"Provided init method action config for executor {executor}: {init_method} is not accomplished yet, please check. Skipping.." + ) + return action_list + else: + init_func = INIT_METHOD_MAPPING[init_method] + action_list = init_func(action_list, executor, executor_init_info, env) + + return action_list + + @staticmethod + @tag_node + @resolve_env_params + def generate_affordances_from_src(env, affordance_infos: List[Dict]) -> bool: + for affordance_info in affordance_infos: + src_key = affordance_info["src_key"] + dst_key = affordance_info["dst_key"] + valid_funcs_name_kwargs_proc = affordance_info[ + "valid_funcs_name_kwargs_proc" + ] + to_array = env.action_bank.warpping + + ret = generate_affordance_from_src( + env, src_key, dst_key, valid_funcs_name_kwargs_proc, to_array + ) + if not ret: + return False + return True + + def _prepare_warpping(self, env): + if hasattr(env, "affordance_datas"): + for affordance_name, affordance_value in env.affordance_datas.items(): + # NOTE: take only first arena's affordance data + if affordance_value.ndim == 3: + affordance_value = affordance_value[0] + if isinstance(affordance_value, torch.Tensor): + affordance_value = np.asarray(affordance_value.cpu()) + env.affordance_datas[affordance_name] = affordance_value + else: + log_warning("No env.affordance_datas, skip _prepare_warpping..") + + def create_action_list( + self, env, graph_compose: nx.DiGraph, packages: List[Dict], **kwargs + ) -> Dict: + """Create an action list based on the given environment, graph, and packages. + + Args: + env (embodichain.lab.gym.envs.BaseEnv): The environment instance. + graph_compose (nx.DiGraph): The composed graph containing nodes and edges. + packages (List[Dict]): The task packages with scheduling information. + + Returns: + Dict: The generated action list for all executors. + """ + + def initialize_action_list( + scope: Dict, total_num: int + ) -> Tuple[Dict, Dict, Dict]: + """Initialize action list and related variables.""" + action_list = {} + end_time = {} + in_working = {} + + for executor in scope.keys(): + end_time[executor] = 0 + in_working[executor] = False + + action_list[executor] = np.zeros( + tuple(scope[executor]["dim"]) + (total_num,), + dtype=getattr(np, scope[executor]["dtype"]), + ) + + init_info = scope[executor].get("init", {}) + action_list = self.initialize_action_list( + env, action_list, executor, init_info + ) + + return action_list, end_time, in_working + + def generate_nodes(graph_compose: nx.DiGraph, nodes: Dict) -> bool: + """Generate nodes using the graph's node generators.""" + node_generators = nx.get_node_attributes(graph_compose, "generator") + + failed_nodes = [] + log_info("Action bank start node generation for action graph...") + for node_dict_list in nodes.values(): + for node in node_dict_list: + node_name = list(node.keys())[0] + try: + log_info(f"\tGenerating node '{node_name}' .") + ret = node_generators[node_name](env, **kwargs) + if not ret: + log_warning(f"Node '{node_name}' generation fails.") + failed_nodes.append(node_name) + except KeyError as e: + log_warning( + f"[KeyError] '{node_name}': {e}. Node generator might be missing or invalid." + ) + failed_nodes.append(node_name) + except AttributeError as e: + log_warning( + f"[AttributeError] '{node_name}': {e}. Missing required attributes in environment." + ) + failed_nodes.append(node_name) + except TypeError as e: + log_warning( + f"[TypeError] '{node_name}': {e}. Check input data types." + ) + failed_nodes.append(node_name) + except ValueError as e: + log_warning( + f"[ValueError] '{node_name}': {e}. Check input values." + ) + failed_nodes.append(node_name) + except Exception as e: + log_warning( + f"[UnexpectedError] '{node_name}': {e}. Debug dependencies or implementation." + ) + failed_nodes.append(node_name) + if failed_nodes: + log_warning(f"Failed to generate the following nodes: {failed_nodes}") + return False + + log_info( + f"Node generation is finished. Total nodes generated: {sum(len(v) for v in nodes.values())}." + ) + return True + + def generate_edges( + total_num: int, + all_executors: List[str], + edges_flatten: Dict, + node_linkers: Dict, + ) -> None: + """ + Generate edges and populate the action list for all executors. + + Args: + total_num (int): The total number of time steps for the action list. + all_executors (List[str]): A list of executor names (e.g., "left_arm", "right_arm"). + edges_flatten (Dict[str, Dict]): A flattened dictionary of edges, where keys are edge labels + and values are dictionaries containing edge details (e.g., "src", "sink"). + node_linkers (Dict[Tuple[str, str], Callable]): A dictionary mapping edge (source, sink) pairs + to their corresponding linker functions. + + Returns: + None: This function modifies the `action_list` in place. + """ + + def get_task_in_time(tasks, time): + """Get the task that is active at the given time.""" + return next( + (task for task in tasks if task["start"] <= time < task["end"]), + None, + ) + + for i in tqdm(range(total_num), desc="Generating edges"): + for executor in all_executors: + if end_time[executor] == i: + in_working[executor] = False + + if not in_working[executor]: + pkg = get_task_in_time( + [ + pkg + for pkg in packages["packages"] + if pkg["legend"] == executor + ], + i, + ) + if pkg is None: + if i >= 1: + action_list[executor][..., i] = action_list[executor][ + ..., i - 1 + ] + else: + end_time[executor] = pkg["end"] + skill_idx = ( + edges_flatten[pkg["label"]]["src"], + edges_flatten[pkg["label"]]["sink"], + ) + ret = node_linkers[skill_idx](env) + if not isinstance(ret, np.ndarray): + + if isinstance(ret, torch.Tensor): + ret = ret.cpu().numpy() + else: + raise TypeError( + "The return value of the linker {} must be a numpy array, but a {}.".format( + skill_idx, type(ret) + ) + ) + + start_idx = pkg["start"] + end_idx = pkg["end"] + + T_need = end_idx - start_idx + T_orig = ret.shape[1] + + # fill_type of this edge + ft = edges_flatten[pkg["label"]].get( + "fill_type", pkg.get("fill_type", "still") + ) + + def _resample_time(x, new_T): + if new_T == x.shape[1]: + return x + if x.shape[1] <= 1: + return np.repeat(x, new_T, axis=1)[:, :new_T] + t_old = np.linspace(0.0, 1.0, x.shape[1]) + t_new = np.linspace(0.0, 1.0, new_T) + out = np.empty((x.shape[0], new_T), dtype=x.dtype) + for d in range(x.shape[0]): + out[d] = np.interp(t_new, t_old, x[d]) + return out + + def _pad_or_trim_last(x, new_T): + if new_T <= x.shape[1]: + return x[:, :new_T] + pad = np.repeat(x[:, -1:], new_T - x.shape[1], axis=1) + return np.concatenate([x, pad], axis=1) + + if T_need != T_orig: + if ft == "scalable": + ret = _resample_time(ret, T_need) + else: # "still" + ret = _pad_or_trim_last(ret, T_need) + + action_list[executor][..., start_idx:end_idx] = ret + in_working[executor] = True + + # Main logic + scope = self.conf["scope"] + total_num = packages["total_num"] + all_executors = list(scope.keys()) + edges_flatten = { + k: v + for edges in self.conf["edge"].values() + for edge in edges + for k, v in edge.items() + } + node_linkers = nx.get_edge_attributes(graph_compose, "linker") + + action_list, end_time, in_working = initialize_action_list(scope, total_num) + + if self.warpping: + self._prepare_warpping(env) + + if not generate_nodes(graph_compose, self.conf["node"]): + return None + + # After node initialization, check if env.affordance_datas contains updated initial value for each executor. + for executor in scope.keys(): + init_node_name = get_init_affordance(executor) + if ( + not hasattr(env, "affordance_datas") + or init_node_name not in env.affordance_datas + ): + log_warning( + f"Executor '{executor}': init_node_name '{init_node_name}' not found in env.affordance_datas. Skipping initial value update." + ) + continue + affordance_init = env.affordance_datas[init_node_name] + affordance_init = np.asarray(affordance_init) + action_init_slice = action_list[executor][:, 0] + if affordance_init.shape != action_init_slice.shape: + log_warning( + f"Executor '{executor}': affordance_init shape {affordance_init.shape} does not match action_list[executor][:, 0] shape {action_init_slice.shape}. Skipping initial value update." + ) + continue + if not np.allclose(action_init_slice, affordance_init): + log_info( + f"Updated initial value for executor '{executor}' in action_list from affordance_datas['{init_node_name}']." + ) + action_list[executor][:, 0] = affordance_init + + generate_edges(total_num, all_executors, edges_flatten, node_linkers) + + return action_list + + +def attach_node_and_edge( + cls: ActionBank, functions_dict: Dict[str, Dict[str, Callable]] +) -> ActionBank: + for tag, funcs in functions_dict.items(): + tag_function = get_func_tag(tag) + for func_name, func in funcs.items(): + setattr(cls, func_name, staticmethod(func)) + + class_name = cls.__name__ + if class_name in tag_function.functions.keys(): + tag_function.functions[class_name].update({func_name: func}) + else: + tag_function.functions.update({class_name: {func_name: func}}) + return cls + + +def attach_action_bank(cls, action_bank: ActionBank, **kwargs): + def set_attr_for_cls(cls, attr_name: str, attr_value: Any): + if hasattr(cls, attr_name): + getattr(cls, attr_name).append(attr_value) + else: + setattr(cls, attr_name, [attr_value]) + + action_config = kwargs.get("action_config", None) + if action_config is None: + log_error( + f"The action config is None, but it's needed for Env: {type(cls).__name__}, Task Type: {cls.metadata['task_type']}." + ) + set_attr_for_cls(cls, "action_banks", action_bank(action_config)) + + vis_graph = kwargs.get("vis", False) + graph_compose, jobs_data, jobkey2index = cls.action_banks[-1].parse_network( + get_func_tag("node").functions[cls.action_banks[-1].__class__.__name__], + get_func_tag("edge").functions[cls.action_banks[-1].__class__.__name__], + vis_graph=vis_graph, + ) + + vis_gantt = kwargs.get("vis", False) + package = cls.action_banks[-1].gantt(jobs_data, jobkey2index, vis=vis_gantt) + + set_attr_for_cls(cls, "packages", package) + set_attr_for_cls(cls, "graph_composes", graph_compose) + + return cls + + +def get_xpos_name(affordance_name: str) -> str: + if affordance_name.find("qpos") == -1: + affordance_xpos_name = affordance_name + "_xpos" + else: + affordance_xpos_name = affordance_name.replace("qpos", "xpos") + return affordance_xpos_name + + +def get_control_part(env, agent_uid): + control_parts = env.metadata["dataset"]["robot_meta"].get("control_parts", []) + + if agent_uid in control_parts: + return agent_uid + else: + return _data_key_to_control_part( + robot=env.robot, + control_parts=control_parts, + data_key=agent_uid, + ) + + +def generate_trajectory_qpos( + env, + agent_uid: str, + trajectory: Dict[str, np.ndarray], + trajectory_id: str, + gather_index: List[int], + trajectory_index: int, + affordance_name: str, + slaver: str = "", + canonical_trajectory: List[float] = None, + canonical_trajectory_index: int = None, + canonical_pose: List[float] = [], + vis: bool = False, +) -> bool: + affordance_xpos_name = get_xpos_name(affordance_name) + + current_qpos = torch.as_tensor(trajectory[trajectory_id])[trajectory_index][ + None, gather_index + ] # TODO: only for 1 env + affordance_xpos = env.robot.compute_fk( + torch.as_tensor(current_qpos), + get_control_part(env, agent_uid), + to_matrix=True, + ) + if slaver != "": + assert canonical_trajectory is not None + assert canonical_trajectory_index is not None + assert ( + len(canonical_pose) == 4 + ), f"canonical_pose should be a 4x4 matrix, but got {len(canonical_pose)} elements." + canonical_pose = torch.as_tensor( + canonical_pose, + device=affordance_xpos.device, + dtype=affordance_xpos.dtype, + ).reshape(1, 4, 4) + can_affordance_xpos = env.robot.compute_fk( + torch.as_tensor(canonical_trajectory)[canonical_trajectory_index][ + gather_index + ], + get_control_part(env, agent_uid), + to_matrix=True, + ) + can_obj_xpos = canonical_pose + obj_xpos = env.sim.get_asset(slaver).get_local_pose(to_matrix=True) + affordance_xpos = torch.bmm( + obj_xpos, torch.bmm(pose_inv(can_obj_xpos), can_affordance_xpos) + ) + control_part = get_control_part(env, agent_uid) + qpos_seed = env.robot.get_qpos()[:, env.robot.get_joint_ids(name=control_part)] + ret, current_qpos = env.robot.compute_ik( + affordance_xpos, qpos_seed, control_part + ) + ret = ret.all().item() + if not ret: + log_warning( + f"IK failed for slaver {slaver} with xpos {affordance_xpos}. Using the previous qpos instead." + ) + return False + + if vis: + env.sim.draw_marker( + cfg=MarkerCfg( + marker_type="axis", + axis_xpos=affordance_xpos, + axis_size=0.002, + axis_len=0.005, + ) + ) + # TODO: only support 1 env numpy now + current_qpos = current_qpos.squeeze(0).cpu().numpy() + affordance_xpos = affordance_xpos.squeeze(0).cpu().numpy() + + env.affordance_datas[affordance_name] = current_qpos + env.affordance_datas[affordance_xpos_name] = affordance_xpos + return True + + +def modify_action_config_edges( + action_config: Dict, + duration_updates: Dict[str, int] = None, + trajectory_updates: Dict[str, List] = None, + analytic_planner: bool = False, +) -> Dict: + """ + Modify the action configuration by updating the duration and trajectory of edges. + + This function iterates through all edges in the action configuration and applies updates to their + duration and trajectory based on the provided mappings. If `analytic_planner` is enabled, the edge + name is set to "plan_trajectory". + + Args: + action_config (Dict): The original action configuration. + duration_updates (Dict[str, int], optional): A mapping of edge names to their new durations. + trajectory_updates (Dict[str, List], optional): A mapping of edge names to their new trajectories. + analytic_planner (bool, optional): If True, sets the edge name to "plan_trajectory". Defaults to False. + + Returns: + Dict: The modified action configuration. + """ + modified_config = deepcopy(action_config) + + # Iterate through all scopes in the action configuration + for scope_name, scope_edges in modified_config["edge"].items(): + for edge_config in scope_edges: + edge_name = list(edge_config.keys())[0] + edge_data = edge_config[edge_name] + # If analytic_planner is enabled, set the edge name to "plan_trajectory" + if analytic_planner: + edge_data["name"] = "plan_trajectory" + + # Update the duration if a mapping is provided + if duration_updates and edge_name in duration_updates: + edge_data["duration"] = duration_updates[edge_name] + + # Update the trajectory if a mapping is provided + if trajectory_updates and edge_name in trajectory_updates: + edge_data.setdefault("kwargs", {}) # Ensure "kwargs" exists + edge_data["kwargs"]["trajectory"] = trajectory_updates[edge_name] + + return modified_config + + +def to_affordance_name(name: str) -> str: + return name.replace("generate_", "") + + +def to_affordance_node_func(name: str) -> str: + return "generate_" + name + + +class GeneralActionBank(ActionBank): + @staticmethod + @tag_edge + def load_trajectory( + env, + trajectory_id: str, + gather_index: List[int], + keypose_timesteps: Tuple[int, int], + raw_duration: int, + duration: int, + **kwargs, + ): + from scipy import interpolate + + f = {} + start_t, end_t = keypose_timesteps[0], keypose_timesteps[1] + trajectory = np.asarray(env.trajectory[trajectory_id])[:, gather_index] + sub_trajectory = trajectory[start_t:end_t, :] + ds_sub_trajectory = np.zeros((duration, sub_trajectory.shape[1])) + for i in range(sub_trajectory.shape[1]): + x = np.arange(sub_trajectory.shape[0]) + f[i] = interpolate.interp1d(x, sub_trajectory[:, i], axis=-1) + ds_sub_trajectory[:, i] = f[i](np.linspace(0, raw_duration - 1, duration)) + + return ds_sub_trajectory.T # (D, T) + + @staticmethod + @tag_edge + def mimic_trajectory( + env, + agent_uid: str, + raw_edge: Dict, + raw_affordance: Dict, + target_edge: Dict, + vis: bool = False, + **kwargs, + ): + + GeneralActionBank.generate_trajectory_qpos = generate_trajectory_qpos + if isinstance(raw_affordance, dict): + aff_kwargs = deepcopy(raw_affordance.get("kwargs", {})) + aff_kwargs.pop("trajectory", {}) + aff_kwargs.pop("canonical_trajectory", {}) + getattr(GeneralActionBank, raw_affordance["name"])( + env, + **aff_kwargs, + trajectory=env.trajectory, + canonical_trajectory=env.canonical_trajectory, + ) + xpos = env.affordance_datas[ + get_xpos_name(to_affordance_name(raw_affordance["name"])) + ] + else: + log_warning( + f"raw_affordance is not a dict, but {type(raw_affordance)} and {raw_affordance}. Using it as a string name directly." + ) + xpos = env.affordance_datas[get_xpos_name(raw_affordance)] + + # raw_trajectory = getattr(GeneralActionBank, raw_edge["name"])( + # env, **raw_edge.get("kwargs", {}) + # ) + # base_pose = env.agent.get_base_xpos(agent_uid) + + # import time + # for t, temp in enumerate([env.agent.get_fk(raw_trajectory[:, i], uid=agent_uid) + # for i in range(raw_trajectory.shape[1]) + # ]): + # if t % 10 ==0: + + # print(temp) + # env.scene.draw_marker(cfg=MarkerCfg( + # marker_type="axis", + # axis_xpos=env.agent.get_base_xpos(agent_uid) @ temp, + # axis_size=0.002, + # axis_len=0.005 + # )) + # time.sleep(0.01) + + # trans = np.linalg.inv(base_pose) @ new_xpos @ np.linalg.inv(xpos) @ base_pose + # ref_poses = [ + # trans @ env.agent.get_fk(raw_trajectory[:, i], uid=agent_uid) + # for i in range(raw_trajectory.shape[1]) + # ] + # if vis: + # env.scene.draw_marker(cfg=MarkerCfg( + # marker_type="axis", + # axis_xpos=xpos, + # axis_size=0.002, + # axis_len=0.005 + # )) + + # for t, temp in enumerate(ref_poses): + # print(temp) + # if t % 10 ==0: + # env.scene.draw_marker(cfg=MarkerCfg( + # marker_type="axis", + # axis_xpos=env.agent.get_base_xpos(agent_uid) @ temp, + # axis_size=0.002, + # axis_len=0.005 + # )) + # time.sleep(0.01) + + ref_poses = [] + target_edge["name"] = "plan_trajectory" + return getattr(GeneralActionBank, target_edge["name"])( + env, + ref_poses=ref_poses, + duration=target_edge["duration"], + vis=vis, + **target_edge.get("kwargs", {}), + ) + + @staticmethod + @tag_edge + def plan_trajectory( + env, + agent_uid: str, + keypose_names: List[str], + duration: int, + ref_poses: List[np.ndarray] = [], + vis: bool = False, + **kwargs, + ) -> np.ndarray: + from embodichain.lab.gym.motion_generation.action.arm_action import ( + ArmAction, + ) + + # Retrieve the start and end positions + start_qpos = env.affordance_datas[keypose_names[0]] + + control_part = get_control_part(env, agent_uid) + start_qpos = torch.as_tensor(env.affordance_datas[keypose_names[0]])[None] + start_xpos = torch.bmm( + env.robot.get_control_part_base_pose(control_part, to_matrix=True), + env.robot.compute_fk(start_qpos, control_part, to_matrix=True), + ) + + end_qpos = torch.as_tensor(env.affordance_datas[keypose_names[-1]]) + end_xpos = torch.bmm( + env.robot.get_control_part_base_pose(control_part, to_matrix=True), + env.robot.compute_fk(end_qpos, control_part, to_matrix=True), + ) + + # TODO: only 1 env + start_qpos = start_qpos.squeeze(0).cpu().numpy() + start_xpos = start_xpos.squeeze(0).cpu().numpy() + end_qpos = end_qpos.squeeze(0).cpu().numpy() + end_xpos = end_xpos.squeeze(0).cpu().numpy() + + if vis: + env.sim.draw_marker( + cfg=MarkerCfg( + marker_type="axis", + axis_xpos=start_xpos, + axis_size=0.002, + axis_len=0.005, + ) + ) + + env.sim.draw_marker( + cfg=MarkerCfg( + marker_type="axis", + axis_xpos=end_xpos, + axis_size=0.002, + axis_len=0.005, + ) + ) + + filtered_keyposes = [start_qpos, end_qpos] + if "eef" in agent_uid: + filtered_keyposes = [start_qpos] + + if len(filtered_keyposes) == 1 and len(ref_poses) == 0: + # 只有一个点,返回静止轨迹 + ret = np.array([filtered_keyposes[0]] * duration) + else: + # 生成轨迹 + if len(ref_poses) == 0: + ret, _ = ArmAction.create_discrete_trajectory( + agent=env.robot, + uid=get_control_part(env, agent_uid), + qpos_list=filtered_keyposes, + sample_num=duration, + qpos_seed=filtered_keyposes[0], + is_use_current_qpos=False, + **getattr(env, "planning_config", {}), + ) + else: + ret, _ = ArmAction.create_discrete_trajectory( + agent=env.robot, + uid=get_control_part(env, agent_uid), + xpos_list=[start_xpos] + ref_poses + [end_xpos], + sample_num=duration, + is_use_current_qpos=False, + **getattr(env, "planning_config", {}), + ) + if isinstance(ret, list): + print(ret) + return ret.T + + @staticmethod + @tag_edge + def execute_open(env, **kwargs): + from embodichain.lab.gym.utils.misc import ( + mul_linear_expand, + ) + + duration = kwargs.get("duration", 1) + expand = kwargs.get("expand", True) + if expand: + action = mul_linear_expand(np.array([[1.0], [0.0]]), [duration - 1]) + action = np.concatenate([action, np.array([[0.0]])]).transpose() + else: + action = np.zeros((1, duration)) + return action + + @staticmethod + @tag_edge + def execute_close(env, **kwargs): + from embodichain.lab.gym.utils.misc import ( + mul_linear_expand, + ) + + duration = kwargs.get("duration", 1) + expand = kwargs.get("expand", True) + if expand: + action = mul_linear_expand(np.array([[0.0], [1.0]]), [duration - 1]) + action = np.concatenate([action, np.array([[1.0]])]).transpose() + else: + action = np.ones((1, duration)) + return action + + +class ActionBankMimic: + def __init__(self, action_banks: List[ActionBank], prob: float = 0.5) -> None: + self.action_banks = action_banks + self.keyword = "mimicable" + self.prob = prob + + def mimic(self, id=None) -> ActionBank: + if len(self.action_banks) == 1: + return self.action_banks[0] + + if id is None: + id = np.random.randint(len(self.action_banks)) + assert id < len( + self.action_banks + ), f"Invalid id {id}, should be less than {len(self.action_banks)}" + + acb = self.action_banks[id] + ret_acb = deepcopy(acb) + node_names = acb.get_node_names(bool_attr_name=self.keyword) + + ret_node_grap2id = ret_acb.graph2id() + edge_need_modify = {} + for scope in node_names.keys(): + edge_need_modify[scope] = [] + # if np.random.random() < self.prob: + # continue + for node in node_names[scope]: + mimic_id = np.random.randint(len(self.action_banks)) + action_bank_mimic_for_this_node = self.action_banks[mimic_id] + mimic_node_names = action_bank_mimic_for_this_node.get_node_names( + bool_attr_name=self.keyword + ) + temp_graph2id = action_bank_mimic_for_this_node.graph2id() + + if node in mimic_node_names[scope]: + ret_acb.conf["node"][scope][ret_node_grap2id[scope][node]][ + node + ] = deepcopy( + action_bank_mimic_for_this_node.conf["node"][scope][ + temp_graph2id[scope][node] + ][node] + ) + + edges = ret_acb.get_edge_names(node_name=node) + for edge in edges[scope]: + edge.update({"mimic_id": mimic_id}) + edge_need_modify[scope].extend(edges[scope]) + else: + log_warning( + f"Node {node} in scope {scope} not found in action bank {mimic_id} [{mimic_node_names[scope]}] to mimic." + ) + edge_need_modify[scope] = { + v["name"]: v for v in edge_need_modify[scope] + }.values() + + raw_edge_grap2id = acb.graph2id("edge") + raw_node_grap2id = acb.graph2id("node") + ret_edge_grap2id = ret_acb.graph2id("edge") + for scope in node_names.keys(): + for edge in edge_need_modify[scope]: + edge_name = edge["name"] + mimic_id = edge.pop("mimic_id") + mimic_grap2id = self.action_banks[mimic_id].graph2id("edge") + ret_acb.conf["edge"][scope][ret_edge_grap2id[scope][edge_name]][ + edge_name + ]["name"] = "mimic_trajectory" + ret_acb.conf["edge"][scope][ret_edge_grap2id[scope][edge_name]][ + edge_name + ]["duration"] = deepcopy( + self.action_banks[mimic_id].conf["edge"][scope][ + mimic_grap2id[scope][edge_name] + ][edge_name]["duration"] + ) + + ret_acb.conf["edge"][scope][ret_edge_grap2id[scope][edge_name]][ + edge_name + ]["kwargs"] = {} + ret_acb.conf["edge"][scope][ret_edge_grap2id[scope][edge_name]][ + edge_name + ]["kwargs"]["agent_uid"] = scope + ret_acb.conf["edge"][scope][ret_edge_grap2id[scope][edge_name]][ + edge_name + ]["kwargs"]["raw_edge"] = deepcopy( + acb.conf["edge"][scope][raw_edge_grap2id[scope][edge_name]][ + edge_name + ] + ) + ret_acb.conf["edge"][scope][ret_edge_grap2id[scope][edge_name]][ + edge_name + ]["kwargs"]["raw_affordance"] = ( + deepcopy( + acb.conf["node"][scope][raw_node_grap2id[scope][node]][node] + ) + if node in raw_node_grap2id[scope] + else node + ) + ret_acb.conf["edge"][scope][ret_edge_grap2id[scope][edge_name]][ + edge_name + ]["kwargs"]["target_edge"] = deepcopy( + self.action_banks[mimic_id].conf["edge"][scope][ + mimic_grap2id[scope][edge_name] + ][edge_name] + ) + + return ret_acb diff --git a/embodichain/lab/gym/envs/action_bank/utils.py b/embodichain/lab/gym/envs/action_bank/utils.py new file mode 100644 index 00000000..52fb7c08 --- /dev/null +++ b/embodichain/lab/gym/envs/action_bank/utils.py @@ -0,0 +1,69 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +import numpy as np + +from copy import deepcopy +from typing import List, Union, Optional + +from embodichain.utils import logger +from embodichain.lab.gym.utils.misc import validation_with_process_from_name + + +"""Node Generation Utils""" + + +def get_init_affordance(scope: str, tag: str = "init") -> str: + return "{}_{}_qpos".format(scope, tag) + + +def generate_affordance_from_src( + env, + src_key: str, + dst_key: str, + valid_funcs_name_kwargs_proc: Optional[List] = None, + to_array: bool = True, +) -> bool: + """Generate a new affordance entry in env.affordance_datas by applying a validation and processing + pipeline to an existing source affordance. + + Args: + env: The environment object containing affordance data. + src_key (str): The key of the source affordance in env.affordance_datas. + dst_key (str): The key to store the generated affordance in env.affordance_datas. + valid_funcs_name_kwargs_proc (Optional[List]): A list of validation or processing functions (with kwargs) + to apply to the source affordance. Defaults to an empty list. + to_array (bool): Whether to convert the result to a numpy array before storing. Defaults to True. + + Returns: + bool: True if the affordance was successfully generated and stored, False otherwise. + """ + if valid_funcs_name_kwargs_proc is None: + valid_funcs_name_kwargs_proc = [] + try: + result = validation_with_process_from_name( + env, + deepcopy(env.affordance_datas[src_key]), + valid_funcs_name_kwargs_proc, + ) + if result is None: + logger.log_warning(f"Failed to generate {dst_key} from {src_key}") + return False + + env.affordance_datas[dst_key] = np.asarray(result) if to_array else result + return True + except Exception as e: + logger.log_error(f"Affordance generation error: {e}") + return False diff --git a/embodichain/lab/gym/envs/base_env.py b/embodichain/lab/gym/envs/base_env.py new file mode 100644 index 00000000..123c2c04 --- /dev/null +++ b/embodichain/lab/gym/envs/base_env.py @@ -0,0 +1,506 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import gymnasium as gym + +from typing import Dict, List, Union, Tuple, Any, Optional, Sequence +from functools import cached_property + +from embodichain.lab.sim.types import EnvObs, EnvAction +from embodichain.lab.sim import SimulationManagerCfg, SimulationManager +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim.sensors import BaseSensor +from embodichain.lab.gym.utils import gym_utils +from embodichain.utils import configclass +from embodichain.utils import logger, set_seed + +__all__ = ["BaseEnv", "EnvCfg"] + + +@configclass +class EnvCfg: + """Configuration for an Robot Learning Environment.""" + + num_envs: int = 1 + """The number of sub environments (arena in dexsim context) to be simulated in parallel.""" + + sim_cfg: SimulationManagerCfg = SimulationManagerCfg() + """Simulation configuration for the environment.""" + + seed: Optional[int] = None + """The seed for the random number generator. Defaults to -1, in which case the seed is not set. + + Note: + The seed is set at the beginning of the environment initialization. This ensures that the environment + creation is deterministic and behaves similarly across different runs. + """ + + sim_steps_per_control: int = 4 + """Number of simulation steps per control (env) step. + + For instance, if the simulation dt is 0.01s and the control dt is 0.1s, then the `sim_steps_per_control` is 10. + This means that the control action is updated every 10 simulation steps. + """ + + ignore_terminations: bool = False + """Whether to ignore terminations when deciding when to auto reset. Terminations can be caused by + the task reaching a success or fail state as defined in a task's evaluation function. + + If set to False, meaning there is early stop in episode rollouts. + If set to True, this would generally for situations where you may want to model a task as infinite horizon where a task + stops only due to the timelimit. + """ + + +class BaseEnv(gym.Env): + """Base environment for robot learning. + + Args: + cfg (EnvCfg): The environment configuration. + **kwargs: Additional keyword arguments. + """ + + # placeholder contains any meta information about the environment. + metadata: Dict = {} + + # The simulator manager instance. + sim: SimulationManager = None + + # TODO: May be support multiple robots in the future. + # The robot agent instance. + robot: Robot = None + + # The sensors used in the environment. + sensors: Dict[str, BaseSensor] = {} + + # The action space is determined by the robot agent and the task the environment is used for. + action_space: gym.spaces.Space = None + # The observation space is determined by the sensors used in the environment and the task the environment is used for. + observation_space: gym.spaces.Space = None + + single_action_space: gym.spaces.Space = None + single_observation_space: gym.spaces.Space = None + + def __init__( + self, + cfg: EnvCfg, + **kwargs, + ): + self.cfg = cfg + + # the number of envs to be simulated in parallel. + self.num_envs = self.cfg.num_envs + + if self.cfg.sim_cfg is None: + self.sim_cfg = SimulationManagerCfg(headless=True) + else: + self.sim_cfg = self.cfg.sim_cfg + + if self.cfg.seed is not None: + self.cfg.seed = set_seed(self.cfg.seed) + else: + logger.log_info(f"No seed is set for the environment.") + + self.sim_freq = int(1 / self.sim_cfg.physics_dt) + self.control_freq = self.sim_freq // self.cfg.sim_steps_per_control + + self._setup_scene(**kwargs) + + # TODO: To be removed. + if self.device.type == "cuda": + self.sim.init_gpu_physics() + + if not self.sim_cfg.headless: + self.sim.open_window() + + self._elapsed_steps = torch.zeros( + self.num_envs, dtype=torch.int32, device=self.sim_cfg.sim_device + ) + + self._init_sim_state(**kwargs) + + self._init_raw_obs: Dict = self.get_obs(**kwargs) + + logger.log_info("[INFO]: Initialized environment:") + logger.log_info(f"\tEnvironment device : {self.sim.device}") + logger.log_info(f"\tNumber of environments: {self.num_envs}") + logger.log_info(f"\tEnvironment seed : {self.cfg.seed}") + logger.log_info(f"\tPhysics dt : {self.sim_cfg.physics_dt}") + logger.log_info( + f"\tEnvironment dt : {self.sim_cfg.physics_dt * self.cfg.sim_steps_per_control}" + ) + + @property + def device(self) -> torch.Tensor: + """Return the device used by the environment.""" + return self.sim.device + + @cached_property + def single_observation_space(self) -> gym.spaces.Space: + if self.num_envs == 1: + return gym_utils.convert_observation_to_space(self._init_raw_obs) + else: + return gym_utils.convert_observation_to_space( + self._init_raw_obs, unbatched=True + ) + + @cached_property + def observation_space(self) -> gym.spaces.Space: + if self.num_envs == 1: + return self.single_observation_space + else: + return gym.vector.utils.batch_space( + self.single_observation_space, n=self.num_envs + ) + + @cached_property + def action_space(self) -> gym.spaces.Space: + if self.num_envs == 1: + return self.single_action_space + else: + return gym.vector.utils.batch_space( + self.single_action_space, n=self.num_envs + ) + + @property + def elapsed_steps(self) -> Union[int, torch.Tensor]: + return self._elapsed_steps + + def get_sensor(self, name: str, **kwargs) -> BaseSensor: + """Get the sensor instance by name. + + Args: + name: The name of the sensor. + kwargs: Additional keyword arguments. + + Returns: + The sensor instance. + """ + if name not in self.sensors: + logger.log_error( + f"Sensor '{name}' not found in the environment. Available sensors: {list(self.sensors.keys())}" + ) + + return self.sensors[name] + + def _setup_scene(self, **kwargs): + # Init sim manager. + # we want to open gui window when the scene is setup, so init sim manager in headless mode first. + headless = self.sim_cfg.headless + self.sim_cfg.headless = True + self.sim = SimulationManager(self.sim_cfg) + self.sim_cfg.headless = headless + self.sim.set_manual_update(True) + + logger.log_info( + f"Initializing {self.num_envs} environments on {self.sim_cfg.sim_device}." + ) + if self.num_envs > 1: + self.sim.build_multiple_arenas(self.num_envs) + + self.robot = self._setup_robot(**kwargs) + if self.robot is None: + logger.log_error( + f"The robot instance must be initialized in :meth:`_setup_robot` function." + ) + if self.single_action_space is None: + logger.log_error( + f":attr:`single_action_space` must be defined in the :meth:`_setup_robot` function." + ) + + self._prepare_scene(**kwargs) + + self.sensors = self._setup_sensors(**kwargs) + + def _setup_robot(self, **kwargs) -> Robot: + """Load the robot agent, setup the controller and action space. + + Note: + 1. The fuction must return the robot instance. + 2. The self.single_action_space should be defined. + """ + + # TODO: single_action_space may be configured in config? + pass + + def _prepare_scene(self, **kwargs) -> None: + """Prepare the scene assets into the environment. + + This function can be customized to performed different scene creation ways, such as loading from file. + """ + pass + + def _setup_sensors(self, **kwargs) -> Dict[str, BaseSensor]: + """Setup the sensors used in the environment. + + The sensors to be setup could be binding to the robot or the environment. + + Note: + If the function is overridden, it must return a dictionary of sensors with the sensor name as the key + and the sensor instance as the value. + """ + return {} + + def _init_sim_state(self, **kwargs): + """Initialize the simulation state at the beginning of scene creation.""" + pass + + def _update_sim_state(self, **kwargs): + """Update the simulation state at each step. + + The function is called internally by the environment in :meth:`step` after update the physics simulation. + + Note: + Currently, the interface is designed to perform randomization of lighting, textures at each simulation step. + + Args: + **kwargs: Additional keyword arguments to be passed to the :meth:`_update_sim_state` function. + """ + # TODO: Add randomization event here. + pass + + def _initialize_episode(self, env_ids: Optional[Sequence[int]] = None, **kwargs): + """Initialize the simulation assets before each episode. Randomization can be performed at this stage. + + Args: + env_ids: The environment IDs to be initialized. If None, all environments are initialized. + This is useful for vectorized environments to reset only the specified environments. + **kwargs: Additional keyword arguments to be passed to the :meth:`_initialize_episode` function. + """ + pass + + def _get_sensor_obs(self, **kwargs) -> Dict[str, any]: + """Get the sensor observation from the environment. + + Args: + **kwargs: Additional keyword arguments to be passed to the :meth:`_get_sensor_obs` function. + + Returns: + The sensor observation dictionary. + """ + obs = {} + + fetch_only = False + if self.sim.is_rt_enabled: + fetch_only = True + self.sim.render_camera_group() + + for sensor_name, sensor in self.sensors.items(): + sensor.update(fetch_only=fetch_only) + obs[sensor_name] = sensor.get_data() + return obs + + def _extend_obs(self, obs: EnvObs, **kwargs) -> EnvObs: + """Extend the observation dictionary. + + Overwrite this function to extend or modify extra observation to the existing keys (robot, sensor, extra). + + Args: + obs: The observation dictionary. + **kwargs: Additional keyword arguments to be passed to the :meth:`_extend_obs` function. + + Returns: + The extended observation dictionary. + """ + return obs + + def get_obs(self, **kwargs) -> EnvObs: + """Get the observation from the robot agent and the environment. + + The default observation are: + - robot: the robot proprioception. + - sensor (optional): the sensor readings. + - extra (optional): any extra information. + + Note: + If self.num_envs == 1, return the observation in single_observation_space format. + If self.num_envs > 1, return the observation in observation_space format. + + Args: + **kwargs: Additional keyword arguments to be passed to the :meth:`_get_sensor_obs` functions. + + Returns: + The observation dictionary. + """ + obs = None + + obs = dict(robot=self.robot.get_proprioception()) + + sensor_obs = self._get_sensor_obs(**kwargs) + if sensor_obs: + obs["sensor"] = sensor_obs + + obs = self._extend_obs(obs=obs, **kwargs) + + return obs + + def evaluate(self, **kwargs) -> Dict[str, Any]: + """ + Evaluate whether the environment is currently in a success state by returning a dictionary with a "success" key or + a failure state via a "fail" key + + This function may also return additional data that has been computed (e.g. is the robot grasping some object) that may be + reused when generating observations and rewards. + + By default if not overridden, this function returns an empty dictionary + + Args: + **kwargs: Additional keyword arguments to be passed to the :meth:`evaluate` function. + + Returns: + The evaluation dictionary. + """ + return dict() + + def get_info(self, **kwargs) -> Dict[str, Any]: + """Get info about the current environment state, include elapsed steps, success, fail, etc. + + The returned info dictionary must contain at the success and fail status of the current step. + + Args: + **kwargs: Additional keyword arguments to be passed to the :meth:`get_info` function. + + Returns: + The info dictionary. + """ + info = dict(elapsed_steps=self._elapsed_steps) + + info.update(self.evaluate(**kwargs)) + return info + + def check_truncated(self, obs: EnvObs, info: Dict[str, Any]) -> bool: + """Check if the episode is truncated. + + Args: + obs: The observation from the environment. + info: The info dictionary. + + Returns: + True if the episode is truncated, False otherwise. + """ + return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) + + def get_reward( + self, + obs: EnvObs, + action: EnvAction, + info: Dict[str, Any], + ) -> float: + """Get the reward for the current step. + + Each SimulationManager env must implement its own get_reward function to define the reward function for the task, If the + env is considered for RL/IL training. + + Args: + obs: The observation from the environment. + action: The action applied to the robot agent. + info: The info dictionary. + + Returns: + The reward for the current step. + """ + + return torch.zeros(self.num_envs, dtype=torch.float32, device=self.device) + + def _step_action(self, action: EnvAction) -> EnvAction: + """Set action control command into simulation. + + Args: + action: The action applied to the robot agent. + + Returns: + The action return. + """ + pass + + def reset( + self, seed: Optional[int] = None, options: Optional[Dict] = None + ) -> Tuple[EnvObs, Dict]: + """Reset the SimulationManager environment and return the observation and info. + + Args: + seed: The seed for the random number generator. Defaults to None, in which case the seed is not set. + options: Additional options for resetting the environment. This can include: + + Returns: + A tuple containing the observations and infos. + """ + if seed is not None: + torch.manual_seed(seed) + + if options is None: + options = dict() + + reset_ids = options.get( + "reset_ids", + torch.arange(self.num_envs, dtype=torch.int32, device=self.device), + ) + self.sim.reset_objects_state(env_ids=reset_ids) + self._elapsed_steps[reset_ids] = 0 + + # Reset hook for user to perform any custom reset logic. + self._initialize_episode(reset_ids, **options) + + return self.get_obs(**options), self.get_info(**options) + + def step( + self, action: EnvAction, **kwargs + ) -> Tuple[EnvObs, torch.Tensor, torch.Tensor, torch.Tensor, Dict[str, Any]]: + """Step the environment with the given action. + + Args: + action: The action applied to the robot agent. + + Returns: + A tuple contraining the observation, reward, terminated, truncated, and info dictionary. + """ + self._elapsed_steps += 1 + + # TODO: may be add hook for action preprocessing. + action = self._step_action(action=action) + self.sim.update(self.sim_cfg.physics_dt, self.cfg.sim_steps_per_control) + self._update_sim_state(**kwargs) + + obs = self.get_obs(**kwargs) + info = self.get_info(**kwargs) + rewards = self.get_reward(obs=obs, action=action, info=info) + + terminateds = torch.logical_or( + info.get( + "success", + torch.zeros(self.num_envs, dtype=torch.bool, device=self.device), + ), + info.get( + "fail", torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) + ), + ) + truncateds = self.check_truncated(obs=obs, info=info) + if self.cfg.ignore_terminations: + terminateds[:] = False + + dones = torch.logical_or(terminateds, truncateds) + reset_env_ids = dones.nonzero(as_tuple=False).squeeze(-1) + if len(reset_env_ids) > 0: + obs, _ = self.reset(options={"reset_ids": reset_env_ids}) + + # TODO: may be add hook for observation postprocessing. + + return obs, rewards, terminateds, truncateds, info + + def close(self) -> None: + """Close the environment and release resources.""" + self.sim.destroy() diff --git a/embodichain/lab/gym/envs/embodied_env.py b/embodichain/lab/gym/envs/embodied_env.py new file mode 100644 index 00000000..4dcd2412 --- /dev/null +++ b/embodichain/lab/gym/envs/embodied_env.py @@ -0,0 +1,506 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import torch +import numpy as np +import gymnasium as gym + +from dataclasses import MISSING +from typing import Dict, Union, Optional, Sequence, Tuple, Any, List + +from embodichain.lab.sim.cfg import ( + RobotCfg, + RigidObjectCfg, + RigidObjectGroupCfg, + ArticulationCfg, + LightCfg, +) +from embodichain.lab.gym.envs.action_bank.configurable_action import ( + get_func_tag, +) +from embodichain.lab.gym.envs.action_bank.configurable_action import ( + ActionBank, +) +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim.sensors import BaseSensor, SensorCfg +from embodichain.lab.sim.types import EnvObs, EnvAction +from embodichain.lab.gym.envs import BaseEnv, EnvCfg +from embodichain.lab.gym.envs.managers import ( + EventManager, + ObservationManager, +) +from embodichain.lab.gym.utils.registration import register_env +from embodichain.utils import configclass, logger + + +__all__ = ["EmbodiedEnvCfg", "EmbodiedEnv"] + + +@configclass +class EmbodiedEnvCfg(EnvCfg): + """Configuration class for the Embodied Environment. Inherits from EnvCfg and can be extended + with additional parameters if needed. + """ + + @configclass + class EnvLightCfg: + direct: List[LightCfg] = [] + + # TODO: support more types of indirect light in the future. + # indirect: Dict[str, Any] | None = None + + robot: RobotCfg = MISSING + + sensor: List[SensorCfg] = [] + + light: EnvLightCfg = EnvLightCfg() + + background: List[RigidObjectCfg] = [] + + rigid_object: List[RigidObjectCfg] = [] + + rigid_object_group: List[RigidObjectGroupCfg] = [] + + articulation: List[ArticulationCfg] = [] + + events: Union[object, None] = None + """Event settings. Defaults to None, in which case no events are applied through the event manager. + + Please refer to the :class:`embodichain.lab.gym.managers.EventManager` class for more details. + """ + + observations: Union[object, None] = None + """Observation settings. Defaults to None, in which case no additional observations are applied through + the observation manager. + + Please refer to the :class:`embodichain.lab.gym.managers.ObservationManager` class for more details. + """ + + # TODO: This would be changed to a more generic data pipeline configuration. + dataset: Union[Dict[str, Any], None] = None + """Data pipeline configuration. Defaults to None. + """ + + # Some helper attributes + filter_visual_rand: bool = False + """Whether to filter out visual randomization + + This is useful when we want to disable visual randomization for debug motion and physics issues. + """ + + +@register_env("EmbodiedEnv-v1") +class EmbodiedEnv(BaseEnv): + """Embodied AI environment that is used to simulate the Embodied AI tasks. + + Core simulation components for Embodied AI environments. + - sensor: The sensors used to perceive the environment, which could be attached to the agent or the environment. + - robot: The robot which will be used to interact with the environment. + - light: The lights in the environment, which could be used to illuminate the environment. + - indirect: the indirect light sources, such as ambient light, IBL, etc. + The indirect light sources are used for global illumination which affects the entire scene. + - direct: The direct light sources, such as point light, spot light, etc. + The direct light sources are used for local illumination which mainly affects the arena in the scene. + - background: Kinematic or Static rigid objects, such as obstacles or landmarks. + - rigid_object: Dynamic objects that can be interacted with. + - rigid_object_group: Groups of rigid objects that can be interacted with. + - deformable_object(TODO: supported in the future): Deformable volumes or surfaces (cloth) that can be interacted with. + - articulation: Articulated objects that can be manipulated, such as doors, drawers, etc. + - event manager: The event manager is used to manage the events in the environment, such as randomization, + perturbation, etc. + - observation manager: The observation manager is used to manage the observations in the environment, + such as depth, segmentation, etc. + - action bank: The action bank is used to manage the actions in the environment, such as action composition, action graph, etc. + - affordance_datas: The affordance data that can be used to store the intermediate results or information + """ + + def __init__(self, cfg: EmbodiedEnvCfg, **kwargs): + self.affordance_datas = {} + self.action_bank = None + + extensions = getattr(cfg, "extensions", {}) or {} + + defaults = { + "obs_mode": "state", + "episode_length": 50, + "joint_limits": 0.5, + "action_scale": 0.1, + } + + for name, default in defaults.items(): + value = extensions.get(name, getattr(cfg, name, default)) + setattr(cfg, name, value) + setattr(self, name, getattr(cfg, name)) + + super().__init__(cfg, **kwargs) + + def _init_sim_state(self, **kwargs): + """Initialize the simulation state at the beginning of scene creation.""" + + self._apply_functor_filter() + + # create event manager + self.cfg: EmbodiedEnvCfg + if self.cfg.events: + self.event_manager = EventManager(self.cfg.events, self) + + # perform events at the start of the simulation + if "startup" in self.event_manager.available_modes: + self.event_manager.apply(mode="startup") + + if self.cfg.observations: + self.observation_manager = ObservationManager(self.cfg.observations, self) + + # TODO: A workaround for handling dataset saving, which need history data of obs-action pairs. + # We may improve this by implementing a data manager to handle data saving and online streaming. + if self.cfg.dataset is not None: + self.metadata["dataset"] = self.cfg.dataset + self.episode_obs_list = [] + self.episode_action_list = [] + + self.curr_episode = 0 + + def _apply_functor_filter(self) -> None: + """Apply functor filters to the environment components based on configuration. + + This method is used to filter out certain components of the environment, such as visual randomization, + based on the configuration settings. For example, if `filter_visual_rand` is set to True in the configuration, + all visual randomization functors will be removed from the event manager. + """ + from embodichain.utils.module_utils import get_all_exported_items_from_module + from embodichain.lab.gym.envs.managers.cfg import EventCfg + + functors_to_remove = get_all_exported_items_from_module( + "embodichain.lab.gym.envs.managers.randomization.rendering" + ) + if self.cfg.filter_visual_rand and self.cfg.events: + # Iterate through all attributes of the events object + for attr_name in dir(self.cfg.events): + attr = getattr(self.cfg.events, attr_name) + if isinstance(attr, EventCfg): + if attr.func.__name__ in functors_to_remove: + logger.log_info( + f"Filtering out visual randomization functor: {attr.func.__name__}" + ) + setattr(self.cfg.events, attr_name, None) + + def _init_action_bank( + self, action_bank_cls: ActionBank, action_config: Dict[str, Any] + ): + """ + Initialize action bank and parse action graph structure. + + Args: + action_bank_cls: The ActionBank class for this environment. + action_config: The configuration dict for the action bank. + """ + self.action_bank = action_bank_cls(action_config) + misc_cfg = action_config.get("misc", {}) + try: + this_class_name = self.action_bank.__class__.__name__ + node_func = {} + edge_func = {} + for class_name in [this_class_name, ActionBank.__name__]: + node_func.update(get_func_tag("node").functions.get(class_name, {})) + edge_func.update(get_func_tag("edge").functions.get(class_name, {})) + except KeyError as e: + raise KeyError( + f"Function tag for {e} not found in action bank function registry." + ) + + self.graph_compose, jobs_data, jobkey2index = self.action_bank.parse_network( + node_functions=node_func, edge_functions=edge_func, vis_graph=False + ) + self.packages = self.action_bank.gantt( + tasks_data=jobs_data, taskkey2index=jobkey2index, vis=False + ) + + def set_affordance(self, key: str, value: Any): + """ + Set an affordance value by key. + + Args: + key (str): The affordance key. + value (Any): The affordance value. + """ + self.affordance_datas[key] = value + + def get_affordance(self, key: str, default: Any = None): + """ + Get an affordance value by key. + + Args: + key (str): The affordance key. + default (Any, optional): Default value if key not found. + + Returns: + Any: The affordance value or default. + """ + return self.affordance_datas.get(key, default) + + def reset( + self, seed: Optional[int] = None, options: Optional[Dict] = None + ) -> Tuple[EnvObs, Dict]: + obs, info = super().reset(seed=seed, options=options) + + if hasattr(self, "episode_obs_list"): + self.episode_obs_list = [obs] + self.episode_action_list = [] + + return obs, info + + def step( + self, action: EnvAction, **kwargs + ) -> Tuple[EnvObs, torch.Tensor, torch.Tensor, torch.Tensor, Dict[str, Any]]: + # TODO: Maybe add action preprocessing manager and its functors. + obs, reward, done, truncated, info = super().step(action, **kwargs) + + if hasattr(self, "episode_action_list"): + + self.episode_obs_list.append(obs) + self.episode_action_list.append(action) + + return obs, reward, done, truncated, info + + def _extend_obs(self, obs: EnvObs, **kwargs) -> EnvObs: + if self.observation_manager: + obs = self.observation_manager.compute(obs) + return obs + + def _prepare_scene(self, **kwargs) -> None: + self._setup_lights() + self._setup_background() + self._setup_interactive_objects() + + def _update_sim_state(self, **kwargs) -> None: + """Perform the simulation step and apply events if configured. + + The events manager applies its functors after physics simulation and rendering, + and before the observation and reward computation (if applicable). + """ + if self.cfg.events: + if "interval" in self.event_manager.available_modes: + self.event_manager.apply(mode="interval") + + def _initialize_episode( + self, env_ids: Optional[Sequence[int]] = None, **kwargs + ) -> None: + # apply events such as randomization for environments that need a reset + if self.cfg.events: + if "reset" in self.event_manager.available_modes: + self.event_manager.apply(mode="reset", env_ids=env_ids) + + def _step_action(self, action: EnvAction) -> EnvAction: + """Set action control command into simulation. + + Args: + action: The action applied to the robot agent. + + Returns: + The action return. + """ + # TODO: Support data structure action input such as struct. + qpos = action + + self.robot.set_qpos(qpos=qpos) + + return action + + def _setup_robot(self, **kwargs) -> Robot: + """Setup the robot in the environment. + + Currently, only joint position control is supported. Would be extended to support joint velocity and torque + control in the future. + + Returns: + Robot: The robot instance added to the scene. + """ + if self.cfg.robot is None: + logger.error("Robot configuration is not provided.") + + # Initialize the robot based on the configuration. + robot: Robot = self.sim.add_robot(self.cfg.robot) + + robot.build_pk_serial_chain() + + # TODO: we may need control parts to group actual controlled joints ids. + # In this way, the action pass to env should be a dict or struct to store the + # joint ids as well. + qpos_limits = robot.body_data.qpos_limits[0].cpu().numpy() + self.single_action_space = gym.spaces.Box( + low=qpos_limits[:, 0], high=qpos_limits[:, 1], dtype=np.float32 + ) + return robot + + def _setup_sensors(self, **kwargs) -> Dict[str, BaseSensor]: + """Setup the sensors in the environment. + + Returns: + Dict[str, BaseSensor]: A dictionary mapping sensor UIDs to sensor instances. + """ + + # TODO: support sensor attachment to the robot. + + sensors = {} + for cfg in self.cfg.sensor: + sensor = self.sim.add_sensor(cfg) + sensors[cfg.uid] = sensor + return sensors + + def _setup_lights(self) -> None: + """Setup the lights in the environment.""" + for cfg in self.cfg.light.direct: + self.sim.add_light(cfg=cfg) + + def _setup_background(self) -> None: + """Setup the static rigid objects in the environment.""" + for cfg in self.cfg.background: + if cfg.body_type == "dynamic": + logger.log_error( + f"Background object must be kinematic or static rigid object." + ) + self.sim.add_rigid_object(cfg=cfg) + + def _setup_interactive_objects(self) -> None: + """Setup the interactive objects in the environment.""" + + for cfg in self.cfg.articulation: + self.sim.add_articulation(cfg=cfg) + + for cfg in self.cfg.rigid_object: + if cfg.body_type != "dynamic": + logger.log_error( + f"Interactive rigid object must be dynamic rigid object." + ) + self.sim.add_rigid_object(cfg=cfg) + + for cfg in self.cfg.rigid_object_group: + self.sim.add_rigid_object_group(cfg=cfg) + + def preview_sensor_data( + self, name: str, data_type: str = "color", env_ids: int = 0, method: str = "plt" + ) -> None: + """Preview the sensor data by matplotlib + + Note: + Currently only support RGB image preview. + + Args: + name (str): name of the sensor to preview. + data_type (str): type of the sensor data to preview. + env_ids (int): index of the arena to preview. Defaults to 0. + method (str): method to preview the sensor data. Currently support "plt" and "cv2". Defaults to "plt". + """ + # TODO: this function need to be improved to support more sensor types and data types. + + sensor = self.get_sensor(name=name) + + if data_type not in sensor.SUPPORTED_DATA_TYPES: + logger.error( + f"Data type '{data_type}' not supported by sensor '{name}'. Supported types: {sensor.SUPPORTED_DATA_TYPES}" + ) + + sensor.update() + + data = sensor.get_data() + + # TODO: maybe put the preview (visualization) method to the sensor class. + if sensor.cfg.sensor_type == "StereoCamera": + view = data[data_type][env_ids].cpu().numpy() + view_right = data[f"{data_type}_right"][env_ids].cpu().numpy() + view = np.concatenate((view, view_right), axis=1) + else: + view = data[data_type][env_ids].cpu().numpy() + + if method == "cv2": + import cv2 + + cv2.imshow( + f"sensor_data_{data_type}", cv2.cvtColor(view, cv2.COLOR_RGB2BGR) + ) + cv2.waitKey(0) + elif method == "plt": + from matplotlib import pyplot as plt + + plt.imshow(view) + plt.savefig(f"sensor_data_{data_type}.png") + + def create_demo_action_list(self, *args, **kwargs) -> Optional[Sequence[EnvAction]]: + """Create a demonstration action list for the environment. + + This function should be implemented in subclasses to generate a sequence of actions + that demonstrate a specific task or behavior within the environment. + + Returns: + Optional[Sequence[EnvAction]]: A list of actions if a demonstration is available, otherwise None. + """ + raise NotImplementedError( + "The method 'create_demo_action_list' must be implemented in subclasses." + ) + + def to_dataset( + self, id: str, save_path: str = None, folder_name: str = None + ) -> Optional[str]: + """ + Convert the recorded episode data to a dataset format and save to disk. + + Args: + id (str): Unique identifier for the dataset. + save_path (str, optional): Path to save the dataset. If None, use config or default. + folder_name (str, optional): Folder name for saving. If None, auto-generate. + + Returns: + Optional[str]: The path to the saved dataset, or None if failed. + """ + # TODO: To be refactor data pipeline into more modularized and extendable way. + from embodichain.data.data_engine.data_dict_extractor import ( + fetch_imitation_dataset, + ) + from embodichain.lab.gym.utils.misc import camel_to_snake + + save_path = self.cfg.dataset.get("save_path", None) + if save_path is None: + from embodichain.data import database_demo_dir + + save_path = database_demo_dir + + if self.curr_episode == 0: + self.folder_name = f"{camel_to_snake(self.__class__.__name__)}_{camel_to_snake(self.robot.cfg.uid)}" + if os.path.exists(os.path.join(save_path, self.folder_name)): + self.folder_name = f"{self.folder_name}_{np.random.randint(0, 1000)}" + + dataset_path = fetch_imitation_dataset( + self, + self.episode_obs_list[:-1], + self.episode_action_list, + id, + self.folder_name, + ) + return dataset_path + + def is_task_success(self, **kwargs) -> torch.Tensor: + """Determine if the task is successfully completed. This is mainly used in the data generation process + of the imitation learning. + + Args: + **kwargs: Additional arguments for task-specific success criteria. + + Returns: + torch.Tensor: A boolean tensor indicating success for each environment in the batch. + """ + + return torch.ones(self.num_envs, dtype=torch.bool, device=self.device) diff --git a/embodichain/lab/gym/envs/managers/__init__.py b/embodichain/lab/gym/envs/managers/__init__.py new file mode 100644 index 00000000..946165a8 --- /dev/null +++ b/embodichain/lab/gym/envs/managers/__init__.py @@ -0,0 +1,20 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .cfg import FunctorCfg, SceneEntityCfg, EventCfg, ObservationCfg +from .manager_base import Functor, ManagerBase +from .event_manager import EventManager +from .observation_manager import ObservationManager diff --git a/embodichain/lab/gym/envs/managers/cfg.py b/embodichain/lab/gym/envs/managers/cfg.py new file mode 100644 index 00000000..3f5c8da6 --- /dev/null +++ b/embodichain/lab/gym/envs/managers/cfg.py @@ -0,0 +1,311 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import torch + +from collections.abc import Callable +from dataclasses import MISSING +from typing import TYPE_CHECKING, Any, Literal + +from embodichain.lab.sim.objects import Articulation, RigidObject +from embodichain.utils import configclass + +if TYPE_CHECKING: + from embodichain.lab.sim import SimulationManager + from .manager_base import Functor + + # from .recorder_manager import RecorderTerm + + +@configclass +class FunctorCfg: + """Configuration for a functor.""" + + func: Callable | Functor = MISSING + """The function or class to be called for the functor. + + The function must take the environment object as the first argument. + The remaining arguments are specified in the :attr:`params` attribute. + + It also supports `callable classes`_, i.e. classes that implement the :meth:`__call__` + method. In this case, the class should inherit from the :class:`Functor` class + and implement the required methods. + + .. _`callable classes`: https://docs.python.org/3/reference/datamodel.html#object.__call__ + """ + + params: dict[str, Any | SceneEntityCfg] = dict() + """The parameters to be passed to the function as keyword arguments. Defaults to an empty dict. + + .. note:: + If the value is a :class:`SceneEntityCfg` object, the manager will query the scene entity + from the :class:`SimulationManager` and process the entity's joints and bodies as specified + in the :class:`SceneEntityCfg` object. + """ + + +@configclass +class EventCfg(FunctorCfg): + """Configuration for a event functor. + + The event functor is used to trigger events in the environment at specific times or under specific conditions. + The `mode` attribute determines when the functor is applied. + - `startup`: The functor is applied when the environment is started. + - `interval`: The functor is applied at each env step. + - `reset`: The functor is applied when the environment is reset. + """ + + mode: Literal["startup", "interval", "reset"] = "reset" + """The mode in which the event functor is applied. + + Note: + The mode name ``"interval"`` is a special mode that is handled by the + manager Hence, its name is reserved and cannot be used for other modes. + """ + + # TODO: maybe support simulation time-based events (time = step * (physics_dt * sim_steps_per_control)) + interval_step: int = 10 + """The number of environment step after which the functor is applied. Defaults to 4.""" + + is_global: bool = False + """Whether the event should be tracked on a per-environment basis. Defaults to False. + + If True, the same interval step is used for all the environment instances. + If False, the interval step is sampled independently for each environment instance + and the functor is applied when the current step hits the interval step for that instance. + + Note: + This is only used if the mode is ``"interval"``. + """ + + +@configclass +class ObservationCfg(FunctorCfg): + """Configuration for an observation functor. + + The observation functor is used to compute observations for the environment. The `mode` attribute + determines whether the observation is already present in the observation space or not. + """ + + mode: Literal["modify", "add"] = "modify" + """The mode for the observation computation. + + - `modify`: The observation is already present in the observation space, updated the value in-place. + - `add`: The observation is not present in the observation space, add a new entry to the observation space. + """ + + name: str = MISSING + """The name of the observation. + + The name can be a new key to observation space, eg: + - `object_position`: shape of (num_envs, 3) + - `robot/eef_pose`: shape of (num_envs, 7) or (num_envs, 4, 4) + - `sensor/cam_high/mask`: shape of (num_envs, H, W) + or a existing key to modify, eg: + - `robot/qpos`: shape of (num_envs, num_dofs) + `/` is used to separate different levels of hierarchy in the observation dictionary. + """ + + +@configclass +class SceneEntityCfg: + """Configuration for a scene entity that is used by the manager's functor. + + This class is used to specify the name of the scene entity that is queried from the + :class:`SimulationManager` and passed to the manager's functor. + """ + + uid: str = MISSING + """The name of the scene entity. + + This is the name defined in the scene configuration file. See the :class:`SimulationManagerCfg` + class for more details. + """ + + joint_names: str | list[str] | None = None + """The names of the joints from the scene entity. Defaults to None. + + The names can be either joint names or a regular expression matching the joint names. + + These are converted to joint indices on initialization of the manager and passed to the functor + as a list of joint indices under :attr:`joint_ids`. + """ + + joint_ids: list[int] | slice = slice(None) + """The indices of the joints from the asset required by the functor. Defaults to slice(None), which means + all the joints in the asset (if present). + + If :attr:`joint_names` is specified, this is filled in automatically on initialization of the + manager. + """ + + link_names: str | list[str] | None = None + """The names of the links from the asset required by the functor. Defaults to None. + + The names can be either link names or a regular expression matching the link names. + """ + + control_parts: str | list[str] | None = None + """The names of the control parts from the asset(only support for robot) required by the functor. Defaults to None. + """ + + # TODO: Maybe support tendon names and ids in the future. + + body_names: str | list[str] | None = None + """The names of the bodies from the asset required by the functor. Defaults to None. + + The names can be either body names or a regular expression matching the body names. + + These are converted to body indices on initialization of the manager and passed to the functor + function as a list of body indices under :attr:`body_ids`. + """ + + body_ids: list[int] | slice = slice(None) + """The indices of the bodies from the asset required by the functor. Defaults to slice(None), which means + all the bodies in the asset. + + If :attr:`body_names` is specified, this is filled in automatically on initialization of the + manager. + """ + + # TODO: Maybe support object collection (same as IsaacLab definitions). + + preserve_order: bool = False + """Whether to preserve indices ordering to match with that in the specified joint, body, or object collection names. + Defaults to False. + + If False, the ordering of the indices are sorted in ascending order (i.e. the ordering in the entity's joints, + bodies, or object in the object collection). Otherwise, the indices are preserved in the order of the specified + joint, body, or object collection names. + + For more details, see the :meth:`isaaclab.utils.string.resolve_matching_names` function. + + .. note:: + This attribute is only used when :attr:`joint_names`, :attr:`body_names` are specified. + + """ + + def resolve(self, scene: SimulationManager): + """Resolves the scene entity and converts the joint and body names to indices. + + This function examines the scene entity from the :class:`SimulationManager` and resolves the indices + and names of the joints and bodies. It is an expensive operation as it resolves regular expressions + and should be called only once. + + Args: + scene: The interactive scene instance. + + Raises: + ValueError: If the scene entity is not found. + ValueError: If both ``joint_names`` and ``joint_ids`` are specified and are not consistent. + ValueError: If both ``body_names`` and ``body_ids`` are specified and are not consistent. + """ + # check if the entity is valid + asset_uids = scene.asset_uids + if self.uid not in asset_uids: + raise ValueError( + f"The scene entity '{self.uid}' does not exist. Available entities: {asset_uids}." + ) + + # convert joint names to indices based on regex + self._resolve_joint_names(scene) + + # convert body names to indices based on regex + self._resolve_body_names(scene) + + def _resolve_joint_names(self, scene: SimulationManager): + # convert joint names to indices based on regex + if self.joint_names is not None or self.joint_ids != slice(None): + entity: Articulation = scene[self.uid] + # -- if both are not their default values, check if they are valid + if self.joint_names is not None and self.joint_ids != slice(None): + if isinstance(self.joint_names, str): + self.joint_names = [self.joint_names] + if isinstance(self.joint_ids, int): + self.joint_ids = [self.joint_ids] + joint_ids, _ = entity.find_joints( + self.joint_names, preserve_order=self.preserve_order + ) + joint_names = [entity.joint_names[i] for i in self.joint_ids] + if joint_ids != self.joint_ids or joint_names != self.joint_names: + raise ValueError( + "Both 'joint_names' and 'joint_ids' are specified, and are not consistent." + f"\n\tfrom joint names: {self.joint_names} [{joint_ids}]" + f"\n\tfrom joint ids: {joint_names} [{self.joint_ids}]" + "\nHint: Use either 'joint_names' or 'joint_ids' to avoid confusion." + ) + # -- from joint names to joint indices + elif self.joint_names is not None: + if isinstance(self.joint_names, str): + self.joint_names = [self.joint_names] + self.joint_ids, _ = entity.find_joints( + self.joint_names, preserve_order=self.preserve_order + ) + # performance optimization (slice offers faster indexing than list of indices) + # only all joint in the entity order are selected + if ( + len(self.joint_ids) == entity.num_joints + and self.joint_names == entity.joint_names + ): + self.joint_ids = slice(None) + # -- from joint indices to joint names + elif self.joint_ids != slice(None): + if isinstance(self.joint_ids, int): + self.joint_ids = [self.joint_ids] + self.joint_names = [entity.joint_names[i] for i in self.joint_ids] + + def _resolve_body_names(self, scene: SimulationManager): + # convert body names to indices based on regex + if self.body_names is not None or self.body_ids != slice(None): + entity: RigidObject = scene[self.uid] + # -- if both are not their default values, check if they are valid + if self.body_names is not None and self.body_ids != slice(None): + if isinstance(self.body_names, str): + self.body_names = [self.body_names] + if isinstance(self.body_ids, int): + self.body_ids = [self.body_ids] + body_ids, _ = entity.find_bodies( + self.body_names, preserve_order=self.preserve_order + ) + body_names = [entity.body_names[i] for i in self.body_ids] + if body_ids != self.body_ids or body_names != self.body_names: + raise ValueError( + "Both 'body_names' and 'body_ids' are specified, and are not consistent." + f"\n\tfrom body names: {self.body_names} [{body_ids}]" + f"\n\tfrom body ids: {body_names} [{self.body_ids}]" + "\nHint: Use either 'body_names' or 'body_ids' to avoid confusion." + ) + # -- from body names to body indices + elif self.body_names is not None: + if isinstance(self.body_names, str): + self.body_names = [self.body_names] + self.body_ids, _ = entity.find_bodies( + self.body_names, preserve_order=self.preserve_order + ) + # performance optimization (slice offers faster indexing than list of indices) + # only all bodies in the entity order are selected + if ( + len(self.body_ids) == entity.num_bodies + and self.body_names == entity.body_names + ): + self.body_ids = slice(None) + # -- from body indices to body names + elif self.body_ids != slice(None): + if isinstance(self.body_ids, int): + self.body_ids = [self.body_ids] + self.body_names = [entity.body_names[i] for i in self.body_ids] diff --git a/embodichain/lab/gym/envs/managers/event_manager.py b/embodichain/lab/gym/envs/managers/event_manager.py new file mode 100644 index 00000000..fa06b9d8 --- /dev/null +++ b/embodichain/lab/gym/envs/managers/event_manager.py @@ -0,0 +1,353 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. + +# All rights reserved. +# +# This file incorporates code from the Isaac Lab Project +# Copyright (c) 2022-2025, The Isaac Lab Project Developers +# (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# ---------------------------------------------------------------------------- + +"""Event manager for orchestrating operations based on different simulation events.""" + +from __future__ import annotations + +import inspect +import torch +from collections.abc import Sequence +from prettytable import PrettyTable +from typing import TYPE_CHECKING, Union + +from embodichain.utils import logger +from .manager_base import ManagerBase +from .cfg import EventCfg + +if TYPE_CHECKING: + from embodichain.lab.gym.envs import EmbodiedEnv + + +class EventManager(ManagerBase): + """Manager for orchestrating operations based on different simulation events. + + The event manager applies operations to the environment based on different simulation events. For example, + changing the masses of objects or their friction coefficients during initialization/ reset, or applying random + pushes to the robot at a fixed interval of steps. The user can specify several modes of events to fine-tune the + behavior based on when to apply the event. + + The event functors are parsed from a config class containing the manager's settings and each functor's + parameters. Each event functor should instantiate the :class:`EventCfg` class. + + Event functors can be grouped by their mode. The mode is a user-defined string that specifies when + the event functor should be applied. This provides the user complete control over when event + functors should be applied. + + For a typical training process, you may want to apply events in the following modes: + + - "prestartup": Event is applied once at the beginning of the training before the simulation starts. + This is used to randomize USD-level properties of the simulation stage. + - "startup": Event is applied once at the beginning of the training once simulation is started. + - "reset": Event is applied at every reset. + - "interval": Event is applied at pre-specified intervals of time. + + However, you can also define your own modes and use them in the training process as you see fit. + For this you will need to add the triggering of that mode in the environment implementation as well. + + .. note:: + + The triggering of operations corresponding to the mode ``"interval"`` are the only mode that are + directly handled by the manager itself. The other modes are handled by the environment implementation. + + """ + + _env: EmbodiedEnv + """The environment instance.""" + + def __init__(self, cfg: object, env: EmbodiedEnv): + """Initialize the event manager. + + Args: + cfg: A configuration object or dictionary (``dict[str, EventCfg]``). + env: An environment object. + """ + # create buffers to parse and store functors + self._mode_functor_names: dict[str, list[str]] = dict() + self._mode_functor_cfgs: dict[str, list[EventCfg]] = dict() + self._mode_class_functor_cfgs: dict[str, list[EventCfg]] = dict() + + # call the base class (this will parse the functors config) + super().__init__(cfg, env) + + def __str__(self) -> str: + """Returns: A string representation for event manager.""" + functor_num = sum(len(v) for v in self._mode_functor_names.values()) + msg = f" contains {functor_num} active functors.\n" + + # add info on each mode + for mode in self._mode_functor_names: + # create table for functor information + table = PrettyTable() + table.title = f"Active Event Functors in Mode: '{mode}'" + # add table headers based on mode + if mode == "interval": + table.field_names = ["Index", "Name", "Interval step"] + table.align["Name"] = "l" + for index, (name, cfg) in enumerate( + zip(self._mode_functor_names[mode], self._mode_functor_cfgs[mode]) + ): + table.add_row([index, name, cfg.interval_step]) + else: + table.field_names = ["Index", "Name"] + table.align["Name"] = "l" + for index, name in enumerate(self._mode_functor_names[mode]): + table.add_row([index, name]) + # convert table to string + msg += table.get_string() + msg += "\n" + + return msg + + """ + Properties. + """ + + @property + def active_functors(self) -> dict[str, list[str]]: + """Name of active event functors. + + The keys are the modes of event and the values are the names of the event functors. + """ + return self._mode_functor_names + + @property + def available_modes(self) -> list[str]: + """Modes of events.""" + return list(self._mode_functor_names.keys()) + + """ + Operations. + """ + + def reset(self, env_ids: Union[Sequence[int], None] = None) -> dict[str, float]: + # call all functors that are classes + for mode_cfg in self._mode_class_functor_cfgs.values(): + for functor_cfg in mode_cfg: + functor_cfg.func.reset(env_ids=env_ids) + + # resolve number of environments + if env_ids is None: + num_envs = self._env.num_envs + else: + num_envs = len(env_ids) + + # May be add more useful reset logic later. + + # nothing to log here + return {} + + def apply( + self, + mode: str, + env_ids: Union[Sequence[int], None] = None, + ): + """Calls each event functor in the specified mode. + + This function iterates over all the event functors in the specified mode and calls the function + corresponding to the functor. The function is called with the environment instance and the environment + indices to apply the event to. + + For the "interval" mode, the function is called when the time interval has passed. This requires + specifying the time step of the environment. + + For the "reset" mode, the function is called when the mode is "reset" and the total number of environment + steps that have happened since the last trigger of the function is equal to its configured parameter for + the number of environment steps between resets. + + Args: + mode: The mode of event. + env_ids: The indices of the environments to apply the event to. + Defaults to None, in which case the event is applied to all environments when applicable. + + Raises: + ValueError: If the mode is ``"interval"`` and the environment indices are provided. This is an undefined + behavior as the environment indices are computed based on the time left for each environment. + ValueError: If the mode is ``"reset"`` and the total number of environment steps that have happened + is not provided. + """ + # check if mode is valid + if mode not in self._mode_functor_names: + logger.log_warning(f"Event mode '{mode}' is not defined. Skipping event.") + return + + if mode == "interval" and env_ids is not None: + logger.log_error( + f"Event mode '{mode}' does not require environment indices. This is an undefined behavior" + " as the environment indices are computed based on the time left for each environment." + ) + + # iterate over all the event functors + for index, functor_cfg in enumerate(self._mode_functor_cfgs[mode]): + functor_cfg: EventCfg + if mode == "interval": + self._interval_functor_step_count[index] += 1 + + # check if the interval has passed and sample a new interval + # note: we compare with a small value to handle floating point errors + if ( + functor_cfg.is_global + and self._interval_functor_step_count[index] + % functor_cfg.interval_step + == 0 + ): + + # call the event functor (with None for env_ids) + functor_cfg.func(self._env, None, **functor_cfg.params) + else: + valid_env_ids = ( + ( + self._interval_functor_step_count[index] + % functor_cfg.interval_step + == 0 + ) + .nonzero() + .flatten() + ) + if len(valid_env_ids) > 0: + # call the event functor + functor_cfg.func(self._env, valid_env_ids, **functor_cfg.params) + elif mode == "reset": + # resolve the environment indices + if env_ids is None: + env_ids = slice(None) + + functor_cfg.func(self._env, env_ids, **functor_cfg.params) + else: + # call the event functor + functor_cfg.func(self._env, env_ids, **functor_cfg.params) + + """ + Operations - Functor settings. + """ + + def set_functor_cfg(self, functor_name: str, cfg: EventCfg): + """Sets the configuration of the specified functor into the manager. + + The method finds the functor by name by searching through all the modes. + It then updates the configuration of the functor with the first matching name. + + Args: + functor_name: The name of the event functor. + cfg: The configuration for the event functor. + + Raises: + ValueError: If the functor name is not found. + """ + functor_found = False + for mode, functors in self._mode_functor_names.items(): + if functor_name in functors: + self._mode_functor_cfgs[mode][functors.index(functor_name)] = cfg + functor_found = True + break + if not functor_found: + logger.log_error(f"Event functor '{functor_name}' not found.") + + def get_functor_cfg(self, functor_name: str) -> EventCfg: + """Gets the configuration for the specified functor. + + The method finds the functor by name by searching through all the modes. + It then returns the configuration of the functor with the first matching name. + + Args: + functor_name: The name of the event functor. + + Returns: + The configuration of the event functor. + + Raises: + ValueError: If the functor name is not found. + """ + for mode, functors in self._mode_functor_names.items(): + if functor_name in functors: + return self._mode_functor_cfgs[mode][functors.index(functor_name)] + logger.log_error(f"Event functor '{functor_name}' not found.") + + """ + Operations - Visit functor. + """ + + def get_functor(self, functor_name: str): + """ + Retrieve a functor from the configuration by its name. + + Args: + functor_name (str): The name of the functor to retrieve. + + Returns: + The functor if it exists in the configuration, otherwise None. + """ + if hasattr(self.cfg, functor_name): + functor = getattr(self.cfg, functor_name).func + return functor + else: + logger.log_warning( + f"Got no functor {functor_name} in event_manager, please check again." + ) + return None + + """ + Helper functions. + """ + + def _prepare_functors(self): + # buffer to store the time left for "interval" mode + # if interval is global, then it is a single value, otherwise it is per environment + self._interval_functor_step_count: list[torch.Tensor] = list() + + # check if config is dict already + if isinstance(self.cfg, dict): + cfg_items = self.cfg.items() + else: + cfg_items = self.cfg.__dict__.items() + # iterate over all the functors + for functor_name, functor_cfg in cfg_items: + # check for non config + if functor_cfg is None: + continue + # check for valid config type + if not isinstance(functor_cfg, EventCfg): + raise TypeError( + f"Configuration for the functor '{functor_name}' is not of type EventCfg." + f" Received: '{type(functor_cfg)}'." + ) + + # resolve common parameters + self._resolve_common_functor_cfg(functor_name, functor_cfg, min_argc=2) + + # check if mode is a new mode + if functor_cfg.mode not in self._mode_functor_names: + # add new mode + self._mode_functor_names[functor_cfg.mode] = list() + self._mode_functor_cfgs[functor_cfg.mode] = list() + self._mode_class_functor_cfgs[functor_cfg.mode] = list() + # add functor name and parameters + self._mode_functor_names[functor_cfg.mode].append(functor_name) + self._mode_functor_cfgs[functor_cfg.mode].append(functor_cfg) + + # check if the functor is a class + if inspect.isclass(functor_cfg.func): + self._mode_class_functor_cfgs[functor_cfg.mode].append(functor_cfg) + + # resolve the mode of the events + # -- interval mode + if functor_cfg.mode == "interval": + # sample the time left for global + if functor_cfg.is_global: + count = torch.zeros(1, dtype=torch.int32, device=self.device) + self._interval_functor_step_count.append(count) + else: + count = torch.zeros( + self.num_envs, dtype=torch.int32, device=self.device + ) + self._interval_functor_step_count.append(count) diff --git a/embodichain/lab/gym/envs/managers/events.py b/embodichain/lab/gym/envs/managers/events.py new file mode 100644 index 00000000..1e089434 --- /dev/null +++ b/embodichain/lab/gym/envs/managers/events.py @@ -0,0 +1,610 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import torch +import os +import random + +from copy import deepcopy +from typing import TYPE_CHECKING, List, Union, Tuple, Dict + +from embodichain.lab.sim.objects import ( + Light, + RigidObject, + RigidObjectGroup, + Articulation, + Robot, +) +from embodichain.lab.sim.cfg import RigidObjectCfg, ArticulationCfg +from embodichain.lab.sim.shapes import MeshCfg +from embodichain.lab.gym.envs.managers.cfg import SceneEntityCfg +from embodichain.lab.gym.envs.managers import Functor, FunctorCfg +from embodichain.utils.module_utils import find_function_from_modules +from embodichain.utils.string import remove_regex_chars, resolve_matching_names +from embodichain.utils.file import get_all_files_in_directory +from embodichain.utils.math import ( + sample_uniform, + pose_inv, + xyz_quat_to_4x4_matrix, + trans_matrix_to_xyz_quat, +) +from embodichain.utils import logger +from embodichain.data import get_data_path + +if TYPE_CHECKING: + from embodichain.lab.gym.envs import EmbodiedEnv + + +class replace_assets_from_group(Functor): + """Replace assets in the environment from a specified group of assets. + + The group of assets can be defined in the following ways: + - A directory containing multiple asset files. + - A json file listing multiple assets with their properties. (not supported yet) + - ... (other methods can be added in the future) + """ + + def __init__(self, cfg: FunctorCfg, env: EmbodiedEnv): + """Initialize the term. + + Args: + cfg: The configuration of the functor. + env: The environment instance. + + Raises: + ValueError: If the asset is not a RigidObject or an Articulation. + """ + super().__init__(cfg, env) + + # extract the used quantities (to enable type-hinting) + entity_cfg: SceneEntityCfg = cfg.params["entity_cfg"] + asset = env.sim.get_asset(entity_cfg.uid) + if asset is None: + logger.log_error( + f"Asset with UID '{entity_cfg.uid}' not found in the simulation." + ) + + if ( + isinstance(asset, RigidObject) + and isinstance(asset.cfg.shape, MeshCfg) is False + ): + logger.log_error( + "Only mesh-based RigidObject assets are supported for replacement." + ) + + self.asset_cfg = asset.cfg + self.asset_type = type(asset) + + if isinstance(asset, Articulation): + logger.log_error("Replacing articulation assets is not supported yet.") + + self._asset_group_path: list[str] = [] + + # The following block of code only handle rigid object assets. + # If we want to support articulation assets, the group path format + # should be changed into list of folder (each folder contains a urdf file + # and its associated resources) + folder_path = cfg.params.get("folder_path", None) + + if folder_path is None: + logger.log_error( + "folder_path must be specified in the functor configuration." + ) + + if folder_path.endswith("/") is False: + folder_path, patterns = os.path.split(folder_path) + + # remove regular expression from patterns + patterns = remove_regex_chars(patterns) + full_path = get_data_path(f"{folder_path}/") + self._asset_group_path = get_all_files_in_directory( + full_path, patterns=patterns + ) + else: + full_path = get_data_path(folder_path) + self._asset_group_path = get_all_files_in_directory(full_path) + + def __call__( + self, + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + folder_path: str, + ) -> None: + + env.sim.remove_asset(entity_cfg.uid) + asset_path = random.choice(self._asset_group_path) + self.asset_cfg.shape.fpath = asset_path + if self.asset_type == RigidObject: + new_asset = env.sim.add_rigid_object(cfg=self.asset_cfg) + else: + logger.log_error("Only RigidObject assets are supported for replacement.") + + +class prepare_extra_attr(Functor): + def __init__(self, cfg: FunctorCfg, env: EmbodiedEnv): + """ + Initializes the event manager with the given configuration and environment. + + Args: + cfg (FunctorCfg): The configuration object for the functor. + env (EmbodiedEnv): The embodied environment instance. + + Attributes: + extra_attrs (dict): A dictionary to hold additional attributes. + """ + super().__init__(cfg, env) + + self.extra_attrs = {} + + def __call__( + self, env: EmbodiedEnv, env_ids: Union[torch.Tensor, None], attrs: List[Dict] + ) -> None: + """ + Processes extra attributes for the given environment. + + This method iterates over a list of attributes, validates them, and updates + the `extra_attrs` dictionary based on the specified modes and values. It handles + both static and callable attributes, logging warnings for any issues encountered. + + Args: + env (EmbodiedEnv): The environment instance to which the attributes are applied. + env_ids (Union[torch.Tensor, None]): Optional tensor of environment IDs (not used in this method). + attrs (List[Dict]): A list of dictionaries containing attribute configurations. + Each dictionary must contain a 'name', and may contain 'entity_cfg', 'entities', + 'mode', 'value', 'func_name', and 'func_kwargs'. + + Returns: + None: This method does not return a value. + """ + for attr_idx, attr in enumerate(attrs): + attr_name = attr.get("name", None) + if attr_name is None: + logger.log_warning( + f"{attr_idx}-th extra attribute got no name, skipping.." + ) + continue + if attr.get("entity_cfg", None) is not None: + entity_cfgs = [SceneEntityCfg(**attr["entity_cfg"])] + elif attr.get("entity_uids", None) is not None: + entity_uids = attr["entity_uids"] + if isinstance(entity_uids, (str, list)): + entity_uids = resolve_uids(env, entity_uids) + if entity_uids is None: + logger.log_warning( + f"Entities string {entity_uids} is not supported, skipping.." + ) + continue + else: + logger.log_warning( + f"Entities type {type(entity_uids)} is not supported, skipping.." + ) + continue + entity_cfgs = [SceneEntityCfg(uid=uid) for uid in entity_uids] + else: + logger.log_warning( + f"'entity_cfg' or 'entity_uids' must be provieded, skipping.." + ) + continue + + attr_mode = attr.get("mode", None) + if attr_mode is None: + logger.log_info( + f"Extra attribute {attr_name} got no mode, setting mode to default 'static'.", + color="green", + ) + attr_mode = "static" + + if attr_mode == "static": + attr_value = attr.get("value", None) + if attr_value is None: + logger.log_warning( + f"Extra attribute {attr_name} got mode 'static' but no value, skipping.." + ) + continue + for cfg in entity_cfgs: + if cfg.uid not in self.extra_attrs: + self.extra_attrs[cfg.uid] = {} + self.extra_attrs[cfg.uid].update({attr_name: attr_value}) + + elif attr_mode == "callable": + attr_func_name = attr.get("func_name", None) + if attr_func_name is None: + logger.log_info( + f"Extra attribute {attr_name} got mode 'callable' but no 'func_name', skipping..", + color="green", + ) + continue + + attr_func_kwargs = attr.get("func_kwargs", None) + if attr_func_name is None: + logger.log_info( + f"Extra attribute {attr_name} got no func_kwargs, setting func_kwargs to default empty dict..", + color="green", + ) + attr_func_kwargs = {} + + is_global_func = True + ASSET_MODULES = [ + "embodichain.lab.gym.envs.object", + "embodichain.lab.gym.utils.misc", + ] + global_func = find_function_from_modules( + attr_func_name, modules=ASSET_MODULES, raise_if_not_found=False + ) + if global_func is None: + is_global_func = False + for cfg in entity_cfgs: + if cfg.uid not in self.extra_attrs: + self.extra_attrs[cfg.uid] = {} + if not is_global_func: + asset = env.sim.get_asset(cfg.uid) + if callable((attr_func := getattr(asset, attr_func_name))): + attr_func_ret = attr_func(**attr_func_kwargs) + else: + logger.log_warning( + f"Extra attribute {attr_name} got no attr_func_name '{attr_func_name}', skipping.." + ) + continue + else: + attr_func_kwargs.update( + {"env": env, "env_ids": env_ids, "entity_cfg": cfg} + ) + attr_func_ret = global_func(**attr_func_kwargs) + self.extra_attrs[cfg.uid].update({attr_name: attr_func_ret}) + + +def register_entity_attrs( + env: EmbodiedEnv, + env_ids: torch.Tensor, + entity_cfg: SceneEntityCfg, + registration: str = "affordance_datas", + attrs: List[str] = [], + prefix: bool = True, +): + """Register the atrributes of an entity to the `env.registration` dict. + + TODO: Currently this method only support 1 env or multi-envs that reset() together, + + as it's behavior is to update a overall dict every time it's called. + + In the future, asynchronously reset mode shall be supported. + + Args: + env (EmbodiedEnv): The environment the entity is in. + env_ids (Union[torch.Tensor, None]): The ids of the envs that the entity should be registered. + entity_cfg (SceneEntityCfg): The config of the entity. + attrs (List[str]): The list of entity attributes that asked to be registered. + registration (str, optional): The env's registration string where the attributes should be injected to. + """ + entity = env.sim.get_asset(entity_cfg.uid) + + if not hasattr(env, registration): + logger.log_warning( + f"Environment has no atrtribute {registration} for registration, please check again." + ) + return + else: + registration_dict = getattr(env, registration, None) + if not isinstance(registration_dict, Dict): + logger.log_warning( + f"Got registration env.{registration} with type {type(registration_dict)}, please check again." + ) + return + + for attr in attrs: + attr_key = f"{entity_cfg.uid}_{attr}" if prefix else attr + if (attr_val := getattr(entity, attr_key, None)) is not None: + registration_dict.update({attr_key: attr_val}) + elif ( + attr_val := getattr( + env.event_manager.get_functor("prepare_extra_attr"), "extra_attrs", {} + ) + .get(entity_cfg.uid, {}) + .get(attr) + ) is not None: + registration_dict.update({attr_key: attr_val}) + else: + logger.log_warning( + f"Attr {attr} for entity {entity_cfg.uid} has neither been found in entity attrbutes nor prepare_extra_attrs functor, skipping.." + ) + + +def register_entity_pose( + env: EmbodiedEnv, + env_ids: torch.Tensor, + entity_cfg: SceneEntityCfg, + registration: str = "affordance_datas", + compute_relative: Union[bool, List, str] = "all_robots", + compute_pose_object_to_arena: bool = True, + to_matrix: bool = True, +): + update_registration_dict = {} + if not hasattr(env, registration): + logger.log_warning( + f"Environment has no atrtribute {registration} for registration, please check again." + ) + return + else: + registration_dict = getattr(env, registration, None) + if not isinstance(registration_dict, Dict): + logger.log_warning( + f"Got registration env.{registration} with type {type(registration_dict)}, please check again." + ) + return + + entity_pose_name, entity_pose = get_pose( + env, env_ids, entity_cfg, return_name=True, to_matrix=True + ) + update_registration_dict.update({entity_pose_name: entity_pose}) + + if compute_relative: + # transform other entity's pose to entity frame + relative_poses = {} + if compute_relative == True: + entity_uids = ( + env.sim.get_articulation_uid_list() + + env.sim.get_rigid_object_uid_list() + + env.sim.get_robot_uid_list() + ) + elif isinstance(compute_relative, (str, list)): + entity_uids = resolve_uids(env, compute_relative) + else: + logger.log_warning( + f"Compute relative pose option with type {type(compute_relative)} is not supported, using empty list for skipping.." + ) + entity_uids = [] + + for other_entity_uid in entity_uids: + if other_entity_uid != entity_cfg.uid: + # TODO: this is only for asset + other_entity_pose = env.sim.get_asset(other_entity_uid).get_local_pose( + to_matrix=True + )[env_ids, :] + relative_pose = torch.bmm(pose_inv(entity_pose), other_entity_pose) + relative_poses.update( + { + f"{other_entity_uid}_pose_{entity_pose_name.replace('_pose', '')}": relative_pose + } + ) + + update_registration_dict.update(relative_poses) + + entity = env.sim.get_asset(entity_cfg.uid) + if isinstance(entity, RigidObject): + extra_attr_functor = env.event_manager.get_functor("prepare_extra_attr") + entity_extra_attrs = getattr(extra_attr_functor, "extra_attrs", {}).get( + entity_cfg.uid, {} + ) + for ( + entity_extra_attr_key, + entity_extra_attr_val, + ) in entity_extra_attrs.items(): + if entity_extra_attr_key.endswith("_pose_object"): + entity_extra_attr_val = torch.as_tensor( + entity_extra_attr_val, device=env.device + ) + if entity_extra_attr_val.ndim < 3: + logger.log_info( + f"Got xyz_quat pose {entity_extra_attr_key}: {entity_extra_attr_val}, transforming it to matrix.", + color="green", + ) + entity_extra_attr_val = xyz_quat_to_4x4_matrix( + entity_extra_attr_val + ) + update_registration_dict.update( + { + entity_cfg.uid + + "_" + + (entity_extra_attr_key): entity_extra_attr_val + } + ) + if compute_pose_object_to_arena: + pose_arena = torch.bmm(entity_pose, entity_extra_attr_val) + update_registration_dict.update( + { + entity_cfg.uid + + "_" + + ( + entity_extra_attr_key.replace("_pose_object", "_pose") + ): pose_arena + } + ) + else: + logger.log_warning( + f"Now compute_pose_object_to_arena only support RigidObject type entity, skipping.." + ) + + if not to_matrix: + for key, val in update_registration_dict.items(): + update_registration_dict[key] = trans_matrix_to_xyz_quat(val) + + registration_dict = getattr(env, registration, None) + if not isinstance(registration_dict, Dict): + logger.log_warning( + f"Got registration env.{registration} with type {type(registration_dict)}, please check again." + ) + return + registration_dict.update(update_registration_dict) + + +def register_info_to_env( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + registry: List[Dict], + registration: str = "affordance_datas", + sim_update: bool = True, +): + if env_ids is None: + env_ids = torch.arange(env.num_envs, device=env.device) + if sim_update: + logger.log_info( + "Calling env.sim.update(100) for after-physics-applied object attributes..", + color="green", + ) + env.sim.update(100) + for entity_registry in registry: + entity_cfg = SceneEntityCfg(**entity_registry["entity_cfg"]) + logger.log_info(f"Registering {entity_cfg.uid}..", color="green") + if (entity_attrs := entity_registry.get("attrs")) is not None: + prefix = entity_registry.get("prefix", True) + register_entity_attrs( + env, env_ids, entity_cfg, registration, entity_attrs, prefix + ) + if ( + pose_register_params := entity_registry.get("pose_register_params") + ) is not None: + register_entity_pose( + env, env_ids, entity_cfg, registration, **pose_register_params + ) + + +"""Helper Function""" + + +def resolve_uids(env: EmbodiedEnv, entity_uids: Union[List[str], str]) -> List[str]: + if isinstance(entity_uids, str): + if entity_uids == "all_objects": + entity_uids = ( + env.sim.get_rigid_object_uid_list() + + env.sim.get_articulation_uid_list() + ) + elif entity_uids == "all_robots": + entity_uids = env.sim.get_robot_uid_list() + elif entity_uids == "all_sensors": + entity_uids = env.sim.get_sensor_uid_list() + else: + # logger.log_warning(f"Entity uids {entity_uids} not supported in ['all_objects', 'all_robots', 'all_sensors'], wrapping it as a list..") + entity_uids = [entity_uids] + elif isinstance(entity_uids, (list, set, tuple)): + entity_uids = list(entity_uids) + else: + logger.log_error( + f"Entity uids {entity_uids} with type {type(entity_uids)} not supported in [List[str], str], please check again." + ) + return entity_uids + + +def resolve_dict(env: EmbodiedEnv, entity_dict: Dict): + for entity_key in list(entity_dict.keys()): + entity_val = entity_dict.pop(entity_key) + entity_uids = resolve_uids(env, entity_key) + for entity_uid in entity_uids: + entity_dict.update({entity_uid: deepcopy(entity_val)}) + return entity_dict + + +EntityWithPose = Union[RigidObject, Robot] + + +def get_pose( + env: EmbodiedEnv, + env_ids: torch.Tensor, + entity_cfg: SceneEntityCfg, + return_name: bool = True, + to_matrix: bool = True, +): + entity = env.sim.get_asset(entity_cfg.uid) + + if isinstance(entity, RigidObject): + entity_pose = entity.get_local_pose(to_matrix=to_matrix)[env_ids, :] + entity_pose_register_name = entity_cfg.uid + "_pose" + elif isinstance(entity, Robot): + _, control_parts = resolve_matching_names( + entity_cfg.control_parts, list(entity.control_parts.keys()) + ) + if len(control_parts) != 1: + logger.log_warning( + "Only 1 control part can be assigned for computing the robot pose, please check again. Skipping" + ) + return None + entity_cfg.control_parts = control_parts + control_part = control_parts[0] + control_part_qpos = entity.get_qpos()[ + env_ids, entity.get_joint_ids(control_part) + ] + entity_pose = entity.compute_fk( + control_part_qpos, name=control_part, to_matrix=to_matrix + ) # NOTE: now compute_fk returns arena pose + entity_pose_register_name = control_part + "_pose" + else: + logger.log_warning( + f"Entity with tyope {type(entity)} is not supported, please check again." + ) + return None + + if return_name: + return entity_pose_register_name, entity_pose + else: + return entity_pose + + +def drop_rigid_object_group_sequentially( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + drop_position: List[float] = [0.0, 0.0, 1.0], + position_range: Tuple[List[float], List[float]] = ( + [-0.1, -0.1, 0.0], + [0.1, 0.1, 0.0], + ), + physics_step: int = 2, +) -> None: + """Drop rigid object group from a specified height sequentially in the environment. + + Args: + env (EmbodiedEnv): The environment instance. + env_ids (Union[torch.Tensor, None]): The environment IDs to apply the randomization. + entity_cfg (SceneEntityCfg): The configuration of the scene entity to randomize. + drop_position (List[float]): The base position from which to drop the objects. Default is [0.0, 0.0, 1.0]. + position_range (Tuple[List[float], List[float]]): The range for randomizing the drop position around the base position. + physics_step (int): The number of physics steps to simulate after dropping the objects. Default is 2. + """ + + obj_group: RigidObjectGroup = env.sim.get_rigid_object_group(entity_cfg.uid) + + if obj_group is None: + logger.log_error( + f"RigidObjectGroup with UID '{entity_cfg.uid}' not found in the simulation." + ) + + num_instance = len(env_ids) + num_objects = obj_group.num_objects + + range_low = torch.tensor(position_range[0], device=env.device) + range_high = torch.tensor(position_range[1], device=env.device) + drop_pos = ( + torch.tensor(drop_position, device=env.device) + .unsqueeze_(0) + .repeat(num_instance, 1) + ) + drop_pose = torch.zeros((num_instance, 7), device=env.device) + drop_pose[:, 3] = 1.0 # w component of quaternion + drop_pose[:, :3] = drop_pos + for i in range(num_objects): + random_offset = sample_uniform( + lower=range_low, + upper=range_high, + size=(num_instance, 3), + ) + drop_pose_i = drop_pose.unsqueeze(1) + drop_pose_i[:, 0, :3] = drop_pos + random_offset + + obj_group.set_local_pose(pose=drop_pose_i, env_ids=env_ids, obj_ids=[i]) + + env.sim.update(step=physics_step) diff --git a/embodichain/lab/gym/envs/managers/manager_base.py b/embodichain/lab/gym/envs/managers/manager_base.py new file mode 100644 index 00000000..d89503bc --- /dev/null +++ b/embodichain/lab/gym/envs/managers/manager_base.py @@ -0,0 +1,408 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# All rights reserved. +# +# This file incorporates code from the Isaac Lab Project +# Copyright (c) 2022-2025, The Isaac Lab Project Developers +# (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import copy +import inspect +from abc import ABC, abstractmethod +from collections.abc import Sequence +from typing import TYPE_CHECKING, Any, Union + +from embodichain.utils.string import string_to_callable, resolve_matching_names +from embodichain.utils.utility import class_to_dict +from embodichain.utils import logger + +from .cfg import FunctorCfg, SceneEntityCfg + +if TYPE_CHECKING: + from embodichain.lab.gym.envs import EmbodiedEnv + + +class Functor(ABC): + """Base class for Functor. + + Functor implementations can be functions or classes. If the functor is a class, it should + inherit from this base class and implement the required methods. + + Each manager is implemented as a class that inherits from the :class:`ManagerBase` class. Each manager + class should also have a corresponding configuration class that defines the configuration functors for the + manager. Each functor should the :class:`FunctorCfg` class or its subclass. + + Example pseudo-code for creating a manager: + + .. code-block:: python + + from embodichain.utils import configclass + from embodichain.lab.gym.managers import ManagerBase + from embodichain.lab.gym.managers FunctorCfg + + @configclass + class MyManagerCfg: + + functor1: FunctorCfg = FunctorCfg(...) + functor2: FunctorCfg = FunctorCfg(...) + functor3: FunctorCfg = FunctorCfg(...) + + # define manager instance + my_manager = ManagerBase(cfg=ManagerCfg(), env=env) + + """ + + def __init__(self, cfg: FunctorCfg, env: EmbodiedEnv): + """Initialize the functor. + + Args: + cfg: The configuration object. + env: The environment instance. + """ + # store the inputs + self.cfg = cfg + self._env = env + + """ + Properties. + """ + + @property + def num_envs(self) -> int: + """Number of environments.""" + return self._env.num_envs + + @property + def device(self) -> str: + """Device on which to perform computations.""" + return self._env.device + + @property + def __name__(self) -> str: + """Return the name of the class or subclass.""" + return self.__class__.__name__ + + """ + Operations. + """ + + def reset(self, env_ids: Union[Sequence[int], None] = None) -> None: + """Resets the functor. + + Args: + env_ids: The environment ids. Defaults to None, in which case + all environments are considered. + """ + pass + + def serialize(self) -> dict: + """General serialization call. Includes the configuration dict.""" + return {"cfg": class_to_dict(self.cfg)} + + def __call__(self, *args) -> Any: + """Returns the value of the functor required by the manager. + + In case of a class implementation, this function is called by the manager + to get the value of the functor. The arguments passed to this function are + the ones specified in the functor configuration (see :attr:`FunctorCfg.params`). + + .. attention:: + To be consistent with memory-less implementation of functors with functions, it is + recommended to ensure that the returned mutable quantities are cloned before + returning them. For instance, if the functor returns a tensor, it is recommended + to ensure that the returned tensor is a clone of the original tensor. This prevents + the manager from storing references to the tensors and altering the original tensors. + + Args: + *args: Variable length argument list. + + Returns: + The value of the functor. + """ + raise NotImplementedError( + "The method '__call__' should be implemented by the subclass." + ) + + +class ManagerBase(ABC): + """Base class for all managers.""" + + def __init__(self, cfg: object, env: EmbodiedEnv): + """Initialize the manager. + + This function is responsible for parsing the configuration object and creating the functors. + + If the simulation is not playing, the scene entities are not resolved immediately. + Instead, the resolution is deferred until the simulation starts. This is done to ensure + that the scene entities are resolved even if the manager is created after the simulation + has already started. + + Args: + cfg: The configuration object. If None, the manager is initialized without any functors. + env: The environment instance. + """ + # store the inputs + self.cfg = copy.deepcopy(cfg) + self._env = env + + # parse config to create functors information + if self.cfg: + self._prepare_functors() + + def __repr__(self) -> str: + return self.__str__() + + """ + Properties. + """ + + @property + def num_envs(self) -> int: + """Number of environments.""" + return self._env.num_envs + + @property + def device(self) -> str: + """Device on which to perform computations.""" + return self._env.device + + @property + @abstractmethod + def active_functors(self) -> Union[list[str], dict[str, list[str]]]: + """Name of active functors.""" + raise NotImplementedError + + """ + Operations. + """ + + def reset(self, env_ids: Union[Sequence[int], None] = None) -> dict[str, float]: + """Resets the manager and returns logging information for the current time-step. + + Args: + env_ids: The environment ids for which to log data. + Defaults None, which logs data for all environments. + + Returns: + Dictionary containing the logging information. + """ + return {} + + def find_functors(self, name_keys: Union[str, Sequence[str]]) -> list[str]: + """Find functors in the manager based on the names. + + This function searches the manager for functors based on the names. The names can be + specified as regular expressions or a list of regular expressions. The search is + performed on the active functors in the manager. + + Please check the :meth:`~embodichain.utils.string.resolve_matching_names` function for more + information on the name matching. + + Args: + name_keys: A regular expression or a list of regular expressions to match the functor names. + + Returns: + A list of functor names that match the input keys. + """ + # resolve search keys + if isinstance(self.active_functors, dict): + list_of_strings = [] + for names in self.active_functors.values(): + list_of_strings.extend(names) + else: + list_of_strings = self.active_functors + + # return the matching names + return resolve_matching_names(name_keys, list_of_strings)[1] + + def get_active_iterable_functors( + self, env_idx: int + ) -> Sequence[tuple[str, Sequence[float]]]: + """Returns the active functors as iterable sequence of tuples. + + The first element of the tuple is the name of the functor and the second element is the raw value(s) of the functor. + + Returns: + The active functors. + """ + raise NotImplementedError + + """ + Implementation specific. + """ + + @abstractmethod + def _prepare_functors(self): + """Prepare functors information from the configuration object.""" + raise NotImplementedError + + """ + Internal callbacks. + """ + + def _resolve_functors_callback(self, event): + """Resolve configurations of functors once the simulation starts. + + Please check the :meth:`_process_functor_cfg_at_play` method for more information. + """ + # check if scene entities have been resolved + if self._is_scene_entities_resolved: + return + # check if config is dict already + if isinstance(self.cfg, dict): + cfg_items = self.cfg.items() + else: + cfg_items = self.cfg.__dict__.items() + + # iterate over all the functors + for functor_name, functor_cfg in cfg_items: + # check for non config + if functor_cfg is None: + continue + # process attributes at runtime + # these properties are only resolvable once the simulation starts playing + self._process_functor_cfg_at_play(functor_name, functor_cfg) + + # set the flag + self._is_scene_entities_resolved = True + + """ + Internal functions. + """ + + def _resolve_common_functor_cfg( + self, functor_name: str, functor_cfg: FunctorCfg, min_argc: int = 1 + ): + """Resolve common attributes of the functor configuration. + + Usually, called by the :meth:`_prepare_functors` method to resolve common attributes of the functor + configuration. These include: + + * Resolving the functor function and checking if it is callable. + * Checking if the functor function's arguments are matched by the parameters. + * Resolving special attributes of the functor configuration like ``entity_cfg``, ``sensor_cfg``, etc. + * Initializing the functor if it is a class. + + By default, all functor functions are expected to have at least one argument, which is the + environment object. Some other managers may expect functions to take more arguments, for + instance, the environment indices as the second argument. In such cases, the + ``min_argc`` argument can be used to specify the minimum number of arguments + required by the functor function to be called correctly by the manager. + + Args: + functor_name: The name of the functor. + functor_cfg: The functor configuration. + min_argc: The minimum number of arguments required by the functor function to be called correctly + by the manager. + + Raises: + TypeError: If the functor configuration is not of type :class:`FunctorCfg`. + ValueError: If the scene entity defined in the functor configuration does not exist. + AttributeError: If the functor function is not callable. + ValueError: If the functor function's arguments are not matched by the parameters. + """ + # check if the functor is a valid functor config + if not isinstance(functor_cfg, FunctorCfg): + raise TypeError( + f"Configuration for the functor '{functor_name}' is not of type FunctorCfg." + f" Received: '{type(functor_cfg)}'." + ) + + # get the corresponding function or functional class + if isinstance(functor_cfg.func, str): + functor_cfg.func = string_to_callable(functor_cfg.func) + # check if function is callable + if not callable(functor_cfg.func): + raise AttributeError( + f"The functor '{functor_name}' is not callable. Received: {functor_cfg.func}" + ) + + # check if the functor is a class of valid type + if inspect.isclass(functor_cfg.func): + if not issubclass(functor_cfg.func, Functor): + raise TypeError( + f"Configuration for the functor '{functor_name}' is not of type ManagerTermBase." + f" Received: '{type(functor_cfg.func)}'." + ) + func_static = functor_cfg.func.__call__ + min_argc += 1 # forward by 1 to account for 'self' argument + else: + func_static = functor_cfg.func + # check if function is callable + if not callable(func_static): + raise AttributeError( + f"The functor '{functor_name}' is not callable. Received: {functor_cfg.func}" + ) + + # check statically if the functor's arguments are matched by params + functor_params = list(functor_cfg.params.keys()) + args = inspect.signature(func_static).parameters + args_with_defaults = [ + arg for arg in args if args[arg].default is not inspect.Parameter.empty + ] + args_without_defaults = [ + arg for arg in args if args[arg].default is inspect.Parameter.empty + ] + args = args_without_defaults + args_with_defaults + # ignore first two arguments for env and env_ids + # Think: Check for cases when kwargs are set inside the function? + if len(args) > min_argc: + if set(args[min_argc:]) != set(functor_params + args_with_defaults): + raise ValueError( + f"The functor '{functor_name}' expects mandatory parameters: {args_without_defaults[min_argc:]}" + f" and optional parameters: {args_with_defaults}, but received: {functor_params}." + ) + + # process attributes at runtime + # these properties are only resolvable once the simulation starts playing + self._process_functor_cfg_at_play(functor_name, functor_cfg) + + def _process_functor_cfg_at_play(self, functor_name: str, functor_cfg: FunctorCfg): + """Process the functor configuration at runtime. + + This function is called when the simulation starts playing. It is used to process the functor + configuration at runtime. This includes: + + * Resolving the scene entity configuration for the functor. + * Initializing the functor if it is a class. + + Since the above steps rely on PhysX to parse over the simulation scene, they are deferred + until the simulation starts playing. + + Args: + functor_name: The name of the functor. + functor_cfg: The functor configuration. + """ + for key, value in functor_cfg.params.items(): + if isinstance(value, SceneEntityCfg): + # load the entity + try: + value.resolve(self._env.sim) + except ValueError as e: + raise ValueError(f"Error while parsing '{functor_name}:{key}'. {e}") + # log the entity for checking later + msg = f"[{functor_cfg.__class__.__name__}:{functor_name}] Found entity '{value.uid}'." + if value.joint_ids is not None: + msg += f"\n\tJoint names: {value.joint_names} [{value.joint_ids}]" + if value.body_ids is not None: + msg += f"\n\tBody names: {value.body_names} [{value.body_ids}]" + # print the information + print(f"[INFO]: {msg}") + # store the entity + functor_cfg.params[key] = value + + # initialize the functor if it is a class + if inspect.isclass(functor_cfg.func): + try: + logger.log_info( + f"Initializing functor '{functor_name}' with class '{functor_cfg.func.__name__}'." + ) + functor_cfg.func = functor_cfg.func(cfg=functor_cfg, env=self._env) + except Exception as e: + logger.log_error(f"Failed to initialize functor '{functor_name}': {e}") diff --git a/embodichain/lab/gym/envs/managers/observation_manager.py b/embodichain/lab/gym/envs/managers/observation_manager.py new file mode 100644 index 00000000..cd1dc70a --- /dev/null +++ b/embodichain/lab/gym/envs/managers/observation_manager.py @@ -0,0 +1,213 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +"""Observation manager for orchestrating operations based on different simulation observations.""" + +from __future__ import annotations + +import inspect +import torch +from collections.abc import Sequence +from prettytable import PrettyTable +from typing import TYPE_CHECKING, Union + +from embodichain.utils import logger +from embodichain.lab.sim.types import EnvObs +from embodichain.lab.gym.utils.gym_utils import ( + fetch_data_from_dict, + assign_data_to_dict, +) +from .manager_base import ManagerBase +from .cfg import ObservationCfg + +if TYPE_CHECKING: + from embodichain.lab.gym.envs import EmbodiedEnv + + +class ObservationManager(ManagerBase): + """Manager for orchestrating operations based on different simulation observations. + + The default observation space will contain two observation groups: + - `robot`: Contains the default observations related to the robot. + - `qpos`: The joint positions of the robot. + - `qvel`: The joint velocities of the robot. + - `qf`: The joint forces of the robot. + - `sensor`: Contains the observations related to the sensors which are enabled in the environment. + + The observation manager offers two modes of operation: + - `modify`: This mode perform data fetching and modification on existing observation data. + - `add`: This mode perform new observation computation and add new observation data to the observation space. + """ + + _env: EmbodiedEnv + """The environment instance.""" + + def __init__(self, cfg: object, env: EmbodiedEnv): + """Initialize the observation manager. + + Args: + cfg: A configuration object or dictionary (``dict[str, ObservationCfg]``). + env: An environment object. + """ + + self._mode_functor_names: dict[str, list[str]] = dict() + self._mode_functor_cfgs: dict[str, list[ObservationCfg]] = dict() + self._mode_class_functor_cfgs: dict[str, list[ObservationCfg]] = dict() + + # call the base class (this will parse the functors config) + super().__init__(cfg, env) + + def __str__(self) -> str: + """Returns: A string representation for observation manager.""" + functor_num = sum(len(v) for v in self._mode_functor_names.values()) + msg = f" contains {functor_num} active functors.\n" + + # add info on each mode + for mode in self._mode_functor_names: + # create table for functor information + table = PrettyTable() + table.title = f"Active Observation Functors in Mode: '{mode}'" + + table.field_names = ["Index", "Name"] + table.align["Name"] = "l" + for index, name in enumerate(self._mode_functor_names[mode]): + table.add_row([index, name]) + + # convert table to string + msg += table.get_string() + msg += "\n" + + return msg + + """ + Properties. + """ + + @property + def active_functors(self) -> dict[str, list[str]]: + """Name of active observation functors. + + The keys are the modes of observation and the values are the names of the observation functors. + """ + return self._mode_functor_names + + """ + Operations. + """ + + def reset(self, env_ids: Union[Sequence[int], None] = None) -> dict[str, float]: + # call all functors that are classes + for mode_cfg in self._mode_class_functor_cfgs.values(): + for functor_cfg in mode_cfg: + functor_cfg.func.reset(env_ids=env_ids) + + # nothing to log here + return {} + + def compute( + self, + obs: EnvObs, + ) -> EnvObs: + """Calls each observation functor in the specified mode. + + This function iterates over all the observation functors in the specified mode and calls the function + corresponding to the functor. The function is called with the environment instance and the environment + indices to apply the observation to. + + Args: + obs: The observation data to apply the observation to. + + Returns: + The modified observation data. + + Raises: + ValueError: If the mode is not supported. + """ + + # iterate over all the observation functors + for mode, functor_cfgs in self._mode_functor_cfgs.items(): + for functor_cfg in functor_cfgs: + functor_cfg: ObservationCfg + + if mode == "modify": + data = fetch_data_from_dict(obs, functor_cfg.name) + data = functor_cfg.func(self._env, data, **functor_cfg.params) + elif mode == "add": + data = functor_cfg.func(self._env, obs, **functor_cfg.params) + assign_data_to_dict(obs, functor_cfg.name, data) + else: + logger.log_error(f"Unsupported observation mode '{mode}'.") + + return obs + + def get_functor_cfg(self, functor_name: str) -> ObservationCfg: + """Gets the configuration for the specified functor. + + The method finds the functor by name by searching through all the modes. + It then returns the configuration of the functor with the first matching name. + + Args: + functor_name: The name of the observation functor. + + Returns: + The configuration of the observation functor. + + Raises: + ValueError: If the functor name is not found. + """ + for mode, functors in self._mode_functor_names.items(): + if functor_name in functors: + return self._mode_functor_cfgs[mode][functors.index(functor_name)] + logger.log_error(f"observation functor '{functor_name}' not found.") + + """ + Helper functions. + """ + + def _prepare_functors(self): + # check if config is dict already + if isinstance(self.cfg, dict): + cfg_items = self.cfg.items() + else: + cfg_items = self.cfg.__dict__.items() + # iterate over all the functors + for functor_name, functor_cfg in cfg_items: + # check for non config + if functor_cfg is None: + continue + # check for valid config type + if not isinstance(functor_cfg, ObservationCfg): + raise TypeError( + f"Configuration for the functor '{functor_name}' is not of type ObservationCfg." + f" Received: '{type(functor_cfg)}'." + ) + + # resolve common parameters + self._resolve_common_functor_cfg(functor_name, functor_cfg, min_argc=2) + + # check if mode is a new mode + if functor_cfg.mode not in self._mode_functor_names: + # add new mode + self._mode_functor_names[functor_cfg.mode] = list() + self._mode_functor_cfgs[functor_cfg.mode] = list() + self._mode_class_functor_cfgs[functor_cfg.mode] = list() + # add functor name and parameters + self._mode_functor_names[functor_cfg.mode].append(functor_name) + self._mode_functor_cfgs[functor_cfg.mode].append(functor_cfg) + + # check if the functor is a class + if inspect.isclass(functor_cfg.func): + self._mode_class_functor_cfgs[functor_cfg.mode].append(functor_cfg) diff --git a/embodichain/lab/gym/envs/managers/observations.py b/embodichain/lab/gym/envs/managers/observations.py new file mode 100644 index 00000000..c628384c --- /dev/null +++ b/embodichain/lab/gym/envs/managers/observations.py @@ -0,0 +1,615 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import torch +import os +import random +from typing import TYPE_CHECKING, Literal, Union, Optional, List, Dict, Sequence + +from embodichain.lab.sim.objects import RigidObject, Articulation, Robot +from embodichain.lab.sim.sensors import Camera, StereoCamera +from embodichain.lab.sim.types import EnvObs +from embodichain.lab.gym.envs.managers.cfg import SceneEntityCfg +from embodichain.lab.gym.envs.managers.events import resolve_dict +from embodichain.lab.gym.envs.managers import Functor, FunctorCfg +from embodichain.utils import logger + +if TYPE_CHECKING: + from embodichain.lab.gym.envs import EmbodiedEnv + + +def get_rigid_object_pose( + env: EmbodiedEnv, + obs: EnvObs, + entity_cfg: SceneEntityCfg, +) -> torch.Tensor: + """Get the world poses of the rigid objects in the environment. + + Args: + env: The environment instance. + obs: The observation dictionary. + entity_cfg: The configuration of the scene entity. + + Returns: + A tensor of shape (num_envs, 4, 4) representing the world poses of the rigid objects. + """ + + obj = env.sim.get_rigid_object(entity_cfg.uid) + + return obj.get_local_pose(to_matrix=True) + + +def normalize_robot_joint_data( + env: EmbodiedEnv, + data: torch.Tensor, + joint_ids: Sequence[int], + limit: Literal["qpos_limits", "qvel_limits"] = "qpos_limits", +) -> torch.Tensor: + """Normalize the robot joint positions to the range of [0, 1] based on the joint limits. + + Args: + env: The environment instance. + obs: The observation dictionary. + joint_ids: The indices of the joints to be normalized. + limit: The type of joint limits to be used for normalization. Options are: + - `qpos_limits`: Use the joint position limits for normalization. + - `qvel_limits`: Use the joint velocity limits for normalization. + """ + + robot = env.robot + + # shape of target_limits: (num_envs, len(joint_ids), 2) + target_limits = getattr(robot.body_data, limit)[:, joint_ids, :] + + # normalize the joint data to the range of [0, 1] + data[:, joint_ids] = (data[:, joint_ids] - target_limits[:, :, 0]) / ( + target_limits[:, :, 1] - target_limits[:, :, 0] + ) + + return data + + +def compute_semantic_mask( + env: EmbodiedEnv, + obs: EnvObs, + entity_cfg: SceneEntityCfg, + foreground_uids: Sequence[str], + is_right: bool = False, +) -> torch.Tensor: + """Compute the semantic mask for the specified scene entity. + + Note: + The semantic mask is defined as (B, H, W, 3) where the three channels represents: + - robot channel: the instance id of the robot is set to 1 (0 if not robot) + - background channel: the instance id of the background is set to 1 (0 if not background) + - foreground channel: the instance id of the foreground objects is set to 1 (0 if not foreground) + + Args: + env: The environment instance. + obs: The observation dictionary. + entity_cfg: The configuration of the scene entity. + foreground_uids: The list of uids for the foreground objects. + is_right: Whether to use the right camera for stereo cameras. Default is False. + Only applicable if the sensor is a StereoCamera. + + Returns: + A tensor of shape (num_envs, height, width) representing the semantic mask. + """ + + sensor: Union[Camera, StereoCamera] = env.sim.get_sensor(entity_cfg.uid) + if sensor.cfg.enable_mask is False: + logger.log_error( + f"Sensor '{entity_cfg.uid}' does not have mask enabled. Please enable the mask in the sensor configuration." + ) + + if isinstance(sensor, StereoCamera) and is_right: + mask = obs["sensor"][entity_cfg.uid]["mask_right"] + else: + mask = obs["sensor"][entity_cfg.uid]["mask"] + + robot_uids = env.robot.get_user_ids() + + mask_exp = mask.unsqueeze(-1) + + robot_uids_exp = robot_uids.unsqueeze_(1).unsqueeze_(1) + + robot_mask = (mask_exp == robot_uids_exp).any(-1).squeeze_(-1) + + foreground_assets = [env.sim.get_asset(uid) for uid in foreground_uids] + + # cat assets uid (num_envs, n) into dim 1 + foreground_uids = torch.cat( + [ + asset.get_user_ids().unsqueeze(1) + if asset.get_user_ids().dim() == 1 + else asset.get_user_ids() + for asset in foreground_assets + ], + dim=1, + ) + + foreground_uids_exp = foreground_uids.unsqueeze_(1).unsqueeze_(1) + + foreground_mask = (mask_exp == foreground_uids_exp).any(-1).squeeze_(-1) + + background_mask = ~(robot_mask | foreground_mask).squeeze_(-1) + + return torch.stack([robot_mask, background_mask, foreground_mask], dim=-1) + + +class compute_exteroception(Functor): + """Compute the exteroception for the observation space. + + The exteroception is currently defined as a set of keypoints around a reference pose, which are prjected from 3D + space to 2D image plane. + The reference pose can derive from the following sources: + - Pose from robot control part (e.g., end-effector, usually tcp pose) + - Object affordance pose (e.g., handle pose of a mug or a pick pose of a cube) + + Therefore, the exteroception are defined in the camera-like sensor, for example. + descriptor = { + "cam_high": [ + { + "type": "affordance", + "obj_uid": "obj1", + "key": "grasp_pose", + "is_arena_coord": True + }, + { + "type": "affordance", + "obj_uid": "obj1", + "key": "place_pose", + }, + { + "type": "robot", + "control_part": "left_arm", + }, + { + "type": "robot", + "control_part": "right_arm", + } + ], + ... + } + + Explanation of the parameters: + - The key of the dictionary is the sensor uid. + - The value is another dictionary, where the key is the source type, and the value is a dictionary of parameters. + - For `affordance` source type, the parameters are: + - `obj_uid`: The uid of the object to get the affordance pose from. + - `key`: The key of the affordance pose in the affordance data. + - `is_arena_coord`: Whether the affordance pose is in the arena coordinate system. Default is False. + - For `robot` source type, the parameters are: + - `control_part`: The control part of the robot to get the pose from. + """ + + def __init__( + self, + cfg: FunctorCfg, + env: EmbodiedEnv, + ): + super().__init__(cfg, env) + + if self._env.num_envs != 1: + logger.log_error( + f"Exteroception functor only supported env with 'num_envs=1' but got 'num_envs={self._env.num_envs}'. Please check again." + ) + + self._valid_source = ["robot", "affordance"] + + @staticmethod + def shift_pose(pose: torch.Tensor, axis: int, shift: float) -> torch.Tensor: + """Shift the pose along the specified axis by the given amount. + + Args: + pose: The original pose tensor of shape (B, 4, 4). + axis: The axis along which to shift (0 for x, 1 for y, 2 for z). + shift: The amount to shift along the specified axis. + """ + shift_pose = torch.linalg.inv(pose) + shift_pose[:, axis, -1] += shift + shift_pose = torch.linalg.inv(shift_pose) + return shift_pose + + @staticmethod + def expand_pose( + pose: torch.Tensor, + x_interval: float, + y_interval: float, + kpnts_number: int, + ref_pose: torch.Tensor = None, + ) -> torch.Tensor: + """Expand pose with keypoints along x and y axes. + + Args: + pose: The original pose tensor of shape (B, 4, 4). + x_interval: The interval for expanding along x-axis. + y_interval: The interval for expanding along y-axis. + kpnts_number: Number of keypoints to generate for each axis. + ref_pose: Reference pose tensor of shape (B, 4, 4). If None, uses identity matrix. + + Returns: + Expanded poses tensor of shape (B, 1 + 2*kpnts_number, 4, 4). + """ + batch_size = pose.shape[0] + device = pose.device + + # Create default reference pose if not provided + if ref_pose is None: + ref_pose = ( + torch.eye(4, device=device).unsqueeze_(0).repeat(batch_size, 1, 1) + ) + + # Start with the original pose transformed by ref_pose + ret = [ref_pose @ pose] + + # Generate x-axis offsets and expand poses + # TODO: only support 1 env + xoffset = torch.linspace(-x_interval, x_interval, kpnts_number, device=device) + for x_shift in xoffset: + shifted_pose = compute_exteroception.shift_pose(pose, 0, x_shift.item()) + x_expanded = ref_pose @ shifted_pose + ret.append(x_expanded) + + # Generate y-axis offsets and expand poses + # TODO: only support 1 env + yoffset = torch.linspace(-y_interval, y_interval, kpnts_number, device=device) + for y_shift in yoffset: + shifted_pose = compute_exteroception.shift_pose(pose, 1, y_shift.item()) + y_expanded = ref_pose @ shifted_pose + ret.append(y_expanded) + + # Stack all poses along a new dimension + return torch.stack(ret, dim=1) + + @staticmethod + def _project_3d_to_2d( + cam_pose: torch.Tensor, + intrinsics: torch.Tensor, + height: int, + width: int, + target_poses: torch.Tensor, + normalize: bool = True, + ) -> torch.Tensor: + """Project 3D poses to 2D image plane. + + Args: + cam_pose: Camera pose of in arena frame of shape (B, 4, 4). + intrinsics: Camera intrinsic matrix of shape (B, 3, 3). + height: Image height. + width: Image width. + target_poses: 3D poses of shape (B, N, 4, 4). + normalize: Whether to normalize the projected points to [0, 1] range. + + Returns: + Projected 2D points of shape (B, N, 2). + """ + batch_size, num_poses = target_poses.shape[:2] + + # Convert to opencv coordinate system + cam_pose[:, :3, 1] = -cam_pose[:, :3, 1] + cam_pose[:, :3, 2] = -cam_pose[:, :3, 2] + + # Expand cam_pose_inv and intrinsics to match target_poses batch dimension + cam_pose_inv = torch.linalg.inv(cam_pose) # (B, 4, 4) + cam_pose_inv_expanded = cam_pose_inv.unsqueeze(1).expand( + -1, num_poses, -1, -1 + ) # (B, N, 4, 4) + cam_pose_inv_reshaped = cam_pose_inv_expanded.reshape(-1, 4, 4) # (B*N, 4, 4) + + intrinsics_expanded = intrinsics.unsqueeze(1).expand( + -1, num_poses, -1, -1 + ) # (B, N, 3, 3) + intrinsics_reshaped = intrinsics_expanded.reshape(-1, 3, 3) # (B*N, 3, 3) + + # Reshape target_poses to (B*N, 4, 4) + target_poses_reshaped = target_poses.reshape(-1, 4, 4) # (B*N, 4, 4) + + # Transform 3D points to camera coordinates in parallel + # Extract translation part (position) from target poses: (B*N, 4, 1) + target_positions = target_poses_reshaped[:, :, 3:4] # (B*N, 4, 1) + + # Transform to camera coordinates: (B*N, 4, 1) + cam_positions = cam_pose_inv_reshaped.bmm(target_positions) # (B*N, 4, 1) + cam_positions_3d = cam_positions[:, :3, 0] # (B*N, 3) + + # Project to 2D using intrinsics in parallel + # Add small epsilon to avoid division by zero + eps = 1e-8 + z_safe = torch.clamp(cam_positions_3d[:, 2], min=eps) # (B*N,) + + # Normalize by depth + normalized_points = cam_positions_3d[:, :2] / z_safe.unsqueeze(-1) # (B*N, 2) + + # Convert to homogeneous coordinates and apply intrinsics + normalized_homogeneous = torch.cat( + [normalized_points, torch.ones_like(normalized_points[:, :1])], dim=-1 + ) # (B*N, 3) + pixel_coords = intrinsics_reshaped.bmm( + normalized_homogeneous.unsqueeze(-1) + ).squeeze( + -1 + ) # (B*N, 3) + + # Extract 2D coordinates + points_2d_flat = pixel_coords[:, :2] # (B*N, 2) + + # Reshape back to (B, N, 2) + points_2d = points_2d_flat.reshape(batch_size, num_poses, 2) + + # clip to range [0, width] and [0, height] + points_2d[..., 0] = torch.clamp(points_2d[..., 0], 0, width - 1) + points_2d[..., 1] = torch.clamp(points_2d[..., 1], 0, height - 1) + + if normalize: + # Normalize to [0, 1] range + points_2d[..., 0] /= width + points_2d[..., 1] /= height + + return points_2d + + def _get_gripper_ratio( + self, control_part: str, gripper_qpos: Optional[torch.Tensor] = None + ): + robot: Robot = self._env.robot + gripper_max_limit = robot.body_data.qpos_limits[ + :, robot.get_joint_ids(control_part) + ][:, 0, 1] + + if gripper_qpos is None: + gripper_qpos = robot.get_qpos()[:, robot.get_joint_ids(control_part)][:, 0] + + return gripper_qpos / gripper_max_limit + + def _get_robot_exteroception( + self, + control_part: Optional[str] = None, + x_interval: float = 0.02, + y_interval: float = 0.02, + kpnts_number: int = 12, + offset: Optional[Union[List, torch.Tensor]] = None, + follow_eef: bool = False, + ) -> torch.Tensor: + """Get the robot exteroception poses. + + Args: + control_part: The part of the robot to use as reference. If None, uses the base. + x_interval: The interval for expanding along x-axis. + y_interval: The interval for expanding along y-axis. + kpnts_number: Number of keypoints to generate for each axis. + offset: Intrinsic offset that need to be substracted. + follow_eef: Whether to follow the gripper or not. + + Returns: + A tensor of shape (num_envs, 1 + 2*kpnts_number, 4, 4) representing the exteroception poses. + """ + robot: Robot = self._env.robot + if control_part is not None: + current_qpos = robot.get_qpos()[:, robot.get_joint_ids(control_part)] + robot_pose = robot.compute_fk( + current_qpos, name=control_part, to_matrix=True + ) + if follow_eef: + gripper_ratio = self._get_gripper_ratio( + control_part.replace("_arm", "_eef") + ) # TODO: "_eef" hardcode + # TODO: only support 1 env + y_interval = (y_interval * gripper_ratio)[0].item() + else: + logger.log_error("Not supported Robot without control part yet.") + + if offset is not None: + offset = torch.as_tensor( + offset, dtype=torch.float32, device=self._env.device + ) + + if (offset.ndim > 2) or (offset.shape[-1] != 3): + logger.log_error( + f"Only (N, 3) shaped xyz-intrinsic offset supported, got shape {offset.shape}" + ) + elif offset.ndim == 1: + offset = offset[None] + # TODO: This operation may be slow when large scale Parallelization, but when small (num_envs=1) this operation is faster + robot_pose[:, :3, 3] = robot_pose[:, :3, 3] - torch.einsum( + "bij,bj->bi", robot_pose[:, :3, :3], offset + ) + + return compute_exteroception.expand_pose( + robot_pose, + x_interval, + y_interval, + kpnts_number, + ) + + def _get_object_exteroception( + self, + uid: str, + affordance_key: str, + x_interval: float = 0.02, + y_interval: float = 0.02, + kpnts_number: int = 12, + is_arena_coord: bool = False, + follow_eef: Optional[str] = None, + ) -> torch.Tensor: + """Get the rigid object exteroception poses. + + Args: + uid: The UID of the object. + affordance_key: The key of the affordance to use for the object pose. + x_interval: The interval for expanding along x-axis. + y_interval: The interval for expanding along y-axis. + kpnts_number: Number of keypoints to generate for each axis. + is_arena_coord: Whether to use the arena coordinate system. Default is False. + + Returns: + A tensor of shape (num_envs, 1 + 2*kpnts_number, 4, 4) representing the exteroception poses. + """ + + obj: RigidObject = self._env.sim.get_rigid_object(uid) + if obj is None: + logger.log_error( + f"Rigid object with UID '{uid}' not found in the simulation." + ) + + if hasattr(self._env, "affordance_datas") is False: + logger.log_error( + "Affordance data is not available in the environment. We cannot compute object exteroception." + ) + + if affordance_key not in self._env.affordance_datas: + # TODO: should this default behavior be warned? + # logger.log_warning( + # f"Affordance key '{affordance_key}' not found in the affordance data, using identity pose.." + # ) + pass + + affordance_pose = torch.as_tensor( + self._env.affordance_datas.get( + affordance_key, torch.eye(4).repeat(self._env.num_envs, 1, 1) + ), + dtype=torch.float32, + ) + if affordance_pose.ndim < 3: + affordance_pose = affordance_pose.repeat(self._env.num_envs, 1, 1) + + ref_pose = None if is_arena_coord else obj.get_local_pose(to_matrix=True) + + if follow_eef is not None: + gripper_ratio = self._get_gripper_ratio(control_part=follow_eef) + # TODO: only support 1 env + y_interval = (y_interval * gripper_ratio)[0].item() + + return compute_exteroception.expand_pose( + affordance_pose, + x_interval, + y_interval, + kpnts_number, + ref_pose=ref_pose, + ) + + def _check_source_valid(self, source: str) -> bool: + if source not in self._valid_source: + logger.log_error( + f"Invalid exteroception source '{source}'. Supported sources are {self._valid_source}." + ) + return True + + def __call__( + self, + env: EmbodiedEnv, + obs: EnvObs, + descriptor: Dict[str, Dict[str, str]], + x_interval: float = 0.02, + y_interval: float = 0.02, + kpnts_number: int = 12, + groups: int = 6, + ) -> Dict[str, Dict[str, torch.Tensor]]: + """Compute the exteroception poses based on the asset type. + + Args: + descriptor: The observation dictionary. + + Returns: + A dictionary containing the exteroception poses with key 'exteroception'. + """ + + exteroception = {} + descriptor = resolve_dict(self._env, descriptor) + for sensor_uid, sources in descriptor.items(): + sensor: Union[Camera, StereoCamera] = self._env.sim.get_sensor(sensor_uid) + if sensor is None: + logger.log_error( + f"Sensor with UID '{sensor_uid}' not found in the simulation." + ) + + if not isinstance(sensor, (Camera, StereoCamera)): + logger.log_error( + f"Sensor with UID '{sensor_uid}' is not a Camera or StereoCamera." + ) + + height, width = sensor.cfg.height, sensor.cfg.width + + exteroception[sensor_uid] = {} + taget_pose_list = [] + for source in sources: + source_type = source["type"] + self._check_source_valid(source_type) + + if source_type == "robot": + target_pose = self._get_robot_exteroception( + control_part=source["control_part"], + x_interval=x_interval, + y_interval=y_interval, + kpnts_number=kpnts_number, + offset=source.get("offset", None), + follow_eef=source.get("follow_eef", False), + ) + elif source_type == "affordance": + target_pose = self._get_object_exteroception( + uid=source["obj_uid"], + affordance_key=source["key"], + x_interval=x_interval, + y_interval=y_interval, + kpnts_number=kpnts_number, + is_arena_coord=source["is_arena_coord"], + follow_eef=source.get("follow_eef", None), + ) + else: + logger.log_error( + f"Unsupported exteroception source '{source_type}'. Supported sources are 'robot' and 'affordance." + ) + taget_pose_list.append(target_pose) + + target_poses = torch.cat(taget_pose_list, dim=1) + if target_poses.shape[1] / (2 * kpnts_number + 1) != groups: + logger.log_error( + f"Exteroception groups number mismatch. Expected {groups}, but got {int(target_poses.shape[1] / (2 * kpnts_number + 1))}." + ) + + if isinstance(sensor, StereoCamera): + intrinsics, right_intrinsics = sensor.get_intrinsics() + left_arena_pose, right_arena_pose = sensor.get_left_right_arena_pose() + projected_kpnts = compute_exteroception._project_3d_to_2d( + left_arena_pose, + intrinsics, + height, + width, + target_poses, + ) + exteroception[sensor_uid]["l"] = projected_kpnts + + projected_kpnts = compute_exteroception._project_3d_to_2d( + right_arena_pose, + right_intrinsics, + height, + width, + target_poses, + ) + exteroception[sensor_uid]["r"] = projected_kpnts + else: + intrinsics = sensor.get_intrinsics() + projected_kpnts = compute_exteroception._project_3d_to_2d( + sensor.get_arena_pose(to_matrix=True), + intrinsics, + height, + width, + target_poses, + ) + exteroception[sensor_uid] = projected_kpnts + + return exteroception diff --git a/embodichain/lab/gym/envs/managers/randomization/__init__.py b/embodichain/lab/gym/envs/managers/randomization/__init__.py new file mode 100644 index 00000000..6483181f --- /dev/null +++ b/embodichain/lab/gym/envs/managers/randomization/__init__.py @@ -0,0 +1,22 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .rendering import * +from .spatial import * + +""" +Randomization are all implemented as Event functors. +""" diff --git a/embodichain/lab/gym/envs/managers/randomization/rendering.py b/embodichain/lab/gym/envs/managers/randomization/rendering.py new file mode 100644 index 00000000..7c0aed82 --- /dev/null +++ b/embodichain/lab/gym/envs/managers/randomization/rendering.py @@ -0,0 +1,469 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import torch +import os +import random +from typing import TYPE_CHECKING, Literal, Union, Optional, Dict + +from embodichain.lab.sim.objects import Light, RigidObject, Articulation +from embodichain.lab.sim.sensors import Camera, StereoCamera +from embodichain.lab.gym.envs.managers.cfg import SceneEntityCfg +from embodichain.lab.gym.envs.managers import Functor, FunctorCfg +from embodichain.lab.sim import ( + VisualMaterial, + VisualMaterialInst, + VisualMaterialCfg, +) +from embodichain.utils.string import resolve_matching_names +from embodichain.utils.math import sample_uniform +from embodichain.utils import logger +from embodichain.data import get_data_path + +if TYPE_CHECKING: + from embodichain.lab.gym.envs import EmbodiedEnv + + +__all__ = [ + "randomize_light", + "randomize_camera_intrinsics", + "randomize_visual_material", +] + + +def randomize_light( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + position_range: Optional[tuple[list[float], list[float]]] = None, + color_range: Optional[tuple[list[float], list[float]]] = None, + intensity_range: Optional[tuple[float, float]] = None, +) -> None: + """Randomize light properties by adding, scaling, or setting random values. + + This function allows randomizing light properties in the scene. The function samples random values from the + given distribution parameters and adds, scales, or sets the values into the physics simulation based on the + operation. + + The distribution parameters are lists of two elements each, representing the lower and upper bounds of the + distribution for the x, y, and z components of the light properties. The function samples random values for each + component independently. + + .. attention:: + This function applied the same light properties for all the environments. + + position_range is the x, y, z value added into light's cfg.init_pos. + color_range is the absolute r, g, b value set to the light object. + intensity_range is the value added into light's cfg.intensity. + + .. tip:: + This function uses CPU tensors to assign light properties. + + Args: + env (EmbodiedEnv): The environment instance. + env_ids (Union[torch.Tensor, None]): The environment IDs to apply the randomization. + entity_cfg (SceneEntityCfg): The configuration of the scene entity to randomize. + position_range (Optional[tuple[list[float], list[float]]]): The range for the position randomization. + color_range (Optional[tuple[list[float], list[float]]]): The range for the color randomization. + intensity_range (Optional[tuple[float, float]]): The range for the intensity randomization. + """ + + light: Light = env.sim.get_light(entity_cfg.uid) + num_instance = len(env_ids) + + if position_range: + init_pos = light.cfg.init_pos + new_pos = ( + torch.tensor(init_pos, dtype=torch.float32) + .unsqueeze_(0) + .repeat(num_instance, 1) + ) + random_value = sample_uniform( + lower=torch.tensor(position_range[0]), + upper=torch.tensor(position_range[1]), + size=new_pos.shape, + ) + new_pos += random_value + light.set_local_pose(new_pos, env_ids=env_ids) + + if color_range: + color = torch.zeros((num_instance, 3), dtype=torch.float32) + random_value = sample_uniform( + lower=torch.tensor(color_range[0]), + upper=torch.tensor(color_range[1]), + size=color.shape, + ) + color += random_value + light.set_color(color, env_ids=env_ids) + + if intensity_range: + init_intensity = light.cfg.intensity + new_intensity = ( + torch.tensor(init_intensity, dtype=torch.float32) + .unsqueeze_(0) + .repeat(num_instance, 1) + ) + random_value = sample_uniform( + lower=torch.tensor(intensity_range[0]), + upper=torch.tensor(intensity_range[1]), + size=new_intensity.shape, + ) + new_intensity += random_value + new_intensity.squeeze_(1) + light.set_intensity(new_intensity, env_ids=env_ids) + + +def randomize_camera_intrinsics( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + focal_x_range: Optional[tuple[float, float]] = None, + focal_y_range: Optional[tuple[float, float]] = None, + cx_range: Optional[tuple[float, float]] = None, + cy_range: Optional[tuple[float, float]] = None, +) -> None: + """Randomize camera intrinsic properties by adding, scaling, or setting random values. + + This function allows randomizing camera intrinsic parameters in the scene. The function samples random values + from the given distribution parameters and adds, scales, or sets the values into the physics simulation based + on the operation. + + The distribution parameters are tuples of two elements each, representing the lower and upper bounds of the + distribution for the focal length (fx, fy) and principal point (cx, cy) components of the camera intrinsics. + The function samples random values for each component independently. + + .. attention:: + This function applies the same intrinsic properties for all the environments. + + focal_x_range and focal_y_range are values added to the camera's current fx and fy values. + focal_xy_range is a combined range for both fx and fy, where the range is specified as + [[fx_min, fy_min], [fx_max, fy_max]]. + cx_range and cy_range are values added to the camera's current cx and cy values. + + .. tip:: + This function uses CPU tensors to assign camera intrinsic properties. + + Args: + env (EmbodiedEnv): The environment instance. + env_ids (Union[torch.Tensor, None]): The environment IDs to apply the randomization. + entity_cfg (SceneEntityCfg): The configuration of the scene entity to randomize. + focal_x_range (Optional[tuple[float, float]]): The range for the focal length x randomization. + focal_y_range (Optional[tuple[float, float]]): The range for the focal length y randomization. + cx_range (Optional[tuple[float, float]]): The range for the principal point x randomization. + cy_range (Optional[tuple[float, float]]): The range for the principal point y randomization. + """ + + camera: Union[Camera, StereoCamera] = env.sim.get_sensor(entity_cfg.uid) + num_instance = len(env_ids) + + # Get current intrinsics as baseline + current_intrinsics = camera.cfg.intrinsics # (fx, fy, cx, cy) + + # Create new intrinsics tensor for all instances + new_intrinsics = ( + torch.tensor(current_intrinsics, dtype=torch.float32) + .unsqueeze(0) + .repeat(num_instance, 1) + ) + + # Randomize focal length x (fx) + if focal_x_range: + random_value = sample_uniform( + lower=torch.tensor(focal_x_range[0]), + upper=torch.tensor(focal_x_range[1]), + size=(num_instance,), + ) + new_intrinsics[:, 0] += random_value + + # Randomize focal length y (fy) + if focal_y_range: + random_value = sample_uniform( + lower=torch.tensor(focal_y_range[0]), + upper=torch.tensor(focal_y_range[1]), + size=(num_instance,), + ) + new_intrinsics[:, 1] += random_value + + # Randomize principal point x (cx) + if cx_range: + random_value = sample_uniform( + lower=torch.tensor(cx_range[0]), + upper=torch.tensor(cx_range[1]), + size=(num_instance,), + ) + new_intrinsics[:, 2] += random_value + + # Randomize principal point y (cy) + if cy_range: + random_value = sample_uniform( + lower=torch.tensor(cy_range[0]), + upper=torch.tensor(cy_range[1]), + size=(num_instance,), + ) + new_intrinsics[:, 3] += random_value + + camera.set_intrinsics(new_intrinsics, env_ids=env_ids) + + +class randomize_visual_material(Functor): + """Randomize the the visual material properties of a RigidObject or an Articulation. + + Note: + 1. Currently supported randomized properties include: + - base_color: RGB color of the material. Value should be in [0, 1], shape of (3,) + - base_color_texture: Texture image for the base color of the material. + The textures will be preloaded from the given texture_path during initialization. + - metallic: Metallic property of the material. Value should be in [0, 1]. + - roughness: Roughness property of the material. Value should be in [0, 1]. + - ior: Index of Refraction of the material (only supported in ray tracing mode). + 2. The default ground plane can also be randomized by setting entity_cfg.uid to "default_plane". + """ + + def __init__(self, cfg: FunctorCfg, env: EmbodiedEnv): + """Initialize the term. + + Args: + cfg: The configuration of the functor. + env: The environment instance. + + Raises: + ValueError: If the asset is not a RigidObject or an Articulation. + """ + super().__init__(cfg, env) + + self.entity_cfg: SceneEntityCfg = cfg.params["entity_cfg"] + + # special case: default ground plane. + if self.entity_cfg.uid == "default_plane": + pass + else: + self.entity: Union[RigidObject, Articulation] = env.sim.get_asset( + self.entity_cfg.uid + ) + + if not isinstance(self.entity, (RigidObject, Articulation)): + raise ValueError( + f"Randomization functor 'randomize_visual_material' not supported for asset: '{self.entity_cfg.uid}'" + f" with type: '{type(self.entity)}'." + ) + + # TODO: Maybe need to consider two cases: + # 1. the texture folder is very large, and we don't want to load all the textures into memory. + # 2. the texture is generated on the fly. + + # Preload textures (currently only base color textures are supported) + self.textures = [] + texture_path = get_data_path(cfg.params.get("texture_path", None)) + if texture_path is not None: + from embodichain.utils.utility import read_all_folder_images + + texture_key = os.path.basename(texture_path) + # check if the texture group is already loaded in the global texture cache + if texture_key in env.sim.get_texture_cache(): + logger.log_info( + f"Texture group '{texture_key}' is already loaded in the global texture cache." + ) + self.textures = env.sim.get_texture_cache(texture_key) + else: + self.textures = read_all_folder_images(texture_path) + + # padding the texture with alpha channel if not exist + for i in range(len(self.textures)): + if self.textures[i].shape[2] == 3: + data = torch.as_tensor(self.textures[i]) + alpha_channel = ( + torch.ones( + (data.shape[0], data.shape[1], 1), dtype=data.dtype + ) + * 255 + ) + data = torch.cat((data, alpha_channel), dim=2) + self.textures[i] = data + + env.sim.set_texture_cache(texture_key, self.textures) + + if self.entity_cfg.uid == "default_plane": + pass + + else: + # TODO: we may need to get the default material instance from the asset itself. + mat: VisualMaterial = env.sim.create_visual_material( + cfg=VisualMaterialCfg( + base_color=[1.0, 1.0, 1.0, 1.0], + uid=f"{self.entity_cfg.uid}_random_mat", + ) + ) + if isinstance(self.entity, RigidObject): + self.entity.set_visual_material(mat) + elif isinstance(self.entity, Articulation): + _, link_names = resolve_matching_names( + self.entity_cfg.link_names, self.entity.link_names + ) + self.entity_cfg.link_names = link_names + self.entity.set_visual_material(mat, link_names=link_names) + + @staticmethod + def gen_random_base_color_texture(width: int, height: int) -> torch.Tensor: + """Generate a random base color texture. + + Args: + width: The width of the texture. + height: The height of the texture. + + Returns: + A torch tensor representing the random base color texture with shape (height, width, 4). + """ + # Generate random RGB values + rgb = torch.ones((height, width, 3), dtype=torch.float32) + rgb *= torch.rand((1, 1, 3), dtype=torch.float32) + rgba = torch.cat((rgb, torch.ones((height, width, 1))), dim=2) + rgba = (rgba * 255).to(torch.uint8) + return rgba + + def _randomize_texture(self, mat_inst: VisualMaterialInst) -> None: + if len(self.textures) > 0: + # Randomly select a texture from the preloaded textures + texture_idx = torch.randint(0, len(self.textures), (1,)).item() + mat_inst.set_base_color_texture(texture_data=self.textures[texture_idx]) + + def _randomize_mat_inst( + self, + mat_inst: VisualMaterialInst, + plan: Dict[str, torch.Tensor], + random_texture_prob: float, + idx: int = 0, + ) -> None: + # randomize the material instance pbr properties based on the plan. + for key, value in plan.items(): + if key == "base_color": + mat_inst.set_base_color(value[idx].tolist()) + else: + getattr(mat_inst, f"set_{key}")(value[idx].item()) + + # randomize texture or base color based on the probability. + if random_texture_prob <= 0.0 or len(self.textures) == 0: + return + if random.random() < random_texture_prob: + self._randomize_texture(mat_inst) + else: + # set a random base color instead. + random_color = torch.rand(3).tolist() + random_color.append(1.0) # alpha + mat_inst.set_base_color(random_color) + + def __call__( + self, + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + random_texture_prob: float = 0.5, + texture_path: Optional[str] = None, + base_color_range: Optional[tuple[list[float], list[float]]] = None, + metallic_range: Optional[tuple[float, float]] = None, + roughness_range: Optional[tuple[float, float]] = None, + ior_range: Optional[tuple[float, float]] = None, + ): + from embodichain.lab.sim.utility import is_rt_enabled + + # resolve environment ids + if env_ids is None: + env_ids = torch.arange(env.num_envs, device="cpu") + else: + env_ids = env_ids.cpu() + + if self.entity_cfg.uid == "default_plane": + env_ids = [0] + + randomize_plan = {} + if base_color_range: + base_color = sample_uniform( + lower=torch.tensor(base_color_range[0], dtype=torch.float32), + upper=torch.tensor(base_color_range[1], dtype=torch.float32), + size=(len(env_ids), 3), # RGB + ) + # append alpha channel + alpha_channel = torch.ones((len(env_ids), 1), dtype=torch.float32) + base_color = torch.cat((base_color, alpha_channel), dim=1) + randomize_plan["base_color"] = base_color + + if metallic_range: + metallic = sample_uniform( + lower=torch.tensor(metallic_range[0], dtype=torch.float32), + upper=torch.tensor(metallic_range[1], dtype=torch.float32), + size=(len(env_ids), 1), + ) + randomize_plan["metallic"] = metallic + + if roughness_range: + roughness = sample_uniform( + lower=torch.tensor(roughness_range[0], dtype=torch.float32), + upper=torch.tensor(roughness_range[1], dtype=torch.float32), + size=(len(env_ids), 1), + ) + randomize_plan["roughness"] = roughness + + if ior_range and is_rt_enabled(): + ior = sample_uniform( + lower=torch.tensor(ior_range[0], dtype=torch.float32), + upper=torch.tensor(ior_range[1], dtype=torch.float32), + size=(len(env_ids), 1), + ) + randomize_plan["ior"] = ior + + # ground plane only has one instance. + mat_insts = None + if self.entity_cfg.uid == "default_plane": + mat_inst = env.sim.get_visual_material("plane_mat").get_default_instance() + self._randomize_mat_inst( + mat_inst=mat_inst, + plan=randomize_plan, + random_texture_prob=random_texture_prob, + idx=0, + ) + return + elif isinstance(self.entity, RigidObject): + mat_insts = self.entity.get_visual_material_inst(env_ids=env_ids) + elif isinstance(self.entity, Articulation): + mat_insts = self.entity.get_visual_material_inst( + env_ids=env_ids, + link_names=self.entity_cfg.link_names, + ) + + for i, data in enumerate(mat_insts): + if isinstance(self.entity, RigidObject): + # For RigidObject, data is the material instance directly + mat: VisualMaterialInst = data + elif isinstance(self.entity, Articulation): + # For Articulation, data is the key-value pair of link name and material instance + mat: Dict[str, VisualMaterialInst] = data + + if isinstance(self.entity, RigidObject): + self._randomize_mat_inst( + mat_inst=mat, + plan=randomize_plan, + random_texture_prob=random_texture_prob, + idx=i, + ) + else: + for name, mat_inst in mat.items(): + self._randomize_mat_inst( + mat_inst=mat_inst, + plan=randomize_plan, + random_texture_prob=random_texture_prob, + idx=i, + ) diff --git a/embodichain/lab/gym/envs/managers/randomization/spatial.py b/embodichain/lab/gym/envs/managers/randomization/spatial.py new file mode 100644 index 00000000..70bcabe8 --- /dev/null +++ b/embodichain/lab/gym/envs/managers/randomization/spatial.py @@ -0,0 +1,261 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import torch +from typing import TYPE_CHECKING, Literal, Union, Optional, List + +from embodichain.lab.sim.objects import RigidObject, Robot +from embodichain.lab.gym.envs.managers.cfg import SceneEntityCfg +from embodichain.utils.math import sample_uniform, matrix_from_euler +from embodichain.utils import logger + + +if TYPE_CHECKING: + from embodichain.lab.gym.envs import EmbodiedEnv + + +def get_random_pose( + init_pos: torch.Tensor, + init_rot: torch.Tensor, + position_range: Optional[tuple[list[float], list[float]]] = None, + rotation_range: Optional[tuple[list[float], list[float]]] = None, + relative_position: bool = True, + relative_rotation: bool = False, +) -> torch.Tensor: + """Generate a random pose based on the initial position and rotation. + + Args: + init_pos (torch.Tensor): The initial position tensor of shape (num_instance, 3). + init_rot (torch.Tensor): The initial rotation tensor of shape (num_instance, 3, 3). + position_range (Optional[tuple[list[float], list[float]]]): The range for the position randomization. + rotation_range (Optional[tuple[list[float], list[float]]]): The range for the rotation randomization. + The rotation is represented as Euler angles (roll, pitch, yaw) in degree. + relative_position (bool): Whether to randomize the position relative to the initial position. Default is True. + relative_rotation (bool): Whether to randomize the rotation relative to the initial rotation. Default is False. + + Returns: + torch.Tensor: The generated random pose tensor of shape (num_instance, 4, 4). + """ + + num_instance = init_pos.shape[0] + pose = ( + torch.eye(4, dtype=torch.float32, device=init_pos.device) + .unsqueeze_(0) + .repeat(num_instance, 1, 1) + ) + pose[:, :3, :3] = init_rot + pose[:, :3, 3] = init_pos + + if position_range: + + pos_low = torch.tensor(position_range[0], device=init_pos.device) + pos_high = torch.tensor(position_range[1], device=init_pos.device) + + random_value = sample_uniform( + lower=pos_low, + upper=pos_high, + size=(num_instance, 3), + ) + if relative_position: + random_value += init_pos + + pose[:, :3, 3] = random_value + + if rotation_range: + + rot_low = torch.tensor(rotation_range[0], device=init_pos.device) + rot_high = torch.tensor(rotation_range[1], device=init_pos.device) + + random_value = ( + sample_uniform( + lower=rot_low, + upper=rot_high, + size=(num_instance, 3), + ) + * torch.pi + / 180.0 + ) + rot = matrix_from_euler(random_value) + + if relative_rotation: + rot = torch.bmm(init_rot, rot) + pose[:, :3, :3] = rot + + return pose + + +def randomize_rigid_object_pose( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + position_range: Optional[tuple[list[float], list[float]]] = None, + rotation_range: Optional[tuple[list[float], list[float]]] = None, + relative_position: bool = True, + relative_rotation: bool = False, +) -> None: + """Randomize the pose of a rigid object in the environment. + + Args: + env (EmbodiedEnv): The environment instance. + env_ids (Union[torch.Tensor, None]): The environment IDs to apply the randomization. + entity_cfg (SceneEntityCfg): The configuration of the scene entity to randomize. + position_range (Optional[tuple[list[float], list[float]]]): The range for the position randomization. + rotation_range (Optional[tuple[list[float], list[float]]]): The range for the rotation randomization. + The rotation is represented as Euler angles (roll, pitch, yaw) in degree. + relative_position (bool): Whether to randomize the position relative to the object's initial position. Default is True. + relative_rotation (bool): Whether to randomize the rotation relative to the object's initial rotation. Default is False. + """ + + rigid_object: RigidObject = env.sim.get_rigid_object(entity_cfg.uid) + num_instance = len(env_ids) + + init_pos = ( + torch.tensor(rigid_object.cfg.init_pos, dtype=torch.float32, device=env.device) + .unsqueeze_(0) + .repeat(num_instance, 1) + ) + init_rot = ( + torch.tensor(rigid_object.cfg.init_rot, dtype=torch.float32, device=env.device) + * torch.pi + / 180.0 + ) + init_rot = init_rot.unsqueeze_(0).repeat(num_instance, 1) + init_rot = matrix_from_euler(init_rot) + + pose = get_random_pose( + init_pos=init_pos, + init_rot=init_rot, + position_range=position_range, + rotation_range=rotation_range, + relative_position=relative_position, + relative_rotation=relative_rotation, + ) + + rigid_object.set_local_pose(pose, env_ids=env_ids) + rigid_object.clear_dynamics() + + +def randomize_robot_eef_pose( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + position_range: Optional[tuple[list[float], list[float]]] = None, + rotation_range: Optional[tuple[list[float], list[float]]] = None, +) -> None: + """Randomize the initial end-effector pose of a robot in the environment. + + Note: + - The position and rotation are performed randomization in a relative manner. + - The current state of eef pose is computed based on the current joint positions of the robot. + + Args: + env (EmbodiedEnv): The environment instance. + env_ids (Union[torch.Tensor, None]): The environment IDs to apply the randomization. + robot_name (str): The name of the robot. + entity_cfg (SceneEntityCfg): The configuration of the scene entity to randomize. + position_range (Optional[tuple[list[float], list[float]]]): The range for the position randomization. + rotation_range (Optional[tuple[list[float], list[float]]]): The range for the rotation randomization. + The rotation is represented as Euler angles (roll, pitch, yaw) in degree. + """ + + def set_random_eef_pose(joint_ids: List[int], robot: Robot) -> None: + current_qpos = robot.get_qpos()[env_ids][:, joint_ids] + if current_qpos.dim() == 1: + current_qpos = current_qpos.unsqueeze_(0) + + current_eef_pose = robot.compute_fk( + name=part, qpos=current_qpos, to_matrix=True + ) + + new_eef_pose = get_random_pose( + init_pos=current_eef_pose[:, :3, 3], + init_rot=current_eef_pose[:, :3, :3], + position_range=position_range, + rotation_range=rotation_range, + relative_position=True, + relative_rotation=True, + ) + + ret, new_qpos = robot.compute_ik( + pose=new_eef_pose, name=part, joint_seed=current_qpos + ) + + new_qpos[ret == False] = current_qpos[ret == False] + robot.set_qpos(new_qpos, env_ids=env_ids, joint_ids=joint_ids) + + robot = env.sim.get_robot(entity_cfg.uid) + + control_parts = entity_cfg.control_parts + if control_parts is None: + joint_ids = robot.get_joint_ids() + set_random_eef_pose(joint_ids, robot) + else: + for part in control_parts: + joint_ids = robot.get_joint_ids(part) + set_random_eef_pose(joint_ids, robot) + + # simulate 10 steps to let the robot reach the target pose. + env.sim.update(step=10) + + +def randomize_robot_qpos( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + qpos_range: Optional[tuple[list[float], list[float]]] = None, + relative_qpos: bool = True, + joint_ids: Optional[List[int]] = None, +) -> None: + """Randomize the initial joint positions of a robot in the environment. + + Args: + env (EmbodiedEnv): The environment instance. + env_ids (Union[torch.Tensor, None]): The environment IDs to apply the randomization. + entity_cfg (SceneEntityCfg): The configuration of the scene entity to randomize. + qpos_range (Optional[tuple[list[float], list[float]]]): The range for the joint position randomization. + relative_qpos (bool): Whether to randomize the joint positions relative to the current joint positions. Default is True. + joint_ids (Optional[List[int]]): The list of joint IDs to randomize. If None, all joints will be randomized. + """ + if qpos_range is None: + return + + num_instance = len(env_ids) + + robot = env.sim.get_robot(entity_cfg.uid) + + if joint_ids is None: + if len(qpos_range[0]) != robot.dof: + logger.log_error( + f"The length of qpos_range {len(qpos_range[0])} does not match the robot dof {robot.dof}." + ) + joint_ids = robot.get_joint_ids() + + qpos = sample_uniform( + lower=torch.tensor(qpos_range[0], device=env.device), + upper=torch.tensor(qpos_range[1], device=env.device), + size=(num_instance, len(joint_ids)), + ) + + if relative_qpos: + current_qpos = robot.get_qpos()[env_ids][:, joint_ids] + current_qpos += qpos + else: + current_qpos = qpos + + robot.set_qpos(qpos=current_qpos, env_ids=env_ids, joint_ids=joint_ids) + env.sim.update(step=100) diff --git a/embodichain/lab/gym/envs/managers/record.py b/embodichain/lab/gym/envs/managers/record.py new file mode 100644 index 00000000..157064a7 --- /dev/null +++ b/embodichain/lab/gym/envs/managers/record.py @@ -0,0 +1,237 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import torch +import os +import random +import numpy as np +from typing import TYPE_CHECKING, Literal, Union, List + +from dexsim.utility import images_to_video +from embodichain.lab.gym.envs.managers import Functor, FunctorCfg +from embodichain.lab.sim.sensors.camera import CameraCfg + +if TYPE_CHECKING: + from embodichain.lab.gym.envs import EmbodiedEnv + + +class record_camera_data(Functor): + """Record camera data in the environment. The camera is usually setup with third-person view, and + is used to record the scene during the episode. It is helpful for debugging and visualization. + + Note: + Currently, the functor is implemented in `interval' mode such that, it can only save the + recorded frames when in :meth:`env.step()` function call. For example: + ```python + env.step() + # perform multiple steps in the same episode + env.reset() + env.step() # the video of the first episode will be saved here. + ``` + The final episode frames will not be saved in the current implementation. + We may improve it in the future. + """ + + def __init__(self, cfg: FunctorCfg, env: EmbodiedEnv): + """Initialize the functor. + + Args: + cfg: The configuration of the functor. + env: The environment instance. + + Raises: + ValueError: If the asset is not a RigidObject or an Articulation. + """ + super().__init__(cfg, env) + + # extract the used quantities (to enable type-hinting) + self._name = cfg.params.get("name", "default") + resolution = cfg.params.get("resolution", (640, 480)) + eye = cfg.params.get("eye", (0, 0, 2)) + target = cfg.params.get("target", (0, 0, 0)) + up = cfg.params.get("up", (0, 0, 1)) + intrinsics = cfg.params.get( + "intrinsics", (600, 600, int(resolution[0] / 2), int(resolution[1] / 2)) + ) + + self.camera = env.sim.add_sensor( + sensor_cfg=CameraCfg( + uid=self._name, + width=resolution[0], + height=resolution[1], + extrinsics=CameraCfg.ExtrinsicsCfg(eye=eye, target=target, up=up), + intrinsics=intrinsics, + ) + ) + + self._current_episode = 0 + self._frames: List[np.ndarray] = [] + + def _draw_frames_into_one_image(self, frames: torch.Tensor) -> torch.Tensor: + """ + Concatenate multiple frames into a single image with nearly square arrangement. + + Args: + frames: Tensor with shape (B, H, W, 4) where B is batch size + + Returns: + Single concatenated image tensor with shape (grid_h * H, grid_w * W, 4) + """ + if frames.numel() == 0: + return frames + + B, H, W, C = frames.shape + + # Calculate grid dimensions for nearly square arrangement + grid_w = int(torch.ceil(torch.sqrt(torch.tensor(B, dtype=torch.float32)))) + grid_h = int(torch.ceil(torch.tensor(B, dtype=torch.float32) / grid_w)) + + # Create empty grid to hold all frames + result = torch.zeros( + (grid_h * H, grid_w * W, C), dtype=frames.dtype, device=frames.device + ) + + # Fill the grid with frames + for i in range(B): + row = i // grid_w + col = i % grid_w + + start_h = row * H + end_h = start_h + H + start_w = col * W + end_w = start_w + W + + result[start_h:end_h, start_w:end_w] = frames[i] + + return result + + def __call__( + self, + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + name: str, + resolution: tuple[int, int] = (640, 480), + eye: tuple[float, float, float] = (0, 0, 2), + target: tuple[float, float, float] = (0, 0, 0), + up: tuple[float, float, float] = (0, 0, 1), + intrinsics: tuple[float, float, float, float] = ( + 600, + 600, + 320, + 240, + ), + max_env_num: int = 16, + save_path: str = "./outputs/videos", + ): + # TODO: the current implementation will lost the final episode frames recording. + # Check if the frames should be saved for the current episode + if env.elapsed_steps.sum().item() == len(env_ids) and len(self._frames) > 0: + video_name = f"episode_{self._current_episode}_{self._name}" + images_to_video(self._frames, save_path, video_name, fps=20) + + self._current_episode += 1 + self._frames = [] + + self.camera.update(fetch_only=self.camera.is_rt_enabled) + data = self.camera.get_data() + rgb = data["color"] + + num_frames = max(rgb.shape[0], max_env_num) + rgb = rgb[:num_frames] + rgb = self._draw_frames_into_one_image(rgb)[..., :3].cpu().numpy() + self._frames.append(rgb) + + +class record_camera_data_async(record_camera_data): + """Record camera data for multiple environments, merge and save as a single video at episode end.""" + + def __init__(self, cfg: FunctorCfg, env: EmbodiedEnv): + super().__init__(cfg, env) + self._num_envs = min(4, getattr(env, "num_envs", 1)) + self._frames_list = [[] for _ in range(self._num_envs)] + self._ep_idx = [0 for _ in range(self._num_envs)] + + def __call__( + self, + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + name: str, + resolution: tuple[int, int] = (640, 480), + eye: tuple[float, float, float] = (0, 0, 2), + target: tuple[float, float, float] = (0, 0, 0), + up: tuple[float, float, float] = (0, 0, 1), + intrinsics: tuple[float, float, float, float] = ( + 600, + 600, + 320, + 240, + ), + max_env_num: int = 16, + save_path: str = "./outputs/videos", + ): + self.camera.update(fetch_only=self.camera.is_rt_enabled) + data = self.camera.get_data() + rgb = data["color"] # shape: (num_envs, H, W, 4) + if isinstance(rgb, torch.Tensor): + rgb_np = rgb.cpu().numpy() + else: + rgb_np = rgb + # Only collect frames for the first 4 environments + for i in range(self._num_envs): + self._frames_list[i].append(rgb_np[i][..., :]) + + # Check if elapsed_steps==1 (just reset) + elapsed = env.elapsed_steps + if isinstance(elapsed, torch.Tensor): + elapsed_np = elapsed.cpu().numpy() + else: + elapsed_np = elapsed + # Only check reset for the first 4 environments + ready_envs = [ + i + for i in range(self._num_envs) + if elapsed_np[i] == 1 and len(self._frames_list[i]) > 1 + ] + # Used to temporarily store episode frames for each env + if not hasattr(self, "_pending_env_episodes"): + self._pending_env_episodes = {} + for i in ready_envs: + if i not in self._pending_env_episodes: + self._pending_env_episodes[i] = self._frames_list[i][:-1] + self._frames_list[i] = [ + self._frames_list[i][-1] + ] # Only keep the first frame after reset + self._ep_idx[i] += 1 + # If all specified envs have collected frames, concatenate and save + if len(self._pending_env_episodes) == self._num_envs: + min_len = min(len(frames) for frames in self._pending_env_episodes.values()) + big_frames = [] + for j in range(min_len): + frames = [ + self._pending_env_episodes[i][j] for i in range(self._num_envs) + ] + frames_tensor = torch.from_numpy(np.stack(frames)).to(torch.uint8) + big_frame = ( + self._draw_frames_into_one_image(frames_tensor)[..., :3] + .cpu() + .numpy() + ) + big_frames.append(big_frame) + video_name = f"ep{self._ep_idx[0]-1}_{self._name}_allenvs" + images_to_video(big_frames, save_path, video_name, fps=20) + self._pending_env_episodes.clear() diff --git a/embodichain/lab/gym/envs/object/__init__.py b/embodichain/lab/gym/envs/object/__init__.py new file mode 100644 index 00000000..851d86e2 --- /dev/null +++ b/embodichain/lab/gym/envs/object/__init__.py @@ -0,0 +1,17 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .geometry import * diff --git a/embodichain/lab/gym/envs/object/geometry.py b/embodichain/lab/gym/envs/object/geometry.py new file mode 100644 index 00000000..b95faf3c --- /dev/null +++ b/embodichain/lab/gym/envs/object/geometry.py @@ -0,0 +1,138 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np +import open3d as o3d + +from typing import Union + +from dexsim.models import MeshObject +from embodichain.utils import logger +from embodichain.lab.sim.objects import RigidObject +from embodichain.lab.gym.envs.managers.cfg import SceneEntityCfg +from embodichain.utils.utility import inv_transform + + +def get_pc_svd_frame(pc: Union[np.ndarray, torch.Tensor]) -> np.ndarray: + """ + Computes the pose of a point cloud using Singular Value Decomposition (SVD). + + This function centers the point cloud, performs SVD to obtain the rotation, + and constructs a 4x4 transformation matrix representing the pose of the point cloud. + + Args: + pc (np.ndarray): A 2D numpy array of shape (N, 3) representing the point cloud, + where N is the number of points. + + Returns: + np.ndarray: A 4x4 transformation matrix that includes the rotation and translation + of the point cloud. + """ + if pc.ndim != 2: + logger.log_error( + f"get_pc_svd_frame only support the pc of 1 object, which means that pc.ndim==2, but got {pc.ndim}" + ) + pc_center = pc.mean(axis=0) + pc_centered = pc - pc_center + u, s, vt = torch.linalg.svd(pc_centered) + rotation = vt.T + pc_pose = torch.eye(4, dtype=torch.float32) + pc_pose[:3, :3] = rotation + pc_pose[:3, 3] = pc_center + return pc_pose + + +def apply_svd_transfer_pc( + geometry: Union[ + np.ndarray, + torch.Tensor, + o3d.cuda.pybind.geometry.TriangleMesh, + MeshObject, + RigidObject, + ], + sample_points: int = 1000, +) -> np.ndarray: + """ + Applies Singular Value Decomposition (SVD) transfer to a point cloud represented by geometry. + + Parameters: + geometry (Union[np.ndarray, MeshObject]): The input geometry, which can be a NumPy array of vertices + or a MeshObject containing vertex data. + sample_points (int): The number of sample points to consider (default is 1000). + + Returns: + np.ndarray: The transformed vertices in standard position after applying SVD. + """ + if isinstance(geometry, (RigidObject, MeshObject)): + verts = torch.as_tensor(geometry.get_vertices()) + elif isinstance(geometry, (np.ndarray, torch.Tensor)): + verts = torch.as_tensor(geometry) + elif isinstance(geometry, o3d.cuda.pybind.geometry.TriangleMesh): + verts = torch.as_tensor(geometry.vertices) + else: + logger.log_error( + f"Unsupported geometry type: {type(geometry)}. Expected np.ndarray, torch.Tensor, MeshObject, or RigidObject." + ) + + if verts.ndim < 3: + verts = verts[None] + + sample_ids = ( + np.random.choice(verts.shape[1], sample_points) + if isinstance(verts, np.ndarray) + else torch.randint(0, verts.shape[1], (sample_points,)) + ) + verts = verts[:, sample_ids, :] + + standard_verts = [] + for object_verts in verts: + pc_svd_frame = get_pc_svd_frame(object_verts) + inv_svd_frame = inv_transform(pc_svd_frame) + standard_object_verts = ( + object_verts @ inv_svd_frame[:3, :3].T + inv_svd_frame[:3, 3] + ) + standard_verts.append(standard_object_verts) + + return torch.stack(standard_verts) + + +def compute_object_length( + env, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + sample_points: int, + is_svd_frame: bool = True, +): + rigid_object: RigidObject = env.sim.get_rigid_object(entity_cfg.uid) + object_lengths = {} + for axis in ["x", "y", "z"]: + object_lengths.update( + {axis: torch.zeros((env.num_envs,), dtype=torch.float32, device=env.device)} + ) + pcs = rigid_object.get_vertices(env_ids) + body_scale = rigid_object.get_body_scale(env_ids) + scaled_pcs = pcs * body_scale + + if is_svd_frame: + scaled_pcs = apply_svd_transfer_pc(scaled_pcs, sample_points) + + for axis, idx in zip(["x", "y", "z"], [0, 1, 2]): + scaled_pos = scaled_pcs[..., idx] # (num_envs, sample_points) + length = scaled_pos.max(dim=1)[0] - scaled_pos.min(dim=1)[0] + object_lengths.update({axis: length}) + + return object_lengths diff --git a/embodichain/lab/gym/envs/rl_env_cfg.py b/embodichain/lab/gym/envs/rl_env_cfg.py new file mode 100644 index 00000000..34448747 --- /dev/null +++ b/embodichain/lab/gym/envs/rl_env_cfg.py @@ -0,0 +1,33 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from typing import Any, Dict + +from embodichain.lab.gym.envs.embodied_env import EmbodiedEnvCfg +from embodichain.utils import configclass + + +@configclass +class RLEnvCfg(EmbodiedEnvCfg): + """Extended configuration for RL environments built from gym-style specs.""" + + env_id: str = "" + extensions: Dict[str, Any] = {} + + @classmethod + def from_dict(cls, d): + """Create an instance from a dictionary.""" + return cls(**d) diff --git a/embodichain/lab/gym/envs/tasks/rl/__init__.py b/embodichain/lab/gym/envs/tasks/rl/__init__.py new file mode 100644 index 00000000..f8cf3031 --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/rl/__init__.py @@ -0,0 +1,32 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +from copy import deepcopy +from embodichain.lab.gym.utils import registration as env_registry +from embodichain.lab.gym.envs.rl_env_cfg import RLEnvCfg + + +def build_env(env_id: str, base_env_cfg: RLEnvCfg): + """Create env from registry id, auto-inferring cfg class (EnvName -> EnvNameCfg).""" + env = env_registry.make(env_id, cfg=deepcopy(base_env_cfg)) + return env + + +__all__ = [ + "build_env", +] diff --git a/embodichain/lab/gym/envs/tasks/rl/push_cube.py b/embodichain/lab/gym/envs/tasks/rl/push_cube.py new file mode 100644 index 00000000..412877e7 --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/rl/push_cube.py @@ -0,0 +1,227 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np +from typing import Dict, Any, Optional, Sequence +from gymnasium import spaces + +from embodichain.lab.gym.utils.registration import register_env +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.sim.cfg import MarkerCfg +from embodichain.lab.sim.types import EnvObs, EnvAction +from embodichain.utils import logger + + +@register_env("PushCubeRL", max_episode_steps=50, override=True) +class PushCubeEnv(EmbodiedEnv): + """Push cube task for reinforcement learning. + + The task involves pushing a cube to a target goal position using a robotic arm. + The reward consists of reaching reward, placing reward, action penalty, and success bonus. + """ + + def __init__(self, cfg=None, **kwargs): + if cfg is None: + cfg = EmbodiedEnvCfg() + + extensions = getattr(cfg, "extensions", {}) or {} + + # cfg.sim_cfg.enable_rt = True + + defaults = { + "success_threshold": 0.1, + "reaching_reward_weight": 0.1, + "place_reward_weight": 2.0, + "place_penalty_weight": 0.5, + "action_penalty_weight": 0.01, + "success_bonus_weight": 10.0, + } + for name, default in defaults.items(): + value = extensions.get(name, getattr(cfg, name, default)) + setattr(cfg, name, value) + setattr(self, name, getattr(cfg, name)) + + self.last_cube_goal_dist = None + + super().__init__(cfg, **kwargs) + + def _draw_goal_marker(self): + """Draw axis marker at goal position for visualization.""" + goal_sphere = self.sim.get_rigid_object("goal_sphere") + if goal_sphere is None: + return + + num_envs = self.cfg.num_envs + + # Get actual goal positions from each arena + goal_poses = goal_sphere.get_local_pose(to_matrix=True) # (num_envs, 4, 4) + + # Draw marker for each arena separately + for arena_idx in range(num_envs): + marker_name = f"goal_marker_{arena_idx}" + + self.sim.remove_marker(marker_name) + + goal_pose = goal_poses[arena_idx].detach().cpu().numpy() + marker_cfg = MarkerCfg( + name=marker_name, + marker_type="axis", + axis_xpos=[goal_pose], + axis_size=0.003, + axis_len=0.02, + arena_index=arena_idx, + ) + self.sim.draw_marker(cfg=marker_cfg) + + def _init_sim_state(self, **kwargs): + super()._init_sim_state(**kwargs) + self.single_action_space = spaces.Box( + low=-self.joint_limits, + high=self.joint_limits, + shape=(6,), + dtype=np.float32, + ) + if self.obs_mode == "state": + self.single_observation_space = spaces.Box( + low=-np.inf, high=np.inf, shape=(15,), dtype=np.float32 + ) + + def _initialize_episode( + self, env_ids: Optional[Sequence[int]] = None, **kwargs + ) -> None: + super()._initialize_episode(env_ids=env_ids, **kwargs) + cube = self.sim.get_rigid_object("cube") + + # Calculate previous distance (for incremental reward) based on current (possibly randomized) pose + cube_pos = cube.body_data.pose[:, :3] + goal_sphere = self.sim.get_rigid_object("goal_sphere") + goal_pos = goal_sphere.body_data.pose[ + :, :3 + ] # Get actual goal positions for each environment + self.last_cube_goal_dist = torch.norm(cube_pos[:, :2] - goal_pos[:, :2], dim=1) + + # Draw marker at goal position + # self._draw_goal_marker() + + def _step_action(self, action: EnvAction) -> EnvAction: + scaled_action = action * self.action_scale + scaled_action = torch.clamp( + scaled_action, -self.joint_limits, self.joint_limits + ) + current_qpos = self.robot.body_data.qpos + target_qpos = current_qpos.clone() + target_qpos[:, :6] += scaled_action[:, :6] + self.robot.set_qpos(qpos=target_qpos) + return scaled_action + + def get_obs(self, **kwargs) -> EnvObs: + qpos_all = self.robot.body_data.qpos[:, :6] + ee_pose_matrix = self.robot.compute_fk( + name="arm", qpos=qpos_all, to_matrix=True + ) + ee_pos_all = ee_pose_matrix[:, :3, 3] + cube = self.sim.get_rigid_object("cube") + cube_pos_all = cube.body_data.pose[:, :3] + # Get actual goal positions for each environment + goal_sphere = self.sim.get_rigid_object("goal_sphere") + goal_pos_all = goal_sphere.body_data.pose[:, :3] + if self.obs_mode == "state": + return torch.cat([qpos_all, ee_pos_all, cube_pos_all, goal_pos_all], dim=1) + return { + "robot": {"qpos": qpos_all, "ee_pos": ee_pos_all}, + "object": {"cube_pos": cube_pos_all, "goal_pos": goal_pos_all}, + } + + def get_reward( + self, obs: EnvObs, action: EnvAction, info: Dict[str, Any] + ) -> torch.Tensor: + if self.obs_mode == "state": + ee_pos = obs[:, 6:9] + cube_pos = obs[:, 9:12] + goal_pos = obs[:, 12:15] + else: + ee_pos = obs["robot"]["ee_pos"] + cube_pos = obs["object"]["cube_pos"] + goal_pos = obs["object"]["goal_pos"] + push_direction = goal_pos - cube_pos + push_dir_norm = torch.norm(push_direction, dim=1, keepdim=True) + 1e-6 + push_dir_normalized = push_direction / push_dir_norm + push_pose = ( + cube_pos + - 0.015 * push_dir_normalized + + torch.tensor([0, 0, 0.015], device=self.device, dtype=torch.float32) + ) + ee_to_push_dist = torch.norm(ee_pos - push_pose, dim=1) + reaching_reward_raw = 1.0 - torch.tanh(5.0 * ee_to_push_dist) + reaching_reward = self.reaching_reward_weight * reaching_reward_raw + cube_to_goal_dist = torch.norm(cube_pos[:, :2] - goal_pos[:, :2], dim=1) + distance_delta = 10.0 * (self.last_cube_goal_dist - cube_to_goal_dist) + distance_delta_normalized = torch.tanh(distance_delta) + place_reward = torch.where( + distance_delta_normalized >= 0, + self.place_reward_weight * distance_delta_normalized, + self.place_penalty_weight * distance_delta_normalized, + ) + self.last_cube_goal_dist = cube_to_goal_dist + action_magnitude = torch.norm(action, dim=1) + action_penalty = -self.action_penalty_weight * action_magnitude + success_bonus_raw = info["success"].float() + success_bonus = self.success_bonus_weight * success_bonus_raw + reward = reaching_reward + place_reward + action_penalty + success_bonus + # Organize reward components in a dedicated "rewards" dict + # This allows trainer to easily identify and log reward components + if "rewards" not in info: + info["rewards"] = {} + info["rewards"]["reaching_reward"] = reaching_reward + info["rewards"]["place_reward"] = place_reward + info["rewards"]["action_penalty"] = action_penalty + info["rewards"]["success_bonus"] = success_bonus + return reward + + def get_info(self, **kwargs) -> Dict[str, Any]: + cube = self.sim.get_rigid_object("cube") + cube_pos = cube.body_data.pose[:, :3] + # Get actual goal positions for each environment + goal_sphere = self.sim.get_rigid_object("goal_sphere") + goal_pos = goal_sphere.body_data.pose[:, :3] + xy_distance = torch.norm(cube_pos[:, :2] - goal_pos[:, :2], dim=1) + is_success = xy_distance < self.success_threshold + info = { + "success": is_success, + "fail": torch.zeros( + self.cfg.num_envs, device=self.device, dtype=torch.bool + ), + "elapsed_steps": self._elapsed_steps, + } + info["metrics"] = { + "distance_to_goal": xy_distance, + } + return info + + def check_truncated(self, obs: EnvObs, info: Dict[str, Any]) -> torch.Tensor: + is_timeout = self._elapsed_steps >= self.episode_length + cube = self.sim.get_rigid_object("cube") + cube_pos = cube.body_data.pose[:, :3] + is_fallen = cube_pos[:, 2] < -0.1 + return is_timeout | is_fallen + + def evaluate(self, **kwargs) -> Dict[str, Any]: + info = self.get_info(**kwargs) + return { + "success": info["success"][0].item(), + "distance_to_goal": info["distance_to_goal"], + } diff --git a/embodichain/lab/gym/envs/tasks/tableware/__init__.py b/embodichain/lab/gym/envs/tasks/tableware/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/embodichain/lab/gym/envs/tasks/tableware/pour_water/__init__.py b/embodichain/lab/gym/envs/tasks/tableware/pour_water/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/embodichain/lab/gym/envs/tasks/tableware/pour_water/action_bank.py b/embodichain/lab/gym/envs/tasks/tableware/pour_water/action_bank.py new file mode 100644 index 00000000..8938aeb6 --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/pour_water/action_bank.py @@ -0,0 +1,233 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np +from copy import deepcopy +from typing import Dict, Tuple, Union, List, Any, Optional, Callable +from embodichain.lab.gym.envs.action_bank.configurable_action import ( + ActionBank, + tag_node, + tag_edge, +) + +from embodichain.lab.gym.utils.misc import ( + resolve_env_params, + mul_linear_expand, + get_offset_pose_list, + get_changed_pose, +) + +from embodichain.lab.sim.planners.motion_generator import MotionGenerator +from embodichain.utils import logger + + +__all__ = ["PourWaterActionBank"] + + +class PourWaterActionBank(ActionBank): + @staticmethod + @tag_node + @resolve_env_params + def generate_left_arm_aim_qpos( + env, + valid_funcs_name_kwargs_proc: Optional[List] = None, + ): + # FIXME FIXME FIXME FIXME + logger.log_warning( + f"CAUTION=============================THIS FUNC generate_left_arm_aim_qpos IS WRONG!!!! PLEASE FIX IT!!!!" + ) + left_aim_horizontal_angle = np.arctan2( + *( + ( + env.affordance_datas["cup_pose"][:2, 3] + - env.affordance_datas["left_arm_base_pose"][:2, 3] + )[1::-1] + ) + ) + left_arm_aim_qpos = deepcopy(env.affordance_datas["left_arm_init_qpos"]) + left_arm_aim_qpos[0] = left_aim_horizontal_angle + env.affordance_datas["left_arm_aim_qpos"] = left_arm_aim_qpos + return True + + @staticmethod + @tag_node + @resolve_env_params + # DONE: valid & process qpos & fk + def generate_right_arm_aim_qpos( + env, + valid_funcs_name_kwargs_proc: Optional[List] = None, + ): + # FIXME FIXME FIXME FIXME + logger.log_warning( + f"CAUTION=============================THIS FUNC generate_right_arm_aim_qpos IS WRONG!!!! PLEASE FIX IT!!!!" + ) + right_aim_horizontal_angle = np.arctan2( + *( + ( + env.affordance_datas["bottle_pose"][:2, 3] + - env.affordance_datas["right_arm_base_pose"][:2, 3] + )[1::-1] + ) + ) + right_arm_aim_qpos = deepcopy(env.affordance_datas["right_arm_init_qpos"]) + right_arm_aim_qpos[0] = right_aim_horizontal_angle + env.affordance_datas["right_arm_aim_qpos"] = right_arm_aim_qpos + return True + + @staticmethod + @tag_node + @resolve_env_params + def compute_unoffset_for_exp(env, pose_input_output_names_changes: Dict = {}): + env.affordance_datas["bottle_grasp_unoffset_matrix_object"] = np.eye( + 4 + ) # For the overall transform matrix calculation + for input_pose_name, change_params in pose_input_output_names_changes.items(): + output_pose_name = change_params["output_pose_name"] + pose_changes = change_params["pose_changes"] + env.affordance_datas[output_pose_name] = get_changed_pose( + env.affordance_datas[input_pose_name], pose_changes + ) + + return True + + @staticmethod + @tag_edge + @tag_node + # TODO: Got the dimension from the scope + def execute_open(env, return_action: bool = False, **kwargs): + if return_action: + duration = kwargs.get("duration", 1) + expand = kwargs.get("expand", False) + if expand: + action = mul_linear_expand(np.array([[0.0], [1.0]]), [duration - 1]) + action = np.concatenate([action, np.array([[1.0]])]).transpose() + else: + action = np.ones((1, duration)) + return action + else: + return True + + @staticmethod + @tag_edge + @tag_node + def execute_close(env, return_action: bool = False, **kwargs): + + if return_action: + duration = kwargs.get("duration", 1) + expand = kwargs.get("expand", False) + if expand: + action = mul_linear_expand(np.array([[1.0], [0.0]]), [duration - 1]) + action = np.concatenate([action, np.array([[0.0]])]).transpose() + else: + action = np.zeros((1, duration)) + return action + else: + return True + + @staticmethod + @tag_edge + def plan_trajectory( + env, + agent_uid: str, + keypose_names: List[str], + duration: int, + edge_name: str = "", + ): + keyposes = [ + env.affordance_datas[keypose_name] for keypose_name in keypose_names + ] + + keyposes = [ + kp.cpu().numpy() if hasattr(kp, "cpu") and hasattr(kp, "numpy") else kp + for kp in keyposes + ] + + if all( + np.linalg.norm(former - latter).sum() <= 1e-3 + for former, latter in zip(keyposes, keyposes[1:]) + ): + logger.log_warning( + f"Applying plan_trajectory to two very close qpos! Using stand_still." + ) + keyposes = [keyposes[0]] * 2 + ret_transposed = PourWaterActionBank.stand_still( + env, + agent_uid, + keypose_names, + duration, + ) + + return ret_transposed + + else: + mo_gen = MotionGenerator(robot=env.robot, uid=agent_uid) + ret, _ = mo_gen.create_discrete_trajectory( + qpos_list=keyposes, + sample_num=duration, + qpos_seed=keyposes[0], + is_use_current_qpos=False, + ) + + return ret.T + + @staticmethod + @tag_edge + def stand_still( + env, + agent_uid: str, + keypose_names: List[str], + duration: int, + ): + keyposes = [ + env.affordance_datas[keypose_name] for keypose_name in keypose_names + ] + + stand_still_qpos = keyposes[0] + + if ( + stand_still_qpos.shape + != np.asarray(env.robot.get_joint_ids("left_arm")).shape + ): + logger.log_error( + f"The shape of stand_still qpos is different from {agent_uid}'s setting." + ) + + if any( + np.linalg.norm(former - latter).sum() > 1e-6 + for former, latter in zip(keyposes, keyposes[1:]) + ): + logger.log_warning( + f"Applying stand still to two different qpos! Using the first qpos {stand_still_qpos}" + ) + keyposes = [stand_still_qpos] * 2 + + ret = np.asarray([stand_still_qpos] * duration) + + return ret.T + + @staticmethod + @tag_edge + def left_arm_go_back(env, duration: int): + left_arm_monitor_qpos, left_arm_init_qpos = ( + env.affordance_datas["left_arm_monitor_qpos"], + env.affordance_datas["left_arm_init_qpos"], + ) + left_home_sample_num = duration + qpos_expand_left = np.array([left_arm_monitor_qpos, left_arm_init_qpos]) + qpos_expand_left = mul_linear_expand(qpos_expand_left, [left_home_sample_num]) + ret = np.array(qpos_expand_left).T + return ret diff --git a/embodichain/lab/gym/envs/tasks/tableware/pour_water/pour_water.py b/embodichain/lab/gym/envs/tasks/tableware/pour_water/pour_water.py new file mode 100644 index 00000000..433b76de --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/pour_water/pour_water.py @@ -0,0 +1,147 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch + +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.utils import logger + +from embodichain.lab.gym.envs.tasks.tableware.pour_water.action_bank import ( + PourWaterActionBank, +) + +__all__ = ["PourWaterEnv"] + + +@register_env("PourWater-v3", max_episode_steps=600) +class PourWaterEnv(EmbodiedEnv): + def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): + super().__init__(cfg, **kwargs) + + action_config = kwargs.get("action_config", None) + if action_config is not None: + self.action_config = action_config + + def create_demo_action_list(self, *args, **kwargs): + """ + Create a demonstration action list for the current task. + + Returns: + list: A list of demo actions generated by the task. + """ + logger.log_info("Create demo action list for PourWaterTask.") + + if getattr(self, "action_config") is not None: + self._init_action_bank(PourWaterActionBank, self.action_config) + action_list = self.create_expert_demo_action_list(*args, **kwargs) + else: + logger.log_error("No action_config found in env, please check again.") + + if action_list is None: + return action_list + + logger.log_info( + f"Demo action list created with {len(action_list)} steps.", color="green" + ) + return action_list + + def create_expert_demo_action_list(self, **kwargs): + """ + Create an expert demonstration action list using the action bank. + + This function generates a trajectory based on expert knowledge, mapping joint and end-effector + states to the required action format for the environment and robot type. + + Args: + **kwargs: Additional keyword arguments. + + Returns: + list: A list of actions, each containing joint positions ("qpos"). + """ + + if hasattr(self, "action_bank") is False or self.action_bank is None: + logger.log_error( + "Action bank is not initialized. Cannot create expert demo action list." + ) + + ret = self.action_bank.create_action_list( + self, self.graph_compose, self.packages + ) + + if ret is None: + logger.log_warning("Failed to generate expert demo action list.") + return None + + # TODO: to be removed, need a unified interface in robot class + left_arm_joints = self.robot.get_joint_ids(name="left_arm") + right_arm_joints = self.robot.get_joint_ids(name="right_arm") + left_eef_joints = self.robot.get_joint_ids(name="left_eef") + right_eef_joints = self.robot.get_joint_ids(name="right_eef") + + total_traj_num = ret[list(ret.keys())[0]].shape[-1] + actions = torch.zeros( + (total_traj_num, self.num_envs, self.robot.dof), dtype=torch.float32 + ) + + for key, joints in [ + ("left_arm", left_arm_joints), + ("right_arm", right_arm_joints), + ("left_eef", left_eef_joints), + ("right_eef", right_eef_joints), + ]: + if key in ret: + # TODO: only 1 env supported now + actions[:, 0, joints] = torch.as_tensor(ret[key].T, dtype=torch.float32) + + return actions + + def is_task_success(self, **kwargs) -> torch.Tensor: + """Determine if the task is successfully completed. This is mainly used in the data generation process + of the imitation learning. + + Args: + **kwargs: Additional arguments for task-specific success criteria. + + Returns: + torch.Tensor: A boolean tensor indicating success for each environment in the batch. + """ + + bottle = self.sim.get_rigid_object("bottle") + cup = self.sim.get_rigid_object("cup") + + bottle_final_xpos = bottle.get_local_pose(to_matrix=True) + cup_final_xpos = cup.get_local_pose(to_matrix=True) + + bottle_ret = self._is_fall(bottle_final_xpos) + cup_ret = self._is_fall(cup_final_xpos) + + return ~(bottle_ret | cup_ret) + + def _is_fall(self, pose: torch.Tensor) -> torch.Tensor: + # Extract z-axis from rotation matrix (last column, first 3 elements) + pose_rz = pose[:, :3, 2] + world_z_axis = torch.tensor([0, 0, 1], dtype=pose.dtype, device=pose.device) + + # Compute dot product for each batch element + dot_product = torch.sum(pose_rz * world_z_axis, dim=-1) # Shape: (batch_size,) + + # Clamp to avoid numerical issues with arccos + dot_product = torch.clamp(dot_product, -1.0, 1.0) + + # Compute angle and check if fallen + angle = torch.arccos(dot_product) + return angle >= torch.pi / 4 diff --git a/embodichain/lab/gym/envs/tasks/tableware/scoop_ice.py b/embodichain/lab/gym/envs/tasks/tableware/scoop_ice.py new file mode 100644 index 00000000..46f6afad --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/scoop_ice.py @@ -0,0 +1,214 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import torch +import numpy as np +import pickle + +from copy import deepcopy +from typing import Optional, Sequence +from scipy.spatial.transform import Rotation as R + +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.data import get_data_path +from embodichain.utils import logger +from tqdm import tqdm + + +@register_env("ScoopIce-v1", max_episode_steps=600) +class ScoopIce(EmbodiedEnv): + def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): + super().__init__(cfg, **kwargs) + + self.affordance_datas = {} + + # TODO: hardcode code, should be implemented as functor way. + self.trajectory = pickle.load( + open( + get_data_path("ScoopIceNewEnv/pose_record_20250919_184544.pkl"), + "rb", + ) + ) + self.trajectory_sample_rate = 2 + + def set_scoop_pose(self, xyzrxryrz): + scoop = self.sim.get_rigid_object("scoop") + pose = np.eye(4) + pose[:3, 3] = xyzrxryrz[:3] + pose[:3, :3] = R.from_euler("XYZ", xyzrxryrz[3:], degrees=True).as_matrix() + n_env = self.sim.num_envs + pose_t = torch.tensor( + pose[None, :, :].repeat(n_env, axis=0), + dtype=torch.float32, + device=self.device, + ) + scoop.set_local_pose(pose_t) + + def set_cup_pose(self, xyzrxryrz): + cup = self.sim.get_rigid_object("paper_cup") + pose = np.eye(4) + pose[:3, 3] = xyzrxryrz[:3] + pose[:3, :3] = R.from_euler("XYZ", xyzrxryrz[3:], degrees=True).as_matrix() + n_env = self.sim.num_envs + pose_t = torch.tensor( + pose[None, :, :].repeat(n_env, axis=0), + dtype=torch.float32, + device=self.device, + ) + cup.set_local_pose(pose_t) + + def add_xpos_offset(self, arm_qpos: np.ndarray, offset: np.ndarray, is_left: bool): + """Add offset to arm qposes along end-effector x axis. + + Args: + arm_qposes (np.ndarray): [waypoint_num, dof] + """ + waypoint_num = arm_qpos.shape[0] + dof = arm_qpos.shape[1] + offset_t = torch.tensor(offset, dtype=torch.float32, device=self.device) + control_part = "left_arm" if is_left else "right_arm" + + arm_qpos_batch = torch.tensor( + arm_qpos[None, :, :], dtype=torch.float32, device=self.device + ) + + arm_xpos_batch = self.robot.compute_batch_fk( + qpos=arm_qpos_batch, name=control_part, to_matrix=True + ) + arm_xpos_batch[:, :, :3, 3] += offset_t + ret, arm_qpos_offset_batch = self.robot.compute_batch_ik( + pose=arm_xpos_batch, + joint_seed=arm_qpos_batch, + name=control_part, + ) + return arm_qpos_offset_batch[0].to("cpu").numpy() + + def pack_qpos(self): + self.num_envs = self.sim.num_envs + left_arm_qpos = self.trajectory["left_arm"] # [waypoint_num, dof] + logger.log_info("Adding x and z offset to left arm trajectory...") + left_arm_qpos = self.add_xpos_offset( + arm_qpos=left_arm_qpos, offset=np.array([-0.018, 0.0, -0.01]), is_left=True + ) + right_arm_qpos = self.trajectory["right_arm"] # [waypoint_num, dof] + # TODO: add z offset to right arm + logger.log_info("Adding z offset to right arm trajectory...") + right_arm_qpos = self.add_xpos_offset( + arm_qpos=right_arm_qpos, offset=np.array([0.00, 0.0, 0.02]), is_left=False + ) + left_eef_qpos = self.trajectory["left_eef"] # [waypoint_num, hand_dof] + right_eef_qpos = self.trajectory["right_eef"] + torso_qpos = self.trajectory["torso"] + # TODO: need head qpos. + + left_arm_qpos_expand = left_arm_qpos[None, :, :].repeat(self.num_envs, axis=0) + right_arm_qpos_expand = right_arm_qpos[None, :, :].repeat(self.num_envs, axis=0) + left_eef_qpos_expand = left_eef_qpos[None, :, :].repeat(self.num_envs, axis=0) + right_eef_qpos_expand = right_eef_qpos[None, :, :].repeat(self.num_envs, axis=0) + torso_qpos_expand = torso_qpos[None, :, :].repeat(self.num_envs, axis=0) + all_qpos = np.concatenate( + [ + left_arm_qpos_expand, + right_arm_qpos_expand, + left_eef_qpos_expand, + right_eef_qpos_expand, + torso_qpos_expand, + ], + axis=2, + ) + return all_qpos + + def _initialize_episode( + self, env_ids: Optional[Sequence[int]] = None, **kwargs + ) -> None: + + left_arm_ids = self.robot.get_joint_ids(name="left_arm") + right_arm_ids = self.robot.get_joint_ids(name="right_arm") + left_eef_ids = self.robot.get_joint_ids(name="left_eef") + right_eef_ids = self.robot.get_joint_ids(name="right_eef") + torso_ids = self.robot.get_joint_ids(name="torso") + all_ids = np.hstack( + [left_arm_ids, right_arm_ids, left_eef_ids, right_eef_ids, torso_ids] + ) + + # TODO: read xy random range from config + xy_random_range = np.array([[-0.01, -0.01], [0.01, 0.01]]) + xy_random_offset = np.zeros(shape=(self.num_envs, 2)) + for arena_id in range(self.num_envs): + xy_random_offset[arena_id] = np.random.uniform( + low=xy_random_range[0], high=xy_random_range[1], size=(2,) + ) + # TODO: apply warping to container pose + + all_qpos = self.pack_qpos() + all_qpos_t = torch.tensor(all_qpos, dtype=torch.float32, device=self.device) + + # to initial qpos + left_open_qpos = np.array([0.06, 1.5, 0.2, 0.2, 0.2, 0.2]) + left_close_qpos = np.array([0.13, 1.5, 0.5, 0.5, 0.5, 0.5]) + right_open_qpos = np.array([0.3, 1.5, 0.3, 0.3, 0.3, 0.3]) + right_close_qpos = np.array([0.6, 1.5, 0.7, 0.5, 0.7, 0.6]) + + all_qpos_t[:, :, 14:20] = torch.tensor( + left_close_qpos, dtype=torch.float32, device=self.device + ) + all_qpos_t[:, :, 20:26] = torch.tensor( + right_close_qpos, dtype=torch.float32, device=self.device + ) + + first_close_qpos = all_qpos_t[:, 0, :].to("cpu").numpy() + first_open_qpos = deepcopy(first_close_qpos) + + # to first open pose + first_open_qpos[:, 14:20] = left_open_qpos + first_open_qpos[:, 20:26] = right_open_qpos + self.robot.set_qpos( + torch.tensor(first_open_qpos, dtype=torch.float32, device=self.device), + joint_ids=all_ids, + ) + self.sim.update(step=200) + # save warp trajectory as demo action list + waypoint_num = self.trajectory["left_arm"].shape[0] + current_qpos = self.robot.get_qpos() + self.demo_action_list = [] + for waypoint_idx in range(waypoint_num): + action = current_qpos.clone() + action[:, all_ids] = all_qpos_t[:, waypoint_idx, :] + # TODO: sample in trajectory + self.demo_action_list.append(action) + + # TODO: tricky implementation. Hold the first joint state for a while. + if waypoint_idx == 0: + for _ in range(20): + self.demo_action_list.append(action) + + self.sim.update(step=100) + + # apply events such as randomization for environments that need a reset + if self.cfg.events: + if "reset" in self.event_manager.available_modes: + self.event_manager.apply(mode="reset", env_ids=env_ids) + + def create_demo_action_list(self, *args, **kwargs): + logger.log_info( + f"The original demo action list length: {len(self.demo_action_list)}" + ) + logger.log_info( + f"Downsample the demo action list by self.trajectory_sample_rate5 times." + ) + return self.demo_action_list[:: self.trajectory_sample_rate] diff --git a/embodichain/lab/gym/envs/wrapper/__init__.py b/embodichain/lab/gym/envs/wrapper/__init__.py new file mode 100644 index 00000000..3e39714b --- /dev/null +++ b/embodichain/lab/gym/envs/wrapper/__init__.py @@ -0,0 +1,17 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .no_fail import NoFailWrapper diff --git a/embodichain/lab/gym/envs/wrapper/no_fail.py b/embodichain/lab/gym/envs/wrapper/no_fail.py new file mode 100644 index 00000000..e5806d11 --- /dev/null +++ b/embodichain/lab/gym/envs/wrapper/no_fail.py @@ -0,0 +1,31 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import gymnasium as gym + + +class NoFailWrapper(gym.Wrapper): + """A wrapper that alter the env's is_task_success method to make sure all the is_task_success determination return True. + + Args: + env (gym.Env): the environment to wrap. + """ + + def __init__(self, env: gym.Env): + super().__init__(env) + + def is_task_success(self, *args, **kwargs): + return True diff --git a/embodichain/lab/gym/utils/__init__.py b/embodichain/lab/gym/utils/__init__.py new file mode 100644 index 00000000..e4655620 --- /dev/null +++ b/embodichain/lab/gym/utils/__init__.py @@ -0,0 +1,15 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- diff --git a/embodichain/lab/gym/utils/gym_utils.py b/embodichain/lab/gym/utils/gym_utils.py new file mode 100644 index 00000000..42692190 --- /dev/null +++ b/embodichain/lab/gym/utils/gym_utils.py @@ -0,0 +1,617 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import numpy as np +import torch +import dexsim + +from typing import Dict, Any, List, Tuple, Union, Sequence, Optional +from gymnasium import spaces +from copy import deepcopy + +from embodichain.lab.sim.types import Device, Array +from embodichain.lab.sim.objects import Robot +from embodichain.utils.module_utils import find_function_from_modules +from embodichain.utils.utility import get_class_instance +from dexsim.utility import log_debug, log_error + + +def get_dtype_bounds(dtype: np.dtype): + """Gets the min and max values of a given numpy type""" + if np.issubdtype(dtype, np.floating): + info = np.finfo(dtype) + return info.min, info.max + elif np.issubdtype(dtype, np.integer): + info = np.iinfo(dtype) + return info.min, info.max + elif np.issubdtype(dtype, np.bool_): + return 0, 1 + else: + raise TypeError(dtype) + + +def convert_observation_to_space( + observation: Any, prefix: str = "", unbatched: bool = False +) -> spaces.Space: + """Convert observation to OpenAI gym observation space (recursively). + Modified from `gym.envs.mujoco_env` + """ + if isinstance(observation, (dict)): + # CATUION: Explicitly create a list of key-value tuples + # Otherwise, spaces.Dict will sort keys if a dict is provided + space = spaces.Dict( + [ + ( + k, + convert_observation_to_space( + v, prefix + "/" + k, unbatched=unbatched + ), + ) + for k, v in observation.items() + ] + ) + elif isinstance(observation, (list, tuple)): + array = np.array(observation) + dtype = array.dtype + space = spaces.Box(-np.inf, np.inf, shape=array.shape, dtype=dtype) + elif isinstance(observation, np.ndarray): + if unbatched: + shape = observation.shape[1:] + else: + shape = observation.shape + dtype = observation.dtype + low, high = get_dtype_bounds(dtype) + if np.issubdtype(dtype, np.floating): + low, high = -np.inf, np.inf + space = spaces.Box(low, high, shape=shape, dtype=dtype) + elif isinstance(observation, (float, np.float32, np.float64)): + log_debug(f"The observation ({prefix}) is a (float) scalar") + space = spaces.Box(-np.inf, np.inf, shape=[1], dtype=np.float32) + elif isinstance(observation, (int, np.int32, np.int64)): + log_debug(f"The observation ({prefix}) is a (integer) scalar") + space = spaces.Box(-np.inf, np.inf, shape=[1], dtype=int) + elif isinstance(observation, (bool, np.bool_)): + log_debug(f"The observation ({prefix}) is a (bool) scalar") + space = spaces.Box(0, 1, shape=[1], dtype=np.bool_) + else: + raise NotImplementedError(type(observation), observation) + + return space + + +def _batch(array: Union[np.ndarray, Sequence]): + if isinstance(array, (dict)): + return {k: _batch(v) for k, v in array.items()} + if isinstance(array, str): + return array + if isinstance(array, np.ndarray): + if array.shape == (): + return array.reshape(1, 1) + return array[None, :] + if isinstance(array, list): + if len(array) == 1: + return [array] + if ( + isinstance(array, float) + or isinstance(array, int) + or isinstance(array, bool) + or isinstance(array, np.bool_) + ): + return np.array([[array]]) + return array + + +def batch(*args: Tuple[Union[np.ndarray, Dict]]): + """Adds one dimension in front of everything. If given a dictionary, every leaf in the dictionary + has a new dimension. If given a tuple, returns the same tuple with each element batched + """ + x = [_batch(x) for x in args] + if len(args) == 1: + return x[0] + return tuple(x) + + +def to_tensor(array: Array, device: Optional[Device] = None): + """ + Maps any given sequence to a torch tensor on the CPU/GPU. If physx gpu is not enabled then we use CPU, otherwise GPU, unless specified + by the device argument + + Args: + array: The data to map to a tensor + device: The device to put the tensor on. By default this is None and to_tensor will put the device on the GPU if physx is enabled + and CPU otherwise + + """ + if isinstance(array, (dict)): + return {k: to_tensor(v) for k, v in array.items()} + if torch.cuda.is_available(): + if isinstance(array, np.ndarray): + if array.dtype == np.uint16: + array = array.astype(np.int32) + ret = torch.from_numpy(array) + if ret.dtype == torch.float64: + ret = ret.float() + elif isinstance(array, torch.Tensor): + ret = array + else: + ret = torch.tensor(array) + if device is None: + if ret.device.type == "cpu": + return ret.cuda() + # keep same device if already on GPU + return ret + else: + return ret.to(device) + else: + if isinstance(array, np.ndarray): + if array.dtype == np.uint16: + array = array.astype(np.int32) + if array.dtype == np.uint32: + array = array.astype(np.int64) + ret = torch.from_numpy(array) + if ret.dtype == torch.float64: + ret = ret.float() + elif isinstance(array, list) and isinstance(array[0], np.ndarray): + ret = torch.from_numpy(np.array(array)) + if ret.dtype == torch.float64: + ret = ret.float() + elif np.iterable(array): + ret = torch.Tensor(array) + else: + ret = torch.Tensor(array) + if device is None: + return ret + else: + return ret.to(device) + + +def to_cpu_tensor(array: Array): + """ + Maps any given sequence to a torch tensor on the CPU. + """ + if isinstance(array, (dict)): + return {k: to_tensor(v) for k, v in array.items()} + if isinstance(array, np.ndarray): + ret = torch.from_numpy(array) + if ret.dtype == torch.float64: + ret = ret.float() + return ret + elif isinstance(array, torch.Tensor): + return array.cpu() + else: + return torch.tensor(array).cpu() + + +def flatten_state_dict( + state_dict: dict, use_torch=False, device: Device = None +) -> Array: + """Flatten a dictionary containing states recursively. Expects all data to be either torch or numpy + + Args: + state_dict: a dictionary containing scalars or 1-dim vectors. + use_torch (bool): Whether to convert the data to torch tensors. + + Raises: + AssertionError: If a value of @state_dict is an ndarray with ndim > 2. + + Returns: + np.ndarray | torch.Tensor: flattened states. + + Notes: + The input is recommended to be ordered (e.g. dict). + However, since python 3.7, dictionary order is guaranteed to be insertion order. + """ + states = [] + + for key, value in state_dict.items(): + if isinstance(value, dict): + state = flatten_state_dict(value, use_torch=use_torch) + if state.size == 0: + state = None + if use_torch: + state = to_tensor(state) + elif isinstance(value, (tuple, list)): + state = None if len(value) == 0 else value + if use_torch: + state = to_tensor(state) + elif isinstance(value, (bool, np.bool_, int, np.int32, np.int64)): + # x = np.array(1) > 0 is np.bool_ instead of ndarray + state = int(value) + if use_torch: + state = to_tensor(state) + elif isinstance(value, (float, np.float32, np.float64)): + state = np.float32(value) + if use_torch: + state = to_tensor(state) + elif isinstance(value, np.ndarray): + if value.ndim > 2: + raise AssertionError( + "The dimension of {} should not be more than 2.".format(key) + ) + state = value if value.size > 0 else None + if use_torch: + state = to_tensor(state) + + elif isinstance(value, torch.Tensor): + state = value + if len(state.shape) == 1: + state = state[:, None] + else: + raise TypeError("Unsupported type: {}".format(type(value))) + if state is not None: + states.append(state) + + if use_torch: + if len(states) == 0: + return torch.empty(0, device=device) + else: + return torch.hstack(states) + else: + if len(states) == 0: + return np.empty(0) + else: + return np.hstack(states) + + +def clip_and_scale_action( + action: Union[np.ndarray, torch.Tensor], low: float, high: float +): + """Clip action to [-1, 1] and scale according to a range [low, high].""" + if isinstance(action, np.ndarray): + action = np.clip(action, -1, 1) + elif isinstance(action, torch.Tensor): + action = torch.clip(action, -1, 1) + else: + log_error("Unsupported type: {}".format(type(action))) + return 0.5 * (high + low) + 0.5 * (high - low) * action + + +def dict_array_to_torch_inplace( + data: Dict[str, Any], device: Union[str, torch.device] = "cpu" +) -> None: + """ + Convert arrays in a dictionary to torch tensors in-place. + + Args: + data (Dict[str, Any]): Dictionary to modify in-place + device (Union[str, torch.device]): Device to place the tensors on + """ + for key, value in data.items(): + if isinstance(value, np.ndarray): + item: torch.Tensor = torch.from_numpy(value).to(device) + if len(item.shape) == 1: + item.unsqueeze_(0) + data[key] = item + elif isinstance(value, dict): + dict_array_to_torch_inplace(value, device) + + +def cat_tensor_with_ids( + tensors: List[torch.Tensor], ids: List[List[int]], dim: int +) -> torch.Tensor: + """ + Concatenate tensors along a new dimension specified by `dim`, using the provided `ids` to index into the tensors. + + Args: + tensors (List[torch.Tensor]): List of tensors to concatenate. + ids (List[List[int]]): List of lists, where each inner list contains the indices to select from the corresponding tensor. + dim (int): The dimension along which to concatenate the tensors. + + Returns: + torch.Tensor: The concatenated tensor. + """ + out = torch.zeros( + (tensors[0].shape[0], dim), dtype=tensors[0].dtype, device=tensors[0].device + ) + + for i, tensor in enumerate(tensors): + out[:, ids[i]] = tensor + + return out + + +def config_to_rl_cfg(config: dict) -> "RLEnvCfg": + """Parse gym-style configuration dict into an RL-ready config object.""" + + from embodichain.lab.gym.envs.rl_env_cfg import RLEnvCfg + + # Use config_to_cfg to parse shared fields + env_cfg = config_to_cfg(config) + # Convert to RLEnvCfg if needed + if not isinstance(env_cfg, RLEnvCfg): + env_cfg = RLEnvCfg.from_dict(env_cfg.__dict__) + # RL-specific fields + env_cfg.env_id = config.get("id") + env_cfg.num_envs = config["env"].get("num_envs", env_cfg.num_envs) + env_cfg.extensions = deepcopy(config.get("env", {}).get("extensions", {})) + # Add any RL-specific parsing here + return env_cfg + + +def config_to_cfg(config: dict) -> "EmbodiedEnvCfg": + """Parser configuration file into cfgs for env initialization. + + Args: + config (dict): The configuration dictionary containing robot, sensor, light, background, and interactive objects. + + Returns: + EmbodiedEnvCfg: A configuration object for initializing the environment. + """ + + from embodichain.lab.sim.cfg import ( + RobotCfg, + RigidObjectCfg, + RigidObjectGroupCfg, + ArticulationCfg, + LightCfg, + ) + from embodichain.lab.gym.envs import EmbodiedEnvCfg + from embodichain.lab.sim.sensors import SensorCfg + from embodichain.lab.gym.envs.managers import ( + SceneEntityCfg, + EventCfg, + ObservationCfg, + ) + from embodichain.utils import configclass + from embodichain.data import get_data_path + + @configclass + class ComponentCfg: + """Configuration for env events. + + This class is used to define various events that can occur in the environment, + """ + + pass + + env_cfg = EmbodiedEnvCfg() + + # check all necessary keys + required_keys = ["id", "max_episodes", "env", "robot"] + for key in required_keys: + if key not in config: + log_error(f"Missing required config key: {key}") + + # parser robot config + # TODO: support multiple robots cfg initialization from config, eg, cobotmagic, dexforce_w1, etc. + if "robot_type" in config["robot"]: + robot_cfg = get_class_instance( + "embodichain.lab.sim.robots", + config["robot"]["robot_type"] + "Cfg", + ) + config["robot"].pop("robot_type") + robot_cfg = robot_cfg.from_dict(config["robot"]) + else: + robot_cfg = RobotCfg.from_dict(config["robot"]) + + env_cfg.robot = robot_cfg + + # parser sensor config + env_cfg.sensor = [SensorCfg.from_dict(s) for s in config.get("sensor", [])] + + # parser light config + if "light" in config: + env_cfg.light = EmbodiedEnvCfg.EnvLightCfg() + env_cfg.light.direct = [ + LightCfg.from_dict(l) for l in config["light"].get("direct", []) + ] + + # parser background objects config + if "background" in config: + for obj_dict in config["background"]: + shape_type = obj_dict["shape"]["shape_type"] + if shape_type == "Mesh": + obj_dict["shape"]["fpath"] = get_data_path(obj_dict["shape"]["fpath"]) + # Set to static object if not specified. + obj_dict["body_type"] = ( + "static" if "body_type" not in obj_dict else obj_dict["body_type"] + ) + cfg = RigidObjectCfg.from_dict(obj_dict) + env_cfg.background.append(cfg) + + # parser scene objects config + if "rigid_object" in config: + for obj_dict in config["rigid_object"]: + shape_type = obj_dict["shape"]["shape_type"] + if shape_type == "Mesh": + obj_dict["shape"]["fpath"] = get_data_path(obj_dict["shape"]["fpath"]) + cfg = RigidObjectCfg.from_dict(obj_dict) + env_cfg.rigid_object.append(cfg) + + if "rigid_object_group" in config: + for obj_dict in config["rigid_object_group"]: + if "folder_path" in obj_dict: + obj_dict["folder_path"] = get_data_path(obj_dict["folder_path"]) + for rigid_obj in obj_dict["rigid_objects"].values(): + shape_type = rigid_obj["shape"]["shape_type"] + if shape_type == "Mesh" and "fpath" in rigid_obj["shape"]: + rigid_obj["shape"]["fpath"] = get_data_path( + rigid_obj["shape"]["fpath"] + ) + cfg = RigidObjectGroupCfg.from_dict(obj_dict) + env_cfg.rigid_object_group.append(cfg) + + if "articulation" in config: + for obj_dict in config["articulation"]: + obj_dict["fpath"] = get_data_path(obj_dict["fpath"]) + cfg = ArticulationCfg.from_dict(obj_dict) + env_cfg.articulation.append(cfg) + + env_cfg.sim_steps_per_control = config["env"].get("sim_steps_per_control", 4) + + # load dataset config + env_cfg.dataset = config["env"].get("dataset", None) + + # TODO: support more env events, eg, grasp pose generation, mesh preprocessing, etc. + + env_cfg.events = ComponentCfg() + if "events" in config["env"]: + # Define modules to search for event functions + event_modules = [ + "embodichain.lab.gym.envs.managers.randomization", + "embodichain.lab.gym.envs.managers.record", + "embodichain.lab.gym.envs.managers.events", + ] + + # parser env events config + for event_name, event_params in config["env"]["events"].items(): + event_params_modified = deepcopy(event_params) + if "entity_cfg" in event_params["params"]: + entity_cfg = SceneEntityCfg( + **event_params_modified["params"]["entity_cfg"] + ) + event_params_modified["params"]["entity_cfg"] = entity_cfg + + # Find the function from multiple modules using the utility function + event_func = find_function_from_modules( + event_params["func"], event_modules, raise_if_not_found=True + ) + interval_step = event_params_modified.get("interval_step", 10) + + event = EventCfg( + func=event_func, + mode=event_params_modified["mode"], + params=event_params_modified["params"], + interval_step=interval_step, + ) + setattr(env_cfg.events, event_name, event) + + env_cfg.observations = ComponentCfg() + if "observations" in config["env"]: + # Define modules to search for observation functions + observation_modules = [ + "embodichain.lab.gym.envs.managers.observations", + ] + + for obs_name, obs_params in config["env"]["observations"].items(): + obs_params_modified = deepcopy(obs_params) + + if "entity_cfg" in obs_params["params"]: + entity_cfg = SceneEntityCfg( + **obs_params_modified["params"]["entity_cfg"] + ) + obs_params_modified["params"]["entity_cfg"] = entity_cfg + + # Find the function from multiple modules using the utility function + obs_func = find_function_from_modules( + obs_params["func"], + observation_modules, + raise_if_not_found=True, + ) + + observation = ObservationCfg( + func=obs_func, + mode=obs_params_modified["mode"], + name=obs_params_modified["name"], + params=obs_params_modified["params"], + ) + + setattr(env_cfg.observations, obs_name, observation) + + return env_cfg + + +def map_qpos_to_eef_pose( + robot: Robot, qpos: torch.Tensor, control_parts: List[str] +) -> Dict[str, torch.Tensor]: + """Map qpos to end-effector pose. + + Note: + The computed eef pose will be in the base frame of the control part. + + Args: + robot (Robot): The robot instance. + qpos (torch.Tensor): The qpos tensor of shape (N, num_joints). + control_parts (List[str]): List of control part names. + to_dict (bool): Whether to return the result as a dictionary. + + Returns: + Dict[str, torch.Tensor]: A dictionary containing the end-effector poses for each control part. + """ + from embodichain.data.enum import EefType + + eef_pose_dict = {} + for i, name in enumerate(control_parts): + eef_pose = torch.zeros( + (qpos.shape[0], 9), dtype=torch.float32, device=qpos.device + ) + + # TODO: need to be configurable. + control_ids = robot.get_joint_ids(name) + current_qpos = qpos[:, control_ids] + part_eef_pose = ( + robot.pk_serial_chain[name] + .forward_kinematics(current_qpos, end_only=True) + .get_matrix() + ) + + eef_pose[:, :3] = part_eef_pose[:, :3, 3] + eef_pose[:, 3:6] = part_eef_pose[:, :3, 0] + eef_pose[:, 6:9] = part_eef_pose[:, :3, 1] + + eef_pose_dict[name + EefType.POSE.value] = eef_pose + + return eef_pose_dict + + +def fetch_data_from_dict( + data_dict: Dict[str, Union[Any, Dict[str, Any]]], name: str +) -> Any: + """Fetch data from a nested dictionary using a '/' separated key. + + Args: + data_dict (Dict[str, Union[Any, Dict[str, Any]]]): The nested dictionary to fetch data from. + name (str): The '/' separated key string. + + Returns: + Any: The fetched data. + + Raises: + KeyError: If the specified key does not exist in the dictionary. + """ + keys = name.split("/") + current_data = data_dict + + for key in keys: + if key in current_data: + current_data = current_data[key] + else: + raise KeyError(f"Key '{key}' not found in the dictionary.") + + return current_data + + +def assign_data_to_dict( + data_dict: Dict[str, Union[Any, Dict[str, Any]]], name: str, value: Any +) -> None: + """Assign data to a nested dictionary using a '/' separated key. + Missing intermediate dictionaries will be created automatically. + + Args: + data_dict (Dict[str, Union[Any, Dict[str, Any]]]): The nested dictionary to assign data to. + name (str): The '/' separated key string. + value (Any): The value to assign. + """ + keys = name.split("/") + current_data = data_dict + + for key in keys[:-1]: + if key not in current_data or not isinstance(current_data[key], dict): + current_data[key] = {} # create intermediate dict if missing + current_data = current_data[key] + + last_key = keys[-1] + current_data[last_key] = value diff --git a/embodichain/lab/gym/utils/misc.py b/embodichain/lab/gym/utils/misc.py new file mode 100644 index 00000000..92098663 --- /dev/null +++ b/embodichain/lab/gym/utils/misc.py @@ -0,0 +1,1564 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import re +import os +import ast +import cv2 +import h5py +import torch +import inspect +import open3d as o3d + +from copy import deepcopy +from functools import partial, wraps, lru_cache +from collections import OrderedDict +from importlib import import_module +from scipy.spatial.transform import Rotation as R +from typing import Any, Dict, List, Tuple, Union, Sequence, Callable, Optional, Mapping + +import numpy as np + +from embodichain.lab.sim.objects import Robot +from embodichain.utils.utility import inv_transform +from embodichain.utils.logger import log_info, log_warning, log_error + + +def no_validation(*args, **kwargs): + return True + + +def add_xy_random_offset( + pose: np.ndarray, max_offset: Union[float, List[float]] +) -> np.ndarray: + """ + Add a random offset to the x and y translation of a pose. + + Args: + pose (np.ndarray): 4x4 pose matrix. + max_offset (float or List[float]): If float, uniform in [-max_offset, max_offset] for both axes. + If list, [x_min, x_max, y_min, y_max]. + + Returns: + np.ndarray: Pose with random xy offset. + """ + shift_pose = deepcopy(pose) + if isinstance(max_offset, float): + xy_shift = np.random.uniform(-max_offset, max_offset, size=2) + else: + x_shift = np.random.uniform(max_offset[0], max_offset[1]) + y_shift = np.random.uniform(max_offset[2], max_offset[3]) + xy_shift = np.array([x_shift, y_shift]) + shift_pose[:2, 3] += xy_shift + return shift_pose + + +def mul_linear_expand( + arr: np.ndarray, expand_times: Union[int, List[int]], is_interp: bool = True +) -> np.ndarray: + """ + Linearly interpolate or repeat between points in an array. + + Args: + arr (np.ndarray): Input array of shape (N, D). + expand_times (int or List[int]): Number of samples between each pair. + is_interp (bool): If True, interpolate; else, repeat. + + Returns: + np.ndarray: Expanded/interpolated array. + """ + arr = np.asarray(arr) + arr_len, dim = arr.shape + if isinstance(expand_times, int): + interp_path = np.zeros(shape=(arr_len * expand_times, dim), dtype=float) + else: + assert len(expand_times) == arr_len - 1, "Invalid expand_times size." + interp_path = np.zeros(shape=(sum(expand_times), dim), dtype=float) + + idx = 0 + for i in range(arr_len - 1): + sample_times = ( + expand_times if isinstance(expand_times, int) else expand_times[i] + ) + for k in range(sample_times): + if is_interp: + alpha = k / sample_times + v = (1 - alpha) * arr[i] + alpha * arr[i + 1] + else: + v = arr[i] + interp_path[idx] = v + idx += 1 + interp_path = interp_path[:idx] + return interp_path + + +def axis_idx(k: str) -> int: + return {"x": 0, "y": 1, "z": 2}.get(k, None) + + +def axis_str_to_list(s: str): + if any(c not in "xyz" for c in s): + return None + return ["xyz".index(c) for c in s] + + +def is_pose_axis_align( + pose: List, + vector: List, + axis_str: str, + mode: str, + cos_threshold: float = None, + degree_threshold: float = None, +): + """Check if the given `axis` of a `pose` is aligned with given vector, under given mode and cos_threshold. + i.e. the cosine value of the angle between the pose's `axis` and `vector` is respecting (leq or geq) the `cos_threhold` or not. + + Args: + pose (List): The pose to be checked. + vector (List): The vector to be aligning to. + axis_str (str): The string of the axis. + mode (str): leq or geq. + cos_threshold (float): The threshold of the cosine value between the pose's axis and vector. + degree_threshold (float): The threshold of the degree value between the pose's axis and vector, only functions when cos_threshold is not given. + """ + pose = np.asarray(pose) + vector = np.asarray(vector) + + if cos_threshold is None: + if degree_threshold is None: + log_error( + 'cos_threshold & angle_threshold are both None, illegal for "is_pose_axis_align".' + ) + else: + cos_threshold = np.cos(np.deg2rad(degree_threshold)) + + axis_id = axis_idx(axis_str) + axis = pose[:3, axis_id] + cos_value = np.dot(axis, vector) / np.linalg.norm(vector) + + if "abs" in mode: + cos_value = abs(cos_value) + + if "leq" in mode: + return cos_value <= cos_threshold + elif "geq" in mode: + return cos_value >= cos_threshold + + +def is_pose_flip( + pose: list, ref_pose: list, axis_str: str = "y", return_inverse: bool = False +): + pose = np.asarray(pose) + ref_pose = np.asarray(ref_pose) + axis_idx = axis_idx(axis_str) + if axis_idx is None: + log_error(f'Axis {axis_str} is not among ["x", "y", "z"]') + relative_angle = np.abs(np.arccos(pose[:3, axis_idx].dot(ref_pose[:3, axis_idx]))) + valid_ret = relative_angle > np.pi / 2 + + if return_inverse: + valid_ret = not valid_ret + + return valid_ret + + +def is_qpos_exceed(qpos: np.ndarray, agent, uid: str): + return not ( + any(qpos < agent.get_joint_limits(uid)[:, 0]) + or any(qpos > agent.get_joint_limits(uid)[:, 1]) + ) + + +def is_qpos_exceed_new( + qpos: Union[np.ndarray, torch.Tensor], robot: Robot, control_part: str +) -> bool: + """ + Check if the given qpos exceeds the joint limits of the specified control part. + Supports both numpy and torch tensor inputs. + + Args: + qpos (Union[np.ndarray, torch.Tensor]): The joint positions to check. + robot (Robot): The robot object containing joint limits. + control_part (str): The name of the control part to check. + + Returns: + bool: True if qpos exceeds joint limits, False otherwise. + """ + joint_limits = robot.body_data.qpos_limits[0][ + robot.get_joint_ids(name=control_part) + ] + # Convert joint_limits to tensor if qpos is tensor, else to numpy + if isinstance(qpos, torch.Tensor): + joint_limits = torch.as_tensor( + joint_limits, dtype=qpos.dtype, device=qpos.device + ) + exceed = torch.any(qpos < joint_limits[:, 0]) or torch.any( + qpos > joint_limits[:, 1] + ) + return not exceed + else: + qpos = np.asarray(qpos) + # 保证 joint_limits 是 numpy 类型 + if isinstance(joint_limits, torch.Tensor): + joint_limits = joint_limits.cpu().numpy() + exceed = np.any(qpos < joint_limits[:, 0]) or np.any(qpos > joint_limits[:, 1]) + return not exceed + + +def is_qpos_flip( + qpos: Union[np.ndarray, torch.Tensor], + qpos_ref: Union[np.ndarray, torch.Tensor], + qpos_ids: Union[List, np.ndarray], + threshold: float = 1.1 * np.pi, + mode: str = "delta", + return_inverse: bool = False, +): + """ + Check whether the joint positions (qpos) are flipped compared to a reference (qpos_ref). + Supports both numpy and torch tensor inputs. + + Args: + qpos (Union[np.ndarray, torch.Tensor]): The joint positions to check. + qpos_ref (Union[np.ndarray, torch.Tensor]): The reference joint positions. + qpos_ids (Union[List, np.ndarray]): Indices of joints to compare. + threshold (float, optional): Threshold for delta mode. Defaults to 1.1 * np.pi. + mode (str, optional): "delta" for norm difference, "sign" for sign difference. Defaults to "delta". + return_inverse (bool, optional): If True, returns the inverse result. Defaults to False. + + Returns: + bool: True if flipped, False otherwise. + """ + # Ensure qpos_ids is numpy array for indexing + if isinstance(qpos_ids, torch.Tensor): + qpos_ids = qpos_ids.cpu().numpy() + # If either input is torch.Tensor, convert both to tensor for comparison + if isinstance(qpos, torch.Tensor) or isinstance(qpos_ref, torch.Tensor): + if not isinstance(qpos, torch.Tensor): + qpos = torch.from_numpy(qpos) + if not isinstance(qpos_ref, torch.Tensor): + qpos_ref = torch.from_numpy(qpos_ref) + qpos_ids_tensor = torch.as_tensor(qpos_ids, dtype=torch.long) + if mode == "delta": + # Compute norm difference for selected joints + qpos_diff = torch.norm(qpos[qpos_ids_tensor] - qpos_ref[qpos_ids_tensor]) + valid_ret = qpos_diff > threshold + elif mode == "sign": + # Check sign difference for selected joints + valid_ret = (qpos[qpos_ids_tensor] * qpos_ref[qpos_ids_tensor]) < 0 + else: + log_error(f"The qpos flip mode {mode} has not been implemented yet.") + # Convert torch scalar to Python bool + if isinstance(valid_ret, torch.Tensor): + valid_ret = valid_ret.item() if valid_ret.numel() == 1 else bool(valid_ret) + else: + qpos_ids = np.asarray(qpos_ids) + if mode == "delta": + qpos_diff = np.linalg.norm(qpos[qpos_ids] - qpos_ref[qpos_ids]) + valid_ret = qpos_diff > threshold + elif mode == "sign": + valid_ret = (qpos[qpos_ids] * qpos_ref[qpos_ids]) < 0 + else: + log_error(f"The qpos flip mode {mode} has not been implemented yet.") + + if return_inverse: + valid_ret = not valid_ret + + return valid_ret + + +def get_replaced_pose( + pose_to_change: np.ndarray, + pose_replace_value: Union[float, List], + axis_str_replace: str, +) -> np.ndarray: + """ + Replace specific axes of a pose with new values. + + Args: + pose_to_change (np.ndarray): The pose to be modified (4x4 matrix). + pose_replace_value (Union[float, List]): The values to replace the specified axes. + axis_str_replace (str): A string specifying the axes to replace (e.g., "xy"). + + Returns: + np.ndarray: The modified pose. + + Raises: + ValueError: If the lengths of `pose_replace_value` and `axis_str_replace` do not match. + """ + axis_list_replace = axis_str_to_list(axis_str_replace) + if axis_list_replace is None: + raise ValueError(f"Invalid axis string: {axis_str_replace}") + + if isinstance(pose_replace_value, (Sequence, np.ndarray)): + pose_replace_value_length = len(pose_replace_value) + else: + pose_replace_value_length = 1 + pose_replace_value = [pose_replace_value] + + if pose_replace_value_length != len(axis_list_replace): + log_error( + f'The axis asked to be raplaced is "{axis_str_replace}", but got {pose_replace_value_length} changes quantity.' + ) + for axis, replace_quantity in zip(axis_list_replace, pose_replace_value): + pose_to_change[axis, 3] = replace_quantity + return pose_to_change + + +def get_offset_pose( + pose_to_change: np.ndarray, + offset_value: Union[float, List[float]], + direction: Union[str, List] = "z", + mode: str = "extrinsic", +) -> np.ndarray: + """Offset the `pose_to_change` given the `offset_value`, `direction` & `mode`. Returns the offset pose. + + Args: + pose_to_change (np.ndarray): The pose to be offset. + offset_value (Union[float, List[float]]): The offset. + direction (Union[str, List], optional): String as "x", "y" or, "z" and 3-dim np.ndarray indicating the offset directions. Defaults to "z". + mode (str, optional): String "extrinsic" or "intrinsic", indicating which system frame should each offset shall be done. Defaults to "extrinsic". + + Returns: + np.ndarray: The resulting 4x4 offset pose. + + Raises: + ValueError: If inputs are invalid or incompatible. + """ + if isinstance(direction, str): + minus = "-" in direction + direction = direction.removeprefix("-") + direction = np.isin(np.arange(3), axis_str_to_list(direction)).astype(int) * ( + -1 if minus else 1 + ) + + direction = np.asarray(direction) + direction = direction / np.linalg.norm(direction) + offset_matrix = np.eye(4) + offset_matrix[:3, 3] = offset_value * direction + if mode == "extrinsic": + offset_pose = offset_matrix @ pose_to_change + elif mode == "intrinsic": + offset_pose = pose_to_change @ offset_matrix + else: + log_error(f"Mode {mode} illegal.") + return offset_pose + + +# TODO: This one is not for work +def get_offset_pose_list( + pose_to_change: np.ndarray, + offsets: Union[float, List[float]], + directions: Union[str, np.ndarray, List[str], List[np.ndarray]] = [], + modes: Union[str, List[str]] = [], +): + """Offset the `pose_to_change` given the `offsets`, `directions` & `modes`. Returns the offset poses. + + Args: + pose_to_change (np.ndarray): The pose to be offset. + offsets (Union[float, List[float]]): The offset or the offset list. + directions (Union[str, np.ndarray, List[str], List[np.ndarray]], optional): String as "x", "y" or, "z" and 3-dim np.ndarray indicating the offset directions, together with their list that have same size of `offsets` . Defaults to []. + modes (Union[str, List[str]], optional): String "extrinsic" or "intrinsic", and its list, indicating which system frame should each offset shall be done. Defaults to []. + return_single_pose: Whether return the single pose or not + """ + num_offset_pose = len(offsets) if isinstance(offsets, list) else 1 + num_offset_direction = len(directions) if isinstance(directions, list) else 1 + num_offset_mode = len(modes) if isinstance(modes, list) else 1 + if num_offset_direction == 0: + directions = ["z"] * num_offset_pose + num_offset_direction = num_offset_pose + if num_offset_mode == 0: + modes = ["extrinsic"] * num_offset_direction + num_offset_mode = num_offset_direction + if num_offset_direction != num_offset_pose: + log_error( + f"The offsets {offsets} have a different length {num_offset_pose} other than directions {directions}'s {num_offset_direction}." + ) + if num_offset_mode != num_offset_direction: + log_warning( + f"The directions {directions} have a different length {num_offset_direction} other than modes {modes}'s {num_offset_mode}." + ) + if num_offset_direction == 1 and not isinstance(directions, list): + directions = [directions] + if num_offset_mode == 1 and not isinstance(modes, list): + modes = [modes] + + offset_poses = [] + for idx, (offset, (direction, mode)) in enumerate( + zip(offsets, zip(directions, modes)) + ): + offset_pose = get_offset_pose(pose_to_change, offset, direction, mode) + offset_poses.append(offset_pose) + + return offset_poses + + +def get_rotated_pose( + pose_to_change: np.ndarray, + rot_angle: float, + rot_axis: Union[str, List] = "z", + mode: str = "extrinsic", + degrees: Union[bool, str] = None, +): + """Rotate the `pose_to_change` given the `rot_angel`, `rot_axis` & `mode`. Returns the rotate pose. + + Args: + pose_to_change (np.ndarray): The pose to be rotated. + rot_angle (float): The rotation angle. + rot_axis (Union[str, List], optional): String as "x", "y" or, "z" and 3-dim np.ndarray indicating the rotation axis. Defaults to "z". + mode (str, optional): String "extrinsic" or "intrinsic", and its list, indicating which system frame should each rotation shall be done. Defaults to "extrinsic". + degrees (str): If it's "degrees" then the input rotation angle is degree, then it's not degrees but radians. + """ + if isinstance(rot_axis, str): + rot_axis = np.isin(np.arange(3), axis_str_to_list(rot_axis)).astype(int) + rot_axis = np.asarray(rot_axis) + rot_axis = rot_axis / np.linalg.norm(rot_axis) + + if degrees == "degrees" or degrees == True: + rot_angle = np.deg2rad(rot_angle) + + rotation_matrix = np.eye(4) + rotation_matrix[:3, :3] = R.from_rotvec(rot_axis * rot_angle).as_matrix() + if mode == "extrinsic": + rotated_pose = rotation_matrix @ pose_to_change + elif mode == "intrinsic": + rotated_pose = pose_to_change @ rotation_matrix + else: + log_error(f"Mode {mode} illegal.") + return rotated_pose + + +def get_rotation_replaced_pose( + pose_to_change: np.ndarray, + rotation_value: Union[float, List], + rot_axis: Union[str, List] = "z", + mode: str = "extrinsic", + degrees: Union[bool, str] = None, +): + if isinstance(rotation_value, (float, int, np.number)): + replaced_rotation_matrix = get_rotated_pose( + np.eye(4), rotation_value, rot_axis, mode, degrees + )[:3, :3] + elif isinstance(rotation_value, list): + rotation_value = np.asarray(rotation_value) + if rotation_value.shape == (3, 3): + replaced_rotation_matrix == rotation_value + elif rotation_value.shape == (3,): + log_warning( + f'Getting shape (3,) rotation_value {rotation_value} for "rotreplace", make sure it\'s rpy.' + ) + replaced_rotation_matrix = R.from_euler("xyz", rotation_value).as_matrix() + elif rotation_value.shape == (4,): + log_warning( + f'Getting shape (4,) rotation_value {rotation_value} for "rotreplace", make sure it\'s xyzw quaternion.' + ) + replaced_rotation_matrix = R.from_quat(rotation_value).as_matrix() + else: + log_error( + f'rotation_value has shape {rotation_value.shape}, not suppoorted by "rotreplace".' + ) + else: + log_error( + f'rotation_value has type {type(rotation_value)}, not suppoorted by "rotreplace".' + ) + rotation_replaced_pose = deepcopy(pose_to_change) + rotation_replaced_pose[:3, :3] = replaced_rotation_matrix + return rotation_replaced_pose + + +def get_frame_changed_pose( + pose_to_change: np.ndarray, + frame_change_matrix: Union[List, np.ndarray], + mode: bool = "extrinsic", + inverse: Union[bool, str] = False, +): + if isinstance(frame_change_matrix, list): + frame_change_matrix = np.asarray(frame_change_matrix) + if not isinstance(frame_change_matrix, np.ndarray): + log_error( + f'frame_change_matrix has type{type(frame_change_matrix)} other than np.ndarray, not suppoorted by "get_frame_changed_pose".' + ) + else: + if frame_change_matrix.shape != (4, 4): + log_error( + f'frame_change_matrix has shape {frame_change_matrix.shape} other than (4,4), not suppoorted by "get_frame_changed_pose".' + ) + + if inverse == "inverse" or inverse == True: + frame_change_matrix = inv_transform(frame_change_matrix) + + if mode == "extrinsic": + pose_to_change = frame_change_matrix @ pose_to_change + elif mode == "intrinsic": + pose_to_change = pose_to_change @ frame_change_matrix + else: + log_error(f"Mode {mode} illegal.") + + return pose_to_change + + +def get_aligned_pose( + pose_to_change: np.ndarray, + align_vector: List, + pose_axis: str = "z", +): + align_vector = np.asarray(align_vector) + pose_axis = axis_idx(pose_axis) + rotation_axis = np.cross(pose_to_change[:3, pose_axis], align_vector) + rotation_axis_norm = np.linalg.norm(rotation_axis) + if rotation_axis_norm >= 1e-5: + rotation_axis = rotation_axis / rotation_axis_norm + rotation_angle = np.arccos(pose_to_change[:3, 2].dot(align_vector)) + pose_to_change[:3, :3] = ( + R.from_rotvec(rotation_axis * rotation_angle).as_matrix() + @ pose_to_change[:3, :3] + ) + return pose_to_change + + +# TODO: automatically routing,given kwargs automatically find the mode. +def get_changed_pose( + pose_to_change: np.ndarray, pose_changes: List[Tuple[str, Any]] = [] +): + """Change the single pose given the `pose_changes` that indicates how to change the pose. + + Args: + pose_to_change (np.ndarray): The pose to be changed. + pose_changes (List[Tuple[str, Any]], optional): The list contains tuples that [0] refer to pose change name that indicates the change mode and parameters, split by "_", e.g. "offset_${np.array([0.05, -0.10, 0.125])}". And [1] be the change value, e.g. "${env.affordance_datas[\"cup_move_pose\"][:2,3]}". Defaults to []. + + Returns: + pose_to_change (np.ndarray): The changed pose. + """ + for pose_change_name, pose_change_value in pose_changes: + change_partition = pose_change_name.split("_") + change_mode = change_partition[0] + if change_mode == "replace": + pose_to_change = get_replaced_pose( + pose_to_change, + pose_replace_value=pose_change_value, + axis_str_replace=change_partition[1], + ) + elif change_mode == "offset": + pose_to_change = get_offset_pose( + pose_to_change, [pose_change_value], *change_partition[1:] + ) + elif change_mode == "rotation": + pose_to_change = get_rotated_pose( + pose_to_change, + pose_change_value, + *change_partition[1:], + ) + elif change_mode == "rotreplace": + pose_to_change = get_rotation_replaced_pose( + pose_to_change, pose_change_value, *change_partition[1:] + ) + elif change_mode == "framechange": + pose_to_change = get_frame_changed_pose( + pose_to_change, pose_change_value, *change_partition[1:] + ) + elif change_mode == "align": + get_aligned_pose(pose_to_change, pose_change_value, change_partition[1]) + else: + # TODO + log_error(f"The {change_mode} change mode haven't realized yet!") + return pose_to_change + + +def get_replaced_qpos( + qpos_to_change: Union[np.ndarray, torch.Tensor], + replace_value: Union[float, List[float]], + joint_list_replace: List, +): + if not isinstance(replace_value, Sequence): + replace_value = [replace_value] + for joint, replace_quantity in zip(joint_list_replace, replace_value): + qpos_to_change[joint] = float(replace_quantity) + return qpos_to_change + + +def get_offset_qpos( + qpos_to_change: np.ndarray, + offset_value: Union[float, List[float]], + joint_list_offset: List, + degrees: Union[str, bool, List[int]] = None, +) -> np.ndarray: + if not isinstance(offset_value, Sequence): + offset_value = [offset_value] + + degrees_joint_list = [] + if degrees is not None: + if isinstance(degrees, str): + degrees_all = degrees == "degrees" + + if degrees_all: + degrees_joint_list = joint_list_offset + else: + degrees_joint_str = degrees.split("degrees")[1] + for degerees_joint_idx_str in degrees_joint_str: + degrees_joint_list.append(int(degerees_joint_idx_str)) + elif isinstance(degrees, bool): + degrees_all = degrees == True + if degrees_all: + degrees_joint_list = joint_list_offset + elif isinstance(degrees, list): + degrees_joint_list = degrees + + if not set(degrees_joint_list).issubset(set(joint_list_offset)): + log_error( + f"degrees_joint_list {degrees_joint_list}, not subset to joint_list_offset {joint_list_offset}." + ) + + for joint, offset_quantity in zip(joint_list_offset, offset_value): + if joint in degrees_joint_list: + offset_quantity = np.deg2rad(offset_quantity) + qpos_to_change[joint] += offset_quantity + + return qpos_to_change + + +def get_changed_qpos( + qpos_to_change: np.ndarray, qpos_changes: List[Tuple[str, Any]] = [], frame=None +): + """Change the single qpos given the `qpos_changes` that indicates how to change the qpos. + + Args: + qpos_to_change (np.ndarray): The qpos to be changed. + qpos_changes (Dict[str, Any], optional): The list contains tuples that [0] refer to pose change name that indicates the change mode and parameters, split by "_", e.g. "offset_123". And [1] be the change value, e.g. "[0.5, 0.6, 0.7]". Defaults to [] + + Returns: + qpos_to_change (np.ndarray): The changed qpos. + """ + if isinstance(qpos_to_change, torch.tensor): + qpos_to_change = np.asarray(qpos_to_change) + + for qpos_change_name, qpos_change_value in qpos_changes: + change_partition = qpos_change_name.split("_") + change_mode = change_partition[0] + if not isinstance(qpos_change_value, Sequence): + qpos_change_value = [qpos_change_value] + + joint_str_change = change_partition[1] + joint_list_change = [] + for joint_idx_str in joint_str_change: + joint_list_change.append(int(joint_idx_str)) + if len(qpos_change_value) != len(joint_list_change): + log_error( + f'The joints asked to be raplaced is "{joint_str_change}", but got {len(qpos_change_value)} changes quantity.' + ) + + if change_mode == "replace": + qpos_to_change = get_offset_qpos( + qpos_to_change, + replace_value=qpos_change_value, + replace_joint_list=joint_list_change, + ) + elif change_mode == "offset": + qpos_to_change = get_offset_qpos( + qpos_to_change, + offset_value=qpos_change_value, + offset_joint_list=joint_list_change, + degrees=change_partition[2], + ) + else: + log_error(f"The {change_mode} change mode haven't realized yet!") + return qpos_to_change + + +def pose_shift(pose_in_cam: np.ndarray, axis: int, shift: float) -> np.ndarray: + shift_pose = np.copy(pose_in_cam) + shift_pose = np.linalg.inv(shift_pose) + shift_pose[axis, -1] += shift + shift_pose = np.linalg.inv(shift_pose) + return shift_pose + + +def expand_pose( + pose: np.ndarray, + x_interval: float, + y_interval: float, + kpnts_number: int, + grab_ratios: List = None, + ref_pose: np.ndarray = np.eye(4), +): + ret = [ref_pose @ pose] + + xoffset = np.linspace(-x_interval, x_interval, kpnts_number) + + if grab_ratios is None: + yoffset = np.linspace(-y_interval, y_interval, kpnts_number) + else: + yoffset = np.linspace( + -y_interval * grab_ratios[0], + y_interval * grab_ratios[1], + kpnts_number, + ) + + x_expand = [ref_pose @ pose_shift(pose, 0, x) for x in list(xoffset)] + y_expand = [ref_pose @ pose_shift(pose, 1, y) for y in list(yoffset)] + return ret + x_expand + y_expand + + +def parse_mask_by_uuids( + mask: np.ndarray, uuids: Dict[str, int] +) -> Dict[str, np.ndarray]: + from embodichain.data.enum import SemanticMask + + if len(uuids.keys()) == 0: + return {} + + robot_mask = np.zeros_like(mask, dtype=np.bool_) + robot_uuids = uuids["robot"] + for uuid in robot_uuids: + robot_mask[mask == uuid] = True + + object_uuids = uuids.get("object", []) + foreground_mask = np.zeros_like(mask, dtype=np.bool_) + for uuid in object_uuids: + foreground_mask[mask == uuid] = True + + background_mask = np.logical_not(np.logical_or(robot_mask, foreground_mask)) + + ret_masks = np.tile( + np.expand_dims(np.zeros_like(robot_mask), -1), [1, 1, len(SemanticMask)] + ) + ret_masks[:, :, SemanticMask.ROBOT.value] = robot_mask + ret_masks[:, :, SemanticMask.BACKGROUND.value] = background_mask + ret_masks[:, :, SemanticMask.FOREGROUND.value] = foreground_mask + + return ret_masks + + +def project_3d_to_2d( + cam, poses: List[np.ndarray], normalize: bool = True +) -> np.ndarray: + import dexsim.utility as dexutils + + cam_pose = cam._camera.get_world_pose() + cam_pose = dexutils.change_coordinate_stystem(cam_pose, ["X", "-Y", "-Z"]) + + intrinsic = cam._camera.get_intrinsic() + height = cam._camera.get_height() + width = cam._camera.get_width() + keypoints = [] + for pose in poses: + pose_ = np.matmul(np.linalg.inv(cam_pose), pose) + rvec, tvec = cv2.Rodrigues(np.eye(3))[0], np.zeros((3, 1)) + image_points, _ = cv2.projectPoints( + pose_[:3, -1], + rvec, + tvec, + np.array(intrinsic).reshape(3, 3), + np.zeros( + 5, + ), + ) + keypoints.append(image_points.reshape(1, 2)) + + keypoints = np.concatenate(keypoints, 0) + keypoints[:, 0] = np.clip(keypoints[:, 0], 0, width - 1) + keypoints[:, 1] = np.clip(keypoints[:, 1], 0, height - 1) + + if normalize: + keypoints[:, 0] = keypoints[:, 0] / width + keypoints[:, 1] = keypoints[:, 1] / height + return keypoints + + +def camel_to_snake(name): + # Insert underscores before each uppercase letter and convert to lowercase + s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name) + snake_case = re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower() + return snake_case + + +def print_keys_recursively(h5file: h5py.Group, path="/"): + """ + Recursively prints the keys in the HDF5 file. + + :param h5file: An open h5py File object. + :param path: The current path in the HDF5 file. + """ + for key in h5file[path].keys(): + print(f"{path}{key}") + if isinstance(h5file[path + key], h5py.Group): + print_keys_recursively(h5file, path + key + "/") + + +def hdf5_to_dict(h5file: h5py.Group): + def recursive_dict(group): + result = {} + for key, item in group.items(): + if isinstance(item, h5py.Dataset): + result[key] = item[()] + elif isinstance(item, h5py.Group): + result[key] = recursive_dict(item) + return result + + return recursive_dict(h5file) + + +def extract_keys_hierarchically(d, assign_data_type: str = "list"): + result = {} + + for key, value in d.items(): + # If the value is a dictionary, recursively extract its keys + if isinstance(value, dict): + result[key] = extract_keys_hierarchically(value) + else: + if assign_data_type == "null": + result[key] = None + elif assign_data_type == "list": + result[key] = [] + else: + raise ValueError(f"Invalid assign_data_type: {assign_data_type}") + + return result + + +def get_file_list(path: str, ext: str): + file_list = [] + for root, dirs, files in os.walk(path): + for file in files: + if file.endswith(ext): + file_list.append(os.path.join(root, file)) + + return file_list + + +# Pattern to recognize an attribute or indexer sequence, e.g., foo, ["bar"], [0] +_TOKEN_RE = re.compile( + r"""( + (?P[A-Za-z_]\w*) # attribute name + | \[\s*(?P"[^"]*"|'[^']*'|\d+)\s*\] # bracket indexer with quoted key or integer +)""", + re.VERBOSE, +) + + +def resolve_env_attr(obj: Any, env: Any) -> Any: + """ + Recursively replace any string of the form 'env:...' by evaluating it as a Python expression on the given `env` object. + Other containers (mappings, sequences) will be traversed and resolved element-wise. + + Supports: + - Arbitrary attribute access (e.g. env.x.y.z) + - Arbitrary indexing and slicing (e.g. env.x["key"][1:4]) + - Any valid Python expression after the 'env:' prefix. + + Args: + obj: The object to resolve. If it's: + - A dict-like Mapping: each value is passed back into resolve_env_attr. + - A Sequence (list/tuple/etc.) but not str: each element is resolved. + - A str starting with 'env:': the suffix is treated as a Python + expression relative to `env` and eval'ed. + - Anything else: returned unchanged. + env: An object whose attributes, methods, indices, etc. may be + referenced in the 'env:' expressions. + + Returns: + The resolved object, with 'env:' strings replaced by their eval results. + """ + # 1) If it's a mapping, recurse into its values + if isinstance(obj, Mapping): + return {k: resolve_env_attr(v, env) for k, v in obj.items()} + + # 2) If it's a non-str sequence, recurse into its elements + if isinstance(obj, Sequence) and not isinstance(obj, str): + return type(obj)(resolve_env_attr(item, env) for item in obj) + + # 3) If it's a string starting with "env.", eval it directly + if isinstance(obj, str) and obj.startswith("env."): + return eval(obj, {}, {"env": env}) + + # 4) Everything else passes through unchanged + return obj + + +_EXPR = re.compile(r"\$\{([^}]+)\}") # For searching ${...} marker + + +def resolve_formatted_string(obj, local_vars=None, global_vars=None): + """Given a dict carrys "${...}"-like strings , `eval` the "${...}$" values while keep the dict structure. + + Args: + obj (Union[Dict, Sequence]): The original "Grand" dict or the iterables in it. + local_vars (_type_, optional): _description_. Defaults to None. + global_vars (_type_, optional): _description_. Defaults to None. + + Returns: + _type_: _description_ + """ + # Gut the caller's locals & globals + if local_vars is None or global_vars is None: + frame = inspect.currentframe().f_back # caller frame + local_vars = local_vars or frame.f_locals + global_vars = global_vars or frame.f_globals + + # 1) dict + if isinstance(obj, Mapping): + return { + k: resolve_formatted_string(v, local_vars, global_vars) + for k, v in obj.items() + } + + # 2) list/tuple + if isinstance(obj, Sequence) and not isinstance(obj, str): + return type(obj)( + resolve_formatted_string(v, local_vars, global_vars) for v in obj + ) + + # 3) str + if isinstance(obj, str): + full = _EXPR.fullmatch(obj.strip()) + if full: + # the whole string is ${expr} -> return eval(expr) + return eval( + full.group(1), + {"__builtins__": None}, # eval with given locals & globals + {**global_vars, **local_vars}, + ) + # par tof the string is ${expr}:replace ...${expr}.. -> str(...eval(expr)..) + def _sub(m): + return str( + eval(m.group(1), {"__builtins__": None}, {**global_vars, **local_vars}) + ) + + return _EXPR.sub(_sub, obj) + + # 4) other type just return + return obj + + +def resolve_params(resolve_func): + """ + Decorator factory that applies `resolve_func` to each argument of the + decorated function, with optional per-decorator `exclude` names. + + If `resolve_func`'s signature is: resolve_func(obj) + then we call: resolve_func(val) + + If its signature is: resolve_func(obj, x, y, ...) + then for each argument `val` of the decorated function we call: resolve_func(val, x=bound['x'], y=bound['y'], ...) pulling `x`, `y`, etc. by name from the decorated function's bound args. + + Usage patterns: + + # 1) create a decorator + resolve_formatted_params = resolve_params(resolve_formatted_string) and use without exclude: + @resolve_formatted_params + def generate_func(a, b, c): ... + + # 2) use the same decorator with an exclude list: + @resolve_formatted_params(exclude=['c']) + def generate_func(a, b, c): ... + + # 3) or inline: + @resolve_params(resolve_env_attr, exclude=['env']) + def generate_func(env, path, mode): ... + + Args: + resolve_func: function whose first parameter is the value to transform. Any additional parameters will be looked up by name in the decorated function's arguments. + + Returns: + A decorator which can be used either as: + @decorator + or: + @decorator(exclude=[...]) + """ + resolve_sig = inspect.signature(resolve_func) + resolve_param_names = list(resolve_sig.parameters.keys()) + + def decorator_factory(*, exclude=()): + exclude = set(exclude) + + def decorator(func): + func_sig = inspect.signature(func) + + @wraps(func) + def wrapper(*args, **kwargs): + bound = func_sig.bind_partial(*args, **kwargs) + bound.apply_defaults() + + # Resolve each argument except those in exclude + resolved = {} + for name, val in bound.arguments.items(): + if name in exclude: + resolved[name] = val + continue + + try: + if len(resolve_param_names) == 1: + # single-arg resolver + resolved_val = resolve_func(val) + else: + # multi-arg resolver: gather extra args by name + extra_kwargs = { + pname: bound.arguments[pname] + for pname in resolve_param_names[1:] + } + resolved_val = resolve_func(val, **extra_kwargs) + resolved[name] = resolved_val + except Exception as e: + log_error(f"{e}") + resolved[name] = val + + # Rebuild positional and keyword args in original order + args_to_pass = [] + kwargs_to_pass = {} + for param in func_sig.parameters.values(): + if param.kind in ( + param.POSITIONAL_ONLY, + param.POSITIONAL_OR_KEYWORD, + ): + if param.name in resolved: + args_to_pass.append(resolved.pop(param.name)) + elif param.kind is param.VAR_POSITIONAL: + args_to_pass.extend(resolved.pop(param.name, ())) + elif param.kind is param.KEYWORD_ONLY: + if param.name in resolved: + kwargs_to_pass[param.name] = resolved.pop(param.name) + elif param.kind is param.VAR_KEYWORD: + kwargs_to_pass.update(resolved.pop(param.name, {})) + + return func(*args_to_pass, **kwargs_to_pass) + + return wrapper + + return decorator + + def decorator_or_factory(func=None, *, exclude=()): + # @decorator + if func is not None and callable(func): + return decorator_factory(exclude=())(func) + # @decorator(exclude=[...]) + return decorator_factory(exclude=exclude) + + return decorator_or_factory + + +resolve_formatted_params = resolve_params(resolve_formatted_string) +resolve_env_params = resolve_params(resolve_env_attr) + + +def transfer_str_to_lambda( + lambda_string: str, locals_dict: Dict = {}, globals_dict: Dict = {} +): + """Transfer the string represented lambda function into a real lambda function. + + Args: + lambda_string (str): The lambda string to be transfer + locals_dict (dict): Read-only dict that carrys local variables for lambda function to use. Defaults to be {}. + globals_dict (dict): Read-only dict that carrys global variables for lambda function to use. Defaults to be {}. + + Returns: + lambda_function: The lambda function + """ + # AST analyze + node = ast.parse(lambda_string, mode="eval") + # Assure the top to be a lambda + if not isinstance(node.body, ast.Lambda): + log_error(f'The lambda string "{lambda_string}" is not illegal.') + # Compile to be a function object + code = compile(node, filename="", mode="eval") + # eval to be a real lambda function + return eval(code, locals_dict, globals_dict) + + +def find_function( + func_name: Union[str, Callable[..., Any]], + instances: List = [], + module_names: List[str] = [], +): + """ + Finds and returns a function by its name from a list of instances or module names. + + Args: + func_name (Union[str, Callable[..., Any]]): The name of the function to find, + or the function itself. + instances (List, optional): A list of instances to search for the function. + Defaults to an empty list. + module_names (List[str], optional): A list of module names to search for the function. + Defaults to an empty list. + + Returns: + Callable[..., Any] or bool: The found function if it exists, otherwise False. + """ + if isinstance(func_name, str): + if any(hasattr(instance := inst, func_name) for inst in instances): + func = getattr(instance, func_name) + elif any( + hasattr((module := import_module(module_name)), func_name) + for module_name in module_names + ): + func = getattr(module, func_name) + else: + return False + else: + func = func_name + return func + + +def find_funcs_with_kwargs( + funcs_name_kwargs_proc: List[Dict[str, Any]], + instances: List, + module_names: List, +): + for func_name_kwargs_proc in funcs_name_kwargs_proc: + func_name = func_name_kwargs_proc["name"] + func = find_function( + func_name, + instances=instances, + module_names=module_names, + ) + if func != False: + func_name_kwargs_proc.update({"func": func}) + else: + log_warning(f"Function {func_name} not found, skipping...") + + return funcs_name_kwargs_proc + + +def validate_with_process( + env, + input: Any, + valid_funcs_kwargs_proc: List[Dict[str, Any]], +): + for valid_func_kwargs_proc in valid_funcs_kwargs_proc: + validation_func = valid_func_kwargs_proc["func"] + kwargs = valid_func_kwargs_proc["kwargs"] + rejected_processes = valid_func_kwargs_proc.get("rejected_processes", None) + pass_processes = valid_func_kwargs_proc.get("pass_processes", None) + + ret = validation_func(input, **kwargs) + if not ret: + log_warning( + f"Validation function {validation_func.__name__} returns False." + ) + if rejected_processes is not None: + log_warning("Processing with rejected_processes..") + for rejected_process in rejected_processes: + rejected_process_func_name = rejected_process["name"] + rejected_process_kwargs = rejected_process.get("kwargs", {}) + + rejected_process_func = find_function( + rejected_process_func_name, + instances=[env], + module_names=[ + __name__, + ], + ) + if rejected_process_func != False: + input = rejected_process_func(input, **rejected_process_kwargs) + else: + log_error( + f"rejected_process_func {rejected_process_func_name} after validation_func {validation_func.__name__} not found." + ) + else: + log_warning("Skipping..") + return None + + if pass_processes is not None: + for pass_process in pass_processes: + pass_process_func_name = pass_process["name"] + pass_process_kwargs = pass_process.get("kwargs", {}) + + pass_process_func = find_function( + pass_process_func_name, + instances=[env], + module_names=[ + __name__, + ], + ) + if pass_process_func != False: + input = pass_process_func(input, **pass_process_kwargs) + else: + log_error( + f"pass_process_func {pass_process_func_name} after validation_func {validation_func.__name__} not found." + ) + + return input + + +def validation_with_process_from_name( + env, + input: List[np.ndarray], + valid_funcs_name_kwargs_proc: List[Dict[str, Any]], + module_names: Optional[List[str]] = None, +): + """Apply a sequence of validation and processing functions (by name) to the input data. + + Args: + env: The environment object, used for method lookup. + input_data: The data to be validated and processed. + valid_funcs_name_kwargs_proc: List of dicts, each specifying a function name and kwargs. + module_names: List of module names to search for functions. Defaults to [__name__]. + + Returns: + The processed data if all validations pass, otherwise None. + """ + if valid_funcs_name_kwargs_proc is None: + valid_funcs_name_kwargs_proc = [] + if module_names is None: + module_names = [__name__] + + valid_funcs_kwargs_proc = find_funcs_with_kwargs( + valid_funcs_name_kwargs_proc, + instances=[env], + module_names=[__name__], + ) + valid_output = validate_with_process(env, input, valid_funcs_kwargs_proc) + return valid_output + + +def _get_valid_grasp( + env, + grasp_list: List[np.ndarray], + valid_funcs_name_kwargs_proc: List[Union[str, Dict[str, Any]]], +) -> np.ndarray: + """TODO 懒狗了,总而言之言而总之就是一个函数,可以集成一堆validation function,检验grasp_pose是否valid,也可以再特定的alidatrion function后面跟一堆process + + Args: + env: TODO + grasp_list (List[np.ndarray]): TODO + validation_func_names_kwargs (Dict[str, dict]): TODO + validation_func_names_process (Optional[Dict[str, Dict[str, dict]]], optional): TODO. Defaults to None. + + Returns: + np.ndarray: TODO + """ + valid_func_kwargs_proc = find_funcs_with_kwargs( + valid_funcs_name_kwargs_proc, instances=[env], module_names=[__name__] + ) + + for grasp in grasp_list: + grasp_pose = grasp.pose # TODO: be a func? + grasp_pose = validate_with_process(env, grasp_pose, valid_func_kwargs_proc) + # The loop is broken as ONE validation results is False + if grasp_pose is None: + continue + # All validation results are True in the loop + else: + return grasp_pose + return None + + +def lru_cache_n(maxsize: int = 10, max_count: int = 2) -> Callable: + """ + Decorator to provide an LRU cache with a maximum call count per key. + After a key is accessed `max_count` times, the result will be recomputed. + + Args: + maxsize: Maximum number of cache entries. + max_count: Number of times a cached result can be returned before recomputation. + + Returns: + Decorator for caching function results. + """ + + def decorator(func): + cache = OrderedDict() + + def _make_hashable(x): + try: + hash(x) + return x + except TypeError: + if isinstance(x, np.ndarray): + return (x.shape, str(x.dtype), x.tobytes()) + if isinstance(x, dict): + return tuple(sorted((k, _make_hashable(v)) for k, v in x.items())) + if isinstance(x, set): + return tuple(sorted(_make_hashable(i) for i in x)) + if isinstance(x, (list, tuple)): + return tuple(_make_hashable(i) for i in x) + raise TypeError(f"Unhashable type in cache key: {type(x)}") + + @wraps(func) + def wrapper(*args, **kwargs): + key = ( + tuple(_make_hashable(a) for a in args), + tuple(sorted((k, _make_hashable(v)) for k, v in kwargs.items())), + ) + res, cnt = cache.pop(key, (None, max_count)) + if cnt == max_count: + res, cnt = func(*args, **kwargs), 0 + cache[key] = (res, cnt + 1) + if len(cache) > maxsize: + cache.popitem(last=False) + return res + + return wrapper + + return decorator + + +def multi_output_factory_function( + func_name: Union[str, Callable], + instances: Optional[List] = None, + module_names: Optional[List[str]] = None, + output_num: int = 1, +) -> Callable: + """ + Factory to create a cached version of a function that may have multiple outputs. + + Args: + func_name: Function name (str) or function object. + instances: The instances that may carrys the method that match the func_name. + Usually be environment that carrys the methods wherein the function may be found. + module_names: The list of modules that the function may be found. Defaults to []. + output_num: Number of outputs expected from the function. + + Returns: + Cached function callable. + """ + if instances is None: + instances = [] + if module_names is None: + module_names = [] + func = find_function(func_name, instances, module_names) + if not callable(func): + raise ValueError(f"Function {func_name} not found or not callable.") + + max_count = max(1, output_num - 1) + + @lru_cache_n(max_count=max_count) + def cached_func(*args, **kwargs): + return func(*args, **kwargs) + + return cached_func + + +def cached_ik( + target_xpos: np.ndarray, + ik_func: Union[str, Callable], + control_part: str, + is_left: bool, + qpos_seed: np.ndarray, + instances: list = [], + module_names: list = [], +) -> tuple: + """ + Call the inverse kinematics (IK) function with caching for efficiency. + + Args: + target_xpos: The target end-effector position (usually a numpy array). + ik_func: The IK function or function name to be called. + control_part: String of the cotrol part for IK computing. + is_left: Whether the control part is on the left side. + qpos_seed: The initial guess for the joint positions. + instances: The instances that may carrys the method that match the func_name. + Usually be environment that carrys the methods wherein the function may be found. + module_names: The list of modules that the function may be found. Defaults to []. + + Returns: + Tuple: (ik_result, qpos_result), where ik_result is the IK status and qpos_result is the joint solution. + """ + # cached_ik_func = multi_output_factory_function("_get_arm_ik", instances=[env], module_names=[__name__], output_num=2) + cached_ik_func = multi_output_factory_function( + ik_func, instances=instances, module_names=module_names, output_num=2 + ) + if control_part == "none": + return cached_ik_func(target_xpos, is_left, qpos_seed) + + ret, qpos = cached_ik_func(torch.as_tensor(target_xpos), qpos_seed, control_part) + if isinstance(ret, torch.Tensor): + ret = ret.all().item() + return ret, qpos.squeeze(0).cpu().numpy() + + +def get_ik_ret( + target_xpos: np.ndarray, + ik_func: Union[str, Callable], + qpos_seed: np.ndarray, + control_part: str = "none", + is_left: bool = True, + instances: list = [], + module_names: list = [], +) -> bool: + """ + Get the first return value from the cached IK function, typically the IK status or result flag. + + Args: + target_xpos: The target end-effector position. + ik_func: The IK function or function name to be called. + control_part: String of the cotrol part for IK computing. + qpos_seed: The initial guess for the joint positions. + instances: The instances that may carrys the method that match the func_name. + Usually be environment that carrys the methods wherein the function may be found. + module_names: The list of modules that the function may be found. Defaults to []. + + Returns: + The first output of the IK function (e.g., success flag or status). + """ + ret = cached_ik( + target_xpos, + ik_func, + control_part, + is_left, + qpos_seed, + instances=instances, + module_names=module_names, + )[0] + return ret + + +def get_ik_qpos( + target_xpos: np.ndarray, + ik_func: Union[str, Callable], + qpos_seed: np.ndarray, + control_part: str = "none", + is_left: bool = True, + instances: list = [], + module_names: list = [], +) -> np.ndarray: + """ + Get the second return value from the cached IK function, typically the joint positions. + + Args: + target_xpos: The target end-effector position. + ik_func: The IK function or function name to be called. + control_part: String of the control part for IK computing. + is_left: Whether the control part is on the left side. Defaults to True. + qpos_seed: The initial guess for the joint positions. + instances: The instances that may carrys the method that match the func_name. + Usually be environment that carrys the methods wherein the function may be found. + module_names: The list of modules that the function may be found. Defaults to []. + + Returns: + The second output of the IK function (e.g., the joint position solution). + """ + qpos = cached_ik( + target_xpos, + ik_func, + control_part, + is_left, + qpos_seed, + instances=instances, + module_names=module_names, + )[1] + return qpos + + +def get_fk_xpos( + target_qpos: np.ndarray, + control_part: str, + fk_func: Union[str, Callable], +) -> np.ndarray: + xpos = fk_func(name=control_part, qpos=torch.as_tensor(target_qpos), to_matrix=True) + + # the xpos computed from robot is in the local arena frame, which is equivalent to world frame of the + # old version. + return xpos.squeeze(0).cpu().numpy() + + +# FIXME: remove +def _data_key_to_control_part(robot, control_parts, data_key: str) -> Optional[str]: + # TODO: Temporary workaround, should be removed after refactoring data dict extractor. + # @lru_cache(max_size=None) # NOTE: no way to pass a hashable parameter + def is_eef_hand(robot, control_parts) -> bool: + # TODO: This is a temporary workaround, should be used a more general method to check + # whether the end-effector is a hand. + for part in control_parts: + if "eef" in part: + joint_ids = robot.get_joint_ids(part, remove_mimic=True) + return len(joint_ids) >= 2 + return False + + if "left_arm" in data_key: + if "qpos" in data_key: + return "left_arm" + if "hand" in data_key and is_eef_hand(robot, control_parts): + return "left_eef" + if "gripper" in data_key and is_eef_hand(robot, control_parts) is False: + return "left_eef" + return None + + if "right_arm" in data_key: + if "qpos" in data_key: + return "right_arm" + if "hand" in data_key and is_eef_hand(robot, control_parts): + return "right_eef" + if "gripper" in data_key and is_eef_hand(robot, control_parts) is False: + return "right_eef" + return None + + +# FIXME: only for v3 W1 +def map_ee_state_to_env_actions( + robot, ee_state: np.ndarray, env_actions: np.ndarray +) -> np.ndarray: + """ + Map end-effector (gripper) state to environment joint actions. + + Args: + ee_state (np.ndarray): Normalized gripper state, shape (batch, 2). + env_actions (np.ndarray): Environment joint actions to be updated. + + Returns: + np.ndarray: Updated environment joint actions with gripper positions. + """ + from embodichain.data.enum import ControlParts, JointType, EndEffector + + left_eef_limits = ( + robot.body_data.qpos_limits.squeeze(0) + .cpu() + .numpy()[robot.get_joint_ids(name=ControlParts.LEFT_EEF.value)] + ) + right_eef_limits = ( + robot.body_data.qpos_limits.squeeze(0) + .cpu() + .numpy()[robot.get_joint_ids(name=ControlParts.RIGHT_EEF.value)] + ) + + def w1_gripper_mapping(normalized_state, eef_limits): + # Define normalized open/close positions for the gripper (range 0-1) + open_state_normalized = np.array([90.0, 0.0, 0.0, 0.0, 0.0, 0.0]) / 100.0 + close_state_normalized = np.array([90.0, 55.0, 30.0, 30.0, 30.0, 30.0]) / 100.0 + + # Convert normalized values to actual joint angles + open_state_actual = eef_limits[:, 0] + open_state_normalized * ( + eef_limits[:, 1] - eef_limits[:, 0] + ) + close_state_actual = eef_limits[:, 0] + close_state_normalized * ( + eef_limits[:, 1] - eef_limits[:, 0] + ) + + # Interpolate between open and close joint angles + if isinstance(normalized_state, np.ndarray) and normalized_state.ndim > 0: + return ( + open_state_actual * (1 - normalized_state[:, None]) + + close_state_actual * normalized_state[:, None] + ) + else: + return ( + open_state_actual * (1 - normalized_state) + + close_state_actual * normalized_state + ) + + if ee_state.ndim == 1: + ee_state = ee_state.reshape(1, -1) + if env_actions.ndim == 1: + env_actions = env_actions.reshape(1, -1) + + # Map normalized gripper state to actual joint positions + left_hand_qpos = w1_gripper_mapping(ee_state[:, 0], left_eef_limits) + right_hand_qpos = w1_gripper_mapping(ee_state[:, 1], right_eef_limits) + + # Get indices for left and right end-effector joints + left_eef_ids = robot.get_joint_ids(name=ControlParts.LEFT_EEF.value) + right_eef_ids = robot.get_joint_ids(name=ControlParts.RIGHT_EEF.value) + + env_actions[:, left_eef_ids] = left_hand_qpos + env_actions[:, right_eef_ids] = right_hand_qpos + return env_actions diff --git a/embodichain/lab/gym/utils/registration.py b/embodichain/lab/gym/utils/registration.py new file mode 100644 index 00000000..a3e9c61f --- /dev/null +++ b/embodichain/lab/gym/utils/registration.py @@ -0,0 +1,204 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import json +import sys +from copy import deepcopy +from functools import partial +from typing import TYPE_CHECKING, Dict, Type + +import gymnasium as gym +from gymnasium.envs.registration import EnvSpec as GymEnvSpec +from gymnasium.envs.registration import WrapperSpec + +from dexsim.utility import log_warning + +if TYPE_CHECKING: + from embodichain.lab.gym.envs import BaseEnv + + +class EnvSpec: + def __init__( + self, + uid: str, + cls: Type[BaseEnv], + max_episode_steps=None, + default_kwargs: dict = None, + ): + """A specification for a Embodied environment.""" + self.uid = uid + self.cls = cls + self.max_episode_steps = max_episode_steps + self.default_kwargs = {} if default_kwargs is None else default_kwargs + + def make(self, **kwargs): + _kwargs = self.default_kwargs.copy() + _kwargs.update(kwargs) + return self.cls(**_kwargs) + + @property + def gym_spec(self): + """Return a gym EnvSpec for this env""" + entry_point = self.cls.__module__ + ":" + self.cls.__name__ + return GymEnvSpec( + self.uid, + entry_point, + max_episode_steps=self.max_episode_steps, + kwargs=self.default_kwargs, + ) + + +REGISTERED_ENVS: Dict[str, EnvSpec] = {} + + +def register( + name: str, cls: Type[BaseEnv], max_episode_steps=None, default_kwargs: dict = None +): + """Register a Embodied environment.""" + + # hacky way to avoid circular import errors when users inherit a task in DexSim and try to register it themselves + from embodichain.lab.gym.envs import BaseEnv, BaseEnv + + if name in REGISTERED_ENVS: + log_warning(f"Env {name} already registered") + if not (issubclass(cls, BaseEnv) or issubclass(cls, BaseEnv)): + raise TypeError(f"Env {name} must inherit from BaseEnv or BaseEnv") + REGISTERED_ENVS[name] = EnvSpec( + name, cls, max_episode_steps=max_episode_steps, default_kwargs=default_kwargs + ) + + +class TimeLimitWrapper(gym.Wrapper): + """like the standard gymnasium timelimit wrapper but fixes truncated variable to be a batched array""" + + def __init__(self, env: gym.Env, max_episode_steps: int): + super().__init__(env) + prev_frame_locals = sys._getframe(1).f_locals + frame = sys._getframe(1) + # check for user supplied max_episode_steps during gym.make calls + if frame.f_code.co_name == "make" and "max_episode_steps" in prev_frame_locals: + if prev_frame_locals["max_episode_steps"] is not None: + max_episode_steps = prev_frame_locals["max_episode_steps"] + # do some wrapper surgery to remove the previous timelimit wrapper + # with gymnasium 0.29.1, this will remove the timelimit wrapper and nothing else. + curr_env = env + while curr_env is not None: + if isinstance(curr_env, gym.wrappers.TimeLimit): + self.env = curr_env.env + break + self._max_episode_steps = max_episode_steps + + @property + def base_env(self) -> BaseEnv: + return self.env.unwrapped + + def step(self, action): + observation, reward, terminated, truncated, info = self.env.step(action) + truncated = truncated | (self.base_env.elapsed_steps >= self._max_episode_steps) + return observation, reward, terminated, truncated, info + + +def make(env_id, **kwargs): + """Instantiate a Embodied environment. + + Args: + env_id (str): Environment ID. + as_gym (bool, optional): Add TimeLimit wrapper as gym. + **kwargs: Keyword arguments to pass to the environment. + """ + if env_id not in REGISTERED_ENVS: + raise KeyError("Env {} not found in registry".format(env_id)) + env_spec = REGISTERED_ENVS[env_id] + + env = env_spec.make(**kwargs) + return env + + +def make_vec(env_id, **kwargs): + env = gym.make(env_id, **kwargs) + return env + + +def register_env(uid: str, max_episode_steps=None, override=False, **kwargs): + """A decorator to register Embodied environments. + + Args: + uid (str): unique id of the environment. + max_episode_steps (int): maximum number of steps in an episode. + override (bool): whether to override the environment if it is already registered. + + Notes: + - `max_episode_steps` is processed differently from other keyword arguments in gym. + `gym.make` wraps the env with `gym.wrappers.TimeLimit` to limit the maximum number of steps. + - `gym.EnvSpec` uses kwargs instead of **kwargs! + """ + try: + json.dumps(kwargs) + except TypeError: + raise RuntimeError( + f"You cannot register_env with non json dumpable kwargs, e.g. classes or types. If you really need to do this, it is recommended to create a mapping of string to the unjsonable data and to pass the string in the kwarg and during env creation find the data you need" + ) + + def _register_env(cls): + cls = register_env_function(cls, uid, override, max_episode_steps, **kwargs) + return cls + + return _register_env + + +def register_env_function(cls, uid, override=False, max_episode_steps=None, **kwargs): + if uid in REGISTERED_ENVS: + if override: + from gymnasium.envs.registration import registry + + log_warning(f"Override registered env {uid}") + REGISTERED_ENVS.pop(uid) + registry.pop(uid) + else: + log_warning(f"Env {uid} is already registered. Skip registration.") + return cls + + # Register for ManiSkil2 + register( + uid, + cls, + max_episode_steps=max_episode_steps, + default_kwargs=deepcopy(kwargs), + ) + + # Register for gym + gym.register( + uid, + entry_point=partial(make, env_id=uid), + vector_entry_point=partial(make_vec, env_id=uid), + max_episode_steps=max_episode_steps, + disable_env_checker=True, # Temporary solution as we allow empty observation spaces + kwargs=deepcopy(kwargs), + additional_wrappers=[ + WrapperSpec( + "MSTimeLimit", + entry_point="embodichain.lab.gym.utils.registration:TimeLimitWrapper", + kwargs=dict(max_episode_steps=max_episode_steps) + if max_episode_steps is not None + else {}, + ) + ] + if max_episode_steps is not None + else [], + ) + return cls diff --git a/embodichain/lab/scripts/generate_video.py b/embodichain/lab/scripts/generate_video.py new file mode 100644 index 00000000..4b51b3dd --- /dev/null +++ b/embodichain/lab/scripts/generate_video.py @@ -0,0 +1,162 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from embodichain.utils.logger import log_info, log_warning + +import h5py +import argparse +import numpy as np +import os + +from tqdm import tqdm +from dexsim.utility import images_to_video +from typing import Dict, Callable, Tuple +from embodichain.utils.visualizer import draw_keypoints, draw_action_distribution +from embodichain.data.enum import EefType, JointType, Modality, PrivilegeType +from embodichain.data.data_engine.unified_state import ActionIndicesGenerator + + +class VideoCreator: + def __init__(self) -> None: + pass + + @staticmethod + def _sub_function( + images, + output_path, + video_key, + exteroceptions: Dict = None, + multiplier: int = 1, + drawer: Callable = lambda x: x, + ): + for key in images.keys(): + imgs = images[key] + if imgs is None: + log_warning(f"No images found for key: {key}. Skipping.") + continue + img_list = [] + for i in tqdm(range(imgs.shape[0])): + image_i = drawer(imgs[i] * multiplier) + if exteroceptions is not None and len(exteroceptions[key]) != 0: + image_i = draw_keypoints( + image_i, exteroceptions[key][i].reshape(-1, 2) + ) + img_list.append(image_i) + + images_to_video(img_list, output_path, f"{key}_{video_key}") + + @staticmethod + def monocular_save( + observations: Dict, + video_key: str, + output_path: str, + multiplier: int = 1, + drawer: Callable = lambda x: x, + draw_exteroception: bool = True, + ): + images = observations[video_key] + if ( + PrivilegeType.EXTEROCEPTION.value in observations.keys() + and draw_exteroception + ): + exteroceptions = observations[PrivilegeType.EXTEROCEPTION.value] + else: + exteroceptions = None + VideoCreator._sub_function( + images, + output_path, + video_key, + exteroceptions, + multiplier, + drawer, + ) + + +def visualize_data_dict(f: Dict, output_path: str): + observations = f["observations"] + + if PrivilegeType.MASK.value in observations.keys(): + VideoCreator.monocular_save( + observations, + PrivilegeType.MASK.value, + output_path, + 255, + draw_exteroception=False, + ) + + if Modality.GEOMAP.value in observations.keys(): + from embodichain.utils.img_utils import gen_disp_colormap + + VideoCreator.monocular_save( + observations, + Modality.GEOMAP.value, + output_path, + 1, + lambda x: (gen_disp_colormap(x).transpose(1, 2, 0) * 255).astype(np.uint8), + draw_exteroception=False, + ) + + VideoCreator.monocular_save(observations, Modality.IMAGES.value, output_path) + + +def main(args): + + data_path = args.data_path + output_path = args.output_path + assert data_path.endswith(".hdf5"), "Data path must have format of .hdf5" + with h5py.File(data_path, "r") as f: + from embodichain.data.data_engine.data_dict_extractor import ( + CompressedVideoHDF5, + ) + import hdfdict + + data = hdfdict.load(data_path) + data = CompressedVideoHDF5(output_path).safe_filter(data) + + visualize_data_dict(data, output_path) + robot_meta = data["robot_meta"] + arm_dofs = robot_meta["arm_dofs"][()] + indices_generator = ActionIndicesGenerator(arm_dofs) + + actions = f[Modality.ACTIONS.value][()] + key_names = indices_generator.global_mapping.mapping_from_name_to_indices.keys() + log_info(f"Arm dofs: {arm_dofs}", color="green") + indices_dict = {} + for key_name in key_names: + indices_dict[key_name] = indices_generator.get([key_name]) + draw_action_distribution(actions, indices_dict, output_path, smooth=args.smooth) + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("--data_path", type=str, help="Path to the data file.") + parser.add_argument( + "--output_path", + type=str, + help="Path to the output video file.", + default="./outputs", + ) + parser.add_argument( + "--smooth", + action="store_true", + default=False, + help="whether smooth joints.", + ) + args = parser.parse_args() + + main(args) diff --git a/embodichain/lab/scripts/preview_env.py b/embodichain/lab/scripts/preview_env.py new file mode 100644 index 00000000..9357584d --- /dev/null +++ b/embodichain/lab/scripts/preview_env.py @@ -0,0 +1,149 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import gymnasium +import argparse +import numpy as np + +from embodichain.lab.sim import SimulationManagerCfg +from embodichain.lab.gym.envs import EmbodiedEnvCfg +from embodichain.lab.gym.utils.gym_utils import ( + config_to_cfg, +) +from embodichain.utils.utility import load_json +from embodichain.utils import logger + +if __name__ == "__main__": + np.set_printoptions(precision=5, suppress=True) + torch.set_printoptions(precision=5, sci_mode=False) + + parser = argparse.ArgumentParser() + parser.add_argument( + "--num_envs", + help="The number of environments to run in parallel.", + default=1, + type=int, + ) + parser.add_argument( + "--device", + type=str, + default="cpu", + help="device to run the environment on, e.g., 'cpu' or 'cuda'", + ) + parser.add_argument( + "--headless", + help="Whether to perform the simulation in headless mode.", + default=False, + action="store_true", + ) + parser.add_argument( + "--enable_rt", + help="Whether to use RTX rendering backend for the simulation.", + default=False, + action="store_true", + ) + parser.add_argument( + "--gpu_id", + help="The GPU ID to use for the simulation.", + default=0, + type=int, + ) + parser.add_argument( + "--enable_sensors_in_step", + help="Whether to enable sensors in each step of the simulation.", + default=False, + action="store_true", + ) + parser.add_argument("--gym_config", type=str, help="gym_config", default="") + parser.add_argument( + "--action_config", + type=str, + help="Path to the action configuration file.", + default=None, + ) + parser.add_argument( + "--filter_visual_rand", + help="Whether to filter out visual randomization.", + default=False, + action="store_true", + ) + + args = parser.parse_args() + + """ + TODO: Currently, this file is only used to preview the template.json config file. + We may add more features to support more general case parsing from config files. + """ + + ############################################################################################## + # load gym config + gym_config = load_json(args.gym_config) + cfg: EmbodiedEnvCfg = config_to_cfg(gym_config) + cfg.filter_visual_rand = args.filter_visual_rand + + action_config = {} + if args.action_config is not None: + action_config = load_json(args.action_config) + action_config["action_config"] = action_config + + cfg.num_envs = args.num_envs + cfg.sim_cfg = SimulationManagerCfg( + headless=args.headless, + sim_device=args.device, + enable_rt=args.enable_rt, + gpu_id=args.gpu_id, + ) + + env = gymnasium.make(id=gym_config["id"], cfg=cfg, **action_config) + + if args.enable_sensors_in_step is False: + pass + + obs, info = env.reset() + + """ + Run the following code to create a demonstration and perform env steps. + + ``` + # Demo version of environment rollout + for i in range(10): + qpos = env.robot.get_qpos() + + obs, reward, done, truncated, info = env.step(qpos) + + # reset the environment + env.reset() + ``` + + Run the following code to preview the sensor observations. + + ``` + env.preview_sensor_data("camera") + ``` + """ + + end = False + while end is False: + print("Press `p` to into embed mode to interact with the environment.") + print("Press `q` to quit the simulation.") + txt = input() + if txt == "p": + from IPython import embed + + embed() + elif txt == "q": + end = True diff --git a/embodichain/lab/scripts/run_env.py b/embodichain/lab/scripts/run_env.py new file mode 100644 index 00000000..5fcb07fa --- /dev/null +++ b/embodichain/lab/scripts/run_env.py @@ -0,0 +1,301 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import gymnasium +import numpy as np +import argparse +import os +import torch + +from threading import Thread + +from embodichain.utils.utility import load_json +from embodichain.lab.sim import SimulationManagerCfg +from embodichain.lab.gym.envs import EmbodiedEnvCfg +from embodichain.lab.gym.utils.gym_utils import ( + config_to_cfg, +) +from embodichain.lab.scripts.generate_video import visualize_data_dict +from embodichain.data.data_engine.online.online_generator import ( + OnlineGenerator, +) +from embodichain.utils.logger import log_warning, log_info, log_error +from embodichain.lab.sim.cfg import MarkerCfg + + +def generate_and_execute_action_list(env, idx, debug_mode): + + action_list = env.create_demo_action_list(action_sentence=idx) + + # TODO: To be modified. + # if debug_mode: + # env.visual_action(action_list) + + if action_list is None or len(action_list) == 0: + log_warning("Action is invalid. Skip to next generation.") + return False + + for action in action_list: + # Step the environment with the current action + obs, reward, terminated, truncated, info = env.step(action) + + # TODO: To be modified. + # if debug_mode: + # xpos_dict = env.agent.get_debug_xpos_dict() + + # for key, val in xpos_dict.items(): + # env.scene.draw_marker(cfg=MarkerCfg( + # marker_type="axis", + # axis_xpos=val, + # axis_size=0.002, + # axis_len=0.005 + # )) + + # for key, val in xpos_dict.items(): + # env.scene.remove_fixed_actor(key) + + # TODO: we may assume in export demonstration rollout, there is no truncation from the env. + # but truncation is useful to improve the generation efficiency. + + return True + + +def generate_function( + env, + obj_num, + time_id: int = 0, + online_training: bool = False, + save_path: str = "", + save_video: bool = False, + debug_mode: bool = False, + **kwargs, +): + """ + Generate and execute a sequence of actions in the environment. + + This function resets the environment, generates and executes action trajectories, + collects data, and optionally saves videos of the episodes. It supports both online + and offline data generation modes. + + Args: + env: The environment instance. + obj_num (int): Number of trajectories to generate per episode. + time_id (int, optional): Identifier for the current time step or episode. + online_training (bool, optional): Whether to use online data generation. + save_path (str, optional): Path to save generated videos. + save_video (bool, optional): Whether to save episode videos. + debug_mode (bool, optional): Enable debug mode for visualization and logging. + **kwargs: Additional keyword arguments for data generation. + + Returns: + list or bool: Returns a list of data dicts if online_training is True, + otherwise returns True if generation is successful. + """ + + def wait_for_threads(threads): + for t in threads: + t.join() + + vis_threads = [] + valid = True + while True: + _, _ = env.reset() + + ret = [] + for trajectory_idx in range(obj_num): + valid = generate_and_execute_action_list(env, trajectory_idx, debug_mode) + + if not valid: + log_warning("Invalid action, skipping trajectory.") + break + + if not debug_mode and env.is_task_success().item(): + # Create a unique identifier for the dataset entry + dataset_id = f"time_{time_id}_trajectory_{trajectory_idx}" + if online_training: + dataset_id += "_online_generated" + num_samples = kwargs.get("num_samples", 0) + is_save_dataset = time_id < num_samples + + data_dict = env.to_dataset( + id=dataset_id if is_save_dataset else None, + ) + + ret.append(data_dict) + else: + data_dict = env.to_dataset( + id=dataset_id, + ) + + episode = getattr(env, "get_current_episode", lambda: time_id)() + + if save_video: + video_path = os.path.join(save_path, f"episode_{episode}") + if online_training: + vis_thread = Thread( + target=visualize_data_dict, + args=(data_dict["data"], video_path), + daemon=True, + ) + vis_thread.start() + vis_threads.append(vis_thread) + else: + visualize_data_dict(data_dict["data"], video_path) + + else: + log_warning(f"Task fail, Skip to next generation.") + valid = False + break + + if valid: + break + else: + log_warning("Reset valid flag to True.") + valid = True + + wait_for_threads(vis_threads) + return ret if online_training else True + + +def main(args, env, gym_config): + is_online_training = os.path.exists(args.online_config) + if is_online_training: + + log_info("Start online data generation.", color="green") + assert os.path.exists(args.online_config), "{} does not exist.".format( + args.online_config + ) + + online_config = load_json(args.online_config) + online_callback = OnlineGenerator(**online_config) + + obj_num = 1 + generator_func = lambda time_id, **kwargs: generate_function( + env, + obj_num, + time_id, + online_training=is_online_training, + save_path=args.save_path, + save_video=args.save_video, + headless=args.headless, + **kwargs, + ) + online_callback.generator(generator_func, **online_config) + else: + log_info("Start offline data generation.", color="green") + obj_num = 1 + for i in range(gym_config["max_episodes"]): + generate_function( + env, + obj_num, + i, + online_training=is_online_training, + save_path=args.save_path, + save_video=args.save_video, + debug_mode=args.debug_mode, + ) + + if args.headless: + env.reset(options={"final": True}) + + +if __name__ == "__main__": + np.set_printoptions(5, suppress=True) + torch.set_printoptions(precision=5, sci_mode=False) + + parser = argparse.ArgumentParser() + # parser.add_argument("--task_type", help="Type of task to perform.") + # parser.add_argument("--robot_name", help="Name of the robot.") + parser.add_argument( + "--num_envs", + help="The number of environments to run in parallel.", + default=1, + type=int, + ) + parser.add_argument( + "--device", + type=str, + default="cpu", + help="device to run the environment on, e.g., 'cpu' or 'cuda'", + ) + parser.add_argument( + "--headless", + help="Whether to perform the simulation in headless mode.", + default=False, + action="store_true", + ) + parser.add_argument( + "--enable_rt", + help="Whether to use RTX rendering backend for the simulation.", + default=False, + action="store_true", + ) + parser.add_argument( + "--gpu_id", + help="The GPU ID to use for the simulation.", + default=0, + type=int, + ) + parser.add_argument( + "--save_video", + help="Whether to save data as video.", + default=False, + action="store_true", + ) + parser.add_argument( + "--save_path", help="path", default="./outputs/thirdviewvideo", type=str + ) + parser.add_argument( + "--debug_mode", + help="Enable debug mode.", + default=False, + action="store_true", + ) + parser.add_argument( + "--filter_visual_rand", + help="Whether to filter out visual randomization.", + default=False, + action="store_true", + ) + + parser.add_argument("--online_config", type=str, help="online_config", default="") + parser.add_argument("--gym_config", type=str, help="gym_config", default="") + parser.add_argument("--action_config", type=str, help="action_config", default=None) + + args = parser.parse_args() + + if args.num_envs != 1: + log_error(f"Currently only support num_envs=1, but got {args.num_envs}.") + + gym_config = load_json(args.gym_config) + cfg: EmbodiedEnvCfg = config_to_cfg(gym_config) + cfg.filter_visual_rand = args.filter_visual_rand + + action_config = {} + if args.action_config is not None: + action_config = load_json(args.action_config) + action_config["action_config"] = action_config + + cfg.num_envs = args.num_envs + cfg.sim_cfg = SimulationManagerCfg( + headless=args.headless, + sim_device=args.device, + enable_rt=args.enable_rt, + gpu_id=args.gpu_id, + ) + + env = gymnasium.make(id=gym_config["id"], cfg=cfg, **action_config) + main(args, env, gym_config) diff --git a/embodichain/lab/sim/__init__.py b/embodichain/lab/sim/__init__.py new file mode 100644 index 00000000..9ec8105a --- /dev/null +++ b/embodichain/lab/sim/__init__.py @@ -0,0 +1,19 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .material import VisualMaterialCfg, VisualMaterial, VisualMaterialInst +from .common import BatchEntity +from .sim_manager import * diff --git a/embodichain/lab/sim/cfg.py b/embodichain/lab/sim/cfg.py new file mode 100644 index 00000000..396c71f3 --- /dev/null +++ b/embodichain/lab/sim/cfg.py @@ -0,0 +1,1051 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations +import os +import numpy as np +import torch + +from typing import Sequence, Union, Dict, Literal, List, Optional, Any +from dataclasses import field, MISSING + +from dexsim.types import ( + PhysicalAttr, + ActorType, + AxisArrowType, + AxisCornerType, + VoxelConfig, + SoftBodyAttr, + SoftBodyMaterialModel, +) +from embodichain.utils import configclass, is_configclass +from embodichain.data.constants import EMBODICHAIN_DEFAULT_DATA_ROOT +from embodichain.data import get_data_path +from embodichain.utils import logger +from embodichain.utils.utility import key_in_nested_dict + +from .shapes import ShapeCfg, MeshCfg + + +@configclass +class PhysicsCfg: + gravity: np.ndarray = field(default_factory=lambda: np.array([0, 0, -9.81])) + bounce_threshold: float = 2.0 + enable_pcm: bool = True + enable_tgs: bool = True + enable_ccd: bool = False + enable_enhanced_determinism: bool = False + enable_friction_every_iteration: bool = True + + length_tolerance: float = 0.05 + """The length tolerance for the simulation. + + Note: the larger the tolerance, the faster the simulation will be. + """ + speed_tolerance: float = 0.25 + """The speed tolerance for the simulation. + + Note: the larger the tolerance, the faster the simulation will be. + """ + + def to_dexsim_args(self) -> Dict[str, Any]: + """Convert to dexsim physics args dictionary.""" + args = { + "gravity": self.gravity.tolist(), + "bounce_threshold": self.bounce_threshold, + "enable_pcm": self.enable_pcm, + "enable_tgs": self.enable_tgs, + "enable_ccd": self.enable_ccd, + "enable_enhanced_determinism": self.enable_enhanced_determinism, + "enable_friction_every_iteration": self.enable_friction_every_iteration, + } + return args + + +@configclass +class MarkerCfg: + """Configuration for visual markers in the simulation. + + This class defines properties for creating visual markers such as coordinate frames, + lines, and points that can be used for debugging, visualization, or reference purposes + in the simulation environment. + """ + + name: str = "empty-mesh" + """Name of the marker for identification purposes.""" + marker_type: Literal["axis", "line", "point"] = "axis" + """Type of marker to display. Can be 'axis' (3D coordinate frame), 'line', or 'point'. (only axis supported now)""" + axis_xpos: List[np.ndarray] = None + """List of 4x4 transformation matrices defining the position and orientation of each axis marker.""" + axis_size: float = 0.002 + """Thickness/size of the axis lines in meters.""" + axis_len: float = 0.005 + """Length of each axis arm in meters.""" + line_color: List[float] = [1, 1, 0, 1.0] + """RGBA color values for the marker lines. Values should be between 0.0 and 1.0.""" + arrow_type: AxisArrowType = AxisArrowType.CONE + """Type of arrow head for axis markers (e.g., CONE, ARROW, etc.).""" + corner_type: AxisCornerType = AxisCornerType.SPHERE + """Type of corner/joint visualization for axis markers (e.g., SPHERE, CUBE, etc.).""" + arena_index: int = -1 + """Index of the arena where the marker should be placed. -1 means all arenas.""" + + +@configclass +class GPUMemoryCfg: + """A gpu memory configuration dataclass that neatly holds all parameters that configure physics GPU memory for simulation""" + + temp_buffer_capacity: int = 2**24 + """Increase this if you get 'PxgPinnedHostLinearMemoryAllocator: overflowing initial allocation size, increase capacity to at least %.' """ + max_rigid_contact_count: int = 2**19 + """Increase this if you get 'Contact buffer overflow detected'""" + max_rigid_patch_count: int = ( + 2**18 + ) # 81920 is DexSim default but most tasks work with 2**18 + """Increase this if you get 'Patch buffer overflow detected'""" + heap_capacity: int = 2**26 + found_lost_pairs_capacity: int = ( + 2**25 + ) # 262144 is DexSim default but most tasks work with 2**25 + found_lost_aggregate_pairs_capacity: int = 2**10 + total_aggregate_pairs_capacity: int = 2**10 + + +@configclass +class RigidBodyAttributesCfg: + """Physical attributes for rigid bodies. + + There are three parts of attributes that can be set: + 1. The dynamic properties, such as mass, damping, etc. + 2. The collision properties. + 3. The physics material properties. + """ + + mass: float = 1.0 + # set mass to 0 will use density to calculate mass. + density: float = 1000.0 + + angular_damping: float = 0.7 + linear_damping: float = 0.7 + max_depenetration_velocity: float = 10.0 + sleep_threshold: float = 0.001 + min_position_iters: int = 4 + min_velocity_iters: int = 1 + + max_linear_velocity: float = 1e2 + max_angular_velocity: float = 1e2 + + # collision properties. + enable_ccd: bool = False + contact_offset: float = 0.002 + rest_offset: float = 0.001 + enable_collision: bool = True + + # physics material properties. + restitution: float = 0.0 + dynamic_friction: float = 0.5 + static_friction: float = 0.5 + + def attr(self) -> PhysicalAttr: + """Convert to dexsim PhysicalAttr""" + attr = PhysicalAttr() + attr.mass = self.mass + attr.contact_offset = self.contact_offset + attr.rest_offset = self.rest_offset + attr.enable_collision = self.enable_collision + attr.dynamic_friction = self.dynamic_friction + attr.static_friction = self.static_friction + attr.angular_damping = self.angular_damping + attr.linear_damping = self.linear_damping + attr.sleep_threshold = self.sleep_threshold + attr.restitution = self.restitution + attr.enable_ccd = self.enable_ccd + attr.max_depenetration_velocity = self.max_depenetration_velocity + attr.min_position_iters = self.min_position_iters + attr.min_velocity_iters = self.min_velocity_iters + return attr + + @classmethod + def from_dict( + cls, init_dict: Dict[str, Union[str, float, int]] + ) -> RigidBodyAttributesCfg: + """Initialize the configuration from a dictionary.""" + cfg = cls() + for key, value in init_dict.items(): + if hasattr(cfg, key): + setattr(cfg, key, value) + else: + logger.log_warning( + f"Key '{key}' not found in {cfg.__class__.__name__}." + ) + return cfg + + +@configclass +class SoftbodyVoxelAttributesCfg: + # voxel config + triangle_remesh_resolution: int = 8 + """Resolution to remesh the softbody mesh before building physx collision mesh.""" + + triangle_simplify_target: int = 0 + """Simplify mesh faces to target value. Do nothing if this value is zero.""" + + # TODO: this value will be automatically computed with simulation_mesh_resolution and mesh scale. + maximal_edge_length: float = 0 + # """To shorten edges that are too long, additional points get inserted at their center leading to a subdivision of the input mesh. Do nothing if this value is zero.""" + + simulation_mesh_resolution: int = 8 + """Resolution to build simulation voxelize textra mesh. This value must be greater than 0.""" + + simulation_mesh_output_obj: bool = False + """Whether to output the simulation mesh as an obj file for debugging.""" + + def attr(self) -> VoxelConfig: + """Convert to dexsim VoxelConfig""" + attr = VoxelConfig() + attr.triangle_remesh_resolution = self.triangle_remesh_resolution + attr.maximal_edge_length = self.maximal_edge_length + attr.simulation_mesh_resolution = self.simulation_mesh_resolution + attr.triangle_simplify_target = self.triangle_simplify_target + return attr + + +@configclass +class SoftbodyPhysicalAttributesCfg: + # material properties + youngs: float = 1e6 + """Young's modulus (higher = stiffer).""" + + poissons: float = 0.45 + """Poisson's ratio (higher = closer to incompressible).""" + + dynamic_friction: float = 0.0 + """Dynamic friction coefficient.""" + + elasticity_damping: float = 0.0 + """Elasticity damping factor.""" + + # soft body properties + material_model: SoftBodyMaterialModel = SoftBodyMaterialModel.CO_ROTATIONAL + """Material constitutive model.""" + + # --- Mode / collision switches --- + enable_kinematic: bool = False + """If True, (partially) kinematic behavior is enabled.""" + + enable_ccd: bool = False + """Enable continuous collision detection (CCD).""" + + enable_self_collision: bool = False + """Enable self-collision handling.""" + + has_gravity: bool = True + """Whether the soft body is affected by gravity.""" + + # --- Self-collision & simplification parameters --- + self_collision_stress_tolerance: float = 0.9 + """Stress tolerance threshold for self-collision constraints.""" + + collision_mesh_simplification: bool = True + """Whether to simplify the collision mesh for self-collision.""" + + self_collision_filter_distance: float = 0.1 + """Distance threshold below which vertex pairs may be filtered from self-collision checks.""" + + # --- Damping, sleep & settling --- + vertex_velocity_damping: float = 0.005 + """Per-vertex velocity damping.""" + + linear_damping: float = 0.0 + """Global linear damping applied to the soft body.""" + + sleep_threshold: float = 0.05 + """Velocity/energy threshold below which the soft body can go to sleep.""" + + settling_threshold: float = 0.1 + """Threshold used to decide convergence/settling state.""" + + settling_damping: float = 10.0 + """Additional damping applied during settling phase.""" + + # --- Mass / density & velocity limits --- + mass: float = -1.0 + """Total mass of the soft body. If set to a negative value, density will be used to compute mass.""" + + density: float = 1000.0 + """Material density in kg/m^3.""" + + max_depenetration_velocity: float = 1e6 + """Maximum velocity used to resolve penetrations. Must be larger than zero.""" + + max_velocity: float = 100 + """Clamp for linear (or vertex) velocity. If set to zero, the limit is ignored.""" + + # --- Solver iteration counts --- + min_position_iters: int = 4 + """Minimum solver iterations for position correction.""" + + min_velocity_iters: int = 1 + """Minimum solver iterations for velocity updates.""" + + def attr(self) -> SoftBodyAttr: + attr = SoftBodyAttr() + attr.youngs = self.youngs + attr.poissons = self.poissons + attr.dynamic_friction = self.dynamic_friction + attr.elasticity_damping = self.elasticity_damping + attr.material_model = self.material_model + attr.enable_kinematic = self.enable_kinematic + attr.enable_ccd = self.enable_ccd + attr.enable_self_collision = self.enable_self_collision + attr.has_gravity = self.has_gravity + attr.self_collision_stress_tolerance = self.self_collision_stress_tolerance + attr.collision_mesh_simplification = self.collision_mesh_simplification + attr.vertex_velocity_damping = self.vertex_velocity_damping + attr.mass = self.mass + attr.density = self.density + attr.max_depenetration_velocity = self.max_depenetration_velocity + attr.max_velocity = self.max_velocity + attr.self_collision_filter_distance = self.self_collision_filter_distance + attr.linear_damping = self.linear_damping + attr.sleep_threshold = self.sleep_threshold + attr.settling_threshold = self.settling_threshold + attr.settling_damping = self.settling_damping + attr.min_position_iters = self.min_position_iters + attr.min_velocity_iters = self.min_velocity_iters + return attr + + +@configclass +class JointDrivePropertiesCfg: + """Properties to define the drive mechanism of a joint.""" + + drive_type: Literal["force", "acceleration"] = "force" + """Joint drive type to apply. + + If the drive type is "force", then the joint is driven by a force and the acceleration is computed based on the force applied. + If the drive type is "acceleration", then the joint is driven by an acceleration and the force is computed based on the acceleration applied. + """ + + stiffness: Union[Dict[str, float], float] = 1e3 + """Stiffness of the joint drive. + + The unit depends on the joint model: + + * For linear joints, the unit is kg-m/s^2 (N/m). + * For angular joints, the unit is kg-m^2/s^2/rad (N-m/rad). + """ + + damping: Union[Dict[str, float], float] = 1e2 + """Damping of the joint drive. + + The unit depends on the joint model: + + * For linear joints, the unit is kg-m/s (N-s/m). + * For angular joints, the unit is kg-m^2/s/rad (N-m-s/rad). + """ + + max_effort: Union[Dict[str, float], float] = 1e10 + """Maximum effort that can be applied to the joint (in kg-m^2/s^2).""" + + max_velocity: Union[Dict[str, float], float] = 1e10 + """Maximum velocity that the joint can reach (in rad/s or m/s). + + For linear joints, this is the maximum linear velocity with unit m/s. + For angular joints, this is the maximum angular velocity with unit rad/s. + """ + + friction: Union[Dict[str, float], float] = 0.0 + """Friction coefficient of the joint""" + + @classmethod + def from_dict( + cls, init_dict: Dict[str, Union[str, float, int]] + ) -> JointDrivePropertiesCfg: + """Initialize the configuration from a dictionary.""" + cfg = cls() + for key, value in init_dict.items(): + if hasattr(cfg, key): + setattr(cfg, key, value) + else: + logger.log_warning( + f"Key '{key}' not found in {cfg.__class__.__name__}." + ) + return cfg + + +@configclass +class ObjectBaseCfg: + """Base configuration for an asset in the simulation. + + This class defines the basic properties of an asset, such as its type, initial state, and collision group. + It is used as a base class for specific asset configurations. + """ + + uid: Union[str, None] = None + + init_pos: tuple[float, float, float] = (0.0, 0.0, 0.0) + """Position of the root in simulation world frame. Defaults to (0.0, 0.0, 0.0).""" + + init_rot: tuple[float, float, float] = (0.0, 0.0, 0.0) + """Euler angles (in degree) of the root in simulation world frame. Defaults to (0.0, 0.0, 0.0).""" + + init_local_pose: Optional[np.ndarray] = None + """4x4 transformation matrix of the root in local frame. If specified, it will override init_pos and init_rot.""" + + @classmethod + def from_dict(cls, init_dict: Dict[str, Union[str, float, tuple]]) -> ObjectBaseCfg: + """Initialize the configuration from a dictionary.""" + cfg = cls() # Create a new instance of the class (cls) + for key, value in init_dict.items(): + if hasattr(cfg, key): + attr = getattr(cfg, key) + if is_configclass(attr): + setattr( + cfg, key, attr.from_dict(value) + ) # Call from_dict on the attribute + else: + setattr(cfg, key, value) + else: + logger.log_warning( + f"Key '{key}' not found in {cfg.__class__.__name__}." + ) + + # Automatically infer init_local_pose if not provided + if cfg.init_local_pose is None: + # If only init_pos or init_rot are provided, generate the 4x4 pose matrix + from scipy.spatial.transform import Rotation as R + + T = np.eye(4) + T[:3, 3] = np.array(cfg.init_pos) + T[:3, :3] = R.from_euler("xyz", np.deg2rad(cfg.init_rot)).as_matrix() + cfg.init_local_pose = T + else: + # If only init_local_pose is provided, extract init_pos and init_rot + from scipy.spatial.transform import Rotation as R + + T = np.array(cfg.init_local_pose) + cfg.init_pos = tuple(T[:3, 3]) + cfg.init_rot = tuple(R.from_matrix(T[:3, :3]).as_euler("xyz", degrees=True)) + + return cfg + + +@configclass +class LightCfg(ObjectBaseCfg): + """Configuration for a light asset in the simulation. + + This class extends the base asset configuration to include specific properties for lights, + """ + + # TODO: to be added more light type, such as spot, sun, etc. + light_type: Literal["point"] = "point" + + color: tuple[float, float, float] = (1.0, 1.0, 1.0) + + intensity: float = 50.0 + """Intensity of the light source with unit of watts/m^2.""" + + radius: float = 1e2 + """Falloff of the light, only used for point light.""" + + +@configclass +class RigidObjectCfg(ObjectBaseCfg): + """Configuration for a rigid body asset in the simulation. + + This class extends the base asset configuration to include specific properties for rigid bodies, + such as physical attributes and collision group. + """ + + shape: ShapeCfg = ShapeCfg() + """Shape configuration for the rigid body. """ + + # TODO: supoort basic primitive shapes, such as box, sphere, etc cfg and spawn method. + + attrs: RigidBodyAttributesCfg = RigidBodyAttributesCfg() + + body_type: Literal["dynamic", "kinematic", "static"] = "dynamic" + + max_convex_hull_num: int = 1 + """The maximum number of convex hulls that will be created for the rigid body. + + If `max_convex_hull_num` is set to larger than 1, the rigid body will be decomposed into multiple convex hulls using coacd alogorithm. + Reference: https://github.com/SarahWeiii/CoACD + """ + + body_scale: Union[tuple, list] = (1.0, 1.0, 1.0) + """Scale of the rigid body in the simulation world frame.""" + + def to_dexsim_body_type(self) -> ActorType: + """Convert the body type to dexsim ActorType.""" + if self.body_type == "dynamic": + return ActorType.DYNAMIC + elif self.body_type == "kinematic": + return ActorType.KINEMATIC + elif self.body_type == "static": + return ActorType.STATIC + else: + logger.log_error( + f"Invalid body type '{self.body_type}' specified. Must be one of 'dynamic', 'kinematic', or 'static'." + ) + + +@configclass +class SoftObjectCfg(ObjectBaseCfg): + """Configuration for a soft body asset in the simulation. + + This class extends the base asset configuration to include specific properties for soft bodies, + such as physical attributes and collision group. + """ + + voxel_attr: SoftbodyVoxelAttributesCfg = SoftbodyVoxelAttributesCfg() + """Tetra mesh voxelization attributes for the soft body.""" + + physical_attr: SoftbodyPhysicalAttributesCfg = SoftbodyPhysicalAttributesCfg() + """Physical attributes for the soft body.""" + + shape: MeshCfg = MeshCfg() + """Mesh configuration for the soft body.""" + + +@configclass +class RigidObjectGroupCfg: + """Configuration for a rigid object group asset in the simulation. + + Rigid object groups can be initialized from multiple rigid object configurations specified in a folder. + If `folder_path` is specified, user should provide a RigidObjectCfg in `rigid_objects` as a template configuration for + all objects in the group. + + For example: + ```python + rigid_object_group: RigidObjectGroupCfg( + folder_path="path/to/folder", + max_num=5, + rigid_objects={ + "template_obj": RigidObjectCfg( + shape=MeshCfg( + fpath="", # fpath will be ignored when folder_path is specified + ), + body_type="dynamic", + ) + } + ) + """ + + uid: Union[str, None] = None + + rigid_objects: Dict[str, RigidObjectCfg] = MISSING + """Configuration for the rigid objects in the group.""" + + body_type: Literal["dynamic", "kinematic"] = "dynamic" + """Body type for all rigid objects in the group. """ + + folder_path: Optional[str] = None + """Path to the folder containing the rigid object assets. + + This is used to initialize multiple rigid object configurations from a folder. + """ + + max_num: int = 1 + """Maximum number of rigid objects to initialize from the folder. + + This is only used when `folder_path` is specified. + """ + + ext: str = ".obj" + """File extension for the rigid object assets. + + This is only used when `folder_path` is specified. + """ + + @classmethod + def from_dict(cls, init_dict: Dict[str, Any]) -> RigidObjectGroupCfg: + """Initialize the configuration from a dictionary.""" + cfg = cls() + for key, value in init_dict.items(): + if hasattr(cfg, key): + attr = getattr(cfg, key) + if is_configclass(attr): + setattr( + cfg, key, attr.from_dict(value) + ) # Call from_dict on the attribute + elif key == "rigid_objects" and "folder_path" not in init_dict: + rigid_objects_cfg = {} + for obj_name, obj_cfg in value.items(): + rigid_objects_cfg[obj_name] = RigidObjectCfg.from_dict(obj_cfg) + setattr(cfg, key, rigid_objects_cfg) + elif key == "rigid_objects" and "folder_path" in init_dict: + folder_path = init_dict["folder_path"] + max_num = init_dict.get("max_num", 1) + rigid_objects_cfg = {} + if os.path.exists(folder_path) and os.path.isdir(folder_path): + files = os.listdir(folder_path) + files = [f for f in files if f.endswith(cfg.ext)] + # select files up to max_num + n_file = len(files) + select_files = [] + for i in range(max_num): + select_files.append(files[i % n_file]) + + for i, file_name in enumerate(select_files): + file_path = os.path.join(folder_path, file_name) + rigid_obj_cfg: RigidObjectCfg = RigidObjectCfg.from_dict( + list(init_dict["rigid_objects"].values())[0] + ) + rigid_obj_cfg.uid = f"{cfg.uid}_obj_{i}" + rigid_obj_cfg.shape.fpath = file_path + rigid_objects_cfg[rigid_obj_cfg.uid] = rigid_obj_cfg + setattr(cfg, "rigid_objects", rigid_objects_cfg) + else: + logger.log_error( + f"Folder '{folder_path}' does not exist or is not a directory." + ) + else: + setattr(cfg, key, value) + else: + logger.log_warning( + f"Key '{key}' not found in {cfg.__class__.__name__}." + ) + return cfg + + +@configclass +class URDFCfg: + """Standalone configuration class for URDF assembly.""" + + components: Dict[str, Dict[str, Union[str, Dict, np.ndarray]]] = field( + default_factory=dict + ) + """Dictionary of robot components to be assembled.""" + + sensors: Dict[str, Dict[str, Union[str, np.ndarray]]] = field(default_factory=dict) + """Dictionary of sensors to be attached to the robot.""" + + use_signature_check: bool = True + """Whether to use signature check when merging URDFs.""" + + base_link_name: str = "base_link" + """Name of the base link in the assembled robot.""" + + fpath: Optional[str] = None + """Full output file path for the assembled URDF. If specified, overrides fname and fpath_prefix.""" + + fname: Optional[str] = None + """Name used for output file and directory. If not specified, auto-generated from component names.""" + + fpath_prefix: str = EMBODICHAIN_DEFAULT_DATA_ROOT + "/assembled" + """Output directory prefix for the assembled URDF file.""" + + def __init__( + self, + components: Optional[List[Dict[str, Union[str, np.ndarray]]]] = None, + sensors: Optional[Dict[str, Dict[str, Union[str, np.ndarray]]]] = None, + fpath: Optional[str] = None, + fname: Optional[str] = None, + fpath_prefix: str = EMBODICHAIN_DEFAULT_DATA_ROOT + "/assembled", + use_signature_check: bool = True, + base_link_name: str = "base_link", + ): + """ + Initialize URDFCfg with optional list of components and output path settings. + + Args: + components (Optional[List[Dict]]): List of component configurations. Each dict should contain: + - 'component_type' (str): The type/name of the component (e.g., 'chassis', 'arm', 'hand'). + - 'urdf_path' (str): Path to the component's URDF file. + - 'transform' (Optional[np.ndarray]): 4x4 transformation matrix (optional). + - Additional params can be included as extra keys. + sensors (Optional[Dict]): Sensor configurations for the robot. + fpath (Optional[str]): Full output file path for the assembled URDF. If specified, overrides fname and fpath_prefix. + fname (Optional[str]): Name used for output file and directory. If not specified, auto-generated from component names. + fpath_prefix (str): Output directory prefix for the assembled URDF file. + use_signature_check (bool): Whether to use signature check when merging URDFs. + base_link_name (str): Name of the base link in the assembled robot. + """ + self.components = {} + self.sensors = sensors or {} + self.fpath = fpath + self.use_signature_check = use_signature_check + self.base_link_name = base_link_name + self.fname = fname + self.fpath_prefix = fpath_prefix + + # Auto-add components if provided + if components: + for comp_config in components: + if not isinstance(comp_config, dict): + logger.log_error( + f"Component configuration must be a dict, got {type(comp_config)}" + ) + continue + + # Extract required fields + component_type = comp_config.get("component_type") + urdf_path = comp_config.get("urdf_path") + + if not component_type or not urdf_path: + logger.log_error( + f"Component configuration must contain 'component_type' and 'urdf_path', got {comp_config}" + ) + continue + + # Extract optional fields + transform = comp_config.get("transform", np.eye(4)) + + # Extract additional params (exclude known keys) + params = { + k: v + for k, v in comp_config.items() + if k not in ["component_type", "urdf_path", "transform"] + } + + # Add the component + self.add_component(component_type, urdf_path, transform, **params) + + if sensors is not None: + if not isinstance(sensors, list): + logger.log_error( + f"sensors must be a list of dicts, got {type(sensors)}" + ) + self.sensors = [] + else: + # Optionally check each sensor dict + valid_sensors = [] + for sensor_config in sensors: + if not isinstance(sensor_config, dict): + logger.log_error( + f"Sensor configuration must be a dict, got {type(sensor_config)}" + ) + continue + sensor_name = sensor_config.get("sensor_name") + if not sensor_name: + logger.log_error( + f"Sensor configuration must contain 'sensor_name', got {sensor_config}" + ) + continue + valid_sensors.append(sensor_config) + self.sensors = valid_sensors + + def set_urdf(self, urdf_path: str) -> "URDFCfg": + """Directly specify a single URDF file for the robot, compatible with the single-URDF robot case. + + Args: + urdf_path (str): Path to the robot's URDF file. + + Returns: + URDFCfg: Returns self to allow method chaining. + """ + self.components.clear() + urdf_file = os.path.splitext(os.path.basename(urdf_path))[0] + self.components[urdf_file] = { + "urdf_path": urdf_path, + "transform": None, + "params": {}, + } + self.fpath = urdf_path + return self + + def add_component( + self, + component_type: str, + urdf_path: str, + transform: Optional[np.ndarray] = None, + **params, + ) -> URDFCfg: + """Add a robot component to the assembly configuration. + + Args: + component_type (str): The type/name of the component. Should be one of SUPPORTED_COMPONENTS + (e.g., 'chassis', 'torso', 'head', 'left_arm', 'right_hand', 'arm', 'hand', etc.). + urdf_path (str): Path to the component's URDF file. + transform (Optional[np.ndarray]): 4x4 transformation matrix for the component in the robot frame (default: None). + **params: Additional keyword parameters for the component (e.g., color, material, etc.). + + Returns: + URDFCfg: Returns self to allow method chaining. + """ + if urdf_path: + if not os.path.exists(urdf_path): + urdf_path_candidate = get_data_path(urdf_path) + if os.path.exists(urdf_path_candidate): + urdf_path = urdf_path_candidate + else: + logger.log_error(f"URDF path '{urdf_path}' does not exist.") + raise FileNotFoundError(f"URDF path '{urdf_path}' does not exist.") + + self.components[component_type] = { + "urdf_path": urdf_path, + "transform": np.array(transform), + "params": params, + } + + if self.fname: + self.fpath = f"{self.fpath_prefix}/{self.fname}/{self.fname}.urdf" + else: + # Update output_path to use all component urdf file names joined by underscores as directory + if len(self.components) == 1: + # Only one component, use its urdf file name + urdf_file = os.path.splitext(os.path.basename(urdf_path))[0] + name = urdf_file + else: + # Multiple components, join all urdf file names + urdf_files = [ + os.path.splitext(os.path.basename(v["urdf_path"]))[0] + for v in self.components.values() + ] + name = "_".join(urdf_files) + self.fpath = f"{self.fpath_prefix}/{name}/{name}.urdf" + + return self + + def add_sensor(self, sensor_name: str, **sensor_config) -> URDFCfg: + """Add a sensor to the robot configuration. + + Args: + sensor_name (str): The name of the sensor. + **sensor_config: Additional configuration parameters for the sensor. + + Returns: + URDFCfg: Returns self to allow method chaining. + """ + self.sensors.append({"sensor_name": sensor_name, **sensor_config}) + return self + + def assemble_urdf(self) -> str: + """Assemble URDF files for the robot based on the configuration. + + Returns: + str: The path to the resulting (possibly merged) URDF file. + """ + components = list(self.components.items()) + # If there is only one component, return its URDF path directly. + if len(components) == 1: + _, comp_config = components[0] + return comp_config["urdf_path"] + + from embodichain.toolkits.urdf_assembly import URDFAssemblyManager + + # If there are multiple components, merge them into a single URDF file. + manager = URDFAssemblyManager() + manager.base_link_name = self.base_link_name + for comp_type, comp_config in components: + params = comp_config.get("params", {}) + success = manager.add_component( + comp_type, + comp_config["urdf_path"], + comp_config.get("transform"), + **params, + ) + if not success: + logger.log_error( + f"Failed to add component '{comp_type}' with config: {comp_config}" + ) + + for sensor in self.sensors: + manager.attach_sensor( + sensor_name=sensor.get("sensor_name"), + sensor_source=sensor.get("sensor_source"), + parent_component=sensor.get("parent_component"), + parent_link=sensor.get("parent_link"), + sensor_type=sensor.get("sensor_type"), + **{ + k: v + for k, v in sensor.items() + if k + not in [ + "sensor_name", + "sensor_source", + "parent_component", + "parent_link", + "sensor_type", + ] + }, + ) + + try: + # Merge all added components into a single URDF file at the specified output path. + merged_urdf_xml = manager.merge_urdfs(self.fpath, self.use_signature_check) + except Exception as e: + logger.log_error(f"URDF merge failed: {e}") + + return self.fpath + + @classmethod + def from_dict(cls, init_dict: Dict) -> "URDFCfg": + if isinstance(init_dict, cls): + return init_dict + components = init_dict.get("components", None) + if isinstance(components, dict): + components = [{"component_type": k, **v} for k, v in components.items()] + sensors = init_dict.get("sensors", None) + fpath = init_dict.get("fpath", None) + use_signature_check = init_dict.get("use_signature_check", True) + base_link_name = init_dict.get("base_link_name", "base_link") + return cls( + components=components, + sensors=sensors, + fpath=fpath, + use_signature_check=use_signature_check, + base_link_name=base_link_name, + ) + + +@configclass +class ArticulationCfg(ObjectBaseCfg): + """Configuration for an articulation asset in the simulation. + + This class extends the base asset configuration to include specific properties for articulations, + such as joint drive properties, physical attributes. + """ + + fpath: str = None + """Path to the articulation asset file.""" + + drive_pros: JointDrivePropertiesCfg = JointDrivePropertiesCfg() + """Properties to define the drive mechanism of a joint.""" + + attrs: RigidBodyAttributesCfg = RigidBodyAttributesCfg() + """Physical attributes for all links . """ + + fix_base: bool = True + """Whether to fix the base of the articulation. + + Set to True for articulations that should not move, such as a fixed base robot arm or a door. + Set to False for articulations that should move freely, such as a mobile robot or a humanoid robot. + """ + + disable_self_collision: bool = True + """Whether to enable or disable self-collisions.""" + + init_qpos: Union[torch.Tensor, np.ndarray, Sequence[float]] = None + """Initial joint positions of the articulation. + + If None, the joint positions will be set to zero. + If provided, it should be a array of shape (num_joints,). + """ + + sleep_threshold: float = 0.005 + """Energy below which the articulation may go to sleep. Range: [0, max_float32]""" + + min_position_iters: int = 4 + """Number of position iterations the solver should perform for this articulation. Range: [1,255].""" + + min_velocity_iters: int = 1 + """Number of velocity iterations the solver should perform for this articulation. Range: [0,255].""" + + +@configclass +class RobotCfg(ArticulationCfg): + from embodichain.lab.sim.solvers import SolverCfg + + """Configuration for a robot asset in the simulation. + + # TODO: solver and motion planner may not be configurable inside the robot. + # But currently we put them here and could be moved if necessary. + """ + + control_parts: Union[Dict[str, List[str]], None] = None + """Control parts is the mapping from part name to joint names. + + For example, {'left_arm': ['joint1', 'joint2'], 'right_arm': ['joint3', 'joint4']} + If no control part is specified, the robot will use all joints as a single control part. + + Note: + - if `control_parts` is specified, `solver_cfg` must be a dict with part names as + keys corresponding to the control parts name. + - The joint names in the control parts support regular expressions, e.g., 'joint[1-6]'. + After initialization of robot, the names will be expanded to a list of full joint names. + """ + + urdf_cfg: Optional[URDFCfg] = None + """URDF assembly configuration which allows for assembling a robot from multiple URDF components. + """ + + # TODO: how to support one solver for multiple parts? + solver_cfg: Union[SolverCfg, Dict[str, SolverCfg], None] = None + """Solver is used to compute forward and inverse kinematics for the robot. + """ + + @classmethod + def from_dict(cls, init_dict: Dict[str, Union[str, float, tuple]]) -> RobotCfg: + """Initialize the configuration from a dictionary.""" + if isinstance(init_dict, cls): + return init_dict + + import importlib + + solver_module = importlib.import_module("embodichain.lab.sim.solvers") + + cfg = cls() # Create a new instance of the class (cls) + for key, value in init_dict.items(): + if hasattr(cfg, key): + attr = getattr(cfg, key) + if key == "urdf_cfg": + from embodichain.lab.sim.cfg import URDFCfg + + setattr(cfg, key, URDFCfg.from_dict(value)) + elif is_configclass(attr): + setattr( + cfg, key, attr.from_dict(value) + ) # Call from_dict on the attribute + elif "class_type" in value: + setattr( + cfg, + key, + getattr(solver_module, f"{value['class_type']}Cfg").from_dict( + value + ), + ) + elif isinstance(value, dict) and key_in_nested_dict( + value, "class_type" + ): + setattr( + cfg, + key, + { + k: getattr( + solver_module, f"{v['class_type']}Cfg" + ).from_dict(v) + for k, v in value.items() + }, + ) + + else: + setattr(cfg, key, value) + else: + logger.log_warning( + f"Key '{key}' not found in {cfg.__class__.__name__}." + ) + return cfg + + def build_pk_serial_chain( + self, device: torch.device = torch.device("cpu"), **kwargs + ) -> Dict[str, "pk.SerialChain"]: + """Build the serial chain from the URDF file. + + Note: + This method is usually used in imitation dataset saving (compute eef pose from qpos using FK) + and model training (provide a differentiable FK layer or loss computation). + + Args: + device (torch.device): The device to which the chain will be moved. Defaults to CPU. + **kwargs: Additional arguments for building the serial chain. + + Returns: + Dict[str, pk.SerialChain]: The serial chain of the robot for specified control part. + """ + return {} diff --git a/embodichain/lab/sim/common.py b/embodichain/lab/sim/common.py new file mode 100644 index 00000000..d129b5a6 --- /dev/null +++ b/embodichain/lab/sim/common.py @@ -0,0 +1,105 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import torch + +from dataclasses import dataclass +from abc import ABC, abstractmethod +from typing import List, TypeVar, Sequence, Optional +from functools import cached_property + +from embodichain.lab.sim.cfg import ObjectBaseCfg +from embodichain.utils import logger + +T = TypeVar("T") + + +@dataclass +class BatchEntity(ABC): + """Abstract base class for batch entity in the simulation engine. + + This class defines the interfaces for managing and manipulating a batch of entity. + A single entity could be one of the following assets: + - actor (eg. rigid object) + - articulation (eg. robot) + - camera + - light + - sensor (eg. force sensor) + + """ + + uid: Optional[str] = None + cfg: ObjectBaseCfg = None + _entities: List[T] = None + device: torch.device = None + + def __init__( + self, + cfg: ObjectBaseCfg, + entities: List[T] = None, + device: torch.device = torch.device("cpu"), + ) -> None: + + if entities is None or len(entities) == 0: + logger.log_error("Invalid entities list: must not be empty.") + + self.cfg = cfg.copy() + self.uid = self.cfg.uid + if self.uid is None: + logger.log_error("UID must be set in the configuration.") + self._entities = entities + self.device = device + + self.reset() + + def __str__(self) -> str: + return f"{self.__class__}: managing {self.num_instances} {self._entities[0].__class__} objects | uid: {self.uid} | device: {self.device}" + + def __repr__(self) -> str: + return self.__str__() + + @property + def num_instances(self) -> int: + return len(self._entities) + + @abstractmethod + def set_local_pose( + self, pose: torch.Tensor, env_ids: Optional[Sequence[int]] = None + ) -> None: + pass + + @abstractmethod + def get_local_pose(self, to_matrix: bool = False) -> torch.Tensor: + pass + + @property + def pose(self) -> torch.Tensor: + return self.get_local_pose(to_matrix=False) + + @abstractmethod + def reset(self, env_ids: Optional[Sequence[int]] = None) -> None: + """Reset the entity to its initial state. + + Args: + env_ids (Optional[Sequence[int]]): The environment IDs to reset. If None, reset all environments. + """ + pass + + def destroy(self) -> None: + """Destroy all entities managed by this batch entity.""" + pass diff --git a/embodichain/lab/sim/material.py b/embodichain/lab/sim/material.py new file mode 100644 index 00000000..fe6ad0db --- /dev/null +++ b/embodichain/lab/sim/material.py @@ -0,0 +1,386 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import copy +import torch +import dexsim +import numpy as np + +from typing import Optional, Dict, Union +from functools import cached_property + +from dexsim.engine import MaterialInst, Material +from embodichain.lab.sim.utility import is_rt_enabled +from embodichain.utils import configclass, logger + + +@configclass +class VisualMaterialCfg: + """Configuration for visual material with PBR properties for rasterization and ray tracing.""" + + uid: str = "default_mat" + + # Basic PBR properties + base_color: list = [0.5, 0.5, 0.5, 1.0] + """Base color/diffuse color (RGBA)""" + + metallic: float = 0.0 + """Metallic factor (0.0 = dielectric, 1.0 = metallic)""" + + roughness: float = 0.5 + """Surface roughness (0.0 = smooth, 1.0 = rough)""" + + # Additional PBR properties + emissive: list = [0.0, 0.0, 0.0] # Emissive color (RGB) + emissive_intensity: float = 1.0 # Emissive intensity multiplier + + # Texture maps + base_color_texture: str = None + """Base color texture map""" + + metallic_texture: str = None + """Metallic map""" + + roughness_texture: str = None + """Roughness map""" + + normal_texture: str = None + """Normal map""" + + ao_texture: str = None + """Ambient occlusion map""" + + # Ray tracing specific properties + ior: float = 1.5 + """Index of refraction for ray tracing materials""" + + rt_material_type: str = "BRDF_GGX_SMITH" + """Ray tracing material type. Options: 'BRDF_GGX_SMITH', 'BTDF_GGX_SMITH', 'BSDF_GGX_SMITH'""" + + # Currently disabled properties + # subsurface: float = 0.0 # Subsurface scattering factor + # subsurface_color: list = [1.0, 1.0, 1.0] # Subsurface scattering color + + @classmethod + def from_dict(cls, cfg_dict: dict) -> VisualMaterialCfg: + base = cls() + for k, v in cfg_dict.items(): + if hasattr(base, k): + setattr(base, k, v) + else: + logger.log_warning(f"Unknown field '{k}' in VisualMaterialCfg.") + return base + + +class VisualMaterial: + """Visual material definition in the simulation environment. + + A visual material is actually a material template from which material instances can be created. + It holds multiple material instances, which is used to assign to different objects in the environment. + """ + + RT_MATERIAL_TYPES = [ + "BRDF_GGX_SMITH", + "BTDF_GGX_SMITH", + "BSDF_GGX_SMITH", + ] + + def __init__(self, cfg: VisualMaterialCfg, mat: Material): + self.uid = cfg.uid + self.cfg = copy.deepcopy(cfg) + self._mat = mat + + self._default_mat_inst = self.create_instance(self.uid) + + @cached_property + def is_rt_enabled(self) -> bool: + return is_rt_enabled() + + @property + def mat(self) -> Material: + return self._mat + + def set_default_properties( + self, mat_inst: VisualMaterialInst, cfg: VisualMaterialCfg + ) -> None: + mat_inst.set_base_color(cfg.base_color) + mat_inst.set_metallic(cfg.metallic) + mat_inst.set_roughness(cfg.roughness) + mat_inst.set_emissive(cfg.emissive) + # mat_inst.set_emissive_intensity(self.cfg.emissive_intensity) # Unimplemented + + mat_inst.set_base_color_texture(cfg.base_color_texture) + mat_inst.set_metallic_texture(cfg.metallic_texture) + mat_inst.set_roughness_texture(cfg.roughness_texture) + mat_inst.set_normal_texture(cfg.normal_texture) + mat_inst.set_ao_texture(cfg.ao_texture) + + if self.is_rt_enabled: + mat_inst.set_ior(cfg.ior) + mat_inst.mat.update_pbr_material_type(cfg.rt_material_type) + + def create_instance(self, uid: str) -> VisualMaterialInst: + """Create a new material instance from this material template. + + Note: + - If the uid already exists, the existing instance will be returned. + + Args: + uid (str): Unique identifier for the material instance. + + Returns: + VisualMaterialInst: The created material instance. + """ + inst = VisualMaterialInst(uid, self._mat) + # TODO: Support change default properties for material. + # This will improve the instance creation efficiency. + self.set_default_properties(inst, self.cfg) + return inst + + def get_default_instance(self) -> VisualMaterialInst: + """Get the default material instance created with the same uid as the material template. + + Returns: + VisualMaterialInst: The default material instance. + """ + return self._default_mat_inst + + def get_instance(self, uid: str) -> VisualMaterialInst: + """Get an existing material instance by its uid. + + Args: + uid (str): Unique identifier for the material instance. + + Returns: + VisualMaterialInst: The material instance. + """ + return VisualMaterialInst(uid, self._mat) + + +class VisualMaterialInst: + """Instance of a visual material in the simulation environment.""" + + def __init__(self, uid: str, mat: Material): + self.uid = uid + self._mat = mat + + # Init properties with default values + self.base_color = [0.5, 0.5, 0.5, 1.0] + self.metallic = 0.0 + self.roughness = 0.5 + self.emissive = [0.0, 0.0, 0.0] + self.emissive_intensity = 1.0 + self.base_color_texture = None + self.metallic_texture = None + self.roughness_texture = None + self.normal_texture = None + self.ao_texture = None + self.ior = 1.5 + # self.subsurface = 0.0 + + @property + def mat(self) -> MaterialInst: + return self._mat.get_inst(self.uid) + + def set_base_color(self, color: list) -> None: + """Set base color/diffuse color.""" + self.base_color = color + self.mat.set_base_color(color) + + def set_metallic(self, metallic: float) -> None: + """Set metallic factor.""" + self.metallic = metallic + inst = self._mat.get_inst(self.uid) + inst.set_metallic(metallic) + + def set_roughness(self, roughness: float) -> None: + """Set surface roughness.""" + self.roughness = roughness + inst = self._mat.get_inst(self.uid) + inst.set_roughness(roughness) + + def set_emissive(self, emissive: list) -> None: + """Set emissive color.""" + self.emissive = emissive + value = np.zeros(4) + value[0:3] = emissive + inst = self._mat.get_inst(self.uid) + inst.set_emissive(value) + + def set_emissive_intensity(self, intensity: float) -> None: + """Set emissive intensity multiplier.""" + logger.log_error("Unimplemented: set_emissive_intensity") + + def set_base_color_texture( + self, texture_path: str = None, texture_data: Optional[torch.Tensor] = None + ) -> None: + """Set base color texture from file path or texture data. + + Args: + texture_path: Path to texture file + texture_data: Texture data as a torch.Tensor + """ + if texture_path is not None and texture_data is not None: + logger.log_warning( + "Both texture_path and texture_data are provided. Using texture_path." + ) + + if texture_path is not None: + self.base_color_texture = texture_path + inst = self._mat.get_inst(self.uid) + inst.set_base_color_map(texture_path) + elif texture_data is not None: + self.base_color_texture = texture_data + inst = self._mat.get_inst(self.uid) + + # TODO: Optimize texture creation method. + world = dexsim.default_world() + env = world.get_env() + color_texture = env.create_color_texture( + texture_data.cpu().numpy(), has_alpha=True + ) + inst.set_base_color_map(color_texture) + + def set_metallic_texture( + self, texture_path: str = None, texture_data: Optional[torch.Tensor] = None + ) -> None: + """Set metallic texture from file path or texture data. + + Args: + texture_path: Path to texture file + texture_data: Texture data as a torch.Tensor + """ + if texture_path is not None and texture_data is not None: + logger.log_warning( + "Both texture_path and texture_data are provided. Using texture_path." + ) + + if texture_path is not None: + self.metallic_texture = texture_path + inst = self._mat.get_inst(self.uid) + inst.set_metallic_map(texture_path) + elif texture_data is not None: + self.metallic_texture = texture_data + inst = self._mat.get_inst(self.uid) + + # TODO: Optimize texture creation method. + world = dexsim.default_world() + env = world.get_env() + metallic_texture = env.create_color_texture( + texture_data.cpu().numpy(), has_alpha=False + ) + inst.set_metallic_map(metallic_texture) + + def set_roughness_texture( + self, texture_path: str = None, texture_data: Optional[torch.Tensor] = None + ) -> None: + """Set roughness texture from file path or texture data. + + Args: + texture_path: Path to texture file + texture_data: Texture data as a torch.Tensor + """ + if texture_path is not None and texture_data is not None: + logger.log_warning( + "Both texture_path and texture_data are provided. Using texture_path." + ) + + if texture_path is not None: + self.roughness_texture = texture_path + inst = self._mat.get_inst(self.uid) + inst.set_roughness_map(texture_path) + elif texture_data is not None: + self.roughness_texture = texture_data + inst = self._mat.get_inst(self.uid) + + # TODO: Optimize texture creation method. + world = dexsim.default_world() + env = world.get_env() + roughness_texture = env.create_color_texture( + texture_data.cpu().numpy(), has_alpha=False + ) + inst.set_roughness_map(roughness_texture) + + def set_normal_texture( + self, texture_path: str = None, texture_data: Optional[torch.Tensor] = None + ) -> None: + """Set normal texture from file path or texture data. + + Args: + texture_path: Path to texture file + texture_data: Texture data as a torch.Tensor + """ + if texture_path is not None and texture_data is not None: + logger.log_warning( + "Both texture_path and texture_data are provided. Using texture_path." + ) + + if texture_path is not None: + self.normal_texture = texture_path + inst = self._mat.get_inst(self.uid) + inst.set_normal_map(texture_path) + elif texture_data is not None: + self.normal_texture = texture_data + inst = self._mat.get_inst(self.uid) + + # TODO: Optimize texture creation method. + world = dexsim.default_world() + env = world.get_env() + normal_texture = env.create_color_texture( + texture_data.cpu().numpy(), has_alpha=False + ) + inst.set_normal_map(normal_texture) + + def set_ao_texture( + self, texture_path: str = None, texture_data: Optional[torch.Tensor] = None + ) -> None: + """Set ambient occlusion texture from file path or texture data. + + Args: + texture_path: Path to texture file + texture_data: Texture data as a torch.Tensor + """ + if texture_path is not None and texture_data is not None: + logger.log_warning( + "Both texture_path and texture_data are provided. Using texture_path." + ) + + if texture_path is not None: + self.ao_texture = texture_path + inst = self._mat.get_inst(self.uid) + inst.set_ao_map(texture_path) + elif texture_data is not None: + self.ao_texture = texture_data + inst = self._mat.get_inst(self.uid) + + # TODO: Optimize texture creation method. + world = dexsim.default_world() + env = world.get_env() + ao_texture = env.create_color_texture( + texture_data.cpu().numpy(), has_alpha=False + ) + inst.set_ao_map(ao_texture) + + def set_ior(self, ior: float) -> None: + """Set index of refraction.""" + if is_rt_enabled() is False: + logger.log_debug("Ray Tracing rendering not enabled, ignoring IOR setting.") + return + self.ior = ior + inst = self._mat.get_inst(self.uid) + inst.set_rt_param("ior", ior) diff --git a/embodichain/lab/sim/objects/__init__.py b/embodichain/lab/sim/objects/__init__.py new file mode 100644 index 00000000..9c4ba945 --- /dev/null +++ b/embodichain/lab/sim/objects/__init__.py @@ -0,0 +1,28 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from ..common import BatchEntity +from .rigid_object import RigidObject, RigidBodyData, RigidObjectCfg +from .rigid_object_group import ( + RigidObjectGroup, + RigidBodyGroupData, + RigidObjectGroupCfg, +) +from .soft_object import SoftObject, SoftBodyData, SoftObjectCfg +from .articulation import Articulation, ArticulationData, ArticulationCfg +from .robot import Robot, RobotCfg +from .light import Light, LightCfg +from .gizmo import Gizmo diff --git a/embodichain/lab/sim/objects/articulation.py b/embodichain/lab/sim/objects/articulation.py new file mode 100644 index 00000000..c9f56090 --- /dev/null +++ b/embodichain/lab/sim/objects/articulation.py @@ -0,0 +1,1487 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import dexsim +import numpy as np + +from dataclasses import dataclass +from functools import cached_property +from typing import List, Sequence, Optional, Dict, Union + +from dexsim.engine import Articulation as _Articulation +from dexsim.types import ( + ArticulationGPUAPIWriteType, + ArticulationGPUAPIReadType, +) +from dexsim.engine import CudaArray, PhysicsScene + +from embodichain.lab.sim import VisualMaterialInst, VisualMaterial +from embodichain.lab.sim.cfg import ArticulationCfg, JointDrivePropertiesCfg +from embodichain.lab.sim.common import BatchEntity +from embodichain.utils.math import ( + matrix_from_quat, + quat_from_matrix, + convert_quat, + matrix_from_euler, +) +from embodichain.lab.sim.utility.sim_utils import ( + get_dexsim_drive_type, + set_dexsim_articulation_cfg, + is_rt_enabled, +) +from embodichain.lab.sim.utility.solver_utils import ( + create_pk_chain, + create_pk_serial_chain, +) +from embodichain.utils import logger + + +@dataclass +class ArticulationData: + """GPU data manager for articulation.""" + + def __init__( + self, entities: List[_Articulation], ps: PhysicsScene, device: torch.device + ) -> None: + """Initialize the ArticulationData. + + Args: + entities (List[_Articulation]): List of DexSim Articulation objects. + ps (PhysicsScene): The physics scene. + device (torch.device): The device to use for the articulation data. + """ + self.entities = entities + self.ps = ps + self.num_instances = len(entities) + self.device = device + + # get gpu indices for the entities. + # only meaningful when using GPU physics. + self.gpu_indices = torch.as_tensor( + [np.int32(entity.get_gpu_index()) for entity in self.entities], + dtype=torch.int32, + device=self.device, + ) + + self.dof = self.entities[0].get_dof() + self.num_links = self.entities[0].get_links_num() + self.link_names = self.entities[0].get_link_names() + + self._root_pose = torch.zeros( + (self.num_instances, 7), dtype=torch.float32, device=self.device + ) + self._root_lin_vel = torch.zeros( + (self.num_instances, 3), dtype=torch.float32, device=self.device + ) + self._root_ang_vel = torch.zeros( + (self.num_instances, 3), dtype=torch.float32, device=self.device + ) + + max_num_links = ( + self.ps.gpu_get_articulation_max_link_count() + if self.device.type == "cuda" + else self.num_links + ) + self._body_link_pose = torch.zeros( + (self.num_instances, max_num_links, 7), + dtype=torch.float32, + device=self.device, + ) + self._body_link_vel = torch.zeros( + (self.num_instances, max_num_links, 6), + dtype=torch.float32, + device=self.device, + ) + + self._body_link_lin_vel = torch.zeros( + (self.num_instances, max_num_links, 3), + dtype=torch.float32, + device=self.device, + ) + self._body_link_ang_vel = torch.zeros( + (self.num_instances, max_num_links, 3), + dtype=torch.float32, + device=self.device, + ) + + max_dof = ( + self.ps.gpu_get_articulation_max_dof() + if self.device.type == "cuda" + else self.dof + ) + self._qpos = torch.zeros( + (self.num_instances, max_dof), dtype=torch.float32, device=self.device + ) + self._qvel = torch.zeros( + (self.num_instances, max_dof), dtype=torch.float32, device=self.device + ) + self._qacc = torch.zeros( + (self.num_instances, max_dof), dtype=torch.float32, device=self.device + ) + self._qf = torch.zeros( + (self.num_instances, max_dof), dtype=torch.float32, device=self.device + ) + + @property + def root_pose(self) -> torch.Tensor: + """Get the root pose of the articulation. + + Returns: + torch.Tensor: The root pose of the articulation with shape of (num_instances, 7). + """ + if self.device.type == "cpu": + # Fetch pose from CPU entities + root_pose = torch.as_tensor( + np.array([entity.get_local_pose() for entity in self.entities]), + dtype=torch.float32, + device=self.device, + ) + xyzs = root_pose[:, :3, 3] + quats = quat_from_matrix(root_pose[:, :3, :3]) + return torch.cat((xyzs, quats), dim=-1) + else: + self.ps.gpu_fetch_root_data( + data=self._root_pose, + gpu_indices=self.gpu_indices, + data_type=ArticulationGPUAPIReadType.ROOT_GLOBAL_POSE, + ) + self._root_pose[:, :4] = convert_quat(self._root_pose[:, :4], to="wxyz") + return self._root_pose[:, [4, 5, 6, 0, 1, 2, 3]] + + @property + def root_lin_vel(self) -> torch.Tensor: + """Get the linear velocity of the root link of the articulation. + + Returns: + torch.Tensor: The linear velocity of the root link with shape of (num_instances, 3). + """ + if self.device.type == "cpu": + # Fetch linear velocity from CPU entities + return torch.as_tensor( + np.array( + [entity.get_root_link_velocity()[:3] for entity in self.entities] + ), + dtype=torch.float32, + device=self.device, + ) + else: + self.ps.gpu_fetch_root_data( + data=self._root_lin_vel, + gpu_indices=self.gpu_indices, + data_type=ArticulationGPUAPIReadType.ROOT_LINEAR_VELOCITY, + ) + return self._root_lin_vel.clone() + + @property + def root_ang_vel(self) -> torch.Tensor: + """Get the angular velocity of the root link of the articulation. + + Returns: + torch.Tensor: The angular velocity of the root link with shape of (num_instances, 3). + """ + if self.device.type == "cpu": + # Fetch angular velocity from CPU entities + return torch.as_tensor( + np.array( + [entity.get_root_link_velocity()[3:] for entity in self.entities] + ), + dtype=torch.float32, + device=self.device, + ) + else: + self.ps.gpu_fetch_root_data( + data=self._root_ang_vel, + gpu_indices=self.gpu_indices, + data_type=ArticulationGPUAPIReadType.ROOT_ANGULAR_VELOCITY, + ) + return self._root_ang_vel.clone() + + @property + def root_vel(self) -> torch.Tensor: + """Get the velocity of the root link of the articulation. + + Returns: + torch.Tensor: The velocity of the root link, concatenating linear and angular velocities. + """ + return torch.cat((self.root_lin_vel, self.root_ang_vel), dim=-1) + + @property + def qpos(self) -> torch.Tensor: + """Get the current positions (qpos) of the articulation. + + Returns: + torch.Tensor: The current positions of the articulation with shape of (num_instances, dof). + """ + if self.device.type == "cpu": + # Fetch qpos from CPU entities + return torch.as_tensor( + np.array( + [entity.get_current_qpos() for entity in self.entities], + ), + dtype=torch.float32, + device=self.device, + ) + else: + self.ps.gpu_fetch_joint_data( + data=self._qpos, + gpu_indices=self.gpu_indices, + data_type=ArticulationGPUAPIReadType.JOINT_POSITION, + ) + return self._qpos[:, : self.dof].clone() + + @property + def qvel(self) -> torch.Tensor: + """Get the current velocities (qvel) of the articulation. + + Returns: + torch.Tensor: The current velocities of the articulation with shape of (num_instances, dof). + """ + if self.device.type == "cpu": + # Fetch qvel from CPU entities + return torch.as_tensor( + np.array([entity.get_current_qvel() for entity in self.entities]), + dtype=torch.float32, + device=self.device, + ) + else: + self.ps.gpu_fetch_joint_data( + data=self._qvel, + gpu_indices=self.gpu_indices, + data_type=ArticulationGPUAPIReadType.JOINT_VELOCITY, + ) + return self._qvel[:, : self.dof].clone() + + @property + def qacc(self) -> torch.Tensor: + """Get the current accelerations (qacc) of the articulation. + + Returns: + torch.Tensor: The current accelerations of the articulation with shape of (num_instances, dof). + """ + if self.device.type == "cpu": + # Fetch qacc from CPU entities + return torch.as_tensor( + np.array([entity.get_current_qacc() for entity in self.entities]), + dtype=torch.float32, + device=self.device, + ) + else: + self.ps.gpu_fetch_joint_data( + data=self._qacc, + gpu_indices=self.gpu_indices, + data_type=ArticulationGPUAPIReadType.JOINT_ACCELERATION, + ) + return self._qacc[:, : self.dof].clone() + + @property + def qf(self) -> torch.Tensor: + """Get the current forces (qf) of the articulation. + + Returns: + torch.Tensor: The current forces of the articulation with shape of (num_instances, dof). + """ + if self.device.type == "cpu": + # Fetch qf from CPU entities + return torch.as_tensor( + np.array([entity.get_current_qf() for entity in self.entities]), + dtype=torch.float32, + device=self.device, + ) + else: + self.ps.gpu_fetch_joint_data( + data=self._qf, + gpu_indices=self.gpu_indices, + data_type=ArticulationGPUAPIReadType.JOINT_FORCE, + ) + return self._qf[:, : self.dof].clone() + + @property + def body_link_pose(self) -> torch.Tensor: + """Get the pose of all links in the articulation. + + Returns: + torch.Tensor: The poses of the links in the articulation with shape (N, num_links, 7). + """ + if self.device.type == "cpu": + from embodichain.lab.sim.utility import get_dexsim_arenas + + arenas = get_dexsim_arenas() + for j, entity in enumerate(self.entities): + + link_pose = np.zeros((self.num_links, 4, 4), dtype=np.float32) + for i, link_name in enumerate(self.link_names): + pose = entity.get_link_pose(link_name) + arena_pose = arenas[j].get_root_node().get_local_pose() + pose[:2, 3] -= arena_pose[:2, 3] + link_pose[i] = pose + + link_pose = torch.from_numpy(link_pose) + xyz = link_pose[:, :3, 3] + quat = quat_from_matrix(link_pose[:, :3, :3]) + self._body_link_pose[j][: self.num_links, :] = torch.cat( + (xyz, quat), dim=-1 + ) + return self._body_link_pose[:, : self.num_links, :] + else: + self.ps.gpu_fetch_link_data( + data=self._body_link_pose, + gpu_indices=self.gpu_indices, + data_type=ArticulationGPUAPIReadType.LINK_GLOBAL_POSE, + ) + quat = convert_quat(self._body_link_pose[..., :4], to="wxyz") + return torch.cat((self._body_link_pose[..., 4:], quat), dim=-1) + + @property + def body_link_vel(self) -> torch.Tensor: + """Get the velocities of all links in the articulation. + + Returns: + torch.Tensor: The poses of the links in the articulation with shape (N, num_links, 6). + """ + if self.device.type == "cpu": + for i, entity in enumerate(self.entities): + self._body_link_vel[i][: self.num_links] = torch.from_numpy( + entity.get_link_general_velocities() + ) + return self._body_link_vel[:, : self.num_links, :] + else: + self.ps.gpu_fetch_link_data( + data=self._body_link_lin_vel, + gpu_indices=self.gpu_indices, + data_type=ArticulationGPUAPIReadType.LINK_LINEAR_VELOCITY, + ) + self.ps.gpu_fetch_link_data( + data=self._body_link_ang_vel, + gpu_indices=self.gpu_indices, + data_type=ArticulationGPUAPIReadType.LINK_ANGULAR_VELOCITY, + ) + self._body_link_vel[..., :3] = self._body_link_lin_vel + self._body_link_vel[..., 3:] = self._body_link_ang_vel + return self._body_link_vel[:, : self.num_links, :] + + @property + def joint_stiffness(self) -> torch.Tensor: + """Get the joint stiffness of the articulation. + + Returns: + torch.Tensor: The joint stiffness of the articulation with shape (N, dof). + """ + return torch.as_tensor( + np.array([entity.get_drive()[0] for entity in self.entities]), + dtype=torch.float32, + device=self.device, + ) + + @property + def joint_damping(self) -> torch.Tensor: + """Get the joint damping of the articulation. + + Returns: + torch.Tensor: The joint damping of the articulation with shape (N, dof). + """ + return torch.as_tensor( + np.array([entity.get_drive()[1] for entity in self.entities]), + dtype=torch.float32, + device=self.device, + ) + + @property + def joint_friction(self) -> torch.Tensor: + """Get the joint friction of the articulation. + + Returns: + torch.Tensor: The joint friction of the articulation with shape (N, dof). + """ + return torch.as_tensor( + np.array([entity.get_drive()[4] for entity in self.entities]), + dtype=torch.float32, + device=self.device, + ) + + @cached_property + def qpos_limits(self) -> torch.Tensor: + """Get the joint position limits of the articulation. + + Returns: + torch.Tensor: The joint position limits of the articulation with shape (N, dof, 2). + """ + return torch.as_tensor( + np.array([entity.get_joint_limits() for entity in self.entities]), + dtype=torch.float32, + device=self.device, + ) + + @cached_property + def qvel_limits(self) -> torch.Tensor: + """Get the joint velocity limits of the articulation. + + Returns: + torch.Tensor: The joint velocity limits of the articulation with shape (N, dof). + """ + # TODO: get joint velocity limits always returns zero? + return torch.as_tensor( + np.array( + [entity.get_drive()[3] for entity in self.entities], + ), + dtype=torch.float32, + device=self.device, + ) + + @cached_property + def qf_limits(self) -> torch.Tensor: + """Get the joint effort limits of the articulation. + + Returns: + torch.Tensor: The joint effort limits of the articulation with shape (N, dof). + """ + return torch.as_tensor( + np.array( + [entity.get_drive()[2] for entity in self.entities], + ), + dtype=torch.float32, + device=self.device, + ) + + +class Articulation(BatchEntity): + """Articulation represents a batch of articulations in the simulation. + + An articulation is a collection of rigid bodies connected by joints. The joints can be either + fixed or actuated. The joints can be of different types, such as revolute or prismatic. + + For fixed-base articulation, it can be a robot arm, door, etc. + For floating-base articulation, it can be a humanoid, drawer, etc. + + Args: + cfg (ArticulationCfg): Configuration for the articulation. + entities (List[_Articulation], optional): List of articulation entities. + device (torch.device, optional): Device to use (CPU or CUDA). + """ + + def __init__( + self, + cfg: ArticulationCfg, + entities: List[_Articulation] = None, + device: torch.device = torch.device("cpu"), + ) -> None: + # Initialize world and physics scene + self._world = dexsim.default_world() + self._ps = self._world.get_physics_scene() + + self.cfg = cfg + self._entities = entities + self.device = device + + # Store all indices for batch operations + self._all_indices = torch.arange( + len(entities), dtype=torch.int32, device=device + ) + + if device.type == "cuda": + self._world.update(0.001) + + self._data = ArticulationData(entities=entities, ps=self._ps, device=device) + + self.cfg: ArticulationCfg + if self.cfg.init_qpos is None: + self.cfg.init_qpos = torch.zeros(self.dof, dtype=torch.float32) + + # Set articulation configuration in DexSim + set_dexsim_articulation_cfg(entities, self.cfg) + + # Init joint drive parameters. + num_entities = len(entities) + dof = self._data.dof + default_cfg = JointDrivePropertiesCfg() + self.default_joint_damping = torch.full( + (num_entities, dof), default_cfg.damping, dtype=torch.float32, device=device + ) + self.default_joint_stiffness = torch.full( + (num_entities, dof), + default_cfg.stiffness, + dtype=torch.float32, + device=device, + ) + self.default_joint_max_effort = torch.full( + (num_entities, dof), + default_cfg.max_effort, + dtype=torch.float32, + device=device, + ) + self.default_joint_max_velocity = torch.full( + (num_entities, dof), + default_cfg.max_velocity, + dtype=torch.float32, + device=device, + ) + self.default_joint_friction = torch.full( + (num_entities, dof), + default_cfg.friction, + dtype=torch.float32, + device=device, + ) + self._set_default_joint_drive() + + self.pk_chain = create_pk_chain(urdf_path=self.cfg.fpath, device=self.device) + + # For rendering purposes, each articulation can have multiple material instances associated with its links. + self._visual_material: List[Dict[str, VisualMaterialInst]] = [ + {} for _ in range(len(entities)) + ] + + # Stores mimic information for joints. + self._mimic_info = entities[0].get_mimic_info() + + # TODO: very weird that we must call update here to make sure the GPU indices are valid. + if device.type == "cuda": + self._world.update(0.001) + + super().__init__(cfg, entities, device) + + # set default collision filter + self._set_default_collision_filter() + + def __str__(self) -> str: + parent_str = super().__str__() + return parent_str + f" | dof: {self.dof} | num_links: {self.num_links}" + + @property + def dof(self) -> int: + """Get the degree of freedom of the articulation. + + Returns: + int: The degree of freedom of the articulation. + """ + return self._data.dof + + @property + def num_links(self) -> int: + """Get the number of links in the articulation. + + Returns: + int: The number of links in the articulation. + """ + return self._data.num_links + + @property + def link_names(self) -> List[str]: + """Get the names of the links in the articulation. + + Returns: + List[str]: The names of the links in the articulation. + """ + return self._data.link_names + + @property + def root_link_name(self) -> str: + """Get the name of the root link of the articulation. + + Returns: + str: The name of the root link. + """ + return self.entities[0].get_root_link_name() + + @property + def joint_names(self) -> List[str]: + """Get the names of the actived joints in the articulation. + + Returns: + List[str]: The names of the actived joints in the articulation. + """ + return self._entities[0].get_actived_joint_names() + + @property + def all_joint_names(self) -> List[str]: + """Get the names of the joints in the articulation. + + Returns: + List[str]: The names of the joints in the articulation. + """ + return self._entities[0].get_joint_names() + + @property + def body_data(self) -> ArticulationData: + """Get the rigid body data manager for this rigid object. + + Returns: + RigidBodyData: The rigid body data manager. + """ + return self._data + + @property + def root_state(self) -> torch.Tensor: + """Get the root state of the articulation. + + Returns: + torch.Tensor: The root state of the articulation with shape (N, 13). + """ + root_pose = self.body_data.root_pose + root_lin_vel = self.body_data.root_lin_vel + root_ang_vel = self.body_data.root_ang_vel + return torch.cat((root_pose, root_lin_vel, root_ang_vel), dim=-1) + + @property + def body_state(self) -> torch.Tensor: + """Get the body state of the articulation. + + Returns: + torch.Tensor: The body state of the articulation with shape (N, num_links, 13). + """ + body_pose = self.body_data.body_link_pose + body_vel = self.body_data.body_link_vel + return torch.cat((body_pose, body_vel), dim=-1) + + @property + def mimic_ids(self) -> List[Optional[int]]: + """Get the mimic joint ids for the articulation. + + Returns: + List[Optional[int]]: The mimic joint ids. + """ + return self._mimic_info.mimic_id.tolist() + + @property + def mimic_parents(self) -> List[Optional[int]]: + """Get the mimic joint parent ids for the articulation. + + Returns: + List[Optional[int]]: The mimic joint parent ids. + """ + return self._mimic_info.mimic_parent.tolist() + + @property + def mimic_multipliers(self) -> List[float]: + """Get the mimic joint multipliers for the articulation. + + Returns: + List[float]: The mimic joint multipliers. + """ + return self._mimic_info.mimic_multiplier.tolist() + + @property + def mimic_offsets(self) -> List[float]: + """Get the mimic joint offsets for the articulation. + + Returns: + List[float]: The mimic joint offsets. + """ + return self._mimic_info.mimic_offset.tolist() + + def _set_default_collision_filter(self) -> None: + collision_filter_data = torch.zeros( + size=(self.num_instances, 4), dtype=torch.int32 + ) + for i in range(self.num_instances): + collision_filter_data[i, 0] = i + collision_filter_data[i, 1] = 1 + self.set_collision_filter(collision_filter_data) + + def set_collision_filter( + self, filter_data: torch.Tensor, env_ids: Optional[Sequence[int]] = None + ) -> None: + """set collision filter data for the rigid object. + + Args: + filter_data (torch.Tensor): [N, 4] of int. + First element of each object is arena id. + If 2nd element is 0, the object will collision with all other objects in world. + 3rd and 4th elements are not used currently. + + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. Defaults to None. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + if len(local_env_ids) != len(filter_data): + logger.log_error( + f"Length of env_ids {len(local_env_ids)} does not match pose length {len(filter_data)}." + ) + + filter_data_np = filter_data.cpu().numpy().astype(np.uint32) + for i, env_idx in enumerate(local_env_ids): + self._entities[env_idx].set_collision_filter_data(filter_data_np[i]) + + def set_local_pose( + self, pose: torch.Tensor, env_ids: Optional[Sequence[int]] = None + ) -> None: + """Set local pose of the articulation. + + Args: + pose (torch.Tensor): The local pose of the articulation with shape (N, 7) or (N, 4, 4). + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + if len(local_env_ids) != len(pose): + logger.log_error( + f"Length of env_ids {len(local_env_ids)} does not match pose length {len(pose)}." + ) + + if self.device.type == "cpu": + pose = pose.cpu() + if pose.dim() == 2 and pose.shape[1] == 7: + pose_matrix = torch.eye(4).unsqueeze(0).repeat(pose.shape[0], 1, 1) + pose_matrix[:, :3, 3] = pose[:, :3] + pose_matrix[:, :3, :3] = matrix_from_quat(pose[:, 3:7]) + for i, env_idx in enumerate(local_env_ids): + self._entities[env_idx].set_local_pose(pose_matrix[i]) + elif pose.dim() == 3 and pose.shape[1:] == (4, 4): + for i, env_idx in enumerate(local_env_ids): + self._entities[env_idx].set_local_pose(pose[i]) + else: + logger.log_error( + f"Invalid pose shape {pose.shape}. Expected (N, 7) or (N, 4, 4)." + ) + + # TODO: in manual physics mode, the update should be explicitly called after + # setting the pose to synchronize the state to renderer. + self._world.update(0.001) + + else: + if pose.dim() == 2 and pose.shape[1] == 7: + xyz = pose[:, :3] + quat = convert_quat(pose[:, 3:7], to="xyzw") + elif pose.dim() == 3 and pose.shape[1:] == (4, 4): + xyz = pose[:, :3, 3] + quat = quat_from_matrix(pose[:, :3, :3]) + quat = convert_quat(quat, to="xyzw") + else: + logger.log_error( + f"Invalid pose shape {pose.shape}. Expected (N, 7) or (N, 4, 4)." + ) + + # we should keep `pose_` life cycle to the end of the function. + pose_ = torch.cat((quat, xyz), dim=-1) + indices = self.body_data.gpu_indices[local_env_ids] + self._ps.gpu_apply_root_data( + data=pose_, + gpu_indices=indices, + data_type=ArticulationGPUAPIWriteType.ROOT_GLOBAL_POSE, + ) + self._ps.gpu_compute_articulation_kinematic(gpu_indices=indices) + + # TODO: To be removed when gpu articulation data sync is supported. + if is_rt_enabled() is False: + self.body_data.body_link_pose + link_pose = self.body_data._body_link_pose[local_env_ids] + self._world.sync_poses_gpu_to_cpu( + link_pose=CudaArray(link_pose), + articulation_gpu_indices=CudaArray(indices), + ) + + def get_local_pose(self, to_matrix=False) -> torch.Tensor: + """Get local pose (root link pose) of the articulation. + + Args: + to_matrix (bool, optional): If True, return the pose as a 4x4 matrix. If False, return as (x, y, z, qw, qx, qy, qz). Defaults to False. + + Returns: + torch.Tensor: The local pose of the articulation with shape (N, 7) or (N, 4, 4) depending on `to_matrix`. + """ + pose = self.body_data.root_pose + if to_matrix: + xyz = pose[:, :3] + mat = matrix_from_quat(pose[:, 3:7]) + pose = ( + torch.eye(4, dtype=torch.float32, device=self.device) + .unsqueeze(0) + .repeat(pose.shape[0], 1, 1) + ) + pose[:, :3, 3] = xyz + pose[:, :3, :3] = mat + return pose + + def get_link_pose( + self, link_name: str, env_ids: Optional[Sequence[int]] = None, to_matrix=False + ) -> torch.Tensor: + """Get the pose of a specific link in the articulation. + + Args: + link_name (str): The name of the link. + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + to_matrix (bool, optional): If True, return the pose as a 4x4 matrix. If False, return as (x, y, z, qw, qx, qy, qz). Defaults to False. + + Returns: + torch.Tensor: The pose of the specified link with shape (N, 7) or (N, 4, 4) depending on `to_matrix`. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + if link_name not in self.link_names: + logger.log_error( + f"Link name {link_name} not found in {self.__class__.__name__}. Available links: {self.link_names}" + ) + + link_idx = self.link_names.index(link_name) + link_pose = self.body_data.body_link_pose[local_env_ids, link_idx, :] + + if to_matrix: + xyz = link_pose[:, :3] + mat = matrix_from_quat(link_pose[:, 3:7]) + link_pose = ( + torch.eye(4, dtype=torch.float32, device=self.device) + .unsqueeze(0) + .repeat(link_pose.shape[0], 1, 1) + ) + link_pose[:, :3, 3] = xyz + link_pose[:, :3, :3] = mat + return link_pose + + def get_qpos(self) -> torch.Tensor: + """Get the current positions (qpos) of the articulation.""" + return self.body_data.qpos + + def set_qpos( + self, + qpos: torch.Tensor, + joint_ids: Optional[Sequence[int]] = None, + env_ids: Optional[Sequence[int]] = None, + target: bool = True, + ) -> None: + """Set the joint positions (qpos) or target positions for the articulation. + + Args: + qpos (torch.Tensor): Joint positions with shape (N, dof), where N is the number of environments. + joint_ids (Optional[Sequence[int]], optional): Joint indices to apply the positions. If None, applies to all joints. + env_ids (Optional[Sequence[int]]): Environment indices to apply the positions. Defaults to all environments. + target (bool): If True, sets target positions for simulation. If False, updates current positions directly. + + Raises: + ValueError: If the length of `env_ids` does not match the length of `qpos`. + """ + if not isinstance(qpos, torch.Tensor): + qpos = torch.as_tensor(qpos, dtype=torch.float32, device=self.device) + + if joint_ids is None: + local_joint_ids = torch.arange( + self.dof, device=self.device, dtype=torch.int32 + ) + elif not isinstance(joint_ids, torch.Tensor): + local_joint_ids = torch.as_tensor( + joint_ids, dtype=torch.int32, device=self.device + ) + else: + local_joint_ids = joint_ids + + local_env_ids = self._all_indices if env_ids is None else env_ids + + # TODO: Refactor this part to use a more generic and extensible approach, + # such as a class decorator that can automatically convert ndarray to torch.Tensor + # and handle dimension padding for specified member functions. + # This will make the codebase cleaner and reduce repetitive type checks/conversions. + # (e.g., support specifying which methods should be decorated for auto-conversion.) + qpos = torch.as_tensor(qpos, dtype=torch.float32, device=self.device) + + if self.device.type == "cuda": + limits = self.body_data.qpos_limits[0].T + # clamp qpos to limits + lower_limits = limits[0][local_joint_ids] + upper_limits = limits[1][local_joint_ids] + qpos = qpos.clamp(lower_limits, upper_limits) + + # Make sure qpos is 2D tensor + if qpos.dim() == 1: + qpos = qpos.unsqueeze(0) + # If only one qpos is provided, repeat it for all envs + if len(qpos) == 1 and len(local_env_ids) > 1: + qpos = qpos.repeat(len(local_env_ids), 1) + + if len(local_env_ids) != len(qpos): + logger.log_error( + f"Length of env_ids {len(local_env_ids)} does not match qpos length {len(qpos)}. " + f"env_ids: {local_env_ids}, qpos.shape: {qpos.shape}" + ) + + data_type = ( + ArticulationGPUAPIWriteType.JOINT_TARGET_POSITION + if target + else ArticulationGPUAPIWriteType.JOINT_POSITION + ) + + if self.device.type == "cpu": + for i, env_idx in enumerate(local_env_ids): + setter = ( + self._entities[env_idx].set_current_qpos + if target + else self._entities[env_idx].set_qpos + ) + setter(qpos[i].numpy(), local_joint_ids.numpy()) + else: + # TODO: trigger qpos getter to sync data, otherwise crash + if joint_ids is not None: + self.body_data.qpos + + indices = self.body_data.gpu_indices[local_env_ids] + qpos_set = self.body_data._qpos[local_env_ids] + qpos_set[:, local_joint_ids] = qpos + self._ps.gpu_apply_joint_data( + data=qpos_set, + gpu_indices=indices, + data_type=data_type, + ) + + def get_qvel(self) -> torch.Tensor: + """Get the current velocities (qvel) of the articulation. + + Returns: + torch.Tensor: The current velocities of the articulation. + """ + return self.body_data.qvel + + def set_qvel( + self, + qvel: torch.Tensor, + joint_ids: Optional[Sequence[int]] = None, + env_ids: Optional[Sequence[int]] = None, + target: bool = True, + ) -> None: + """Set the velocities (qvel) or target velocities of the articulation. + + Args: + qvel (torch.Tensor): The velocities with shape (N, dof). + joint_ids (Optional[Sequence[int]], optional): Joint indices to apply the velocities. If None, applies to all joints. + env_ids (Optional[Sequence[int]], optional): Environment indices. Defaults to all indices. + If True, sets target positions for simulation. If False, updates current positions directly. + + Raises: + ValueError: If the length of `env_ids` does not match the length of `qvel`. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + if len(local_env_ids) != len(qvel): + logger.log_error( + f"Length of env_ids {len(local_env_ids)} does not match qvel length {len(qvel)}." + ) + + data_type = ( + ArticulationGPUAPIWriteType.JOINT_TARGET_VELOCITY + if target + else ArticulationGPUAPIWriteType.JOINT_VELOCITY + ) + + if self.device.type == "cpu": + local_joint_ids = np.arange(self.dof) if joint_ids is None else joint_ids + for i, env_idx in enumerate(local_env_ids): + setter = ( + self._entities[env_idx].set_current_qvel + if target + else self._entities[env_idx].set_qvel + ) + setter(qvel[i].numpy(), local_joint_ids) + else: + indices = self.body_data.gpu_indices[local_env_ids] + if joint_ids is None: + qvel_set = self.body_data._qvel[local_env_ids] + qvel_set[:, : self.dof] = qvel + else: + self.body_data.qvel + qvel_set = self.body_data._qvel[local_env_ids] + qvel_set[:, joint_ids] = qvel + self._ps.gpu_apply_joint_data( + data=qvel_set, + gpu_indices=indices, + data_type=data_type, + ) + + def set_qf( + self, + qf: torch.Tensor, + joint_ids: Optional[Sequence[int]] = None, + env_ids: Optional[Sequence[int]] = None, + ) -> None: + """Set the generalized efforts (qf) of the articulation. + + Args: + qf (torch.Tensor): The generalized efforts with shape (N, dof). + joint_ids (Optional[Sequence[int]], optional): Joint indices to apply the efforts. If None, applies to all joints. + env_ids (Optional[Sequence[int]], optional): Environment indices. Defaults to all indices. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + if len(local_env_ids) != len(qf): + logger.log_error( + f"Length of env_ids {len(local_env_ids)} does not match qf length {len(qf)}." + ) + + if self.device.type == "cpu": + local_joint_ids = np.arange(self.dof) if joint_ids is None else joint_ids + for i, env_idx in enumerate(local_env_ids): + setter = self._entities[env_idx].set_current_qf + setter(qf[i].numpy(), local_joint_ids) + else: + indices = self.body_data.gpu_indices[local_env_ids] + if joint_ids is None: + qf_set = self.body_data._qf[local_env_ids] + qf_set[:, : self.dof] = qf + else: + self.body_data.qf + qf_set = self.body_data._qf[local_env_ids] + qf_set[:, joint_ids] = qf + self._ps.gpu_apply_joint_data( + data=qf_set, + gpu_indices=indices, + data_type=ArticulationGPUAPIWriteType.JOINT_FORCE, + ) + + def set_drive( + self, + stiffness: Optional[torch.Tensor] = None, + damping: Optional[torch.Tensor] = None, + max_effort: Optional[torch.Tensor] = None, + max_velocity: Optional[torch.Tensor] = None, + friction: Optional[torch.Tensor] = None, + drive_type: str = "force", + joint_ids: Optional[Sequence[int]] = None, + env_ids: Optional[Sequence[int]] = None, + ) -> None: + """Set the drive properties for the articulation. + + Args: + stiffness (torch.Tensor): The stiffness of the joint drive with shape (len(env_ids), len(joint_ids)). + damping (torch.Tensor): The damping of the joint drive with shape (len(env_ids), len(joint_ids)). + max_effort (torch.Tensor): The maximum effort of the joint drive with shape (len(env_ids), len(joint_ids)). + max_velocity (torch.Tensor): The maximum velocity of the joint drive with shape (len(env_ids), len(joint_ids)). + friction (torch.Tensor): The joint friction coefficient with shape (len(env_ids), len(joint_ids)). + drive_type (str, optional): The type of drive to apply. Defaults to "force". + joint_ids (Optional[Sequence[int]], optional): The joint indices to apply the drive to. If None, applies to all joints. Defaults to None. + env_ids (Optional[Sequence[int]], optional): The environment indices to apply the drive to. If None, applies to all environments. Defaults to None. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + local_joint_ids = np.arange(self.dof) if joint_ids is None else joint_ids + + for i, env_idx in enumerate(local_env_ids): + drive_args = { + "drive_type": get_dexsim_drive_type(drive_type), + "joint_ids": local_joint_ids, + } + if stiffness is not None: + drive_args["stiffness"] = stiffness[i].cpu().numpy() + if damping is not None: + drive_args["damping"] = damping[i].cpu().numpy() + if max_effort is not None: + drive_args["max_force"] = max_effort[i].cpu().numpy() + if max_velocity is not None: + drive_args["max_velocity"] = max_velocity[i].cpu().numpy() + if friction is not None: + drive_args["joint_friction"] = friction[i].cpu().numpy() + self._entities[env_idx].set_drive(**drive_args) + + def get_user_ids(self) -> torch.Tensor: + """Get the user ids of the articulation. + + Returns: + torch.Tensor: The user ids of the articulation with shape (N, num_link). + """ + return torch.as_tensor( + np.array( + [entity.get_user_ids() for entity in self._entities], + ), + dtype=torch.int32, + device=self.device, + ) + + def clear_dynamics(self, env_ids: Optional[Sequence[int]] = None) -> None: + """Clear the dynamics of the articulation. + + Args: + env_ids (Optional[Sequence[int]]): Environment indices. If None, then all indices are used. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + if self.device.type == "cpu": + zero_joint_data = np.zeros((len(local_env_ids), self.dof), dtype=np.float32) + for i, env_idx in enumerate(local_env_ids): + self._entities[env_idx].set_qvel(zero_joint_data[i]) + self._entities[env_idx].set_current_qf(zero_joint_data[i]) + else: + zeros = torch.zeros( + (len(local_env_ids), self.dof), dtype=torch.float32, device=self.device + ) + indices = self.body_data.gpu_indices[local_env_ids] + self._ps.gpu_apply_joint_data( + data=zeros, + gpu_indices=indices, + data_type=ArticulationGPUAPIWriteType.JOINT_VELOCITY, + ) + self._ps.gpu_apply_joint_data( + data=zeros, + gpu_indices=indices, + data_type=ArticulationGPUAPIWriteType.JOINT_FORCE, + ) + + def reallocate_body_data(self) -> None: + """Reallocate body data tensors to match the current articulation state in the GPU physics scene.""" + if self.device.type == "cpu": + logger.log_warning(f"Reallocating body data on CPU is not supported.") + return + + max_dof = self._ps.gpu_get_articulation_max_dof() + max_num_links = self._ps.gpu_get_articulation_max_link_count() + self._data._qpos = torch.zeros( + (self.num_instances, max_dof), dtype=torch.float32, device=self.device + ) + self._data._qvel = torch.zeros( + (self.num_instances, max_dof), dtype=torch.float32, device=self.device + ) + self._data._qacc = torch.zeros( + (self.num_instances, max_dof), dtype=torch.float32, device=self.device + ) + self._data._qf = torch.zeros( + (self.num_instances, max_dof), dtype=torch.float32, device=self.device + ) + self._data._body_link_pose = torch.zeros( + (self.num_instances, max_num_links, 7), + dtype=torch.float32, + device=self.device, + ) + self._data._body_link_vel = torch.zeros( + (self.num_instances, max_num_links, 6), + dtype=torch.float32, + device=self.device, + ) + + self._data._body_link_lin_vel = torch.zeros( + (self.num_instances, max_num_links, 3), + dtype=torch.float32, + device=self.device, + ) + self._data._body_link_ang_vel = torch.zeros( + (self.num_instances, max_num_links, 3), + dtype=torch.float32, + device=self.device, + ) + + def reset(self, env_ids: Optional[Sequence[int]] = None) -> None: + local_env_ids = self._all_indices if env_ids is None else env_ids + num_instances = len(local_env_ids) + self.cfg: ArticulationCfg + pos = torch.as_tensor( + self.cfg.init_pos, dtype=torch.float32, device=self.device + ) + rot = ( + torch.as_tensor(self.cfg.init_rot, dtype=torch.float32, device=self.device) + * torch.pi + / 180.0 + ) + pos = pos.unsqueeze(0).repeat(num_instances, 1) + rot = rot.unsqueeze(0).repeat(num_instances, 1) + mat = matrix_from_euler(rot, "XYZ") + pose = ( + torch.eye(4, dtype=torch.float32, device=self.device) + .unsqueeze(0) + .repeat(num_instances, 1, 1) + ) + pose[:, :3, 3] = pos + pose[:, :3, :3] = mat + self.set_local_pose(pose, env_ids=local_env_ids) + + qpos = torch.as_tensor( + self.cfg.init_qpos, dtype=torch.float32, device=self.device + ) + qpos = qpos.unsqueeze(0).repeat(num_instances, 1) + self.set_qpos(qpos, target=False, env_ids=local_env_ids) + # Set drive target to hold position. + self.set_qpos(qpos, target=True, env_ids=local_env_ids) + + self.clear_dynamics(env_ids=local_env_ids) + + if self.device.type == "cuda": + self._ps.gpu_compute_articulation_kinematic( + gpu_indices=self.body_data.gpu_indices[local_env_ids] + ) + + # TODO: To be removed when gpu articulation data sync is supported. + if is_rt_enabled() is False: + self.body_data.body_link_pose + link_pose = self.body_data._body_link_pose[local_env_ids] + indices = self.body_data.gpu_indices[local_env_ids] + self._world.sync_poses_gpu_to_cpu( + link_pose=CudaArray(link_pose), + articulation_gpu_indices=CudaArray(indices), + ) + else: + self._world.update(0.001) + + def _set_default_joint_drive(self) -> None: + """Set default joint drive parameters based on the configuration.""" + import numbers + from embodichain.utils.string import resolve_matching_names_values + + drive_props = [ + ("damping", self.default_joint_damping), + ("stiffness", self.default_joint_stiffness), + ("max_effort", self.default_joint_max_effort), + ("max_velocity", self.default_joint_max_velocity), + ("friction", self.default_joint_friction), + ] + + for prop_name, default_array in drive_props: + value = getattr(self.cfg.drive_pros, prop_name, None) + if value is None: + continue + if isinstance(value, numbers.Number): + default_array[:] = value + else: + try: + indices, _, values = resolve_matching_names_values( + value, self.joint_names + ) + default_array[:, indices] = torch.as_tensor( + values, dtype=torch.float32, device=self.device + ) + except Exception as e: + logger.log_error(f"Failed to set {prop_name}: {e}") + + drive_pros = self.cfg.drive_pros + if isinstance(drive_pros, dict): + drive_type = drive_pros.get("drive_type", None) + else: + drive_type = getattr(drive_pros, "drive_type", None) + + # Apply drive parameters to all articulations in the batch + self.set_drive( + stiffness=self.default_joint_stiffness, + damping=self.default_joint_damping, + max_effort=self.default_joint_max_effort, + max_velocity=self.default_joint_max_velocity, + friction=self.default_joint_friction, + drive_type=drive_type, + ) + + def compute_fk( + self, + qpos: Optional[Union[torch.tensor, np.ndarray]], + link_names: Optional[Union[str, list[str], tuple[str]]] = None, + end_link_name: Optional[str] = None, + root_link_name: Optional[str] = None, + to_dict: bool = False, + **kwargs, + ) -> Union[torch.tensor, dict[str, "pk.Transform3d"]]: + """Compute the forward kinematics (FK) for the given joint positions. + + Args: + qpos (torch.Tensor): Joint positions. Shape can be (dof,) for a single configuration or + (batch_size, dof) for batched configurations. + link_names (Union[str, list[str], tuple[str]], optional): Names of the links for which FK is computed. + If None, all links are considered. + end_link_name (str, optional): Name of the end link for which FK is computed. If None, all links are considered. + root_link_name (str, optional): Name of the root link for which FK is computed. Defaults to None. + to_dict (bool, optional): If True, returns the FK result as a dictionary of Transform3d objects. Defaults to False. + **kwargs: Additional keyword arguments for customization. + + Returns: + torch.Tensor: The homogeneous transformation matrix/matrices for the specified links. + Shape is (batch_size, 4, 4) for batched input or (4, 4) for single input. + If `to_dict` is True, returns a dictionary of Transform3d objects instead. + """ + frame_indices = None + + # Adapt link_names to work with get_frame_indices + if link_names is not None: + if isinstance(link_names, str): + # Single link name + frame_indices = self.pk_chain.get_frame_indices(link_names) + elif isinstance(link_names, (list, tuple)): + # Multiple link names + frame_indices = self.pk_chain.get_frame_indices(*link_names) + else: + raise TypeError( + f"Invalid type for link_names: {type(link_names)}. Expected str, list, or tuple." + ) + + if end_link_name is None and root_link_name is None: + result = self.pk_chain.forward_kinematics( + th=qpos, frame_indices=frame_indices + ) + else: + pk_serial_chain = create_pk_serial_chain( + chain=self.pk_chain, + root_link_name=root_link_name, + end_link_name=end_link_name, + ) + result = pk_serial_chain.forward_kinematics(th=qpos, end_only=True) + + if to_dict: + return result + + # Extract transformation matrices + if isinstance(result, dict): + if link_names: + matrices = torch.stack( + [result[name].get_matrix() for name in link_names], dim=0 + ) + else: + link_name = end_link_name if end_link_name else list(result.keys())[-1] + matrices = result[link_name].get_matrix() + elif isinstance(result, list): + matrices = torch.stack( + [xpos.get_matrix().squeeze() for xpos in result], dim=0 + ) + else: + matrices = result.get_matrix() + + # Ensure batch format + if matrices.dim() == 2: + matrices = matrices.unsqueeze(0) + + # Create result tensor with proper homogeneous coordinates + if matrices.dim() == 4: # Multiple links + num_links, batch_size, _, _ = matrices.shape + result = ( + torch.eye(4, device=self.device) + .expand(num_links, batch_size, 4, 4) + .clone() + ) + result[:, :, :3, :] = matrices[:, :, :3, :] + result = result.permute(1, 0, 2, 3) # (batch_size, num_links, 4, 4) + elif matrices.dim() == 3: # Single link + batch_size, _, _ = matrices.shape + result = torch.eye(4, device=self.device).expand(batch_size, 4, 4).clone() + result[:, :3, :] = matrices[:, :3, :] + else: + raise ValueError(f"Unexpected matrices shape: {matrices.shape}") + + return result + + def compute_jacobian( + self, + qpos: Optional[Union[torch.Tensor, np.ndarray]], + end_link_name: str = None, + root_link_name: str = None, + locations: Optional[Union[torch.Tensor, np.ndarray]] = None, + jac_type: str = "full", + ) -> torch.Tensor: + """Compute the Jacobian matrix for the given joint positions using the pk_serial_chain. + + Args: + qpos (torch.Tensor): The joint positions. Shape can be (dof,) for a single configuration + or (batch_size, dof) for batched configurations. + end_link_name (str, optional): The name of the end link for which the Jacobian is computed. + Defaults to the last link in the chain. + root_link_name (str, optional): The name of the root link for which the Jacobian is computed. + Defaults to the first link in the chain. + locations (Union[torch.Tensor, np.ndarray], optional): Offset points relative to the end-effector + frame for which the Jacobian is computed. + Shape can be (batch_size, 3) or (3,) for a single offset. + Defaults to None (origin of the end-effector frame). + jac_type (str, optional): Specifies the part of the Jacobian to return: + - 'full': Returns the full Jacobian (6, dof) or (batch_size, 6, dof). + - 'trans': Returns only the translational part (3, dof) or (batch_size, 3, dof). + - 'rot': Returns only the rotational part (3, dof) or (batch_size, 3, dof). + Defaults to 'full'. + + Returns: + torch.Tensor: The Jacobian matrix. Shape depends on the input: + - For a single link: (6, dof) or (batch_size, 6, dof). + - For multiple links: (num_links, 6, dof) or (num_links, batch_size, 6, dof). + The shape also depends on the `jac_type` parameter. + """ + if qpos is None: + qpos = torch.zeros(self.dof, device=self.device) + + # Ensure qpos is a tensor on the correct device + qpos = torch.as_tensor(qpos, dtype=torch.float32, device=self.device) + + # Default root and end link names if not provided + frame_names = self.pk_chain.get_frame_names() + if root_link_name is None: + root_link_name = frame_names[0] # Default to the first frame + if end_link_name is None: + end_link_name = frame_names[-1] # Default to the last frame + + # Create pk_serial_chain + pk_serial_chain = create_pk_serial_chain( + chain=self.pk_chain, + root_link_name=root_link_name, + end_link_name=end_link_name, + ) + + # Compute the Jacobian using the kinematics chain + J = pk_serial_chain.jacobian(th=qpos, locations=locations) + + # Handle jac_type to return the desired part of the Jacobian + if jac_type == "trans": + return J[:, :3, :] if J.dim() == 3 else J[:3, :] + elif jac_type == "rot": + return J[:, 3:, :] if J.dim() == 3 else J[3:, :] + elif jac_type == "full": + return J + else: + raise ValueError( + f"Invalid jac_type '{jac_type}'. Must be 'full', 'trans', or 'rot'." + ) + + def set_visual_material( + self, + mat: VisualMaterial, + env_ids: Optional[Sequence[int]] = None, + link_names: Optional[List[str]] = None, + ) -> None: + """Set visual material for the rigid object. + + Args: + mat (VisualMaterial): The material to set. + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + link_names (Optional[List[str]], optional): List of link names to apply the material to. If None, applies to all links. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + link_names = self.link_names if link_names is None else link_names + + for i, env_idx in enumerate(local_env_ids): + for link_name in link_names: + mat_inst = mat.create_instance( + f"{mat.uid}_{self.uid}_{link_name}_{env_idx}" + ) + self._entities[env_idx].set_material(link_name, mat_inst.mat) + self._visual_material[env_idx][link_name] = mat_inst + + def get_visual_material_inst( + self, + env_ids: Optional[Sequence[int]] = None, + link_names: Optional[List[str]] = None, + ) -> List[Dict[str, VisualMaterialInst]]: + """Get visual material instances for the rigid object. + + Args: + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + link_names (Optional[List[str]], optional): List of link names to filter materials. If None, returns materials for all links. + Returns: + List[Dict[str, VisualMaterialInst]]: A list where each element corresponds to an environment and contains a dictionary mapping link names to their VisualMaterialInst. + """ + if env_ids is None and link_names is None: + return self._visual_material + + local_env_ids = self._all_indices if env_ids is None else env_ids + link_names = self.link_names if link_names is None else link_names + + result = [] + for i, env_idx in enumerate(local_env_ids): + if link_names is None: + result.append(self._visual_material[env_idx]) + else: + mat_dict = { + link_name: self._visual_material[env_idx][link_name] + for link_name in link_names + if link_name in self._visual_material[env_idx] + } + result.append(mat_dict) + return result + + def destroy(self) -> None: + env = self._world.get_env() + arenas = env.get_all_arenas() + if len(arenas) == 0: + arenas = [env] + for i, entity in enumerate(self._entities): + arenas[i].remove_articulation(entity) diff --git a/embodichain/lab/sim/objects/gizmo.py b/embodichain/lab/sim/objects/gizmo.py new file mode 100644 index 00000000..137fe20d --- /dev/null +++ b/embodichain/lab/sim/objects/gizmo.py @@ -0,0 +1,545 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +""" +Gizmo: A reusable controller for interactive manipulation of simulation elements (object, robot, camera, etc.) +""" + + +import numpy as np +import torch +import dexsim +from typing import Callable, Optional +from scipy.spatial.transform import Rotation as R + +from embodichain.lab.sim.common import BatchEntity +from embodichain.lab.sim.objects import RigidObject, Robot +from embodichain.lab.sim.sensors import Camera +from embodichain.utils import configclass, logger + +from dexsim.types import ( + AxisOption, + RotationRingsOption, + AxisArrowType, + AxisCornerType, + AxisTagType, + TransformMask, + ActorType, + RigidBodyShape, + PhysicalAttr, +) +from dexsim.render import GizmoController + +from embodichain.lab.sim.utility.gizmo_utils import create_gizmo_callback + + +@configclass +class GizmoCfg: + """Configuration class for Gizmo parameters. + + This class defines the visual and interaction parameters for gizmo controllers, + including axis appearance and rotation rings settings. + """ + + # Axis configuration + axis_length_x: float = 0.2 + """Length of X-axis arrow.""" + axis_length_y: float = 0.2 + """Length of Y-axis arrow.""" + axis_length_z: float = 0.2 + """Length of Z-axis arrow.""" + axis_size: float = 0.01 + """Thickness of axis lines.""" + arrow_type: AxisArrowType = AxisArrowType.CONE + """Type of arrow head.""" + corner_type: AxisCornerType = AxisCornerType.SPHERE + """Type of axis corner.""" + tag_type: AxisTagType = AxisTagType.PLANE + """Type of axis label.""" + + # Rotation rings configuration + rings_radius: float = 0.15 + """Radius of rotation rings.""" + rings_size: float = 0.01 + """Thickness of rotation rings.""" + + def to_options_dict(self) -> dict: + """Convert configuration to options dictionary format expected by gizmo creation. + + Returns: + Dictionary containing AxisOption and RotationRingsOption objects. + """ + return { + "axis": AxisOption( + lx=self.axis_length_x, + ly=self.axis_length_y, + lz=self.axis_length_z, + size=self.axis_size, + arrow_type=self.arrow_type, + corner_type=self.corner_type, + tag_type=self.tag_type, + ), + "rings": RotationRingsOption( + radius=self.rings_radius, size=self.rings_size + ), + } + + +class Gizmo: + """ + Generic Gizmo controller for simulation elements. + Supports RigidObject, Robot, and Camera with type-specific handling. + + Note: + Gizmo can only be used in single environment mode (num_envs=1). + Will raise RuntimeError if used with multiple environments. + """ + + def __init__( + self, + target: BatchEntity, + cfg: Optional[GizmoCfg] = None, + control_part: Optional[str] = "arm", + ): + """ + Args: + target: The simulation element to control (RigidObject, Robot, or Camera) + cfg: Gizmo configuration parameters (optional, uses default if None) + control_part: For robots, specifies which control part to use (optional, default: "arm") + """ + self.target = target + self._target_type = self._detect_target_type(target) + self._control_part = control_part + self._env = dexsim.default_world().get_env() + self._windows = dexsim.default_world().get_windows() + + # Check if running in single environment (num_env must be 1) + num_envs = dexsim.get_world_num() + if num_envs > 1: + raise RuntimeError( + f"Gizmo can only be used in single environment mode (num_env=1), " + f"but current num_envs={num_envs}. Please create simulation with num_envs=1." + ) + + # Use provided config or get default + if cfg is None: + cfg = self._get_default_cfg() + self.cfg = cfg + self._gizmo = self._create_gizmo(self.cfg) + self._callback = None + self._state = "active" + self._setup_gizmo_follow() + + def _detect_target_type(self, target: BatchEntity) -> str: + """Detect target type: 'rigidobject', 'robot', or 'camera' using isinstance only.""" + if Robot is not None and isinstance(target, Robot): + return "robot" + if Camera is not None and isinstance(target, Camera): + return "camera" + if RigidObject is not None and isinstance(target, RigidObject): + return "rigidobject" + + raise ValueError( + f"Unsupported target type: {type(target)}. Only RigidObject, Robot, and Camera are supported." + ) + + def _get_default_cfg(self) -> GizmoCfg: + """Get default gizmo configuration (same for all target types)""" + return GizmoCfg() + + def _create_gizmo(self, cfg: GizmoCfg): + """Create gizmo using configuration object""" + options = cfg.to_options_dict() + axis = options["axis"] + rings = options["rings"] + return self._env.create_gizmo(axis, rings) + + def _compute_ee_pose_fk(self): + """Compute end-effector pose using forward kinematics""" + # Get current joint positions for this arm + proprioception = self.target.get_proprioception() + current_qpos_full = proprioception["qpos"] + current_joint_ids = self.target.get_joint_ids(self._robot_arm_name) + + joint_positions = current_qpos_full[:, current_joint_ids] + if joint_positions.dim() > 1: + joint_positions = joint_positions[0] + + # Compute forward kinematics + ee_pose = self.target.compute_fk( + joint_positions, name=self._control_part, to_matrix=True + ) + + return ee_pose + + def _create_proxy_cube( + self, position: np.ndarray, rotation_matrix: np.ndarray, name: str + ): + """Create a proxy cube for gizmo tracking""" + # Convert rotation matrix to euler angles + euler = R.from_matrix(rotation_matrix).as_euler("xyz", degrees=False) + + # Create small proxy cube at specified position + proxy_cube = self._env.create_cube(0.02, 0.02, 0.02) # 2cm cube + proxy_cube.set_location(position[0], position[1], position[2]) + proxy_cube.set_rotation_euler(euler[0], euler[1], euler[2]) + + # Add kinematic physics to proxy cube + attr = PhysicalAttr() + attr.mass = 0.05 + proxy_cube.add_rigidbody(ActorType.KINEMATIC, RigidBodyShape.CONVEX, attr) + + # Connect gizmo to proxy cube + self._gizmo.node.update_gizmo_follow(proxy_cube.node) + + logger.log_info(f"{name} gizmo proxy created at position: {position}") + return proxy_cube + + def _setup_camera_gizmo(self): + """Setup gizmo for Camera by creating a proxy RigidObject at camera position""" + # Get current camera pose + camera_pose = self.target.get_local_pose(to_matrix=True)[0] # Get first camera + camera_pos = camera_pose[:3, 3].cpu().numpy() + camera_rot_matrix = camera_pose[:3, :3].cpu().numpy() + + # Create proxy cube and set callback + self._proxy_cube = self._create_proxy_cube( + camera_pos, camera_rot_matrix, "Camera" + ) + self._gizmo.node.set_flush_transform_callback(self._proxy_gizmo_callback) + + def _proxy_gizmo_callback(self, node, translation, rotation, flag): + """Generic callback for proxy-based gizmo: only updates proxy cube transform, defers actual updates""" + if node is None: + return + + # Check if proxy cube still exists (not destroyed) + if not hasattr(self, "_proxy_cube") or self._proxy_cube is None: + return + + # Update proxy cube transform + if flag == (TransformMask.TRANSFORM_LOCAL | TransformMask.TRANSFORM_T): + node.set_translation(translation) + elif flag == (TransformMask.TRANSFORM_LOCAL | TransformMask.TRANSFORM_R): + node.set_rotation_rpy(rotation) + + # Mark that target needs to be updated, save target transform + proxy_pos = self._proxy_cube.get_location() + proxy_rot = self._proxy_cube.get_rotation_euler() + target_transform = torch.eye(4, dtype=torch.float32) + target_transform[:3, 3] = torch.tensor( + [proxy_pos[0], proxy_pos[1], proxy_pos[2]], dtype=torch.float32 + ) + target_transform[:3, :3] = torch.tensor( + R.from_euler("xyz", proxy_rot).as_matrix(), dtype=torch.float32 + ) + self._pending_target_transform = target_transform + + def _update_camera_pose(self, target_transform: torch.Tensor): + """Update camera pose to match target transform""" + try: + # Set camera pose using set_local_pose method + # target_transform shape: (4, 4), but set_local_pose expects (N, 4, 4) + target_transform_batch = target_transform.unsqueeze( + 0 + ) # Add batch dimension + self.target.set_local_pose(target_transform_batch) + return True + except Exception as e: + logger.log_error(f"Error updating camera pose: {e}") + return False + + def _setup_robot_gizmo(self): + """Setup gizmo for Robot by creating a proxy RigidObject at end-effector""" + # Get end-effector pose using specified control part + if self.target.cfg.solver_cfg is None: + raise ValueError( + "Robot has no solver configured for IK/FK computations for gizmo" + ) + + arm_names = list(self.target.control_parts.keys()) + if not arm_names: + raise ValueError("Robot has no control parts defined") + + # Use specified control part or fall back to first available + if self._control_part and self._control_part in arm_names: + self._robot_arm_name = self._control_part + else: + logger.log_error(f"Control part '{self._control_part}' not found.") + + logger.log_info(f"Using control part: {self._robot_arm_name}") + + # Get end-effector pose using forward kinematics + ee_pose = self._compute_ee_pose_fk()[0] # remove batch dimension + + ee_pos = ee_pose[:3, 3].cpu().numpy() + ee_rot_matrix = ee_pose[:3, :3].cpu().numpy() + + # Create proxy cube and set callback + self._proxy_cube = self._create_proxy_cube(ee_pos, ee_rot_matrix, "Robot") + self._gizmo.node.set_flush_transform_callback(self._proxy_gizmo_callback) + + def _update_robot_ik(self, target_transform: torch.Tensor): + """Update robot joints using IK to reach target transform""" + try: + # Get robot solver for the arm + solver = self.target.get_solver(self._robot_arm_name) + if solver is None: + logger.log_warning(f"No solver found for arm: {self._robot_arm_name}") + return False + + # Get current joint positions as seed using proprioception + current_qpos_full = self.target.get_qpos() + + # Get joint IDs for this arm + current_joint_ids = self.target.get_joint_ids(self._robot_arm_name) + + # Extract joint positions for this specific arm + if len(current_joint_ids) > 0: + joint_seed = current_qpos_full[ + :, current_joint_ids + ] # Select arm joints + if joint_seed.dim() > 1: + joint_seed = joint_seed[0] # Take first batch element + else: + logger.log_warning( + f"No joint IDs found for arm: {self._robot_arm_name}" + ) + return False + + # Solve IK + ik_success, new_qpos = solver.get_ik( + target_xpos=target_transform, joint_seed=joint_seed + ) + + if ik_success: + # Ensure correct dimensions for setting qpos + if new_qpos.dim() == 1: + new_qpos = new_qpos.unsqueeze(0) + elif new_qpos.dim() == 3: + new_qpos = new_qpos[:, 0, :] + + # Update robot joint positions + self.target.set_qpos(qpos=new_qpos, joint_ids=current_joint_ids) + return True + else: + logger.log_warning("IK solution not found") + return False + + except Exception as e: + logger.log_error(f"Error in robot IK: {e}") + return False + + def _setup_gizmo_follow(self): + """Setup gizmo based on target type""" + if self._target_type == "rigidobject": + # RigidObject: direct node access through MeshObject + self._gizmo.node.update_gizmo_follow(self.target._entities[0].node) + self._gizmo.node.set_flush_transform_callback(create_gizmo_callback()) + elif self._target_type == "robot": + # Robot: create proxy object at end-effector position + self._setup_robot_gizmo() + elif self._target_type == "camera": + # Camera: create proxy object at camera position + self._setup_camera_gizmo() + + def attach(self, target: BatchEntity): + """Attach gizmo to a new simulation element.""" + self.target = target + self._target_type = self._detect_target_type(target) + self._setup_gizmo_follow() + + def detach(self): + """Detach gizmo from current element.""" + self.target = None + # Use detach_parent to properly disconnect gizmo + try: + self._gizmo.node.detach_parent() + except Exception as e: + logger.log_warning(f"Failed to detach gizmo parent: {e}") + + def set_transform_callback(self, callback: Callable): + """Set callback for gizmo transform events (translation/rotation).""" + self._callback = callback + self._gizmo.node.set_flush_transform_callback(callback) + + def set_world_pose(self, pose): + """Set gizmo's world pose.""" + self._gizmo.node.set_world_pose(pose) + + def set_local_pose(self, pose): + """Set gizmo's local pose.""" + self._gizmo.node.set_local_pose(pose) + + def set_line_width(self, width: float): + """Set gizmo line width.""" + self._gizmo.node.set_line_width(width) + + def enable_collision(self, enabled: bool): + """Enable or disable gizmo collision.""" + self._gizmo.node.enable_collision(enabled) + + def get_world_pose(self): + """Get gizmo's world pose.""" + return self._gizmo.node.get_world_pose() + + def get_local_pose(self): + """Get gizmo's local pose.""" + return self._gizmo.node.get_local_pose() + + def get_name(self): + """Get gizmo node name.""" + return self._gizmo.node.get_name() + + def get_parent(self): + """Get gizmo's parent node.""" + return self._gizmo.node.get_parent() + + def toggle_visibility(self) -> bool: + """ + Toggle the visibility of the gizmo. + + Returns: + bool: The new visibility state (True = visible, False = hidden) + """ + if not hasattr(self, "_is_visible"): + self._is_visible = True # Default to visible + + # Toggle the state + self._is_visible = not self._is_visible + + # Apply the visibility setting to the gizmo node + if self._gizmo and hasattr(self._gizmo, "node"): + self._gizmo.node.set_physical_visible(self._is_visible, self._is_visible) + + return self._is_visible + + def set_visibility(self, visible: bool): + """ + Set the visibility of the gizmo. + + Args: + visible (bool): True to show, False to hide the gizmo + """ + self._is_visible = visible + + # Apply the visibility setting to the gizmo node + if self._gizmo and hasattr(self._gizmo, "node"): + self._gizmo.node.set_physical_visible(self._is_visible, self._is_visible) + + def is_visible(self) -> bool: + """ + Check if the gizmo is currently visible. + + Returns: + bool: True if visible, False if hidden + """ + return getattr(self, "_is_visible", True) + + def update(self): + """Synchronize gizmo with target's current transform, and handle IK solving here.""" + if self._target_type == "rigidobject": + self._gizmo.node.update_gizmo_follow(self.target._entities[0].node) + elif self._target_type == "robot": + # If there is a pending target, solve IK and clear it + if ( + hasattr(self, "_pending_target_transform") + and self._pending_target_transform is not None + ): + self._update_robot_ik(self._pending_target_transform) + self._pending_target_transform = None + elif self._target_type == "camera": + # Update proxy cube position to match current camera pose + if hasattr(self, "_proxy_cube") and self._proxy_cube: + camera_pose = self.target.get_local_pose(to_matrix=True)[0] + camera_pos = camera_pose[:3, 3].cpu().numpy() + self._proxy_cube.set_location( + camera_pos[0], camera_pos[1], camera_pos[2] + ) + + # If there is a pending camera target, update camera pose and clear it + if ( + hasattr(self, "_pending_target_transform") + and self._pending_target_transform is not None + ): + self._update_camera_pose(self._pending_target_transform) + self._pending_target_transform = None + + def apply_transform(self, translation, rotation): + """Apply transform based on target type""" + if self._target_type == "rigidobject": + self.target.set_location(*translation) + self.target.set_rotation_euler(*rotation) + elif self._target_type == "robot": + # Robot transforms are handled by IK in the gizmo callback + if hasattr(self, "_proxy_cube") and self._proxy_cube: + self._proxy_cube.set_location(*translation) + self._proxy_cube.set_rotation_euler(*rotation) + elif self._target_type == "camera": + # Camera transforms are handled by pose update in the gizmo callback + if hasattr(self, "_proxy_cube") and self._proxy_cube: + self._proxy_cube.set_location(*translation) + self._proxy_cube.set_rotation_euler(*rotation) + else: + # Other target types + pass + + def destroy(self): + """Clean up gizmo resources and release references.""" + # Clear transform callback first to avoid bad_function_call + if hasattr(self, "_gizmo") and self._gizmo and hasattr(self._gizmo, "node"): + try: + # Clear transform callback before any other cleanup + self._gizmo.node.set_flush_transform_callback(None) + logger.log_info("Cleared gizmo transform callback") + except Exception as e: + logger.log_warning(f"Failed to clear gizmo callback: {e}") + + # Remove proxy cube if exists (before detaching gizmo) + if hasattr(self, "_proxy_cube") and self._proxy_cube: + try: + # Detach gizmo from proxy cube first + if ( + hasattr(self, "_gizmo") + and self._gizmo + and hasattr(self._gizmo, "node") + ): + self._gizmo.node.detach_parent() + # Then remove the proxy cube + self._env.remove_actor(self._proxy_cube) + logger.log_info("Successfully removed proxy cube from environment") + except Exception as e: + logger.log_warning(f"Failed to remove proxy cube: {e}") + self._proxy_cube = None + + # Final gizmo cleanup + if hasattr(self, "_gizmo") and self._gizmo and hasattr(self._gizmo, "node"): + try: + # Ensure detach_parent is called if not done above + if self._target_type in ["robot", "camera"]: + pass # Already detached above + else: + self._gizmo.node.detach_parent() + logger.log_info("Successfully cleaned up gizmo node") + except Exception as e: + logger.log_warning(f"Failed to cleanup gizmo node: {e}") + + # Clear pending transform + if hasattr(self, "_pending_target_transform"): + self._pending_target_transform = None + + # Directly release references + self._gizmo = None + self.target = None diff --git a/embodichain/lab/sim/objects/light.py b/embodichain/lab/sim/objects/light.py new file mode 100644 index 00000000..fb085e88 --- /dev/null +++ b/embodichain/lab/sim/objects/light.py @@ -0,0 +1,281 @@ +import torch +import numpy as np +from typing import List, Optional, Sequence +from dexsim.render import Light as _Light +from embodichain.lab.sim.cfg import LightCfg +from embodichain.lab.sim.common import BatchEntity +from embodichain.utils import logger + + +class Light(BatchEntity): + """Light represents a batch of lights in the simulation. + + Each light supports the following properties: + - Color (3 floats) + - Intensity (1 float) + - Falloff (1 float) + - Location (3 floats) + """ + + def __init__( + self, + cfg: LightCfg, + entities: List[_Light] = None, + device: torch.device = torch.device("cpu"), + ) -> None: + + super().__init__(cfg, entities, device) + + def set_color( + self, colors: torch.Tensor, env_ids: Optional[Sequence[int]] = None + ) -> None: + """Set color for one or more lights. + + Args: + colors (torch.Tensor): Tensor of shape (M, 3) or (3,), representing RGB values. + - If shape is (3,), the same color is applied to all targeted instances. + - If shape is (M, 3), M must match the number of targeted instances. + env_ids (Optional[Sequence[int]]): Indices of instances to set. If None: + - For colors.shape == (3,), applies to all instances. + - For colors.shape == (M, 3), M must equal num_instances, applies per-instance. + """ + self._apply_vector3(colors, env_ids, "set_color") + + def set_intensity( + self, intensities: torch.Tensor, env_ids: Optional[Sequence[int]] = None + ) -> None: + """Set intensity for one or more lights. + + Args: + intensities (torch.Tensor): Tensor of shape (M,), (1,), or scalar (0-dim). + - If scalar or shape (1,), the same intensity is applied to all targeted instances. + - If shape (M,), M must match the number of targeted instances. + env_ids (Optional[Sequence[int]]): Indices of instances to set. If None: + - For scalar/shape (1,), applies to all instances. + - For shape (M,), M must equal num_instances, applies per-instance. + """ + self._apply_scalar(intensities, env_ids, "set_intensity") + + def set_falloff( + self, falloffs: torch.Tensor, env_ids: Optional[Sequence[int]] = None + ) -> None: + """Set falloff (radius) for one or more lights. + + Args: + falloffs (torch.Tensor): Tensor of shape (M,), (1,), or scalar (0-dim). + - If scalar or shape (1,), the same falloff is applied to all targeted instances. + - If shape (M,), M must match the number of targeted instances. + env_ids (Optional[Sequence[int]]): Indices of instances to set. If None: + - For scalar/shape (1,), applies to all instances. + - For shape (M,), M must equal num_instances, applies per-instance. + """ + self._apply_scalar(falloffs, env_ids, "set_falloff") + + def set_local_pose( + self, + pose: torch.Tensor, + env_ids: Optional[Sequence[int]] = None, + to_matrix: bool = False, + ) -> None: + """Set local pose (translation) for one or more lights. + + Args: + pose (torch.Tensor): + - If to_matrix=False: shape (3,) or (M, 3), representing (x, y, z). + - If to_matrix=True: shape (4, 4) or (M, 4, 4); translation extracted automatically. + env_ids (Optional[Sequence[int]]): Indices to set. If None: + - For vector input (3,) broadcast to all, or (M,3) with M == num_instances. + - For matrix input (4,4) broadcast to all, or (M,4,4) with M == num_instances. + to_matrix (bool): Interpret `pose` as full 4x4 matrix if True, else as vector(s). + """ + if not torch.is_tensor(pose): + logger.log_error( + f"set_local_pose requires a torch.Tensor, got {type(pose)}" + ) + return + + cpu = pose.detach().cpu() + if to_matrix: + if cpu.ndim == 2 and cpu.shape == (4, 4): + trans = cpu[:3, 3] + elif cpu.ndim == 3 and cpu.shape[1:] == (4, 4): + trans = cpu[..., 0:3, 3] + else: + logger.log_error( + f"set_local_pose matrix: expected (4,4) or (N,4,4), got {tuple(cpu.shape)}" + ) + return + else: + trans = cpu # expect (3,) or (M,3) + + try: + self._apply_vector3(trans, env_ids, setter_name="set_location") + except Exception as e: + logger.log_error(f"set_local_pose: error while applying translation: {e}") + + def get_local_pose(self, to_matrix: bool = False) -> torch.Tensor: + """Get local pose of each light, either as full matrix or translation vector. + + Args: + to_matrix (bool, optional): If True, return poses as 4×4 matrices. + If False, return translations only as (x, y, z). Defaults to False. + Returns: + torch.Tensor: + - If to_matrix=True: Tensor of shape (N, 4, 4), where N == num_instances. + - If to_matrix=False: Tensor of shape (N, 3), containing translations. + On error or empty instances, returns an empty tensor with shape (0, 4, 4) or (0, 3) respectively, and logs via logger.log_error. + """ + mats = [] + for i in range(self.num_instances): + try: + mat = self._entities[i].get_local_pose() # expect numpy (4,4) + arr = np.array(mat, dtype=np.float32) + if arr.shape != (4, 4): + logger.log_error( + f"get_local_pose: unexpected shape {arr.shape} for instance {i}" + ) + return torch.empty( + (0, 4, 4) if to_matrix else (0, 3), dtype=torch.float32 + ) + mats.append(arr) + except Exception as e: + logger.log_error(f"get_local_pose: error for instance {i}: {e}") + return torch.empty( + (0, 4, 4) if to_matrix else (0, 3), dtype=torch.float32 + ) + + if not mats: + return torch.empty((0, 4, 4) if to_matrix else (0, 3), dtype=torch.float32) + + stacked = np.stack(mats, axis=0) # (N,4,4) + tensor4 = torch.from_numpy(stacked) + if to_matrix: + return tensor4 + # else return translations + return tensor4[:, 0:3, 3].clone() + + def _apply_vector3( + self, + tensor: torch.Tensor, + env_ids: Optional[Sequence[int]], + setter_name: str, + ) -> None: + """ + Generic helper for 3-element vectors (color, location). + Expects tensor shape: (3,), or (M,3) with M == num_instances or M == len(env_ids). + """ + # Validate tensor type + if not torch.is_tensor(tensor): + logger.log_error( + f"{setter_name} requires a torch.Tensor, got {type(tensor)}" + ) + return + + cpu = tensor.detach().cpu() + # Determine target indices + if env_ids is None: + all_ids = list(range(self.num_instances)) + else: + all_ids = list(env_ids) + + # Cases: + # 1) cpu.ndim == 1 and size == 3: broadcast to all_ids + if cpu.ndim == 1 and cpu.shape[0] == 3: + arr = cpu.numpy() + for i in all_ids: + getattr(self._entities[i], setter_name)( + float(arr[0]), float(arr[1]), float(arr[2]) + ) + return + + # 2) cpu.ndim == 2 and cpu.shape == (num_instances, 3), env_ids None or full + if cpu.ndim == 2 and cpu.shape == (self.num_instances, 3) and env_ids is None: + arr_all = cpu.numpy() + for i in range(self.num_instances): + getattr(self._entities[i], setter_name)( + float(arr_all[i, 0]), float(arr_all[i, 1]), float(arr_all[i, 2]) + ) + return + + # 3) cpu.ndim == 2 and env_ids provided, cpu.shape == (len(env_ids), 3) + if ( + cpu.ndim == 2 + and env_ids is not None + and cpu.shape[0] == len(all_ids) + and cpu.shape[1] == 3 + ): + arr_sel = cpu.numpy() + for idx, i in enumerate(all_ids): + getattr(self._entities[i], setter_name)( + float(arr_sel[idx, 0]), + float(arr_sel[idx, 1]), + float(arr_sel[idx, 2]), + ) + return + + logger.log_error( + f"{setter_name}: tensor shape {tuple(cpu.shape)} is invalid for broadcasting " + f"(expected (3,) or ({self.num_instances},3) or ({len(all_ids)},3))." + ) + + def _apply_scalar( + self, + tensor: torch.Tensor, + env_ids: Optional[Sequence[int]], + setter_name: str, + ) -> None: + """ + Generic helper for scalar floats (intensity, falloff). + Accepts tensor shape: () (0-dim), (1,), or (M,) with M == num_instances or M == len(env_ids). + """ + if not torch.is_tensor(tensor): + logger.log_error( + f"{setter_name} requires a torch.Tensor, got {type(tensor)}" + ) + return + + cpu = tensor.detach().cpu() + if env_ids is None: + all_ids = list(range(self.num_instances)) + else: + all_ids = list(env_ids) + + # 1) scalar tensor: broadcast + if cpu.ndim == 0: + val = float(cpu.item()) + for i in all_ids: + getattr(self._entities[i], setter_name)(val) + return + + # 2) 1D tensor: + if cpu.ndim == 1: + length = cpu.shape[0] + arr = cpu.numpy() + # a) length == num_instances and env_ids None: map one-to-one + if length == self.num_instances and env_ids is None: + for i in range(self.num_instances): + getattr(self._entities[i], setter_name)(float(arr[i])) + return + # b) length == len(env_ids) when env_ids provided: map one-to-one + if env_ids is not None and length == len(all_ids): + for idx, i in enumerate(all_ids): + getattr(self._entities[i], setter_name)(float(arr[idx])) + return + # c) length == 1: broadcast + if length == 1: + val = float(arr[0]) + for i in all_ids: + getattr(self._entities[i], setter_name)(val) + return + + logger.log_error( + f"{setter_name}: tensor shape {tuple(cpu.shape)} is invalid for broadcasting " + f"(expected scalar, (1,), ({self.num_instances},) or ({len(all_ids)},))." + ) + + def reset(self, env_ids: Optional[Sequence[int]] = None) -> None: + self.cfg: LightCfg + self.set_color(torch.as_tensor(self.cfg.color), env_ids=env_ids) + self.set_intensity(torch.as_tensor(self.cfg.intensity), env_ids=env_ids) + self.set_falloff(torch.as_tensor(self.cfg.radius), env_ids=env_ids) + self.set_local_pose(torch.as_tensor(self.cfg.init_pos), env_ids=env_ids) diff --git a/embodichain/lab/sim/objects/rigid_object.py b/embodichain/lab/sim/objects/rigid_object.py new file mode 100644 index 00000000..d5b4bb6e --- /dev/null +++ b/embodichain/lab/sim/objects/rigid_object.py @@ -0,0 +1,667 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import dexsim +import numpy as np + +from dataclasses import dataclass +from typing import List, Sequence, Optional, Union + +from dexsim.models import MeshObject +from dexsim.types import RigidBodyGPUAPIReadType, RigidBodyGPUAPIWriteType +from dexsim.engine import CudaArray, PhysicsScene +from embodichain.lab.sim.cfg import RigidObjectCfg, RigidBodyAttributesCfg +from embodichain.lab.sim import ( + VisualMaterial, + VisualMaterialInst, + BatchEntity, +) +from embodichain.lab.sim.utility import is_rt_enabled +from embodichain.utils.math import convert_quat +from embodichain.utils.math import matrix_from_quat, quat_from_matrix, matrix_from_euler +from embodichain.utils import logger + + +@dataclass +class RigidBodyData: + """Data manager for rigid body with body type of dynamic or kinematic. + + Note: + 1. The pose data managed by dexsim is in the format of (qx, qy, qz, qw, x, y, z), but in SimulationManager, we use (x, y, z, qw, qx, qy, qz) format. + """ + + def __init__( + self, entities: List[MeshObject], ps: PhysicsScene, device: torch.device + ) -> None: + """Initialize the RigidBodyData. + + Args: + entities (List[MeshObject]): List of MeshObjects representing the rigid bodies. + ps (PhysicsScene): The physics scene. + device (torch.device): The device to use for the rigid body data. + """ + self.entities = entities + self.ps = ps + self.num_instances = len(entities) + self.device = device + + # get gpu indices for the entities. + self.gpu_indices = torch.as_tensor( + [entity.get_gpu_index() for entity in self.entities], + dtype=torch.int32, + device=self.device, + ) + + # Initialize rigid body data. + self._pose = torch.zeros( + (self.num_instances, 7), dtype=torch.float32, device=self.device + ) + self._lin_vel = torch.zeros( + (self.num_instances, 3), dtype=torch.float32, device=self.device + ) + self._ang_vel = torch.zeros( + (self.num_instances, 3), dtype=torch.float32, device=self.device + ) + + @property + def pose(self) -> torch.Tensor: + if self.device.type == "cpu": + # Fetch pose from CPU entities + xyzs = torch.as_tensor( + np.array([entity.get_location() for entity in self.entities]), + dtype=torch.float32, + device=self.device, + ) + quats = torch.as_tensor( + np.array( + [entity.get_rotation_quat() for entity in self.entities], + ), + dtype=torch.float32, + device=self.device, + ) + quats = convert_quat(quats, to="wxyz") + self._pose = torch.cat((xyzs, quats), dim=-1) + else: + self.ps.gpu_fetch_rigid_body_data( + data=self._pose, + gpu_indices=self.gpu_indices, + data_type=RigidBodyGPUAPIReadType.POSE, + ) + self._pose[:, :4] = convert_quat(self._pose[:, :4], to="wxyz") + self._pose = self._pose[:, [4, 5, 6, 0, 1, 2, 3]] + return self._pose + + @property + def lin_vel(self) -> torch.Tensor: + if self.device.type == "cpu": + # Fetch linear velocity from CPU entities + self._lin_vel = torch.as_tensor( + np.array([entity.get_linear_velocity() for entity in self.entities]), + dtype=torch.float32, + device=self.device, + ) + else: + self.ps.gpu_fetch_rigid_body_data( + data=self._lin_vel, + gpu_indices=self.gpu_indices, + data_type=RigidBodyGPUAPIReadType.LINEAR_VELOCITY, + ) + return self._lin_vel + + @property + def ang_vel(self) -> torch.Tensor: + if self.device.type == "cpu": + # Fetch angular velocity from CPU entities + self._ang_vel = torch.as_tensor( + np.array( + [entity.get_angular_velocity() for entity in self.entities], + ), + dtype=torch.float32, + device=self.device, + ) + else: + self.ps.gpu_fetch_rigid_body_data( + data=self._ang_vel, + gpu_indices=self.gpu_indices, + data_type=RigidBodyGPUAPIReadType.ANGULAR_VELOCITY, + ) + return self._ang_vel + + @property + def vel(self) -> torch.Tensor: + """Get the linear and angular velocities of the rigid bodies. + + Returns: + torch.Tensor: The linear and angular velocities concatenated, with shape (N, 6). + """ + return torch.cat((self.lin_vel, self.ang_vel), dim=-1) + + +class RigidObject(BatchEntity): + """RigidObject represents a batch of rigid body in the simulation. + + There are three types of rigid body: + - Static: Actors that do not move and are used as the environment. + - Dynamic: Actors that can move and are affected by physics. + - Kinematic: Actors that can move but are not affected by physics. + + """ + + def __init__( + self, + cfg: RigidObjectCfg, + entities: List[MeshObject] = None, + device: torch.device = torch.device("cpu"), + ) -> None: + self.body_type = cfg.body_type + + self._world = dexsim.default_world() + self._ps = self._world.get_physics_scene() + + self._all_indices = torch.arange( + len(entities), dtype=torch.int32, device=device + ) + + # data for managing body data (only for dynamic and kinematic bodies) on GPU. + self._data: Optional[RigidBodyData] = None + if self.is_static is False: + self._data = RigidBodyData(entities=entities, ps=self._ps, device=device) + + # For rendering purposes, each instance can have its own material. + self._visual_material: List[VisualMaterialInst] = [None] * len(entities) + + for entity in entities: + entity.set_body_scale(*cfg.body_scale) + entity.set_physical_attr(cfg.attrs.attr()) + + if device.type == "cuda": + self._world.update(0.001) + + super().__init__(cfg, entities, device) + + # set default collision filter + self._set_default_collision_filter() + + def __str__(self) -> str: + parent_str = super().__str__() + return ( + parent_str + + f" | body type: {self.body_type} | max_convex_hull_num: {self.cfg.max_convex_hull_num}" + ) + + @property + def body_data(self) -> Optional[RigidBodyData]: + """Get the rigid body data manager for this rigid object. + + Returns: + RigidBodyData: The rigid body data manager. + """ + if self.is_static: + logger.log_warning("Static rigid object has no body data.") + return None + + return self._data + + @property + def body_state(self) -> torch.Tensor: + """Get the body state of the rigid object. + + The body state of a rigid object is represented as a tensor with the following format: + [x, y, z, qw, qx, qy, qz, lin_x, lin_y, lin_z, ang_x, ang_y, ang_z] + + If the rigid object is static, linear and angular velocities will be zero. + + Returns: + torch.Tensor: The body state of the rigid object with shape (N, 13), where N is the number of instances. + """ + if self.is_static: + # For static bodies, we return the state with zero velocities. + zero_velocity = torch.zeros((self.num_instances, 6), device=self.device) + return torch.cat((self.pose, zero_velocity), dim=-1) + + return torch.cat( + (self.body_data.pose, self.body_data.lin_vel, self.body_data.ang_vel), + dim=-1, + ) + + @property + def is_static(self) -> bool: + """Check if the rigid object is static. + + Returns: + bool: True if the rigid object is static, False otherwise. + """ + return self.body_type == "static" + + @property + def is_non_dynamic(self) -> bool: + """Check if the rigid object is non-dynamic (static or kinematic). + + Returns: + bool: True if the rigid object is non-dynamic, False otherwise. + """ + return self.body_type in ("static", "kinematic") + + def _set_default_collision_filter(self) -> None: + collision_filter_data = torch.zeros( + size=(self.num_instances, 4), dtype=torch.int32 + ) + for i in range(self.num_instances): + collision_filter_data[i, 0] = i + collision_filter_data[i, 1] = 1 + self.set_collision_filter(collision_filter_data) + + def set_collision_filter( + self, filter_data: torch.Tensor, env_ids: Optional[Sequence[int]] = None + ) -> None: + """set collision filter data for the rigid object. + + Args: + filter_data (torch.Tensor): [N, 4] of int. + First element of each object is arena id. + If 2nd element is 0, the object will collision with all other objects in world. + 3rd and 4th elements are not used currently. + + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. Defaults to None. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + if len(local_env_ids) != len(filter_data): + logger.log_error( + f"Length of env_ids {len(local_env_ids)} does not match pose length {len(filter_data)}." + ) + + filter_data_np = filter_data.cpu().numpy().astype(np.uint32) + for i, env_idx in enumerate(local_env_ids): + self._entities[env_idx].get_physical_body().set_collision_filter_data( + filter_data_np[i] + ) + + def set_local_pose( + self, pose: torch.Tensor, env_ids: Optional[Sequence[int]] = None + ) -> None: + """Set local pose of the rigid object. + + Args: + pose (torch.Tensor): The local pose of the rigid object with shape (N, 7) or (N, 4, 4). + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + if len(local_env_ids) != len(pose): + logger.log_error( + f"Length of env_ids {len(local_env_ids)} does not match pose length {len(pose)}." + ) + + if self.device.type == "cpu" or self.is_static: + pose = pose.cpu() + if pose.dim() == 2 and pose.shape[1] == 7: + pose_matrix = torch.eye(4).unsqueeze(0).repeat(pose.shape[0], 1, 1) + pose_matrix[:, :3, 3] = pose[:, :3] + pose_matrix[:, :3, :3] = matrix_from_quat(pose[:, 3:7]) + for i, env_idx in enumerate(local_env_ids): + self._entities[env_idx].set_local_pose(pose_matrix[i]) + elif pose.dim() == 3 and pose.shape[1:] == (4, 4): + for i, env_idx in enumerate(local_env_ids): + self._entities[env_idx].set_local_pose(pose[i]) + else: + logger.log_error( + f"Invalid pose shape {pose.shape}. Expected (N, 7) or (N, 4, 4)." + ) + + else: + if pose.dim() == 2 and pose.shape[1] == 7: + xyz = pose[:, :3] + quat = convert_quat(pose[:, 3:7], to="xyzw") + elif pose.dim() == 3 and pose.shape[1:] == (4, 4): + xyz = pose[:, :3, 3] + quat = quat_from_matrix(pose[:, :3, :3]) + quat = convert_quat(quat, to="xyzw") + else: + logger.log_error( + f"Invalid pose shape {pose.shape}. Expected (N, 7) or (N, 4, 4)." + ) + + # we should keep `pose_` life cycle to the end of the function. + pose = torch.cat((quat, xyz), dim=-1) + indices = self.body_data.gpu_indices[local_env_ids] + self._ps.gpu_apply_rigid_body_data( + data=pose.clone(), + gpu_indices=indices, + data_type=RigidBodyGPUAPIWriteType.POSE, + ) + if is_rt_enabled() is False: + self._world.sync_poses_gpu_to_cpu( + rigid_pose=CudaArray(pose), rigid_gpu_indices=CudaArray(indices) + ) + + def get_local_pose(self, to_matrix: bool = False) -> torch.Tensor: + """Get local pose of the rigid object. + + Args: + to_matrix (bool, optional): If True, return the pose as a 4x4 matrix. If False, return as (x, y, z, qw, qx, qy, qz). Defaults to False. + + Returns: + torch.Tensor: The local pose of the rigid object with shape (N, 7) or (N, 4, 4) depending on `to_matrix`. + """ + + def get_local_pose_cpu( + entities: List[MeshObject], to_matrix: bool + ) -> torch.Tensor: + """Helper function to get local pose on CPU.""" + if to_matrix: + pose = torch.as_tensor( + [entity.get_local_pose() for entity in entities], + ) + else: + xyzs = torch.as_tensor([entity.get_location() for entity in entities]) + quats = torch.as_tensor( + [entity.get_rotation_quat() for entity in entities] + ) + quats = convert_quat(quats, to="wxyz") + pose = torch.cat((xyzs, quats), dim=-1) + + return pose + + if self.is_static: + return get_local_pose_cpu(self._entities, to_matrix).to(self.device) + + pose = self.body_data.pose + if to_matrix: + xyz = pose[:, :3] + mat = matrix_from_quat(pose[:, 3:7]) + pose = ( + torch.eye(4, dtype=torch.float32, device=self.device) + .unsqueeze(0) + .repeat(pose.shape[0], 1, 1) + ) + pose[:, :3, 3] = xyz + pose[:, :3, :3] = mat + return pose + + def add_force_torque( + self, + force: Optional[torch.Tensor] = None, + torque: Optional[torch.Tensor] = None, + pos: Optional[torch.Tensor] = None, + env_ids: Optional[Sequence[int]] = None, + ) -> None: + """Add force and/or torque to the rigid object. + + TODO: Currently, apply force at position `pos` is not supported. + + Note: there are a few different ways to apply force and torque: + - If `pos` is specified, the force is applied at that position. + - if not `pos` is specified, the force and torque are applied at the center of mass of the rigid body. + + Args: + force (Optional[torch.Tensor] = None): The force to add with shape (N, 3). Defaults to None. + torque (Optional[torch.Tensor], optional): The torque to add with shape (N, 3). Defaults to None. + pos (Optional[torch.Tensor], optional): The position to apply the force at with shape (N, 3). Defaults to None. + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + """ + if force is None and torque is None: + logger.log_warning( + "Both force and torque are None. No force or torque will be applied." + ) + return + + if self.is_non_dynamic: + logger.log_warning( + "Cannot apply force or torque to non-dynamic rigid body." + ) + return + + local_env_ids = self._all_indices if env_ids is None else env_ids + + if force is not None and len(local_env_ids) != len(force): + logger.log_error( + f"Length of env_ids {len(local_env_ids)} does not match force length {len(force)}." + ) + + if torque is not None and len(local_env_ids) != len(torque): + logger.log_error( + f"Length of env_ids {len(local_env_ids)} does not match torque length {len(torque)}." + ) + + if self.device.type == "cpu": + for i, env_idx in enumerate(local_env_ids): + if force is not None: + self._entities[env_idx].add_force(force[i].cpu().numpy()) + if torque is not None: + self._entities[env_idx].add_torque(torque[i].cpu().numpy()) + + else: + indices = self.body_data.gpu_indices[local_env_ids] + if force is not None: + self._ps.gpu_apply_rigid_body_data( + data=force, + gpu_indices=indices, + data_type=RigidBodyGPUAPIWriteType.FORCE, + ) + if torque is not None: + self._ps.gpu_apply_rigid_body_data( + data=torque, + gpu_indices=indices, + data_type=RigidBodyGPUAPIWriteType.TORQUE, + ) + + def set_attrs( + self, + attrs: Union[RigidBodyAttributesCfg, List[RigidBodyAttributesCfg]], + env_ids: Optional[Sequence[int]] = None, + ) -> None: + """Set physical attributes for the rigid object. + + Args: + attrs (Union[RigidBodyAttributesCfg, List[RigidBodyAttributesCfg]]): The physical attributes to set. + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + if isinstance(attrs, List) and len(local_env_ids) != len(attrs): + logger.log_error( + f"Length of env_ids {len(local_env_ids)} does not match attrs length {len(attrs)}." + ) + + # TODO: maybe need to improve the physical attributes setter efficiency. + if isinstance(attrs, RigidBodyAttributesCfg): + for i, env_idx in enumerate(local_env_ids): + self._entities[env_idx].set_physical_attr(attrs.attr()) + else: + for i, env_idx in enumerate(local_env_ids): + self._entities[env_idx].set_physical_attr(attrs[i].attr()) + + def set_visual_material( + self, mat: VisualMaterial, env_ids: Optional[Sequence[int]] = None + ) -> None: + """Set visual material for the rigid object. + + Args: + mat (VisualMaterial): The material to set. + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + for i, env_idx in enumerate(local_env_ids): + mat_inst = mat.create_instance(f"{mat.uid}_{self.uid}_{env_idx}") + self._entities[env_idx].set_material(mat_inst.mat) + self._visual_material[env_idx] = mat_inst + + def get_visual_material_inst( + self, env_ids: Optional[Sequence[int]] = None + ) -> List[VisualMaterialInst]: + """Get material instances for the rigid object. + + Args: + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + + Returns: + List[MaterialInst]: List of material instances. + """ + ids = env_ids if env_ids is not None else range(self.num_instances) + return [self._visual_material[i] for i in ids] + + def get_body_scale(self, env_ids: Optional[Sequence[int]] = None) -> torch.Tensor: + """ + Retrieve the body scale for specified environment instances. + + Args: + env_ids (Optional[Sequence[int]]): A sequence of environment instance IDs. + If None, retrieves the body scale for all instances. + + Returns: + torch.Tensor: A tensor containing the body scales of the specified instances, + with shape (N, 3) dtype int32 and located on the specified device. + """ + ids = env_ids if env_ids is not None else range(self.num_instances) + return torch.as_tensor( + [self._entities[id].get_body_scale() for id in ids], + dtype=torch.float32, + device=self.device, + ) + + def set_body_scale( + self, scale: torch.Tensor, env_ids: Optional[Sequence[int]] = None + ) -> None: + """Set the scale of the rigid body. + + Args: + scale (torch.Tensor): The scale to set with shape (N, 3). + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + if len(local_env_ids) != len(scale): + logger.log_error( + f"Length of env_ids {len(local_env_ids)} does not match scale length {len(scale)}." + ) + + if self.device.type == "cpu": + for i, env_idx in enumerate(local_env_ids): + scale = scale[i].cpu().numpy() + self._entities[env_idx].set_body_scale(*scale) + else: + logger.log_error(f"Setting body scale on GPU is not supported yet.") + + def get_vertices(self, env_ids: Optional[Sequence[int]] = None) -> torch.Tensor: + """ + Retrieve the vertices of the rigid objects. + + Args: + env_ids (Optional[Sequence[int]]): A sequence of environment IDs for which to retrieve vertices. + If None, retrieves vertices for all instances. + + Returns: + torch.Tensor: A tensor containing the user IDs of the specified rigid objects with shape (N, num_verts, 3). + """ + ids = env_ids if env_ids is not None else range(self.num_instances) + return torch.as_tensor( + np.array( + [self._entities[id].get_vertices() for id in ids], + ), + dtype=torch.float32, + device=self.device, + ) + + def get_user_ids(self) -> torch.Tensor: + """Get the user ids of the rigid bodies. + + Returns: + torch.Tensor: A tensor of shape (num_envs,) representing the user ids of the rigid bodies. + """ + return torch.as_tensor( + [entity.get_user_id() for entity in self._entities], + dtype=torch.int32, + device=self.device, + ) + + def clear_dynamics(self, env_ids: Optional[Sequence[int]] = None) -> None: + """Clear the dynamics of the rigid bodies by resetting velocities and applying zero forces and torques. + + Args: + env_ids (Optional[Sequence[int]]): Environment indices. If None, then all indices are used. + """ + if self.is_non_dynamic: + return + + local_env_ids = self._all_indices if env_ids is None else env_ids + + if self.device.type == "cpu": + for env_idx in local_env_ids: + self._entities[env_idx].clear_dynamics() + else: + # Apply zero force and torque to the rigid bodies. + zeros = torch.zeros( + (len(local_env_ids), 3), dtype=torch.float32, device=self.device + ) + indices = self.body_data.gpu_indices[local_env_ids] + self._ps.gpu_apply_rigid_body_data( + data=zeros, + gpu_indices=indices, + data_type=RigidBodyGPUAPIWriteType.LINEAR_VELOCITY, + ) + self._ps.gpu_apply_rigid_body_data( + data=zeros, + gpu_indices=indices, + data_type=RigidBodyGPUAPIWriteType.ANGULAR_VELOCITY, + ) + self._ps.gpu_apply_rigid_body_data( + data=zeros, + gpu_indices=indices, + data_type=RigidBodyGPUAPIWriteType.FORCE, + ) + self._ps.gpu_apply_rigid_body_data( + data=zeros, + gpu_indices=indices, + data_type=RigidBodyGPUAPIWriteType.TORQUE, + ) + + def reset(self, env_ids: Optional[Sequence[int]] = None) -> None: + local_env_ids = self._all_indices if env_ids is None else env_ids + num_instances = len(local_env_ids) + self.set_attrs(self.cfg.attrs, env_ids=local_env_ids) + + pos = torch.as_tensor( + self.cfg.init_pos, dtype=torch.float32, device=self.device + ) + rot = ( + torch.as_tensor(self.cfg.init_rot, dtype=torch.float32, device=self.device) + * torch.pi + / 180.0 + ) + pos = pos.unsqueeze(0).repeat(num_instances, 1) + rot = rot.unsqueeze(0).repeat(num_instances, 1) + mat = matrix_from_euler(rot, "XYZ") + pose = ( + torch.eye(4, dtype=torch.float32, device=self.device) + .unsqueeze(0) + .repeat(num_instances, 1, 1) + ) + pose[:, :3, 3] = pos + pose[:, :3, :3] = mat + self.set_local_pose(pose, env_ids=local_env_ids) + + self.clear_dynamics(env_ids=local_env_ids) + + def destroy(self) -> None: + env = self._world.get_env() + arenas = env.get_all_arenas() + if len(arenas) == 0: + arenas = [env] + for i, entity in enumerate(self._entities): + arenas[i].remove_actor(entity) diff --git a/embodichain/lab/sim/objects/rigid_object_group.py b/embodichain/lab/sim/objects/rigid_object_group.py new file mode 100644 index 00000000..2db3053f --- /dev/null +++ b/embodichain/lab/sim/objects/rigid_object_group.py @@ -0,0 +1,513 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import dexsim +import numpy as np + +from dataclasses import dataclass +from typing import List, Sequence, Optional, Union + +from dexsim.models import MeshObject +from dexsim.types import RigidBodyGPUAPIReadType, RigidBodyGPUAPIWriteType +from dexsim.engine import CudaArray, PhysicsScene +from embodichain.lab.sim.cfg import ( + RigidObjectGroupCfg, + RigidBodyAttributesCfg, +) +from embodichain.lab.sim import ( + BatchEntity, +) +from embodichain.lab.sim.material import VisualMaterial, VisualMaterialInst +from embodichain.utils.math import convert_quat +from embodichain.utils.math import matrix_from_quat, quat_from_matrix, matrix_from_euler +from embodichain.utils import logger + + +@dataclass +class RigidBodyGroupData: + """Data manager for rigid body group with body type of dynamic or kinematic.""" + + def __init__( + self, entities: List[List[MeshObject]], ps: PhysicsScene, device: torch.device + ) -> None: + """Initialize the RigidBodyGroupData. + + Args: + entities (List[List[MeshObject]]): List of List MeshObjects representing the rigid body group. + ps (PhysicsScene): The physics scene. + device (torch.device): The device to use for the rigid body group data. + """ + self.entities = entities + self.ps = ps + self.num_instances = len(entities) + self.num_objects = len(entities[0]) + self.device = device + + # get gpu indices for the rigid bodies with shape of (num_instances, num_objects) + self.gpu_indices = torch.as_tensor( + [[entity.get_gpu_index() for entity in instance] for instance in entities], + dtype=torch.int32, + device=self.device, + ) + + # Initialize rigid body group data tensors. Shape of (num_instances, num_objects, data_dim) + self._pose = torch.zeros( + (self.num_instances, self.num_objects, 7), + dtype=torch.float32, + device=self.device, + ) + self._lin_vel = torch.zeros( + (self.num_instances, self.num_objects, 3), + dtype=torch.float32, + device=self.device, + ) + self._ang_vel = torch.zeros( + (self.num_instances, self.num_objects, 3), + dtype=torch.float32, + device=self.device, + ) + + @property + def pose(self) -> torch.Tensor: + if self.device.type == "cpu": + # Fetch pose from CPU entities + xyzs = torch.as_tensor( + [ + [entity.get_location() for entity in instance] + for instance in self.entities + ], + device=self.device, + ) + quats = torch.as_tensor( + [ + [entity.get_rotation_quat() for entity in instance] + for instance in self.entities + ], + device=self.device, + ) + quats = convert_quat(quats.reshape(-1, 4), to="wxyz").reshape( + -1, self.num_objects, 4 + ) + return torch.cat((xyzs, quats), dim=-1) + else: + pose = self._pose.reshape(-1, 7) + self.ps.gpu_fetch_rigid_body_data( + data=pose, + gpu_indices=self.gpu_indices.flatten(), + data_type=RigidBodyGPUAPIReadType.POSE, + ) + pose = convert_quat(pose[:, :4], to="wxyz") + pose = pose[:, [4, 5, 6, 0, 1, 2, 3]] + return self._pose + + @property + def lin_vel(self) -> torch.Tensor: + if self.device.type == "cpu": + # Fetch linear velocity from CPU entities + self._lin_vel = torch.as_tensor( + [ + [entity.get_linear_velocity() for entity in instance] + for instance in self.entities + ], + dtype=torch.float32, + device=self.device, + ) + else: + lin_vel = self._lin_vel.reshape(-1, 3) + self.ps.gpu_fetch_rigid_body_data( + data=lin_vel, + gpu_indices=self.gpu_indices.flatten(), + data_type=RigidBodyGPUAPIReadType.LINEAR_VELOCITY, + ) + return self._lin_vel + + @property + def ang_vel(self) -> torch.Tensor: + if self.device.type == "cpu": + # Fetch angular velocity from CPU entities + self._ang_vel = torch.as_tensor( + [ + [entity.get_linear_velocity() for entity in instance] + for instance in self.entities + ], + dtype=torch.float32, + device=self.device, + ) + else: + ang_vel = self._ang_vel.reshape(-1, 3) + self.ps.gpu_fetch_rigid_body_data( + data=ang_vel, + gpu_indices=self.gpu_indices.flatten(), + data_type=RigidBodyGPUAPIReadType.ANGULAR_VELOCITY, + ) + return self._ang_vel + + @property + def vel(self) -> torch.Tensor: + """Get the linear and angular velocities of the rigid bodies. + + Returns: + torch.Tensor: The linear and angular velocities concatenated, with shape (num_instances, num_objects, 6). + """ + return torch.cat((self.lin_vel, self.ang_vel), dim=-1) + + +class RigidObjectGroup(BatchEntity): + """RigidObjectGroup represents a batch of rigid bodies in the simulation.""" + + def __init__( + self, + cfg: RigidObjectGroupCfg, + entities: List[List[MeshObject]] = None, + device: torch.device = torch.device("cpu"), + ) -> None: + self.body_type = cfg.body_type + + self._world = dexsim.default_world() + self._ps = self._world.get_physics_scene() + + self._all_indices = torch.arange( + len(entities), dtype=torch.int32, device=device + ) + self._all_obj_indices = torch.arange( + len(entities[0]), dtype=torch.int32, device=device + ) + + # data for managing body data (only for dynamic and kinematic bodies) on GPU. + self._data = RigidBodyGroupData(entities=entities, ps=self._ps, device=device) + + body_cfgs = list(cfg.rigid_objects.values()) + for instance in entities: + for i, body in enumerate(instance): + body.set_body_scale(*body_cfgs[i].body_scale) + body.set_physical_attr(body_cfgs[i].attrs.attr()) + + if device.type == "cuda": + self._world.update(0.001) + + super().__init__(cfg, entities, device) + + # set default collision filter + self._set_default_collision_filter() + + def __str__(self) -> str: + parent_str = super().__str__() + return ( + parent_str + + f" | body type: {self.body_type} | num_objects: {self.num_objects}" + ) + + @property + def num_objects(self) -> int: + """Get the number of objects in each rigid body instance. + + Returns: + int: The number of objects in each rigid body instance. + """ + return self._data.num_objects + + @property + def body_data(self) -> RigidBodyGroupData: + """Get the rigid body data manager for this rigid object. + + Returns: + RigidBodyGroupData: The rigid body data manager. + """ + return self._data + + @property + def body_state(self) -> torch.Tensor: + """Get the body state of the rigid object. + + The body state of a rigid object is represented as a tensor with the following format: + [x, y, z, qw, qx, qy, qz, lin_x, lin_y, lin_z, ang_x, ang_y, ang_z] + + If the rigid object is static, linear and angular velocities will be zero. + + Returns: + torch.Tensor: The body state of the rigid object with shape (num_instances, num_objects, 13), + where N is the number of instances. + """ + return torch.cat( + (self.body_data.pose, self.body_data.lin_vel, self.body_data.ang_vel), + dim=-1, + ) + + @property + def is_non_dynamic(self) -> bool: + """Check if the rigid object is non-dynamic (static or kinematic). + + Returns: + bool: True if the rigid object is non-dynamic, False otherwise. + """ + return self.body_type in ("static", "kinematic") + + def _set_default_collision_filter(self) -> None: + collision_filter_data = torch.zeros( + size=(self.num_instances, 4), dtype=torch.int32 + ) + for i in range(self.num_instances): + collision_filter_data[i, 0] = i + collision_filter_data[i, 1] = 1 + self.set_collision_filter(collision_filter_data) + + def set_collision_filter( + self, filter_data: torch.Tensor, env_ids: Optional[Sequence[int]] = None + ) -> None: + """set collision filter data for the rigid object group. + + Args: + filter_data (torch.Tensor): [N, 4] of int. + First element of each object is arena id. + If 2nd element is 0, the object will collision with all other objects in world. + 3rd and 4th elements are not used currently. + + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. Defaults to None. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + if len(local_env_ids) != len(filter_data): + logger.log_error( + f"Length of env_ids {len(local_env_ids)} does not match pose length {len(filter_data)}." + ) + + filter_data_np = filter_data.cpu().numpy().astype(np.uint32) + for i, env_idx in enumerate(local_env_ids): + for entity in self._entities[env_idx]: + entity.get_physical_body().set_collision_filter_data(filter_data_np[i]) + + def set_local_pose( + self, + pose: torch.Tensor, + env_ids: Optional[Sequence[int]] = None, + obj_ids: Optional[Sequence[int]] = None, + ) -> None: + """Set local pose of the rigid object group. + + Args: + pose (torch.Tensor): The local pose of the rigid object group with shape (num_instances, num_objects, 7) or + (num_instances, num_objects, 4, 4). + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + obj_ids (Optional[Sequence[int]], optional): Object indices within the group. If None, all objects are set. Defaults to None. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + local_obj_ids = self._all_obj_indices if obj_ids is None else obj_ids + + if len(local_env_ids) != len(pose): + logger.log_error( + f"Length of env_ids {len(local_env_ids)} does not match pose length {len(pose)}." + ) + + if self.device.type == "cpu": + pose = pose.cpu() + if pose.dim() == 3 and pose.shape[2] == 7: + reshape_pose = pose.reshape(-1, 7) + pose_matrix = ( + torch.eye(4).unsqueeze(0).repeat(reshape_pose.shape[0], 1, 1) + ) + pose_matrix[:, :3, 3] = reshape_pose[:, :3] + pose_matrix[:, :3, :3] = matrix_from_quat(reshape_pose[:, 3:7]) + pose = pose_matrix.reshape(-1, len(local_obj_ids), 4, 4) + elif pose.dim() == 4 and pose.shape[2:] == (4, 4): + pass + else: + logger.log_error( + f"Invalid pose shape {pose.shape}. Expected (num_instances, num_objects, 7) or (num_instances, num_objects, 4, 4)." + ) + + for i, env_idx in enumerate(local_env_ids): + for j, obj_idx in enumerate(local_obj_ids): + self._entities[env_idx][obj_idx].set_local_pose(pose[i, j]) + + else: + if pose.dim() == 3 and pose.shape[2] == 7: + xyz = pose[..., :3].reshape(-1, 3) + quat = pose[..., 3:7].reshape(-1, 4) + quat = convert_quat(quat, to="xyzw") + elif pose.dim() == 4 and pose.shape[2:] == (4, 4): + xyz = pose[..., :3, 3].reshape(-1, 3) + mat = pose[..., :3, :3].reshape(-1, 3, 3) + quat = quat_from_matrix(mat) + quat = convert_quat(quat, to="xyzw") + else: + logger.log_error( + f"Invalid pose shape {pose.shape}. Expected (N, 7) or (N, 4, 4)." + ) + + # we should keep `pose_` life cycle to the end of the function. + pose = torch.cat((quat, xyz), dim=-1) + indices = self.body_data.gpu_indices[local_env_ids][ + :, local_obj_ids + ].flatten() + self._ps.gpu_apply_rigid_body_data( + data=pose.clone(), + gpu_indices=indices, + data_type=RigidBodyGPUAPIWriteType.POSE, + ) + self._world.sync_poses_gpu_to_cpu( + rigid_pose=CudaArray(pose), rigid_gpu_indices=CudaArray(indices) + ) + + def get_local_pose(self, to_matrix: bool = False) -> torch.Tensor: + """Get local pose of the rigid object group. + + Args: + to_matrix (bool, optional): If True, return the pose as a 4x4 matrix. If False, return as (x, y, z, qw, qx, qy, qz). Defaults to False. + + Returns: + torch.Tensor: The local pose of the rigid object with shape (num_instances, num_objects, 7) or (num_instances, num_objects, 4, 4) depending on `to_matrix`. + """ + pose = self.body_data.pose + if to_matrix: + pose = pose.reshape(-1, 7) + xyz = pose[:, :3] + mat = matrix_from_quat(pose[:, 3:7]) + pose = ( + torch.eye(4, dtype=torch.float32, device=self.device) + .unsqueeze(0) + .repeat(self.num_instances * self.num_objects, 1, 1) + ) + pose[:, :3, 3] = xyz + pose[:, :3, :3] = mat + pose = pose.reshape(self.num_instances, self.num_objects, 4, 4) + return pose + + def get_user_ids(self) -> torch.Tensor: + """Get the user ids of the rigid body group. + + Returns: + torch.Tensor: A tensor of shape (num_envs, num_objects) representing the user ids of the rigid body group. + """ + return torch.as_tensor( + [ + [entity.get_user_id() for entity in instance] + for instance in self._entities + ], + dtype=torch.int32, + device=self.device, + ) + + def clear_dynamics(self, env_ids: Optional[Sequence[int]] = None) -> None: + """Clear the dynamics of the rigid bodies by resetting velocities and applying zero forces and torques. + + Args: + env_ids (Optional[Sequence[int]]): Environment indices. If None, then all indices are used. + """ + if self.is_non_dynamic: + return + + local_env_ids = self._all_indices if env_ids is None else env_ids + + if self.device.type == "cpu": + for env_idx in local_env_ids: + for entity in self._entities[env_idx]: + entity.clear_dynamics() + else: + # Apply zero force and torque to the rigid bodies. + zeros = torch.zeros( + (len(local_env_ids) * self.num_objects, 3), + dtype=torch.float32, + device=self.device, + ) + indices = self.body_data.gpu_indices[local_env_ids].flatten() + self._ps.gpu_apply_rigid_body_data( + data=zeros, + gpu_indices=indices, + data_type=RigidBodyGPUAPIWriteType.LINEAR_VELOCITY, + ) + self._ps.gpu_apply_rigid_body_data( + data=zeros, + gpu_indices=indices, + data_type=RigidBodyGPUAPIWriteType.ANGULAR_VELOCITY, + ) + self._ps.gpu_apply_rigid_body_data( + data=zeros, + gpu_indices=indices, + data_type=RigidBodyGPUAPIWriteType.FORCE, + ) + self._ps.gpu_apply_rigid_body_data( + data=zeros, + gpu_indices=indices, + data_type=RigidBodyGPUAPIWriteType.TORQUE, + ) + + def set_visual_material( + self, mat: VisualMaterial, env_ids: Optional[Sequence[int]] = None + ) -> None: + """Set visual material for the rigid object group. + + Args: + mat (VisualMaterial): The material to set. + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + for i, env_idx in enumerate(local_env_ids): + for j, entity in enumerate(self._entities[env_idx]): + mat_inst = mat.create_instance(f"{mat.uid}_{self.uid}_{env_idx}_{j}") + entity.set_material(mat_inst.mat) + + # Note: The rigid object group is not supported to change the visual material once created. + # If needed, we should create a visual material dict to store the material instances, and + # implement a get_visual_material method to retrieve the material instances. + + def reset(self, env_ids: Optional[Sequence[int]] = None) -> None: + local_env_ids = self._all_indices if env_ids is None else env_ids + num_instances = len(local_env_ids) + + self.cfg: RigidObjectGroupCfg + body_cfgs = list(self.cfg.rigid_objects.values()) + + init_pos = [] + init_rot = [] + for cfg in body_cfgs: + init_pos.append(cfg.init_pos) + init_rot.append(cfg.init_rot) + + # (num_objects, 3) + pos = torch.as_tensor(init_pos, dtype=torch.float32, device=self.device) + rot = ( + torch.as_tensor(init_rot, dtype=torch.float32, device=self.device) + * torch.pi + / 180.0 + ) + # Convert pos and rot to shape (num_instances, num_objects, dim) + pos = pos.unsqueeze_(0).repeat(num_instances, 1, 1) + rot = rot.unsqueeze_(0).repeat(num_instances, 1, 1) + + mat = matrix_from_euler(rot.reshape(-1, 3), "XYZ") + # Init pose with shape (num_instances, num_objects, 4, 4) + pose = ( + torch.eye(4, dtype=torch.float32, device=self.device) + .unsqueeze_(0) + .repeat(num_instances * self.num_objects, 1, 1) + ) + pose[:, :3, 3] = pos.reshape(-1, 3) + pose[:, :3, :3] = mat + pose = pose.reshape(num_instances, self.num_objects, 4, 4) + self.set_local_pose(pose, env_ids=local_env_ids) + + self.clear_dynamics(env_ids=local_env_ids) + + def destroy(self) -> None: + env = self._world.get_env() + arenas = env.get_all_arenas() + if len(arenas) == 0: + arenas = [env] + for i, instance in enumerate(self._entities): + for entity in instance: + arenas[i].remove_actor(entity) diff --git a/embodichain/lab/sim/objects/robot.py b/embodichain/lab/sim/objects/robot.py new file mode 100644 index 00000000..d15f50fb --- /dev/null +++ b/embodichain/lab/sim/objects/robot.py @@ -0,0 +1,653 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + +from typing import List, Dict, Optional, Tuple, Union, Sequence +from dataclasses import dataclass, field + +from dexsim.engine import Articulation as _Articulation +from embodichain.lab.sim.cfg import RobotCfg +from embodichain.lab.sim.solvers import SolverCfg, BaseSolver +from embodichain.lab.sim.objects import Articulation +from embodichain.lab.sim.utility.tensor import to_tensor +from embodichain.utils.math import quat_from_matrix +from embodichain.utils.string import ( + is_regular_expression, + resolve_matching_names_values, +) +from embodichain.utils import logger + + +@dataclass +class ControlGroup: + r"""Represents a group of controllable joints in a robot. + + Attributes: + joint_names (List[str]): Names of the joints in this control group. + joint_ids (List[int]): IDs corresponding to the joints in this control group. + link_names (List[str]): Names of child links associated with the joints. + """ + + joint_names: List[str] = field(default_factory=list) + joint_ids: List[int] = field(default_factory=list) + link_names: List[str] = field(default_factory=list) + + def __post_init__(self): + pass + + +class Robot(Articulation): + """A class representing a batch of robots in the simulation environment. + + Robot is a specific type of articulation that can have additional properties or methods. + - `control_parts`: Specify the parts that can be controlled in a different manner. Different part may have + different joint ids, drive properties, pyhsical attributes, kinematic solvers or motion planners. + - `solvers`: Specify the kinematic solvers for the robot. + - `planners`: Specify the motion planner for the robot. + """ + + def __init__( + self, + cfg: RobotCfg, + entities: List[_Articulation], + device: torch.device = torch.device("cpu"), + ) -> None: + super().__init__(cfg, entities, device) + + self._solvers = {} + + # Initialize joint ids for control parts. + self._joint_ids: Dict[str, List[int]] = {} + + self._control_groups: Dict[str, ControlGroup] = {} + + if self.cfg.control_parts: + self._init_control_parts(self.cfg.control_parts) + + if self.cfg.solver_cfg: + self.init_solver(self.cfg.solver_cfg) + + def __str__(self) -> str: + parent_str = super().__str__() + return ( + parent_str + + f" | control_parts: {self.control_parts}, solvers: {self._solvers}" + ) + + @property + def control_parts(self) -> Union[Dict[str, List[str]], None]: + """Get the control parts of the robot.""" + return self.cfg.control_parts + + def get_joint_ids( + self, name: Optional[str] = None, remove_mimic: bool = False + ) -> List[int]: + """Get the joint ids of the robot for a specific control part. + + Args: + name (str, optional): The name of the control part to get the joint ids for. If None, the default part is used. + remove_mimic (bool, optional): If True, mimic joints will be excluded from the returned joint ids. Defaults to False. + + Returns: + List[int]: The joint ids of the robot for the specified control part. + """ + if not self.control_parts or name is None: + return ( + torch.arange(self.dof, dtype=torch.int32).tolist() + if not remove_mimic + else [i for i in range(self.dof) if i not in self.mimic_ids] + ) + + if name not in self.control_parts: + logger.log_error( + f"The control part '{name}' does not exist in the robot's control parts." + ) + return ( + self._joint_ids[name] + if not remove_mimic + else [i for i in self._joint_ids[name] if i not in self.mimic_ids] + ) + + def get_proprioception(self) -> Dict[str, torch.Tensor]: + """Gets robot proprioception information, primarily for agent state representation in robot learning scenarios. + + The default proprioception information includes: + - qpos: Joint positions. + - qvel: Joint velocities. + - qf: Joint efforts. + + Returns: + Dict[str, torch.Tensor]: A dictionary containing the robot's proprioception information + """ + + return dict( + qpos=self.body_data.qpos, qvel=self.body_data.qvel, qf=self.body_data.qf + ) + + def compute_fk( + self, + qpos: Optional[Union[torch.tensor, np.ndarray]], + name: Optional[str] = None, + link_names: Optional[List[str]] = None, + end_link_name: Optional[str] = None, + root_link_name: Optional[str] = None, + env_ids: Optional[Sequence[int]] = None, + to_matrix: bool = False, + ) -> torch.Tensor: + """Compute the forward kinematics of the robot given joint positions and optionally a specific part name. + The output pose will be in the local arena frame. + + Args: + qpos (Optional[Union[torch.tensor, np.ndarray]]): Joint positions of the robot, (n_envs, num_joints). + name (str, optional): The name of the control part to compute the FK for. If None, the default part is used. + link_names (List[str], optional): The names of the links to compute the FK for. If None, all links are used. + end_link_name (str, optional): The name of the end link to compute the FK for. If None, the default end link is used. + root_link_name (str, optional): The name of the root link to compute the FK for. If None, the default root link is used. + env_ids (Sequence[int], optional): The environment ids to compute the FK for. If None, all environments are used. + to_matrix (bool, optional): If True, returns the transformation in the form of a 4x4 matrix. + + Returns: + torch.Tensor: The forward kinematics result with shape (n_envs, 7) or (n_envs, 4, 4) if `to_matrix` is True. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + if name is None and hasattr(super(), "compute_fk"): + return super().compute_fk( + qpos=qpos, + link_names=link_names, + end_link_name=end_link_name, + root_link_name=root_link_name, + ) + + if not self._solvers: + logger.log_error( + "No solvers are defined for the robot. Please ensure that the robot has solvers configured." + ) + + solver = self._solvers.get(name if name is not None else "default", None) + if solver is None: + logger.log_error( + f"The control part '{name}' does not have an associated solver. Please ensure that a valid control part with an available solver is provided." + ) + return None + + if qpos.dim() == 1: + qpos = qpos.unsqueeze(0) + + if qpos.shape[0] != len(local_env_ids): + logger.log_error( + f"Joint positions batch size mismatch. Expected {len(local_env_ids)} but got {qpos.shape[0]}." + ) + + if qpos.shape[1] != solver.dof: + logger.log_error( + f"Joint positions shape mismatch. Expected {solver.dof} joints, got {qpos.shape[1]}." + ) + + result_matrix = solver.get_fk(qpos=qpos) + + base_pose = self.get_link_pose( + link_name=solver.root_link_name, env_ids=local_env_ids, to_matrix=True + ) + result_matrix = torch.bmm(base_pose, result_matrix) + + if to_matrix: + return result_matrix + else: + pos = result_matrix[:, :3, 3] + quat = quat_from_matrix(result_matrix[:, :3, :3]) + return torch.cat((pos, quat), dim=-1) + + def compute_ik( + self, + pose: Union[torch.Tensor, np.ndarray], + joint_seed: Optional[Union[torch.Tensor, np.ndarray]] = None, + name: Optional[str] = None, + env_ids: Optional[Sequence[int]] = None, + return_all_solutions: bool = False, + ) -> Optional[Tuple[torch.Tensor, torch.Tensor]]: + """Compute the inverse kinematics of the robot given joint positions and optionally a specific part name. + The input pose should be in the local arena frame. + + Args: + pose (torch.Tensor): The end effector pose of the robot, (n_envs, 7) or (n_envs, 4, 4). + joint_seed (torch.Tensor, optional): The joint positions to use as a seed for the IK computation, (n_envs, dof). + If None, the zero joint positions will be used as the seed. + name (str, optional): The name of the control part to compute the IK for. If None, the default part is used. + env_ids (Optional[Sequence[int]]): Environment indices to apply the positions. Defaults to all environments. + return_all_solutions (bool, optional): Whether to return all IK solutions or just the best one. Defaults to False. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: The success Tensor with shape (n_envs, ) and qpos Tensor with shape (n_envs, max_results, dof). + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + solver = self._solvers.get(name if name is not None else "default", None) + if solver is None: + logger.log_error( + f"The control part '{name}' does not have an associated solver. Please ensure that a valid control part with an available solver is provided." + ) + return None + + pose = to_tensor(pose, device=self.device) + if (pose.dim() == 1 and pose.shape[1] == 7) or ( + pose.dim() == 2 and pose.shape[1] == 4 + ): + pose = pose.unsqueeze(0) + + if pose.shape[0] != len(local_env_ids): + logger.log_error( + f"Pose batch size mismatch. Expected {len(local_env_ids)} but got {pose.shape[0]}." + ) + + if joint_seed is not None: + joint_seed = to_tensor(joint_seed, device=self.device) + if joint_seed.dim() == 1: + joint_seed = joint_seed.unsqueeze(0) + + if joint_seed.shape[0] != len(local_env_ids): + logger.log_error( + f"Joint seed batch size mismatch. Expected {len(local_env_ids)} but got {joint_seed.shape[0]}." + ) + + if pose.shape[-1] == 7 and pose.dim() == 2: + # Convert pose from (batch, 7) to (batch, 4, 4) + pose = torch.cat( + ( + pose[:, :3].unsqueeze(-1), # Position + quat_from_matrix(pose[:, 3:]).unsqueeze(-1), # Quaternion + ), + dim=-1, + ) + pose = torch.cat( + ( + pose, + torch.tensor([[0, 0, 0, 1]], device=pose.device).expand( + pose.shape[0], -1, -1 + ), + ), + dim=1, + ) + + base_pose = self.get_link_pose( + link_name=solver.root_link_name, env_ids=local_env_ids, to_matrix=True + ) + pose = torch.bmm(torch.inverse(base_pose), pose) + + ret, qpos = solver.get_ik( + target_xpos=pose, + qpos_seed=joint_seed, + return_all_solutions=return_all_solutions, + ) + dof = qpos.shape[-1] + if not return_all_solutions: + qpos = qpos.reshape(-1, dof) + + return ret.to(self.device), qpos.to(self.device) + + def compute_batch_fk( + self, + qpos: torch.tensor, + name: str, + env_ids: Optional[Sequence[int]] = None, + to_matrix: bool = False, + ): + """Compute the forward kinematics of the robot given joint positions and optionally a specific part name. + The output pose will be in the local arena frame. + + Args: + qpos (Optional[Union[torch.tensor, np.ndarray]]): Joint positions of the robot, (n_envs, n_batch, num_joints). + name (str, optional): The name of the control part to compute the FK for. If None, the default part is used. + env_ids (Sequence[int], optional): The environment ids to compute the FK for. If None, all environments are used. + to_matrix (bool, optional): If True, returns the transformation in the form of a 4x4 matrix. + + Returns: + torch.Tensor: The forward kinematics result with shape (n_envs, batch, 7) or (n_envs, batch, 4, 4) if `to_matrix` is True. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + if not self._solvers: + logger.log_error( + "No solvers are defined for the robot. Please ensure that the robot has solvers configured." + ) + + solver = self._solvers.get(name if name is not None else "default", None) + if solver is None: + logger.log_error( + f"The control part '{name}' does not have an associated solver. Please ensure that a valid control part with an available solver is provided." + ) + return None + + if qpos.shape[0] != len(local_env_ids): + logger.log_error( + f"Joint positions batch size mismatch. Expected {len(local_env_ids)} but got {qpos.shape[0]}." + ) + + if qpos.shape[2] != solver.dof: + logger.log_error( + f"Joint positions shape mismatch. Expected {solver.dof} joints, got {qpos.shape[1]}." + ) + + n_batch = qpos.shape[1] + qpos_batch = qpos.reshape(-1, solver.dof) + xpos_batch = solver.get_fk(qpos=qpos_batch) + + # get xpos from link root + base_xpos_n_envs = self.get_link_pose( + link_name=solver.root_link_name, env_ids=local_env_ids, to_matrix=True + ) + base_xpos_batch = ( + base_xpos_n_envs[:, None, :, :].repeat(1, n_batch, 1, 1).reshape(-1, 4, 4) + ) + result_matrix = torch.bmm(base_xpos_batch, xpos_batch) + + if to_matrix: + result_matrix = result_matrix.reshape(len(local_env_ids), n_batch, 4, 4) + return result_matrix + else: + pos = result_matrix[:, :3, 3] + quat = quat_from_matrix(result_matrix[:, :3, :3]) + result = torch.cat((pos, quat), dim=-1) + result = result.reshape(len(local_env_ids), n_batch, 7) + return result + + def compute_batch_ik( + self, + pose: Union[torch.Tensor, np.ndarray], + joint_seed: Optional[Union[torch.Tensor, np.ndarray]], + name: str, + env_ids: Optional[Sequence[int]] = None, + ): + """Compute the inverse kinematics of the robot given joint positions and optionally a specific part name. + The input pose should be in the local arena frame. + + Args: + pose (torch.Tensor): The end effector pose of the robot, (n_envs, n_batch, 7) or (n_envs, n_batch, 4, 4). + joint_seed (torch.Tensor, optional): The joint positions to use as a seed for the IK computation, (n_envs, n_batch, dof). If None, the zero joint positions will be used as the seed. + name (str): The name of the control part to compute the IK for. If None, the default part is used. + env_ids (Optional[Sequence[int]]): Environment indices to apply the positions. Defaults to all environments. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: + Success Tensor with shape (n_envs, n_batch) + Qpos Tensor with shape (n_envs, n_batch, dof). + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + solver = self._solvers.get(name if name is not None else "default", None) + if solver is None: + logger.log_error( + f"The control part '{name}' does not have an associated solver. Please ensure that a valid control part with an available solver is provided." + ) + return None + pose = to_tensor(pose, device=self.device) + + if pose.shape[0] != len(local_env_ids): + logger.log_error( + f"Pose batch size mismatch. Expected {len(local_env_ids)} but got {pose.shape[0]}." + ) + + n_batch = pose.shape[1] + n_dof = solver.dof + if joint_seed is None: + joint_seed = torch.zeros( + (len(local_env_ids), n_batch, n_dof), + dtype=torch.float32, + device=self.device, + ) + + if joint_seed.shape[0] != len(local_env_ids): + logger.log_error( + f"Joint seed env size mismatch. Expected {len(local_env_ids)} but got {joint_seed.shape[0]}." + ) + + if joint_seed.shape[1] != n_batch: + logger.log_error( + f"Joint seed batch size mismatch. Expected {n_batch} but got {joint_seed.shape[1]}." + ) + + if joint_seed.shape[-1] != n_dof: + logger.log_error( + f"Joint seed dof size mismatch. Expected {n_batch} but got {joint_seed.shape[-1]}." + ) + + if pose.shape[-1] == 7 and pose.dim() == 3: + # Convert pose from (n_envs, n_batch, 7) to (n_envs * n_batch, 4, 4) + pose_batch = torch.reshape(-1, 7) + pose_batch = torch.cat( + ( + pose_batch[:, :3].unsqueeze(-1), # Position + quat_from_matrix(pose_batch[:, 3:]).unsqueeze(-1), # Quaternion + ), + dim=-1, + ) + pose_batch = torch.cat( + ( + pose_batch, + torch.tensor([[0, 0, 0, 1]], device=pose_batch.device).expand( + pose_batch.shape[0], -1, -1 + ), + ), + dim=1, + ) + else: + # Convert pose from (n_envs, n_batch, 4, 4) to (n_envs * n_batch, 4, 4) + pose_batch = pose.reshape(-1, 4, 4) + + # get xpos from link root + base_xpos_n_envs = self.get_link_pose( + link_name=solver.root_link_name, env_ids=local_env_ids, to_matrix=True + ) + base_inv_xpos_n_envs = torch.inverse(base_xpos_n_envs) + base_inv_xpos_batch = ( + base_inv_xpos_n_envs[:, None, :, :] + .repeat(1, n_batch, 1, 1) + .reshape(-1, 4, 4) + ) + pose_batch = torch.bmm(base_inv_xpos_batch, pose_batch) + + joint_seed_batch = joint_seed.reshape(-1, n_dof) + ret, qpos_batch = solver.get_ik( + target_xpos=pose_batch, + qpos_seed=joint_seed_batch, + return_all_solutions=False, + ) + ret = ret.reshape(len(local_env_ids), n_batch) + qpos = qpos_batch.reshape(len(local_env_ids), n_batch, n_dof) + return ret, qpos + + def _init_control_parts(self, control_parts: Dict[str, List[str]]) -> None: + """Initialize the control parts of the robot. + + Args: + control_parts (Dict[str, List[str]]): A dictionary where keys are control part names and values are lists of + joint names or regular expressions that match joint names. + """ + joint_name_to_ids = {name: i for i, name in enumerate(self.joint_names)} + for name, joint_names in control_parts.items(): + # convert joint_names which is a regular expression to a list of joint names + joint_names_expanded = [] + for jn in joint_names: + if is_regular_expression(jn): + _, names, _ = resolve_matching_names_values( + {jn: None}, self.joint_names + ) + joint_names_expanded.extend(names) + else: + joint_names_expanded.append(jn) + + self._joint_ids[name] = [ + joint_name_to_ids[joint_name] + for joint_name in joint_names_expanded + if joint_name in joint_name_to_ids + ] + if len(self._joint_ids[name]) != len(joint_names_expanded): + logger.log_error( + f"joint names in control part '{name}' do not match the robot's joint names. The full joint names are: {self.joint_names}." + ) + self.cfg.control_parts[name] = joint_names_expanded + + # Initialize control groups + self._control_groups = self._extract_control_groups() + + def init_solver(self, cfg: Union[SolverCfg, Dict[str, SolverCfg]]) -> None: + """Initialize the kinematic solver for the robot. + + Args: + cfg (Union[SolverCfg, Dict[str, SolverCfg]]): The configuration for the kinematic solver. + """ + self.cfg: RobotCfg + + if isinstance(cfg, SolverCfg): + if self.control_parts: + logger.log_error( + "Control parts are defined in the robot configuration, solver_cfg must be a dictionary." + ) + + if cfg.urdf_path is None: + cfg.urdf_path = self.cfg.fpath + self._solvers["default"] = cfg.init_solver(device=self.device) + elif isinstance(cfg, Dict): + if isinstance(self.cfg.control_parts, Dict) is False: + logger.log_error( + "When `solver_cfg` is a dictionary, `control_parts` must also be a dictionary." + ) + + # If solver_cfg is a dictionary, iterate through it to create solvers + for name, solver_cfg in cfg.items(): + if solver_cfg.urdf_path is None: + solver_cfg.urdf_path = self.cfg.fpath + _, part_names, value = resolve_matching_names_values( + {name: solver_cfg}, self.cfg.control_parts.keys() + ) + for part_name in part_names: + if ( + not hasattr(solver_cfg, "joint_names") + or solver_cfg.joint_names is None + ): + solver_cfg.joint_names = self.cfg.control_parts[part_name] + self._solvers[name] = solver_cfg.init_solver(device=self.device) + + def get_solver(self, name: Optional[str] = None) -> Optional[BaseSolver]: + """Get the kinematic solver for a specific control part. + + Args: + name (str, optional): The name of the control part to get the solver for. If None, the default part is used. + + Returns: + Optional[BaseSolver]: The kinematic solver for the specified control part, or None if not found. + """ + + if not self._solvers: + logger.log_error( + "No solvers are defined for the robot. Please ensure that the robot has solvers configured." + ) + return None + + return self._solvers.get(name if name is not None else "default", None) + + def get_control_part_base_pose( + self, + name: Optional[str] = None, + env_ids: Optional[Sequence[int]] = None, + to_matrix: bool = False, + ) -> torch.Tensor: + """Retrieves the base pose of the control part for a specified robot. + + Args: + name (Optional[str]): The name of the control part the solver adhere to. If None, the default solver is used. + env_ids (Optional[Sequence[int]]): A sequence of environment IDs to specify the environments. + If None, all indices are used. + to_matrix (bool): If True, returns the pose in the form of a 4x4 matrix. + + Returns: + The pose of the specified link in the form of a matrix. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + root_link_name = None + if name in self._control_groups: + root_link_name = self._control_groups[name].link_names[0] + + return self.get_link_pose( + link_name=root_link_name, env_ids=local_env_ids, to_matrix=to_matrix + ) + + def _extract_control_groups(self) -> Dict[str, ControlGroup]: + r"""Extract control groups from the active joint names. + + This method creates a dictionary of control groups where each control + group is associated with its corresponding joint names. It utilizes + the `_extract_control_group` method to populate the control groups. + + Returns: + Dict[str, ControlGroup]: A dictionary mapping control group names + to their corresponding ControlGroup instances. + """ + if not self.control_parts: + return {} + + control_groups = { + control_group_name: self._extract_control_group(joint_names) + for control_group_name, joint_names in self.control_parts.items() + } + + return control_groups + + def _extract_control_group(self, joint_names: List[str]) -> ControlGroup: + r"""Extract a control group from the given list of joint names. + + Args: + joint_names (List[str]): A list of joint names + to be included in the control group. + + Returns: + ControlGroup: An instance of ControlGroup containing the specified joints + and their associated links. + """ + control_group = ControlGroup() + joint_id_list = [] + + for joint_name in joint_names: + if joint_name in self.joint_names: + joint_index = self.joint_names.index(joint_name) + joint_id_list.append(joint_index) + control_group.joint_names.append(joint_name) + + # Set root link for first joint + if len(control_group.link_names) == 0: + parent_names = self._entities[0].get_ancestral_link_names( + joint_index + ) + control_group.link_names.extend(parent_names) + + child_name = self._entities[0].get_child_link_name(joint_index) + control_group.link_names.append(child_name) + + control_group.joint_ids = joint_id_list + return control_group + + def build_pk_serial_chain(self) -> None: + """Build the kinematic serial chain for the robot. + + This method is mainly used for robot learning scenarios, for example: + - Imitation learning dataset generation. + """ + self.pk_serial_chain = self.cfg.build_pk_serial_chain(device=self.device) + + def destroy(self) -> None: + return super().destroy() diff --git a/embodichain/lab/sim/objects/soft_object.py b/embodichain/lab/sim/objects/soft_object.py new file mode 100644 index 00000000..fcbf1c95 --- /dev/null +++ b/embodichain/lab/sim/objects/soft_object.py @@ -0,0 +1,376 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import dexsim +import numpy as np +from functools import cached_property + +from dataclasses import dataclass +from typing import List, Sequence, Optional, Union + +from dexsim.models import MeshObject +from dexsim.engine import PhysicsScene +from dexsim.types import SoftBodyGPUAPIReadWriteType +from embodichain.lab.sim.common import ( + BatchEntity, +) +from embodichain.utils.math import ( + matrix_from_euler, +) +from embodichain.utils import logger +from embodichain.lab.sim.cfg import ( + SoftObjectCfg, +) +from embodichain.utils.math import xyz_quat_to_4x4_matrix + + +@dataclass +class SoftBodyData: + """Data manager for soft body + + Note: + 1. The pose data managed by dexsim is in the format of (qx, qy, qz, qw, x, y, z), but in EmbodySim, we use (x, y, z, qw, qx, qy, qz) format. + """ + + def __init__( + self, entities: List[MeshObject], ps: PhysicsScene, device: torch.device + ) -> None: + """Initialize the SoftBodyData. + + Args: + entities (List[MeshObject]): List of MeshObjects representing the soft bodies. + ps (PhysicsScene): The physics scene. + device (torch.device): The device to use for the soft body data. + """ + self.entities = entities + # TODO: soft body data can only be stored in cuda device for now. + self.device = device + # TODO: inorder to retrieve arena position, we need to access the node of each entity. + self._arena_positions = self._get_arena_position() + self.ps = ps + self.num_instances = len(entities) + + softbodies = [ + self.entities[i].get_physical_body() for i in range(self.num_instances) + ] + self.n_collision_vertices = softbodies[0].get_num_vertices() + self.n_sim_vertices = softbodies[0].get_num_sim_vertices() + + self._rest_position_buffer = torch.empty( + (self.num_instances, self.n_collision_vertices, 4), + device=self.device, + dtype=torch.float32, + ) + for i, softbody in enumerate(softbodies): + self._rest_position_buffer[i] = softbody.get_position_inv_mass_buffer() + + self._rest_sim_position_buffer = torch.empty( + (self.num_instances, self.n_sim_vertices, 4), + device=self.device, + dtype=torch.float32, + ) + + for i, softbody in enumerate(softbodies): + self._rest_sim_position_buffer[ + i + ] = softbody.get_sim_position_inv_mass_buffer() + + self._collision_position_buffer = torch.zeros( + (self.num_instances, self.n_collision_vertices, 4), + device=self.device, + dtype=torch.float32, + ) + self._sim_vertex_velocity_buffer = torch.zeros( + (self.num_instances, self.n_sim_vertices, 4), + device=self.device, + dtype=torch.float32, + ) + self._sim_vertex_position_buffer = torch.zeros( + (self.num_instances, self.n_sim_vertices, 4), + device=self.device, + dtype=torch.float32, + ) + + def _get_arena_position(self): + n_env = len(self.entities) + arena_positions = torch.empty( + (n_env, 3), device=self.device, dtype=torch.float32 + ) + for i, entity in enumerate(self.entities): + arena = entity.node.get_parent() + arena_position = arena.get_world_pose()[:3, 3] + arena_positions[i] = torch.as_tensor( + arena_position, device=self.device, dtype=torch.float32 + ) + return arena_positions + + @property + def rest_collision_vertices(self): + """Get the rest position buffer of the soft bodies.""" + return self._rest_position_buffer[:, :, :3].clone() + + @property + def rest_sim_vertices(self): + """Get the rest sim position buffer of the soft bodies.""" + return self._rest_sim_position_buffer[:, :, :3].clone() + + @property + def collision_position_buffer(self): + """Get the current vertex position buffer of the soft bodies.""" + for i, softbody in enumerate(self.soft_bodies): + self._collision_position_buffer[i] = softbody.get_position_inv_mass_buffer() + return self._collision_position_buffer.clone() + + @property + def sim_vertex_position_buffer(self): + """Get the current sim vertex position buffer of the soft bodies.""" + for i, softbody in enumerate(self.soft_bodies): + self._sim_vertex_position_buffer[ + i + ] = softbody.get_sim_position_inv_mass_buffer() + return self._sim_vertex_position_buffer.clone() + + @property + def sim_vertex_velocity_buffer(self): + """Get the current vertex velocity buffer of the soft bodies.""" + for i, softbody in enumerate(self.soft_bodies): + self._sim_vertex_velocity_buffer[ + i + ] = softbody.get_sim_position_inv_mass_buffer() + return self._sim_vertex_velocity_buffer.clone() + + +class SoftObject(BatchEntity): + """SoftObject represents a batch of rigid body in the simulation.""" + + def __init__( + self, + cfg: SoftObjectCfg, + entities: List[MeshObject] = None, + device: torch.device = torch.device("cpu"), + ) -> None: + self._world = dexsim.default_world() + self._ps = self._world.get_physics_scene() + self._all_indices = torch.arange( + len(entities), dtype=torch.int32, device=device + ) + + self._data = SoftBodyData(entities=entities, ps=self._ps, device=device) + + # TODO: soft body physical attribute is already set in soft body creation(embodichain/lab/sim/utility/sim_utils.py load_soft_object_from_cfg) + self._world.update(0.001) + + super().__init__(cfg=cfg, entities=entities, device=device) + + # set default collision filter + self._set_default_collision_filter() + + def _set_default_collision_filter(self) -> None: + collision_filter_data = torch.zeros( + size=(self.num_instances, 4), dtype=torch.int32 + ) + for i in range(self.num_instances): + collision_filter_data[i, 0] = i + collision_filter_data[i, 1] = 1 + self.set_collision_filter(collision_filter_data) + + def set_collision_filter( + self, filter_data: torch.Tensor, env_ids: Optional[Sequence[int]] = None + ) -> None: + """set collision filter data for the rigid object. + + Args: + filter_data (torch.Tensor): [N, 4] of int. + First element of each object is arena id. + If 2nd element is 0, the object will collision with all other objects in world. + 3rd and 4th elements are not used currently. + + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. Defaults to None. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + if len(local_env_ids) != len(filter_data): + logger.log_error( + f"Length of env_ids {len(local_env_ids)} does not match pose length {len(filter_data)}." + ) + + filter_data_np = filter_data.cpu().numpy().astype(np.uint32) + for i, env_idx in enumerate(local_env_ids): + self._entities[env_idx].get_physical_body().set_collision_filter_data( + filter_data_np[i] + ) + + @property + def body_data(self) -> Optional[SoftBodyData]: + """Get the soft body data manager for this rigid object. + + Returns: + SoftBodyData: The rigid body data manager. + """ + return self._data + + def set_local_pose( + self, pose: torch.Tensor, env_ids: Optional[Sequence[int]] = None + ) -> None: + """Set local pose of the rigid object. + + Args: + pose (torch.Tensor): The local pose of the rigid object with shape (N, 7) or (N, 4, 4). + env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + if len(local_env_ids) != len(pose): + logger.log_error( + f"Length of env_ids {len(local_env_ids)} does not match pose length {len(pose)}." + ) + + if pose.dim() == 2 and pose.shape[1] == 7: + pose4x4 = xyz_quat_to_4x4_matrix(pose) + elif pose.dim() == 3 and pose.shape[1:3] == (4, 4): + pose4x4 = pose + else: + logger.log_error( + f"Invalid pose shape {pose.shape}. Expected (N, 7) or (N, 4, 4)." + ) + + for i, env_idx in enumerate(local_env_ids): + # TODO: soft body cannot directly set by `set_local_pose` currently. + rest_collision_vertices = self.body_data.rest_collision_vertices[i] + rest_sim_vertices = self.body_data.rest_sim_vertices[i] + rotation = pose4x4[i][:3, :3] + translation = pose4x4[i][:3, 3] + + # apply transformation to local rest vertices and back + rest_collision_vertices_local = ( + rest_collision_vertices - self._data._arena_positions[i] + ) + transformed_collision_vertices = ( + rest_collision_vertices_local @ rotation.T + translation + ) + transformed_collision_vertices = ( + transformed_collision_vertices + self._data._arena_positions[i] + ) + + rest_sim_vertices_local = rest_sim_vertices - self._data._arena_positions[i] + transformed_sim_vertices = ( + rest_sim_vertices_local @ rotation.T + translation + ) + transformed_sim_vertices = ( + transformed_sim_vertices + self._data._arena_positions[i] + ) + + # apply vertices to soft body + soft_body = self._entities[env_idx].get_physical_body() + collision_position_buffer = soft_body.get_position_inv_mass_buffer() + sim_position_buffer = soft_body.get_sim_position_inv_mass_buffer() + sim_velocity_buffer = soft_body.get_sim_velocity_buffer() + + collision_position_buffer[:, :3] = transformed_collision_vertices + sim_position_buffer[:, :3] = transformed_sim_vertices + sim_velocity_buffer[:, :3] = 0.0 + + soft_body.mark_dirty(SoftBodyGPUAPIReadWriteType.ALL) + # TODO: currently soft body has no wake up interface, use set_wake_counter and pass in a positive value to wake it up + soft_body.set_wake_counter(0.4) + + def get_rest_collision_vertices(self) -> torch.Tensor: + """Get the rest collision vertices of the soft object. + + Returns: + torch.Tensor: The rest collision vertices with shape (N, num_collision_vertices, 3). + """ + return self.body_data.rest_collision_vertices + + def get_rest_sim_vertices(self) -> torch.Tensor: + """Get the rest sim vertices of the soft object. + + Returns: + torch.Tensor: The rest sim vertices with shape (N, num_sim_vertices, 3). + """ + return self.body_data.rest_sim_vertices + + def get_current_collision_vertices(self) -> torch.Tensor: + """Get the current collision vertices of the soft object. + + Returns: + torch.Tensor: The current collision vertices with shape (N, num_collision_vertices, 3). + """ + return self.body_data.collision_position_buffer + + def get_current_sim_vertices(self) -> torch.Tensor: + """Get the current sim vertices of the soft object. + + Returns: + torch.Tensor: The current sim vertices with shape (N, num_sim_vertices, 3). + """ + return self.body_data.sim_vertex_position_buffer + + def get_current_sim_vertex_velocities(self) -> torch.Tensor: + """Get the current sim vertex velocities of the soft object. + + Returns: + torch.Tensor: The current sim vertex velocities with shape (N, num_sim_vertices, 3). + """ + return self.body_data.sim_vertex_velocity_buffer + + def get_local_pose(self, to_matrix: bool = False) -> torch.Tensor: + """Get local pose of the rigid object. + + Args: + to_matrix (bool, optional): If True, return the pose as a 4x4 matrix. If False, return as (x, y, z, qw, qx, qy, qz). Defaults to False. + + Returns: + torch.Tensor: The local pose of the rigid object with shape (N, 7) or (N, 4, 4) depending on `to_matrix`. + """ + raise NotImplementedError("Getting local pose for SoftObject is not supported.") + + def reset(self, env_ids: Optional[Sequence[int]] = None) -> None: + local_env_ids = self._all_indices if env_ids is None else env_ids + num_instances = len(local_env_ids) + + # TODO: set attr for soft body after loading in physx scene + + # rest soft body to init_pos + pos = torch.as_tensor( + self.cfg.init_pos, dtype=torch.float32, device=self.device + ) + rot = ( + torch.as_tensor(self.cfg.init_rot, dtype=torch.float32, device=self.device) + * torch.pi + / 180.0 + ) + pos = pos.unsqueeze(0).repeat(num_instances, 1) + rot = rot.unsqueeze(0).repeat(num_instances, 1) + mat = matrix_from_euler(rot, "XYZ") + pose = ( + torch.eye(4, dtype=torch.float32, device=self.device) + .unsqueeze(0) + .repeat(num_instances, 1, 1) + ) + pose[:, :3, 3] = pos + pose[:, :3, :3] = mat + self.set_local_pose(pose, env_ids=local_env_ids) + + def destroy(self) -> None: + # TODO: not tested yet + env = self._world.get_env() + arenas = env.get_all_arenas() + if len(arenas) == 0: + arenas = [env] + for i, entity in enumerate(self._entities): + arenas[i].remove_actor(entity) diff --git a/embodichain/lab/sim/planners/base_planner.py b/embodichain/lab/sim/planners/base_planner.py new file mode 100644 index 00000000..d85e026d --- /dev/null +++ b/embodichain/lab/sim/planners/base_planner.py @@ -0,0 +1,201 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import numpy as np +from abc import ABC, abstractmethod +from typing import Dict, List, Tuple, Union, Optional +import matplotlib.pyplot as plt + +from embodichain.lab.sim.planners.utils import TrajectorySampleMethod +from embodichain.utils import logger + + +class BasePlanner(ABC): + r"""Base class for trajectory planners. + + This class provides common functionality that can be shared across different + planner implementations, such as constraint checking and trajectory visualization. + + Args: + dofs: Number of degrees of freedom + max_constraints: Dictionary containing 'velocity' and 'acceleration' constraints + """ + + def __init__(self, dofs: int, max_constraints: Dict[str, List[float]]): + self.dofs = dofs + self.max_constraints = max_constraints + + @abstractmethod + def plan( + self, + current_state: Dict, + target_states: List[Dict], + **kwargs, + ) -> Tuple[ + bool, + Optional[np.ndarray], + Optional[np.ndarray], + Optional[np.ndarray], + Optional[np.ndarray], + float, + ]: + r"""Execute trajectory planning. + + This method must be implemented by subclasses to provide the specific + planning algorithm. + + Args: + current_state: Dictionary containing 'position', 'velocity', 'acceleration' for current state + target_states: List of dictionaries containing target states + + Returns: + Tuple of (success, positions, velocities, accelerations, times, duration): + - success: bool, whether planning succeeded + - positions: np.ndarray (N, DOF), joint positions along trajectory + - velocities: np.ndarray (N, DOF), joint velocities along trajectory + - accelerations: np.ndarray (N, DOF), joint accelerations along trajectory + - times: np.ndarray (N,), time stamps for each point + - duration: float, total trajectory duration + """ + logger.log_error("Subclasses must implement plan() method", NotImplementedError) + + def is_satisfied_constraint( + self, velocities: np.ndarray, accelerations: np.ndarray + ) -> bool: + r"""Check if the trajectory satisfies velocity and acceleration constraints. + + This method checks whether the given velocities and accelerations satisfy + the constraints defined in max_constraints. It allows for some tolerance + to account for numerical errors in dense waypoint scenarios. + + Args: + velocities: Velocity array (N, DOF) where N is the number of trajectory points + accelerations: Acceleration array (N, DOF) where N is the number of trajectory points + + Returns: + bool: True if all constraints are satisfied, False otherwise + + Note: + - Allows 10% tolerance for velocity constraints + - Allows 25% tolerance for acceleration constraints + - Prints exceed information if constraints are violated + - Assumes symmetric constraints (velocities and accelerations can be positive or negative) + """ + # Convert max_constraints to symmetric format for constraint checking + # This assumes symmetric constraints (common for most planners) + vlims = np.array([[-v, v] for v in self.max_constraints["velocity"]]) + alims = np.array([[-a, a] for a in self.max_constraints["acceleration"]]) + + vel_check = np.all((velocities >= vlims[:, 0]) & (velocities <= vlims[:, 1])) + acc_check = np.all( + (accelerations >= alims[:, 0]) & (accelerations <= alims[:, 1]) + ) + + # 超限情况 + if not vel_check: + vel_exceed_info = [] + min_vel = np.min(velocities, axis=0) + max_vel = np.max(velocities, axis=0) + for i in range(self.dofs): + exceed_percentage = 0 + max_vel_limit = self.max_constraints["velocity"][i] + if min_vel[i] < -max_vel_limit: + exceed_percentage = (min_vel[i] + max_vel_limit) / max_vel_limit + if max_vel[i] > max_vel_limit: + temp = (max_vel[i] - max_vel_limit) / max_vel_limit + if temp > exceed_percentage: + exceed_percentage = temp + vel_exceed_info.append(exceed_percentage * 100) + logger.log_info(f"Velocity exceed info: {vel_exceed_info} percentage") + + if not acc_check: + acc_exceed_info = [] + min_acc = np.min(accelerations, axis=0) + max_acc = np.max(accelerations, axis=0) + for i in range(self.dofs): + exceed_percentage = 0 + max_acc_limit = self.max_constraints["acceleration"][i] + if min_acc[i] < -max_acc_limit: + exceed_percentage = (min_acc[i] + max_acc_limit) / max_acc_limit + if max_acc[i] > max_acc_limit: + temp = (max_acc[i] - max_acc_limit) / max_acc_limit + if temp > exceed_percentage: + exceed_percentage = temp + acc_exceed_info.append(exceed_percentage * 100) + logger.log_info(f"Acceleration exceed info: {acc_exceed_info} percentage") + + return vel_check and acc_check + + def plot_trajectory( + self, positions: np.ndarray, velocities: np.ndarray, accelerations: np.ndarray + ) -> None: + r"""Plot trajectory data. + + This method visualizes the trajectory by plotting position, velocity, and + acceleration curves for each joint over time. It also displays the constraint + limits for reference. + + Args: + positions: Position array (N, DOF) where N is the number of trajectory points + velocities: Velocity array (N, DOF) where N is the number of trajectory points + accelerations: Acceleration array (N, DOF) where N is the number of trajectory points + + Note: + - Creates a 3-subplot figure (position, velocity, acceleration) + - Shows constraint limits as dashed lines + - Requires matplotlib to be installed + """ + time_step = 0.01 + time_steps = np.arange(positions.shape[0]) * time_step + fig, axs = plt.subplots(3, 1, figsize=(10, 8)) + + for i in range(self.dofs): + axs[0].plot(time_steps, positions[:, i], label=f"Joint {i+1}") + axs[1].plot(time_steps, velocities[:, i], label=f"Joint {i+1}") + axs[2].plot(time_steps, accelerations[:, i], label=f"Joint {i+1}") + + # Plot velocity constraints (only for first joint to avoid clutter) + # Convert max_constraints to symmetric format for visualization + if self.dofs > 0: + max_vel = self.max_constraints["velocity"][0] + max_acc = self.max_constraints["acceleration"][0] + axs[1].plot( + time_steps, + [-max_vel] * len(time_steps), + "k--", + label="Max Velocity", + ) + axs[1].plot(time_steps, [max_vel] * len(time_steps), "k--") + # Plot acceleration constraints (only for first joint to avoid clutter) + axs[2].plot( + time_steps, + [-max_acc] * len(time_steps), + "k--", + label="Max Accleration", + ) + axs[2].plot(time_steps, [max_acc] * len(time_steps), "k--") + + axs[0].set_title("Position") + axs[1].set_title("Velocity") + axs[2].set_title("Acceleration") + + for ax in axs: + ax.set_xlabel("Time [s]") + ax.legend() + ax.grid() + + plt.tight_layout() + plt.show() diff --git a/embodichain/lab/sim/planners/motion_generator.py b/embodichain/lab/sim/planners/motion_generator.py new file mode 100644 index 00000000..165844f7 --- /dev/null +++ b/embodichain/lab/sim/planners/motion_generator.py @@ -0,0 +1,604 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np +from typing import Dict, List, Tuple, Union, Optional, Any +from enum import Enum +from scipy.spatial.transform import Rotation, Slerp + +from embodichain.lab.sim.planners.toppra_planner import ToppraPlanner +from embodichain.lab.sim.planners.utils import TrajectorySampleMethod +from embodichain.lab.sim.objects.robot import Robot +from embodichain.utils import logger + + +class PlannerType(Enum): + r"""Enumeration for different planner types.""" + TOPPRA = "toppra" + """TOPPRA planner for time-optimal trajectory planning.""" + + +class MotionGenerator: + r"""Unified motion generator for robot trajectory planning. + + This class provides a unified interface for trajectory planning with and without + collision checking. It supports V3 environment interfaces and can use different + types of planners (ToppraPlanner, RRT, PRM, etc.) for trajectory generation. + + Args: + robot: Robot agent object (must support compute_fk, compute_ik, dof, get_joint_ids) + uid: Unique identifier for the robot (optional) + sim: Simulation environment object (optional, reserved for future collision checking) + planner_type: Type of planner to use (default: "toppra") + default_velocity: Default velocity limits for each joint (rad/s) + default_acceleration: Default acceleration limits for each joint (rad/s²) + collision_margin: Safety margin for collision checking (meters, reserved for future use) + **kwargs: Additional arguments passed to planner initialization + """ + + def __init__( + self, + robot: Robot, + uid: str, + sim=None, + planner_type: Union[str, PlannerType] = "toppra", + default_velocity: float = 0.2, + default_acceleration: float = 0.5, + collision_margin: float = 0.01, + **kwargs, + ): + self.robot = robot + self.sim = sim + self.collision_margin = collision_margin + self.uid = uid + + # Get robot DOF using get_joint_ids for specified control part (None for whole body) + self.dof = len(robot.get_joint_ids(uid)) + + # Create planner based on planner_type + self.planner_type = self._parse_planner_type(planner_type) + self.planner = self._create_planner( + self.planner_type, default_velocity, default_acceleration, **kwargs + ) + + def _parse_planner_type(self, planner_type: Union[str, PlannerType]) -> str: + r"""Parse planner type from string or enum. + + Args: + planner_type: Planner type as string or PlannerType enum + + Returns: + Planner type as string + """ + if isinstance(planner_type, PlannerType): + return planner_type.value + elif isinstance(planner_type, str): + planner_type_lower = planner_type.lower() + # Validate planner type + valid_types = [e.value for e in PlannerType] + if planner_type_lower not in valid_types: + logger.log_warning( + f"Unknown planner type '{planner_type}', using 'toppra'. " + f"Valid types: {valid_types}" + ) + return "toppra" + return planner_type_lower + else: + logger.log_error( + f"planner_type must be str or PlannerType, got {type(planner_type)}", + TypeError, + ) + + def _create_planner( + self, + planner_type: str, + default_velocity: float, + default_acceleration: float, + **kwargs, + ) -> Any: + r"""Create planner instance based on planner type. + + Args: + planner_type: Type of planner to create + default_velocity: Default velocity limit + default_acceleration: Default acceleration limit + **kwargs: Additional arguments for planner initialization + + Returns: + Planner instance + """ + # Get constraints from robot or use defaults + max_constraints = self._get_constraints( + default_velocity, default_acceleration, **kwargs + ) + + if planner_type == "toppra": + return ToppraPlanner(self.dof, max_constraints) + else: + logger.log_error( + f"Unknown planner type '{planner_type}'. " + f"Supported types: {[e.value for e in PlannerType]}", + ValueError, + ) + + def _get_constraints( + self, default_velocity: float, default_acceleration: float, **kwargs + ) -> Dict[str, List[float]]: + r"""Get velocity and acceleration constraints for the robot. + + Priority: + 1. kwargs['max_constraints'] if provided + 2. Robot's built-in constraints (if available) + 3. Default values + + Args: + default_velocity: Default velocity limit + default_acceleration: Default acceleration limit + **kwargs: Additional arguments + + Returns: + Dictionary with 'velocity' and 'acceleration' constraints + """ + # Check if constraints are provided in kwargs + if "max_constraints" in kwargs and kwargs["max_constraints"] is not None: + constraints = kwargs["max_constraints"] + if isinstance(constraints, dict) and "velocity" in constraints: + return constraints + + # Try to get constraints from robot (if available) + # TODO: Add robot.get_joint_limits() or similar if available in future + + # Use default constraints + return { + "velocity": [default_velocity] * self.dof, + "acceleration": [default_acceleration] * self.dof, + } + + def _create_state_dict( + self, position: np.ndarray, velocity: Optional[np.ndarray] = None + ) -> Dict: + r"""Create a state dictionary for trajectory planning. + + Args: + position: Joint positions + velocity: Joint velocities (optional, defaults to zeros) + acceleration: Joint accelerations (optional, defaults to zeros) + + Returns: + State dictionary with 'position', 'velocity', 'acceleration' + """ + if velocity is None: + velocity = np.zeros(self.dof) + + if isinstance(position, torch.Tensor) | isinstance(position, np.ndarray): + position = position.squeeze() + + return { + "position": position.tolist() + if isinstance(position, np.ndarray) + else position, + "velocity": velocity.tolist() + if isinstance(velocity, np.ndarray) + else velocity, + "acceleration": [0.0] * self.dof, + } + + def plan( + self, + current_state: Dict, + target_states: List[Dict], + sample_method: TrajectorySampleMethod = TrajectorySampleMethod.TIME, + sample_interval: Union[float, int] = 0.01, + **kwargs, + ) -> Tuple[ + bool, + Optional[np.ndarray], + Optional[np.ndarray], + Optional[np.ndarray], + Optional[np.ndarray], + float, + ]: + r"""Plan trajectory without collision checking. + + This method generates a smooth trajectory using the selected planner that satisfies + velocity and acceleration constraints, but does not check for collisions. + + Args: + current_state: Dictionary containing current state: + - "position": Current joint positions (required) + - "velocity": Current joint velocities (optional, defaults to zeros) + - "acceleration": Current joint accelerations (optional, defaults to zeros) + target_states: List of target state dictionaries, each with same format as current_state + sample_method: Sampling method (TIME or QUANTITY) + sample_interval: Sampling interval (time in seconds for TIME method, or number of points for QUANTITY) + **kwargs: Additional arguments + + Returns: + Tuple of (success, positions, velocities, accelerations, times, duration): + - success: bool, whether planning succeeded + - positions: np.ndarray (N, DOF), joint positions along trajectory + - velocities: np.ndarray (N, DOF), joint velocities along trajectory + - accelerations: np.ndarray (N, DOF), joint accelerations along trajectory + - times: np.ndarray (N,), time stamps for each point + - duration: float, total trajectory duration + """ + # Validate inputs + if len(current_state["position"]) != self.dof: + logger.log_warning( + f"Current state position dimension {len(current_state['position'])} " + f"does not match robot DOF {self.dof}" + ) + return False, None, None, None, None, 0.0 + + for i, target in enumerate(target_states): + if len(target["position"]) != self.dof: + logger.log_warning( + f"Target state {i} position dimension {len(target['position'])} " + f"does not match robot DOF {self.dof}" + ) + return False, None, None, None, None, 0.0 + + # Plan trajectory using selected planner + ( + success, + positions, + velocities, + accelerations, + times, + duration, + ) = self.planner.plan( + current_state=current_state, + target_states=target_states, + sample_method=sample_method, + sample_interval=sample_interval, + ) + + return success, positions, velocities, accelerations, times, duration + + def plan_with_collision( + self, + current_state: Dict, + target_states: List[Dict], + sample_method: TrajectorySampleMethod = TrajectorySampleMethod.TIME, + sample_interval: Union[float, int] = 0.01, + collision_check_interval: float = 0.01, + **kwargs, + ) -> None: + r"""Plan trajectory with collision checking. + + TODO: This method is not yet implemented. It should: + 1. Generate a trajectory using the selected planner + 2. Check for collisions along the trajectory + 3. Return failure if collisions are detected + """ + pass + + def create_discrete_trajectory( + self, + xpos_list: Optional[List[np.ndarray]] = None, + qpos_list: Optional[List[np.ndarray]] = None, + is_use_current_qpos: bool = True, + is_linear: bool = False, + sample_method: TrajectorySampleMethod = TrajectorySampleMethod.QUANTITY, + sample_num: Union[float, int] = 20, + qpos_seed: Optional[np.ndarray] = None, + **kwargs, + ) -> Tuple[List[np.ndarray], List[np.ndarray]]: + r"""Generate a discrete trajectory between waypoints using cartesian or joint space interpolation. + + This method supports two trajectory planning approaches: + 1. Linear interpolation: Fast, uniform spacing, no dynamics constraints + 2. Planner-based: Smooth, considers velocity/acceleration limits, realistic motion + + Args: + xpos_list: List of waypoints as 4x4 transformation matrices (optional) + qpos_list: List of joint configurations (optional) + is_use_current_qpos: Whether to use current joint angles as starting point + is_linear: If True, use cartesian linear interpolation, else joint space + sample_method: Sampling method (QUANTITY or TIME) + sample_num: Number of interpolated points for final trajectory + qpos_seed: Initial joint configuration for IK solving + **kwargs: Additional arguments + + Returns: + A tuple containing: + - List[np.ndarray]: Joint space trajectory as a list of joint configurations + - List[np.ndarray]: Cartesian space trajectory as a list of 4x4 matrices + """ + + def interpolate_xpos( + current_xpos: np.ndarray, target_xpos: np.ndarray, num_samples: int + ) -> List[np.ndarray]: + """Interpolate between two poses using Slerp for rotation and linear for translation.""" + if num_samples < 2: + num_samples = 2 + + slerp = Slerp( + [0, 1], + Rotation.from_matrix([current_xpos[:3, :3], target_xpos[:3, :3]]), + ) + interpolated_poses = [] + for s in np.linspace(0, 1, num_samples): + interp_rot = slerp(s).as_matrix() + interp_trans = (1 - s) * current_xpos[:3, 3] + s * target_xpos[:3, 3] + interp_pose = np.eye(4) + interp_pose[:3, :3] = interp_rot + interp_pose[:3, 3] = interp_trans + interpolated_poses.append(interp_pose) + return interpolated_poses + + def calculate_point_allocations( + xpos_list: List[np.ndarray], + step_size: float = 0.002, + angle_step: float = np.pi / 90, + ) -> List[int]: + """Calculate number of interpolation points between each pair of waypoints.""" + point_allocations = [] + + for i in range(len(xpos_list) - 1): + start_pose = xpos_list[i] + end_pose = xpos_list[i + 1] + + if isinstance(start_pose, torch.Tensor): + start_pose = start_pose.squeeze().cpu().numpy() + if isinstance(end_pose, torch.Tensor): + end_pose = end_pose.squeeze().cpu().numpy() + + pos_dist = np.linalg.norm(end_pose[:3, 3] - start_pose[:3, 3]) + pos_points = max(1, int(pos_dist / step_size)) + + angle_diff = Rotation.from_matrix( + start_pose[:3, :3].T @ end_pose[:3, :3] + ) + angle = abs(angle_diff.as_rotvec()).max() + rot_points = max(1, int(angle / angle_step)) + + num_points = max(pos_points, rot_points) + point_allocations.append(num_points) + + return point_allocations + + # Handle input arguments + if qpos_list is not None: + qpos_list = np.asarray(qpos_list) + qpos_tensor = ( + torch.tensor(qpos_list) + if not isinstance(qpos_list, torch.Tensor) + else qpos_list + ) + xpos_list = [ + self.robot.compute_fk(qpos=q, name=self.uid, to_matrix=True) + .squeeze(0) + .cpu() + .numpy() + for q in qpos_tensor + ] + + if xpos_list is None: + logger.log_warning("Either xpos_list or qpos_list must be provided") + return [], [] + + # Get current position if needed + if is_use_current_qpos: + joint_ids = self.robot.get_joint_ids(self.uid) + qpos_tensor = self.robot.get_qpos() + # qpos_tensor shape: (batch, dof), usually batch=1 + current_qpos = qpos_tensor[0, joint_ids] + + current_xpos = ( + self.robot.compute_fk(qpos=current_qpos, name=self.uid, to_matrix=True) + .squeeze(0) + .cpu() + .numpy() + ) + + # Check if current position is significantly different from first waypoint + pos_diff = np.linalg.norm(current_xpos[:3, 3] - xpos_list[0][:3, 3]) + rot_diff = np.linalg.norm(current_xpos[:3, :3] - xpos_list[0][:3, :3]) + + if pos_diff > 0.001 or rot_diff > 0.01: + xpos_list = np.concatenate( + [current_xpos[None, :, :], xpos_list], axis=0 + ) + if qpos_list is not None: + qpos_list = np.concatenate( + [current_qpos[None, :], qpos_list], axis=0 + ) + + if qpos_seed is None and qpos_list is not None: + qpos_seed = qpos_list[0] + + # Input validation + if len(xpos_list) < 2: + logger.log_warning("xpos_list must contain at least 2 points") + return [], [] + + # Calculate point allocations for interpolation + interpolated_point_allocations = calculate_point_allocations( + xpos_list, step_size=0.002, angle_step=np.pi / 90 + ) + + # Generate trajectory + interpolate_qpos_list = [] + if is_linear or qpos_list is None: + # Linear cartesian interpolation + for i in range(len(xpos_list) - 1): + interpolated_poses = interpolate_xpos( + xpos_list[i], xpos_list[i + 1], interpolated_point_allocations[i] + ) + for xpos in interpolated_poses: + success, qpos = self.robot.compute_ik( + pose=xpos, joint_seed=qpos_seed, name=self.uid + ) + + if isinstance(success, torch.Tensor): + is_success = bool(success.all()) + elif isinstance(success, np.ndarray): + is_success = bool(np.all(success)) + elif isinstance(success, (list, tuple)): + is_success = all(success) + else: + is_success = bool(success) + + if isinstance(qpos, torch.Tensor): + has_nan = torch.isnan(qpos).any().item() + else: + has_nan = np.isnan(qpos).any() + + if not is_success or qpos is None or has_nan: + logger.log_debug( + f"IK failed or returned nan at pose, skipping this point." + ) + continue + + interpolate_qpos_list.append( + qpos[0] if isinstance(qpos, (np.ndarray, list)) else qpos + ) + qpos_seed = ( + qpos[0] if isinstance(qpos, (np.ndarray, list)) else qpos + ) + else: + # Joint space interpolation + interpolate_qpos_list = ( + qpos_list.tolist() if isinstance(qpos_list, np.ndarray) else qpos_list + ) + + if len(interpolate_qpos_list) < 2: + logger.log_error("Need at least 2 waypoints for trajectory planning") + + # Create trajectory dictionary + current_state = self._create_state_dict(interpolate_qpos_list[0]) + target_states = [ + self._create_state_dict(pos) for pos in interpolate_qpos_list[1:] + ] + + # Plan trajectory using internal plan method + success, positions, velocities, accelerations, times, duration = self.plan( + current_state=current_state, + target_states=target_states, + sample_method=sample_method, + sample_interval=sample_num, + **kwargs, + ) + + if not success or positions is None: + logger.log_error("Failed to plan trajectory") + + # Convert positions to list + out_qpos_list = ( + positions.tolist() if isinstance(positions, np.ndarray) else positions + ) + + out_qpos_list = ( + torch.tensor(out_qpos_list) + if not isinstance(out_qpos_list, torch.Tensor) + else out_qpos_list + ) + out_xpos_list = [ + self.robot.compute_fk(qpos=q.unsqueeze(0), name=self.uid, to_matrix=True) + .squeeze(0) + .cpu() + .numpy() + for q in out_qpos_list + ] + + return out_qpos_list, out_xpos_list + + def estimate_trajectory_sample_count( + self, + xpos_list: List[np.ndarray] = None, + qpos_list: List[np.ndarray] = None, + step_size: float = 0.01, + angle_step: float = np.pi / 90, + **kwargs, + ) -> int: + """Estimate the number of trajectory sampling points required. + + This function estimates the total number of sampling points needed to generate + a trajectory based on the given waypoints and sampling parameters. It can be + used to predict computational load and memory requirements before actual + trajectory generation. + + Args: + xpos_list: List of 4x4 transformation matrices representing waypoints + qpos_list: List of joint positions (optional) + is_linear: Whether to use linear interpolation + step_size: Maximum allowed distance between consecutive points (in meters) + angle_step: Maximum allowed angular difference between consecutive points (in radians) + **kwargs: Additional parameters for further customization + + Returns: + int: Estimated number of trajectory sampling points + """ + + def rotation_matrix_to_angle(self, rot_matrix: np.ndarray) -> float: + cos_angle = (np.trace(rot_matrix) - 1) / 2 + cos_angle = np.clip(cos_angle, -1.0, 1.0) + return np.arccos(cos_angle) + + # Input validation + if xpos_list is None and qpos_list is None: + return 0 + + # If joint position list is provided but end effector position list is not, + # convert through forward kinematics + if qpos_list is not None and xpos_list is None: + if len(qpos_list) < 2: + return 1 if len(qpos_list) == 1 else 1 + xpos_list = [ + self.robot.compute_fk( + qpos=torch.tensor(q, dtype=torch.float32), + name=self.uid, + to_matrix=True, + ) + .squeeze(0) + .cpu() + .numpy() + for q in qpos_list + ] + + if xpos_list is None or len(xpos_list) == 0: + return 1 + + if len(xpos_list) == 1: + return 1 + + total_samples = 1 # Starting point + + total_pos_dist = 0.0 + total_angle = 0.0 + + for i in range(len(xpos_list) - 1): + start_pose = xpos_list[i] + end_pose = xpos_list[i + 1] + + pos_diff = end_pose[:3, 3] - start_pose[:3, 3] + total_pos_dist += np.linalg.norm(pos_diff) + + try: + rot_matrix = start_pose[:3, :3].T @ end_pose[:3, :3] + angle = rotation_matrix_to_angle(rot_matrix) + total_angle += angle + except Exception: + pass + + pos_samples = max(1, int(total_pos_dist / step_size)) + rot_samples = max(1, int(total_angle / angle_step)) + + total_samples = max(pos_samples, rot_samples) + + return max(2, total_samples) diff --git a/embodichain/lab/sim/planners/toppra_planner.py b/embodichain/lab/sim/planners/toppra_planner.py new file mode 100644 index 00000000..0a37b783 --- /dev/null +++ b/embodichain/lab/sim/planners/toppra_planner.py @@ -0,0 +1,172 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import numpy as np +from embodichain.utils import logger +from embodichain.lab.sim.planners.utils import TrajectorySampleMethod +from embodichain.lab.sim.planners.base_planner import BasePlanner + +from typing import TYPE_CHECKING, Union, Optional, Tuple + +try: + import toppra as ta + import toppra.constraint as constraint +except ImportError: + logger.log_error( + "toppra not installed. Install with `pip install toppra==0.6.3`", ImportError + ) + +ta.setup_logging(level="WARN") + + +class ToppraPlanner(BasePlanner): + def __init__(self, dofs, max_constraints): + r"""Initialize the TOPPRA trajectory planner. + + Args: + dofs: Number of degrees of freedom + max_constraints: Dictionary containing 'velocity' and 'acceleration' constraints + """ + super().__init__(dofs, max_constraints) + + # Create TOPPRA-specific constraint arrays (symmetric format) + # This format is required by TOPPRA library + self.vlims = np.array([[-v, v] for v in max_constraints["velocity"]]) + self.alims = np.array([[-a, a] for a in max_constraints["acceleration"]]) + + def plan( + self, + current_state: dict, + target_states: list[dict], + **kwargs, + ): + r"""Execute trajectory planning. + + Args: + current_state: Dictionary containing 'position', 'velocity', 'acceleration' for current state + target_states: List of dictionaries containing target states + + Returns: + Tuple of (success, positions, velocities, accelerations, times, duration) + """ + sample_method = kwargs.get("sample_method", TrajectorySampleMethod.TIME) + sample_interval = kwargs.get("sample_interval", 0.01) + if not isinstance(sample_interval, (float, int)): + logger.log_error( + f"sample_interval must be float/int, got {type(sample_interval)}", + TypeError, + ) + if sample_method == TrajectorySampleMethod.TIME and sample_interval <= 0: + logger.log_error("Time interval must be positive", ValueError) + elif sample_method == TrajectorySampleMethod.QUANTITY and sample_interval < 2: + logger.log_error("At least 2 sample points required", ValueError) + + # Check waypoints + if len(current_state["position"]) != self.dofs: + logger.log_info("Current wayponit does not align") + return False, None, None, None, None, None + for target in target_states: + if len(target["position"]) != self.dofs: + logger.log_info("Target Wayponits does not align") + return False, None, None, None, None, None + + if ( + len(target_states) == 1 + and np.sum( + np.abs( + np.array(target_states[0]["position"]) + - np.array(current_state["position"]) + ) + ) + < 1e-3 + ): + logger.log_info("Only two same waypoints, do not plan") + return ( + True, + np.array([current_state["position"], target_states[0]["position"]]), + np.array([[0.0] * self.dofs, [0.0] * self.dofs]), + np.array([[0.0] * self.dofs, [0.0] * self.dofs]), + 0, + 0, + ) + + # Build waypoints + waypoints = [np.array(current_state["position"])] + for target in target_states: + waypoints.append(np.array(target["position"])) + waypoints = np.array(waypoints) + + # Create spline interpolation + # NOTE: Suitable for dense waypoints + ss = np.linspace(0, 1, len(waypoints)) + + # NOTE: Suitable for sparse waypoints; for dense waypoints, CubicSpline may fail strict monotonicity requirement + # len_total = 0 + # len_from_start = [0] + # for i in range(len(waypoints)-1): + # len_total += np.sum(np.abs(waypoints[i+1] - waypoints[i])) + # len_from_start.append(len_total) + # ss = np.array([cur/len_total for cur in len_from_start]) + + path = ta.SplineInterpolator(ss, waypoints) + + # Set constraints + pc_vel = constraint.JointVelocityConstraint(self.vlims) + pc_acc = constraint.JointAccelerationConstraint(self.alims) + + # Create TOPPRA instance + instance = ta.algorithm.TOPPRA( + [pc_vel, pc_acc], + path, + parametrizer="ParametrizeConstAccel", + gridpt_min_nb_points=max(100, 10 * len(waypoints)), + ) + # NOTES:合理设置gridpt_min_nb_points对加速度约束很重要 + + # Compute parameterized trajectory + jnt_traj = instance.compute_trajectory() + if jnt_traj is None: + # raise RuntimeError("Unable to find feasible trajectory") + logger.log_info("Unable to find feasible trajectory") + return False, None, None, None, None, None + + duration = jnt_traj.duration + # Sample trajectory points + if duration <= 0: + logger.log_error(f"Duration must be positive, got {duration}", ValueError) + if sample_method == TrajectorySampleMethod.TIME: + n_points = max(2, int(np.ceil(duration / sample_interval)) + 1) + ts = np.linspace(0, duration, n_points) + else: + ts = np.linspace(0, duration, num=int(sample_interval)) + + positions = [] + velocities = [] + accelerations = [] + + for t in ts: + positions.append(jnt_traj.eval(t)) + velocities.append(jnt_traj.evald(t)) + accelerations.append(jnt_traj.evaldd(t)) + + return ( + True, + np.array(positions), + np.array(velocities), + np.array(accelerations), + ts, + duration, + ) diff --git a/embodichain/lab/sim/planners/utils.py b/embodichain/lab/sim/planners/utils.py new file mode 100644 index 00000000..154e8529 --- /dev/null +++ b/embodichain/lab/sim/planners/utils.py @@ -0,0 +1,54 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from enum import Enum +from typing import Union +from embodichain.utils import logger + + +class TrajectorySampleMethod(Enum): + r"""Enumeration for different trajectory sampling methods. + + This enum defines various methods for sampling trajectories, + providing meaningful names for different sampling strategies. + """ + TIME = "time" + """Sample based on time intervals.""" + + QUANTITY = "quantity" + """Sample based on a specified number of points.""" + + DISTANCE = "distance" + """Sample based on distance intervals.""" + + @classmethod + def from_str( + cls, value: Union[str, "TrajectorySampleMethod"] + ) -> "TrajectorySampleMethod": + if isinstance(value, cls): + return value + try: + return cls[value.upper()] + except KeyError: + valid_values = [e.name for e in cls] + logger.log_error( + f"Invalid version '{value}'. Valid values are: {valid_values}", + ValueError, + ) + + def __str__(self): + """Override string representation for better readability.""" + return self.value.capitalize() diff --git a/embodichain/lab/sim/robots/__init__.py b/embodichain/lab/sim/robots/__init__.py new file mode 100644 index 00000000..de4c08aa --- /dev/null +++ b/embodichain/lab/sim/robots/__init__.py @@ -0,0 +1,18 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .dexforce_w1 import * +from .cobotmagic import CobotMagicCfg diff --git a/embodichain/lab/sim/robots/cobotmagic.py b/embodichain/lab/sim/robots/cobotmagic.py new file mode 100644 index 00000000..93308f46 --- /dev/null +++ b/embodichain/lab/sim/robots/cobotmagic.py @@ -0,0 +1,227 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import torch +import numpy as np + +from typing import Dict, List, Optional, Any, Union + +from embodichain.lab.sim.cfg import ( + RobotCfg, + URDFCfg, + JointDrivePropertiesCfg, + RigidBodyAttributesCfg, +) +from embodichain.lab.sim.solvers import SolverCfg, OPWSolverCfg +from embodichain.data import get_data_path +from embodichain.utils import configclass +from embodichain.utils import logger + + +@configclass +class CobotMagicCfg(RobotCfg): + urdf_cfg: URDFCfg = None + control_parts: Optional[Dict[str, List[str]]] = None + solver_cfg: Optional[Dict[str, "SolverCfg"]] = None + + @classmethod + def from_dict(cls, init_dict: Dict[str, Union[str, float, int]]) -> CobotMagicCfg: + from embodichain.lab.sim.solvers import merge_solver_cfg + + cfg = cls() + default_cfgs = cls()._build_default_cfgs() + for key, value in default_cfgs.items(): + setattr(cfg, key, value) + + robot_cfg = RobotCfg.from_dict(init_dict) + + # set attrs into cfg from the robot_cfg + for key, value in init_dict.items(): + if key == "solver_cfg": + # merge provided solver_cfg values into default solver config + provided_solver_cfg = init_dict.get("solver_cfg") + if provided_solver_cfg: + for part, item in provided_solver_cfg.items(): + if "class_type" in provided_solver_cfg[part]: + cfg.solver_cfg[part] = robot_cfg.solver_cfg[part] + else: + try: + merged = merge_solver_cfg( + cfg.solver_cfg, provided_solver_cfg + ) + cfg.solver_cfg = merged + except Exception: + logger.log_error( + f"Failed to merge solver_cfg, using provided config outright." + ) + else: + setattr(cfg, key, getattr(robot_cfg, key)) + + return cfg + + @staticmethod + def _build_default_cfgs() -> Dict[str, Any]: + arm_urdf = get_data_path("CobotMagicArm/CobotMagicWithGripperV100.urdf") + left_arm_xpos = np.array( + [ + [1.0, 0.0, 0.0, 0.233], + [0.0, 1.0, 0.0, 0.300], + [0.0, 0.0, 1.0, 0.000], + [0.0, 0.0, 0.0, 1.000], + ] + ) + right_arm_xpos = np.array( + [ + [1.0, 0.0, 0.0, 0.233], + [0.0, 1.0, 0.0, -0.300], + [0.0, 0.0, 1.0, 0.000], + [0.0, 0.0, 0.0, 1.000], + ] + ) + urdf_cfg = URDFCfg( + components=[ + { + "component_type": "left_arm", + "urdf_path": arm_urdf, + "transform": left_arm_xpos, + }, + { + "component_type": "right_arm", + "urdf_path": arm_urdf, + "transform": right_arm_xpos, + }, + ] + ) + return { + "uid": "CobotMagic", + "urdf_cfg": urdf_cfg, + "control_parts": { + "left_arm": [ + "LEFT_JOINT1", + "LEFT_JOINT2", + "LEFT_JOINT3", + "LEFT_JOINT4", + "LEFT_JOINT5", + "LEFT_JOINT6", + ], + "left_eef": ["LEFT_JOINT7", "LEFT_JOINT8"], + "right_arm": [ + "RIGHT_JOINT1", + "RIGHT_JOINT2", + "RIGHT_JOINT3", + "RIGHT_JOINT4", + "RIGHT_JOINT5", + "RIGHT_JOINT6", + ], + "right_eef": ["RIGHT_JOINT7", "RIGHT_JOINT8"], + }, + "solver_cfg": { + "left_arm": OPWSolverCfg( + end_link_name="left_link6", + root_link_name="left_arm_base", + tcp=np.array( + [[-1, 0, 0, 0], [0, -1, 0, 0], [0, 0, 1, 0.143], [0, 0, 0, 1]] + ), + ), + "right_arm": OPWSolverCfg( + end_link_name="right_link6", + root_link_name="right_arm_base", + tcp=np.array( + [[-1, 0, 0, 0], [0, -1, 0, 0], [0, 0, 1, 0.143], [0, 0, 0, 1]] + ), + ), + }, + "min_position_iters": 8, + "min_velocity_iters": 2, + "drive_pros": JointDrivePropertiesCfg( + stiffness={ + "LEFT_JOINT[1-6]": 7e4, + "RIGHT_JOINT[1-6]": 7e4, + "LEFT_JOINT[7-8]": 3e2, + "RIGHT_JOINT[7-8]": 3e2, + }, + damping={ + "LEFT_JOINT[1-6]": 1e3, + "RIGHT_JOINT[1-6]": 1e3, + "LEFT_JOINT[7-8]": 3e1, + "RIGHT_JOINT[7-8]": 3e1, + }, + max_effort={ + "LEFT_JOINT[1-6]": 3e6, + "RIGHT_JOINT[1-6]": 3e6, + "LEFT_JOINT[7-8]": 3e3, + "RIGHT_JOINT[7-8]": 3e3, + }, + ), + "attrs": RigidBodyAttributesCfg( + mass=0.1, + static_friction=0.95, + dynamic_friction=0.9, + linear_damping=0.7, + angular_damping=0.7, + contact_offset=0.005, + rest_offset=0.001, + restitution=0.01, + max_depenetration_velocity=1e1, + ), + } + + def build_pk_serial_chain( + self, device: torch.device = torch.device("cpu"), **kwargs + ) -> Dict[str, "pk.SerialChain"]: + from embodichain.lab.sim.utility.solver_utils import ( + create_pk_chain, + create_pk_serial_chain, + ) + + urdf_path = get_data_path("CobotMagicArm/CobotMagicNoGripper.urdf") + chain = create_pk_chain(urdf_path, device) + + left_arm_chain = create_pk_serial_chain( + chain=chain, end_link_name="link6", root_link_name="base_link" + ).to(device=device) + right_arm_chain = create_pk_serial_chain( + chain=chain, end_link_name="link6", root_link_name="base_link" + ).to(device=device) + return {"left_arm": left_arm_chain, "right_arm": right_arm_chain} + + +if __name__ == "__main__": + from embodichain.lab.sim import SimulationManager, SimulationManagerCfg + from embodichain.lab.sim.robots import CobotMagicCfg + + torch.set_printoptions(precision=5, sci_mode=False) + + config = SimulationManagerCfg(headless=False, sim_device="cuda") + sim = SimulationManager(config) + sim.build_multiple_arenas(2) + sim.set_manual_update(True) + + config = { + "init_pos": [0.0, 0.0, 1.0], + } + + cfg = CobotMagicCfg.from_dict(config) + robot = sim.add_robot(cfg=cfg) + + sim.init_gpu_physics() + print("CobotMagic added to the simulation.") + + from IPython import embed + + embed() diff --git a/embodichain/lab/sim/robots/dexforce_w1/__init__.py b/embodichain/lab/sim/robots/dexforce_w1/__init__.py new file mode 100644 index 00000000..5aee21db --- /dev/null +++ b/embodichain/lab/sim/robots/dexforce_w1/__init__.py @@ -0,0 +1,17 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .cfg import DexforceW1Cfg diff --git a/embodichain/lab/sim/robots/dexforce_w1/cfg.py b/embodichain/lab/sim/robots/dexforce_w1/cfg.py new file mode 100644 index 00000000..c049a071 --- /dev/null +++ b/embodichain/lab/sim/robots/dexforce_w1/cfg.py @@ -0,0 +1,341 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import enum +import json +import numpy as np +import typing +import torch + +from typing import Dict + +from embodichain.lab.sim.robots.dexforce_w1.types import ( + DexforceW1HandBrand, + DexforceW1ArmSide, + DexforceW1ArmKind, + DexforceW1Version, +) +from embodichain.lab.sim.robots.dexforce_w1.utils import ( + build_dexforce_w1_cfg, +) +from embodichain.lab.sim.solvers import SolverCfg +from embodichain.lab.sim.cfg import ( + RobotCfg, + JointDrivePropertiesCfg, + RigidBodyAttributesCfg, +) +from embodichain.data import get_data_path +from embodichain.utils import configclass, logger + + +@configclass +class DexforceW1Cfg(RobotCfg): + """DexforceW1 specific configuration, inherits from RobotCfg and allows custom parameters.""" + + version: DexforceW1Version = DexforceW1Version.V021 + arm_kind: DexforceW1ArmKind = DexforceW1ArmKind.INDUSTRIAL + + @classmethod + def from_dict( + cls, init_dict: typing.Dict[str, typing.Union[str, float, tuple]] + ) -> DexforceW1Cfg: + """Initialize DexforceW1Cfg from a dictionary. + + Args: + init_dict (Dict[str, Union[str, float, tuple]]): Dictionary of configuration parameters. + + Returns: + DexforceW1Cfg: An instance of DexforceW1Cfg with parameters set. + """ + from embodichain.lab.sim.solvers import merge_solver_cfg + + init_dict_m = init_dict.copy() + version = init_dict_m.get("version", "v021") + arm_kind = init_dict_m.get("arm_kind", "anthropomorphic") + init_dict_m.pop("version", None) + init_dict_m.pop("arm_kind", None) + cfg: DexforceW1Cfg = cls()._build_default_cfg( + version=version, arm_kind=arm_kind + ) + + default_physics_cfgs = cls()._build_default_physics_cfgs() + for key, value in default_physics_cfgs.items(): + setattr(cfg, key, value) + + default_solver_cfg = cls()._build_default_solver_cfg( + is_industrial=(arm_kind == "industrial") + ) + cfg.solver_cfg = default_solver_cfg + + # override default values with those provided in init_dict. + robot_cfg = RobotCfg.from_dict(init_dict_m) + + # set attrs into cfg from the robot_cfg, but merge solver_cfg specially + for key, value in init_dict_m.items(): + if key == "solver_cfg": + # merge provided solver_cfg values into default solver config + provided_solver_cfg = init_dict_m.get("solver_cfg") + if provided_solver_cfg: + for part, item in provided_solver_cfg.items(): + if "class_type" in provided_solver_cfg[part]: + cfg.solver_cfg[part] = robot_cfg.solver_cfg[part] + else: + try: + merged = merge_solver_cfg( + cfg.solver_cfg, provided_solver_cfg + ) + cfg.solver_cfg = merged + except Exception: + logger.log_error( + f"Failed to merge solver_cfg, using provided config outright." + ) + else: + setattr(cfg, key, getattr(robot_cfg, key)) + + return cfg + + @staticmethod + def _build_default_solver_cfg(is_industrial: bool) -> SolverCfg: + # TODO: maybe change default solver for DexforceW1 + from embodichain.lab.sim.solvers import PytorchSolverCfg + from embodichain.lab.sim.solvers import SRSSolverCfg + from embodichain.lab.sim.robots.dexforce_w1.params import ( + W1ArmKineParams, + ) + + if is_industrial: + w1_left_arm_params = W1ArmKineParams( + arm_side=DexforceW1ArmSide.LEFT, + arm_kind=DexforceW1ArmKind.INDUSTRIAL, + version=DexforceW1Version.V021, + ) + w1_right_arm_params = W1ArmKineParams( + arm_side=DexforceW1ArmSide.RIGHT, + arm_kind=DexforceW1ArmKind.INDUSTRIAL, + version=DexforceW1Version.V021, + ) + else: + w1_left_arm_params = W1ArmKineParams( + arm_side=DexforceW1ArmSide.LEFT, + arm_kind=DexforceW1ArmKind.ANTHROPOMORPHIC, + version=DexforceW1Version.V021, + ) + w1_right_arm_params = W1ArmKineParams( + arm_side=DexforceW1ArmSide.RIGHT, + arm_kind=DexforceW1ArmKind.ANTHROPOMORPHIC, + version=DexforceW1Version.V021, + ) + + return { + "right_arm": SRSSolverCfg( + end_link_name="right_ee", + root_link_name="right_arm_base", + dh_params=w1_right_arm_params.dh_params, + qpos_limits=w1_right_arm_params.qpos_limits, + T_e_oe=w1_right_arm_params.T_e_oe, + T_b_ob=w1_right_arm_params.T_b_ob, + link_lengths=w1_right_arm_params.link_lengths, + rotation_directions=w1_right_arm_params.rotation_directions, + tcp=np.array( + [ + [1.0, 0.0, 0.0, 0.012], + [0.0, 0.0, -1.0, -0.0675], + [0.0, 1.0, 0.0, 0.127], + [0.0, 0.0, 0.0, 1.0], + ] + ), + ), + "left_arm": SRSSolverCfg( + end_link_name="left_ee", + root_link_name="left_arm_base", + dh_params=w1_left_arm_params.dh_params, + qpos_limits=w1_left_arm_params.qpos_limits, + T_e_oe=w1_left_arm_params.T_e_oe, + T_b_ob=w1_left_arm_params.T_b_ob, + link_lengths=w1_left_arm_params.link_lengths, + rotation_directions=w1_left_arm_params.rotation_directions, + tcp=np.array( + [ + [-1.0, 0.0, 0.0, 0.012], + [0.0, 0.0, 1.0, 0.0675], + [0.0, 1.0, 0.0, 0.127], + [0.0, 0.0, 0.0, 1.0], + ] + ), + ), + } + + @staticmethod + def _build_default_physics_cfgs() -> typing.Dict[str, any]: + return { + "min_position_iters": 32, + "min_velocity_iters": 8, + "drive_pros": JointDrivePropertiesCfg( + stiffness={ + "(RIGHT|LEFT)_J[0-9]": 1e4, + "(RIGHT|LEFT)_[A-Z|_]+": 1e2, + "(ANKLE|KNEE|BUTTOCK|WAIST)": 1e7, + }, + damping={ + "(RIGHT|LEFT)_J[0-2]": 1e3, + "(RIGHT|LEFT)_[A-Z|_]+": 1e1, + "(ANKLE|KNEE|BUTTOCK|WAIST)": 1e4, + }, + max_effort={ + "(RIGHT|LEFT)_J[0-9]": 1e5, + "(RIGHT|LEFT)_[A-Z|_]+": 1e3, + "(ANKLE|KNEE|BUTTOCK|WAIST)": 1e10, + }, + ), + # TODO: we may use the some properties from URDF as default values + # eg. mass, friction, damping, etc. + "attrs": RigidBodyAttributesCfg( + mass=1.0, + static_friction=0.95, + dynamic_friction=0.9, + linear_damping=0.7, + angular_damping=0.7, + contact_offset=0.005, + rest_offset=0.001, + restitution=0.05, + max_depenetration_velocity=10.0, + ), + } + + @staticmethod + def _build_default_cfg( + version: str = "v021", arm_kind: str = "anthropomorphic" + ) -> DexforceW1Cfg: + hand_types = { + DexforceW1ArmSide.LEFT: DexforceW1HandBrand.BRAINCO_HAND, + DexforceW1ArmSide.RIGHT: DexforceW1HandBrand.BRAINCO_HAND, + } + hand_versions = { + DexforceW1ArmSide.LEFT: DexforceW1Version(version), + DexforceW1ArmSide.RIGHT: DexforceW1Version(version), + } + + cfg = build_dexforce_w1_cfg( + arm_kind=DexforceW1ArmKind(arm_kind), + hand_types=hand_types, + hand_versions=hand_versions, + ) + cfg.version = DexforceW1Version(version) + cfg.arm_kind = DexforceW1ArmKind(arm_kind) + + return cfg + + def to_dict(self): + """Convert config to a Python dict, handling enums and numpy arrays.""" + + def serialize(obj, _visited=None): + if _visited is None: + _visited = set() + # Only skip recursion for mutable objects (dict, custom class) + if isinstance(obj, (dict, object)) and not isinstance( + obj, (str, int, float, bool, type(None)) + ): + obj_id = id(obj) + if obj_id in _visited: + return None # Prevent infinite recursion + _visited.add(obj_id) + + if isinstance(obj, enum.Enum): + return obj.value + if isinstance(obj, np.ndarray): + return obj.tolist() + if isinstance(obj, dict): + # Only serialize values, keep keys as str/int/float/bool/None + return {str(k): serialize(v, _visited) for k, v in obj.items()} + if isinstance(obj, (list, tuple)): + return [serialize(v, _visited) for v in obj] + if hasattr(obj, "to_dict") and obj is not self: + return serialize(obj.to_dict(), _visited) + if hasattr(obj, "__dict__"): + return {k: serialize(v, _visited) for k, v in obj.__dict__.items()} + return obj + + return serialize(self) + + def to_string(self): + """Return config as a JSON string.""" + return json.dumps(self.to_dict(), indent=2) + + def save_to_file(self, filepath): + """Save config to a local file as JSON.""" + with open(filepath, "w") as f: + f.write(self.to_string()) + + def build_pk_serial_chain( + self, device: torch.device = torch.device("cpu"), **kwargs + ) -> Dict[str, "pk.SerialChain"]: + from embodichain.lab.sim.utility.solver_utils import ( + create_pk_chain, + create_pk_serial_chain, + ) + + if DexforceW1ArmKind.INDUSTRIAL == self.arm_kind: + urdf_path = get_data_path("DexforceW1V021/DexforceW1_v02_2.urdf") + elif DexforceW1ArmKind.ANTHROPOMORPHIC == self.arm_kind: + urdf_path = get_data_path("DexforceW1V021/DexforceW1_v02_1.urdf") + + chain = create_pk_chain(urdf_path, device) + + left_arm_chain = create_pk_serial_chain( + chain=chain, end_link_name="left_ee", root_link_name="left_arm_base" + ).to(device=device) + right_arm_chain = create_pk_serial_chain( + chain=chain, end_link_name="right_ee", root_link_name="right_arm_base" + ).to(device=device) + + return { + "left_arm": left_arm_chain, + "right_arm": right_arm_chain, + } + + +if __name__ == "__main__": + # Example usage + import numpy as np + + np.set_printoptions(precision=5, suppress=True) + from embodichain.lab.sim import SimulationManager, SimulationManagerCfg + from embodichain.lab.sim.robots.dexforce_w1.types import ( + DexforceW1ArmKind, + ) + + config = SimulationManagerCfg(headless=True, sim_device="cpu") + sim = SimulationManager(config) + sim.build_multiple_arenas(1) + sim.set_manual_update(True) + + cfg = DexforceW1Cfg.from_dict( + { + "uid": "dexforce_w1", + "version": "v021", + "arm_kind": "anthropomorphic", + } + ) + + robot = sim.add_robot(cfg=cfg) + sim.update(step=1) + print("DexforceW1 robot added to the simulation.") + + from IPython import embed + + embed() diff --git a/embodichain/lab/sim/robots/dexforce_w1/params.py b/embodichain/lab/sim/robots/dexforce_w1/params.py new file mode 100644 index 00000000..6dfdf349 --- /dev/null +++ b/embodichain/lab/sim/robots/dexforce_w1/params.py @@ -0,0 +1,269 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np +from typing import Optional +from dataclasses import dataclass, field +from embodichain.lab.sim.robots.dexforce_w1.types import ( + DexforceW1HandBrand, + DexforceW1ArmSide, + DexforceW1ArmKind, + DexforceW1Version, +) + + +@dataclass +class W1ArmKineParams: + """Kinematics parameters for W1 arm variants. + + - arm_kind and W1Version enum types expected to be defined elsewhere. + - dh_params stored as numpy array of shape (7,4). + - qpos_limits stored as numpy array of shape (7,2) in radians. + """ + + arm_side: "DexforceW1ArmSide" + arm_kind: "DexforceW1ArmKind" + version: "DexforceW1Version" = field(default_factory=lambda: DexforceW1Version.V021) + + # (initialized in __post_init__) + # physical constants + d_list: list[float] = field(init=False, default_factory=list) + link_lengths: list[float] = field(init=False, default_factory=list) + rotation_directions: list[float] = field(init=False, default_factory=list) + + # transforms + T_b_ob: np.ndarray = field(init=False) + T_e_oe: np.ndarray = field(init=False) + + # kinematic parameters + dh_params: np.ndarray = field(init=False) + qpos_limits: np.ndarray = field(init=False) + + def __post_init__(self): + if self.version == DexforceW1Version.V021: + self.d_list = np.array([0.0, 0.0, 0.260, 0.0, 0.166, 0.098, 0.0]) + self.link_lengths = np.array( + [ + self.d_list[0] + self.d_list[1], + self.d_list[2] + self.d_list[3], + self.d_list[4] + self.d_list[5], + self.d_list[6], + ] + ) + else: + raise ValueError(f"W1Version {self.version} are not supported.") + + # helpers: create DH rows and clamp limits + def dh_row(d, alpha, a, theta): + return [d, alpha, a, theta] + + def deg2rad_list(list_of_pairs): + return np.deg2rad(np.array(list_of_pairs, dtype=float)) + + T_b_ob = np.array( + [ + [1.0, 0.0, 0.0, 0.0], + [0.0, 1.0, 0.0, 0.0], + [0.0, 0.0, 1.0, 0.1025], + [0.0, 0.0, 0.0, 1.0], + ] + ) + # Build parameters per arm_kind and side, minimizing duplication + if self.arm_kind == DexforceW1ArmKind.INDUSTRIAL: + # default tcp for industrial + T_e_oe = np.array( + [ + [-1.0, 0.0, 0.0, 0.0], + [0.0, -1.0, 0.0, 0.0], + [0.0, 0.0, 1.0, 0.066], + [0.0, 0.0, 0.0, 1.0], + ] + ) + + # fmt: off + dh = [ + dh_row(self.link_lengths[0], -np.pi / 2, 0.0, 0.0), + dh_row(0.0, np.pi / 2, 0.0, 0.0), + dh_row(self.link_lengths[1], np.pi / 2, 0.0, np.pi / 2), + dh_row(0.0, -np.pi / 2, 0.0, 0.0), + dh_row(self.link_lengths[2], -np.pi / 2, 0.0, 0.0), + dh_row(0.0, np.pi / 2, 0.0, 0.0), + dh_row(self.link_lengths[3], 0.0, 0.0, 0.0), + ] + + # fmt: on + if self.arm_side == DexforceW1ArmSide.LEFT: + limits = [ + [-170.0, 170.0], + [-120.0, 90.0], + [-170.0, 170.0], + [-135.0, 90.0], + [-170.0, 170.0], + [-90.0, 90.0], + [-170.0, 170.0], + ] + rotation_directions = np.array([1, 1, 1, 1, 1, -1, 1]) + else: + limits = [ + [-170.0, 170.0], + [-90.0, 120.0], + [-170.0, 170.0], + [-90.0, 135.0], + [-170.0, 170.0], + [-90.0, 90.0], + [-170.0, 170.0], + ] + rotation_directions = np.array([1, 1, 1, -1, 1, 1, 1]) + + self.T_e_oe = T_e_oe + + elif self.arm_kind == DexforceW1ArmKind.ANTHROPOMORPHIC: + T_e_oe = np.array( + [ + [0.0, 0.0, -1.0, -0.066], + [0.0, 1.0, 0.0, 0.0], + [1.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 1.0], + ] + ) + # fmt: off + dh = [ + dh_row(self.link_lengths[0], -np.pi / 2, 0.0, 0.0), + dh_row(0.0, np.pi / 2, 0.0, 0.0), + dh_row(self.link_lengths[1], np.pi / 2, 0.0, np.pi / 2), + dh_row(0.0, -np.pi / 2, 0.0, 0.0), + dh_row(self.link_lengths[2], -np.pi / 2, 0.0, 0.0), + dh_row(0.0, np.pi / 2, 0.0, np.pi / 2), + dh_row(self.link_lengths[3], 0.0, 0.0, 0.0), + ] + # fmt: on + + if self.arm_side == DexforceW1ArmSide.LEFT: + limits = [ + [-170.0, 170.0], + [-120.0, 90.0], + [-170.0, 170.0], + [-135.0, 90.0], + [-170.0, 170.0], + [-45.0, 45.0], + [-90.0, 60.0], + ] + rotation_directions = np.array([1, 1, 1, 1, 1, -1, 1]) + else: + limits = [ + [-170.0, 170.0], + [-90.0, 120.0], + [-170.0, 170.0], + [-90.0, 135.0], + [-170.0, 170.0], + [-45.0, 45.0], + [-60.0, 90.0], + ] + rotation_directions = np.array([1, 1, 1, -1, 1, 1, 1]) + else: + raise ValueError(f"Unsupported arm_kind: {self.arm_kind}") + + self.T_b_ob = T_b_ob + self.T_e_oe = T_e_oe + + # finalize arrays + self.dh_params = np.array(dh, dtype=float) + self.qpos_limits = deg2rad_list(limits) + self.rotation_directions = rotation_directions + + # sanity checks + assert self.dh_params.shape == (7, 4), "dh_params must be shape (7,4)" + assert self.qpos_limits.shape == (7, 2), "qpos_limits must be shape (7,2)" + + def as_dict(self) -> dict: + return { + "arm_side": self.arm_side.name, + "arm_kind": self.arm_kind.name, + "version": self.version.name, + "link_lengths": self.link_lengths.tolist(), + "T_b_ob": self.T_b_ob.tolist(), + "T_e_oe": self.T_e_oe.tolist(), + "dh_params": self.dh_params.tolist(), + "qpos_limits": self.qpos_limits.tolist(), + "rotation_directions": self.rotation_directions.tolist(), + } + + @classmethod + def from_dict(cls, data: dict) -> "W1ArmKineParams": + arm_side = ( + DexforceW1ArmSide[data["arm_side"]] + if isinstance(data.get("arm_side"), str) + else data.get("arm_side") + ) + + arm_kind = ( + DexforceW1ArmKind[data["arm_kind"]] + if isinstance(data.get("arm_kind"), str) + else data.get("arm_kind") + ) + version = ( + DexforceW1Version[data["version"]] + if isinstance(data.get("version"), str) + else data.get("version", DexforceW1Version.V021) + ) + inst = cls(arm_side=arm_side, arm_kind=arm_kind, version=version) + + # allow overriding computed arrays if provided + if "dh_params" in data: + object.__setattr__( + inst, "dh_params", np.array(data["dh_params"], dtype=float) + ) + if "qpos_limits" in data: + object.__setattr__( + inst, + "qpos_limits", + np.deg2rad(np.array(data["qpos_limits"], dtype=float)), + ) if np.max( + np.abs(np.array(data["qpos_limits"])) + ) > 2 * np.pi else object.__setattr__( + inst, "qpos_limits", np.array(data["qpos_limits"], dtype=float) + ) + if "link_lengths" in data: + object.__setattr__( + inst, "link_lengths", np.array(data["link_lengths"], dtype=float) + ) + if "T_b_ob" in data: + object.__setattr__(inst, "T_b_ob", np.array(data["T_b_ob"], dtype=float)) + if "T_e_oe" in data: + object.__setattr__(inst, "T_e_oe", np.array(data["T_e_oe"], dtype=float)) + if "rotation_directions" in data: + object.__setattr__( + inst, + "rotation_directions", + np.array(data["rotation_directions"], dtype=float), + ) + inst.validate() + return inst + + def to_torch( + self, device: Optional[torch.device] = None, dtype: torch.dtype = torch.float32 + ) -> dict: + dev = torch.device("cpu") if device is None else device + return { + "dh_params": torch.tensor(self.dh_params, dtype=dtype, device=dev), + "qpos_limits": torch.tensor(self.qpos_limits, dtype=dtype, device=dev), + "T_b_ob": torch.tensor(self.T_b_ob, dtype=dtype, device=dev), + "T_e_oe": torch.tensor(self.T_e_oe, dtype=dtype, device=dev), + "rotation_directions": torch.tensor( + self.rotation_directions, dtype=dtype, device=dev + ), + } diff --git a/embodichain/lab/sim/robots/dexforce_w1/types.py b/embodichain/lab/sim/robots/dexforce_w1/types.py new file mode 100644 index 00000000..939dde31 --- /dev/null +++ b/embodichain/lab/sim/robots/dexforce_w1/types.py @@ -0,0 +1,66 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import enum + +all = [ + "DexforceW1Version", + "DexforceW1ArmKind", + "DexforceW1ArmSide", + "DexforceW1Type", +] + + +class DexforceW1Version(enum.Enum): + """Versioning for DexforceW1 components.""" + + V021 = "v021" + + +class DexforceW1ArmKind(enum.Enum): + """Arm type for DexforceW1: anthropomorphic or industrial.""" + + ANTHROPOMORPHIC = "anthropomorphic" + INDUSTRIAL = "industrial" + + +class DexforceW1ArmSide(enum.Enum): + """Arm side for DexforceW1: left or right.""" + + LEFT = "left" + RIGHT = "right" + + +class DexforceW1Type(enum.Enum): + """Component type for DexforceW1.""" + + CHASSIS = "chassis" + TORSO = "torso" + EYES = "eyes" + HEAD = "head" + LEFT_ARM1 = "left_arm" # Anthropomorphic left arm + RIGHT_ARM1 = "right_arm" # Anthropomorphic right arm + LEFT_ARM2 = "left_arm2" # Industrial left arm + RIGHT_ARM2 = "right_arm2" # Industrial right arm + LEFT_HAND = "left_hand" + RIGHT_HAND = "right_hand" + FULL_BODY = "full_body" # Full robot + + +class DexforceW1HandBrand(enum.Enum): + BRAINCO_HAND = "BRAINCO_HAND" + DH_PGC_GRIPPER = "DH_PGC_GRIPPER" + DH_PGC_GRIPPER_M = "DH_PGC_GRIPPER_M" diff --git a/embodichain/lab/sim/robots/dexforce_w1/utils.py b/embodichain/lab/sim/robots/dexforce_w1/utils.py new file mode 100644 index 00000000..1bfbeb6d --- /dev/null +++ b/embodichain/lab/sim/robots/dexforce_w1/utils.py @@ -0,0 +1,746 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +import numpy as np +from scipy.spatial.transform import Rotation as R +from typing import List, Dict, Optional + +from embodichain.lab.sim.robots.dexforce_w1.types import ( + DexforceW1ArmKind, + DexforceW1Type, + DexforceW1ArmSide, + DexforceW1Version, + DexforceW1HandBrand, +) +from embodichain.data import get_data_path +from embodichain.lab.sim.solvers import SolverCfg +from embodichain.lab.sim.cfg import RobotCfg, URDFCfg + + +all = [ + "ChassisManager", + "TorsoManager", + "HeadManager", + "ArmManager", + "HandManager", + "EyesManager", + "build_dexforce_w1_assembly_urdf_cfg", + "build_dexforce_w1_cfg", +] + + +class ChassisManager: + def __init__(self): + self.urdf_paths = { + DexforceW1Version.V021: get_data_path("DexforceW1ChassisV021/chassis.urdf"), + } + + def get_urdf(self, version=DexforceW1Version.V021): + return self.urdf_paths[version] + + def get_config(self, version=DexforceW1Version.V021): + return { + "urdf_path": self.get_urdf(version), + "joint_names": [], + "end_link_name": "base_link", + "root_link_name": "base_link", + } + + +class TorsoManager: + def __init__(self): + self.urdf_paths = { + DexforceW1Version.V021: get_data_path("DexforceW1TorsoV021/torso.urdf"), + } + self.joint_names = ["ANKLE", "KNEE", "BUTTOCK", "WAIST"] + + def get_urdf(self, version=DexforceW1Version.V021): + return self.urdf_paths[version] + + def get_config(self, version=DexforceW1Version.V021): + return { + "urdf_path": self.get_urdf(version), + "joint_names": self.joint_names, + "end_link_name": "waist", + "root_link_name": "base_link", + } + + +class HeadManager: + def __init__(self): + self.urdf_paths = { + DexforceW1Version.V021: get_data_path("DexforceW1HeadV021/head.urdf"), + } + self.joint_names = ["NECK1", "NECK2"] + + def get_urdf(self, version=DexforceW1Version.V021): + return self.urdf_paths[version] + + def get_config(self, version=DexforceW1Version.V021): + return { + "urdf_path": self.get_urdf(version), + "joint_names": self.joint_names, + "end_link_name": "neck2", + "root_link_name": "neck1", + } + + +class EyesManager: + def __init__(self): + self.urdf_paths = { + DexforceW1Version.V021: get_data_path("DexforceW1EyesV021/eyes.urdf"), + } + + def get_urdf(self, version=DexforceW1Version.V021): + return self.urdf_paths[version] + + def get_config(self, version=DexforceW1Version.V021): + return { + "urdf_path": self.get_urdf(version), + "joint_names": [], + "end_link_name": "eyes", + "root_link_name": "base_link", + } + + +class ArmManager: + def __init__(self): + self.urdf_paths = { + ( + DexforceW1ArmKind.ANTHROPOMORPHIC, + DexforceW1ArmSide.LEFT, + DexforceW1Version.V021, + ): get_data_path("DexforceW1LeftArm1V021/left_arm.urdf"), + ( + DexforceW1ArmKind.ANTHROPOMORPHIC, + DexforceW1ArmSide.RIGHT, + DexforceW1Version.V021, + ): get_data_path("DexforceW1RightArm1V021/right_arm.urdf"), + ( + DexforceW1ArmKind.INDUSTRIAL, + DexforceW1ArmSide.LEFT, + DexforceW1Version.V021, + ): get_data_path("DexforceW1LeftArm2V021/left_arm.urdf"), + ( + DexforceW1ArmKind.INDUSTRIAL, + DexforceW1ArmSide.RIGHT, + DexforceW1Version.V021, + ): get_data_path("DexforceW1RightArm2V021/right_arm.urdf"), + } + + def get_urdf(self, kind, side, version=DexforceW1Version.V021): + return self.urdf_paths[(kind, side, version)] + + def get_config(self, kind, side, version=DexforceW1Version.V021): + prefix = "LEFT" if side == DexforceW1ArmSide.LEFT else "RIGHT" + return { + "urdf_path": self.get_urdf(kind, side, version), + "joint_names": [f"{prefix}_J{i}" for i in range(1, 8)], + "end_link_name": f"{prefix.lower()}_ee", + "root_link_name": f"{prefix.lower()}_arm_base", + } + + +class HandManager: + def __init__(self): + self.urdf_paths = { + ( + DexforceW1HandBrand.BRAINCO_HAND, + DexforceW1ArmSide.LEFT, + DexforceW1Version.V021, + ): get_data_path("BrainCoHandRevo1/BrainCoLeftHand/BrainCoLeftHand.urdf"), + ( + DexforceW1HandBrand.BRAINCO_HAND, + DexforceW1ArmSide.RIGHT, + DexforceW1Version.V021, + ): get_data_path("BrainCoHandRevo1/BrainCoRightHand/BrainCoRightHand.urdf"), + ( + DexforceW1HandBrand.DH_PGC_GRIPPER, + DexforceW1ArmSide.LEFT, + DexforceW1Version.V021, + ): get_data_path("DH_PGC_140_50/DH_PGC_140_50.urdf"), + ( + DexforceW1HandBrand.DH_PGC_GRIPPER, + DexforceW1ArmSide.RIGHT, + DexforceW1Version.V021, + ): get_data_path("DH_PGC_140_50/DH_PGC_140_50.urdf"), + ( + DexforceW1HandBrand.DH_PGC_GRIPPER_M, + DexforceW1ArmSide.LEFT, + DexforceW1Version.V021, + ): get_data_path("DH_PGC_140_50_M/DH_PGC_140_50_M.urdf"), + ( + DexforceW1HandBrand.DH_PGC_GRIPPER_M, + DexforceW1ArmSide.RIGHT, + DexforceW1Version.V021, + ): get_data_path("DH_PGC_140_50_M/DH_PGC_140_50_M.urdf"), + } + + def get_config( + self, + brand: DexforceW1HandBrand, + side: DexforceW1ArmSide, + version: DexforceW1Version = DexforceW1Version.V021, + ): + prefix = "LEFT" if side == DexforceW1ArmSide.LEFT else "RIGHT" + if brand == DexforceW1HandBrand.BRAINCO_HAND: + if side == DexforceW1ArmSide.LEFT: + base_link_name = f"{prefix.lower()}_hand_base" + root_link_name = f"{prefix.lower()}_thumb_dist" + joint_names = [ + f"{prefix}_HAND_THUMB1", # Left thumb flexion + f"{prefix}_HAND_THUMB2", # Left thumb abduction/adduction + f"{prefix}_HAND_INDEX", # Left index finger flexion + f"{prefix}_HAND_MIDDLE", # Left middle finger flexion + f"{prefix}_HAND_RING", # Left ring finger flexion + f"{prefix}_HAND_PINKY", # Left pinky finger flexion + ] + else: + base_link_name = f"{prefix.lower()}_hand_base" + root_link_name = f"{prefix.lower()}_thumb_dist" + joint_names = [ + f"{prefix}_HAND_THUMB1", # Right thumb flexion + f"{prefix}_HAND_THUMB2", # Right thumb abduction/adduction + f"{prefix}_HAND_INDEX", # Right index finger flexion + f"{prefix}_HAND_MIDDLE", # Right middle finger flexion + f"{prefix}_HAND_RING", # Right ring finger flexion + f"{prefix}_HAND_PINKY", # Right pinky finger flexion + ] + elif brand == DexforceW1HandBrand.DH_PGC_GRIPPER: + base_link_name = f"{prefix.lower()}_base_link_1" + root_link_name = (f"{prefix.lower()}_finger2_link",) + joint_names = [f"{prefix}_FINGER1_JOINT", f"{prefix}_FINGER2_JOINT"] + elif brand == DexforceW1HandBrand.DH_PGC_GRIPPER_M: + base_link_name = f"{prefix.lower()}_base_link_1" + root_link_name = (f"{prefix.lower()}_finger2",) + joint_names = [f"{prefix}_FINGER1", f"{prefix}_FINGER2"] + else: + raise ValueError(f"Unknown hand brand: {brand}") + + return { + "urdf_path": self.get_urdf(brand, side, version), + "joint_names": joint_names, + "end_link_name": base_link_name, + "root_link_name": root_link_name, + } + + def get_urdf( + self, + brand: DexforceW1HandBrand, + side: DexforceW1ArmSide, + version: DexforceW1Version = DexforceW1Version.V021, + ): + return self.urdf_paths[(brand, side, version)] + + def get_attach_xpos( + self, + brand: DexforceW1HandBrand, + arm_kind: DexforceW1ArmKind = DexforceW1ArmKind.INDUSTRIAL, + is_left: bool = True, + ): + if brand == DexforceW1HandBrand.BRAINCO_HAND: + rot_params = { + (DexforceW1ArmKind.INDUSTRIAL, True): [90, 0, 0], + (DexforceW1ArmKind.INDUSTRIAL, False): [90, 0, 180], + (DexforceW1ArmKind.ANTHROPOMORPHIC, True): [90, 0, 180], + (DexforceW1ArmKind.ANTHROPOMORPHIC, False): [90, 0, 0], + } + attach_xpos = np.eye(4) + rot = R.from_euler("xyz", rot_params[(arm_kind, is_left)], degrees=True) + attach_xpos[:3, :3] = rot.as_matrix() + attach_xpos[2, 3] = 0.0 + return attach_xpos + elif brand == DexforceW1HandBrand.DH_PGC_GRIPPER: + attach_xpos = np.array( + [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.015], [0, 0, 0, 1]] + ) + attach_xpos[:3, :3] = ( + attach_xpos[:3, :3] + @ R.from_rotvec([0, 0, 90], degrees=True).as_matrix() + ) + return attach_xpos + elif brand == DexforceW1HandBrand.DH_PGC_GRIPPER_M: + attach_xpos = np.eye(4) + attach_xpos[:3, :3] = ( + attach_xpos[:3, :3] + @ R.from_rotvec([0, 0, 90], degrees=True).as_matrix() + ) + return attach_xpos + else: + raise ValueError(f"Unknown brand: {brand}") + + +eyes_manager = EyesManager() +chassis_manager = ChassisManager() +torso_manager = TorsoManager() +head_manager = HeadManager() +arm_manager = ArmManager() +hand_manager = HandManager() + + +def build_dexforce_w1_assembly_urdf_cfg( + arm_kind: DexforceW1ArmKind, + arm_sides: List[DexforceW1ArmSide] = [ + DexforceW1ArmSide.LEFT, + DexforceW1ArmSide.RIGHT, + ], + fname: Optional[str] = "DexforceW1V021", + hand_types: Optional[Dict[DexforceW1ArmSide, DexforceW1HandBrand]] = None, + hand_versions: Optional[Dict[DexforceW1ArmSide, DexforceW1Version]] = None, + hand_attach_xposes: Optional[Dict[DexforceW1ArmSide, np.ndarray]] = None, + include_chassis: bool = True, + include_torso: bool = True, + include_head: bool = True, + include_hand: bool = True, + include_eyes: bool = True, + include_wrist_cameras: bool = True, + component_versions: Optional[Dict[DexforceW1Type, DexforceW1Version]] = None, +) -> URDFCfg: + """ + Assemble DexforceW1 robot urdf configuration. + + Args: + arm_kind: Arm type (anthropomorphic or industrial). + arm_sides: List of arm sides to include (left/right). Default both sides. + fname: Output configuration name. Default "DexforceW1V021". + hand_types: Dict specifying hand brand (DexforceW1HandBrand) for each arm side. Default None, which uses the default brand. + hand_versions: Dict specifying hand version for each arm side. Default None, which uses the default version. + hand_attach_xposes: Dict specifying hand attachment pose for each arm side. Default None, which uses the default attachment pose. + include_chassis: Whether to include chassis. Default True. + include_torso: Whether to include torso. Default True. + include_head: Whether to include head. Default True. + include_hand: Whether to include hand. Default True. + include_wrist_cameras: Whether to include wrist cameras. Default True. + component_versions: Dict specifying version for each robot component. Default all V021. + + Returns: + URDFCfg: Assembled URDF configuration. + """ + + def get_version(t, default=DexforceW1Version.V021): + return (component_versions or {}).get(t, default) + + components = [] + if include_chassis: + components.append( + { + "component_type": "chassis", + "urdf_path": chassis_manager.get_urdf( + get_version(DexforceW1Type.CHASSIS) + ), + } + ) + if include_torso: + components.append( + { + "component_type": "torso", + "urdf_path": torso_manager.get_urdf(get_version(DexforceW1Type.TORSO)), + } + ) + if include_head: + components.append( + { + "component_type": "head", + "urdf_path": head_manager.get_urdf(get_version(DexforceW1Type.HEAD)), + } + ) + + sensors = [] + + if include_eyes: + # TODO: Support user-defined eye transforms + import xml.etree.ElementTree as ET + + attach_xpos = np.array( + [ + [-0.0, 0.25959, -0.96572, 0.091], + [0.0, -0.96572, -0.25959, -0.051], + [-1.0, -0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 1.0], + ] + ) + + joint_xml = """ + + + + + + """ + + link_xml = """ + + + + + + + + """ + + joint_elem = ET.fromstring(joint_xml) + link_elem = ET.fromstring(link_xml) + + sensors.append( + { + "sensor_name": "eyes", + "sensor_source": ([link_elem], [joint_elem]), # eyes_manager.get_urdf() + "parent_component": "head", + "parent_link": "neck2", + "transform": attach_xpos, + "sensor_type": "camera", + } + ) + if include_wrist_cameras: + for arm_side in arm_sides: + # TODO: Support user-defined eye transforms + import xml.etree.ElementTree as ET + + if arm_side == DexforceW1ArmSide.LEFT: + rpy = [2.79252648, 0.0, 1.57079633] + xyz = [0.08, 0.0, 0.06] + tf_xpos = np.eye(4) + tf_xpos[:3, :3] = R.from_rotvec([0, 0, -90], degrees=True).as_matrix() + else: + rpy = [2.79252648, 0.0, 1.57079633] + xyz = [0.08, 0.0, 0.06] + tf_xpos = np.eye(4) + tf_xpos[:3, :3] = R.from_rotvec([0, 0, 90], degrees=True).as_matrix() + + attach_xpos = np.eye(4) + attach_xpos[:3, :3] = R.from_euler("xyz", rpy).as_matrix() + attach_xpos[:3, 3] = xyz + attach_xpos = tf_xpos @ attach_xpos + + joint_xml = f""" + + + + + + """ + + link_xml = f""" + + + + + + + + """ + + joint_elem = ET.fromstring(joint_xml) + link_elem = ET.fromstring(link_xml) + sensors.append( + { + "sensor_name": f"{arm_side.value.lower()}_wrist_camera", + "sensor_source": ([link_elem], [joint_elem]), + "parent_component": f"{arm_side.value}_arm", + "parent_link": f"{arm_side.value}_ee", + "transform": attach_xpos, + "sensor_type": "camera", + } + ) + + for arm_side in arm_sides: + if arm_kind == DexforceW1ArmKind.ANTHROPOMORPHIC: + arm_type = ( + DexforceW1Type.LEFT_ARM1 + if arm_side == DexforceW1ArmSide.LEFT + else DexforceW1Type.RIGHT_ARM1 + ) + else: + arm_type = ( + DexforceW1Type.LEFT_ARM2 + if arm_side == DexforceW1ArmSide.LEFT + else DexforceW1Type.RIGHT_ARM2 + ) + arm_version = get_version(arm_type) + arm_cfg = arm_manager.get_config(arm_kind, arm_side, arm_version) + components.append( + { + "component_type": f"{arm_side.value}_arm", + "urdf_path": arm_cfg["urdf_path"], + } + ) + + if include_hand: + for arm_side in arm_sides: + # hand_brand: DexforceW1HandBrand + hand_brand = (hand_types or {}).get( + arm_side, DexforceW1HandBrand.BRAINCO_HAND + ) + hand_version = (hand_versions or {}).get( + arm_side, + get_version( + DexforceW1Type.LEFT_HAND + if arm_side == DexforceW1ArmSide.LEFT + else DexforceW1Type.RIGHT_HAND + ), + ) + urdf_path = hand_manager.get_urdf(hand_brand, arm_side, hand_version) + + attach_xpos = (hand_attach_xposes or {}).get( + arm_side, + hand_manager.get_attach_xpos( + hand_brand, arm_kind, arm_side == DexforceW1ArmSide.LEFT + ), + ) + components.append( + { + "component_type": f"{arm_side.value}_hand", + "urdf_path": urdf_path, + "transform": attach_xpos, + } + ) + return URDFCfg(components=components, sensors=sensors, fname=fname) + + +def build_dexforce_w1_solver_cfg( + arm_kind: DexforceW1ArmKind, + arm_sides: List[DexforceW1ArmSide] = [ + DexforceW1ArmSide.LEFT, + DexforceW1ArmSide.RIGHT, + ], + component_versions: Optional[Dict[DexforceW1Type, DexforceW1Version]] = None, + urdf_cfg: Optional[URDFCfg] = None, +) -> Dict[DexforceW1Type, SolverCfg]: + """ + Build DexforceW1 solver configuration dict. + + Args: + arm_kind: Arm type. + arm_sides: Included arm sides. Optional, default both sides. + component_versions: Component version dict. Optional, default all V021. + urdf_cfg: Optional, URDFCfg object from build_dexforce_w1_assembly_urdf_cfg. + + Returns: + Dict[DexforceW1Type, SolverCfg] + """ + + def get_version(t, default=DexforceW1Version.V021): + return (component_versions or {}).get(t, default) + + solver_cfg = {} + + for arm_side in arm_sides: + if arm_kind == DexforceW1ArmKind.ANTHROPOMORPHIC: + arm_type = ( + DexforceW1Type.LEFT_ARM1 + if arm_side == DexforceW1ArmSide.LEFT + else DexforceW1Type.RIGHT_ARM1 + ) + else: + arm_type = ( + DexforceW1Type.LEFT_ARM2 + if arm_side == DexforceW1ArmSide.LEFT + else DexforceW1Type.RIGHT_ARM2 + ) + arm_version = get_version(arm_type) + arm_cfg = arm_manager.get_config(arm_kind, arm_side, arm_version) + solver_cfg[arm_type] = SolverCfg.from_dict( + { + "class_type": "PytorchSolver", + "urdf_path": arm_cfg["urdf_path"], + "joint_names": arm_cfg["joint_names"], + "end_link_name": arm_cfg["end_link_name"], + "root_link_name": arm_cfg["root_link_name"], + } + ) + + # Use urdf_cfg.fname if provided, otherwise fallback to default path + full_body_urdf_path = ( + urdf_cfg.fname + if urdf_cfg is not None + else get_data_path("DexforceW1FullBodyV021/full_body.urdf") + ) + + solver_cfg[DexforceW1Type.FULL_BODY] = SolverCfg.from_dict( + { + "class_type": "PytorchSolver", + "urdf_path": full_body_urdf_path, + "joint_names": [ + "ANKLE", + "KNEE", + "BUTTOCK", + "WAIST", + "NECK1", + "NECK2", + "LEFT_J1", + "LEFT_J2", + "LEFT_J3", + "LEFT_J4", + "LEFT_J5", + "LEFT_J6", + "LEFT_J7", + "RIGHT_J1", + "RIGHT_J2", + "RIGHT_J3", + "RIGHT_J4", + "RIGHT_J5", + "RIGHT_J6", + "RIGHT_J7", + ], + "end_link_name": "right_ee", + "root_link_name": "base_link", + } + ) + return solver_cfg + + +def build_dexforce_w1_cfg( + arm_kind: DexforceW1ArmKind, + arm_sides: List[DexforceW1ArmSide] = [ + DexforceW1ArmSide.LEFT, + DexforceW1ArmSide.RIGHT, + ], + hand_types: Optional[Dict[DexforceW1ArmSide, DexforceW1HandBrand]] = None, + hand_versions: Optional[Dict[DexforceW1ArmSide, DexforceW1Version]] = None, + hand_attach_xposes: Optional[Dict[DexforceW1ArmSide, np.ndarray]] = None, + include_chassis: bool = True, + include_torso: bool = True, + include_head: bool = True, + include_hand: bool = True, + component_versions: Optional[Dict[DexforceW1Type, DexforceW1Version]] = None, + solver_cfg: Optional[Dict[DexforceW1Type, SolverCfg]] = None, +) -> "DexforceW1Cfg": + """ + Build DexforceW1 robot configuration object. + + Args: + arm_kind: Arm type (anthropomorphic or industrial). + arm_sides: List of arm sides to include (left/right). Default both sides. + hand_types: Dict specifying hand brand (DexforceW1HandBrand) for each arm side. Default None, which uses the default brand. + hand_versions: Dict specifying hand version for each arm side. Default None, which uses the default version. + hand_attach_xposes: Dict specifying hand attachment pose for each arm side. Default None, which uses the default attachment pose. + include_chassis: Whether to include chassis. Optional, default True. + include_torso: Whether to include torso. Optional, default True. + include_head: Whether to include head. Optional, default True. + include_hand: Whether to include hand. Optional, default True. + include_wrist_cameras: Whether to include wrist cameras. Optional, default True. + component_versions: Dict specifying version for each robot component. + solver_cfg: Optional, pre-defined solver configuration dict. + + Returns: + DexforceW1Cfg: Robot configuration object. + """ + urdf_cfg = build_dexforce_w1_assembly_urdf_cfg( + arm_kind=arm_kind, + arm_sides=arm_sides, + hand_types=hand_types, + hand_versions=hand_versions, + hand_attach_xposes=hand_attach_xposes, + include_chassis=include_chassis, + include_torso=include_torso, + include_head=include_head, + component_versions=component_versions, + ) + + left_arm_joints = [] + right_arm_joints = [] + for arm_side in arm_sides: + if arm_kind == DexforceW1ArmKind.ANTHROPOMORPHIC: + arm_type = ( + DexforceW1Type.LEFT_ARM1 + if arm_side == DexforceW1ArmSide.LEFT + else DexforceW1Type.RIGHT_ARM1 + ) + else: + arm_type = ( + DexforceW1Type.LEFT_ARM2 + if arm_side == DexforceW1ArmSide.LEFT + else DexforceW1Type.RIGHT_ARM2 + ) + arm_version = (component_versions or {}).get(arm_type, DexforceW1Version.V021) + arm_cfg = arm_manager.get_config(arm_kind, arm_side, arm_version) + if arm_side == DexforceW1ArmSide.LEFT: + left_arm_joints = arm_cfg["joint_names"] + elif arm_side == DexforceW1ArmSide.RIGHT: + right_arm_joints = arm_cfg["joint_names"] + + torso_joints = [] + head_joints = [] + left_hand_joints = [] + right_hand_joints = [] + + if include_torso: + torso_joints = torso_manager.get_config()["joint_names"] + if include_head: + head_joints = head_manager.get_config()["joint_names"] + if include_hand: + if DexforceW1ArmSide.LEFT in arm_sides: + left_hand_brand = (hand_types or {}).get( + DexforceW1ArmSide.LEFT, DexforceW1HandBrand.BRAINCO_HAND + ) + left_hand_version = (hand_versions or {}).get( + DexforceW1ArmSide.LEFT, DexforceW1Version.V021 + ) + left_hand_cfg = hand_manager.get_config( + left_hand_brand, DexforceW1ArmSide.LEFT, left_hand_version + ) + left_hand_joints = left_hand_cfg["joint_names"] + if DexforceW1ArmSide.RIGHT in arm_sides: + right_hand_brand = (hand_types or {}).get( + DexforceW1ArmSide.RIGHT, DexforceW1HandBrand.BRAINCO_HAND + ) + right_hand_version = (hand_versions or {}).get( + DexforceW1ArmSide.RIGHT, DexforceW1Version.V021 + ) + right_hand_cfg = hand_manager.get_config( + right_hand_brand, DexforceW1ArmSide.RIGHT, right_hand_version + ) + right_hand_joints = right_hand_cfg["joint_names"] + + control_parts = {} + + if torso_joints: + control_parts["torso"] = torso_joints + if head_joints: + control_parts["head"] = head_joints + if left_arm_joints: + control_parts["left_arm"] = left_arm_joints + if right_arm_joints: + control_parts["right_arm"] = right_arm_joints + if left_arm_joints and right_arm_joints: + control_parts["dual_arm"] = left_arm_joints + right_arm_joints + if left_hand_joints: + control_parts["left_eef"] = left_hand_joints + if right_hand_joints: + control_parts["right_eef"] = right_hand_joints + + if torso_joints and head_joints and left_arm_joints and right_arm_joints: + control_parts["full_body"] = ( + torso_joints + head_joints + left_arm_joints + right_arm_joints + ) + + from embodichain.lab.sim.robots.dexforce_w1.cfg import DexforceW1Cfg + + cfg = DexforceW1Cfg() + cfg.arm_kind = arm_kind + cfg.urdf_cfg = urdf_cfg + cfg.control_parts = control_parts + + if solver_cfg is not None: + cfg.solver_cfg = solver_cfg + else: + cfg.solver_cfg = build_dexforce_w1_solver_cfg( + arm_kind=arm_kind, + arm_sides=arm_sides, + component_versions=component_versions, + urdf_cfg=urdf_cfg, + ) + + return cfg diff --git a/embodichain/lab/sim/sensors/__init__.py b/embodichain/lab/sim/sensors/__init__.py new file mode 100644 index 00000000..36c4d0e6 --- /dev/null +++ b/embodichain/lab/sim/sensors/__init__.py @@ -0,0 +1,19 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .base_sensor import BaseSensor, SensorCfg +from .camera import Camera, CameraCfg +from .stereo import StereoCamera, StereoCameraCfg diff --git a/embodichain/lab/sim/sensors/base_sensor.py b/embodichain/lab/sim/sensors/base_sensor.py new file mode 100644 index 00000000..70f78c6e --- /dev/null +++ b/embodichain/lab/sim/sensors/base_sensor.py @@ -0,0 +1,175 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import torch + +from abc import abstractmethod +from typing import Dict, List, Any, Optional, Sequence, Tuple, Union +from embodichain.lab.sim.cfg import ObjectBaseCfg +from embodichain.lab.sim.common import BatchEntity +from embodichain.utils.math import matrix_from_quat +from embodichain.lab.sim.utility import get_dexsim_arena_num +from embodichain.utils import configclass, is_configclass, logger + + +@configclass +class SensorCfg(ObjectBaseCfg): + """Configuration class for sensors. + + This class can be extended to include specific sensor configurations. + """ + + @configclass + class OffsetCfg: + """Configuration of the sensor offset relative to the parent frame.""" + + pos: Tuple[float, float, float] = (0.0, 0.0, 0.0) + """Position of the sensor in the parent frame. Defaults to (0.0, 0.0, 0.0).""" + quat: Tuple[float, float, float, float] = (1.0, 0.0, 0.0, 0.0) + """Orientation of the sensor in the parent frame as a quaternion (w, x, y, z). Defaults to (1.0, 0.0, 0.0, 0.0).""" + + parent: Optional[str] = None + """Name of the parent frame. If not specified, the sensor will be placed in the arena frame. + + This is usually the case when the sensor is not attached to any specific object, eg, link of a robot arm. + """ + + @property + def transformation(self) -> torch.Tensor: + pos = torch.tensor(self.pos, dtype=torch.float32) + quat = torch.tensor(self.quat, dtype=torch.float32) + rot = matrix_from_quat(quat.unsqueeze(0)).squeeze(0) + T = torch.eye(4, dtype=torch.float32) + T[:3, :3] = rot + T[:3, 3] = pos + return T + + @classmethod + def from_dict(cls, init_dict: dict) -> SensorCfg.OffsetCfg: + cfg = cls() + for key, value in init_dict.items(): + if hasattr(cfg, key): + setattr(cfg, key, value) + else: + logger.log_warning(f"Key '{key}' not found in {cls.__name__}.") + return cfg + + @abstractmethod + def get_data_types(self) -> List[str]: + """Get the data types supported by this sensor configuration. + + Returns: + A list of data types that this sensor configuration supports. + """ + return [] + + sensor_type: str = "BaseSensor" + + @classmethod + def from_dict(cls, init_dict: Dict[str, Any]) -> "SensorCfg": + """Initialize the configuration from a dictionary.""" + from embodichain.utils.utility import get_class_instance + + cfg = get_class_instance( + "embodichain.lab.sim.sensors", init_dict["sensor_type"] + "Cfg" + )() + for key, value in init_dict.items(): + if hasattr(cfg, key): + attr = getattr(cfg, key) + if is_configclass(attr): + setattr( + cfg, key, attr.from_dict(value) + ) # Call from_dict on the attribute + else: + setattr(cfg, key, value) + else: + logger.log_warning( + f"Key '{key}' not found in {cfg.__class__.__name__}." + ) + return cfg + + +class BaseSensor(BatchEntity): + """Base class for sensor abstraction in the simulation engine. + + Sensors should inherit from this class and implement the `update` and `get_data` methods. + """ + + SUPPORTED_DATA_TYPES = [] + + def __init__( + self, config: SensorCfg, device: torch.device = torch.device("cpu") + ) -> None: + + self._data_buffer: Dict[str, torch.Tensor] = {} + + self._entities = [None for _ in range(get_dexsim_arena_num())] + self._build_sensor_from_config(config, device=device) + + super().__init__(config, self._entities, device) + + @abstractmethod + def _build_sensor_from_config( + self, config: SensorCfg, device: torch.device + ) -> None: + """Build the sensor from the provided configuration. + + Args: + config: The configuration for the sensor. + device: The device of the sensor + """ + pass + + @abstractmethod + def update(self, **kwargs) -> None: + """Update the sensor state based on the current simulation state. + + This method is called periodically to ensure the sensor data is up-to-date. + + Args: + **kwargs: Additional keyword arguments for sensor update. + """ + pass + + @abstractmethod + def get_arena_pose(self, to_matrix: bool = False) -> torch.Tensor: + """Get the pose of the sensor in the arena frame. + + Args: + to_matrix: If True, return the pose as a 4x4 transformation matrix. + + Returns: + A tensor representing the pose of the sensor in the arena frame. + """ + logger.log_error("Not implemented yet.") + + def get_data(self, copy: bool = True) -> Dict[str, torch.Tensor]: + """Retrieve data from the sensor. + + Args: + copy: If True, return a copy of the data buffer. Defaults to True. + + Returns: + The data collected by the sensor. + """ + if copy: + return {key: value.clone() for key, value in self._data_buffer.items()} + return self._data_buffer + + def reset(self, env_ids: Optional[Sequence[int]] = None) -> None: + return super().reset(env_ids) diff --git a/embodichain/lab/sim/sensors/camera.py b/embodichain/lab/sim/sensors/camera.py new file mode 100644 index 00000000..11f05bbb --- /dev/null +++ b/embodichain/lab/sim/sensors/camera.py @@ -0,0 +1,537 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import dexsim +import math +import torch +import dexsim.render as dr +import warp as wp + +from functools import cached_property +from typing import Union, Tuple, Optional, Sequence, List + +from embodichain.lab.sim.sensors import BaseSensor, SensorCfg +from embodichain.utils.math import matrix_from_quat, quat_from_matrix, look_at_to_pose +from embodichain.utils.warp.kernels import reshape_tiled_image +from embodichain.utils import logger, configclass +from embodichain.lab.sim.utility.sim_utils import is_rt_enabled + + +@configclass +class CameraCfg(SensorCfg): + """Configuration class for Camera.""" + + @configclass + class ExtrinsicsCfg(SensorCfg.OffsetCfg): + """Configuration class for camera extrinsics. + + The extrinsics define the position and orientation of the camera in the 3D world. + If eye, target, and up are provided, they will be used to compute the extrinsics. + Otherwise, the position and orientation will be set to the defaults. + """ + + eye: Union[Tuple[float, float, float], None] = None + target: Union[Tuple[float, float, float], None] = None + up: Union[Tuple[float, float, float], None] = None + """Alternative way to specify the camera extrinsics using eye, target, and up vectors.""" + + @property + def transformation(self) -> torch.Tensor: + if self.eye: + self.up = (0.0, 0.0, 1.0) if self.up is None else self.up + return look_at_to_pose(self.eye, self.target, self.up).squeeze(0) + else: + return super().transformation + + sensor_type: str = "Camera" + + # Camera parameters + width: int = 640 + height: int = 480 + near: float = 0.005 + far: float = 100.0 + + # The camera intrinsics are defined as (fx, fy, cx, cy) + intrinsics: Tuple[float, float, float, float] = (600, 600, 320.0, 240.0) + extrinsics: ExtrinsicsCfg = ExtrinsicsCfg() + + enable_color: bool = True + enable_depth: bool = False + enable_mask: bool = False + enable_normal: bool = False + enable_position: bool = False + + fx: float = intrinsics[0] + fy: float = intrinsics[1] + cx: float = intrinsics[2] + cy: float = intrinsics[3] + + def get_view_attrib(self) -> dr.ViewFlags: + """Get the view attributes for the camera. + + The camera view whcich is used to render the scene + Default view attributes for the camera are: [COLOR, DEPTH, MASK] + The supported view attributes are: + - COLOR: RGBA images + - DEPTH: Depth images + - MASK: Instance segmentation masks + - NORMAL: Normal images + - POSITION: Position images with 3D coordinates. + + Returns: + The view attributes for the camera. + """ + view_attrib: dr.ViewFlags = dr.ViewFlags.COLOR + # TODO: change for fast-rt renderer backend. + if self.enable_color: + view_attrib |= dr.ViewFlags.COLOR + if self.enable_depth: + if is_rt_enabled() is False: + view_attrib |= dr.ViewFlags.NORMAL + view_attrib |= dr.ViewFlags.DEPTH + if self.enable_mask: + view_attrib |= dr.ViewFlags.MASK + if is_rt_enabled() is False: + view_attrib |= dr.ViewFlags.DEPTH + if self.enable_normal: + view_attrib |= dr.ViewFlags.NORMAL + if self.enable_position: + view_attrib |= dr.ViewFlags.POSITION + return view_attrib + + def get_data_types(self) -> List[str]: + data_types = [] + if self.enable_color: + data_types.append("color") + if self.enable_depth: + data_types.append("depth") + if self.enable_mask: + data_types.append("mask") + if self.enable_normal: + data_types.append("normal") + if self.enable_position: + data_types.append("position") + return data_types + + +class Camera(BaseSensor): + """Base class for sensor abstraction in the simulation engine. + + Sensors should inherit from this class and implement the `update` and `get_data` methods. + """ + + SUPPORTED_DATA_TYPES = ["color", "depth", "mask", "normal", "position"] + + def __init__( + self, config: CameraCfg, device: torch.device = torch.device("cpu") + ) -> None: + super().__init__(config, device) + + def _build_sensor_from_config( + self, config: CameraCfg, device: torch.device + ) -> None: + self._world = dexsim.default_world() + env = self._world.get_env() + arenas = env.get_all_arenas() + if len(arenas) == 0: + arenas = [env] + num_instances = len(arenas) + + if self.is_rt_enabled: + self._frame_buffer = self._world.create_camera_group( + [config.width, config.height], num_instances, True + ) + + view_attrib = config.get_view_attrib() + for i, arena in enumerate(arenas): + view_name = f"{self.uid}_view{i + 1}" + view = arena.create_camera( + view_name, + config.width, + config.height, + True, + view_attrib, + self._frame_buffer, + ) + view.set_intrinsic(config.intrinsics) + view.set_near(config.near) + view.set_far(config.far) + self._entities[i] = view + + else: + self._grid_size = math.ceil(math.sqrt(num_instances)) + frame_width = self._grid_size * config.width + frame_height = self._grid_size * config.height + view_attrib = config.get_view_attrib() + # Create the data frame + self._frame_buffer = self._world.create_frame_buffer( + [frame_width, frame_height], view_attrib, True + ) + self._frame_buffer.set_read_able(view_attrib) + + # Create camera views + for i, arena in enumerate(arenas): + col = i // self._grid_size + row = i % self._grid_size + x = row * config.width + y = col * config.height + view_name = f"{self.uid}_view{i + 1}" + + view = arena.create_camera_view( + view_name, (x, y), (config.width, config.height), self._frame_buffer + ) + view.set_intrinsic(config.intrinsics) + view.set_near(config.near) + view.set_far(config.far) + view.enable_postprocessing(True) + + self._entities[i] = view + + # Define a mapping of data types to their respective shapes and dtypes + buffer_specs = { + "color": ( + (self.num_instances, config.height, config.width, 4), + torch.uint8, + ), + "depth": ( + (self.num_instances, config.height, config.width), + torch.float32, + ), + "mask": ( + (self.num_instances, config.height, config.width), + torch.int32, + ), + "normal": ( + (self.num_instances, config.height, config.width, 3), + torch.float32, + ), + "position": ( + (self.num_instances, config.height, config.width, 3), + torch.float32, + ), + } + data_types = config.get_data_types() + + # Iterate through enabled data types and initialize buffers + for data_type in data_types: + if getattr(config, f"enable_{data_type}", False): + shape, dtype = buffer_specs[data_type] + self._data_buffer[data_type] = torch.empty( + shape, dtype=dtype, device=device + ) + + self.cfg: CameraCfg = config + if self.cfg.extrinsics.parent is not None: + self._attach_to_entity() + + @cached_property + def is_rt_enabled(self) -> bool: + """Check if Ray Tracing rendering backend is enabled in the default dexsim world. + + Returns: + bool: True if Ray Tracing rendering is enabled, False otherwise. + """ + return is_rt_enabled() + + def update(self, **kwargs) -> None: + """Update the sensor data. + + The supported data types are: + - color: RGB images with shape (B, H, W, 4) and dtype torch.uint8 + - depth: Depth images with shape (B, H, W) and dtype torch.float32 + - mask: Instance segmentation masks with shape (B, H, W) and dtype torch.int32 + - normal: Normal images with shape (B, H, W, 3) and dtype torch.float32 + - position: Position images with shape (B, H, W, 3) and dtype torch.float32 + + Args: + **kwargs: Additional keyword arguments for sensor update. + - fetch_only (bool): If True, only fetch the data from dexsim internal frame buffer without performing rendering. + """ + fetch_only = kwargs.get("fetch_only", False) + if not fetch_only: + if self.is_rt_enabled: + self._frame_buffer.apply() + else: + self._frame_buffer.apply_frame() + + self.cfg: CameraCfg + # TODO: support fetch data from gpu buffer directly. + if self.cfg.enable_color: + if self.is_rt_enabled: + self._data_buffer["color"] = self._frame_buffer.get_rgb_gpu_buffer().to( + self.device + ) + else: + data = self._frame_buffer.get_color_gpu_buffer().to(self.device) + self._update_buffer_impl(data, self._data_buffer["color"]) + + if self.cfg.enable_depth: + data = self._frame_buffer.get_depth_gpu_buffer().to(self.device) + if self.is_rt_enabled: + self._data_buffer["depth"] = data + else: + self._update_buffer_impl( + data, self._data_buffer["depth"].unsqueeze_(-1) + ) + self._data_buffer["depth"].squeeze_(-1) + + if self.cfg.enable_mask: + if self.is_rt_enabled: + data = self._frame_buffer.get_visible_mask_gpu_buffer().to( + self.device, torch.int32 + ) + self._data_buffer["mask"] = data + else: + data = self._frame_buffer.get_visible_gpu_buffer().to( + self.device, torch.int32 + ) + self._update_buffer_impl(data, self._data_buffer["mask"].unsqueeze_(-1)) + self._data_buffer["mask"].squeeze_(-1) + + if self.cfg.enable_normal: + data = self._frame_buffer.get_normal_gpu_buffer().to(self.device) + if self.is_rt_enabled: + self._data_buffer["normal"] = data + else: + self._update_buffer_impl(data, self._data_buffer["normal"]) + + if self.cfg.enable_position: + data = self._frame_buffer.get_position_gpu_buffer().to(self.device) + if self.is_rt_enabled: + self._data_buffer["position"] = data + else: + self._update_buffer_impl(data, self._data_buffer["position"]) + + def _update_buffer_impl( + self, data_buffer: torch.Tensor, data_buffer_out: torch.Tensor + ) -> None: + device = str(self.device) + channel = data_buffer.shape[-1] if data_buffer.dim() >= 3 else 1 + wp.launch( + kernel=reshape_tiled_image, + dim=(self.num_instances, self.cfg.height, self.cfg.width), + inputs=[ + wp.from_torch(data_buffer).flatten(), + wp.from_torch(data_buffer_out), + self.cfg.height, + self.cfg.width, + channel, + self._grid_size, + ], + device="cuda:0" if device == "cuda" else device, + ) + + def _attach_to_entity(self) -> None: + """Attach the sensor to the parent entity in each environment.""" + env = self._world.get_env() + for i, entity in enumerate(self._entities): + + parent = None + if i == 0: + parent = env.find_node(f"{self.cfg.extrinsics.parent}") + else: + parent = env.find_node(f"{self.cfg.extrinsics.parent}.{i-1}") + if parent is None: + logger.log_error( + f"Failed to find parent entity {self.cfg.extrinsics.parent} for sensor {self.cfg.uid}." + ) + + entity.attach_node(parent) + + def set_local_pose( + self, pose: torch.Tensor, env_ids: Optional[Sequence[int]] = None + ) -> None: + """Set the local pose of the camera. + + Note: The pose should be in the OpenGL coordinate system, which means the Y is up and Z is forward. + + Args: + pose (torch.Tensor): The local pose to set, should be a 4x4 transformation matrix. + env_ids (Optional[Sequence[int]]): The environment IDs to set the pose for. If None, set for all environments. + """ + if env_ids is None: + local_env_ids = range(len(self._entities)) + else: + local_env_ids = env_ids + + pose = pose.cpu() + if pose.dim() == 2 and pose.shape[1] == 7: + pose_matrix = torch.eye(4).unsqueeze(0).repeat(pose.shape[0], 1, 1) + pose_matrix[:, :3, 3] = pose[:, :3] + pose_matrix[:, :3, :3] = matrix_from_quat(pose[:, 3:7]) + for i, env_idx in enumerate(local_env_ids): + self._entities[env_idx].set_local_pose(pose_matrix[i].numpy()) + elif pose.dim() == 3 and pose.shape[1:] == (4, 4): + for i, env_idx in enumerate(local_env_ids): + self._entities[env_idx].set_local_pose(pose[i].numpy()) + else: + logger.log_error( + f"Invalid pose shape {pose.shape}. Expected (N, 7) or (N, 4, 4)." + ) + + def get_local_pose(self, to_matrix: bool = False) -> torch.Tensor: + """Get the local pose of the camera. + + Args: + to_matrix (bool): If True, return the pose as a 4x4 matrix. If False, return as a quaternion. + + Returns: + torch.Tensor: The local pose of the camera. + """ + poses = [] + for entity in self._entities: + pose = entity.get_local_pose() + poses.append(torch.as_tensor(pose, dtype=torch.float32)) + + poses = torch.stack(poses, dim=0).to(self.device) + if to_matrix is False: + xyz = poses[:, :3, 3] + quat = quat_from_matrix(poses[:, :3, :3]) + return torch.cat((xyz, quat), dim=-1) + return poses + + def get_arena_pose(self, to_matrix: bool = False) -> torch.Tensor: + """Get the pose of the sensor in the arena frame. + + Args: + to_matrix (bool): If True, return the pose as a 4x4 transformation matrix. + + Returns: + A tensor representing the pose of the sensor in the arena frame. + """ + from embodichain.lab.sim.utility import get_dexsim_arenas + + arenas = get_dexsim_arenas() + + poses = [] + for i, entity in enumerate(self._entities): + pose = entity.get_world_pose() + pose[:2, 3] -= arenas[i].get_root_node().get_local_pose()[:2, 3] + poses.append(torch.as_tensor(pose, dtype=torch.float32)) + + poses = torch.stack(poses, dim=0).to(self.device) + if to_matrix is False: + xyz = poses[:, :3, 3] + quat = quat_from_matrix(poses[:, :3, :3]) + return torch.cat((xyz, quat), dim=-1) + return poses + + def look_at( + self, + eye: torch.Tensor, + target: torch.Tensor, + up: Optional[torch.Tensor] = None, + env_ids: Optional[Sequence[int]] = None, + ) -> None: + """Set the camera to look at a target point. + + Args: + eye (torch.Tensor): The position of the camera (eye) with shape (N, 3). + target (torch.Tensor): The point the camera should look at (target) with shape (N, 3). + up (Optional[torch.Tensor]): The up direction vector. If None, defaults to [0, 0, 1]. + env_ids (Optional[Sequence[int]]): The environment IDs to set the look at for. If None, set for all environments. + """ + if up is None: + up = torch.tensor([[0.0, 0.0, 1.0]]).repeat(eye.shape[0], 1) + + pose = look_at_to_pose(eye, target, up) + # To opengl coordinate system. + pose[:, :3, 1] = -pose[:, :3, 1] + pose[:, :3, 2] = -pose[:, :3, 2] + self.set_local_pose(pose, env_ids=env_ids) + + def set_intrinsics( + self, + intrinsics: torch.Tensor, + env_ids: Optional[Sequence[int]] = None, + ) -> None: + """ + Set the camera intrinsics for both left and right cameras. + + Args: + intrinsics (torch.Tensor): The intrinsics for the left camera with shape (4,) / (3, 3) or (N, 4) / (N, 3, 3). + env_ids (Optional[Sequence[int]], optional): The environment ids to set the intrinsics. + If None, set for all environments. Defaults to None. + """ + ids = env_ids if env_ids is not None else range(self.num_instances) + + if intrinsics.dim() == 2 and intrinsics.shape[1] == 3: + intrinsics = intrinsics.unsqueeze(0).repeat(len(ids), 1, 1) + + if intrinsics.dim() == 1: + intrinsics = intrinsics.unsqueeze(0).repeat(len(ids), 1) + + if len(ids) != intrinsics.shape[0]: + logger.log_error( + f"Invalid intrinsics shape {intrinsics.shape} for {len(ids)} environments." + ) + + for i, env_id in enumerate(ids): + entity = self._entities[env_id] + if intrinsics.shape[1] == 3: + entity.set_intrinsic(intrinsics[i].cpu().numpy()) + else: + entity.set_intrinsic(intrinsics[i].cpu().tolist()) + + def get_intrinsics(self) -> torch.Tensor: + """ + Get the camera intrinsics for both left and right cameras. + + Returns: + torch.Tensor: The intrinsics for the left camera with shape (N, 3, 3). + """ + intrinsics = [] + for entity in self._entities: + intrinsics.append( + torch.as_tensor(entity.get_intrinsic(), dtype=torch.float32) + ) + + return torch.stack(intrinsics, dim=0).to(self.device) + + def reset(self, env_ids: Optional[Sequence[int]] = None) -> None: + self.cfg: CameraCfg + + if self.cfg.extrinsics.eye is not None: + eye = ( + torch.tensor(self.cfg.extrinsics.eye, dtype=torch.float32) + .squeeze_(0) + .repeat(self.num_instances, 1) + ) + target = ( + torch.tensor(self.cfg.extrinsics.target, dtype=torch.float32) + .squeeze_(0) + .repeat(self.num_instances, 1) + ) + up = ( + torch.tensor(self.cfg.extrinsics.up, dtype=torch.float32) + .squeeze_(0) + .repeat(self.num_instances, 1) + if self.cfg.extrinsics.up is not None + else None + ) + self.look_at(eye, target, up, env_ids=env_ids) + else: + pose = self.cfg.extrinsics.transformation + pose = pose.unsqueeze_(0).repeat(self.num_instances, 1, 1) + + if self.cfg.extrinsics.parent is None: + # To opengl coordinate system. + pose[:, :3, 1] = -pose[:, :3, 1] + pose[:, :3, 2] = -pose[:, :3, 2] + + self.set_local_pose(pose, env_ids=env_ids) diff --git a/embodichain/lab/sim/sensors/stereo.py b/embodichain/lab/sim/sensors/stereo.py new file mode 100644 index 00000000..d8b8e51d --- /dev/null +++ b/embodichain/lab/sim/sensors/stereo.py @@ -0,0 +1,538 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import dexsim +import math +import torch +import numpy as np +import warp as wp +import dexsim.render as dr + +from typing import Dict, Tuple, List, Optional, Sequence + +from dexsim.utility import inv_transform +from embodichain.lab.sim.sensors import Camera, CameraCfg +from embodichain.utils.warp.kernels import reshape_tiled_image +from embodichain.utils.math import matrix_from_euler +from embodichain.utils import logger, configclass +from embodichain.lab.sim.utility.sim_utils import is_rt_enabled + + +@configclass +class StereoCameraCfg(CameraCfg): + """Configuration class for StereoCamera.""" + + sensor_type: str = "StereoCamera" + + # The camera intrinsics of the right camera. + # The default camera is the left camera. + intrinsics_right: Tuple[float, float, float, float] = (600, 600, 320.0, 240.0) + + left_to_right_pos: Tuple[float, float, float] = (0.05, 0.0, 0.0) + # The rotation from left camera to right camera in degrees. + left_to_right_rot: Tuple[float, float, float] = (0.0, 0.0, 0.0) + + enable_disparity: bool = False + + fx_r: float = intrinsics_right[0] + fy_r: float = intrinsics_right[1] + cx_r: float = intrinsics_right[2] + cy_r: float = intrinsics_right[3] + + @property + def left_to_right(self) -> torch.Tensor: + """Get the transformation matrix from left camera to right camera.""" + left_to_right = torch.eye(4, dtype=torch.float32) + left_to_right[:3, 3] = torch.tensor(self.left_to_right_pos, dtype=torch.float32) + rot = torch.tensor(self.left_to_right_rot, dtype=torch.float32) + left_to_right[:3, :3] = matrix_from_euler(rot.unsqueeze(0)).squeeze(0) + return left_to_right + + @property + def right_to_left(self) -> torch.Tensor: + """Get the transformation matrix from right camera to left camera.""" + return torch.inverse(self.left_to_right) + + def get_data_types(self) -> List[str]: + data_types = [] + if self.enable_color: + data_types.append("color") + data_types.append("color_right") + if self.enable_depth: + data_types.append("depth") + data_types.append("depth_right") + if self.enable_mask: + data_types.append("mask") + data_types.append("mask_right") + if self.enable_normal: + data_types.append("normal") + data_types.append("normal_right") + if self.enable_position: + data_types.append("position") + data_types.append("position_right") + if self.enable_disparity: + data_types.append("disparity") + return data_types + + +class PairCameraView: + def __init__( + self, + left_view: dr.CameraView, + right_view: dr.CameraView, + left_to_right: np.ndarray, + ) -> PairCameraView: + self._left_view = left_view + self._right_view = right_view + self._left_to_right = left_to_right + + self._left_to_center = np.eye(4, dtype=np.float32) + self._left_to_center[:3, 3] = left_to_right[:3, 3] * -0.5 + + self._right_to_center = np.eye(4, dtype=np.float32) + self._right_to_center[:3, 3] = left_to_right[:3, 3] * 0.5 + + def set_local_pose(self, pose: np.ndarray) -> None: + left_pose = pose @ self._left_to_center + right_pose = pose @ self._right_to_center + self._left_view.set_local_pose(left_pose) + self._right_view.set_local_pose(right_pose) + + def get_local_pose(self) -> np.ndarray: + left_pose = self._left_view.get_local_pose() + return left_pose @ inv_transform(self._left_to_center) + + def get_node(self) -> dexsim.engine.Node: + return self._left_view.get_node() + + def attach_node(self, parent: dexsim.engine.Node) -> None: + self._left_view.attach_node(parent) + self._right_view.attach_node(parent) + + +class StereoCamera(Camera): + """Base class for sensor abstraction in the simulation engine. + + Sensors should inherit from this class and implement the `update` and `get_data` methods. + """ + + SUPPORTED_DATA_TYPES = [ + "color", + "depth", + "mask", + "normal", + "position", + "color_right", + "depth_right", + "mask_right", + "normal_right", + "position_right", + "disparity", + ] + + def __init__( + self, + config: StereoCameraCfg, + device: torch.device = torch.device("cpu"), + ) -> None: + super().__init__(config, device) + + # check valid config + if self.cfg.enable_disparity and not self.cfg.enable_depth: + logger.log_error("Disparity can only be enabled when depth is enabled.") + + def _build_sensor_from_config( + self, config: StereoCameraCfg, device: torch.device + ) -> None: + self._world = dexsim.default_world() + env = self._world.get_env() + arenas = env.get_all_arenas() + if len(arenas) == 0: + arenas = [env] + num_instances = len(arenas) + + if self.is_rt_enabled: + self._frame_buffer = self._world.create_camera_group( + [config.width, config.height], num_instances * 2, True + ) + view_attrib = config.get_view_attrib() + left_list = [] + right_list = [] + for i, arena in enumerate(arenas): + left_view_name = f"{self.uid}_left_view{i + 1}" + left_view = arena.create_camera( + left_view_name, + config.width, + config.height, + True, + view_attrib, + self._frame_buffer, + ) + left_view.set_intrinsic(config.intrinsics) + left_view.set_near(config.near) + left_view.set_far(config.far) + left_list.append(left_view) + + for i, arena in enumerate(arenas): + right_view_name = f"{self.uid}_right_view{i + 1}" + right_view = arena.create_camera( + right_view_name, + config.width, + config.height, + True, + view_attrib, + self._frame_buffer, + ) + right_view.set_intrinsic(config.intrinsics_right) + right_view.set_near(config.near) + right_view.set_far(config.far) + right_list.append(right_view) + + for i in range(num_instances): + self._entities[i] = PairCameraView( + left_list[i], right_list[i], config.left_to_right.cpu().numpy() + ) + + else: + self._grid_size = math.ceil(math.sqrt(num_instances)) + + # stereo camera has two views, we append the right camera to the left camera's view list + frame_width = self._grid_size * config.width * 2 + frame_height = self._grid_size * config.height + view_attrib = config.get_view_attrib() + + # Create the data frame + self._frame_buffer = self._world.create_frame_buffer( + [frame_width, frame_height], view_attrib, True + ) + self._frame_buffer.set_read_able(view_attrib) + + # Create camera views + for i, arena in enumerate(arenas): + col = i // self._grid_size + row = i % self._grid_size + x = row * config.width * 2 + y = col * config.height + left_view_name = f"{self.uid}_left_view{i + 1}" + + left_view = arena.create_camera_view( + left_view_name, + (x, y), + (config.width, config.height), + self._frame_buffer, + ) + + left_view.set_intrinsic(config.intrinsics) + left_view.set_near(config.near) + left_view.set_far(config.far) + left_view.enable_postprocessing(True) + + right_view_name = f"{self.uid}_right_view{i + 1}" + right_view = arena.create_camera_view( + right_view_name, + (x + config.width, y), + (config.width, config.height), + self._frame_buffer, + ) + right_view.set_intrinsic(config.intrinsics_right) + right_view.set_near(config.near) + right_view.set_far(config.far) + right_view.enable_postprocessing(True) + + self._entities[i] = PairCameraView( + left_view, right_view, config.left_to_right.cpu().numpy() + ) + + # Define a mapping of data types to their respective shapes and dtypes + buffer_specs = { + "color": ( + (self.num_instances, config.height, config.width, 4), + torch.uint8, + ), + "depth": ( + (self.num_instances, config.height, config.width, 1), + torch.float32, + ), + "mask": ( + (self.num_instances, config.height, config.width, 1), + torch.int32, + ), + "normal": ( + (self.num_instances, config.height, config.width, 3), + torch.float32, + ), + "position": ( + (self.num_instances, config.height, config.width, 3), + torch.float32, + ), + "disparity": ( + (self.num_instances, config.height, config.width, 1), + torch.float32, + ), + } + buffer_specs.update( + { + f"{data_type}_right": buffer_specs[data_type] + for data_type in ["color", "depth", "mask", "normal", "position"] + } + ) + data_types = config.get_data_types() + + # stereo buffer to store data for left and right cameras + # the data in `_data_buffer` is shared with the data in `_data_buffer_stereo`. + self._data_buffer_stereo: Dict[str, torch.Tensor] = {} + + # Iterate through enabled data types and initialize buffers + for data_type in data_types: + if "right" in data_type: + continue + if getattr(config, f"enable_{data_type}", False): + shape, dtype = buffer_specs[data_type] + if data_type == "disparity": + self._data_buffer[data_type] = torch.empty( + shape, dtype=dtype, device=device + ) + + # create new shape with width * 2 for stereo camera + shape_ = (shape[0], shape[1], shape[2] * 2, shape[3]) + + self._data_buffer_stereo[data_type] = torch.empty( + shape_, dtype=dtype, device=device + ) + self._data_buffer[data_type] = self._data_buffer_stereo[data_type][ + :, :, : config.width, : + ] + self._data_buffer[f"{data_type}_right"] = self._data_buffer_stereo[ + data_type + ][:, :, config.width :, :] + + self.cfg: CameraCfg = config + if self.cfg.extrinsics.parent is not None: + self._attach_to_entity() + + def update(self, **kwargs) -> None: + """Update the sensor data. + + The supported data types are: + - color: RGB images with shape (B, H, W, 4) and dtype torch.uint8 + - depth: Depth images with shape (B, H, W, 1) and dtype torch.float32 + - mask: Instance segmentation masks with shape (B, H, W, 1) and dtype torch.int32 + - normal: Normal images with shape (B, H, W, 3) and dtype torch.float32 + - position: Position images with shape (B, H, W, 3) and dtype torch.float32 + - disparity: Disparity images with shape (B, H, W, 1) and dtype torch.float32 + Args: + **kwargs: Additional keyword arguments for sensor update. + - fetch_only (bool): If True, only fetch the data from dexsim internal frame buffer without performing rendering. + """ + + fetch_only = kwargs.get("fetch_only", False) + if not fetch_only: + if self.is_rt_enabled: + self._frame_buffer.apply() + else: + self._frame_buffer.apply_frame() + + self.cfg: StereoCameraCfg + if self.cfg.enable_color: + if self.is_rt_enabled: + data = self._frame_buffer.get_rgb_gpu_buffer().to(self.device) + self._data_buffer["color"] = data[: self.num_instances, ...] + self._data_buffer[f"color_right"] = data[self.num_instances :, ...] + else: + data = self._frame_buffer.get_color_gpu_buffer().to(self.device) + self._update_buffer_impl(data, self._data_buffer_stereo["color"]) + if self.cfg.enable_depth: + data = self._frame_buffer.get_depth_gpu_buffer().to(self.device) + if self.is_rt_enabled: + self._data_buffer["depth"] = data[: self.num_instances, ...].unsqueeze_( + -1 + ) + self._data_buffer[f"depth_right"] = data[ + self.num_instances :, ... + ].unsqueeze_(-1) + else: + self._update_buffer_impl(data, self._data_buffer_stereo["depth"]) + if self.cfg.enable_mask: + if self.is_rt_enabled: + data = self._frame_buffer.get_visible_mask_gpu_buffer().to( + self.device, torch.int32 + ) + self._data_buffer["mask"] = data[: self.num_instances, ...].unsqueeze_( + -1 + ) + self._data_buffer[f"mask_right"] = data[ + self.num_instances :, ... + ].unsqueeze_(-1) + else: + data = self._frame_buffer.get_visible_gpu_buffer().to( + self.device, torch.int32 + ) + self._update_buffer_impl(data, self._data_buffer_stereo["mask"]) + if self.cfg.enable_normal: + data = self._frame_buffer.get_normal_gpu_buffer().to(self.device) + if self.is_rt_enabled: + self._data_buffer["normal"] = data[: self.num_instances, ...] + self._data_buffer[f"normal_right"] = data[self.num_instances :, ...] + else: + self._update_buffer_impl(data, self._data_buffer_stereo["normal"]) + if self.cfg.enable_position: + data = self._frame_buffer.get_position_gpu_buffer().to(self.device) + if self.is_rt_enabled: + self._data_buffer["position"] = data[: self.num_instances, ...] + self._data_buffer[f"position_right"] = data[self.num_instances :, ...] + else: + self._update_buffer_impl(data, self._data_buffer_stereo["position"]) + if self.cfg.enable_disparity: + disparity = self._data_buffer["disparity"] + disparity.fill_(0.0) + distance = torch.sqrt( + torch.sum(torch.square(self.cfg.left_to_right[:3, 3])) + ) + # Compute disparity only for non-zero depth values + depth = self._data_buffer["depth"] + valid_depth_mask = depth > 0 + disparity[valid_depth_mask] = ( + self.cfg.fx * distance / depth[valid_depth_mask] + ) + + def _update_buffer_impl( + self, data_buffer: torch.Tensor, data_buffer_out: torch.Tensor + ) -> None: + device = str(self.device) + channel = data_buffer.shape[-1] if data_buffer.dim() >= 3 else 1 + wp.launch( + kernel=reshape_tiled_image, + dim=(self.num_instances, self.cfg.height, self.cfg.width * 2), + inputs=[ + wp.from_torch(data_buffer).flatten(), + wp.from_torch(data_buffer_out), + self.cfg.height, + self.cfg.width * 2, + channel, + self._grid_size, + ], + device="cuda:0" if device == "cuda" else device, + ) + + def get_left_right_arena_pose(self) -> torch.Tensor: + """Get the local pose of the left and right cameras. + + Returns: + torch.Tensor: The local pose of the left camera with shape (num_envs, 4, 4). + """ + from embodichain.lab.sim.utility import get_dexsim_arenas + + arenas = get_dexsim_arenas() + + left_poses = [] + right_poses = [] + for i, entity in enumerate(self._entities): + arena_pose = arenas[i].get_root_node().get_local_pose() + left_pose = entity._left_view.get_world_pose() + left_pose[:2, 3] -= arena_pose[:2, 3] + left_poses.append( + torch.as_tensor( + left_pose, + dtype=torch.float32, + ) + ) + right_pose = entity._right_view.get_world_pose() + right_pose[:2, 3] -= arena_pose[:2, 3] + right_poses.append( + torch.as_tensor( + right_pose, + dtype=torch.float32, + ) + ) + return torch.stack(left_poses, dim=0).to(self.device), torch.stack( + right_poses, dim=0 + ).to(self.device) + + def set_intrinsics( + self, + intrinsics: torch.Tensor, + right_intrinsics: Optional[torch.Tensor] = None, + env_ids: Optional[Sequence[int]] = None, + ) -> None: + """ + Set the camera intrinsics for both left and right cameras. + + Args: + intrinsics (torch.Tensor): The intrinsics for the left camera with shape (4,) / (3, 3) or (B, 4) / (B, 3, 3). + right_intrinsics (Optional[torch.Tensor], optional): The intrinsics for the right camera with shape 4,) / (3, 3) or (B, 4) / (B, 3, 3). + If None, use the same intrinsics as the left camera. Defaults to None. + env_ids (Optional[Sequence[int]], optional): The environment ids to set the intrinsics. If None, set for all environments. + Defaults to None. + """ + ids = env_ids if env_ids is not None else range(self.num_instances) + + if intrinsics.dim() == 2 and intrinsics.shape[1] == 3: + intrinsics = intrinsics.unsqueeze(0).repeat(len(ids), 1, 1) + + if intrinsics.dim() == 1: + intrinsics = intrinsics.unsqueeze(0).repeat(len(ids), 1) + + if len(ids) != intrinsics.shape[0]: + logger.log_error( + f"Intrinsics shape {intrinsics.shape} does not match env_ids length {len(ids)}" + ) + + if right_intrinsics is None: + right_intrinsics = intrinsics + else: + if right_intrinsics.dim() == 2 and right_intrinsics.shape[1] == 3: + right_intrinsics = right_intrinsics.unsqueeze(0).repeat(len(ids), 1, 1) + + if right_intrinsics.dim() == 1: + right_intrinsics = right_intrinsics.unsqueeze(0).repeat(len(ids), 1) + + if len(ids) != right_intrinsics.shape[0]: + logger.log_error( + f"Right intrinsics shape {right_intrinsics.shape} does not match env_ids length {len(ids)}" + ) + + for i, env_id in enumerate(ids): + entity = self._entities[env_id] + if intrinsics.shape[1] == 3: + entity._left_view.set_intrinsic(intrinsics[i].cpu().numpy()) + entity._right_view.set_intrinsic(right_intrinsics[i].cpu().numpy()) + else: + entity._left_view.set_intrinsic(intrinsics[i].cpu().tolist()) + entity._right_view.set_intrinsic(right_intrinsics[i].cpu().tolist()) + + def get_intrinsics(self) -> Tuple[torch.Tensor, torch.Tensor]: + """ + Get the camera intrinsics for both left and right cameras. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: The intrinsics for the left and right cameras with shape (B, 3, 3). + """ + intrinsics_left = [] + intrinsics_right = [] + for entity in self._entities: + intrinsics_left.append( + torch.as_tensor(entity._left_view.get_intrinsic(), dtype=torch.float32) + ) + intrinsics_right.append( + torch.as_tensor(entity._right_view.get_intrinsic(), dtype=torch.float32) + ) + + return ( + torch.stack(intrinsics_left, dim=0).to(self.device), + torch.stack(intrinsics_right, dim=0).to(self.device), + ) diff --git a/embodichain/lab/sim/shapes.py b/embodichain/lab/sim/shapes.py new file mode 100644 index 00000000..8135943b --- /dev/null +++ b/embodichain/lab/sim/shapes.py @@ -0,0 +1,144 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +from typing import Optional, List, Dict, Union, TYPE_CHECKING, Any +from dataclasses import MISSING +from embodichain.utils import configclass, is_configclass, logger + +if TYPE_CHECKING: + from embodichain.lab.sim.material import VisualMaterialCfg + + +@configclass +class LoadOption: + + rebuild_normals: bool = False + """Whether to rebuild normals for the shape. Defaults to False.""" + + rebuild_tangent: bool = False + """Whether to rebuild tangents for the shape. Defaults to False.""" + + rebuild_3rdnormal: bool = False + """Whether to rebuild the normal for the shape using 3rd party library. Defaults to False.""" + + rebuild_3rdtangent: bool = False + """Whether to rebuild the tangent for the shape using 3rd party library. Defaults to False.""" + + smooth: float = -1.0 + """Angle threshold (in degrees) for smoothing normals. Defaults to -1.0 (no smoothing).""" + + @classmethod + def from_dict(cls, init_dict: Dict[str, Any]) -> LoadOption: + """Initialize the configuration from a dictionary.""" + cfg = cls() + for key, value in init_dict.items(): + if hasattr(cfg, key): + setattr(cfg, key, value) + else: + logger.log_warning( + f"Key '{key}' not found in {cfg.__class__.__name__}." + ) + return cfg + + +@configclass +class ShapeCfg: + + shape_type: str = MISSING + """Type of the shape. Must be specified in subclasses.""" + + visual_material: Optional[VisualMaterialCfg] = None + """Configuration parameters for the visual material of the shape. Defaults to None.""" + + @classmethod + def from_dict(cls, init_dict: Dict[str, Any]) -> ShapeCfg: + """Initialize the configuration from a dictionary.""" + from embodichain.utils.utility import get_class_instance + + if "shape_type" not in init_dict: + logger.log_error("shape type must be specified in the configuration.") + + cfg = get_class_instance( + "embodichain.lab.sim.shapes", init_dict["shape_type"] + "Cfg" + )() + for key, value in init_dict.items(): + if hasattr(cfg, key): + attr = getattr(cfg, key) + if key == "visual_material" and isinstance(value, dict): + setattr( + cfg, + key, + VisualMaterialCfg.from_dict(value), + ) + elif is_configclass(attr): + setattr(cfg, key, attr.from_dict(value)) + else: + setattr(cfg, key, value) + else: + logger.log_warning( + f"Key '{key}' not found in {cfg.__class__.__name__}." + ) + return cfg + + +@configclass +class MeshCfg(ShapeCfg): + """Configuration parameters for a triangle mesh shape.""" + + shape_type: str = "Mesh" + + fpath: str = MISSING + """File path to the shape mesh file.""" + + load_option: LoadOption = LoadOption() + """Options for loading and processing the shape. + + Please refer to dexsim.types.LoadOption for more details: http://192.168.3.120/MixedAI/docs_dev/dexsim/tutorial/basics/physics/actor.html + """ + + compute_uv: bool = False + """Whether to compute UV coordinates for the shape. Defaults to False. + + If the shape already has UV coordinates, setting this to True will recompute and overwrite them. + """ + + project_direction: List[float] = [1.0, 1.0, 1.0] + """Direction to project the UV coordinates. Defaults to [1.0, 1.0, 1.0].""" + + +@configclass +class CubeCfg(ShapeCfg): + """Configuration parameters for a cube shape.""" + + shape_type: str = "Cube" + + size: List[float] = [1.0, 1.0, 1.0] + """Size of the cube (in m) as [length, width, height].""" + + +@configclass +class SphereCfg(ShapeCfg): + """Configuration parameters for a sphere shape.""" + + shape_type: str = "Sphere" + + radius: float = 1.0 + """Radius of the sphere (in m).""" + + resolution: int = 20 + """Resolution of the sphere mesh. Defaults to 20.""" diff --git a/embodichain/lab/sim/sim_manager.py b/embodichain/lab/sim/sim_manager.py new file mode 100644 index 00000000..7d2e216e --- /dev/null +++ b/embodichain/lab/sim/sim_manager.py @@ -0,0 +1,1486 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import sys +import dexsim +import torch +import numpy as np +import warp as wp + +from tqdm import tqdm +from pathlib import Path +from copy import deepcopy +from functools import cached_property +from typing import List, Union, Optional, Dict, Tuple, Union, Sequence +from dataclasses import dataclass, asdict, field, MISSING + +# Global cache directories +SIM_CACHE_DIR = Path.home() / ".cache" / "embodichain_cache" +MATERIAL_CACHE_DIR = SIM_CACHE_DIR / "mat_cache" +CONVEX_DECOMP_DIR = SIM_CACHE_DIR / "convex_decomposition" +REACHABLE_XPOS_DIR = SIM_CACHE_DIR / "robot_reachable_xpos" + +from dexsim.types import ( + Backend, + ThreadMode, + PhysicalAttr, + ActorType, + RigidBodyShape, + RigidBodyGPUAPIReadType, + ArticulationGPUAPIReadType, +) +from dexsim.engine import CudaArray, Material +from dexsim.models import MeshObject +from dexsim.render import Light as _Light, LightType +from dexsim.render import GizmoController + +from embodichain.lab.sim.objects import ( + RigidObject, + RigidObjectGroup, + SoftObject, + Articulation, + Robot, + Light, +) +from embodichain.lab.sim.objects.gizmo import Gizmo +from embodichain.lab.sim.sensors import ( + SensorCfg, + BaseSensor, + Camera, + StereoCamera, +) +from embodichain.lab.sim.cfg import ( + PhysicsCfg, + MarkerCfg, + GPUMemoryCfg, + LightCfg, + RigidObjectCfg, + SoftObjectCfg, + RigidObjectGroupCfg, + ArticulationCfg, + RobotCfg, +) +from embodichain.lab.sim import VisualMaterial, VisualMaterialCfg +from embodichain.data.assets import SimResources +from embodichain.utils import configclass, logger + +__all__ = [ + "SimulationManager", + "SimulationManagerCfg", + "SIM_CACHE_DIR", + "MATERIAL_CACHE_DIR", + "CONVEX_DECOMP_DIR", + "REACHABLE_XPOS_DIR", +] + + +@configclass +class SimulationManagerCfg: + """Global robot simulation configuration.""" + + width: int = 1920 + """The width of the simulation window.""" + + height: int = 1080 + """The height of the simulation window.""" + + headless: bool = False + """Whether to run the simulation in headless mode (no Window).""" + + enable_rt: bool = False + """Whether to enable ray tracing rendering.""" + + enable_denoiser: bool = True + """Whether to enable denoising for ray tracing rendering.""" + + spp: int = 64 + """Samples per pixel for ray tracing rendering. This parameter is only valid when ray tracing is enabled and enable_denoiser is False.""" + + gpu_id: int = 0 + """The gpu index that the simulation engine will be used. + + Note: it will affect the gpu physics device if using gpu physics. + """ + + thread_mode: ThreadMode = ThreadMode.RENDER_SHARE_ENGINE + """The threading mode for the simulation engine. + + - RENDER_SHARE_ENGINE: The rendering thread shares the same thread with the simulation engine. + - RENDER_SCENE_SHARE_ENGINE: The rendering thread and scene update thread share the same thread with the simulation engine. + """ + + arena_space: float = 5.0 + """The distance between each arena when building multiple arenas.""" + + physics_dt: float = 1.0 / 100.0 + """The time step for the physics simulation.""" + + sim_device: Union[str, torch.device] = "cpu" + """The device for the simulation engine. Can be 'cpu', 'cuda', or a torch.device object.""" + + physics_config: PhysicsCfg = field(default_factory=PhysicsCfg) + """The physics configuration parameters.""" + gpu_memory_config: GPUMemoryCfg = field(default_factory=GPUMemoryCfg) + """The GPU memory configuration parameters.""" + + +class SimulationManager: + r"""Global Embodied AI simulation manager. + + This class is used to manage the global simulation environment and simulated assets. + - assets loading, creation, modification and deletion. + - assets include robots, fixed actors, dynamic actors and background. + - manager the scenes and the simulation environment. + - parallel scenes simulation on both CPU and GPU. + - sensors arrangement + - lighting and indirect lighting + - physics simulation parameters control + - ... + + Note: + 1. The arena is used as a standalone space for robots to simulate in. When :meth:`build_multiple_arenas` is called, + it will create multiple arenas in a grid pattern. Meanwhile, each simulation assets adding interface will + take an additional parameter `arena_index` to specify which arena to place the asset. The name of the asset to + be added will be appended with the arena index to avoid name conflict. + 2. In GUI mode, the physics will be set to a fps (or a wait time for manual mode) for better visualization. + + + Args: + sim_config (SimulationManagerCfg, optional): simulation configuration. Defaults to SimulationManagerCfg(). + """ + + SUPPORTED_SENSOR_TYPES = {"Camera": Camera, "StereoCamera": StereoCamera} + + def __init__( + self, sim_config: SimulationManagerCfg = SimulationManagerCfg() + ) -> None: + # Cache paths + self._sim_cache_dir = SIM_CACHE_DIR + self._material_cache_dir = MATERIAL_CACHE_DIR + self._convex_decomp_dir = CONVEX_DECOMP_DIR + self._reachable_xpos_dir = REACHABLE_XPOS_DIR + + # Setup cache file path. + for path in [ + self._sim_cache_dir, + self._material_cache_dir, + self._convex_decomp_dir, + self._reachable_xpos_dir, + ]: + os.makedirs(path, exist_ok=True) + + self.sim_config = sim_config + self.device = torch.device("cpu") + + world_config = self._convert_sim_config(sim_config) + + # Initialize warp runtime context before creating the world. + wp.init() + self._world = dexsim.World(world_config) + + fps = int(1.0 / sim_config.physics_dt) + self._world.set_physics_fps(fps) + + self._world.set_time_scale(1.0) + self._world.set_delta_time(sim_config.physics_dt) + self._world.show_coordinate_axis(False) + + if sys.platform == "linux": + dexsim.set_physics_config(**sim_config.physics_config.to_dexsim_args()) + dexsim.set_physics_gpu_memory_config( + **sim_config.gpu_memory_config.to_dict() + ) + + self._is_initialized_gpu_physics = False + self._ps = self._world.get_physics_scene() + + # activate physics + self.enable_physics(True) + + self._env = self._world.get_env() + + self._default_resources = SimResources() + + # set unique material path to accelerate material creation. + if self.sim_config.enable_rt is False: + self._env.set_unique_mat_path( + os.path.join(self._material_cache_dir, "dexsim_mat") + ) + + # arena is used as a standalone space for robots to simulate in. + self._arenas: List[dexsim.environment.Arena] = [] + + # gizmo management + self._gizmos: Dict[str, object] = dict() # Store active gizmos + + # marker management + self._markers: Dict[str, MeshObject] = dict() + + self._rigid_objects: Dict[str, RigidObject] = dict() + self._rigid_object_groups: Dict[str, RigidObjectGroup] = dict() + self._soft_objects: Dict[str, SoftObject] = dict() + self._articulations: Dict[str, Articulation] = dict() + self._robots: Dict[str, Robot] = dict() + + self._sensors: Dict[str, BaseSensor] = dict() + self._lights: Dict[str, _Light] = dict() + + # material placeholder. + self._visual_materials: Dict[str, VisualMaterial] = dict() + + # Global texture cache for material creation or randomization. + # The structure is keys to the loaded texture data. The keys represent the texture group. + self._texture_cache: Dict[str, Union[torch.Tensor, List[torch.Tensor]]] = dict() + + # TODO: maybe need to add some interface to interact with background and layouts. + # background and layouts are 3d assets that can has only render body for visualization. + + self._create_default_plane() + self.set_default_background() + + def _convert_sim_config( + self, sim_config: SimulationManagerCfg + ) -> dexsim.WorldConfig: + world_config = dexsim.WorldConfig() + win_config = dexsim.WindowsConfig() + win_config.width = sim_config.width + win_config.height = sim_config.height + world_config.win_config = win_config + world_config.open_windows = not sim_config.headless + self.is_window_opened = not sim_config.headless + world_config.backend = Backend.VULKAN + world_config.thread_mode = sim_config.thread_mode + world_config.cache_path = str(self._material_cache_dir) + world_config.length_tolerance = sim_config.physics_config.length_tolerance + world_config.speed_tolerance = sim_config.physics_config.speed_tolerance + + if sim_config.enable_rt: + world_config.renderer = dexsim.types.Renderer.FASTRT + if sim_config.enable_denoiser is False: + world_config.raytrace_config.spp = sim_config.spp + world_config.raytrace_config.open_denoise = False + + if type(sim_config.sim_device) is str: + self.device = torch.device(sim_config.sim_device) + else: + self.device = sim_config.sim_device + + if self.device.type == "cuda": + world_config.enable_gpu_sim = True + world_config.direct_gpu_api = True + + if self.device.index is not None and sim_config.gpu_id != self.device.index: + logger.log_warning( + f"Conflict gpu_id {sim_config.gpu_id} and device index {self.device.index}. Using device index." + ) + sim_config.gpu_id = self.device.index + + self.device = torch.device(f"cuda:{sim_config.gpu_id}") + + world_config.gpu_id = sim_config.gpu_id + + return world_config + + def get_default_resources(self) -> SimResources: + """Get the default resources instance. + + Returns: + SimResources: The default resources path. + """ + return self._default_resources + + @property + def num_envs(self) -> int: + """Get the number of arenas in the simulation. + + Returns: + int: number of arenas. + """ + return len(self._arenas) if len(self._arenas) > 0 else 1 + + @cached_property + def is_use_gpu_physics(self) -> bool: + """Check if the physics simulation is using GPU.""" + world_config = dexsim.get_world_config() + return self.device.type == "cuda" and world_config.enable_gpu_sim + + @property + def is_rt_enabled(self) -> bool: + """Check if Ray Tracing rendering backend is enabled.""" + return self.sim_config.enable_rt + + @property + def is_physics_manually_update(self) -> bool: + return self._world.is_physics_manually_update() + + @property + def asset_uids(self) -> List[str]: + """Get all assets uid in the simulation. + + The assets include lights, sensors, robots, rigid objects and articulations. + + Returns: + List[str]: list of all assets uid. + """ + uid_list = ["default_plane"] + uid_list.extend(list(self._lights.keys())) + uid_list.extend(list(self._sensors.keys())) + uid_list.extend(list(self._robots.keys())) + uid_list.extend(list(self._rigid_objects.keys())) + uid_list.extend(list(self._rigid_object_groups.keys())) + uid_list.extend(list(self._articulations.keys())) + return uid_list + + def enable_physics(self, enable: bool) -> None: + """Enable or disable physics simulation. + + Args: + enable (bool): whether to enable physics simulation. + """ + self._world.enable_physics(enable) + + def set_manual_update(self, enable: bool) -> None: + """Set manual update for physics simulation. + + If enable is True, the physics simulation will be updated manually by calling :meth:`update`. + If enable is False, the physics simulation will be updated automatically by the engine thread loop. + + Args: + enable (bool): whether to enable manual update. + """ + self._world.set_manual_update(enable) + + def init_gpu_physics(self) -> None: + """Initialize the GPU physics simulation.""" + if self.device.type != "cuda": + logger.log_warning( + "The simulation device is not cuda, cannot initialize GPU physics." + ) + return + + if self._is_initialized_gpu_physics: + return + + # init rigid body. + rigid_body_num = ( + 0 + if self._get_non_static_rigid_obj_num() == 0 + else len(self._ps.gpu_rigid_indices) + ) + self._rigid_body_pose = torch.zeros( + (rigid_body_num, 7), dtype=torch.float32, device=self.device + ) + + # init articulation. + articulation_num = ( + 0 + if len(self._articulations) == 0 and len(self._robots) == 0 + else len(self._ps.gpu_articulation_indices) + ) + max_link_count = self._ps.gpu_get_articulation_max_link_count() + self._link_pose = torch.zeros( + (articulation_num, max_link_count, 7), + dtype=torch.float32, + device=self.device, + ) + for art in self._articulations.values(): + art.reallocate_body_data() + for robot in self._robots.values(): + robot.reallocate_body_data() + + # We do not perform reallocate body data for robot. + + self._is_initialized_gpu_physics = True + + def render_camera_group(self) -> None: + """Render all camera group in the simulation. + + Note: This interface is only valid when Ray Tracing rendering backend is enabled. + """ + + if self.is_rt_enabled: + self._world.render_camera_group() + else: + logger.log_warning( + "This interface is only valid when Ray Tracing rendering backend is enabled." + ) + + def update(self, physics_dt: Optional[float] = None, step: int = 10) -> None: + """Update the physics. + + Args: + physics_dt (Optional[float], optional): the time step for physics simulation. Defaults to None. + step (int, optional): the number of steps to update physics. Defaults to 10. + """ + if self.is_use_gpu_physics and not self._is_initialized_gpu_physics: + logger.log_warning( + f"Using GPU physics, but not initialized yet. Forcing initialization." + ) + self.init_gpu_physics() + + if self.is_physics_manually_update: + if physics_dt is None: + physics_dt = self.sim_config.physics_dt + for i in range(step): + self._world.update(physics_dt) + + if self.sim_config.enable_rt is False: + self._sync_gpu_data() + + else: + logger.log_warning("Physics simulation is not manually updated.") + + def _sync_gpu_data(self) -> None: + if not self.is_use_gpu_physics: + return + + if not self._is_initialized_gpu_physics: + logger.log_warning( + "GPU physics is not initialized. Skipping GPU data synchronization." + ) + return + + if self.is_window_opened or self._sensors: + if len(self._rigid_body_pose) > 0: + self._ps.gpu_fetch_rigid_body_data( + data=CudaArray(self._rigid_body_pose), + gpu_indices=self._ps.gpu_rigid_indices, + data_type=RigidBodyGPUAPIReadType.POSE, + ) + + if len(self._link_pose) > 0: + self._ps.gpu_fetch_link_data( + data=CudaArray(self._link_pose), + gpu_indices=self._ps.gpu_articulation_indices, + data_type=ArticulationGPUAPIReadType.LINK_GLOBAL_POSE, + ) + + # TODO: might be optimized. + self._world.sync_poses_gpu_to_cpu( + rigid_pose=CudaArray(self._rigid_body_pose), + link_pose=CudaArray(self._link_pose), + ) + + def get_env(self, arena_index: int = -1) -> dexsim.environment.Arena: + """Get the arena or env by index. + + If arena_index is -1, return the global env. + If arena_index is valid, return the corresponding arena. + + Args: + arena_index (int, optional): the index of arena to get, -1 for global env. Defaults to -1. + + Returns: + dexsim.environment.Arena: The arena or global env. + """ + if arena_index >= 0: + if arena_index > len(self._arenas) - 1: + logger.log_error( + f"Invalid arena index: {arena_index}. Current number of arenas: {len(self._arenas)}" + ) + return self._arenas[arena_index] + else: + return self._env + + def get_world(self) -> dexsim.World: + return self._world + + def open_window(self) -> None: + """Open the simulation window.""" + self._world.open_window() + self.is_window_opened = True + + def close_window(self) -> None: + """Close the simulation window.""" + self._world.close_window() + self.is_window_opened = False + + def build_multiple_arenas(self, num: int, space: Optional[float] = None) -> None: + """Build multiple arenas in a grid pattern. + + This interface is used for vectorized simulation. + + Args: + num (int): number of arenas to build. + space (float, optional): The distance between each arena. Defaults to the arena_space in sim_config. + """ + + if space is None: + space = self.sim_config.arena_space + + if num <= 0: + logger.log_warning("Number of arenas must be greater than 0.") + return + + scene_grid_length = int(np.ceil(np.sqrt(num))) + + for i in range(num): + arena = self._env.add_arena(f"arena_{i}") + + id_x, id_y = i % scene_grid_length, i // scene_grid_length + arena.set_root_node_position([id_x * space, id_y * space, 0]) + self._arenas.append(arena) + + def set_indirect_lighting(self, name: str) -> None: + """Set indirect lighting. + + Args: + name (str): name of path of the indirect lighting. + """ + if name.startswith("/") is False: + ibl_path = self._default_resources.get_ibl_path(name) + logger.log_info(f"Set IBL {name} from sim default resources.") + else: + ibl_path = name + logger.log_info(f"Set IBL {name} from custom path.") + + self._env.set_IBL(ibl_path) + + def set_emission_light( + self, color: Optional[Sequence[float]] = None, intensity: Optional[float] = None + ) -> None: + """Set environment emission light. + + Args: + color (Sequence[float]): color of the light. + intensity (float): intensity of the light. + """ + if color is None: + self._env.set_env_light_emission(color) + if intensity is None: + self._env.set_env_light_intensity(intensity) + + def _create_default_plane(self): + default_length = 1000 + repeat_uv_size = int(default_length / 2) + self._default_plane = self._env.create_plane( + 0, default_length, repeat_uv_size, repeat_uv_size + ) + self._default_plane.set_name("default_plane") + plane_collision = self._env.create_cube( + default_length, default_length, default_length / 10 + ) + plane_collision_pose = np.eye(4, dtype=float) + plane_collision_pose[2, 3] = -default_length / 20 - 0.001 + plane_collision.set_local_pose(plane_collision_pose) + plane_collision.add_rigidbody(ActorType.KINEMATIC, RigidBodyShape.CONVEX) + + # TODO: add default physics attributes for the plane. + + def set_default_background(self) -> None: + """Set default background.""" + + mat_name = "plane_mat" + mat = None + mat_path = self._default_resources.get_material_path("PlaneDark") + color_texture = os.path.join(mat_path, "PlaneDark_2K_Color.jpg") + roughness_texture = os.path.join(mat_path, "PlaneDark_2K_Roughness.jpg") + mat = self.create_visual_material( + cfg=VisualMaterialCfg( + uid=mat_name, + base_color_texture=color_texture, + roughness_texture=roughness_texture, + ) + ) + + if self.sim_config.enable_rt: + self.set_emission_light([0.1, 0.1, 0.1], 10.0) + else: + self.set_indirect_lighting("lab_day") + + self._default_plane.set_material(mat.get_instance("plane_mat").mat) + self._visual_materials[mat_name] = mat + + def set_texture_cache( + self, key: str, texture: Union[torch.Tensor, List[torch.Tensor]] + ) -> None: + """Set the texture to the global texture cache. + + Args: + key (str): The key of the texture. + texture (Union[torch.Tensor, List[torch.Tensor]]): The texture data. + """ + self._texture_cache[key] = texture + + def get_texture_cache( + self, key: Optional[str] = None + ) -> Optional[Union[torch.Tensor, List[torch.Tensor]]]: + """Get the texture from the global texture cache. + + Args: + key (str, optional): The key of the texture. If None, return None. Defaults to None. + + Returns: + Optional[Union[torch.Tensor, List[torch.Tensor]]]: The texture if found, otherwise None. + """ + if key is None: + return self._texture_cache + + if key not in self._texture_cache: + logger.log_warning(f"Texture {key} not found in global texture cache.") + return None + return self._texture_cache[key] + + def get_asset( + self, uid: str + ) -> Optional[Union[Light, BaseSensor, Robot, RigidObject, Articulation]]: + """Get an asset by its UID. + + The asset can be a light, sensor, robot, rigid object or articulation. + + Args: + uid (str): The UID of the asset. + + Returns: + Light | BaseSensor | Robot | RigidObject | Articulation | None: The asset instance if found, otherwise None. + """ + if uid in self._lights: + return self._lights[uid] + if uid in self._sensors: + return self._sensors[uid] + if uid in self._robots: + return self._robots[uid] + if uid in self._rigid_objects: + return self._rigid_objects[uid] + if uid in self._rigid_object_groups: + return self._rigid_object_groups[uid] + if uid in self._articulations: + return self._articulations[uid] + + logger.log_warning(f"Asset {uid} not found.") + return None + + def add_light(self, cfg: LightCfg) -> Light: + """Create a light in the scene. + + Args: + cfg (LightCfg): Configuration for the light, including type, color, intensity, and radius. + + Returns: + Light: The created light instance. + """ + if cfg.uid is None: + uid = "light" + cfg.uid = uid + else: + uid = cfg.uid + + if uid in self._lights: + logger.log_error(f"Light {uid} already exists.") + + light_type = cfg.light_type + if light_type == "point": + light_type = LightType.POINT + else: + logger.log_error( + f"Unsupported light type: {light_type}. Supported types: point." + ) + + env_list = [self._env] if len(self._arenas) == 0 else self._arenas + light_list = [] + for i, env in enumerate(env_list): + light_name = f"{uid}_{i}" + light = env.create_light(light_name, light_type) + light_list.append(light) + + batch_lights = Light(cfg=cfg, entities=light_list) + + self._lights[uid] = batch_lights + + return batch_lights + + def get_light(self, uid: str) -> Optional[Light]: + """Get a light by its UID. + + Args: + uid (str): The UID of the light. + + Returns: + Light | None: The light instance if found, otherwise None. + """ + if uid not in self._lights: + logger.log_warning(f"Light {uid} not found.") + return None + return self._lights[uid] + + def add_rigid_object( + self, + cfg: RigidObjectCfg, + ) -> RigidObject: + """Add a rigid object to the scene. + + Args: + cfg (RigidObjectCfg): Configuration for the rigid object. + + Returns: + RigidObject: The added rigid object instance handle. + """ + from embodichain.lab.sim.utility.sim_utils import ( + load_mesh_objects_from_cfg, + ) + + uid = cfg.uid + if uid is None: + logger.log_error("Rigid object uid must be specified.") + if uid in self._rigid_objects: + logger.log_error(f"Rigid object {uid} already exists.") + + env_list = [self._env] if len(self._arenas) == 0 else self._arenas + obj_list = load_mesh_objects_from_cfg( + cfg=cfg, + env_list=env_list, + cache_dir=self._convex_decomp_dir, + ) + + rigid_obj = RigidObject(cfg=cfg, entities=obj_list, device=self.device) + + if cfg.shape.visual_material: + mat = self.create_visual_material(cfg.shape.visual_material) + rigid_obj.set_visual_material(mat) + + self._rigid_objects[uid] = rigid_obj + + return rigid_obj + + def add_soft_object(self, cfg: SoftObjectCfg) -> SoftObject: + """Add a soft object to the scene. + + Args: + cfg (SoftObjectCfg): Configuration for the soft object. + + Returns: + SoftObject: The added soft object instance handle. + """ + if not self.is_use_gpu_physics: + logger.log_error("Soft object requires GPU physics to be enabled.") + + from embodichain.lab.sim.utility import ( + load_soft_object_from_cfg, + ) + + uid = cfg.uid + if uid is None: + logger.log_error("Soft object uid must be specified.") + + env_list = [self._env] if len(self._arenas) == 0 else self._arenas + obj_list = load_soft_object_from_cfg( + cfg=cfg, + env_list=env_list, + ) + + soft_obj = SoftObject(cfg=cfg, entities=obj_list, device=self.device) + self._soft_objects[uid] = soft_obj + return soft_obj + + def get_rigid_object(self, uid: str) -> Optional[RigidObject]: + """Get a rigid object by its unique ID. + + Args: + uid (str): The unique ID of the rigid object. + + Returns: + Optional[RigidObject]: The rigid object instance if found, otherwise None. + """ + if uid not in self._rigid_objects: + logger.log_warning(f"Rigid object {uid} not found.") + return None + return self._rigid_objects[uid] + + def get_rigid_object_uid_list(self) -> List[str]: + """Get current rigid body uid list + + Returns: + List[str]: list of rigid body uid. + """ + return list(self._rigid_objects.keys()) + + def add_rigid_object_group(self, cfg: RigidObjectGroupCfg) -> RigidObjectGroup: + """Add a rigid object group to the scene. + + Args: + cfg (RigidObjectGroupCfg): Configuration for the rigid object group. + """ + from embodichain.lab.sim.utility.sim_utils import ( + load_mesh_objects_from_cfg, + ) + + uid = cfg.uid + if uid is None: + logger.log_error("Rigid object group uid must be specified.") + if uid in self._rigid_object_groups: + logger.log_error(f"Rigid object group {uid} already exists.") + + if cfg.body_type == "static": + logger.log_error("Rigid object group cannot be static.") + + env_list = [self._env] if len(self._arenas) == 0 else self._arenas + + obj_group_list = [] + for key, rigid_cfg in tqdm( + cfg.rigid_objects.items(), desc="Loading rigid objects" + ): + obj_list = load_mesh_objects_from_cfg( + cfg=rigid_cfg, + env_list=env_list, + cache_dir=self._convex_decomp_dir, + ) + obj_group_list.append(obj_list) + + # Convert [a1, a2, ...], [b1, b2, ...] to [(a1, b1, ...), (a2, b2, ...), ...] + obj_group_list = list(zip(*obj_group_list)) + rigid_obj_group = RigidObjectGroup( + cfg=cfg, entities=obj_group_list, device=self.device + ) + + self._rigid_object_groups[uid] = rigid_obj_group + + return rigid_obj_group + + def get_rigid_object_group(self, uid: str) -> Optional[RigidObjectGroup]: + """Get a rigid object group by its unique ID. + + Args: + uid (str): The unique ID of the rigid object group. + + Returns: + Optional[RigidObjectGroup]: The rigid object group instance if found, otherwise None. + """ + if uid not in self._rigid_object_groups: + logger.log_warning(f"Rigid object group {uid} not found.") + return None + return self._rigid_object_groups[uid] + + def _get_non_static_rigid_obj_num(self) -> int: + """Get the number of non-static rigid objects in the scene. + + Returns: + int: The number of non-static rigid objects. + """ + count = 0 + for obj in self._rigid_objects.values(): + if obj.cfg.body_type != "static": + count += 1 + return count + + def add_articulation( + self, + cfg: ArticulationCfg, + ) -> Articulation: + """Add an articulation to the scene. + + Args: + cfg (ArticulationCfg): Configuration for the articulation. + + Returns: + Articulation: The added articulation instance handle. + """ + + uid = cfg.uid + if uid is None: + uid = os.path.splitext(os.path.basename(cfg.fpath))[0] + cfg.uid = uid + if uid in self._articulations: + logger.log_error(f"Articulation {uid} already exists.") + + env_list = [self._env] if len(self._arenas) == 0 else self._arenas + obj_list = [] + + for env in env_list: + art = env.load_urdf(cfg.fpath) + obj_list.append(art) + + articulation = Articulation(cfg=cfg, entities=obj_list, device=self.device) + + self._articulations[uid] = articulation + + return articulation + + def get_articulation(self, uid: str) -> Optional[Articulation]: + """Get an articulation by its unique ID. + + Args: + uid (str): The unique ID of the articulation. + + Returns: + Optional[Articulation]: The articulation instance if found, otherwise None. + """ + if uid not in self._articulations: + logger.log_warning(f"Articulation {uid} not found.") + return None + return self._articulations[uid] + + def get_articulation_uid_list(self) -> List[str]: + """Get current articulation uid list + + Returns: + List[str]: list of articulation uid. + """ + return list(self._articulations.keys()) + + def add_robot(self, cfg: RobotCfg) -> Optional[Robot]: + """Add a Robot to the scene. + + Args: + cfg (RobotCfg): Configuration for the robot. + + Returns: + Optional[Robot]: The added robot instance handle, or None if failed. + """ + + uid = cfg.uid + if cfg.fpath is None: + if cfg.urdf_cfg is None: + logger.log_error( + "Robot configuration must have a valid fpath or urdf_cfg." + ) + return None + + cfg.fpath = cfg.urdf_cfg.assemble_urdf() + + if uid is None: + uid = os.path.splitext(os.path.basename(cfg.fpath))[0] + cfg.uid = uid + if uid in self._robots: + logger.log_error(f"Robot {uid} already exists.") + return self._robots[uid] + + env_list = [self._env] if len(self._arenas) == 0 else self._arenas + obj_list = [] + + for env in env_list: + art = env.load_urdf(cfg.fpath) + obj_list.append(art) + + robot = Robot(cfg=cfg, entities=obj_list, device=self.device) + + self._robots[uid] = robot + + return robot + + def get_robot(self, uid: str) -> Optional[Robot]: + """Get a Robot by its unique ID. + + Args: + uid (str): The unique ID of the robot. + + Returns: + Optional[Robot]: The robot instance if found, otherwise None. + """ + if uid not in self._robots: + logger.log_warning(f"Robot {uid} not found.") + return None + return self._robots[uid] + + def get_robot_uid_list(self) -> List[str]: + """ + Retrieves a list of unique identifiers (UIDs) for all robots in the V2 system. + + Returns: + list: A list containing the UIDs of the robots. + """ + return list(self._robots.keys()) + + def enable_gizmo( + self, uid: str, control_part: Optional[str] = None, gizmo_cfg: object = None + ) -> None: + """Enable gizmo control for any simulation object (Robot, RigidObject, Camera, etc.). + + Args: + uid (str): UID of the object to attach gizmo to (searches in robots, rigid_objects, sensors, etc.) + control_part (Optional[str], optional): Control part name for robots. Defaults to "arm". + gizmo_cfg (object, optional): Gizmo configuration object. Defaults to None. + """ + # Create gizmo key combining uid and control_part + gizmo_key = f"{uid}:{control_part}" if control_part else uid + + # Check if gizmo already exists + if gizmo_key in self._gizmos: + logger.log_warning( + f"Gizmo for '{uid}' with control_part '{control_part}' already exists." + ) + return + + # Search for target object in different collections + target = None + object_type = None + + if uid in self._robots: + target = self._robots[uid] + object_type = "robot" + elif uid in self._rigid_objects: + target = self._rigid_objects[uid] + object_type = "rigid_object" + elif uid in self._sensors: + target = self._sensors[uid] + object_type = "sensor" + + else: + logger.log_error( + f"Object with uid '{uid}' not found in any collection (robots, rigid_objects, sensors, articulations)." + ) + return + + try: + gizmo = Gizmo(target, gizmo_cfg, control_part) + self._gizmos[gizmo_key] = gizmo + logger.log_info( + f"Gizmo enabled for {object_type} '{uid}' with control_part '{control_part}'" + ) + + # Initialize GizmoController if not already done. + if not hasattr(self, "_gizmo_controller") or self._gizmo_controller is None: + windows = ( + self._world.get_windows() + if hasattr(self._world, "get_windows") + else None + ) + self._gizmo_controller = GizmoController(windows) + print("GizmoController attributes and methods:") + print(dir(self._gizmo_controller)) + + except Exception as e: + logger.log_error( + f"Failed to create gizmo for {object_type} '{uid}' with control_part '{control_part}': {e}" + ) + + def disable_gizmo(self, uid: str, control_part: Optional[str] = None) -> None: + """Disable and remove gizmo for a robot. + + Args: + uid (str): Object UID to disable gizmo for + control_part (Optional[str], optional): Control part name for robots. Defaults to None. + """ + # Create gizmo key combining uid and control_part + gizmo_key = f"{uid}:{control_part}" if control_part else uid + + if gizmo_key not in self._gizmos: + from embodichain.utils import logger + + logger.log_warning( + f"No gizmo found for '{uid}' with control_part '{control_part}'." + ) + return + + try: + gizmo = self._gizmos[gizmo_key] + if gizmo is not None: + gizmo.destroy() + del self._gizmos[gizmo_key] + + from embodichain.utils import logger + + logger.log_info( + f"Gizmo disabled for '{uid}' with control_part '{control_part}'" + ) + + except Exception as e: + from embodichain.utils import logger + + logger.log_error( + f"Failed to disable gizmo for '{uid}' with control_part '{control_part}': {e}" + ) + + def get_gizmo(self, uid: str, control_part: Optional[str] = None) -> object: + """Get gizmo instance for a robot. + + Args: + uid (str): Object UID + control_part (Optional[str], optional): Control part name for robots. Defaults to None. + + Returns: + object: Gizmo instance if found, None otherwise. + """ + # Create gizmo key combining uid and control_part + gizmo_key = f"{uid}:{control_part}" if control_part else uid + return self._gizmos.get(gizmo_key, None) + + def has_gizmo(self, uid: str, control_part: Optional[str] = None) -> bool: + """Check if a gizmo exists for the given UID and control part. + + Args: + uid (str): Object UID to check + control_part (Optional[str], optional): Control part name for robots. Defaults to None. + + Returns: + bool: True if gizmo exists, False otherwise. + """ + # Create gizmo key combining uid and control_part + gizmo_key = f"{uid}:{control_part}" if control_part else uid + return gizmo_key in self._gizmos + + def list_gizmos(self) -> Dict[str, bool]: + """List all active gizmos and their status. + + Returns: + Dict[str, bool]: Dictionary mapping gizmo keys (uid:control_part) to gizmo active status. + """ + return { + gizmo_key: (gizmo is not None) for gizmo_key, gizmo in self._gizmos.items() + } + + def update_gizmos(self): + """Update all active gizmos.""" + for gizmo_key, gizmo in list( + self._gizmos.items() + ): # Use list() to avoid modification during iteration + if gizmo is not None: + try: + gizmo.update() + except Exception as e: + from embodichain.utils import logger + + logger.log_error(f"Error updating gizmo '{gizmo_key}': {e}") + + def toggle_gizmo_visibility( + self, uid: str, control_part: Optional[str] = None + ) -> bool: + """ + Toggle the visibility of a gizmo by uid and optional control_part. + Returns the new visibility state (True=visible, False=hidden), or None if not found. + """ + gizmo = self.get_gizmo(uid, control_part) + if gizmo is not None: + return gizmo.toggle_visibility() + return None + + def set_gizmo_visibility( + self, uid: str, visible: bool, control_part: Optional[str] = None + ) -> None: + """ + Set the visibility of a gizmo by uid and optional control_part. + """ + gizmo = self.get_gizmo(uid, control_part) + if gizmo is not None: + gizmo.set_visibility(visible) + + def add_sensor(self, sensor_cfg: SensorCfg) -> BaseSensor: + """General interface to add a sensor to the scene and returns a handle. + + Args: + sensor_cfg (SensorCfg): configuration for the sensor. + + Returns: + BaseSensor: The added sensor instance handle. + """ + sensor_type = sensor_cfg.sensor_type + if sensor_type not in self.SUPPORTED_SENSOR_TYPES: + logger.log_warning(f"Unsupported sensor type: {sensor_type}") + return None + + sensor_uid = sensor_cfg.uid + if sensor_uid is None: + sensor_uid = f"{sensor_type.lower()}_{len(self._sensors)}" + sensor_cfg.uid = sensor_uid + + if sensor_uid in self._sensors: + logger.log_warning(f"Sensor {sensor_uid} already exists.") + return None + + sensor = self.SUPPORTED_SENSOR_TYPES[sensor_type](sensor_cfg, self.device) + + self._sensors[sensor_uid] = sensor + + # Check if the sensor needs to change the parent frame. + + return sensor + + def get_sensor(self, uid: str) -> Optional[BaseSensor]: + """Get a sensor by its UID. + + Args: + uid (str): The UID of the sensor. + + Returns: + BaseSensor | None: The sensor instance if found, otherwise None. + """ + if uid not in self._sensors: + logger.log_warning(f"Sensor {uid} not found.") + return None + return self._sensors[uid] + + def get_sensor_uid_list(self) -> List[str]: + """Get current sensor uid list + + Returns: + List[str]: list of sensor uid. + """ + return list(self._sensors.keys()) + + def remove_asset(self, uid: str) -> bool: + """Remove an asset by its UID. + + The asset can be a light, sensor, robot, rigid object or articulation. + + Note: + Currently, lights and sensors are not supported to be removed. + + Args: + uid (str): The UID of the asset. + Returns: + bool: True if the asset is removed successfully, otherwise False. + """ + if uid in self._rigid_objects: + obj = self._rigid_objects.pop(uid) + obj.destroy() + return True + + if uid in self._soft_objects: + obj = self._soft_objects.pop(uid) + obj.destroy() + return True + + if uid in self._rigid_object_groups: + group = self._rigid_object_groups.pop(uid) + group.destroy() + return True + + if uid in self._articulations: + art = self._articulations.pop(uid) + art.destroy() + return True + + if uid in self._robots: + robot = self._robots.pop(uid) + robot.destroy() + return True + + return False + + def get_asset( + self, uid: str + ) -> Optional[Union[RigidObject, Articulation, Robot, Light, BaseSensor]]: + """Get an asset by its UID. + + The asset can be a rigid object, articulation or robot. + + Args: + uid (str): The UID of the asset. + """ + if uid in self._rigid_objects: + return self._rigid_objects[uid] + + if uid in self._articulations: + return self._articulations[uid] + + if uid in self._robots: + return self._robots[uid] + + if uid in self._lights: + return self._lights[uid] + + if uid in self._sensors: + return self._sensors[uid] + + logger.log_warning(f"Asset {uid} not found.") + return None + + def draw_marker( + self, + cfg: MarkerCfg, + ) -> MeshObject: + """Draw visual markers in the simulation scene for debugging and visualization. + + Args: + cfg (MarkerCfg): Marker configuration with the following key parameters: + - name (str): Unique identifier for the marker group + - marker_type (str): Type of marker ("axis" currently supported) + - axis_xpos (np.ndarray | List[np.ndarray]): 4x4 transformation matrices + for marker positions and orientations + - axis_size (float): Thickness of axis arrows + - axis_len (float): Length of axis arrows + - arena_index (int): Arena index for placement (-1 for global) + + Returns: + List[MeshObject]: List of created marker handles, False if invalid input, + None if no poses provided. + + Example: + ```python + cfg = MarkerCfg(name="test_axis", marker_type="axis", axis_xpos=np.eye(4)) + markers = sim.draw_marker(cfg) + ``` + """ + # Validate marker type + if cfg.marker_type != "axis": + logger.log_error( + f"Unsupported marker type '{cfg.marker_type}'. Currently only 'axis' is supported." + ) + return False + + draw_xpos = deepcopy(cfg.axis_xpos) + draw_xpos = np.array(draw_xpos) + if draw_xpos.ndim == 2: + if draw_xpos.shape == (4, 4): + draw_xpos = np.expand_dims(draw_xpos, axis=0) + else: + logger.log_error( + f"axis_xpos must be of shape (N, 4, 4), got {draw_xpos.shape}." + ) + return False + elif draw_xpos.ndim != 3 or draw_xpos.shape[1:] != (4, 4): + logger.log_error( + f"axis_xpos must be of shape (N, 4, 4), got {draw_xpos.shape}." + ) + return False + + original_name = cfg.name + name = original_name + count = 0 + + while name in self._markers: + count += 1 + name = f"{original_name}_{count}" + if count > 0: + logger.log_warning( + f"Marker name '{original_name}' already exists. Using '{name}'." + ) + + marker_num = len(draw_xpos) + if marker_num == 0: + logger.log_warning(f"No marker poses provided.") + return None + + if cfg.arena_index >= 0: + name = f"{name}_{cfg.arena_index}" + + env = self.get_env(cfg.arena_index) + + # Create markers based on marker type + marker_handles = [] + + if cfg.marker_type == "axis": + # Create coordinate axes + axis_option = dexsim.types.AxisOption( + lx=cfg.axis_len, + ly=cfg.axis_len, + lz=cfg.axis_len, + size=cfg.axis_size, + arrow_type=cfg.arrow_type, + corner_type=cfg.corner_type, + tag_type=dexsim.types.AxisTagType.NONE, + ) + + for i, pose in enumerate(draw_xpos): + axis_handle = env.create_axis(axis_option) + axis_handle.set_local_pose(pose) + marker_handles.append(axis_handle) + + # TODO: Add support for other marker types in the future + # elif cfg.marker_type == "line": + # # Create line markers + # pass + # elif cfg.marker_type == "point": + # # Create point markers + # pass + + self._markers[name] = (marker_handles, cfg.arena_index) + + if self.is_physics_manually_update: + self.update(step=1) + + return marker_handles + + def remove_marker(self, name: str) -> bool: + """Remove markers (including axis) with the given name. + + Args: + name (str): The name of the marker to remove. + Returns: + bool: True if the marker was removed successfully, False otherwise. + """ + if name not in self._markers: + logger.log_warning(f"Marker {name} not found.") + return False + try: + env = self.get_env(self._markers[name][1]) + marker_handles, arena_index = self._markers[name] + for marker_handle in marker_handles: + if marker_handle is not None: + env.remove_actor(marker_handle.get_name()) + self._markers.pop(name) + return True + except Exception as e: + logger.log_warning(f"Failed to remove marker {name}: {str(e)}") + return False + + def create_visual_material(self, cfg: VisualMaterialCfg) -> VisualMaterial: + """Create a visual material with given configuration. + + Args: + cfg (VisualMaterialCfg): configuration for the visual material. + + Returns: + VisualMaterial: the created visual material instance handle. + """ + + if cfg.uid in self._visual_materials: + logger.log_warning( + f"Visual material {cfg.uid} already exists. Returning the existing one." + ) + return self._visual_materials[cfg.uid] + + mat: Material = self._env.create_pbr_material(cfg.uid, True) + visual_mat = VisualMaterial(cfg, mat) + + self._visual_materials[cfg.uid] = visual_mat + return visual_mat + + def get_visual_material(self, uid: str) -> VisualMaterial: + """Get visual material by UID. + + Args: + uid (str): uid of visual material. + """ + if uid not in self._visual_materials: + logger.log_warning(f"Visual material {uid} not found.") + return None + + return self._visual_materials[uid] + + def clean_materials(self): + self._visual_materials = {} + self._env.clean_materials() + + def reset_objects_state(self, env_ids: Optional[Sequence[int]] = None) -> None: + """Reset the state of all objects in the scene. + + Args: + env_ids: The environment IDs to reset. If None, reset all environments. + """ + for robot in self._robots.values(): + robot.reset(env_ids) + for articulation in self._articulations.values(): + articulation.reset(env_ids) + for rigid_obj in self._rigid_objects.values(): + rigid_obj.reset(env_ids) + for rigid_obj_group in self._rigid_object_groups.values(): + rigid_obj_group.reset(env_ids) + for light in self._lights.values(): + light.reset(env_ids) + for sensor in self._sensors.values(): + sensor.reset(env_ids) + + def destroy(self) -> None: + """Destroy all simulated assets and release resources.""" + # Clean up all gizmos before destroying the simulation + for uid in list(self._gizmos.keys()): + self.disable_gizmo(uid) + + self.clean_materials() + + self._env.clean() + self._world.quit() diff --git a/embodichain/lab/sim/solvers/__init__.py b/embodichain/lab/sim/solvers/__init__.py new file mode 100644 index 00000000..6f6123fa --- /dev/null +++ b/embodichain/lab/sim/solvers/__init__.py @@ -0,0 +1,23 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .base_solver import SolverCfg, BaseSolver, merge_solver_cfg +from .pytorch_solver import PytorchSolverCfg, PytorchSolver +from .pinocchio_solver import PinocchioSolverCfg, PinocchioSolver +from .differential_solver import DifferentialSolverCfg, DifferentialSolver +from .pink_solver import PinkSolverCfg, PinkSolver +from .opw_solver import OPWSolverCfg, OPWSolver +from .srs_solver import SRSSolverCfg, SRSSolver diff --git a/embodichain/lab/sim/solvers/base_solver.py b/embodichain/lab/sim/solvers/base_solver.py new file mode 100644 index 00000000..af7433cc --- /dev/null +++ b/embodichain/lab/sim/solvers/base_solver.py @@ -0,0 +1,457 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np +from typing import List, Optional, Dict, Any, Union, TYPE_CHECKING, Tuple +from abc import abstractmethod, ABCMeta + +from embodichain.utils import configclass, logger + +if TYPE_CHECKING: + from typing import Self + +from embodichain.lab.sim.utility.solver_utils import create_pk_serial_chain + + +@configclass +class SolverCfg: + """Configuration for the kinematic solver used in the robot simulation.""" + + class_type: str = "BaseSolver" + """The class type of the solver to be used.""" + + urdf_path: Optional[str] = None + """The file path to the URDF model of the robot.""" + + joint_names: Optional[list[str]] = None + """List of joint names for the solver. + + If None, all joints in the URDF will be used. + If specified, only these named joints will be included in the kinematic chain. + """ + + end_link_name: str = None + """The name of the end-effector link for the solver. + + This defines the target link for forward/inverse kinematics calculations. + Must match a link name in the URDF file. + """ + + root_link_name: str = None + """The name of the root/base link for the solver. + + This defines the starting point of the kinematic chain. + Must match a link name in the URDF file. + """ + + # TODO: may be support pos and rot separately for easier manipulation. + tcp: Union[torch.Tensor, np.ndarray] = np.eye(4) + """The tool center point (TCP) position as a 4x4 homogeneous matrix. + + This represents the position and orientation of the tool in the robot's end-effector frame. + """ + + ik_nearest_weight: Optional[List[float]] = None + """Weights for the inverse kinematics nearest calculation. + + The weights influence how the solver prioritizes closeness to the seed position + when multiple solutions are available. + """ + + @abstractmethod + def init_solver(self, device: torch.device, **kwargs) -> "BaseSolver": + pass + + @classmethod + def from_dict(cls, init_dict: Dict[str, Any]) -> "SolverCfg": + """Initialize the configuration from a dictionary.""" + from embodichain.utils.utility import get_class_instance + + if "class_type" not in init_dict: + logger.log_error("class type must be specified in the configuration.") + + cfg = get_class_instance( + "embodichain.lab.sim.solvers", init_dict["class_type"] + "Cfg" + )() + for key, value in init_dict.items(): + if hasattr(cfg, key): + setattr(cfg, key, value) + else: + logger.log_warning( + f"Key '{key}' not found in {cfg.__class__.__name__}." + ) + return cfg + + +class BaseSolver(metaclass=ABCMeta): + def __init__(self, cfg: SolverCfg = None, device: str = None, **kwargs): + r"""Initializes the kinematics solver with a robot model. + + Args: + cfg (SolverCfg): The configuration for the solver. + device (str or torch.device, optional): The device to run the solver on. Defaults to "cuda" if available, otherwise "cpu". + **kwargs: Additional keyword arguments for customization. + """ + self.cfg = cfg + + if device is None: + self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + elif isinstance(device, str): + self.device = torch.device(device) + else: + self.device = device + + self.urdf_path = cfg.urdf_path + + self.joint_names = cfg.joint_names + + self.end_link_name = cfg.end_link_name + + self.root_link_name = cfg.root_link_name + + # TODO: Check whether the joint name is revolute or prismatic + # Degrees of freedom of robot joints + self.dof = len(self.joint_names) if self.joint_names else 0 + + # Weight for nearest neighbor search in IK (Inverse Kinematics) algorithms + if cfg.ik_nearest_weight is not None: + if len(cfg.ik_nearest_weight) != self.dof: + logger.log_error( + f"Length of ik_nearest_weight ({len(cfg.ik_nearest_weight)}) does not match the number of DOF ({self.dof})." + ) + self.ik_nearest_weight = torch.tensor( + cfg.ik_nearest_weight, dtype=torch.float32, device=self.device + ) + else: + self.ik_nearest_weight = torch.ones( + self.dof, dtype=torch.float32, device=self.device + ) + + self.tcp_xpos = np.eye(4) + + self.pk_serial_chain = kwargs.get("pk_serial_chain", None) + if self.pk_serial_chain is None: + self.pk_serial_chain = create_pk_serial_chain( + urdf_path=self.urdf_path, + end_link_name=self.end_link_name, + root_link_name=self.root_link_name, + device=self.device, + ) + + def set_ik_nearest_weight( + self, ik_weight: np.ndarray, joint_ids: np.ndarray = None + ) -> bool: + r"""Sets the inverse kinematics nearest weight. + + Args: + ik_weight (np.ndarray): A numpy array representing the nearest weights for inverse kinematics. + joint_ids (np.ndarray, optional): A numpy array representing the indices of the joints to which the weights apply. + If None, defaults to all joint indices. + + Returns: + bool: True if the weights are set successfully, False otherwise. + """ + ik_weight = np.array(ik_weight) + + # Set joint_ids to all joint indices if it is None + if joint_ids is None: + joint_ids = np.arange(self.dof) + + joint_ids = np.array(joint_ids) + + # Check if joint_ids has valid indices + if np.any(joint_ids >= self.dof) or np.any(joint_ids < 0): + logger.log_warning( + "joint_ids must contain valid indices between 0 and {}.".format( + self.dof - 1 + ) + ) + return False + + # Check if ik_weight and joint_ids have the same length + if ik_weight.shape[0] != joint_ids.shape[0]: + logger.log_warning("ik_weight and joint_ids must have the same length.") + return False + + # Initialize the weights + if self.ik_nearest_weight is None: + # If ik_nearest_weight is None, set all weights to 1 + self.ik_nearest_weight = np.ones(self.dof) + + # Set specific weights for joint_ids to the provided ik_weight + for i, joint_id in enumerate(joint_ids): + self.ik_nearest_weight[joint_id] = ik_weight[i] + else: + # If ik_nearest_weight is not None, only fill joint_ids + for i, joint_id in enumerate(joint_ids): + self.ik_nearest_weight[joint_id] = ik_weight[i] + + return True + + def get_ik_nearest_weight(self): + r"""Gets the inverse kinematics nearest weight. + + Returns: + np.ndarray: A numpy array representing the nearest weights for inverse kinematics. + """ + return self.ik_nearest_weight + + def set_position_limits( + self, + lower_position_limits: List[float], + upper_position_limits: List[float], + ) -> bool: + r"""Sets the upper and lower joint position limits. + + Parameters: + lower_position_limits (List[float]): A list of lower limits for each joint. + upper_position_limits (List[float]): A list of upper limits for each joint. + + Returns: + bool: True if limits are successfully set, False if the input is invalid. + """ + if ( + len(lower_position_limits) != self.model.nq + or len(upper_position_limits) != self.model.nq + ): + logger.log_warning("Length of limits must match the number of joints.") + return False + + if any( + lower > upper + for lower, upper in zip(lower_position_limits, upper_position_limits) + ): + logger.log_warning( + "Each lower limit must be less than or equal to the corresponding upper limit." + ) + return False + + self.lower_position_limits = np.array(lower_position_limits) + self.upper_position_limits = np.array(upper_position_limits) + return True + + def get_position_limits(self) -> dict: + r"""Returns the current joint position limits. + + Returns: + dict: A dictionary containing: + - lower_position_limits (List[float]): The current lower limits for each joint. + - upper_position_limits (List[float]): The current upper limits for each joint. + """ + return { + "lower_position_limits": self.lower_position_limits.tolist(), + "upper_position_limits": self.upper_position_limits.tolist(), + } + + def set_tcp(self, xpos: np.ndarray): + r"""Sets the TCP position with the given 4x4 homogeneous matrix. + + Args: + xpos (np.ndarray): The 4x4 homogeneous matrix to be set as the TCP position. + + Raises: + ValueError: If the input is not a 4x4 numpy array. + """ + xpos = np.array(xpos) + if xpos.shape != (4, 4): + raise ValueError("Input must be a 4x4 homogeneous matrix") + self.tcp_xpos = xpos + + def get_tcp(self) -> np.ndarray: + r"""Returns the current TCP position. + + Returns: + np.ndarray: The current TCP position. + + Raises: + ValueError: If the TCP position has not been set. + """ + return self.tcp_xpos + + @abstractmethod + def get_ik( + self, + target_pose: torch.Tensor, + joint_seed: Optional[torch.Tensor] = None, + num_samples: Optional[int] = None, + **kwargs, + ) -> Tuple[torch.Tensor, torch.Tensor]: + r"""Computes the inverse kinematics for a given target pose. + + This method generates random joint configurations within the specified limits, + including the provided joint_seed, and attempts to find valid inverse kinematics solutions. + It then identifies the joint position that is closest to the joint_seed. + + Args: + target_pose (torch.Tensor): The target pose represented as a 4x4 transformation matrix. + joint_seed (Optional[torch.Tensor]): The initial joint positions used as a seed. + num_samples (Optional[int]): The number of random joint seeds to generate. + **kwargs: Additional keyword arguments for customization. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: + - success (torch.Tensor): Boolean tensor indicating IK solution validity for each environment, shape (num_envs,). + - target_joints (torch.Tensor): Computed target joint positions, shape (num_envs, num_joints). + """ + pass + + def get_fk(self, qpos: torch.tensor, **kwargs) -> torch.Tensor: + r""" + Computes the forward kinematics for the end-effector link. + + Args: + qpos (torch.Tensor): Joint positions. Can be a single configuration (dof,) or a batch (batch_size, dof). + **kwargs: Additional keyword arguments for customization. + + Returns: + torch.Tensor: The homogeneous transformation matrix of the end link with TCP applied. + Shape is (4, 4) for single input, or (batch_size, 4, 4) for batch input. + """ + tcp_xpos = torch.as_tensor( + self.tcp_xpos, device=self.device, dtype=torch.float32 + ) + qpos = torch.as_tensor(qpos, dtype=torch.float32, device=self.device) + + # Compute forward kinematics + result = self.pk_serial_chain.forward_kinematics( + qpos, end_only=(self.end_link_name is None) + ) + + # Extract transformation matrices + if isinstance(result, dict): + matrices = result[self.end_link_name].get_matrix() + elif isinstance(result, list): + matrices = torch.stack([xpos.get_matrix().squeeze() for xpos in result]) + else: + matrices = result.get_matrix() + + # Ensure batch format + if matrices.dim() == 2: + matrices = matrices.unsqueeze(0) + + # Create result tensor with proper homogeneous coordinates + result = ( + torch.eye(4, device=self.device).expand(matrices.shape[0], 4, 4).clone() + ) + result[:, :3, :] = matrices[:, :3, :] + + # Ensure batch format for TCP + batch_size = result.shape[0] + tcp_xpos_batch = tcp_xpos.unsqueeze(0).expand(batch_size, -1, -1) + + # Apply TCP transformation + return torch.bmm(result, tcp_xpos_batch) + + def get_jacobian( + self, + qpos: torch.Tensor, + locations: Optional[Union[torch.Tensor, np.ndarray]] = None, + jac_type: str = "full", + ) -> torch.Tensor: + r"""Compute the Jacobian matrix for the given joint positions. + + Args: + qpos (torch.Tensor): The joint positions. Shape: (dof,) or (batch_size, dof). + locations (Optional[torch.Tensor]): The offset points (relative to the end-effector coordinate system). + Shape: (batch_size, 3) or (3,) for a single offset. + jac_type (str, optional): 'full', 'trans', or 'rot' for full, translational, or rotational Jacobian. + Defaults to 'full'. + + Returns: + torch.Tensor: The Jacobian matrix. Shape: + - (batch_size, 6, dof) for 'full' + - (batch_size, 3, dof) for 'trans' or 'rot' + """ + if qpos is None: + qpos = torch.zeros(self.dof, device=self.device) + + # Ensure qpos is a tensor + qpos = torch.as_tensor(qpos, dtype=torch.float32, device=self.device) + + # Ensure locations is a tensor if provided + if locations is not None: + locations = torch.as_tensor( + locations, dtype=torch.float32, device=self.device + ) + + # Compute the Jacobian using the kinematics chain + J = self.pk_serial_chain.jacobian(th=qpos, locations=locations) + + # Handle jac_type to return the desired part of the Jacobian + if jac_type == "trans": + return J[:, :3, :] if J.dim() == 3 else J[:3, :] + elif jac_type == "rot": + return J[:, 3:, :] if J.dim() == 3 else J[3:, :] + elif jac_type == "full": + return J + else: + raise ValueError( + f"Invalid jac_type '{jac_type}'. Must be 'full', 'trans', or 'rot'." + ) + + +def merge_solver_cfg( + default: Dict[str, SolverCfg], provided: Dict[str, Any] +) -> Dict[str, SolverCfg]: + """Merge provided solver configuration into the default solver config. + + Rules: + - For each arm key in provided, if the key exists in default, update fields provided. + - If a provided value is a dict, update attributes on the SolverCfg-like object (or dict) by setting keys. + - Primitive values or arrays/lists replace the target value. + - Unknown keys in provided create new entries in the result. + """ + + result = {} + # copy defaults shallowly + for k, v in default.items(): + result[k] = v + + for k, v in provided.items(): + if k in result: + target = result[k] + # if target has __dict__ or is a dataclass-like, set attrs + if hasattr(target, "__dict__") or isinstance(target, dict): + # if provided is a dict, set/override attributes + if isinstance(v, dict): + for sub_k, sub_v in v.items(): + # try to set attribute if possible, otherwise assign into dict + if hasattr(target, sub_k): + try: + setattr(target, sub_k, sub_v) + except Exception: + # fallback to dict assignment if object doesn't accept + try: + target[sub_k] = sub_v + except Exception: + pass + else: + try: + target[sub_k] = sub_v + except Exception: + setattr(target, sub_k, sub_v) + else: + # non-dict provided value replaces the target entirely + result[k] = v + else: + # target is a primitive, replace + result[k] = v + else: + # new solver entry provided; include as-is + result[k] = v + + return result diff --git a/embodichain/lab/sim/solvers/differential_solver.py b/embodichain/lab/sim/solvers/differential_solver.py new file mode 100644 index 00000000..5bbb8028 --- /dev/null +++ b/embodichain/lab/sim/solvers/differential_solver.py @@ -0,0 +1,424 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +from copy import deepcopy +from typing import Optional, Union, Tuple, Any, Literal, TYPE_CHECKING +from scipy.spatial.transform import Rotation + +from embodichain.utils import configclass, logger +from embodichain.lab.sim.solvers import SolverCfg, BaseSolver +from embodichain.utils.math import ( + apply_delta_pose, + compute_pose_error, +) + + +if TYPE_CHECKING: + from typing import Self + + +@configclass +class DifferentialSolverCfg(SolverCfg): + """Configuration for differential inverse kinematics controller.""" + + class_type: str = "DifferentialSolver" + + pos_eps: float = 5e-4 # Tolerance for convergence for position + rot_eps: float = 5e-4 # Tolerance for convergence for rotation + max_iterations: int = 1000 # Maximum number of iterations for the solver + + # Constraint configuration + is_only_position_constraint: bool = ( + False # Whether to only consider position constraints + ) + + # Type of task-space command to control the articulation's body. + command_type: Literal["position", "pose"] = "pose" + + # Whether to use relative mode for the controller. + use_relative_mode: bool = False + + # Method for computing inverse of Jacobian.""" + ik_method: Literal["pinv", "svd", "trans", "dls"] = "pinv" + + # Parameters for the inverse-kinematics method. + ik_params: Optional[dict] = None + + def __post_init__(self): + # Default parameters for different inverse kinematics approaches + default_ik_params = { + "pinv": {"k_val": 1.0}, + "svd": {"k_val": 1.0, "min_singular_value": 1e-5}, + "trans": {"k_val": 1.0}, + "dls": {"lambda_val": 0.01}, + } + + # Update parameters for IK-method if not provided + params = self.ik_params or {} + self.ik_params = {**default_ik_params[self.ik_method], **params} + + def init_solver( + self, num_envs: int = 1, device: torch.device = torch.device("cpu"), **kwargs + ) -> "DifferentialSolver": + """Initialize the solver with the configuration. + + Args: + device (torch.device): The device to use for the solver. Defaults to CPU. + num_envs (int): The number of environments for which the solver is initialized. + **kwargs: Additional keyword arguments that may be used for solver initialization. + + Returns: + DifferentialSolver: An initialized solver instance. + """ + + solver = DifferentialSolver( + cfg=self, num_envs=num_envs, device=device, **kwargs + ) + + # Set the Tool Center Point (TCP) for the solver + if isinstance(self.tcp, torch.Tensor): + tcp = self.tcp.cpu().numpy() + else: + tcp = self.tcp + solver.set_tcp(tcp) + + return solver + + +class DifferentialSolver(BaseSolver): + r"""Differential inverse kinematics (IK) controller. + + This controller implements differential inverse kinematics using various methods for + computing the inverse of the Jacobian matrix. + """ + + def __init__( + self, + cfg: DifferentialSolverCfg, + num_envs: int = 1, + device: str = "cpu", + **kwargs, + ): + r"""Initializes the differential kinematics solver. + + This constructor sets up the kinematics solver using differential methods, + allowing for efficient computation of robot kinematics based on + the specified URDF model. + + Args: + cfg: The configuration for the solver. + num_envs (int): The number of environments for the solver. Defaults to 1. + device (str, optional): The device to use for the solver (e.g., "cpu" or "cuda"). Defaults to "cpu". + **kwargs: Additional keyword arguments passed to the base solver. + + """ + super().__init__(cfg=cfg, num_envs=num_envs, device=device, **kwargs) + + # Initialize buffers + self.ee_pos_des = torch.zeros(num_envs, 3, device=device) + self.ee_quat_des = torch.zeros(num_envs, 4, device=device) + self._command = torch.zeros(num_envs, self.action_dim, device=device) + + @property + def action_dim(self) -> int: + """Returns the dimension of the controller's input command. + + Returns: + int: The dimension of the input command. + """ + if self.cfg.command_type == "position": + return 3 # (x, y, z) + elif self.cfg.command_type == "pose" and self.cfg.use_relative_mode: + return 6 # (dx, dy, dz, droll, dpitch, dyaw) + else: + return 7 # (x, y, z, qw, qx, qy, qz) + + def reset(self, env_ids: Optional[torch.Tensor] = None): + """Reset the internal buffers for the specified environments. + + Args: + env_ids (Optional[torch.Tensor]): The environment indices to reset. If None, reset all. + """ + if env_ids is None: + env_ids = torch.arange(self.num_envs, device=self.device) + + self.ee_pos_des[env_ids] = 0 + self.ee_quat_des[env_ids] = torch.tensor([1.0, 0, 0, 0], device=self.device) + self._command[env_ids] = 0 + + def set_command( + self, + command: torch.Tensor, + ee_pos: Optional[torch.Tensor] = None, + ee_quat: Optional[torch.Tensor] = None, + ) -> bool: + """Set the target end-effector pose command. + + Args: + command (torch.Tensor): The command tensor. + ee_pos (Optional[torch.Tensor]): Current end-effector position (for relative mode). + ee_quat (Optional[torch.Tensor]): Current end-effector quaternion (for relative mode). + + Returns: + bool: True if the command was set successfully, False otherwise. + """ + # TODO: Init solver with correct batch size + batch_size = command.shape[0] + if self._command.shape[0] != batch_size: + device = command.device + self._command = torch.zeros(batch_size, self.action_dim, device=device) + self.ee_pos_des = torch.zeros(batch_size, 3, device=device) + self.ee_quat_des = torch.zeros(batch_size, 4, device=device) + self._command[:] = command + + if self.cfg.command_type == "position": + if ee_quat is None: + logger.log_warning( + "End-effector orientation cannot be None for position control" + ) + return False + + if self.cfg.use_relative_mode: + if ee_pos is None: + logger.log_warning("Current position required for relative mode") + return False + self.ee_pos_des[:] = ee_pos + self._command + self.ee_quat_des[:] = ee_quat + else: + self.ee_pos_des[:] = self._command + self.ee_quat_des[:] = ee_quat + else: + if self.cfg.use_relative_mode: + if ee_pos is None or ee_quat is None: + logger.log_warning("Current pose required for relative mode") + return False + self.ee_pos_des, self.ee_quat_des = apply_delta_pose( + ee_pos, ee_quat, self._command + ) + else: + self.ee_pos_des = self._command[:, 0:3] + self.ee_quat_des = self._command[:, 3:7] + + return True + + def get_ik( + self, + target_xpos: torch.Tensor, + qpos_seed: torch.Tensor = None, + return_all_solutions: bool = False, + jacobian: torch.Tensor = None, + **kwargs, + ) -> Tuple[torch.Tensor, torch.Tensor]: + """Compute target joint positions using differential inverse kinematics. + + Args: + target_xpos (torch.Tensor): Current end-effector position, shape (num_envs, 3). + qpos_seed (torch.Tensor): Current joint positions, shape (num_envs, num_joints). Defaults to zeros. + return_all_solutions (bool, optional): Whether to return all IK solutions or just the best one. Defaults to False. + jacobian (torch.Tensor): Jacobian matrix, shape (num_envs, 6, num_joints). + **kwargs: Additional keyword arguments for future extensions. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: + - success (torch.Tensor): Boolean tensor indicating IK solution validity for each environment, shape (num_envs,). + - target_joints (torch.Tensor): Computed target joint positions, shape (num_envs, num_joints). + """ + if qpos_seed is None: + qpos_seed = torch.zeros(self.dof, device=self.device) + + if jacobian is None: + jacobian = self.get_jacobian(qpos_seed) + current_xpos = self.get_fk(qpos_seed, to_matrix=True) + + # Transform target_xpos by TCP + tcp_xpos = torch.as_tensor( + deepcopy(self.tcp_xpos), device=self.device, dtype=torch.float32 + ) + current_xpos = current_xpos @ torch.inverse(tcp_xpos) + compute_xpos = target_xpos @ torch.inverse(tcp_xpos) + + # Ensure compute_xpos is a batch of matrices + if current_xpos.dim() == 2 and current_xpos.shape == (4, 4): + current_xpos = current_xpos.unsqueeze(0) + + # Ensure compute_xpos is a batch of matrices + if compute_xpos.dim() == 2 and compute_xpos.shape == (4, 4): + compute_xpos = compute_xpos.unsqueeze(0) + + compute_pose = self._matrix_to_pos_quat(compute_xpos) + self.set_command(command=compute_pose) + + qpos = qpos_seed + num_iter = 1 if self.cfg.max_iterations == 1 else self.cfg.max_iterations + for i in range(num_iter): + current_pose = self._matrix_to_pos_quat(current_xpos) + ee_pos = current_pose[:, :3] + ee_quat = current_pose[:, 3:] + + if self.cfg.command_type == "position": + position_error = self.ee_pos_des - ee_pos + jacobian_pos = jacobian[:, :3] + delta_joint_pos = self._compute_delta_joint_pos( + delta_pose=position_error, jacobian=jacobian_pos + ) + else: + pos_error, rot_error = compute_pose_error( + ee_pos, ee_quat, self.ee_pos_des, self.ee_quat_des + ) + pose_error = torch.cat((pos_error, rot_error), dim=1) + delta_joint_pos = self._compute_delta_joint_pos( + delta_pose=pose_error, jacobian=jacobian + ) + + qpos = qpos + delta_joint_pos + current_xpos = self.get_fk(qpos) + + # Ensure current_xpos and target_xpos are batches of matrices + if current_xpos.dim() == 2 and current_xpos.shape == (4, 4): + current_xpos = current_xpos.unsqueeze(0) + + if target_xpos.dim() == 2 and target_xpos.shape == (4, 4): + target_xpos = target_xpos.unsqueeze(0) + + pos_converged = ( + torch.norm(current_xpos[:, :3, 3] - target_xpos[:, :3, 3], dim=1) + < self.cfg.pos_eps + ) + rot_converged = ( + torch.norm(current_xpos[:, :3, :3] - target_xpos[:, :3, :3], dim=(1, 2)) + < self.cfg.rot_eps + ) + + if self.cfg.is_only_position_constraint: + if pos_converged.all(): + break + else: + if (pos_converged & rot_converged).all(): + break + + if return_all_solutions: + logger.log_warning( + "return_all_solutions=True is not supported in DifferentialSolver. Returning the best solution only." + ) + + if self.cfg.is_only_position_constraint: + success = pos_converged + else: + success = pos_converged & rot_converged + + return success, qpos + + # Helper functions + def _compute_delta_joint_pos( + self, delta_pose: torch.Tensor, jacobian: torch.Tensor + ) -> torch.Tensor: + """Compute joint-space delta using the specified IK method. + + Args: + delta_pose (torch.Tensor): The pose error tensor. + jacobian (torch.Tensor): The Jacobian matrix. + + Returns: + torch.Tensor: The joint-space delta tensor. + """ + method = self.cfg.ik_method + params = self.cfg.ik_params + + # compute the delta in joint-space + if method == "pinv": # Jacobian pseudo-inverse + # params + k_val = params["k_val"] + # compute + jacobian_pinv = torch.linalg.pinv(jacobian) + delta_joint_pos = k_val * ( + jacobian_pinv @ delta_pose.unsqueeze(-1) + ).squeeze(-1) + elif method == "svd": + # params + k_val = params["k_val"] + min_singular_value = params["min_singular_value"] + # compute + # U: 6xd, S: dxd, V: d x num-joint + U, S, Vh = torch.linalg.svd(jacobian, full_matrices=False) + S_inv = 1.0 / S + S_inv = torch.where(S > min_singular_value, S_inv, torch.zeros_like(S_inv)) + jacobian_pinv = ( + torch.transpose(Vh, 1, 2)[:, :, :6] + @ torch.diag_embed(S_inv) + @ torch.transpose(U, 1, 2) + ) + delta_joint_pos = k_val * ( + jacobian_pinv @ delta_pose.unsqueeze(-1) + ).squeeze(-1) + elif method == "trans": + # params + k_val = params["k_val"] + # compute + jacobian_T = torch.transpose(jacobian, 1, 2) + delta_joint_pos = params["k_val"] * ( + jacobian_T @ delta_pose.unsqueeze(-1) + ).squeeze(-1) + elif method == "dls": + # params + lambda_val = self.cfg.ik_params["lambda_val"] + # compute + jacobian_T = torch.transpose(jacobian, 1, 2) + lambda_matrix = (lambda_val**2) * torch.eye( + jacobian.shape[1], device=self.device + ) + delta_joint_pos = ( + jacobian_T + @ torch.linalg.solve( + jacobian @ jacobian_T + lambda_matrix, delta_pose.unsqueeze(-1) + ) + ).squeeze(-1) + else: + raise ValueError(f"Unsupported IK method: {method}") + + return delta_joint_pos + + @staticmethod + def _matrix_to_pos_quat(mat): + """Convert a transformation matrix to position and quaternion. + + Args: + mat (torch.Tensor): Transformation matrix tensor of shape (N, 4, 4). + + Returns: + torch.Tensor: Concatenated position and quaternion tensor of shape (N, 7). + """ + # Ensure mat is a batch of matrices + if mat.dim() == 2 and mat.shape == (4, 4): + mat = mat.unsqueeze(0) # Convert (4, 4) to (1, 4, 4) + elif mat.dim() != 3 or mat.shape[1:] != (4, 4): + raise ValueError( + f"Expected mat to have shape (N, 4, 4), but got {mat.shape}" + ) + + # Extract position + pos = mat[:, :3, 3] + + # Extract rotation matrix and convert to quaternion + rot_matrices = mat[:, :3, :3].cpu().numpy() # Convert to NumPy for scipy + quats = Rotation.from_matrix(rot_matrices).as_quat() # (N, 4), [x, y, z, w] + + # Convert quaternion back to torch.Tensor and reorder to [w, x, y, z] + quats = torch.tensor(quats, device=mat.device, dtype=mat.dtype) # (N, 4) + quats = quats[:, [3, 0, 1, 2]] # Reorder to [w, x, y, z] + + # Concatenate position and quaternion + return torch.cat([pos, quats], dim=1) diff --git a/embodichain/lab/sim/solvers/null_space_posture_task.py b/embodichain/lab/sim/solvers/null_space_posture_task.py new file mode 100644 index 00000000..13d4e590 --- /dev/null +++ b/embodichain/lab/sim/solvers/null_space_posture_task.py @@ -0,0 +1,270 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + + +import numpy as np +from typing import List, Optional, Union, TYPE_CHECKING +from embodichain.utils import logger + +try: + import pinocchio as pin +except ImportError: + logger.log_warning("pinocchio not installed. Install with `pip install pin==2.7.0`") + +try: + from pink.configuration import Configuration + from pink.tasks import Task +except ImportError: + logger.log_warning( + "pin-pink not installed. Install with `pip install pin-pink==3.4.0`" + ) + + +class NullSpacePostureTask(Task): + r"""Pink-based task that adds a posture objective that is in the null space projection of other tasks. + + This task implements posture control in the null space of higher priority tasks + (typically end-effector pose tasks) within the Pink inverse kinematics framework. + + **Mathematical Formulation:** + + For details on Pink Inverse Kinematics optimization formulation visit: https://github.com/stephane-caron/pink + + **Null Space Posture Task Implementation:** + + This task consists of two components: + + 1. **Error Function**: The posture error is computed as: + + .. math:: + + \mathbf{e}(\mathbf{q}) = \mathbf{M} \cdot (\mathbf{q}^* - \mathbf{q}) + + where: + - :math:`\mathbf{q}^*` is the target joint configuration + - :math:`\mathbf{q}` is the current joint configuration + - :math:`\mathbf{M}` is a joint selection mask matrix + + 2. **Jacobian Matrix**: The task Jacobian is the null space projector: + + .. math:: + + \mathbf{J}_{\text{posture}}(\mathbf{q}) = \mathbf{N}(\mathbf{q}) = \mathbf{I} - \mathbf{J}_{\text{primary}}^+ \mathbf{J}_{\text{primary}} + + where: + - :math:`\mathbf{J}_{\text{primary}}` is the combined Jacobian of all higher priority tasks + - :math:`\mathbf{J}_{\text{primary}}^+` is the pseudoinverse of the primary task Jacobian + - :math:`\mathbf{N}(\mathbf{q})` is the null space projector matrix + + For example, if there are two frame tasks (e.g., controlling the pose of two end-effectors), the combined Jacobian + :math:`\mathbf{J}_{\text{primary}}` is constructed by stacking the individual Jacobians for each frame vertically: + + .. math:: + + \mathbf{J}_{\text{primary}} = + \begin{bmatrix} + \mathbf{J}_1(\mathbf{q}) \\ + \mathbf{J}_2(\mathbf{q}) + \end{bmatrix} + + where :math:`\mathbf{J}_1(\mathbf{q})` and :math:`\mathbf{J}_2(\mathbf{q})` are the Jacobians for the first and second frame tasks, respectively. + + The null space projector ensures that joint velocities in the null space produce zero velocity + for the primary tasks: :math:`\mathbf{J}_{\text{primary}} \cdot \dot{\mathbf{q}}_{\text{null}} = \mathbf{0}`. + + **Task Integration:** + + When integrated into the Pink framework, this task contributes to the optimization as: + + .. math:: + + \left\| \mathbf{N}(\mathbf{q}) \mathbf{v} + \mathbf{M} \cdot (\mathbf{q}^* - \mathbf{q}) \right\|_{W_{\text{posture}}}^2 + + This formulation allows the robot to maintain a desired posture while respecting the constraints + imposed by higher priority tasks (e.g., end-effector positioning). + + """ + + def __init__( + self, + cost: float, + lm_damping: float = 0.0, + gain: float = 1.0, + controlled_frames: Optional[List[str]] = None, + controlled_joints: Optional[List[str]] = None, + ) -> None: + r"""Initialize the null space posture task. + + This task maintains a desired joint posture in the null space of higher-priority + frame tasks. Joint selection allows excluding specific joints (e.g., wrist joints + in humanoid manipulation) to prevent large rotational ranges from overwhelming + errors in critical joints like shoulders and waist. + + Args: + cost: Task weighting factor in the optimization objective. + Units: :math:`[\text{cost}] / [\text{rad}]`. + lm_damping: Levenberg-Marquardt regularization scale (unitless). Defaults to 0.0. + gain: Task gain :math:`\alpha \in [0, 1]` for low-pass filtering. + Defaults to 1.0 (no filtering). + controlled_frames: Frame names whose Jacobians define the primary tasks for + null space projection. If None or empty, no projection is applied. + controlled_joints: Joint names to control in the posture task. If None or + empty, all actuated joints are controlled. + """ + super().__init__(cost=cost, gain=gain, lm_damping=lm_damping) + self.target_q: np.ndarray | None = None + self.controlled_frames: list[str] = controlled_frames or [] + self.controlled_joints: list[str] = controlled_joints or [] + self._joint_mask: np.ndarray | None = None + self._frame_names: list[str] | None = None + + def __repr__(self) -> str: + """Human-readable representation of the task.""" + return ( + f"NullSpacePostureTask(cost={self.cost}, gain={self.gain}, lm_damping={self.lm_damping}," + f" controlled_frames={self.controlled_frames}, controlled_joints={self.controlled_joints})" + ) + + def _build_joint_mapping(self, configuration: Configuration) -> None: + """Build joint mask and cache frequently used values. + + Creates a binary mask that selects which joints should be controlled + in the posture task. + + Args: + configuration: Robot configuration containing the model and joint information. + """ + # Create joint mask for full configuration size + self._joint_mask = np.zeros(configuration.model.nq) + + # Create dictionary for joint names to indices (exclude root joint) + joint_names = configuration.model.names.tolist()[1:] + + # Build joint mask efficiently + for i, joint_name in enumerate(joint_names): + if joint_name in self.controlled_joints: + self._joint_mask[i] = 1.0 + + # Cache frame names for performance + self._frame_names = list(self.controlled_frames) + + def set_target(self, target_q: np.ndarray) -> None: + """Set target posture configuration. + + Args: + target_q: Target vector in the configuration space. If the model + has a floating base, then this vector should include + floating-base coordinates (although they have no effect on the + posture task since only actuated joints are controlled). + """ + self.target_q = target_q.copy() + + def set_target_from_configuration(self, configuration: Configuration) -> None: + """Set target posture from a robot configuration. + + Args: + configuration: Robot configuration whose joint angles will be used + as the target posture. + """ + self.set_target(configuration.q) + + def compute_error(self, configuration: Configuration) -> np.ndarray: + r"""Compute posture task error. + + The error computation follows: + + .. math:: + + \mathbf{e}(\mathbf{q}) = \mathbf{M} \cdot (\mathbf{q}^* - \mathbf{q}) + + where :math:`\mathbf{M}` is the joint selection mask and :math:`\mathbf{q}^* - \mathbf{q}` + is computed using Pinocchio's difference function to handle joint angle wrapping. + + Args: + configuration: Robot configuration :math:`\mathbf{q}`. + + Returns: + Posture task error :math:`\mathbf{e}(\mathbf{q})` with the same dimension + as the configuration vector, but with zeros for non-controlled joints. + + Raises: + ValueError: If no posture target has been set. + """ + if self.target_q is None: + raise ValueError("No posture target has been set. Call set_target() first.") + + # Initialize joint mapping if needed + if self._joint_mask is None: + self._build_joint_mapping(configuration) + + # Compute configuration difference using Pinocchio's difference function + # This handles joint angle wrapping correctly + err = pin.difference( + configuration.model, + self.target_q, + configuration.q, + ) + + # Apply pre-computed joint mask to select only controlled joints + return self._joint_mask * err + + def compute_jacobian(self, configuration: Configuration) -> np.ndarray: + r"""Compute the null space projector Jacobian. + + The null space projector is defined as: + + .. math:: + + \mathbf{N}(\mathbf{q}) = \mathbf{I} - \mathbf{J}_{\text{primary}}^+ \mathbf{J}_{\text{primary}} + + where: + - :math:`\mathbf{J}_{\text{primary}}` is the combined Jacobian of all controlled frames + - :math:`\mathbf{J}_{\text{primary}}^+` is the pseudoinverse of the primary task Jacobian + - :math:`\mathbf{I}` is the identity matrix + + The null space projector ensures that joint velocities in the null space produce + zero velocity for the primary tasks: :math:`\mathbf{J}_{\text{primary}} \cdot \dot{\mathbf{q}}_{\text{null}} = \mathbf{0}`. + + If no controlled frames are specified, returns the identity matrix. + + Args: + configuration: Robot configuration :math:`\mathbf{q}`. + + Returns: + Null space projector matrix :math:`\mathbf{N}(\mathbf{q})` with dimensions + :math:`n_q \times n_q` where :math:`n_q` is the number of configuration variables. + """ + # Initialize joint mapping if needed + if self._frame_names is None: + self._build_joint_mapping(configuration) + + # If no frame tasks are defined, return identity matrix (no null space projection) + if not self._frame_names: + return np.eye(configuration.model.nq) + + # Get Jacobians for all frame tasks and combine them + J_frame_tasks = [ + configuration.get_frame_jacobian(frame_name) + for frame_name in self._frame_names + ] + J_combined = np.concatenate(J_frame_tasks, axis=0) + + # Compute null space projector: N = I - J^+ * J + N_combined = ( + np.eye(J_combined.shape[1]) - np.linalg.pinv(J_combined) @ J_combined + ) + + return N_combined diff --git a/embodichain/lab/sim/solvers/opw_solver.py b/embodichain/lab/sim/solvers/opw_solver.py new file mode 100644 index 00000000..1dfd751e --- /dev/null +++ b/embodichain/lab/sim/solvers/opw_solver.py @@ -0,0 +1,734 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np +from itertools import product +from typing import Optional, Union, Tuple, Any, Literal, TYPE_CHECKING +from scipy.spatial.transform import Rotation + +from embodichain.utils import configclass, logger +from embodichain.lab.sim.solvers import SolverCfg, BaseSolver +from embodichain.utils.warp.kinematics.opw_solver import ( + OPWparam, + opw_fk_kernel, + opw_ik_kernel, + opw_best_ik_kernel, + wp_vec6f, +) +from embodichain.utils.device_utils import standardize_device_string +import warp as wp +import polars as pl + +try: + from py_opw_kinematics import KinematicModel, Robot, EulerConvention +except ImportError: + raise ImportError( + "py_opw_kinematics not installed. Install with `pip install py_opw_kinematics==0.1.6`" + ) + + +if TYPE_CHECKING: + from typing import Self + + +def normalize_to_pi(angle): + angle = (angle + np.pi) % (2.0 * np.pi) - np.pi + return angle + + +@configclass +class OPWSolverCfg(SolverCfg): + """Configuration for OPW inverse kinematics controller.""" + + class_type: str = "OPWSolver" + + # OPW-specific parameters + a1 = 0.0 + a2 = -21.984 + b = 0.0 + c1 = 123.0 + c2 = 285.03 + c3 = 250.75 + c4 = 91.0 + offsets = ( + 0.0, + 82.21350356417211 * np.pi / 180.0, + -167.21710113148163 * np.pi / 180.0, + 0.0, + 0.0, + 0.0, + ) + flip_axes = (False, False, False, False, False, False) + has_parallelogram = False + + # Parameters for the inverse-kinematics method. + ik_params: Optional[dict] = None + + def init_solver( + self, device: torch.device = torch.device("cpu"), **kwargs + ) -> "OPWSolver": + """Initialize the solver with the configuration. + + Args: + device (torch.device): The device to use for the solver. Defaults to CPU. + n_sample (int): The number of environments for which the solver is initialized. + **kwargs: Additional keyword arguments that may be used for solver initialization. + + Returns: + OPWSolver: An initialized solver instance. + """ + + solver = OPWSolver(cfg=self, device=device, **kwargs) + + # Set the Tool Center Point (TCP) for the solver + if isinstance(self.tcp, torch.Tensor): + tcp = self.tcp.cpu().numpy() + else: + tcp = self.tcp + solver.set_tcp(tcp) + + return solver + + +class OPWSolver(BaseSolver): + r"""OPW inverse kinematics (IK) controller. + + This controller implements OPW inverse kinematics using various methods for + computing the inverse of the Jacobian matrix. + """ + + def __init__(self, cfg: OPWSolverCfg, device: str = "cpu", **kwargs): + r"""Initializes the OPW kinematics solver. + + This constructor sets up the kinematics solver using OPW methods, + allowing for efficient computation of robot kinematics based on + the specified URDF model. + + Args: + cfg: The configuration for the solver. + device (str, optional): The device to use for the solver (e.g., "cpu" or "cuda"). Defaults to "cpu". + **kwargs: Additional keyword arguments passed to the base solver. + + """ + super().__init__(cfg=cfg, device=device, **kwargs) + if self.device.type == "cpu": + self._init_py_opw_kinematics_solver(cfg, **kwargs) + else: + self._init_warp_solver(cfg, **kwargs) + self.set_tcp(np.eye(4)) + + def _init_py_opw_kinematics_solver(self, cfg: OPWSolverCfg, **kwargs) -> None: + self.kinematic_model = KinematicModel( + a1=cfg.a1, + a2=cfg.a2, + b=cfg.b, + c1=cfg.c1, + c2=cfg.c2, + c3=cfg.c3, + c4=cfg.c4, + offsets=cfg.offsets, + flip_axes=cfg.flip_axes, + has_parallelogram=cfg.has_parallelogram, + ) + self.euler_convention = EulerConvention("ZYX", extrinsic=False, degrees=False) + self.opw_robot = Robot( + self.kinematic_model, self.euler_convention, ee_rotation=(0, 0, 0) + ) + if self.pk_serial_chain != "": + fk_dict = self.pk_serial_chain.forward_kinematics( + th=np.zeros(6), end_only=False + ) + root_tf = fk_dict[list(fk_dict.keys())[0]] + + self.root_base_xpos = root_tf.get_matrix().cpu().numpy() + + def set_tcp(self, xpos: np.ndarray): + super().set_tcp(xpos) + if self.device.type != "cpu": + self._tcp_warp = wp.mat44f(self.tcp_xpos) + tcp_inv = np.eye(4, dtype=float) + tcp_inv[:3, :3] = self.tcp_xpos[:3, :3].T + tcp_inv[:3, 3] = -tcp_inv[:3, :3].T @ self.tcp_xpos[:3, 3] + self._tcp_inv_warp = wp.mat44f(tcp_inv) + + def _init_warp_solver(self, cfg: OPWSolverCfg, **kwargs): + self.params = OPWparam() + # convert unit from mm to m, increate precision + self.params.a1 = cfg.a1 / 1000.0 + self.params.a2 = cfg.a2 / 1000.0 + self.params.b = cfg.b / 1000.0 + self.params.c1 = cfg.c1 / 1000.0 + self.params.c2 = cfg.c2 / 1000.0 + self.params.c3 = cfg.c3 / 1000.0 + self.params.c4 = cfg.c4 / 1000.0 + self.offsets = wp.array( + cfg.offsets, dtype=float, device=standardize_device_string(self.device) + ) + self.sign_corrections = wp.array( + [-1.0 if flip else 1.0 for flip in cfg.flip_axes], + dtype=float, + device=standardize_device_string(self.device), + ) + + def get_fk(self, qpos: torch.tensor, **kwargs) -> torch.tensor: + r""" + Computes the forward kinematics for the end-effector link. + + Args: + qpos (torch.Tensor): Joint positions. Can be a single configuration (dof,) or a batch (batch_size, dof). + **kwargs: Additional keyword arguments for customization. + + Returns: + torch.Tensor: The homogeneous transformation matrix of the end link with TCP applied. + Shape is (4, 4) for single input, or (batch_size, 4, 4) for batch input. + """ + if standardize_device_string(self.device) == "cpu": + return super().get_fk(qpos, **kwargs) + else: + return self.get_fk_warp(qpos, **kwargs) + + def get_fk_warp(self, qpos: torch.tensor, **kwargs) -> torch.tensor: + r""" + Computes the forward kinematics for the end-effector link. + + Args: + qpos (torch.Tensor): Joint positions. Can be a single configuration (dof,) or a batch (batch_size, dof). + **kwargs: Additional keyword arguments for customization. + + Returns: + torch.Tensor: The homogeneous transformation matrix of the end link with TCP applied. + Shape is (4, 4) for single input, or (batch_size, 4, 4) for batch input. + """ + if qpos.shape == (6,): + qpos_batch = qpos[None, :] + else: + qpos_batch = qpos + n_sample = qpos_batch.shape[0] + qpos_wp = wp.from_torch(qpos_batch.reshape(-1)) # dtype=float, device="cuda") + # qpos_wp = wp.array(qpos_batch.detach().cpu().numpy().reshape(-1), dtype=float, device=self.device) + xpos_wp = wp.zeros( + n_sample * 16, dtype=float, device=standardize_device_string(self.device) + ) + wp.launch( + kernel=opw_fk_kernel, + dim=(n_sample), + inputs=[ + qpos_wp, + self._tcp_warp, + self.params, + self.offsets, + self.sign_corrections, + ], + outputs=[xpos_wp], + device=standardize_device_string(self.device), + ) + xpos = wp.to_torch(xpos_wp).reshape(n_sample, 4, 4) + return xpos + + def get_ik( + self, + target_xpos: torch.Tensor, + qpos_seed: torch.Tensor = None, + return_all_solutions: bool = False, + **kwargs, + ): + """Compute target joint positions using OPW inverse kinematics. + + Args: + target_xpos (torch.Tensor): Current end-effector pose, shape (n_sample, 4, 4). + qpos_seed (torch.Tensor): Current joint positions, shape (n_sample, num_joints). Defaults to None. + return_all_solutions (bool, optional): Whether to return all IK solutions or just the best one. Defaults to False. + **kwargs: Additional keyword arguments for future extensions. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: + - target_joints (torch.Tensor): Computed target joint positions, shape (n_sample, num_joints). + - success (torch.Tensor): Boolean tensor indicating IK solution validity for each environment, shape (n_sample,). + """ + if self.device.type == "cpu": + return self.get_ik_py_opw( + target_xpos, qpos_seed, return_all_solutions, **kwargs + ) + else: + return self.get_ik_warp( + target_xpos, qpos_seed, return_all_solutions, **kwargs + ) + + def get_ik_warp( + self, + target_xpos: torch.Tensor, + qpos_seed: torch.Tensor, + return_all_solutions: bool = False, + **kwargs, + ): + """Compute target joint positions using OPW inverse kinematics. + + Args: + target_xpos (torch.Tensor): Current end-effector pose, shape (n_sample, 4, 4). + qpos_seed (torch.Tensor): Current joint positions, shape (n_sample, num_joints). + return_all_solutions (bool, optional): Whether to return all IK solutions or just the best one. Defaults to False. + **kwargs: Additional keyword arguments for future extensions. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: + - target_joints (torch.Tensor): Computed target joint positions, shape (n_sample, n_solution, num_joints). + - success (torch.Tensor): Boolean tensor indicating IK solution validity for each environment, shape (n_sample,). + """ + N_SOL = 8 + DOF = 6 + n_sample = target_xpos.shape[0] + + if target_xpos.shape == (4, 4): + target_xpos_batch = target_xpos[None, :, :] + else: + target_xpos_batch = target_xpos + target_xpos_wp = wp.from_torch(target_xpos_batch.reshape(-1)) + + all_qpos_wp = wp.zeros( + n_sample * N_SOL * DOF, + dtype=float, + device=standardize_device_string(self.device), + ) + all_ik_valid_wp = wp.zeros( + n_sample * N_SOL, dtype=int, device=standardize_device_string(self.device) + ) + + # TODO: whether require gradient + wp.launch( + kernel=opw_ik_kernel, + dim=(n_sample), + inputs=( + target_xpos_wp, + self._tcp_inv_warp, + self.params, + self.offsets, + self.sign_corrections, + ), + outputs=[all_qpos_wp, all_ik_valid_wp], + device=standardize_device_string(self.device), + ) + + if return_all_solutions: + all_qpos = wp.to_torch(all_qpos_wp).reshape(n_sample, N_SOL, DOF) + all_ik_valid = wp.to_torch(all_ik_valid_wp).reshape(n_sample, N_SOL) + return all_ik_valid, all_qpos + + if qpos_seed is not None: + qpos_seed_wp = wp.from_torch(qpos_seed.reshape(-1)) + else: + qpos_seed_wp = wp.zeros( + n_sample * DOF, + dtype=float, + device=standardize_device_string(self.device), + ) + joint_weight = kwargs.get("joint_weight", torch.zeros(size=(DOF,), dtype=float)) + joint_weight_wp = wp_vec6f( + joint_weight[0], + joint_weight[1], + joint_weight[2], + joint_weight[3], + joint_weight[4], + joint_weight[5], + ) + best_ik_result_wp = wp.zeros( + n_sample * 6, dtype=float, device=standardize_device_string(self.device) + ) + best_ik_valid_wp = wp.zeros( + n_sample, dtype=int, device=standardize_device_string(self.device) + ) + wp.launch( + kernel=opw_best_ik_kernel, + dim=(n_sample), + inputs=[ + all_qpos_wp, + all_ik_valid_wp, + qpos_seed_wp, + joint_weight_wp, + ], + outputs=[best_ik_result_wp, best_ik_valid_wp], + device=standardize_device_string(self.device), + ) + best_ik_result = wp.to_torch(best_ik_result_wp).reshape(n_sample, 1, 6) + best_ik_valid = wp.to_torch(best_ik_valid_wp) + return best_ik_valid, best_ik_result + + def get_ik_py_opw( + self, + target_xpos: torch.Tensor, + qpos_seed: torch.Tensor, + return_all_solutions: bool = False, + **kwargs, + ) -> Tuple[torch.Tensor, torch.Tensor]: + """Compute target joint positions using OPW inverse kinematics. + + Args: + target_xpos (torch.Tensor): Current end-effector position, shape (n_sample, 3). + qpos_seed (torch.Tensor): Current joint positions, shape (n_sample, num_joints). + return_all_solutions (bool, optional): Whether to return all IK solutions or just the best one. Defaults to False. + **kwargs: Additional keyword arguments for future extensions. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: + - target_joints (torch.Tensor): Computed target joint positions, shape (n_sample, num_joints). + - success (torch.Tensor): Boolean tensor indicating IK solution validity for each environment, shape (n_sample,). + """ + # TODO: opw solver can only get one solution at a time + DOF = 6 + if qpos_seed is not None: + if isinstance(qpos_seed, torch.Tensor): + qpos_seed_np = qpos_seed.detach().cpu().numpy() + else: + qpos_seed_np = np.array(qpos_seed) + else: + qpos_seed_np = np.zeros(DOF) + + if isinstance(target_xpos, torch.Tensor): + target_xpos = target_xpos.detach().cpu().numpy() + + if target_xpos.shape == (4, 4): + target_xpos_batch = target_xpos[None, :, :] + else: + target_xpos_batch = target_xpos + + # TODO: support root base transform + # target_xpos = self.root_base_xpos @ target_xpos + # compute_xpos = target_xpos @ np.linalg.inv(self.tcp_xpos) + + # TODO: single version + # if target_xpos.ndim == 3: + # target_xpos = target_xpos[0] + # position = np.array(compute_xpos[:3, 3]) * 1000 + # rotation = Rotation.from_matrix(compute_xpos[:3, :3]) + # rotation = rotation.as_euler("ZYX") + # solutions = self.opw_robot.inverse((position, rotation)) + # if len(solutions) == 0: + # logger.log_warning("OPWSolver failed: No solutions found.") + # if return_all_solutions: + # return torch.tensor([False]), torch.zeros((1, 1, 6)) + # else: + # return torch.tensor([False]), torch.zeros((1, 6)) + + # ret, qpos = self._select_optimal_solution( + # qpos_seed_np, solutions, weights=None, return_all_valid=return_all_solutions + # ) + # if not ret or len(qpos) == 0: + # logger.log_warning("No valid solutions found within joint limits.") + # if return_all_solutions: + # return torch.tensor([False]), torch.zeros((1, 1, 6)) + # else: + # return torch.tensor([False]), torch.zeros((1, 6)) + + # if return_all_solutions: + # # qpos: (N, 6) -> (1, N, 6) + # qpos_tensor = torch.from_numpy(qpos).float().unsqueeze(0) + # else: + # # qpos: (6,) -> (1, 6) + # qpos_tensor = torch.from_numpy(qpos).float().reshape(1, 6) + + x_list = [] + y_list = [] + z_list = [] + a_list = [] + b_list = [] + c_list = [] + for xpos in target_xpos_batch: + compute_xpos = xpos @ np.linalg.inv(self.tcp_xpos) + position = np.array(compute_xpos[:3, 3]) * 1000 + rotation = Rotation.from_matrix(compute_xpos[:3, :3]) + rotation = rotation.as_euler("ZYX") + x_list.append(position[0]) + y_list.append(position[1]) + z_list.append(position[2]) + a_list.append(rotation[0]) + b_list.append(rotation[1]) + c_list.append(rotation[2]) + poses = pl.DataFrame( + { + "X": x_list, + "Y": y_list, + "Z": z_list, + "A": a_list, + "B": b_list, + "C": c_list, + } + ) + qpos_seed_np = qpos_seed_np.reshape(-1)[:DOF] + res = self.opw_robot.batch_inverse(current_joints=qpos_seed_np, poses=poses) + solutions = res.to_numpy().copy() + is_success = np.any(np.logical_not(np.isnan(solutions)), axis=1) + for i in range(solutions.shape[0]): + for j in range(solutions.shape[1]): + solutions[i, j] = normalize_to_pi(solutions[i, j]) + + if return_all_solutions: + logger.log_warning( + "return_all_solutions=True is not supported in OPWSolverCPUMode. Returning the best solution only." + ) + qpos_tensor = torch.tensor(solutions, dtype=torch.float32, device=self.device) + qpos_tensor = qpos_tensor.reshape(-1, 1, DOF) + return torch.tensor(is_success), qpos_tensor + + def _calculate_dynamic_weights( + self, current_joints, joint_limits, base_weights=None + ) -> np.ndarray: + r"""Calculate dynamic joint weights based on proximity to joint limits. + + This function increases the weight of joints that are close to their limits, making the IK solver + penalize solutions that move joints near their boundaries. The closer a joint is to its limit, + the higher its weight will be, encouraging safer joint configurations. + + Args: + current_joints (np.ndarray): Current joint positions, shape (6,). + joint_limits (list or np.ndarray): List of (min, max) tuples for each joint, shape (6, 2). + base_weights (np.ndarray, optional): Base weights for each joint, shape (6,). Defaults to ones. + + Returns: + np.ndarray: Dynamic weights for each joint, shape (6,). + """ + if base_weights is None: + base_weights = np.ones(6) + + dynamic_weights = np.copy(base_weights) + for i in range(6): + cj = current_joints[i] + if isinstance(cj, np.ndarray): + if cj.size == 1: + cj = float(cj) + else: + cj = float(cj.flat[0]) + jl_min = joint_limits[i][0] + jl_max = joint_limits[i][1] + range_size = jl_max - jl_min + distance_to_min = cj - jl_min + distance_to_max = jl_max - cj + + min_ratio = distance_to_min / range_size + max_ratio = distance_to_max / range_size + danger_ratio = min(float(min_ratio), float(max_ratio)) + if danger_ratio < 0.2: + dynamic_weights[i] *= 5.0 + elif danger_ratio < 0.4: + dynamic_weights[i] *= 2.0 + + return dynamic_weights + + def _select_optimal_solution( + self, + current_joints, + all_solutions, + joint_limits=None, + weights=None, + prev_joints=None, + return_all_valid=False, + ) -> Tuple[bool, np.ndarray]: + r"""Select the optimal IK solution based on joint limits and weighted differences. + + Args: + current_joints (np.ndarray): Current joint positions in radians, shape=(6,) + all_solutions (List[np.ndarray]): List of all possible IK solutions, each solution has shape=(6,) + joint_limits (List[Tuple], optional): Joint limits list [(min1,max1),...,(min6,max6)]. Defaults to None. + weights (np.ndarray, optional): Weight coefficients for each joint, shape=(6,). Defaults to None. + prev_joints (np.ndarray, optional): Previous joint positions in radians, shape=(6,). Defaults to None. + return_all_valid (bool, optional): If True, return all valid solutions instead of just the optimal one. Defaults to False. + + Returns: + Tuple[bool, np.ndarray]: A tuple containing: + - Success flag (True if solution found) + - Joint angles of the optimal solution (single solution) or all valid solutions (if return_all_valid=True) + """ + # Input validation + if current_joints is None or all_solutions is None: + return False, np.array([]) + + # Convert inputs to numpy arrays + current_joints = np.asarray(current_joints).reshape(-1) + all_solutions = [(np.asarray(sol)) for sol in all_solutions] + + # Set default joint limits if none provided + if joint_limits is None: + joint_limits = [ + (-np.pi, np.pi), # joint 1 + (-np.pi, np.pi), # joint 2 + (-np.pi, np.pi), # joint 3 + (-np.pi, np.pi), # joint 4 + (-np.pi, np.pi), # joint 5 + (-np.pi, np.pi), # joint 6 + ] + + # TODO: support funciton to setting safty margin + # SAFETY_MARGIN = np.radians(5.0) + # joint_limits = [ + # (-2.618 + SAFETY_MARGIN, 2.618 - SAFETY_MARGIN), # 约(-145.5°+5°, 124.2°-5°) + # (0.0 + SAFETY_MARGIN, 3.14 - SAFETY_MARGIN), # 约(0°+5°, 180°-5°) + # (-2.967 + SAFETY_MARGIN, 0.0 - SAFETY_MARGIN), # 约(-170°+5°, 0°-5°) + # (-1.745 + SAFETY_MARGIN, 1.745 - SAFETY_MARGIN), # 约(-100°+5°, 100°-5°) + # (-1.22 + SAFETY_MARGIN, 1.22 - SAFETY_MARGIN), # 约(-70°+5°, 70°-5°) + # (-2.0944 + SAFETY_MARGIN, 2.0944 - SAFETY_MARGIN), # 约(-120°+5°, 120°-5°) + # ] + + # Handle empty solution case + if len(all_solutions) == 0: + logger.log_warning("No available solutions found.") + return None, np.array([]) + + # Set default weights if none provided + if weights is None: + weights = np.ones(6) + else: + weights = np.asarray(weights) + + # Initialize previous joints if not provided + if prev_joints is None: + prev_joints = current_joints + else: + prev_joints = np.asarray(prev_joints) + + # Ensure we only work with first 6 joints + current_joints = current_joints[:6] + prev_joints = prev_joints[:6] + + # Calculate dynamic weights considering joint limits + dynamic_weights = self._calculate_dynamic_weights( + current_joints, joint_limits, weights + ) + + # Initialize variables for tracking best solution and all valid solutions with scores + best_score = float("inf") + best_qpos = None + all_valid_solutions = [] # List of (solution, score) tuples for sorting + + # Evaluate each IK solution + for q in all_solutions: + possible_arrays = [] + valid_solution = True + + # Generate possible joint values considering 2π periodicity + for i in range(6): + current_possible_values = [] + # Determine previous movement direction + prev_move = current_joints[i] - prev_joints[i] + + # Prefer offsets in the same direction as previous movement + preferred_offsets = range(0, 3) if prev_move >= 0 else range(-2, 1) + for offset in preferred_offsets: + adjusted_value = q[i] + offset * (2 * np.pi) + if joint_limits[i][0] <= adjusted_value <= joint_limits[i][1]: + current_possible_values.append(adjusted_value) + + # If no values found in preferred direction, try all directions + if not current_possible_values: + for offset in range(-2, 3): + adjusted_value = q[i] + offset * (2 * np.pi) + if joint_limits[i][0] <= adjusted_value <= joint_limits[i][1]: + current_possible_values.append(adjusted_value) + + # If still no valid values, mark solution as invalid + if not current_possible_values: + valid_solution = False + break + + possible_arrays.append(current_possible_values) + + # Skip invalid solutions + if not valid_solution: + continue + + # Helper function to safely normalize weights + def safe_normalize(weights): + max_weight = np.max(weights) + if max_weight > 0: + return weights / max_weight + return np.zeros_like(weights) + + # Evaluate all combinations of possible joint values + for combination in product(*possible_arrays): + solution = np.array(combination) + if solution.size != 6: + continue + + solution = solution.reshape(current_joints.shape) + + # Calculate optimization score for this solution + # 1. Position difference penalty (weighted squared difference) + pos_diff = np.sum((solution - current_joints) ** 2 * dynamic_weights) + + # 2. Joint limit proximity penalty + limit_penalty = 0 + for i in range(6): + margin = 0.05 # 5% safety margin + # Calculate safe operating range + lower = joint_limits[i][0] + margin * ( + joint_limits[i][1] - joint_limits[i][0] + ) + upper = joint_limits[i][1] - margin * ( + joint_limits[i][1] - joint_limits[i][0] + ) + + # Apply penalty if near joint limits + if solution[i] < lower or solution[i] > upper: + normalized_weights = safe_normalize(dynamic_weights) + limit_penalty += 5.0 * (1 - normalized_weights[i]) + + # 3. Direction change penalty (for avoiding sign flips) + direction_penalty = 0 + for i in range(6): + prev_move = current_joints[i] - prev_joints[i] + current_move = solution[i] - current_joints[i] + # Penalize direction reversals + if prev_move * current_move < 0: # Opposite signs + direction_penalty += ( + abs(current_move) * dynamic_weights[i] * 2.0 + ) + + # 4. Velocity continuity penalty (for smooth motion) + velocity_penalty = 0 + for i in range(6): + prev_vel = current_joints[i] - prev_joints[i] + current_vel = solution[i] - current_joints[i] + accel = abs(current_vel - prev_vel) + # Penalize excessive acceleration (>30°/s²) + if accel > np.radians(30): + velocity_penalty += accel * dynamic_weights[i] * 5.0 + + # Combine all penalty terms + total_score = ( + pos_diff + limit_penalty + direction_penalty + velocity_penalty + ) + + # Add to valid solutions list with score (for sorting when return_all_valid=True) + all_valid_solutions.append((solution.copy(), total_score)) + + # Update best solution if current one is better (for single solution return) + if total_score < best_score: + best_score = total_score + best_qpos = solution.copy() + + # Return results based on what was requested + if return_all_valid: + if len(all_valid_solutions) == 0: + return False, np.array([]) + + # Sort solutions by score (ascending order - lower score is better) + all_valid_solutions.sort(key=lambda x: x[1]) + + # Extract only the solutions (remove scores) + sorted_solutions = np.array([sol[0] for sol in all_valid_solutions]) + return True, sorted_solutions + else: + if best_qpos is None: + return False, np.array([]) + return True, best_qpos diff --git a/embodichain/lab/sim/solvers/pink_solver.py b/embodichain/lab/sim/solvers/pink_solver.py new file mode 100644 index 00000000..b9d74a5f --- /dev/null +++ b/embodichain/lab/sim/solvers/pink_solver.py @@ -0,0 +1,417 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import torch +import numpy as np +from typing import List, Optional, Tuple, Union, TYPE_CHECKING +from embodichain.utils import logger + +from embodichain.lab.sim.utility.import_utils import ( + lazy_import_pinocchio, + lazy_import_pink, +) + +from embodichain.utils import configclass, logger +from embodichain.lab.sim.solvers import SolverCfg, BaseSolver + +from embodichain.utils.string import ( + is_regular_expression, + resolve_matching_names_values, +) + +if TYPE_CHECKING: + from typing import Self + + +@configclass +class PinkSolverCfg(SolverCfg): + """Configuration for Pink IK Solver.""" + + class_type: str = "PinkSolver" + + # Solver iteration parameters + pos_eps: float = 5e-4 # Tolerance for convergence for position + rot_eps: float = 5e-4 # Tolerance for convergence for rotation + max_iterations: int = 1000 # Maximum number of iterations for the solver + dt: float = 0.1 # Time step for numerical integration + damp: float = 1e-6 # Damping factor to prevent numerical instability + + # Constraint configuration + is_only_position_constraint: bool = ( + False # Whether to only consider position constraints + ) + + # Path to the mesh files associated with the robot. These files are also loaded by Pinocchio's `robot_wrapper.BuildFromURDF`. + mesh_path: Optional[str] = None + + # A list of tasks for the Pink IK controller. These tasks are controllable by the env action. + # These tasks can be used to control the pose of a frame or the angles of joints. + # For more details, visit: https://github.com/stephane-caron/pink + variable_input_tasks: List["pink.tasks.FrameTask"] = None + + # A list of tasks for the Pink IK controller. These tasks are fixed and not controllable by the env action. + # These tasks can be used to fix the pose of a frame or the angles of joints to a desired configuration. + # For more details, visit: https://github.com/stephane-caron/pink + fixed_input_tasks: List["pink.tasks.FrameTask"] = None + + # Show warning if IK solver fails to find a solution. + show_ik_warnings: bool = True + + # If True, the Pink IK solver will fail and raise an error if any joint limit is violated during optimization. + # PinkSolver will handle the error by setting the last joint positions. + # If False, the solver will ignore joint limit violations and return the closest solution found. + fail_on_joint_limit_violation: bool = True + + # Solver options: + # "clarabel": High-performance SOCP solver written in Rust. + # - Suitable for large-scale problems. + # - Fast and supports sparse matrices. + # + # "ecos": Efficient SOCP solver for small to medium-scale problems. + # - Fast and memory-efficient. + # + # "osqp": Quadratic programming solver based on ADMM. + # - Ideal for sparse and large-scale QP problems. + # - Numerically stable and widely used in robotics/control. + # + # "proxqp": C++ solver for dense and sparse QP problems. + # - Optimized for real-time applications. + # + # "scs": Solver for linear cone programming and SOCP. + # - Suitable for large-scale problems with low precision requirements. + # + # "daqp": Specialized QP solver for real-time and embedded systems. + # - Designed for fast and reliable quadratic programming. + solver_type = "osqp" + + def init_solver(self, **kwargs) -> "PinkSolver": + """Initialize the solver with the configuration. + + Args: + **kwargs: Additional keyword arguments that may be used for solver initialization. + + Returns: + PinkSolver: An initialized solver instance. + """ + + solver = PinkSolver(cfg=self, **kwargs) + + # Set the Tool Center Point (TCP) for the solver + if isinstance(self.tcp, torch.Tensor): + tcp = self.tcp.cpu().numpy() + else: + tcp = self.tcp + + solver.set_tcp(tcp) + + return solver + + +class PinkSolver(BaseSolver): + """Standalone implementation of Pink IK Solver.""" + + def __init__(self, cfg: PinkSolverCfg, **kwargs): + """Initialize the solver with the configuration. + + Args: + **kwargs: Additional keyword arguments that may be used for solver initialization. + + Returns: + PinkSolver: An initialized solver instance. + """ + super().__init__(cfg=cfg, **kwargs) + + self.pin = lazy_import_pinocchio() + self.pink = lazy_import_pink() + + from embodichain.lab.sim.solvers.null_space_posture_task import ( + NullSpacePostureTask, + ) + + self.tcp = cfg.tcp + + if cfg.mesh_path is None: + urdf_dir = os.path.dirname(cfg.urdf_path) + cfg.mesh_path = urdf_dir + + # Initialize robot model + self.entire_robot = self.pin.RobotWrapper.BuildFromURDF( + self.cfg.urdf_path, self.cfg.mesh_path, root_joint=None + ) + + self.pink_joint_names = self.entire_robot.model.names.tolist()[ + 1: + ] # Exclude 'universe' joint + + self.pink_dof = ( + self.entire_robot.model.njoints - 1 + ) # Degrees of freedom of robot joints + + # Get reduced robot model + self.robot = self._get_reduce_robot() + + # Initialize Pink configuration + self.pink_cfg = self.pink.configuration.Configuration( + self.robot.model, self.robot.data, self.robot.q0 + ) + + if self.cfg.variable_input_tasks is None: + self.cfg.variable_input_tasks = [ + self.pink.tasks.FrameTask( + frame=self.cfg.end_link_name, # Frame name (use actual frame name from URDF) + position_cost=1.0, # Position cost weight + orientation_cost=1.0, # Orientation cost weight + ) + ] + + if self.cfg.fixed_input_tasks is None: + self.cfg.fixed_input_tasks = [] + + # Set default targets for tasks + for task in self.cfg.variable_input_tasks: + if isinstance(task, NullSpacePostureTask): + task.set_target(self.init_qpos) + continue + task.set_target_from_configuration(self.pink_cfg) + for task in self.cfg.fixed_input_tasks: + task.set_target_from_configuration(self.pink_cfg) + + # Create joint name mappings if provided + if self.cfg.joint_names: + pink_joint_names = self.robot.model.names.tolist()[ + 1: + ] # Exclude 'universe' joint + self.dexsim_to_pink_ordering = [ + self.cfg.joint_names.index(pink_joint) + for pink_joint in pink_joint_names + ] + self.pink_to_dexsim_ordering = [ + pink_joint_names.index(isaac_joint) + for isaac_joint in self.cfg.joint_names + ] + else: + self.dexsim_to_pink_ordering = None + self.pink_to_dexsim_ordering = None + + def _get_reduce_robot(self) -> "pin.RobotWrapper": + """Build a reduced robot model by locking all joints except those in self.joint_names. + + Returns: + pin.RobotWrapper: The reduced robot model with specified joints unlocked. + """ + pink_joint_names = self.entire_robot.model.names.tolist() + + # Lock all joints except those in self.joint_names and 'universe' + fixed_joint_names = [ + name + for name in pink_joint_names + if name not in self.joint_names and name != "universe" + ] + + reduced_robot = self.entire_robot.buildReducedRobot( + list_of_joints_to_lock=fixed_joint_names + ) + return reduced_robot + + def reorder_array( + self, input_array: List[float], reordering_array: List[int] + ) -> List[float]: + """Reorder array elements based on provided indices. + + Args: + input_array: Array to reorder + reordering_array: Indices for reordering + + Returns: + Reordered array + """ + return [input_array[i] for i in reordering_array] + + def update_null_space_joint_targets(self, current_qpos: np.ndarray): + """Update the null space joint targets. + + This method updates the target joint positions for null space posture tasks based on the current + joint configuration. This is useful for maintaining desired joint configurations when the primary + task allows redundancy. + + Args: + current_qpos: The current joint positions of shape (num_joints,). + """ + from embodichain.lab.sim.solvers.null_space_posture_task import ( + NullSpacePostureTask, + ) + + for task in self.cfg.variable_input_tasks: + if isinstance(task, NullSpacePostureTask): + task.set_target(current_qpos) + + def get_ik( + self, + target_xpos: Optional[Union[torch.Tensor, np.ndarray]], + qpos_seed: Optional[Union[torch.Tensor, np.ndarray]] = None, + return_all_solutions: bool = False, + **kwargs, + ) -> Tuple[torch.Tensor, torch.Tensor]: + """Compute target joint positions using inverse kinematics. + + Args: + target_pose (Optional[Union[torch.Tensor, np.ndarray]]): Target end-effector pose + qpos_seed (Optional[Union[torch.Tensor, np.ndarray]]): Seed joint positions + return_all_solutions (bool, optional): Whether to return all IK solutions or just the best one. Defaults to False. + **kwargs: Additional keyword arguments for future extensions. + + Returns: + Target joint positions. (n_sample, 1, dof) of float. + """ + if qpos_seed is None: + qpos_seed = np.zeros(self.dof) + + if isinstance(qpos_seed, torch.Tensor): + qpos_seed = qpos_seed.detach().cpu().numpy() + if qpos_seed.ndim > 1: + qpos_seed = qpos_seed.flatten() + + if target_xpos.ndim == 2: + target_xpos = target_xpos.unsqueeze(0) + if isinstance(target_xpos, torch.Tensor): + target_xpos = target_xpos.detach().cpu().numpy() + + if target_xpos.shape == (1, 4, 4): + target_xpos = target_xpos[0] + + if target_xpos.shape == (4, 4): + xpos = self.pin.SE3(target_xpos) + else: + raise ValueError( + f"target_xpos shape {target_xpos.shape} not supported for SE3 construction." + ) + + self.cfg.variable_input_tasks[0].set_target(xpos) + + # Handle joint ordering if mapping provided + if self.dexsim_to_pink_ordering: + qpos_pink = np.array( + self.reorder_array(qpos_seed, self.dexsim_to_pink_ordering) + ) + else: + qpos_pink = np.array(qpos_seed) + + # Update configuration with current joint positions + self.pink_cfg.update(qpos_pink) + + tasks = self.cfg.variable_input_tasks + self.cfg.fixed_input_tasks + + try: + num_iter = 1 if self.cfg.max_iterations == 1 else self.cfg.max_iterations + + for i in range(num_iter): + # Solve IK to get joint velocities + velocity = self.pink.solve_ik( + configuration=self.pink_cfg, + tasks=tasks, + damping=self.cfg.damp, + dt=self.cfg.dt, + solver=self.cfg.solver_type, + safety_break=self.cfg.fail_on_joint_limit_violation, + ) + self.pink_cfg.integrate_inplace(velocity, self.cfg.dt) + err = self.cfg.variable_input_tasks[0].compute_error(self.pink_cfg) + + # Compute joint position changes + # Update joint positions + # delta_q = velocity * self.cfg.dt + # self.pink_cfg.update(delta_q) + # logger.log_warning(f"Iteration {i}, error: {err}, delta_q: {delta_q}") + pos_achieved = np.linalg.norm(err[:3]) <= self.cfg.pos_eps + + if self.cfg.is_only_position_constraint: + if pos_achieved: + break + else: + ori_achieved = np.linalg.norm(err[3:]) <= self.cfg.rot_eps + if pos_achieved and ori_achieved: + break + + # except NoSolutionFound as e: + except (AssertionError, Exception) as e: + # Print warning and return the current joint positions as the target + # Not using omni.log since its not available in CI during docs build + if self.cfg.show_ik_warnings: + logger.log_warning( + "Warning: IK quadratic solver could not find a solution! Did not update the target joint" + f" positions.\nError: {e}" + ) + return torch.tensor(False, dtype=torch.bool), torch.tensor( + qpos_seed, device=self.device, dtype=torch.float32 + ) + + qpos = torch.tensor( + self.pink_cfg.q[self.pink_to_dexsim_ordering], + device=self.device, + dtype=torch.float32, + ) + + if return_all_solutions: + logger.log_warning( + "return_all_solutions=True is not supported in DifferentialSolver. Returning the best solution only." + ) + + # Add the velocity changes to the current joint positions to get the target joint positions + # target_qpos = torch.add( + # qvel_dexsim, + # torch.tensor(joint_seed, device=self.device, dtype=torch.float32), + # ) + dof = qpos.shape[-1] + qpos = qpos.reshape(-1, 1, dof) + return torch.tensor(True, dtype=torch.bool), qpos + + def _get_fk( + self, + qpos: Optional[Union[torch.Tensor, np.ndarray]], + **kwargs, + ) -> torch.tensor: + """Compute the forward kinematics for the robot given joint positions. + + Args: + qpos (torch.Tensor or np.ndarray): Joint positions, shape should be (nq,). + **kwargs: Additional keyword arguments (not used). + + Returns: + torch.Tensor: The homogeneous transformation matrix (4x4) of the end-effector (after applying TCP). + """ + if isinstance(qpos, torch.Tensor): + qpos_np = qpos.detach().cpu().numpy() + else: + qpos_np = np.array(qpos) + + qpos_np = np.squeeze(qpos_np) + if qpos_np.ndim != 1: + raise ValueError(f"qpos shape must be (nq,), but got {qpos_np.shape}") + + self.pin.forwardKinematics(self.robot.model, self.robot.data, qpos_np) + + # Retrieve the pose of the specified link + frame_index = self.robot.model.getFrameId(self.end_link_name) + joint_index = self.robot.model.frames[frame_index].parent + xpos_se3 = self.robot.data.oMi.tolist()[joint_index] + + xpos = np.eye(4) + xpos[:3, :3] = xpos_se3.rotation + xpos[:3, 3] = xpos_se3.translation.T + + result = np.dot(xpos, self.tcp_xpos) + return torch.from_numpy(result) diff --git a/embodichain/lab/sim/solvers/pinocchio_solver.py b/embodichain/lab/sim/solvers/pinocchio_solver.py new file mode 100644 index 00000000..719fabbe --- /dev/null +++ b/embodichain/lab/sim/solvers/pinocchio_solver.py @@ -0,0 +1,644 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import torch +import numpy as np +from typing import Optional, Union, Tuple, Any, List, TYPE_CHECKING +from itertools import product +from copy import deepcopy + +from embodichain.utils import configclass, logger +from embodichain.lab.sim.solvers import SolverCfg, BaseSolver + +from embodichain.lab.sim.utility.import_utils import ( + lazy_import_pinocchio, + lazy_import_casadi, + # lazy_import_pinocchio_casadi, +) + + +if TYPE_CHECKING: + from typing import Self + + +@configclass +class PinocchioSolverCfg(SolverCfg): + + class_type: str = "PinocchioSolver" + + mesh_path: str = None + + # Solver iteration parameters + pos_eps: float = 5e-4 # Tolerance for convergence for position + rot_eps: float = 5e-4 # Tolerance for convergence for rotation + max_iterations: int = 1000 # Maximum number of iterations for the solver + dt: float = 0.1 # Time step for numerical integration + damp: float = 1e-6 # Damping factor to prevent numerical instability + + # Constraint configuration + is_only_position_constraint: bool = ( + False # Whether to only consider position constraints + ) + + # Sampling configuration + num_samples: int = ( + 30 # Number of samples to generate different joint seeds for IK iterations + ) + + def init_solver(self, **kwargs) -> "PinocchioSolver": + """Initialize the solver with the configuration. + + Args: + **kwargs: Additional keyword arguments that may be used for solver initialization. + + Returns: + PinocchioSolver: An initialized solver instance. + """ + + solver = PinocchioSolver(cfg=self, **kwargs) + + # Set the Tool Center Point (TCP) for the solver + if isinstance(self.tcp, torch.Tensor): + tcp = self.tcp.cpu().numpy() + else: + tcp = self.tcp + + solver.set_tcp(tcp) + + return solver + + +class PinocchioSolver(BaseSolver): + def __init__(self, cfg: PinocchioSolverCfg, **kwargs): + super().__init__(cfg=cfg, **kwargs) + + self.pin = lazy_import_pinocchio() + self.casadi = lazy_import_casadi() + # self.cpin = lazy_import_pinocchio_casadi() + + # Set Tool Center Point (TCP) + self.tcp = cfg.tcp + + # Set IK solver parameters + self.pos_eps = cfg.pos_eps + self.rot_eps = cfg.rot_eps + self.max_iterations = cfg.max_iterations + self.dt = cfg.dt + self.damp = cfg.damp + self.is_only_position_constraint = cfg.is_only_position_constraint + self.num_samples = cfg.num_samples + + # Set mesh path if not provided + if cfg.mesh_path is None: + urdf_dir = os.path.dirname(cfg.urdf_path) + cfg.mesh_path = urdf_dir + + # Load full robot model from URDF + self.entire_robot = self.pin.RobotWrapper.BuildFromURDF( + cfg.urdf_path, cfg.mesh_path, root_joint=None + ) + + # Get all joint names and degrees of freedom (excluding 'universe') + self.all_joint_names = self.entire_robot.model.names.tolist()[ + 1: + ] # Exclude 'universe' joint + self.all_dof = ( + self.entire_robot.model.njoints - 1 + ) # Degrees of freedom of robot joints + + # Build reduced robot model (only relevant joints unlocked) + self.robot = self._get_reduce_robot() + self.joint_names = self.robot.model.names.tolist()[ + 1: + ] # Exclude 'universe' joint + self.dof = ( + self.robot.model.njoints - 1 + ) # Degrees of freedom of reduced robot joints + + self.upper_position_limits = self.robot.model.upperPositionLimit + self.lower_position_limits = self.robot.model.lowerPositionLimit + + self.ik_nearest_weight = np.ones(self.dof) + + # TODO: The Casadi-based solver is currently disabled due to stability issues. + # Note: Casadi-based optimization is currently prone to divergence and requires further debugging and optimization. + if __debug__ and False: + # Creating Casadi models and data for symbolic computing + self.cmodel = self.cpin.Model(self.robot.model) + self.cdata = self.cmodel.createData() + self.cq = self.casadi.SX.sym("q", self.robot.model.nq, 1) + self.cTf = self.casadi.SX.sym("Tf", 4, 4) + self.cpin.framesForwardKinematics(self.cmodel, self.cdata, self.cq) + self.ee_id = self.robot.model.getFrameId(self.end_link_name) + + # Define error functions for position and orientation + self.translational_error = self.casadi.Function( + "translational_error", + [self.cq, self.cTf], + [self.cdata.oMf[self.ee_id].translation - self.cTf[:3, 3]], + ) + self.rotational_error = self.casadi.Function( + "rotational_error", + [self.cq, self.cTf], + [ + self.cpin.log3( + self.cdata.oMf[self.ee_id].rotation @ self.cTf[:3, :3].T + ) + ], + ) + + # Set up CasADi optimization problem + self.opti = self.casadi.Opti() + self.var_q = self.opti.variable(self.robot.model.nq) + self.var_q_last = self.opti.parameter(self.robot.model.nq) + self.param_tf = self.opti.parameter(4, 4) + self.translational_cost = self.casadi.sumsqr( + self.translational_error(self.var_q, self.param_tf) + ) + self.rotation_cost = self.casadi.sumsqr( + self.rotational_error(self.var_q, self.param_tf) + ) + self.regularization_cost = self.casadi.sumsqr(self.var_q) + self.smooth_cost = self.casadi.sumsqr(self.var_q - self.var_q_last) + + # Add joint position constraints to ensure the solution stays within physical joint limits. + self.opti.subject_to( + self.opti.bounded( + self.robot.model.lowerPositionLimit, + self.var_q, + self.robot.model.upperPositionLimit, + ) + ) + + # Define the objective function for IK optimization: + # - Prioritize end-effector position accuracy (high weight) + # - Include orientation accuracy + # - Add regularization to avoid extreme joint values + # - Encourage smoothness between consecutive solutions + self.opti.minimize( + 100 * self.translational_cost + + 50 * self.rotation_cost + + 0.02 * self.regularization_cost + + 0.1 * self.smooth_cost + ) + + # Set solver options for IPOPT + opts = { + "ipopt": { + "print_level": 0, + "max_iter": self.max_iterations, + "tol": self.pos_eps, + }, + "print_time": False, + "calc_lam_p": True, + } + self.opti.solver("ipopt", opts) + + # Initialize joint positions to zero + self.init_qpos = np.zeros(self.robot.model.nq) + + # Perform forward kinematics with zero configuration + self.pin.forwardKinematics(self.robot.model, self.robot.data, self.init_qpos) + + # Retrieve the pose of the specified root link + frame_index = self.robot.model.getFrameId(self.root_link_name) + root_base_pose = self.robot.model.frames[frame_index].placement + self.root_base_xpos = np.eye(4) + self.root_base_xpos[:3, :3] = root_base_pose.rotation + self.root_base_xpos[:3, 3] = root_base_pose.translation.T + + def _get_reduce_robot(self) -> "pin.RobotWrapper": + """Build a reduced robot model by locking all joints except those in self.joint_names. + + Returns: + pin.RobotWrapper: The reduced robot model with specified joints unlocked. + """ + all_joint_names = self.entire_robot.model.names.tolist() + + # Lock all joints except those in self.joint_names and 'universe' + fixed_joint_names = [ + name + for name in all_joint_names + if name not in self.joint_names and name != "universe" + ] + + reduced_robot = self.entire_robot.buildReducedRobot( + list_of_joints_to_lock=fixed_joint_names + ) + return reduced_robot + + def set_tcp(self, tcp: np.ndarray): + self.tcp = tcp + + def get_iteration_params(self) -> dict: + r"""Returns the current iteration parameters. + + Returns: + dict: A dictionary containing the current values of: + - pos_eps (float): Pos convergence threshold + - rot_eps (float): Rot convergence threshold + - max_iterations (int): Maximum number of iterations. + - dt (float): Time step size. + - damp (float): Damping factor. + - num_samples (int): Number of samples. + - is_only_position_constraint (bool): Flag to indicate whether the solver should only consider position constraints. + """ + return { + "pos_eps": self._pos_eps, + "rot_eps": self._rot_eps, + "max_iterations": self._max_iterations, + "dt": self._dt, + "damp": self._damp, + "num_samples": self._num_samples, + } + + def set_iteration_params( + self, + pos_eps: float = 5e-4, + rot_eps: float = 5e-4, + max_iterations: int = 1000, + dt: float = 0.1, + damp: float = 1e-6, + num_samples: int = 30, + is_only_position_constraint: bool = False, + ) -> bool: + r"""Sets the iteration parameters for the kinematics solver. + + Args: + pos_eps (float): Pos convergence threshold, must be positive. + rot_eps (float): Rot convergence threshold, must be positive. + max_iterations (int): Maximum number of iterations, must be positive. + dt (float): Time step size, must be positive. + damp (float): Damping factor, must be non-negative. + num_samples (int): Number of samples, must be positive. + is_only_position_constraint (bool): Flag to indicate whether the solver should only consider position constraints. + + Returns: + bool: True if all parameters are valid and set, False otherwise. + """ + # TODO: Check which parameters are no longer needed. + # Validate parameters + if pos_eps <= 0: + logger.log_warning("Pos epsilon must be positive.") + return False + if rot_eps <= 0: + logger.log_warning("Rot epsilon must be positive.") + return False + if max_iterations <= 0: + logger.log_warning("Max iterations must be positive.") + return False + if dt <= 0: + logger.log_warning("Time step must be positive.") + return False + if damp < 0: + logger.log_warning("Damping factor must be non-negative.") + return False + if num_samples <= 0: + logger.log_warning("Number of samples must be positive.") + return False + + # Set parameters if all are valid + self.pos_eps = pos_eps + self.rot_eps = rot_eps + self.max_iterations = max_iterations + self.dt = dt + self.damp = damp + self.num_samples = num_samples + self.is_only_position_constraint = is_only_position_constraint + + if False: + opts = { + "ipopt": { + "print_level": 0, + "max_iter": self.max_iterations, + "tol": self.pos_eps, + }, + "print_time": False, + "calc_lam_p": False, + } + self.opti.solver("ipopt", opts) + + return True + + def qpos_to_limits( + self, + q: np.ndarray, + joint_seed: np.ndarray, + ): + """Adjusts the joint positions (q) to be within specified limits and as close as possible to the joint seed, + while minimizing the total weighted difference. + + Args: + q (np.ndarray): The original joint positions. + joint_seed (np.ndarray): The desired (seed) joint positions. + + Returns: + np.ndarray: The adjusted joint positions within the specified limits. + """ + best_qpos_limit = np.copy(q) + best_total_q_diff = float("inf") + + # Initialize a list for possible values for each joint + possible_arrays = [] + + if self.ik_nearest_weight is None: + self.ik_nearest_weight = np.ones_like(best_qpos_limit) + + # Generate possible values for each joint + dof_num = len(q) + for i in range(dof_num): + current_possible_values = [] + + # Calculate how many 2π fits into the adjustment to the limits + lower_adjustment = (q[i] - self.lower_position_limits[i]) // (2 * np.pi) + upper_adjustment = (self.upper_position_limits[i] - q[i]) // (2 * np.pi) + + # Consider the current value and its periodic adjustments + for offset in range( + int(lower_adjustment) - 1, int(upper_adjustment) + 2 + ): # Adjust by calculated limits + adjusted_value = q[i] + offset * (2 * np.pi) + + # Check if the adjusted value is within limits + if ( + self.lower_position_limits[i] + <= adjusted_value + <= self.upper_position_limits[i] + ): + current_possible_values.append(adjusted_value) + + # Also check the original value + if self.lower_position_limits[i] <= q[i] <= self.upper_position_limits[i]: + current_possible_values.append(q[i]) + + if not current_possible_values: + return [] # If no possible values for an active joint + possible_arrays.append(current_possible_values) + + # Generate all possible combinations + all_possible_combinations = product(*possible_arrays) + + # Check each combination and calculate the absolute difference sum + for combination in all_possible_combinations: + total_q_diff = np.sum( + np.abs(np.array(combination) - joint_seed) * self.ik_nearest_weight + ) + + # If a smaller difference sum is found, update the best solution + if total_q_diff < best_total_q_diff: + best_total_q_diff = total_q_diff + best_qpos_limit = np.array(combination) + + return best_qpos_limit + + def get_ik( + self, + target_xpos: Optional[Union[torch.Tensor, np.ndarray]], + qpos_seed: np.ndarray = None, + qvel_seed: np.ndarray = None, + return_all_solutions: bool = False, + **kwargs, + ) -> Tuple[bool, np.ndarray]: + """Solve inverse kinematics (IK) for the robot to achieve the specified end-effector pose. + + Args: + target_xpos (torch.Tensor or np.ndarray): Desired end-effector pose as a (4, 4) homogeneous transformation matrix. + qpos_seed (np.ndarray, optional): Initial joint positions used as the seed for optimization. If None, uses zero configuration. + qvel_seed (np.ndarray, optional): Initial joint velocities (not used in current implementation). + return_all_solutions (bool, optional): If True, return all valid IK solutions found; otherwise, return only the best solution. Default is False. + **kwargs: Additional keyword arguments for future extensions. + + Returns: + Tuple[bool, np.ndarray]: + - success (bool or torch.BoolTensor): True if a valid solution is found, False otherwise. + - qpos (np.ndarray or torch.Tensor): Joint positions that achieve the target pose. If no solution, returns the seed joint positions. + """ + if qpos_seed is not None: + if isinstance(qpos_seed, torch.Tensor): + self.init_qpos = qpos_seed.detach().cpu().numpy() + else: + self.init_qpos = np.array(qpos_seed) + + if isinstance(target_xpos, torch.Tensor): + target_xpos = target_xpos.detach().cpu().numpy() + + if target_xpos.ndim == 3: + target_xpos = target_xpos[0] + + target_xpos = self.root_base_xpos @ target_xpos + compute_xpos = target_xpos @ np.linalg.inv(self.tcp_xpos) + + frame_index = self.robot.model.getFrameId(self.end_link_name) + joint_index = self.robot.model.frames[frame_index].parent + + l2w = self.pin.SE3() + l2w.translation[:] = compute_xpos[:3, 3] + l2w.rotation[:] = compute_xpos[:3, :3] + l2j = self.robot.model.frames[frame_index].placement + oMdes = l2w * l2j.inverse() + + # Deep copy joint seed to avoid modifying the original seed + q = deepcopy(self.init_qpos).astype(np.float64).flatten() + + for i in range(self.max_iterations): + # Perform forward kinematics to compute the current pose + self.pin.forwardKinematics(self.robot.model, self.robot.data, q) + current_pose_se3 = self.robot.data.oMi[joint_index] + + if self.is_only_position_constraint: + # Fix the rotation part of the pose + fixed_pose = np.eye(4) + fixed_pose[:3, :3] = compute_xpos[:3, :3] # Use target rotation + fixed_pose[ + :3, 3 + ] = current_pose_se3.translation.T # Use current position + fixed_pose_SE3 = self.pin.SE3(fixed_pose) + current_pose_se3 = self.pin.SE3(fixed_pose_SE3) + + iMd = current_pose_se3.actInv(oMdes) # Calculate the pose error + err = self.pin.log6(iMd).vector # Get the error vector + + # Check position convergence + pos_converged = np.linalg.norm(err[:3]) < self.pos_eps + + if self.is_only_position_constraint: + if pos_converged: + # Convergence achieved, apply joint limits + q = self.qpos_to_limits(q, self.init_qpos) + if 0 == len(q): + continue + return torch.tensor([True], dtype=torch.bool), torch.from_numpy( + q + ).to(dtype=torch.float32) + else: + # Check rotation convergence + rot_converged = np.linalg.norm(err[3:]) < self.rot_eps + + # Check for overall convergence + if pos_converged and rot_converged: + # Convergence achieved, apply joint limits + q = self.qpos_to_limits(q, self.init_qpos) + if 0 == len(q): + continue + return torch.tensor([True], dtype=torch.bool), torch.from_numpy( + q + ).to(dtype=torch.float32) + + # Compute the Jacobian + J = self.pin.computeJointJacobian( + self.robot.model, self.robot.data, q, joint_index + ) + Jlog = self.pin.Jlog6(iMd.inverse()) + J = -Jlog @ J + + # Damped least squares + JJt = J @ J.T + JJt[np.diag_indices_from(JJt)] += self.damp + # Compute the velocity update + v = -(J.T @ np.linalg.solve(JJt, err)) + + # Update joint positions + new_q = self.pin.integrate(self.robot.model, q, v * self.dt) + q = new_q + + # Return failure and the last computed joint positions + return torch.tensor([False], dtype=torch.bool), torch.from_numpy( + np.array(q) + ).to(dtype=torch.float32) + + # TODO: The Casadi-based solver is currently disabled due to stability issues. + # Note: Casadi-based optimization is currently prone to divergence and requires further debugging and optimization. + if __debug__ and False: + self.opti.set_initial(self.var_q, self.init_qpos) + + self.opti.set_value(self.param_tf, compute_xpos) + + try: + num_iter = 1 if self.max_iterations == 1 else self.max_iterations + + for i in range(num_iter): + self.opti.set_value(self.var_q_last, self.init_qpos) + sol = self.opti.solve() + sol_q = self.opti.value(self.var_q) + # self.smooth_filter.add_data(sol_q) + # sol_q = self.smooth_filter.filtered_data + self.init_qpos = sol_q + + # if qvel_seed is not None: + # v = qvel_seed * 0.0 + # else: + # v = (sol_q - self.init_qpos) * 0.0 + # sol_tauff = pin.rnea( + # self.robot.model, + # self.robot.data, + # sol_q, + # v, + # np.zeros(self.robot.model.nv), + # ) + + temp_xpos = self._get_fk(sol_q) + err = temp_xpos - target_xpos + pos_converged = np.linalg.norm(err[:3]) < self.pos_eps + print(f"Iter {i}: pos_err={np.linalg.norm(err[:3])}") + + if self.is_only_position_constraint: + if pos_converged: + break + else: + rot_converged = np.linalg.norm(err[:3, :3]) < self.rot_eps + if pos_converged and rot_converged: + break + + if return_all_solutions: + logger.log_warning( + "return_all_solutions=True is not supported in DifferentialSolver. Returning the best solution only." + ) + + return torch.tensor(True, dtype=torch.bool), torch.from_numpy(sol_q).to( + dtype=torch.float32 + ) + + except Exception as e: + logger.log_warning(f"IK solver failed to converge. Debug info: {e}") + + sol_q = self.opti.debug.value(self.var_q) + # self.smooth_filter.add_data(sol_q) + # sol_q = self.smooth_filter.filtered_data + self.init_qpos = sol_q + + # if qvel_seed is not None: + # v = qvel_seed * 0.0 + # else: + # v = (sol_q - self.init_qpos) * 0.0 + + # sol_tauff = pin.rnea( + # self.robot.model, + # self.robot.data, + # sol_q, + # v, + # np.zeros(self.robot.model.nv), + # ) + + logger.log_debug( + f"sol_q:{sol_q} \nmotorstate: \n{qpos_seed} \nwrist_pose: \n{target_xpos}" + ) + + if return_all_solutions: + logger.log_warning( + "return_all_solutions=True is not supported in DifferentialSolver. Returning the best solution only." + ) + + return torch.tensor(False, dtype=torch.bool), torch.from_numpy( + np.array(qpos_seed) + ).to(dtype=torch.float32) + + def _get_fk( + self, + qpos: Optional[Union[torch.Tensor, np.ndarray]], + **kwargs, + ) -> np.ndarray: + """Compute the forward kinematics for the robot given joint positions. + + Args: + qpos (torch.Tensor or np.ndarray): Joint positions, shape should be (nq,). + **kwargs: Additional keyword arguments (not used). + + Returns: + np.ndarray: The resulting end-effector pose as a (4, 4) homogeneous transformation matrix. + """ + if isinstance(qpos, torch.Tensor): + qpos_np = qpos.detach().cpu().numpy() + else: + qpos_np = np.array(qpos) + + qpos_np = np.squeeze(qpos_np) + if qpos_np.ndim != 1: + raise ValueError(f"qpos shape must be (nq,), but got {qpos_np.shape}") + + self.pin.forwardKinematics(self.robot.model, self.robot.data, qpos_np) + + # Retrieve the pose of the specified link + frame_index = self.robot.model.getFrameId(self.end_link_name) + joint_index = self.robot.model.frames[frame_index].parent + xpos_se3 = self.robot.data.oMi.tolist()[joint_index] + + xpos = np.eye(4) + xpos[:3, :3] = xpos_se3.rotation + xpos[:3, 3] = xpos_se3.translation.T + + result = np.dot(xpos, self.tcp_xpos) + return result diff --git a/embodichain/lab/sim/solvers/pytorch_solver.py b/embodichain/lab/sim/solvers/pytorch_solver.py new file mode 100644 index 00000000..238e8912 --- /dev/null +++ b/embodichain/lab/sim/solvers/pytorch_solver.py @@ -0,0 +1,603 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch + +from typing import Optional, Union, Tuple, List, TYPE_CHECKING +from dataclasses import MISSING +from copy import deepcopy + +from embodichain.utils import configclass, logger +from embodichain.lab.sim.solvers import SolverCfg, BaseSolver +from embodichain.lab.sim.solvers.qpos_seed_sampler import QposSeedSampler + +if TYPE_CHECKING: + from typing import Self + +from embodichain.lab.sim.utility.import_utils import ( + lazy_import_pytorch_kinematics, +) + + +@configclass +class PytorchSolverCfg(SolverCfg): + """Configuration for the pytorch kinematics solver used in the robot simulation. + + This configuration includes properties related to the solver setup, such as the URDF path, + the end link name, and the root link name, along with the Tool Center Point (TCP). + """ + + class_type: str = "PytorchSolver" + + # Solver iteration parameters + pos_eps: float = 5e-4 + """Tolerance for convergence for position""" + + rot_eps: float = 5e-4 + """Tolerance for convergence for rotation""" + + max_iterations: int = 500 + """Maximum number of iterations for the solver""" + + dt: float = 0.1 + """Time step for numerical integration""" + + damp: float = 1e-6 + """Damping factor to prevent numerical instability""" + + is_only_position_constraint: bool = False + """Flag to indicate whether the solver should only consider position constraints.""" + + num_samples: int = 5 + """Number of samples to generate different joint seeds for IK iterations. + + A higher number of samples increases the chances of finding a valid solution + """ + + ik_nearest_weight: Optional[List[float]] = None + """Weights for the inverse kinematics nearest calculation. + + The weights influence how the solver prioritizes closeness to the seed position + when multiple solutions are available. + """ + + def init_solver( + self, device: torch.device = torch.device("cpu"), **kwargs + ) -> "PytorchSolver": + """Initialize the solver with the configuration. + + Args: + device (torch.device): The device to use for the solver. Defaults to CPU. + **kwargs: Additional keyword arguments that may be used for solver initialization. + + Returns: + PytorchSolver: An initialized solver instance. + """ + + solver = PytorchSolver(cfg=self, device=device, **kwargs) + + # Set the Tool Center Point (TCP) for the solver + if isinstance(self.tcp, torch.Tensor): + tcp = self.tcp.cpu().numpy() + else: + tcp = self.tcp + solver.set_tcp(tcp) + + return solver + + +def ensure_pose_shape(func): + """ + Decorator to ensure the input target_pose is of shape (n, 4, 4). + If input is (4, 4), it will be converted to (1, 4, 4). + Raises ValueError if shape is invalid. + """ + + def wrapper(self, target_xpos, *args, **kwargs): + target_xpos = torch.as_tensor( + target_xpos, device=self.device, dtype=torch.float32 + ) + if target_xpos.dim() == 2: + if target_xpos.shape != (4, 4): + raise ValueError("target_xpos must be of shape (4, 4) or (n, 4, 4).") + target_xpos = target_xpos.unsqueeze(0) + elif target_xpos.dim() == 3: + if target_xpos.shape[1:] != (4, 4): + raise ValueError("target_xpos must be of shape (4, 4) or (n, 4, 4).") + else: + raise ValueError( + "target_xpos must be a tensor of shape (4, 4) or (n, 4, 4)." + ) + return func(self, target_xpos, *args, **kwargs) + + return wrapper + + +class PytorchSolver(BaseSolver): + def __init__( + self, + cfg: PytorchSolverCfg, + device: str = None, + **kwargs, + ): + r"""Initializes the PyTorch kinematics solver. + + This constructor sets up the kinematics solver using PyTorch, + allowing for efficient computation of robot kinematics based on + the specified URDF model. + + Args: + cfg: The configuration for the solver. + device (str, optional): The device to use for the solver (e.g., "cpu" or "cuda"). + **kwargs: Additional keyword arguments passed to the base solver. + + """ + super().__init__(cfg=cfg, device=device, **kwargs) + + self.pk = lazy_import_pytorch_kinematics() + + # Initialize solver parameters from configuration + self._pos_eps = cfg.pos_eps + self._rot_eps = cfg.rot_eps + self._max_iterations = cfg.max_iterations + self._dt = cfg.dt + self._damp = cfg.damp + self._is_only_position_constraint = cfg.is_only_position_constraint + self._num_samples = cfg.num_samples + + # Get agent joint limits. + self.lim = torch.tensor( + self.pk_serial_chain.get_joint_limits(), device=self.device + ) + + # Inverse kinematics is available via damped least squares (iterative steps with Jacobian pseudo-inverse damped to avoid oscillation near singularlities). + self.pik = self.pk.PseudoInverseIK( + self.pk_serial_chain, + pos_tolerance=self._pos_eps, + rot_tolerance=self._rot_eps, + joint_limits=self.lim.T, + early_stopping_any_converged=True, + max_iterations=self._max_iterations, + lr=self._dt, + num_retries=1, + ) + + self.dof = self.pk_serial_chain.n_joints + + self.upper_position_limits = self.pk_serial_chain.high + self.lower_position_limits = self.pk_serial_chain.low + + def get_iteration_params(self) -> dict: + r"""Returns the current iteration parameters. + + Returns: + dict: A dictionary containing the current values of: + - pos_eps (float): Pos convergence threshold + - rot_eps (float): Rot convergence threshold + - max_iterations (int): Maximum number of iterations. + - dt (float): Time step size. + - damp (float): Damping factor. + - num_samples (int): Number of samples. + - is_only_position_constraint (bool): Flag to indicate whether the solver should only consider position constraints. + """ + return { + "pos_eps": self._pos_eps, + "rot_eps": self._rot_eps, + "max_iterations": self._max_iterations, + "dt": self._dt, + "damp": self._damp, + "num_samples": self._num_samples, + } + + def set_iteration_params( + self, + pos_eps: float = 5e-4, + rot_eps: float = 5e-4, + max_iterations: int = 1000, + dt: float = 0.1, + damp: float = 1e-6, + num_samples: int = 30, + is_only_position_constraint: bool = False, + ) -> bool: + r"""Sets the iteration parameters for the kinematics solver. + + Args: + pos_eps (float): Pos convergence threshold, must be positive. + rot_eps (float): Rot convergence threshold, must be positive. + max_iterations (int): Maximum number of iterations, must be positive. + dt (float): Time step size, must be positive. + damp (float): Damping factor, must be non-negative. + num_samples (int): Number of samples, must be positive. + is_only_position_constraint (bool): Flag to indicate whether the solver should only consider position constraints. + + Returns: + bool: True if all parameters are valid and set, False otherwise. + """ + # Validate parameters + if pos_eps <= 0: + logger.log_warning("Pos epsilon must be positive.") + return False + if rot_eps <= 0: + logger.log_warning("Rot epsilon must be positive.") + return False + if max_iterations <= 0: + logger.log_warning("Max iterations must be positive.") + return False + if dt <= 0: + logger.log_warning("Time step must be positive.") + return False + if damp < 0: + logger.log_warning("Damping factor must be non-negative.") + return False + if num_samples <= 0: + logger.log_warning("Number of samples must be positive.") + return False + + # Set parameters if all are valid + self._pos_eps = pos_eps + self._rot_eps = rot_eps + self._max_iterations = max_iterations + self._dt = dt + self._damp = damp + self._num_samples = num_samples + self._is_only_position_constraint = is_only_position_constraint + + self.pik = self.pk.PseudoInverseIK( + self.pk_serial_chain, + pos_tolerance=self._pos_eps, + rot_tolerance=self._rot_eps, + joint_limits=self.lim.T, + early_stopping_any_converged=True, + max_iterations=self._max_iterations, + lr=self._dt, + num_retries=1, + ) + + return True + + def _compute_inverse_kinematics( + self, target_pose: torch.Tensor, joint_seed: torch.Tensor + ) -> Tuple[Union[bool, torch.Tensor], torch.Tensor]: + r"""Computes the inverse kinematics solutions for the given target poses and joint seeds. + + Args: + target_pose (torch.Tensor): The target poses represented as a (batch_size, 4, 4) tensor. + joint_seed (torch.Tensor): The initial joint positions used as a seed. It can be either a 1D tensor of shape (dof,) or a 2D tensor of shape (batch_size, dof). + + Returns: + Tuple[Union[bool, torch.Tensor], torch.Tensor]: + - First element: + - If solutions exist: torch.BoolTensor of shape (batch_size,) indicating convergence per pose + - If no solutions: Python False + - Second element: + - If solutions exist: torch.Tensor of shape (batch_size, dof) containing joint solutions + - If no solutions: Empty torch.Tensor + """ + target_pose = target_pose.to(self.device).float() + joint_seed = joint_seed.to(self.device).float() + + # Extract translation and rotation parts + pos = target_pose[:, :3, 3] + rot = target_pose[:, :3, :3] + + tf = self.pk.Transform3d( + pos=pos, + rot=rot, + device=self.device, + ) + self.pik.initial_config = joint_seed + + result = self.pik.solve(tf) + + if result.converged_any.any().item(): + return result.converged_any, result.solutions[:, 0, :].squeeze(0) + + return False, torch.empty(0) + + @staticmethod + def _qpos_to_limits_single( + q: torch.Tensor, + joint_seed: torch.Tensor, + lower_position_limits: torch.Tensor, + upper_position_limits: torch.Tensor, + ik_nearest_weight: torch.Tensor, + periodic_mask: torch.Tensor = None, # Optional mask for periodic joints + ) -> torch.Tensor: + """ + Adjusts the given joint positions (q) to fit within the specified limits while minimizing the difference to the seed position. + + Args: + q (torch.Tensor): The initial joint positions. + joint_seed (torch.Tensor): The seed joint positions for comparison. + lower_position_limits (torch.Tensor): The lower bounds for the joint positions. + upper_position_limits (torch.Tensor): The upper bounds for the joint positions. + ik_nearest_weight (torch.Tensor): The weights for the inverse kinematics nearest calculation. + periodic_mask (torch.Tensor, optional): Boolean mask indicating which joints are periodic. + + Returns: + torch.Tensor: The adjusted joint positions that fit within the limits. + """ + device = q.device + joint_seed = joint_seed.to(device) + lower = lower_position_limits.to(device) + upper = upper_position_limits.to(device) + weight = ik_nearest_weight.to(device) + + # If periodic_mask is not provided, assume all joints are periodic + if periodic_mask is None: + periodic_mask = torch.ones_like(q, dtype=torch.bool, device=device) + + # Only enumerate [-2π, 0, 2π] for periodic joints, single value for non-periodic + offsets = torch.tensor([-2 * torch.pi, 0, 2 * torch.pi], device=device) + candidate_list = [] + for i in range(q.size(0)): + if periodic_mask[i]: + candidate_list.append(q[i] + offsets) + else: + candidate_list.append(q[i].unsqueeze(0)) + # Generate all possible combinations + mesh = torch.meshgrid(*candidate_list, indexing="ij") + candidates = torch.stack([m.reshape(-1) for m in mesh], dim=1) + # Filter candidates that are out of limits + mask = (candidates >= lower) & (candidates <= upper) + valid_mask = mask.all(dim=1) + valid_candidates = candidates[valid_mask] + if valid_candidates.shape[0] == 0: + return torch.tensor([]).to(device) + # Compute weighted distance to seed and select the closest + diffs = torch.abs(valid_candidates - joint_seed) * weight + distances = torch.sum(diffs, dim=1) + min_idx = torch.argmin(distances) + return valid_candidates[min_idx] + + def _qpos_to_limits( + self, qpos_list_split: torch.Tensor, joint_seed: torch.Tensor + ) -> torch.Tensor: + r"""Adjusts a batch of joint positions to fit within joint limits and minimize the weighted distance to the seed position. + + Args: + qpos_list_split (torch.Tensor): Batch of candidate joint positions, shape (N, dof). + joint_seed (torch.Tensor): The reference joint positions for comparison, shape (dof,). + + Returns: + torch.Tensor: Batch of adjusted joint positions that fit within the limits, shape (M, dof), + where M <= N (invalid candidates are filtered out). + """ + + periodic_mask = torch.ones_like( + qpos_list_split[0], dtype=torch.bool, device=self.device + ) + + adjusted_qpos_list = [ + self._qpos_to_limits_single( + q, + joint_seed, + self.lower_position_limits, + self.upper_position_limits, + self.ik_nearest_weight, + periodic_mask, + ) + for q in qpos_list_split + ] + + # Filter out empty results + adjusted_qpos_list = [q for q in adjusted_qpos_list if q.numel() > 0] + + return ( + torch.stack(adjusted_qpos_list).to(qpos_list_split.device) + if adjusted_qpos_list + else torch.tensor([], device=self.device) + ) + + @ensure_pose_shape + def get_ik( + self, + target_xpos: torch.Tensor, + qpos_seed: torch.Tensor = None, + num_samples: int = None, + return_all_solutions: bool = False, + **kwargs, + ) -> Tuple[torch.Tensor, torch.Tensor]: + r"""Computes the inverse kinematics for given target poses. + + This function generates random joint configurations within the specified limits, + including the provided joint_seed, and attempts to find valid inverse kinematics solutions. + It then identifies the joint positions that are closest to the joint_seed. + + Args: + target_xpos (torch.Tensor): A tensor representing the target positions. It can be of shape + (batch_size, 3) for multiple positions or (3,) for a single position. + qpos_seed (torch.Tensor, optional): Initial joint positions used as seed for IK solving. + Can be: + - 1D tensor of shape (dof,): Single seed for all target positions + - 2D tensor of shape (batch_size, dof): Individual seed per position + If None, defaults to zero configuration. Defaults to None. + num_samples (int, optional): The number of random samples to generate. Must be positive. + Defaults to None. + return_all_solutions (bool, optional): If True, returns all valid solutions found. + **kwargs: Additional arguments for future extensions. + + Returns: + Tuple[List[bool], torch.Tensor]: A tuple containing: + - A tensor of booleans indicating whether valid solutions were found for each target pose. (Shape: (batch_size,)) + - A tensor of shape (batch_size, 1, dof) containing joint positions for + each target pose, or an empty tensor if no valid solutions were found. + """ + # Convert target_pose to tensor and ensure correct device and dtype + target_xpos = torch.as_tensor( + target_xpos, device=self.device, dtype=torch.float32 + ) + if num_samples is not None: + self._num_samples = num_samples + + # Prepare qpos_seed + if qpos_seed is None: + qpos_seed = torch.zeros(self.dof, device=self.device) + else: + qpos_seed = torch.as_tensor(qpos_seed, device=self.device) + + # Check qpos_seed dimensions + if qpos_seed.dim() == 1: + qpos_seed = qpos_seed.unsqueeze(0) + qpos_seed_ndim = 1 + elif qpos_seed.dim() == 2: + qpos_seed_ndim = 2 + if qpos_seed.shape[0] != target_xpos.shape[0]: + raise ValueError( + "Batch size of qpos_seed must match batch size of target_xpos when qpos_seed is a 2D tensor." + ) + else: + raise ValueError("`qpos_seed` must be a tensor of shape (n,) or (n, n).") + + # Transform target_xpos by TCP + tcp_xpos = torch.as_tensor( + deepcopy(self.tcp_xpos), device=self.device, dtype=torch.float32 + ) + target_xpos = target_xpos @ torch.inverse(tcp_xpos) + + # Get joint limits and ensure shape matches dof + upper_limits = self.upper_position_limits.float() + lower_limits = self.lower_position_limits.float() + + batch_size = target_xpos.shape[0] + + sampler = QposSeedSampler( + num_samples=self._num_samples, dof=self.dof, device=self.device + ) + random_qpos_seeds = sampler.sample( + qpos_seed, lower_limits, upper_limits, batch_size + ) + target_xpos_repeated = sampler.repeat_target_xpos( + target_xpos, self._num_samples + ) + + # Compute IK solutions for all samples + res_list, qpos_list = self._compute_inverse_kinematics( + target_xpos_repeated, random_qpos_seeds + ) + + if not isinstance(res_list, torch.Tensor) or not res_list.any(): + logger.log_warning( + "Pk: No valid solutions found for the given target poses and joint seeds." + ) + return torch.zeros( + batch_size, dtype=torch.bool, device=self.device + ), torch.zeros((batch_size, self.dof), device=self.device) + + # Split res_list and qpos_list according to self._num_samples + res_list_split = torch.split(res_list, self._num_samples) + qpos_list_split = torch.split(qpos_list, self._num_samples) + + # Initialize the final results and the closest joint positions + final_results = [] + final_qpos = [] + + # For each batch, select the closest valid solution to qpos_seed + for i in range(batch_size): + target_qpos_seed = qpos_seed[i] if qpos_seed_ndim == 2 else qpos_seed + + if not res_list_split[i].any(): + final_results.append(False) + final_qpos.append(torch.zeros((1, self.dof), device=self.device)) + continue + + result_qpos_limit = self._qpos_to_limits( + qpos_list_split[i], target_qpos_seed + ) + + if result_qpos_limit.shape[0] == 0: + final_results.append(False) + final_qpos.append(torch.zeros((self.dof), device=self.device)) + continue + + distances = torch.norm(result_qpos_limit - target_qpos_seed, dim=1) + sorted_indices = torch.argsort(distances) + # shape: (N, dof) + sorted_qpos_array = result_qpos_limit[sorted_indices] + final_qpos.append(sorted_qpos_array) + final_results.append(True) + + # Pad all batches to the same number of solutions for stacking + max_solutions = max([q.shape[0] for q in final_qpos]) if final_qpos else 1 + final_qpos_tensor = torch.zeros( + (batch_size, max_solutions, self.dof), device=self.device + ) + for i, q in enumerate(final_qpos): + n = q.shape[0] + final_qpos_tensor[i, :n, :] = q + + final_results = torch.tensor( + final_results, dtype=torch.bool, device=self.device + ) + + if return_all_solutions: + # Return all sorted solutions for each batch (shape: batch_size, max_solutions, dof) + return final_results, final_qpos_tensor + + # Only return the closest solution for each batch (shape: batch_size, 1, dof) + # If multiple solutions, take the first (closest) + final_qpos_tensor = final_qpos_tensor[:, :1, :] + return final_results, final_qpos_tensor + + def get_all_fk(self, qpos: torch.tensor) -> torch.tensor: + r"""Get the forward kinematics for all links from root to end link. + + Args: + qpos (torch.Tensor): The joint positions. + + Returns: + list: A list of 4x4 homogeneous transformation matrices representing the poses of all links from root to end link. + """ + qpos = torch.as_tensor(qpos) + qpos = qpos.to(self.device) + + ret = self.pk_serial_chain.forward_kinematics(qpos, end_only=False) + link_names = list(ret.keys()) + + if self.root_link_name is not None: + try: + start_index = link_names.index(self.root_link_name) + except ValueError: + raise KeyError( + f"Root link name '{self.root_link_name}' not found in the kinematic chain" + ) + else: + start_index = 0 + + if self.end_link_name is not None: + try: + end_index = link_names.index(self.end_link_name) + 1 + except ValueError: + raise KeyError( + f"End link name '{self.end_link_name}' not found in the kinematic chain" + ) + else: + end_index = len(link_names) + + poses = [] + for link_name in link_names[start_index:end_index]: + xpos = ret[link_name] + if not hasattr(xpos, "get_matrix"): + raise AttributeError( + f"The result for link '{link_name}' must have 'get_matrix' attributes." + ) + xpos_t = torch.eye(4, device=xpos.get_matrix().device) + m = xpos.get_matrix() + xpos_t[:3, 3] = m[:, :3, 3] + xpos_t[:3, :3] = m[:, :3, :3] + poses.append(xpos_t) + + return poses diff --git a/embodichain/lab/sim/solvers/qpos_seed_sampler.py b/embodichain/lab/sim/solvers/qpos_seed_sampler.py new file mode 100644 index 00000000..91f7f3c6 --- /dev/null +++ b/embodichain/lab/sim/solvers/qpos_seed_sampler.py @@ -0,0 +1,88 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch + + +class QposSeedSampler: + """ + Standard joint seed sampler for IK solving. + + Generates joint seed samples for each target pose in a batch, including the provided seed and random samples within joint limits. + + Args: + num_samples (int): Number of samples per batch (including the seed). + dof (int): Degrees of freedom. + device (torch.device): Target device. + """ + + def __init__(self, num_samples: int, dof: int, device: torch.device): + self.num_samples = num_samples + self.dof = dof + self.device = device + + def sample( + self, + qpos_seed: torch.Tensor, + lower_limits: torch.Tensor, + upper_limits: torch.Tensor, + batch_size: int, + ) -> torch.Tensor: + """Generate joint seed samples for IK solving. + + Args: + qpos_seed (torch.Tensor): (batch_size, dof) or (1, dof) initial seed. + lower_limits (torch.Tensor): (dof,) lower joint limits. + upper_limits (torch.Tensor): (dof,) upper joint limits. + batch_size (int): Batch size. + + Returns: + torch.Tensor: (batch_size * num_samples, dof) joint seeds. + """ + joint_seeds_list = [] + for i in range(batch_size): + current_seed = ( + qpos_seed[i].unsqueeze(0) + if qpos_seed.shape[0] == batch_size + else qpos_seed + ) + if self.num_samples > 1: + rand_part = lower_limits + (upper_limits - lower_limits) * torch.rand( + (self.num_samples - 1, self.dof), device=self.device + ) + else: + rand_part = torch.empty((0, self.dof), device=self.device) + seeds = torch.cat([current_seed, rand_part], dim=0) + joint_seeds_list.append(seeds) + return torch.cat(joint_seeds_list, dim=0) + + def repeat_target_xpos( + self, target_xpos: torch.Tensor, num_samples: int + ) -> torch.Tensor: + """Repeat each target pose num_samples times for batch processing. + + Args: + target_xpos (torch.Tensor): (batch_size, 4, 4) or (batch_size, 3, 3) target poses. + num_samples (int): Number of repeats per batch. + + Returns: + torch.Tensor: (batch_size * num_samples, 4, 4) or (batch_size * num_samples, 3, 3) + """ + repeated_list = [ + target_xpos[i].unsqueeze(0).repeat(num_samples, 1, 1) + for i in range(target_xpos.shape[0]) + ] + return torch.cat(repeated_list, dim=0) diff --git a/embodichain/lab/sim/solvers/srs_solver.py b/embodichain/lab/sim/solvers/srs_solver.py new file mode 100644 index 00000000..44fa894f --- /dev/null +++ b/embodichain/lab/sim/solvers/srs_solver.py @@ -0,0 +1,1222 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np +import warp as wp +from itertools import product +from typing import Optional, Union, Tuple, Any, Literal, TYPE_CHECKING +from embodichain.utils import configclass, logger +from embodichain.lab.sim.solvers import SolverCfg, BaseSolver + +from embodichain.utils.warp.kinematics.srs_solver import ( + transform_pose_kernel, + compute_ik_kernel, + sort_ik_kernel, + nearest_ik_kernel, + check_success_kernel, +) +from embodichain.utils.device_utils import standardize_device_string + +if TYPE_CHECKING: + from typing import Self + from embodichain.lab.sim.robots.dexforce_w1.params import W1ArmKineParams + + +all = ["SRSSolver", "SRSSolverCfg"] + + +@configclass +class SRSSolverCfg(SolverCfg): + """Configuration for SRS inverse kinematics controller.""" + + class_type: str = "SRSSolver" + """Type of the solver class.""" + + # kine_params: "W1ArmKineParams" + # SRS-specific parameters + dh_params = [] + """Denavit-Hartenberg parameters for the robot's kinematic chain.""" + + qpos_limits = [] + """Joint position limits for the robot.""" + + T_b_ob = np.eye(4) + """Base to observed base transform.""" + + T_e_oe = np.eye(4) + """End-effector to observed end-effector transform.""" + + link_lengths = [] + """Link lengths of the robot arm.""" + + rotation_directions = [] + """Rotation directions for each joint.""" + + num_samples: int = 100 + """Number of samples for elbow angle during IK computation.""" + + sort_ik: bool = True + """Whether to sort IK solutions based on proximity to seed joint positions.""" + + # TODO: Each target pose may have multiple IK solutions; weights can help select the best one. + ik_nearest_weight: np.array = np.ones(7) + """Weights for each joint when finding the nearest IK solution.""" + + def init_solver( + self, num_envs: int = 1, device: torch.device = torch.device("cpu"), **kwargs + ) -> "SRSSolver": + """Initialize the solver with the configuration. + + Args: + device (torch.device): The device to use for the solver. Defaults to CPU. + num_envs (int): The number of environments for which the solver is initialized. + **kwargs: Additional keyword arguments that may be used for solver initialization. + + Returns: + SRSSolver: An initialized solver instance. + """ + + solver = SRSSolver(cfg=self, num_envs=num_envs, device=device, **kwargs) + + # Set the Tool Center Point (TCP) for the solver + if isinstance(self.tcp, torch.Tensor): + tcp = self.tcp.cpu().numpy() + else: + tcp = self.tcp + solver.set_tcp(tcp) + + return solver + + +class _BaseSRSSolverImpl: + """Base implementation for the SRS inverse kinematics solver.""" + + def __init__(self, cfg: SRSSolverCfg, device: torch.device): + # Initialize configuration and device + self.cfg = cfg + self.device = device + self.dofs = 7 + self.dh_params = cfg.dh_params + self.qpos_limits = cfg.qpos_limits + self.tcp_xpos = np.eye(4) + + # Initialize transformation matrices + self._parse_params() + + def _parse_params(self): + # Compute the inverse transformation matrices for TCP, end-effector, and base. + self.tcp_xpos = self.cfg.tcp + self.tcp_inv_np = np.linalg.inv(self.tcp_xpos) + self.T_e_oe_inv_np = np.linalg.inv(self.cfg.T_e_oe) + self.T_b_ob_inv_np = np.linalg.inv(self.cfg.T_b_ob) + + # Convert configuration parameters to numpy arrays for efficient computation. + self.dh_params_np = np.asarray(self.cfg.dh_params) + self.qpos_limits_np = np.asarray(self.cfg.qpos_limits) + self.link_lengths_np = np.asarray(self.cfg.link_lengths) + self.rotation_directions_np = np.asarray(self.cfg.rotation_directions) + + +class _CPUSRSSolverImpl(_BaseSRSSolverImpl): + """CPU implementation of the SRS inverse kinematics solver.""" + + def __init__(self, cfg: SRSSolverCfg, device: torch.device): + super().__init__(cfg, device) + + def _parse_params(self): + super()._parse_params() + + # Generate all possible configuration combinations for shoulder, elbow, and wrist. + # Each configuration is represented by a vector of three elements, each being +1 or -1. + # This covers all 8 possible sign combinations for the three joints. + self.configs = [ + np.array([x, y, z]) for x, y, z in product([1.0, -1.0], repeat=3) + ] + + # Generate a set of elbow angles sampled uniformly from -π to π. + # The number of samples is determined by self.cfg.num_samples. + # These angles are used for searching possible IK solutions. + self.elbow_angles = torch.linspace( + -torch.pi, torch.pi, self.cfg.num_samples, device=self.device + ) + + # Convert ik_nearest_weight to a tensor for efficient computation. + self.ik_nearest_weight_tensor = torch.tensor( + self.cfg.ik_nearest_weight, dtype=torch.float32, device=self.device + ) + + def _get_fk(self, target_joint: np.ndarray) -> np.ndarray: + """ + Compute the forward kinematics (FK) for a given joint state. + + Args: + target_joint (np.ndarray): Joint angles (shape: [7,]). + + Returns: + np.ndarray: 4x4 transformation matrix representing the end-effector pose. + """ + # Initialize pose as identity matrix + pose = np.eye(4) + + # Iterate through the DH parameters and compute the transformation + for i in range(self.dh_params.shape[0]): + d = self.dh_params[i, 0] + alpha = self.dh_params[i, 1] + a = self.dh_params[i, 2] + theta = self.dh_params[i, 3] + + # Add joint angle contribution if within bounds + if i < target_joint.size: + theta += target_joint[i] * self.cfg.rotation_directions[i] + + # Compute the transformation matrix for this joint + T = self._dh_transform(d, alpha, a, theta) + pose = pose @ T + + # Apply additional transformations: user frame, base, and tool center point (TCP) + pose = ( + self.cfg.T_b_ob + @ pose + @ self.cfg.T_e_oe # End-effector-to-observed-end-effector transform + @ self.tcp_xpos # Tool center point transform + ) + + return pose + + def _calculate_arm_joint_angles( + self, + P26: np.ndarray, + elbow_config: int, + joints: np.ndarray, + link_lengths: np.ndarray, + ) -> bool: + """ + Calculate joint angles based on the position vector P26. + + Args: + P26 (np.ndarray): Vector from shoulder to wrist. + elbow_config (int): Elbow configuration (+1 or -1). + joints (np.ndarray): Joint angles to be updated. + link_lengths (np.ndarray): Link lengths of the robot. + + Returns: + bool: True if successful, False otherwise. + """ + d_bs, d_se, d_ew = link_lengths[:3] + + norm_P26 = np.linalg.norm(P26) + if norm_P26 < np.abs(d_bs + d_ew): + logger.log_warning("Specified pose outside reachable workspace.") + return False + + elbow_cos_angle = (norm_P26**2 - d_se**2 - d_ew**2) / (2 * d_se * d_ew) + if abs(elbow_cos_angle) > 1.0: + logger.log_debug("Elbow singularity. End effector at limit.") + return False + + joints[3] = elbow_config * np.arccos(elbow_cos_angle) + + if abs(P26[2]) > 1e-6: + joints[0] = np.arctan2(P26[1], P26[0]) + else: + joints[0] = 0 + + euclidean_norm = np.hypot(P26[0], P26[1]) + angle_phi = np.arccos( + (d_se**2 + norm_P26**2 - d_ew**2) / (2 * d_se * norm_P26) + ) + joints[1] = np.arctan2(euclidean_norm, P26[2]) + elbow_config * angle_phi + + return True + + def _dh_transform( + self, d: float, alpha: float, a: float, theta: float + ) -> np.ndarray: + """ + Compute the Denavit-Hartenberg transformation matrix. + + Args: + d (float): Link offset. + alpha (float): Link twist. + a (float): Link length. + theta (float): Joint angle. + + Returns: + np.ndarray: 4x4 transformation matrix. + """ + cos_theta, sin_theta = np.cos(theta), np.sin(theta) + cos_alpha, sin_alpha = np.cos(alpha), np.sin(alpha) + + # fmt: off + return np.array( + [ + [cos_theta, -sin_theta * cos_alpha, sin_theta * sin_alpha, a * cos_theta], + [sin_theta, cos_theta * cos_alpha, -cos_theta * sin_alpha, a * sin_theta], + [0, sin_alpha, cos_alpha, d], + [0, 0, 0, 1], + ] + ) + # fmt: on + + def _skew(self, vector: np.ndarray) -> np.ndarray: + """ + Compute the skew-symmetric matrix of a vector. + + Args: + vector (np.ndarray): Input vector (3,). + + Returns: + np.ndarray: Skew-symmetric matrix (3x3). + """ + return np.array( + [ + [0, -vector[2], vector[1]], + [vector[2], 0, -vector[0]], + [-vector[1], vector[0], 0], + ] + ) + + def _compute_reference_plane( + self, target_pose: np.ndarray, elbow_config: int + ) -> Tuple[Optional[np.ndarray], Optional[np.ndarray], Optional[np.ndarray]]: + """ + Calculate the reference plane vector, rotation matrix, and joint values. + + Args: + target_pose (np.ndarray): Transformed target pose (4x4). + elbow_config (int): Elbow configuration (+1 or -1). + + Returns: + tuple: (plane_normal, base_to_elbow_rotation, joint_angles) or (None, None, None) if failed. + """ + dh_params = self.dh_params + link_lengths = self.cfg.link_lengths + + P_target = target_pose[:3, 3] + P02 = np.array([0, 0, link_lengths[0]]) + P67 = np.array([0, 0, dh_params[6, 0]]) + P06 = P_target - target_pose[:3, :3] @ P67 + P26 = P06 - P02 + + joint_angles = np.zeros(7) + if not self._calculate_arm_joint_angles( + P26, elbow_config, joint_angles, link_lengths + ): + return None, None, None + + T34_v = self._dh_transform( + dh_params[3, 0], dh_params[3, 1], dh_params[3, 2], joint_angles[3] + ) + P34_v = T34_v[:3, 3] + + norm_P34_P02 = np.linalg.norm(P34_v - P02) + if norm_P34_P02 > 1e-6: + v1 = (P34_v - P02) / norm_P34_P02 + else: + v1 = np.zeros_like(P34_v - P02) + v2 = (P06 - P02) / np.linalg.norm(P06 - P02) + plane_normal = np.cross(v1, v2) + + base_to_elbow_rotation = np.eye(3) + for i in range(3): + T = self._dh_transform( + dh_params[i, 0], dh_params[i, 1], dh_params[i, 2], joint_angles[i] + ) + base_to_elbow_rotation = base_to_elbow_rotation @ T[:3, :3] + + return plane_normal, base_to_elbow_rotation, joint_angles + + def _process_all_solutions( + self, + ik_qpos_tensor: torch.Tensor, + qpos_seed: torch.Tensor, + valid_mask: torch.Tensor, + success_tensor: torch.Tensor, + ) -> Tuple[torch.Tensor, torch.Tensor]: + """Returns all valid IK solutions (optionally sorted). + + Args: + ik_qpos_tensor (torch.Tensor): The IK joint position tensor. + qpos_seed (torch.Tensor): The seed joint position tensor. + valid_mask (torch.Tensor): The mask indicating valid solutions. + success_tensor (torch.Tensor): The tensor indicating success of IK solutions. + + Returns: + torch.Tensor: The success tensor. + torch.Tensor: The IK solutions tensor (sorted if specified). + """ + if self.cfg.sort_ik: + weighted_diff = ( + ik_qpos_tensor - qpos_seed.unsqueeze(1) + ) * self.ik_nearest_weight_tensor + distances = torch.norm(weighted_diff, dim=2) + distances[~valid_mask] = float("inf") + sorted_indices = torch.argsort(distances, dim=1) + sorted_ik_qpos_tensor = torch.gather( + ik_qpos_tensor, 1, sorted_indices.unsqueeze(-1).expand(-1, -1, 7) + ) + return success_tensor, sorted_ik_qpos_tensor + else: + return success_tensor, ik_qpos_tensor + + def _process_single_solution( + self, + ik_qpos_tensor: torch.Tensor, + qpos_seed: torch.Tensor, + valid_mask: torch.Tensor, + success_tensor: torch.Tensor, + ) -> Tuple[torch.Tensor, torch.Tensor]: + """Returns the nearest valid IK solution (optionally sorted). + + Args: + ik_qpos_tensor (torch.Tensor): The IK joint position tensor. + qpos_seed (torch.Tensor): The seed joint position tensor. + valid_mask (torch.Tensor): The mask indicating valid solutions. + success_tensor (torch.Tensor): The tensor indicating success of IK solutions. + + Returns: + torch.Tensor: The success tensor. + torch.Tensor: The nearest valid IK solution tensor. + """ + num_targets = ik_qpos_tensor.shape[0] + if self.cfg.sort_ik: + weighted_diff = ( + ik_qpos_tensor - qpos_seed.unsqueeze(1) + ) * self.ik_nearest_weight_tensor + distances = torch.norm(weighted_diff, dim=2) + mask = success_tensor.unsqueeze(1) & valid_mask + distances[~mask] = float("inf") + nearest_indices = torch.argmin(distances, dim=1) + nearest_solutions = torch.zeros( + (num_targets, 7), dtype=qpos_seed.dtype, device=self.device + ) + has_solution = distances.min(dim=1).values != float("inf") + if has_solution.any(): + nearest_solutions[has_solution] = ik_qpos_tensor[ + torch.arange(num_targets)[has_solution], + nearest_indices[has_solution], + ] + return success_tensor, nearest_solutions.unsqueeze(1) + else: + # Return first solution only + return success_tensor, ik_qpos_tensor[:, :1, :] + + def _get_each_ik( + self, target_pose: np.ndarray, nsparam: float, config: np.ndarray + ) -> Tuple[bool, Optional[np.ndarray]]: + """ + Computes the inverse kinematics for a given target pose, normalization parameter, and configuration. + + Args: + target_pose (np.ndarray): 4x4 target pose matrix. + nsparam (float): Normalization parameter (angle). + config (np.ndarray): Configuration index. + + Returns: + bool: Success flag. + np.ndarray: List of joint solutions (7) or None if no solution is found. + """ + # Validate the target pose matrix + target_pose = np.array(target_pose) + if target_pose.ndim == 3 and target_pose.shape[0] == 1: + target_pose = target_pose[0] # Extract the first matrix + if target_pose.shape != (4, 4): + logger.log_error( + f"Invalid xpos shape: {target_pose.shape}, expected (4,4)." + ) + return False, None + + shoulder_config, elbow_config, wrist_config = config[0], config[1], config[2] + + dof = self.dofs + joints_output = np.zeros(dof) + + # Extract parameters + dh_params = self.dh_params + link_lengths = self.cfg.link_lengths + rotation_directions = self.cfg.rotation_directions + + # Transform target pose + target_xpos = ( + self.T_b_ob_inv_np @ target_pose @ self.tcp_inv_np @ self.T_e_oe_inv_np + ) + P_target = target_xpos[:3, 3] + R_target = target_xpos[:3, :3] + P02 = np.array([0, 0, link_lengths[0]]) # Base to shoulder + P67 = np.array([0, 0, dh_params[6, 0]]) # Hand to end-effector + P06 = P_target - R_target @ P67 + P26 = P06 - P02 + + # Calculate joint angles + joints = np.zeros(dof) + if not self._calculate_arm_joint_angles( + P26, elbow_config, joints, link_lengths + ): + return False, None + + # Calculate transformations + T34 = self._dh_transform( + dh_params[3, 0], dh_params[3, 1], dh_params[3, 2], joints[3] + ) + R34 = T34[:3, :3] + + # Calculate reference plane + V_v_to_sew, R03_o, joint_v = self._compute_reference_plane( + target_xpos, config[1] + ) + if V_v_to_sew is None: + return False, None + + # Calculate shoulder joint rotation matrices + usw = P26 / np.linalg.norm(P26) + skew_usw = self._skew(usw) + angle_psi = nsparam + s_psi = wp.sin(angle_psi) + c_psi = wp.cos(angle_psi) + + # Calculate rotation matrix R03 + A_s = skew_usw @ R03_o + B_s = -skew_usw @ skew_usw @ R03_o + C_s = (usw[:, None] @ usw[None, :]) @ R03_o + R03 = A_s * s_psi + B_s * c_psi + C_s + + # Calculate shoulder joint angles + angle1 = np.arctan2(R03[1, 1] * shoulder_config, R03[0, 1] * shoulder_config) + angle2 = np.arccos(R03[2, 1]) * shoulder_config + angle3 = np.arctan2(-R03[2, 2] * shoulder_config, -R03[2, 0] * shoulder_config) + + # Calculate wrist joint angles + A_w = R34.T @ A_s.T @ R_target + B_w = R34.T @ B_s.T @ R_target + C_w = R34.T @ C_s.T @ R_target + R47 = A_w * s_psi + B_w * c_psi + C_w + + angle5 = np.arctan2(R47[1, 2] * wrist_config, R47[0, 2] * wrist_config) + angle6 = np.arccos(R47[2, 2]) * wrist_config + angle7 = np.arctan2(R47[2, 1] * wrist_config, -R47[2, 0] * wrist_config) + + joints_output[0] = (angle1 - dh_params[0, 3]) * rotation_directions[0] + joints_output[1] = (angle2 - dh_params[1, 3]) * rotation_directions[1] + joints_output[2] = (angle3 - dh_params[2, 3]) * rotation_directions[2] + joints_output[3] = (joints[3] - dh_params[3, 3]) * rotation_directions[3] + joints_output[4] = (angle5 - dh_params[4, 3]) * rotation_directions[4] + joints_output[5] = (angle6 - dh_params[5, 3]) * rotation_directions[5] + joints_output[6] = (angle7 - dh_params[6, 3]) * rotation_directions[6] + + return True, joints_output + + def get_ik( + self, + target_xpos: torch.Tensor, + qpos_seed: torch.Tensor, + return_all_solutions: bool = False, + **kwargs, + ) -> Tuple[torch.Tensor, torch.Tensor]: + """ + Compute inverse kinematics (IK) for the given target pose using CPU. + + Args: + target_xpos: Target end-effector pose (4x4). + qpos_seed: Initial joint positions (rad). + return_all_solutions: Whether to return all solutions. Default is False. + kwargs: Additional keyword arguments. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: Success flag and joint positions. + """ + num_targets = target_xpos.shape[0] + # Validate and normalize qpos_seed + if qpos_seed is None: + qpos_seed = torch.zeros( + (target_xpos.shape[0], 7), dtype=torch.float32, device=self.device + ) + + # Prepare to collect results + max_possible_solutions = len(self.elbow_angles) * len(self.configs) + all_solutions = np.zeros( + (num_targets, max_possible_solutions, 7), dtype=np.float32 + ) + solution_counts = np.zeros(num_targets, dtype=np.int32) + + # Iterate over target poses + for target_idx, xpos in enumerate(target_xpos): + sol_idx = 0 + for psi in self.elbow_angles: + for config in self.configs: + success, qpos = self._get_each_ik(xpos, psi.item(), config) + if success: + fk_xpos = self._get_fk(qpos) + if np.allclose(fk_xpos, xpos, atol=1e-4): + all_solutions[target_idx, sol_idx, :] = qpos + sol_idx += 1 + solution_counts[target_idx] = sol_idx + + has_solution = solution_counts > 0 + if not any(has_solution): + logger.log_warning( + f"Failed to calculate IK solutions.\n" + f"Target pose: {target_xpos}\nSeed: {qpos_seed}" + ) + return ( + torch.zeros(num_targets, dtype=torch.bool, device=self.device), + torch.zeros( + (num_targets, num_targets, 7), + dtype=qpos_seed.dtype, + device=self.device, + ), + ) + max_solutions = solution_counts.max() + + # Convert results to tensors + ik_qpos_tensor = torch.zeros( + (num_targets, max_solutions, 7), + dtype=qpos_seed.dtype, + device=self.device, + ) + for target_idx in range(num_targets): + count = solution_counts[target_idx] + if count > 0: + ik_qpos_tensor[target_idx, :count] = torch.from_numpy( + all_solutions[target_idx, :count] + ).to(self.device, dtype=qpos_seed.dtype) + + valid_mask = ik_qpos_tensor.abs().sum(dim=2) > 0 # (num_targets, max_solutions) + success_tensor = torch.from_numpy(has_solution).to(self.device) + if return_all_solutions: + return self._process_all_solutions( + ik_qpos_tensor, qpos_seed, valid_mask, success_tensor + ) + else: + return self._process_single_solution( + ik_qpos_tensor, qpos_seed, valid_mask, success_tensor + ) + + +class _CUDASRSSolverImpl(_BaseSRSSolverImpl): + """CUDA implementation of the SRS inverse kinematics solver.""" + + def __init__(self, cfg: SRSSolverCfg, device: torch.device): + super().__init__(cfg, device) + + def _parse_params(self): + super()._parse_params() + + # Convert numpy transformation matrices to Warp mat44 format for CUDA computation. + self.tcp_inv_wp = wp.mat44(*self.tcp_inv_np.flatten()) + self.T_b_ob_inv_wp = wp.mat44(*self.T_b_ob_inv_np.flatten()) + self.T_e_oe_inv_wp = wp.mat44(*self.T_e_oe_inv_np.flatten()) + + # Convert DH parameters, joint limits, link lengths, and rotation directions to Warp arrays. + self.dh_params_wp = wp.array( + self.dh_params_np.flatten(), + dtype=float, + device=standardize_device_string(self.device), + ) + self.qpos_limits_wp = wp.array( + self.qpos_limits_np, + dtype=wp.vec2, + device=standardize_device_string(self.device), + ) + self.link_lengths_wp = wp.array( + self.link_lengths_np.flatten(), + dtype=float, + device=standardize_device_string(self.device), + ) + self.rotation_directions_wp = wp.array( + self.rotation_directions_np.flatten(), + dtype=float, + device=standardize_device_string(self.device), + ) + + # Generate all possible configuration combinations for shoulder, elbow, and wrist. + # Each configuration is represented by a vector of three elements, each being +1 or -1. + # This covers all 8 possible sign combinations for the three joints. + self.configs = [wp.vec3(x, y, z) for x, y, z in product([1.0, -1.0], repeat=3)] + self.configs_wp = wp.array( + self.configs, dtype=wp.vec3, device=standardize_device_string(self.device) + ) + + # Generate a set of elbow angles sampled uniformly from -π to π. + # The number of samples is determined by self.cfg.num_samples. + # These angles are used for searching possible IK solutions. + joint_reference_limits = [-wp.pi, wp.pi] + self.elbow_angles = np.linspace( + joint_reference_limits[0], joint_reference_limits[1], self.cfg.num_samples + ).tolist() + + # Convert elbow angles to Warp array for CUDA computation. + self.elbow_angles_wp = wp.array( + self.elbow_angles, + dtype=float, + device=standardize_device_string(self.device), + ) + + def _sort_ik_solutions( + self, qpos_out_wp, success_wp, qpos_seed, num_targets, num_configs, num_angles + ): + """ + Sort IK solutions based on weighted distance. + + Args: + qpos_out_wp: Warp array of IK solutions (shape: [num_targets * num_configs * num_angles, 7]). + success_wp: Warp array of validity flags (shape: [num_targets * num_configs * num_angles]). + qpos_seed: Warp array of seed positions (shape: [num_targets, 7]). + num_targets: Number of targets. + num_configs: Number of configurations. + num_angles: Number of angles. + + Returns: + Tuple[wp.array, wp.array]: Sorted IK solutions and their validity flags. + """ + N = num_targets + N_SOL = num_configs * num_angles + DOF = 7 + + sorted_ik_solutions = wp.zeros( + N * N_SOL * DOF, dtype=float, device=standardize_device_string(self.device) + ) + sorted_ik_valid_flags = wp.zeros( + N * N_SOL, dtype=int, device=standardize_device_string(self.device) + ) + distances = wp.zeros( + N * N_SOL, dtype=float, device=standardize_device_string(self.device) + ) + indices = wp.zeros( + N * N_SOL, dtype=int, device=standardize_device_string(self.device) + ) + + wp.launch( + kernel=sort_ik_kernel, + dim=num_targets, + inputs=[ + qpos_out_wp, + success_wp, + qpos_seed, + wp.array( + self.cfg.ik_nearest_weight, + dtype=float, + device=standardize_device_string(self.device), + ), + distances, + indices, + N_SOL, + ], + outputs=[ + sorted_ik_solutions, + sorted_ik_valid_flags, + ], + device=standardize_device_string(self.device), + ) + return sorted_ik_solutions, sorted_ik_valid_flags + + def _nearest_ik_solution( + self, qpos_out_wp, success_wp, qpos_seed, num_targets, num_configs, num_angles + ): + """ + Find the nearest valid IK solution for each target pose. + + Selects the IK solution closest to the seed configuration among all valid solutions. + + Args: + qpos_out_wp: IK solutions array of shape [num_targets * num_configs * num_angles, 7] + success_wp: Validity flags array of shape [num_targets * num_configs * num_angles] + qpos_seed: Seed configurations array of shape [num_targets, 7] + num_targets: Number of target poses + num_configs: Number of IK configurations + num_angles: Number of sampling angles + + Returns: + Tuple[wp.array, wp.array]: + - Nearest IK solutions array of shape [num_targets, 7] + - Validity flags array of shape [num_targets] indicating solution feasibility + """ + N = num_targets + N_SOL = num_configs * num_angles + DOF = 7 + + nearest_ik_solutions = wp.zeros( + N * DOF, dtype=float, device=standardize_device_string(self.device) + ) + nearest_ik_valid_flags = wp.zeros( + N, dtype=int, device=standardize_device_string(self.device) + ) + + wp.launch( + kernel=nearest_ik_kernel, + dim=num_targets, + inputs=[ + qpos_out_wp, + success_wp, + qpos_seed.flatten(), + wp.array( + self.cfg.ik_nearest_weight, + dtype=float, + device=standardize_device_string(self.device), + ), + N_SOL, + ], + outputs=[ + nearest_ik_solutions, + nearest_ik_valid_flags, + ], + device=standardize_device_string(self.device), + ) + return nearest_ik_solutions, nearest_ik_valid_flags + + def _process_all_solutions( + self, + qpos_out_wp: wp.array, + success_wp: wp.array, + qpos_seed: wp.array, + num_targets: int, + num_configs: int, + num_angles: int, + ) -> Tuple[torch.Tensor, torch.Tensor]: + """ + Process and return all valid IK solutions. + + Args: + qpos_out_wp: Warp array of IK solutions. + success_wp: Warp array of success flags. + qpos_seed: Seed joint positions. + num_targets: Number of target poses. + num_configs: Number of configurations. + num_angles: Number of angles. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: Success flags and all valid joint positions. + """ + num_per_target = num_configs * num_angles + + if self.cfg.sort_ik: + sorted_ik_solutions, sorted_ik_valid_flags = self._sort_ik_solutions( + qpos_out_wp, + success_wp, + qpos_seed.flatten(), + num_targets, + num_configs, + num_angles, + ) + + ik_solutions_tensor = wp.to_torch(sorted_ik_solutions).view( + num_targets, num_per_target, 7 + ) + ik_valid_flags_tensor = ( + wp.to_torch(sorted_ik_valid_flags) + .view(num_targets, num_per_target) + .bool() + ) + else: + ik_solutions_tensor = wp.to_torch(qpos_out_wp).view( + num_targets, num_per_target, 7 + ) + ik_valid_flags_tensor = ( + wp.to_torch(success_wp).view(num_targets, num_per_target).bool() + ) + + success_flags = ik_valid_flags_tensor.any(dim=1) + + valid_qpos_list = [ + ik_solutions_tensor[i][ik_valid_flags_tensor[i]] for i in range(num_targets) + ] + max_solutions = max(q.shape[0] for q in valid_qpos_list) + valid_qpos_tensor = torch.zeros( + (num_targets, max_solutions, 7), + dtype=torch.float32, + device=self.device, + ) + for i, q in enumerate(valid_qpos_list): + valid_qpos_tensor[i, : q.shape[0]] = q.to(self.device) + + return success_flags.to(self.device), valid_qpos_tensor + + def _process_single_solution( + self, + qpos_out_wp: wp.array, + success_wp: wp.array, + qpos_seed: wp.array, + num_targets: int, + num_configs: int, + num_angles: int, + ) -> Tuple[torch.Tensor, torch.Tensor]: + """ + Process and return the nearest valid IK solution for each target. + + Args: + qpos_out_wp: Warp array of IK solutions. + success_wp: Warp array of success flags. + qpos_seed: Seed joint positions. + num_targets: Number of target poses. + num_configs: Number of configurations. + num_angles: Number of angles. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: Success flags and nearest valid joint positions. + """ + num_per_target = num_configs * num_angles + + if self.cfg.sort_ik: + nearest_ik_solutions, nearest_ik_valid_flags = self._nearest_ik_solution( + qpos_out_wp, + success_wp, + qpos_seed, + num_targets, + num_configs, + num_angles, + ) + + nearest_ik_solutions_tensor = wp.to_torch(nearest_ik_solutions).view( + num_targets, 7 + ) + nearest_ik_valid_flags_tensor = ( + wp.to_torch(nearest_ik_valid_flags).view(num_targets).bool() + ) + + first_valid_qpos = torch.zeros( + (num_targets, 1, 7), dtype=torch.float32, device=self.device + ) + for i in range(num_targets): + if nearest_ik_valid_flags_tensor[i]: + first_valid_qpos[i, 0] = nearest_ik_solutions_tensor[i].to( + self.device + ) + + return nearest_ik_valid_flags_tensor.to(self.device), first_valid_qpos + else: + ik_solutions_tensor = wp.to_torch(qpos_out_wp).view( + num_targets, num_per_target, 7 + ) + ik_valid_flags_tensor = ( + wp.to_torch(success_wp).view(num_targets, num_per_target).bool() + ) + + first_valid_qpos = torch.zeros( + (num_targets, 1, 7), dtype=torch.float32, device=self.device + ) + valid_flags = torch.zeros(num_targets, dtype=torch.bool, device=self.device) + for i in range(num_targets): + valid_indices = torch.where(ik_valid_flags_tensor[i])[0] + if len(valid_indices) > 0: + first_valid_qpos[i, 0] = ik_solutions_tensor[ + i, valid_indices[0] + ].to(self.device) + valid_flags[i] = True + + return valid_flags, first_valid_qpos + + def _check_success_flags( + self, + success_wp: wp.array, + num_targets: int, + num_configs: int, + num_angles: int, + ) -> torch.Tensor: + """ + Check success flags for IK solutions. + + Args: + success_wp: Warp array of success flags. + num_targets: Number of target poses. + num_configs: Number of configurations. + num_angles: Number of angles. + + Returns: + torch.Tensor: Success flags as a boolean tensor. + """ + num_solutions = num_configs * num_angles + success_flags_wp = wp.empty( + num_targets, dtype=int, device=standardize_device_string(self.device) + ) + wp.launch( + kernel=check_success_kernel, + dim=num_targets, + inputs=[ + success_wp, + num_solutions, + ], + outputs=[ + success_flags_wp, + ], + device=standardize_device_string(self.device), + ) + return wp.to_torch(success_flags_wp).bool().to(self.device) + + def _compute_ik_solutions( + self, + combinations_wp: wp.array, + xpos_wp: wp.array, + qpos_out_wp: wp.array, + success_wp: wp.array, + num_combinations: int, + ) -> None: + """ + Compute IK solutions using the provided combinations. + + Args: + combinations_wp: Warp array of combinations for parallel processing. + xpos_wp: Transformed target poses. + qpos_out_wp: Output array for joint positions. + success_wp: Output array for success flags. + num_combinations: Total number of combinations to process. + """ + # Temporary arrays + res_arm_angles = wp.zeros( + num_combinations, dtype=int, device=standardize_device_string(self.device) + ) + joints_arm = wp.zeros( + num_combinations, + dtype=wp.vec4, + device=standardize_device_string(self.device), + ) + res_plane_normal = wp.zeros( + num_combinations, dtype=int, device=standardize_device_string(self.device) + ) + plane_normal = wp.zeros( + num_combinations, + dtype=wp.vec3, + device=standardize_device_string(self.device), + ) + base_to_elbow_rotation = wp.zeros( + num_combinations, + dtype=wp.mat33, + device=standardize_device_string(self.device), + ) + joints_plane = wp.zeros( + num_combinations, + dtype=wp.vec4, + device=standardize_device_string(self.device), + ) + + # Launch kernel to compute IK solutions + wp.launch( + kernel=compute_ik_kernel, + dim=num_combinations, + inputs=( + combinations_wp, + xpos_wp, + self.elbow_angles_wp, + self.qpos_limits_wp, + self.configs_wp, + self.dh_params_wp, + self.link_lengths_wp, + self.rotation_directions_wp, + res_arm_angles, + joints_arm, + res_plane_normal, + plane_normal, + base_to_elbow_rotation, + joints_plane, + ), + outputs=[success_wp, qpos_out_wp], + device=standardize_device_string(self.device), + ) + + def get_ik( + self, + target_xpos: torch.Tensor, + qpos_seed: torch.Tensor, + return_all_solutions: bool = False, + **kwargs, + ) -> Tuple[torch.Tensor, torch.Tensor]: + """ + Compute inverse kinematics (IK) for the given target pose. + + Args: + target_xpos: Target end-effector pose (4x4). + qpos_seed: Initial joint positions (rad). + return_all_solutions: Whether to return all solutions. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: Success flag and joint positions. + """ + # Prepare inputs + target_xpos = target_xpos.to(self.device) + target_xpos = target_xpos.view(-1, 4, 4) + target_xpos_wp = wp.from_torch(target_xpos, dtype=wp.mat44) + + # transform pose + xpos_wp = wp.zeros( + target_xpos_wp.shape[0], + dtype=wp.mat44, + device=standardize_device_string(self.device), + ) + wp.launch( + kernel=transform_pose_kernel, + dim=target_xpos_wp.shape[0], + inputs=[ + target_xpos_wp, + self.T_b_ob_inv_wp, + self.T_e_oe_inv_wp, + self.tcp_inv_wp, + ], + outputs=[xpos_wp], + device=standardize_device_string(self.device), + ) + + # Define configurations and angles + if qpos_seed is None: + qpos_seed = wp.zeros( + (target_xpos.shape[0], 7), + dtype=float, + device=standardize_device_string(self.device), + ) + # TODO: Currently, full-space sampling is used to temporarily address situations + # where joint space discontinuities or solution failures occur in different user scenarios. + # Future plans include reducing the sampling space and adjusting the configuration. + # + # self.configs = [wp.vec3(*np.sign(qpos_seed[[1, 3, 5]].cpu().numpy()))] + + # Prepare output arrays + num_targets = target_xpos_wp.shape[0] + num_configs = len(self.configs) + num_angles = len(self.elbow_angles) + # num_solutions = num_configs * num_angles + num_combinations = num_targets * num_configs * num_angles + + # Generate combinations for parallel processing + combinations_np = np.stack( + np.meshgrid( + np.arange(num_targets), + np.arange(num_configs), + np.arange(num_angles), + indexing="ij", + ), + axis=-1, + ).reshape(-1, 3) + combinations_wp = wp.array( + combinations_np, + dtype=wp.vec3, + device=standardize_device_string(self.device), + ) + + # Output arrays + qpos_out_wp = wp.zeros( + num_combinations * 7, + dtype=float, + device=standardize_device_string(self.device), + ) + success_wp = wp.zeros( + num_combinations, dtype=int, device=standardize_device_string(self.device) + ) + + # Compute IK solutions + self._compute_ik_solutions( + combinations_wp, xpos_wp, qpos_out_wp, success_wp, num_combinations + ) + + # Check for successful solutions + success_flags_tensor = self._check_success_flags( + success_wp, num_targets, num_configs, num_angles + ) + + if success_flags_tensor.any(): + if return_all_solutions: + return self._process_all_solutions( + qpos_out_wp, + success_wp, + qpos_seed, + num_targets, + num_configs, + num_angles, + ) + else: + return self._process_single_solution( + qpos_out_wp, + success_wp, + qpos_seed, + num_targets, + num_configs, + num_angles, + ) + else: + return ( + torch.zeros(num_targets, dtype=torch.bool, device=self.device), + torch.zeros( + (num_targets, num_targets, 7), + dtype=torch.float32, + device=self.device, + ), + ) + + +class SRSSolver(BaseSolver): + r"""SRS inverse kinematics (IK) controller. + + This controller implements SRS inverse kinematics using various methods for + computing the inverse of the Jacobian matrix. + """ + + def __init__(self, cfg: SRSSolverCfg, num_envs: int, device: str, **kwargs): + r"""Initializes the SRS kinematics solver. + + This constructor sets up the kinematics solver using SRS methods, + allowing for efficient computation of robot kinematics based on + the specified URDF model. + + Args: + cfg: The configuration for the solver. + num_envs (int): The number of environments for the solver. + device (str, optional): The device to use for the solver (e.g., "cpu" or "cuda"). + **kwargs: Additional keyword arguments passed to the base solver. + + """ + super().__init__(cfg=cfg, num_envs=num_envs, device=device, **kwargs) + + # Degrees of freedom + self.dofs = 7 + + # Tool Center Point (TCP) position + self.tcp_xpos = np.eye(4) + + # Compute root base transform + fk_dict = self.pk_serial_chain.forward_kinematics( + th=np.zeros(7), end_only=False + ) + root_tf = fk_dict[list(fk_dict.keys())[0]] + self.root_base_xpos = root_tf.get_matrix().cpu().numpy() + + # Initialize implementation based on device + if self.device.type == "cuda": + self.impl = _CUDASRSSolverImpl(cfg, self.device) + else: + self.impl = _CPUSRSSolverImpl(cfg, self.device) + + def get_ik( + self, + target_xpos: torch.Tensor, + qpos_seed: torch.Tensor = None, + return_all_solutions: bool = False, + **kwargs, + ) -> Tuple[torch.Tensor, torch.Tensor]: + """ + Compute inverse kinematics (IK) for the given target pose. + + Args: + target_xpos: Target end-effector pose (4x4). + qpos_seed: Initial joint positions (rad). Default is None. + return_all_solutions: Whether to return all solutions. Default is False. + kwargs: Additional keyword arguments. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: Success flag and joint positions. + """ + return self.impl.get_ik( + target_xpos=target_xpos, + qpos_seed=qpos_seed, + return_all_solutions=return_all_solutions, + **kwargs, + ) diff --git a/embodichain/lab/sim/types.py b/embodichain/lab/sim/types.py new file mode 100644 index 00000000..3e080f4e --- /dev/null +++ b/embodichain/lab/sim/types.py @@ -0,0 +1,28 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import numpy as np +import torch + +from typing import Sequence, Union, Dict, Literal + + +Array = Union[torch.Tensor, np.ndarray, Sequence] +Device = Union[str, torch.device] + +EnvObs = Dict[str, Union[torch.Tensor, Dict[str, torch.Tensor]]] + +EnvAction = Union[torch.Tensor, Dict[str, torch.Tensor]] diff --git a/embodichain/lab/sim/utility/__init__.py b/embodichain/lab/sim/utility/__init__.py new file mode 100644 index 00000000..94cbbc59 --- /dev/null +++ b/embodichain/lab/sim/utility/__init__.py @@ -0,0 +1,19 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .sim_utils import * +from .mesh_utils import * +from .gizmo_utils import * diff --git a/embodichain/lab/sim/utility/action_utils.py b/embodichain/lab/sim/utility/action_utils.py new file mode 100644 index 00000000..2fc70cee --- /dev/null +++ b/embodichain/lab/sim/utility/action_utils.py @@ -0,0 +1,337 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import numpy as np +import torch +import warp as wp + +from typing import Tuple + +from embodichain.utils.utility import inv_transform +from embodichain.utils.warp import ( + trajectory_get_diff_kernel, + trajectory_interpolate_kernel, + trajectory_add_origin_kernel, + get_offset_qpos_kernel, + pairwise_distances, + cumsum_distances, + repeat_first_point, + interpolate_along_distance, +) +from embodichain.lab.sim.solvers.base_solver import BaseSolver +from embodichain.utils.device_utils import standardize_device_string + + +def compute_pose_offset_related_to_first(full_pose: torch.Tensor) -> torch.Tensor: + """Compute pose offset relative to the first pose. + + Args: + full_pose (torch.Tensor): The full pose tensor of shape (N, 4, 4). + + Returns: + torch.Tensor: The pose offset tensor of shape (N, 4, 4). + """ + inv_pose0_np = inv_transform(full_pose[0].to("cpu").numpy()) + inv_pose0 = torch.tensor(inv_pose0_np, device=full_pose.device) + inv_pose0_repeat = inv_pose0[None, :, :].repeat(full_pose.shape[0], 1, 1) + return torch.bmm(inv_pose0_repeat, full_pose) + + +def sort_and_padding_key_frame( + trajectory: np.ndarray, key_indices: np.ndarray, key_frames_batch: np.ndarray +) -> Tuple[np.ndarray, np.ndarray]: + """sort and padding key frames for warping trajectory + + Args: + trajectory (torch.Tensor): raw trajectory. [n_waypoint, dof] of float. + key_indices (torch.Tensor): key frame waypoint indices. [n_keyframe,] of int. + key_frames_batch (torch.Tensor): batch key frames. [n_batch, n_keyframe, dof] of float. + + Returns: + key_indices_ascending (np.ndarray): padded and sorted key frame indices. [n_keyframe_new,] of int. + key_frames_ascending (np.ndarray): padded and sorted batch key frames. [n_batch, n_keyframe_new, dof] of float. + """ + sort_ids = np.argsort(key_indices) + key_indices_ascending = key_indices[sort_ids] + key_frames_ascending = key_frames_batch[:, sort_ids, :] + n_batch = key_frames_batch.shape[0] + if key_indices_ascending[0] != 0: + key_indices_ascending = np.hstack([0, key_indices_ascending]) + padding_frame = trajectory[0][None, None, :].repeat(n_batch, axis=0) + key_frames_ascending = np.concatenate( + [padding_frame, key_frames_ascending], axis=1 + ) + if key_indices_ascending[-1] != trajectory.shape[0] - 1: + key_indices_ascending = np.hstack( + [key_indices_ascending, trajectory.shape[0] - 1] + ) + padding_frame = trajectory[trajectory.shape[0] - 1][None, None, :].repeat( + n_batch, axis=0 + ) + key_frames_ascending = np.concatenate( + [key_frames_ascending, padding_frame], axis=1 + ) + return key_indices_ascending, key_frames_ascending + + +def warp_trajectory_qpos( + trajectory: torch.Tensor, + key_indices: torch.Tensor, + key_frames_batch: torch.Tensor, + device: str = "cuda", +) -> torch.Tensor: + """warp trajectory + + Args: + trajectory (torch.Tensor): raw trajectory. [n_waypoint, dof] of float. + key_indices (torch.Tensor): key frame waypoint indices. [n_keyframe,] of int. + key_frames_batch (torch.Tensor): batch key frames. [n_batch, n_keyframe, dof] of float. + device (str, optional): torch tensor device. Defaults to "cuda". + + Returns: + torch.Tensor: warped trajectory. [n_batch, n_waypoint, dof] of float. + """ + # sort and pad key frames + trajectory_np = trajectory.to("cpu").numpy().astype(np.float32) + key_indices_np = key_indices.to("cpu").numpy().astype(np.int32) + key_frames_batch_np = key_frames_batch.to("cpu").numpy().astype(np.float32) + + key_indices_padded, key_frames_padded = sort_and_padding_key_frame( + trajectory_np, key_indices_np, key_frames_batch_np + ) + + # allocate cuda memory + n_batch = key_frames_padded.shape[0] + n_keyframe = key_indices_padded.shape[0] + n_waypoint, dof = trajectory_np.shape + wp_in_trajectory = wp.array( + trajectory_np.flatten(), dtype=float, device=standardize_device_string(device) + ) + out_trajectory = np.zeros((n_batch, n_waypoint, dof), dtype=np.float32) + wp_out_trajectory = wp.array( + out_trajectory.flatten(), dtype=float, device=standardize_device_string(device) + ) + wp_key_indices = wp.array( + key_indices_padded, dtype=int, device=standardize_device_string(device) + ) + wp_key_frames = wp.array( + key_frames_padded.flatten(), + dtype=float, + device=standardize_device_string(device), + ) + + # calcuate + wp.launch( + kernel=trajectory_get_diff_kernel, + dim=(n_batch, dof), + inputs=[ + wp_in_trajectory, + wp_key_indices, + wp_key_frames, + n_waypoint, + dof, + n_keyframe, + ], + outputs=[ + wp_out_trajectory, + ], + device=standardize_device_string(device), + ) + wp.launch( + kernel=trajectory_interpolate_kernel, + dim=(n_batch, n_waypoint, dof), + inputs=[wp_key_indices, n_waypoint, dof, n_keyframe], + outputs=[ + wp_out_trajectory, + ], + device=standardize_device_string(device), + ) + wp.launch( + kernel=trajectory_add_origin_kernel, + dim=(n_batch, n_waypoint, dof), + inputs=[wp_in_trajectory, n_waypoint, dof], + outputs=[ + wp_out_trajectory, + ], + device=standardize_device_string(device), + ) + warp_traj = ( + wp.to_torch(wp_out_trajectory) + .reshape(n_batch, n_waypoint, dof) + .to(torch.device(device)) + ) + return warp_traj + + +def get_trajectory_object_offset_qpos( + trajectory: torch.Tensor, + key_indices: torch.Tensor, + key_obj_indices: torch.Tensor, + obj_offset: torch.Tensor, + solver: BaseSolver, + base_xpos: torch.Tensor, + device=torch.device("cuda"), +): + """warp trajectory according to object pose offset + + Args: + trajectory (torch.Tensor): raw trajectory. [n_waypoint, dof] of float, joint positions. + key_indices (torch.Tensor): key frame waypoint indices. [n_keyframe,] of int. + key_obj_indices (torch.Tensor): key frame belong to which object index. [n_keyframe,] of int. + obj_offset (torch.Tensor): each object pose offset. [obj_num, n_batch, 4, 4] of float. + solver (BaseSolver): robot kinematic solver. + base_xpos (torch.Tensor): solver root link pose in world coordinate. [4, 4] of float. + device (str, optional): torch tensor device. Defaults to "cuda". + + Returns: + torch.Tensor: warped trajectory. [n_batch, n_waypoint, dof] of float. + """ + assert key_indices.shape[0] == key_obj_indices.shape[0] + dof = trajectory.shape[1] + key_qpos = trajectory[key_indices] # [n_keyframe, DOF] + n_batch = obj_offset.shape[1] # batch num, aws arena num + n_keyframe = key_qpos.shape[0] + key_xpos = solver.get_fk(key_qpos) # [n_keyframe, 4, 4] + + base_xpos_repeat = base_xpos[None, :, :].repeat(n_keyframe, 1, 1) + key_xpos = torch.bmm(base_xpos_repeat, key_xpos) + + base_xpos_inv_np = inv_transform(base_xpos.to("cpu").numpy()) + base_xpos_inv_wp = wp.mat44f(base_xpos_inv_np) + key_obj_indices_wp = wp.from_torch(key_obj_indices.reshape(-1)) + obj_offset_wp = wp.from_torch(obj_offset.reshape(-1)) + key_xpos_wp = wp.from_torch(key_xpos.reshape(-1)) + key_obj_offset_wp = wp.zeros( + n_batch * n_keyframe * 16, dtype=float, device=standardize_device_string(device) + ) + + wp.launch( + kernel=get_offset_qpos_kernel, + dim=(n_batch, n_keyframe), + inputs=[ + key_obj_indices_wp, + obj_offset_wp, + key_xpos_wp, + base_xpos_inv_wp, + n_batch, + n_keyframe, + ], + outputs=[ + key_obj_offset_wp, + ], + device=standardize_device_string(device), + ) + key_xpos_offset = wp.to_torch(key_obj_offset_wp).reshape(n_batch * n_keyframe, 4, 4) + key_qpos_batch = key_qpos[None, :, :].repeat(n_batch, 1, 1).reshape(-1, dof) + # for pytorch solver, ik use qpos seed but not joint seed + is_success, key_qpos_offset = solver.get_ik( + target_xpos=key_xpos_offset, + qpos_seed=key_qpos_batch, + ) + key_qpos_offset = key_qpos_offset.reshape(n_batch, n_keyframe, -1) + return is_success, key_qpos_offset + + +def interpolate_with_distance_warp( + trajectory: torch.Tensor, # expected shape [B, N, M], float or convertible to float + interp_num: int, # T + device=torch.device("cuda"), +) -> torch.Tensor: + """ + Resample a batch of trajectories of shape [B, N, M] into [B, T, M] by + piecewise-linear interpolation over cumulative Euclidean distance + along the N dimension, handling each batch independently. + + Args: + trajectory: Torch.Tensor of shape [B, N, M]. + interp_num: Target number of samples T. + device: Warp device string ('cpu', 'cuda', 'cuda:0', ...). + dtype: Working dtype (wp.float32 or wp.float64). Defaults to wp.float32. + + Returns: + Torch.Tensor of shape [B, T, M] with interpolated trajectories. + """ + # Flatten input trajectory for warp kernels (avoid multi-dimensional wp.array bugs) + trajectory_flat = trajectory.contiguous().to(device).view(-1) + points = wp.from_torch(trajectory_flat) + + B, N, M = trajectory.shape # original shape components + T = int(interp_num) + + if T < 0: + raise ValueError("`interp_num` must be non-negative.") + + # Handle degenerate T + out = ( + wp.empty( + (B * T * M,), dtype=wp.float32, device=standardize_device_string(device) + ) + if T > 0 + else wp.empty((0,), dtype=wp.float32, device=standardize_device_string(device)) + ) + + # Handle N < 2 + if N < 2: + if N == 1 and T > 0: + # Repeat the single point across T (kernel expects flattened arrays) + wp.launch( + kernel=repeat_first_point, + dim=B * T, + inputs=[points, out, B, T, M, N], + device=standardize_device_string(device), + ) + # N == 0 -> return empty (out already allocated) + interp_trajectory = ( + wp.to_torch(out).view(B, T, M) if T > 0 else wp.to_torch(out).view(B, 0, M) + ) + return interp_trajectory + + if T == 0: + return out # nothing to do + + # 1) pairwise distances along N + dists = wp.empty( + (B * (N - 1),), dtype=wp.float32, device=standardize_device_string(device) + ) + wp.launch( + kernel=pairwise_distances, + dim=B * (N - 1), + inputs=[points, dists, B, N, M], + device=standardize_device_string(device), + ) + + # 2) cumulative distances per batch + cumulative = wp.empty( + (B * N,), dtype=wp.float32, device=standardize_device_string(device) + ) + wp.launch( + kernel=cumsum_distances, + dim=B, + inputs=[dists, cumulative, B, N], + device=standardize_device_string(device), + ) + + # 3) interpolation per (b, t) + wp.launch( + kernel=interpolate_along_distance, + dim=B * T, + inputs=[points, cumulative, out, B, N, M, T], + device=standardize_device_string(device), + ) + + # wp.synchronize_device(device) + interp_trajectory = wp.to_torch(out).view(B, T, M) + return interp_trajectory diff --git a/embodichain/lab/sim/utility/gizmo_utils.py b/embodichain/lab/sim/utility/gizmo_utils.py new file mode 100644 index 00000000..5595a825 --- /dev/null +++ b/embodichain/lab/sim/utility/gizmo_utils.py @@ -0,0 +1,46 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +""" +Gizmo utility functions for EmbodiSim. + +This module provides utility functions for creating gizmo transform callbacks. +""" + +from typing import Callable +from dexsim.types import TransformMask + + +def create_gizmo_callback() -> Callable: + """Create a standard gizmo transform callback function. + + This callback handles basic translation and rotation operations for gizmo controls. + It applies transformations directly to the node when gizmo controls are manipulated. + + Returns: + Callable: A callback function that can be used with gizmo.node.set_flush_transform_callback() + """ + + def gizmo_transform_callback(node, translation, rotation, flag): + if node is not None: + if flag == (TransformMask.TRANSFORM_LOCAL | TransformMask.TRANSFORM_T): + # Handle translation changes + node.set_translation(translation) + elif flag == (TransformMask.TRANSFORM_LOCAL | TransformMask.TRANSFORM_R): + # Handle rotation changes + node.set_rotation_rpy(rotation) + + return gizmo_transform_callback diff --git a/embodichain/lab/sim/utility/import_utils.py b/embodichain/lab/sim/utility/import_utils.py new file mode 100644 index 00000000..0630a48e --- /dev/null +++ b/embodichain/lab/sim/utility/import_utils.py @@ -0,0 +1,125 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from embodichain.utils import logger + + +def lazy_import_pytorch_kinematics(): + """ + Lazily import pytorch_kinematics and return the module. + + Returns: + module: The pytorch_kinematics module if available. + + Raises: + ImportError: If the module is not installed. + """ + try: + import pytorch_kinematics as pk + + return pk + except ImportError as e: + logger.log_warning( + "pytorch_kinematics not installed. Install with `pip install pytorch_kinematics==0.7.5`" + ) + raise e + + +def lazy_import_pinocchio(): + """ + Lazily import pinocchio and return the module. + + Returns: + module: The pinocchio module if available. + + Raises: + ImportError: If the module is not installed. + """ + try: + import pinocchio as pin + + return pin + except ImportError as e: + logger.log_warning( + "pinocchio not installed. Install with `conda install pinocchio==3.1.0 -c conda-forge`" + ) + raise e + + +def lazy_import_casadi(): + """ + Lazily import casadi and return the module. + + Returns: + module: The casadi module if available. + + Raises: + ImportError: If the module is not installed. + """ + try: + import casadi + + return casadi + except ImportError as e: + logger.log_warning( + "casadi not installed. Install with `pip install casadi==3.6.7`" + ) + raise e + + +def lazy_import_pinocchio_casadi(): + """ + Lazily import pinocchio.casadi and return the module. + + Returns: + module: The pinocchio.casadi module if available. + + Raises: + ImportError: If the module is not installed. + """ + try: + from pinocchio import casadi as cpin + + return cpin + except ImportError as e: + logger.log_warning( + f"Failed to import pinocchio.casadi: {e}. Install with `conda install pinocchio-casadi -c conda-forge` first." + ) + raise e + + +def lazy_import_pink(): + """ + Lazily import pin-pink and return its components. + + Returns: + tuple: The solve_ik, Configuration, and FrameTask components. + + Raises: + ImportError: If the module is not installed. + """ + try: + from pink import solve_ik + from pink.configuration import Configuration + from pink.tasks import FrameTask + import pink + + return pink + except ImportError as e: + logger.log_warning( + "Failed to import 'pin-pink'. Please install it using `pip install pin-pink==3.4.0`." + ) + raise ImportError("pin-pink is required but not installed.") from e diff --git a/embodichain/lab/sim/utility/io_utils.py b/embodichain/lab/sim/utility/io_utils.py new file mode 100644 index 00000000..b4d7fbd6 --- /dev/null +++ b/embodichain/lab/sim/utility/io_utils.py @@ -0,0 +1,26 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from os import devnull +from contextlib import contextmanager, redirect_stderr, redirect_stdout + + +@contextmanager +def suppress_stdout_stderr(): + """A context manager that redirects stdout and stderr to devnull""" + with open(devnull, "w") as fnull: + with redirect_stderr(fnull) as err, redirect_stdout(fnull) as out: + yield (err, out) diff --git a/embodichain/lab/sim/utility/mesh_utils.py b/embodichain/lab/sim/utility/mesh_utils.py new file mode 100644 index 00000000..4a30bd7c --- /dev/null +++ b/embodichain/lab/sim/utility/mesh_utils.py @@ -0,0 +1,208 @@ +import os +import dexsim.engine +import numpy as np +import open3d as o3d +import trimesh +from typing import Tuple, List, Dict, Any, Optional, Union + +import dexsim +from embodichain.utils import logger +from embodichain.data import get_data_path + + +def process_meshes( + mesh_config: Union[List[Dict], Dict], processor_config: Dict = None +) -> List[str]: + r"""Process a list of mesh files using the specified processor configuration. + + Args: + mesh_config (list): A list of dictionaries containing mesh file paths. + processor_config (dict): A dictionary containing the processor configuration. + + Returns: + list: A list of processed mesh file paths. + """ + from embodichain.toolkits.processor.function.mesh_processor import ( + build_mesh_processors, + ) + from embodichain.toolkits.processor.component import TriangleComponent + from embodichain.toolkits.processor.entity import MeshEntity + + processors, replace = None, False + if processor_config is not None: + if "replace" in processor_config: + replace = processor_config.pop("replace") + processors = build_mesh_processors(processor_config) + + if isinstance(mesh_config, dict): + mesh_config_list = list(mesh_config.values()) + else: + mesh_config_list = mesh_config + batch_meshes, batch_index = [], [] + for idx, config in enumerate(mesh_config_list): + if "mesh_file" not in config and "mesh_path" not in config: + logger.log_error("Config must contain 'mesh_file' and 'mesh_path' keys.") + key = "mesh_file" if "mesh_file" in config else "mesh_path" + mesh_fpath = config[key] + mesh_fpath = get_data_path(mesh_fpath) + if not os.path.exists(mesh_fpath): + logger.log_error(f"Mesh file not found at path: {mesh_fpath}") + config[key] = mesh_fpath + save_fpath = ( + os.path.dirname(config[key]) + + "/mesh_processed_" + + os.path.basename(config[key]) + ) + + if processors is None and "mesh_processor" not in config: + # No processors specified, so just return + continue + elif os.path.exists(save_fpath) and not replace: + config[key] = save_fpath + continue + elif "mesh_processor" in config: + # Process the mesh file with the specified processor + mesh_processor = build_mesh_processors(config["mesh_processor"]) + tri_component = TriangleComponent.from_fpath(mesh_fpath) + mesh_entity = MeshEntity("mesh", tri_component) + mesh = mesh_processor.apply([mesh_entity])[0] + mesh.save_mesh(save_fpath) + # Update the mesh file path in the config + config[key] = save_fpath + else: + tri_component = TriangleComponent.from_fpath(mesh_fpath) + mesh_entity = MeshEntity("mesh", tri_component) + batch_meshes.append(mesh_entity) + batch_index.append(idx) + + # Process the batch of meshes with the default processors + if batch_meshes and processors is not None: + meshes = processors.apply(batch_meshes) + for idx, config in enumerate(mesh_config_list): + if idx in batch_index: + save_fpath = ( + os.path.dirname(config[key]) + + "/mesh_processed_" + + os.path.basename(config[key]) + ) + meshes[batch_index.index(idx)].save_mesh(save_fpath) + config[key] = save_fpath + if isinstance(mesh_config, dict): + mesh_config = {k: v for k, v in zip(mesh_config.keys(), mesh_config_list)} + return mesh_config + + +def export_articulation_mesh( + articulation: Union[dexsim.engine.Articulation, list], + output_path: str = "./articulation.obj", + link_names: Optional[Union[List[str], Dict[Any, List[str]]]] = None, + base_xpos: Optional[np.ndarray] = None, + base_link_name: Optional[str] = None, + **kwargs: Any, +) -> o3d.geometry.TriangleMesh: + r"""Export a combined mesh from all links of one or more articulations to a mesh file format. + + This function retrieves the link geometries and poses from the given articulation(s), + transforms each link mesh to its world pose, merges them into a single mesh, and + exports the result to the specified file path. The export format is inferred from + the file extension (e.g., .obj, .ply, .stl, .glb, .gltf). + + Args: + articulation (dexsim.engine.Articulation or list): The articulation object or list of articulations. + output_path (str): The output file path including the file name and extension. + Supported extensions: .obj, .ply, .stl, .glb, .gltf. + link_names (list[str] or dict[Any, list[str]], optional): + Specify which links to export. If None, export all links. + base_xpos (np.ndarray, optional): 4x4 homogeneous transformation matrix. + All meshes will be transformed into this base pose coordinate system. + base_link_name (str, optional): If specified, use the pose of this link as the base pose. + The link will be searched from all link_names of all articulations. + + Returns: + o3d.geometry.TriangleMesh: The combined Open3D mesh object of all articulations. + """ + output_path = os.path.abspath(output_path) + os.makedirs(os.path.dirname(output_path), exist_ok=True) + + combined_mesh = o3d.geometry.TriangleMesh() + articulations = ( + articulation if isinstance(articulation, (list, tuple)) else [articulation] + ) + + # Determine base transform: priority base_xpos > base_link_name > identity + base_inv = None + if base_xpos is not None: + base_inv = np.linalg.inv(base_xpos) + elif base_link_name is not None: + # Search base_link_name from all link_names of all articulations + found = False + for art in articulations: + # Get all possible link names for this articulation + if link_names is None: + cur_link_names = art.get_link_names() + elif isinstance(link_names, dict): + cur_link_names = link_names.get(art, art.get_link_names()) + else: + cur_link_names = link_names + if base_link_name in cur_link_names: + base_pose = art.get_link_pose(base_link_name) + base_inv = np.linalg.inv(base_pose) + found = True + break + if not found: + logger.log_warning( + f"base_link_name '{base_link_name}' not found in any articulation, using identity." + ) + base_inv = np.eye(4) + else: + base_inv = np.eye(4) + + for art in articulations: + if link_names is None: + cur_link_names = art.get_link_names() + elif isinstance(link_names, dict): + cur_link_names = link_names.get(art, art.get_link_names()) + else: + cur_link_names = link_names + + link_poses = [art.get_link_pose(name) for name in cur_link_names] + + for i, link_name in enumerate(cur_link_names): + verts, faces = art.get_link_vert_face(link_name) + logger.log_debug( + f"Link '{link_name}' has {verts.shape[0]} vertices, {verts.shape[1]} faces." + ) + if verts.shape[0] == 0: + continue + + mesh = o3d.geometry.TriangleMesh( + o3d.utility.Vector3dVector(verts), o3d.utility.Vector3iVector(faces) + ) + mesh.compute_vertex_normals() + mesh.transform(link_poses[i]) + mesh.transform(base_inv) + combined_mesh += mesh + + combined_mesh.compute_vertex_normals() + + ext = os.path.splitext(output_path)[1].lower() + + if ext in [".obj", ".ply", ".stl"]: + o3d.io.write_triangle_mesh(output_path, combined_mesh) + logger.log_info(f"Mesh exported using Open3D to: {output_path}") + + elif ext in [".glb", ".gltf"]: + mesh_trimesh = trimesh.Trimesh( + vertices=np.asarray(combined_mesh.vertices), + faces=np.asarray(combined_mesh.triangles), + vertex_normals=np.asarray(combined_mesh.vertex_normals), + ) + mesh_trimesh.export(output_path) + logger.log_info(f"Mesh exported using trimesh to: {output_path}") + + else: + raise ValueError( + f"Unsupported file format: '{ext}'. Supported: obj, ply, stl, glb, gltf" + ) + + return combined_mesh diff --git a/embodichain/lab/sim/utility/sim_utils.py b/embodichain/lab/sim/utility/sim_utils.py new file mode 100644 index 00000000..adcc53e4 --- /dev/null +++ b/embodichain/lab/sim/utility/sim_utils.py @@ -0,0 +1,286 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import dexsim +import open3d as o3d + +from typing import List, Union, Optional + +from dexsim.types import DriveType, ArticulationFlag, LoadOption, RigidBodyShape +from dexsim.engine import Articulation +from dexsim.environment import Env, Arena +from dexsim.models import MeshObject + +from embodichain.lab.sim.cfg import ArticulationCfg, RigidObjectCfg, SoftObjectCfg +from embodichain.lab.sim.shapes import MeshCfg, CubeCfg, SphereCfg +from embodichain.utils import logger +from dexsim.kit.meshproc import get_mesh_auto_uv +import numpy as np + + +def get_dexsim_arenas() -> List[dexsim.environment.Arena]: + """Get all arenas in the default dexsim world. + + Returns: + List[dexsim.environment.Arena]: A list of arenas in the default world, or an empty list if no world is found. + """ + world = dexsim.default_world() + if world is None: + logger.log_warning(f"No default world found. Returning empty arena list.") + return [] + + env = world.get_env() + arenas = env.get_all_arenas() + if len(arenas) == 0: + return [env] + return arenas + + +def get_dexsim_arena_num() -> int: + """Get the number of arenas in the default dexsim world. + + Returns: + int: The number of arenas in the default world, or 0 if no world is found. + """ + arenas = get_dexsim_arenas() + return len(arenas) + + +def get_dexsim_drive_type(drive_type: str) -> DriveType: + """Get the dexsim drive type from a string. + + Args: + drive_type (str): The drive type as a string. + + Returns: + DriveType: The corresponding DriveType enum. + """ + if drive_type == "force": + return DriveType.FORCE + elif drive_type == "acceleration": + return DriveType.ACCELERATION + else: + logger.error(f"Invalid dexsim drive type: {drive_type}") + + +def set_dexsim_articulation_cfg(arts: List[Articulation], cfg: ArticulationCfg) -> None: + """Set articulation configuration for a list of dexsim articulations. + + Args: + arts (List[Articulation]): List of dexsim articulations to configure. + cfg (ArticulationCfg): Configuration object containing articulation settings. + """ + + def get_drive_type(drive_pros): + if isinstance(drive_pros, dict): + return drive_pros.get("drive_type", None) + return getattr(drive_pros, "drive_type", None) + + drive_pros = getattr(cfg, "drive_pros", None) + drive_type = get_drive_type(drive_pros) if drive_pros is not None else None + + if drive_type == "force": + drive_type = DriveType.FORCE + elif drive_type == "target": + drive_type == DriveType.FORCE + else: + logger.log_error(f"Unknow drive type {drive_type}") + + for art in arts: + art.set_physical_attr(cfg.attrs.attr()) + art.set_articulation_flag(ArticulationFlag.FIX_BASE, cfg.fix_base) + art.set_articulation_flag( + ArticulationFlag.DISABLE_SELF_COLLISION, cfg.disable_self_collision + ) + art.set_solver_iteration_counts( + min_position_iters=cfg.min_position_iters, + min_velocity_iters=cfg.min_velocity_iters, + ) + link_names = art.get_link_names() + for name in link_names: + physical_body = art.get_physical_body(name) + inertia = physical_body.get_mass_space_inertia_tensor() + inertia = np.maximum(inertia, 1e-4) + physical_body.set_mass_space_inertia_tensor(inertia) + + +def is_rt_enabled() -> bool: + """Check if Ray Tracing rendering backend is enabled in the default dexsim world. + + Returns: + bool: True if Ray Tracing rendering is enabled, False otherwise. + """ + config = dexsim.get_world_config() + + return config.renderer == dexsim.types.Renderer.FASTRT + + +def create_cube( + envs: List[Union[Env, Arena]], size: List[float], uid: str = "cube" +) -> List[MeshObject]: + """Create cube objects in the specified environments or arenas. + + Args: + envs (List[Union[Env, Arena]]): List of environments or arenas to create cubes in. + size (List[float]): Size of the cube as [length, width, height] in meters. + uid (str, optional): Unique identifier for the cube objects. Defaults to "cube". + + Returns: + List[MeshObject]: List of created cube mesh objects. + """ + cubes = [] + for i, env in enumerate(envs): + cube = env.create_cube(size[0], size[1], size[2]) + cube.set_name(f"{uid}_{i}") + cubes.append(cube) + return cubes + + +def create_sphere( + envs: List[Union[Env, Arena]], + radius: float, + resolution: int = 20, + uid: str = "sphere", +) -> List[MeshObject]: + """Create sphere objects in the specified environments or arenas. + + Args: + envs (List[Union[Env, Arena]]): List of environments or arenas to create spheres in. + radius (float): Radius of the sphere in meters. + resolution (int, optional): Resolution of the sphere mesh. Defaults to 20. + uid (str, optional): Unique identifier for the sphere objects. Defaults to "sphere". + + Returns: + List[MeshObject]: List of created sphere mesh objects. + """ + spheres = [] + for i, env in enumerate(envs): + sphere = env.create_sphere(radius, resolution) + sphere.set_name(f"{uid}_{i}") + spheres.append(sphere) + return spheres + + +def load_mesh_objects_from_cfg( + cfg: RigidObjectCfg, env_list: List[Arena], cache_dir: Optional[str] = None +) -> List[MeshObject]: + """Load mesh objects from configuration. + + Args: + cfg (RigidObjectCfg): Configuration for the rigid object. + env_list (List[Arena]): List of arenas to load the objects into. + + cache_dir (Optional[str], optional): Directory for caching convex decomposition files. Defaults to None + Returns: + List[MeshObject]: List of loaded mesh objects. + """ + obj_list = [] + body_type = cfg.to_dexsim_body_type() + if isinstance(cfg.shape, MeshCfg): + + option = LoadOption() + option.rebuild_normals = cfg.shape.load_option.rebuild_normals + option.rebuild_tangent = cfg.shape.load_option.rebuild_tangent + option.rebuild_3rdnormal = cfg.shape.load_option.rebuild_3rdnormal + option.rebuild_3rdtangent = cfg.shape.load_option.rebuild_3rdtangent + option.smooth = cfg.shape.load_option.smooth + + cfg: RigidObjectCfg + max_convex_hull_num = cfg.max_convex_hull_num + fpath = cfg.shape.fpath + + compute_uv = cfg.shape.compute_uv + + for i, env in enumerate(env_list): + if max_convex_hull_num > 1: + obj = env.load_actor_with_coacd( + fpath, + duplicate=True, + attach_scene=True, + option=option, + cache_path=cache_dir, + actor_type=body_type, + max_convex_hull_num=max_convex_hull_num, + ) + else: + obj = env.load_actor( + fpath, duplicate=True, attach_scene=True, option=option + ) + obj.add_rigidbody(body_type, RigidBodyShape.CONVEX) + obj.set_name(f"{cfg.uid}_{i}") + obj_list.append(obj) + + if compute_uv: + vertices = obj.get_vertices() + triangles = obj.get_triangles() + + o3d_mesh = o3d.t.geometry.TriangleMesh(vertices, triangles) + _, uvs = get_mesh_auto_uv( + o3d_mesh, np.array(cfg.shape.project_direction) + ) + obj.set_uv_mapping(uvs) + + elif isinstance(cfg.shape, CubeCfg): + from embodichain.lab.sim.utility.sim_utils import create_cube + + obj_list = create_cube(env_list, cfg.shape.size, uid=cfg.uid) + for obj in obj_list: + obj.add_rigidbody(body_type, RigidBodyShape.BOX) + + elif isinstance(cfg.shape, SphereCfg): + from embodichain.lab.sim.utility.sim_utils import create_sphere + + obj_list = create_sphere( + env_list, cfg.shape.radius, cfg.shape.resolution, uid=cfg.uid + ) + for obj in obj_list: + obj.add_rigidbody(body_type, RigidBodyShape.SPHERE) + else: + logger.log_error( + f"Unsupported rigid object shape type: {type(cfg.shape)}. Supported types: MeshCfg, CubeCfg, SphereCfg." + ) + return obj_list + + +def load_soft_object_from_cfg( + cfg: SoftObjectCfg, env_list: List[Arena] +) -> List[MeshObject]: + obj_list = [] + + option = LoadOption() + option.rebuild_normals = cfg.shape.load_option.rebuild_normals + option.rebuild_tangent = cfg.shape.load_option.rebuild_tangent + option.rebuild_3rdnormal = cfg.shape.load_option.rebuild_3rdnormal + option.rebuild_3rdtangent = cfg.shape.load_option.rebuild_3rdtangent + option.smooth = cfg.shape.load_option.smooth + option.share_mesh = False + + for i, env in enumerate(env_list): + obj = env.load_actor( + fpath=cfg.shape.fpath, duplicate=True, attach_scene=True, option=option + ) + obj.add_softbody(cfg.voxel_attr.attr(), cfg.physical_attr.attr()) + if cfg.shape.compute_uv: + vertices = obj.get_vertices() + triangles = obj.get_triangles() + + o3d_mesh = o3d.t.geometry.TriangleMesh(vertices, triangles) + _, uvs = get_mesh_auto_uv(o3d_mesh, cfg.shape.project_direction) + obj.set_uv_mapping(uvs) + obj.set_name(f"{cfg.uid}_{i}") + obj_list.append(obj) + return obj_list diff --git a/embodichain/lab/sim/utility/solver_utils.py b/embodichain/lab/sim/utility/solver_utils.py new file mode 100644 index 00000000..976462f2 --- /dev/null +++ b/embodichain/lab/sim/utility/solver_utils.py @@ -0,0 +1,111 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +from embodichain.lab.sim.utility.io_utils import suppress_stdout_stderr + +from typing import Optional, Union, Tuple, Any, TYPE_CHECKING +from copy import deepcopy + +from embodichain.utils import configclass, logger + +if TYPE_CHECKING: + from typing import Self + +from embodichain.lab.sim.utility.import_utils import ( + lazy_import_pytorch_kinematics, +) + + +def create_pk_chain( + urdf_path: str, + device: torch.device, + **kwargs, +) -> "pk.SerialChain": + """ + Factory method to create a pk.SerialChain object from a URDF file. + + Args: + urdf_path (str): Path to the URDF file. + end_link_name (str): Name of the end-effector link. + root_link_name (Optional[str]): Name of the root link. If None, the chain starts from the base. + device (torch.device): The device to which the chain will be moved. + is_serial (bool): Whether the chain is serial or not. + + Returns: + pk.SerialChain: The created serial chain object. + """ + pk = lazy_import_pytorch_kinematics() + with open(urdf_path, "rb") as f: + urdf_str = f.read() + + with suppress_stdout_stderr(): + return pk.build_chain_from_urdf(urdf_str).to(device=device) + + +def create_pk_serial_chain( + urdf_path: str = None, + device: torch.device = None, + end_link_name: str = None, + root_link_name: Optional[Union[str, None]] = None, + chain: Optional["pk.SerialChain"] = None, + **kwargs, +) -> "pk.SerialChain": + """ + Factory method to create a pk.SerialChain object from a URDF file. + + Args: + urdf_path (str): Path to the URDF file. + end_link_name (str): Name of the end-effector link. + root_link_name (Optional[str]): Name of the root link. If None, the chain starts from the base. + device (torch.device): The device to which the chain will be moved. + is_serial (bool): Whether the chain is serial or not. + + Returns: + pk.SerialChain: The created serial chain object. + """ + if urdf_path is None and chain is None: + raise ValueError("Either `urdf_path` or `chain` must be provided.") + if urdf_path and chain: + raise ValueError("`urdf_path` and `chain` cannot be provided at the same time.") + + pk = lazy_import_pytorch_kinematics() + + if chain is None: + try: + with open(urdf_path, "rb") as f: + urdf_str = f.read() + except FileNotFoundError: + raise ValueError(f"URDF file not found at path: {urdf_path}") + except IOError as e: + raise ValueError(f"Failed to read URDF file: {e}") + + with suppress_stdout_stderr(): + if root_link_name is None: + return pk.build_serial_chain_from_urdf( + urdf_str, + end_link_name=end_link_name, + ).to(device=device) + else: + return pk.build_serial_chain_from_urdf( + urdf_str, + end_link_name=end_link_name, + root_link_name=root_link_name, + ).to(device=device) + else: + return pk.SerialChain( + chain=chain, end_frame_name=end_link_name, root_frame_name=root_link_name + ) diff --git a/embodichain/lab/sim/utility/tensor.py b/embodichain/lab/sim/utility/tensor.py new file mode 100644 index 00000000..3b8553cf --- /dev/null +++ b/embodichain/lab/sim/utility/tensor.py @@ -0,0 +1,55 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + +from typing import Union, Optional + + +def to_tensor( + arr: Union[torch.Tensor, np.ndarray, list], + dtype: torch.dtype = torch.float32, + device: Optional[torch.device] = None, +) -> torch.Tensor: + """Convert input to torch.Tensor with specified dtype and device. + + Supports torch.Tensor, np.ndarray, and list. + + Args: + arr (Union[torch.Tensor, np.ndarray, list]): Input array. + dtype (torch.dtype, optional): Desired tensor dtype. Defaults to torch.float32. + device (torch.device, optional): Desired device. If None, uses current device. + + Returns: + torch.Tensor: Converted tensor. + """ + if isinstance(arr, torch.Tensor): + return arr.to(dtype=dtype, device=device) if device else arr.to(dtype=dtype) + elif isinstance(arr, np.ndarray): + return ( + torch.from_numpy(arr).to(dtype=dtype, device=device) + if device + else torch.from_numpy(arr).to(dtype=dtype) + ) + elif isinstance(arr, list): + return ( + torch.tensor(arr, dtype=dtype, device=device) + if device + else torch.tensor(arr, dtype=dtype) + ) + else: + raise TypeError("Input must be a torch.Tensor, np.ndarray, or list.") diff --git a/embodichain/toolkits/__init__.py b/embodichain/toolkits/__init__.py new file mode 100644 index 00000000..e4655620 --- /dev/null +++ b/embodichain/toolkits/__init__.py @@ -0,0 +1,15 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- diff --git a/embodichain/toolkits/graspkit/pg_grasp/__init__.py b/embodichain/toolkits/graspkit/pg_grasp/__init__.py new file mode 100644 index 00000000..4409079f --- /dev/null +++ b/embodichain/toolkits/graspkit/pg_grasp/__init__.py @@ -0,0 +1,21 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .antipodal import AntipodalGenerator, GraspSelectMethod + +__all__ = ["AntipodalGenerator", "GraspSelectMethod"] + +del antipodal diff --git a/embodichain/toolkits/graspkit/pg_grasp/antipodal.py b/embodichain/toolkits/graspkit/pg_grasp/antipodal.py new file mode 100644 index 00000000..56239749 --- /dev/null +++ b/embodichain/toolkits/graspkit/pg_grasp/antipodal.py @@ -0,0 +1,671 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import open3d as o3d +import numpy as np +import time +import pathlib +import pickle +import os + +from enum import Enum +from copy import deepcopy +from typing import List + +from .cone_sampler import ConeSampler +from embodichain.utils.utility import get_mesh_md5 +from embodichain.utils import logger + + +class GraspSelectMethod(Enum): + NORMAL_SCORE = 0 + NEAR_APPROACH = 1 + CENTER = 2 + + +class AntipodalGrasp: + def __init__(self, pose: np.ndarray, open_len: float, score: float) -> None: + self.pose = pose # [4, 4] of float grasp pose + self.open_len = open_len # gripper open length + self.score = score # grasp pose score + + def grasp_pose_visual_mesh(self, gripper_open_length: float = None): + if gripper_open_length is None: + gripper_open_length = self.open_len + open_ratio = 1.0 + else: + open_ratio = self.open_len / gripper_open_length + open_ratio = max(1e-4, open_ratio) + gripper_finger = o3d.geometry.TriangleMesh.create_box( + gripper_open_length * 0.04, + gripper_open_length * 0.04, + gripper_open_length * 0.5, + ) + gripper_finger.translate( + np.array( + [ + -gripper_open_length * 0.02, + -gripper_open_length * 0.02, + -gripper_open_length * 0.25, + ] + ) + ) + gripper_left = deepcopy(gripper_finger) + gripper_left = gripper_left.translate( + np.array( + [ + -gripper_open_length * open_ratio * 0.5, + 0, + -gripper_open_length * 0.25, + ] + ) + ) + + gripper_right = deepcopy(gripper_finger) + gripper_right = gripper_right.translate( + np.array( + [gripper_open_length * open_ratio * 0.5, 0, -gripper_open_length * 0.25] + ) + ) + + gripper_root1 = o3d.geometry.TriangleMesh.create_box( + gripper_open_length * open_ratio, + gripper_open_length * 0.04, + gripper_open_length * 0.04, + ) + gripper_root1.translate( + np.array( + [ + gripper_open_length * open_ratio * -0.5, + gripper_open_length * -0.02, + gripper_open_length * -0.02, + ] + ) + ) + gripper_root1.translate( + np.array( + [ + 0, + 0, + gripper_open_length * -0.5, + ] + ) + ) + + gripper_root2 = o3d.geometry.TriangleMesh.create_box( + gripper_open_length * 0.04, + gripper_open_length * 0.04, + gripper_open_length * 0.5, + ) + gripper_root2.translate( + np.array( + [ + gripper_open_length * -0.02, + gripper_open_length * -0.02, + gripper_open_length * -0.25, + ] + ) + ) + gripper_root2.translate( + np.array( + [ + 0, + 0, + gripper_open_length * -0.75, + ] + ) + ) + + gripper_visual = gripper_left + gripper_right + gripper_root1 + gripper_root2 + gripper_visual.compute_vertex_normals() + return gripper_visual + + +class Antipodal: + def __init__( + self, + point_a: np.ndarray, + point_b: np.ndarray, + normal_a: np.ndarray, + normal_b: np.ndarray, + ) -> None: + """antipodal contact pair + + Args: + point_a (np.ndarray): position in point a + point_b (np.ndarray): position in point b + normal_a (np.ndarray): normal in point a + normal_b (np.ndarray): normal in point b + """ + self.point_a = point_a + self.point_b = point_b + self.normal_a = normal_a + self.normal_b = normal_b + self.dis = np.linalg.norm(point_a - point_b) + self.angle_cos = self.normal_a.dot(-self.normal_b) + self.score = self._get_score() + self._canonical_pose = self._get_canonical_pose() + + def _get_score(self): + # TODO: only normal angle is taken into account + return self.angle_cos + + def get_dis(self, another) -> float: + """get distance acoording to another antipodal + + Args: + other (Antipodal): another antipodal + + Returns: + float: distance + """ + aa_dis = np.linalg.norm(self.point_a - another.point_a) + bb_dis = np.linalg.norm(self.point_b - another.point_b) + ab_dis = np.linalg.norm(self.point_a - another.point_b) + ba_dis = np.linalg.norm(self.point_b - another.point_a) + return min(aa_dis, bb_dis, ab_dis, ba_dis) + + def get_dis_arr(self, others) -> np.ndarray: + """get distance acoording to others antipodals + + Args: + others (List[Antipodal]): other antipodals + + Returns: + np.ndarray: distance array + """ + other_num = len(others) + other_a = np.empty(shape=(other_num, 3), dtype=float) + other_b = np.empty(shape=(other_num, 3), dtype=float) + for i in range(other_num): + other_a[i] = others[i].point_a + other_b[i] = others[i].point_b + aa_dis = np.linalg.norm(other_a - self.point_a, axis=1) + ab_dis = np.linalg.norm(other_a - self.point_b, axis=1) + ba_dis = np.linalg.norm(other_b - self.point_a, axis=1) + bb_dis = np.linalg.norm(other_b - self.point_b, axis=1) + dis_arr = np.vstack([aa_dis, ab_dis, ba_dis, bb_dis]).min(axis=0) + return dis_arr + + def _get_canonical_pose(self) -> np.ndarray: + """get canonical pose of antipodal contact pair + + Returns: + np.ndarray: canonical pose + """ + # assume gripper closing along x_axis + x_d = self.point_a - self.point_b + x_d = x_d / np.linalg.norm(x_d) + y_d = np.cross(np.array([0, 0, 1.0], dtype=float), x_d) + if np.linalg.norm(y_d) < 1e-4: + y_d = np.cross(np.array([1, 0, 0.0], dtype=float), x_d) + y_d = y_d / np.linalg.norm(y_d) + z_d = np.cross(x_d, y_d) + pose = np.eye(4, dtype=float) + pose[:3, 0] = x_d # rotation x + pose[:3, 1] = y_d # rotation y + pose[:3, 2] = z_d # rotation z + pose[:3, 3] = (self.point_a + self.point_b) / 2 # position + return pose + + def sample_pose(self, sample_num: int = 36) -> np.ndarray: + """sample parallel gripper grasp poses given antipodal contact pairs + + Args: + sample_num (int, optional): sample number. Defaults to 36. + + Returns: + np.ndarray: [sample_num, 4, 4] of float. Sample poses. + """ + # assume gripper closing along x_axis + x_d = self._canonical_pose[:3, 0] + y_d = self._canonical_pose[:3, 1] + z_d = self._canonical_pose[:3, 2] + position = self._canonical_pose[:3, 3] + beta_list = np.linspace(2 * np.pi / sample_num, 2 * np.pi, sample_num) + grasp_poses = np.empty(shape=(sample_num, 4, 4), dtype=float) + for i in range(sample_num): + sample_z = np.sin(beta_list[i]) * y_d + np.cos(beta_list[i]) * z_d + sample_z = sample_z / np.linalg.norm(sample_z) + sample_y = np.cross(sample_z, x_d) + pose = np.eye(4, dtype=float) + pose[:3, 0] = x_d # rotation x + pose[:3, 1] = sample_y # rotation y + pose[:3, 2] = sample_z # rotation z + pose[:3, 3] = position # position + grasp_poses[i] = pose + return grasp_poses + + +class AntipodalGenerator: + def __init__( + self, + mesh_o3dt: o3d.t.geometry.TriangleMesh, + open_length: float, + min_open_length: float = 0.002, + max_angle: float = np.pi / 10, + surface_sample_num: int = 5000, + layer_num: int = 4, + sample_each_layer: int = 6, + nms_ratio: float = 0.02, + antipodal_sample_num: int = 16, + unique_id: str = None, + cache_dir: str = None, + ): + """antipodal grasp pose generator + + Args: + mesh_o3dt (o3d.t.geometry.TriangleMesh): input mesh + open_length (float): gripper maximum open length + max_angle (float, optional): maximum grasp direction with surface normal. Defaults to np.pi/10. + surface_sample_num (int, optional): contact sample number in mesh surface. Defaults to 5000. + layer_num (int, optional): cone sample layer number . Defaults to 4. + sample_each_layer (int, optional): cone sample number in each layer. Defaults to 6. + nms_ratio (float, optional): nms distance ratio. Defaults to 0.02. + antipodal_sample_num (int, optional): grasp poses sample on each antipodal contact pair. Defaults to 16. + cache_dir (str, optional): file cache directory. Defaults to None. + """ + self._antipodal_max_angle = max_angle + self._open_length = open_length + self._min_open_length = min_open_length + self._mesh_o3dt = mesh_o3dt + verts = mesh_o3dt.vertex.positions.numpy() + self._center_of_mass = verts.mean(axis=0) + if unique_id is None: + unique_file_name = self._get_unique_id( + mesh_o3dt, open_length, max_angle, surface_sample_num + ) + else: + unique_file_name = f"{unique_id}_{str(open_length)}_{str(max_angle)}_{str(surface_sample_num)}" + if cache_dir is None: + cache_dir = os.path.join(pathlib.Path.home(), "grasp_pose") + logger.log_debug(f"Set cache directory to {cache_dir}.") + if not os.path.isdir(cache_dir): + os.mkdir(cache_dir) + cache_file = os.path.join(cache_dir, f"{unique_file_name}.pickle") + if not os.path.isfile(cache_file): + # generate cache + grasp_list = self._generate_cache( + cache_file, + mesh_o3dt=mesh_o3dt, + max_angle=max_angle, + surface_sample_num=surface_sample_num, + layer_num=layer_num, + sample_each_layer=sample_each_layer, + nms_ratio=nms_ratio, + antipodal_sample_num=antipodal_sample_num, + ) + else: + # load cache + grasp_list = self._load_cache(cache_file) + self._grasp_list = grasp_list + + def _get_unique_id( + self, + mesh_o3dt: o3d.t.geometry.TriangleMesh, + open_length: float, + max_angle: float, + surface_sample_num: int, + ) -> str: + mesh_md5 = get_mesh_md5(mesh_o3dt) + return ( + f"{mesh_md5}_{str(open_length)}_{str(max_angle)}_{str(surface_sample_num)}" + ) + + def _generate_cache( + self, + cache_file: str, + mesh_o3dt: o3d.t.geometry.TriangleMesh, + max_angle: float = np.pi / 10, + surface_sample_num: int = 5000, + layer_num: int = 4, + sample_each_layer: int = 6, + nms_ratio: float = 0.02, + antipodal_sample_num: int = 16, + ): + self._mesh_o3dt = mesh_o3dt + self._cone_sampler = ConeSampler( + max_angle=max_angle, + layer_num=layer_num, + sample_each_layer=sample_each_layer, + ) + mesh_o3dt = mesh_o3dt.compute_vertex_normals() + assert 1e-4 < max_angle < np.pi / 2 + self._mesh_len = self._get_pc_size(mesh_o3dt.vertex.positions.numpy()).max() + start_time = time.time() + antipodal_list = self._antipodal_generate(mesh_o3dt, surface_sample_num) + logger.log_debug( + f"Antipodal sampling cost {(time.time() - start_time) * 1000} ms." + ) + logger.log_debug(f"Find {len(antipodal_list)} initial antipodal pairs.") + + valid_antipodal_list = self._antipodal_clean(antipodal_list) + + start_time = time.time() + nms_antipodal_list = self._antipodal_nms( + valid_antipodal_list, nms_ratio=nms_ratio + ) + logger.log_debug(f"NMS cost {(time.time() - start_time) * 1000} ms.") + logger.log_debug( + f"There are {len(nms_antipodal_list)} antipodal pair after nms." + ) + # all poses + start_time = time.time() + grasp_poses, score, open_length = self._sample_grasp_pose( + nms_antipodal_list, antipodal_sample_num + ) + logger.log_debug(f"Pose sampling cost {(time.time() - start_time) * 1000} ms.") + logger.log_debug( + f"There are {grasp_poses.shape[0]} poses after grasp pose sampling." + ) + # write data + data_dict = { + "grasp_poses": grasp_poses, + "score": score, + "open_length": open_length, + } + pickle.dump(data_dict, open(cache_file, "wb")) + # TODO: contact pair visualization + # self.antipodal_visual(nms_antipodal_list) + grasp_num = grasp_poses.shape[0] + logger.log_debug(f"Write {grasp_num} poses to pickle file {cache_file}.") + grasp_list = [None for i in range(grasp_num)] + for i in range(grasp_num): + grasp_list[i] = AntipodalGrasp(grasp_poses[i], open_length[i], score[i]) + return grasp_list + + def _load_cache(self, cache_file: str): + data_dict = pickle.load(open(cache_file, "rb")) + grasp_num = data_dict["grasp_poses"].shape[0] + logger.log_debug(f"Load {grasp_num} poses from pickle file {cache_file}.") + grasp_list = [None for i in range(grasp_num)] + for i in range(grasp_num): + grasp_list[i] = AntipodalGrasp( + data_dict["grasp_poses"][i], + data_dict["open_length"][i], + data_dict["score"][i], + ) + return grasp_list + + def _get_pc_size(self, vertices): + return np.array( + [ + vertices[:, 0].max() - vertices[:, 0].min(), + vertices[:, 1].max() - vertices[:, 1].min(), + vertices[:, 2].max() - vertices[:, 2].min(), + ] + ) + + def _antipodal_generate( + self, mesh_o3dt: o3d.t.geometry.TriangleMesh, surface_sample_num: int = 5000 + ): + surface_pcd = mesh_o3dt.to_legacy().sample_points_uniformly(surface_sample_num) + points = np.array(surface_pcd.points) + normals = np.array(surface_pcd.normals) + point_num = points.shape[0] + scene = o3d.t.geometry.RaycastingScene() + scene.add_triangles(mesh_o3dt) + # raycast + ray_n = self._cone_sampler._ray_num + ray_num = point_num * ray_n + ray_begins = np.empty(shape=(ray_num, 3), dtype=float) + ray_direcs = np.empty(shape=(ray_num, 3), dtype=float) + origin_normals = np.empty(shape=(ray_num, 3), dtype=float) + origin_points = np.empty(shape=(ray_num, 3), dtype=float) + start_time = time.time() + for i in range(point_num): + ray_direc = self._cone_sampler.cone_sample_direc( + normals[i], is_visual=False + ) + # raycast from outside of object + ray_begin = points[i] - 2 * self._mesh_len * ray_direc + ray_direcs[i * ray_n : (i + 1) * ray_n, :] = ray_direc + ray_begins[i * ray_n : (i + 1) * ray_n, :] = ray_begin + origin_normals[i * ray_n : (i + 1) * ray_n, :] = normals[i] + origin_points[i * ray_n : (i + 1) * ray_n, :] = points[i] + logger.log_debug(f"Cone sampling cost {(time.time() - start_time) * 1000} ms.") + + start_time = time.time() + rays = o3d.core.Tensor( + np.hstack([ray_begins, ray_direcs]), dtype=o3d.core.Dtype.Float32 + ) + logger.log_debug(f"Open3d raycast {(time.time() - start_time) * 1000} ms.") + + raycast_rtn = scene.cast_rays(rays) + hit_dis_all = raycast_rtn["t_hit"].numpy() + hit_normal_all = raycast_rtn["primitive_normals"].numpy() + + # max_angle_cos = np.cos(self._antipodal_max_angle) + antipodal_list = [] + # get antipodal points + start_time = time.time() + for i in range(ray_num): + hit_dis = hit_dis_all[i] + hit_normal = hit_normal_all[i] + hit_point = ray_begins[i] + ray_direcs[i] * hit_dis + antipodal_dis = np.linalg.norm(origin_points[i] - hit_point) + if ( + antipodal_dis > self._min_open_length + and antipodal_dis < self._open_length + ): + # reject thin close object + antipodal = Antipodal( + origin_points[i], hit_point, origin_normals[i], hit_normal + ) + antipodal_list.append(antipodal) + logger.log_debug( + f"Antipodal initialize cost {(time.time() - start_time) * 1000} ms." + ) + return antipodal_list + + def _sample_grasp_pose( + self, antipodal_list: List[Antipodal], antipodal_sample_num: int = 36 + ): + antipodal_num = len(antipodal_list) + grasp_poses = np.empty( + shape=(antipodal_sample_num * antipodal_num, 4, 4), dtype=float + ) + scores = np.empty(shape=(antipodal_sample_num * antipodal_num,), dtype=float) + open_length = np.empty( + shape=(antipodal_sample_num * antipodal_num,), dtype=float + ) + for i in range(antipodal_num): + grasp_poses[ + i * antipodal_sample_num : (i + 1) * antipodal_sample_num + ] = antipodal_list[i].sample_pose(antipodal_sample_num) + scores[ + i * antipodal_sample_num : (i + 1) * antipodal_sample_num + ] = antipodal_list[i].score + open_length[ + i * antipodal_sample_num : (i + 1) * antipodal_sample_num + ] = antipodal_list[i].dis + return grasp_poses, scores, open_length + + def get_all_grasp(self) -> List[AntipodalGrasp]: + """get all grasp + + Returns: + List[AntipodalGrasp]: list of grasp + """ + return self._grasp_list + + def select_grasp( + self, + approach_direction: np.ndarray, + select_num: int = 20, + max_angle: float = np.pi / 10, + select_method: GraspSelectMethod = GraspSelectMethod.NORMAL_SCORE, + ) -> List[AntipodalGrasp]: + """Select grasps. Masked by max_angle and sort by grasp score + + Args: + approach_direction (np.ndarray): gripper approach direction + select_num (int, optional): select grasp number. Defaults to 10. + max_angle (float, optional): max angle threshold (angle with surface normal). Defaults to np.pi/10. + select_method (select_method, optional) + Return: + List[AntipodalGrasp]: list of grasp + """ + grasp_num = len(self._grasp_list) + all_idx = np.arange(grasp_num) + grasp_poses = np.empty(shape=(grasp_num, 4, 4), dtype=float) + scores = np.empty(shape=(grasp_num,), dtype=float) + position = grasp_poses[:, :3, 3] + + for i in range(grasp_num): + grasp_poses[i] = self._grasp_list[i].pose + scores[i] = self._grasp_list[i].score + + # mask acoording to table up direction + grasp_z = grasp_poses[:, :3, 2] + direc_dot = (grasp_z * approach_direction).sum(axis=1) + valid_mask = direc_dot > np.cos(max_angle) + valid_id = all_idx[valid_mask] + + # sort acoording to different grasp score + if select_method == GraspSelectMethod.NORMAL_SCORE: + valid_score = scores[valid_id] + sort_valid_idx = np.argsort(valid_score)[::-1] # large is better + elif select_method == GraspSelectMethod.NEAR_APPROACH: + position_dot = (position * approach_direction).sum(axis=1) + valid_height = position_dot[valid_id] + sort_valid_idx = np.argsort(valid_height) + elif select_method == GraspSelectMethod.CENTER: + center_dis = np.linalg.norm(position - self._center_of_mass, axis=1) + valid_center_dis = center_dis[valid_id] + sort_valid_idx = np.argsort(valid_center_dis) + else: + logger.log_warning(f"select_method {select_method.name} not implemented.") + # return all grasp + return self._grasp_list + + # get best score sample index + result_num = min(len(sort_valid_idx), select_num) + best_valid_idx = sort_valid_idx[:result_num] + best_idx = valid_id[best_valid_idx] + + result_grasp_list = [] + for idx in best_idx: + result_grasp_list.append(self._grasp_list[idx]) + return result_grasp_list + + def _antipodal_nms( + self, antipodal_list: List[Antipodal], nms_ratio: float = 0.02 + ) -> List[Antipodal]: + antipodal_num = len(antipodal_list) + nms_mask = np.empty(shape=(antipodal_num,), dtype=bool) + nms_mask.fill(True) + score_list = np.empty(shape=(antipodal_num,), dtype=float) + + for i in range(antipodal_num): + score_list[i] = antipodal_list[i].score + + sort_idx = np.argsort(score_list)[::-1] + + dis_th = self._mesh_len * nms_ratio + for i in range(antipodal_num): + if not nms_mask[sort_idx[i]]: + continue + antipodal_max = antipodal_list[sort_idx[i]] + other_antipodal = [] + other_idx = [] + for j in range(i + 1, antipodal_num): + if nms_mask[sort_idx[j]]: + other_antipodal.append(antipodal_list[sort_idx[j]]) + other_idx.append(sort_idx[j]) + dis_arr = antipodal_max.get_dis_arr(other_antipodal) + invalid_mask = dis_arr < dis_th + for j, flag in enumerate(invalid_mask): + if flag: + nms_mask[other_idx[j]] = False + nms_antipodal_list = [] + for i in range(antipodal_num): + if nms_mask[sort_idx[i]]: + nms_antipodal_list.append(antipodal_list[sort_idx[i]]) + + # TODO: nms validation check. remove in future + # antipodal_num = len(nms_antipodal_list) + # for i in range(antipodal_num): + # for j in range(i + 1, antipodal_num): + # antipodal_dis = nms_antipodal_list[i].get_dis(nms_antipodal_list[j]) + # if antipodal_dis < dis_th: + # logger.log_warning(f"find near antipodal {i} and {j} with dis {antipodal_dis}") + return nms_antipodal_list + + def _antipodal_clean(self, antipodal_list: List[Antipodal]): + # TODO: need collision checker + + valid_antipodal = [] + max_angle_cos = np.cos(self._antipodal_max_angle) + for antipodal in antipodal_list: + if ( + 1e-5 < antipodal.dis < self._open_length + and antipodal.angle_cos > max_angle_cos + ): + valid_antipodal.append(antipodal) + return valid_antipodal + + def antipodal_visual(self, antipodal_list): + mesh_visual = self._mesh_o3dt.to_legacy() + antipodal_num = len(antipodal_list) + draw_points = np.empty(shape=(antipodal_num * 2, 3), dtype=float) + draw_lines = np.empty(shape=(antipodal_num, 2), dtype=int) + for i in range(antipodal_num): + direc = antipodal_list[i].point_b - antipodal_list[i].point_a + direc = direc / np.linalg.norm(direc) + anti_begin = antipodal_list[i].point_a - direc * 0.005 + anti_end = antipodal_list[i].point_b + direc * 0.005 + draw_points[i * 2] = anti_begin + draw_points[i * 2 + 1] = anti_end + draw_lines[i] = np.array([i * 2, i * 2 + 1], dtype=int) + + line_set = o3d.geometry.LineSet( + points=o3d.utility.Vector3dVector(draw_points), + lines=o3d.utility.Vector2iVector(draw_lines), + ) + draw_colors = np.empty(shape=(antipodal_num, 3), dtype=float) + draw_colors[:] = np.array([0.0, 1.0, 1.0]) + line_set.colors = o3d.utility.Vector3dVector(draw_colors) + o3d.visualization.draw_geometries([line_set, mesh_visual]) + + def grasp_pose_visual( + self, grasp_list: List[AntipodalGrasp] + ) -> List[o3d.t.geometry.TriangleMesh]: + """visualize grasp pose + + Args: + grasp_list (List[AntipodalGrasp]): list of grasp + + Returns: + List[o3d.t.geometry.TriangleMesh]: list of visualization mesh + """ + pose_num = len(grasp_list) + visual_mesh_list = [self._mesh_o3dt.compute_vertex_normals()] + + max_angle_cos = np.cos(self._antipodal_max_angle) + + for i in range(pose_num): + grasp_mesh = grasp_list[i].grasp_pose_visual_mesh( + gripper_open_length=self._open_length + ) + grasp_mesh.transform(grasp_list[i].pose) + # low score: red | hight score: blue + score_ratio = (grasp_list[i].score - max_angle_cos) / (1 - max_angle_cos) + score_ratio = min(1.0, score_ratio) + score_ratio = max(0.0, score_ratio) + grasp_mesh.paint_uniform_color(np.array([1 - score_ratio, 0, score_ratio])) + visual_mesh_list.append(o3d.t.geometry.TriangleMesh.from_legacy(grasp_mesh)) + return visual_mesh_list diff --git a/embodichain/toolkits/graspkit/pg_grasp/cone_sampler.py b/embodichain/toolkits/graspkit/pg_grasp/cone_sampler.py new file mode 100644 index 00000000..5de52f4c --- /dev/null +++ b/embodichain/toolkits/graspkit/pg_grasp/cone_sampler.py @@ -0,0 +1,121 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import open3d as o3d +import numpy as np +from scipy.spatial.transform import Rotation as R + + +def rotate_to_ref(direc: np.ndarray, rotate_ref: np.ndarray): + assert direc.shape == (3,) + direc_len = np.linalg.norm(direc) + assert direc_len > 1e-5 + direc_unit = direc / direc_len + + assert rotate_ref.shape == (3,) + rotate_ref_len = np.linalg.norm(rotate_ref) + assert rotate_ref_len > 1e-5 + rotate_ref_unit = rotate_ref / rotate_ref_len + + rotate_axis = np.cross(rotate_ref_unit, direc_unit) + rotate_axis_len = np.linalg.norm(rotate_axis) + if rotate_axis_len < 1e-5: + # co axis, no need to do rotation + dot_res = direc_unit.dot(rotate_ref_unit) + if dot_res > 0: + # identity rotation + return np.eye(3, dtype=float) + else: + # negative, rotate 180 degree + # rotate with a perpendicular axis + random_axis = np.random.random(size=(3,)) + perpendicular_axis = np.cross(random_axis, rotate_ref_unit) + perpendicular_axis = perpendicular_axis / np.linalg.norm(perpendicular_axis) + ref_rotation = R.from_rotvec(perpendicular_axis * np.pi).as_matrix() + return ref_rotation + else: + rotate_axis = rotate_axis / rotate_axis_len + angle = np.arccos(direc_unit.dot(rotate_ref_unit)) + ref_rotation = R.from_rotvec(angle * rotate_axis, degrees=False).as_matrix() + return ref_rotation + + +class ConeSampler: + def __init__( + self, max_angle: float, layer_num: int = 2, sample_each_layer: int = 4 + ) -> None: + """cone ray sampler + + Args: + max_angle (float): maximum ray angle to surface normal + layer_num (int, optional): circle layer. Defaults to 2. + sample_each_layer (int, optional): ray samples in each circle layer. Defaults to 4. + """ + self._max_angle = max_angle + self._layer_num = layer_num + self._ray_num = layer_num * sample_each_layer + 1 + alpha_list = np.linspace(max_angle / layer_num, max_angle, layer_num) + beta_list = np.linspace( + 2 * np.pi / sample_each_layer, 2 * np.pi, sample_each_layer + ) + self._direc_ref = np.array([0, 0, 1]) + + rotation_list = np.empty(shape=(self._ray_num, 3, 3), dtype=float) + + for i, alpha in enumerate(alpha_list): + for j, beta in enumerate(beta_list): + x_rotation = R.from_euler( + seq="XYZ", angles=np.array([alpha, 0, 0]), degrees=False + ).as_matrix() + z_rotation = R.from_euler( + seq="XYZ", angles=np.array([0, 0, beta]), degrees=False + ).as_matrix() + rotation_list[i * sample_each_layer + j + 1] = z_rotation @ x_rotation + # original direction + rotation_list[0] = np.eye(3) + self._sample_direc = rotation_list[:, :3, 2] # z-axis + + def cone_sample_direc(self, direc: np.ndarray, is_visual: bool = False): + """sample cone directly + + Args: + direc (np.ndarray): direction to sample a cone + is_visual (bool, optional): use visualization or not. Defaults to False. + + Returns: + np.ndarray: [_ray_num, 3] of float, cone direction list + """ + ref_rotation = rotate_to_ref(direc, self._direc_ref) + cone_direc_list = self._sample_direc @ ref_rotation.T + if is_visual: + self._visual(cone_direc_list) + return cone_direc_list + + def _visual(self, cone_direc_list: np.ndarray): + drawer = o3d.geometry.TriangleMesh.create_coordinate_frame(0.5) + for cone_direc in cone_direc_list: + arrow = o3d.geometry.TriangleMesh.create_arrow( + cylinder_radius=0.02, + cone_radius=0.03, + cylinder_height=0.9, + cone_height=0.1, + ) + arrow.compute_vertex_normals() + arrow_rotation = rotate_to_ref(cone_direc, self._direc_ref) + arrow.rotate(arrow_rotation, center=(0, 0, 0)) + arrow.paint_uniform_color(np.array([0.5, 0.5, 0.5])) + drawer += arrow + o3d.visualization.draw_geometries([drawer]) diff --git a/embodichain/toolkits/urdf_assembly/__init__.py b/embodichain/toolkits/urdf_assembly/__init__.py new file mode 100644 index 00000000..f0866a6f --- /dev/null +++ b/embodichain/toolkits/urdf_assembly/__init__.py @@ -0,0 +1,18 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +from .urdf_assembly_manager import URDFAssemblyManager + +__all__ = ["URDFAssemblyManager"] diff --git a/embodichain/toolkits/urdf_assembly/component.py b/embodichain/toolkits/urdf_assembly/component.py new file mode 100644 index 00000000..603225a3 --- /dev/null +++ b/embodichain/toolkits/urdf_assembly/component.py @@ -0,0 +1,342 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import traceback +import numpy as np +from pathlib import Path +from dataclasses import dataclass +import xml.etree.ElementTree as ET +from typing import Dict, Optional + +from embodichain.toolkits.urdf_assembly.logging_utils import ( + URDFAssemblyLogger, +) +from embodichain.toolkits.urdf_assembly.mesh import URDFMeshManager + + +__all__ = ["ComponentRegistry", "URDFComponent", "URDFComponentManager"] + + +class ComponentRegistry: + r"""Registry for storing and retrieving URDFComponent objects.""" + + def __init__(self): + self._components = {} + + def add(self, component_type: str, component_obj): + self._components[component_type] = component_obj + + def get(self, component_type: str): + return self._components.get(component_type) + + def all(self): + return self._components + + def remove(self, component_type: str): + if component_type in self._components: + del self._components[component_type] + + +@dataclass +class URDFComponent: + r"""Represents a URDF component with its configuration and transformation. + + This dataclass encapsulates all the information needed to process and integrate + a URDF component into the robot assembly, including file path, attachment + configuration, parameters, and optional spatial transformation. + """ + + urdf_path: str # Path to the URDF file for this component + default_attach_link: str = ( + "base_link" # Default link name for attachment (usually the first link) + ) + params: Dict = None # Component-specific parameters (e.g., wheel_type for chassis) + transform: Optional[ + np.ndarray + ] = None # Optional 4x4 transformation matrix for positioning + + def __post_init__(self): + # Convert path to Path object for better path handling + if isinstance(self.urdf_path, str): + self.urdf_path = Path(self.urdf_path) + + # Validate transformation matrix dimensions and type + if self.transform is not None: + if not isinstance(self.transform, np.ndarray) or self.transform.shape != ( + 4, + 4, + ): + raise ValueError("Transform must be a 4x4 numpy array") + + +class URDFComponentManager: + """Responsible for loading, renaming, and processing meshes for a single component.""" + + def __init__(self, mesh_manager: URDFMeshManager): + self.mesh_manager = mesh_manager + self.logger = URDFAssemblyLogger.get_logger("component_manager") + + def process_component( + self, + comp: str, + prefix: str, + comp_obj, + name_mapping: dict, + base_points: dict, + links: list, + joints: list, + ): + r"""Process a single URDF component by renaming elements and handling meshes. + + Args: + comp (str): Component name (e.g., 'chassis', 'left_arm', 'hand'). + prefix (str): Prefix to add to component elements for uniqueness (e.g., 'left_'). + None means no prefix will be applied. + comp_obj: URDFComponent object containing the component's URDF path and parameters. + name_mapping (dict): Dictionary mapping (component, original_name) tuples to new names. + Used for resolving cross-references between components. + base_points (dict): Dictionary mapping component names to their base connection link names. + Used for establishing parent-child relationships. + links (list): Global list to collect all processed link elements from all components. + joints (list): Global list to collect all processed joint elements from all components. + """ + + try: + urdf_root = ET.parse(comp_obj.urdf_path).getroot() + + # Safe way to get link and joint names, handling None values + global_link_names = { + link.get("name").lower() + for link in links + if link.get("name") is not None + } + global_joint_names = { + joint.get("name").upper() + for joint in joints + if joint.get("name") is not None + } + + first_link_flag = True + joint_name_mapping = {} + + # Process links first + for link in urdf_root.findall("link"): + orig_name = link.get("name") + if orig_name is None: + self.logger.warning( + f"Found link with no name in component {comp}, skipping" + ) + continue + + # Generate unique name + if prefix: + new_name = self._generate_unique_name( + orig_name, prefix, global_link_names + ).lower() + else: + # For components without prefix, ensure names are unique + if orig_name.lower() in global_link_names: + new_name = f"{comp}_{orig_name}".lower() + else: + new_name = orig_name.lower() + + global_link_names.add(new_name) + + # Set first link as base point + if first_link_flag: + base_points[comp] = new_name + first_link_flag = False + + # Update link name mapping and set link name to lowercase + name_mapping[(comp, orig_name)] = new_name + link.set("name", new_name) + links.append(link) + + self._process_meshes(link, comp_obj.urdf_path, comp) + + # Process joints: Build mapping table AND process all at once + joints_to_process = [] + + # First collect all joints and build complete mapping + for joint in urdf_root.findall("joint"): + orig_joint_name = joint.get("name") + if orig_joint_name is None: + continue + + new_joint_name = self._generate_unique_name( + orig_joint_name, prefix, global_joint_names + ).upper() + global_joint_names.add(new_joint_name) + + # Build the complete mapping table + joint_name_mapping[orig_joint_name] = new_joint_name + joints_to_process.append((joint, orig_joint_name, new_joint_name)) + + self.logger.debug(f"Joint name mapping for [{comp}]: {joint_name_mapping}") + + # Now process all joints with complete mapping available + for joint, orig_joint_name, new_joint_name in joints_to_process: + # Set the new joint name + joint.set("name", new_joint_name) + + # Update parent and child links to lowercase - with None checks + parent_elem = joint.find("parent") + child_elem = joint.find("child") + + if parent_elem is not None: + parent = parent_elem.get("link") + if parent is not None: + new_parent_name = name_mapping.get( + (comp, parent), parent + ).lower() + parent_elem.set("link", new_parent_name) + else: + self.logger.warning( + f"Found parent element with no link attribute in joint {orig_joint_name}" + ) + + if child_elem is not None: + child = child_elem.get("link") + if child is not None: + new_child_name = name_mapping.get((comp, child), child).lower() + child_elem.set("link", new_child_name) + else: + self.logger.warning( + f"Found child element with no link attribute in joint {orig_joint_name}" + ) + + # Process mimic joint references using the complete mapping table + mimic_elem = joint.find("mimic") + if mimic_elem is not None: + mimic_joint = mimic_elem.get("joint") + if mimic_joint is not None: + self.logger.info( + f"Processing mimic joint reference: ({mimic_joint}) in joint ({orig_joint_name})" + ) + # Look up the corresponding new joint name in the mapping table + new_mimic_joint = joint_name_mapping.get(mimic_joint) + if new_mimic_joint: + # Update the mimic element to reference the renamed joint + mimic_elem.set("joint", new_mimic_joint) + self.logger.info( + f"✓ Updated mimic joint reference: ({mimic_joint}) -> ({new_mimic_joint})" + ) + else: + self.logger.warning( + f"✗ Could not find mapping for mimic joint: ({mimic_joint})" + ) + self.logger.warning( + f"Available mappings: {list(joint_name_mapping.keys())}" + ) + + joints.append(joint) + + self.logger.debug( + f"Processed component: [{comp}], links: {len(urdf_root.findall('link'))}, joints: {len(urdf_root.findall('joint'))}" + ) + + except Exception as e: + self.logger.error( + f"Failed to process component [{comp}]: {e}", exc_info=True + ) + self.logger.error(f"Traceback: {traceback.format_exc()}") + + def _generate_unique_name( + self, orig_name: str, prefix: str, existing_names: set + ) -> str: + r"""Generate a unique name by adding a prefix and ensuring no conflicts. + + Args: + orig_name (str): The original name to modify. + prefix (str): The prefix to add to the name. + existing_names (set): A set of existing names to check for conflicts. + + Returns: + str: A unique name derived from the original name. + """ + if orig_name is None: + orig_name = "unnamed" + + if prefix and not orig_name.lower().startswith(prefix.lower()): + new_name = f"{prefix}{orig_name}".lower() + else: + new_name = orig_name.lower() + + # Ensure the new name is unique + if new_name in existing_names: + counter = 1 + unique_name = f"{new_name}_{counter}" + while unique_name in existing_names: + counter += 1 + unique_name = f"{new_name}_{counter}" + new_name = unique_name + + return new_name + + def _process_meshes(self, link: ET.Element, base_urdf_path: str, comp_name: str): + r"""Process visual and collision meshes for a link. + + Args: + link (ET.Element): The URDF link element to process. + base_urdf_path (str): The base path for the URDF files. + comp_name (str): The name of the component being processed. + """ + try: + for visual in link.findall("visual"): + geometry = visual.find("geometry") + if geometry is not None: + mesh = geometry.find("mesh") + if mesh is not None: + filename = mesh.get("filename") + if filename is not None: + self.logger.debug(f"Processing visual mesh: {filename}") + new_mesh_filename = ( + self.mesh_manager.copy_and_modify_mesh_file( + base_urdf_path, + filename, + "Visual", + comp_name, + ) + ) + self.logger.debug( + f"Updated visual mesh filename: {new_mesh_filename}" + ) + mesh.set("filename", new_mesh_filename) + + for collision in link.findall("collision"): + geometry = collision.find("geometry") + if geometry is not None: + mesh = geometry.find("mesh") + if mesh is not None: + filename = mesh.get("filename") + if filename is not None: + self.logger.debug(f"Processing collision mesh: {filename}") + new_mesh_filename = ( + self.mesh_manager.copy_and_modify_mesh_file( + base_urdf_path, + filename, + "Collision", + comp_name, + ) + ) + self.logger.debug( + f"Updated collision mesh filename: {new_mesh_filename}" + ) + mesh.set("filename", new_mesh_filename) + except Exception as e: + self.logger.error( + f"Failed to process meshes for component {comp_name}: {e}" + ) diff --git a/embodichain/toolkits/urdf_assembly/connection.py b/embodichain/toolkits/urdf_assembly/connection.py new file mode 100644 index 00000000..0e871b83 --- /dev/null +++ b/embodichain/toolkits/urdf_assembly/connection.py @@ -0,0 +1,212 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import xml.etree.ElementTree as ET + +from scipy.spatial.transform import Rotation as R + +from embodichain.toolkits.urdf_assembly.logging_utils import ( + URDFAssemblyLogger, +) + +__all__ = ["URDFConnectionManager"] + + +class URDFConnectionManager: + r""" + Responsible for managing connection rules between components and sensor attachments. + """ + + def __init__(self, base_link_name: str): + r"""Initialize the URDFConnectionManager. + + Args: + base_link_name (str): The name of the base link to which the chassis or other components may be attached. + """ + self.base_link_name = base_link_name + self.logger = URDFAssemblyLogger.get_logger("connection_manager") + + def add_connections( + self, + joints: list, + base_points: dict, + parent_attach_points: dict, + connection_rules: list, + component_transforms: dict = None, + ): + r"""Add connection joints between robot components according to the specified rules. + + Args: + joints (list): A list to collect joint elements. + base_points (dict): A mapping from component names to their child connection link names. + parent_attach_points (dict): A mapping from component names to their parent connection link names. + connection_rules (list): A list of (parent, child) tuples specifying connection relationships. + component_transforms (dict): Optional mapping from component names to their transform matrices. + """ + chassis_component = "chassis" + component_transforms = component_transforms or {} + + existing_joint_names = { + joint.get("name") for joint in joints if hasattr(joint, "get") + } + + # chassis is always attached to base_link (no transform applied to this connection) + if chassis_component in base_points: + chassis_first_link = base_points[chassis_component] + joint_name = f"BASE_LINK_TO_{chassis_component.upper()}_CONNECTOR" + if joint_name not in existing_joint_names: + joint = ET.Element("joint", name=joint_name, type="fixed") + ET.SubElement(joint, "origin", xyz="0 0 0", rpy="0 0 0") + ET.SubElement(joint, "parent", link=self.base_link_name) + ET.SubElement(joint, "child", link=chassis_first_link) + joints.append(joint) + existing_joint_names.add(joint_name) + self.logger.info( + f"[{chassis_component.capitalize()}] connected to [base_link] via ({chassis_first_link})" + ) + else: + # If no chassis, connect components directly to base_link with their transforms + self.logger.info( + "No chassis found, connecting components directly to base_link" + ) + + # Find components that don't have parents in connection_rules + components_with_parents = {child for parent, child in connection_rules} + orphan_components = [ + comp + for comp in base_points.keys() + if comp not in components_with_parents + ] + + for comp in orphan_components: + comp_first_link = base_points[comp] + joint_name = f"BASE_TO_{comp.upper()}_CONNECTOR" + + if joint_name not in existing_joint_names: + joint = ET.Element("joint", name=joint_name, type="fixed") + + # Apply transform to this specific connection if the component has one + if comp in component_transforms: + transform = component_transforms[comp] + xyz = transform[:3, 3] # Extract translation + rotation = R.from_matrix(transform[:3, :3]) + rpy = rotation.as_euler("xyz") + + ET.SubElement( + joint, + "origin", + xyz=f"{xyz[0]} {xyz[1]} {xyz[2]}", + rpy=f"{rpy[0]} {rpy[1]} {rpy[2]}", + ) + self.logger.info( + f"Applied transform to base connection {comp}: xyz={xyz}, rpy={rpy}" + ) + else: + ET.SubElement(joint, "origin", xyz="0 0 0", rpy="0 0 0") + + ET.SubElement(joint, "parent", link=self.base_link_name) + ET.SubElement(joint, "child", link=comp_first_link) + joints.append(joint) + existing_joint_names.add(joint_name) + + self.logger.info( + f"[{comp.capitalize()}] connected to [base_link] via ({comp_first_link})" + ) + + # Process other connection relationships + for parent, child in connection_rules: + if parent in parent_attach_points and child in base_points: + parent_connect_link = parent_attach_points[parent].lower() + child_connect_link = base_points[child].lower() + + self.logger.info( + f"Connecting [{parent}]-({parent_connect_link}) to [{child}]-({child_connect_link})" + ) + + # Create a unique joint name + base_joint_name = f"{parent.upper()}_TO_{child.upper()}_CONNECTOR" + if base_joint_name not in existing_joint_names: + joint = ET.Element("joint", name=base_joint_name, type="fixed") + + # Apply transform to this specific connection if the child component has one + if child in component_transforms: + transform = component_transforms[child] + xyz = transform[:3, 3] # Extract translation + rotation = R.from_matrix(transform[:3, :3]) + rpy = rotation.as_euler("xyz") + + ET.SubElement( + joint, + "origin", + xyz=f"{xyz[0]} {xyz[1]} {xyz[2]}", + rpy=f"{rpy[0]} {rpy[1]} {rpy[2]}", + ) + self.logger.info( + f"Applied transform to connection {parent} -> {child}: xyz={xyz}, rpy={rpy}" + ) + else: + ET.SubElement(joint, "origin", xyz="0 0 0", rpy="0 0 0") + + ET.SubElement(joint, "parent", link=parent_connect_link) + ET.SubElement(joint, "child", link=child_connect_link) + joints.append(joint) + existing_joint_names.add(base_joint_name) + else: + self.logger.warning( + f"Duplicate connection rule: {parent} -> {child}" + ) + else: + self.logger.error(f"Invalid connection rule: {parent} -> {child}") + + def add_sensor_attachments( + self, joints: list, attach_dict: dict, base_points: dict + ): + r"""Attach sensors to the robot by creating fixed joints.""" + for sensor_name, attach in attach_dict.items(): + sensor_urdf = ET.parse(attach.sensor_urdf).getroot() + + # Add sensor links and joints to the main lists + for link in sensor_urdf.findall("link"): + # Ensure sensor link names are lowercase + link.set("name", link.get("name").lower()) + joints.append(link) # This should be added to links list instead + + for joint in sensor_urdf.findall("joint"): + # Ensure sensor joint names are uppercase and link references are lowercase + joint.set("name", joint.get("name").upper()) + parent_elem = joint.find("parent") + child_elem = joint.find("child") + if parent_elem is not None: + parent_elem.set("link", parent_elem.get("link").lower()) + if child_elem is not None: + child_elem.set("link", child_elem.get("link").lower()) + joints.append(joint) + + parent_link = base_points.get( + attach.parent_component, attach.parent_component + ).lower() # Ensure lowercase + + # Create connection joint with uppercase name + joint_name = ( + f"{attach.parent_component.upper()}_TO_{sensor_name.upper()}_CONNECTOR" + ) + joint = ET.Element("joint", name=joint_name, type="fixed") + ET.SubElement(joint, "origin", xyz="0 0 0", rpy="0 0 0") + ET.SubElement(joint, "parent", link=parent_link) + ET.SubElement( + joint, "child", link=sensor_urdf.find("link").get("name").lower() + ) + joints.append(joint) diff --git a/embodichain/toolkits/urdf_assembly/file_writer.py b/embodichain/toolkits/urdf_assembly/file_writer.py new file mode 100644 index 00000000..18d6a24e --- /dev/null +++ b/embodichain/toolkits/urdf_assembly/file_writer.py @@ -0,0 +1,211 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from datetime import datetime + +import xml.etree.ElementTree as ET + +from embodichain.toolkits.urdf_assembly.logging_utils import ( + URDFAssemblyLogger, +) + +__all__ = ["URDFFileWriter"] + + +class URDFFileWriter: + r"""Responsible for formatting XML and writing URDF files with proper headers.""" + + def __init__(self, module_names: list = None): + r"""Initialize the URDFFileWriter. + + Args: + module_names (list): List of module names to include in the header. + """ + self.module_names = module_names or [] + self.logger = URDFAssemblyLogger.get_logger("file_writer") + + def create_section_comment( + self, content: str, comment_type: str = "section" + ) -> ET.Comment: + r"""Create standardized section comments for URDF organization. + + Args: + content (str): The content of the comment. + comment_type (str): Type of comment - "section", "start", "end", "empty". + + Returns: + ET.Comment: XML comment element. + """ + if comment_type == "empty": + return ET.Comment("") + elif comment_type == "start": + return ET.Comment(f" Start of ({content.lower()}) ") + elif comment_type == "end": + return ET.Comment(f" End of ({content.lower()}) ") + else: + return ET.Comment(f" {content} ") + + def add_section_comments( + self, elements_list: list, part_name: str, section_type: str + ): + r"""Add standardized section comments to elements list. + + Args: + elements_list (list): List to add comments to (links or joints). + part_name (str): Name of the component part. + section_type (str): Type of section ("Links" or "Joints"). + """ + elements_list.append(self.create_section_comment("", "empty")) + elements_list.append( + self.create_section_comment( + f"{section_type} for part: {part_name}", "start" + ) + ) + + def add_section_end_comments( + self, elements_list: list, part_name: str, section_type: str + ): + r"""Add standardized section end comments to elements list. + + Args: + elements_list (list): List to add comments to (links or joints). + part_name (str): Name of the component part. + section_type (str): Type of section ("Links" or "Joints"). + """ + elements_list.append( + self.create_section_comment(f"{section_type} for part: {part_name}", "end") + ) + elements_list.append(self.create_section_comment("", "empty")) + + def make_comment_line(self, content: str, width: int = 80) -> str: + r"""Create a properly formatted comment line with centered content. + + Args: + content (str): The content to be centered in the comment. + width (int): Total width of the comment line (default is 80). + + Returns: + str: A formatted XML comment line. + """ + content = content.strip() + pad_total = width - 7 - len(content) + pad_left = pad_total // 2 + pad_right = pad_total - pad_left + if pad_total < 0: + pad_left = 0 + pad_right = 0 + return f"" + + def generate_header( + self, module_names: list = None, assembly_signature: str = None + ) -> str: + r"""Generate a standard header for URDF files with assembly signature. + + Args: + module_names (list): List of module names to include in the header. + assembly_signature (str): MD5 signature of the assembly configuration. + + Returns: + str: Formatted header string. + """ + if module_names is None: + module_names = self.module_names + + now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + # Calculate proper spacing for centered content + header_width = 80 + separator_line = "" + + def center_comment(text: str) -> str: + """Center text within comment brackets with proper padding.""" + content_width = header_width - 8 # Account for + text_len = len(text) + if text_len >= content_width: + return f"" + + padding = content_width - text_len + left_pad = padding // 2 + right_pad = padding - left_pad + return f"" + + header_lines = [ + '', + separator_line, + center_comment("Robot URDF Model Generation Report"), + center_comment(f"Generation Time: {now}"), + center_comment("Tool Version: DexForce URDF Composer V1.0"), + center_comment(f"Included Modules: {' + '.join(module_names)}"), + ] + + # Add assembly signature if provided + if assembly_signature: + header_lines.append( + center_comment(f"配置签名 ASSEMBLY_SIGNATURE: {assembly_signature}") + ) + + header_lines.append(separator_line) + + return "\n".join(header_lines) + "\n" + + def prettify(self, elem: ET.Element, level: int = 0) -> ET.Element: + r"""Format an XML element by adding newlines and indentation. + + Args: + elem (ET.Element): The XML element to format. + level (int): The current indentation level (default is 0). + + Returns: + ET.Element: The formatted XML element. + """ + indent = "\n" + " " * level # Create indentation string based on level + if len(elem): # If the element has children + if not elem.text or not elem.text.strip(): + elem.text = indent + " " # Add indentation if no text + if not elem.tail or not elem.tail.strip(): + elem.tail = indent # Add indentation after the element + for child in elem: + self.prettify(child, level + 1) # Recursive call for children + if not child.tail or not child.tail.strip(): + child.tail = indent # Ensure the last child has proper tail indentation + else: # If the element has no children + if level and (not elem.tail or not elem.tail.strip()): + elem.tail = indent # Add indentation for elements at a non-zero level + return elem + + def write_urdf( + self, + merged_urdf: ET.Element, + output_path: str, + module_names: list = None, + assembly_signature: str = None, + ): + r"""Write the merged URDF to file with proper formatting and header including signature. + + Args: + merged_urdf (ET.Element): The merged URDF XML element. + output_path (str): Path where the URDF file will be written. + module_names (list): Optional list of module names for the header. + assembly_signature (str): Optional assembly signature to include in header. + """ + header = self.generate_header(module_names, assembly_signature) + xml_str = ET.tostring(self.prettify(merged_urdf), encoding="unicode") + + with open(output_path, "w", encoding="utf-8") as f: + f.write(header) + f.write(xml_str) + + self.logger.info(f"URDF file written to: {output_path}") diff --git a/embodichain/toolkits/urdf_assembly/logging_utils.py b/embodichain/toolkits/urdf_assembly/logging_utils.py new file mode 100644 index 00000000..63c17d0c --- /dev/null +++ b/embodichain/toolkits/urdf_assembly/logging_utils.py @@ -0,0 +1,131 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import logging +from typing import Optional + +__all__ = ["URDFAssemblyLogger"] + + +class URDFColorFormatter(logging.Formatter): + r"""Color formatter for URDF assembly logging""" + + COLORS = { + "DEBUG": "\033[36m", # Cyan + "INFO": "\033[32m", # Green + "WARNING": "\033[33m", # Yellow + "ERROR": "\033[31m", # Red + "CRITICAL": "\033[41m", # Red background + } + # Symbol colors + BRACKET_COLOR = "\033[94m" # Bright blue for [] + PAREN_COLOR = "\033[95m" # Magenta for () + RESET = "\033[0m" + + def format(self, record): + color = self.COLORS.get(record.levelname, self.RESET) + message = super().format(record) + + # Apply symbol coloring first + message = self._colorize_symbols(message, color) + + return f"{color}{message}{self.RESET}" + + def _colorize_symbols(self, message, base_color): + r"""Add colors to brackets and parentheses while preserving base color""" + import re + + # Color square brackets and their content, then restore base color + message = re.sub( + r"\[([^\]]+)\]", + f"{self.BRACKET_COLOR}[\\1]{self.RESET}{base_color}", + message, + ) + + # Color parentheses and their content, then restore base color + message = re.sub( + r"\(([^)]+)\)", f"{self.PAREN_COLOR}(\\1){self.RESET}{base_color}", message + ) + + return message + + +class URDFAssemblyLogger: + r"""URDF Assembly module-specific logger manager""" + + _loggers = {} # Cache for created loggers + _initialized = False + + @classmethod + def get_logger(cls, name: Optional[str] = None) -> logging.Logger: + r"""Get or create a URDF assembly-specific logger + + Args: + name: Logger name, defaults to calling module name + + Returns: + Configured logger instance + """ + if name is None: + # Get caller's module name + import inspect + + frame = inspect.currentframe().f_back + module_name = frame.f_globals.get("__name__", "unknown") + if module_name == "__main__": + name = "urdf_assembly.main" + else: + name = f'urdf_assembly.{module_name.split(".")[-1]}' + else: + # Ensure using urdf_assembly prefix + if not name.startswith("urdf_assembly."): + name = f"urdf_assembly.{name}" + + # Return cached logger or create new one + if name not in cls._loggers: + logger = logging.getLogger(name) + + # Avoid duplicate handlers + if not logger.handlers: + handler = logging.StreamHandler() + formatter = URDFColorFormatter("[%(levelname)s] %(name)s: %(message)s") + handler.setFormatter(formatter) + logger.addHandler(handler) + logger.setLevel(logging.INFO) + logger.propagate = False # Don't propagate to root logger + + cls._loggers[name] = logger + + return cls._loggers[name] + + @classmethod + def set_level(cls, level): + r"""Set log level for all URDF assembly loggers""" + for logger in cls._loggers.values(): + logger.setLevel(level) + + @classmethod + def disable_other_loggers(cls): + r"""Disable output from other non-URDF loggers""" + logging.getLogger().setLevel(logging.CRITICAL) + + +# Remove original setup_logger function, replace with URDF-specific initialization +def setup_urdf_logging(): + """Initialize URDF assembly logging system""" + # Optional: disable other logger outputs + URDFAssemblyLogger.disable_other_loggers() + return URDFAssemblyLogger.get_logger("urdf_assembly.main") diff --git a/embodichain/toolkits/urdf_assembly/mesh.py b/embodichain/toolkits/urdf_assembly/mesh.py new file mode 100644 index 00000000..c03a28c8 --- /dev/null +++ b/embodichain/toolkits/urdf_assembly/mesh.py @@ -0,0 +1,190 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import shutil +import xml.etree.ElementTree as ET + +from embodichain.toolkits.urdf_assembly.logging_utils import ( + URDFAssemblyLogger, +) + +__all__ = ["URDFMeshManager"] + + +class URDFMeshManager: + r"""Responsible for copying, renaming, and handling dependencies of mesh files.""" + + def __init__(self, output_dir: str): + r"""Initialize the URDFMeshManager with output directory configuration. + + Args: + output_dir (str): Base directory where mesh files will be organized. + Creates subdirectories 'Visual' and 'Collision' for + different mesh types. + """ + self.output_dir = output_dir + self.logger = URDFAssemblyLogger.get_logger("mesh_manager") + + def ensure_dirs(self): + r"""Ensure that the output directory contains 'Collision' and 'Visual' subdirectories. + Creates them if they do not exist. + + Returns: + tuple: Paths to the 'Collision' and 'Visual' directories. + """ + collision_dir = os.path.join(self.output_dir, "Collision") + visual_dir = os.path.join(self.output_dir, "Visual") + os.makedirs(collision_dir, exist_ok=True) + os.makedirs(visual_dir, exist_ok=True) + return collision_dir, visual_dir + + def copy_and_modify_mesh_file( + self, base_urdf_path: str, mesh_file_name: str, sub_folder: str, comp_name: str + ): + r"""Copy a mesh file to the output directory and handle dependencies. + + Args: + base_urdf_path (str): Path to the base URDF file. + mesh_file_name (str): Name of the mesh file to copy. + sub_folder (str): 'Visual' or 'Collision'. + comp_name (str): Component name, e.g. 'chassis', 'left_arm'. + + Returns: + str: Relative path to the new mesh file for URDF reference. + """ + # New mesh path format: output_dir/{sub_folder}/{comp_name}/{original_filename} + target_dir = os.path.join(self.output_dir, sub_folder, comp_name) + os.makedirs(target_dir, exist_ok=True) + + # Get URDF directory + urdf_dir = os.path.dirname(base_urdf_path) + + # Handle different path types + if os.path.isabs(mesh_file_name): + # Absolute path + original_mesh_path = mesh_file_name + else: + # Relative path - join with URDF directory and normalize + original_mesh_path = os.path.join(urdf_dir, mesh_file_name) + original_mesh_path = os.path.normpath(original_mesh_path) + + # Debug information + self.logger.debug(f"Processing mesh file:") + self.logger.debug(f" URDF path: {base_urdf_path}") + self.logger.debug(f" URDF dir: {urdf_dir}") + self.logger.debug(f" Mesh reference: {mesh_file_name}") + self.logger.debug(f" Resolved path: {original_mesh_path}") + + # Check if file exists + if not os.path.exists(original_mesh_path): + # Try some common alternative patterns + alternatives = [] + + # Try removing '../' and looking in same directory as URDF + if mesh_file_name.startswith("../"): + alt_path = os.path.join(urdf_dir, mesh_file_name[3:]) + alternatives.append(alt_path) + + # Try looking in parent directory structure + parent_dir = os.path.dirname(urdf_dir) + if mesh_file_name.startswith("../"): + alt_path = os.path.join(parent_dir, mesh_file_name[3:]) + alternatives.append(alt_path) + else: + alt_path = os.path.join(parent_dir, mesh_file_name) + alternatives.append(alt_path) + + # Try looking directly in the mesh filename as basename + basename = os.path.basename(mesh_file_name) + alt_path = os.path.join(urdf_dir, basename) + alternatives.append(alt_path) + + # Check alternatives + found_alternative = None + for alt in alternatives: + alt_normalized = os.path.normpath(alt) + if os.path.exists(alt_normalized): + found_alternative = alt_normalized + self.logger.debug( + f"Found mesh file at alternative location: {alt_normalized}" + ) + break + + if found_alternative: + original_mesh_path = found_alternative + else: + self.logger.error(f"Mesh file not found: {original_mesh_path}") + self.logger.debug(f" Tried alternatives: {alternatives}") + # Return original path to keep existing URDF reference + return mesh_file_name + + new_mesh_path = os.path.join(target_dir, os.path.basename(mesh_file_name)) + + try: + shutil.copyfile(original_mesh_path, new_mesh_path) + self.logger.debug(f"Copied mesh: {original_mesh_path} -> {new_mesh_path}") + except Exception as e: + self.logger.error(f"Failed to copy mesh file: {e}", exc_info=True) + return mesh_file_name + + # Handle OBJ's mtl dependency + if mesh_file_name.lower().endswith(".obj"): + mtl_filename = os.path.splitext(mesh_file_name)[0] + ".mtl" + original_mtl_path = os.path.join( + os.path.dirname(original_mesh_path), mtl_filename + ) + if os.path.exists(original_mtl_path): + new_mtl_path = os.path.join(target_dir, os.path.basename(mtl_filename)) + shutil.copyfile(original_mtl_path, new_mtl_path) + # Fix mtllib path in obj file to reference local filename + with open(new_mesh_path, "r") as f: + obj_content = f.read() + obj_content = obj_content.replace( + f"mtllib {mtl_filename}", f"mtllib {os.path.basename(mtl_filename)}" + ) + with open(new_mesh_path, "w") as f: + f.write(obj_content) + + # Handle DAE's texture dependency + if mesh_file_name.lower().endswith(".dae"): + try: + dae_tree = ET.parse(original_mesh_path) + dae_root = dae_tree.getroot() + ns = {} + if "}" in dae_root.tag: + ns["c"] = dae_root.tag.split("}")[0].strip("{") + image_tags = dae_root.findall(".//c:image", ns) + else: + image_tags = dae_root.findall(".//image") + for image in image_tags: + init_from = ( + image.find("c:init_from", ns) if ns else image.find("init_from") + ) + if init_from is not None and init_from.text: + tex_filename = os.path.basename(init_from.text) + original_tex_path = os.path.join( + os.path.dirname(original_mesh_path), tex_filename + ) + if os.path.exists(original_tex_path): + new_tex_path = os.path.join(target_dir, tex_filename) + shutil.copyfile(original_tex_path, new_tex_path) + except Exception as e: + self.logger.warning( + f"Failed to parse DAE texture dependency: {e}", exc_info=True + ) + + return os.path.join(sub_folder, comp_name, os.path.basename(mesh_file_name)) diff --git a/embodichain/toolkits/urdf_assembly/sensor.py b/embodichain/toolkits/urdf_assembly/sensor.py new file mode 100644 index 00000000..6cf87829 --- /dev/null +++ b/embodichain/toolkits/urdf_assembly/sensor.py @@ -0,0 +1,957 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import copy +import traceback +import numpy as np +from dataclasses import dataclass +import xml.etree.ElementTree as ET + +from scipy.spatial.transform import Rotation as R +from typing import Dict, List, Optional, Union, Tuple + +from embodichain.toolkits.urdf_assembly.logging_utils import ( + URDFAssemblyLogger, +) +from embodichain.toolkits.urdf_assembly.mesh import URDFMeshManager + +__all__ = ["SensorRegistry", "SensorAttachment", "URDFSensorManager"] + + +class SensorRegistry: + """Registry for storing and retrieving SensorAttachment objects.""" + + def __init__(self): + self._sensors = {} + + def add(self, sensor_name: str, sensor_obj): + self._sensors[sensor_name] = sensor_obj + + def get(self, sensor_name: str): + return self._sensors.get(sensor_name) + + def all(self): + return self._sensors + + def remove(self, sensor_name: str): + if sensor_name in self._sensors: + del self._sensors[sensor_name] + + +@dataclass +class SensorAttachment: + r"""Represents a sensor attachment configuration to a robot component. + + This dataclass defines how a sensor should be attached to a specific component + and link within the robot assembly, including optional spatial transformation + to position the sensor correctly relative to the attachment point. + """ + + sensor_urdf: str # Path to the sensor's URDF file + parent_component: str # Name of the component to which the sensor is attached + parent_link: str # Specific link name within the parent component for attachment + transform: Optional[ + np.ndarray + ] = None # Optional 4x4 transformation matrix for sensor positioning + sensor_type: Optional[str] = None # Optional sensor type field + + +class URDFSensorManager: + r"""Responsible for loading, processing, and managing sensor attachments.""" + + def __init__(self, mesh_manager: URDFMeshManager): + r"""Initialize the URDFSensorManager. + + Args: + mesh_manager (URDFMeshManager): Manager for handling mesh files. + """ + self.mesh_manager = mesh_manager + self.logger = URDFAssemblyLogger.get_logger("sensor_manager") + self.attached_sensors = {} # Maps sensor_name to processed sensor data + + def attach_sensor( + self, + sensor_name: str, + sensor_source: Union[ + str, ET.Element, Dict, Tuple[List[ET.Element], List[ET.Element]] + ], + parent_component: str, + parent_link: str, + transform: Optional[np.ndarray] = None, + sensor_type: Optional[str] = None, + extract_links: Optional[List[str]] = None, + extract_joints: Optional[List[str]] = None, + ) -> bool: + r"""Attach a sensor to a specific component and link with multiple input format support. + + Args: + sensor_name (str): Unique identifier for the sensor attachment. + sensor_source: Sensor definition source (multiple formats supported). + parent_component (str): Target component name for sensor attachment. + parent_link (str): Specific link within parent component for attachment. + transform (Optional[np.ndarray]): Optional 4x4 homogeneous transformation matrix. + sensor_type (Optional[str]): Sensor type classification. + extract_links (Optional[List[str]]): Specific link names to extract from URDF. + extract_joints (Optional[List[str]]): Specific joint names to extract from URDF. + + Returns: + bool: True if sensor attachment successful, False on failure. + """ + try: + # Phase 1: Input validation + if not self._validate_sensor_params( + sensor_name, sensor_source, parent_component, parent_link, transform + ): + return False + + # Phase 2: Process sensor source based on input type + sensor_elements = self._process_sensor_source( + sensor_source, extract_links, extract_joints, sensor_name + ) + + if not sensor_elements: + self.logger.error("Failed to process sensor source") + return False + + sensor_links, sensor_joints, sensor_urdf_path = sensor_elements + + # Phase 3: Validate sensor elements + if not self._validate_sensor_elements(sensor_links, sensor_joints): + return False + + # Phase 4: Process and rename sensor elements to avoid conflicts + processed_elements = self._process_and_rename_sensor_elements( + sensor_links, sensor_joints, sensor_name + ) + + if not processed_elements: + self.logger.error("Failed to process sensor elements") + return False + + processed_links, processed_joints = processed_elements + + # Phase 5: Create sensor attachment data (compatible with existing SensorAttachment) + sensor_attachment = SensorAttachment( + sensor_urdf=sensor_urdf_path, + parent_component=parent_component, + parent_link=parent_link, + transform=transform, + ) + + # Store processed sensor data + self.attached_sensors[sensor_name] = { + "attachment": sensor_attachment, + "links": processed_links, + "joints": processed_joints, + "sensor_type": sensor_type, + } + + self.logger.debug( + f"Successfully attached sensor [{sensor_name}] " + f"({sensor_type or 'unspecified'}) with {len(processed_links)} links " + f"and {len(processed_joints)} joints to component ({parent_component}) " + f"at link ({parent_link})" + ) + return True + + except Exception as e: + self.logger.error(f"Sensor attachment failed for [{sensor_name}]: {str(e)}") + self.logger.debug(f"Traceback: {traceback.format_exc()}") + return False + + def _validate_sensor_params( + self, + sensor_name: str, + sensor_source, + parent_component: str, + parent_link: str, + transform: Optional[np.ndarray], + ) -> bool: + r"""Validate input parameters for sensor attachment. + + Args: + sensor_name: Sensor identifier to validate + sensor_source: Sensor source to validate + parent_component: Parent component name to validate + parent_link: Parent link name to validate + transform: Transformation matrix to validate + + Returns: + bool: True if all parameters are valid, False otherwise + """ + # Validate sensor name + if not sensor_name or not isinstance(sensor_name, str): + self.logger.error("Sensor name must be a non-empty string") + return False + + if not sensor_name.replace("_", "").replace("-", "").isalnum(): + self.logger.error( + "Sensor name must contain only alphanumeric characters, underscores, and hyphens" + ) + return False + + # Validate sensor source + if sensor_source is None: + self.logger.error("Sensor source cannot be None") + return False + + # Validate parent component and link + if not parent_component or not isinstance(parent_component, str): + self.logger.error("Parent component must be a non-empty string") + return False + + if not parent_link or not isinstance(parent_link, str): + self.logger.error("Parent link must be a non-empty string") + return False + + # Validate transformation matrix if provided + if transform is not None: + if not isinstance(transform, np.ndarray): + self.logger.error("Transform must be a numpy array") + return False + + if transform.shape != (4, 4): + self.logger.error( + f"Transform must be 4x4 matrix, got shape {transform.shape}" + ) + return False + + if not self._is_valid_homogeneous_transform(transform): + self.logger.error( + "Transform is not a valid homogeneous transformation matrix" + ) + return False + + return True + + def _process_sensor_source( + self, + sensor_source, + extract_links: Optional[List[str]], + extract_joints: Optional[List[str]], + sensor_name: str, + ) -> Optional[Tuple[List[ET.Element], List[ET.Element], str]]: + r"""Process sensor source based on input type and extract relevant elements. + + Args: + sensor_source: Input sensor source in various formats + extract_links: Optional list of specific link names to extract + extract_joints: Optional list of specific joint names to extract + sensor_name: Sensor name for path generation + + Returns: + Optional tuple of (links, joints, urdf_path) or None on failure + """ + try: + if isinstance(sensor_source, str): + # Handle URDF file path + return self._process_urdf_file_source( + sensor_source, extract_links, extract_joints + ) + + elif isinstance(sensor_source, ET.Element): + # Handle pre-loaded URDF element + return self._process_urdf_element_source( + sensor_source, extract_links, extract_joints, sensor_name + ) + + elif isinstance(sensor_source, dict): + # Handle configuration dictionary + return self._process_config_dict_source(sensor_source, sensor_name) + + elif isinstance(sensor_source, tuple) and len(sensor_source) == 2: + # Handle direct (links, joints) tuple + return self._process_element_tuple_source(sensor_source, sensor_name) + + else: + self.logger.error( + f"Unsupported sensor source type: {type(sensor_source)}" + ) + return None + + except Exception as e: + self.logger.error(f"Error processing sensor source: {str(e)}") + return None + + def _process_urdf_file_source( + self, + file_path: str, + extract_links: Optional[List[str]], + extract_joints: Optional[List[str]], + ) -> Optional[Tuple[List[ET.Element], List[ET.Element], str]]: + r"""Process URDF file source and extract specified elements. + + Args: + file_path: Path to URDF file + extract_links: Optional list of link names to extract + extract_joints: Optional list of joint names to extract + + Returns: + Tuple of (links, joints, file_path) or None on failure + """ + if not os.path.exists(file_path): + self.logger.error(f"Sensor URDF file not found: {file_path}") + return None + + try: + urdf_element = ET.parse(file_path).getroot() + links, joints = self._extract_elements_from_urdf( + urdf_element, extract_links, extract_joints + ) + return links, joints, file_path + + except ET.ParseError as e: + self.logger.error(f"Failed to parse URDF file {file_path}: {str(e)}") + return None + + def _process_urdf_element_source( + self, + urdf_element: ET.Element, + extract_links: Optional[List[str]], + extract_joints: Optional[List[str]], + sensor_name: str, + ) -> Tuple[List[ET.Element], List[ET.Element], str]: + r"""Process pre-loaded URDF element source. + + Args: + urdf_element: Pre-loaded URDF root element + extract_links: Optional list of link names to extract + extract_joints: Optional list of joint names to extract + sensor_name: Sensor name for path generation + + Returns: + Tuple of (links, joints, generated_path) + """ + links, joints = self._extract_elements_from_urdf( + urdf_element, extract_links, extract_joints + ) + generated_path = f"" + return links, joints, generated_path + + def _process_config_dict_source( + self, config: Dict, sensor_name: str + ) -> Tuple[List[ET.Element], List[ET.Element], str]: + r"""Process configuration dictionary source and create URDF elements. + + Args: + config: Configuration dictionary for sensor creation + sensor_name: Sensor name for element generation + + Returns: + Tuple of (links, joints, generated_path) + """ + urdf_element = self._create_sensor_from_config(config, sensor_name) + links = urdf_element.findall("link") + joints = urdf_element.findall("joint") + generated_path = f"" + return links, joints, generated_path + + def _process_element_tuple_source( + self, element_tuple: Tuple, sensor_name: str + ) -> Optional[Tuple[List[ET.Element], List[ET.Element], str]]: + r"""Process direct element tuple source. + + Args: + element_tuple: Tuple containing (links_list, joints_list) + sensor_name: Sensor name for path generation + + Returns: + Tuple of (links, joints, generated_path) or None on failure + """ + links_list, joints_list = element_tuple + + if not isinstance(links_list, list) or not isinstance(joints_list, list): + self.logger.error( + "Element tuple must contain (List[ET.Element], List[ET.Element])" + ) + return None + + # Validate that all elements are actually ET.Element instances + for i, link in enumerate(links_list): + if not isinstance(link, ET.Element): + self.logger.error(f"Links list item {i} is not an ET.Element") + return None + + for i, joint in enumerate(joints_list): + if not isinstance(joint, ET.Element): + self.logger.error(f"Joints list item {i} is not an ET.Element") + return None + + generated_path = f"" + return links_list, joints_list, generated_path + + def _extract_elements_from_urdf( + self, + urdf_element: ET.Element, + extract_links: Optional[List[str]] = None, + extract_joints: Optional[List[str]] = None, + ) -> Tuple[List[ET.Element], List[ET.Element]]: + r"""Extract specified links and joints from URDF element. + + Args: + urdf_element: URDF root element to extract from + extract_links: Optional list of specific link names to extract + extract_joints: Optional list of specific joint names to extract + + Returns: + Tuple of (extracted_links, extracted_joints) + """ + # Extract links + all_links = urdf_element.findall("link") + if extract_links: + links = [] + for link_name in extract_links: + link = urdf_element.find(f".//link[@name='{link_name}']") + if link is not None: + links.append(link) + self.logger.debug(f"Extracted link: {link_name}") + else: + self.logger.warning(f"Link '{link_name}' not found in URDF") + else: + links = all_links + self.logger.debug(f"Extracted all {len(links)} links from URDF") + + # Extract joints + all_joints = urdf_element.findall("joint") + if extract_joints: + joints = [] + for joint_name in extract_joints: + joint = urdf_element.find(f".//joint[@name='{joint_name}']") + if joint is not None: + joints.append(joint) + self.logger.debug(f"Extracted joint: {joint_name}") + else: + self.logger.warning(f"Joint '{joint_name}' not found in URDF") + else: + joints = all_joints + self.logger.debug(f"Extracted all {len(joints)} joints from URDF") + + return links, joints + + def _validate_sensor_elements( + self, sensor_links: List[ET.Element], sensor_joints: List[ET.Element] + ) -> bool: + r"""Validate extracted sensor elements for completeness and consistency. + + Args: + sensor_links: List of sensor link elements + sensor_joints: List of sensor joint elements + + Returns: + bool: True if elements are valid, False otherwise + """ + if not sensor_links: + self.logger.error("No links found in sensor definition") + return False + + # Validate link elements + for i, link in enumerate(sensor_links): + if not isinstance(link, ET.Element): + self.logger.error(f"Invalid link element at index {i}") + return False + + link_name = link.get("name") + if not link_name: + self.logger.error(f"Link at index {i} has no name attribute") + return False + + # Validate joint elements + for i, joint in enumerate(sensor_joints): + if not isinstance(joint, ET.Element): + self.logger.error(f"Invalid joint element at index {i}") + return False + + joint_name = joint.get("name") + if not joint_name: + self.logger.error(f"Joint at index {i} has no name attribute") + return False + + self.logger.debug( + f"Validated {len(sensor_links)} links and {len(sensor_joints)} joints" + ) + return True + + def _is_valid_homogeneous_transform(self, transform: np.ndarray) -> bool: + """ + Validate that a 4x4 matrix is a plausible homogeneous transformation matrix. + Only warn if not strictly valid, but still return True. + + Args: + transform: 4x4 transformation matrix to validate + + Returns: + bool: Always True, but warns if not strictly valid + """ + try: + # Check shape + if transform.shape != (4, 4): + self.logger.warning("Transform matrix is not 4x4.") + return False + + # Check bottom row + expected_bottom_row = np.array([0, 0, 0, 1]) + if not np.allclose(transform[3, :], expected_bottom_row, atol=1e-6): + self.logger.warning("Transform bottom row is not [0, 0, 0, 1].") + + # Check rotation matrix orthogonality + rotation_matrix = transform[:3, :3] + should_be_identity = np.dot(rotation_matrix, rotation_matrix.T) + if not np.allclose(should_be_identity, np.eye(3), atol=1e-6): + self.logger.warning("Rotation part of transform is not orthogonal.") + + # Check determinant + if not np.isclose(np.linalg.det(rotation_matrix), 1.0, atol=1e-6): + self.logger.warning("Rotation matrix determinant is not close to 1.") + + # Always return True, just warn + return True + + except Exception as e: + self.logger.warning(f"Transform validation exception: {e}") + return True + + def _process_and_rename_sensor_elements( + self, + sensor_links: List[ET.Element], + sensor_joints: List[ET.Element], + sensor_name: str, + ) -> Optional[Tuple[List[ET.Element], List[ET.Element]]]: + r"""Process and rename sensor link and joint elements to avoid name conflicts. + + Args: + sensor_links (List[ET.Element]): List of sensor link XML elements. + sensor_joints (List[ET.Element]): List of sensor joint XML elements. + sensor_name (str): The sensor's name, used as a prefix. + + Returns: + Optional[Tuple[List[ET.Element], List[ET.Element]]]: Tuple of processed (links, joints), + or None if processing fails. + """ + try: + processed_links = [] + processed_joints = [] + sensor_prefix = f"{sensor_name}_" + sensor_name_lower = sensor_name.lower() + link_name_mapping = {} + + # Process links: add prefix if needed and build mapping + for link in sensor_links: + original_name = link.get("name") + # If the name already contains the sensor name (case-insensitive), do not add prefix + if sensor_name_lower in original_name.lower(): + new_name = original_name + else: + new_name = f"{sensor_prefix}{original_name}" + link_name_mapping[original_name] = new_name + new_link = copy.deepcopy(link) + new_link.set("name", new_name) + processed_links.append(new_link) + + # Process joints: add prefix if needed and update parent/child references + for joint in sensor_joints: + original_name = joint.get("name") + if sensor_name_lower in original_name.lower(): + new_name = original_name + else: + new_name = f"{sensor_prefix}{original_name}" + new_joint = copy.deepcopy(joint) + new_joint.set("name", new_name) + + # Update parent link reference + parent_elem = new_joint.find("parent") + if parent_elem is not None: + parent_link_name = parent_elem.get("link") + parent_elem.set( + "link", + link_name_mapping.get(parent_link_name, parent_link_name), + ) + # Update child link reference + child_elem = new_joint.find("child") + if child_elem is not None: + child_link_name = child_elem.get("link") + child_elem.set( + "link", link_name_mapping.get(child_link_name, child_link_name) + ) + + processed_joints.append(new_joint) + + return processed_links, processed_joints + except Exception as e: + self.logger.error(f"Failed to process sensor elements: {str(e)}") + return None + + def _create_sensor_from_config(self, config: Dict, sensor_name: str) -> ET.Element: + r"""Create sensor URDF element from configuration dictionary. + + Args: + config: Configuration dictionary containing sensor specifications + sensor_name: Name for the generated sensor + + Returns: + ET.Element: Root element of generated sensor URDF + """ + # Create root robot element + robot = ET.Element("robot", name=f"sensor_{sensor_name}") + + # Create main sensor link + link_name = config.get("link_name", f"{sensor_name}_link") + link = ET.SubElement(robot, "link", name=link_name) + + # Add visual element if specified + if "visual" in config: + visual_config = config["visual"] + visual = ET.SubElement(link, "visual") + + # Add origin if specified + if "origin" in visual_config: + origin_data = visual_config["origin"] + ET.SubElement( + visual, + "origin", + xyz=origin_data.get("xyz", "0 0 0"), + rpy=origin_data.get("rpy", "0 0 0"), + ) + + # Add geometry + geometry = ET.SubElement(visual, "geometry") + geom_type = visual_config.get("type", "box") + + if geom_type == "box": + size = visual_config.get("size", "0.1 0.1 0.1") + ET.SubElement(geometry, "box", size=size) + + elif geom_type == "cylinder": + radius = str(visual_config.get("radius", 0.05)) + length = str(visual_config.get("length", 0.1)) + ET.SubElement(geometry, "cylinder", radius=radius, length=length) + + elif geom_type == "sphere": + radius = str(visual_config.get("radius", 0.05)) + ET.SubElement(geometry, "sphere", radius=radius) + + elif geom_type == "mesh": + filename = visual_config.get("filename", "") + if filename: + mesh_elem = ET.SubElement(geometry, "mesh", filename=filename) + if "scale" in visual_config: + mesh_elem.set("scale", visual_config["scale"]) + + # Add material/color if specified + if "color" in visual_config: + material = ET.SubElement( + visual, "material", name=f"{sensor_name}_material" + ) + ET.SubElement(material, "color", rgba=visual_config["color"]) + + # Add collision element if specified + if "collision" in config: + collision_config = config["collision"] + collision = ET.SubElement(link, "collision") + + # Add origin if specified + if "origin" in collision_config: + origin_data = collision_config["origin"] + ET.SubElement( + collision, + "origin", + xyz=origin_data.get("xyz", "0 0 0"), + rpy=origin_data.get("rpy", "0 0 0"), + ) + + # Add geometry (similar to visual) + geometry = ET.SubElement(collision, "geometry") + geom_type = collision_config.get("type", "box") + + if geom_type == "box": + size = collision_config.get("size", "0.1 0.1 0.1") + ET.SubElement(geometry, "box", size=size) + + elif geom_type == "cylinder": + radius = str(collision_config.get("radius", 0.05)) + length = str(collision_config.get("length", 0.1)) + ET.SubElement(geometry, "cylinder", radius=radius, length=length) + + elif geom_type == "sphere": + radius = str(collision_config.get("radius", 0.05)) + ET.SubElement(geometry, "sphere", radius=radius) + + # Add inertial properties if specified + if "inertial" in config: + inertial_config = config["inertial"] + inertial = ET.SubElement(link, "inertial") + + # Add origin if specified + if "origin" in inertial_config: + origin_data = inertial_config["origin"] + ET.SubElement( + inertial, + "origin", + xyz=origin_data.get("xyz", "0 0 0"), + rpy=origin_data.get("rpy", "0 0 0"), + ) + + # Add mass + mass_value = str(inertial_config.get("mass", 0.1)) + ET.SubElement(inertial, "mass", value=mass_value) + + # Add inertia tensor + inertia_elem = ET.SubElement(inertial, "inertia") + inertia_properties = { + "ixx": "ixx", + "iyy": "iyy", + "izz": "izz", + "ixy": "ixy", + "ixz": "ixz", + "iyz": "iyz", + } + + for attr, config_key in inertia_properties.items(): + value = str(inertial_config.get(config_key, 0.0)) + inertia_elem.set(attr, value) + + # Add any additional joints if specified in config + if "joints" in config: + for joint_config in config["joints"]: + joint = ET.SubElement( + robot, + "joint", + name=joint_config.get("name", f"{sensor_name}_joint"), + type=joint_config.get("type", "fixed"), + ) + + # Add origin + if "origin" in joint_config: + origin_data = joint_config["origin"] + ET.SubElement( + joint, + "origin", + xyz=origin_data.get("xyz", "0 0 0"), + rpy=origin_data.get("rpy", "0 0 0"), + ) + + # Add parent and child links + if "parent" in joint_config: + ET.SubElement(joint, "parent", link=joint_config["parent"]) + if "child" in joint_config: + ET.SubElement(joint, "child", link=joint_config["child"]) + + # Add axis for revolute/prismatic joints + if ( + joint_config.get("type") in ["revolute", "prismatic"] + and "axis" in joint_config + ): + ET.SubElement(joint, "axis", xyz=joint_config["axis"]) + + # Add limits for revolute/prismatic joints + if "limits" in joint_config: + limits_data = joint_config["limits"] + limit_elem = ET.SubElement(joint, "limit") + for attr in ["lower", "upper", "effort", "velocity"]: + if attr in limits_data: + limit_elem.set(attr, str(limits_data[attr])) + + self.logger.debug(f"Generated sensor URDF from config for '{sensor_name}'") + return robot + + def process_sensor_attachments( + self, + links: list, + joints: list, + base_points: dict, + existing_link_names: set, + existing_joint_names: set, + ): + r"""Process all attached sensors by adding their link and joint elements to the robot. + + Args: + links (list): Global list to collect sensor link elements. + joints (list): Global list to collect sensor joint elements. + base_points (dict): Mapping from component names to their base link names. + existing_link_names (set): Set of existing link names to avoid conflicts. + existing_joint_names (set): Set of existing joint names to avoid conflicts. + """ + for sensor_name, sensor_data in self.attached_sensors.items(): + try: + attachment = sensor_data["attachment"] + sensor_links = sensor_data["links"] + sensor_joints = sensor_data["joints"] + sensor_type = sensor_data.get("sensor_type", "unknown") + + self.logger.debug( + f"Processing sensor attachment: {sensor_name} ({sensor_type})" + ) + + # Process sensor links: ensure names are lowercase and prefixed + for link in sensor_links: + link_name = link.get("name") + if link_name: + # Get original and sensor type strings + original_name = link_name.lower() + sensor_type_str = ( + str(sensor_type).lower() if sensor_type else "" + ) + # Add prefix only if not already present + if sensor_type_str and sensor_type_str not in original_name: + formatted_name = f"{original_name}_{sensor_type_str}" + else: + formatted_name = original_name + + # Ensure unique link names + unique_name = formatted_name + count = 1 + while unique_name in existing_link_names: + unique_name = f"{formatted_name}_{count}" + self.logger.warning( + f"Link name '{unique_name}' already exists. Trying a new name '{unique_name}' with suffix: '{count}'" + ) + formatted_name = unique_name + count += 1 + + link.set("name", formatted_name) + + # Track link names and add to global list + existing_link_names.add(formatted_name) + links.append(link) + + # Process meshes for this sensor link + self._process_sensor_meshes( + link, attachment.sensor_urdf, sensor_name + ) + + self.logger.debug(f"Added sensor link: {formatted_name}") + + # Process sensor joints: ensure names are UPPERCASE and follow PARENT_TO_CHILD format + for joint in sensor_joints: + joint_name = joint.get("name") + if joint_name: + parent_elem = joint.find("parent") + child_elem = joint.find("child") + parent_link = ( + parent_elem.get("link").lower() + if parent_elem is not None + else "" + ) + child_link = ( + child_elem.get("link").lower() + if child_elem is not None + else "" + ) + + # Format joint name as PARENT_TO_CHILD in uppercase + formatted_name = f"{parent_link}_to_{child_link}".upper() + joint.set("name", formatted_name) + + # Ensure parent/child link references are lowercase + if parent_elem is not None: + parent_elem.set("link", parent_link) + if child_elem is not None: + child_elem.set("link", child_link) + + if attachment.transform is not None: + transform = attachment.transform + xyz = transform[:3, 3] + rotation = R.from_matrix(transform[:3, :3]) + rpy = rotation.as_euler("xyz") + + origin_elem = joint.find("origin") + if origin_elem is None: + origin_elem = ET.SubElement(joint, "origin") + origin_elem.set("xyz", f"{xyz[0]} {xyz[1]} {xyz[2]}") + origin_elem.set("rpy", f"{rpy[0]} {rpy[1]} {rpy[2]}") + + self.logger.info( + f"Applied transform to sensor joint {joint.get('name')}: xyz={xyz}, rpy={rpy}" + ) + + existing_joint_names.add(formatted_name) + joints.append(joint) + self.logger.debug(f"Added sensor joint: {formatted_name}") + + except Exception as e: + self.logger.error( + f"Failed to process sensor attachment {sensor_name}: {str(e)}" + ) + self.logger.debug(f"Traceback: {traceback.format_exc()}") + + def _process_sensor_meshes( + self, link: ET.Element, base_urdf_path: str, sensor_name: str + ): + r"""Process visual and collision meshes for a sensor link. + + Args: + link (ET.Element): The URDF link element to process. + base_urdf_path (str): The base path for the URDF files. + sensor_name (str): The name of the sensor being processed. + """ + try: + # Process visual meshes + for visual in link.findall("visual"): + geometry = visual.find("geometry") + if geometry is not None: + mesh = geometry.find("mesh") + if mesh is not None: + filename = mesh.get("filename") + if filename is not None: + self.logger.debug( + f"Processing sensor visual mesh: {filename}" + ) + new_mesh_filename = self.mesh_manager.copy_and_modify_mesh_file( + base_urdf_path, + filename, + "Visual", + f"sensor_{sensor_name}", # Use sensor prefix for organization + ) + self.logger.debug( + f"Updated sensor visual mesh filename: {new_mesh_filename}" + ) + mesh.set("filename", new_mesh_filename) + + # Process collision meshes + for collision in link.findall("collision"): + geometry = collision.find("geometry") + if geometry is not None: + mesh = geometry.find("mesh") + if mesh is not None: + filename = mesh.get("filename") + if filename is not None: + self.logger.debug( + f"Processing sensor collision mesh: {filename}" + ) + new_mesh_filename = self.mesh_manager.copy_and_modify_mesh_file( + base_urdf_path, + filename, + "Collision", + f"sensor_{sensor_name}", # Use sensor prefix for organization + ) + self.logger.debug( + f"Updated sensor collision mesh filename: {new_mesh_filename}" + ) + mesh.set("filename", new_mesh_filename) + + except Exception as e: + self.logger.error(f"Failed to process meshes for sensor {sensor_name}: {e}") + + def get_attached_sensors(self) -> Dict: + r"""Get all attached sensors with processed data.""" + return self.attached_sensors + + def convert_to_legacy_format(self) -> Dict: + r"""Convert processed sensors to legacy attach_dict format for compatibility.""" + legacy_dict = {} + for sensor_name, sensor_data in self.attached_sensors.items(): + legacy_dict[sensor_name] = sensor_data["attachment"] + return legacy_dict diff --git a/embodichain/toolkits/urdf_assembly/signature.py b/embodichain/toolkits/urdf_assembly/signature.py new file mode 100644 index 00000000..d0b5de9e --- /dev/null +++ b/embodichain/toolkits/urdf_assembly/signature.py @@ -0,0 +1,204 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import json +import hashlib +from pathlib import Path +import xml.etree.ElementTree as ET + +from embodichain.toolkits.urdf_assembly.logging_utils import ( + URDFAssemblyLogger, +) + +__all__ = ["URDFAssemblySignatureManager"] + + +class URDFAssemblySignatureManager: + r"""Simple MD5-based signature manager for URDF assemblies without persistent cache.""" + + def __init__(self): + self.logger = URDFAssemblyLogger.get_logger("signature_manager") + + def _calculate_file_md5(self, file_path: str) -> str: + r"""Calculate MD5 hash of a file.""" + hash_md5 = hashlib.md5() + try: + with open(file_path, "rb") as f: + for chunk in iter(lambda: f.read(4096), b""): + hash_md5.update(chunk) + return hash_md5.hexdigest() + except Exception as e: + self.logger.error(f"Error calculating MD5 for {file_path}: {e}") + return "" + + def _calculate_string_md5(self, content: str) -> str: + r"""Calculate MD5 hash of a string.""" + return hashlib.md5(content.encode("utf-8")).hexdigest() + + def calculate_assembly_signature(self, urdf_dict: dict, output_path: str) -> str: + r"""Calculate a unique signature for the assembly configuration. + + Args: + urdf_dict (dict): Dictionary of components and their configurations + output_path (str): Target output path for the assembly + + Returns: + str: MD5 hash representing the assembly configuration + """ + signature_data = { + "output_filename": os.path.basename(output_path), + "components": {}, + } + + def to_serializable(obj): + r"""Recursively convert objects to types that are JSON serializable. + + Args: + obj: The object to convert (could be Path, dict, list, or other types). + + Returns: + The converted object, ready for JSON serialization. + - Path objects are converted to strings. + - dict and list are recursively processed. + - Other types are returned as-is. + """ + if isinstance(obj, Path): + return str(obj) + elif isinstance(obj, dict): + return {k: to_serializable(v) for k, v in obj.items()} + elif isinstance(obj, list): + return [to_serializable(i) for i in obj] + else: + return obj + + # Process each component + for comp_type, comp_obj in urdf_dict.items(): + if comp_obj is None: + continue + + # Calculate file MD5 + file_md5 = self._calculate_file_md5(comp_obj.urdf_path) + if not file_md5: + self.logger.warning(f"Could not calculate MD5 for {comp_obj.urdf_path}") + continue + + # Include component configuration + comp_data = { + "urdf_path": str(comp_obj.urdf_path), + "file_md5": file_md5, + "params": to_serializable(comp_obj.params or {}), + "transform": comp_obj.transform.tolist() + if comp_obj.transform is not None + else None, + } + + signature_data["components"][comp_type] = comp_data + + # Convert to JSON string for consistent hashing + signature_json = json.dumps(signature_data, sort_keys=True, ensure_ascii=False) + assembly_md5 = self._calculate_string_md5(signature_json) + + self.logger.info(f"Assembly signature calculated: [{assembly_md5}]") + self.logger.debug(f"Signature data: {signature_json}") + + return assembly_md5 + + def extract_signature_from_urdf(self, urdf_file_path: str) -> str: + r"""Extract signature from existing URDF file's header comment. + + Args: + urdf_file_path (str): Path to existing URDF file + + Returns: + str: Extracted signature or empty string if not found + """ + try: + with open(urdf_file_path, "r", encoding="utf-8") as f: + content = f.read() + + # Look for signature in comment + import re + + # 1. + # 2. + patterns = [ + r"", + r"", + ] + + for pattern in patterns: + match = re.search(pattern, content) + if match: + signature = match.group(1) + self.logger.info( + f"Found existing signature in ({urdf_file_path}): [{signature}]" + ) + return signature + + self.logger.debug(f"No signature found in {urdf_file_path}") + return "" + + except Exception as e: + self.logger.warning( + f"Failed to extract signature from {urdf_file_path}: {e}", exc_info=True + ) + return "" + + def is_assembly_up_to_date(self, current_signature: str, output_path: str) -> bool: + r"""Check if the assembly at output_path has the same signature as current configuration. + + Args: + current_signature (str): MD5 signature of current assembly configuration + output_path (str): Path to existing URDF file + + Returns: + bool: True if signatures match and file exists + """ + if not os.path.exists(output_path): + self.logger.info(f"Output file does not exist: {output_path}") + return False + + # Verify file is not empty and is valid URDF + try: + if os.path.getsize(output_path) == 0: + self.logger.warning(f"Output file is empty: {output_path}") + return False + + # Try to parse as XML to ensure it's valid + ET.parse(output_path) + except Exception as e: + self.logger.warning( + f"Output file is invalid: {output_path}, error: {e}", exc_info=True + ) + return False + + # Extract signature from existing file + existing_signature = self.extract_signature_from_urdf(output_path) + + if existing_signature == current_signature: + self.logger.info( + f"✅ Assembly is up-to-date. Signature: {current_signature}" + ) + return True + else: + if existing_signature: + self.logger.info(f"Assembly signatures differ:") + self.logger.info(f" Current: {current_signature}") + self.logger.info(f" Existing: {existing_signature}") + else: + self.logger.info(f"No signature found in existing file: {output_path}") + return False diff --git a/embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py b/embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py new file mode 100644 index 00000000..80bcd90f --- /dev/null +++ b/embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py @@ -0,0 +1,783 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import time +import logging +import numpy as np +from pathlib import Path +from functools import wraps +import xml.etree.ElementTree as ET + +from scipy.spatial.transform import Rotation as R +from typing import Dict, List, Optional, Union, Tuple + +from embodichain.toolkits.urdf_assembly.logging_utils import ( + setup_urdf_logging, +) +from embodichain.toolkits.urdf_assembly.signature import ( + URDFAssemblySignatureManager, +) +from embodichain.toolkits.urdf_assembly.component import ( + URDFComponent, + ComponentRegistry, + URDFComponentManager, +) +from embodichain.toolkits.urdf_assembly.sensor import ( + SensorAttachment, + SensorRegistry, + URDFSensorManager, +) +from embodichain.toolkits.urdf_assembly.connection import ( + URDFConnectionManager, +) +from embodichain.toolkits.urdf_assembly.mesh import URDFMeshManager +from embodichain.toolkits.urdf_assembly.file_writer import ( + URDFFileWriter, +) +from embodichain.toolkits.urdf_assembly.utils import ( + ensure_directory_exists, +) + +__all__ = ["URDFAssemblyManager"] + + +def performance_monitor(func): + r"""Performance monitoring decorator for tracking function execution time""" + + @wraps(func) + def wrapper(self, *args, **kwargs): + start_time = time.time() + try: + result = func(self, *args, **kwargs) + duration = time.time() - start_time + self.logger.debug(f"{func.__name__} completed in {duration:.3f}s") + return result + except Exception as e: + duration = time.time() - start_time + self.logger.error(f"{func.__name__} failed after {duration:.3f}s: {e}") + raise + + return wrapper + + +class URDFAssemblyManager: + r""" + A class to manage the assembly of URDF files and their components. + """ + # Supported wheel types for chassis components + SUPPORTED_WHEEL_TYPES = [ + "omni", + "differential", + "tracked", + ] + + # Supported robot component types + SUPPORTED_COMPONENTS = [ + "chassis", + "legs", + "torso", + "head", + "left_arm", + "right_arm", + "left_hand", + "right_hand", + "arm", + "hand", + ] + + # Supported sensor types for attachment + SUPPORTED_SENSORS = [ + "camera", + "lidar", + "imu", + "gps", + "force", + ] + + # Supported mesh file formats + SUPPORTED_MESH_TYPES = [ + "stl", + "obj", + "ply", + "dae", + "glb", + ] + + def __init__( + self, + component_registry: ComponentRegistry = None, + sensor_registry: SensorRegistry = None, + mesh_manager: URDFMeshManager = None, + component_manager: "URDFComponentManager" = None, + sensor_manager: "URDFSensorManager" = None, + ): + self.logger = setup_urdf_logging() + + # Use registries for components and sensors + self.component_registry = component_registry or ComponentRegistry() + self.sensor_registry = sensor_registry or SensorRegistry() + + # Initialize mesh manager + self.mesh_manager = mesh_manager or URDFMeshManager(output_dir=".") + + # Initialize managers for components and sensors + self.component_manager = component_manager or URDFComponentManager( + self.mesh_manager + ) + self.sensor_manager = sensor_manager or URDFSensorManager(self.mesh_manager) + + # Processing order for components with their name prefixes + # Tuple format: (component_name, prefix) + self.component_order = [ + ("chassis", None), + ("legs", None), + ("torso", None), + ("head", None), + ("left_arm", "left_"), + ("right_arm", "right_"), + ("left_hand", "left_"), + ("right_hand", "right_"), + ("arm", None), + ("hand", None), + ] + + # Attachment position indices for component connections. + # This dictionary defines which link of each component should be used as the connection point + # when attaching to other components: + # 0 : use the first link in the component's URDF (typically for child connections) + # -1 : use the last link in the component's URDF (typically for parent connections) + # For example, 'chassis': 0 means the first link of the chassis is used for child attachments; + # 'torso': -1 means the last link of the torso is used for child attachments, etc. + self.attach_positions = { + "chassis": 0, # Use first link of chassis for child connections + "legs": -1, # Use last link of legs for child connections + "torso": -1, # Use last link of torso for child connections + "head": 0, # Use first link of head for connections + "left_arm": -1, # Use last link of left_arm for hand attachment + "right_arm": -1, # Use last link of right_arm for hand attachment + "left_hand": 0, # Use first link of left_hand for connections + "right_hand": 0, # Use first link of right_hand for connections + "arm": -1, # Use last link of arm for hand attachment + "hand": 0, # Use first link of hand for connections + } + + # Connection rules defining parent-child relationships between components + self.connection_rules = [ + ("chassis", "legs"), + ("legs", "torso"), + ("chassis", "torso"), + ("chassis", "left_arm"), + ("chassis", "right_arm"), + ("chassis", "arm"), + ("torso", "head"), + ("torso", "left_arm"), + ("torso", "right_arm"), + ("torso", "arm"), + ("left_arm", "left_hand"), + ("right_arm", "right_hand"), + ("arm", "hand"), + ] + + # Configure logging + logging.basicConfig(level=logging.INFO) + + # Name of the base link for the robot + self.base_link_name = "base_link" + + # Initialize the URDF file writer for output formatting + self.file_writer = URDFFileWriter() + + # Initialize signature manager instead of cache manager + self.signature_manager = URDFAssemblySignatureManager() + + def add_component( + self, + component_type: str, + urdf_path: Union[str, Path], + transform: Optional[np.ndarray] = None, + **params, + ) -> bool: + r"""Add a URDF component to the component registry. + + This method creates a URDFComponent object and registers it in the component registry. + + Args: + component_type (str): The type/name of the component (e.g., 'chassis', 'head'). + urdf_path (str or Path): Path to the URDF file for this component. + transform (np.ndarray, optional): 4x4 transformation matrix for positioning the component. + **params: Additional component-specific parameters (e.g., wheel_type for chassis). + + Returns: + bool: True if component added successfully, False otherwise. + """ + try: + if not isinstance(component_type, str): + raise ValueError("component_type must be a string") + if not isinstance(urdf_path, (str, Path)): + raise ValueError("urdf_path must be a string or Path") + + component = URDFComponent( + urdf_path=urdf_path, params=params, transform=transform + ) + self.component_registry.add(component_type, component) + self.logger.info( + f"Added component: [{component_type}], URDF: ({urdf_path})" + ) + return True + except Exception as e: + self.logger.error(f"Failed to add component [{component_type}]: {e}") + return False + + def attach_sensor( + self, + sensor_name: str, + sensor_source, + parent_component: str, + parent_link: str, + transform: Optional[np.ndarray] = None, + **kwargs, + ) -> bool: + r"""Attach a sensor to a specific component and link, and register it in the sensor registry. + + This method creates a SensorAttachment object and registers it in the sensor registry. + + Args: + sensor_name (str): Unique name for the sensor (e.g., 'camera'). + sensor_source (str or ET.Element): Path to the sensor's URDF file or an XML element. + parent_component (str): Name of the component to which the sensor is attached. + parent_link (str): Name of the link within the parent component for attachment. + **kwargs: Additional keyword arguments (e.g., transform, sensor_type). + + Returns: + bool: True if sensor attached successfully, False otherwise. + """ + try: + sensor = SensorAttachment( + sensor_urdf=sensor_source, + parent_component=parent_component, + parent_link=parent_link, + transform=transform, + **kwargs, + ) + self.sensor_registry.add(sensor_name, sensor) + urdf_info = ( + f"\n\tURDF: ({sensor.sensor_urdf})" + if sensor.sensor_urdf + else ", URDF: [N/A]" + ) + self.logger.info( + f"Attached sensor: [{sensor_name}] " + f"to [{parent_component}] at link [{parent_link}]{urdf_info}" + ) + return True + except Exception as e: + self.logger.error(f"Failed to attach sensor [{sensor_name}]: {e}") + return False + + def get_component(self, component_type: str): + r"""Retrieve a component from the registry by its type/name. + + Args: + component_type (str): The type/name of the component to retrieve. + + Returns: + URDFComponent or None: The registered component object, or None if not found. + """ + return self.component_registry.get(component_type) + + def get_attached_sensors(self): + r"""Get all attached sensors from the sensor registry. + + Returns: + dict: A dictionary mapping sensor names to SensorAttachment objects. + """ + return self.sensor_registry.all() + + def _load_urdf(self, urdf_path: str) -> Optional[ET.Element]: + r"""Load a URDF file and return its root element. + + Args: + urdf_path (str): Path to the URDF file. + + Returns: + ET.Element: The root element of the parsed URDF XML. + """ + try: + tree = ET.parse(urdf_path) + return tree.getroot() + except Exception as e: + self.logger.error(f"Failed to load URDF {urdf_path}: {e}") + return None + + def _apply_transformation( + self, urdf: ET.Element, transform: np.ndarray, link_name: str + ): + r"""Applies a transformation matrix to the 'xyz' attributes of the origins of the specified link and its first joint in the URDF. + + Args: + urdf (ET.Element): The root element of the URDF to transform. + transform (np.ndarray): A 4x4 transformation matrix to apply. + link_name (str): The name of the link to apply the transformation to. + """ + # Now handle the first joint connected to this link + for joint in urdf.findall("joint"): + origin = joint.find("origin") + if origin is not None: + # Check if the joint connects to the specified link + child_link = joint.find("child").get("link") + if child_link == link_name: + xyz = np.array([float(val) for val in origin.get("xyz").split()]) + transformed_xyz = np.dot(transform[:3, :3], xyz) + transform[:3, 3] + origin.set("xyz", " ".join(map(str, transformed_xyz))) + + # Apply transformation to rpy + if "rpy" in origin.attrib: + rpy = np.array( + [float(val) for val in origin.get("rpy").split()] + ) + rotation = R.from_euler("xyz", rpy) + transformed_rotation = ( + R.from_matrix(transform[:3, :3]) * rotation + ) + transformed_rpy = transformed_rotation.as_euler("xyz") + origin.set("rpy", " ".join(map(str, transformed_rpy))) + elif "quat" in origin.attrib: + quat = np.array( + [float(val) for val in origin.get("quat").split()] + ) + rotation = R.from_euler("xyz", quat) + transformed_rotation = ( + R.from_matrix(transform[:3, :3]) * rotation + ) + transformed_rpy = transformed_rotation.as_euler("xyz") + origin.set("rpy", " ".join(map(str, transformed_rpy))) + + break # Stop after processing the first joint + + def _create_base_link(self) -> ET.Element: + r"""Creates a base link and returns it. + + Returns: + ET.Element: The base link element. + """ + base_link = ET.Element("link", name=self.base_link_name) + + return base_link + + def _validate_urdf_file(self, urdf_path: str) -> bool: + r"""Validate URDF file integrity and format compliance + + Args: + urdf_path (str): Path to the URDF file to validate + + Returns: + bool: True if file is valid, False otherwise + """ + try: + # Check if file exists + if not os.path.exists(urdf_path): + self.logger.error(f"URDF file not found: {urdf_path}") + return False + + # Check file size to ensure it's not empty + if os.path.getsize(urdf_path) == 0: + self.logger.error(f"URDF file is empty: {urdf_path}") + return False + + # Attempt to parse XML structure + root = ET.parse(urdf_path).getroot() + if root.tag != "robot": + self.logger.error(f"Invalid URDF root element: {root.tag}") + return False + + # Check for presence of basic link elements + if not root.findall("link"): + self.logger.error(f"No links found in URDF: {urdf_path}") + return False + + # Check robot name attribute + robot_name = root.get("name") + if not robot_name: + self.logger.warning(f"URDF robot has no name attribute: {urdf_path}") + + self.logger.debug(f"URDF file validation passed: {urdf_path}") + return True + + except ET.ParseError as e: + self.logger.error(f"XML parse error in {urdf_path}: {e}") + return False + except Exception as e: + self.logger.error(f"Validation error for {urdf_path}: {e}") + return False + + def _generate_connection_rules(self) -> list: + r"""Dynamically generate connection rules based on available components. + + Returns: + list: A list of (parent, child) tuples specifying connection relationships. + """ + connection_rules = [] + + # Filter components that exist in urdf_dict + existing_components = [ + comp + for comp in self.SUPPORTED_COMPONENTS + if self.component_registry.get(comp) + ] + + self.logger.debug(f"Existing components: {existing_components}") + + # Define explicit connection rules - only meaningful relationships + # Rule 1: chassis connects to torso (if both exist) + if "chassis" in existing_components and "legs" in existing_components: + connection_rules.append(("chassis", "legs")) + if "torso" in existing_components: + connection_rules.append(("legs", "torso")) + elif "chassis" in existing_components and "torso" in existing_components: + # If there are no legs, chassis connects directly to torso + connection_rules.append(("chassis", "torso")) + + # Rule 2: torso connects to head (if both exist) + if "torso" in existing_components and "head" in existing_components: + connection_rules.append(("torso", "head")) + + # Rule 3: torso connects to arms (if they exist) + if "torso" in existing_components: + if "left_arm" in existing_components: + connection_rules.append(("torso", "left_arm")) + if "right_arm" in existing_components: + connection_rules.append(("torso", "right_arm")) + if "arm" in existing_components: + connection_rules.append(("torso", "arm")) + + # Rule 4: arms connect to hands (if both exist) + if "left_arm" in existing_components and "left_hand" in existing_components: + connection_rules.append(("left_arm", "left_hand")) + if "right_arm" in existing_components and "right_hand" in existing_components: + connection_rules.append(("right_arm", "right_hand")) + + # Rule 5: single arm connects to hand + if "arm" in existing_components and "hand" in existing_components: + connection_rules.append(("arm", "hand")) + + # Rule 6: If no torso, chassis can directly connect to head and arms + if "chassis" in existing_components and "torso" not in existing_components: + if "head" in existing_components: + connection_rules.append(("chassis", "head")) + if "left_arm" in existing_components: + connection_rules.append(("chassis", "left_arm")) + if "right_arm" in existing_components: + connection_rules.append(("chassis", "right_arm")) + # Connect single arm directly to chassis (no torso scenario) + if "arm" in existing_components: + connection_rules.append(("chassis", "arm")) + + connection_rules = list(set(connection_rules)) + + self.logger.info( + f"Generated connection rules: {connection_rules}, total {len(connection_rules)} rules" + ) + + return connection_rules + + def _find_end_link( + self, component: str, base_points: dict, joints: list + ) -> Union[str, None]: + """Find the end link of a component by traversing the joint chain downward. + + Args: + component (str): Component name to find the end link for. + base_points (dict): Mapping from component names to their base link names. + joints (list): List of joint elements to traverse. + + Returns: + Union[str, None]: Name of the end link, or None if component not found. + """ + current_link = base_points.get(component) + if not current_link: + return None + + visited_links = set() # Prevent infinite loops in joint chains + while True: + visited_links.add(current_link) + found = False + for joint in joints: + if hasattr(joint, "find"): # Ensure it's an XML element, not a comment + parent = joint.find("parent") + child = joint.find("child") + if parent is not None and parent.get("link") == current_link: + if child is not None: + next_link = child.get("link") + if next_link not in visited_links: # Avoid revisiting links + current_link = next_link + found = True + break + if not found: + break # No further links found in the chain + return current_link + + @performance_monitor + def merge_urdfs( + self, + output_path: str = "./assembly_robot.urdf", + use_signature_check: bool = True, + ) -> ET.Element: + """Merge URDF files according to single base link, connection point naming, + and type compatibility matrix rules. + + Args: + output_path (str): Path where the merged URDF file will be saved. + use_signature_check (bool): Whether to check signatures to avoid redundant processing. + + Returns: + ET.Element: The root element of the merged URDF. + """ + output_path = os.path.abspath(output_path) + assembly_signature = None + + # Log components to be merged + available_components = [ + comp + for comp, obj in self.component_registry.all().items() + if obj is not None + ] + self.logger.info(f"🔧 Preparing to merge components: {available_components}") + + for comp in available_components: + comp_obj = self.component_registry.get(comp) + self.logger.info(f" [{comp}]: {comp_obj.urdf_path}") + if comp_obj.params: + self.logger.debug(f" Parameters: {comp_obj.params}") + if comp_obj.transform is not None: + self.logger.debug(f" Transform: applied") + + if use_signature_check: + # Calculate current assembly signature + assembly_signature = self.signature_manager.calculate_assembly_signature( + self.component_registry.all(), output_path + ) + + self.logger.info(f"Current assembly signature: [{assembly_signature}]") + self.logger.debug(f"Target output path: ({output_path})") + + # Check if assembly is up-to-date + if self.signature_manager.is_assembly_up_to_date( + assembly_signature, output_path + ): + self.logger.info( + f"✅ URDF assembly is up-to-date: ({output_path}), skipping rebuild." + ) + return ET.parse(output_path).getroot() + else: + self.logger.info( + "Assembly configuration has changed or file doesn't exist, rebuilding..." + ) + + # Perform normal assembly process + self.logger.info("🔄 Building new URDF assembly...") + + # 1. Generate standard header with module information + module_names = [ + os.path.splitext(os.path.basename(obj.urdf_path))[0] + for comp, obj in self.component_registry.all().items() + if obj + ] + + robot_name = os.path.splitext(os.path.basename(output_path))[0] + merged_urdf = ET.Element("robot", name=robot_name) + + # 2. Create single base link for the entire robot + base_link = ET.Element("link", name=self.base_link_name) + # Store links and joints separately for proper ordering + links = [base_link] + joints = [] + + # Mapping tables for component processing + name_mapping = {} # Maps (component, original_name) to new_name + base_points = {} # Maps component to its base connection link + parent_attach_points = {} # Maps component to its parent connection link + + # Initialize managers for mesh handling and component processing + output_dir = os.path.dirname(output_path) or "." + ensure_directory_exists(output_dir, self.logger) + mesh_manager = URDFMeshManager(output_dir) + mesh_manager.ensure_dirs() + component_manager = URDFComponentManager(mesh_manager) + connection_manager = URDFConnectionManager(self.base_link_name) + + # Initialize sensor manager with mesh_manager + sensor_manager = URDFSensorManager(mesh_manager) + + # Process any pending enhanced sensors + if hasattr(self, "_pending_sensors"): + for sensor_name, params in self._pending_sensors.items(): + success = sensor_manager.attach_sensor( + sensor_name=sensor_name, **params + ) + if success: + # Sync to legacy attach_dict for backward compatibility + self.attach_dict.update(sensor_manager.convert_to_legacy_format()) + + # 3. Process all components in defined order + connection_rules = self._generate_connection_rules() + + # Collect component transforms for connection joints + component_transforms = {} + for comp, comp_obj in self.component_registry.all().items(): + if comp_obj and comp_obj.transform is not None: + component_transforms[comp] = comp_obj.transform + + for comp, prefix in self.component_order: + comp_obj = self.component_registry.get(comp) + if not comp_obj: + continue + + # Add section comments using file writer + self.file_writer.add_section_comments(links, comp, "Links") + self.file_writer.add_section_comments(joints, comp, "Joints") + + # Parse component URDF to analyze its structure + urdf_root = ET.parse(comp_obj.urdf_path).getroot() + + # Determine parent component and attachment point for current component + parent_component = None + parent_attach_link = None + + # Find parent component based on connection rules + for parent, child in connection_rules: + if child == comp and parent in base_points: + parent_component = parent + # Use base connection point for chassis + if parent == "chassis": + parent_attach_link = base_points[parent] + else: + # For other components, find their end link + parent_attach_link = self._find_end_link( + parent, base_points, joints + ) + break + + if parent_component and parent_attach_link: + self.logger.debug( + f"Component [{comp}] will connect to parent [{parent_component}] at link: ({parent_attach_link})" + ) + else: + self.logger.debug( + f"Component [{comp}] has no parent component (likely chassis or standalone)" + ) + + # Process the component using the component manager + component_manager.process_component( + comp, prefix, comp_obj, name_mapping, base_points, links, joints + ) + + # Determine attachment positions for current component + original_links = urdf_root.findall("link") + + if original_links: + # Set base connection point (always first link for child connections) + first_original_name = original_links[0].get("name") + first_mapped_name = name_mapping.get( + (comp, first_original_name), first_original_name + ) + base_points[comp] = first_mapped_name + + self.logger.debug( + f"Set base_points[{comp}] = ({first_mapped_name}) .first link for child connection, original: ({first_original_name})" + ) + + # Set parent connection point based on attach_positions configuration + index = self.attach_positions.get(comp, 0) + try: + if 0 <= index < len(original_links): + original_attach_name = original_links[index].get("name") + elif index == -1 and original_links: + original_attach_name = original_links[-1].get("name") + else: + original_attach_name = ( + original_links[0].get("name") if original_links else None + ) + + # Find mapped name for the attachment point + mapped_attach_name = name_mapping.get( + (comp, original_attach_name), original_attach_name + ) + parent_attach_points[comp] = mapped_attach_name + + self.logger.debug( + f"Set parent_attach_points[{comp}] = ({mapped_attach_name}). Index {index} for parent connection, original: ({original_attach_name})" + ) + except IndexError: + # Fall back to first link if index is out of range + parent_attach_points[comp] = first_mapped_name + self.logger.warning( + f"Index {index} out of range for component {comp}, using first link: {first_mapped_name}" + ) + + # Add section end comments using file writer + self.file_writer.add_section_end_comments(links, comp, "Links") + self.file_writer.add_section_end_comments(joints, comp, "Joints") + + # 4. Create connection joints between components using transforms + connection_manager.add_connections( + joints, + base_points, + parent_attach_points, + connection_rules, + component_transforms, + ) + + # Track existing names for sensor processing + existing_link_names = { + link.get("name").lower() for link in links if link.get("name") + } + existing_joint_names = { + joint.get("name").upper() for joint in joints if joint.get("name") + } + + # 5. Process sensor attachments using the new sensor manager + for sensor_name, sensor_attach in self.sensor_registry.all().items(): + sensor_manager.attach_sensor( + sensor_name=sensor_name, + sensor_source=sensor_attach.sensor_urdf, + parent_component=sensor_attach.parent_component, + parent_link=sensor_attach.parent_link, + transform=sensor_attach.transform, + ) + + sensor_manager.process_sensor_attachments( + links, joints, base_points, existing_link_names, existing_joint_names + ) + + # 6. Add all links and joints to merged URDF in proper order + for link in links: + merged_urdf.append(link) + for joint in joints: + merged_urdf.append(joint) + + # 7. Write the final URDF file with proper formatting, header and signature + if use_signature_check and assembly_signature: + self.file_writer.write_urdf( + merged_urdf, output_path, module_names, assembly_signature + ) + self.logger.info( + f"✅ URDF assembly written with signature: {assembly_signature}" + ) + else: + self.file_writer.write_urdf(merged_urdf, output_path, module_names) + self.logger.info("✅ URDF assembly written without signature.") + return merged_urdf diff --git a/embodichain/toolkits/urdf_assembly/utils.py b/embodichain/toolkits/urdf_assembly/utils.py new file mode 100644 index 00000000..68ed896c --- /dev/null +++ b/embodichain/toolkits/urdf_assembly/utils.py @@ -0,0 +1,30 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from pathlib import Path +import logging + + +def ensure_directory_exists(path: str, logger: logging.Logger = None): + """Ensure the directory exists, create if not.""" + try: + path_obj = Path(path) + path_obj.mkdir(parents=True, exist_ok=True) + except Exception as e: + if logger: + logger.error(f"Failed to create directory {path}: {e}") + else: + print(f"Failed to create directory {path}: {e}") diff --git a/embodichain/utils/__init__.py b/embodichain/utils/__init__.py new file mode 100644 index 00000000..f30c7bcc --- /dev/null +++ b/embodichain/utils/__init__.py @@ -0,0 +1,59 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .configclass import configclass, is_configclass + + +GLOBAL_SEED = 1024 + + +def set_seed(seed: int, deterministic: bool = False) -> int: + """Set the random seed for reproducibility. + + Args: + seed (int): The seed value to set. If -1, a random seed will be generated. + deterministic (bool): If True, sets the environment to deterministic mode for reproducibility. + """ + import random + import numpy as np + import torch + import os + import warp as wp + + if seed == -1 and deterministic: + seed = GLOBAL_SEED + elif seed == -1: + seed = np.random.randint(0, 10000) + + random.seed(seed) + np.random.seed(seed) + torch.manual_seed(seed) + os.environ["PYTHONHASHSEED"] = str(seed) + torch.cuda.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + wp.rand_init(seed) + + if deterministic: + # refer to https://docs.nvidia.com/cuda/cublas/index.html#cublasApi_reproducibility + os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8" + torch.backends.cudnn.benchmark = False + torch.backends.cudnn.deterministic = True + torch.use_deterministic_algorithms(True) + else: + torch.backends.cudnn.benchmark = True + torch.backends.cudnn.deterministic = False + + return seed diff --git a/embodichain/utils/cfg.py b/embodichain/utils/cfg.py new file mode 100644 index 00000000..47faa48b --- /dev/null +++ b/embodichain/utils/cfg.py @@ -0,0 +1,598 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +import functools +import inspect +import logging + +from copy import deepcopy +from pathlib import Path +from typing import Dict, List, Optional, Union + +from fvcore.common.config import BASE_KEY +from fvcore.common.config import CfgNode as _CfgNode +from iopath.common.file_io import PathManager as PathManagerBase +from yacs.config import _VALID_TYPES, _assert_with_logging + +sep = "." +prefix = "" +PathManager = PathManagerBase() +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) + + +def _flatten_dict( + src: Dict, + prefix: Optional[str] = prefix, + sep: Optional[str] = sep, + dct: Optional[Dict] = {}, +) -> Dict: + """Traverse a dictionary and return all keys including nested ones. + + Args: + src (Dict): an instance of :class:`Dict`. + prefix (Optional[str], optional): [description]. Defaults to prefix. + sep (Optional[str], optional): [description]. Defaults to sep. + dct (Optional[Dict], optional): [description]. Defaults to {}. + + Returns: + Dict: flatten dictionary with all keys. + """ + items = [] + for k, v in src.items(): + new_key = prefix + sep + k if prefix else k + if isinstance(v, dict): + items.extend(_flatten_dict(v, new_key, sep=sep).items()) + else: + items.append((new_key, v)) + return dict(items) + + +def _dict_depth(d: Dict | CfgNode) -> int: + """Calculate the maximal depth of dictionary + + Args: + d (Dict): an instance of :class:`Dict`. + + Returns: + int: maximal depth. + """ + if isinstance(d, dict): + # 如果d是空dict就直接给0 + return 1 + (max(map(_dict_depth, d.values())) if d else 0) + # return 1 + (max(map(_dict_depth, d.values())) if d else 0) + else: + return 0 + # 无限递归最后肯定不是dict,也就是说肯定会raise error,这是不合理的 + # TypeError("Expected type is dict but {} is received".format( + # type(d).__name__)) + + +# NOTE: given the new config system +# (https://detectron2.readthedocs.io/en/latest/tutorials/lazyconfigs.html), +# they will stop adding new functionalities to default CfgNode. + + +# NOTE: maybe someday one require save config orderly, I have tried and find it not easy. +# there is a method making yaml.load() output ordered dict: https://tendcode.com/article/yaml_order/ , +# but yacs.config.CfgNode is a subclass of :class:`Dict`, so it may hard to make a dict +# subclass has ordered key when initialize. +class CfgNode(_CfgNode): + # counter records user visits of every attributes and is used in self.unvisited_keys() + COUNTER = "__COUNTER__" + CACHED_NAMES = "__CACHED_NAMES__" + + def __init__(self, init_dict=None, key_list=None, new_allowed=False): + """ + Args: + init_dict (dict): the possibly-nested dictionary to initailize the CfgNode. + key_list (list[str]): a list of names which index this CfgNode from the root. + Currently only used for logging purposes. + new_allowed (bool): whether adding new key is allowed when merging with + other configs. + """ + super(CfgNode, self).__init__(init_dict) + # when self.load_cfg_from_file(), it consequently goes to cls(cfg_as_dict), where `init_dict` is not None + # counter dict only contain flattened leaf node of a CfgNode rather than direct child node, + # for example, counter dict of node + # TOPKEYA: + # KEYA: "value1" + # KEYB: + # SUBKEYA: 1000 + # SUBKEYB: 2000 + # has key ['TOPKEYA.KEYA', 'TOPKEYA.KEYB.SUBKEYA', 'TOPKEYA.KEYB.SUBKEYB'], but has no 'TOPKEYA' or 'TOPKEA.KEYB', + # and the counter dict of node TOPKEYA has key ['KEYA', 'KEYB.SUBKEYA', 'KEYB.SUBKEYB'], but has no 'KEYB'. + if init_dict is not None: + self.__dict__[CfgNode.COUNTER] = _flatten_dict(init_dict) + for key in self.__dict__[CfgNode.COUNTER].keys(): + self.__dict__[CfgNode.COUNTER][key] = 0 + else: + self.__dict__[CfgNode.COUNTER] = {} + self.__dict__[CfgNode.CACHED_NAMES] = [] + + self.set_new_allowed(new_allowed) + + def __getattr__(self, name): + if name in self: + self.__dict__[CfgNode.CACHED_NAMES].append(name) + concated_name = sep.join(self.__dict__[CfgNode.CACHED_NAMES]) + if concated_name in self.__dict__[CfgNode.COUNTER]: + # only parent node of leaf CfgNode can reach here, and top level node can't + self.__dict__[CfgNode.COUNTER][concated_name] += 1 + self.__dict__[CfgNode.CACHED_NAMES] = [] + return self[name] + else: + raise AttributeError(name) + + # TODO: overload __setattr__ to use `new_allowed` to avoid user manually add key by `cfg["key"]=value`. + # Or is it necessary to do that? Because neither yacs and detectron2 make this feature. + + # TODO: When adding a new key, COUNTER does not contain an entry for the newly added key + + @classmethod + def _open_cfg(cls, filename): + return PathManager.open(filename, "r", encoding="utf-8") + + @classmethod + def load_cfg_from_file( + cls, + filename_or_str_content: Union[str, Path], + new_allowed: bool = True, + root_path: str = None, + ) -> CfgNode: + """load configration from a yaml file. + Modified from function load_yaml_with_base() of fvcore.common.config.CfgNode. + The original one do not support `NEW_ALLOWED` key, but I think sometime it will + be needed, so we had better add it. + + Args: + filename_or_str_content (Union[str, Path]): a yaml filename or yaml content string + new_allowed (bool): whether adding new key is allowed when merging with + other configs. + root_path (str): Parent directory of `_BASE_` config. Usually _BASE_ is written + as a relative path, the result will change if the path executing command change, + and we directly use `root_path` as the actual parent directory of `_BASE_` config file + to avoid this confusion. + + Returns: + cfg: a :class:`CfgNode` instance. + """ + is_file = PathManager.isfile(filename_or_str_content) + if len(str(filename_or_str_content)) < 256 and str( + filename_or_str_content + ).endswith(".yaml"): + # We assume if input is a yaml file path, it will not longer than 256 + # and it should ends with '.yaml' + if is_file: + with cls._open_cfg(filename_or_str_content) as file: + # load_cfg use yaml.safe_load() to prevent malicious code (see https://zhuanlan.zhihu.com/p/54332357); + # fvcore supports yaml.unsafe_load(), but I don't see any code use it both in detectron2 and fvcore, + # so I think use original load_cfg() in yacs is enough. + cfg = cls.load_cfg(file) + else: + msg = ( + f"CfgNode: Input string: '{filename_or_str_content}' looks like" + " a yaml file path, but the file is not found on disk!" + ) + logger.error(msg) + raise FileNotFoundError(msg) + else: + # Otherwise the input is a yaml-format string + cfg = cls.load_cfg(filename_or_str_content) + + if root_path is not None and hasattr(cfg, "_BASE_"): + path = Path(root_path) / cfg._BASE_ + if not path.exists(): + raise ValueError("Path {} does not exist.".format(path)) + cfg._BASE_ = str(path) + + def _load_with_base(base_cfg_file: str) -> CfgNode: + if base_cfg_file.startswith("~"): + base_cfg_file = Path(base_cfg_file).expanduser() + if not any(map(base_cfg_file.startswith, ["/", "https://", "http://"])): + if is_file: + # the path to base cfg is relative to the config file itself. + base_cfg_file = Path(filename_or_str_content).parent / base_cfg_file + return cls.load_cfg_from_file(base_cfg_file, new_allowed=new_allowed) + + if BASE_KEY in cfg: + if isinstance(cfg[BASE_KEY], list): + base_cfg = cls(new_allowed=new_allowed) + base_cfg_files = cfg[BASE_KEY] + # NOTE: `new_allowed` of the new added key is default False, so after a "new_allowed" merge new keys from other config, + # the new key is not `new_allowed`, which is unreasonable, so we manually update `new_allowed` of merged new keys + for base_cfg_file in base_cfg_files: + base_cfg.merge_from_other_cfg(_load_with_base(base_cfg_file)) + base_cfg.set_new_allowed(new_allowed) + else: + base_cfg_file = cfg[BASE_KEY] + base_cfg = _load_with_base(base_cfg_file) + del cfg[BASE_KEY] + + base_cfg.merge_from_other_cfg(cfg) + return base_cfg + + cfg.set_new_allowed(new_allowed) + return cfg + + def merge_from_other_cfg(self, cfg_other): + """Merge `cfg_other` into this CfgNode.""" + _merge_a_into_b(cfg_other, self, self, []) + other_counter = cfg_other.__dict__[CfgNode.COUNTER] + self.__dict__[CfgNode.COUNTER] = { + **self.__dict__[CfgNode.COUNTER], + **other_counter, + } + + def dict(self): + # NOTE: Without deepcopy, if value is a list, cfg.dict() will use a shallow copy of this list, + # then change this list of cfg.dict() will lead to unexpected changeing of original cfg + result = {} + for key, value in deepcopy(self).items(): + if isinstance(value, CfgNode): + result[key] = value.dict() + else: + result[key] = value + + return result + + def diff(self, other: CfgNode): + """Show the difference between self and other `CfgNode`, helping user + find Help users quickly identify the difference between them. + + Args: + other (CfgNode): Another `CfgNode`. + + Returns: + DeepDiff: A class containing difference, include adding, deleting and modifing. + """ + from deepdiff import DeepDiff + + return DeepDiff(self, other) + + def dump(self, *args, **kwargs): + """ + At present dump() can only ensure original CfgNode == the one after dump and reload, + but can not ensure the order of their keys is consistent. + + Returns: + str: a yaml string representation of the config + """ + # to make it show up in docs + return super().dump(*args, **kwargs) + + def save(self, filepath): + with open(filepath, "w", encoding="utf-8") as fp: + # set sort_key=False to keep writing order the same as original + # input file rather than ordered by alphabetically; + # set default_flow_style=None to keep list element written in one line + # allow_unicode=True to support Chinese input + self.dump( + stream=fp, sort_keys=False, default_flow_style=None, allow_unicode=True + ) + + def depth(self): + return _dict_depth(self) + + def unvisited_keys(self, inverse: Optional[bool] = False) -> List[str]: + """Return all unvisited keys. + + Args: + inverse (Optional[bool], optional): return all visited keys if `inverse` is True. Defaults to False. + + Returns: + List[str]: list of all unvisited/visited keys. + """ + self.__update_counter(self) + condition = lambda x: x == 0 if not inverse else x > 0 + return [ + key + for key, value in self.__dict__[CfgNode.COUNTER].items() + if condition(value) + ] + + def __update_counter(self, root: CfgNode, prefix=""): + """Internal methods to recursively update counter for each keys. + + Args: + root (CfgNode): Parent node of current CfgNode. + prefix (str, optional): Concatenation of parent, grandparent and so on. + For root CfgNode `prefix` is "", for a SUBKEY `prefix` may be "TOPKEYA.KEYB". + """ + for key, kid_node in self.items(): + new_key = prefix + sep + key if prefix else key + if isinstance(kid_node, dict) and _dict_depth(kid_node) > 0: + kid_node.__update_counter(root, new_key) + else: + # a new_key of value "TOPKEYA.KEYB.SUBKEYA" lead to a1 slice_key + # of value "['KEYB.SUBKEYA', 'TOPKEYA.KEYB.SUBKEYA']", which contain all parent keys + sliced_keys = [ + ".".join(new_key.split(".")[-k:]) + for k in range(2, 1 + len(new_key.split("."))) + ] + # `self` is the father of `key`, and `root` is the father of `self` + for root_key in root.__dict__[CfgNode.COUNTER].keys(): + matched = any( + [sliced_key in root_key for sliced_key in sliced_keys] + ) + if matched: + root.__dict__[CfgNode.COUNTER][root_key] = self.__dict__[ + CfgNode.COUNTER + ][key] + + +def _check_and_coerce_cfg_value_type(replacement, original, key, full_key): + """Checks that `replacement`, which is intended to replace `original` is of + the right type. The type is correct if it matches exactly or is one of a few + cases in which the type can be easily coerced. + """ + original_type = type(original) + replacement_type = type(replacement) + + # The types must match (with some exceptions) + if replacement_type == original_type or issubclass(original_type, replacement_type): + return replacement + + # If either of them is None, allow type conversion to one of the valid types + if (replacement_type == type(None) and original_type in _VALID_TYPES) or ( + original_type == type(None) and replacement_type in _VALID_TYPES + ): + return replacement + + # Cast replacement from from_type to to_type if the replacement and original + # types match from_type and to_type + def conditional_cast(from_type, to_type): + if replacement_type == from_type and original_type == to_type: + return True, to_type(replacement) + else: + return False, None + + # Conditionally casts + # list <-> tuple + casts = [(tuple, list), (list, tuple)] + # For py2: allow converting from str (bytes) to a unicode string + try: + casts.append((str, unicode)) # noqa: F821 + except Exception: + pass + + for from_type, to_type in casts: + converted, converted_value = conditional_cast(from_type, to_type) + if converted: + return converted_value + + raise ValueError( + f"Key type mismatchs during merging config! Key: {full_key}, original: {original} of type {original_type}, new: {replacement} of type {replacement_type}." + ) + + +def _merge_a_into_b(a, b, root, key_list): + """Merge config dictionary a into config dictionary b, clobbering the + options in b whenever they are also specified in a. + """ + _assert_with_logging( + isinstance(a, CfgNode), + "`a` (cur type {}) must be an instance of {}".format(type(a), CfgNode), + ) + _assert_with_logging( + isinstance(b, CfgNode), + "`b` (cur type {}) must be an instance of {}".format(type(b), CfgNode), + ) + + for k, v_ in a.items(): + full_key = ".".join(key_list + [k]) + + v = deepcopy(v_) + v = b._decode_cfg_value(v) + + if k in b: + v = _check_and_coerce_cfg_value_type(v, b[k], k, full_key) + # Recursively merge dicts + if isinstance(v, CfgNode): + try: + _merge_a_into_b(v, b[k], root, key_list + [k]) + except BaseException: + raise + else: + b[k] = v + elif b.is_new_allowed() or isinstance(b, MutableCfgNode): + b[k] = v + else: + if root.key_is_deprecated(full_key): + continue + elif root.key_is_renamed(full_key): + root.raise_key_rename_error(full_key) + else: + raise KeyError("Non-existent config key: {}".format(full_key)) + + +class MutableCfgNode(CfgNode): + def __init__(self, init_dict=None, key_list=None, new_allowed=False): + super().__init__(init_dict, key_list, new_allowed) + self.set_new_allowed(new_allowed) + + +def _get_args_from_config(from_config_func, *args, **kwargs): + """ + Use `from_config` to obtain explicit arguments. + Returns: + dict: arguments to be used for cls.__init__ + """ + # inspect.signature() obtains parameter list of function, such as (a, b=0, *c, d, e=1, **f) + signature = inspect.signature(from_config_func) + # cfg should be passed as the first parameter, whether it is a positional or keyword argument + if list(signature.parameters.keys())[0] != "cfg": + if inspect.isfunction(from_config_func): + name = from_config_func.__name__ + else: + name = f"{from_config_func.__self__}.from_config" + raise TypeError(f"{name} must take 'cfg' as the first argument!") + support_var_arg = any( + param.kind in [param.VAR_POSITIONAL, param.VAR_KEYWORD] + for param in signature.parameters.values() + ) + if ( + support_var_arg + ): # forward all arguments to from_config, if from_config accepts them + ret = from_config_func(*args, **kwargs) + else: + # forward supported arguments to from_config + supported_arg_names = set(signature.parameters.keys()) + extra_kwargs = {} + for name in list(kwargs.keys()): + if name not in supported_arg_names: + extra_kwargs[name] = kwargs.pop(name) + ret = from_config_func(*args, **kwargs) + # forward the other arguments to __init__ + ret.update(extra_kwargs) + return ret + + +def _called_with_cfg(*args, **kwargs): + """ + Returns: + bool: whether the arguments contain CfgNode and should be considered + forwarded to from_config. + """ + from omegaconf import DictConfig + + if len(args) and isinstance(args[0], (_CfgNode, DictConfig)): + return True + if isinstance(kwargs.pop("cfg", None), (_CfgNode, DictConfig)): + return True + # `from_config`'s first argument is forced to be "cfg". + # So the above check covers all cases. + return False + + +def configurable(init_func=None, *, from_config=None): + """ + Decorate a function or a class's method so that it can be called + with a :class:`CfgNode` object using a :func:`from_config` function that translates + :class:`CfgNode` to arguments. + Examples: + :: + # Usage 1: Decorator on __init__: + class A: + @configurable + def __init__(self, a, b=2, c=3): + pass + @classmethod + def from_config(cls, cfg): # 'cfg' must be the first argument + # Returns kwargs to be passed to __init__ + return {"a": cfg.A, "b": cfg.B} + a1 = A(a=1, b=2) # regular construction + a2 = A(cfg) # construct with a cfg + a3 = A(cfg, b=3, c=4) # construct with extra overwrite + + # Usage 2: Decorator on any function. Needs an extra from_config argument: + @configurable(from_config=lambda cfg: {"a": cfg.A, "b": cfg.B}) + def a_func(a, b=2, c=3): + pass + a1 = a_func(a=1, b=2) # regular call + a2 = a_func(cfg) # call with a cfg + a3 = a_func(cfg, b=3, c=4) # call with extra overwrite + + # Usage 3: Decorator on any method of class. Needs an extra from_config argument: + class A: + @configurable(from_config=lambda cfg: {"a": cfg.A, "b": cfg.B}) + def a_func(self, a, b=2, c=3): + pass + insA = A() + cfg = CfgNode.load_cfg('{"A": "2", "B": "3"}') + a1 = insA.a_func(a=1, b=2) # regular call + a2 = insA.a_func(cfg) # call with a cfg + a3 = insA.a_func(cfg, b=3, c=4) # call with extra overwrite + + Args: + init_func (callable): a class's ``__init__`` method in usage 1. The + class must have a ``from_config`` classmethod which takes `cfg` as + the first argument. + from_config (callable): the from_config function in usage 2 and 3. It must take `cfg` + as its first argument. + """ + if init_func is not None: + assert ( + inspect.isfunction(init_func) + and from_config is None + and init_func.__name__ == "__init__" + ), "Incorrect use of @configurable. Check API documentation for examples." + + @functools.wraps(init_func) + def wrapped(self, *args, **kwargs): + try: + from_config_func = type(self).from_config + except AttributeError as e: + raise AttributeError( + "Class with @configurable must have a 'from_config' classmethod." + ) from e + if not inspect.ismethod(from_config_func): + raise TypeError( + "Class with @configurable must have a 'from_config' classmethod." + ) + + if _called_with_cfg(*args, **kwargs): + explicit_args = _get_args_from_config(from_config_func, *args, **kwargs) + init_func(self, **explicit_args) + else: + init_func(self, *args, **kwargs) + + return wrapped + + else: + if from_config is None: + return configurable # @configurable() is made equivalent to @configurable + assert inspect.isfunction( + from_config + ), "from_config argument of configurable must be a function!" + + def wrapper(orig_func): + params = inspect.signature(orig_func).parameters + if "self" in params or "cls" in params: # classmethod or instancemethod + + @functools.wraps(orig_func) + def wrapped( + self, *args, **kwargs + ): # here `self` means actual `self` or `cls` + if _called_with_cfg(*args, **kwargs): + explicit_args = _get_args_from_config( + from_config, *args, **kwargs + ) + return orig_func(self, **explicit_args) + else: + return orig_func(self, *args, **kwargs) + + wrapped.from_config = from_config + return wrapped + + else: # function or staticmethod + + @functools.wraps(orig_func) + def wrapped(*args, **kwargs): + if _called_with_cfg(*args, **kwargs): + explicit_args = _get_args_from_config( + from_config, *args, **kwargs + ) + return orig_func(**explicit_args) + else: + return orig_func(*args, **kwargs) + + wrapped.from_config = from_config + return wrapped + + return wrapper diff --git a/embodichain/utils/configclass.py b/embodichain/utils/configclass.py new file mode 100644 index 00000000..61727d60 --- /dev/null +++ b/embodichain/utils/configclass.py @@ -0,0 +1,616 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# All rights reserved. +# +# This file incorporates code from the Isaac Lab Project +# Copyright (c) 2022-2025, The Isaac Lab Project Developers +# (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# ---------------------------------------------------------------------------- + + +import torch +import inspect +import types +from collections.abc import Callable, Mapping, Iterable, Sized +from copy import deepcopy +from dataclasses import MISSING, Field, dataclass, field, replace +from typing import Any, ClassVar, Optional +from .string import callable_to_string, string_to_callable + + +_CONFIGCLASS_METHODS = ["to_dict", "replace", "copy", "validate"] +"""List of class methods added at runtime to dataclass.""" + +""" +Wrapper around dataclass. +""" + + +def __dataclass_transform__(): + """Add annotations decorator for PyLance.""" + return lambda a: a + + +def is_configclass(cls: Any) -> bool: + """Check if a class is a configclass. + + Args: + cls: The class to check. + + Returns: + True if the class is a configclass, False otherwise. + """ + return hasattr(cls, "validate") + + +@__dataclass_transform__() +def configclass(cls, **kwargs): + """Wrapper around `dataclass` functionality to add extra checks and utilities. + + As of Python 3.7, the standard dataclasses have two main issues which makes them non-generic for + configuration use-cases. These include: + + 1. Requiring a type annotation for all its members. + 2. Requiring explicit usage of :meth:`field(default_factory=...)` to reinitialize mutable variables. + + This function provides a decorator that wraps around Python's `dataclass`_ utility to deal with + the above two issues. It also provides additional helper functions for dictionary <-> class + conversion and easily copying class instances. + + Usage: + + .. code-block:: python + + from dataclasses import MISSING + + from isaaclab.utils.configclass import configclass + + + @configclass + class ViewerCfg: + eye: list = [7.5, 7.5, 7.5] # field missing on purpose + lookat: list = field(default_factory=[0.0, 0.0, 0.0]) + + + @configclass + class EnvCfg: + num_envs: int = MISSING + episode_length: int = 2000 + viewer: ViewerCfg = ViewerCfg() + + # create configuration instance + env_cfg = EnvCfg(num_envs=24) + + # print information as a dictionary + print(env_cfg.to_dict()) + + # create a copy of the configuration + env_cfg_copy = env_cfg.copy() + + # replace arbitrary fields using keyword arguments + env_cfg_copy = env_cfg_copy.replace(num_envs=32) + + Args: + cls: The class to wrap around. + **kwargs: Additional arguments to pass to :func:`dataclass`. + + Returns: + The wrapped class. + + .. _dataclass: https://docs.python.org/3/library/dataclasses.html + + Reference: + https://github.com/isaac-sim/IsaacLab/blob/main/source/isaaclab/isaaclab/utils/configclass.py + """ + # add type annotations + _add_annotation_types(cls) + # add field factory + _process_mutable_types(cls) + # copy mutable members + # note: we check if user defined __post_init__ function exists and augment it with our own + if hasattr(cls, "__post_init__"): + setattr( + cls, "__post_init__", combined_function(cls.__post_init__, custom_post_init) + ) + else: + setattr(cls, "__post_init__", custom_post_init) + # add helper functions for dictionary conversion + setattr(cls, "to_dict", class_to_dict) + # setattr(cls, "from_dict", update_class_from_dict) + setattr(cls, "replace", _replace_class_with_kwargs) + setattr(cls, "copy", _replace_class_with_kwargs) + setattr(cls, "validate", _validate) + # wrap around dataclass + cls = dataclass(cls, **kwargs) + # return wrapped class + return cls + + +def combined_function(f1: Callable, f2: Callable) -> Callable: + """Combine two functions into one. + + Args: + f1: The first function. + f2: The second function. + + Returns: + The combined function. + """ + + def _combined(*args, **kwargs): + # call both functions + f1(*args, **kwargs) + f2(*args, **kwargs) + + return _combined + + +def custom_post_init(obj): + """Deepcopy all elements to avoid shared memory issues for mutable objects in dataclasses initialization. + + This function is called explicitly instead of as a part of :func:`_process_mutable_types()` to prevent mapping + proxy type i.e. a read only proxy for mapping objects. The error is thrown when using hierarchical data-classes + for configuration. + """ + for key in dir(obj): + # skip dunder members + if key.startswith("__"): + continue + # get data member + value = getattr(obj, key) + # check annotation + ann = obj.__class__.__dict__.get(key) + # duplicate data members that are mutable + if not callable(value) and not isinstance(ann, property): + try: + setattr(obj, key, deepcopy(value)) + except AttributeError as e: + from IPython import embed + + embed() + + +def class_to_dict(obj: object) -> dict[str, Any]: + """Convert an object into dictionary recursively. + + Note: + Ignores all names starting with "__" (i.e. built-in methods). + + Args: + obj: An instance of a class to convert. + + Raises: + ValueError: When input argument is not an object. + + Returns: + Converted dictionary mapping. + """ + # check that input data is class instance + if not hasattr(obj, "__class__"): + raise ValueError(f"Expected a class instance. Received: {type(obj)}.") + # convert object to dictionary + if isinstance(obj, dict): + obj_dict = obj + elif isinstance(obj, torch.Tensor): + # We have to treat torch tensors specially because `torch.tensor.__dict__` returns an empty + # dict, which would mean that a torch.tensor would be stored as an empty dict. Instead we + # want to store it directly as the tensor. + return obj + elif hasattr(obj, "__dict__"): + obj_dict = obj.__dict__ + else: + return obj + + # convert to dictionary + data = dict() + for key, value in obj_dict.items(): + # disregard builtin attributes + if key.startswith("__"): + continue + # check if attribute is callable -- function + if callable(value): + data[key] = callable_to_string(value) + # check if attribute is a dictionary + elif hasattr(value, "__dict__") or isinstance(value, dict): + data[key] = class_to_dict(value) + # check if attribute is a list or tuple + elif isinstance(value, (list, tuple)): + data[key] = type(value)([class_to_dict(v) for v in value]) + else: + data[key] = value + return data + + +def update_class_from_dict(obj, data: dict[str, Any], _ns: str = "") -> None: + """Reads a dictionary and sets object variables recursively. + + This function performs in-place update of the class member attributes. + + Args: + obj: An instance of a class to update. + data: Input dictionary to update from. + _ns: Namespace of the current object. This is useful for nested configuration + classes or dictionaries. Defaults to "". + + Raises: + TypeError: When input is not a dictionary. + ValueError: When dictionary has a value that does not match default config type. + KeyError: When dictionary has a key that does not exist in the default config type. + """ + for key, value in data.items(): + # key_ns is the full namespace of the key + key_ns = _ns + "/" + key + + # -- A) if key is present in the object ------------------------------------ + if hasattr(obj, key) or (isinstance(obj, dict) and key in obj): + obj_mem = obj[key] if isinstance(obj, dict) else getattr(obj, key) + + # -- 1) nested mapping → recurse --------------------------- + if isinstance(value, Mapping): + # recursively call if it is a dictionary + update_class_from_dict(obj_mem, value, _ns=key_ns) + continue + + # -- 2) iterable (list / tuple / etc.) --------------------- + if isinstance(value, Iterable) and not isinstance(value, str): + + # ---- 2a) flat iterable → replace wholesale ---------- + if all(not isinstance(el, Mapping) for el in value): + out_val = tuple(value) if isinstance(obj_mem, tuple) else value + if isinstance(obj, dict): + obj[key] = out_val + else: + setattr(obj, key, out_val) + continue + + # ---- 2b) existing value is None → abort ------------- + if obj_mem is None: + raise ValueError( + f"[Config]: Cannot merge list under namespace: {key_ns} because the existing value is None." + ) + + # ---- 2c) length mismatch → abort ------------------- + if ( + isinstance(obj_mem, Sized) + and isinstance(value, Sized) + and len(obj_mem) != len(value) + ): + raise ValueError( + f"[Config]: Incorrect length under namespace: {key_ns}." + f" Expected: {len(obj_mem)}, Received: {len(value)}." + ) + + # ---- 2d) keep tuple/list parity & recurse ---------- + if isinstance(obj_mem, tuple): + value = tuple(value) + else: + set_obj = True + # recursively call if iterable contains Mappings + for i in range(len(obj_mem)): + if isinstance(value[i], Mapping): + update_class_from_dict(obj_mem[i], value[i], _ns=key_ns) + set_obj = False + # do not set value to obj, otherwise it overwrites the cfg class with the dict + if not set_obj: + continue + + # -- 3) callable attribute → resolve string -------------- + elif callable(obj_mem): + # update function name + value = string_to_callable(value) + + # -- 4) simple scalar / explicit None --------------------- + elif value is None or isinstance(value, type(obj_mem)): + pass + + # -- 5) type mismatch → abort ----------------------------- + else: + raise ValueError( + f"[Config]: Incorrect type under namespace: {key_ns}." + f" Expected: {type(obj_mem)}, Received: {type(value)}." + ) + + # -- 6) final assignment --------------------------------- + if isinstance(obj, dict): + obj[key] = value + else: + setattr(obj, key, value) + + # -- B) if key is not present ------------------------------------ + else: + raise KeyError(f"[Config]: Key not found under namespace: {key_ns}.") + + +def _replace_class_with_kwargs(obj: object, **kwargs) -> object: + """Return a new object replacing specified fields with new values. + + This is especially useful for frozen classes. Example usage: + + .. code-block:: python + + @configclass(frozen=True) + class C: + x: int + y: int + + c = C(1, 2) + c1 = c.replace(x=3) + assert c1.x == 3 and c1.y == 2 + + Args: + obj: The object to replace. + **kwargs: The fields to replace and their new values. + + Returns: + The new object. + """ + return replace(obj, **kwargs) + + +def _validate(obj: object, prefix: str = "") -> list[str]: + """Check the validity of configclass object. + + This function checks if the object is a valid configclass object. A valid configclass object contains no MISSING + entries. + + Args: + obj: The object to check. + prefix: The prefix to add to the missing fields. Defaults to ''. + + Returns: + A list of missing fields. + + Raises: + TypeError: When the object is not a valid configuration object. + """ + missing_fields = [] + + if type(obj) is type(MISSING): + missing_fields.append(prefix) + return missing_fields + elif isinstance(obj, (list, tuple)): + for index, item in enumerate(obj): + current_path = f"{prefix}[{index}]" + missing_fields.extend(_validate(item, prefix=current_path)) + return missing_fields + elif isinstance(obj, dict): + obj_dict = obj + elif hasattr(obj, "__dict__"): + obj_dict = obj.__dict__ + else: + return missing_fields + + for key, value in obj_dict.items(): + # disregard builtin attributes + if key.startswith("__"): + continue + current_path = f"{prefix}.{key}" if prefix else key + missing_fields.extend(_validate(value, prefix=current_path)) + + # raise an error only once at the top-level call + if prefix == "" and missing_fields: + formatted_message = "\n".join(f" - {field}" for field in missing_fields) + raise TypeError( + f"Missing values detected in object {obj.__class__.__name__} for the following" + f" fields:\n{formatted_message}\n" + ) + return missing_fields + + +def _add_annotation_types(cls): + """Add annotations to all elements in the dataclass. + + By definition in Python, a field is defined as a class variable that has a type annotation. + + In case type annotations are not provided, dataclass ignores those members when :func:`__dict__()` is called. + This function adds these annotations to the class variable to prevent any issues in case the user forgets to + specify the type annotation. + + This makes the following a feasible operation: + + @dataclass + class State: + pos = (0.0, 0.0, 0.0) + ^^ + If the function is NOT used, the following type-error is returned: + TypeError: 'pos' is a field but has no type annotation + """ + # get type hints + hints = {} + # iterate over class inheritance + # we add annotations from base classes first + for base in reversed(cls.__mro__): + # check if base is object + if base is object: + continue + # get base class annotations + ann = base.__dict__.get("__annotations__", {}) + # directly add all annotations from base class + hints.update(ann) + # iterate over base class members + # Note: Do not change this to dir(base) since it orders the members alphabetically. + # This is not desirable since the order of the members is important in some cases. + for key in base.__dict__: + # get class member + value = getattr(base, key) + # skip members + if _skippable_class_member(key, value, hints): + continue + # add type annotations for members that don't have explicit type annotations + # for these, we deduce the type from the default value + if not isinstance(value, type): + if key not in hints: + # check if var type is not MISSING + # we cannot deduce type from MISSING! + if value is MISSING: + raise TypeError( + f"Missing type annotation for '{key}' in class '{cls.__name__}'." + " Please add a type annotation or set a default value." + ) + # add type annotation + hints[key] = type(value) + elif key != value.__name__: + # note: we don't want to add type annotations for nested configclass. Thus, we check if + # the name of the type matches the name of the variable. + # since Python 3.10, type hints are stored as strings + hints[key] = f"type[{value.__name__}]" + + # Note: Do not change this line. `cls.__dict__.get("__annotations__", {})` is different from + # `cls.__annotations__` because of inheritance. + cls.__annotations__ = cls.__dict__.get("__annotations__", {}) + cls.__annotations__ = hints + + +def _process_mutable_types(cls): + """Initialize all mutable elements through :obj:`dataclasses.Field` to avoid unnecessary complaints. + + By default, dataclass requires usage of :obj:`field(default_factory=...)` to reinitialize mutable objects every time a new + class instance is created. If a member has a mutable type and it is created without specifying the `field(default_factory=...)`, + then Python throws an error requiring the usage of `default_factory`. + + Additionally, Python only explicitly checks for field specification when the type is a list, set or dict. This misses the + use-case where the type is class itself. Thus, the code silently carries a bug with it which can lead to undesirable effects. + + This function deals with this issue + + This makes the following a feasible operation: + + @dataclass + class State: + pos: list = [0.0, 0.0, 0.0] + ^^ + If the function is NOT used, the following value-error is returned: + ValueError: mutable default for field pos is not allowed: use default_factory + """ + # note: Need to set this up in the same order as annotations. Otherwise, it + # complains about missing positional arguments. + ann = cls.__dict__.get("__annotations__", {}) + + # iterate over all class members and store them in a dictionary + class_members = {} + for base in reversed(cls.__mro__): + # check if base is object + if base is object: + continue + # iterate over base class members + for key in base.__dict__: + # get class member + f = getattr(base, key) + # skip members + if _skippable_class_member(key, f): + continue + # store class member if it is not a type or if it is already present in annotations + if not isinstance(f, type) or key in ann: + class_members[key] = f + # iterate over base class data fields + # in previous call, things that became a dataclass field were removed from class members + # so we need to add them back here as a dataclass field directly + for key, f in base.__dict__.get("__dataclass_fields__", {}).items(): + # store class member + if not isinstance(f, type): + class_members[key] = f + + # check that all annotations are present in class members + # note: mainly for debugging purposes + if len(class_members) != len(ann): + raise ValueError( + f"In class '{cls.__name__}', number of annotations ({len(ann)}) does not match number of class members" + f" ({len(class_members)}). Please check that all class members have type annotations and/or a default" + " value. If you don't want to specify a default value, please use the literal `dataclasses.MISSING`." + ) + # iterate over annotations and add field factory for mutable types + for key in ann: + # find matching field in class + value = class_members.get(key, MISSING) + # check if key belongs to ClassVar + # in that case, we cannot use default_factory! + origin = getattr(ann[key], "__origin__", None) + if origin is ClassVar: + continue + # check if f is MISSING + # note: commented out for now since it causes issue with inheritance + # of dataclasses when parent have some positional and some keyword arguments. + # Ref: https://stackoverflow.com/questions/51575931/class-inheritance-in-python-3-7-dataclasses + # TODO: check if this is fixed in Python 3.10 + # if f is MISSING: + # continue + if isinstance(value, Field): + setattr(cls, key, value) + elif not isinstance(value, type): + # create field factory for mutable types + value = field(default_factory=_return_f(value)) + setattr(cls, key, value) + + +def _skippable_class_member(key: str, value: Any, hints: Optional[dict] = None) -> bool: + """Check if the class member should be skipped in configclass processing. + + The following members are skipped: + + * Dunder members: ``__name__``, ``__module__``, ``__qualname__``, ``__annotations__``, ``__dict__``. + * Manually-added special class functions: From :obj:`_CONFIGCLASS_METHODS`. + * Members that are already present in the type annotations. + * Functions bounded to class object or class. + * Properties bounded to class object. + + Args: + key: The class member name. + value: The class member value. + hints: The type hints for the class. Defaults to None, in which case, the + members existence in type hints are not checked. + + Returns: + True if the class member should be skipped, False otherwise. + """ + # skip dunder members + if key.startswith("__"): + return True + # skip manually-added special class functions + if key in _CONFIGCLASS_METHODS: + return True + # check if key is already present + if hints is not None and key in hints: + return True + # skip functions bounded to class + if callable(value): + # FIXME: This doesn't yet work for static methods because they are essentially seen as function types. + # check for class methods + if isinstance(value, types.MethodType): + return True + # check for instance methods + signature = inspect.signature(value) + if "self" in signature.parameters or "cls" in signature.parameters: + return True + # skip property methods + if isinstance(value, property): + return True + # Otherwise, don't skip + return False + + +def _return_f(f: Any) -> Callable[[], Any]: + """Returns default factory function for creating mutable/immutable variables. + + This function should be used to create default factory functions for variables. + + Example: + + .. code-block:: python + + value = field(default_factory=_return_f(value)) + setattr(cls, key, value) + """ + + def _wrap(): + if isinstance(f, Field): + if f.default_factory is MISSING: + return deepcopy(f.default) + else: + return f.default_factory + else: + return deepcopy(f) + + return _wrap diff --git a/embodichain/utils/device_utils.py b/embodichain/utils/device_utils.py new file mode 100644 index 00000000..198ca84e --- /dev/null +++ b/embodichain/utils/device_utils.py @@ -0,0 +1,39 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch + +from typing import Union + + +def standardize_device_string(device: Union[str, torch.device]) -> str: + """Standardize the device string for Warp compatibility. + + Args: + device (Union[str, torch.device]): The device specification. + + Returns: + str: The standardized device string. + """ + if isinstance(device, str): + device_str = device + else: + device_str = str(device) + + if device_str.startswith("cuda"): + device_str = "cuda:0" + + return device_str diff --git a/embodichain/utils/file.py b/embodichain/utils/file.py new file mode 100644 index 00000000..cd089491 --- /dev/null +++ b/embodichain/utils/file.py @@ -0,0 +1,54 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import re + +from typing import Optional, List + + +def get_all_files_in_directory( + directory: str, + exts: Optional[List[str]] = None, + patterns: Optional[List[str]] = None, +) -> List[str]: + """Get all files in a directory with optional filtering by extensions or regex patterns. + + Args: + directory (str): The directory to search for files. + exts (Optional[List[str]]): List of file extensions to filter by. If None, all files are returned. + patterns (Optional[List[str]]): List of regex patterns to match file names. If None, no pattern matching is applied. + + Returns: + List[str]: List of file paths in the directory matching the specified extensions or patterns. + """ + all_files = [] + compiled_patterns = ( + [re.compile(pattern) for pattern in patterns] if patterns else [] + ) + + for root, _, files in os.walk(directory): + for file in files: + match_ext = exts is None or any( + file.lower().endswith(ext.lower()) for ext in exts + ) + match_pattern = not compiled_patterns or any( + pattern.search(file) for pattern in compiled_patterns + ) + + if match_ext and match_pattern: + all_files.append(os.path.join(root, file)) + return all_files diff --git a/embodichain/utils/img_utils.py b/embodichain/utils/img_utils.py new file mode 100644 index 00000000..14593c49 --- /dev/null +++ b/embodichain/utils/img_utils.py @@ -0,0 +1,154 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch + + +def batched_mask_to_box(masks: torch.Tensor) -> torch.Tensor: + """Convert binary masks to bounding boxes. + + Args: + masks (torch.Tensor): A tensor of shape (..., H, W) containing binary masks + where non-zero values indicate the presence of the object. + + Returns: + torch.Tensor: A tensor of shape (..., 4) containing the bounding boxes + in XYXY format. + """ + # torch.max below raises an error on empty inputs, just skip in this case + if torch.numel(masks) == 0: + return torch.zeros(*masks.shape[:-2], 4, device=masks.device) + + # Normalize shape to CxHxW + shape = masks.shape + h, w = shape[-2:] + if len(shape) > 2: + masks = masks.flatten(0, -3) + else: + masks = masks.unsqueeze(0) + + # Get top and bottom edges + in_height, _ = torch.max(masks, dim=-1) + in_height_coords = in_height * torch.arange(h, device=in_height.device)[None, :] + bottom_edges, _ = torch.max(in_height_coords, dim=-1) + in_height_coords = in_height_coords + h * (~in_height) + top_edges, _ = torch.min(in_height_coords, dim=-1) + + # Get left and right edges + in_width, _ = torch.max(masks, dim=-2) + in_width_coords = in_width * torch.arange(w, device=in_width.device)[None, :] + right_edges, _ = torch.max(in_width_coords, dim=-1) + in_width_coords = in_width_coords + w * (~in_width) + left_edges, _ = torch.min(in_width_coords, dim=-1) + + # If the mask is empty the right edge will be to the left of the left edge. + # Replace these boxes with [0, 0, 0, 0] + empty_filter = (right_edges < left_edges) | (bottom_edges < top_edges) + out = torch.stack([left_edges, top_edges, right_edges, bottom_edges], dim=-1) + out = out * (~empty_filter).unsqueeze(-1) + + # Return to original shape + if len(shape) > 2: + out = out.reshape(*shape[:-2], 4) + else: + out = out[0] + + return out + + +def gen_disp_colormap(inputs, normalize=True, torch_transpose=True): + """ + Generate an RGB visualization using the "plasma" colormap for 2D/3D/4D scalar image inputs. + + This utility maps scalar image(s) to an RGB colormap suitable for display or further processing. + It accepts either a NumPy array or a torch.Tensor (torch tensors are detached, moved to CPU and + converted to NumPy). The matplotlib "plasma" colormap with 256 entries is used. + + Parameters + - inputs (numpy.ndarray or torch.Tensor): + Scalar image data with one of the following dimensionalities: + * 2D: (H, W) -> a single image + * 3D: (N, H, W) -> a batch of N single-channel images + * 4D: (N, C, H, W) -> a batch with channel dimension; expected C==1 (first channel used) + The function will convert torch.Tensor input to numpy internally. + - normalize (bool, default True): + If True, input values are linearly scaled to [0, 1] using (x - min) / (max - min). + If the input is constant (min == max), a small divisor (1e5) is used to avoid division + by zero, which effectively maps values near 0. If False, values are assumed to already be + in the [0, 1] range (no scaling is performed). + - torch_transpose (bool, default True): + Controls the output channel ordering to match common PyTorch conventions: + * If True: outputs are transposed to channel-first form: + - 2D input -> (3, H, W) + - 3D input -> (N, 3, H, W) + - 4D input -> (N, 3, H, W) (uses the first channel) + * If False: outputs keep channel-last ordering: + - 2D input -> (H, W, 3) + - 3D input -> (N, H, W, 3) + - 4D input -> (N, H, W, 3) + + Returns + - numpy.ndarray: + RGB image(s) with float values in [0, 1]. The exact output shape depends on the input + dimensionality and the value of torch_transpose (see above). The alpha channel produced by + the colormap is discarded; only the RGB channels are returned. + + Notes and behavior + - The function uses matplotlib.pyplot.get_cmap("plasma", 256). + - For 4D inputs the code selects the first channel (index 0) before applying the colormap. + - Inputs with dimensionality other than 2, 3, or 4 are not supported and will likely raise + an error or produce unintended results. + - This function is non-destructive: it returns a new NumPy array and does not modify the input. + - Typical use cases: visualizing depth maps, single-channel activation maps, or other scalar + images as colored RGB images for inspection or logging. + + Examples + - 2D array (H, W) -> returns (3, H, W) if torch_transpose=True + - 3D array (N, H, W) -> returns (N, 3, H, W) if torch_transpose=True + - 4D array (N, 1, H, W) -> returns (N, 3, H, W) if torch_transpose=True + """ + import matplotlib.pyplot as plt + import torch + + _DEPTH_COLORMAP = plt.get_cmap("plasma", 256) # for plotting + if isinstance(inputs, torch.Tensor): + inputs = inputs.detach().cpu().numpy() + + vis = inputs + if normalize: + ma = float(vis.max()) + mi = float(vis.min()) + d = ma - mi if ma != mi else 1e5 + vis = (vis - mi) / d + + if vis.ndim == 4: + vis = vis.transpose([0, 2, 3, 1]) + vis = _DEPTH_COLORMAP(vis) + vis = vis[:, :, :, 0, :3] + if torch_transpose: + vis = vis.transpose(0, 3, 1, 2) + elif vis.ndim == 3: + vis = _DEPTH_COLORMAP(vis) + vis = vis[:, :, :3] + if torch_transpose: + vis = vis.transpose(0, 3, 1, 2) + elif vis.ndim == 2: + vis = _DEPTH_COLORMAP(vis) + vis = vis[..., :3] + if torch_transpose: + vis = vis.transpose(2, 0, 1) + + return vis diff --git a/embodichain/utils/logger.py b/embodichain/utils/logger.py new file mode 100644 index 00000000..b2dd22eb --- /dev/null +++ b/embodichain/utils/logger.py @@ -0,0 +1,74 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import logging + +logging.basicConfig( + level=logging.INFO, format="%(asctime)s %(message)s", datefmt="%H:%M:%S" +) + +# Create a custom logger +logger = logging.getLogger(__name__) + +# Set the default log level +logger.setLevel(logging.INFO) + + +def decorate_str_color(msg: str, color: str): + """Decorate a string with a specific color.""" + color_map = { + "red": "\033[91m", + "green": "\033[92m", + "yellow": "\033[93m", + "blue": "\033[94m", + "purple": "\033[95m", + "cyan": "\033[96m", + "orange": "\033[33m", + "white": "\033[97m", + } + return f"{color_map.get(color, '')}{msg}\033[0m" if color else msg + + +def set_log_level(level: str): + """Set the logging level.""" + level = level.upper() + assert level in ["DEBUG", "INFO", "WARNING", "ERROR"], "Invalid log level" + logger.setLevel(getattr(logging, level)) + + +def format_message(level: str, message: str): + """Format the log message with a consistent prefix.""" + return f"[EmbodiChain {level}]: {message}" + + +def log_info(message, color=None): + """Log an info message.""" + logger.info(decorate_str_color(format_message("INFO", message), color)) + + +def log_debug(message, color="blue"): + """Log a debug message.""" + logger.debug(decorate_str_color(format_message("DEBUG", message), color)) + + +def log_warning(message): + """Log a warning message.""" + logger.warning(decorate_str_color(format_message("WARNING", message), "purple")) + + +def log_error(message, error_type=RuntimeError): + """Log an error message.""" + raise error_type(decorate_str_color(format_message("ERROR", message), "red")) diff --git a/embodichain/utils/math.py b/embodichain/utils/math.py new file mode 100644 index 00000000..c42f4374 --- /dev/null +++ b/embodichain/utils/math.py @@ -0,0 +1,2269 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +# needed to import for allowing type-hinting: Union[torch.Tensor, np.ndarray] +from __future__ import annotations + +import math +import torch +import numpy as np +import torch.nn.functional +from typing import Literal, Optional, Union + + +def look_at_to_pose( + eye: Union[torch.Tensor, list], + target: Union[torch.Tensor, list], + up: Union[torch.Tensor, list] = [0, 0, 1], +) -> torch.Tensor: + """Get the camera pose from eye to target with up direction, supporting batch processing. + + Args: + eye (Union[torch.Tensor, list]): Camera positions with shape (N, 3). + target (Union[torch.Tensor, list]): Target positions with shape (N, 3). + up (Union[torch.Tensor, list], optional): Up directions with shape (N, 3) or (3,). Defaults to [0, 0, 1]. + + Returns: + torch.Tensor: Camera pose matrices with shape (N, 4, 4). + """ + eye = ( + torch.tensor(eye, dtype=torch.float32) + if not isinstance(eye, torch.Tensor) + else eye + ) + target = ( + torch.tensor(target, dtype=torch.float32) + if not isinstance(target, torch.Tensor) + else target + ) + up = ( + torch.tensor(up, dtype=torch.float32) + if not isinstance(up, torch.Tensor) + else up + ) + + if eye.ndim == 1: + eye = eye.unsqueeze(0) + + if target.ndim == 1: + target = target.unsqueeze(0) + + if up.ndim == 1: + up = up.unsqueeze(0).repeat( + eye.shape[0], 1 + ) # Broadcast up vector to batch size + + assert ( + eye.shape[-1] == 3 and target.shape[-1] == 3 and up.shape[-1] == 3 + ), "Inputs must have shape (N, 3)." + + # Compute camera axes + camera_z = target - eye + camera_z = camera_z / torch.norm( + camera_z, dim=1, keepdim=True + ) # Normalize camera_z + camera_x = torch.cross(camera_z, up, dim=1) + camera_x_norm = torch.norm(camera_x, dim=1, keepdim=True) + if torch.any(camera_x_norm < 1e-6): # Handle degenerate cases + up = ( + torch.tensor([0, 1, 0], dtype=torch.float32) + .unsqueeze(0) + .repeat(eye.shape[0], 1) + ) + camera_x = torch.cross(up, camera_z, dim=1) + camera_x = camera_x / torch.norm( + camera_x, dim=1, keepdim=True + ) # Normalize camera_x + camera_y = torch.cross(camera_z, camera_x, dim=1) # Compute camera_y + + # Construct camera pose matrices + camera_pose = ( + torch.eye(4, dtype=torch.float32).unsqueeze(0).repeat(eye.shape[0], 1, 1) + ) # (N, 4, 4) + camera_pose[:, :3, 0] = camera_x + camera_pose[:, :3, 1] = camera_y + camera_pose[:, :3, 2] = camera_z + camera_pose[:, :3, 3] = eye + + return camera_pose + + +@torch.jit.script +def scale_transform( + x: torch.Tensor, lower: torch.Tensor, upper: torch.Tensor +) -> torch.Tensor: + """Normalizes a given input tensor to a range of [-1, 1]. + + .. note:: + It uses pytorch broadcasting functionality to deal with batched input. + + Args: + x: Input tensor of shape (N, dims). + lower: The minimum value of the tensor. Shape is (N, dims) or (dims,). + upper: The maximum value of the tensor. Shape is (N, dims) or (dims,). + + Returns: + Normalized transform of the tensor. Shape is (N, dims). + """ + # default value of center + offset = (lower + upper) * 0.5 + # return normalized tensor + return 2 * (x - offset) / (upper - lower) + + +@torch.jit.script +def unscale_transform( + x: torch.Tensor, lower: torch.Tensor, upper: torch.Tensor +) -> torch.Tensor: + """De-normalizes a given input tensor from range of [-1, 1] to (lower, upper). + + .. note:: + It uses pytorch broadcasting functionality to deal with batched input. + + Args: + x: Input tensor of shape (N, dims). + lower: The minimum value of the tensor. Shape is (N, dims) or (dims,). + upper: The maximum value of the tensor. Shape is (N, dims) or (dims,). + + Returns: + De-normalized transform of the tensor. Shape is (N, dims). + """ + # default value of center + offset = (lower + upper) * 0.5 + # return normalized tensor + return x * (upper - lower) * 0.5 + offset + + +@torch.jit.script +def saturate(x: torch.Tensor, lower: torch.Tensor, upper: torch.Tensor) -> torch.Tensor: + """Clamps a given input tensor to (lower, upper). + + It uses pytorch broadcasting functionality to deal with batched input. + + Args: + x: Input tensor of shape (N, dims). + lower: The minimum value of the tensor. Shape is (N, dims) or (dims,). + upper: The maximum value of the tensor. Shape is (N, dims) or (dims,). + + Returns: + Clamped transform of the tensor. Shape is (N, dims). + """ + return torch.max(torch.min(x, upper), lower) + + +@torch.jit.script +def normalize(x: torch.Tensor, eps: float = 1e-9) -> torch.Tensor: + """Normalizes a given input tensor to unit length. + + Args: + x: Input tensor of shape (N, dims). + eps: A small value to avoid division by zero. Defaults to 1e-9. + + Returns: + Normalized tensor of shape (N, dims). + """ + return x / x.norm(p=2, dim=-1).clamp(min=eps, max=None).unsqueeze(-1) + + +@torch.jit.script +def wrap_to_pi(angles: torch.Tensor) -> torch.Tensor: + r"""Wraps input angles (in radians) to the range :math:`[-\pi, \pi]`. + + This function wraps angles in radians to the range :math:`[-\pi, \pi]`, such that + :math:`\pi` maps to :math:`\pi`, and :math:`-\pi` maps to :math:`-\pi`. In general, + odd positive multiples of :math:`\pi` are mapped to :math:`\pi`, and odd negative + multiples of :math:`\pi` are mapped to :math:`-\pi`. + + The function behaves similar to MATLAB's `wrapToPi `_ + function. + + Args: + angles: Input angles of any shape. + + Returns: + Angles in the range :math:`[-\pi, \pi]`. + """ + # wrap to [0, 2*pi) + wrapped_angle = (angles + torch.pi) % (2 * torch.pi) + # map to [-pi, pi] + # we check for zero in wrapped angle to make it go to pi when input angle is odd multiple of pi + return torch.where( + (wrapped_angle == 0) & (angles > 0), torch.pi, wrapped_angle - torch.pi + ) + + +@torch.jit.script +def copysign(mag: float, other: torch.Tensor) -> torch.Tensor: + """Create a new floating-point tensor with the magnitude of input and the sign of other, element-wise. + + Note: + The implementation follows from `torch.copysign`. The function allows a scalar magnitude. + + Args: + mag: The magnitude scalar. + other: The tensor containing values whose signbits are applied to magnitude. + + Returns: + The output tensor. + """ + mag_torch = abs(mag) * torch.ones_like(other) + return torch.copysign(mag_torch, other) + + +""" +Rotation +""" + + +@torch.jit.script +def quat_unique(q: torch.Tensor) -> torch.Tensor: + """Convert a unit quaternion to a standard form where the real part is non-negative. + + Quaternion representations have a singularity since ``q`` and ``-q`` represent the same + rotation. This function ensures the real part of the quaternion is non-negative. + + Args: + q: The quaternion orientation in (w, x, y, z). Shape is (..., 4). + + Returns: + Standardized quaternions. Shape is (..., 4). + """ + return torch.where(q[..., 0:1] < 0, -q, q) + + +@torch.jit.script +def matrix_from_quat(quaternions: torch.Tensor) -> torch.Tensor: + """Convert rotations given as quaternions to rotation matrices. + + Args: + quaternions: The quaternion orientation in (w, x, y, z). Shape is (..., 4). + + Returns: + Rotation matrices. The shape is (..., 3, 3). + + Reference: + https://github.com/facebookresearch/pytorch3d/blob/main/pytorch3d/transforms/rotation_conversions.py#L41-L70 + """ + r, i, j, k = torch.unbind(quaternions, -1) + # pyre-fixme[58]: `/` is not supported for operand types `float` and `Tensor`. + two_s = 2.0 / (quaternions * quaternions).sum(-1) + + o = torch.stack( + ( + 1 - two_s * (j * j + k * k), + two_s * (i * j - k * r), + two_s * (i * k + j * r), + two_s * (i * j + k * r), + 1 - two_s * (i * i + k * k), + two_s * (j * k - i * r), + two_s * (i * k - j * r), + two_s * (j * k + i * r), + 1 - two_s * (i * i + j * j), + ), + -1, + ) + return o.reshape(quaternions.shape[:-1] + (3, 3)) + + +def convert_quat( + quat: Union[torch.Tensor, np.ndarray], to: Literal["xyzw", "wxyz"] = "xyzw" +) -> Union[torch.Tensor, np.ndarray]: + """Converts quaternion from one convention to another. + + The convention to convert TO is specified as an optional argument. If to == 'xyzw', + then the input is in 'wxyz' format, and vice-versa. + + Args: + quat: The quaternion of shape (..., 4). + to: Convention to convert quaternion to.. Defaults to "xyzw". + + Returns: + The converted quaternion in specified convention. + + Raises: + ValueError: Invalid input argument `to`, i.e. not "xyzw" or "wxyz". + ValueError: Invalid shape of input `quat`, i.e. not (..., 4,). + """ + # check input is correct + if quat.shape[-1] != 4: + msg = f"Expected input quaternion shape mismatch: {quat.shape} != (..., 4)." + raise ValueError(msg) + if to not in ["xyzw", "wxyz"]: + msg = f"Expected input argument `to` to be 'xyzw' or 'wxyz'. Received: {to}." + raise ValueError(msg) + # check if input is numpy array (we support this backend since some classes use numpy) + if isinstance(quat, np.ndarray): + # use numpy functions + if to == "xyzw": + # wxyz -> xyzw + return np.roll(quat, -1, axis=-1) + else: + # xyzw -> wxyz + return np.roll(quat, 1, axis=-1) + else: + # convert to torch (sanity check) + if not isinstance(quat, torch.Tensor): + quat = torch.tensor(quat, dtype=float) + # convert to specified quaternion type + if to == "xyzw": + # wxyz -> xyzw + return quat.roll(-1, dims=-1) + else: + # xyzw -> wxyz + return quat.roll(1, dims=-1) + + +@torch.jit.script +def quat_conjugate(q: torch.Tensor) -> torch.Tensor: + """Computes the conjugate of a quaternion. + + Args: + q: The quaternion orientation in (w, x, y, z). Shape is (..., 4). + + Returns: + The conjugate quaternion in (w, x, y, z). Shape is (..., 4). + """ + shape = q.shape + q = q.reshape(-1, 4) + return torch.cat((q[..., 0:1], -q[..., 1:]), dim=-1).view(shape) + + +@torch.jit.script +def quat_inv(q: torch.Tensor, eps: float = 1e-9) -> torch.Tensor: + """Computes the inverse of a quaternion. + + Args: + q: The quaternion orientation in (w, x, y, z). Shape is (N, 4). + eps: A small value to avoid division by zero. Defaults to 1e-9. + + Returns: + The inverse quaternion in (w, x, y, z). Shape is (N, 4). + """ + return quat_conjugate(q) / q.pow(2).sum(dim=-1, keepdim=True).clamp(min=eps) + + +@torch.jit.script +def quat_from_euler_xyz( + roll: torch.Tensor, pitch: torch.Tensor, yaw: torch.Tensor +) -> torch.Tensor: + """Convert rotations given as Euler angles in radians to Quaternions. + + Note: + The euler angles are assumed in XYZ convention. + + Args: + roll: Rotation around x-axis (in radians). Shape is (N,). + pitch: Rotation around y-axis (in radians). Shape is (N,). + yaw: Rotation around z-axis (in radians). Shape is (N,). + + Returns: + The quaternion in (w, x, y, z). Shape is (N, 4). + """ + cy = torch.cos(yaw * 0.5) + sy = torch.sin(yaw * 0.5) + cr = torch.cos(roll * 0.5) + sr = torch.sin(roll * 0.5) + cp = torch.cos(pitch * 0.5) + sp = torch.sin(pitch * 0.5) + # compute quaternion + qw = cy * cr * cp + sy * sr * sp + qx = cy * sr * cp - sy * cr * sp + qy = cy * cr * sp + sy * sr * cp + qz = sy * cr * cp - cy * sr * sp + + return torch.stack([qw, qx, qy, qz], dim=-1) + + +@torch.jit.script +def _sqrt_positive_part(x: torch.Tensor) -> torch.Tensor: + """Returns torch.sqrt(torch.max(0, x)) but with a zero sub-gradient where x is 0. + + Reference: + https://github.com/facebookresearch/pytorch3d/blob/main/pytorch3d/transforms/rotation_conversions.py#L91-L99 + """ + ret = torch.zeros_like(x) + positive_mask = x > 0 + ret[positive_mask] = torch.sqrt(x[positive_mask]) + return ret + + +@torch.jit.script +def quat_from_matrix(matrix: torch.Tensor) -> torch.Tensor: + """Convert rotations given as rotation matrices to quaternions. + + Args: + matrix: The rotation matrices. Shape is (..., 3, 3). + + Returns: + The quaternion in (w, x, y, z). Shape is (..., 4). + + Reference: + https://github.com/facebookresearch/pytorch3d/blob/main/pytorch3d/transforms/rotation_conversions.py#L102-L161 + """ + if matrix.size(-1) != 3 or matrix.size(-2) != 3: + raise ValueError(f"Invalid rotation matrix shape {matrix.shape}.") + + batch_dim = matrix.shape[:-2] + m00, m01, m02, m10, m11, m12, m20, m21, m22 = torch.unbind( + matrix.reshape(batch_dim + (9,)), dim=-1 + ) + + q_abs = _sqrt_positive_part( + torch.stack( + [ + 1.0 + m00 + m11 + m22, + 1.0 + m00 - m11 - m22, + 1.0 - m00 + m11 - m22, + 1.0 - m00 - m11 + m22, + ], + dim=-1, + ) + ) + + # we produce the desired quaternion multiplied by each of r, i, j, k + quat_by_rijk = torch.stack( + [ + # pyre-fixme[58]: `**` is not supported for operand types `Tensor` and `int`. + torch.stack([q_abs[..., 0] ** 2, m21 - m12, m02 - m20, m10 - m01], dim=-1), + # pyre-fixme[58]: `**` is not supported for operand types `Tensor` and `int`. + torch.stack([m21 - m12, q_abs[..., 1] ** 2, m10 + m01, m02 + m20], dim=-1), + # pyre-fixme[58]: `**` is not supported for operand types `Tensor` and `int`. + torch.stack([m02 - m20, m10 + m01, q_abs[..., 2] ** 2, m12 + m21], dim=-1), + # pyre-fixme[58]: `**` is not supported for operand types `Tensor` and `int`. + torch.stack([m10 - m01, m20 + m02, m21 + m12, q_abs[..., 3] ** 2], dim=-1), + ], + dim=-2, + ) + + # We floor here at 0.1 but the exact level is not important; if q_abs is small, + # the candidate won't be picked. + flr = torch.tensor(0.1).to(dtype=q_abs.dtype, device=q_abs.device) + quat_candidates = quat_by_rijk / (2.0 * q_abs[..., None].max(flr)) + + # if not for numerical problems, quat_candidates[i] should be same (up to a sign), + # forall i; we pick the best-conditioned one (with the largest denominator) + return quat_candidates[ + torch.nn.functional.one_hot(q_abs.argmax(dim=-1), num_classes=4) > 0.5, : + ].reshape(batch_dim + (4,)) + + +def xyz_quat_to_4x4_matrix(xyz_quat: torch.Tensor) -> torch.Tensor: + """Convert a 7D pose vector (x, y, z, qw, qx, qy, qz) to a 4x4 transformation matrix. + + Args: + xyz_quat: The pose vector in (x, y, z, qw, qx, qy, qz). Shape is (..., 7). + + Returns: + The transformation matrix. Shape is (..., 4, 4). + """ + if xyz_quat.shape[-1] != 7: + raise ValueError(f"Invalid input shape {xyz_quat.shape}, expected (..., 7).") + + # get rotation matrix from quaternion + rot_mat = matrix_from_quat(xyz_quat[..., 3:7]) # (..., 3, 3) + + # create transformation + trans = ( + torch.eye(4, dtype=xyz_quat.dtype, device=xyz_quat.device) + .unsqueeze_(0) + .repeat(xyz_quat.shape[0], 1, 1) + ) + trans[..., :3, 3] = xyz_quat[..., :3] + trans[..., :3, :3] = rot_mat + return trans + + +def trans_matrix_to_xyz_quat(matrix: torch.Tensor) -> torch.Tensor: + """Convert a (4, 4) pose transformation matrix ((R, t), (0, 1)) to a 7D pose vector. + + Args: + matrix: The pose transformation matrix in ((R, t), (0, 1)). Shape is (..., 4, 4). + + Returns: + The pose vector in (x, y, z, qw, qx, qy, qz). Shape is (..., 7). + """ + if matrix.shape[-2:] != (4, 4): + raise ValueError(f"Invalid input shape {matrix.shape}, expected (..., 4, 4).") + + # get rotation matrix from quaternion + quat = quat_from_matrix(matrix[..., :3, :3]) # (..., 4) + + # create vector + vec = torch.concatenate([matrix[..., :3, 3], quat], dim=-1).to( + dtype=matrix.dtype, device=matrix.device + ) + return vec + + +@torch.jit.script +def quat_from_euler_xyz( + roll: torch.Tensor, pitch: torch.Tensor, yaw: torch.Tensor +) -> torch.Tensor: + """Convert rotations given as Euler angles in radians to Quaternions. + + Note: + The euler angles are assumed in XYZ convention. + + Args: + roll: Rotation around x-axis (in radians). Shape is (N,). + pitch: Rotation around y-axis (in radians). Shape is (N,). + yaw: Rotation around z-axis (in radians). Shape is (N,). + + Returns: + The quaternion in (w, x, y, z). Shape is (N, 4). + """ + cy = torch.cos(yaw * 0.5) + sy = torch.sin(yaw * 0.5) + cr = torch.cos(roll * 0.5) + sr = torch.sin(roll * 0.5) + cp = torch.cos(pitch * 0.5) + sp = torch.sin(pitch * 0.5) + # compute quaternion + qw = cy * cr * cp + sy * sr * sp + qx = cy * sr * cp - sy * cr * sp + qy = cy * cr * sp + sy * sr * cp + qz = sy * cr * cp - cy * sr * sp + + return torch.stack([qw, qx, qy, qz], dim=-1) + + +def _axis_angle_rotation( + axis: Literal["X", "Y", "Z"], angle: torch.Tensor +) -> torch.Tensor: + """Return the rotation matrices for one of the rotations about an axis of which Euler angles describe, + for each value of the angle given. + + Args: + axis: Axis label "X" or "Y or "Z". + angle: Euler angles in radians of any shape. + + Returns: + Rotation matrices. Shape is (..., 3, 3). + + Reference: + https://github.com/facebookresearch/pytorch3d/blob/main/pytorch3d/transforms/rotation_conversions.py#L164-L191 + """ + cos = torch.cos(angle) + sin = torch.sin(angle) + one = torch.ones_like(angle) + zero = torch.zeros_like(angle) + + if axis == "X": + R_flat = (one, zero, zero, zero, cos, -sin, zero, sin, cos) + elif axis == "Y": + R_flat = (cos, zero, sin, zero, one, zero, -sin, zero, cos) + elif axis == "Z": + R_flat = (cos, -sin, zero, sin, cos, zero, zero, zero, one) + else: + raise ValueError("letter must be either X, Y or Z.") + + return torch.stack(R_flat, -1).reshape(angle.shape + (3, 3)) + + +def matrix_from_euler( + euler_angles: torch.Tensor, convention: str = "XYZ" +) -> torch.Tensor: + """ + Convert rotations given as Euler angles (intrinsic) in radians to rotation matrices. + + Args: + euler_angles: Euler angles in radians. Shape is (..., 3). + convention: Convention string of three uppercase letters from {"X", "Y", and "Z"}. + For example, "XYZ" means that the rotations should be applied first about x, + then y, then z. Defaults to "XYZ". + + Returns: + Rotation matrices. Shape is (..., 3, 3). + + Reference: + https://github.com/facebookresearch/pytorch3d/blob/main/pytorch3d/transforms/rotation_conversions.py#L194-L220 + """ + if euler_angles.dim() == 0 or euler_angles.shape[-1] != 3: + raise ValueError("Invalid input euler angles.") + if len(convention) != 3: + raise ValueError("Convention must have 3 letters.") + if convention[1] in (convention[0], convention[2]): + raise ValueError(f"Invalid convention {convention}.") + for letter in convention: + if letter not in ("X", "Y", "Z"): + raise ValueError(f"Invalid letter {letter} in convention string.") + matrices = [ + _axis_angle_rotation(c, e) + for c, e in zip(convention, torch.unbind(euler_angles, -1)) + ] + # return functools.reduce(torch.matmul, matrices) + return torch.matmul(torch.matmul(matrices[0], matrices[1]), matrices[2]) + + +@torch.jit.script +def euler_xyz_from_quat( + quat: torch.Tensor, wrap_to_2pi: bool = False +) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Convert rotations given as quaternions to Euler angles in radians. + + Note: + The euler angles are assumed in XYZ extrinsic convention. + + Args: + quat: The quaternion orientation in (w, x, y, z). Shape is (N, 4). + wrap_to_2pi (bool): Whether to wrap output Euler angles into [0, 2π). If + False, angles are returned in the default range (−π, π]. Defaults to + False. + + Returns: + A tuple containing roll-pitch-yaw. Each element is a tensor of shape (N,). + + Reference: + https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles + """ + q_w, q_x, q_y, q_z = quat[:, 0], quat[:, 1], quat[:, 2], quat[:, 3] + # roll (x-axis rotation) + sin_roll = 2.0 * (q_w * q_x + q_y * q_z) + cos_roll = 1 - 2 * (q_x * q_x + q_y * q_y) + roll = torch.atan2(sin_roll, cos_roll) + + # pitch (y-axis rotation) + sin_pitch = 2.0 * (q_w * q_y - q_z * q_x) + pitch = torch.where( + torch.abs(sin_pitch) >= 1, + copysign(torch.pi / 2.0, sin_pitch), + torch.asin(sin_pitch), + ) + + # yaw (z-axis rotation) + sin_yaw = 2.0 * (q_w * q_z + q_x * q_y) + cos_yaw = 1 - 2 * (q_y * q_y + q_z * q_z) + yaw = torch.atan2(sin_yaw, cos_yaw) + + if wrap_to_2pi: + return roll % (2 * torch.pi), pitch % (2 * torch.pi), yaw % (2 * torch.pi) + return roll, pitch, yaw + + +@torch.jit.script +def axis_angle_from_quat(quat: torch.Tensor, eps: float = 1.0e-6) -> torch.Tensor: + """Convert rotations given as quaternions to axis/angle. + + Args: + quat: The quaternion orientation in (w, x, y, z). Shape is (..., 4). + eps: The tolerance for Taylor approximation. Defaults to 1.0e-6. + + Returns: + Rotations given as a vector in axis angle form. Shape is (..., 3). + The vector's magnitude is the angle turned anti-clockwise in radians around the vector's direction. + + Reference: + https://github.com/facebookresearch/pytorch3d/blob/main/pytorch3d/transforms/rotation_conversions.py#L526-L554 + """ + # Modified to take in quat as [q_w, q_x, q_y, q_z] + # Quaternion is [q_w, q_x, q_y, q_z] = [cos(theta/2), n_x * sin(theta/2), n_y * sin(theta/2), n_z * sin(theta/2)] + # Axis-angle is [a_x, a_y, a_z] = [theta * n_x, theta * n_y, theta * n_z] + # Thus, axis-angle is [q_x, q_y, q_z] / (sin(theta/2) / theta) + # When theta = 0, (sin(theta/2) / theta) is undefined + # However, as theta --> 0, we can use the Taylor approximation 1/2 - theta^2 / 48 + quat = quat * (1.0 - 2.0 * (quat[..., 0:1] < 0.0)) + mag = torch.linalg.norm(quat[..., 1:], dim=-1) + half_angle = torch.atan2(mag, quat[..., 0]) + angle = 2.0 * half_angle + # check whether to apply Taylor approximation + sin_half_angles_over_angles = torch.where( + angle.abs() > eps, torch.sin(half_angle) / angle, 0.5 - angle * angle / 48 + ) + return quat[..., 1:4] / sin_half_angles_over_angles.unsqueeze(-1) + + +@torch.jit.script +def quat_from_angle_axis(angle: torch.Tensor, axis: torch.Tensor) -> torch.Tensor: + """Convert rotations given as angle-axis to quaternions. + + Args: + angle: The angle turned anti-clockwise in radians around the vector's direction. Shape is (N,). + axis: The axis of rotation. Shape is (N, 3). + + Returns: + The quaternion in (w, x, y, z). Shape is (N, 4). + """ + theta = (angle / 2).unsqueeze(-1) + xyz = normalize(axis) * theta.sin() + w = theta.cos() + return normalize(torch.cat([w, xyz], dim=-1)) + + +@torch.jit.script +def quat_mul(q1: torch.Tensor, q2: torch.Tensor) -> torch.Tensor: + """Multiply two quaternions together. + + Args: + q1: The first quaternion in (w, x, y, z). Shape is (..., 4). + q2: The second quaternion in (w, x, y, z). Shape is (..., 4). + + Returns: + The product of the two quaternions in (w, x, y, z). Shape is (..., 4). + + Raises: + ValueError: Input shapes of ``q1`` and ``q2`` are not matching. + """ + # check input is correct + if q1.shape != q2.shape: + msg = f"Expected input quaternion shape mismatch: {q1.shape} != {q2.shape}." + raise ValueError(msg) + # reshape to (N, 4) for multiplication + shape = q1.shape + q1 = q1.reshape(-1, 4) + q2 = q2.reshape(-1, 4) + # extract components from quaternions + w1, x1, y1, z1 = q1[:, 0], q1[:, 1], q1[:, 2], q1[:, 3] + w2, x2, y2, z2 = q2[:, 0], q2[:, 1], q2[:, 2], q2[:, 3] + # perform multiplication + ww = (z1 + x1) * (x2 + y2) + yy = (w1 - y1) * (w2 + z2) + zz = (w1 + y1) * (w2 - z2) + xx = ww + yy + zz + qq = 0.5 * (xx + (z1 - x1) * (x2 - y2)) + w = qq - ww + (z1 - y1) * (y2 - z2) + x = qq - xx + (x1 + w1) * (x2 + w2) + y = qq - yy + (w1 - x1) * (y2 + z2) + z = qq - zz + (z1 + y1) * (w2 - x2) + + return torch.stack([w, x, y, z], dim=-1).view(shape) + + +@torch.jit.script +def yaw_quat(quat: torch.Tensor) -> torch.Tensor: + """Extract the yaw component of a quaternion. + + Args: + quat: The orientation in (w, x, y, z). Shape is (..., 4) + + Returns: + A quaternion with only yaw component. + """ + shape = quat.shape + quat_yaw = quat.view(-1, 4) + qw = quat_yaw[:, 0] + qx = quat_yaw[:, 1] + qy = quat_yaw[:, 2] + qz = quat_yaw[:, 3] + yaw = torch.atan2(2 * (qw * qz + qx * qy), 1 - 2 * (qy * qy + qz * qz)) + quat_yaw = torch.zeros_like(quat_yaw) + quat_yaw[:, 3] = torch.sin(yaw / 2) + quat_yaw[:, 0] = torch.cos(yaw / 2) + quat_yaw = normalize(quat_yaw) + return quat_yaw.view(shape) + + +@torch.jit.script +def quat_box_minus(q1: torch.Tensor, q2: torch.Tensor) -> torch.Tensor: + """The box-minus operator (quaternion difference) between two quaternions. + + Args: + q1: The first quaternion in (w, x, y, z). Shape is (N, 4). + q2: The second quaternion in (w, x, y, z). Shape is (N, 4). + + Returns: + The difference between the two quaternions. Shape is (N, 3). + + Reference: + https://github.com/ANYbotics/kindr/blob/master/doc/cheatsheet/cheatsheet_latest.pdf + """ + quat_diff = quat_mul(q1, quat_conjugate(q2)) # q1 * q2^-1 + return axis_angle_from_quat(quat_diff) # log(qd) + + +@torch.jit.script +def quat_box_plus( + q: torch.Tensor, delta: torch.Tensor, eps: float = 1.0e-6 +) -> torch.Tensor: + """The box-plus operator (quaternion update) to apply an increment to a quaternion. + + Args: + q: The initial quaternion in (w, x, y, z). Shape is (N, 4). + delta: The axis-angle perturbation. Shape is (N, 3). + eps: A small value to avoid division by zero. Defaults to 1e-6. + + Returns: + The updated quaternion after applying the perturbation. Shape is (N, 4). + + Reference: + https://github.com/ANYbotics/kindr/blob/master/doc/cheatsheet/cheatsheet_latest.pdf + """ + delta_norm = torch.clamp_min( + torch.linalg.norm(delta, dim=-1, keepdim=True), min=eps + ) + delta_quat = quat_from_angle_axis( + delta_norm.squeeze(-1), delta / delta_norm + ) # exp(dq) + new_quat = quat_mul(delta_quat, q) # Apply perturbation + return quat_unique(new_quat) + + +@torch.jit.script +def quat_apply(quat: torch.Tensor, vec: torch.Tensor) -> torch.Tensor: + """Apply a quaternion rotation to a vector. + + Args: + quat: The quaternion in (w, x, y, z). Shape is (..., 4). + vec: The vector in (x, y, z). Shape is (..., 3). + + Returns: + The rotated vector in (x, y, z). Shape is (..., 3). + """ + # store shape + shape = vec.shape + # reshape to (N, 3) for multiplication + quat = quat.reshape(-1, 4) + vec = vec.reshape(-1, 3) + # extract components from quaternions + xyz = quat[:, 1:] + t = xyz.cross(vec, dim=-1) * 2 + return (vec + quat[:, 0:1] * t + xyz.cross(t, dim=-1)).view(shape) + + +@torch.jit.script +def quat_apply_inverse(quat: torch.Tensor, vec: torch.Tensor) -> torch.Tensor: + """Apply an inverse quaternion rotation to a vector. + + Args: + quat: The quaternion in (w, x, y, z). Shape is (..., 4). + vec: The vector in (x, y, z). Shape is (..., 3). + + Returns: + The rotated vector in (x, y, z). Shape is (..., 3). + """ + # store shape + shape = vec.shape + # reshape to (N, 3) for multiplication + quat = quat.reshape(-1, 4) + vec = vec.reshape(-1, 3) + # extract components from quaternions + xyz = quat[:, 1:] + t = xyz.cross(vec, dim=-1) * 2 + return (vec - quat[:, 0:1] * t + xyz.cross(t, dim=-1)).view(shape) + + +@torch.jit.script +def quat_apply_yaw(quat: torch.Tensor, vec: torch.Tensor) -> torch.Tensor: + """Rotate a vector only around the yaw-direction. + + Args: + quat: The orientation in (w, x, y, z). Shape is (N, 4). + vec: The vector in (x, y, z). Shape is (N, 3). + + Returns: + The rotated vector in (x, y, z). Shape is (N, 3). + """ + quat_yaw = yaw_quat(quat) + return quat_apply(quat_yaw, vec) + + +def quat_rotate(q: torch.Tensor, v: torch.Tensor) -> torch.Tensor: + """Rotate a vector by a quaternion along the last dimension of q and v. + .. deprecated v2.1.0: + This function will be removed in a future release in favor of the faster implementation :meth:`quat_apply`. + + Args: + q: The quaternion in (w, x, y, z). Shape is (..., 4). + v: The vector in (x, y, z). Shape is (..., 3). + + Returns: + The rotated vector in (x, y, z). Shape is (..., 3). + """ + # deprecation + omni.log.warn( + "The function 'quat_rotate' will be deprecated in favor of the faster method 'quat_apply'." + " Please use 'quat_apply' instead...." + ) + return quat_apply(q, v) + + +def quat_rotate_inverse(q: torch.Tensor, v: torch.Tensor) -> torch.Tensor: + """Rotate a vector by the inverse of a quaternion along the last dimension of q and v. + + .. deprecated v2.1.0: + This function will be removed in a future release in favor of the faster implementation :meth:`quat_apply_inverse`. + Args: + q: The quaternion in (w, x, y, z). Shape is (..., 4). + v: The vector in (x, y, z). Shape is (..., 3). + + Returns: + The rotated vector in (x, y, z). Shape is (..., 3). + """ + omni.log.warn( + "The function 'quat_rotate_inverse' will be deprecated in favor of the faster method 'quat_apply_inverse'." + " Please use 'quat_apply_inverse' instead...." + ) + return quat_apply_inverse(q, v) + + +@torch.jit.script +def quat_error_magnitude(q1: torch.Tensor, q2: torch.Tensor) -> torch.Tensor: + """Computes the rotation difference between two quaternions. + + Args: + q1: The first quaternion in (w, x, y, z). Shape is (..., 4). + q2: The second quaternion in (w, x, y, z). Shape is (..., 4). + + Returns: + Angular error between input quaternions in radians. + """ + axis_angle_error = quat_box_minus(q1, q2) + return torch.norm(axis_angle_error, dim=-1) + + +@torch.jit.script +def skew_symmetric_matrix(vec: torch.Tensor) -> torch.Tensor: + """Computes the skew-symmetric matrix of a vector. + + Args: + vec: The input vector. Shape is (3,) or (N, 3). + + Returns: + The skew-symmetric matrix. Shape is (1, 3, 3) or (N, 3, 3). + + Raises: + ValueError: If input tensor is not of shape (..., 3). + """ + # check input is correct + if vec.shape[-1] != 3: + raise ValueError( + f"Expected input vector shape mismatch: {vec.shape} != (..., 3)." + ) + # unsqueeze the last dimension + if vec.ndim == 1: + vec = vec.unsqueeze(0) + # create a skew-symmetric matrix + skew_sym_mat = torch.zeros(vec.shape[0], 3, 3, device=vec.device, dtype=vec.dtype) + skew_sym_mat[:, 0, 1] = -vec[:, 2] + skew_sym_mat[:, 0, 2] = vec[:, 1] + skew_sym_mat[:, 1, 2] = -vec[:, 0] + skew_sym_mat[:, 1, 0] = vec[:, 2] + skew_sym_mat[:, 2, 0] = -vec[:, 1] + skew_sym_mat[:, 2, 1] = vec[:, 0] + + return skew_sym_mat + + +""" +Transformations +""" + + +def is_identity_pose(pos: torch.tensor, rot: torch.tensor) -> bool: + """Checks if input poses are identity transforms. + + The function checks if the input position and orientation are close to zero and + identity respectively using L2-norm. It does NOT check the error in the orientation. + + Args: + pos: The cartesian position. Shape is (N, 3). + rot: The quaternion in (w, x, y, z). Shape is (N, 4). + + Returns: + True if all the input poses result in identity transform. Otherwise, False. + """ + # create identity transformations + pos_identity = torch.zeros_like(pos) + rot_identity = torch.zeros_like(rot) + rot_identity[..., 0] = 1 + # compare input to identity + return torch.allclose(pos, pos_identity) and torch.allclose(rot, rot_identity) + + +@torch.jit.script +def combine_frame_transforms( + t01: torch.Tensor, + q01: torch.Tensor, + t12: Optional[torch.Tensor] = None, + q12: Optional[torch.Tensor] = None, +) -> tuple[torch.Tensor, torch.Tensor]: + r"""Combine transformations between two reference frames into a stationary frame. + + It performs the following transformation operation: :math:`T_{02} = T_{01} \times T_{12}`, + where :math:`T_{AB}` is the homogeneous transformation matrix from frame A to B. + + Args: + t01: Position of frame 1 w.r.t. frame 0. Shape is (N, 3). + q01: Quaternion orientation of frame 1 w.r.t. frame 0 in (w, x, y, z). Shape is (N, 4). + t12: Position of frame 2 w.r.t. frame 1. Shape is (N, 3). + Defaults to None, in which case the position is assumed to be zero. + q12: Quaternion orientation of frame 2 w.r.t. frame 1 in (w, x, y, z). Shape is (N, 4). + Defaults to None, in which case the orientation is assumed to be identity. + + Returns: + A tuple containing the position and orientation of frame 2 w.r.t. frame 0. + Shape of the tensors are (N, 3) and (N, 4) respectively. + """ + # compute orientation + if q12 is not None: + q02 = quat_mul(q01, q12) + else: + q02 = q01 + # compute translation + if t12 is not None: + t02 = t01 + quat_apply(q01, t12) + else: + t02 = t01 + + return t02, q02 + + +def rigid_body_twist_transform( + v0: torch.Tensor, w0: torch.Tensor, t01: torch.Tensor, q01: torch.Tensor +) -> tuple[torch.Tensor, torch.Tensor]: + r"""Transform the linear and angular velocity of a rigid body between reference frames. + + Given the twist of 0 relative to frame 0, this function computes the twist of 1 relative to frame 1 + from the position and orientation of frame 1 relative to frame 0. The transformation follows the + equations: + + .. math:: + + w_11 = R_{10} w_00 = R_{01}^{-1} w_00 + v_11 = R_{10} v_00 + R_{10} (w_00 \times t_01) = R_{01}^{-1} (v_00 + (w_00 \times t_01)) + + where + + - :math:`R_{01}` is the rotation matrix from frame 0 to frame 1 derived from quaternion :math:`q_{01}`. + - :math:`t_{01}` is the position of frame 1 relative to frame 0 expressed in frame 0 + - :math:`w_0` is the angular velocity of 0 in frame 0 + - :math:`v_0` is the linear velocity of 0 in frame 0 + + Args: + v0: Linear velocity of 0 in frame 0. Shape is (N, 3). + w0: Angular velocity of 0 in frame 0. Shape is (N, 3). + t01: Position of frame 1 w.r.t. frame 0. Shape is (N, 3). + q01: Quaternion orientation of frame 1 w.r.t. frame 0 in (w, x, y, z). Shape is (N, 4). + + Returns: + A tuple containing: + - The transformed linear velocity in frame 1. Shape is (N, 3). + - The transformed angular velocity in frame 1. Shape is (N, 3). + """ + w1 = quat_rotate_inverse(q01, w0) + v1 = quat_rotate_inverse(q01, v0 + torch.cross(w0, t01, dim=-1)) + return v1, w1 + + +# @torch.jit.script +def subtract_frame_transforms( + t01: torch.Tensor, + q01: torch.Tensor, + t02: Union[torch.Tensor, None] = None, + q02: Union[torch.Tensor, None] = None, +) -> tuple[torch.Tensor, torch.Tensor]: + r"""Subtract transformations between two reference frames into a stationary frame. + + It performs the following transformation operation: :math:`T_{12} = T_{01}^{-1} \times T_{02}`, + where :math:`T_{AB}` is the homogeneous transformation matrix from frame A to B. + + Args: + t01: Position of frame 1 w.r.t. frame 0. Shape is (N, 3). + q01: Quaternion orientation of frame 1 w.r.t. frame 0 in (w, x, y, z). Shape is (N, 4). + t02: Position of frame 2 w.r.t. frame 0. Shape is (N, 3). + Defaults to None, in which case the position is assumed to be zero. + q02: Quaternion orientation of frame 2 w.r.t. frame 0 in (w, x, y, z). Shape is (N, 4). + Defaults to None, in which case the orientation is assumed to be identity. + + Returns: + A tuple containing the position and orientation of frame 2 w.r.t. frame 1. + Shape of the tensors are (N, 3) and (N, 4) respectively. + """ + # compute orientation + q10 = quat_inv(q01) + if q02 is not None: + q12 = quat_mul(q10, q02) + else: + q12 = q10 + # compute translation + if t02 is not None: + t12 = quat_apply(q10, t02 - t01) + else: + t12 = quat_apply(q10, -t01) + return t12, q12 + + +# @torch.jit.script +def compute_pose_error( + t01: torch.Tensor, + q01: torch.Tensor, + t02: torch.Tensor, + q02: torch.Tensor, + rot_error_type: Literal["quat", "axis_angle"] = "axis_angle", +) -> tuple[torch.Tensor, torch.Tensor]: + """Compute the position and orientation error between source and target frames. + + Args: + t01: Position of source frame. Shape is (N, 3). + q01: Quaternion orientation of source frame in (w, x, y, z). Shape is (N, 4). + t02: Position of target frame. Shape is (N, 3). + q02: Quaternion orientation of target frame in (w, x, y, z). Shape is (N, 4). + rot_error_type: The rotation error type to return: "quat", "axis_angle". + Defaults to "axis_angle". + + Returns: + A tuple containing position and orientation error. Shape of position error is (N, 3). + Shape of orientation error depends on the value of :attr:`rot_error_type`: + + - If :attr:`rot_error_type` is "quat", the orientation error is returned + as a quaternion. Shape is (N, 4). + - If :attr:`rot_error_type` is "axis_angle", the orientation error is + returned as an axis-angle vector. Shape is (N, 3). + + Raises: + ValueError: Invalid rotation error type. + """ + # Compute quaternion error (i.e., difference quaternion) + # Reference: https://personal.utdallas.edu/~sxb027100/dock/quaternion.html + # q_current_norm = q_current * q_current_conj + source_quat_norm = quat_mul(q01, quat_conjugate(q01))[:, 0] + # q_current_inv = q_current_conj / q_current_norm + source_quat_inv = quat_conjugate(q01) / source_quat_norm.unsqueeze(-1) + # q_error = q_target * q_current_inv + quat_error = quat_mul(q02, source_quat_inv) + + # Compute position error + pos_error = t02 - t01 + + # return error based on specified type + if rot_error_type == "quat": + return pos_error, quat_error + elif rot_error_type == "axis_angle": + # Convert to axis-angle error + axis_angle_error = axis_angle_from_quat(quat_error) + return pos_error, axis_angle_error + else: + raise ValueError( + f"Unsupported orientation error type: {rot_error_type}. Valid: 'quat', 'axis_angle'." + ) + + +@torch.jit.script +def apply_delta_pose( + source_pos: torch.Tensor, + source_rot: torch.Tensor, + delta_pose: torch.Tensor, + eps: float = 1.0e-6, +) -> tuple[torch.Tensor, torch.Tensor]: + """Applies delta pose transformation on source pose. + + The first three elements of `delta_pose` are interpreted as cartesian position displacement. + The remaining three elements of `delta_pose` are interpreted as orientation displacement + in the angle-axis format. + + Args: + source_pos: Position of source frame. Shape is (N, 3). + source_rot: Quaternion orientation of source frame in (w, x, y, z). Shape is (N, 4).. + delta_pose: Position and orientation displacements. Shape is (N, 6). + eps: The tolerance to consider orientation displacement as zero. Defaults to 1.0e-6. + + Returns: + A tuple containing the displaced position and orientation frames. + Shape of the tensors are (N, 3) and (N, 4) respectively. + """ + # number of poses given + num_poses = source_pos.shape[0] + device = source_pos.device + + # interpret delta_pose[:, 0:3] as target position displacements + target_pos = source_pos + delta_pose[:, 0:3] + # interpret delta_pose[:, 3:6] as target rotation displacements + rot_actions = delta_pose[:, 3:6] + angle = torch.linalg.vector_norm(rot_actions, dim=1) + axis = rot_actions / angle.unsqueeze(-1) + # change from axis-angle to quat convention + identity_quat = torch.tensor([1.0, 0.0, 0.0, 0.0], device=device).repeat( + num_poses, 1 + ) + rot_delta_quat = torch.where( + angle.unsqueeze(-1).repeat(1, 4) > eps, + quat_from_angle_axis(angle, axis), + identity_quat, + ) + # TODO: Check if this is the correct order for this multiplication. + target_rot = quat_mul(rot_delta_quat, source_rot) + + return target_pos, target_rot + + +# @torch.jit.script +def transform_points( + points: torch.Tensor, + pos: Union[torch.Tensor, None] = None, + quat: Union[torch.Tensor, None] = None, +) -> torch.Tensor: + r"""Transform input points in a given frame to a target frame. + + This function transform points from a source frame to a target frame. The transformation is defined by the + position :math:`t` and orientation :math:`R` of the target frame in the source frame. + + .. math:: + p_{target} = R_{target} \times p_{source} + t_{target} + + If the input `points` is a batch of points, the inputs `pos` and `quat` must be either a batch of + positions and quaternions or a single position and quaternion. If the inputs `pos` and `quat` are + a single position and quaternion, the same transformation is applied to all points in the batch. + + If either the inputs :attr:`pos` and :attr:`quat` are None, the corresponding transformation is not applied. + + Args: + points: Points to transform. Shape is (N, P, 3) or (P, 3). + pos: Position of the target frame. Shape is (N, 3) or (3,). + Defaults to None, in which case the position is assumed to be zero. + quat: Quaternion orientation of the target frame in (w, x, y, z). Shape is (N, 4) or (4,). + Defaults to None, in which case the orientation is assumed to be identity. + + Returns: + Transformed points in the target frame. Shape is (N, P, 3) or (P, 3). + + Raises: + ValueError: If the inputs `points` is not of shape (N, P, 3) or (P, 3). + ValueError: If the inputs `pos` is not of shape (N, 3) or (3,). + ValueError: If the inputs `quat` is not of shape (N, 4) or (4,). + """ + points_batch = points.clone() + # check if inputs are batched + is_batched = points_batch.dim() == 3 + # -- check inputs + if points_batch.dim() == 2: + points_batch = points_batch[None] # (P, 3) -> (1, P, 3) + if points_batch.dim() != 3: + raise ValueError( + f"Expected points to have dim = 2 or dim = 3: got shape {points.shape}" + ) + if not (pos is None or pos.dim() == 1 or pos.dim() == 2): + raise ValueError( + f"Expected pos to have dim = 1 or dim = 2: got shape {pos.shape}" + ) + if not (quat is None or quat.dim() == 1 or quat.dim() == 2): + raise ValueError( + f"Expected quat to have dim = 1 or dim = 2: got shape {quat.shape}" + ) + # -- rotation + if quat is not None: + # convert to batched rotation matrix + rot_mat = matrix_from_quat(quat) + if rot_mat.dim() == 2: + rot_mat = rot_mat[None] # (3, 3) -> (1, 3, 3) + # convert points to matching batch size (N, P, 3) -> (N, 3, P) + # and apply rotation + points_batch = torch.matmul(rot_mat, points_batch.transpose_(1, 2)) + # (N, 3, P) -> (N, P, 3) + points_batch = points_batch.transpose_(1, 2) + # -- translation + if pos is not None: + # convert to batched translation vector + if pos.dim() == 1: + pos = pos[None, None, :] # (3,) -> (1, 1, 3) + else: + pos = pos[:, None, :] # (N, 3) -> (N, 1, 3) + # apply translation + points_batch += pos + # -- return points in same shape as input + if not is_batched: + points_batch = points_batch.squeeze(0) # (1, P, 3) -> (P, 3) + + return points_batch + + +""" +Projection operations. +""" + + +@torch.jit.script +def orthogonalize_perspective_depth( + depth: torch.Tensor, intrinsics: torch.Tensor +) -> torch.Tensor: + """Converts perspective depth image to orthogonal depth image. + + Perspective depth images contain distances measured from the camera's optical center. + Meanwhile, orthogonal depth images provide the distance from the camera's image plane. + This method uses the camera geometry to convert perspective depth to orthogonal depth image. + + The function assumes that the width and height are both greater than 1. + + Args: + depth: The perspective depth images. Shape is (H, W) or or (H, W, 1) or (N, H, W) or (N, H, W, 1). + intrinsics: The camera's calibration matrix. If a single matrix is provided, the same + calibration matrix is used across all the depth images in the batch. + Shape is (3, 3) or (N, 3, 3). + + Returns: + The orthogonal depth images. Shape matches the input shape of depth images. + + Raises: + ValueError: When depth is not of shape (H, W) or (H, W, 1) or (N, H, W) or (N, H, W, 1). + ValueError: When intrinsics is not of shape (3, 3) or (N, 3, 3). + """ + # Clone inputs to avoid in-place modifications + perspective_depth_batch = depth.clone() + intrinsics_batch = intrinsics.clone() + + # Check if inputs are batched + is_batched = perspective_depth_batch.dim() == 4 or ( + perspective_depth_batch.dim() == 3 and perspective_depth_batch.shape[-1] != 1 + ) + + # Track whether the last dimension was singleton + add_last_dim = False + if perspective_depth_batch.dim() == 4 and perspective_depth_batch.shape[-1] == 1: + add_last_dim = True + perspective_depth_batch = perspective_depth_batch.squeeze( + dim=3 + ) # (N, H, W, 1) -> (N, H, W) + if perspective_depth_batch.dim() == 3 and perspective_depth_batch.shape[-1] == 1: + add_last_dim = True + perspective_depth_batch = perspective_depth_batch.squeeze( + dim=2 + ) # (H, W, 1) -> (H, W) + + if perspective_depth_batch.dim() == 2: + perspective_depth_batch = perspective_depth_batch[None] # (H, W) -> (1, H, W) + + if intrinsics_batch.dim() == 2: + intrinsics_batch = intrinsics_batch[None] # (3, 3) -> (1, 3, 3) + + if is_batched and intrinsics_batch.shape[0] == 1: + intrinsics_batch = intrinsics_batch.expand( + perspective_depth_batch.shape[0], -1, -1 + ) # (1, 3, 3) -> (N, 3, 3) + + # Validate input shapes + if perspective_depth_batch.dim() != 3: + raise ValueError( + f"Expected depth images to have 2, 3, or 4 dimensions; got {depth.shape}." + ) + if intrinsics_batch.dim() != 3: + raise ValueError( + f"Expected intrinsics to have shape (3, 3) or (N, 3, 3); got {intrinsics.shape}." + ) + + # Image dimensions + im_height, im_width = perspective_depth_batch.shape[1:] + + # Get the intrinsics parameters + fx = intrinsics_batch[:, 0, 0].view(-1, 1, 1) + fy = intrinsics_batch[:, 1, 1].view(-1, 1, 1) + cx = intrinsics_batch[:, 0, 2].view(-1, 1, 1) + cy = intrinsics_batch[:, 1, 2].view(-1, 1, 1) + + # Create meshgrid of pixel coordinates + u_grid = torch.arange(im_width, device=depth.device, dtype=depth.dtype) + v_grid = torch.arange(im_height, device=depth.device, dtype=depth.dtype) + u_grid, v_grid = torch.meshgrid(u_grid, v_grid, indexing="xy") + + # Expand the grids for batch processing + u_grid = u_grid.unsqueeze(0).expand(perspective_depth_batch.shape[0], -1, -1) + v_grid = v_grid.unsqueeze(0).expand(perspective_depth_batch.shape[0], -1, -1) + + # Compute the squared terms for efficiency + x_term = ((u_grid - cx) / fx) ** 2 + y_term = ((v_grid - cy) / fy) ** 2 + + # Calculate the orthogonal (normal) depth + orthogonal_depth = perspective_depth_batch / torch.sqrt(1 + x_term + y_term) + + # Restore the last dimension if it was present in the input + if add_last_dim: + orthogonal_depth = orthogonal_depth.unsqueeze(-1) + + # Return to original shape if input was not batched + if not is_batched: + orthogonal_depth = orthogonal_depth.squeeze(0) + + return orthogonal_depth + + +@torch.jit.script +def unproject_depth( + depth: torch.Tensor, intrinsics: torch.Tensor, is_ortho: bool = True +) -> torch.Tensor: + r"""Un-project depth image into a pointcloud. + + This function converts orthogonal or perspective depth images into points given the calibration matrix + of the camera. It uses the following transformation based on camera geometry: + + .. math:: + p_{3D} = K^{-1} \times [u, v, 1]^T \times d + + where :math:`p_{3D}` is the 3D point, :math:`d` is the depth value (measured from the image plane), + :math:`u` and :math:`v` are the pixel coordinates and :math:`K` is the intrinsic matrix. + + The function assumes that the width and height are both greater than 1. This makes the function + deal with many possible shapes of depth images and intrinsics matrices. + + .. note:: + If :attr:`is_ortho` is False, the input depth images are transformed to orthogonal depth images + by using the :meth:`orthogonalize_perspective_depth` method. + + Args: + depth: The depth measurement. Shape is (H, W) or or (H, W, 1) or (N, H, W) or (N, H, W, 1). + intrinsics: The camera's calibration matrix. If a single matrix is provided, the same + calibration matrix is used across all the depth images in the batch. + Shape is (3, 3) or (N, 3, 3). + is_ortho: Whether the input depth image is orthogonal or perspective depth image. If True, the input + depth image is considered as the *orthogonal* type, where the measurements are from the camera's + image plane. If False, the depth image is considered as the *perspective* type, where the + measurements are from the camera's optical center. Defaults to True. + + Returns: + The 3D coordinates of points. Shape is (P, 3) or (N, P, 3). + + Raises: + ValueError: When depth is not of shape (H, W) or (H, W, 1) or (N, H, W) or (N, H, W, 1). + ValueError: When intrinsics is not of shape (3, 3) or (N, 3, 3). + """ + # clone inputs to avoid in-place modifications + intrinsics_batch = intrinsics.clone() + # convert depth image to orthogonal if needed + if not is_ortho: + depth_batch = orthogonalize_perspective_depth(depth, intrinsics) + else: + depth_batch = depth.clone() + + # check if inputs are batched + is_batched = depth_batch.dim() == 4 or ( + depth_batch.dim() == 3 and depth_batch.shape[-1] != 1 + ) + # make sure inputs are batched + if depth_batch.dim() == 3 and depth_batch.shape[-1] == 1: + depth_batch = depth_batch.squeeze(dim=2) # (H, W, 1) -> (H, W) + if depth_batch.dim() == 2: + depth_batch = depth_batch[None] # (H, W) -> (1, H, W) + if depth_batch.dim() == 4 and depth_batch.shape[-1] == 1: + depth_batch = depth_batch.squeeze(dim=3) # (N, H, W, 1) -> (N, H, W) + if intrinsics_batch.dim() == 2: + intrinsics_batch = intrinsics_batch[None] # (3, 3) -> (1, 3, 3) + # check shape of inputs + if depth_batch.dim() != 3: + raise ValueError( + f"Expected depth images to have dim = 2 or 3 or 4: got shape {depth.shape}" + ) + if intrinsics_batch.dim() != 3: + raise ValueError( + f"Expected intrinsics to have shape (3, 3) or (N, 3, 3): got shape {intrinsics.shape}" + ) + + # get image height and width + im_height, im_width = depth_batch.shape[1:] + # create image points in homogeneous coordinates (3, H x W) + indices_u = torch.arange(im_width, device=depth.device, dtype=depth.dtype) + indices_v = torch.arange(im_height, device=depth.device, dtype=depth.dtype) + img_indices = torch.stack( + torch.meshgrid([indices_u, indices_v], indexing="ij"), dim=0 + ).reshape(2, -1) + pixels = torch.nn.functional.pad( + img_indices, (0, 0, 0, 1), mode="constant", value=1.0 + ) + pixels = pixels.unsqueeze(0) # (3, H x W) -> (1, 3, H x W) + + # unproject points into 3D space + points = torch.matmul(torch.inverse(intrinsics_batch), pixels) # (N, 3, H x W) + points = points / points[:, -1, :].unsqueeze(1) # normalize by last coordinate + # flatten depth image (N, H, W) -> (N, H x W) + depth_batch = ( + depth_batch.transpose_(1, 2).reshape(depth_batch.shape[0], -1).unsqueeze(2) + ) + depth_batch = depth_batch.expand(-1, -1, 3) + # scale points by depth + points_xyz = points.transpose_(1, 2) * depth_batch # (N, H x W, 3) + + # return points in same shape as input + if not is_batched: + points_xyz = points_xyz.squeeze(0) + + return points_xyz + + +@torch.jit.script +def project_points(points: torch.Tensor, intrinsics: torch.Tensor) -> torch.Tensor: + r"""Projects 3D points into 2D image plane. + + This project 3D points into a 2D image plane. The transformation is defined by the intrinsic + matrix of the camera. + + .. math:: + + \begin{align} + p &= K \times p_{3D} = \\ + p_{2D} &= \begin{pmatrix} u \\ v \\ d \end{pmatrix} + = \begin{pmatrix} p[0] / p[2] \\ p[1] / p[2] \\ Z \end{pmatrix} + \end{align} + + where :math:`p_{2D} = (u, v, d)` is the projected 3D point, :math:`p_{3D} = (X, Y, Z)` is the + 3D point and :math:`K \in \mathbb{R}^{3 \times 3}` is the intrinsic matrix. + + If `points` is a batch of 3D points and `intrinsics` is a single intrinsic matrix, the same + calibration matrix is applied to all points in the batch. + + Args: + points: The 3D coordinates of points. Shape is (P, 3) or (N, P, 3). + intrinsics: Camera's calibration matrix. Shape is (3, 3) or (N, 3, 3). + + Returns: + Projected 3D coordinates of points. Shape is (P, 3) or (N, P, 3). + """ + # clone the inputs to avoid in-place operations modifying the original data + points_batch = points.clone() + intrinsics_batch = intrinsics.clone() + + # check if inputs are batched + is_batched = points_batch.dim() == 2 + # make sure inputs are batched + if points_batch.dim() == 2: + points_batch = points_batch[None] # (P, 3) -> (1, P, 3) + if intrinsics_batch.dim() == 2: + intrinsics_batch = intrinsics_batch[None] # (3, 3) -> (1, 3, 3) + # check shape of inputs + if points_batch.dim() != 3: + raise ValueError(f"Expected points to have dim = 3: got shape {points.shape}.") + if intrinsics_batch.dim() != 3: + raise ValueError( + f"Expected intrinsics to have shape (3, 3) or (N, 3, 3): got shape {intrinsics.shape}." + ) + + # project points into 2D image plane + points_2d = torch.matmul(intrinsics_batch, points_batch.transpose(1, 2)) + points_2d = points_2d / points_2d[:, -1, :].unsqueeze( + 1 + ) # normalize by last coordinate + points_2d = points_2d.transpose_(1, 2) # (N, 3, P) -> (N, P, 3) + # replace last coordinate with depth + points_2d[:, :, -1] = points_batch[:, :, -1] + + # return points in same shape as input + if not is_batched: + points_2d = points_2d.squeeze(0) # (1, 3, P) -> (3, P) + + return points_2d + + +""" +Sampling +""" + + +@torch.jit.script +def default_orientation(num: int, device: str) -> torch.Tensor: + """Returns identity rotation transform. + + Args: + num: The number of rotations to sample. + device: Device to create tensor on. + + Returns: + Identity quaternion in (w, x, y, z). Shape is (num, 4). + """ + quat = torch.zeros((num, 4), dtype=torch.float32, device=device) + quat[..., 0] = 1.0 + + return quat + + +@torch.jit.script +def random_orientation(num: int, device: str) -> torch.Tensor: + """Returns sampled rotation in 3D as quaternion. + + Args: + num: The number of rotations to sample. + device: Device to create tensor on. + + Returns: + Sampled quaternion in (w, x, y, z). Shape is (num, 4). + + Reference: + https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.transform.Rotation.random.html + """ + # sample random orientation from normal distribution + quat = torch.randn((num, 4), dtype=torch.float32, device=device) + # normalize the quaternion + return torch.nn.functional.normalize(quat, p=2.0, dim=-1, eps=1e-12) + + +@torch.jit.script +def random_yaw_orientation(num: int, device: str) -> torch.Tensor: + """Returns sampled rotation around z-axis. + + Args: + num: The number of rotations to sample. + device: Device to create tensor on. + + Returns: + Sampled quaternion in (w, x, y, z). Shape is (num, 4). + """ + roll = torch.zeros(num, dtype=torch.float32, device=device) + pitch = torch.zeros(num, dtype=torch.float32, device=device) + yaw = 2 * torch.pi * torch.rand(num, dtype=torch.float32, device=device) + + return quat_from_euler_xyz(roll, pitch, yaw) + + +def sample_triangle( + lower: float, upper: float, size: Union[int, tuple[int, ...]], device: str +) -> torch.Tensor: + """Randomly samples tensor from a triangular distribution. + + Args: + lower: The lower range of the sampled tensor. + upper: The upper range of the sampled tensor. + size: The shape of the tensor. + device: Device to create tensor on. + + Returns: + Sampled tensor. Shape is based on :attr:`size`. + """ + # convert to tuple + if isinstance(size, int): + size = (size,) + # create random tensor in the range [-1, 1] + r = 2 * torch.rand(*size, device=device) - 1 + # convert to triangular distribution + r = torch.where(r < 0.0, -torch.sqrt(-r), torch.sqrt(r)) + # rescale back to [0, 1] + r = (r + 1.0) / 2.0 + # rescale to range [lower, upper] + return (upper - lower) * r + lower + + +def sample_uniform( + lower: Union[torch.Tensor, float], + upper: Union[torch.Tensor, float], + size: Union[int, tuple[int, ...]], +) -> torch.Tensor: + """Sample uniformly within a range. + + Args: + lower: Lower bound of uniform range. + upper: Upper bound of uniform range. + size: The shape of the tensor. + device: Device to create tensor on. + + Returns: + Sampled tensor. Shape is based on :attr:`size`. + """ + # convert to tuple + if isinstance(size, int): + size = (size,) + # return tensor + return torch.rand(*size, device=lower.device) * (upper - lower) + lower + + +def sample_log_uniform( + lower: Union[torch.Tensor, float], + upper: Union[torch.Tensor, float], + size: Union[int, tuple[int, ...]], + device: str, +) -> torch.Tensor: + r"""Sample using log-uniform distribution within a range. + + The log-uniform distribution is defined as a uniform distribution in the log-space. It + is useful for sampling values that span several orders of magnitude. The sampled values + are uniformly distributed in the log-space and then exponentiated to get the final values. + + .. math:: + + x = \exp(\text{uniform}(\log(\text{lower}), \log(\text{upper}))) + + Args: + lower: Lower bound of uniform range. + upper: Upper bound of uniform range. + size: The shape of the tensor. + device: Device to create tensor on. + + Returns: + Sampled tensor. Shape is based on :attr:`size`. + """ + # cast to tensor if not already + if not isinstance(lower, torch.Tensor): + lower = torch.tensor(lower, dtype=torch.float32, device=device) + if not isinstance(upper, torch.Tensor): + upper = torch.tensor(upper, dtype=torch.float32, device=device) + # sample in log-space and exponentiate + return torch.exp(sample_uniform(torch.log(lower), torch.log(upper), size, device)) + + +def sample_gaussian( + mean: Union[torch.Tensor, float], + std: Union[torch.Tensor, float], + size: Union[int, tuple[int, ...]], + device: str, +) -> torch.Tensor: + """Sample using gaussian distribution. + + Args: + mean: Mean of the gaussian. + std: Std of the gaussian. + size: The shape of the tensor. + device: Device to create tensor on. + + Returns: + Sampled tensor. + """ + if isinstance(mean, float): + if isinstance(size, int): + size = (size,) + return torch.normal(mean=mean, std=std, size=size).to(device=device) + else: + return torch.normal(mean=mean, std=std).to(device=device) + + +def sample_cylinder( + radius: float, + h_range: tuple[float, float], + size: Union[int, tuple[int, ...]], + device: str, +) -> torch.Tensor: + """Sample 3D points uniformly on a cylinder's surface. + + The cylinder is centered at the origin and aligned with the z-axis. The height of the cylinder is + sampled uniformly from the range :obj:`h_range`, while the radius is fixed to :obj:`radius`. + + The sampled points are returned as a tensor of shape :obj:`(*size, 3)`, i.e. the last dimension + contains the x, y, and z coordinates of the sampled points. + + Args: + radius: The radius of the cylinder. + h_range: The minimum and maximum height of the cylinder. + size: The shape of the tensor. + device: Device to create tensor on. + + Returns: + Sampled tensor. Shape is :obj:`(*size, 3)`. + """ + # sample angles + angles = (torch.rand(size, device=device) * 2 - 1) * torch.pi + h_min, h_max = h_range + # add shape + if isinstance(size, int): + size = (size, 3) + else: + size += (3,) + # allocate a tensor + xyz = torch.zeros(size, device=device) + xyz[..., 0] = radius * torch.cos(angles) + xyz[..., 1] = radius * torch.sin(angles) + xyz[..., 2].uniform_(h_min, h_max) + # return positions + return xyz + + +""" +Orientation Conversions +""" + + +def convert_camera_frame_orientation_convention( + orientation: torch.Tensor, + origin: Literal["opengl", "ros", "world"] = "opengl", + target: Literal["opengl", "ros", "world"] = "ros", +) -> torch.Tensor: + r"""Converts a quaternion representing a rotation from one convention to another. + + In USD, the camera follows the ``"opengl"`` convention. Thus, it is always in **Y up** convention. + This means that the camera is looking down the -Z axis with the +Y axis pointing up , and +X axis pointing right. + However, in ROS, the camera is looking down the +Z axis with the +Y axis pointing down, and +X axis pointing right. + Thus, the camera needs to be rotated by :math:`180^{\circ}` around the X axis to follow the ROS convention. + + .. math:: + + T_{ROS} = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & -1 & 0 & 0 \\ 0 & 0 & -1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} T_{USD} + + On the other hand, the typical world coordinate system is with +X pointing forward, +Y pointing left, + and +Z pointing up. The camera can also be set in this convention by rotating the camera by :math:`90^{\circ}` + around the X axis and :math:`-90^{\circ}` around the Y axis. + + .. math:: + + T_{WORLD} = \begin{bmatrix} 0 & 0 & -1 & 0 \\ -1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} T_{USD} + + Thus, based on their application, cameras follow different conventions for their orientation. This function + converts a quaternion from one convention to another. + + Possible conventions are: + + - :obj:`"opengl"` - forward axis: -Z - up axis +Y - Offset is applied in the OpenGL (Usd.Camera) convention + - :obj:`"ros"` - forward axis: +Z - up axis -Y - Offset is applied in the ROS convention + - :obj:`"world"` - forward axis: +X - up axis +Z - Offset is applied in the World Frame convention + + Args: + orientation: Quaternion of form `(w, x, y, z)` with shape (..., 4) in source convention. + origin: Convention to convert from. Defaults to "opengl". + target: Convention to convert to. Defaults to "ros". + + Returns: + Quaternion of form `(w, x, y, z)` with shape (..., 4) in target convention + """ + if target == origin: + return orientation.clone() + + # -- unify input type + if origin == "ros": + # convert from ros to opengl convention + rotm = matrix_from_quat(orientation) + rotm[:, :, 2] = -rotm[:, :, 2] + rotm[:, :, 1] = -rotm[:, :, 1] + # convert to opengl convention + quat_gl = quat_from_matrix(rotm) + elif origin == "world": + # convert from world (x forward and z up) to opengl convention + rotm = matrix_from_quat(orientation) + rotm = torch.matmul( + rotm, + matrix_from_euler( + torch.tensor([math.pi / 2, -math.pi / 2, 0], device=orientation.device), + "XYZ", + ), + ) + # convert to isaac-sim convention + quat_gl = quat_from_matrix(rotm) + else: + quat_gl = orientation + + # -- convert to target convention + if target == "ros": + # convert from opengl to ros convention + rotm = matrix_from_quat(quat_gl) + rotm[:, :, 2] = -rotm[:, :, 2] + rotm[:, :, 1] = -rotm[:, :, 1] + return quat_from_matrix(rotm) + elif target == "world": + # convert from opengl to world (x forward and z up) convention + rotm = matrix_from_quat(quat_gl) + rotm = torch.matmul( + rotm, + matrix_from_euler( + torch.tensor([math.pi / 2, -math.pi / 2, 0], device=orientation.device), + "XYZ", + ).T, + ) + return quat_from_matrix(rotm) + else: + return quat_gl.clone() + + +def create_rotation_matrix_from_view( + eyes: torch.Tensor, + targets: torch.Tensor, + up_axis: Literal["Y", "Z"] = "Z", + device: str = "cpu", +) -> torch.Tensor: + """Compute the rotation matrix from world to view coordinates. + + This function takes a vector ''eyes'' which specifies the location + of the camera in world coordinates and the vector ''targets'' which + indicate the position of the object. + The output is a rotation matrix representing the transformation + from world coordinates -> view coordinates. + + The inputs eyes and targets can each be a + - 3 element tuple/list + - torch tensor of shape (1, 3) + - torch tensor of shape (N, 3) + + Args: + eyes: Position of the camera in world coordinates. + targets: Position of the object in world coordinates. + up_axis: The up axis of the camera. Defaults to "Z". + device: The device to create torch tensors on. Defaults to "cpu". + + The vectors are broadcast against each other so they all have shape (N, 3). + + Returns: + R: (N, 3, 3) batched rotation matrices + + Reference: + Based on PyTorch3D (https://github.com/facebookresearch/pytorch3d/blob/eaf0709d6af0025fe94d1ee7cec454bc3054826a/pytorch3d/renderer/cameras.py#L1635-L1685) + """ + if up_axis == "Y": + up_axis_vec = torch.tensor( + (0, 1, 0), device=device, dtype=torch.float32 + ).repeat(eyes.shape[0], 1) + elif up_axis == "Z": + up_axis_vec = torch.tensor( + (0, 0, 1), device=device, dtype=torch.float32 + ).repeat(eyes.shape[0], 1) + else: + raise ValueError(f"Invalid up axis: {up_axis}. Valid options are 'Y' and 'Z'.") + + # get rotation matrix in opengl format (-Z forward, +Y up) + z_axis = -torch.nn.functional.normalize(targets - eyes, eps=1e-5) + x_axis = torch.nn.functional.normalize( + torch.cross(up_axis_vec, z_axis, dim=1), eps=1e-5 + ) + y_axis = torch.nn.functional.normalize(torch.cross(z_axis, x_axis, dim=1), eps=1e-5) + is_close = torch.isclose(x_axis, torch.tensor(0.0), atol=5e-3).all( + dim=1, keepdim=True + ) + if is_close.any(): + replacement = torch.nn.functional.normalize( + torch.cross(y_axis, z_axis, dim=1), eps=1e-5 + ) + x_axis = torch.where(is_close, replacement, x_axis) + R = torch.cat((x_axis[:, None, :], y_axis[:, None, :], z_axis[:, None, :]), dim=1) + return R.transpose(1, 2) + + +def make_pose(pos: torch.Tensor, rot: torch.Tensor) -> torch.Tensor: + """Creates transformation matrices from positions and rotation matrices. + + Args: + pos: Batch of position vectors with last dimension of 3. + rot: Batch of rotation matrices with last 2 dimensions of (3, 3). + + Returns: + Batch of pose matrices with last 2 dimensions of (4, 4). + """ + assert isinstance(pos, torch.Tensor), "Input must be a torch tensor" + assert isinstance(rot, torch.Tensor), "Input must be a torch tensor" + assert pos.shape[:-1] == rot.shape[:-2] + assert pos.shape[-1] == rot.shape[-2] == rot.shape[-1] == 3 + pose = torch.zeros(pos.shape[:-1] + (4, 4), dtype=pos.dtype, device=pos.device) + pose[..., :3, :3] = rot + pose[..., :3, 3] = pos + pose[..., 3, 3] = 1.0 + return pose + + +def unmake_pose(pose: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]: + """Splits transformation matrices into positions and rotation matrices. + + Args: + pose: Batch of pose matrices with last 2 dimensions of (4, 4). + + Returns: + Tuple containing: + - Batch of position vectors with last dimension of 3. + - Batch of rotation matrices with last 2 dimensions of (3, 3). + """ + assert isinstance(pose, torch.Tensor), "Input must be a torch tensor" + return pose[..., :3, 3], pose[..., :3, :3] + + +def pose_inv(pose: torch.Tensor) -> torch.Tensor: + """Computes the inverse of transformation matrices. + + The inverse of a pose matrix [R t; 0 1] is [R.T -R.T*t; 0 1]. + + Args: + pose: Batch of pose matrices with last 2 dimensions of (4, 4). + + Returns: + Batch of inverse pose matrices with last 2 dimensions of (4, 4). + """ + assert isinstance(pose, torch.Tensor), "Input must be a torch tensor" + num_axes = len(pose.shape) + assert num_axes >= 2 + + inv_pose = torch.zeros_like(pose) + + # Take transpose of last 2 dimensions + inv_pose[..., :3, :3] = pose[..., :3, :3].transpose(-1, -2) + + # note: PyTorch matmul wants shapes [..., 3, 3] x [..., 3, 1] -> [..., 3, 1] so we add a dimension and take it away after + inv_pose[..., :3, 3] = torch.matmul(-inv_pose[..., :3, :3], pose[..., :3, 3:4])[ + ..., 0 + ] + inv_pose[..., 3, 3] = 1.0 + return inv_pose + + +def pose_in_A_to_pose_in_B( + pose_in_A: torch.Tensor, pose_A_in_B: torch.Tensor +) -> torch.Tensor: + """Converts poses from one coordinate frame to another. + + Transforms matrices representing point C in frame A + to matrices representing the same point C in frame B. + + Example usage: + + frame_C_in_B = pose_in_A_to_pose_in_B(frame_C_in_A, frame_A_in_B) + + Args: + pose_in_A: Batch of transformation matrices of point C in frame A. + pose_A_in_B: Batch of transformation matrices of frame A in frame B. + + Returns: + Batch of transformation matrices of point C in frame B. + """ + assert isinstance(pose_in_A, torch.Tensor), "Input must be a torch tensor" + assert isinstance(pose_A_in_B, torch.Tensor), "Input must be a torch tensor" + return torch.matmul(pose_A_in_B, pose_in_A) + + +def quat_slerp(q1: torch.Tensor, q2: torch.Tensor, tau: float) -> torch.Tensor: + """Performs spherical linear interpolation (SLERP) between two quaternions. + + This function does not support batch processing. + + Args: + q1: First quaternion in (w, x, y, z) format. + q2: Second quaternion in (w, x, y, z) format. + tau: Interpolation coefficient between 0 (q1) and 1 (q2). + + Returns: + Interpolated quaternion in (w, x, y, z) format. + """ + assert isinstance(q1, torch.Tensor), "Input must be a torch tensor" + assert isinstance(q2, torch.Tensor), "Input must be a torch tensor" + if tau == 0.0: + return q1 + elif tau == 1.0: + return q2 + d = torch.dot(q1, q2) + if abs(abs(d) - 1.0) < torch.finfo(q1.dtype).eps * 4.0: + return q1 + if d < 0.0: + # Invert rotation + d = -d + q2 *= -1.0 + angle = torch.acos(torch.clamp(d, -1, 1)) + if abs(angle) < torch.finfo(q1.dtype).eps * 4.0: + return q1 + isin = 1.0 / torch.sin(angle) + q1 = q1 * torch.sin((1.0 - tau) * angle) * isin + q2 = q2 * torch.sin(tau * angle) * isin + q1 = q1 + q2 + return q1 + + +def interpolate_rotations( + R1: torch.Tensor, R2: torch.Tensor, num_steps: int, axis_angle: bool = True +) -> torch.Tensor: + """Interpolates between two rotation matrices. + + Args: + R1: First rotation matrix. (4x4). + R2: Second rotation matrix. (4x4). + num_steps: Number of desired interpolated rotations (excluding start and end). + axis_angle: If True, interpolate in axis-angle representation; + otherwise use slerp. Defaults to True. + + Returns: + Stack of interpolated rotation matrices of shape (num_steps + 1, 4, 4), + including the start and end rotations. + """ + assert isinstance(R1, torch.Tensor), "Input must be a torch tensor" + assert isinstance(R2, torch.Tensor), "Input must be a torch tensor" + if axis_angle: + # Delta rotation expressed as axis-angle + delta_rot_mat = torch.matmul(R2, R1.transpose(-1, -2)) + delta_quat = quat_from_matrix(delta_rot_mat) + delta_axis_angle = axis_angle_from_quat(delta_quat) + + # Grab angle + delta_angle = torch.linalg.norm(delta_axis_angle) + + # Fix the axis, and chunk the angle up into steps + rot_step_size = delta_angle / num_steps + + # Convert into delta rotation matrices, and then convert to absolute rotations + if delta_angle < 0.05: + # Small angle - don't bother with interpolation + rot_steps = torch.stack([R2 for _ in range(num_steps)]) + else: + # Make sure that axis is a unit vector + delta_axis = delta_axis_angle / delta_angle + delta_rot_steps = [ + matrix_from_quat(quat_from_angle_axis(i * rot_step_size, delta_axis)) + for i in range(num_steps) + ] + rot_steps = torch.stack( + [torch.matmul(delta_rot_steps[i], R1) for i in range(num_steps)] + ) + else: + q1 = quat_from_matrix(R1) + q2 = quat_from_matrix(R2) + rot_steps = torch.stack( + [ + matrix_from_quat(quat_slerp(q1, q2, tau=float(i) / num_steps)) + for i in range(num_steps) + ] + ) + + # Add in endpoint + rot_steps = torch.cat([rot_steps, R2[None]], dim=0) + + return rot_steps + + +def interpolate_poses( + pose_1: torch.Tensor, + pose_2: torch.Tensor, + num_steps: int = None, + step_size: float = None, + perturb: bool = False, +) -> tuple[torch.Tensor, int]: + """Performs linear interpolation between two poses. + + Args: + pose_1: 4x4 start pose. + pose_2: 4x4 end pose. + num_steps: If provided, specifies the number of desired interpolated points. + Passing 0 corresponds to no interpolation. If None, step_size must be provided. + step_size: If provided, determines number of steps based on distance between poses. + perturb: If True, randomly perturbs interpolated position points. + + Returns: + Tuple containing: + - Array of shape (N + 2, 4, 4) corresponding to the interpolated pose path. + - Number of interpolated points (N) in the path. + """ + assert isinstance(pose_1, torch.Tensor), "Input must be a torch tensor" + assert isinstance(pose_2, torch.Tensor), "Input must be a torch tensor" + assert step_size is None or num_steps is None + + pos1, rot1 = unmake_pose(pose_1) + pos2, rot2 = unmake_pose(pose_2) + + if num_steps == 0: + # Skip interpolation + return ( + torch.cat([pos1[None], pos2[None]], dim=0), + torch.cat([rot1[None], rot2[None]], dim=0), + num_steps, + ) + + delta_pos = pos2 - pos1 + if num_steps is None: + assert torch.norm(delta_pos) > 0 + num_steps = math.ceil(torch.norm(delta_pos) / step_size) + + num_steps += 1 # Include starting pose + assert num_steps >= 2 + + # Linear interpolation of positions + pos_step_size = delta_pos / num_steps + grid = torch.arange(num_steps, dtype=torch.float32) + if perturb: + # Move interpolation grid points by up to half-size forward or backward + perturbations = torch.rand(num_steps - 2) - 0.5 + grid[1:-1] += perturbations + pos_steps = torch.stack([pos1 + grid[i] * pos_step_size for i in range(num_steps)]) + + # Add in endpoint + pos_steps = torch.cat([pos_steps, pos2[None]], dim=0) + + # Interpolate rotations + rot_steps = interpolate_rotations( + R1=rot1, R2=rot2, num_steps=num_steps, axis_angle=True + ) + + pose_steps = make_pose(pos_steps, rot_steps) + return pose_steps, num_steps - 1 + + +def transform_poses_from_frame_A_to_frame_B( + src_poses: torch.Tensor, frame_A: torch.Tensor, frame_B: torch.Tensor +) -> torch.Tensor: + """Transforms poses from one coordinate frame to another preserving relative poses. + + Args: + src_poses: Input pose sequence (shape [T, 4, 4]) from source demonstration. + frame_A: 4x4 frame A pose. + frame_B: 4x4 frame B pose. + + Returns: + Transformed pose sequence of shape [T, 4, 4]. + """ + # Transform source end effector poses to be relative to source object frame + src_poses_rel_frame_B = pose_in_A_to_pose_in_B( + pose_in_A=src_poses, + pose_A_in_B=pose_inv(frame_B[None]), + ) + + # Apply relative poses to current object frame to obtain new target eef poses + transformed_poses = pose_in_A_to_pose_in_B( + pose_in_A=src_poses_rel_frame_B, + pose_A_in_B=frame_A[None], + ) + return transformed_poses + + +def generate_random_rotation(rot_boundary: float = (2 * math.pi)) -> torch.Tensor: + """Generates a random rotation matrix using Euler angles. + + Args: + rot_boundary: Range for random rotation angles around each axis (x, y, z). + + Returns: + 3x3 rotation matrix. + """ + angles = torch.rand(3) * rot_boundary + Rx = torch.tensor( + [ + [1, 0, 0], + [0, torch.cos(angles[0]), -torch.sin(angles[0])], + [0, torch.sin(angles[0]), torch.cos(angles[0])], + ] + ) + + Ry = torch.tensor( + [ + [torch.cos(angles[1]), 0, torch.sin(angles[1])], + [0, 1, 0], + [-torch.sin(angles[1]), 0, torch.cos(angles[1])], + ] + ) + + Rz = torch.tensor( + [ + [torch.cos(angles[2]), -torch.sin(angles[2]), 0], + [torch.sin(angles[2]), torch.cos(angles[2]), 0], + [0, 0, 1], + ] + ) + + # Combined rotation matrix + R = torch.matmul(torch.matmul(Rz, Ry), Rx) + return R + + +def generate_random_translation(pos_boundary: float = 1) -> torch.Tensor: + """Generates a random translation vector. + + Args: + pos_boundary: Range for random translation values in 3D space. + + Returns: + 3-element translation vector. + """ + return ( + torch.rand(3) * 2 * pos_boundary - pos_boundary + ) # Random translation in 3D space + + +def generate_random_transformation_matrix( + pos_boundary: float = 1, rot_boundary: float = (2 * math.pi) +) -> torch.Tensor: + """Generates a random transformation matrix combining rotation and translation. + + Args: + pos_boundary: Range for random translation values. + rot_boundary: Range for random rotation angles. + + Returns: + 4x4 transformation matrix. + """ + R = generate_random_rotation(rot_boundary) + translation = generate_random_translation(pos_boundary) + + # Create the transformation matrix + T = torch.eye(4) + T[:3, :3] = R + T[:3, 3] = translation + + return T diff --git a/embodichain/utils/module_utils.py b/embodichain/utils/module_utils.py new file mode 100644 index 00000000..a62eb41c --- /dev/null +++ b/embodichain/utils/module_utils.py @@ -0,0 +1,217 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import importlib +from typing import List, Union, Optional, Callable, Any + + +def find_function_from_modules( + function_name: str, modules: List[Union[str, Any]], raise_if_not_found: bool = True +) -> Optional[Callable]: + """ + Find a function from multiple Python modules. + + Args: + function_name (str): Name of the function to find + modules (List[Union[str, Any]]): List of module names (strings) or module objects + raise_if_not_found (bool): Whether to raise an exception if function is not found + + Returns: + Optional[Callable]: The function if found, None otherwise + + Raises: + AttributeError: If function is not found and raise_if_not_found is True + ImportError: If a module cannot be imported + """ + for module in modules: + try: + # Handle both module names (strings) and module objects + if isinstance(module, str): + mod = importlib.import_module(module) + else: + mod = module + + # Check if the function exists in this module + if hasattr(mod, function_name): + return getattr(mod, function_name) + + except ImportError as e: + print(f"Warning: Could not import module {module}: {e}") + continue + + if raise_if_not_found: + raise AttributeError( + f"Function '{function_name}' not found in any of the provided modules: {modules}" + ) + + return None + + +def find_class_from_modules( + class_name: str, modules: List[Union[str, Any]], raise_if_not_found: bool = True +) -> Optional[type]: + """ + Find a class from multiple Python modules. + + Args: + class_name (str): Name of the class to find + modules (List[Union[str, Any]]): List of module names (strings) or module objects + raise_if_not_found (bool): Whether to raise an exception if class is not found + + Returns: + Optional[type]: The class if found, None otherwise + + Raises: + AttributeError: If class is not found and raise_if_not_found is True + ImportError: If a module cannot be imported + """ + for module in modules: + try: + # Handle both module names (strings) and module objects + if isinstance(module, str): + mod = importlib.import_module(module) + else: + mod = module + + # Check if the class exists in this module + if hasattr(mod, class_name): + return getattr(mod, class_name) + + except ImportError as e: + print(f"Warning: Could not import module {module}: {e}") + continue + + if raise_if_not_found: + raise AttributeError( + f"Class '{class_name}' not found in any of the provided modules: {modules}" + ) + + return None + + +def get_all_functions_from_module(module: Union[str, Any]) -> dict: + """ + Get all functions from a module. + + Args: + module (Union[str, Any]): Module name (string) or module object + + Returns: + dict: Dictionary mapping function names to function objects + """ + import inspect + + if isinstance(module, str): + mod = importlib.import_module(module) + else: + mod = module + + functions = {} + for name, obj in inspect.getmembers(mod): + if inspect.isfunction(obj): + functions[name] = obj + + return functions + + +def find_function_by_pattern( + pattern: str, modules: List[Union[str, Any]], case_sensitive: bool = True +) -> dict: + """ + Find functions matching a pattern from multiple modules. + + Args: + pattern (str): Pattern to match (supports wildcards * and ?) + modules (List[Union[str, Any]]): List of module names or module objects + case_sensitive (bool): Whether the search should be case sensitive + + Returns: + dict: Dictionary mapping module names to dictionaries of matching functions + """ + import fnmatch + + results = {} + + for module in modules: + try: + if isinstance(module, str): + mod = importlib.import_module(module) + module_name = module + else: + mod = module + module_name = mod.__name__ + + module_functions = get_all_functions_from_module(mod) + matching_functions = {} + + for func_name, func_obj in module_functions.items(): + if case_sensitive: + if fnmatch.fnmatch(func_name, pattern): + matching_functions[func_name] = func_obj + else: + if fnmatch.fnmatch(func_name.lower(), pattern.lower()): + matching_functions[func_name] = func_obj + + if matching_functions: + results[module_name] = matching_functions + + except ImportError as e: + print(f"Warning: Could not import module {module}: {e}") + continue + + return results + + +def get_all_exported_items_from_module(module: Union[str, Any]) -> List[str]: + """ + Get all exported items from a module by checking its __all__ attribute. + + Args: + module (Union[str, Any]): Module name (string) or module object + + Returns: + List[str]: List of exported item names + """ + if isinstance(module, str): + mod = importlib.import_module(module) + else: + mod = module + + if hasattr(mod, "__all__"): + return list(mod.__all__) + else: + # If __all__ is not defined, return all public attributes (not starting with _) + return [name for name in dir(mod) if not name.startswith("_")] + + +# Example usage and test functions +if __name__ == "__main__": + # Example 1: Find a specific function from multiple modules + modules_to_search = ["math", "os", "sys"] + + # Find 'sqrt' function + sqrt_func = find_function_from_modules( + "sqrt", modules_to_search, raise_if_not_found=False + ) + if sqrt_func: + print(f"Found sqrt function: {sqrt_func}") + print(f"sqrt(16) = {sqrt_func(16)}") + + # Example 2: Find functions by pattern + pattern_results = find_function_by_pattern( + "*path*", ["os", "os.path"], case_sensitive=False + ) + print(f"Functions matching '*path*': {pattern_results}") diff --git a/embodichain/utils/string.py b/embodichain/utils/string.py new file mode 100644 index 00000000..ba794f75 --- /dev/null +++ b/embodichain/utils/string.py @@ -0,0 +1,336 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# All rights reserved. +# +# This file incorporates code from the Isaac Lab Project +# Copyright (c) 2022-2025, The Isaac Lab Project Developers +# (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# ---------------------------------------------------------------------------- + + +import ast +import importlib +import inspect +import re +from collections.abc import Callable, Sequence +from typing import Any, Union + + +def callable_to_string(value: Callable) -> str: + """Converts a callable object to a string. + + Args: + value: A callable object. + + Raises: + ValueError: When the input argument is not a callable object. + + Returns: + A string representation of the callable object. + """ + # check if callable + if not callable(value): + raise ValueError(f"The input argument is not callable: {value}.") + # check if lambda function + if value.__name__ == "": + # we resolve the lambda expression by checking the source code and extracting the line with lambda expression + # we also remove any comments from the line + lambda_line = ( + inspect.getsourcelines(value)[0][0] + .strip() + .split("lambda")[1] + .strip() + .split(",")[0] + ) + lambda_line = re.sub(r"#.*$", "", lambda_line).rstrip() + return f"lambda {lambda_line}" + else: + # get the module and function name + module_name = value.__module__ + function_name = value.__name__ + # return the string + return f"{module_name}:{function_name}" + + +def string_to_callable(name: str) -> Callable: + """Resolves the module and function names to return the function. + + Args: + name: The function name. The format should be 'module:attribute_name' or a + lambda expression of format: 'lambda x: x'. + + Raises: + ValueError: When the resolved attribute is not a function. + ValueError: When the module cannot be found. + + Returns: + Callable: The function loaded from the module. + """ + try: + if is_lambda_expression(name): + callable_object = eval(name) + else: + mod_name, attr_name = name.split(":") + mod = importlib.import_module(mod_name) + callable_object = getattr(mod, attr_name) + # check if attribute is callable + if callable(callable_object): + return callable_object + else: + raise AttributeError(f"The imported object is not callable: '{name}'") + except (ValueError, ModuleNotFoundError) as e: + msg = ( + f"Could not resolve the input string '{name}' into callable object." + " The format of input should be 'module:attribute_name'.\n" + f"Received the error:\n {e}." + ) + raise ValueError(msg) + + +def is_regular_expression(pattern: str) -> bool: + """Checks if the input string is a valid regular expression. + Args: + pattern: The input string to check. + + Returns: + bool: True if the input string is a valid regular expression, False otherwise. + """ + try: + re.compile(pattern) + return True + except re.error: + return False + + +def remove_regex_chars(pattern: str) -> str: + """Remove common regex metacharacters from the input pattern. + Args: + pattern: The input string pattern. + + Returns: + The cleaned pattern with regex metacharacters removed. + """ + # Remove common regex metacharacters + regex_chars = r"[\.\*\+\?\[\]\(\)\{\}\^\$\|\\]" + return re.sub(regex_chars, "", pattern) + + +def is_lambda_expression(name: str) -> bool: + """Checks if the input string is a lambda expression. + + Args: + name: The input string. + + Returns: + Whether the input string is a lambda expression. + """ + try: + ast.parse(name) + return isinstance(ast.parse(name).body[0], ast.Expr) and isinstance( + ast.parse(name).body[0].value, ast.Lambda + ) + except SyntaxError: + return False + + +def resolve_matching_names( + keys: Union[str, Sequence[str]], + list_of_strings: Sequence[str], + preserve_order: bool = False, +) -> tuple[list[int], list[str]]: + """Match a list of query regular expressions against a list of strings and return the matched indices and names. + + When a list of query regular expressions is provided, the function checks each target string against each + query regular expression and returns the indices of the matched strings and the matched strings. + + If the :attr:`preserve_order` is True, the ordering of the matched indices and names is the same as the order + of the provided list of strings. This means that the ordering is dictated by the order of the target strings + and not the order of the query regular expressions. + + If the :attr:`preserve_order` is False, the ordering of the matched indices and names is the same as the order + of the provided list of query regular expressions. + + For example, consider the list of strings is ['a', 'b', 'c', 'd', 'e'] and the regular expressions are ['a|c', 'b']. + If :attr:`preserve_order` is False, then the function will return the indices of the matched strings and the + strings as: ([0, 1, 2], ['a', 'b', 'c']). When :attr:`preserve_order` is True, it will return them as: + ([0, 2, 1], ['a', 'c', 'b']). + + Note: + The function does not sort the indices. It returns the indices in the order they are found. + + Args: + keys: A regular expression or a list of regular expressions to match the strings in the list. + list_of_strings: A list of strings to match. + preserve_order: Whether to preserve the order of the query keys in the returned values. Defaults to False. + + Returns: + A tuple of lists containing the matched indices and names. + + Raises: + ValueError: When multiple matches are found for a string in the list. + ValueError: When not all regular expressions are matched. + """ + # resolve name keys + if isinstance(keys, str): + keys = [keys] + # find matching patterns + index_list = [] + names_list = [] + key_idx_list = [] + # book-keeping to check that we always have a one-to-one mapping + # i.e. each target string should match only one regular expression + target_strings_match_found = [None for _ in range(len(list_of_strings))] + keys_match_found = [[] for _ in range(len(keys))] + # loop over all target strings + for target_index, potential_match_string in enumerate(list_of_strings): + for key_index, re_key in enumerate(keys): + if re.fullmatch(re_key, potential_match_string): + # check if match already found + if target_strings_match_found[target_index]: + raise ValueError( + f"Multiple matches for '{potential_match_string}':" + f" '{target_strings_match_found[target_index]}' and '{re_key}'!" + ) + # add to list + target_strings_match_found[target_index] = re_key + index_list.append(target_index) + names_list.append(potential_match_string) + key_idx_list.append(key_index) + # add for regex key + keys_match_found[key_index].append(potential_match_string) + # reorder keys if they should be returned in order of the query keys + if preserve_order: + reordered_index_list = [None] * len(index_list) + global_index = 0 + for key_index in range(len(keys)): + for key_idx_position, key_idx_entry in enumerate(key_idx_list): + if key_idx_entry == key_index: + reordered_index_list[key_idx_position] = global_index + global_index += 1 + # reorder index and names list + index_list_reorder = [None] * len(index_list) + names_list_reorder = [None] * len(index_list) + for idx, reorder_idx in enumerate(reordered_index_list): + index_list_reorder[reorder_idx] = index_list[idx] + names_list_reorder[reorder_idx] = names_list[idx] + # update + index_list = index_list_reorder + names_list = names_list_reorder + # check that all regular expressions are matched + if not all(keys_match_found): + # make this print nicely aligned for debugging + msg = "\n" + for key, value in zip(keys, keys_match_found): + msg += f"\t{key}: {value}\n" + msg += f"Available strings: {list_of_strings}\n" + # raise error + raise ValueError( + f"Not all regular expressions are matched! Please check that the regular expressions are correct: {msg}" + ) + # return + return index_list, names_list + + +def resolve_matching_names_values( + data: dict[str, Any], list_of_strings: Sequence[str], preserve_order: bool = False +) -> tuple[list[int], list[str], list[Any]]: + """Match a list of regular expressions in a dictionary against a list of strings and return + the matched indices, names, and values. + + If the :attr:`preserve_order` is True, the ordering of the matched indices and names is the same as the order + of the provided list of strings. This means that the ordering is dictated by the order of the target strings + and not the order of the query regular expressions. + + If the :attr:`preserve_order` is False, the ordering of the matched indices and names is the same as the order + of the provided list of query regular expressions. + + For example, consider the dictionary is {"a|d|e": 1, "b|c": 2}, the list of strings is ['a', 'b', 'c', 'd', 'e']. + If :attr:`preserve_order` is False, then the function will return the indices of the matched strings, the + matched strings, and the values as: ([0, 1, 2, 3, 4], ['a', 'b', 'c', 'd', 'e'], [1, 2, 2, 1, 1]). When + :attr:`preserve_order` is True, it will return them as: ([0, 3, 4, 1, 2], ['a', 'd', 'e', 'b', 'c'], [1, 1, 1, 2, 2]). + + Args: + data: A dictionary of regular expressions and values to match the strings in the list. + list_of_strings: A list of strings to match. + preserve_order: Whether to preserve the order of the query keys in the returned values. Defaults to False. + + Returns: + A tuple of lists containing the matched indices, names, and values. + + Raises: + TypeError: When the input argument :attr:`data` is not a dictionary. + ValueError: When multiple matches are found for a string in the dictionary. + ValueError: When not all regular expressions in the data keys are matched. + + Reference: + https://github.com/isaac-sim/IsaacLab/blob/main/source/isaaclab/isaaclab/utils/string.py#L178-L271 + """ + # check valid input + if not isinstance(data, dict): + raise TypeError( + f"Input argument `data` should be a dictionary. Received: {data}" + ) + # find matching patterns + index_list = [] + names_list = [] + values_list = [] + key_idx_list = [] + # book-keeping to check that we always have a one-to-one mapping + # i.e. each target string should match only one regular expression + target_strings_match_found = [None for _ in range(len(list_of_strings))] + keys_match_found = [[] for _ in range(len(data))] + # loop over all target strings + for target_index, potential_match_string in enumerate(list_of_strings): + for key_index, (re_key, value) in enumerate(data.items()): + if re.fullmatch(re_key, potential_match_string): + # check if match already found + if target_strings_match_found[target_index]: + raise ValueError( + f"Multiple matches for '{potential_match_string}':" + f" '{target_strings_match_found[target_index]}' and '{re_key}'!" + ) + # add to list + target_strings_match_found[target_index] = re_key + index_list.append(target_index) + names_list.append(potential_match_string) + values_list.append(value) + key_idx_list.append(key_index) + # add for regex key + keys_match_found[key_index].append(potential_match_string) + # reorder keys if they should be returned in order of the query keys + if preserve_order: + reordered_index_list = [None] * len(index_list) + global_index = 0 + for key_index in range(len(data)): + for key_idx_position, key_idx_entry in enumerate(key_idx_list): + if key_idx_entry == key_index: + reordered_index_list[key_idx_position] = global_index + global_index += 1 + # reorder index and names list + index_list_reorder = [None] * len(index_list) + names_list_reorder = [None] * len(index_list) + values_list_reorder = [None] * len(index_list) + for idx, reorder_idx in enumerate(reordered_index_list): + index_list_reorder[reorder_idx] = index_list[idx] + names_list_reorder[reorder_idx] = names_list[idx] + values_list_reorder[reorder_idx] = values_list[idx] + # update + index_list = index_list_reorder + names_list = names_list_reorder + values_list = values_list_reorder + # check that all regular expressions are matched + if not all(keys_match_found): + # make this print nicely aligned for debugging + msg = "\n" + for key, value in zip(data.keys(), keys_match_found): + msg += f"\t{key}: {value}\n" + msg += f"Available strings: {list_of_strings}\n" + # raise error + raise ValueError( + f"Not all regular expressions are matched! Please check that the regular expressions are correct: {msg}" + ) + # return + return index_list, names_list, values_list diff --git a/embodichain/utils/utility.py b/embodichain/utils/utility.py new file mode 100644 index 00000000..d5506df6 --- /dev/null +++ b/embodichain/utils/utility.py @@ -0,0 +1,650 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + + +import cv2 +import pickle +import argparse +import time +import torch +import functools +import open3d as o3d +import numpy as np + +from tqdm import tqdm +from PIL import Image +from functools import wraps +from typing import Dict, List, Tuple, Optional, Callable, Any + +from embodichain.utils.string import callable_to_string + + +@functools.lru_cache(maxsize=None) # memoization +def get_func_tag(tagName): + return TagDecorator(tagName) + + +# https://stackoverflow.com/questions/41834530/how-to-make-python-decorators-work-like-a-tag-to-make-function-calls-by-tag +class TagDecorator(object): + def __init__(self, tagName): + self.functions = {} + self.tagName = tagName + + def __str__(self): + return "".format(tagName=self.tagName) + + def __call__(self, f): + class_name = f.__qualname__.split(".")[0] + if class_name in self.functions.keys(): + self.functions[class_name].update({f.__name__: f}) + else: + self.functions.update({class_name: {f.__name__: f}}) + return f + + +def set_attributes_for_class(self, params=None): + if params: + for k, v in params.items(): + if k != "self" and not k.startswith("_"): + setattr(self, k, v) + + +def timer(func): + @wraps(func) + def wrapper(*args, **kwargs): + start_time = time.time() # 记录开始时间 + result = func(*args, **kwargs) # 执行被装饰的函数 + end_time = time.time() # 记录结束时间 + elapsed_time = end_time - start_time # 计算耗时 + # log_warning( + # f"Function '{func.__name__}' executed in {elapsed_time:.4f} seconds" + # ) + return result # 返回被装饰函数的执行结果 + + return wrapper + + +from embodichain.utils.logger import log_warning, log_error + + +def snake_to_camel(name): + import re + + name = re.sub("_([a-zA-Z])", lambda m: (m.group(1).upper()), name) + name = re.sub("-+", "_", name) + return name + + +def convert_bytes(d): + if isinstance(d, dict): + return {convert_bytes(k): convert_bytes(v) for k, v in d.items()} + if isinstance(d, list): + return [convert_bytes(i) for i in d] + if isinstance(d, bytes): + return d.decode("UTF-8") + return d + + +def pad_to_chunk(x: np.ndarray, chunk_size: int) -> np.ndarray: + if x.shape[0] < chunk_size: + + if len(x.shape) <= 2: + x = np.concatenate( + [ + x, + np.tile( + x[-1:], + (chunk_size - x.shape[0], 1), + ), + ], + axis=0, + ) + elif len(x.shape) == 3 or len(x.shape) == 4: + x = np.concatenate( + [ + x, + np.tile( + x[-1:], + ( + (chunk_size - x.shape[0], 1, 1, 1) + if len(x[:1].shape) == 4 + else (chunk_size - x.shape[0], 1, 1) + ), + ), + ], + axis=0, + ) + else: + raise ValueError("Unsupported shape {}.".format(x.shape)) + + assert x.shape[0] == chunk_size, "shape {} vs chunk_size {}.".format( + x.shape, chunk_size + ) + return x + + +def dict2args(d: Dict) -> argparse.ArgumentParser: + args = argparse.Namespace(**d) + return args + + +def parser2dict(args) -> Dict: + return vars(args) + + +def change_nested_dict(dict, keys, mode: str = "update", value=None): + """ + Update or delete a nested dictionary at a specific key. + + Args: + dict (dict): The dictionary to update. + keys (tuple): Tuple of keys to the target value. + mode (str): Whether to delete or remove the given key-value pair. + value: The new value to set. + + Returns: + dict: The updated dictionary. + """ + if mode == "update": + if value is None: + log_error("The value to be updated is None, please check.") + else: + if len(keys) == 1: + dict[keys[0]] = value + else: + change_nested_dict(dict[keys[0]], keys[1:], "update", value) + elif mode == "delete": + if value is not None: + log_warning( + f"Under mode 'delete' only the keys to be removed need to be provided. But got a not-None vlaue {value}." + ) + if len(keys) == 1: + del dict[keys[0]] + else: + change_nested_dict(dict[keys[0]], keys[1:], "delete") + else: + log_error(f"Mode '{mode}; is noet realized yet.") + + return dict + + +def set_texture_to_material(material, texture: np.ndarray, env, type: str = "color"): + if type == "color": + # TODO: Currently, create texture for base color map without alpha has error. + # should be fixed in the future. + if texture.shape[-1] == 3: + texture = np.concatenate( + [texture, np.ones_like(texture[..., :1]) * 255], axis=-1 + ) + + color_texture = env.create_color_texture(texture, has_alpha=True) + if color_texture: + material.get_inst().set_base_color_map(color_texture) + else: + log_error(f"Unsupported texture type: {type}. Only 'color' is supported.") + + +def get_random_real_image(base_path: str, read: bool = True) -> np.ndarray: + import os, random + + # 随机选择一个子文件夹 + subfolders = [f.path for f in os.scandir(base_path) if f.is_dir()] + selected_subfolder = random.choice(subfolders) + + # 随机选择一个图片文件 + image_files = [ + f.path + for f in os.scandir(selected_subfolder) + if f.is_file() and f.path.endswith((".png", ".jpg", ".jpeg")) + ] + selected_image_file = random.choice(image_files) + + # 读取图片 + if read: + real_image = cv2.imread(selected_image_file) + return real_image + else: + return selected_image_file + + +def read_all_folder_images(base_path: str) -> List[np.ndarray]: + """Read all images from all subfolders under the base path. + + Args: + base_path (str): The base directory containing subfolders with images. + + Returns: + List[np.ndarray]: A list of images read from the subfolders. + """ + import os + + images = [] + # 遍历所有子文件夹 + # First, collect all image files + image_files = [] + for subdir, _, files in os.walk(base_path): + for file in files: + if file.endswith((".png", ".jpg", ".jpeg")): + image_files.append(os.path.join(subdir, file)) + + # Then process with progress bar + for image_path in tqdm(image_files, desc="Loading images"): + image = cv2.imread(image_path) + image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) + if image is not None: + images.append(image) + return images + + +def reset_all_seeds(seed: int = 0): + import torch + import random + import open3d as o3d + + torch.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + np.random.seed(seed) + random.seed(seed) + torch.backends.cudnn.deterministic = True + o3d.utility.random.seed(seed) + + +def do_process_decorator( + pre_process: Optional[bool] = True, post_process: Optional[bool] = True +): + """A decorator to decorate :meth:`inference`. Usage and example is comming soon. + + Args: + pre_process (Optional[bool], optional): whether do pre-process. Defaults to True. + post_process (Optional[bool], optional): whether do post-process. Defaults to True. + """ + + def inner_decorator(func: Callable): + def main_wrapper(self, *args, **kwargs): + if pre_process: + input = getattr(self, "pre_process")(*args, **kwargs) + if isinstance(input, dict): + ret = func(self, input) + else: + ret = func(self, *input) + if post_process: + output = getattr(self, "post_process")(*ret) + return output + + return main_wrapper + + return inner_decorator + + +def pad_img_list(img_list, max_len): + while len(img_list) < max_len: + img_list.append(None) + + +def get_right_name(name: str): + return name + "_r" + + +def read_video(video_path: str): + video = cv2.VideoCapture(video_path) + total_frame_count = int(video.get(cv2.CAP_PROP_FRAME_COUNT)) + length = total_frame_count + fps = video.get(cv2.CAP_PROP_FPS) + return video, fps, length + + +def create_video_writer( + video_path: str, resolution: Tuple[int, int], fps: int +) -> cv2.VideoWriter: + fourcc = cv2.VideoWriter_fourcc(*"mp4v") # 用于mp4格式的生成 + video_vis = cv2.VideoWriter( + video_path, + fourcc, + fps, + (resolution[1], resolution[0]), + ) + return video_vis + + +def update_array( + mat: np.ndarray, vec: np.ndarray, first_is_latest: bool = True +) -> np.ndarray: + if first_is_latest: + mat[1:, :] = mat[:-1, :] + mat[0, :] = vec + return mat + else: + mat[:-1, :] = mat[1:, :] + mat[-1, :] = vec + return mat + + +def save_pkl(path: str, content): + with open(path, "wb") as f: # open a text file + pickle.dump(content, f) # serialize the list + + +def load_pkl( + path: str, +): + with open(path, "rb") as f: + content = pickle.load(f) + return content + + +def save_json(path: str, data): + import json + + with open(path, "w") as f: + json.dump(data, f, indent=4) + + +def save_json(path: str, data): + import json + + with open(path, "w") as f: + json.dump(data, f, indent=4) + + +def load_json(path: str) -> Dict: + import json + + with open(path) as f: + config = json.load(f) + return config + + +def load_txt(path: str) -> str: + with open(path, "r") as f: + contents = f.read().strip() + return contents + + +def encode_image(image: np.ndarray, format: str = "png"): + import base64 + + image_encode = cv2.imencode(f".{format}", image)[1] + base64_image = base64.b64encode(image_encode).decode("utf-8") + return base64_image + + +def inv_transform(transform: np.ndarray) -> np.ndarray: + """inverse transformation + + Args: + transform (np.array): [np.array of size [4 x 4]] + + Returns: + np.array: [np.array of size [4 x 4]] + """ + r = transform[:3, :3] + t = transform[:3, 3].T + inv_r = r.T + inv_t = -inv_r @ t + inv_pose = np.eye(4, dtype=np.float32) + inv_pose[:3, :3] = inv_r + inv_pose[:3, 3] = inv_t + return inv_pose + + +def scale_image(image, scale=0.5): + import cv2 + + h, w = image.shape[:2] + if image.dtype == np.uint8: + return cv2.resize( + image, + ( + int(w * scale), + int(h * scale), + ), + ) + elif image.dtype == np.bool_: + + image = image.astype(np.uint8) + image = cv2.resize( + image, + ( + int(w * scale), + int(h * scale), + ), + ) + return image.astype(np.bool_) + + +def padding_by_longest_edge(img: np.ndarray) -> np.ndarray: + w, h, c = img.shape[:3] + e = np.maximum(w, h) + ret = np.zeros((e, e, c)).astype(img.dtype) + ret[:w, :h] = img + return ret + + +def center_crop(img: np.ndarray, dim: Tuple[int, int]) -> np.ndarray: + """Returns center cropped image + Args: + img: image to be center cropped + dim: dimensions (width, height) to be cropped + """ + width, height = img.shape[1], img.shape[0] + + # process crop width and height for max available dimension + crop_width = dim[0] if dim[0] < img.shape[1] else img.shape[1] + crop_height = dim[1] if dim[1] < img.shape[0] else img.shape[0] + mid_x, mid_y = int(width / 2), int(height / 2) + cw2, ch2 = int(crop_width / 2), int(crop_height / 2) + crop_img = img[mid_y - ch2 : mid_y + ch2, mid_x - cw2 : mid_x + cw2] + return crop_img + + +def postprocess_small_regions( + masks: np.ndarray, + min_area: int, + max_area: int, +) -> List[int]: + keep_idx = [] + n = len(masks) if isinstance(masks, list) else masks.shape[0] + for i in range(n): + area = masks[i].astype(np.uint8).sum() + keep = area > min_area and area <= max_area + if keep: + keep_idx.append(i) + return keep_idx + + +def mask_to_box(mask: np.ndarray) -> np.ndarray: + from torchvision.ops import masks_to_boxes + import torch + + bbox = ( + masks_to_boxes(torch.from_numpy(mask).unsqueeze(0)) + .squeeze(0) + .numpy() + .astype(np.int16) + ) + return bbox + + +def postprocess_small_regions( + masks: np.ndarray, + min_area: int, + max_area: int, +) -> List[int]: + keep_idx = [] + n = len(masks) if isinstance(masks, list) else masks.shape[0] + for i in range(n): + area = masks[i].astype(np.uint8).sum() + keep = area > min_area and area <= max_area + if keep: + keep_idx.append(i) + return keep_idx + + +def remove_overlap_mask( + masks: List[np.ndarray], keep_inner_threshold: float = 0.5, eps: float = 1e-5 +) -> List[int]: + keep_ids = [] + + areas = [mask.astype(np.uint8).sum() for mask in masks] + + for i, maskA in enumerate(masks): + keep = True + for j, maskB in enumerate(masks): + if i == j: + # 同一个mask,跳过 + continue + if areas[i] > areas[j]: + # 大的包裹mask不能被过滤 + continue + + # 计算交集 + intersection = (maskA * maskB).sum() + # 计算maskA的覆盖比例 + overlap_ratio = intersection / (areas[i] + eps) + # maskA被maskB覆盖的面积比例达到threshold,不保留 + if overlap_ratio >= keep_inner_threshold: + keep = False + break + + if keep: + keep_ids.append(i) + + return keep_ids + + +def encode_image_from_path(image_path: str): + import base64 + + with open(image_path, "rb") as image_file: + return base64.b64encode(image_file.read()).decode("utf-8") + + +def check_shared_memory_exists(name): + from multiprocessing import shared_memory + + try: + shm = shared_memory.SharedMemory(name=name) + return True + except FileNotFoundError: + return False + + +def get_class_instance(module_name, class_name, *args, **kwargs): + """Get an instance of a class from a module. + + Args: + module_name (str): The name of the module to import. + class_name (str): The name of the class to instantiate. + + Returns: + object: An instance of the specified class. + """ + import importlib + + # Import the module + module = importlib.import_module(module_name) + # Get the class from the module + cls = getattr(module, class_name) + return cls + + +def key_in_nested_dict(d: Dict, key: str) -> bool: + """Check if a key exists in a nested dictionary. + + Args: + d (Dict): A dictionary that may contain nested dictionaries. + key (str): The key to search for in the dictionary. + + Returns: + bool: True if the key exists in the dictionary or any of its nested dictionaries, False otherwise. + """ + if key in d: + return True + for value in d.values(): + if isinstance(value, dict): # Check if the value is a nested dictionary + if key_in_nested_dict( + value, key + ): # Recursively check the nested dictionary + return True + return False + + +def class_to_dict(obj: object) -> dict[str, Any]: + """Convert an object into dictionary recursively. + + Note: + Ignores all names starting with "__" (i.e. built-in methods). + + Args: + obj: An instance of a class to convert. + + Raises: + ValueError: When input argument is not an object. + + Returns: + Converted dictionary mapping. + """ + # check that input data is class instance + if not hasattr(obj, "__class__"): + raise ValueError(f"Expected a class instance. Received: {type(obj)}.") + # convert object to dictionary + if isinstance(obj, dict): + obj_dict = obj + elif isinstance(obj, torch.Tensor): + # We have to treat torch tensors specially because `torch.tensor.__dict__` returns an empty + # dict, which would mean that a torch.tensor would be stored as an empty dict. Instead we + # want to store it directly as the tensor. + return obj + elif hasattr(obj, "__dict__"): + obj_dict = obj.__dict__ + else: + return obj + + # convert to dictionary + data = dict() + for key, value in obj_dict.items(): + # disregard builtin attributes + if key.startswith("__"): + continue + # check if attribute is callable -- function + if callable(value): + data[key] = callable_to_string(value) + # check if attribute is a dictionary + elif hasattr(value, "__dict__") or isinstance(value, dict): + data[key] = class_to_dict(value) + # check if attribute is a list or tuple + elif isinstance(value, (list, tuple)): + data[key] = type(value)([class_to_dict(v) for v in value]) + else: + data[key] = value + return data + + +def get_mesh_md5(mesh: o3d.t.geometry.TriangleMesh) -> str: + """get mesh md5 unique key + + Args: + mesh (o3d.geometry.TriangleMesh): mesh + + Returns: + str: mesh md5 value. + """ + import hashlib + + vert = np.array(mesh.vertex.positions.numpy(), dtype=float) + face = np.array(mesh.triangle.indices.numpy(), dtype=float) + mix = np.vstack([vert, face]) + return hashlib.md5(np.array2string(mix).encode()).hexdigest() diff --git a/embodichain/utils/visualizer.py b/embodichain/utils/visualizer.py new file mode 100644 index 00000000..0b24a362 --- /dev/null +++ b/embodichain/utils/visualizer.py @@ -0,0 +1,568 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import platform +import numpy as np +import matplotlib.pyplot as plt + +from matplotlib.colors import LogNorm +from matplotlib.patches import Circle, Rectangle +from matplotlib import colors as mcolors +from embodichain.utils.logger import log_error +from typing import Dict, List +from operator import sub + +from matplotlib import rc + +x_min, x_max = 0.275, 1.125 +y_min, y_max = -0.425, 0.425 +bins = 100 + + +def draw_keypoints( + rgb: np.ndarray, keypoints_2d: np.ndarray, color_dict: dict = None +) -> np.ndarray: + import cv2 + + keypoints_2d = np.nan_to_num(keypoints_2d, nan=0) + assert ( + keypoints_2d.max(0)[0] <= 1 and keypoints_2d.max(0)[1] <= 1 + ), keypoints_2d.max(0) + assert ( + keypoints_2d.min(0)[0] >= 0 and keypoints_2d.min(0)[1] >= 0 + ), keypoints_2d.min(0) + n = keypoints_2d.shape[0] + color = [(255 - i / n * 255, 0, i / n * 255) for i in range(n)] + height, width = rgb.shape[:2] + + rgb = np.copy(rgb) + + for i in range(n): + assigned_color = False + if color_dict is not None: + for key_ids, color_str in color_dict.items(): + if i in key_ids: + color[i] = tuple( + int(chl * 255) for chl in mcolors.to_rgb(color_str)[::-1] + ) + assigned_color = True + break + if not assigned_color: + log_error( + f"Once color_dict is provided, all the keypoints ought to be colored, but got {i} not colored." + ) + + # Draw the keypoint + rgb = cv2.circle( + rgb.copy(), + (int(keypoints_2d[i][0] * width), int(keypoints_2d[i][1] * height)), + 2, + color[i], + 2, + ) + + return rgb + + +def draw_action_distribution( + actions: Dict[str, np.ndarray], + indices: Dict[str, List[int]] = None, + output_path: str = None, + smooth: bool = False, + return_data: bool = False, +): + import matplotlib.pyplot as plt + from scipy.ndimage import gaussian_filter1d + + key_names = indices.keys() if indices is not None else actions.keys() + data = {} + for key_name in key_names: + qpos = ( + actions[ + :, + indices[key_name], + ] + if indices is not None + else actions[key_name] + ) + num_dim = qpos.shape[1] + min_square = int(np.ceil(np.sqrt(num_dim))) + rowcol = (min_square, min_square) + + fig, axs = plt.subplots(rowcol[0], rowcol[1], figsize=(20, 20)) + for i in range(num_dim): + row = i // rowcol[0] + col = i % rowcol[1] + ax_i = axs[row, col] if min_square != 1 else axs + ax_i.plot( + ( + qpos[:, i] + if not smooth + else gaussian_filter1d(qpos[:, i], sigma=3, axis=0, mode="nearest") + ), + marker="o", + ms=2, + ) + ax_i.set_title(f"{key_name}_{i}") + + plt.tight_layout() + data[key_name] = fig + if output_path is not None and os.path.exists(output_path): + plt.savefig( + os.path.join(output_path, "action_distribution_{}.png".format(key_name)) + ) + + if return_data: + return data + + +def draw_feature( + feature_list: List[np.ndarray], vis_images: List[np.ndarray] +) -> List[np.ndarray]: + import cv2 + from copy import deepcopy + + vis_features = [] + for feature, image in zip(feature_list, vis_images): + feature_ = cv2.resize( + feature, + (image.shape[1], image.shape[0]), + interpolation=cv2.INTER_LINEAR, + ) + image = cv2.addWeighted(deepcopy(image), 0.5, feature_, 0.5, 0) + vis_features.append(image) + return vis_features + + +class HeatMapEnv: + def __init__(self, is_success): + """Initialize the drawing environment and static elements""" + self.points = [] + self.b_fail_points = [] + self.c_fail_points = [] + self.fig, self.ax = plt.subplots(figsize=(10, 8)) + self.ax.set_aspect("equal") + + circle1 = Circle( + (0.7, 0), + radius=0.425, + fill=False, + edgecolor="red", + linewidth=2, + linestyle="--", + label="Circle Zone", + ) + circle2 = Circle( + (0.233, 0.3), + radius=0.08, + fill=False, + edgecolor="red", + linewidth=2, + linestyle="--", + label="Circle Zone", + ) + circle3 = Circle( + (0.233, -0.3), + radius=0.08, + fill=False, + edgecolor="red", + linewidth=2, + linestyle="--", + label="Circle Zone", + ) + + rectangle1 = Rectangle( + (0.67, -0.22), + 0.16, + 0.16, + angle=0, + fill=False, + edgecolor="blue", + linewidth=2, + linestyle="-.", + label="Rect Zone", + ) + + rectangle2 = Rectangle( + (0.67, 0.06), + 0.16, + 0.16, + angle=0, + fill=False, + edgecolor="green", + linewidth=2, + linestyle="-.", + label="Rect Zone", + ) + + for patch in [circle1, circle2, circle3, rectangle1, rectangle2]: + self.ax.add_patch(patch) + + self.ax.set( + xlim=(x_min, x_max), + ylim=(y_min, y_max), + xticks=np.arange(x_min, x_max + 0.01, 0.04), + yticks=np.arange(y_min, y_max + 0.01, 0.04), + ) + self.ax.grid(True, linestyle="--", alpha=0.3) + self.ax.set_title("Real-time Heatmap") + self.ax.set_xlabel("X") + self.ax.set_ylabel("Y") + + hist = np.zeros((bins, bins)) + self.im = self.ax.imshow( + hist.T, + origin="lower", + extent=[x_min, x_max, y_min, y_max], + cmap="Greys", + norm=LogNorm(vmin=0.1, vmax=10), + ) + + self.cbar = self.fig.colorbar(self.im) + self.cbar.set_label("Density") + self.is_success = is_success + if self.is_success: + text = "Success_Points_Pair: 0" + else: + text = "Bottle_Fail_Points: 0\nCup_Fail_Points: 0" + self.text_label = self.ax.text( + 0.95, + 0.95, + text, + transform=self.ax.transAxes, + fontsize=14, + color="red", + ha="right", + ) + + plt.ion() + plt.show(block=False) + plt.tight_layout() + + def update_heatmap(self, new_point, new_fail): + if self.is_success: + self.points.append(new_point) + x_coords = [p[0] for p in self.points] + y_coords = [p[1] for p in self.points] + else: + if new_fail == 0: + self.b_fail_points.append(new_point) + x_coords = [p[0] for p in self.b_fail_points] + y_coords = [p[1] for p in self.b_fail_points] + else: + self.c_fail_points.append(new_point) + x_coords = [p[0] for p in self.c_fail_points] + y_coords = [p[1] for p in self.c_fail_points] + + hist, x_edges, y_edges = np.histogram2d( + x_coords, y_coords, bins=bins, range=[[x_min, x_max], [y_min, y_max]] + ) + + self.im.set_data(hist.T) + + if self.is_success: + self.text_label.set_text(f"Success_Points_Pair: {len(self.points)/2}") + else: + if new_fail == 0: + self.text_label.set_text( + f"Bottle_Fail_Points: {len(self.b_fail_points)}\nCup_Fail_Points: {len(self.c_fail_points)}" + ) + else: + self.text_label.set_text( + f"Bottle_Fail_Points: {len(self.b_fail_points)}\nCup_Fail_Points: {len(self.c_fail_points)}" + ) + # im.autoscale() + + self.fig.canvas.draw_idle() + self.fig.canvas.flush_events() + + def save_map(self): + if self.is_success: + plt.savefig("./outputs/success_heatmap.png") + else: + plt.savefig("./outputs/fail_heatmap.png") + + +# TeX support: on Linux assume TeX in /usr/bin, on OSX check for texlive +if (platform.system() == "Darwin") and "tex" in os.getenv("PATH"): + LATEX = True +elif (platform.system() == "Linux") and os.path.isfile("/usr/bin/latex"): + LATEX = True +else: + LATEX = False + +# setup pyplot w/ tex support +if LATEX: + rc("text", usetex=True) + + +class Package: + """Encapsulation of a work package + + A work package is instantiated from a dictionary. It **has to have** + a label, astart and an end. Optionally it may contain milestones + and a color + + :arg str pkg: dictionary w/ package data name + """ + + def __init__(self, pkg): + + DEFCOLOR = "#32AEE0" + + self.label = pkg["label"] + self.start = pkg["start"] + self.end = pkg["end"] + + if self.start < 0 or self.end < 0: + raise ValueError("Package cannot begin at t < 0") + if self.start > self.end: + raise ValueError("Cannot end before started") + + try: + self.milestones = pkg["milestones"] + except KeyError: + pass + + try: + self.color = pkg["color"] + except KeyError: + self.color = DEFCOLOR + + try: + self.legend = pkg["legend"] + except KeyError: + self.legend = None + + +# https://github.com/stefanSchinkel/gantt/tree/master +class Gantt: + """Gantt + Class to render a simple Gantt chart, with optional milestones + """ + + def __init__(self, dict: Dict): + """Instantiation + + Create a new Gantt using the data in the file provided + or the sample data that came along with the script + + :arg str dataFile: file holding Gantt data + """ + + # some lists needed + self.packages = [] + self.labels = [] + + self._loadData(dict) + self._procData() + + def _loadData(self, data): + """Load data from a JSON file that has to have the keys: + packages & title. Packages is an array of objects with + a label, start and end property and optional milesstones + and color specs. + """ + + # must-haves + self.title = data["title"] + + for pkg in data["packages"]: + self.packages.append(Package(pkg)) + + self.labels = [pkg["label"] for pkg in data["packages"]] + + # optionals + self.milestones = {} + for pkg in self.packages: + try: + self.milestones[pkg.label] = pkg.milestones + except AttributeError: + pass + + try: + self.xlabel = data["xlabel"] + except KeyError: + self.xlabel = "" + try: + self.xticks = data["xticks"] + except KeyError: + self.xticks = "" + + def _procData(self): + """Process data to have all values needed for plotting""" + # parameters for bars + self.nPackages = len(self.labels) + self.start = [None] * self.nPackages + self.end = [None] * self.nPackages + + for pkg in self.packages: + idx = self.labels.index(pkg.label) + self.start[idx] = pkg.start + self.end[idx] = pkg.end + + self.durations = map(sub, self.end, self.start) + self.yPos = np.arange(self.nPackages, 0, -1) + + def format(self): + """Format various aspect of the plot, such as labels,ticks, BBox + :todo: Refactor to use a settings object + """ + # format axis + plt.tick_params( + axis="both", # format x and y + which="both", # major and minor ticks affected + bottom="on", # bottom edge ticks are on + top="off", # top, left and right edge ticks are off + left="off", + right="off", + ) + + # tighten axis but give a little room from bar height + plt.xlim(0, max(self.end)) + plt.ylim(0.5, self.nPackages + 0.5) + + # add title and package names + plt.yticks(self.yPos, [label.replace("qpos", "") for label in self.labels]) + plt.title(self.title) + + if self.xlabel: + plt.xlabel(self.xlabel) + + if self.xticks: + plt.xticks(self.xticks, map(str, self.xticks)) + + def add_milestones(self): + """Add milestones to GANTT chart. + The milestones are simple yellow diamonds + """ + + if not self.milestones: + return + + x = [] + y = [] + for key in self.milestones.keys(): + for value in self.milestones[key]: + y += [self.yPos[self.labels.index(key)]] + x += [value] + + plt.scatter( + x, y, s=120, marker="D", color="yellow", edgecolor="black", zorder=3 + ) + + def add_legend(self): + """Add a legend to the plot iff there are legend entries in + the package definitions + """ + cnt = 0 + legends = [] + for pkg in self.packages: + if pkg.legend not in legends: + cnt += 1 + idx = self.labels.index(pkg.label) + self.barlist[idx].set_label(pkg.legend) + legends.append(pkg.legend) + + if cnt > 0: + self.legend = self.ax.legend(shadow=False, ncol=3, fontsize="medium") + + def render(self): + """Prepare data for plotting""" + + # init figure + self.fig, self.ax = plt.subplots() + self.ax.yaxis.grid(False) + self.ax.xaxis.grid(True) + + # assemble colors + colors = [] + for pkg in self.packages: + colors.append(pkg.color) + + self.barlist = plt.barh( + self.yPos, + list(self.durations), + left=self.start, + align="center", + height=0.5, + alpha=1, + color=colors, + ) + + # format plot + self.format() + self.add_milestones() + self.add_legend() + + @staticmethod + def show(): + """Show the plot""" + plt.show() + + @staticmethod + def save(saveFile="img/GANTT.png"): + """Save the plot to a file. It defaults to `img/GANTT.png`. + + :arg str saveFile: file to save to + """ + plt.savefig(saveFile, bbox_inches="tight") + + +def visualize_trajectory(poses: np.ndarray): + """Visualizes a 3D trajectory and its z-axis directions. + + This function takes a series of 4x4 transformation matrices representing + poses in 3D space and visualizes the trajectory along with the z-axis + directions at each pose. + + Args: + poses (np.ndarray): A numpy array of shape (N, 4, 4), where N is the + number of poses. Each pose is a 4x4 transformation matrix. + + """ + fig = plt.figure() + ax = fig.add_subplot(111, projection="3d") + + # positions of the trajectory + positions = poses[:, :3, 3] + ax.plot( + positions[:, 0], positions[:, 1], positions[:, 2], "r-", linewidth=3, label="轨迹" + ) + + # direction of z-axis + for i in range(len(poses)): + R = poses[i, :3, :3] + t = poses[i, :3, 3] + + z_axis = R[:, 2] * 0.01 + ax.quiver( + t[0], + t[1], + t[2], + z_axis[0], + z_axis[1], + z_axis[2], + color="blue", + arrow_length_ratio=0.2, + ) + + ax.set_xlabel("X") + ax.set_ylabel("Y") + ax.set_zlabel("Z") + ax.set_box_aspect([1, 1, 1]) + plt.show() diff --git a/embodichain/utils/warp/__init__.py b/embodichain/utils/warp/__init__.py new file mode 100644 index 00000000..d3e93d7e --- /dev/null +++ b/embodichain/utils/warp/__init__.py @@ -0,0 +1,32 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from .kernels import reshape_tiled_image +from . import kinematics +from .kinematics.opw_solver import opw_fk_kernel, opw_ik_kernel +from .kinematics.warp_trajectory import ( + trajectory_get_diff_kernel, + trajectory_interpolate_kernel, + trajectory_add_origin_kernel, + get_offset_qpos_kernel, +) + +from .kinematics.interpolate import ( + pairwise_distances, + cumsum_distances, + repeat_first_point, + interpolate_along_distance, +) diff --git a/embodichain/utils/warp/kernels.py b/embodichain/utils/warp/kernels.py new file mode 100644 index 00000000..65ab8eaf --- /dev/null +++ b/embodichain/utils/warp/kernels.py @@ -0,0 +1,93 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import warp as wp +from typing import Any + + +@wp.kernel(enable_backward=False) +def reshape_tiled_image( + tiled_image_buffer: Any, + batched_image: Any, + image_height: int, + image_width: int, + num_channels: int, + num_tiles_x: int, +): + """Reshapes a tiled image into a batch of images. + + This function reshapes the input tiled image buffer into a batch of images. The input image buffer + is assumed to be tiled in the x and y directions. The output image is a batch of images with the + specified height, width, and number of channels. + + Args: + tiled_image_buffer: The input image buffer. Shape is (height * width * num_channels * num_cameras,). + batched_image: The output image. Shape is (num_cameras, height, width, num_channels). + image_width: The width of the image. + image_height: The height of the image. + num_channels: The number of channels in the image. + num_tiles_x: The number of tiles in x-direction. + """ + # get the thread id + camera_id, height_id, width_id = wp.tid() + + # resolve the tile indices + tile_x_id = camera_id % num_tiles_x + # TODO: Currently, the tiles arranged in the bottom-to-top order, which should be changed. + tile_y_id = ( + num_tiles_x - 1 - (camera_id // num_tiles_x) + ) # Adjust for bottom-to-top tiling + # compute the start index of the pixel in the tiled image buffer + pixel_start = ( + num_channels + * num_tiles_x + * image_width + * (image_height * tile_y_id + height_id) + + num_channels * tile_x_id * image_width + + num_channels * width_id + ) + + # copy the pixel values into the batched image + for i in range(num_channels): + batched_image[camera_id, height_id, width_id, i] = batched_image.dtype( + tiled_image_buffer[pixel_start + i] + ) + + +# uint32 -> int32 conversion is required for non-colored segmentation annotators +wp.overload( + reshape_tiled_image, + { + "tiled_image_buffer": wp.array(dtype=wp.uint32), + "batched_image": wp.array(dtype=wp.uint32, ndim=4), + }, +) +# uint8 is used for 4 channel annotators +wp.overload( + reshape_tiled_image, + { + "tiled_image_buffer": wp.array(dtype=wp.uint8), + "batched_image": wp.array(dtype=wp.uint8, ndim=4), + }, +) +# float32 is used for single channel annotators +wp.overload( + reshape_tiled_image, + { + "tiled_image_buffer": wp.array(dtype=wp.float32), + "batched_image": wp.array(dtype=wp.float32, ndim=4), + }, +) diff --git a/embodichain/utils/warp/kinematics/__init__.py b/embodichain/utils/warp/kinematics/__init__.py new file mode 100644 index 00000000..8fae6605 --- /dev/null +++ b/embodichain/utils/warp/kinematics/__init__.py @@ -0,0 +1,19 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from . import interpolate +from . import opw_solver +from . import warp_trajectory diff --git a/embodichain/utils/warp/kinematics/interpolate.py b/embodichain/utils/warp/kinematics/interpolate.py new file mode 100644 index 00000000..e11b088a --- /dev/null +++ b/embodichain/utils/warp/kinematics/interpolate.py @@ -0,0 +1,172 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +import warp as wp + + +@wp.kernel +def pairwise_distances( + points: wp.array(dtype=float), # flattened: length B*N*M + distances: wp.array(dtype=float), # flattened: length B*(N-1) + B: int, + N: int, + M: int, +): + """Compute Euclidean distances between consecutive points along N using 1D flattened storage. + + Memory layout (row-major): + points(b, i, j) => b*N*M + i*M + j + distances(b, i) => b*(N-1) + i + Result: + distances[b,i] = ||points[b,i+1,:] - points[b,i,:]||_2 + """ + tid = wp.tid() + total = B * (N - 1) + if tid >= total: + return + + b = tid // (N - 1) + i = tid - b * (N - 1) + + base_points = b * N * M + s = float(0.0) + for j in range(M): + p0 = points[base_points + i * M + j] + p1 = points[base_points + (i + 1) * M + j] + d = p1 - p0 + s = s + d * d + distances[b * (N - 1) + i] = wp.sqrt(s) + + +@wp.kernel +def cumsum_distances( + distances: wp.array(dtype=float), # flattened: length B*(N-1) + cumulative: wp.array(dtype=float), # flattened: length B*N + B: int, + N: int, +): + """Compute per-batch cumulative distances with flattened indexing. + + Layout: + distances(b,i) => b*(N-1) + i + cumulative(b,i) => b*N + i + Definition: + cumulative[b,0] = 0 + cumulative[b,i] = sum_{k=0}^{i-1} distances[b,k] + """ + b = wp.tid() + if b >= B: + return + + cumulative[b * N + 0] = float(0.0) + acc = float(0.0) + for i in range(N - 1): + acc = acc + distances[b * (N - 1) + i] + cumulative[b * N + (i + 1)] = acc + + +@wp.kernel +def repeat_first_point( + points: wp.array(dtype=float), # flattened: length B*N*M (N may be 1) + out: wp.array(dtype=float), # flattened: length B*T*M + B: int, + T: int, + M: int, + N: int, +): + """Repeat the first waypoint of each batch across T samples (used when N==1). + + First point (b,j): b*N*M + j (i=0) + Output (b,t,j): b*T*M + t*M + j + """ + tid = wp.tid() + total = B * T + if tid >= total: + return + + b = tid // T + t = tid - b * T + + base_in = b * N * M # N expected 1 in usage + base_out = b * T * M + t * M + for j in range(M): + out[base_out + j] = points[base_in + j] + + +@wp.kernel +def interpolate_along_distance( + points: wp.array(dtype=float), # flattened B*N*M + cumulative: wp.array(dtype=float), # flattened B*N + out: wp.array(dtype=float), # flattened B*T*M + B: int, + N: int, + M: int, + T: int, +): + """Piecewise-linear interpolation at uniformly spaced cumulative-distance samples. + + Indexing (flattened): + points(b,i,j) => b*N*M + i*M + j + cumulative(b,i) => b*N + i + out(b,t,j) => b*T*M + t*M + j + Steps: + 1. Compute target distance new_d in [0, total_len]. + 2. Binary search cumulative to find segment [lo, hi]. + 3. Linear interpolate each dimension. + """ + tid = wp.tid() + total_threads = B * T + if tid >= total_threads: + return + + b = tid // T + t = tid - b * T + + # total path length for batch b + total_len = cumulative[b * N + (N - 1)] + + # evenly spaced target distance + new_d = float(0.0) + if T > 1: + new_d = total_len * float(t) / float(T - 1) + else: + new_d = float(0.0) + + # binary search for segment boundaries + lo = int(0) + hi = N - 1 + while (lo + 1) < hi: + mid = (lo + hi) // 2 + if cumulative[b * N + mid] <= new_d: + lo = mid + else: + hi = mid + + c_lo = cumulative[b * N + lo] + c_hi = cumulative[b * N + hi] + denom = c_hi - c_lo + + alpha = float(0.0) + if denom > float(0.0): + alpha = (new_d - c_lo) / denom + + base_points = b * N * M + base_out = b * T * M + t * M + p_lo_offset = base_points + lo * M + p_hi_offset = base_points + hi * M + for j in range(M): + p_lo = points[p_lo_offset + j] + p_hi = points[p_hi_offset + j] + out[base_out + j] = p_lo + alpha * (p_hi - p_lo) diff --git a/embodichain/utils/warp/kinematics/opw_solver.py b/embodichain/utils/warp/kinematics/opw_solver.py new file mode 100644 index 00000000..d0d7213b --- /dev/null +++ b/embodichain/utils/warp/kinematics/opw_solver.py @@ -0,0 +1,500 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import warp as wp +import numpy as np +from typing import Tuple + + +wp_vec48f = wp.types.vector(length=48, dtype=float) +wp_vec6f = wp.types.vector(length=6, dtype=float) + + +@wp.func +def normalize_to_pi(angle: float) -> float: + angle = (angle + wp.pi) % (2.0 * wp.pi) - wp.pi + return angle + + +@wp.func +def safe_acos(x: float) -> float: + return wp.acos(wp.clamp(x, -1.0, 1.0)) + + +@wp.func +def th4_th6_for_branch( + i: int, + r_: wp.mat33f, + sin1: wp.vec4f, + cos1: wp.vec4f, + s23: wp.vec4f, + c23: wp.vec4f, +) -> Tuple[float, float]: + th4_y = r_[1, 2] * cos1[i] - r_[0, 2] * sin1[i] + th4_x = ( + r_[0, 2] * c23[i] * cos1[i] + r_[1, 2] * c23[i] * sin1[i] - r_[2, 2] * s23[i] + ) + th4 = wp.atan2(th4_y, th4_x) + + th6_y = ( + r_[0, 1] * s23[i] * cos1[i] + r_[1, 1] * s23[i] * sin1[i] + r_[2, 1] * c23[i] + ) + th6_x = ( + -r_[0, 0] * s23[i] * cos1[i] - r_[1, 0] * s23[i] * sin1[i] - r_[2, 0] * c23[i] + ) + th6 = wp.atan2(th6_y, th6_x) + return th4, th6 + + +@wp.struct +class OPWparam: + a1: float + a2: float + b: float + c1: float + c2: float + c3: float + c4: float + + +@wp.func +def get_transform_err( + transform1: wp.mat44f, transform2: wp.mat44f +) -> Tuple[float, float]: + t_diff = wp.vec3f( + transform1[0, 3] - transform2[0, 3], + transform1[1, 3] - transform2[1, 3], + transform1[2, 3] - transform2[2, 3], + ) + t_err = wp.length(t_diff) + r1 = wp.mat33f( + transform1[0, 0], + transform1[0, 1], + transform1[0, 2], + transform1[1, 0], + transform1[1, 1], + transform1[1, 2], + transform1[2, 0], + transform1[2, 1], + transform1[2, 2], + ) + r2 = wp.mat33f( + transform2[0, 0], + transform2[0, 1], + transform2[0, 2], + transform2[1, 0], + transform2[1, 1], + transform2[1, 2], + transform2[2, 0], + transform2[2, 1], + transform2[2, 2], + ) + r_diff = wp.transpose(r1) * r2 + cos_value = 0.5 * (wp.trace(r_diff) - 1.0) + r_err = wp.abs(safe_acos(cos_value)) + return t_err, r_err + + +@wp.func +def opw_single_fk( + q1: float, q2: float, q3: float, q4: float, q5: float, q6: float, params: OPWparam +): + psi3 = wp.atan2(params.a2, params.c3) + k = wp.sqrt(params.a2 * params.a2 + params.c3 * params.c3) + + # Precompute q23_psi3 for better readability and reuse + q23_psi3 = q2 + q3 + psi3 + sin_q23_psi3 = wp.sin(q23_psi3) + cos_q23_psi3 = wp.cos(q23_psi3) + + cx1 = params.c2 * wp.sin(q2) + k * sin_q23_psi3 + params.a1 + cy1 = params.b + cz1 = params.c2 * wp.cos(q2) + k * cos_q23_psi3 + + cx0 = cx1 * wp.cos(q1) - cy1 * wp.sin(q1) + cy0 = cx1 * wp.sin(q1) + cy1 * wp.cos(q1) + cz0 = cz1 + params.c1 + + s1, c1 = wp.sin(q1), wp.cos(q1) + s2, c2 = wp.sin(q2), wp.cos(q2) + s3, c3 = wp.sin(q3), wp.cos(q3) + s4, c4 = wp.sin(q4), wp.cos(q4) + s5, c5 = wp.sin(q5), wp.cos(q5) + s6, c6 = wp.sin(q6), wp.cos(q6) + + r_0c = wp.mat33f( + c1 * c2 * c3 - c1 * s2 * s3, + -s1, + c1 * c2 * s3 + c1 * s2 * c3, + s1 * c2 * c3 - s1 * s2 * s3, + c1, + s1 * c2 * s3 + s1 * s2 * c3, + -s2 * c3 - c2 * s3, + 0.0, + -s2 * s3 + c2 * c3, + ) + r_ce = wp.mat33f( + c4 * c5 * c6 - s4 * s6, + -c4 * c5 * s6 - s4 * c6, + c4 * s5, + s4 * c5 * c6 + c4 * s6, + -s4 * c5 * s6 + c4 * c6, + s4 * s5, + -s5 * c6, + s5 * s6, + c5, + ) + + r_0e = r_0c * r_ce + t_0e = wp.vec3f( + cx0 + params.c4 * r_0e[0, 2], + cy0 + params.c4 * r_0e[1, 2], + cz0 + params.c4 * r_0e[2, 2], + ) + + return wp.mat44f( + r_0e[0, 0], + r_0e[0, 1], + r_0e[0, 2], + t_0e[0], + r_0e[1, 0], + r_0e[1, 1], + r_0e[1, 2], + t_0e[1], + r_0e[2, 0], + r_0e[2, 1], + r_0e[2, 2], + t_0e[2], + 0.0, + 0.0, + 0.0, + 1.0, + ) + + +@wp.kernel +def opw_fk_kernel( + qpos: wp.array(dtype=float), + ee_pose: wp.mat44f, + params: OPWparam, + offsets: wp.array(dtype=float), + sign_corrections: wp.array(dtype=float), + xpos: wp.array(dtype=float), +): + i = wp.tid() + dof = 6 + q1 = qpos[0 + i * dof] * sign_corrections[0] - offsets[0] + q2 = qpos[1 + i * dof] * sign_corrections[1] - offsets[1] + q3 = qpos[2 + i * dof] * sign_corrections[2] - offsets[2] + q4 = qpos[3 + i * dof] * sign_corrections[3] - offsets[3] + q5 = qpos[4 + i * dof] * sign_corrections[4] - offsets[4] + q6 = qpos[5 + i * dof] * sign_corrections[5] - offsets[5] + + p_0e = opw_single_fk(q1, q2, q3, q4, q5, q6, params) + result = p_0e * ee_pose + + # assign to result + for t in range(16): + xpos[t + i * 16] = result[t // 4, t % 4] + + +@wp.kernel +def opw_ik_kernel( + xpos: wp.array(dtype=float), + ee_pose_inv: wp.mat44f, + params: OPWparam, + offsets: wp.array(dtype=float), + sign_corrections: wp.array(dtype=float), + qpos: wp.array(dtype=float), + ik_valid: wp.array(dtype=int), +): + i = wp.tid() + # TODO: warp slice ? + ee_pose = ( + wp.mat44f( + xpos[i * 16 + 0], + xpos[i * 16 + 1], + xpos[i * 16 + 2], + xpos[i * 16 + 3], + xpos[i * 16 + 4], + xpos[i * 16 + 5], + xpos[i * 16 + 6], + xpos[i * 16 + 7], + xpos[i * 16 + 8], + xpos[i * 16 + 9], + xpos[i * 16 + 10], + xpos[i * 16 + 11], + xpos[i * 16 + 12], + xpos[i * 16 + 13], + xpos[i * 16 + 14], + xpos[i * 16 + 15], + ) + * ee_pose_inv + ) + r_ = wp.mat33f( + ee_pose[0, 0], + ee_pose[0, 1], + ee_pose[0, 2], + ee_pose[1, 0], + ee_pose[1, 1], + ee_pose[1, 2], + ee_pose[2, 0], + ee_pose[2, 1], + ee_pose[2, 2], + ) + rz_ = wp.vec3f(ee_pose[0, 2], ee_pose[1, 2], ee_pose[2, 2]) + t_ = wp.vec3f(ee_pose[0, 3], ee_pose[1, 3], ee_pose[2, 3]) + + # to wrist center position + c = t_ - params.c4 * rz_ + + r_xy2 = c[0] * c[0] + c[1] * c[1] + nx1_sqrt_arg = r_xy2 - params.b * params.b + nx1 = wp.sqrt(nx1_sqrt_arg) - params.a1 + + tmp1 = wp.atan2(c[1], c[0]) + tmp2 = wp.atan2(params.b, nx1 + params.a1) + theta1_i = tmp1 - tmp2 + theta1_ii = tmp1 + tmp2 - wp.pi + + tmp3 = c[2] - params.c1 + s1_2 = nx1 * nx1 + tmp3 * tmp3 + + tmp4 = nx1 + 2.0 * params.a1 + s2_2 = tmp4 * tmp4 + tmp3 * tmp3 + kappa_2 = params.a2 * params.a2 + params.c3 * params.c3 + + c2_2 = params.c2 * params.c2 + + tmp5 = s1_2 + c2_2 - kappa_2 + s1 = wp.sqrt(s1_2) + s2 = wp.sqrt(s2_2) + + # theta2 + tmp13 = safe_acos(tmp5 / (2.0 * s1 * params.c2)) + tmp14 = wp.atan2(nx1, c[2] - params.c1) + theta2_i = -tmp13 + tmp14 + theta2_ii = tmp13 + tmp14 + + tmp6 = s2_2 + c2_2 - kappa_2 + tmp15 = safe_acos(tmp6 / (2.0 * s2 * params.c2)) + tmp16 = wp.atan2(nx1 + 2.0 * params.a1, c[2] - params.c1) + theta2_iii = -tmp15 - tmp16 + theta2_iv = tmp15 - tmp16 + + # theta3 + tmp7 = s1_2 - c2_2 - kappa_2 + tmp8 = s2_2 - c2_2 - kappa_2 + tmp9 = 2.0 * params.c2 * wp.sqrt(kappa_2) + tmp10 = wp.atan2(params.a2, params.c3) + + tmp11 = safe_acos(tmp7 / tmp9) + theta3_i = tmp11 - tmp10 + theta3_ii = -tmp11 - tmp10 + + tmp12 = safe_acos(tmp8 / tmp9) + theta3_iii = tmp12 - tmp10 + theta3_iv = -tmp12 - tmp10 + + # precompute sin/cos(theta1) + theta1_i_sin = wp.sin(theta1_i) + theta1_i_cos = wp.cos(theta1_i) + theta1_ii_sin = wp.sin(theta1_ii) + theta1_ii_cos = wp.cos(theta1_ii) + + sin1 = wp.vec4f(theta1_i_sin, theta1_i_sin, theta1_ii_sin, theta1_ii_sin) + cos1 = wp.vec4f(theta1_i_cos, theta1_i_cos, theta1_ii_cos, theta1_ii_cos) + s23 = wp.vec4f( + wp.sin(theta2_i + theta3_i), + wp.sin(theta2_ii + theta3_ii), + wp.sin(theta2_iii + theta3_iii), + wp.sin(theta2_iv + theta3_iv), + ) + c23 = wp.vec4f( + wp.cos(theta2_i + theta3_i), + wp.cos(theta2_ii + theta3_ii), + wp.cos(theta2_iii + theta3_iii), + wp.cos(theta2_iv + theta3_iv), + ) + + # m for theta5 + m = wp.vec4f( + r_[0, 2] * s23[0] * cos1[0] + r_[1, 2] * s23[0] * sin1[0] + r_[2, 2] * c23[0], + r_[0, 2] * s23[1] * cos1[1] + r_[1, 2] * s23[1] * sin1[1] + r_[2, 2] * c23[1], + r_[0, 2] * s23[2] * cos1[2] + r_[1, 2] * s23[2] * sin1[2] + r_[2, 2] * c23[2], + r_[0, 2] * s23[3] * cos1[3] + r_[1, 2] * s23[3] * sin1[3] + r_[2, 2] * c23[3], + ) + theta5 = wp.vec4f( + wp.atan2(wp.sqrt(wp.clamp(1.0 - m[0] * m[0], 0.0, 1.0)), m[0]), + wp.atan2(wp.sqrt(wp.clamp(1.0 - m[1] * m[1], 0.0, 1.0)), m[1]), + wp.atan2(wp.sqrt(wp.clamp(1.0 - m[2] * m[2], 0.0, 1.0)), m[2]), + wp.atan2(wp.sqrt(wp.clamp(1.0 - m[3] * m[3], 0.0, 1.0)), m[3]), + ) + + theta4_i, theta6_i = th4_th6_for_branch(0, r_, sin1, cos1, s23, c23) + theta4_ii, theta6_ii = th4_th6_for_branch(1, r_, sin1, cos1, s23, c23) + theta4_iii, theta6_iii = th4_th6_for_branch(2, r_, sin1, cos1, s23, c23) + theta4_iv, theta6_iv = th4_th6_for_branch(3, r_, sin1, cos1, s23, c23) + theta5_i, theta5_ii, theta5_iii, theta5_iv = ( + theta5[0], + theta5[1], + theta5[2], + theta5[3], + ) + theta5_v, theta5_vi, theta5_vii, theta5_viii = ( + -theta5_i, + -theta5_ii, + -theta5_iii, + -theta5_iv, + ) + + theta4_v, theta4_vi, theta4_vii, theta4_viii = ( + theta4_i + wp.pi, + theta4_ii + wp.pi, + theta4_iii + wp.pi, + theta4_iv + wp.pi, + ) + theta6_v, theta6_vi, theta6_vii, theta6_viii = ( + theta6_i - wp.pi, + theta6_ii - wp.pi, + theta6_iii - wp.pi, + theta6_iv - wp.pi, + ) + # combine all 8 solutions + theta = wp_vec48f( + theta1_i, + theta2_i, + theta3_i, + theta4_i, + theta5_i, + theta6_i, + theta1_i, + theta2_ii, + theta3_ii, + theta4_ii, + theta5_ii, + theta6_ii, + theta1_ii, + theta2_iii, + theta3_iii, + theta4_iii, + theta5_iii, + theta6_iii, + theta1_ii, + theta2_iv, + theta3_iv, + theta4_iv, + theta5_iv, + theta6_iv, + theta1_i, + theta2_i, + theta3_i, + theta4_v, + theta5_v, + theta6_v, + theta1_i, + theta2_ii, + theta3_ii, + theta4_vi, + theta5_vi, + theta6_vi, + theta1_ii, + theta2_iii, + theta3_iii, + theta4_vii, + theta5_vii, + theta6_vii, + theta1_ii, + theta2_iv, + theta3_iv, + theta4_viii, + theta5_viii, + theta6_viii, + ) + DOF = 6 + N_SOL = 8 + # apply sign correction and offsets, and write to qpos + for j in range(N_SOL): + qpos_start = i * DOF * N_SOL + j * DOF + + for k in range(DOF): + idx = j * DOF + k + qpos[qpos_start + k] = normalize_to_pi( + (theta[idx] + offsets[k]) * sign_corrections[k] + ) + + # filter invalid solutions + check_ee_pose = opw_single_fk( + theta[j * DOF + 0], + theta[j * DOF + 1], + theta[j * DOF + 2], + theta[j * DOF + 3], + theta[j * DOF + 4], + theta[j * DOF + 5], + params, + ) + t_err, r_err = get_transform_err(check_ee_pose, ee_pose) + # mark invalid solutions (cannot pass ik check) + if t_err > 1e-2 or r_err > 1e-1: + ik_valid[i * N_SOL + j] = 0 + else: + ik_valid[i * N_SOL + j] = 1 + + +@wp.kernel +def opw_best_ik_kernel( + full_ik_result: wp.array(dtype=float), + full_ik_valid: wp.array(dtype=int), + qpos_seed: wp.array(dtype=float), + joint_weights: wp_vec6f, + best_ik_result: wp.array(dtype=float), + best_ik_valid: wp.array(dtype=int), +): + i = wp.tid() + DOF = 6 + N_SOL = 8 + + best_weighted_dis = float(1e10) + best_ids = int(-1) + for j in range(N_SOL): + is_full_valid = full_ik_valid[i * N_SOL + j] + if is_full_valid == 0: + # invalid ik result + continue + weighted_dis = 0.0 + for t in range(DOF): + weighted_dis += ( + (full_ik_result[i * N_SOL * DOF + j * DOF + t] - qpos_seed[i * DOF + t]) + * joint_weights[0] + * ( + full_ik_result[i * N_SOL * DOF + j * DOF + t] + - qpos_seed[i * DOF + t] + ) + * joint_weights[0] + ) + if weighted_dis < best_weighted_dis: + best_weighted_dis = weighted_dis + best_ids = j + if best_ids != -1: + # found best solution + best_ik_valid[i] = 1 + for k in range(DOF): + best_ik_result[i * DOF + k] = full_ik_result[ + i * N_SOL * DOF + best_ids * DOF + k + ] + else: + # no valid solution + best_ik_valid[i] = 0 diff --git a/embodichain/utils/warp/kinematics/srs_solver.py b/embodichain/utils/warp/kinematics/srs_solver.py new file mode 100644 index 00000000..4e960b09 --- /dev/null +++ b/embodichain/utils/warp/kinematics/srs_solver.py @@ -0,0 +1,789 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import warp as wp + + +@wp.func +def identity_mat44() -> wp.mat44: + # fmt: off + return wp.mat44( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 + ) + # fmt: on + + +@wp.func +def identity_mat33() -> wp.mat33: + # fmt: off + return wp.mat33( + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0 + ) + # fmt: on + + +@wp.func +def safe_acos(x: float) -> float: + return wp.acos(wp.clamp(x, -0.999999, 0.999999)) + + +@wp.func +def safe_division(numerator: float, denominator: float, eps: float = 1e-10) -> float: + if wp.abs(denominator) < eps: + return 0.0 + return numerator / denominator + + +@wp.func +def skew(vec: wp.vec3) -> wp.mat33: + """ + Calculate the skew-symmetric matrix of a vector. + + Args: + vec (wp.vec3): Input vector. + + Returns: + wp.mat33: Skew-symmetric matrix. + """ + # fmt: off + return wp.mat33( + 0.0, -vec[2], vec[1], + vec[2], 0.0, -vec[0], + -vec[1], vec[0], 0.0, + ) + # fmt: on + + +@wp.func +def dh_transform(d: float, alpha: float, a: float, theta: float) -> wp.mat44: + """ + Compute the Denavit-Hartenberg transformation matrix. + + Args: + d (float): Link offset. + alpha (float): Link twist. + a (float): Link length. + theta (float): Joint angle. + + Returns: + wp.mat44: The resulting transformation matrix. + """ + ct, st = wp.cos(theta), wp.sin(theta) + ca, sa = wp.cos(alpha), wp.sin(alpha) + # fmt: off + return wp.mat44( + ct, -st * ca, st * sa, a * ct, + st, ct * ca, -ct * sa, a * st, + 0.0, sa, ca, d, + 0.0, 0.0, 0.0, 1.0 + ) + # fmt: on + + +@wp.func +def transform_pose( + target_xpos: wp.mat44, + T_b_ob_inv: wp.mat44, + T_e_oe_inv: wp.mat44, + tcp_inv: wp.mat44, +) -> wp.mat44: + """ + Transform the target pose to the TCP frame. + Args: + target_xpos (wp.mat44): The target pose matrix. + T_b_ob_inv (wp.mat44): Inverse base-to-object transform. + tcp_inv (wp.mat44): Inverse TCP transform. + T_e_oe_inv (wp.mat44): Inverse end-effector transform. + Returns: + wp.mat44: Transformed pose in TCP frame. + """ + return T_b_ob_inv @ target_xpos @ tcp_inv @ T_e_oe_inv + + +@wp.kernel +def transform_pose_kernel( + target_xpos: wp.array(dtype=wp.mat44), + T_b_ob_inv: wp.mat44, + T_e_oe_inv: wp.mat44, + tcp_inv: wp.mat44, + output: wp.array(dtype=wp.mat44), +): + """ + Transform a batch of target poses to the TCP frame. + + Args: + target_xpos (wp.array): Batch of target pose matrices. + T_b_ob_inv (wp.mat44): Inverse base-to-object transform. + tcp_inv (wp.mat44): Inverse TCP transform. + T_e_oe_inv (wp.mat44): Inverse end-effector transform. + output (wp.array): Output array for transformed poses. + """ + tid = wp.tid() + output[tid] = T_b_ob_inv @ target_xpos[tid] @ tcp_inv @ T_e_oe_inv + + +@wp.func +def calculate_arm_joint_angles( + P_s_to_w: wp.vec3, + elbow_GC4: float, + link_lengths: wp.array(dtype=float), + res: wp.array(dtype=int), + joints: wp.array(dtype=wp.vec4), + tid: int, +): + """ + Compute joint angles for a 3-DOF arm given the shoulder-to-wrist vector. + + Args: + P_s_to_w (wp.vec3): Shoulder-to-wrist vector. + elbow_GC4 (float): Elbow configuration, typically ±1. + link_lengths (wp.array): [d_bs, d_se, d_ew] for each segment length. + res (wp.array): Output success flag. + joints (wp.array): Output joint angles. + tid (int): Thread index. + """ + d_bs = link_lengths[0] + d_se = link_lengths[1] + d_ew = link_lengths[2] + + # Extract components + x, y, z = P_s_to_w.x, P_s_to_w.y, P_s_to_w.z + horizontal_distance = wp.length(wp.vec2(x, y)) + shoulder_to_wrist_length = wp.length(P_s_to_w) + + # Initialize joint values + joints_val = wp.vec4() + + # Check reachability + if shoulder_to_wrist_length < wp.abs(d_bs + d_ew): + res[tid] = 0 + joints[tid] = joints_val + return + + # Compute elbow angle + elbow_cos_angle = ( + wp.pow(shoulder_to_wrist_length, 2.0) - wp.pow(d_se, 2.0) - wp.pow(d_ew, 2.0) + ) / (2.0 * d_se * d_ew) + if wp.abs(elbow_cos_angle) > 1.0: + res[tid] = 0 + joints[tid] = joints_val + return + + joints_val[3] = elbow_GC4 * safe_acos(elbow_cos_angle) + + # Compute shoulder angle + joints_val[0] = wp.atan2(y, x) if wp.abs(z) > 1e-6 else 0.0 + + # Compute joint 2 angle + angle_phi = safe_acos( + (wp.pow(d_se, 2.0) + wp.pow(shoulder_to_wrist_length, 2.0) - wp.pow(d_ew, 2.0)) + / (2.0 * d_se * shoulder_to_wrist_length) + ) + joints_val[1] = wp.atan2(horizontal_distance, z) + elbow_GC4 * angle_phi + + # Set success flag and output joint values + res[tid] = 1 + joints[tid] = joints_val + + +@wp.func +def compute_reference_plane( + pose: wp.mat44, + elbow_GC4: float, + link_lengths: wp.array(dtype=float), + dh_params: wp.array(dtype=float), + res: wp.array(dtype=int), + plane_normal: wp.array(dtype=wp.vec3), + base_to_elbow_rotation: wp.array(dtype=wp.mat33), + joints: wp.array(dtype=wp.vec4), + tid: int, +): + """ + Compute the reference plane normal, base-to-elbow rotation, and joint angles. + + Args: + pose (wp.mat44): Target pose matrix (4x4). + elbow_GC4 (float): Elbow configuration, typically ±1. + link_lengths (wp.array): Link lengths, at least [d_bs, d_se, d_ew, d_hand]. + dh_params (wp.array): DH parameters, shape [num_joints * 4]. + res (wp.array): Output success flag. + plane_normal (wp.array): Output plane normal vector. + base_to_elbow_rotation (wp.array): Output base-to-elbow rotation matrix. + joints (wp.array): Output joint angles. + tid (int): Thread index. + """ + # Extract position and rotation + P_target = wp.vec3(pose[0, 3], pose[1, 3], pose[2, 3]) + # fmt: off + R_target = wp.mat33( + pose[0, 0], pose[0, 1], pose[0, 2], + pose[1, 0], pose[1, 1], pose[1, 2], + pose[2, 0], pose[2, 1], pose[2, 2], + ) + # fmt: on + + # Base to shoulder + P02 = wp.vec3(0.0, 0.0, link_lengths[0]) + P67 = wp.vec3(0.0, 0.0, dh_params[6 * 4 + 0]) + + # Wrist position + P06 = P_target - R_target @ P67 + # Shoulder to wrist + P26 = P06 - P02 + + # Calculate joint angles + calculate_arm_joint_angles(P26, elbow_GC4, link_lengths, res, joints, tid) + if res[tid] == 0: + plane_normal[tid] = wp.vec3() + base_to_elbow_rotation[tid] = identity_mat33() + joints[tid] = wp.vec4() + return + + # Lower arm transformation (joint 4) + T34 = dh_transform( + dh_params[3 * 4 + 0], dh_params[3 * 4 + 1], dh_params[3 * 4 + 2], 0.0 + ) + P34 = wp.vec3(T34[0, 3], T34[1, 3], T34[2, 3]) + + # Reference plane normal + v1 = wp.normalize(P34 - P02) + v2 = wp.normalize(P06 - P02) + plane_normal[tid] = wp.cross(v1, v2) + + # Compute base-to-elbow rotation + base_to_elbow_rotation[tid] = identity_mat33() + for i in range(3): + base_idx = i * 4 + T = dh_transform( + dh_params[base_idx + 0], + dh_params[base_idx + 1], + dh_params[base_idx + 2], + joints[tid][i], + ) + # fmt: off + base_to_elbow_rotation[tid] = base_to_elbow_rotation[tid] @ wp.mat33( + T[0, 0], T[0, 1], T[0, 2], + T[1, 0], T[1, 1], T[1, 2], + T[2, 0], T[2, 1], T[2, 2], + ) + # fmt: on + + res[tid] = 1 + + +@wp.kernel +def compute_fk_kernel( + joint_angles: wp.array(dtype=float), + dh_params: wp.array(dtype=float), + rotation_directions: wp.array(dtype=float), + T_b_ob: wp.mat44, + T_oe_e: wp.mat44, + tcp_transform: wp.mat44, + pose_out: wp.array(dtype=wp.mat44), + success: wp.array(dtype=int), +): + """ + Compute forward kinematics (FK) for a batch of joint states. + + Args: + joint_angles (wp.array): Array of joint angles for each target ([N * num_joints]). + dh_params (wp.array): Denavit-Hartenberg parameters for the robot + ([num_joints * 4], where each joint has [d, alpha, a, theta]). + rotation_directions (wp.array): Array of rotation direction multipliers for each joint ([num_joints]). + T_b_ob (wp.mat44): Base-to-object transformation matrix. + T_oe_e (wp.mat44): End-effector-to-object transformation matrix. + tcp_transform (wp.mat44): Tool center point (TCP) transformation matrix. + pose_out (wp.array): Output array for computed poses ([N, 4x4]). + success (wp.array): Output array indicating whether FK computation was successful ([N]). + """ + tid = wp.tid() + num_joints = rotation_directions.shape[0] + + # Initialize pose as identity matrix + pose = identity_mat44() + + # Loop through each joint and apply DH transformation + for i in range(num_joints): + base_idx = i * 4 + d = dh_params[base_idx + 0] + alpha = dh_params[base_idx + 1] + a = dh_params[base_idx + 2] + theta = dh_params[base_idx + 3] + theta += joint_angles[tid * num_joints + i] * rotation_directions[i] + T = dh_transform(d, alpha, d, theta) + pose = pose @ T + + # Apply additional transforms: base, end-effector, TCP + pose = T_b_ob @ pose @ T_oe_e @ tcp_transform + + # Output pose and set success flag + pose_out[tid] = pose + success[tid] = 1 + + +@wp.func +def frobenius_norm(mat: wp.mat44) -> float: + """ + Compute the Frobenius norm of a 4x4 matrix. + + Args: + mat (wp.mat44): Input matrix. + + Returns: + float: Frobenius norm of the matrix. + """ + norm = 0.0 + for i in range(4): + for j in range(4): + norm += wp.pow(mat[i, j], 2.0) + return wp.sqrt(norm) + + +@wp.func +def validate_fk_with_target( + q1: float, + q2: float, + q3: float, + q4: float, + q5: float, + q6: float, + q7: float, + dh_params: wp.array(dtype=float), + rotation_directions: wp.array(dtype=float), + target_xpos: wp.mat44, + tolerance: float, +) -> int: + """ + Validate if the FK result matches the target pose within a given tolerance. + + Args: + joint_angles (wp.array): Joint angles for FK computation. + dh_params (wp.array): Denavit-Hartenberg parameters. + rotation_directions (wp.array): Rotation direction multipliers for each joint. + target_xpos (wp.mat44): Target pose matrix. + tolerance (float): Allowed error tolerance for validation. + + Returns: + int: 1 if FK result matches the target pose within tolerance, 0 otherwise. + """ + num_joints = wp.int32(rotation_directions.shape[0]) + + # Initialize pose as identity matrix + pose = identity_mat44() + + # Compute FK + for i in range(num_joints): + d = dh_params[i * 4 + 0] + alpha = dh_params[i * 4 + 1] + a = dh_params[i * 4 + 2] + theta = dh_params[i * 4 + 3] + # Apply joint angle with rotation direction + if i == 0: + joint_angle = q1 + elif i == 1: + joint_angle = q2 + elif i == 2: + joint_angle = q3 + elif i == 3: + joint_angle = q4 + elif i == 4: + joint_angle = q5 + elif i == 5: + joint_angle = q6 + elif i == 6: + joint_angle = q7 + + theta += joint_angle * rotation_directions[i] + T = dh_transform(d, alpha, a, theta) + pose = pose @ T + + # Compute the Frobenius norm of the difference + pose_diff = pose - target_xpos + pose_error = frobenius_norm(pose_diff) + + # Validate against tolerance + return 1 if pose_error <= tolerance else 0 + + +# TODO: automatic gradient support +@wp.kernel +def compute_ik_kernel( + combinations: wp.array(dtype=wp.vec3), + target_xpos_list: wp.array(dtype=wp.mat44), + angles_list: wp.array(dtype=float), + qpos_limits: wp.array(dtype=wp.vec2), + configs: wp.array(dtype=wp.vec3), + dh_params: wp.array(dtype=float), + link_lengths: wp.array(dtype=float), + rotation_directions: wp.array(dtype=float), + res_arm_angles: wp.array(dtype=int), + joints_arm: wp.array(dtype=wp.vec4), + res_plane_normal: wp.array(dtype=int), + plane_normal: wp.array(dtype=wp.vec3), + base_to_elbow_rotation: wp.array(dtype=wp.mat33), + joints_plane: wp.array(dtype=wp.vec4), + success: wp.array(dtype=int), + qpos_out: wp.array(dtype=float), +): + """ + Compute inverse kinematics (IK) in parallel for multiple target poses. + + Args: + combinations (wp.array): Array of combinations, where each entry specifies + the indices of the target pose, configuration, and reference angle. + target_xpos_list (wp.array): Array of target poses (4x4 transformation matrices). + angles_list (wp.array): Array of reference angles for IK computation. + qpos_limits (wp.array): Array of joint position limits (min, max) for each joint. + configs (wp.array): Array of configuration vectors (shoulder, elbow, wrist). + dh_params (wp.array): Denavit-Hartenberg parameters for the robot. + link_lengths (wp.array): Array of link lengths for the robot arm. + rotation_directions (wp.array): Array of rotation direction multipliers for each joint. + res_arm_angles (wp.array): Output array for arm joint angle computation results. + joints_arm (wp.array): Output array for computed arm joint angles. + res_plane_normal (wp.array): Output array for plane normal computation results. + plane_normal (wp.array): Output array for computed plane normal vectors. + base_to_elbow_rotation (wp.array): Output array for base-to-elbow rotation matrices. + joints_plane (wp.array): Output array for computed joint angles in the plane. + success (wp.array): Output array indicating whether IK computation was successful. + qpos_out (wp.array): Output array for computed joint positions. + + Notes: + This kernel computes the inverse kinematics for a batch of target poses in parallel. + It validates the computed joint positions against joint limits and the target pose. + Successful solutions are stored in the output arrays. + """ + tid = wp.tid() # Thread ID (for batch processing, if needed) + + # Extract indices + target_idx = int(combinations[tid][0]) + config_idx = int(combinations[tid][1]) + angle_idx = int(combinations[tid][2]) + + # Load inputs + target_xpos = target_xpos_list[target_idx] + config = configs[config_idx] + angle_ref = angles_list[angle_idx] + + # Extract shoulder, elbow, wrist configurations + shoulder_config, elbow_config, wrist_config = config.x, config.y, config.z + + # Transform target pose (xpos_ = target_xpos @ tcp_inv @ T_e_oe_inv) + # fmt: off + P_target = wp.vec3(target_xpos[0, 3], target_xpos[1, 3], target_xpos[2, 3]) + R_target = wp.mat33( + target_xpos[0, 0], target_xpos[0, 1], target_xpos[0, 2], + target_xpos[1, 0], target_xpos[1, 1], target_xpos[1, 2], + target_xpos[2, 0], target_xpos[2, 1], target_xpos[2, 2], + ) + # fmt: on + + # Compute shoulder-to-wrist vector + P02 = wp.vec3(0.0, 0.0, link_lengths[0]) + P67 = wp.vec3(0.0, 0.0, dh_params[12]) + P06 = P_target - R_target @ P67 + P26 = P06 - P02 + + calculate_arm_joint_angles( + P26, elbow_config, link_lengths, res_arm_angles, joints_arm, tid + ) + if res_arm_angles[tid] == 0: + success[tid] = 0 + return + joints_v = joints_arm[tid] + + # fmt: off + # Calculate transformations + T34 = dh_transform( + dh_params[12], + dh_params[13], + dh_params[14], + joints_v[3], + ) + R34 = wp.mat33( + T34[0, 0], T34[0, 1], T34[0, 2], + T34[1, 0], T34[1, 1], T34[1, 2], + T34[2, 0], T34[2, 1], T34[2, 2], + ) + # fmt: on + + # Calculate reference joint angles + compute_reference_plane( + target_xpos, + elbow_config, + link_lengths, + dh_params, + res_plane_normal, + plane_normal, + base_to_elbow_rotation, + joints_plane, + tid, + ) + if res_plane_normal[tid] == 0: + success[tid] = 0 + return + + R03_o = base_to_elbow_rotation[tid] + + usw = wp.normalize(P26) + skew_usw = skew(usw) + s_psi = wp.sin(angle_ref) + c_psi = wp.cos(angle_ref) + + # Calculate shoulder joint angles (q1, q2, q3) + As = skew_usw @ R03_o + Bs = -skew_usw @ skew_usw @ R03_o + Cs = wp.outer(usw, usw) @ R03_o + R03 = ( + (skew_usw @ R03_o) * s_psi + + (-skew_usw @ skew_usw @ R03_o) * c_psi + + (wp.outer(usw, usw) @ R03_o) + ) + + # TODO: judgment shoulder singularity + q1 = wp.atan2(R03[1, 1] * shoulder_config, R03[0, 1] * shoulder_config) + q2 = safe_acos(R03[2, 1]) * shoulder_config + q3 = wp.atan2(-R03[2, 2] * shoulder_config, -R03[2, 0] * shoulder_config) + + # Calculate wrist joint angles (q5, q6, q7) + Aw = wp.transpose(R34) @ wp.transpose(As) @ R_target + Bw = wp.transpose(R34) @ wp.transpose(Bs) @ R_target + Cw = wp.transpose(R34) @ wp.transpose(Cs) @ R_target + R47 = Aw * s_psi + Bw * c_psi + Cw + + q4 = joints_v[3] + # TODO: judgment wrist singularity + q5 = wp.atan2(R47[1, 2] * wrist_config, R47[0, 2] * wrist_config) + q6 = safe_acos(R47[2, 2]) * wrist_config + q7 = wp.atan2(R47[2, 1] * wrist_config, -R47[2, 0] * wrist_config) + + out_of_limits = int(0) + + q1_val = (q1 - dh_params[3]) * rotation_directions[0] + q2_val = (q2 - dh_params[7]) * rotation_directions[1] + q3_val = (q3 - dh_params[11]) * rotation_directions[2] + q4_val = (q4 - dh_params[15]) * rotation_directions[3] + q5_val = (q5 - dh_params[19]) * rotation_directions[4] + q6_val = (q6 - dh_params[23]) * rotation_directions[5] + q7_val = (q7 - dh_params[27]) * rotation_directions[6] + + out_of_limits = int(0) + out_of_limits = out_of_limits | ( + 1 if (q1_val < qpos_limits[0][0] or q1_val > qpos_limits[0][1]) else 0 + ) + out_of_limits = out_of_limits | ( + 1 if (q2_val < qpos_limits[1][0] or q2_val > qpos_limits[1][1]) else 0 + ) + out_of_limits = out_of_limits | ( + 1 if (q3_val < qpos_limits[2][0] or q3_val > qpos_limits[2][1]) else 0 + ) + out_of_limits = out_of_limits | ( + 1 if (q4_val < qpos_limits[3][0] or q4_val > qpos_limits[3][1]) else 0 + ) + out_of_limits = out_of_limits | ( + 1 if (q5_val < qpos_limits[4][0] or q5_val > qpos_limits[4][1]) else 0 + ) + out_of_limits = out_of_limits | ( + 1 if (q6_val < qpos_limits[5][0] or q6_val > qpos_limits[5][1]) else 0 + ) + out_of_limits = out_of_limits | ( + 1 if (q7_val < qpos_limits[6][0] or q7_val > qpos_limits[6][1]) else 0 + ) + + # Check joint limits + if out_of_limits == 1: + success[tid] = 0 + return + + is_valid = validate_fk_with_target( + q1=q1_val, + q2=q2_val, + q3=q3_val, + q4=q4_val, + q5=q5_val, + q6=q6_val, + q7=q7_val, + dh_params=dh_params, + rotation_directions=rotation_directions, + target_xpos=target_xpos, + tolerance=1e-4, + ) + + # Save joint angles only if valid + if is_valid: + qpos_out[tid * 7] = q1_val + qpos_out[tid * 7 + 1] = q2_val + qpos_out[tid * 7 + 2] = q3_val + qpos_out[tid * 7 + 3] = q4_val + qpos_out[tid * 7 + 4] = q5_val + qpos_out[tid * 7 + 5] = q6_val + qpos_out[tid * 7 + 6] = q7_val + success[tid] = 1 # Mark as successful + else: + success[tid] = 0 # Mark as failed + + +@wp.kernel +def sort_ik_kernel( + qpos_out: wp.array(dtype=float), # [N * N_SOL, 7] + success: wp.array(dtype=int), # [N * N_SOL] + qpos_seed: wp.array(dtype=float), # [N, 7] + ik_weight: wp.array(dtype=float), # [7] + distances: wp.array(dtype=float), # [N, N_SOL] + indices: wp.array(dtype=int), # [N, N_SOL] + N_SOL: int, + sorted_qpos: wp.array(dtype=float), # [N, N_SOL, 7] + sorted_valid: wp.array(dtype=int), # [N, N_SOL] +): + """ + Sort inverse kinematics (IK) solutions for multiple targets based on their distances + to a seed configuration. + + Args: + qpos_out (wp.array): Array of computed joint positions for all solutions + ([N * N_SOL, 7]). + success (wp.array): Array indicating whether each solution is valid ([N * N_SOL]). + qpos_seed (wp.array): Array of seed joint positions for each target ([N, 7]). + ik_weight (wp.array): Array of weights for each joint to compute distance ([7]). + distances (wp.array): Output array to store computed distances ([N, N_SOL]). + indices (wp.array): Output array to store sorted indices ([N, N_SOL]). + N_SOL (int): Number of solutions per target. + sorted_qpos (wp.array): Output array for sorted joint positions ([N, N_SOL, 7]). + sorted_valid (wp.array): Output array for sorted validity flags ([N, N_SOL]). + """ + tid = wp.tid() # target index + + # 1. compute distances + for i in range(N_SOL): + idx = tid * N_SOL + i + valid = success[idx] + dist = 0.0 + if valid: + for j in range(7): + diff = qpos_out[idx * 7 + j] - qpos_seed[tid * 7 + j] + dist += ik_weight[j] * diff * diff + else: + dist = 1e10 + + distances[idx] = dist + indices[idx] = i + + # 2. bubble sort (only sort the N_SOL solutions for the current target) + for i in range(N_SOL): + min_idx = i + for j in range(i + 1, N_SOL): + idx_a = tid * N_SOL + min_idx + idx_b = tid * N_SOL + j + if distances[idx_b] < distances[idx_a]: + min_idx = j + # Swap + if min_idx != i: + idx_i = tid * N_SOL + i + idx_min = tid * N_SOL + min_idx + tmp_dist = distances[idx_i] + distances[idx_i] = distances[idx_min] + distances[idx_min] = tmp_dist + tmp_idx = indices[idx_i] + indices[idx_i] = indices[idx_min] + indices[idx_min] = tmp_idx + + # 3. reorder qpos_out and success according to sorted indices + for i in range(N_SOL): + src_idx = tid * N_SOL + indices[tid * N_SOL + i] + for j in range(7): + sorted_qpos[(tid * N_SOL + i) * 7 + j] = qpos_out[src_idx * 7 + j] + sorted_valid[tid * N_SOL + i] = success[src_idx] + + +@wp.kernel +def nearest_ik_kernel( + qpos_out: wp.array(dtype=float), # [N * N_SOL * 7] + success: wp.array(dtype=int), # [N * N_SOL] + qpos_seed: wp.array(dtype=float), # [N * 7] + ik_weight: wp.array(dtype=float), # [7] + N_SOL: int, + nearest_qpos: wp.array(dtype=float), # [N * 7] + nearest_valid: wp.array(dtype=int), # [N] +): + """ + Find the nearest valid inverse kinematics (IK) solution for each target. + + Args: + qpos_out (wp.array): Array of computed joint positions for all solutions + ([N * N_SOL, 7]). + success (wp.array): Array indicating whether each solution is valid ([N * N_SOL]). + qpos_seed (wp.array): Array of seed joint positions for each target ([N, 7]). + ik_weight (wp.array): Array of weights for each joint to compute distance ([7]). + N_SOL (int): Number of solutions per target. + nearest_qpos (wp.array): Output array for the nearest joint positions ([N, 7]). + nearest_valid (wp.array): Output array indicating whether a valid solution was found ([N]). + """ + + tid = wp.tid() # target index + + min_dist = float(1e20) + nearest_idx = int(-1) + + for i in range(N_SOL): + idx = tid * N_SOL + i + if success[idx]: + dist = 0.0 + for j in range(7): + diff = qpos_out[idx * 7 + j] - qpos_seed[tid * 7 + j] + dist += ik_weight[j] * diff * diff + if dist < min_dist: + min_dist = dist + nearest_idx = idx + + if nearest_idx >= 0: + for j in range(7): + nearest_qpos[tid * 7 + j] = qpos_out[nearest_idx * 7 + j] + nearest_valid[tid] = 1 + else: + for j in range(7): + nearest_qpos[tid * 7 + j] = 0.0 + nearest_valid[tid] = 0 + + +@wp.kernel +def check_success_kernel( + success_wp: wp.array(dtype=int), + num_solutions: int, + success_counts: wp.array(dtype=int), +): + """ + Count the number of successful inverse kinematics (IK) solutions for each target. + + Args: + success_wp (wp.array): Array indicating whether each solution is valid + ([N * num_solutions], where N is the number of targets). + num_solutions (int): Number of solutions per target. + success_counts (wp.array): Output array to store the count of valid solutions + for each target ([N]). + """ + tid = wp.tid() # target index + count = int(0) + + for i in range(num_solutions): + idx = tid * num_solutions + i + if success_wp[idx]: + count += 1 + + success_counts[tid] = count diff --git a/embodichain/utils/warp/kinematics/warp_trajectory.py b/embodichain/utils/warp/kinematics/warp_trajectory.py new file mode 100644 index 00000000..535136b3 --- /dev/null +++ b/embodichain/utils/warp/kinematics/warp_trajectory.py @@ -0,0 +1,180 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +import warp as wp + + +@wp.kernel +def trajectory_get_diff_kernel( + in_trajectory: wp.array(dtype=float), + key_indices: wp.array(dtype=int), + key_frames: wp.array(dtype=float), + waypoint_num: int, + dof: int, + key_frame_num: int, + warp_trajectory: wp.array(dtype=float), +): + """warp trajectory get diff kernel + + Args: + in_trajectory (wp.array, optional): (waypoint_num * dof) of float. Input trajectory. + key_indices (wp.array, optional): (key_frame_num,) of int. Key frame indices. + key_frames (wp.array, optional): (bn * key_frame_num * dof) of float. Batch key frames. + waypoint_num (int): number of waypoints. + dof (int): number of degrees of freedom. + key_frame_num (int): number of key frames. + warp_trajectory (wp.array, optional): (bn * waypoint_num * dof) of float. Output warp trajectory. + """ + arena_id, dim = wp.tid() + + # write_diff + for i in range(key_frame_num): + key_id = key_indices[i] + warp_id = arena_id * waypoint_num * dof + key_id * dof + dim + key_frame_id = arena_id * key_frame_num * dof + i * dof + dim + in_trajectory_id = key_id * dof + dim + warp_trajectory[warp_id] = ( + key_frames[key_frame_id] - in_trajectory[in_trajectory_id] + ) + + +@wp.kernel +def trajectory_interpolate_kernel( + key_indices: wp.array(dtype=int), + waypoint_num: int, + dof: int, + key_frame_num: int, + warp_trajectory: wp.array(dtype=float), +): + """warp trajectory interpolate kernel + + Args: + key_indices (wp.array, optional): (key_frame_num,) of int. Key frame indices. + waypoint_num (int): number of waypoints. + dof (int): number of degrees of freedom. + key_frame_num (int): number of key frames. + warp_trajectory (wp.array, optional): (bn * waypoint_num * dof) of float. Output warp trajectory. + """ + arena_id, waypoint_id, dim = wp.tid() + inter_warp_id = arena_id * waypoint_num * dof + waypoint_id * dof + dim + + start_id = int(-1) + end_id = int(-1) + # find start id and end id + # assume key_indices is sorted, start from 0, end at waypoint_num - 1 + for i in range(key_frame_num): + key_id = key_indices[i] + # to the final one + if waypoint_id >= key_id: + start_id = key_id + end_id = key_indices[i + 1] + + if waypoint_id == end_id or waypoint_id == start_id: + # start | final key frame, only add to interp id + return + + if start_id == -1 or end_id == -1: + # invalid, do nothing + return + + alpha = float(waypoint_id - start_id) / float(end_id - start_id) + start_warp_id = arena_id * waypoint_num * dof + start_id * dof + dim + end_warp_id = arena_id * waypoint_num * dof + end_id * dof + dim + + warp_trajectory[inter_warp_id] = (1.0 - alpha) * warp_trajectory[ + start_warp_id + ] + alpha * warp_trajectory[end_warp_id] + + +@wp.kernel +def trajectory_add_origin_kernel( + in_trajectory: wp.array(dtype=float), + waypoint_num: int, + dof: int, + warp_trajectory: wp.array(dtype=float), +): + arena_id, waypoint_id, dim = wp.tid() + inter_warp_id = arena_id * waypoint_num * dof + waypoint_id * dof + dim + in_trajectory_id = waypoint_id * dof + dim + warp_trajectory[inter_warp_id] += in_trajectory[in_trajectory_id] + + +@wp.kernel +def get_offset_qpos_kernel( + key_obj_indices: wp.array(dtype=int), + obj_offset: wp.array(dtype=float), + key_xpos: wp.array(dtype=float), + base_xpos_inv: wp.mat44f, + n_batch: int, + n_keyframe: int, + key_xpos_offset: wp.array(dtype=float), +): + batch_id, key_id = wp.tid() + obj_idx = key_obj_indices[key_id] + obj_offset_idx = n_batch * obj_idx + batch_id + obj_offset_pose = wp.mat44f( + obj_offset[obj_offset_idx * 16 + 0], + obj_offset[obj_offset_idx * 16 + 1], + obj_offset[obj_offset_idx * 16 + 2], + obj_offset[obj_offset_idx * 16 + 3], + obj_offset[obj_offset_idx * 16 + 4], + obj_offset[obj_offset_idx * 16 + 5], + obj_offset[obj_offset_idx * 16 + 6], + obj_offset[obj_offset_idx * 16 + 7], + obj_offset[obj_offset_idx * 16 + 8], + obj_offset[obj_offset_idx * 16 + 9], + obj_offset[obj_offset_idx * 16 + 10], + obj_offset[obj_offset_idx * 16 + 11], + obj_offset[obj_offset_idx * 16 + 12], + obj_offset[obj_offset_idx * 16 + 13], + obj_offset[obj_offset_idx * 16 + 14], + obj_offset[obj_offset_idx * 16 + 15], + ) + key_xpos_single = wp.mat44f( + key_xpos[key_id * 16 + 0], + key_xpos[key_id * 16 + 1], + key_xpos[key_id * 16 + 2], + key_xpos[key_id * 16 + 3], + key_xpos[key_id * 16 + 4], + key_xpos[key_id * 16 + 5], + key_xpos[key_id * 16 + 6], + key_xpos[key_id * 16 + 7], + key_xpos[key_id * 16 + 8], + key_xpos[key_id * 16 + 9], + key_xpos[key_id * 16 + 10], + key_xpos[key_id * 16 + 11], + key_xpos[key_id * 16 + 12], + key_xpos[key_id * 16 + 13], + key_xpos[key_id * 16 + 14], + key_xpos[key_id * 16 + 15], + ) + key_xpos_offset_i = base_xpos_inv * key_xpos_single * obj_offset_pose + key_xpos_offset_idx = batch_id * n_keyframe + key_id + key_xpos_offset[key_xpos_offset_idx * 16 + 0] = key_xpos_offset_i[0][0] + key_xpos_offset[key_xpos_offset_idx * 16 + 1] = key_xpos_offset_i[0][1] + key_xpos_offset[key_xpos_offset_idx * 16 + 2] = key_xpos_offset_i[0][2] + key_xpos_offset[key_xpos_offset_idx * 16 + 3] = key_xpos_offset_i[0][3] + key_xpos_offset[key_xpos_offset_idx * 16 + 4] = key_xpos_offset_i[1][0] + key_xpos_offset[key_xpos_offset_idx * 16 + 5] = key_xpos_offset_i[1][1] + key_xpos_offset[key_xpos_offset_idx * 16 + 6] = key_xpos_offset_i[1][2] + key_xpos_offset[key_xpos_offset_idx * 16 + 7] = key_xpos_offset_i[1][3] + key_xpos_offset[key_xpos_offset_idx * 16 + 8] = key_xpos_offset_i[2][0] + key_xpos_offset[key_xpos_offset_idx * 16 + 9] = key_xpos_offset_i[2][1] + key_xpos_offset[key_xpos_offset_idx * 16 + 10] = key_xpos_offset_i[2][2] + key_xpos_offset[key_xpos_offset_idx * 16 + 11] = key_xpos_offset_i[2][3] + key_xpos_offset[key_xpos_offset_idx * 16 + 12] = key_xpos_offset_i[3][0] + key_xpos_offset[key_xpos_offset_idx * 16 + 13] = key_xpos_offset_i[3][1] + key_xpos_offset[key_xpos_offset_idx * 16 + 14] = key_xpos_offset_i[3][2] + key_xpos_offset[key_xpos_offset_idx * 16 + 15] = key_xpos_offset_i[3][3] diff --git a/examples/gym/pour_water.sh b/examples/gym/pour_water.sh new file mode 100755 index 00000000..49485f16 --- /dev/null +++ b/examples/gym/pour_water.sh @@ -0,0 +1,3 @@ +python -m embodichain.lab.scripts.run_env --gym_config configs/gym/pour_water/gym_config.json \ + --action_config configs/gym/pour_water/action_config.json \ + --filter_visual_rand diff --git a/examples/gym/run_scoop_ice.sh b/examples/gym/run_scoop_ice.sh new file mode 100755 index 00000000..269f4797 --- /dev/null +++ b/examples/gym/run_scoop_ice.sh @@ -0,0 +1 @@ +python -m embodichain.lab.scripts.run_env --gym_config configs/gym/scoop_ice/gym_config.json diff --git a/examples/sim/demo/grasp_cup_to_caffe.py b/examples/sim/demo/grasp_cup_to_caffe.py new file mode 100644 index 00000000..c1073c3f --- /dev/null +++ b/examples/sim/demo/grasp_cup_to_caffe.py @@ -0,0 +1,469 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +""" +This script demonstrates the creation and simulation of a robot with dexterous hands, +and performs a scoop ice task in a simulated environment. +""" + +import argparse +import numpy as np +import torch +from tqdm import tqdm +from typing import Union +from scipy.spatial.transform import Rotation as R +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.objects import Robot, RigidObject +from embodichain.lab.sim.cfg import ( + LightCfg, + JointDrivePropertiesCfg, + RigidObjectCfg, + RigidBodyAttributesCfg, + ArticulationCfg, +) +from embodichain.lab.sim.utility.action_utils import interpolate_with_distance_warp +from embodichain.lab.sim.shapes import MeshCfg +from embodichain.data import get_data_path +from embodichain.utils import logger + +from embodichain.lab.sim.robots.dexforce_w1.cfg import DexforceW1Cfg + + +def parse_arguments(): + """ + Parse command-line arguments to configure the simulation. + + Returns: + argparse.Namespace: Parsed arguments including number of environments and rendering options. + """ + parser = argparse.ArgumentParser( + description="Create and simulate a robot in SimulationManager" + ) + parser.add_argument( + "--num_envs", type=int, default=9, help="Number of parallel environments" + ) + parser.add_argument( + "--enable_rt", action="store_true", help="Enable ray tracing rendering" + ) + parser.add_argument("--headless", action="store_true", help="Enable headless mode") + parser.add_argument( + "--device", + type=str, + default="cpu", + help="device to run the environment on, e.g., 'cpu' or 'cuda'", + ) + return parser.parse_args() + + +def initialize_simulation(args) -> SimulationManager: + """ + Initialize the simulation environment based on the provided arguments. + + Args: + args (argparse.Namespace): Parsed command-line arguments. + + Returns: + SimulationManager: Configured simulation manager instance. + """ + config = SimulationManagerCfg( + headless=True, + sim_device=args.device, + enable_rt=args.enable_rt, + physics_dt=1.0 / 100.0, + ) + sim = SimulationManager(config) + + sim.build_multiple_arenas(args.num_envs, space=2.5) + # Set manual physics update for precise control + sim.set_manual_update(True) + + if args.enable_rt: + light = sim.add_light( + cfg=LightCfg( + uid="main_light", + color=(0.6, 0.6, 0.6), + intensity=30.0, + init_pos=(1.0, 0, 3.0), + ) + ) + + return sim + + +def create_robot(sim: SimulationManager) -> Robot: + """ + Create and configure a robot with an arm and a dexterous hand in the simulation. + + Args: + sim (SimulationManager): The simulation manager instance. + + Returns: + Robot: The configured robot instance added to the simulation. + """ + cfg = DexforceW1Cfg.from_dict( + { + "uid": "dexforce_w1", + "init_pos": [0.4, -0.5, 0.0], + } + ) + cfg.solver_cfg["left_arm"].tcp = np.array( + [ + [1.0, 0.0, 0.0, 0.012], + [0.0, 1.0, 0.0, 0.04], + [0.0, 0.0, 1.0, 0.11], + [0.0, 0.0, 0.0, 1.0], + ] + ) + cfg.solver_cfg["right_arm"].tcp = np.array( + [ + [1.0, 0.0, 0.0, 0.012], + [0.0, 1.0, 0.0, -0.04], + [0.0, 0.0, 1.0, 0.11], + [0.0, 0.0, 0.0, 1.0], + ] + ) + + cfg.init_qpos = [ + 1.0000e00, + -2.0000e00, + 1.0000e00, + 0.0000e00, + -2.6921e-05, + -2.6514e-03, + -1.5708e00, + 1.4575e00, + -7.8540e-01, + 1.2834e-01, + 1.5708e00, + -2.2310e00, + -7.8540e-01, + 1.4461e00, + -1.5708e00, + 1.6716e00, + 7.8540e-01, + 7.6745e-01, + 0.0000e00, + 3.8108e-01, + 0.0000e00, + 0.0000e00, + 0.0000e00, + 0.0000e00, + 1.5000e00, + 0.0000e00, + 0.0000e00, + 0.0000e00, + 0.0000e00, + 1.5000e00, + 6.9974e-02, + 7.3950e-02, + 6.6574e-02, + 6.0923e-02, + 0.0000e00, + 6.7342e-02, + 7.0862e-02, + 6.3684e-02, + 5.7822e-02, + 0.0000e00, + ] + return sim.add_robot(cfg=cfg) + + +def create_table(sim: SimulationManager) -> RigidObject: + """ + Create a table rigid object in the simulation. + + Args: + sim (SimulationManager): The simulation manager instance. + + Returns: + RigidObject: The table object added to the simulation. + """ + scoop_cfg = RigidObjectCfg( + uid="table", + shape=MeshCfg( + fpath=get_data_path("MultiW1Data/table_a.obj"), + ), + attrs=RigidBodyAttributesCfg( + mass=0.5, + ), + max_convex_hull_num=8, + body_type="kinematic", + init_pos=[1.1, -0.5, 0.08], + init_rot=[0.0, 0.0, 0.0], + ) + scoop = sim.add_rigid_object(cfg=scoop_cfg) + return scoop + + +def create_caffe(sim: SimulationManager) -> Robot: + """ + Create a caffe (container) articulated object in the simulation. + + Args: + sim (SimulationManager): The simulation manager instance. + + Returns: + Robot: The caffe object added to the simulation. + """ + container_cfg = ArticulationCfg( + uid="caffe", + fpath=get_data_path("MultiW1Data/cafe/cafe.urdf"), + init_pos=[1.05, -0.5, 0.79], + init_rot=[0, 0, -30], + attrs=RigidBodyAttributesCfg( + mass=1.0, + ), + drive_pros=JointDrivePropertiesCfg( + stiffness=1.0, damping=0.1, max_effort=100.0, drive_type="force" + ), + ) + container = sim.add_articulation(cfg=container_cfg) + return container + + +def create_cup(sim: SimulationManager) -> RigidObject: + """ + Create a cup rigid object in the simulation. + + Args: + sim (SimulationManager): The simulation manager instance. + + Returns: + RigidObject: The cup object added to the simulation. + """ + scoop_cfg = RigidObjectCfg( + uid="cup", + shape=MeshCfg( + fpath=get_data_path("MultiW1Data/paper_cup_2.obj"), + ), + attrs=RigidBodyAttributesCfg( + mass=0.3, + ), + max_convex_hull_num=1, + body_type="dynamic", + init_pos=[0.86, -0.76, 0.841], + init_rot=[0.0, 0.0, 0.0], + ) + scoop = sim.add_rigid_object(cfg=scoop_cfg) + return scoop + + +def create_trajectory( + sim: SimulationManager, robot: Robot, cup: RigidObject, caffe: Robot +) -> torch.Tensor: + """ + Generate a trajectory for the right arm to grasp the cup and move it to the caffe. + + Args: + sim (SimulationManager): The simulation manager instance. + robot (Robot): The robot instance. + cup (RigidObject): The cup object. + caffe (Robot): The caffe object. + + Returns: + torch.Tensor: Interpolated trajectory of shape [n_envs, n_waypoint, dof]. + """ + right_arm_ids = robot.get_joint_ids("right_arm") + hand_open_qpos = torch.tensor( + [0.0, 1.5, 0.0, 0.0, 0.0, 0.0], + dtype=torch.float32, + device=sim.device, + ) + hand_close_qpos = torch.tensor( + [0.1, 1.5, 0.3, 0.2, 0.3, 0.3], + dtype=torch.float32, + device=sim.device, + ) + + cup_position = cup.get_local_pose(to_matrix=True)[:, :3, 3] + + # grasp cup waypoint generation + rest_right_qpos = robot.get_qpos()[:, right_arm_ids] # [n_envs, dof] + right_arm_xpos = robot.compute_fk( + qpos=rest_right_qpos, name="right_arm", to_matrix=True + ) + approach_cup_relative_position = torch.tensor( + [-0.05, -0.06, 0.025], dtype=torch.float32, device=sim.device + ) + pick_cup_relative_position = torch.tensor( + [-0.03, -0.028, 0.021], dtype=torch.float32, device=sim.device + ) + + approach_xpos = right_arm_xpos.clone() + approach_xpos[:, :3, 3] = cup_position + approach_cup_relative_position + + pick_xpos = right_arm_xpos.clone() + pick_xpos[:, :3, 3] = cup_position + pick_cup_relative_position + + lift_xpos = pick_xpos.clone() + lift_xpos[:, 2, 3] += 0.07 + + # place cup to caffe waypoint generation + caffe_position = caffe.get_local_pose(to_matrix=True)[:, :3, 3] + place_cup_up_relative_position = torch.tensor( + [-0.14, -0.18, 0.13], dtype=torch.float32, device=sim.device + ) + place_cup_down_relative_position = torch.tensor( + [-0.14, -0.18, 0.09], dtype=torch.float32, device=sim.device + ) + + place_cup_up_pose = lift_xpos.clone() + place_cup_up_pose[:, :3, 3] = caffe_position + place_cup_up_relative_position + place_down_pose = lift_xpos.clone() + place_down_pose[:, :3, 3] = caffe_position + place_cup_down_relative_position + # compute ik for each waypoint + is_success, approach_qpos = robot.compute_ik( + pose=approach_xpos, joint_seed=rest_right_qpos, name="right_arm" + ) + is_success, pick_qpos = robot.compute_ik( + pose=pick_xpos, joint_seed=approach_qpos, name="right_arm" + ) + is_success, lift_qpos = robot.compute_ik( + pose=lift_xpos, joint_seed=pick_qpos, name="right_arm" + ) + is_success, place_up_qpos = robot.compute_ik( + pose=place_cup_up_pose, joint_seed=lift_qpos, name="right_arm" + ) + is_success, place_down_qpos = robot.compute_ik( + pose=place_down_pose, joint_seed=place_up_qpos, name="right_arm" + ) + + n_envs = sim.num_envs + + # combine hand and arm trajectory + arm_trajectory = torch.cat( + [ + rest_right_qpos[:, None, :], + approach_qpos[:, None, :], + pick_qpos[:, None, :], + pick_qpos[:, None, :], + lift_qpos[:, None, :], + place_up_qpos[:, None, :], + place_down_qpos[:, None, :], + place_down_qpos[:, None, :], + lift_qpos[:, None, :], + rest_right_qpos[:, None, :], + ], + dim=1, + ) + hand_trajectory = torch.cat( + [ + hand_open_qpos[None, None, :].repeat(n_envs, 1, 1), + hand_open_qpos[None, None, :].repeat(n_envs, 1, 1), + hand_open_qpos[None, None, :].repeat(n_envs, 1, 1), + hand_close_qpos[None, None, :].repeat(n_envs, 1, 1), + hand_close_qpos[None, None, :].repeat(n_envs, 1, 1), + hand_close_qpos[None, None, :].repeat(n_envs, 1, 1), + hand_close_qpos[None, None, :].repeat(n_envs, 1, 1), + hand_open_qpos[None, None, :].repeat(n_envs, 1, 1), + hand_open_qpos[None, None, :].repeat(n_envs, 1, 1), + hand_open_qpos[None, None, :].repeat(n_envs, 1, 1), + ], + dim=1, + ) + all_trajectory = torch.cat([arm_trajectory, hand_trajectory], dim=-1) + # trajetory with shape [n_envs, n_waypoint, dof] + interp_trajectory = interpolate_with_distance_warp( + trajectory=all_trajectory, interp_num=150, device=sim.device + ) + return interp_trajectory + + +def run_simulation( + sim: SimulationManager, robot: Robot, cup: RigidObject, caffe: Robot +): + """ + Execute the generated trajectory to drive the robot to complete the grasp and place task. + + Args: + sim (SimulationManager): The simulation manager instance. + robot (Robot): The robot instance. + cup (RigidObject): The cup object. + caffe (Robot): The caffe object. + """ + # [n_envs, n_waypoint, dof] + interp_trajectory = create_trajectory(sim, robot, cup, caffe) + + right_arm_ids = robot.get_joint_ids("right_arm") + right_hand_ids = robot.get_joint_ids("right_eef") + combine_ids = np.concatenate([right_arm_ids, right_hand_ids]) + n_waypoints = interp_trajectory.shape[1] + logger.log_info(f"Executing trajectory...") + for i in tqdm(range(n_waypoints)): + robot.set_qpos(interp_trajectory[:, i, :], joint_ids=combine_ids) + sim.update(step=10) + + +def apply_random_xy_perturbation( + item: Union[RigidObject, Robot], max_perturbation: float = 0.02 +): + """ + Apply random perturbation to the object's XY position. + + Args: + item (Union[RigidObject, Robot]): The object to perturb. + max_perturbation (float): Maximum perturbation magnitude. + """ + item_pose = item.get_local_pose(to_matrix=True) + item_xy = item_pose[:, :2, 3].to("cpu").numpy() + perturbation = np.random.uniform( + low=-max_perturbation, high=max_perturbation, size=item_xy.shape + ) + new_xy = item_xy + perturbation + item_pose[:, :2, 3] = torch.tensor( + new_xy, dtype=torch.float32, device=item_pose.device + ) + item.set_local_pose(item_pose) + + +def main(): + """ + Main function to demonstrate robot simulation. + + Initializes the simulation, creates the robot and objects, and performs the grasp and place task. + """ + args = parse_arguments() + sim = initialize_simulation(args) + + robot = create_robot(sim) + table = create_table(sim) + caffe = create_caffe(sim) + cup = create_cup(sim) + + # apply random perturbation + apply_random_xy_perturbation(cup, max_perturbation=0.05) + apply_random_xy_perturbation(caffe, max_perturbation=0.05) + + if not args.headless: + sim.open_window() + + run_simulation(sim, robot, cup, caffe) + + logger.log_info("\n Press Ctrl+C to exit simulation loop.") + try: + counter = 0 + while True: + counter += 1 + sim.update(step=10) + if counter % 10 == 0: + pass + + except KeyboardInterrupt: + logger.log_info("\n Exit") + + +if __name__ == "__main__": + main() diff --git a/examples/sim/demo/press_softbody.py b/examples/sim/demo/press_softbody.py new file mode 100644 index 00000000..2d353aad --- /dev/null +++ b/examples/sim/demo/press_softbody.py @@ -0,0 +1,261 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +""" +This script demonstrates the creation and simulation of a robot with dexterous hands, +and performs a scoop ice task in a simulated environment. +""" + +import argparse +import numpy as np +import time +import torch +from tqdm import tqdm +from scipy.spatial.transform import Rotation as R + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.objects import Robot, RigidObject, RigidObjectGroup +from embodichain.lab.sim.cfg import ( + JointDrivePropertiesCfg, + RobotCfg, + URDFCfg, + RigidObjectCfg, + RigidBodyAttributesCfg, + ArticulationCfg, + RigidObjectGroupCfg, + LightCfg, +) +from embodichain.lab.sim.material import VisualMaterialCfg +from embodichain.lab.sim.utility.action_utils import interpolate_with_distance_warp +from embodichain.lab.sim.shapes import MeshCfg, CubeCfg +from embodichain.lab.sim.solvers import PytorchSolverCfg +from embodichain.data import get_data_path +from embodichain.utils import logger +from dexsim.utility.path import get_resources_data_path +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import ( + RigidBodyAttributesCfg, + SoftbodyVoxelAttributesCfg, + SoftbodyPhysicalAttributesCfg, +) +from embodichain.lab.sim.shapes import CubeCfg, MeshCfg +from embodichain.lab.sim.objects import ( + RigidObject, + RigidObjectCfg, + SoftObject, + SoftObjectCfg, +) + + +def parse_arguments(): + """ + Parse command-line arguments to configure the simulation. + + Returns: + argparse.Namespace: Parsed arguments including number of environments, device, and rendering options. + """ + parser = argparse.ArgumentParser( + description="Create and simulate a robot in SimulationManager" + ) + parser.add_argument( + "--enable_rt", action="store_true", help="Enable ray tracing rendering" + ) + return parser.parse_args() + + +def initialize_simulation(args): + """ + Initialize the simulation environment based on the provided arguments. + + Args: + args (argparse.Namespace): Parsed command-line arguments. + + Returns: + SimulationManager: Configured simulation manager instance. + """ + config = SimulationManagerCfg( + headless=True, + sim_device="cuda", + enable_rt=args.enable_rt, + physics_dt=1.0 / 100.0, + ) + sim = SimulationManager(config) + + light = sim.add_light( + cfg=LightCfg(uid="main_light", intensity=50.0, init_pos=(0, 0, 2.0)) + ) + + # Set manual physics update for precise control + sim.set_manual_update(True) + return sim + + +def create_robot(sim: SimulationManager): + """ + Create and configure a robot with an arm and a dexterous hand in the simulation. + + Args: + sim (SimulationManager): The simulation manager instance. + + Returns: + Robot: The configured robot instance added to the simulation. + """ + # Retrieve URDF paths for the robot arm and hand + ur10_urdf_path = get_data_path("UniversalRobots/UR10/UR10.urdf") + hand_urdf_path = get_data_path( + "BrainCoHandRevo1/BrainCoLeftHand/BrainCoLeftHand.urdf" + ) + + # Define transformation for attaching the hand to the arm + hand_attach_xpos = np.eye(4) + hand_attach_xpos[:3, :3] = R.from_rotvec([90, 0, 0], degrees=True).as_matrix() + + # Configure the robot with its components and control properties + cfg = RobotCfg( + uid="ur10_with_brainco", + urdf_cfg=URDFCfg( + components=[ + {"component_type": "arm", "urdf_path": ur10_urdf_path}, + ] + ), + control_parts={ + "arm": ["Joint[0-9]"], + }, + drive_pros=JointDrivePropertiesCfg( + stiffness={ + "Joint[0-9]": 1e4, + }, + damping={ + "Joint[0-9]": 1e3, + }, + max_effort={ + "Joint[0-9]": 1e5, + }, + drive_type="force", + ), + solver_cfg={ + "arm": PytorchSolverCfg( + end_link_name="ee_link", + root_link_name="base_link", + tcp=np.eye(4), + ) + }, + init_qpos=[ + 0.0, + -np.pi / 2, + -np.pi / 2, + np.pi / 2, + -np.pi / 2, + 0.0, + ], + ) + return sim.add_robot(cfg=cfg) + + +def create_soft_cow(sim: SimulationManager) -> SoftObject: + """create soft cow object in the simulation + + Args: + sim (SimulationManager): The simulation manager instance. + + Returns: + SoftObject: soft cow object + """ + cow: SoftObject = sim.add_soft_object( + cfg=SoftObjectCfg( + uid="cow", + shape=MeshCfg( + fpath=get_resources_data_path("Model", "cow", "cow2.obj"), + ), + init_pos=[0.5, 0.0, 0.3], + voxel_attr=SoftbodyVoxelAttributesCfg( + simulation_mesh_resolution=8, + maximal_edge_length=0.5, + ), + physical_attr=SoftbodyPhysicalAttributesCfg( + youngs=1e4, + poissons=0.45, + density=100, + dynamic_friction=0.1, + min_position_iters=30, + ), + ), + ) + return cow + + +def press_cow(sim: SimulationManager, robot: Robot): + """robot press cow softbody with its end link + + Args: + sim (SimulationManager): The simulation manager instance. + robot (Robot): The robot instance to be controlled. + """ + start_qpos = robot.get_qpos() + arm_ids = robot.get_joint_ids("arm") + arm_start_qpos = start_qpos[:, arm_ids] + + arm_start_xpos = robot.compute_fk(arm_start_qpos, name="arm", to_matrix=True) + press_xpos = arm_start_xpos.clone() + press_xpos[:, :3, 3] = torch.tensor([0.5, -0.1, 0.01], device=press_xpos.device) + + approach_xpos = press_xpos.clone() + approach_xpos[:, 2, 3] += 0.05 + + is_success, approach_qpos = robot.compute_ik( + approach_xpos, joint_seed=arm_start_qpos, name="arm" + ) + is_success, press_qpos = robot.compute_ik( + approach_xpos, joint_seed=arm_start_qpos, name="arm" + ) + + arm_trajectory = torch.concatenate([arm_start_qpos, approach_qpos, press_qpos]) + interp_trajectory = interpolate_with_distance_warp( + trajectory=arm_trajectory[None, :, :], interp_num=50, device=sim.device + ) + interp_trajectory = interp_trajectory[0] + for qpos in interp_trajectory: + robot.set_qpos(qpos.unsqueeze(0), joint_ids=arm_ids) + sim.update(step=5) + + +def main(): + """ + Main function to demonstrate robot simulation. + + This function initializes the simulation, creates the robot and other objects, + and performs the press softbody task. + """ + args = parse_arguments() + sim = initialize_simulation(args) + + robot = create_robot(sim) + soft_cow = create_soft_cow(sim) + sim.init_gpu_physics() + sim.open_window() + + press_cow(sim, robot) + + logger.log_info("\n Press Ctrl+C to exit simulation loop.") + try: + while True: + sim.update(step=10) + except KeyboardInterrupt: + logger.log_info("\n Exit") + + +if __name__ == "__main__": + main() diff --git a/examples/sim/demo/scoop_ice.py b/examples/sim/demo/scoop_ice.py new file mode 100644 index 00000000..941f6d6d --- /dev/null +++ b/examples/sim/demo/scoop_ice.py @@ -0,0 +1,569 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +""" +This script demonstrates the creation and simulation of a robot with dexterous hands, +and performs a scoop ice task in a simulated environment. +""" + +import argparse +import numpy as np +import time +import torch +from tqdm import tqdm +from scipy.spatial.transform import Rotation as R + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.objects import Robot, RigidObject, RigidObjectGroup +from embodichain.lab.sim.cfg import ( + JointDrivePropertiesCfg, + RobotCfg, + URDFCfg, + RigidObjectCfg, + RigidBodyAttributesCfg, + ArticulationCfg, + RigidObjectGroupCfg, + LightCfg, +) +from embodichain.lab.sim.material import VisualMaterialCfg +from embodichain.lab.sim.utility.action_utils import interpolate_with_distance_warp +from embodichain.lab.sim.shapes import MeshCfg, CubeCfg +from embodichain.lab.sim.solvers import PytorchSolverCfg +from embodichain.data import get_data_path +from embodichain.utils import logger + + +def initialize_simulation(): + """ + Initialize the simulation environment based on the provided arguments. + + Args: + args (argparse.Namespace): Parsed command-line arguments. + + Returns: + SimulationManager: Configured simulation manager instance. + """ + config = SimulationManagerCfg( + headless=True, + sim_device="cpu", + enable_rt=True, + physics_dt=1.0 / 100.0, + ) + sim = SimulationManager(config) + + light = sim.add_light( + cfg=LightCfg(uid="main_light", intensity=50.0, init_pos=(0, 0, 2.0)) + ) + + # Set manual physics update for precise control + sim.set_manual_update(True) + return sim + + +def randomize_ice_positions(sim, ice_cubes): + """ + Randomly drop ice cubes into the container within a specified range. + + Args: + sim (SimulationManager): The simulation manager instance. + ice_cubes (RigidObjectGroup): Group of ice cube objects to be randomized. + """ + num_objs = ice_cubes.num_objects + position_low = np.array([0.65, -0.45, 0.5]) + position_high = np.array([0.55, -0.35, 0.5]) + position_random = np.random.uniform( + low=position_low, high=position_high, size=(num_objs, 3) + ) + random_drop_pose_np = np.eye(4)[None, :, :].repeat(num_objs, axis=0) + random_drop_pose_np[:, :3, 3] = position_random + + # Assign random positions to each ice cube + for i in tqdm(range(num_objs), desc="Dropping ice cubes"): + ice_cubes.set_local_pose( + pose=torch.tensor( + random_drop_pose_np[i][None, None, :, :], + dtype=torch.float32, + device=sim.device, + ), + obj_ids=[i], + ) + sim.update(step=10) + + +def create_robot(sim): + """ + Create and configure a robot with an arm and a dexterous hand in the simulation. + + Args: + sim (SimulationManager): The simulation manager instance. + + Returns: + Robot: The configured robot instance added to the simulation. + """ + # Retrieve URDF paths for the robot arm and hand + ur10_urdf_path = get_data_path("UniversalRobots/UR10/UR10.urdf") + hand_urdf_path = get_data_path( + "BrainCoHandRevo1/BrainCoLeftHand/BrainCoLeftHand.urdf" + ) + + # Define transformation for attaching the hand to the arm + hand_attach_xpos = np.eye(4) + hand_attach_xpos[:3, :3] = R.from_rotvec([90, 0, 0], degrees=True).as_matrix() + + # Configure the robot with its components and control properties + cfg = RobotCfg( + uid="ur10_with_brainco", + urdf_cfg=URDFCfg( + components=[ + {"component_type": "arm", "urdf_path": ur10_urdf_path}, + { + "component_type": "hand", + "urdf_path": hand_urdf_path, + "transform": hand_attach_xpos, + }, + ] + ), + control_parts={ + "arm": ["JOINT[0-9]"], + "hand": [ + "LEFT_HAND_THUMB1", + "LEFT_HAND_THUMB2", + "LEFT_HAND_INDEX", + "LEFT_HAND_MIDDLE", + "LEFT_HAND_RING", + "LEFT_HAND_PINKY", + ], + }, + drive_pros=JointDrivePropertiesCfg( + stiffness={"JOINT[0-9]": 1e4, "LEFT_[A-Z|_]+[0-9]?": 1e2}, + damping={"JOINT[0-9]": 1e3, "LEFT_[A-Z|_]+[0-9]?": 1e1}, + max_effort={"JOINT[0-9]": 1e5, "LEFT_[A-Z|_]+[0-9]?": 1e3}, + drive_type="force", + ), + solver_cfg={ + "arm": PytorchSolverCfg( + end_link_name="ee_link", + root_link_name="base_link", + tcp=np.eye(4), + ) + }, + init_qpos=[ + 0.0, + -np.pi / 2, + -np.pi / 2, + 2.5, + -np.pi / 2, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.5, + -0.00016, + -0.00010, + -0.00013, + -0.00009, + 0.0, + ], + ) + + return sim.add_robot(cfg=cfg) + + +def create_scoop(sim: SimulationManager): + """Create a scoop rigid object in the simulation.""" + scoop_cfg = RigidObjectCfg( + uid="scoop", + shape=MeshCfg( + fpath=get_data_path("ScoopIceNewEnv/scoop.ply"), + ), + attrs=RigidBodyAttributesCfg( + mass=0.5, + static_friction=0.95, + dynamic_friction=0.9, + restitution=0.01, + min_position_iters=32, + min_velocity_iters=8, + ), + max_convex_hull_num=12, + body_type="dynamic", + init_pos=[0.6, 0.0, 0.09], + init_rot=[0.0, 0.0, 0.0], + ) + scoop = sim.add_rigid_object(cfg=scoop_cfg) + return scoop + + +def create_heave_ice(sim: SimulationManager): + """Create a heave ice rigid object in the simulation. Make sure that""" + heave_ice_cfg = RigidObjectCfg( + uid="heave_ice", + shape=MeshCfg( + fpath=get_data_path("ScoopIceNewEnv/ice_mesh_small/ice_000.obj"), + ), + attrs=RigidBodyAttributesCfg( + mass=0.5, + static_friction=0.95, + dynamic_friction=0.9, + restitution=0.01, + min_position_iters=32, + min_velocity_iters=8, + ), + body_type="dynamic", + init_pos=[10, 10, 0.08], + init_rot=[0.0, 0.0, 0.0], + ) + heave_ice = sim.add_rigid_object(cfg=heave_ice_cfg) + return heave_ice + + +def create_padding_box(sim: SimulationManager): + padding_box_cfg = RigidObjectCfg( + uid="padding_box", + shape=CubeCfg( + size=[0.1, 0.16, 0.05], + ), + attrs=RigidBodyAttributesCfg( + mass=1.0, + static_friction=0.95, + dynamic_friction=0.9, + restitution=0.01, + min_position_iters=32, + min_velocity_iters=8, + ), + body_type="kinematic", + init_pos=[0.6, 0.15, 0.025], + init_rot=[0.0, 0.0, 0.0], + ) + heave_ice = sim.add_rigid_object(cfg=padding_box_cfg) + return heave_ice + + +def create_container(sim: SimulationManager): + container_cfg = ArticulationCfg( + uid="container", + fpath=get_data_path("ScoopIceNewEnv/IceContainer/ice_container.urdf"), + init_pos=[0.7, -0.4, 0.21], + init_rot=[0, 0, -90], + attrs=RigidBodyAttributesCfg( + mass=1.0, + static_friction=0.95, + dynamic_friction=0.9, + restitution=0.01, + min_position_iters=32, + min_velocity_iters=8, + ), + drive_pros=JointDrivePropertiesCfg( + stiffness=1.0, damping=0.1, max_effort=100.0, drive_type="force" + ), + ) + container = sim.add_articulation(cfg=container_cfg) + return container + + +def create_ice_cubes(sim: SimulationManager): + ice_cubes_path = get_data_path("ScoopIceNewEnv/ice_mesh_small") + cfg_dict = { + "uid": "ice_cubes", + "max_num": 300, + "folder_path": ice_cubes_path, + "ext": ".obj", + "rigid_objects": { + "obj": { + "attrs": { + "mass": 0.003, + "contact_offset": 0.001, + "rest_offset": 0, + "dynamic_friction": 0.05, + "static_friction": 0.1, + "restitution": 0.01, + "min_position_iters": 32, + "min_velocity_iters": 4, + "max_depenetration_velocity": 1.0, + }, + "shape": {"shape_type": "Mesh"}, + "init_pos": [20.0, 0, 1.0], + } + }, + } + + ice_cubes_cfg = RigidObjectGroupCfg.from_dict(cfg_dict) + ice_cubes: RigidObjectGroup = sim.add_rigid_object_group(cfg=ice_cubes_cfg) + + # Set visual material for ice cubes. + # The material below only works for ray tracing backend. + # Set ior to 1.31 and material type to "BSDF_GGX_SMITH" for better ice appearance. + ice_mat = sim.create_visual_material( + cfg=VisualMaterialCfg( + base_color=[1.0, 1.0, 1.0, 1.0], + ior=1.31, + roughness=0.05, + rt_material_type="BSDF_GGX_SMITH", + ) + ) + ice_cubes.set_visual_material(mat=ice_mat) + + return ice_cubes + + +def scoop_grasp( + sim: SimulationManager, + robot: Robot, + scoop: RigidObject, + heave_ice: RigidObject, + padding_box: RigidObject, +): + """ + Control the robot to grasp the scoop object and position the heave ice for scooping. + + Args: + sim (SimulationManager): The simulation manager instance. + robot (Robot): The robot instance to be controlled. + scoop (RigidObject): The scoop object to be grasped. + heave_ice (RigidObject): The heave ice object to be positioned. + padding_box (RigidObject): The padding box object used as a reference for positioning. + """ + rest_qpos = robot.get_qpos() + arm_ids = robot.get_joint_ids("arm") + hand_ids = robot.get_joint_ids("hand") + hand_open_qpos = torch.tensor([0.0, 1.5, 0.4, 0.4, 0.4, 0.4]) + hand_close_qpos = torch.tensor([0.4, 1.5, 1.0, 1.1, 1.1, 0.9]) + arm_rest_qpos = rest_qpos[:, arm_ids] + + # Calculate and set the drop pose for the scoop object + padding_box_pose = padding_box.get_local_pose(to_matrix=True) + scoop_drop_relative_pose = torch.tensor( + [ + [1.0, 0.0, 0.0, 0.0], + [0.0, 1.0, 0.0, 0.115], + [0.0, 0.0, 1.0, 0.065], + [0.0, 0.0, 0.0, 1.0], + ], + dtype=torch.float32, + device=sim.device, + ) + scoop_drop_pose = torch.bmm( + padding_box_pose, + scoop_drop_relative_pose[None, :, :].repeat(sim.num_envs, 1, 1), + ) + scoop.set_local_pose(scoop_drop_pose) + + scoop_pose = scoop.get_local_pose(to_matrix=True) + + # tricky implementation + heave_ice_relative = torch.tensor( + [ + [1.0, 0.0, 0.0, 0.0], + [0.0, 1.0, 0.0, -0.13], + [0.0, 0.0, 1.0, 0.04], + [0.0, 0.0, 0.0, 1.0], + ], + dtype=torch.float32, + device=sim.device, + )[None, :, :].repeat(sim.num_envs, 1, 1) + heave_ice_pose = torch.bmm(scoop_pose, heave_ice_relative) + heave_ice.set_local_pose(heave_ice_pose) + sim.update(step=200) + + # move hand to grasp scoop + scoop_pose = scoop.get_local_pose(to_matrix=True) + grasp_scoop_pose_relative = torch.tensor( + [ + [0.00522967, 0.6788424, 0.7342653, -0.05885637], + [0.99054945, 0.0971214, -0.09684561, 0.0301468], + [-0.13705578, 0.72783256, -0.6719191, 0.1040391], + [0.0, 0.0, 0.0, 1.0], + ], + dtype=torch.float32, + device=sim.device, + )[None, :, :].repeat(sim.num_envs, 1, 1) + + grasp_scoop_pose = torch.bmm(scoop_pose, grasp_scoop_pose_relative) + pregrasp_scoop_pose = grasp_scoop_pose.clone() + pregrasp_scoop_pose[:, 2, 3] += 0.1 + is_success, pre_grasp_scoop_qpos = robot.compute_ik( + pregrasp_scoop_pose, joint_seed=arm_rest_qpos, name="arm" + ) + + is_success, grasp_scoop_qpos = robot.compute_ik( + grasp_scoop_pose, joint_seed=arm_rest_qpos, name="arm" + ) + robot.set_qpos(pre_grasp_scoop_qpos, joint_ids=arm_ids) + sim.update(step=100) + robot.set_qpos(grasp_scoop_qpos, joint_ids=arm_ids) + sim.update(step=100) + + # close hand + robot.set_qpos(hand_close_qpos[None, :].repeat(sim.num_envs, 1), joint_ids=hand_ids) + sim.update(step=100) + + # remove heave ice + remove_heave_ice_pose = torch.tensor( + [ + [1.0, 0.0, 0.0, 10.0], + [0.0, 1.0, 0.0, 10.0], + [0.0, 0.0, 1.0, 0.04], + [0.0, 0.0, 0.0, 1.0], + ], + dtype=torch.float32, + device=sim.device, + ) + heave_ice.set_local_pose(remove_heave_ice_pose[None, :, :]) + + +def scoop_ice(sim: SimulationManager, robot: Robot, scoop: RigidObject): + """ + Control the robot to perform the scoop ice task, including lifting, scooping, + and placing the ice. + + Args: + sim (SimulationManager): The simulation manager instance. + robot (Robot): The robot instance to be controlled. + scoop (RigidObject): The scoop object used for scooping ice. + """ + start_qpos = robot.get_qpos() + arm_ids = robot.get_joint_ids("arm") + hand_ids = robot.get_joint_ids("hand") + hand_open_qpos = torch.tensor([0.0, 1.5, 0.4, 0.4, 0.4, 0.4]) + hand_close_qpos = torch.tensor([0.4, 1.5, 1.0, 1.1, 1.1, 0.9]) + arm_start_qpos = start_qpos[:, arm_ids] + + # lift + arm_start_xpos = robot.compute_fk(arm_start_qpos, name="arm", to_matrix=True) + arm_lift_xpos = arm_start_xpos.clone() + arm_lift_xpos[:, 2, 3] += 0.45 + is_success, arm_lift_qpos = robot.compute_ik( + arm_lift_xpos, joint_seed=arm_start_qpos, name="arm" + ) + + # apply 45 degree wrist rotation + wrist_rotation = R.from_euler("X", 45, degrees=True).as_matrix() + arm_lift_rotation = arm_lift_xpos[0, :3, :3].to("cpu").numpy() + new_rotation = wrist_rotation @ arm_lift_rotation + arm_lift_xpos_rotated = arm_lift_xpos.clone() + arm_lift_xpos_rotated[:, :3, :3] = torch.tensor( + new_rotation, dtype=torch.float32, device=sim.device + ) + arm_lift_xpos_rotated[:, :3, 3] = torch.tensor( + [0.5, -0.2, 0.55], dtype=torch.float32, device=sim.device + ) + is_success, arm_lift_qpos_rotated = robot.compute_ik( + arm_lift_xpos_rotated, joint_seed=arm_lift_qpos, name="arm" + ) + + # into container + scoop_dis = 0.252 + scoop_offset = scoop_dis * torch.tensor( + [0.0, -0.58123819, -0.81373347], dtype=torch.float32, device=sim.device + ) + arm_into_container_xpos = arm_lift_xpos_rotated.clone() + arm_into_container_xpos[:, :3, 3] = arm_into_container_xpos[:, :3, 3] + scoop_offset + is_success, arm_into_container_qpos = robot.compute_ik( + arm_into_container_xpos, joint_seed=arm_lift_qpos_rotated, name="arm" + ) + + # apply -60 degree wrist rotation + arm_into_container_rotation = arm_into_container_xpos[0, :3, :3].to("cpu").numpy() + wrist_rotation = R.from_euler("X", -60, degrees=True).as_matrix() + new_rotation = wrist_rotation @ arm_into_container_rotation + arm_scoop_xpos = arm_into_container_xpos.clone() + arm_scoop_xpos[:, :3, :3] = torch.tensor( + new_rotation, dtype=torch.float32, device=sim.device + ) + is_success, arm_scoop_qpos = robot.compute_ik( + arm_scoop_xpos, joint_seed=arm_into_container_qpos, name="arm" + ) + + # minor lift + arm_scoop_xpos[:, 2, 3] += 0.15 + is_success, arm_scoop_lift_qpos = robot.compute_ik( + arm_scoop_xpos, joint_seed=arm_scoop_qpos, name="arm" + ) + + # pack arm and hand trajectory + arm_trajectory = torch.concatenate( + [ + arm_start_qpos, + arm_lift_qpos, + arm_lift_qpos_rotated, + arm_into_container_qpos, + arm_scoop_qpos, + arm_scoop_lift_qpos, + ] + ) + + hand_trajectory = torch.vstack( + [ + hand_close_qpos, + hand_close_qpos, + hand_close_qpos, + hand_close_qpos, + hand_close_qpos, + hand_close_qpos, + ] + ) + + all_trajectory = torch.hstack([arm_trajectory, hand_trajectory]) + interp_trajectory = interpolate_with_distance_warp( + trajectory=all_trajectory[None, :, :], interp_num=200, device=sim.device + ) + interp_trajectory = interp_trajectory[0] + # run trajectory + arm_ids = robot.get_joint_ids("arm") + hand_ids = robot.get_joint_ids("hand") + combine_ids = np.concatenate([arm_ids, hand_ids]) + for qpos in interp_trajectory: + robot.set_qpos(qpos.unsqueeze(0), joint_ids=combine_ids) + sim.update(step=10) + + +def main(): + """ + Main function to demonstrate robot simulation. + + This function initializes the simulation, creates the robot and other objects, + and performs the scoop ice task. + """ + sim = initialize_simulation() + + # Create simulation objects + robot = create_robot(sim) + container = create_container(sim) + padding_box = create_padding_box(sim) + scoop = create_scoop(sim) + heave_ice = create_heave_ice(sim) + ice_cubes = create_ice_cubes(sim) + + sim.open_window() + + # Randomize ice positions + randomize_ice_positions(sim, ice_cubes) + + # Perform tasks + scoop_grasp(sim, robot, scoop, heave_ice, padding_box) + scoop_ice(sim, robot, scoop) + + logger.log_info("\n Press Ctrl+C to exit simulation loop.") + try: + while True: + # sim.update(step=10) + time.sleep(1e-2) + except KeyboardInterrupt: + logger.log_info("\n Exit") + + +if __name__ == "__main__": + main() diff --git a/examples/sim/gizmo/gizmo_camera.py b/examples/sim/gizmo/gizmo_camera.py new file mode 100644 index 00000000..2b782a08 --- /dev/null +++ b/examples/sim/gizmo/gizmo_camera.py @@ -0,0 +1,236 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +""" +This script demonstrates how to use the Gizmo class for interactive camera control. +It shows how to create a gizmo attached to a camera for real-time pose manipulation. +""" + +import argparse +import cv2 +import numpy as np +import time +import torch + +torch.set_printoptions(precision=4, sci_mode=False) + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.sensors import Camera, CameraCfg +from embodichain.lab.sim.cfg import RigidObjectCfg, RigidBodyAttributesCfg +from embodichain.lab.sim.shapes import CubeCfg +from embodichain.utils import logger + + +def main(): + """Main function to demonstrate camera gizmo manipulation.""" + + # Parse command line arguments + parser = argparse.ArgumentParser( + description="Create and simulate a camera with gizmo in SimulationManager" + ) + parser.add_argument( + "--num_envs", type=int, default=1, help="Number of environments to simulate" + ) + parser.add_argument( + "--device", + type=str, + default="cpu", + choices=["cpu", "cuda"], + help="Device to run simulation on", + ) + parser.add_argument("--headless", action="store_true", help="Run in headless mode") + parser.add_argument( + "--enable_rt", + action="store_true", + default=False, + help="Enable ray tracing for better visuals", + ) + args = parser.parse_args() + + # Configure the simulation + sim_cfg = SimulationManagerCfg( + width=1920, + height=1080, + physics_dt=1.0 / 100.0, + sim_device=args.device, + enable_rt=args.enable_rt, + ) + + # Create simulation context + sim = SimulationManager(sim_cfg) + sim.set_manual_update(False) + + # Build multiple arenas if requested + if args.num_envs > 1: + sim.build_multiple_arenas(args.num_envs, space=3.0) + + # Add some objects to the scene for camera to observe + for i in range(5): + cube_cfg = RigidObjectCfg( + uid=f"cube_{i}", + shape=CubeCfg(size=[0.1, 0.1, 0.1]), + body_type="dynamic", + attrs=RigidBodyAttributesCfg( + mass=1.0, + dynamic_friction=0.5, + static_friction=0.5, + restitution=0.3, + ), + init_pos=[0.5 + i * 0.3, 0.0, 0.5], + ) + sim.add_rigid_object(cfg=cube_cfg) + + # Create camera configuration + camera_cfg = CameraCfg( + uid="gizmo_camera", + width=640, + height=480, + intrinsics=(320, 320, 320, 240), # fx, fy, cx, cy + near=0.1, + far=10.0, + enable_color=True, + enable_depth=True, + extrinsics=CameraCfg.ExtrinsicsCfg( + eye=(2.0, 2.0, 2.0), + target=(0.0, 0.0, 0.0), + up=(0.0, 0.0, 1.0), + ), + ) + + # Add camera to simulation + camera = sim.add_sensor(sensor_cfg=camera_cfg) + + # Wait for initialization + time.sleep(0.2) + + # Enable gizmo for interactive camera control using the new unified API + sim.enable_gizmo(uid="gizmo_camera") + if not sim.has_gizmo("gizmo_camera"): + logger.log_error("Failed to enable gizmo for camera!") + return + + # Open simulation window (if not headless) + if not args.headless: + sim.open_window() + + logger.log_info("Gizmo-Camera tutorial started!") + logger.log_info( + "Use the gizmo to interactively control the camera position and orientation" + ) + logger.log_info( + "The camera will follow the gizmo pose for dynamic viewpoint control" + ) + logger.log_info("Press Ctrl+C to stop the simulation") + + # Run simulation loop + run_simulation(sim, camera) + + +def run_simulation(sim, camera): + """Run the simulation loop with gizmo updates.""" + step_count = 0 + last_time = time.time() + last_step = 0 + + logger.log_info("Camera view window will open. Press Ctrl+C or 'q' to exit") + logger.log_info( + "Use the gizmo in the 3D view to control camera position and orientation" + ) + + try: + while True: + # Update all gizmos managed by sim (including camera gizmo) + sim.update_gizmos() + + # Update camera to get latest sensor data + camera.update() + + # Refresh camera data if method available + if hasattr(camera, "refresh"): + camera.refresh() + + step_count += 1 + + # Display camera view in separate window + if step_count % 5 == 0: # Update display every 5 steps for performance + data = camera.get_data() + if "color" in data: + # Get RGB image and convert for OpenCV display + rgb_image = data["color"].cpu().numpy()[0, :, :, :3] # (H, W, 3) + # Convert RGB to BGR for OpenCV + bgr_image = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2BGR) + + # Add text overlay + cv2.putText( + bgr_image, + "Press 'h' to toggle camera gizmo visibility", + (10, 30), + cv2.FONT_HERSHEY_SIMPLEX, + 0.6, + (0, 255, 0), + 2, + ) + + # Display the image + cv2.imshow("Gizmo Camera View", bgr_image) + + # Check for key press + key = cv2.waitKey(1) & 0xFF + if key == ord("h"): + # Toggle the camera gizmo visibility using SimulationManager API + sim.toggle_gizmo_visibility("gizmo_camera") + + # Example: Destroy gizmo after certain steps to test cleanup + if step_count == 30000 and sim.has_gizmo("gizmo_camera"): + logger.log_info("Disabling gizmo at step 30000 (demonstration)") + sim.disable_gizmo("gizmo_camera") + + # Print simulation statistics and camera info + if step_count % 1000 == 0: + current_time = time.time() + elapsed = current_time - last_time + fps = ( + sim.num_envs * (step_count - last_step) / elapsed + if elapsed > 0 + else 0 + ) + + # Get camera pose for debugging + if sim.has_gizmo("gizmo_camera"): + camera_pose = camera.get_local_pose(to_matrix=True)[0] + camera_pos = camera_pose[:3, 3] + logger.log_info( + f"Step: {step_count}, FPS: {fps:.2f}, Camera pos: [{camera_pos[0]:.2f}, {camera_pos[1]:.2f}, {camera_pos[2]:.2f}]" + ) + else: + logger.log_info(f"Step: {step_count}, FPS: {fps:.2f}") + + last_time = current_time + last_step = step_count + + except KeyboardInterrupt: + logger.log_info("\nStopping simulation...") + finally: + # Clean up resources + cv2.destroyAllWindows() + # Disable gizmo if it exists + if sim.has_gizmo("gizmo_camera"): + sim.disable_gizmo("gizmo_camera") + sim.destroy() + logger.log_info("Simulation terminated successfully") + + +if __name__ == "__main__": + main() diff --git a/examples/sim/gizmo/gizmo_object.py b/examples/sim/gizmo/gizmo_object.py new file mode 100644 index 00000000..31967277 --- /dev/null +++ b/examples/sim/gizmo/gizmo_object.py @@ -0,0 +1,175 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +""" +This script demonstrates how to create a simulation scene using SimulationManager. +It shows the basic setup of simulation context, adding objects, and sensors. +""" + +import argparse +import time + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import RigidBodyAttributesCfg +from embodichain.lab.sim.shapes import CubeCfg + +from embodichain.lab.sim.objects import RigidObject, RigidObjectCfg +from embodichain.utils import logger + + +def main(): + """Main function to create and run the simulation scene.""" + + # Parse command line arguments + parser = argparse.ArgumentParser( + description="Create a simulation scene with SimulationManager" + ) + parser.add_argument( + "--headless", + action="store_true", + default=False, + help="Run simulation in headless mode", + ) + parser.add_argument( + "--num_envs", type=int, default=1, help="Number of parallel environments" + ) + parser.add_argument( + "--device", type=str, default="cpu", help="Simulation device (cuda or cpu)" + ) + parser.add_argument( + "--enable_rt", + action="store_true", + default=False, + help="Enable ray tracing for better visuals", + ) + args = parser.parse_args() + + # Configure the simulation + sim_cfg = SimulationManagerCfg( + width=1920, + height=1080, + headless=args.headless, + physics_dt=1.0 / 100.0, # Physics timestep (100 Hz) + sim_device=args.device, + enable_rt=args.enable_rt, # Enable ray tracing for better visuals + ) + + # Create the simulation instance + sim = SimulationManager(sim_cfg) + + # Enable manual physics update for precise control + sim.set_manual_update(True) + + # Build multiple arenas if requested + if args.num_envs > 1: + sim.build_multiple_arenas(args.num_envs, space=3.0) + + # Add two cubes to the scene + cube1: RigidObject = sim.add_rigid_object( + cfg=RigidObjectCfg( + uid="cube1", + shape=CubeCfg(size=[0.1, 0.1, 0.1]), + body_type="kinematic", + attrs=RigidBodyAttributesCfg( + mass=1.0, + dynamic_friction=0.5, + static_friction=0.5, + restitution=0.1, + ), + init_pos=[0.0, 0.0, 1.0], + ) + ) + cube2: RigidObject = sim.add_rigid_object( + cfg=RigidObjectCfg( + uid="cube2", + shape=CubeCfg(size=[0.1, 0.1, 0.1]), + body_type="kinematic", + attrs=RigidBodyAttributesCfg( + mass=1.0, + dynamic_friction=0.5, + static_friction=0.5, + restitution=0.1, + ), + init_pos=[0.3, 0.0, 1.0], + ) + ) + + # Enable Gizmo for both cubes using the new API (only in window mode) + if not args.headless: + sim.enable_gizmo(uid="cube1") + sim.enable_gizmo(uid="cube2") + + logger.log_info("Scene setup complete!") + logger.log_info(f"Running simulation with {args.num_envs} environment(s)") + if not args.headless: + if sim.has_gizmo("cube1"): + logger.log_info("Gizmo enabled for cube1 - you can drag it around!") + if sim.has_gizmo("cube2"): + logger.log_info("Gizmo enabled for cube2 - you can drag it around!") + logger.log_info("Press Ctrl+C to stop the simulation") + + # Open window when the scene has been set up + if not args.headless: + sim.open_window() + + # Run the simulation + run_simulation(sim) + + +def run_simulation(sim: SimulationManager): + """Run the simulation loop.""" + if sim.is_use_gpu_physics: + sim.init_gpu_physics() + + step_count = 0 + try: + last_time = time.time() + last_step = 0 + while True: + sim.update(step=1) + + # Update all gizmos if any are enabled + sim.update_gizmos() + + step_count += 1 + + # Disable gizmo after 200000 steps (example) + if step_count == 200000 and gizmo_enabled: + logger.log_info("Disabling gizmo at step 200000") + sim.disable_gizmo("cube") + gizmo_enabled = False + + # Print FPS every second + if step_count % 1000 == 0: + current_time = time.time() + elapsed = current_time - last_time + fps = ( + sim.num_envs * (step_count - last_step) / elapsed + if elapsed > 0 + else 0 + ) + logger.log_info(f"Simulation step: {step_count}, FPS: {fps:.2f}") + last_time = current_time + last_step = step_count + except KeyboardInterrupt: + logger.log_info("\nStopping simulation...") + finally: + sim.destroy() + logger.log_info("Simulation terminated successfully") + + +if __name__ == "__main__": + main() diff --git a/examples/sim/gizmo/gizmo_robot.py b/examples/sim/gizmo/gizmo_robot.py new file mode 100644 index 00000000..fae79962 --- /dev/null +++ b/examples/sim/gizmo/gizmo_robot.py @@ -0,0 +1,158 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +""" +Gizmo-Robot Example: Test Gizmo class on a robot (UR10) +""" + +import time +import torch +import numpy as np +import argparse + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import ( + RobotCfg, + URDFCfg, + JointDrivePropertiesCfg, +) + +from embodichain.lab.sim.solvers import PinkSolverCfg +from embodichain.data import get_data_path +from embodichain.utils import logger + + +def main(): + """Main function to create and run the simulation scene.""" + + # Parse command line arguments + parser = argparse.ArgumentParser( + description="Create a simulation scene with SimulationManager" + ) + parser.add_argument( + "--num_envs", type=int, default=1, help="Number of parallel environments" + ) + parser.add_argument( + "--device", type=str, default="cpu", help="Simulation device (cuda or cpu)" + ) + parser.add_argument( + "--enable_rt", + action="store_true", + default=False, + help="Enable ray tracing for better visuals", + ) + args = parser.parse_args() + + # Configure the simulation + sim_cfg = SimulationManagerCfg( + width=1920, + height=1080, + physics_dt=1.0 / 100.0, + sim_device=args.device, + enable_rt=args.enable_rt, + ) + + sim = SimulationManager(sim_cfg) + sim.set_manual_update(False) + + # Build multiple arenas if requested + if args.num_envs > 1: + sim.build_multiple_arenas(args.num_envs, space=3.0) + + # Get UR10 URDF path + urdf_path = get_data_path("UniversalRobots/UR10/UR10.urdf") + + # Create UR10 robot + robot_cfg = RobotCfg( + uid="ur10_gizmo_test", + urdf_cfg=URDFCfg( + components=[{"component_type": "arm", "urdf_path": urdf_path}] + ), + control_parts={"arm": ["Joint[1-6]"]}, + solver_cfg={ + "arm": PinkSolverCfg( + urdf_path=urdf_path, + end_link_name="ee_link", + root_link_name="base_link", + pos_eps=1e-2, + rot_eps=5e-2, + max_iterations=300, + dt=0.1, + ) + }, + drive_pros=JointDrivePropertiesCfg( + stiffness={"Joint[1-6]": 1e4}, + damping={"Joint[1-6]": 1e3}, + ), + ) + robot = sim.add_robot(cfg=robot_cfg) + + # Set initial joint positions + initial_qpos = torch.tensor( + [[0, -np.pi / 2, np.pi / 2, 0.0, np.pi / 2, 0.0]], + dtype=torch.float32, + device="cpu", + ) + joint_ids = robot.get_joint_ids("arm") + robot.set_qpos(qpos=initial_qpos, joint_ids=joint_ids) + + time.sleep(0.2) # Wait for a moment to ensure everything is set up + + # Enable gizmo using the new API + sim.enable_gizmo(uid="ur10_gizmo_test", control_part="arm") + if not sim.has_gizmo("ur10_gizmo_test", control_part="arm"): + logger.log_error("Failed to enable gizmo!") + return + + sim.open_window() + + logger.log_info("Gizmo-Robot example started!") + logger.log_info("Use the gizmo to drag the robot end-effector (EE)") + logger.log_info("Press Ctrl+C to stop the simulation") + + run_simulation(sim) + + +def run_simulation(sim: SimulationManager): + step_count = 0 + try: + last_time = time.time() + last_step = 0 + while True: + time.sleep(0.033) # 30Hz + # Update all gizmos managed by sim + sim.update_gizmos() + step_count += 1 + + if step_count % 100 == 0: + current_time = time.time() + elapsed = current_time - last_time + fps = ( + sim.num_envs * (step_count - last_step) / elapsed + if elapsed > 0 + else 0 + ) + logger.log_info(f"Simulation step: {step_count}, FPS: {fps:.2f}") + last_time = current_time + last_step = step_count + except KeyboardInterrupt: + logger.log_info("\nStopping simulation...") + finally: + sim.destroy() + logger.log_info("Simulation terminated successfully") + + +if __name__ == "__main__": + main() diff --git a/examples/sim/gizmo/gizmo_scene.py b/examples/sim/gizmo/gizmo_scene.py new file mode 100644 index 00000000..31c7d233 --- /dev/null +++ b/examples/sim/gizmo/gizmo_scene.py @@ -0,0 +1,263 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +""" +Gizmo Scene Example: Interactive scene with both robot and rigid object gizmos + +This example demonstrates how to create an interactive simulation scene with: +- A UR10 robot with gizmo control for end-effector manipulation +- A rigid object (cube) with gizmo control for direct manipulation +Both objects can be interactively controlled through their respective gizmos. +""" + +import time +import torch +import numpy as np +import argparse +import cv2 + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import ( + RobotCfg, + URDFCfg, + JointDrivePropertiesCfg, + RigidObjectCfg, + RigidBodyAttributesCfg, +) +from embodichain.lab.sim.shapes import CubeCfg +from embodichain.lab.sim.sensors import CameraCfg +from embodichain.lab.sim.solvers import PinkSolverCfg +from embodichain.data import get_data_path +from embodichain.utils import logger + + +def main(): + """Main function to create and run the simulation scene.""" + + parser = argparse.ArgumentParser( + description="Create a simulation scene with SimulationManager" + ) + parser.add_argument( + "--num_envs", type=int, default=1, help="Number of parallel environments" + ) + parser.add_argument( + "--device", type=str, default="cpu", help="Simulation device (cuda or cpu)" + ) + parser.add_argument( + "--enable_rt", + action="store_true", + default=False, + help="Enable ray tracing for better visuals", + ) + args = parser.parse_args() + + # Configure the simulation + sim_cfg = SimulationManagerCfg( + width=1920, + height=1080, + physics_dt=1.0 / 100.0, + sim_device=args.device, + enable_rt=args.enable_rt, + ) + + sim = SimulationManager(sim_cfg) + sim.set_manual_update(False) + + # Build multiple arenas if requested + if args.num_envs > 1: + sim.build_multiple_arenas(args.num_envs, space=3.0) + + # Get DexForce W1 URDF path + urdf_path = get_data_path( + "DexforceW1V021_INDUSTRIAL_DH_PGC_GRIPPER_M/DexforceW1V021.urdf" + ) + + # Create DexForce W1 robot + robot_cfg = RobotCfg( + uid="w1_gizmo_test", + urdf_cfg=URDFCfg( + components=[{"component_type": "humanoid", "urdf_path": urdf_path}] + ), + control_parts={"left_arm": ["LEFT_J[1-7]"], "right_arm": ["RIGHT_J[1-7]"]}, + solver_cfg={ + "left_arm": PinkSolverCfg( + urdf_path=urdf_path, + end_link_name="left_ee", + root_link_name="left_arm_base", + pos_eps=1e-2, + rot_eps=5e-2, + max_iterations=300, + dt=0.1, + ), + "right_arm": PinkSolverCfg( + urdf_path=urdf_path, + end_link_name="right_ee", + root_link_name="right_arm_base", + pos_eps=1e-2, + rot_eps=5e-2, + max_iterations=300, + dt=0.1, + ), + }, + drive_pros=JointDrivePropertiesCfg( + stiffness={"LEFT_J[1-7]": 1e4, "RIGHT_J[1-7]": 1e4}, + damping={"LEFT_J[1-7]": 1e3, "RIGHT_J[1-7]": 1e3}, + ), + ) + robot = sim.add_robot(cfg=robot_cfg) + + # Set initial joint positions for both arms + left_arm_qpos = torch.tensor( + [ + [0, 0, -np.pi / 4, np.pi / 4, -np.pi / 2, 0.0, np.pi / 4, 0.0] + ], # WAIST + LEFT_J[1-7] + dtype=torch.float32, + device="cpu", + ) + right_arm_qpos = torch.tensor( + [ + [0, 0, np.pi / 4, -np.pi / 4, np.pi / 2, 0.0, -np.pi / 4, 0.0] + ], # WAIST + RIGHT_J[1-7] + dtype=torch.float32, + device="cpu", + ) + + left_joint_ids = robot.get_joint_ids("left_arm") + right_joint_ids = robot.get_joint_ids("right_arm") + + robot.set_qpos(qpos=left_arm_qpos, joint_ids=left_joint_ids) + robot.set_qpos(qpos=right_arm_qpos, joint_ids=right_joint_ids) + + # Create a rigid object (cube) positioned to the side of the robot + cube_cfg = RigidObjectCfg( + uid="interactive_cube", + shape=CubeCfg(size=[0.1, 0.1, 0.1]), + body_type="kinematic", + attrs=RigidBodyAttributesCfg( + mass=1.0, + dynamic_friction=0.5, + static_friction=0.5, + restitution=0.1, + ), + init_pos=[1.0, 0.0, 0.5], # Position to the side of the robot + ) + cube = sim.add_rigid_object(cube_cfg) + + camera_cfg = CameraCfg( + uid="scene_camera", + width=640, + height=480, + intrinsics=(320, 320, 320, 240), # fx, fy, cx, cy + near=0.1, + far=10.0, + enable_color=True, + enable_depth=True, + extrinsics=CameraCfg.ExtrinsicsCfg( + eye=(2.0, 2.0, 2.0), + target=(0.0, 0.0, 0.0), + up=(0.0, 0.0, 1.0), + ), + ) + camera = sim.add_sensor(sensor_cfg=camera_cfg) + + # Enable gizmo for all assets after all are created and initialized + sim.enable_gizmo(uid="w1_gizmo_test", control_part="left_arm") + if not sim.has_gizmo("w1_gizmo_test", control_part="left_arm"): + logger.log_error("Failed to enable left arm gizmo!") + return + + sim.enable_gizmo(uid="w1_gizmo_test", control_part="right_arm") + if not sim.has_gizmo("w1_gizmo_test", control_part="right_arm"): + logger.log_error("Failed to enable right arm gizmo!") + return + + sim.enable_gizmo(uid="interactive_cube") + if not sim.has_gizmo("interactive_cube"): + logger.log_error("Failed to enable gizmo for cube!") + return + + sim.enable_gizmo(uid="scene_camera") + if not sim.has_gizmo("scene_camera"): + logger.log_error("Failed to enable gizmo for camera!") + return + + sim.open_window() + + logger.log_info("Gizmo Scene example started!") + logger.log_info("Four gizmos are active in the scene:") + logger.log_info("1. Left arm gizmo - Use to drag the left arm end-effector (EE)") + logger.log_info("2. Right arm gizmo - Use to drag the right arm end-effector (EE)") + logger.log_info("3. Cube gizmo - Use to drag and position the cube") + logger.log_info("4. Camera gizmo - Use to drag and orient the camera") + logger.log_info("Press Ctrl+C to stop the simulation") + + run_simulation(sim) + + +def run_simulation(sim: SimulationManager): + step_count = 0 + # Get the camera instance by uid + camera = sim.get_sensor("scene_camera") + try: + last_time = time.time() + last_step = 0 + while True: + time.sleep(0.033) # 30Hz + sim.update_gizmos() + step_count += 1 + + # Display camera view in a window every 5 steps + if camera is not None and step_count % 5 == 0: + camera.update() + data = camera.get_data() + if "color" in data: + rgb_image = data["color"].cpu().numpy()[0, :, :, :3] + bgr_image = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2BGR) + cv2.putText( + bgr_image, + "Press 'h' to toggle camera gizmo visibility", + (10, 30), + cv2.FONT_HERSHEY_SIMPLEX, + 0.6, + (0, 255, 0), + 2, + ) + cv2.imshow("Camera Sensor View", bgr_image) + key = cv2.waitKey(1) & 0xFF + if key == ord("h"): + # Toggle the camera gizmo visibility using SimulationManager API + sim.toggle_gizmo_visibility("scene_camera") + + if step_count % 100 == 0: + current_time = time.time() + elapsed = current_time - last_time + fps = ( + sim.num_envs * (step_count - last_step) / elapsed + if elapsed > 0 + else 0 + ) + logger.log_info(f"Simulation step: {step_count}, FPS: {fps:.2f}") + last_time = current_time + last_step = step_count + except KeyboardInterrupt: + logger.log_info("\nStopping simulation...") + finally: + cv2.destroyAllWindows() + sim.destroy() + logger.log_info("Simulation terminated successfully") + + +if __name__ == "__main__": + main() diff --git a/examples/sim/gizmo/gizmo_w1.py b/examples/sim/gizmo/gizmo_w1.py new file mode 100644 index 00000000..791582a0 --- /dev/null +++ b/examples/sim/gizmo/gizmo_w1.py @@ -0,0 +1,188 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +""" +Gizmo-Robot Example: Test Gizmo class on a robot (UR10) +""" + +import time +import torch +import numpy as np +import argparse + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import ( + RobotCfg, + URDFCfg, + JointDrivePropertiesCfg, +) + +from embodichain.lab.sim.solvers import PinkSolverCfg +from embodichain.data import get_data_path +from embodichain.utils import logger + + +def main(): + """Main function to create and run the simulation scene.""" + + # Parse command line arguments + parser = argparse.ArgumentParser( + description="Create a simulation scene with SimulationManager" + ) + parser.add_argument( + "--num_envs", type=int, default=1, help="Number of parallel environments" + ) + parser.add_argument( + "--device", type=str, default="cpu", help="Simulation device (cuda or cpu)" + ) + parser.add_argument( + "--enable_rt", + action="store_true", + default=False, + help="Enable ray tracing for better visuals", + ) + args = parser.parse_args() + + # Configure the simulation + sim_cfg = SimulationManagerCfg( + width=1920, + height=1080, + physics_dt=1.0 / 100.0, + sim_device=args.device, + enable_rt=args.enable_rt, + ) + + sim = SimulationManager(sim_cfg) + sim.set_manual_update(False) + + # Build multiple arenas if requested + if args.num_envs > 1: + sim.build_multiple_arenas(args.num_envs, space=3.0) + + # Get DexForce W1 URDF path + urdf_path = get_data_path( + "DexforceW1V021_INDUSTRIAL_DH_PGC_GRIPPER_M/DexforceW1V021.urdf" + ) + + # Create DexForce W1 robot + robot_cfg = RobotCfg( + uid="w1_gizmo_test", + urdf_cfg=URDFCfg( + components=[{"component_type": "humanoid", "urdf_path": urdf_path}] + ), + control_parts={"left_arm": ["LEFT_J[1-7]"], "right_arm": ["RIGHT_J[1-7]"]}, + solver_cfg={ + "left_arm": PinkSolverCfg( + urdf_path=urdf_path, + end_link_name="left_ee", + root_link_name="left_arm_base", + pos_eps=1e-2, + rot_eps=5e-2, + max_iterations=300, + dt=0.1, + ), + "right_arm": PinkSolverCfg( + urdf_path=urdf_path, + end_link_name="right_ee", + root_link_name="right_arm_base", + pos_eps=1e-2, + rot_eps=5e-2, + max_iterations=300, + dt=0.1, + ), + }, + drive_pros=JointDrivePropertiesCfg( + stiffness={"LEFT_J[1-7]": 1e4, "RIGHT_J[1-7]": 1e4}, + damping={"LEFT_J[1-7]": 1e3, "RIGHT_J[1-7]": 1e3}, + ), + ) + robot = sim.add_robot(cfg=robot_cfg) + + # Set initial joint positions for both arms + # Left arm: 8 joints (WAIST + 7 LEFT_J), Right arm: 8 joints (WAIST + 7 RIGHT_J) + left_arm_qpos = torch.tensor( + [ + [0, 0, -np.pi / 4, np.pi / 4, -np.pi / 2, 0.0, np.pi / 4, 0.0] + ], # WAIST + LEFT_J[1-7] + dtype=torch.float32, + device="cpu", + ) + right_arm_qpos = torch.tensor( + [ + [0, 0, np.pi / 4, -np.pi / 4, np.pi / 2, 0.0, -np.pi / 4, 0.0] + ], # WAIST + RIGHT_J[1-7] + dtype=torch.float32, + device="cpu", + ) + + left_joint_ids = robot.get_joint_ids("left_arm") + right_joint_ids = robot.get_joint_ids("right_arm") + + robot.set_qpos(qpos=left_arm_qpos, joint_ids=left_joint_ids) + robot.set_qpos(qpos=right_arm_qpos, joint_ids=right_joint_ids) + + time.sleep(0.2) # Wait for a moment to ensure everything is set up + + # Enable gizmo for both arms using the new API + sim.enable_gizmo(uid="w1_gizmo_test", control_part="left_arm") + if not sim.has_gizmo("w1_gizmo_test", control_part="left_arm"): + logger.log_error("Failed to enable left arm gizmo!") + return + + sim.enable_gizmo(uid="w1_gizmo_test", control_part="right_arm") + if not sim.has_gizmo("w1_gizmo_test", control_part="right_arm"): + logger.log_error("Failed to enable right arm gizmo!") + return + + sim.open_window() + + logger.log_info("Gizmo-DexForce W1 example started!") + logger.log_info("Use the gizmos to drag both robot arms' end-effectors") + logger.log_info("Press Ctrl+C to stop the simulation") + + run_simulation(sim) + + +def run_simulation(sim: SimulationManager): + step_count = 0 + try: + last_time = time.time() + last_step = 0 + while True: + time.sleep(0.033) # 30Hz + # Update all gizmos managed by sim + sim.update_gizmos() + step_count += 1 + + if step_count % 100 == 0: + current_time = time.time() + elapsed = current_time - last_time + fps = ( + sim.num_envs * (step_count - last_step) / elapsed + if elapsed > 0 + else 0 + ) + logger.log_info(f"Simulation step: {step_count}, FPS: {fps:.2f}") + last_time = current_time + last_step = step_count + except KeyboardInterrupt: + logger.log_info("\nStopping simulation...") + finally: + sim.destroy() + logger.log_info("Simulation terminated successfully") + + +if __name__ == "__main__": + main() diff --git a/examples/sim/planners/motion_generator.py b/examples/sim/planners/motion_generator.py new file mode 100644 index 00000000..4557f6d1 --- /dev/null +++ b/examples/sim/planners/motion_generator.py @@ -0,0 +1,146 @@ +import time +import torch +import numpy as np +from copy import deepcopy +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim.robots import CobotMagicCfg +from embodichain.lab.sim.planners.utils import TrajectorySampleMethod +from embodichain.lab.sim.planners.motion_generator import MotionGenerator + + +def move_robot_along_trajectory( + robot: Robot, arm_name: str, qpos_list: list[torch.Tensor], delay: float = 0.1 +): + """ + Set the robot joint positions sequentially along the given joint trajectory. + Args: + robot: Robot instance. + arm_name: Name of the robot arm. + qpos_list: List of joint positions (torch.Tensor). + delay: Time delay between each step (seconds). + """ + for q in qpos_list: + robot.set_qpos(qpos=q.unsqueeze(0), joint_ids=robot.get_joint_ids(arm_name)) + time.sleep(delay) + + +def create_demo_trajectory( + robot: Robot, arm_name: str +) -> tuple[list[torch.Tensor], list[np.ndarray]]: + """ + Generate a three-point trajectory (start, middle, end) for demonstration. + Args: + robot: Robot instance. + arm_name: Name of the robot arm. + Returns: + qpos_list: List of joint positions (torch.Tensor). + xpos_list: List of end-effector poses (numpy arrays). + """ + qpos_fk = torch.tensor( + [[0.0, np.pi / 4, -np.pi / 4, 0.0, np.pi / 4, 0.0]], dtype=torch.float32 + ) + xpos_begin = robot.compute_fk(name=arm_name, qpos=qpos_fk, to_matrix=True) + xpos_mid = deepcopy(xpos_begin) + xpos_mid[0, 2, 3] -= 0.1 # Move down by 0.1m in Z direction + xpos_final = deepcopy(xpos_mid) + xpos_final[0, 0, 3] += 0.2 # Move forward by 0.2m in X direction + + qpos_begin = robot.compute_ik(pose=xpos_begin, name=arm_name)[1][0] + qpos_mid = robot.compute_ik(pose=xpos_mid, name=arm_name)[1][0] + qpos_final = robot.compute_ik(pose=xpos_final, name=arm_name)[1][0] + return [qpos_begin, qpos_mid, qpos_final], [ + xpos_begin[0], + xpos_mid[0], + xpos_final[0], + ] + + +def main(interactive=False): + np.set_printoptions(precision=5, suppress=True) + torch.set_printoptions(precision=5, sci_mode=False) + + # Initialize simulation + sim = SimulationManager(SimulationManagerCfg(headless=False, sim_device="cpu")) + sim.build_multiple_arenas(1) + sim.set_manual_update(False) + + # Robot configuration + cfg_dict = { + "uid": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [ + -0.3, + 0.3, + 1.0, + 1.0, + -1.2, + -1.2, + 0.0, + 0.0, + 0.6, + 0.6, + 0.0, + 0.0, + 0.05, + 0.05, + 0.05, + 0.05, + ], + "solver_cfg": { + "left_arm": { + "class_type": "OPWSolver", + "end_link_name": "left_link6", + "root_link_name": "left_arm_base", + "tcp": [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.143], [0, 0, 0, 1]], + }, + "right_arm": { + "class_type": "OPWSolver", + "end_link_name": "right_link6", + "root_link_name": "right_arm_base", + "tcp": [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.143], [0, 0, 0, 1]], + }, + }, + } + robot: Robot = sim.add_robot(cfg=CobotMagicCfg.from_dict(cfg_dict)) + arm_name = "left_arm" + + # Generate trajectory points + qpos_list, xpos_list = create_demo_trajectory(robot, arm_name) + + # Initialize motion generator + motion_generator = MotionGenerator( + robot=robot, + uid=arm_name, + planner_type="toppra", + default_velocity=0.2, + default_acceleration=0.5, + ) + + # Joint space trajectory + out_qpos_list, _ = motion_generator.create_discrete_trajectory( + qpos_list=[q.numpy() for q in qpos_list], + is_linear=False, + sample_method=TrajectorySampleMethod.QUANTITY, + sample_num=20, + ) + move_robot_along_trajectory(robot, arm_name, out_qpos_list) + + # Cartesian space trajectory + out_qpos_list, _ = motion_generator.create_discrete_trajectory( + xpos_list=[x.numpy() for x in xpos_list], + is_linear=True, + sample_method=TrajectorySampleMethod.QUANTITY, + sample_num=20, + ) + move_robot_along_trajectory(robot, arm_name, out_qpos_list) + + if interactive: + # Enter IPython interactive shell if needed + from IPython import embed + + embed() + + +if __name__ == "__main__": + main() diff --git a/examples/sim/scene/scene_demo.py b/examples/sim/scene/scene_demo.py new file mode 100644 index 00000000..6efa3b13 --- /dev/null +++ b/examples/sim/scene/scene_demo.py @@ -0,0 +1,195 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +""" +This script demonstrates how to create a simulation scene using SimulationManager. +It supports loading kitchen/factory/office scenes via EmbodiChainDataset. +""" + +import argparse +import time +from pathlib import Path +import math +import embodichain.utils.logger as logger +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import RigidBodyAttributesCfg, LightCfg, RobotCfg, URDFCfg +from embodichain.lab.sim.shapes import MeshCfg +from embodichain.lab.sim.objects import RigidObject, RigidObjectCfg, Robot +from embodichain.data.assets.scene_assets import SceneData +from embodichain.data.constants import EMBODICHAIN_DEFAULT_DATA_ROOT + + +def resolve_asset_path(scene_name: str) -> str: + """ + Resolve the asset path for a given scene (.glb/.gltf), + downloading if needed using EmbodiChainData. + """ + + current_dir = Path(__file__).parent + local_glb = current_dir / f"{scene_name}.glb" + local_gltf = current_dir / f"{scene_name}.gltf" + if local_glb.exists(): + logger.log_info(f"Using local asset: {local_glb}") + return str(local_glb) + if local_gltf.exists(): + logger.log_info(f"Using local asset: {local_gltf}") + return str(local_gltf) + + scene_data = SceneData() + + extracted_dir = Path(EMBODICHAIN_DEFAULT_DATA_ROOT) / "extract" / "SceneData" + glb_path = extracted_dir / f"{scene_name}.glb" + gltf_path = extracted_dir / f"{scene_name}.gltf" + + if glb_path.exists(): + logger.log_info(f"Using downloaded asset: {glb_path}") + return str(glb_path) + if gltf_path.exists(): + logger.log_info(f"Using downloaded asset: {gltf_path}") + return str(gltf_path) + + raise FileNotFoundError( + f"No .glb or .gltf found in extracted folder: {extracted_dir}" + ) + + +def run_simulation(sim: SimulationManager): + """Run the simulation loop.""" + if sim.is_use_gpu_physics: + sim.init_gpu_physics() + + try: + while True: + time.sleep(0.01) + except KeyboardInterrupt: + logger.log_info("\n Stopping simulation...") + finally: + sim.destroy() + logger.log_info("Simulation terminated successfully.") + + +def main(): + parser = argparse.ArgumentParser( + description="Create a simulation scene with SimulationManager" + ) + parser.add_argument( + "--scene", + type=str, + default="kitchen", + choices=["kitchen", "factory", "office", "local"], + help="Choose which scene to load", + ) + parser.add_argument( + "--num_envs", type=int, default=1, help="Number of parallel environments" + ) + parser.add_argument( + "--device", type=str, default="cpu", help="Simulation device (cuda or cpu)" + ) + parser.add_argument( + "--disable_rt", + action="store_true", + default=False, + help="Disable ray tracing for better visuals", + ) + args = parser.parse_args() + + logger.log_info(f"Initializing scene '{args.scene}'") + + logger.log_info(f"Resolving and downloading scene '{args.scene}' if needed...") + try: + asset_path = resolve_asset_path(args.scene) + logger.log_info(f"Scene asset ready at: {asset_path}") + except Exception as e: + print(f"Failed to download or resolve scene asset: {e}") + return + + sim_cfg = SimulationManagerCfg( + width=1920, + height=1080, + headless=True, + physics_dt=1.0 / 100.0, + sim_device=args.device, + enable_rt=not args.disable_rt, + ) + sim = SimulationManager(sim_cfg) + sim.set_manual_update(True) + + if args.num_envs > 1: + sim.build_multiple_arenas(args.num_envs, space=10.0) + + num_lights = 8 + radius = 5 + height = 8 + intensity = 200 + lights = [] + + for i in range(num_lights): + angle = 2 * math.pi * i / num_lights + x = radius * math.cos(angle) + y = radius * math.sin(angle) + z = height + uid = f"l{i+1}" + cfg = LightCfg(uid=uid, intensity=intensity, radius=600, init_pos=[x, y, z]) + lights.append(sim.add_light(cfg)) + + physics_attrs = RigidBodyAttributesCfg( + mass=10, + dynamic_friction=0.5, + static_friction=0.5, + restitution=0.1, + ) + + try: + logger.log_info(f"Loading scene asset into simulation: {asset_path}") + scene_obj: RigidObject = sim.add_rigid_object( + cfg=RigidObjectCfg( + uid=args.scene, + shape=MeshCfg(fpath=asset_path), + body_type="static", + init_pos=[0.0, 0.0, 0.1], + init_rot=[90, 180, 0], + attrs=physics_attrs, + ) + ) + if args.scene == "factory": + from embodichain.lab.sim.robots.dexforce_w1.cfg import DexforceW1Cfg + + w1_robot: Robot = sim.add_robot( + cfg=DexforceW1Cfg.from_dict( + { + "uid": "dexforce_w1", + "version": "v021", + "arm_kind": "anthropomorphic", + "init_pos": [-1, -0.5, 0], + "init_rot": [0, 0, 90], + } + ), + ) + + except Exception as e: + logger.log_info(f"Failed to load scene asset: {e}") + return + + logger.log_info(f"Scene '{args.scene}' setup complete!") + logger.log_info(f"Running simulation with {args.num_envs} environment(s)") + logger.log_info("Press Ctrl+C to stop the simulation") + + sim.open_window() + + run_simulation(sim) + + +if __name__ == "__main__": + main() diff --git a/examples/sim/sensors/batch_camera.py b/examples/sim/sensors/batch_camera.py new file mode 100644 index 00000000..efbd17fb --- /dev/null +++ b/examples/sim/sensors/batch_camera.py @@ -0,0 +1,145 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import time +import numpy as np +import matplotlib.pyplot as plt + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import RigidObjectCfg, LightCfg +from embodichain.lab.sim.shapes import MeshCfg +from embodichain.lab.sim.objects import RigidObject, Light +from embodichain.lab.sim.sensors import ( + Camera, + StereoCamera, + CameraCfg, + StereoCameraCfg, +) +from embodichain.data import get_data_path + + +def main(args): + config = SimulationManagerCfg( + headless=True, sim_device=args.device, arena_space=2, enable_rt=args.enable_rt + ) + sim = SimulationManager(config) + sim.build_multiple_arenas(args.num_envs) + + rigid_obj: RigidObject = sim.add_rigid_object( + cfg=RigidObjectCfg( + uid="obj", + shape=MeshCfg(fpath=get_data_path("Chair/chair.glb")), + init_pos=(0, 0, 0.2), + ) + ) + light: Light = sim.add_light( + cfg=LightCfg(light_type="point", init_pos=(0, 0, 2), intensity=50) + ) + + if sim.is_use_gpu_physics: + sim.init_gpu_physics() + + if args.headless is False: + sim.open_window() + + import torch + + torch.set_printoptions(precision=4, sci_mode=False) + + eye = (0.0, 0, 2.0) + target = (0.0, 0.0, 0.0) + if args.sensor_type == "stereo": + camera: StereoCamera = sim.add_sensor( + sensor_cfg=StereoCameraCfg( + width=640, + height=480, + extrinsics=CameraCfg.ExtrinsicsCfg(eye=eye, target=target), + ) + ) + else: + camera: Camera = sim.add_sensor( + sensor_cfg=CameraCfg( + width=640, + height=480, + extrinsics=CameraCfg.ExtrinsicsCfg(eye=eye, target=target), + ) + ) + + # TODO: To be removed + sim.reset_objects_state() + + t0 = time.time() + camera.update() + print(f"Camera update time: {time.time() - t0:.4f} seconds") + + data_frame = camera.get_data() + + t0 = time.time() + rgba = data_frame["color"].cpu().numpy() + if args.sensor_type == "stereo": + rgba_right = data_frame["color_right"].cpu().numpy() + + # plot rgba into a grid of images + grid_x = np.ceil(np.sqrt(args.num_envs)).astype(int) + grid_y = np.ceil(args.num_envs / grid_x).astype(int) + fig, axs = plt.subplots(grid_x, grid_y, figsize=(12, 6)) + axs = axs.flatten() + for i in range(args.num_envs): + + if args.sensor_type == "stereo": + image = np.concatenate((rgba[i], rgba_right[i]), axis=1) + else: + image = rgba[i] + axs[i].imshow(image) + axs[i].axis("off") + axs[i].set_title(f"Env {i}") + + if args.headless: + plt.savefig(f"camera_data.png") + else: + plt.show() + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser(description="Run the batch robot simulation.") + parser.add_argument( + "--num_envs", type=int, default=4, help="Number of environments to simulate." + ) + parser.add_argument( + "--device", + type=str, + default="cpu", + choices=["cpu", "cuda"], + help="Device to run the simulation on.", + ) + parser.add_argument( + "--headless", action="store_true", help="Run the simulation in headless mode." + ) + parser.add_argument( + "--enable_rt", action="store_true", help="Enable ray tracing rendering." + ) + parser.add_argument( + "--sensor_type", + type=str, + default="camera", + choices=["stereo", "camera"], + help="Type of camera sensor to use.", + ) + + args = parser.parse_args() + main(args) diff --git a/examples/sim/solvers/differential_solver.py b/examples/sim/solvers/differential_solver.py new file mode 100644 index 00000000..1f056575 --- /dev/null +++ b/examples/sim/solvers/differential_solver.py @@ -0,0 +1,250 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +import os +import time +import numpy as np +import torch +from IPython import embed + +from embodichain.data import get_data_path +from embodichain.lab.sim.cfg import RobotCfg +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import MarkerCfg + + +def main(visualize: bool = True): + np.set_printoptions(precision=5, suppress=True) + torch.set_printoptions(precision=5, sci_mode=False) + + # Set up simulation with specified device (CPU or CUDA) + sim_device = "cpu" + num_envs = 9 # Number of parallel arenas/environments + config = SimulationManagerCfg( + headless=False, sim_device=sim_device, arena_space=1.5 + ) + sim = SimulationManager(config) + sim.build_multiple_arenas(num_envs) + sim.set_manual_update(False) + + # Load robot URDF file + urdf = get_data_path("Rokae/SR5/SR5.urdf") + assert os.path.isfile(urdf) + + # Robot configuration + cfg_dict = { + "fpath": urdf, + "control_parts": { + "main_arm": [ + "joint1", + "joint2", + "joint3", + "joint4", + "joint5", + "joint6", + ], + }, + "solver_cfg": { + "main_arm": { + "class_type": "DifferentialSolver", + "end_link_name": "ee_link", + "root_link_name": "base_link", + }, + }, + } + + robot: Robot = sim.add_robot(cfg=RobotCfg.from_dict(cfg_dict)) + + # Prepare initial joint positions for all environments + rad = torch.deg2rad(torch.tensor(45.0)) + arm_name = "main_arm" + fk_qpos = torch.full((num_envs, 6), rad, dtype=torch.float32, device="cpu") + # All envs start with the same qpos (can be randomized) + qpos = torch.from_numpy(np.array([0.0, 0.0, np.pi / 2, 0.0, np.pi / 2, 0.0])).to( + fk_qpos.device + ) + qpos = qpos.unsqueeze(0).repeat(num_envs, 1) + robot.set_qpos(qpos=qpos, joint_ids=robot.get_joint_ids(arm_name)) + + time.sleep(3.0) + fk_xpos = robot.compute_fk( + qpos=qpos, name=arm_name, to_matrix=True + ) # (num_envs, 4, 4) + + # Prepare batch start and end poses for all envs + start_pose = fk_xpos.clone() # (num_envs, 4, 4) + end_pose = fk_xpos.clone() + move_vecs = torch.tensor( + [ + [0.3, 0.0, 0.0], + [0.2, -0.2, 0.0], + [0.0, 0.0, 0.2], + [0.2, 0.0, 0.2], + [-0.3, 0.0, 0.0], + [-0.2, 0.2, 0.0], + [0.0, 0.0, -0.2], + [-0.2, 0.0, -0.2], + [0.1, 0.1, -0.1], + ], + dtype=end_pose.dtype, + device=end_pose.device, + ) + end_pose[ + :, :3, 3 + ] += move_vecs # Move each env's end-effector in a different direction + + num_steps = 100 + # Interpolate poses for each env + interpolated_poses = torch.stack( + [torch.lerp(start_pose, end_pose, t) for t in np.linspace(0, 1, num_steps)], + dim=1, + ) # (num_envs, num_steps, 4, 4) + + # Initial joint positions for all envs + ik_qpos = qpos.clone() + + ik_qpos_results = [] + ik_success_flags = [] + + ik_compute_begin = time.time() + # Batch IK solving for each step + for step in range(num_steps): + poses = interpolated_poses[:, step, :, :] # (num_envs, 4, 4) + if poses.shape[0] != num_envs: + poses = poses.expand(num_envs, *poses.shape[1:]) + if ik_qpos.shape[0] != num_envs: + ik_qpos = ik_qpos.expand(num_envs, *ik_qpos.shape[1:]) + assert ( + poses.shape[0] == num_envs + ), f"poses batch mismatch: {poses.shape[0]} vs {num_envs}" + assert ( + ik_qpos.shape[0] == num_envs + ), f"ik_qpos batch mismatch: {ik_qpos.shape[0]} vs {num_envs}" + + # Parallel batch IK solving + res, ik_qpos_new = robot.compute_ik( + pose=poses, joint_seed=ik_qpos, name=arm_name + ) + ik_qpos_results.append(ik_qpos_new.clone()) + ik_success_flags.append(res) + ik_qpos = ik_qpos_new # Update joint seed + ik_compute_end = time.time() + print( + f"IK compute time for {num_steps} steps and {num_envs} envs: {ik_compute_end - ik_compute_begin:.4f} seconds" + ) + + # Collect visualization data for all steps and environments + if visualize: + draw_data = [[] for _ in range(num_envs)] + for env_id in range(num_envs): + for step in range(num_steps): + ik_qpos_new = ik_qpos_results[step] + ik_xpos = robot.compute_fk(qpos=ik_qpos_new, name=arm_name, to_matrix=True) + local_pose = robot._entities[env_id].get_world_pose() + if visualize: + fk_axis = local_pose @ end_pose[env_id].cpu().numpy() + ik_axis = local_pose @ ik_xpos[env_id].cpu().numpy() + local_axis = local_pose @ ik_xpos[env_id].cpu().numpy() + + draw_data[env_id].append( + { + "step": step, + "fk_axis": fk_axis, + "ik_axis": ik_axis, + "local_axis": local_axis, + } + ) + + if visualize: + # Batch draw all steps' data for each environment + for env_id in range(num_envs): + # Only draw fk_axis and ik_axis once per env (first step) + fk_axis = draw_data[env_id][0]["fk_axis"] + ik_axis = draw_data[env_id][0]["ik_axis"] + + sim.draw_marker( + cfg=MarkerCfg( + name=f"fk_axis_env{env_id}", + marker_type="axis", + axis_xpos=fk_axis, + axis_size=0.002, + axis_len=0.005, + arena_index=env_id, + ) + ) + + sim.draw_marker( + cfg=MarkerCfg( + name=f"ik_axis_env{env_id}", + marker_type="axis", + axis_xpos=ik_axis, + axis_size=0.002, + axis_len=0.005, + arena_index=env_id, + ) + ) + + # Draw the whole local_axis trajectory as a single call + local_axes = np.stack( + [item["local_axis"] for item in draw_data[env_id]], axis=0 + ) # (num_steps, 4, 4) or (num_steps, 3) + + sim.draw_marker( + cfg=MarkerCfg( + name=f"local_axis_env{env_id}_trajectory", + marker_type="axis", + axis_xpos=local_axes, + axis_size=0.002, + axis_len=0.005, + arena_index=env_id, + ) + ) + + # Optionally, set qpos for each step (replay or animate) + for step in range(num_steps): + ik_qpos_new = ik_qpos_results[step] + res = ik_success_flags[step] + # Only set qpos for successful IK results + if isinstance(res, (list, np.ndarray, torch.Tensor)): + for env_id, success in enumerate(res): + if success: + q = ( + ik_qpos_new[env_id] + if ik_qpos_new.dim() == 3 + else ik_qpos_new[env_id] + ) + robot.set_qpos( + qpos=q, + joint_ids=robot.get_joint_ids(arm_name), + env_ids=[env_id], + ) + else: + # fallback: set all + if ik_qpos_new.dim() == 3: + robot.set_qpos( + qpos=ik_qpos_new[:, 0, :], joint_ids=robot.get_joint_ids(arm_name) + ) + else: + robot.set_qpos( + qpos=ik_qpos_new, joint_ids=robot.get_joint_ids(arm_name) + ) + time.sleep(0.005) + + embed(header="Test DifferentialSolver example. Press Ctrl-D to exit.") + + +if __name__ == "__main__": + main(visualize=True) diff --git a/examples/sim/solvers/opw_solver.py b/examples/sim/solvers/opw_solver.py new file mode 100644 index 00000000..aa47eae8 --- /dev/null +++ b/examples/sim/solvers/opw_solver.py @@ -0,0 +1,195 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +import os +import time +import torch +import numpy as np +from IPython import embed + +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim.robots import CobotMagicCfg +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import MarkerCfg + + +def main(): + # Set print options for better readability + np.set_printoptions(precision=5, suppress=True) + torch.set_printoptions(precision=5, sci_mode=False) + + # Initialize simulation + sim_device = "cpu" + config = SimulationManagerCfg(headless=False, sim_device=sim_device) + sim = SimulationManager(config) + sim.build_multiple_arenas(1) + sim.set_manual_update(False) + + # Robot configuration dictionary + cfg_dict = { + "uid": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [ + -0.3, + 0.3, + 1.0, + 1.0, + -1.2, + -1.2, + 0.0, + 0.0, + 0.6, + 0.6, + 0.0, + 0.0, + 0.05, + 0.05, + 0.05, + 0.05, + ], + "solver_cfg": { + "left_arm": { + "class_type": "OPWSolver", + "end_link_name": "left_link6", + "root_link_name": "left_arm_base", + "tcp": [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.143], [0, 0, 0, 1]], + }, + "right_arm": { + "class_type": "OPWSolver", + "end_link_name": "right_link6", + "root_link_name": "right_arm_base", + "tcp": [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.143], [0, 0, 0, 1]], + }, + }, + } + + # Add robot to simulation + robot: Robot = sim.add_robot(cfg=CobotMagicCfg.from_dict(cfg_dict)) + + # Left arm control + arm_name = "left_arm" + # Set initial joint positions for left arm + qpos_seed = torch.tensor([[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]], dtype=torch.float32) + qpos_fk = torch.tensor( + [[0.0, np.pi / 4, -np.pi / 4, 0.0, np.pi / 4, 0.0]], dtype=torch.float32 + ) + fk_xpos = robot.compute_fk(qpos=qpos_fk, name=arm_name, to_matrix=True) + + link_pose = robot._entities[0].get_link_pose("left_base_link") + link_pose_tensor = torch.from_numpy(link_pose).to( + fk_xpos.device, dtype=fk_xpos.dtype + ) + + # Solve IK for the left arm + res, ik_qpos = robot.compute_ik(pose=fk_xpos, name=arm_name, joint_seed=qpos_seed) + + # Measure IK computation time and visualize result + a = time.time() + if ik_qpos.dim() == 3: + ik_xpos = robot.compute_fk(qpos=ik_qpos[0][0], name=arm_name, to_matrix=True) + else: + ik_xpos = robot.compute_fk(qpos=ik_qpos, name=arm_name, to_matrix=True) + b = time.time() + print(f"Left arm IK computation time: {b-a:.6f} seconds") + + # Visualize the result in simulation + sim.draw_marker( + cfg=MarkerCfg( + name="fk_xpos_left", + marker_type="axis", + axis_xpos=np.array(fk_xpos.tolist()), + axis_size=0.002, + axis_len=0.005, + ) + ) + + sim.draw_marker( + cfg=MarkerCfg( + name="ik_xpos_left", + marker_type="axis", + axis_xpos=np.array(ik_xpos.tolist()), + axis_size=0.002, + axis_len=0.005, + ) + ) + + # Move robot to IK result joint positions + if ik_qpos.dim() == 3: + robot.set_qpos(qpos=ik_qpos[0][0], joint_ids=robot.get_joint_ids(arm_name)) + else: + robot.set_qpos(qpos=ik_qpos, joint_ids=robot.get_joint_ids(arm_name)) + + # Right arm control + arm_name_r = "right_arm" + # Set initial joint positions for right arm + qpos_seed_r = torch.tensor([[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]], dtype=torch.float32) + qpos_fk_r = torch.tensor( + [[0.0, np.pi / 4, -np.pi / 4, 0.0, np.pi / 4, 0.0]], dtype=torch.float32 + ) + fk_xpos_r = robot.compute_fk(qpos=qpos_fk_r, name=arm_name_r, to_matrix=True) + + link_pose_r = robot._entities[0].get_link_pose("right_base_link") + link_pose_tensor_r = torch.from_numpy(link_pose_r).to( + fk_xpos_r.device, dtype=fk_xpos_r.dtype + ) + + # Solve IK for the right arm + res_r, ik_qpos_r = robot.compute_ik( + pose=fk_xpos_r, name=arm_name_r, joint_seed=qpos_seed_r + ) + + # Measure IK computation time and visualize result + a_r = time.time() + if ik_qpos_r.dim() == 3: + ik_xpos_r = robot.compute_fk( + qpos=ik_qpos_r[0][0], name=arm_name_r, to_matrix=True + ) + else: + ik_xpos_r = robot.compute_fk(qpos=ik_qpos_r, name=arm_name_r, to_matrix=True) + b_r = time.time() + print(f"Right arm IK computation time: {b_r-a_r:.6f} seconds") + + # Visualize the result in simulation + sim.draw_marker( + cfg=MarkerCfg( + name="fk_xpos_right", + marker_type="axis", + axis_xpos=np.array(fk_xpos_r.tolist()), + axis_size=0.002, + axis_len=0.005, + ) + ) + + sim.draw_marker( + cfg=MarkerCfg( + name="ik_xpos_right", + marker_type="axis", + axis_xpos=np.array(ik_xpos_r.tolist()), + axis_size=0.002, + axis_len=0.005, + ) + ) + + # Move robot to IK result joint positions + if ik_qpos_r.dim() == 3: + robot.set_qpos(qpos=ik_qpos_r[0][0], joint_ids=robot.get_joint_ids(arm_name_r)) + else: + robot.set_qpos(qpos=ik_qpos_r, joint_ids=robot.get_joint_ids(arm_name_r)) + + embed(header="Test OPWSolver example. Press Ctrl-D to exit.") + + +if __name__ == "__main__": + main() diff --git a/examples/sim/solvers/pink_solver.py b/examples/sim/solvers/pink_solver.py new file mode 100644 index 00000000..8ad325fe --- /dev/null +++ b/examples/sim/solvers/pink_solver.py @@ -0,0 +1,177 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +import os +import time +import numpy as np +import torch +from IPython import embed + +from embodichain.data import get_data_path +from embodichain.lab.sim.cfg import RobotCfg +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import MarkerCfg + + +def main(): + np.set_printoptions(precision=5, suppress=True) + torch.set_printoptions(precision=5, sci_mode=False) + + # Set up simulation with specified device (CPU or CUDA) + sim_device = "cpu" + config = SimulationManagerCfg(headless=False, sim_device=sim_device) + sim = SimulationManager(config) + sim.build_multiple_arenas(1) + sim.set_manual_update(False) + + # Load robot URDF file + urdf = get_data_path("Rokae/SR5/SR5.urdf") + + assert os.path.isfile(urdf) + + cfg_dict = { + "fpath": urdf, + "control_parts": { + "main_arm": [ + "joint1", + "joint2", + "joint3", + "joint4", + "joint5", + "joint6", + ], + }, + "solver_cfg": { + "main_arm": { + "class_type": "PinkSolver", + "end_link_name": "ee_link", + "root_link_name": "base_link", + }, + }, + } + + robot: Robot = sim.add_robot(cfg=RobotCfg.from_dict(cfg_dict)) + + # Define a sample target pose as a 1x4x4 homogeneous matrix + rad = torch.deg2rad(torch.tensor(45.0)) + + arm_name = "main_arm" + fk_qpos = torch.full((1, 6), rad, dtype=torch.float32, device="cpu") + + # Set initial joint positions + qpos = torch.from_numpy(np.array([0.0, 0.0, np.pi / 2, 0.0, np.pi / 2, 0.0])).to( + fk_qpos.device + ) + qpos = qpos.unsqueeze(0) + robot.set_qpos(qpos=qpos, joint_ids=robot.get_joint_ids("main_arm")) + import time + + time.sleep(3.0) + fk_xpos = robot.compute_fk(qpos=qpos, name=arm_name, to_matrix=True) + print(f"fk_xpos: {fk_xpos}") + start_pose = fk_xpos.clone()[0] # Start pose + end_pose = fk_xpos.clone()[0] # End pose + + end_pose[:3, 3] = end_pose[:3, 3][:3] + torch.tensor( + [0.0, 0.4, 0.0], device=fk_xpos.device + ) + + num_steps = 100 + + # Interpolate poses between start and end + interpolated_poses = [ + torch.lerp(start_pose, end_pose, t) for t in np.linspace(0, 1, num_steps) + ] + + ik_qpos = qpos + + qpos = ik_qpos + res, ik_qpos = robot.compute_ik(pose=end_pose, joint_seed=qpos, name=arm_name) + import time + + a = time.time() + if ik_qpos.dim() == 3: + ik_xpos = robot.compute_fk(qpos=ik_qpos[0][0], name=arm_name, to_matrix=True) + else: + ik_xpos = robot.compute_fk(qpos=ik_qpos, name=arm_name, to_matrix=True) + b = time.time() + print(f"ik time: {b-a}") + + ik_xpos = ik_xpos + + sim.draw_marker( + cfg=MarkerCfg( + name="fk_xpos", + marker_type="axis", + axis_xpos=np.array(end_pose.tolist()), + axis_size=0.002, + axis_len=0.005, + ) + ) + + sim.draw_marker( + cfg=MarkerCfg( + name="ik_xpos", + marker_type="axis", + axis_xpos=np.array(ik_xpos.tolist()), + axis_size=0.002, + axis_len=0.005, + ) + ) + + for i, pose in enumerate(interpolated_poses): + print(f"Step {i}: Moving to pose:\n{pose}") + start_time = time.time() + res, ik_qpos = robot.compute_ik(pose=pose, joint_seed=ik_qpos, name=arm_name) + end_time = time.time() + compute_time = end_time - start_time + print(f"Step {i}: IK computation time: {compute_time:.6f} seconds") + + print(f"IK result: {res}, ik_qpos: {ik_qpos}") + if not res: + print(f"Step {i}: IK failed for pose:\n{pose}") + continue + + # Set robot joint positions + if ik_qpos.dim() == 3: + robot.set_qpos(qpos=ik_qpos[0][0], joint_ids=robot.get_joint_ids(arm_name)) + else: + robot.set_qpos( + qpos=ik_qpos.unsqueeze(0), joint_ids=robot.get_joint_ids(arm_name) + ) + + # Visualize current pose + ik_xpos = robot.compute_fk(qpos=ik_qpos, name=arm_name, to_matrix=True) + ik_xpos = ik_xpos + + sim.draw_marker( + cfg=MarkerCfg( + name=f"ik_xpos_step_{i}", + marker_type="axis", + axis_xpos=np.array(ik_xpos.tolist()), + axis_size=0.002, + axis_len=0.005, + ) + ) + + # Add delay to simulate motion + time.sleep(0.005) + + embed(header="Test PinkSolver example. Press Ctrl-D to exit.") + + +if __name__ == "__main__": + main() diff --git a/examples/sim/solvers/pinocchio_solver.py b/examples/sim/solvers/pinocchio_solver.py new file mode 100644 index 00000000..bfd3730b --- /dev/null +++ b/examples/sim/solvers/pinocchio_solver.py @@ -0,0 +1,127 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +import os +import time +import numpy as np +import torch +from IPython import embed + +from embodichain.data import get_data_path +from embodichain.lab.sim.cfg import RobotCfg +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import MarkerCfg + + +def main(): + # Set print options for better readability + np.set_printoptions(precision=5, suppress=True) + torch.set_printoptions(precision=5, sci_mode=False) + + # Initialize simulation + sim_device = "cpu" + config = SimulationManagerCfg(headless=False, sim_device=sim_device) + sim = SimulationManager(config) + sim.build_multiple_arenas(1) + sim.set_manual_update(False) + + # Load robot URDF file + urdf = get_data_path("DexforceW1V021/DexforceW1_v02_1.urdf") + assert os.path.isfile(urdf) + + # Robot configuration dictionary + cfg_dict = { + "fpath": urdf, + "control_parts": { + "left_arm": [f"LEFT_J{i+1}" for i in range(7)], + "right_arm": [f"RIGHT_J{i+1}" for i in range(7)], + }, + "solver_cfg": { + "left_arm": { + "class_type": "PinocchioSolver", + "end_link_name": "left_ee", + "root_link_name": "left_arm_base", + }, + "right_arm": { + "class_type": "PinocchioSolver", + "end_link_name": "right_ee", + "root_link_name": "right_arm_base", + }, + }, + } + + robot: Robot = sim.add_robot(cfg=RobotCfg.from_dict(cfg_dict)) + arm_name = "left_arm" + # Set initial joint positions for left arm + qpos_seed = torch.tensor( + [[0.0, 0.1, 0.0, -np.pi / 4, 0.0, 0.0, 0.0]], dtype=torch.float32 + ) + qpos_fk = torch.tensor( + [[0.0, 0.0, 0.0, -np.pi / 4, 0.0, 0.0, 0.0]], dtype=torch.float32 + ) + fk_xpos = robot.compute_fk(qpos=qpos_fk, name=arm_name, to_matrix=True) + link_pose = robot._entities[0].get_link_pose("left_arm_base") + link_pose_tensor = torch.from_numpy(link_pose).to( + fk_xpos.device, dtype=fk_xpos.dtype + ) + + # Solve IK for the left arm + res, ik_qpos = robot.compute_ik(pose=fk_xpos, name=arm_name, joint_seed=qpos_seed) + + # Measure IK computation time and visualize result + a = time.time() + if ik_qpos.dim() == 3: + ik_xpos = robot.compute_fk(qpos=ik_qpos[0][0], name=arm_name, to_matrix=True) + else: + ik_xpos = robot.compute_fk(qpos=ik_qpos, name=arm_name, to_matrix=True) + b = time.time() + print(f"IK computation time: {b-a:.6f} seconds") + + fk_xpos = link_pose_tensor @ fk_xpos + ik_xpos = link_pose_tensor @ ik_xpos + + # Visualize the result in simulation + sim.draw_marker( + cfg=MarkerCfg( + name="fk_xpos", + marker_type="axis", + axis_xpos=np.array(fk_xpos.tolist()), + axis_size=0.002, + axis_len=0.005, + ) + ) + + sim.draw_marker( + cfg=MarkerCfg( + name="ik_xpos", + marker_type="axis", + axis_xpos=np.array(ik_xpos.tolist()), + axis_size=0.002, + axis_len=0.005, + ) + ) + + # Move robot to IK result joint positions + if ik_qpos.dim() == 3: + robot.set_qpos(qpos=ik_qpos[0][0], joint_ids=robot.get_joint_ids(arm_name)) + else: + robot.set_qpos(qpos=ik_qpos, joint_ids=robot.get_joint_ids(arm_name)) + + embed(header="Test PinocchioSolver example. Press Ctrl-D to exit.") + + +if __name__ == "__main__": + main() diff --git a/examples/sim/solvers/pytorch_solver.py b/examples/sim/solvers/pytorch_solver.py new file mode 100644 index 00000000..822eac52 --- /dev/null +++ b/examples/sim/solvers/pytorch_solver.py @@ -0,0 +1,226 @@ +import os +import time +import numpy as np +import torch +from IPython import embed + +from embodichain.data import get_data_path +from embodichain.lab.sim.cfg import RobotCfg +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import MarkerCfg + + +def main(): + # Set numpy and torch print options for better readability + np.set_printoptions(precision=5, suppress=True) + torch.set_printoptions(precision=5, sci_mode=False) + + # Initialize simulation environment (CPU or CUDA) + sim_device = "cpu" + num_envs = 9 # Number of parallel environments + config = SimulationManagerCfg( + headless=False, sim_device=sim_device, arena_space=2.0 + ) + sim = SimulationManager(config) + sim.build_multiple_arenas(num_envs) + sim.set_manual_update(False) + + # Load robot URDF file + urdf = get_data_path("DexforceW1V021/DexforceW1_v02_1.urdf") + assert os.path.isfile(urdf) + + # Robot configuration dictionary + cfg_dict = { + "fpath": urdf, + "control_parts": { + "left_arm": [ + "LEFT_J1", + "LEFT_J2", + "LEFT_J3", + "LEFT_J4", + "LEFT_J5", + "LEFT_J6", + "LEFT_J7", + ], + }, + "solver_cfg": { + "left_arm": { + "class_type": "PytorchSolver", + "end_link_name": "left_ee", + "root_link_name": "left_arm_base", + }, + }, + } + + # Add robot to simulation + robot: Robot = sim.add_robot(cfg=RobotCfg.from_dict(cfg_dict)) + + # Prepare initial joint positions for all environments + arm_name = "left_arm" + qpos = ( + torch.tensor([0.0, 0.0, 0.0, -np.pi / 2, 0.0, 0.0, 0.0], dtype=torch.float32) + .unsqueeze(0) + .repeat(num_envs, 1) + ) + robot.set_qpos(qpos=qpos, joint_ids=robot.get_joint_ids(arm_name)) + + time.sleep(2.0) + fk_xpos = robot.compute_fk( + qpos=qpos, name=arm_name, to_matrix=True + ) # (num_envs, 4, 4) + + # Prepare batch start and end poses for all envs + start_pose = fk_xpos.clone() + end_pose = fk_xpos.clone() + move_vecs = torch.tensor( + [ + [0.2, 0.0, 0.0], + [0.0, 0.2, 0.0], + [0.0, -0.2, -0.5], + [-0.2, 0.0, 0.0], + [-0.2, 0.0, 0.0], + [0.0, -0.2, 0.0], + [0.0, 0.0, -0.5], + [-0.2, 0.2, 0.0], + [0.0, 0.2, -0.5], + ], + dtype=end_pose.dtype, + device=end_pose.device, + ) + end_pose[:, :3, 3] += move_vecs + + num_steps = 50 + # Interpolate poses for each env + interpolated_poses = torch.stack( + [torch.lerp(start_pose, end_pose, t) for t in np.linspace(0, 1, num_steps)], + dim=1, + ) # (num_envs, num_steps, 4, 4) + + # Initial joint positions for all envs + ik_qpos = qpos.clone() + ik_qpos_results = [] + ik_success_flags = [] + + # Batch IK solving for each step + ik_compute_begin = time.time() + for step in range(num_steps): + poses = interpolated_poses[:, step, :, :] # (num_envs, 4, 4) + if poses.shape[0] != num_envs: + poses = poses.expand(num_envs, *poses.shape[1:]) + if ik_qpos.shape[0] != num_envs: + ik_qpos = ik_qpos.expand(num_envs, *ik_qpos.shape[1:]) + assert poses.shape[0] == num_envs + assert ik_qpos.shape[0] == num_envs + + # Parallel batch IK solving + res, ik_qpos_new = robot.compute_ik( + pose=poses, joint_seed=ik_qpos, name=arm_name + ) + ik_qpos_results.append(ik_qpos_new.clone()) + ik_success_flags.append(res) + ik_qpos = ik_qpos_new # Update joint seed + ik_compute_end = time.time() + print( + f"IK compute time for {num_steps} steps and {num_envs} envs: {ik_compute_end - ik_compute_begin:.4f} seconds" + ) + + # Collect visualization data for all steps and environments + draw_data = [[] for _ in range(num_envs)] + for env_id in range(num_envs): + for step in range(num_steps): + ik_qpos_new = ik_qpos_results[step] + ik_xpos = robot.compute_fk(qpos=ik_qpos_new, name=arm_name, to_matrix=True) + local_pose = robot._entities[env_id].get_link_pose("left_arm_base") + if isinstance(local_pose, np.ndarray): + local_pose = torch.from_numpy(local_pose).to( + ik_xpos.device, dtype=ik_xpos.dtype + ) + fk_axis = (local_pose @ end_pose[env_id]).cpu().numpy() + ik_axis = (local_pose @ ik_xpos[env_id]).cpu().numpy() + local_axis = (local_pose @ ik_xpos[env_id]).cpu().numpy() + draw_data[env_id].append( + { + "step": step, + "fk_axis": fk_axis, + "ik_axis": ik_axis, + "local_axis": local_axis, + } + ) + + # Batch draw: only draw fk_axis and ik_axis once per env, draw local_axis trajectory for all steps + for env_id in range(num_envs): + fk_axis = draw_data[env_id][0]["fk_axis"] + ik_axis = draw_data[env_id][0]["ik_axis"] + + sim.draw_marker( + cfg=MarkerCfg( + name=f"fk_axis_env{env_id}", + marker_type="axis", + axis_xpos=fk_axis, + axis_size=0.002, + axis_len=0.005, + arena_index=env_id, + ) + ) + + sim.draw_marker( + cfg=MarkerCfg( + name=f"ik_axis_env{env_id}", + marker_type="axis", + axis_xpos=ik_axis, + axis_size=0.002, + axis_len=0.005, + arena_index=env_id, + ) + ) + + # Draw the whole local_axis trajectory as a single call (if supported) + local_axes = np.stack( + [item["local_axis"] for item in draw_data[env_id]], axis=0 + ) + + sim.draw_marker( + cfg=MarkerCfg( + name=f"local_axis_env{env_id}_trajectory", + marker_type="axis", + axis_xpos=local_axes, + axis_size=0.002, + axis_len=0.005, + arena_index=env_id, + ) + ) + + # Optionally, set qpos for each step (replay or animate) + for step in range(num_steps): + ik_qpos_new = ik_qpos_results[step] + res = ik_success_flags[step] + if isinstance(res, (list, np.ndarray, torch.Tensor)): + for env_id, success in enumerate(res): + if success: + q = ( + ik_qpos_new[env_id] + if ik_qpos_new.dim() == 3 + else ik_qpos_new[env_id] + ) + robot.set_qpos( + qpos=q, + joint_ids=robot.get_joint_ids(arm_name), + env_ids=[env_id], + ) + else: + if ik_qpos_new.dim() == 3: + robot.set_qpos( + qpos=ik_qpos_new[:, 0, :], joint_ids=robot.get_joint_ids(arm_name) + ) + else: + robot.set_qpos( + qpos=ik_qpos_new, joint_ids=robot.get_joint_ids(arm_name) + ) + time.sleep(0.005) + + embed(header="Test PytorchSolver batch example. Press Ctrl-D to exit.") + + +if __name__ == "__main__": + main() diff --git a/examples/sim/solvers/srs_solver.py b/examples/sim/solvers/srs_solver.py new file mode 100644 index 00000000..5d9922b3 --- /dev/null +++ b/examples/sim/solvers/srs_solver.py @@ -0,0 +1,85 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import time +import numpy as np +import torch + +from IPython import embed + +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.robots import DexforceW1Cfg + + +def main(): + # Set print options for better readability + np.set_printoptions(precision=5, suppress=True) + torch.set_printoptions(precision=5, sci_mode=False) + + # Initialize simulation + sim_device = "cpu" + sim = SimulationManager( + SimulationManagerCfg( + headless=False, sim_device=sim_device, width=2200, height=1200 + ) + ) + + sim.build_multiple_arenas(1) + sim.set_manual_update(False) + + robot: Robot = sim.add_robot(cfg=DexforceW1Cfg.from_dict({"uid": "dexforce_w1"})) + arm_name = "left_arm" + # Set initial joint positions for left arm + qpos_fk_list = [ + torch.tensor([[0.0, 0.0, 0.0, -np.pi / 2, 0.0, 0.0, 0.0]], dtype=torch.float32), + ] + robot.set_qpos(qpos_fk_list[0], joint_ids=robot.get_joint_ids(arm_name)) + + time.sleep(0.5) + + fk_xpos_batch = torch.cat(qpos_fk_list, dim=0) + + fk_xpos_list = robot.compute_fk(qpos=fk_xpos_batch, name=arm_name, to_matrix=True) + + start_time = time.time() + res, ik_qpos = robot.compute_ik( + pose=fk_xpos_list, + name=arm_name, + # joint_seed=qpos_fk_list[0], + return_all_solutions=True, + ) + end_time = time.time() + print( + f"Batch IK computation time for {len(fk_xpos_list)} poses: {end_time - start_time:.6f} seconds" + ) + + if ik_qpos.dim() == 3: + first_solutions = ik_qpos[:, 0, :] + else: + first_solutions = ik_qpos + robot.set_qpos(first_solutions, joint_ids=robot.get_joint_ids(arm_name)) + + ik_xpos_list = robot.compute_fk(qpos=first_solutions, name=arm_name, to_matrix=True) + + print("fk_xpos_list: ", fk_xpos_list) + print("ik_xpos_list: ", ik_xpos_list) + + embed(header="Test SRSSolver example. Press Ctrl-D to exit.") + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..83b28a47 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,74 @@ +[build-system] +# Use the legacy setuptools backend so the existing `setup.py` (which dynamically +# detects torch and builds C/CUDA extensions via torch.utils.cpp_extension) +# is still executed during build. This is a minimal, non-opinionated pyproject +# that modernizes the package while preserving the custom extension build steps. +requires = ["setuptools>=61.0", "wheel"] +build-backend = "setuptools.build_meta:__legacy__" + + +# Note: +# - Building the torch extensions requires a working PyTorch installation +# available at build time (or FORCE_CUDA=1 for cross-compilation). We keep +# the extension-building logic in `setup.py` because it needs to import +# `torch` at build time to select CUDA/Cpp extension classes. +# - If you prefer a pure PEP 517 build without a legacy setup.py, we can +# refactor the extension-building logic into a custom build backend plugin. + +[project] +name = "embodichain" +version = "0.0.1" +description = "A modular platform for building generalized embodied intelligence." +readme = "README.md" +authors = [ { name = "Dexforce" } ] +requires-python = ">=3.9" + + +# Core install dependencies (kept from requirements.txt). Some VCS links are +# specified using PEP 508 direct references where present. +dependencies = [ + "setuptools==69.5.1", + "gymnasium==0.29.1", + "langchain==0.2.14", + "langchain-openai==0.1.22", + "pillow==9.5.0", + "ffmpeg-python==0.2.0", + "pytransform3d", + "uvicorn", + "fastapi", + "casadi==3.7.1", + "pin==2.7.0", + "toppra==0.6.3", + "qpsolvers==4.8.1", + "pin-pink==3.4.0", + "PyYAML>=6.0", + "transformers==4.48.0", + "diffusers==0.32.1", + "balanced-loss", + "accelerate==1.2.1", + "wandb==0.20.1", + "tensorboard", + "pydantic==2.7.1", + "deepspeed==0.16.2", + "py_opw_kinematics==0.1.6", + "pytorch_kinematics==0.7.5", + "polars==1.31.0", + "cvxpy==1.4.0", + "ortools", + "prettytable", + "transforms3d==0.4.2", + "hdfdict@git+http://69.235.177.182:8081/externalrepo/hdfdict", + "OmegaConf", + "dill", + "black==22.3", + "aenum", + "h5py", + "dacite==1.9.2", + "zmq", +] + +[tool.setuptools.packages.find] +where = ["."] +exclude = ["docs"] + +[tool.black] diff --git a/scripts/benchmark/opw_solver.py b/scripts/benchmark/opw_solver.py new file mode 100644 index 00000000..e3112ab0 --- /dev/null +++ b/scripts/benchmark/opw_solver.py @@ -0,0 +1,155 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np +import warp as wp +from scipy.spatial.transform import Rotation +from embodichain.lab.sim.solvers.opw_solver import OPWSolver, OPWSolverCfg +from typing import Tuple, List +import time + + +def get_pose_err(matrix_a: np.ndarray, matrix_b: np.ndarray) -> Tuple[float, float]: + t_err = np.linalg.norm(matrix_a[:3, 3] - matrix_b[:3, 3]) + relative_rot = matrix_a[:3, :3].T @ matrix_b[:3, :3] + cos_angle = (np.trace(relative_rot) - 1) / 2.0 + cos_angle = np.clip(cos_angle, -1.0, 1.0) + r_err = np.arccos(cos_angle) + return t_err, r_err + + +def get_poses_err( + matrix_a_list: List[np.ndarray], matrix_b_list: List[np.ndarray] +) -> Tuple[float, float]: + t_errs = [] + r_errs = [] + for mat_a, mat_b in zip(matrix_a_list, matrix_b_list): + t_err, r_err = get_pose_err(mat_a, mat_b) + t_errs.append(t_err) + r_errs.append(r_err) + return np.mean(t_errs), np.mean(r_errs) + + +def check_opw_solver(solver_warp, solver_py_opw, n_samples=1000): + DOF = 6 + qpos_np = np.random.uniform(low=-np.pi, high=np.pi, size=(n_samples, DOF)).astype( + float + ) + qpos = torch.tensor(qpos_np, device=torch.device("cuda"), dtype=torch.float32) + xpos = solver_warp.get_fk(qpos) + qpos_seed = torch.tensor( + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + device=torch.device("cuda"), + dtype=torch.float32, + ) + + warp_ik_start_time = time.time() + warp_ik_success, warp_ik_qpos = solver_warp.get_ik( + xpos, + qpos_seed=qpos_seed, + initial_guess=qpos, + # return_all_solutions=True, + ) + warp_cost_time = time.time() - warp_ik_start_time + + # TODO: debug code + # warp_ik_success_np = warp_ik_success.cpu().numpy() + # warp_ik_failure_indices = np.where(warp_ik_success_np == False)[0] + # if len(warp_ik_failure_indices) > 0: + # failure_qpos = qpos_np[warp_ik_failure_indices] + # failure_xpos = xpos.cpu().numpy()[warp_ik_failure_indices] + # print("=====warp_ik_failure_qpos:\n", repr(failure_qpos)) + # print("=====warp_ik_failure_xpos:\n", repr(failure_xpos)) + + # print("=====xpos:\n", repr(xpos.cpu().numpy())) + # print("=====warp_ik_qpos:\n", repr(warp_ik_qpos.cpu().numpy())) + # print("=====warp_ik_success:\n", repr(warp_ik_success.cpu().numpy())) + + check_xpos = solver_warp.get_fk(warp_ik_qpos) + warp_t_mean_err, warp_r_mean_err = get_poses_err( + [x.cpu().numpy() for x in xpos], + [x.cpu().numpy() for x in check_xpos], + ) + + py_opw_ik_start_time = time.time() + py_opw_ik_success, py_opw_ik_qpos = solver_py_opw.get_ik( + xpos, qpos_seed=qpos_seed, initial_guess=qpos + ) + py_opw_cost_time = time.time() - py_opw_ik_start_time + + check_xpos = solver_warp.get_fk(py_opw_ik_qpos.to(torch.device("cuda"))) + py_opw_t_mean_err, py_opw_r_mean_err = get_poses_err( + [x.cpu().numpy() for x in xpos], + [x.cpu().numpy() for x in check_xpos], + ) + + return ( + warp_cost_time, + warp_t_mean_err, + warp_r_mean_err, + py_opw_cost_time, + py_opw_t_mean_err, + py_opw_r_mean_err, + ) + + +def benchmark_opw_solver(): + cfg = OPWSolverCfg() + cfg.a1 = 400.333 + cfg.a2 = -251.449 + cfg.b = 0.0 + cfg.c1 = 830 + cfg.c2 = 1177.556 + cfg.c3 = 1443.593 + cfg.c4 = 230 + cfg.offsets = ( + 0.0, + 82.21350356417211 * np.pi / 180.0, + -167.21710113148163 * np.pi / 180.0, + 0.0, + 0.0, + 0.0, + ) + cfg.flip_axes = (True, False, True, True, False, True) + cfg.has_parallelogram = False + + # TODO: ignore pk_serial_chain for OPW + solver_warp = cfg.init_solver(device=torch.device("cuda"), pk_serial_chain="") + solver_py_opw = cfg.init_solver(device=torch.device("cpu"), pk_serial_chain="") + n_samples = [100, 1000, 10000, 100000] + # n_samples = [100] + for n_sample in n_samples: + # check_opw_solver(solver_warp, solver_py_opw, device=device, n_samples=n_sample) + ( + warp_cost_time, + warp_t_mean_err, + warp_r_mean_err, + py_opw_cost_time, + py_opw_t_mean_err, + py_opw_r_mean_err, + ) = check_opw_solver(solver_warp, solver_py_opw, n_samples=n_sample) + print(f"===warp OPW Solver FK/IK test over {n_sample} samples:") + print(f" Warp IK time: {warp_cost_time * 1000:.6f} ms") + print(f"Translation mean error: {warp_t_mean_err*1000:.6f} mm") + print(f"Rotation mean error: {warp_r_mean_err*180/np.pi:.6f} degrees") + print(f"===Py OPW IK time: {py_opw_cost_time * 1000:.6f} ms") + print(f"Translation mean error: {py_opw_t_mean_err*1000:.6f} mm") + print(f"Rotation mean error: {py_opw_r_mean_err*180/np.pi:.6f} degrees") + + +if __name__ == "__main__": + benchmark_opw_solver() diff --git a/scripts/tutorials/gym/modular_env.py b/scripts/tutorials/gym/modular_env.py new file mode 100644 index 00000000..21b2e893 --- /dev/null +++ b/scripts/tutorials/gym/modular_env.py @@ -0,0 +1,216 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch + +from typing import List, Dict, Any + +import embodichain.lab.gym.envs.managers.randomization as rand +import embodichain.lab.gym.envs.managers.events as events +import embodichain.lab.gym.envs.managers.observations as obs + +from embodichain.lab.gym.envs.managers import ( + EventCfg, + SceneEntityCfg, + ObservationCfg, +) +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.lab.sim.robots import DexforceW1Cfg +from embodichain.lab.sim.sensors import StereoCameraCfg, SensorCfg +from embodichain.lab.sim.shapes import MeshCfg +from embodichain.lab.sim.cfg import ( + LightCfg, + ArticulationCfg, + RobotCfg, + RigidObjectCfg, + RigidBodyAttributesCfg, +) +from embodichain.data import get_data_path +from embodichain.utils import configclass + + +@configclass +class ExampleEventCfg: + + replace_obj: EventCfg = EventCfg( + func=events.replace_assets_from_group, + mode="reset", + params={ + "entity_cfg": SceneEntityCfg( + uid="fork", + ), + "folder_path": get_data_path("TableWare/tableware/fork/"), + }, + ) + + randomize_light: EventCfg = EventCfg( + func=rand.randomize_light, + mode="interval", + interval_step=5, + params={ + "entity_cfg": SceneEntityCfg( + uid="point", + ), + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0], + }, + ) + + randomize_table_mat: EventCfg = EventCfg( + func=rand.randomize_visual_material, + mode="interval", + interval_step=10, + params={ + "entity_cfg": SceneEntityCfg( + uid="table", + ), + "random_texture_prob": 0.5, + "texture_path": get_data_path("CocoBackground/coco"), + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]], + }, + ) + + +@configclass +class ObsCfg: + + obj_pose: ObservationCfg = ObservationCfg( + func=obs.get_rigid_object_pose, + mode="add", + name="fork_pose", + params={"entity_cfg": SceneEntityCfg(uid="fork")}, + ) + + +@configclass +class ExampleCfg(EmbodiedEnvCfg): + + # Define the robot configuration using DexforceW1Cfg + robot: RobotCfg = DexforceW1Cfg.from_dict( + { + "uid": "dexforce_w1", + "version": "v021", + "arm_kind": "anthropomorphic", + "init_pos": [0.0, 0, 0.0], + } + ) + + # Define the sensor configuration using StereoCameraCfg + sensor: List[SensorCfg] = [ + StereoCameraCfg( + uid="eye_in_head", + width=960, + height=540, + enable_mask=True, + enable_depth=True, + left_to_right_pos=(0.06, 0, 0), + intrinsics=(450, 450, 480, 270), + intrinsics_right=(450, 450, 480, 270), + extrinsics=StereoCameraCfg.ExtrinsicsCfg( + parent="eyes", + ), + ) + ] + + light: EmbodiedEnvCfg.EnvLightCfg = EmbodiedEnvCfg.EnvLightCfg( + direct=[ + LightCfg( + uid="point", + light_type="point", + color=(1.0, 1.0, 1.0), + intensity=50.0, + init_pos=(0, 0, 2), + ) + ] + ) + + background: List[RigidObjectCfg] = [ + RigidObjectCfg( + uid="table", + shape=MeshCfg( + fpath=get_data_path("CircleTableSimple/circle_table_simple.ply"), + compute_uv=True, + ), + attrs=RigidBodyAttributesCfg( + mass=10.0, + static_friction=0.95, + dynamic_friction=0.85, + restitution=0.01, + ), + body_type="kinematic", + init_pos=(0.80, 0, 0.8), + init_rot=(0, 90, 0), + ), + ] + + rigid_object: List[RigidObjectCfg] = [ + RigidObjectCfg( + uid="fork", + shape=MeshCfg( + fpath=get_data_path("TableWare/tableware/fork/standard_fork_scale.ply"), + ), + body_scale=(0.75, 0.75, 1.0), + init_pos=(0.8, 0, 1.0), + ), + ] + + articulation_cfg: List[ArticulationCfg] = [ + ArticulationCfg( + uid="drawer", + fpath="SlidingBoxDrawer/SlidingBoxDrawer.urdf", + init_pos=(0.5, 0.0, 0.85), + ) + ] + + events = ExampleEventCfg() + + observations = ObsCfg() + + +@register_env("ModularEnv-v1", max_episode_steps=100, override=True) +class ModularEnv(EmbodiedEnv): + """ + An example of a modular environment that inherits from EmbodiedEnv + and uses custom event and observation managers. + """ + + def __init__(self, cfg: EmbodiedEnvCfg, **kwargs): + super().__init__(cfg, **kwargs) + + +if __name__ == "__main__": + import gymnasium as gym + import argparse + + from embodichain.lab.sim import SimulationManagerCfg + + parser = argparse.ArgumentParser() + parser.add_argument("--enable_rt", action="store_true", help="Enable ray tracing") + args = parser.parse_args() + + env_cfg = ExampleCfg(sim_cfg=SimulationManagerCfg(enable_rt=args.enable_rt)) + + # Create the Gym environment + env = gym.make("ModularEnv-v1", cfg=env_cfg) + + while True: + obs, info = env.reset() + + for i in range(100): + action = torch.zeros(env.action_space.shape, dtype=torch.float32) + obs, reward, done, truncated, info = env.step(action) diff --git a/scripts/tutorials/gym/random_reach.py b/scripts/tutorials/gym/random_reach.py new file mode 100644 index 00000000..a6e4ed0a --- /dev/null +++ b/scripts/tutorials/gym/random_reach.py @@ -0,0 +1,170 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np +import gymnasium as gym + +from embodichain.lab.gym.envs import BaseEnv, EnvCfg +from embodichain.lab.sim import SimulationManagerCfg +from embodichain.lab.sim.types import EnvAction, EnvObs +from embodichain.lab.sim.shapes import CubeCfg +from embodichain.lab.sim.objects import RigidObject, Robot +from embodichain.lab.sim.cfg import ( + RobotCfg, + RigidObjectCfg, + RigidBodyAttributesCfg, +) +from embodichain.lab.gym.utils.registration import register_env + + +@register_env("RandomReach-v1", max_episode_steps=100, override=True) +class RandomReachEnv(BaseEnv): + + robot_init_qpos = np.array( + [1.57079, -1.57079, 1.57079, -1.57079, -1.57079, -3.14159] + ) + + def __init__( + self, + num_envs=1, + headless=False, + device="cpu", + **kwargs, + ): + env_cfg = EnvCfg( + sim_cfg=SimulationManagerCfg( + headless=headless, arena_space=2.0, sim_device=device + ), + num_envs=num_envs, + ) + + super().__init__( + cfg=env_cfg, + **kwargs, + ) + + def _setup_robot(self, **kwargs) -> Robot: + from embodichain.data import get_data_path + + file_path = get_data_path("UniversalRobots/UR10/UR10.urdf") + + robot: Robot = self.sim.add_robot( + cfg=RobotCfg( + uid="ur10", + fpath=file_path, + init_pos=(0, 0, 1), + init_qpos=self.robot_init_qpos, + ) + ) + + qpos_limits = robot.body_data.qpos_limits[0].cpu().numpy() + self.single_action_space = gym.spaces.Box( + low=qpos_limits[:, 0], high=qpos_limits[:, 1], dtype=np.float32 + ) + + return robot + + def _prepare_scene(self, **kwargs) -> None: + size = 0.03 + # Create a kinematic cube object without collision. + # Currently, we use this workaround for visualization purposes. + self.cube: RigidObject = self.sim.add_rigid_object( + cfg=RigidObjectCfg( + uid="cube", + shape=CubeCfg(size=[size, size, size]), + attrs=RigidBodyAttributesCfg(enable_collision=False), + init_pos=(0.0, 0.0, 0.5), + body_type="kinematic", + ), + ) + + def _update_sim_state(self, **kwargs) -> None: + pose = torch.eye(4, device=self.device) + pose = pose.unsqueeze_(0).repeat(self.num_envs, 1, 1) + pose[:, :3, 3] += torch.rand(self.num_envs, 3, device=self.device) * 0.5 - 0.25 + self.cube.set_local_pose(pose=pose) + + def _step_action(self, action: EnvAction) -> EnvAction: + self.robot.set_qpos(qpos=action) + return action + + def _extend_obs(self, obs: EnvObs, **kwargs) -> EnvObs: + # You can also use `cube = self.sim.get_rigid_object("cube")` to access obj. + # obs["cube_position"] = self.cube.get_local_pose()[:, :3] + return obs + + +if __name__ == "__main__": + import argparse + import time + + parser = argparse.ArgumentParser( + description="Demo for running a random reach environment." + ) + parser.add_argument( + "--num_envs", type=int, default=1, help="number of environments to run" + ) + parser.add_argument( + "--device", + type=str, + default="cpu", + help="device to run the environment on, e.g., 'cpu' or 'cuda'", + ) + parser.add_argument("--headless", action="store_true", help="run in headless mode") + args = parser.parse_args() + + env = gym.make( + "RandomReach-v1", + num_envs=args.num_envs, + headless=args.headless, + device=args.device, + ) + + for episode in range(10): + print("Episode:", episode) + env.reset() + start_time = time.time() + total_steps = 0 + + for i in range(100): + action = env.action_space.sample() + action = torch.as_tensor(action, dtype=torch.float32, device=env.device) + + init_pose = env.robot_init_qpos + init_pose = ( + torch.as_tensor(init_pose, dtype=torch.float32, device=env.device) + .unsqueeze_(0) + .repeat(env.num_envs, 1) + ) + action = ( + init_pose + + torch.rand_like(action, dtype=torch.float32, device=env.device) * 0.2 + - 0.1 + ) + + obs, reward, done, truncated, info = env.step(action) + total_steps += env.num_envs + + end_time = time.time() + elapsed_time = end_time - start_time + if elapsed_time > 0: + fps = total_steps / elapsed_time + print(f"Total steps: {total_steps}") + print(f"Elapsed time: {elapsed_time:.2f} seconds") + print(f"FPS: {fps:.2f}") + else: + print("Elapsed time is too short to calculate FPS.") diff --git a/scripts/tutorials/sim/create_rigid_object_group.py b/scripts/tutorials/sim/create_rigid_object_group.py new file mode 100644 index 00000000..f8ae262f --- /dev/null +++ b/scripts/tutorials/sim/create_rigid_object_group.py @@ -0,0 +1,170 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +""" +This script demonstrates how to create a rigid object group using SimulationManager. +""" + +import argparse +import time + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import RigidBodyAttributesCfg +from embodichain.lab.sim.shapes import CubeCfg +from embodichain.lab.sim.objects import ( + RigidObjectGroup, + RigidObjectGroupCfg, + RigidObjectCfg, +) + + +def main(): + """Main function to create and run the simulation scene.""" + + # Parse command line arguments + parser = argparse.ArgumentParser( + description="Create a simulation scene with SimulationManager" + ) + parser.add_argument( + "--headless", + action="store_true", + default=False, + help="Run simulation in headless mode", + ) + parser.add_argument( + "--num_envs", type=int, default=1, help="Number of parallel environments" + ) + parser.add_argument( + "--device", type=str, default="cpu", help="Simulation device (cuda or cpu)" + ) + parser.add_argument( + "--enable_rt", + action="store_true", + default=False, + help="Enable ray tracing for better visuals", + ) + args = parser.parse_args() + + # Configure the simulation + sim_cfg = SimulationManagerCfg( + width=1920, + height=1080, + headless=True, + physics_dt=1.0 / 100.0, # Physics timestep (100 Hz) + sim_device=args.device, + enable_rt=args.enable_rt, # Enable ray tracing for better visuals + ) + + # Create the simulation instance + sim = SimulationManager(sim_cfg) + + # Enable manual physics update for precise control + sim.set_manual_update(True) + + # Build multiple arenas if requested + if args.num_envs > 1: + sim.build_multiple_arenas(args.num_envs, space=3.0) + + physics_attrs = RigidBodyAttributesCfg( + mass=1.0, + dynamic_friction=0.5, + static_friction=0.5, + restitution=0.1, + ) + + # Add objects to the scene + obj_group: RigidObjectGroup = sim.add_rigid_object_group( + cfg=RigidObjectGroupCfg( + uid="obj_group", + rigid_objects={ + "cube_1": RigidObjectCfg( + uid="cube_1", + shape=CubeCfg(size=[0.1, 0.1, 0.1]), + attrs=physics_attrs, + init_pos=[0.0, 0.0, 1.0], + ), + "cube_2": RigidObjectCfg( + uid="cube_2", + shape=CubeCfg(size=[0.2, 0.2, 0.2]), + attrs=physics_attrs, + init_pos=[0.5, 0.0, 1.0], + ), + "cube_3": RigidObjectCfg( + uid="cube_3", + shape=CubeCfg(size=[0.3, 0.3, 0.3]), + attrs=physics_attrs, + init_pos=[-0.5, 0.0, 1.0], + ), + }, + ) + ) + + print("[INFO]: Scene setup complete!") + print(f"[INFO]: Running simulation with {args.num_envs} environment(s)") + print("[INFO]: Press Ctrl+C to stop the simulation") + + # Open window when the scene has been set up + if not args.headless: + sim.open_window() + + # Run the simulation + run_simulation(sim) + + +def run_simulation(sim: SimulationManager): + """Run the simulation loop. + + Args: + sim: The SimulationManager instance to run + """ + + # Initialize GPU physics if using CUDA + if sim.is_use_gpu_physics: + sim.init_gpu_physics() + + step_count = 0 + + try: + last_time = time.time() + last_step = 0 + while True: + # Update physics simulation + sim.update(step=1) + step_count += 1 + + # Print FPS every second + if step_count % 100 == 0: + current_time = time.time() + elapsed = current_time - last_time + fps = ( + sim.num_envs * (step_count - last_step) / elapsed + if elapsed > 0 + else 0 + ) + print(f"[INFO]: Simulation step: {step_count}, FPS: {fps:.2f}") + last_time = current_time + last_step = step_count + + except KeyboardInterrupt: + print("\n[INFO]: Stopping simulation...") + finally: + # Clean up resources + sim.destroy() + print("[INFO]: Simulation terminated successfully") + + +if __name__ == "__main__": + main() diff --git a/scripts/tutorials/sim/create_robot.py b/scripts/tutorials/sim/create_robot.py new file mode 100644 index 00000000..6a504f70 --- /dev/null +++ b/scripts/tutorials/sim/create_robot.py @@ -0,0 +1,218 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +""" +This script demonstrates how to create and simulate a robot using SimulationManager. +It shows how to load a robot from URDF, set up control parts, and run basic simulation. +""" + +import argparse +import numpy as np +import time +import torch + +torch.set_printoptions(precision=4, sci_mode=False) + +from scipy.spatial.transform import Rotation as R + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim.cfg import ( + JointDrivePropertiesCfg, + RobotCfg, + URDFCfg, +) +from embodichain.data import get_data_path + + +def main(): + """Main function to demonstrate robot simulation.""" + + # Parse command line arguments + parser = argparse.ArgumentParser( + description="Create and simulate a robot in SimulationManager" + ) + parser.add_argument( + "--num_envs", type=int, default=1, help="Number of environments to simulate" + ) + parser.add_argument( + "--device", + type=str, + default="cpu", + choices=["cpu", "cuda"], + help="Device to run simulation on", + ) + parser.add_argument("--headless", action="store_true", help="Run in headless mode") + parser.add_argument( + "--enable_rt", action="store_true", help="Enable ray tracing rendering" + ) + args = parser.parse_args() + + # Initialize simulation + print("Creating simulation...") + config = SimulationManagerCfg( + headless=True, + sim_device=args.device, + arena_space=3.0, + enable_rt=args.enable_rt, + physics_dt=1.0 / 100.0, + ) + sim = SimulationManager(config) + + # Build multiple environments if requested + if args.num_envs > 1: + sim.build_multiple_arenas(args.num_envs) + + # Set manual physics update for precise control + sim.set_manual_update(True) + + # Create robot configuration + robot = create_robot(sim) + + # Initialize GPU physics if using CUDA + if sim.is_use_gpu_physics: + sim.init_gpu_physics() + + # Open visualization window if not headless + if not args.headless: + sim.open_window() + + # Run simulation loop + run_simulation(sim, robot) + + +def create_robot(sim): + """Create and configure a robot in the simulation.""" + + print("Loading robot...") + + # Get SR5 arm URDF path + sr5_urdf_path = get_data_path("Rokae/SR5/SR5.urdf") + + # Get hand URDF path + hand_urdf_path = get_data_path( + "BrainCoHandRevo1/BrainCoLeftHand/BrainCoLeftHand.urdf" + ) + + # Define control parts for the robot + # Joint names in control_parts can be regex patterns + CONTROL_PARTS = { + "arm": [ + "JOINT[1-6]", # Matches JOINT1, JOINT2, ..., JOINT6 + ], + "hand": ["LEFT_.*"], # Matches all joints starting with L_ + } + + # Define transformation for hand attachment + hand_attach_xpos = np.eye(4) + hand_attach_xpos[:3, :3] = R.from_rotvec([90, 0, 0], degrees=True).as_matrix() + hand_attach_xpos[2, 3] = 0.02 + + cfg = RobotCfg( + uid="sr5_with_brainco", + urdf_cfg=URDFCfg( + components=[ + { + "component_type": "arm", + "urdf_path": sr5_urdf_path, + }, + { + "component_type": "hand", + "urdf_path": hand_urdf_path, + "transform": hand_attach_xpos, + }, + ] + ), + control_parts=CONTROL_PARTS, + drive_pros=JointDrivePropertiesCfg( + stiffness={"JOINT[1-6]": 1e4, "LEFT_.*": 1e3}, + damping={"JOINT[1-6]": 1e3, "LEFT_.*": 1e2}, + ), + ) + + # Add robot to simulation + robot: Robot = sim.add_robot(cfg=cfg) + + print(f"Robot created successfully with {robot.dof} joints") + + return robot + + +def run_simulation(sim: SimulationManager, robot: Robot): + """Run the simulation loop with robot control.""" + + print("Starting simulation...") + print("Robot will move through different poses") + print("Press Ctrl+C to stop") + + step_count = 0 + + arm_joint_ids = robot.get_joint_ids("arm") + # Define some target joint positions for demonstration + arm_position1 = ( + torch.tensor( + [0.0, -0.5, 0.5, -1.0, 0.5, 0.0], dtype=torch.float32, device=sim.device + ) + .unsqueeze_(0) + .repeat(sim.num_envs, 1) + ) + + arm_position2 = ( + torch.tensor( + [0.5, 0.0, -0.5, 0.5, -0.5, 0.5], dtype=torch.float32, device=sim.device + ) + .unsqueeze_(0) + .repeat(sim.num_envs, 1) + ) + + # Get joint IDs for the hand. + hand_joint_ids = robot.get_joint_ids("hand") + # Define hand open and close positions based on joint limits. + hand_position_open = robot.body_data.qpos_limits[:, hand_joint_ids, 1] + hand_position_close = robot.body_data.qpos_limits[:, hand_joint_ids, 0] + + try: + while True: + # Update physics + sim.update(step=1) + + if step_count % 4000 == 0: + robot.set_qpos(qpos=arm_position1, joint_ids=arm_joint_ids) + print(f"Moving to arm position 1") + + if step_count % 4000 == 1000: + robot.set_qpos(qpos=arm_position2, joint_ids=arm_joint_ids) + print(f"Moving to arm position 2") + + if step_count % 4000 == 2000: + robot.set_qpos(qpos=hand_position_close, joint_ids=hand_joint_ids) + print(f"Closing hand") + + if step_count % 4000 == 3000: + robot.set_qpos(qpos=hand_position_open, joint_ids=hand_joint_ids) + print(f"Opening hand") + + step_count += 1 + + except KeyboardInterrupt: + print("Stopping simulation...") + finally: + print("Cleaning up...") + sim.destroy() + + +if __name__ == "__main__": + main() diff --git a/scripts/tutorials/sim/create_scene.py b/scripts/tutorials/sim/create_scene.py new file mode 100644 index 00000000..3f1082e6 --- /dev/null +++ b/scripts/tutorials/sim/create_scene.py @@ -0,0 +1,149 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +""" +This script demonstrates how to create a simulation scene using SimulationManager. +It shows the basic setup of simulation context, adding objects, and sensors. +""" + +import argparse +import time + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import RigidBodyAttributesCfg +from embodichain.lab.sim.shapes import CubeCfg +from embodichain.lab.sim.objects import RigidObject, RigidObjectCfg + + +def main(): + """Main function to create and run the simulation scene.""" + + # Parse command line arguments + parser = argparse.ArgumentParser( + description="Create a simulation scene with SimulationManager" + ) + parser.add_argument( + "--headless", + action="store_true", + default=False, + help="Run simulation in headless mode", + ) + parser.add_argument( + "--num_envs", type=int, default=1, help="Number of parallel environments" + ) + parser.add_argument( + "--device", type=str, default="cpu", help="Simulation device (cuda or cpu)" + ) + parser.add_argument( + "--enable_rt", + action="store_true", + default=False, + help="Enable ray tracing for better visuals", + ) + args = parser.parse_args() + + # Configure the simulation + sim_cfg = SimulationManagerCfg( + width=1920, + height=1080, + headless=True, + physics_dt=1.0 / 100.0, # Physics timestep (100 Hz) + sim_device=args.device, + enable_rt=args.enable_rt, # Enable ray tracing for better visuals + ) + + # Create the simulation instance + sim = SimulationManager(sim_cfg) + + # Enable manual physics update for precise control + sim.set_manual_update(True) + + # Build multiple arenas if requested + if args.num_envs > 1: + sim.build_multiple_arenas(args.num_envs, space=3.0) + + # Add objects to the scene + cube: RigidObject = sim.add_rigid_object( + cfg=RigidObjectCfg( + uid="cube", + shape=CubeCfg(size=[0.1, 0.1, 0.1]), + body_type="dynamic", + attrs=RigidBodyAttributesCfg( + mass=1.0, + dynamic_friction=0.5, + static_friction=0.5, + restitution=0.1, + ), + init_pos=[0.0, 0.0, 1.0], + ) + ) + + print("[INFO]: Scene setup complete!") + print(f"[INFO]: Running simulation with {args.num_envs} environment(s)") + print("[INFO]: Press Ctrl+C to stop the simulation") + + # Open window when the scene has been set up + if not args.headless: + sim.open_window() + + # Run the simulation + run_simulation(sim) + + +def run_simulation(sim: SimulationManager): + """Run the simulation loop. + + Args: + sim: The SimulationManager instance to run + """ + + # Initialize GPU physics if using CUDA + if sim.is_use_gpu_physics: + sim.init_gpu_physics() + + step_count = 0 + + try: + last_time = time.time() + last_step = 0 + while True: + # Update physics simulation + sim.update(step=1) + step_count += 1 + + # Print FPS every second + if step_count % 100 == 0: + current_time = time.time() + elapsed = current_time - last_time + fps = ( + sim.num_envs * (step_count - last_step) / elapsed + if elapsed > 0 + else 0 + ) + print(f"[INFO]: Simulation step: {step_count}, FPS: {fps:.2f}") + last_time = current_time + last_step = step_count + + except KeyboardInterrupt: + print("\n[INFO]: Stopping simulation...") + finally: + # Clean up resources + sim.destroy() + print("[INFO]: Simulation terminated successfully") + + +if __name__ == "__main__": + main() diff --git a/scripts/tutorials/sim/create_sensor.py b/scripts/tutorials/sim/create_sensor.py new file mode 100644 index 00000000..380852a5 --- /dev/null +++ b/scripts/tutorials/sim/create_sensor.py @@ -0,0 +1,346 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +""" +This script demonstrates how to create and simulate a camera sensor attached to a robot using SimulationManager. +It shows how to configure a camera sensor, attach it to the robot's end-effector, and visualize the sensor's output during simulation. +""" + +import argparse +import cv2 +import numpy as np +import time +import torch + +torch.set_printoptions(precision=4, sci_mode=False) + +from scipy.spatial.transform import Rotation as R + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.sensors import Camera, CameraCfg +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim.cfg import ( + JointDrivePropertiesCfg, + RobotCfg, + URDFCfg, + RigidObjectCfg, +) +from embodichain.lab.sim.shapes import CubeCfg +from embodichain.data import get_data_path + + +def mask_to_color_map(mask, user_ids, fix_seed=True): + """ + Convert instance mask into color map. + :param mask: Instance mask map. + :param user_ids: List of unique user IDs in the mask. + :return: Color map. + """ + # Create a blank RGB image + color_map = np.zeros((mask.shape[0], mask.shape[1], 3), dtype=np.uint8) + + # Generate deterministic colors based on user_id values + colors = [] + for user_id in user_ids: + # Use the user_id as seed to generate deterministic color + np.random.seed(user_id) + color = np.random.choice(range(256), size=3) + colors.append(color) + + for idx, color in enumerate(colors): + # Assign color to the instances of each class + color_map[mask == user_ids[idx]] = color + + return color_map + + +def main(): + """Main function to demonstrate robot sensor simulation.""" + + # Parse command line arguments + parser = argparse.ArgumentParser( + description="Create and simulate a robot in SimulationManager" + ) + parser.add_argument( + "--num_envs", type=int, default=1, help="Number of environments to simulate" + ) + parser.add_argument( + "--device", + type=str, + default="cpu", + choices=["cpu", "cuda"], + help="Device to run simulation on", + ) + parser.add_argument("--headless", action="store_true", help="Run in headless mode") + parser.add_argument( + "--enable_rt", action="store_true", help="Enable ray tracing rendering" + ) + parser.add_argument( + "--attach_sensor", + action="store_true", + help="Attach sensor to robot end-effector", + ) + args = parser.parse_args() + + # Initialize simulation + print("Creating simulation...") + config = SimulationManagerCfg( + headless=True, + sim_device=args.device, + arena_space=3.0, + enable_rt=args.enable_rt, + physics_dt=1.0 / 100.0, + ) + sim = SimulationManager(config) + + # Build multiple environments if requested + if args.num_envs > 1: + sim.build_multiple_arenas(args.num_envs) + + # Set manual physics update for precise control + sim.set_manual_update(True) + + # Create robot configuration + robot = create_robot(sim) + + sensor = create_sensor(sim, args) + + # Add a cube to the scene + cube_cfg = RigidObjectCfg( + uid="cube", + shape=CubeCfg(size=[0.05, 0.05, 0.05]), # Use CubeCfg for a cube + init_pos=[1.2, -0.2, 0.1], + init_rot=[0, 0, 0], + ) + sim.add_rigid_object(cfg=cube_cfg) + + # Initialize GPU physics if using CUDA + if sim.is_use_gpu_physics: + sim.init_gpu_physics() + + # Open visualization window if not headless + if not args.headless: + sim.open_window() + + # Run simulation loop + run_simulation(sim, robot, sensor) + + +def create_sensor(sim: SimulationManager, args): + # intrinsics params + intrinsics = (600, 600, 320.0, 240.0) + width = 640 + height = 480 + + # extrinsics params + pos = [0.09, 0.05, 0.04] + quat = R.from_euler("xyz", [-35, 135, 0], degrees=True).as_quat().tolist() + + # If attach_sensor is True, attach to robot end-effector; otherwise, place it in the scene + if args.attach_sensor: + parent = "ee_link" + else: + parent = None + pos = [1.2, -0.2, 1.5] + quat = R.from_euler("xyz", [0, 180, 0], degrees=True).as_quat().tolist() + quat = [quat[3], quat[0], quat[1], quat[2]] # Convert to (w, x, y, z) + + # create camera sensor and attach to robot end-effector + camera: Camera = sim.add_sensor( + sensor_cfg=CameraCfg( + width=width, + height=height, + intrinsics=intrinsics, + extrinsics=CameraCfg.ExtrinsicsCfg( + parent=parent, + pos=pos, + quat=quat, + ), + near=0.01, + far=10.0, + enable_color=True, + enable_depth=True, + enable_mask=True, + enable_normal=True, + ) + ) + return camera + + +def create_robot(sim): + """Create and configure a robot in the simulation.""" + + print("Loading robot...") + + # Get SR5 URDF path + sr5_urdf_path = get_data_path("Rokae/SR5/SR5.urdf") + + # Get hand URDF path + hand_urdf_path = get_data_path( + "BrainCoHandRevo1/BrainCoLeftHand/BrainCoLeftHand.urdf" + ) + + # Define control parts for the robot + # Joint names in control_parts can be regex patterns + CONTROL_PARTS = { + "arm": [ + "JOINT[1-6]", # Matches JOINT1, JOINT2, ..., JOINT6 + ], + "hand": ["LEFT_.*"], # Matches all joints starting with L_ + } + + # Define transformation for hand attachment + hand_attach_xpos = np.eye(4) + hand_attach_xpos[:3, :3] = R.from_rotvec([90, 0, 0], degrees=True).as_matrix() + hand_attach_xpos[2, 3] = 0.02 + + cfg = RobotCfg( + uid="sr5_with_brainco", + urdf_cfg=URDFCfg( + components=[ + { + "component_type": "arm", + "urdf_path": sr5_urdf_path, + }, + { + "component_type": "hand", + "urdf_path": hand_urdf_path, + "transform": hand_attach_xpos, + }, + ] + ), + control_parts=CONTROL_PARTS, + drive_pros=JointDrivePropertiesCfg( + stiffness={"JOINT[1-6]": 1e4, "LEFT_.*": 1e3}, + damping={"JOINT[1-6]": 1e3, "LEFT_.*": 1e2}, + ), + ) + + # Add robot to simulation + robot: Robot = sim.add_robot(cfg=cfg) + + print(f"Robot created successfully with {robot.dof} joints") + + return robot + + +def get_sensor_image(camera: Camera, headless=False, step_count=0): + """ + Get color, depth, mask, and normals views from the camera, + and visualize them in a 2x2 grid (or save if headless). + """ + import matplotlib.pyplot as plt + + camera.update() + data = camera.get_data() + # Get four views + rgba = data["color"].cpu().numpy()[0, :, :, :3] # (H, W, 3) + depth = data["depth"].squeeze_().cpu().numpy() # (H, W) + mask = data["mask"].squeeze_().cpu().numpy() # (H, W) + normals = data["normal"].cpu().numpy()[0] # (H, W, 3) + + # Normalize for visualization + depth_vis = (depth - depth.min()) / (depth.ptp() + 1e-8) + depth_vis = (depth_vis * 255).astype("uint8") + mask_vis = mask_to_color_map(mask, user_ids=np.unique(mask)) + normals_vis = ((normals + 1) / 2 * 255).astype("uint8") + + # Prepare titles and images for display + titles = ["Color", "Depth", "Mask", "Normals"] + images = [ + cv2.cvtColor(rgba, cv2.COLOR_RGB2BGR), + cv2.cvtColor(depth_vis, cv2.COLOR_GRAY2BGR), + mask_vis, + cv2.cvtColor(normals_vis, cv2.COLOR_RGB2BGR), + ] + + if not headless: + # Concatenate images for 2x2 grid display using OpenCV + top = np.hstack([images[0], images[1]]) + bottom = np.hstack([images[2], images[3]]) + grid = np.vstack([top, bottom]) + cv2.imshow("Sensor Views (Color / Depth / Mask / Normals)", grid) + cv2.waitKey(1) + else: + # Save the 2x2 grid as an image using matplotlib + fig, axs = plt.subplots(2, 2, figsize=(10, 8)) + for ax, img, title in zip(axs.flatten(), images, titles): + ax.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) + ax.set_title(title) + ax.axis("off") + plt.tight_layout() + plt.savefig(f"sensor_views_{step_count}.png") + plt.close(fig) + + +def run_simulation(sim: SimulationManager, robot: Robot, camera: Camera): + """Run the simulation loop with robot and camera sensor control.""" + + print("Starting simulation...") + print("Robot will move through different poses") + print("Press Ctrl+C to stop") + + step_count = 0 + + arm_joint_ids = robot.get_joint_ids("arm") + # Define some target joint positions for demonstration + + arm_position1 = ( + torch.tensor( + [0.0, 0.5, -1.5, 0.3, -0.5, 0], dtype=torch.float32, device=sim.device + ) + .unsqueeze_(0) + .repeat(sim.num_envs, 1) + ) + + arm_position2 = ( + torch.tensor( + [0.0, 0.5, -1.5, -0.3, -0.5, 0], dtype=torch.float32, device=sim.device + ) + .unsqueeze_(0) + .repeat(sim.num_envs, 1) + ) + + try: + while True: + # Update physics + sim.update(step=1) + + if step_count % 1001 == 0: + robot.set_qpos(qpos=arm_position1, joint_ids=arm_joint_ids) + print(f"Moving to arm position 1") + + # Refresh and get image from sensor + get_sensor_image(camera) + + if step_count % 2003 == 0: + robot.set_qpos(qpos=arm_position2, joint_ids=arm_joint_ids) + print(f"Moving to arm position 2") + + # Refresh and get image from sensor + get_sensor_image(camera) + + step_count += 1 + + except KeyboardInterrupt: + print("Stopping simulation...") + finally: + print("Cleaning up...") + sim.destroy() + + +if __name__ == "__main__": + main() diff --git a/scripts/tutorials/sim/create_softbody.py b/scripts/tutorials/sim/create_softbody.py new file mode 100644 index 00000000..af6b5cc8 --- /dev/null +++ b/scripts/tutorials/sim/create_softbody.py @@ -0,0 +1,161 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +""" +This script demonstrates how to create a simulation scene using SimulationManager. +It shows the basic setup of simulation context, adding objects, lighting, and sensors. +""" + +import argparse +import time +from dexsim.utility.path import get_resources_data_path +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import ( + SoftbodyVoxelAttributesCfg, + SoftbodyPhysicalAttributesCfg, +) +from embodichain.lab.sim.shapes import MeshCfg +from embodichain.lab.sim.objects import ( + SoftObject, + SoftObjectCfg, +) + + +def main(): + """Main function to create and run the simulation scene.""" + + # Parse command line arguments + parser = argparse.ArgumentParser( + description="Create a simulation scene with SimulationManager" + ) + parser.add_argument( + "--headless", + action="store_true", + default=False, + help="Run simulation in headless mode", + ) + parser.add_argument( + "--num_envs", type=int, default=4, help="Number of parallel environments" + ) + parser.add_argument( + "--enable_rt", + action="store_true", + default=False, + help="Enable ray tracing for better visuals", + ) + args = parser.parse_args() + + # Configure the simulation + sim_cfg = SimulationManagerCfg( + width=1920, + height=1080, + headless=True, + physics_dt=1.0 / 100.0, # Physics timestep (100 Hz) + sim_device="cuda", # soft simulation only supports cuda device + enable_rt=args.enable_rt, # Enable ray tracing for better visuals + ) + + # Create the simulation instance + sim = SimulationManager(sim_cfg) + + # Enable manual physics update for precise control + sim.set_manual_update(True) + + # Build multiple arenas if requested + if args.num_envs > 1: + sim.build_multiple_arenas(args.num_envs, space=3.0) + print("[INFO]: Scene setup complete!") + + # add softbody to the scene + cow: SoftObject = sim.add_soft_object( + cfg=SoftObjectCfg( + uid="cow", + shape=MeshCfg( + fpath=get_resources_data_path("Model", "cow", "cow.obj"), + ), + init_pos=[0.0, 0.0, 3.0], + voxel_attr=SoftbodyVoxelAttributesCfg( + simulation_mesh_resolution=8, + maximal_edge_length=0.5, + ), + physical_attr=SoftbodyPhysicalAttributesCfg( + youngs=1e6, + poissons=0.45, + density=100, + dynamic_friction=0.1, + min_position_iters=30, + ), + ), + ) + print("[INFO]: Add soft object complete!") + + # Open window when the scene has been set up + if not args.headless: + sim.open_window() + + print(f"[INFO]: Running simulation with {args.num_envs} environment(s)") + print("[INFO]: Press Ctrl+C to stop the simulation") + + # Run the simulation + run_simulation(sim, cow) + + +def run_simulation(sim: SimulationManager, soft_obj: SoftObject) -> None: + """Run the simulation loop. + + Args: + sim: The SimulationManager instance to run + soft_obj: soft object + """ + + # Initialize GPU physics + sim.init_gpu_physics() + + step_count = 0 + + try: + last_time = time.time() + last_step = 0 + while True: + # Update physics simulation + sim.update(step=1) + step_count += 1 + + # Print FPS every second + if step_count % 100 == 0: + current_time = time.time() + elapsed = current_time - last_time + fps = ( + sim.num_envs * (step_count - last_step) / elapsed + if elapsed > 0 + else 0 + ) + print(f"[INFO]: Simulation step: {step_count}, FPS: {fps:.2f}") + last_time = current_time + last_step = step_count + if step_count % 500 == 0: + soft_obj.reset() + + except KeyboardInterrupt: + print("\n[INFO]: Stopping simulation...") + finally: + # Clean up resources + sim.destroy() + print("[INFO]: Simulation terminated successfully") + + +if __name__ == "__main__": + main() diff --git a/scripts/tutorials/sim/gizmo_robot.py b/scripts/tutorials/sim/gizmo_robot.py new file mode 100644 index 00000000..fae79962 --- /dev/null +++ b/scripts/tutorials/sim/gizmo_robot.py @@ -0,0 +1,158 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +""" +Gizmo-Robot Example: Test Gizmo class on a robot (UR10) +""" + +import time +import torch +import numpy as np +import argparse + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import ( + RobotCfg, + URDFCfg, + JointDrivePropertiesCfg, +) + +from embodichain.lab.sim.solvers import PinkSolverCfg +from embodichain.data import get_data_path +from embodichain.utils import logger + + +def main(): + """Main function to create and run the simulation scene.""" + + # Parse command line arguments + parser = argparse.ArgumentParser( + description="Create a simulation scene with SimulationManager" + ) + parser.add_argument( + "--num_envs", type=int, default=1, help="Number of parallel environments" + ) + parser.add_argument( + "--device", type=str, default="cpu", help="Simulation device (cuda or cpu)" + ) + parser.add_argument( + "--enable_rt", + action="store_true", + default=False, + help="Enable ray tracing for better visuals", + ) + args = parser.parse_args() + + # Configure the simulation + sim_cfg = SimulationManagerCfg( + width=1920, + height=1080, + physics_dt=1.0 / 100.0, + sim_device=args.device, + enable_rt=args.enable_rt, + ) + + sim = SimulationManager(sim_cfg) + sim.set_manual_update(False) + + # Build multiple arenas if requested + if args.num_envs > 1: + sim.build_multiple_arenas(args.num_envs, space=3.0) + + # Get UR10 URDF path + urdf_path = get_data_path("UniversalRobots/UR10/UR10.urdf") + + # Create UR10 robot + robot_cfg = RobotCfg( + uid="ur10_gizmo_test", + urdf_cfg=URDFCfg( + components=[{"component_type": "arm", "urdf_path": urdf_path}] + ), + control_parts={"arm": ["Joint[1-6]"]}, + solver_cfg={ + "arm": PinkSolverCfg( + urdf_path=urdf_path, + end_link_name="ee_link", + root_link_name="base_link", + pos_eps=1e-2, + rot_eps=5e-2, + max_iterations=300, + dt=0.1, + ) + }, + drive_pros=JointDrivePropertiesCfg( + stiffness={"Joint[1-6]": 1e4}, + damping={"Joint[1-6]": 1e3}, + ), + ) + robot = sim.add_robot(cfg=robot_cfg) + + # Set initial joint positions + initial_qpos = torch.tensor( + [[0, -np.pi / 2, np.pi / 2, 0.0, np.pi / 2, 0.0]], + dtype=torch.float32, + device="cpu", + ) + joint_ids = robot.get_joint_ids("arm") + robot.set_qpos(qpos=initial_qpos, joint_ids=joint_ids) + + time.sleep(0.2) # Wait for a moment to ensure everything is set up + + # Enable gizmo using the new API + sim.enable_gizmo(uid="ur10_gizmo_test", control_part="arm") + if not sim.has_gizmo("ur10_gizmo_test", control_part="arm"): + logger.log_error("Failed to enable gizmo!") + return + + sim.open_window() + + logger.log_info("Gizmo-Robot example started!") + logger.log_info("Use the gizmo to drag the robot end-effector (EE)") + logger.log_info("Press Ctrl+C to stop the simulation") + + run_simulation(sim) + + +def run_simulation(sim: SimulationManager): + step_count = 0 + try: + last_time = time.time() + last_step = 0 + while True: + time.sleep(0.033) # 30Hz + # Update all gizmos managed by sim + sim.update_gizmos() + step_count += 1 + + if step_count % 100 == 0: + current_time = time.time() + elapsed = current_time - last_time + fps = ( + sim.num_envs * (step_count - last_step) / elapsed + if elapsed > 0 + else 0 + ) + logger.log_info(f"Simulation step: {step_count}, FPS: {fps:.2f}") + last_time = current_time + last_step = step_count + except KeyboardInterrupt: + logger.log_info("\nStopping simulation...") + finally: + sim.destroy() + logger.log_info("Simulation terminated successfully") + + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..ae041d57 --- /dev/null +++ b/setup.py @@ -0,0 +1,123 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import glob +import logging +import os +import shutil +import sys +from os import path as osp +from pathlib import Path + +from setuptools import Command, find_packages, setup + +logging.basicConfig(stream=sys.stderr, level=logging.INFO) +logger = logging.getLogger() + +THIS_DIR = Path(__file__).resolve().parent + +# Defer importing torch until it's actually needed (when building extensions). +# This prevents `setup.py` from failing at import time in environments where +# torch isn't available or isn't on the same interpreter. +BuildExtension = None +CppExtension = None +CUDAExtension = None + + +class CleanCommand(Command): + description = "Delete build, dist, *.egg-info and all __pycache__ directories." + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + for d in ["build", "dist", "embodichain.egg-info"]: + rm_path = THIS_DIR / d + if not rm_path.exists(): + continue + try: + shutil.rmtree(rm_path, ignore_errors=True) + logger.info(f"removed '{rm_path}'") + except: + pass + + for pdir, sdirs, filenames in os.walk(THIS_DIR): + for sdir in sdirs: + if sdir == "__pycache__": + rm_path = Path(pdir) / sdir + shutil.rmtree(str(rm_path), ignore_errors=True) + logger.info(f"removed '{rm_path}'") + for filename in filenames: + if filename.endswith(".so"): + rm_path = Path(pdir) / filename + rm_path.unlink() + logger.info(f"removed '{rm_path}'") + + +def get_data_files_of_a_directory(source_dir, target_dir=None, ignore_py=False): + if target_dir is None: + target_dir = source_dir + + base_dir = os.sep + "embodichain" + os.sep + + filelist = [] + for parent_dir, dirnames, filenames in os.walk(source_dir): + for filename in filenames: + if ignore_py and filename.endswith(".py"): + continue + filelist.append( + ( + os.path.join( + base_dir, parent_dir.replace(source_dir, target_dir, 1) + ), + [os.path.join(parent_dir, filename)], + ) + ) + + return filelist + + +# Extract version +here = osp.abspath(osp.dirname(__file__)) +version = None +with open(os.path.join(os.path.dirname(__file__), "VERSION")) as f: + full_version = f.read().strip() + version = ".".join(full_version.split(".")[:3]) + +ignore_py = sys.argv[1] == "bdist_nuitka" if len(sys.argv) > 1 else False +data_files = [] +data_files += get_data_files_of_a_directory("embodichain", ignore_py=ignore_py) + +cmdclass = {"clean": CleanCommand} +if BuildExtension is not None: + cmdclass["build_ext"] = BuildExtension.with_options(no_python_abi_suffix=True) + +setup( + name="embodichain", + version=version, + url="https://github.com/DexForce/EmbodiChain", + author="EmbodiChain Developers", + description="An end-to-end, GPU-accelerated, and modular platform for building generalized Embodied Intelligence.", + packages=find_packages(exclude=["docs"]), + data_files=data_files, + entry_points={}, + cmdclass=cmdclass, + include_package_data=True, +) diff --git a/tests/common.py b/tests/common.py new file mode 100644 index 00000000..9d80e5c6 --- /dev/null +++ b/tests/common.py @@ -0,0 +1,63 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +from unittest import TestLoader +from fnmatch import fnmatchcase + + +__all__ = ["UnittestMetaclass", "OrderedTestLoader"] + + +# to learn about the usage of metaclass here: https://www.liaoxuefeng.com/wiki/1016959663602400/1017592449371072 +class UnittestMetaclass(type): + def __new__(cls, name, bases, attrs): + # add 'attrs_by_writing_order' attribute containing writing order of all attributes and functions + attrs["attrs_by_writing_order"] = list(attrs.keys()) + return super().__new__(cls, name, bases, attrs) + + +# By default, TestLoader runs tests in alphabetical order. However, some tests +# need to be executed in the order they are written. This custom loader overrides +# the default sorting behavior to run tests sequentially based on the writing order. +# Note that when both errors and failures occur, errors will be logged first, +# which may differ from the execution order. This is acceptable as it prioritizes +# highlighting errors. +class OrderedTestLoader(TestLoader): + """This TestLoader will load testFnNames in the code writing order""" + + # copied from getTestCaseNames() of TestLoader and make some modification + def getTestCaseNames(self, testCaseClass): + """Return a sorted sequence of method names found within testCaseClass""" + + def shouldIncludeMethod(attrname): + if not attrname.startswith(self.testMethodPrefix): + return False + testFunc = getattr(testCaseClass, attrname) + if not callable(testFunc): + return False + fullName = f"%s.%s.%s" % ( + testCaseClass.__module__, + testCaseClass.__qualname__, + attrname, + ) + return self.testNamePatterns is None or any( + fnmatchcase(fullName, pattern) for pattern in self.testNamePatterns + ) + + testFnNames = list( + filter(shouldIncludeMethod, testCaseClass.attrs_by_writing_order) + ) + + return testFnNames diff --git a/tests/datasets/run_pourwater_env_offline.py b/tests/datasets/run_pourwater_env_offline.py new file mode 100644 index 00000000..80da0d4e --- /dev/null +++ b/tests/datasets/run_pourwater_env_offline.py @@ -0,0 +1,107 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import unittest +import sys +from pathlib import Path + +sys.path.append(str(Path(__file__).parent.parent)) +from common import UnittestMetaclass, OrderedTestLoader + +import os +import tempfile +import gymnasium +from pathlib import Path + +from embodichain.utils.utility import dict2args +from embodichain.utils.utility import load_json +from embodichain.lab.sim import SimulationManagerCfg +from embodichain.lab.gym.envs import EmbodiedEnvCfg +from embodichain.lab.gym.utils.gym_utils import config_to_cfg + +os.environ["HDF5_USE_FILE_LOCKING"] = "FALSE" + + +class TestPourWaterv3OfflineRunEnv(unittest.TestCase, metaclass=UnittestMetaclass): + datacenter_backup = Path("/tmp/datacenter_test") + + def setUp(self) -> None: + pass + + def tearDown(self) -> None: + pass + + def test_offline_run_env(self): + from embodichain.lab.scripts.run_env import main + import os + + with tempfile.TemporaryDirectory(prefix=self.__class__.__name__) as temp_dir: + gym_conf_path = os.path.join( + "configs", + "gym", + "pour_water", + "gym_config.json", + ) + action_conf_path = os.path.join( + "configs", + "gym", + "pour_water", + "action_config.json", + ) + input_dict = { + "num_envs": 1, # TODO: change it to >1 as v3 supports it. but now CobotMagic use cpu-OPWSolver. Wait @Chenjian for gpu version. + "device": "cpu", # TODO: test both cpu and cuda device + "headless": True, + "enable_rt": False, + "gpu_id": 0, + "save_video": False, + "save_path": temp_dir, + "debug_mode": False, + "filter_visual_rand": False, + "online_config": "", + "gym_config": gym_conf_path, + "action_config": action_conf_path, + } + args = dict2args(input_dict) + gym_config = load_json(args.gym_config) + gym_config["env"]["dataset"]["save_path"] = temp_dir + gym_config["max_episodes"] = 1 + + cfg: EmbodiedEnvCfg = config_to_cfg(gym_config) + cfg.filter_visual_rand = args.filter_visual_rand + + action_config = {} + if args.action_config is not None: + action_config = load_json(args.action_config) + action_config["action_config"] = action_config + + cfg.num_envs = args.num_envs + cfg.sim_cfg = SimulationManagerCfg( + headless=args.headless, + sim_device=args.device, + enable_rt=args.enable_rt, + gpu_id=args.gpu_id, + ) + + env = gymnasium.make(id=gym_config["id"], cfg=cfg, **action_config) + main(args, env, gym_config) + + +if __name__ == "__main__": + # `unittest.main()` is the standard usage to start testing, here we use a customed + # TestLoader to keep executing order of functions the same as their writing order + + unittest.main(testLoader=OrderedTestLoader()) diff --git a/tests/datasets/test_configurable_action.py b/tests/datasets/test_configurable_action.py new file mode 100644 index 00000000..16593ca0 --- /dev/null +++ b/tests/datasets/test_configurable_action.py @@ -0,0 +1,246 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from embodichain.lab.gym.envs.action_bank.configurable_action import ( + ActionBank, + tag_node, + tag_edge, + get_func_tag, +) +import numpy as np +import os +from typing import Dict, Tuple, Union, List, Callable +import unittest +from embodichain.utils.utility import load_json +import inspect + +import sys +from pathlib import Path + +sys.path.append(str(Path(__file__).parent.parent)) +from common import UnittestMetaclass, OrderedTestLoader + + +class FakePourwaterEnv: + def __init__(self) -> None: + pass + + +class FakePourwaterActionBank(ActionBank): + @staticmethod + @tag_node + def A(env: FakePourwaterEnv): + env.A = "A" + return True + + @staticmethod + @tag_node + def B(env: FakePourwaterEnv): + env.B = env.A + return True + + @staticmethod + @tag_node + def C(env: FakePourwaterEnv): + return True + + @staticmethod + @tag_node + def D(env: FakePourwaterEnv): + return True + + @staticmethod + @tag_node + def a(env: FakePourwaterEnv): + return True + + @staticmethod + @tag_node + def b(env: FakePourwaterEnv): + return True + + @staticmethod + @tag_node + def aa(env: FakePourwaterEnv): + return True + + @staticmethod + @tag_node + def bb(env: FakePourwaterEnv): + return True + + @staticmethod + @tag_node + def cc(env: FakePourwaterEnv): + return True + + @staticmethod + @tag_node + def dd(env: FakePourwaterEnv): + return True + + @staticmethod + @tag_edge + def init_to_pre1(env: FakePourwaterEnv, **kwargs): + return np.random.rand(6, 1) + + @staticmethod + @tag_edge + def grasp_to_move(env: FakePourwaterEnv, **kwargs): + return np.random.rand(6, 2) + + @staticmethod + @tag_edge + def move_to_rotation(env: FakePourwaterEnv, **kwargs): + env.move_to_rotation = np.random.rand(6, 3) + return env.move_to_rotation + + @staticmethod + @tag_edge + def rotation_back_to_move(env: FakePourwaterEnv, **kwargs): + return np.random.rand(6, 4) + + @staticmethod + @tag_edge + def init_to_monitor(env: FakePourwaterEnv, **kwargs): + return np.random.rand(6, 1) + + @staticmethod + @tag_edge + def left_arm_go_back(env: FakePourwaterEnv, **kwargs): + return np.random.rand(6, 2) + + @staticmethod + @tag_edge + def lopen(env: FakePourwaterEnv, **kwargs): + return np.random.rand(1, 10) + + @staticmethod + @tag_edge + def ropen(env: FakePourwaterEnv, **kwargs) -> np.ndarray: + return np.random.rand(1, 10) + + +class TestActionBank(unittest.TestCase, metaclass=UnittestMetaclass): + def setUp(self) -> None: + pass + + def tearDown(self) -> None: + pass + + def test_simple(self): + class FakeFunctions: + def __init__( + self, + ) -> None: + self.dummy_function = lambda: 1 + + def get_functions(self, names: List[str]) -> Dict[str, Callable]: + """ + Returns a dictionary of dummy functions for the given names. + """ + return {name: self.dummy_function for name in names} + + funcs = FakeFunctions() + conf = load_json(os.path.join("configs", "gym", "action_bank", "conf.json")) + action_bank = ActionBank(conf) + action_bank.parse_network( + funcs.get_functions( + ["A", "B", "C", "D", "a", "b", "aa", "bb", "cc", "dd"], + ), + funcs.get_functions( + [ + "init_to_pre1", + "grasp_to_move", + "move_to_rotation", + "rotation_back_to_move", + "move_back_to_grasp", + "grasp_back_to_pre1", + "init_to_monitor", + "left_arm_go_back", + "lopen", + "ropen", + ], + ), + vis_graph=False, + ) + + def test_hook_and_gantt(self): + conf = load_json(os.path.join("configs", "gym", "action_bank", "conf.json")) + action_bank = FakePourwaterActionBank(conf) + print(get_func_tag("node").functions[action_bank.__class__.__name__]) + _, jobs_data, jobkey2index = action_bank.parse_network( + get_func_tag("node").functions[action_bank.__class__.__name__], + get_func_tag("edge").functions[action_bank.__class__.__name__], + vis_graph=False, + ) + + action_bank.gantt(jobs_data, jobkey2index, vis=False) + + def test_create_action_list(self): + np.random.seed(0) + conf = load_json(os.path.join("configs", "gym", "action_bank", "conf.json")) + action_bank = FakePourwaterActionBank(conf) + graph_compose, jobs_data, jobkey2index = action_bank.parse_network( + get_func_tag("node").functions[action_bank.__class__.__name__], + get_func_tag("edge").functions[action_bank.__class__.__name__], + vis_graph=False, + ) + env = FakePourwaterEnv() + packages = action_bank.gantt(jobs_data, jobkey2index, vis=False) + ret = action_bank.create_action_list(env, graph_compose, packages) + + assert ( + np.linalg.norm(ret["left_arm"][:, 3:10] - ret["left_arm"][:, 3:4]) <= 1e-6 + ) # padding. + assert ( + np.linalg.norm(ret["right_arm"][:, 3:6] - env.move_to_rotation) <= 1e-6 + ) # rotation_back_to_move + + def test_bad_conf(self): + np.random.seed(0) + conf = load_json(os.path.join("configs", "gym", "action_bank", "conf.json")) + conf["node"]["right_arm"] = [ + { + "init_to_pre1": { + "src": "home_qpos", + "sink": "bottle_pre1_pose", + "duration": 1, + "kwargs": {}, + }, + "grasp_to_move": { + "src": "bottle_pre1_pose", + "sink": "bottle_grasp", + "duration": 2, + "kwargs": {}, + }, + } + ] + action_bank = FakePourwaterActionBank(conf) + self.assertRaises( + ValueError, + action_bank.parse_network, + get_func_tag("node").functions[action_bank.__class__.__name__], + get_func_tag("edge").functions[action_bank.__class__.__name__], + vis_graph=False, + ) + + +if __name__ == "__main__": + # `unittest.main()` is the standard usage to start testing, here we use a customed + # TestLoader to keep executing order of functions the same as their writing order + + unittest.main(testLoader=OrderedTestLoader()) diff --git a/tests/datasets/test_online_training.py b/tests/datasets/test_online_training.py new file mode 100644 index 00000000..1e05daa4 --- /dev/null +++ b/tests/datasets/test_online_training.py @@ -0,0 +1,102 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import unittest +import sys +from pathlib import Path + +sys.path.append(str(Path(__file__).parent.parent)) +from common import UnittestMetaclass, OrderedTestLoader +from embodichain.data.data_engine.online.engine import OnlineEngine +import numpy as np +from tqdm import tqdm +import time + + +class TestDataDictExtractor(unittest.TestCase, metaclass=UnittestMetaclass): + datacenter_backup = Path("/tmp/datacenter_test") + base_url = "http://192.168.3.120/MixedAI/" + + def setUp(self) -> None: + pass + + def tearDown(self) -> None: + pass + + def test_online_generation( + self, + ): + from embodichain.utils.logger import log_warning + from embodichain.data.data_engine.online.online_generator import ( + OnlineGenerator, + ) + + log_warning("Start online data generation.") + + online_config = { + "episode_limit": 4, + "max_sample_num": 100, + "port": 5566, + "buffer_size": 4, + "max_limit_gb": 5, + } + online_callback = OnlineGenerator(**online_config) + generator_func = lambda **kwargs: [{"data": np.random.randn(1000, 1000)}] + online_callback.generator(generator_func, loop_times=2) + online_callback.empty_memory() + + def test_sample_data(self): + + from embodichain.utils.logger import log_warning + import threading + from embodichain.data.data_engine.online.online_generator import ( + OnlineGenerator, + ) + + log_warning("Start online data generation.") + + online_config = { + "episode_limit": 4, + "max_sample_num": 100, + "port": 7788, + "buffer_size": 4, + "max_limit_gb": 5, + } + online_callback = OnlineGenerator(**online_config) + data_o = np.random.randn(1000, 1000) + generator_func = lambda **kwargs: [{"data": data_o}] + + thread = threading.Thread( + target=online_callback.generator, + kwargs={"generate_func": generator_func, "loop_times": 2}, + daemon=True, + ) + thread.start() + time.sleep(1.0) + + callback = OnlineEngine(**online_config) + callback.start() + time.sleep(1.0) + for i in tqdm(range(5)): + data = callback.sample_data() + assert data.sum() == data_o.sum() + + +if __name__ == "__main__": + # `unittest.main()` is the standard usage to start testing, here we use a customed + # TestLoader to keep executing order of functions the same as their writing order + + unittest.main(testLoader=OrderedTestLoader()) diff --git a/tests/gym/envs/test_base_env.py b/tests/gym/envs/test_base_env.py new file mode 100644 index 00000000..beab6a89 --- /dev/null +++ b/tests/gym/envs/test_base_env.py @@ -0,0 +1,182 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import torch +import pytest +import numpy as np +import gymnasium as gym + +from embodichain.lab.gym.envs import BaseEnv, EnvCfg +from embodichain.lab.sim.objects import RigidObject, Robot +from embodichain.lab.sim.shapes import CubeCfg +from embodichain.lab.sim.cfg import ( + RobotCfg, + JointDrivePropertiesCfg, + RigidObjectCfg, + RigidBodyAttributesCfg, +) +from embodichain.lab.gym.utils.registration import register_env +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.data import get_data_path + +NUM_ENVS = 10 + + +@register_env("RandomReach-v1", max_episode_steps=100, override=True) +class RandomReachEnv(BaseEnv): + + robot_init_qpos = np.array( + [1.57079, -1.57079, 1.57079, -1.57079, -1.57079, -3.14159] + ) + + def __init__( + self, + num_envs=1, + drive_type="force", + headless=False, + device="cpu", + **kwargs, + ): + self.drive_type = drive_type + + env_cfg = EnvCfg( + sim_cfg=SimulationManagerCfg( + headless=headless, arena_space=2.0, sim_device=device + ), + num_envs=num_envs, + ) + + super().__init__( + cfg=env_cfg, + **kwargs, + ) + + def _setup_robot(self, **kwargs): + file_path = get_data_path("UniversalRobots/UR10/UR10.urdf") + + robot: Robot = self.sim.add_robot( + cfg=RobotCfg( + uid="UR10", + fpath=file_path, + init_pos=(0, 0, 1), + init_qpos=self.robot_init_qpos, + drive_pros=JointDrivePropertiesCfg(drive_type=self.drive_type), + ) + ) + + qpos_limits = robot.body_data.qpos_limits[0].cpu().numpy() + self.single_action_space = gym.spaces.Box( + low=qpos_limits[:, 0], high=qpos_limits[:, 1], dtype=np.float32 + ) + + return robot + + def _prepare_scene(self, **kwargs): + size = 0.03 + # Create a kinematic cube object without collision. + # Currently, we use this workaround for visualization purposes. + self.cube: RigidObject = self.sim.add_rigid_object( + cfg=RigidObjectCfg( + uid="cube", + shape=CubeCfg(size=[size, size, size]), + attrs=RigidBodyAttributesCfg(enable_collision=False), + init_pos=(0.0, 0.0, 0.5), + body_type="kinematic", + ), + ) + + def _update_sim_state(self, **kwargs): + pose = torch.eye(4, device=self.device) + pose = pose.unsqueeze_(0).repeat(self.num_envs, 1, 1) + pose[:, :3, 3] += torch.rand(self.num_envs, 3, device=self.device) * 0.5 - 0.25 + self.cube.set_local_pose(pose=pose) + + def _step_action(self, action): + self.robot.set_qpos(qpos=action) + return action + + def _extend_obs(self, obs, **kwargs): + obs["cube_position"] = self.cube.get_local_pose()[:, :3] + return obs + + +class BaseEnvTest: + """Shared test logic for CPU and CUDA.""" + + def setup_simulation(self, sim_device): + self.env = gym.make( + "RandomReach-v1", + num_envs=NUM_ENVS, + headless=True, + device=sim_device, + ) + + def test_env_rollout(self): + """Test environment rollout.""" + for episode in range(2): + print("Episode:", episode) + obs, info = self.env.reset() + + for i in range(2): + action = self.env.action_space.sample() + action = torch.as_tensor( + action, dtype=torch.float32, device=self.env.device + ) + + init_pose = self.env.robot_init_qpos + init_pose = ( + torch.as_tensor( + init_pose, dtype=torch.float32, device=self.env.device + ) + .unsqueeze_(0) + .repeat(self.env.num_envs, 1) + ) + action = ( + init_pose + + torch.rand_like( + action, dtype=torch.float32, device=self.env.device + ) + * 0.2 + - 0.1 + ) + + obs, reward, done, truncated, info = self.env.step(action) + + assert reward.shape == ( + self.env.num_envs, + ), f"Expected reward shape ({self.env.num_envs},), got {reward.shape}" + assert done.shape == ( + self.env.num_envs, + ), f"Expected done shape ({self.env.num_envs},), got {done.shape}" + assert truncated.shape == ( + self.env.num_envs, + ), f"Expected truncated shape ({self.env.num_envs},), got {truncated.shape}" + assert ( + obs.get("cube_position") is not None + ), "Expected 'cube_position' in the obs dict" + assert obs.get("robot") is not None, "Expected 'robot' in the obs dict" + + +class TestBaseEnvCPU(BaseEnvTest): + def setup_method(self): + self.setup_simulation("cpu") + + +@pytest.mark.skip(reason="Skipping CUDA tests temporarily") +class TestBaseEnvCUDA(BaseEnvTest): + def setup_method(self): + self.setup_simulation("cuda") diff --git a/tests/gym/envs/test_embodied_env.py b/tests/gym/envs/test_embodied_env.py new file mode 100644 index 00000000..feb4bc5b --- /dev/null +++ b/tests/gym/envs/test_embodied_env.py @@ -0,0 +1,163 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import torch +import pytest +import numpy as np +import gymnasium as gym + +from embodichain.lab.gym.envs import EmbodiedEnvCfg +from embodichain.lab.sim.objects import RigidObject, Robot +from embodichain.lab.gym.utils.gym_utils import config_to_cfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.data import get_data_path + +NUM_ENVS = 10 + +urdf_path = get_data_path("UniversalRobots/UR5/UR5.urdf") +METADATA = { + "id": "EmbodiedEnv-v1", + "max_episodes": 1, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [500000.0, 1500000.0], + }, + } + } + }, + "sensor": [ + { + "sensor_type": "Camera", + "width": 640, + "height": 480, + "enable_mask": True, + "enable_depth": True, + "extrinsics": { + "eye": [0.0, 0.0, 1.0], + "target": [0.0, 0.0, 0.0], + }, + } + ], + "robot": { + "fpath": urdf_path, + "drive_pros": {"stiffness": {"joint[1-6]": 200.0}}, + "solver_cfg": { + "class_type": "PytorchSolver", + "end_link_name": "ee_link", + "root_link_name": "base_link", + }, + "init_pos": [0.0, 0.3, 1.0], + }, + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 1000000.0, + "init_pos": [0, 0, 2], + "radius": 10.0, + } + ] + }, + "background": [ + { + "uid": "shop_table", + "shape": { + "shape_type": "Mesh", + "fpath": "ShopTableSimple/shop_table_simple.ply", + }, + "max_convex_hull_num": 2, + "attrs": {"mass": 10.0}, + "body_scale": (2, 1.6, 1), + } + ], + "rigid_object": [ + { + "uid": "paper_cup", + "shape": { + "shape_type": "Mesh", + "fpath": "PaperCup/paper_cup.ply", + }, + "body_scale": (0.75, 0.75, 1.0), + "init_pos": (0.0, 0.0, 1.0), + } + ], + "articulation": [ + { + "uid": "sliding_box_drawer", + "fpath": "SlidingBoxDrawer/SlidingBoxDrawer.urdf", + "init_pos": (0.5, 0.0, 0.5), + } + ], +} + + +class EmbodiedEnvTest: + """Shared test logic for CPU and CUDA.""" + + def setup_simulation(self, sim_device): + cfg: EmbodiedEnvCfg = config_to_cfg(METADATA) + cfg.num_envs = NUM_ENVS + cfg.sim_cfg = SimulationManagerCfg(headless=True, sim_device=sim_device) + + self.env = gym.make(id=METADATA["id"], cfg=cfg) + + def test_env_rollout(self): + """Test environment rollout.""" + for episode in range(2): + print("Episode:", episode) + obs, info = self.env.reset() + + for i in range(2): + action = self.env.action_space.sample() + action = torch.as_tensor( + action, dtype=torch.float32, device=self.env.device + ) + + obs, reward, done, truncated, info = self.env.step(action) + + assert reward.shape == ( + self.env.num_envs, + ), f"Expected reward shape ({self.env.num_envs},), got {reward.shape}" + assert done.shape == ( + self.env.num_envs, + ), f"Expected done shape ({self.env.num_envs},), got {done.shape}" + assert truncated.shape == ( + self.env.num_envs, + ), f"Expected truncated shape ({self.env.num_envs},), got {truncated.shape}" + assert obs.get("robot") is not None, "Expected 'robot' info in the info dict" + + +class TestCPU(EmbodiedEnvTest): + def setup_method(self): + self.setup_simulation("cpu") + + +@pytest.mark.skip(reason="Skipping CUDA tests temporarily") +class TestCUDA(EmbodiedEnvTest): + def setup_method(self): + self.setup_simulation("cuda") diff --git a/tests/sim/objects/test_articulation.py b/tests/sim/objects/test_articulation.py new file mode 100644 index 00000000..d233f8f9 --- /dev/null +++ b/tests/sim/objects/test_articulation.py @@ -0,0 +1,198 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +from numpy import mat +import torch +import pytest + +from embodichain.lab.sim import ( + SimulationManager, + SimulationManagerCfg, + VisualMaterialCfg, +) +from embodichain.lab.sim.objects import Articulation +from embodichain.lab.sim.cfg import ArticulationCfg +from embodichain.data import get_data_path +from dexsim.types import ActorType + +ART_PATH = "AiLiMu_BoxDrawer/AiLiMu_BoxDrawer.urdf" +NUM_ARENAS = 10 + + +class BaseArticulationTest: + """Shared test logic for CPU and CUDA.""" + + def setup_simulation(self, sim_device): + config = SimulationManagerCfg(headless=True, sim_device=sim_device) + self.sim = SimulationManager(config) + self.sim.build_multiple_arenas(NUM_ARENAS) + self.sim.set_manual_update(True) + + art_path = get_data_path(ART_PATH) + assert os.path.isfile(art_path) + + cfg_dict = {"fpath": art_path} + self.art: Articulation = self.sim.add_articulation( + cfg=ArticulationCfg.from_dict(cfg_dict) + ) + + if sim_device == "cuda" and getattr(self.sim, "is_use_gpu_physics", False): + self.sim.init_gpu_physics() + + def test_local_pose_behavior(self): + """Test set_local_pose and get_local_pose: + - Drawer pose is correctly set + """ + + # Set initial poses + pose = torch.eye(4, device=self.sim.device) + pose[2, 3] = 1.0 + pose = pose.unsqueeze(0).repeat(NUM_ARENAS, 1, 1) + + self.art.set_local_pose(pose, env_ids=None) + + # --- Check poses immediately after setting + xyz = self.art.get_local_pose()[0, :3] + + expected_pos = torch.tensor( + [0.0, 0.0, 1.0], device=self.sim.device, dtype=torch.float32 + ) + assert torch.allclose( + xyz, expected_pos, atol=1e-5 + ), f"FAIL: Drawer pose not set correctly: {xyz.tolist()}" + + def test_control_api(self): + """Test control API for setting and getting joint positions.""" + # Set initial joint positions + qpos_zero = torch.zeros( + (NUM_ARENAS, self.art.dof), dtype=torch.float32, device=self.sim.device + ) + qpos = qpos_zero.clone() + qpos[:, -1] = 0.1 + + # Test setting joint positions directly. + self.art.set_qpos(qpos, env_ids=None, target=False) + target_qpos = self.art.body_data.qpos + assert torch.allclose( + target_qpos, qpos, atol=1e-5 + ), f"FAIL: Joint positions not set correctly: {target_qpos.tolist()}" + + self.art.set_qpos(qpos=qpos_zero, env_ids=None, target=False) + + # Test setting joint positions with target=True + self.art.set_qpos(qpos, env_ids=None, target=True) + self.sim.update(step=100) + target_qpos = self.art.body_data.qpos + assert torch.allclose( + target_qpos, qpos, atol=1e-5 + ), f"FAIL: Joint positions not set correctly with target=True: {target_qpos.tolist()}" + + self.art.set_qpos(qpos=qpos_zero, env_ids=None, target=False) + self.art.clear_dynamics() + + # Test setting joint forces + qf = torch.ones( + (NUM_ARENAS, self.art.dof), dtype=torch.float32, device=self.sim.device + ) + self.art.set_qf(qf, env_ids=None) + target_qf = self.art.body_data.qf + assert torch.allclose( + target_qf, qf, atol=1e-5 + ), f"FAIL: Joint forces not set correctly: {target_qf.tolist()}" + print("Applying joint forces...") + print(f"qpos before applying force: {qpos_zero.tolist()}") + print(f"qf before applying force: {qf.tolist()}") + + self.sim.update(step=100) + target_qpos = self.art.body_data.qpos + print(f"target_qpos: {target_qpos}") + print(f"qpos_zero: {qpos_zero}") + print("qpos diff:", target_qpos - qpos_zero) + # check target_qpos is greater than qpos + assert torch.any( + (target_qpos - qpos_zero).abs() > 1e-4 + ), f"FAIL: Target qpos did not change after applying force: {target_qpos.tolist()}" + + def test_set_visual_material(self): + """Test setting visual material properties.""" + # Create blue material + blue_mat = self.sim.create_visual_material( + cfg=VisualMaterialCfg(base_color=[0.0, 0.0, 1.0, 1.0]) + ) + + self.art.set_visual_material(blue_mat, link_names=["outer_box", "handle_xpos"]) + + mat_insts = self.art.get_visual_material_inst() + + assert ( + len(mat_insts) == 10 + ), f"FAIL: Expected 10 material instances, got {len(mat_insts)}" + assert ( + "outer_box" in mat_insts[0] + ), "FAIL: 'outer_box' not in material instances" + assert ( + "handle_xpos" in mat_insts[0] + ), "FAIL: 'handle_xpos' not in material instances" + assert mat_insts[0]["outer_box"].base_color == [ + 0.0, + 0.0, + 1.0, + 1.0, + ], f"FAIL: 'outer_box' base color not set correctly: {mat_insts[0]['outer_box'].base_color}" + assert mat_insts[0]["handle_xpos"].base_color == [ + 0.0, + 0.0, + 1.0, + 1.0, + ], f"FAIL: 'handle_xpos' base color not set correctly: {mat_insts[0]['handle_xpos'].base_color}" + + # TODO: Open this test will cause segfault in CI env + # def test_get_link_pose(self): + # """Test getting link poses.""" + # poses = self.art.get_link_pose(link_name="handle_xpos", to_matrix=False) + # assert poses.shape == ( + # NUM_ARENAS, + # 7, + # ), f"FAIL: Expected poses shape {(NUM_ARENAS, 7)}, got {poses.shape}" + + def test_remove_articulation(self): + """Test removing an articulation from the simulation.""" + self.sim.remove_asset(self.art.uid) + assert ( + self.art.uid not in self.sim.asset_uids + ), "FAIL: Articulation UID still present after removal" + + def teardown_method(self): + """Clean up resources after each test method.""" + self.sim.destroy() + + +class TestArticulationCPU(BaseArticulationTest): + def setup_method(self): + self.setup_simulation("cpu") + + +@pytest.mark.skip(reason="Skipping CUDA tests temporarily") +class TestArticulationCUDA(BaseArticulationTest): + def setup_method(self): + self.setup_simulation("cuda") + + +if __name__ == "__main__": + test = TestArticulationCPU() + test.setup_method() + test.test_set_visual_material() diff --git a/tests/sim/objects/test_light.py b/tests/sim/objects/test_light.py new file mode 100644 index 00000000..8f61fce3 --- /dev/null +++ b/tests/sim/objects/test_light.py @@ -0,0 +1,155 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import pytest +import torch +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import LightCfg + + +class TestLight: + def setup_method(self): + # Setup SimulationManager + config = SimulationManagerCfg(headless=True, sim_device="cpu") + self.sim = SimulationManager(config) + self.sim.build_multiple_arenas(10) + # sim.set_manual_update(True) + # Create batch of lights + cfg_dict = { + "light_type": "point", + "color": [0.1, 0.1, 0.1], + "radius": 10.0, + "position": [0.0, 0.0, 2.0], + "uid": "point_light", + } + self.light = self.sim.add_light(cfg=LightCfg.from_dict(cfg_dict)) + + def test_set_color_with_env_ids(self): + """Test set_color with and without env_ids.""" + base_color = torch.tensor([0.1, 0.1, 0.1], device=self.sim.device) + + # Set for all environments + try: + self.light.set_color(base_color) + except Exception as e: + pytest.fail(f"Failed to set color for all envs: {e}") + + # Set for specific envs + env_ids = [1, 3, 5] + new_color = torch.tensor([0.9, 0.8, 0.7], device=self.sim.device) + try: + self.light.set_color(new_color, env_ids=env_ids) + except Exception as e: + pytest.fail(f"Failed to set color for env_ids={env_ids}: {e}") + + def test_set_falloff_with_env_ids(self): + """Test set_falloff with and without env_ids.""" + base_val = torch.tensor(100.0, device=self.sim.device) + + # Set for all + try: + self.light.set_falloff(base_val) + except Exception as e: + pytest.fail(f"Failed to set falloff for all envs: {e}") + + env_ids = [0, 7, 9] + new_vals = torch.tensor([200.0, 300.0, 400.0], device=self.sim.device) + try: + self.light.set_falloff(new_vals, env_ids=env_ids) + except Exception as e: + pytest.fail(f"Failed to set falloff for env_ids={env_ids}: {e}") + + def test_set_and_get_local_pose_matrix_and_vector(self): + """ + Test setting and getting local pose in both matrix and vector forms. + + 1. Set all lights to identity pose (4x4 matrix) + 2. Overwrite subset of lights (env_ids) with custom pose + 3. Check both vector and matrix results match expectations + """ + + # ---------------------------- + # 1. Set all lights to identity matrix + # ---------------------------- + pose_matrix = torch.eye(4, device=self.sim.device) + try: + self.light.set_local_pose(pose_matrix, to_matrix=True) + except Exception as e: + pytest.fail(f"Failed to set pose matrix for all envs: {e}") + + result_matrix = self.light.get_local_pose(to_matrix=True) + assert result_matrix.shape == ( + 10, + 4, + 4, + ), "Unexpected shape from get_local_pose(to_matrix=True)" + for i, mat in enumerate(result_matrix): + assert torch.allclose( + mat, pose_matrix, atol=1e-5 + ), f"Initial matrix pose mismatch at env {i}" + + # ---------------------------- + # 2. Set translation via matrix for selected env_ids + # ---------------------------- + env_ids = [2, 4, 6] + pose_matrix_2 = ( + torch.eye(4, device=self.sim.device).unsqueeze(0).repeat(len(env_ids), 1, 1) + ) + pose_matrix_2[:, 0, 3] = 1.0 + pose_matrix_2[:, 1, 3] = 2.0 + pose_matrix_2[:, 2, 3] = 3.0 + + try: + self.light.set_local_pose(pose_matrix_2, env_ids=env_ids, to_matrix=True) + except Exception as e: + pytest.fail(f"Failed to set pose matrix for env_ids={env_ids}: {e}") + + # ---------------------------- + # 3. Check vector form after env_ids modification + # ---------------------------- + result_vec = self.light.get_local_pose(to_matrix=False) + assert result_vec.shape == ( + 10, + 3, + ), "Unexpected shape from get_local_pose(to_matrix=False)" + + for i in range(10): + expected = ( + torch.tensor([1.0, 2.0, 3.0], device=self.sim.device) + if i in env_ids + else torch.tensor([0.0, 0.0, 0.0], device=self.sim.device) + ) + assert torch.allclose( + result_vec[i], expected, atol=1e-5 + ), f"Translation vector mismatch at env {i}" + + # ---------------------------- + # 4. Verify matrix form translation field + # ---------------------------- + result_matrix = self.light.get_local_pose(to_matrix=True) + for i in range(10): + expected = ( + torch.tensor([1.0, 2.0, 3.0], device=self.sim.device) + if i in env_ids + else torch.tensor([0.0, 0.0, 0.0], device=self.sim.device) + ) + assert torch.allclose( + result_matrix[i][:3, 3], expected, atol=1e-5 + ), f"Translation matrix mismatch at env {i}" + + def teardown_method(self): + """Clean up resources after each test method.""" + self.sim.destroy() diff --git a/tests/sim/objects/test_rigid_object.py b/tests/sim/objects/test_rigid_object.py new file mode 100644 index 00000000..f57f8a91 --- /dev/null +++ b/tests/sim/objects/test_rigid_object.py @@ -0,0 +1,280 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import torch +import pytest + +from embodichain.lab.sim import ( + SimulationManager, + SimulationManagerCfg, + VisualMaterialCfg, +) +from embodichain.lab.sim.objects import RigidObject +from embodichain.lab.sim.cfg import RigidObjectCfg +from embodichain.lab.sim.shapes import MeshCfg +from embodichain.data import get_data_path +from dexsim.types import ActorType + +DUCK_PATH = "ToyDuck/toy_duck.glb" +TABLE_PATH = "ShopTableSimple/shop_table_simple.ply" +CHAIR_PATH = "Chair/chair.glb" +NUM_ARENAS = 2 +Z_TRANSLATION = 2.0 + + +class BaseRigidObjectTest: + """Shared test logic for CPU and CUDA.""" + + def setup_simulation(self, sim_device): + config = SimulationManagerCfg(headless=True, sim_device=sim_device) + self.sim = SimulationManager(config) + self.sim.build_multiple_arenas(NUM_ARENAS) + self.sim.set_manual_update(True) + + duck_path = get_data_path(DUCK_PATH) + assert os.path.isfile(duck_path) + table_path = get_data_path(TABLE_PATH) + assert os.path.isfile(table_path) + chair_path = get_data_path(CHAIR_PATH) + assert os.path.isfile(chair_path) + + cfg_dict = { + "uid": "duck", + "shape": { + "shape_type": "Mesh", + "fpath": duck_path, + }, + "body_type": "dynamic", + } + self.duck: RigidObject = self.sim.add_rigid_object( + cfg=RigidObjectCfg.from_dict(cfg_dict), + ) + self.table: RigidObject = self.sim.add_rigid_object( + cfg=RigidObjectCfg( + uid="table", shape=MeshCfg(fpath=table_path), body_type="static" + ), + ) + self.chair: RigidObject = self.sim.add_rigid_object( + cfg=RigidObjectCfg( + uid="chair", shape=MeshCfg(fpath=chair_path), body_type="kinematic" + ), + ) + + if sim_device == "cuda" and getattr(self.sim, "is_use_gpu_physics", False): + self.sim.init_gpu_physics() + + self.sim.enable_physics(True) + + def test_is_static(self): + """Test the is_static() method of duck, table, and chair objects.""" + assert not self.duck.is_static, "Duck should be dynamic but is marked static" + assert self.table.is_static, "Table should be static but is marked dynamic" + assert ( + not self.chair.is_static + ), "Chair should be kinematic but is marked static" + + def test_local_pose_behavior(self): + """Test set_local_pose and get_local_pose: + - duck pose is correctly set + - duck falls after physics update + - table stays in place throughout + - chair is kinematic and does not move + """ + + # Set initial poses + pose_duck = torch.eye(4, device=self.sim.device) + pose_duck[2, 3] = Z_TRANSLATION + pose_duck = pose_duck.unsqueeze(0).repeat(NUM_ARENAS, 1, 1) + + pose_table = torch.eye(4, device=self.sim.device) + pose_table = pose_table.unsqueeze(0).repeat(NUM_ARENAS, 1, 1) + + pose_chair = torch.eye(4, device=self.sim.device) + pose_chair[0, 3] = 1.0 + pose_chair[1, 3] = 2.0 + pose_chair = pose_chair.unsqueeze(0).repeat(NUM_ARENAS, 1, 1) + + self.duck.set_local_pose(pose_duck) + self.table.set_local_pose(pose_table) + self.chair.set_local_pose(pose_chair) + + # --- Check poses immediately after setting + duck_xyz = self.duck.get_local_pose()[0, :3] + table_xyz = self.table.get_local_pose()[0, :3] + chair_xyz = self.chair.get_local_pose()[0, :3] + + expected_duck_pos = torch.tensor( + [0.0, 0.0, Z_TRANSLATION], device=self.sim.device, dtype=torch.float32 + ) + expected_table_pos = torch.tensor( + [0.0, 0.0, 0.0], device=self.sim.device, dtype=torch.float32 + ) + expected_chair_pos = torch.tensor( + [1.0, 2.0, 0.0], device=self.sim.device, dtype=torch.float32 + ) + + assert torch.allclose( + duck_xyz, expected_duck_pos, atol=1e-5 + ), f"FAIL: Duck pose not set correctly: {duck_xyz.tolist()}" + assert torch.allclose( + table_xyz, expected_table_pos, atol=1e-5 + ), f"FAIL: Table pose not set correctly: {table_xyz.tolist()}" + assert torch.allclose( + chair_xyz, expected_chair_pos, atol=1e-5 + ), f"FAIL: Chair pose not set correctly: {chair_xyz.tolist()}" + + # --- Step simulation + for _ in range(10): + self.sim.update(0.01) + + # --- Post-update checks + duck_z_after = self.duck.get_local_pose()[0, 2].item() + table_xyz_after = self.table.get_local_pose()[0, :3].tolist() + chair_xyz_after = self.chair.get_local_pose()[0, :3] + + assert ( + duck_z_after < Z_TRANSLATION + ), f"FAIL: Duck did not fall: z = {duck_z_after:.3f}" + assert all( + abs(x) < 1e-5 for x in table_xyz_after + ), f"FAIL: Table moved unexpectedly: {table_xyz_after}" + assert torch.allclose( + chair_xyz_after, expected_chair_pos, atol=1e-5 + ), f"FAIL: Chair pose changed unexpectedly: {chair_xyz_after.tolist()}" + + def test_add_force_torque(self): + """Test that add_force applies force correctly to the duck object.""" + + pose_before = self.duck.get_local_pose() + + force = ( + torch.tensor([10.0, 0.0, 0], device=self.sim.device) + .unsqueeze(0) + .repeat(NUM_ARENAS, 1) + ) + self.duck.add_force_torque(force) + + # Update simulation to apply the force + self.sim.update(0.01) + + # Check if the duck's z position has changed + pose_after = self.duck.get_local_pose() + assert not torch.allclose( + pose_before, pose_after + ), "FAIL: Duck pose did not change after applying force" + + pose_before = self.duck.get_local_pose() + torque = ( + torch.tensor([0.0, 10.0, 0.0], device=self.sim.device) + .unsqueeze(0) + .repeat(NUM_ARENAS, 1) + ) + self.duck.add_force_torque(None, torque=torque) + + # Update simulation to apply the torque + self.sim.update(0.01) + + pose_after = self.duck.get_local_pose() + assert not torch.allclose( + pose_before, pose_after + ), "FAIL: Duck pose did not change after applying torque" + + # Test clear dynamics + self.duck.clear_dynamics() + + def test_set_visual_material(self): + """Test that set_material correctly assigns the material to the duck.""" + + # Create blue material + blue_mat = self.sim.create_visual_material( + cfg=VisualMaterialCfg(base_color=[0.0, 0.0, 1.0, 1.0]) + ) + + # Set it to the duck + self.duck.set_visual_material(blue_mat) + + # # # Get material instances + material_list = self.duck.get_visual_material_inst() + + # # Check correctness + assert isinstance(material_list, list), "get_material() did not return a list" + assert ( + len(material_list) == NUM_ARENAS + ), f"Expected {NUM_ARENAS} materials, got {len(material_list)}" + for mat_inst in material_list: + assert mat_inst.base_color == [ + 0.0, + 0.0, + 1.0, + 1.0, + ], f"Material base color incorrect: {mat_inst.base_color}" + + def test_add_cube(self): + cfg_dict = { + "uid": "cube", + "shape": { + "shape_type": "Cube", + }, + "body_type": "dynamic", + } + cube: RigidObject = self.sim.add_rigid_object( + cfg=RigidObjectCfg.from_dict(cfg_dict), + ) + + def test_add_sphere(self): + cfg_dict = { + "uid": "sphere", + "shape": { + "shape_type": "Sphere", + }, + "body_type": "dynamic", + } + sphere: RigidObject = self.sim.add_rigid_object( + cfg=RigidObjectCfg.from_dict(cfg_dict), + ) + + def test_remove(self): + self.sim.remove_asset(self.duck.uid) + + assert ( + self.duck.uid not in self.sim.asset_uids + ), "Duck UID still present after removal" + + def teardown_method(self): + """Clean up resources after each test method.""" + self.sim.destroy() + + +class TestRigidObjectCPU(BaseRigidObjectTest): + def setup_method(self): + self.setup_simulation("cpu") + + +@pytest.mark.skip(reason="Skipping CUDA tests temporarily") +class TestRigidObjectCUDA(BaseRigidObjectTest): + def setup_method(self): + self.setup_simulation("cuda") + + +if __name__ == "__main__": + # pytest.main(["-s", __file__]) + test = TestRigidObjectCPU() + test.setup_method() + test.test_set_visual_material() + from IPython import embed + + embed() diff --git a/tests/sim/objects/test_rigid_object_group.py b/tests/sim/objects/test_rigid_object_group.py new file mode 100644 index 00000000..7ca12fb3 --- /dev/null +++ b/tests/sim/objects/test_rigid_object_group.py @@ -0,0 +1,132 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import torch +import pytest + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.objects import RigidObjectGroup +from embodichain.lab.sim.cfg import RigidObjectGroupCfg, RigidObjectCfg +from embodichain.lab.sim.shapes import MeshCfg +from embodichain.data import get_data_path +from dexsim.types import ActorType + +DUCK_PATH = "ToyDuck/toy_duck.glb" +TABLE_PATH = "ShopTableSimple/shop_table_simple.ply" +NUM_ARENAS = 4 +Z_TRANSLATION = 2.0 + + +class BaseRigidObjectGroupTest: + """Shared test logic for CPU and CUDA.""" + + def setup_simulation(self, sim_device): + config = SimulationManagerCfg(headless=True, sim_device=sim_device) + self.sim = SimulationManager(config) + self.sim.build_multiple_arenas(NUM_ARENAS) + self.sim.set_manual_update(True) + + duck_path = get_data_path(DUCK_PATH) + assert os.path.isfile(duck_path) + table_path = get_data_path(TABLE_PATH) + assert os.path.isfile(table_path) + + cfg_dict = { + "uid": "group", + "rigid_objects": { + "duck1": { + "shape": { + "shape_type": "Mesh", + "fpath": duck_path, + }, + }, + "duck2": { + "shape": { + "shape_type": "Mesh", + "fpath": duck_path, + }, + }, + }, + } + self.obj_group: RigidObjectGroup = self.sim.add_rigid_object_group( + cfg=RigidObjectGroupCfg.from_dict(cfg_dict) + ) + + if sim_device == "cuda" and self.sim.is_use_gpu_physics: + self.sim.init_gpu_physics() + + self.sim.enable_physics(True) + + def test_local_pose_behavior(self): + + # Set initial poses + pose_duck1 = torch.eye(4, device=self.sim.device) + pose_duck1[2, 3] = Z_TRANSLATION + pose_duck1 = pose_duck1.unsqueeze(0).repeat(NUM_ARENAS, 1, 1) + + pose_duck2 = torch.eye(4, device=self.sim.device) + pose_duck2[2, 3] = Z_TRANSLATION + pose_duck2 = pose_duck2.unsqueeze(0).repeat(NUM_ARENAS, 1, 1) + + combined_pose = torch.stack([pose_duck1, pose_duck2], dim=1) + + self.obj_group.set_local_pose(combined_pose) + group_pos = self.obj_group.get_local_pose()[..., :3] + assert torch.allclose( + group_pos, + combined_pose[..., :3, 3], + atol=1e-5, + ), "FAIL: Local poses do not match after setting." + + def test_get_user_ids(self): + """Test get_user_ids method.""" + user_ids = self.obj_group.get_user_ids() + + assert user_ids.shape == (NUM_ARENAS, self.obj_group.num_objects), ( + f"Unexpected user_ids shape: {user_ids.shape}, " + f"expected ({NUM_ARENAS}, {self.obj_group.num_objects})" + ) + + def test_remove(self): + self.sim.remove_asset(self.obj_group.uid) + + assert ( + self.obj_group.uid not in self.sim.asset_uids + ), "Object group UID still present after removal" + + def teardown_method(self): + """Clean up resources after each test method.""" + self.sim.destroy() + + +class TestRigidObjectGroupCPU(BaseRigidObjectGroupTest): + def setup_method(self): + self.setup_simulation("cpu") + + +# TODO: Fix CUDA tests issue. +@pytest.mark.skip(reason="Skipping CUDA tests temporarily") +class TestRigidObjectGroupCUDA(BaseRigidObjectGroupTest): + def setup_method(self): + self.setup_simulation("cuda") + + +if __name__ == "__main__": + # pytest.main(["-s", __file__]) + test = TestRigidObjectGroupCPU() + test.setup_method() + test.test_local_pose_behavior() diff --git a/tests/sim/objects/test_robot.py b/tests/sim/objects/test_robot.py new file mode 100644 index 00000000..78a5ac3a --- /dev/null +++ b/tests/sim/objects/test_robot.py @@ -0,0 +1,264 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import torch +import pytest +import numpy as np + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim.robots.dexforce_w1 import DexforceW1Cfg +from embodichain.data import get_data_path + + +# Define control parts +CONTROL_PARTS = { + "left_arm": [ + "LEFT_J1", + "LEFT_J2", + "LEFT_J3", + "LEFT_J4", + "LEFT_J5", + "LEFT_J6", + "LEFT_J7", + ], + "right_arm": [ + "RIGHT_J1", + "RIGHT_J2", + "RIGHT_J3", + "RIGHT_J4", + "RIGHT_J5", + "RIGHT_J6", + "RIGHT_J7", + ], +} + +# Base test class for CPU and CUDA +class BaseRobotTest: + def setup_simulation(self, sim_device): + # Set up simulation with specified device (CPU or CUDA) + config = SimulationManagerCfg(headless=True, sim_device=sim_device) + self.sim = SimulationManager(config) + self.sim.build_multiple_arenas(10) # NUM_ARENAS = 10 + self.sim.set_manual_update(True) + + cfg = DexforceW1Cfg.from_dict( + { + "uid": "dexforce_w1", + "version": "v021", + "arm_kind": "anthropomorphic", + } + ) + + self.robot: Robot = self.sim.add_robot(cfg=cfg) + + # Initialize GPU physics if needed + if sim_device == "cuda" and getattr(self.sim, "is_use_gpu_physics", False): + self.sim.init_gpu_physics() + + def test_get_joint_ids(self): + left_joint_ids = self.robot.get_joint_ids("left_arm") + right_joint_ids = self.robot.get_joint_ids("right_arm") + + assert left_joint_ids == [ + 6, + 8, + 10, + 12, + 14, + 16, + 18, + ], f"Unexpected left arm joint IDs: {left_joint_ids}" + assert right_joint_ids == [ + 7, + 9, + 11, + 13, + 15, + 17, + 19, + ], f"Unexpected right arm joint IDs: {right_joint_ids}" + + @pytest.mark.parametrize("arm_name", ["left_arm", "right_arm"]) + def test_fk(self, arm_name: str): + # Test forward kinematics (FK) for both to_matrix=True and to_matrix=False + + qpos = torch.randn(10, 7, device=self.sim.device) # Random joint positions + + # Test with to_matrix=False (6D result: translation + Euler angles) + result_7d = self.robot.compute_fk(qpos=qpos, name=arm_name, to_matrix=False) + + # Check result shape for 6D output (batch, 6) + assert result_7d.shape == ( + 10, + 7, + ), f"Expected shape (10, 7), got {result_7d.shape}" + + # Test with to_matrix=True (4x4 matrix result) + result_matrix = self.robot.compute_fk(qpos=qpos, name=arm_name, to_matrix=True) + print("result_matrix:", result_matrix) + # Check result shape for matrix output (batch, 4, 4) + assert result_matrix.shape == ( + 10, + 4, + 4, + ), f"Expected shape (10, 4, 4), got {result_matrix.shape}" + + def test_compute_fk(self): + torch.set_printoptions(precision=6, sci_mode=False) + qpos = np.zeros(40) + result = self.robot.compute_fk(qpos=qpos, link_names=["left_ee", "right_ee"]) + + # Additional checks for specific values (if known) + expected_values = torch.tensor( + [ + [ + [1.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 1.0, 0.791], + [0.0, -1.0, 0.0, 1.3648], + [0.0, 0.0, 0.0, 1.0], + ], + [ + [1.0, 0.0, 0.0, 0.0], + [0.0, 0.0, -1.0, -0.791], + [0.0, 1.0, 0.0, 1.3648], + [0.0, 0.0, 0.0, 1.0], + ], + ], + dtype=torch.float32, + ).unsqueeze_(0) + + assert torch.allclose( + result, expected_values, atol=1e-4, rtol=1e-4 + ), f"FK result does not match expected values. Got {result}, expected {expected_values}." + + def test_compute_jacobian(self): + qpos = np.full(7, 10 * np.pi / 180) + + left_ee_jacobian = self.robot.compute_jacobian( + qpos=qpos, end_link_name="left_ee", root_link_name="left_arm_base" + ) + right_ee_jacobian = self.robot.compute_jacobian( + qpos=qpos, end_link_name="right_ee", root_link_name="right_arm_base" + ) + + assert left_ee_jacobian.shape == ( + 1, + 6, + 7, + ), f"Expected shape (1, 6, 7) for left EE Jacobian, got {left_ee_jacobian.shape}" + assert right_ee_jacobian.shape == ( + 1, + 6, + 7, + ), f"Expected shape (1, 6, 7) for right EE Jacobian, got {right_ee_jacobian.shape}" + + @pytest.mark.parametrize("arm_name", ["left_arm", "right_arm"]) + def test_ik(self, arm_name: str): + # Test inverse kinematics (IK) with a 1x4x4 homogeneous matrix pose and a joint_seed + + # Define a sample target pose as a 1x4x4 homogeneous matrix + target_pose = torch.tensor( + [ + [-0.3490, -0.6369, -0.6874, -0.4502], + [0.2168, -0.7685, 0.6020, -0.0639], + [-0.9117, 0.0611, 0.4063, 0.3361], + [0.0000, 0.0000, 0.0000, 1.0000], + ], + dtype=torch.float32, + device=self.sim.device, + ).unsqueeze(0) + + # Define joint_seed as a tensor of ones with shape (1, 7) for initialization + joint_seed = torch.ones(1, 7, device=self.sim.device) + success_tensor, qpos_tensor = self.robot.compute_ik( + pose=target_pose, name=arm_name, joint_seed=joint_seed, env_ids=[0] + ) + print(f"Success: {success_tensor}, Qpos: {qpos_tensor}") + + # Check output shapes robustly + assert success_tensor.shape == ( + 1, + ), f"Expected shape (1,), got {success_tensor.shape}" + assert isinstance( + qpos_tensor, torch.Tensor + ), "qpos_tensor should be a torch.Tensor" + # Accept both (1, 7) and (1, N, 7) shapes + if qpos_tensor.ndim == 2: + assert qpos_tensor.shape == ( + 1, + 7, + ), f"Expected shape (1, 7), got {qpos_tensor.shape}" + elif qpos_tensor.ndim == 3: + assert ( + qpos_tensor.shape[2] == 7 + ), f"Expected dof 7, got {qpos_tensor.shape[2]}" + assert ( + qpos_tensor.shape[0] == 1 + ), f"Expected batch size 1, got {qpos_tensor.shape[0]}" + assert ( + qpos_tensor.shape[1] >= 1 + ), f"Expected at least one solution, got {qpos_tensor.shape[1]}" + else: + raise AssertionError(f"Unexpected qpos_tensor shape: {qpos_tensor.shape}") + + # If success, check qpos is not all zeros + if success_tensor.item(): + assert not torch.all( + qpos_tensor == 0 + ), "IK returned all zeros for valid solution" + + def test_mimic(self): + + assert ( + len(self.robot.mimic_ids) == 8 + ), f"Expected 8 mimic IDs, got {len(self.robot.mimic_ids)}" + + left_eef_ids_without_mimic = self.robot.get_joint_ids( + "left_eef", remove_mimic=False + ) + right_eef_ids_without_mimic = self.robot.get_joint_ids( + "right_eef", remove_mimic=False + ) + assert ( + len(left_eef_ids_without_mimic) == 6 + ), f"Expected 6 left eef joint IDs without mimic, got {len(left_eef_ids_without_mimic)}" + assert ( + len(right_eef_ids_without_mimic) == 6 + ), f"Expected 6 right eef joint IDs without mimic, got {len(right_eef_ids_without_mimic)}" + + def teardown_method(self): + """Clean up resources after each test method.""" + self.sim.destroy() + + +class TestRobotCPU(BaseRobotTest): + def setup_method(self): + self.setup_simulation("cpu") + + +@pytest.mark.skip(reason="Skipping CUDA tests temporarily") +class TestRobotCUDA(BaseRobotTest): + def setup_method(self): + self.setup_simulation("cuda") + + +if __name__ == "__main__": + # Run tests directly + test_cpu = TestRobotCPU() + test_cpu.setup_method() + test_cpu.test_fk("left_arm") diff --git a/tests/sim/objects/test_soft_object.py b/tests/sim/objects/test_soft_object.py new file mode 100644 index 00000000..9cbc31af --- /dev/null +++ b/tests/sim/objects/test_soft_object.py @@ -0,0 +1,105 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +from dexsim.utility.path import get_resources_data_path +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.cfg import ( + SoftbodyVoxelAttributesCfg, + SoftbodyPhysicalAttributesCfg, +) +from embodichain.lab.sim.shapes import MeshCfg +from embodichain.lab.sim.objects import ( + SoftObject, + SoftObjectCfg, +) +import pytest + +COW_PATH = get_resources_data_path("Model", "cow", "cow.obj") + + +class BaseSoftObjectTest: + def setup_simulation(self): + sim_cfg = SimulationManagerCfg( + width=1920, + height=1080, + headless=True, + physics_dt=1.0 / 100.0, # Physics timestep (100 Hz) + sim_device="cuda", + enable_rt=False, # Enable ray tracing for better visuals + ) + + # Create the simulation instance + self.sim = SimulationManager(sim_cfg) + + assert os.path.isfile(COW_PATH) + + # Enable manual physics update for precise control + self.sim.set_manual_update(True) + self.n_envs = 4 + # Build multiple arenas if requested + self.sim.build_multiple_arenas(self.n_envs, space=3.0) + # add softbody to the scene + self.cow: SoftObject = self.sim.add_soft_object( + cfg=SoftObjectCfg( + uid="cow", + shape=MeshCfg( + fpath=get_resources_data_path("Model", "cow", "cow.obj"), + ), + init_pos=[0.0, 0.0, 3.0], + voxel_attr=SoftbodyVoxelAttributesCfg( + simulation_mesh_resolution=8, + maximal_edge_length=0.5, + ), + physical_attr=SoftbodyPhysicalAttributesCfg( + youngs=1e6, + poissons=0.45, + density=100, + dynamic_friction=0.1, + min_position_iters=30, + ), + ), + ) + + def test_run_simulation(self): + self.sim.init_gpu_physics() + for _ in range(100): + self.sim.update(step=1) + self.cow.reset() + for _ in range(100): + self.sim.update(step=1) + + def test_remove(self): + self.sim.remove_asset(self.cow.uid) + assert ( + self.cow.uid not in self.sim._soft_objects + ), "Cow UID still present after removal" + + def teardown_method(self): + """Clean up resources after each test method.""" + self.sim.destroy() + + +@pytest.mark.skip(reason="Skipping SoftObject test now") +class TestSoftObjectCUDA(BaseSoftObjectTest): + def setup_method(self): + self.setup_simulation() + + +if __name__ == "__main__": + test = TestSoftObjectCUDA() + test.setup_method() + test.test_run_simulation() diff --git a/tests/sim/planners/test_motion_generator.py b/tests/sim/planners/test_motion_generator.py new file mode 100644 index 00000000..67e17dcf --- /dev/null +++ b/tests/sim/planners/test_motion_generator.py @@ -0,0 +1,251 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +import time +import torch +import pytest +import numpy as np +from copy import deepcopy +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim.robots import CobotMagicCfg + +from embodichain.lab.sim.planners.utils import TrajectorySampleMethod +from embodichain.lab.sim.planners.motion_generator import MotionGenerator + + +def to_numpy(tensor): + if isinstance(tensor, torch.Tensor): + tensor = tensor.detach().cpu() + if tensor.ndim == 3 and tensor.shape[0] == 1: + tensor = tensor[0] + return tensor.numpy() + return np.array(tensor) + + +class BaseTestMotionGenerator(object): + @classmethod + def setup_class(cls): + cls.config = SimulationManagerCfg(headless=True, sim_device="cpu") + cls.robot_sim = SimulationManager(cls.config) + cls.robot_sim.build_multiple_arenas(1) + cls.robot_sim.set_manual_update(False) + + cfg_dict = { + "uid": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [ + -0.3, + 0.3, + 1.0, + 1.0, + -1.2, + -1.2, + 0.0, + 0.0, + 0.6, + 0.6, + 0.0, + 0.0, + 0.05, + 0.05, + 0.05, + 0.05, + ], + "solver_cfg": { + "left_arm": { + "class_type": "OPWSolver", + "end_link_name": "left_link6", + "root_link_name": "left_arm_base", + "tcp": [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.143], [0, 0, 0, 1]], + }, + "right_arm": { + "class_type": "OPWSolver", + "end_link_name": "right_link6", + "root_link_name": "right_arm_base", + "tcp": [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.143], [0, 0, 0, 1]], + }, + }, + } + + cls.robot: Robot = cls.robot_sim.add_robot( + cfg=CobotMagicCfg.from_dict(cfg_dict) + ) + + cls.arm_name = "left_arm" + + cls.motion_gen = MotionGenerator( + robot=cls.robot, + uid=cls.arm_name, + planner_type="toppra", + default_velocity=0.2, + default_acceleration=0.5, + ) + + # Test data for trajectory generation + qpos_fk = torch.tensor( + [[0.0, np.pi / 4, -np.pi / 4, 0.0, np.pi / 4, 0.0]], dtype=torch.float32 + ) + xpos_begin = cls.robot.compute_fk( + name=cls.arm_name, qpos=qpos_fk, to_matrix=True + ) + xpos_mid = deepcopy(xpos_begin) + xpos_mid[0, 2, 3] -= 0.1 # Move down by 0.1m in Z direction + xpos_final = deepcopy(xpos_mid) + xpos_final[0, 0, 3] += 0.2 # Move forward by 0.2m in X direction + + qpos_begin = cls.robot.compute_ik(pose=xpos_begin, name=cls.arm_name)[1][0] + qpos_mid = cls.robot.compute_ik(pose=xpos_mid, name=cls.arm_name)[1][0] + qpos_final = cls.robot.compute_ik(pose=xpos_final, name=cls.arm_name)[1][0] + + cls.qpos_list = [qpos_begin, qpos_mid, qpos_final] + cls.xpos_list = [ + xpos_begin[0].numpy(), + xpos_mid[0].numpy(), + xpos_final[0].numpy(), + ] + + cls.sample_num = 20 + + def get_joint_ids(self): + return self.robot.get_joint_ids(self.arm_name) + + def get_current_qpos(self): + qpos_tensor = self.robot.get_qpos() + if qpos_tensor.ndim == 2 and qpos_tensor.shape[0] == 1: + qpos_tensor = qpos_tensor[0] + return qpos_tensor[self.get_joint_ids()].cpu() + + def verify_final_xpos(self, expected_xpos, decimal=5e-3): + final_xpos = self.robot.compute_fk( + qpos=self.get_current_qpos(), name=self.arm_name, to_matrix=True + ) + np.testing.assert_array_almost_equal( + to_numpy(final_xpos)[:3, 3], + to_numpy(expected_xpos)[:3, 3], + decimal=decimal, + err_msg=f"Expected: {to_numpy(expected_xpos)[:3, 3]}, Got: {to_numpy(final_xpos)[:3, 3]}", + ) + + def _execute_trajectory(self, qpos_list, forward=True, delay=0.01): + indices = ( + range(len(qpos_list)) if forward else range(len(qpos_list) - 1, -1, -1) + ) + for i in indices: + self.robot.set_qpos(qpos=qpos_list[i], joint_ids=self.get_joint_ids()) + time.sleep(delay) + time.sleep(delay * 2) + + @classmethod + def teardown_class(cls): + try: + cls.robot_sim.destroy() + print("robot_sim destroyed successfully") + except Exception as e: + print(f"Error during robot_sim.destroy(): {e}") + + def _execute_forward_trajectory(self, robot, qpos_list, delay=0.1): + """Helper method to execute trajectory""" + # Forward + for q in qpos_list: + robot.set_qpos(qpos=q, joint_ids=self.robot.get_joint_ids(self.arm_name)) + time.sleep(delay) + time.sleep(delay * 5) + + def _execute_backward_trajectory(self, robot, qpos_list, delay=0.1): + """Helper method to execute trajectory""" + # Backward + for q in qpos_list[::-1]: + robot.set_qpos(qpos=q, joint_ids=self.robot.get_joint_ids(self.arm_name)) + time.sleep(delay) + time.sleep(delay * 5) + + +class TestMotionGenerator(BaseTestMotionGenerator): + """Test suite for MotionGenerator trajectory generation""" + + @pytest.mark.parametrize("is_linear", [True, False]) + def test_create_trajectory_with_xpos(self, is_linear): + """Test trajectory generation with cartesian positions""" + self.robot.set_qpos(qpos=self.qpos_list[0], joint_ids=self.get_joint_ids()) + time.sleep(0.2) + out_qpos_list, out_xpos_list = self.motion_gen.create_discrete_trajectory( + xpos_list=self.xpos_list, + is_use_current_qpos=True, + sample_num=self.sample_num, + is_linear=is_linear, + sample_method=TrajectorySampleMethod.QUANTITY, + qpos_seed=self.qpos_list[0], + ) + out_qpos_list = to_numpy(out_qpos_list) + assert ( + len(out_qpos_list) == self.sample_num + ), f"Sample number mismatch: {len(out_qpos_list)} != {self.sample_num}" + np.testing.assert_array_almost_equal( + out_xpos_list[-1], self.xpos_list[-1], decimal=3 + ) + self._execute_trajectory(out_qpos_list, forward=True) + self.verify_final_xpos(self.xpos_list[-1]) + self._execute_trajectory(out_qpos_list, forward=False) + self.verify_final_xpos(self.xpos_list[0]) + + @pytest.mark.parametrize("is_linear", [True, False]) + def test_create_trajectory_with_qpos(self, is_linear): + """Test trajectory generation with joint positions""" + self.robot.set_qpos(qpos=self.qpos_list[0], joint_ids=self.get_joint_ids()) + time.sleep(0.05) + qpos_list_in = [qpos.to("cpu").numpy() for qpos in self.qpos_list] + out_qpos_list, out_xpos_list = self.motion_gen.create_discrete_trajectory( + qpos_list=qpos_list_in, + sample_num=self.sample_num, + is_linear=False, + sample_method=TrajectorySampleMethod.QUANTITY, + qpos_seed=self.qpos_list[0], + ) + out_qpos_list = to_numpy(out_qpos_list) + assert ( + len(out_qpos_list) == self.sample_num + ), f"Sample number mismatch: {len(out_qpos_list)} != {self.sample_num}" + np.testing.assert_array_almost_equal( + out_qpos_list[-1], self.qpos_list[-1], decimal=3 + ) + self._execute_trajectory(out_qpos_list, forward=True) + self.verify_final_xpos(self.xpos_list[-1]) + self._execute_trajectory(out_qpos_list, forward=False) + self.verify_final_xpos(self.xpos_list[0]) + + @pytest.mark.parametrize("xpos_or_qpos", ["xpos", "qpos"]) + def test_estimate_trajectory_sample_count(self, xpos_or_qpos: str): + """Test estimation of trajectory sample count""" + if xpos_or_qpos == "xpos": + estimated_num = self.motion_gen.estimate_trajectory_sample_count( + xpos_list=self.xpos_list, + step_size=0.01, + angle_step=np.pi / 90, + ) + else: + estimated_num = self.motion_gen.estimate_trajectory_sample_count( + qpos_list=self.qpos_list, + step_size=0.01, + angle_step=np.pi / 90, + ) + assert (estimated_num - 30) < 2, "Estimated sample count failed" + + +if __name__ == "__main__": + np.set_printoptions(precision=5, suppress=True) + torch.set_printoptions(precision=5, sci_mode=False) + pytest_args = ["-v", "-s", __file__] + pytest.main(pytest_args) diff --git a/tests/sim/sensors/test_camera.py b/tests/sim/sensors/test_camera.py new file mode 100644 index 00000000..8e578177 --- /dev/null +++ b/tests/sim/sensors/test_camera.py @@ -0,0 +1,153 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ----------------------------------------------------------------------------, + +import pytest +import torch +import os + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.sensors import Camera, SensorCfg, CameraCfg +from embodichain.lab.sim.objects import Articulation +from embodichain.lab.sim.cfg import ArticulationCfg +from embodichain.data import get_data_path + + +NUM_ENVS = 4 +ART_PATH = "AiLiMu_BoxDrawer/AiLiMu_BoxDrawer.urdf" + + +class CameraTest: + def setup_simulation(self, sim_device, enable_rt): + # Setup SimulationManager + config = SimulationManagerCfg( + headless=True, sim_device=sim_device, enable_rt=enable_rt + ) + self.sim = SimulationManager(config) + self.sim.build_multiple_arenas(NUM_ENVS) + # Create batch of cameras + cfg_dict = { + "sensor_type": "Camera", + "width": 640, + "height": 480, + "enable_mask": True, + "enable_depth": True, + "enable_normal": True, + "enable_position": True, + } + cfg = SensorCfg.from_dict(cfg_dict) + self.camera: Camera = self.sim.add_sensor(cfg) + + def test_get_data(self): + + self.camera.update() + + # Get data from the camera + data = self.camera.get_data() + + # Check if data is a dictionary + assert isinstance(data, dict), "Camera data should be a dictionary" + + # Check if all expected keys are present + for key in self.camera.SUPPORTED_DATA_TYPES: + assert key in data, f"Missing key in camera data: {key}" + + # Check if the data shape matches the expected shape + assert data["color"].shape == (NUM_ENVS, 480, 640, 4), "RGB data shape mismatch" + assert data["depth"].shape == ( + NUM_ENVS, + 480, + 640, + ), "Depth data shape mismatch" + assert data["normal"].shape == ( + NUM_ENVS, + 480, + 640, + 3, + ), "Normal data shape mismatch" + assert data["position"].shape == ( + NUM_ENVS, + 480, + 640, + 3, + ), "Position data shape mismatch" + assert data["mask"].shape == (NUM_ENVS, 480, 640), "Mask data shape mismatch" + + # Check if the data types are correct + assert data["color"].dtype == torch.uint8, "Color data type mismatch" + assert data["depth"].dtype == torch.float32, "Depth data type mismatch" + assert data["normal"].dtype == torch.float32, "Normal data type mismatch" + assert data["position"].dtype == torch.float32, "Position data type mismatch" + assert data["mask"].dtype == torch.int32, "Mask data type mismatch" + + def test_local_pose_with_env_ids(self): + env_ids = [0, 1, 2] + + pose = ( + torch.eye(4, device=self.sim.device).unsqueeze(0).repeat(len(env_ids), 1, 1) + ) + pose[:, 2, 3] = 2.0 + + self.camera.set_local_pose(pose, env_ids=env_ids) + + # Verify the local pose for specified env_ids + assert torch.allclose(self.camera.get_local_pose(to_matrix=True)[env_ids], pose) + + def test_attach_to_parent(self): + art_path = get_data_path(ART_PATH) + assert os.path.isfile(art_path) + + cfg_dict = {"fpath": art_path} + self.art: Articulation = self.sim.add_articulation( + cfg=ArticulationCfg.from_dict(cfg_dict) + ) + self.camera: Camera = self.sim.add_sensor( + sensor_cfg=CameraCfg( + uid="test", extrinsics=CameraCfg.ExtrinsicsCfg(parent="handle_xpos") + ) + ) + + def test_set_intrinsics(self): + # Define new intrinsic parameters + new_intrinsics = ( + torch.tensor( + [500.0, 500.0, 320.0, 240.0], + device=self.sim.device, + ) + .unsqueeze(0) + .repeat(NUM_ENVS, 1) + ) + + # Set new intrinsic parameters for all environments + self.camera.set_intrinsics(new_intrinsics) + + def teardown_method(self): + """Clean up resources after each test method.""" + self.sim.destroy() + + +class TestCameraRaster(CameraTest): + def setup_method(self): + self.setup_simulation("cpu", enable_rt=False) + + +class TestCameraFastRT(CameraTest): + def setup_method(self): + self.setup_simulation("cpu", enable_rt=True) + + +if __name__ == "__main__": + test = CameraTest() + test.setup_simulation("cpu", enable_rt=False) diff --git a/tests/sim/sensors/test_stereo.py b/tests/sim/sensors/test_stereo.py new file mode 100644 index 00000000..737bae6a --- /dev/null +++ b/tests/sim/sensors/test_stereo.py @@ -0,0 +1,155 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ----------------------------------------------------------------------------, + +import pytest +import torch +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.sensors import StereoCamera, SensorCfg + + +NUM_ENVS = 4 + + +class StereoCameraTest: + def setup_simulation(self, sim_device, enable_rt): + # Setup SimulationManager + config = SimulationManagerCfg( + headless=True, sim_device=sim_device, enable_rt=enable_rt + ) + self.sim = SimulationManager(config) + self.sim.build_multiple_arenas(4) + # Create batch of cameras + cfg_dict = { + "sensor_type": "StereoCamera", + "width": 640, + "height": 480, + "enable_mask": True, + "enable_depth": True, + "enable_normal": True, + "enable_position": True, + "enable_disparity": True, + "left_to_right_pos": (0.1, 0.0, 0.0), + } + cfg = SensorCfg.from_dict(cfg_dict) + self.camera: StereoCamera = self.sim.add_sensor(cfg) + + def test_get_data(self): + + self.camera.update() + + # Get data from the camera + data = self.camera.get_data() + + # Check if data is a dictionary + assert isinstance(data, dict), "Camera data should be a dictionary" + + # Check if all expected keys are present + for key in self.camera.SUPPORTED_DATA_TYPES: + assert key in data, f"Missing key in camera data: {key}" + + # Check if the data shape matches the expected shape + assert data["color"].shape == (NUM_ENVS, 480, 640, 4), "RGB data shape mismatch" + assert data["depth"].shape == ( + NUM_ENVS, + 480, + 640, + 1, + ), "Depth data shape mismatch" + assert data["normal"].shape == ( + NUM_ENVS, + 480, + 640, + 3, + ), "Normal data shape mismatch" + assert data["position"].shape == ( + NUM_ENVS, + 480, + 640, + 3, + ), "Position data shape mismatch" + assert data["mask"].shape == (NUM_ENVS, 480, 640, 1), "Mask data shape mismatch" + assert data["disparity"].shape == ( + NUM_ENVS, + 480, + 640, + 1, + ), "Disparity data shape mismatch" + + # Check if the data types are correct + assert data["color"].dtype == torch.uint8, "Color data type mismatch" + assert data["depth"].dtype == torch.float32, "Depth data type mismatch" + assert data["normal"].dtype == torch.float32, "Normal data type mismatch" + assert data["position"].dtype == torch.float32, "Position data type mismatch" + assert data["mask"].dtype == torch.int32, "Mask data type mismatch" + assert data["disparity"].dtype == torch.float32, "Disparity data type mismatch" + + def test_local_pose_with_env_ids(self): + env_ids = [0, 1, 2] + + pose = ( + torch.eye(4, device=self.sim.device).unsqueeze(0).repeat(len(env_ids), 1, 1) + ) + pose[:, 2, 3] = 2.0 + + self.camera.set_local_pose(pose, env_ids=env_ids) + + # Verify the local pose for specified env_ids + assert torch.allclose(self.camera.get_local_pose(to_matrix=True)[env_ids], pose) + + def test_set_intrinsics(self): + # Define new intrinsic parameters + new_intrinsics = ( + torch.tensor( + [500.0, 500.0, 320.0, 240.0], + device=self.sim.device, + ) + .unsqueeze(0) + .repeat(NUM_ENVS, 1) + ) + + # Set new intrinsic parameters for all environments + self.camera.set_intrinsics(new_intrinsics) + + right_intrinsics = ( + torch.tensor( + [520.0, 520.0, 315.0, 235.0], + device=self.sim.device, + ) + .unsqueeze(0) + .repeat(NUM_ENVS, 1) + ) + + self.camera.set_intrinsics(new_intrinsics, right_intrinsics=right_intrinsics) + + new_intrinsics = torch.tensor( + [500.0, 500.0, 320.0, 240.0], + device=self.sim.device, + ) + self.camera.set_intrinsics(new_intrinsics) + + def teardown_method(self): + """Clean up resources after each test method.""" + self.sim.destroy() + + +class TestStereoCameraRaster(StereoCameraTest): + def setup_method(self): + self.setup_simulation("cpu", enable_rt=False) + + +class TestStereoCameraFastRT(StereoCameraTest): + def setup_method(self): + self.setup_simulation("cpu", enable_rt=True) diff --git a/tests/sim/solvers/test_differential_solver.py b/tests/sim/solvers/test_differential_solver.py new file mode 100644 index 00000000..c9adc24e --- /dev/null +++ b/tests/sim/solvers/test_differential_solver.py @@ -0,0 +1,142 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import torch +import pytest +import numpy as np + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim.cfg import RobotCfg +from embodichain.data import get_data_path + + +# Base test class for differential solver +class BaseSolverTest: + sim = None # Define as a class attribute + + def setup_simulation(self, solver_type: str): + # Set up simulation with specified device (CPU or CUDA) + config = SimulationManagerCfg(headless=True, sim_device="cpu") + self.sim = SimulationManager(config) + self.sim.build_multiple_arenas(1) + self.sim.set_manual_update(True) + + # Load robot URDF file + urdf = get_data_path("DexforceW1V021/DexforceW1_v02_1.urdf") + assert os.path.isfile(urdf) + + cfg_dict = { + "fpath": urdf, + "control_parts": { + "left_arm": [f"LEFT_J{i+1}" for i in range(7)], + "right_arm": [f"RIGHT_J{i+1}" for i in range(7)], + }, + "solver_cfg": { + "left_arm": { + "class_type": solver_type, + "end_link_name": "left_ee", + "root_link_name": "left_arm_base", + }, + "right_arm": { + "class_type": solver_type, + "end_link_name": "right_ee", + "root_link_name": "right_arm_base", + }, + }, + } + + self.robot: Robot = self.sim.add_robot(cfg=RobotCfg.from_dict(cfg_dict)) + + @pytest.mark.parametrize("arm_name", ["left_arm", "right_arm"]) + def test_differential_solver(self, arm_name: str): + # Test differential solver with a 1x4x4 homogeneous matrix pose and a joint_seed + + qpos_fk = torch.tensor( + [[0.0, 0.0, 0.0, -np.pi / 2, 0.0, 0.0, 0.0]], + dtype=torch.float32, + device=self.robot.device, + ) + + fk_xpos = self.robot.compute_fk(qpos=qpos_fk, name=arm_name, to_matrix=True) + + # Define start and end poses + start_pose = fk_xpos.clone()[0] + end_pose = fk_xpos.clone()[0] + end_pose[:3, 3] += torch.tensor( + [0.0, 0.0, -0.02], dtype=torch.float32, device=self.robot.device + ) + + # Interpolate poses + num_steps = 5 + interpolated_poses = [ + torch.lerp(start_pose, end_pose, t) for t in np.linspace(0, 1, num_steps) + ] + + ik_qpos = qpos_fk + + for i, pose in enumerate(interpolated_poses): + res, ik_qpos = self.robot.compute_ik( + pose=pose, joint_seed=ik_qpos, name=arm_name + ) + assert res, f"IK failed for step {i} with pose:\n{pose}" + + # Verify forward kinematics matches the target pose + ik_xpos = self.robot.compute_fk(qpos=ik_qpos, name=arm_name, to_matrix=True) + assert torch.allclose( + pose, ik_xpos, atol=5e-3, rtol=5e-3 + ), f"FK result does not match target pose at step {i}." + + # test for failed xpos + invalid_pose = torch.tensor( + [ + [ + [1.0, 0.0, 0.0, 10.0], + [0.0, 1.0, 0.0, 10.0], + [0.0, 0.0, 1.0, 10.0], + [0.0, 0.0, 0.0, 1.0], + ] + ], + dtype=torch.float32, + device=self.robot.device, + ) + res, ik_qpos = self.robot.compute_ik( + pose=invalid_pose, joint_seed=ik_qpos, name=arm_name + ) + dof = ik_qpos.shape[-1] + assert res[0] == False + assert ik_qpos.shape == (1, dof) + + @classmethod + def teardown_class(cls): + if cls.sim is not None: + try: + cls.sim.destroy() + print("sim destroyed successfully") + except Exception as e: + print(f"Error during sim.destroy(): {e}") + + +class TestDifferentialSolver(BaseSolverTest): + def setup_method(self): + self.setup_simulation(solver_type="DifferentialSolver") + + +if __name__ == "__main__": + torch.set_printoptions(precision=5, sci_mode=False) + pytest_args = ["-v", __file__] + pytest.main(pytest_args) diff --git a/tests/sim/solvers/test_opw_solver.py b/tests/sim/solvers/test_opw_solver.py new file mode 100644 index 00000000..6df71a18 --- /dev/null +++ b/tests/sim/solvers/test_opw_solver.py @@ -0,0 +1,139 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import pytest +import numpy as np + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim.robots import CobotMagicCfg + + +# Base test class for OPWSolver +class BaseSolverTest: + sim = None # Define as a class attribute + + def setup_simulation(self): + config = SimulationManagerCfg(headless=True, sim_device="cpu") + self.sim = SimulationManager(config) + self.sim.build_multiple_arenas(1) + self.sim.set_manual_update(False) + + cfg_dict = { + "uid": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [ + -0.3, + 0.3, + 1.0, + 1.0, + -1.2, + -1.2, + 0.0, + 0.0, + 0.6, + 0.6, + 0.0, + 0.0, + 0.05, + 0.05, + 0.05, + 0.05, + ], + "solver_cfg": { + "left_arm": { + "class_type": "OPWSolver", + "end_link_name": "left_link6", + "root_link_name": "left_arm_base", + "tcp": [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.143], [0, 0, 0, 1]], + }, + "right_arm": { + "class_type": "OPWSolver", + "end_link_name": "right_link6", + "root_link_name": "right_arm_base", + "tcp": [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.143], [0, 0, 0, 1]], + }, + }, + } + + self.robot: Robot = self.sim.add_robot(cfg=CobotMagicCfg.from_dict(cfg_dict)) + + @pytest.mark.parametrize("arm_name", ["left_arm", "right_arm"]) + def test_ik(self, arm_name: str): + # Test inverse kinematics (IK) with a 1x4x4 homogeneous matrix pose and a joint_seed + + qpos_fk = torch.tensor( + [[0.0, np.pi / 4, -np.pi / 4, 0.0, np.pi / 4, 0.0]], dtype=torch.float32 + ) + + fk_xpos = self.robot.compute_fk(qpos=qpos_fk, name=arm_name, to_matrix=True) + + res, ik_qpos = self.robot.compute_ik( + pose=fk_xpos, joint_seed=qpos_fk, name=arm_name + ) + + res, ik_qpos = self.robot.compute_ik(pose=fk_xpos, name=arm_name) + + if ik_qpos.dim() == 3: + ik_xpos = self.robot.compute_fk( + qpos=ik_qpos[0][0], name=arm_name, to_matrix=True + ) + else: + ik_xpos = self.robot.compute_fk(qpos=ik_qpos, name=arm_name, to_matrix=True) + + assert torch.allclose( + fk_xpos, ik_xpos, atol=5e-3, rtol=5e-3 + ), f"FK and IK results do not match for {arm_name}" + # test for failed xpos + invalid_pose = torch.tensor( + [ + [ + [1.0, 0.0, 0.0, 10.0], + [0.0, 1.0, 0.0, 10.0], + [0.0, 0.0, 1.0, 10.0], + [0.0, 0.0, 0.0, 1.0], + ] + ], + dtype=torch.float32, + device=self.robot.device, + ) + res, ik_qpos = self.robot.compute_ik( + pose=invalid_pose, joint_seed=ik_qpos, name=arm_name + ) + dof = ik_qpos.shape[-1] + assert res[0] == False + assert ik_qpos.shape == (1, dof) + + @classmethod + def teardown_class(cls): + if cls.sim is not None: + try: + cls.sim.destroy() + print("sim destroyed successfully") + except Exception as e: + print(f"Error during sim.destroy(): {e}") + + +class TestOPWSolver(BaseSolverTest): + def setup_method(self): + self.setup_simulation() + + +if __name__ == "__main__": + np.set_printoptions(precision=5, suppress=True) + pytest_args = ["-v", "-s", __file__] + pytest.main(pytest_args) diff --git a/tests/sim/solvers/test_pink_solver.py b/tests/sim/solvers/test_pink_solver.py new file mode 100644 index 00000000..590ed6dc --- /dev/null +++ b/tests/sim/solvers/test_pink_solver.py @@ -0,0 +1,146 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import torch +import pytest +import numpy as np + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim.cfg import RobotCfg +from embodichain.data import get_data_path + + +# Base test class for differential solver +class BaseSolverTest: + sim = None # Define as a class attribute + + def setup_simulation(self, solver_type: str): + # Set up simulation with specified device (CPU or CUDA) + config = SimulationManagerCfg(headless=True, sim_device="cpu") + self.sim = SimulationManager(config) + self.sim.build_multiple_arenas(1) + self.sim.set_manual_update(False) + + # Load robot URDF file + urdf = get_data_path("Rokae/SR5/SR5.urdf") + + assert os.path.isfile(urdf) + + cfg_dict = { + "fpath": urdf, + "control_parts": { + "main_arm": [ + "joint1", + "joint2", + "joint3", + "joint4", + "joint5", + "joint6", + ], + }, + "solver_cfg": { + "main_arm": { + "class_type": "PinkSolver", + "end_link_name": "ee_link", + "root_link_name": "base_link", + }, + }, + } + + self.robot: Robot = self.sim.add_robot(cfg=RobotCfg.from_dict(cfg_dict)) + + def test_differential_solver(self): + # Test differential solver with a 1x4x4 homogeneous matrix pose and a joint_seed + arm_name = "main_arm" + + qpos_fk = torch.tensor( + [[0.0, 0.0, np.pi / 2, 0.0, np.pi / 2, 0.0]], dtype=torch.float32 + ) + + fk_xpos = self.robot.compute_fk(qpos=qpos_fk, name=arm_name, to_matrix=True) + + # Define start and end poses + start_pose = fk_xpos.clone()[0] + end_pose = fk_xpos.clone()[0] + end_pose[:3, 3] += torch.tensor([0.0, 0.4, 0.0], dtype=torch.float32) + + # Interpolate poses + num_steps = 100 + interpolated_poses = [ + torch.lerp(start_pose, end_pose, t) for t in np.linspace(0, 1, num_steps) + ] + + ik_qpos = qpos_fk + + for i, pose in enumerate(interpolated_poses): + res, ik_qpos = self.robot.compute_ik( + pose=pose, joint_seed=ik_qpos, name=arm_name + ) + assert res, f"IK failed for step {i} with pose:\n{pose}" + + # Verify forward kinematics matches the target pose + ik_xpos = self.robot.compute_fk(qpos=ik_qpos, name=arm_name, to_matrix=True) + assert torch.allclose( + pose, ik_xpos, atol=1e-3, rtol=1e-3 + ), f"FK result does not match target pose at step {i}." + + # Set robot joint positions + self.robot.set_qpos( + qpos=ik_qpos, joint_ids=self.robot.get_joint_ids(arm_name) + ) + + # test for failed xpos + invalid_pose = torch.tensor( + [ + [ + [1.0, 0.0, 0.0, 10.0], + [0.0, 1.0, 0.0, 10.0], + [0.0, 0.0, 1.0, 10.0], + [0.0, 0.0, 0.0, 1.0], + ] + ], + dtype=torch.float32, + device=self.robot.device, + ) + res, ik_qpos = self.robot.compute_ik( + pose=invalid_pose, joint_seed=ik_qpos, name=arm_name + ) + dof = ik_qpos.shape[-1] + assert res[0] == False + assert ik_qpos.shape == (1, dof) + + @classmethod + def teardown_class(cls): + if cls.sim is not None: + try: + cls.sim.destroy() + print("sim destroyed successfully") + except Exception as e: + print(f"Error during sim.destroy(): {e}") + + +@pytest.mark.skip(reason="Skipping Pink tests temporarily") +class TestPinkSolver(BaseSolverTest): + def setup_method(self): + self.setup_simulation(solver_type="PinkSolver") + + +if __name__ == "__main__": + np.set_printoptions(precision=5, suppress=True) + pytest_args = ["-v", __file__] + pytest.main(pytest_args) diff --git a/tests/sim/solvers/test_pinocchio_solver.py b/tests/sim/solvers/test_pinocchio_solver.py new file mode 100644 index 00000000..db9dd360 --- /dev/null +++ b/tests/sim/solvers/test_pinocchio_solver.py @@ -0,0 +1,126 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import torch +import pytest +import numpy as np + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim.cfg import RobotCfg +from embodichain.data import get_data_path + + +# Base test class for CPU and CUDA +class BaseSolverTest: + sim = None # Define as a class attribute + + def setup_simulation(self, solver_type: str): + # Set up simulation with specified device (CPU or CUDA) + config = SimulationManagerCfg(headless=True, sim_device="cpu") + self.sim = SimulationManager(config) + self.sim.build_multiple_arenas(1) + self.sim.set_manual_update(False) + + # Load robot URDF file + urdf = get_data_path("DexforceW1V021/DexforceW1_v02_1.urdf") + assert os.path.isfile(urdf) + + cfg_dict = { + "fpath": urdf, + "control_parts": { + "left_arm": [f"LEFT_J{i+1}" for i in range(7)], + "right_arm": [f"RIGHT_J{i+1}" for i in range(7)], + }, + "solver_cfg": { + "left_arm": { + "class_type": solver_type, + "end_link_name": "left_ee", + "root_link_name": "left_arm_base", + }, + "right_arm": { + "class_type": solver_type, + "end_link_name": "right_ee", + "root_link_name": "right_arm_base", + }, + }, + } + + self.robot: Robot = self.sim.add_robot(cfg=RobotCfg.from_dict(cfg_dict)) + + @pytest.mark.parametrize("arm_name", ["left_arm", "right_arm"]) + def test_ik(self, arm_name: str): + # Test inverse kinematics (IK) with a 1x4x4 homogeneous matrix pose and a joint_seed + + qpos_fk = torch.tensor( + [[0.0, 0.0, 0.0, -np.pi / 4, 0.0, 0.0, 0.0]], dtype=torch.float32 + ) + + fk_xpos = self.robot.compute_fk(qpos=qpos_fk, name=arm_name, to_matrix=True) + + res, ik_qpos = self.robot.compute_ik(pose=fk_xpos, name=arm_name) + + if ik_qpos.dim() == 3: + ik_xpos = self.robot.compute_fk( + qpos=ik_qpos[0][0], name=arm_name, to_matrix=True + ) + else: + ik_xpos = self.robot.compute_fk(qpos=ik_qpos, name=arm_name, to_matrix=True) + + assert torch.allclose( + fk_xpos, ik_xpos, atol=5e-3, rtol=5e-3 + ), f"FK and IK results do not match for {arm_name}" + + # test for failed xpos + invalid_pose = torch.tensor( + [ + [ + [1.0, 0.0, 0.0, 10.0], + [0.0, 1.0, 0.0, 10.0], + [0.0, 0.0, 1.0, 10.0], + [0.0, 0.0, 0.0, 1.0], + ] + ], + dtype=torch.float32, + device=self.robot.device, + ) + res, ik_qpos = self.robot.compute_ik( + pose=invalid_pose, joint_seed=ik_qpos, name=arm_name + ) + dof = ik_qpos.shape[-1] + assert res[0] == False + assert ik_qpos.shape == (1, dof) + + @classmethod + def teardown_class(cls): + if cls.sim is not None: + try: + cls.sim.destroy() + print("sim destroyed successfully") + except Exception as e: + print(f"Error during sim.destroy(): {e}") + + +class TestPinocchioSolver(BaseSolverTest): + def setup_method(self): + self.setup_simulation(solver_type="PinocchioSolver") + + +if __name__ == "__main__": + np.set_printoptions(precision=5, suppress=True) + pytest_args = ["-v", __file__] + pytest.main(pytest_args) diff --git a/tests/sim/solvers/test_pytorch_solver.py b/tests/sim/solvers/test_pytorch_solver.py new file mode 100644 index 00000000..75129f10 --- /dev/null +++ b/tests/sim/solvers/test_pytorch_solver.py @@ -0,0 +1,130 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import torch +import pytest +import numpy as np + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim.cfg import RobotCfg +from embodichain.data import get_data_path + + +# Base test class for CPU and CUDA +class BaseSolverTest: + sim = None # Define as a class attribute + + def setup_simulation(self, solver_type: str): + # Set up simulation with specified device (CPU or CUDA) + config = SimulationManagerCfg(headless=True, sim_device="cpu") + self.sim = SimulationManager(config) + self.sim.build_multiple_arenas(1) + self.sim.set_manual_update(True) + + # Load robot URDF file + urdf = get_data_path("DexforceW1V021/DexforceW1_v02_1.urdf") + assert os.path.isfile(urdf) + + cfg_dict = { + "fpath": urdf, + "control_parts": { + "left_arm": [f"LEFT_J{i+1}" for i in range(7)], + "right_arm": [f"RIGHT_J{i+1}" for i in range(7)], + }, + "solver_cfg": { + "left_arm": { + "class_type": solver_type, + "end_link_name": "left_ee", + "root_link_name": "left_arm_base", + "ik_nearest_weight": [1.0, 1.0, 1.0, 0.9, 0.9, 0.1, 0.1], + }, + "right_arm": { + "class_type": solver_type, + "end_link_name": "right_ee", + "root_link_name": "right_arm_base", + }, + }, + } + + self.robot: Robot = self.sim.add_robot(cfg=RobotCfg.from_dict(cfg_dict)) + + # Wait for robot to stabilize. + self.sim.update(step=100) + + @pytest.mark.parametrize("arm_name", ["left_arm", "right_arm"]) + def test_ik(self, arm_name: str): + # Test inverse kinematics (IK) with a 1x4x4 homogeneous matrix pose and a joint_seed + + qpos_fk = torch.tensor( + [[0.0, 0.0, 0.0, -np.pi / 4, 0.0, 0.0, 0.0]], dtype=torch.float32 + ) + + fk_xpos = self.robot.compute_fk(qpos=qpos_fk, name=arm_name, to_matrix=True) + + res, ik_qpos = self.robot.compute_ik(pose=fk_xpos, name=arm_name) + + if ik_qpos.dim() == 3: + ik_xpos = self.robot.compute_fk( + qpos=ik_qpos[0][0], name=arm_name, to_matrix=True + ) + else: + ik_xpos = self.robot.compute_fk(qpos=ik_qpos, name=arm_name, to_matrix=True) + + assert torch.allclose( + fk_xpos, ik_xpos, atol=1e-2, rtol=1e-2 + ), f"FK and IK results do not match for {arm_name}" + + # test for failed xpos + invalid_pose = torch.tensor( + [ + [ + [1.0, 0.0, 0.0, 10.0], + [0.0, 1.0, 0.0, 10.0], + [0.0, 0.0, 1.0, 10.0], + [0.0, 0.0, 0.0, 1.0], + ] + ], + dtype=torch.float32, + device=self.robot.device, + ) + res, ik_qpos = self.robot.compute_ik( + pose=invalid_pose, joint_seed=ik_qpos, name=arm_name + ) + dof = ik_qpos.shape[-1] + assert res[0] == False + assert ik_qpos.shape == (1, dof) + + @classmethod + def teardown_class(cls): + if cls.sim is not None: + try: + cls.sim.destroy() + print("sim destroyed successfully") + except Exception as e: + print(f"Error during sim.destroy(): {e}") + + +class TestPytorchSolver(BaseSolverTest): + def setup_method(self): + self.setup_simulation(solver_type="PytorchSolver") + + +if __name__ == "__main__": + np.set_printoptions(precision=5, suppress=True) + test_solver = TestPytorchSolver() + test_solver.setup_method() diff --git a/tests/sim/solvers/test_srs_solver.py b/tests/sim/solvers/test_srs_solver.py new file mode 100644 index 00000000..13860485 --- /dev/null +++ b/tests/sim/solvers/test_srs_solver.py @@ -0,0 +1,307 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import torch +import pytest +import numpy as np + +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim.cfg import RobotCfg +from embodichain.data import get_data_path + +from embodichain.lab.sim.solvers.srs_solver import SRSSolver, SRSSolverCfg +from embodichain.lab.sim.robots.dexforce_w1.types import ( + DexforceW1ArmSide, + DexforceW1ArmKind, + DexforceW1Version, +) +from embodichain.lab.sim.robots.dexforce_w1.params import ( + W1ArmKineParams, +) + + +class BaseSolverTest: + solver = {} + + def get_arm_config(self): + return [ + (DexforceW1ArmSide.LEFT, DexforceW1ArmKind.ANTHROPOMORPHIC, "left_arm"), + (DexforceW1ArmSide.RIGHT, DexforceW1ArmKind.ANTHROPOMORPHIC, "right_arm"), + (DexforceW1ArmSide.LEFT, DexforceW1ArmKind.INDUSTRIAL, "left_arm"), + (DexforceW1ArmSide.RIGHT, DexforceW1ArmKind.INDUSTRIAL, "right_arm"), + ] + + def setup_solver(self, solver_type: str, device: str = "cpu"): + for arm_side, arm_kind, arm_name in self.get_arm_config(): + arm_params = W1ArmKineParams( + arm_side=arm_side, + arm_kind=arm_kind, + version=DexforceW1Version.V021, + ) + if arm_kind == DexforceW1ArmKind.ANTHROPOMORPHIC: + urdf = get_data_path("DexforceW1V021/DexforceW1_v02_1.urdf") + else: + urdf = get_data_path("DexforceW1V021/DexforceW1_v02_2.urdf") + + cfg = SRSSolverCfg() + cfg.joint_names = [ + f"{'LEFT' if arm_side == DexforceW1ArmSide.LEFT else 'RIGHT'}_J{i+1}" + for i in range(7) + ] + cfg.end_link_name = ( + "left_ee" if arm_side == DexforceW1ArmSide.LEFT else "right_ee" + ) + cfg.root_link_name = ( + "left_arm_base" + if arm_side == DexforceW1ArmSide.LEFT + else "right_arm_base" + ) + cfg.urdf_path = urdf + cfg.dh_params = arm_params.dh_params + cfg.qpos_limits = arm_params.qpos_limits + cfg.T_e_oe = arm_params.T_e_oe + cfg.T_b_ob = arm_params.T_b_ob + cfg.link_lengths = arm_params.link_lengths + cfg.rotation_directions = arm_params.rotation_directions + + solver_key = f"{arm_name}_{arm_kind.name}" + self.solver[solver_key] = SRSSolver(cfg=cfg, num_envs=1, device=device) + + @pytest.mark.parametrize( + "arm_side, arm_kind, arm_name", + [ + (DexforceW1ArmSide.LEFT, DexforceW1ArmKind.ANTHROPOMORPHIC, "left_arm"), + (DexforceW1ArmSide.RIGHT, DexforceW1ArmKind.ANTHROPOMORPHIC, "right_arm"), + (DexforceW1ArmSide.LEFT, DexforceW1ArmKind.INDUSTRIAL, "left_arm"), + (DexforceW1ArmSide.RIGHT, DexforceW1ArmKind.INDUSTRIAL, "right_arm"), + ], + ) + def test_ik( + self, arm_side: DexforceW1ArmSide, arm_kind: DexforceW1ArmKind, arm_name: str + ): + # Test inverse kinematics (IK) with a 1x4x4 homogeneous matrix pose and a joint_seed + solver_key = f"{arm_name}_{arm_kind.name}" + device = self.solver[solver_key].device + + qpos_fk = torch.tensor( + [[0.0, 0.0, 0.0, -np.pi / 4, 0.0, 0.0, 0.0]], + dtype=torch.float32, + device=device, + ) + + fk_xpos = self.solver[solver_key].get_fk(qpos=qpos_fk) + + _, ik_qpos = self.solver[solver_key].get_ik(fk_xpos, return_all_solutions=False) + + ik_xpos = self.solver[solver_key].get_fk(qpos=ik_qpos[:, 0, :]) + + assert torch.allclose( + fk_xpos, ik_xpos, atol=1e-3, rtol=1e-3 + ), f"FK and IK results do not match for {solver_key}" + + @classmethod + def teardown_class(cls): + if cls.solver is not None: + try: + del cls.solver + print("solver destroyed successfully") + except Exception as e: + print(f"Error during solver destruction: {e}") + + +# Base test class for CPU and CUDA +class BaseRobotSolverTest: + sim = None # Define as a class attribute + + def setup_simulation(self, solver_type: str, device: str = "cpu"): + # Set up simulation with specified device (CPU or CUDA) + config = SimulationManagerCfg(headless=True, sim_device=device) + self.sim = SimulationManager(config) + self.sim.build_multiple_arenas(1) + self.sim.set_manual_update(True) + + # Load robot URDF file + urdf = get_data_path("DexforceW1V021/DexforceW1_v02_1.urdf") + assert os.path.isfile(urdf) + + w1_left_arm_params = W1ArmKineParams( + arm_side=DexforceW1ArmSide.LEFT, + arm_kind=DexforceW1ArmKind.ANTHROPOMORPHIC, + version=DexforceW1Version.V021, + ) + w1_right_arm_params = W1ArmKineParams( + arm_side=DexforceW1ArmSide.RIGHT, + arm_kind=DexforceW1ArmKind.ANTHROPOMORPHIC, + version=DexforceW1Version.V021, + ) + + # Robot configuration dictionary + cfg_dict = { + "fpath": urdf, + "control_parts": { + "left_arm": [f"LEFT_J{i+1}" for i in range(7)], + "right_arm": [f"RIGHT_J{i+1}" for i in range(7)], + "torso": ["ANKLE", "KNEE", "BUTTOCK", "WAIST"], + "head": [f"NECK{i+1}" for i in range(2)], + }, + "drive_pros": { + "stiffness": { + "LEFT_J[1-7]": 1e4, + "RIGHT_J[1-7]": 1e4, + "ANKLE": 1e7, + "KNEE": 1e7, + "BUTTOCK": 1e7, + "WAIST": 1e7, + }, + "damping": { + "LEFT_J[1-7]": 1e3, + "RIGHT_J[1-7]": 1e3, + "ANKLE": 1e4, + "KNEE": 1e4, + "BUTTOCK": 1e4, + "WAIST": 1e4, + }, + "max_effort": { + "LEFT_J[1-7]": 1e5, + "RIGHT_J[1-7]": 1e5, + "ANKLE": 1e10, + "KNEE": 1e10, + "BUTTOCK": 1e10, + "WAIST": 1e10, + }, + }, + "attrs": { + "mass": 1e-1, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "linear_damping": 0.7, + "angular_damping": 0.7, + "max_depenetration_velocity": 10.0, + "min_position_iters": 32, + "min_velocity_iters": 8, + }, + "solver_cfg": { + "left_arm": { + "class_type": solver_type, + "end_link_name": "left_ee", + "root_link_name": "left_arm_base", + "dh_params": w1_left_arm_params.dh_params, + "qpos_limits": w1_left_arm_params.qpos_limits, + "T_b_ob": w1_right_arm_params.T_b_ob, + "T_e_oe": w1_left_arm_params.T_e_oe, + "link_lengths": w1_left_arm_params.link_lengths, + "rotation_directions": w1_left_arm_params.rotation_directions, + }, + "right_arm": { + "class_type": solver_type, + "end_link_name": "right_ee", + "root_link_name": "right_arm_base", + "dh_params": w1_right_arm_params.dh_params, + "qpos_limits": w1_right_arm_params.qpos_limits, + "T_b_ob": w1_right_arm_params.T_b_ob, + "T_e_oe": w1_right_arm_params.T_e_oe, + "link_lengths": w1_right_arm_params.link_lengths, + "rotation_directions": w1_right_arm_params.rotation_directions, + }, + }, + } + + self.robot: Robot = self.sim.add_robot(cfg=RobotCfg.from_dict(cfg_dict)) + + # Wait for robot to stabilize. + self.sim.update(step=100) + + @pytest.mark.parametrize("arm_name", ["left_arm", "right_arm"]) + def test_robot_ik(self, arm_name: str): + # Test inverse kinematics (IK) with a 1x4x4 homogeneous matrix pose and a joint_seed + + qpos_fk = torch.tensor( + [[0.0, 0.0, 0.0, -np.pi / 4, 0.0, 0.0, 0.0]], + dtype=torch.float32, + device=self.robot.device, + ) + + fk_xpos = self.robot.compute_fk(qpos=qpos_fk, name=arm_name, to_matrix=True) + + res, ik_qpos = self.robot.compute_ik(pose=fk_xpos, name=arm_name) + + if ik_qpos.dim() == 3: + ik_xpos = self.robot.compute_fk( + qpos=ik_qpos[0][0], name=arm_name, to_matrix=True + ) + else: + ik_xpos = self.robot.compute_fk(qpos=ik_qpos, name=arm_name, to_matrix=True) + + assert torch.allclose( + fk_xpos, ik_xpos, atol=1e-4, rtol=1e-4 + ), f"FK and IK results do not match for {arm_name}" + + # test for failed xpos + invalid_pose = torch.tensor( + [ + [ + [1.0, 0.0, 0.0, 10.0], + [0.0, 1.0, 0.0, 10.0], + [0.0, 0.0, 1.0, 10.0], + [0.0, 0.0, 0.0, 1.0], + ] + ], + dtype=torch.float32, + device=self.robot.device, + ) + res, ik_qpos = self.robot.compute_ik( + pose=invalid_pose, joint_seed=ik_qpos, name=arm_name + ) + dof = ik_qpos.shape[-1] + assert res[0] == False + assert ik_qpos.shape == (1, dof) + + @classmethod + def teardown_class(cls): + if cls.sim is not None: + try: + cls.sim.destroy() + print("sim destroyed successfully") + except Exception as e: + print(f"Error during sim.destroy(): {e}") + + +class TestSRSCPUSolver(BaseSolverTest): + def setup_method(self): + self.setup_solver(solver_type="SRSSolver", device="cpu") + + +class TestSRSCUDASolver(BaseSolverTest): + def setup_method(self): + self.setup_solver(solver_type="SRSSolver", device="cuda") + + +class TestSRSCPURobotSolver(BaseRobotSolverTest): + def setup_method(self): + self.setup_simulation(solver_type="SRSSolver", device="cpu") + + +class TestSRSCUDARobotSolver(BaseRobotSolverTest): + def setup_method(self): + self.setup_simulation(solver_type="SRSSolver", device="cuda") + + +if __name__ == "__main__": + np.set_printoptions(precision=5, suppress=True) + pytest_args = ["-v", __file__] + pytest.main(pytest_args) diff --git a/tests/sim/test_sim_manager.py b/tests/sim/test_sim_manager.py new file mode 100644 index 00000000..72b2a254 --- /dev/null +++ b/tests/sim/test_sim_manager.py @@ -0,0 +1,63 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import os +import dexsim.environment +import numpy as np +import dexsim +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from dexsim.utility.path import get_resources_data_path + + +def test_sim_init(): + config = SimulationManagerCfg() + config.headless = True + + sim = SimulationManager(config) + sim.get_env().clean() + + assert isinstance(sim.get_env(), dexsim.environment.Env) + assert isinstance(sim.get_world(), dexsim.World) + + # test add_sensor + intrinsic = np.array([[600, 0, 320], [0, 600, 240], [0, 0, 1]]) + cam1 = sim.add_sensor( + "MonocularCam", sensor_uid="cam1", resolution=(640, 480), intrinsic=intrinsic + ) + assert sim.get_sensor("cam1") == cam1 + assert len(sim.get_sensor_uid_list()) == 1 + assert sim.get_sensor_uid_list()[0] == "cam1" + + # TODO: test add_robot + + # test_add_fixed_actor. + model_path = get_resources_data_path("Model", "lego", "lego.ply") + + actor = sim.add_fixed_actor(fpath=model_path, init_pose=np.eye(4)) + assert sim.get_fixed_actor_uid_list() == ["lego.ply"] + assert sim.get_fixed_actor("lego.ply") == actor + + sim.remove_fixed_actor("lego.ply") + assert sim.get_fixed_actor_uid_list() == [] + + # test add_dynamic_actor + actor = sim.add_dynamic_actor(fpath=model_path, init_pose=np.eye(4)) + assert sim.get_dynamic_actor_uid_list() == ["lego.ply"] + assert sim.get_dynamic_actor("lego.ply") == actor + + +if __name__ == "__main__": + test_sim_init() diff --git a/tests/toolkits/test_pg_grasp.py b/tests/toolkits/test_pg_grasp.py new file mode 100644 index 00000000..dd9f79e5 --- /dev/null +++ b/tests/toolkits/test_pg_grasp.py @@ -0,0 +1,96 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import open3d as o3d +import numpy as np +import os +from embodichain.toolkits.graspkit.pg_grasp import ( + AntipodalGenerator, + GraspSelectMethod, +) +from embodichain.data import get_data_path + + +def test_antipodal_score_selector(is_visual: bool = False): + mesh_path = get_data_path("ChainRainSec/mesh.ply") + mesh_o3dt = o3d.t.io.read_triangle_mesh(mesh_path) + generator = AntipodalGenerator( + mesh_o3dt=mesh_o3dt, + open_length=0.1, + max_angle=np.pi / 6, + surface_sample_num=5000, + cache_dir=None, + ) + grasp_list = generator.select_grasp( + approach_direction=np.array([0, 0, -1]), + select_num=5, + select_method=GraspSelectMethod.NORMAL_SCORE, + ) + assert len(grasp_list) == 5 + if is_visual: + visual_mesh_list = generator.grasp_pose_visual(grasp_list) + visual_mesh_list = [visual_mesh.to_legacy() for visual_mesh in visual_mesh_list] + o3d.visualization.draw_geometries(visual_mesh_list) + + +def test_antipodal_position_selector(is_visual: bool = False): + mesh_path = get_data_path("ChainRainSec/mesh.ply") + mesh_o3dt = o3d.t.io.read_triangle_mesh(mesh_path) + generator = AntipodalGenerator( + mesh_o3dt=mesh_o3dt, + open_length=0.1, + max_angle=np.pi / 6, + surface_sample_num=5000, + cache_dir=None, + ) + grasp_list = generator.select_grasp( + approach_direction=np.array([0, 0, -1]), + select_num=5, + select_method=GraspSelectMethod.NEAR_APPROACH, + ) + assert len(grasp_list) == 5 + if is_visual: + visual_mesh_list = generator.grasp_pose_visual(grasp_list) + visual_mesh_list = [visual_mesh.to_legacy() for visual_mesh in visual_mesh_list] + o3d.visualization.draw_geometries(visual_mesh_list) + + +def test_antipodal_center_selector(is_visual: bool = False): + mesh_path = get_data_path("ChainRainSec/mesh.ply") + mesh_o3dt = o3d.t.io.read_triangle_mesh(mesh_path) + generator = AntipodalGenerator( + mesh_o3dt=mesh_o3dt, + open_length=0.1, + max_angle=np.pi / 6, + surface_sample_num=5000, + cache_dir=None, + ) + grasp_list = generator.select_grasp( + approach_direction=np.array([0, 0, -1]), + select_num=5, + select_method=GraspSelectMethod.CENTER, + ) + assert len(grasp_list) == 5 + if is_visual: + visual_mesh_list = generator.grasp_pose_visual(grasp_list) + visual_mesh_list = [visual_mesh.to_legacy() for visual_mesh in visual_mesh_list] + o3d.visualization.draw_geometries(visual_mesh_list) + + +if __name__ == "__main__": + test_antipodal_score_selector(True) + test_antipodal_position_selector(True) + test_antipodal_center_selector(True) diff --git a/tests/unitest.sh b/tests/unitest.sh new file mode 100755 index 00000000..d827e1cb --- /dev/null +++ b/tests/unitest.sh @@ -0,0 +1,93 @@ +echo "exec python ..." + +export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +log_info() { + echo -e "${BLUE}[INFO] $1${NC}" +} + +log_success() { + echo -e "${GREEN}[SUCCESS] $1${NC}" +} + +log_warn() { + echo -e "${YELLOW}[WARN] $1${NC}" +} + +log_error() { + echo -e "${RED}[ERROR] $1${NC}" +} + +run_python_script() { + local script_name="$1" + local script_path="$2" + + log_info "Running: ${script_name}" + + if python "$script_path"; then + log_success "${script_name} succeeded" + return 0 + else + log_error "${script_name} failed" + return 1 + fi +} + +run_pytest() { + local test_path="$1" + log_info "Running pytest: ${test_path}" + + local pytest_args=( + "--durations=1000" # record the slowest 1000 tests + "--tb=long" # long traceback + "-vv" # verbose + "--disable-warnings" # disable warnings + "--color=yes" # enable color output + ) + + pytest "${pytest_args[@]}" "$test_path" + local status=$? + + # Check if no tests were collected + if pytest --collect-only "$test_path" | grep -q "collected 0 items"; then + log_warn "No tests collected: ${test_path}" + return 0 + fi + + # Check pytest return code + if [ $status -ne 0 ]; then + log_error "pytest failed: ${test_path}" + exit 1 + fi +} + +main() { + echo "Starting scripts..." + + run_python_script "pourwater_offline_test" "tests/datasets/run_pourwater_env_offline.py" || exit 1 + + echo "Starting pytest unit tests..." + + for test_dir in tests/*/; do + # Check whether the directory contains any recursive test_*.py files; do not skip if top-level has none (supports subdirectory structures) + if ! find "$test_dir" -type f -name 'test_*.py' | grep -q .; then + log_warn "Skipping empty directory or no test files: ${test_dir}" + continue + fi + run_pytest "$test_dir" + done + + log_success "All test scripts and unit tests completed!" +} + +main "$@" + +# # demo +# ./demo/origin_demo.sh CI +# echo -e "\e[32morigin_demo executed successfully\e[0m" From cc52fa4204ae6d6f21c7c539a11690812a0e4c35 Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Fri, 21 Nov 2025 17:20:47 +0000 Subject: [PATCH 03/92] Try to fix docs build (#2) --- .readthedocs.yaml | 8 +++++--- docs/requirements.txt | 1 + .../embodichain/embodichain.lab.gym.rst | 14 -------------- .../embodichain/embodichain.lab.gym.utils.rst | 8 -------- .../api_reference/embodichain/embodichain.lab.rst | 9 --------- .../embodichain/embodichain.utils.rst | 9 --------- docs/source/conf.py | 7 ++++--- docs/source/quick_start/install.md | 15 ++++----------- pyproject.toml | 5 +++-- 9 files changed, 17 insertions(+), 59 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 17245082..0aa6b2f0 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -18,6 +18,8 @@ sphinx: # declare the Python requirements required to build your documentation # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html python: - install: - - requirements: docs/requirements.txt - \ No newline at end of file + install: + - requirements: docs/requirements.txt + - method: pip + path: . + \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt index cacbd083..f2d11c7d 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,5 @@ sphinx>=4.0 +autodocsumm sphinx-book-theme>=0.3.0 sphinx-tabs sphinx-copybutton diff --git a/docs/source/api_reference/embodichain/embodichain.lab.gym.rst b/docs/source/api_reference/embodichain/embodichain.lab.gym.rst index e788b8f7..addf6c10 100644 --- a/docs/source/api_reference/embodichain/embodichain.lab.gym.rst +++ b/docs/source/api_reference/embodichain/embodichain.lab.gym.rst @@ -123,13 +123,6 @@ Registration System Gymnasium wrapper that adds episode time limits to environments. -Action Conversion Utilities -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. automodule:: embodichain.lab.gym.utils.action_conversion - - Utilities for converting between different action representations in robotic environments. - Gymnasium Utilities ~~~~~~~~~~~~~~~~~~ @@ -137,13 +130,6 @@ Gymnasium Utilities Helper functions and utilities for Gymnasium environment integration. -Image Utilities -~~~~~~~~~~~~~~~ - -.. automodule:: embodichain.lab.gym.utils.img_utils - - Image processing utilities for visual observations and rendering. - Miscellaneous Utilities ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/source/api_reference/embodichain/embodichain.lab.gym.utils.rst b/docs/source/api_reference/embodichain/embodichain.lab.gym.utils.rst index a0c9f265..4db73036 100644 --- a/docs/source/api_reference/embodichain/embodichain.lab.gym.utils.rst +++ b/docs/source/api_reference/embodichain/embodichain.lab.gym.utils.rst @@ -25,20 +25,12 @@ Registration System Utility Modules --------------- -Action Conversion -~~~~~~~~~~~~~~~~~ - -.. automodule:: embodichain.lab.gym.utils.action_conversion Gymnasium Utilities ~~~~~~~~~~~~~~~~~~~ .. automodule:: embodichain.lab.gym.utils.gym_utils -Image Utilities -~~~~~~~~~~~~~~~ - -.. automodule:: embodichain.lab.gym.utils.img_utils Miscellaneous ~~~~~~~~~~~~~ diff --git a/docs/source/api_reference/embodichain/embodichain.lab.rst b/docs/source/api_reference/embodichain/embodichain.lab.rst index e8a7d565..603c8058 100644 --- a/docs/source/api_reference/embodichain/embodichain.lab.rst +++ b/docs/source/api_reference/embodichain/embodichain.lab.rst @@ -10,7 +10,6 @@ devices gym sim - utility Device Management ----------------- @@ -19,11 +18,3 @@ Device Management :members: :undoc-members: :show-inheritance: - -Utilities ---------- - -.. automodule:: embodichain.lab.utility - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/api_reference/embodichain/embodichain.utils.rst b/docs/source/api_reference/embodichain/embodichain.utils.rst index 52ad4a4f..490962ce 100644 --- a/docs/source/api_reference/embodichain/embodichain.utils.rst +++ b/docs/source/api_reference/embodichain/embodichain.utils.rst @@ -10,7 +10,6 @@ warp configclass file - heat_map logger math module_utils @@ -43,14 +42,6 @@ File Operations :undoc-members: :show-inheritance: -Heat Map Utilities ------------------- - -.. automodule:: embodichain.utils.heat_map - :members: - :undoc-members: - :show-inheritance: - Logging ------- diff --git a/docs/source/conf.py b/docs/source/conf.py index 311ddbf4..ed48c59a 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -10,9 +10,7 @@ import sys -project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) -package_root = os.path.join(project_root, "embodichain") -sys.path.insert(0, package_root) +sys.path.insert(0, os.path.abspath("../..")) project = "EmbodiChain" @@ -30,6 +28,7 @@ extensions = [ + "autodocsumm", "sphinx.ext.autodoc", "sphinx.ext.autosummary", "sphinx.ext.napoleon", @@ -42,6 +41,8 @@ napoleon_google_docstring = True napoleon_numpy_docstring = True +autodoc_typehints = "signature" +autodoc_class_signature = "separated" # generate autosummary even if no references autosummary_generate = True autosummary_generate_overwrite = False diff --git a/docs/source/quick_start/install.md b/docs/source/quick_start/install.md index 8a365939..7641687e 100644 --- a/docs/source/quick_start/install.md +++ b/docs/source/quick_start/install.md @@ -40,15 +40,6 @@ docker pull dexforce/embodichain:ubuntu22.04-cuda12.8 > **We strongly recommend using a virtual environment to avoid dependency conflicts.** -Install `DexSim` manually: -```bash -# If you are using Python 3.10 -pip install http://pyp.open3dv.site:2345/packages/dexsim_engine-0.3.6-cp310-cp310-manylinux_2_31_x86_64.whl -``` - -> We are working on uploading DexSim to PyPI for easier installation. Please stay tuned! - - Clone the EmbodiChain repository: ```bash git clone https://github.com/DexForce/EmbodiChain.git @@ -60,12 +51,14 @@ Install the project in development mode: pip install -e . ``` - ### Verify Installation To verify that EmbodiChain is installed correctly, run a simple demo script to create a simulation scene: ```bash - python scripts/tutorials/sim/create_scene.py +python scripts/tutorials/sim/create_scene.py + +# Or run in headless mode. +python scripts/tutorials/sim/create_scene.py --headless ``` --- diff --git a/pyproject.toml b/pyproject.toml index 83b28a47..109b0baa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,15 +18,16 @@ build-backend = "setuptools.build_meta:__legacy__" [project] name = "embodichain" version = "0.0.1" -description = "A modular platform for building generalized embodied intelligence." +description = "An end-to-end, GPU-accelerated, and modular platform for building generalized Embodied Intelligence." readme = "README.md" -authors = [ { name = "Dexforce" } ] +authors = [ { name = "EmbodiChain Developers" } ] requires-python = ">=3.9" # Core install dependencies (kept from requirements.txt). Some VCS links are # specified using PEP 508 direct references where present. dependencies = [ + "dexsim_engine @ http://pyp.open3dv.site:2345/packages/dexsim_engine-0.3.6-cp310-cp310-manylinux_2_31_x86_64.whl", "setuptools==69.5.1", "gymnasium==0.29.1", "langchain==0.2.14", From 361a39c8a1e3a9eca3b9aa948e46e0d8e725784f Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Sat, 22 Nov 2025 14:33:19 +0000 Subject: [PATCH 04/92] Add tmp docs link (#3) --- README.md | 8 ++++---- docs/source/introduction.rst | 8 ++++---- embodichain/lab/sim/shapes.py | 5 +---- tests/datasets/test_online_training.py | 1 - 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 61c352a4..cf83ecbe 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # EmbodiChain ![teaser](assets/imgs/teaser.jpg) -**📘 [Documentation](http://192.168.3.120/MixedAI/docs_dev/embodichain/index.html)** +**📘 [Documentation](https://6921c7e19027fbac6753678c--astounding-horse-770602.netlify.app/introduction)** --- EmbodiChain is an end-to-end, GPU-accelerated framework for Embodied AI. It streamlines research and development by unifying high-performance simulation, real-to-sim data pipelines, modular model architectures, and efficient training workflows. This integration enables rapid experimentation, seamless deployment of intelligent agents, and effective Sim2Real transfer for real-world robotic systems. @@ -25,9 +25,9 @@ EmbodiChain is an end-to-end, GPU-accelerated framework for Embodied AI. It stre To get started with EmbodiChain, follow these steps: -- [Installation Guide](http://192.168.3.120/MixedAI/docs_dev/embodichain/quick_start/install.html) -- [Quick Start Tutorial](http://192.168.3.120/MixedAI/docs_dev/embodichain/tutorial/index.html) -- [API Reference](http://192.168.3.120/MixedAI/docs_dev/embodichain/api_reference/index.html) +- [Installation Guide](https://6921c7e19027fbac6753678c--astounding-horse-770602.netlify.app/quick_start/install) +- [Quick Start Tutorial](https://6921c7e19027fbac6753678c--astounding-horse-770602.netlify.app/tutorial/) +- [API Reference](https://6921c7e19027fbac6753678c--astounding-horse-770602.netlify.app/api_reference/) ## Citation diff --git a/docs/source/introduction.rst b/docs/source/introduction.rst index 404541da..f82c0afc 100644 --- a/docs/source/introduction.rst +++ b/docs/source/introduction.rst @@ -9,7 +9,7 @@ EmbodiChain .. image:: ../../assets/imgs/teaser.jpg :alt: teaser -📘 `Documentation `_ +📘 `Documentation `_ --- @@ -37,9 +37,9 @@ Getting Started To get started with EmbodiChain, follow these steps: -* `Installation Guide `_ -* `Quick Start Tutorial `_ -* `API Reference `_ +* `Installation Guide `_ +* `Quick Start Tutorial `_ +* `API Reference `_ Citation diff --git a/embodichain/lab/sim/shapes.py b/embodichain/lab/sim/shapes.py index 8135943b..d7cb1eea 100644 --- a/embodichain/lab/sim/shapes.py +++ b/embodichain/lab/sim/shapes.py @@ -106,10 +106,7 @@ class MeshCfg(ShapeCfg): """File path to the shape mesh file.""" load_option: LoadOption = LoadOption() - """Options for loading and processing the shape. - - Please refer to dexsim.types.LoadOption for more details: http://192.168.3.120/MixedAI/docs_dev/dexsim/tutorial/basics/physics/actor.html - """ + """Options for loading and processing the shape.""" compute_uv: bool = False """Whether to compute UV coordinates for the shape. Defaults to False. diff --git a/tests/datasets/test_online_training.py b/tests/datasets/test_online_training.py index 1e05daa4..aafb9c8a 100644 --- a/tests/datasets/test_online_training.py +++ b/tests/datasets/test_online_training.py @@ -28,7 +28,6 @@ class TestDataDictExtractor(unittest.TestCase, metaclass=UnittestMetaclass): datacenter_backup = Path("/tmp/datacenter_test") - base_url = "http://192.168.3.120/MixedAI/" def setUp(self) -> None: pass From c1339279f3f11cd58025baf3952960cff793ec0a Mon Sep 17 00:00:00 2001 From: Lihao Zheng <108066621+LihaoZheng-git@users.noreply.github.com> Date: Sun, 23 Nov 2025 00:55:29 -0600 Subject: [PATCH 05/92] Simple modifications to documentation (#4) Co-authored-by: Lihao --- docs/source/conf.py | 2 +- docs/source/overview/gym/index.rst | 3 ++- docs/source/overview/vla/index.rst | 2 ++ docs/source/resources/robot/index.rst | 2 ++ docs/source/resources/task/index.rst | 6 +++++- docs/source/resources/task/pour_water.md | 3 --- 6 files changed, 12 insertions(+), 6 deletions(-) delete mode 100644 docs/source/resources/task/pour_water.md diff --git a/docs/source/conf.py b/docs/source/conf.py index ed48c59a..3aac3af3 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -64,4 +64,4 @@ html_theme = "sphinx_book_theme" html_static_path = ["_static"] -html_logo = "_static/logo_e.png" +# html_logo = "_static/logo_e.png" diff --git a/docs/source/overview/gym/index.rst b/docs/source/overview/gym/index.rst index 7781adfb..b0fe003d 100644 --- a/docs/source/overview/gym/index.rst +++ b/docs/source/overview/gym/index.rst @@ -1,5 +1,6 @@ Embodied Environments ================== -Overview of the Embodied Environments: +*To be completed by adding a detailed description of the Embodied Environments.* + diff --git a/docs/source/overview/vla/index.rst b/docs/source/overview/vla/index.rst index dc775db1..dcb4c123 100644 --- a/docs/source/overview/vla/index.rst +++ b/docs/source/overview/vla/index.rst @@ -1,2 +1,4 @@ Vision-Language-Action Models ================== + +*To be completed by adding an example of how to build a Vision-Language-Action (VLA) pipeline in EmbodiChain.* diff --git a/docs/source/resources/robot/index.rst b/docs/source/resources/robot/index.rst index 621c5294..2ec774f6 100644 --- a/docs/source/resources/robot/index.rst +++ b/docs/source/resources/robot/index.rst @@ -1,6 +1,8 @@ Supported Robots ====================== +*To be completed by adding more well-defined robot like LeRobot, Unitree H1/G1, etc.* + .. toctree:: :maxdepth: 1 diff --git a/docs/source/resources/task/index.rst b/docs/source/resources/task/index.rst index 7a83855d..998f6614 100644 --- a/docs/source/resources/task/index.rst +++ b/docs/source/resources/task/index.rst @@ -1,7 +1,11 @@ Supported Tasks ====================== +*To be completed by adding more tasks and task descriptions.* + .. toctree:: :maxdepth: 1 - Pour Water \ No newline at end of file + Push Cube + Pour Water + diff --git a/docs/source/resources/task/pour_water.md b/docs/source/resources/task/pour_water.md deleted file mode 100644 index a5be3b73..00000000 --- a/docs/source/resources/task/pour_water.md +++ /dev/null @@ -1,3 +0,0 @@ -# Pour Water - -Zhao Runyi is pouring water now, please do not disturb him... \ No newline at end of file From 417244ad1f6e2b35f9b6f4494fc1baa3d6451236 Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Mon, 24 Nov 2025 01:22:09 +0000 Subject: [PATCH 06/92] Remove some codes (#5) --- configs/gym/pour_water/action_config.json | 6 +- configs/gym/pour_water/gym_config.json | 69 - .../reality_config_PourWaterW1Single_v3.json | 582 --------- configs/gym/scoop_ice/gym_config.json | 19 - embodichain/data/__init__.py | 17 - embodichain/data/assets/demo_assets.py | 7 +- embodichain/data/assets/eef_assets.py | 19 +- embodichain/data/assets/materials.py | 7 +- embodichain/data/assets/obj_assets.py | 41 +- embodichain/data/assets/robot_assets.py | 33 +- embodichain/data/assets/scene_assets.py | 5 +- embodichain/data/assets/w1_assets.py | 39 +- embodichain/data/constants.py | 4 +- embodichain/data/data_engine/__init__.py | 15 - .../data/data_engine/data_dict_extractor.py | 1135 ----------------- .../data/data_engine/datasets/vla_datasets.py | 521 -------- embodichain/data/data_engine/online/engine.py | 525 -------- embodichain/data/data_engine/online/enum.py | 34 - .../data_engine/online/online_generator.py | 191 --- embodichain/data/data_engine/unified_state.py | 381 ------ embodichain/data/enum.py | 305 +---- embodichain/data/global_indices.py | 132 -- embodichain/data/global_mapping.py | 161 --- .../envs/action_bank/configurable_action.py | 13 +- embodichain/lab/gym/envs/embodied_env.py | 34 +- embodichain/lab/gym/envs/managers/events.py | 2 +- .../envs/{ => managers}/object/__init__.py | 0 .../lab/gym/envs/managers/object/geometry.py | 188 +++ embodichain/lab/gym/envs/object/geometry.py | 138 -- embodichain/lab/gym/utils/gym_utils.py | 3 +- embodichain/lab/gym/utils/misc.py | 206 +-- embodichain/lab/scripts/generate_video.py | 162 --- embodichain/lab/scripts/preview_env.py | 9 - embodichain/lab/scripts/run_env.py | 143 +-- embodichain/lab/sim/utility/mesh_utils.py | 102 +- tests/datasets/test_online_training.py | 101 -- 36 files changed, 350 insertions(+), 4999 deletions(-) delete mode 100644 configs/gym/real2sim/reality_config_PourWaterW1Single_v3.json delete mode 100644 embodichain/data/data_engine/__init__.py delete mode 100644 embodichain/data/data_engine/data_dict_extractor.py delete mode 100644 embodichain/data/data_engine/datasets/vla_datasets.py delete mode 100644 embodichain/data/data_engine/online/engine.py delete mode 100644 embodichain/data/data_engine/online/enum.py delete mode 100644 embodichain/data/data_engine/online/online_generator.py delete mode 100644 embodichain/data/data_engine/unified_state.py delete mode 100644 embodichain/data/global_indices.py delete mode 100644 embodichain/data/global_mapping.py rename embodichain/lab/gym/envs/{ => managers}/object/__init__.py (100%) create mode 100644 embodichain/lab/gym/envs/managers/object/geometry.py delete mode 100644 embodichain/lab/gym/envs/object/geometry.py delete mode 100644 embodichain/lab/scripts/generate_video.py delete mode 100644 tests/datasets/test_online_training.py diff --git a/configs/gym/pour_water/action_config.json b/configs/gym/pour_water/action_config.json index 42f036a8..d49561a4 100644 --- a/configs/gym/pour_water/action_config.json +++ b/configs/gym/pour_water/action_config.json @@ -286,7 +286,7 @@ ] }, { - "name": "is_qpos_exceed_new", + "name": "is_qpos_exceed", "kwargs": { "robot": "env.robot", "control_part": "right_arm" @@ -418,7 +418,7 @@ ] }, { - "name": "is_qpos_exceed_new", + "name": "is_qpos_exceed", "kwargs": { "robot": "env.robot", "control_part": "right_arm" @@ -544,7 +544,7 @@ ] }, { - "name": "is_qpos_exceed_new", + "name": "is_qpos_exceed", "kwargs": { "robot": "env.robot", "control_part": "right_arm" diff --git a/configs/gym/pour_water/gym_config.json b/configs/gym/pour_water/gym_config.json index 4207f438..9048f817 100644 --- a/configs/gym/pour_water/gym_config.json +++ b/configs/gym/pour_water/gym_config.json @@ -255,84 +255,15 @@ "entity_cfg": {"uid": "cam_right_wrist"}, "foreground_uids": ["bottle", "cup"] } - }, - "exteroception": { - "func": "compute_exteroception", - "mode": "add", - "name": "exteroception", - "params": { - "descriptor": { - "all_sensors": [ - { - "type": "robot", - "control_part": "left_arm", - "offset": [0.0, 0.0, 0.025], - "follow_eef": true - }, - { - "type": "robot", - "control_part": "right_arm", - "offset": [0.0, 0.0, 0.025], - "follow_eef": true - }, - { - "type": "affordance", - "obj_uid": "bottle", - "key": "bottle_grasp_pose_object_unoffset", - "is_arena_coord": false, - "follow_eef": "right_eef" - }, - { - "type": "affordance", - "obj_uid": "bottle", - "key": "pour_water_start_pose_unoffset", - "is_arena_coord": true, - "follow_eef": "right_eef" - }, - { - "type": "affordance", - "obj_uid": "bottle", - "key": "pour_water_stop_pose_unoffset", - "is_arena_coord": true, - "follow_eef": "right_eef" - }, - { - "type": "affordance", - "obj_uid": "bottle", - "key": "bottle_place_pose_unoffset", - "is_arena_coord": true - } - ] - }, - "x_interval": 0.02, - "y_interval": 0.05, - "kpnts_number": 2, - "groups": 6 - } } }, "dataset": { - "instruction": { - "lang": "Pour water from the bottle into the mug." - }, "robot_meta": { "arm_dofs": 12, "control_freq": 25, "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], - "observation": { - "vision": { - "cam_high": ["mask", "exteroception"], - "cam_right_wrist": ["mask", "exteroception"], - "cam_left_wrist": ["mask", "exteroception"] - }, - "states": ["qpos"], - "exteroception": ["cam_high", "cam_right_wrist", "cam_left_wrist"] - }, "min_len_steps": 5 } - }, - "success_params": { - "strict": false } }, "robot": { diff --git a/configs/gym/real2sim/reality_config_PourWaterW1Single_v3.json b/configs/gym/real2sim/reality_config_PourWaterW1Single_v3.json deleted file mode 100644 index e7801584..00000000 --- a/configs/gym/real2sim/reality_config_PourWaterW1Single_v3.json +++ /dev/null @@ -1,582 +0,0 @@ -{ - "id": "pour_water_single_real2sim", - "max_episodes": 10, - "env": { - "observations": { - "norm_robot_eef_joint": { - "func": "normalize_robot_joint_data", - "mode": "modify", - "name": "robot/qpos", - "params": { - "joint_ids": [7, 15] - } - }, - "bottle_pose": { - "func": "get_rigid_object_pose", - "mode": "add", - "name": "bottle_pose", - "params": { - "entity_cfg": {"uid": "bottle"} - } - }, - "cup_pose": { - "func": "get_rigid_object_pose", - "mode": "add", - "name": "cup_pose", - "params": { - "entity_cfg": {"uid": "cup"} - } - }, - "cam_high_semantic_mask_l": { - "func": "compute_semantic_mask", - "mode": "add", - "name": "sensor/cam_high/semantic_mask_l", - "params": { - "entity_cfg": {"uid": "cam_high"}, - "foreground_uids": ["bottle", "cup"] - } - }, - "cam_high_semantic_mask_r": { - "func": "compute_semantic_mask", - "mode": "add", - "name": "sensor/cam_high/semantic_mask_r", - "params": { - "entity_cfg": {"uid": "cam_high"}, - "foreground_uids": ["bottle", "cup"], - "is_right": true - } - }, - "cam_left_semantic_mask": { - "func": "compute_semantic_mask", - "mode": "add", - "name": "sensor/cam_left_wrist/semantic_mask_l", - "params": { - "entity_cfg": {"uid": "cam_left_wrist"}, - "foreground_uids": ["bottle", "cup"] - } - }, - "cam_right_semantic_mask": { - "func": "compute_semantic_mask", - "mode": "add", - "name": "sensor/cam_right_wrist/semantic_mask_l", - "params": { - "entity_cfg": {"uid": "cam_right_wrist"}, - "foreground_uids": ["bottle", "cup"] - } - }, - "exteroception": { - "func": "compute_exteroception", - "mode": "add", - "name": "exteroception", - "params": { - "descriptor": { - "cam_high": [ - { - "type": "robot", - "control_part": "left_arm" - }, - { - "type": "robot", - "control_part": "right_arm" - } - ] - }, - "x_interval": 0.02, - "y_interval": 0.05, - "kpnts_number": 2, - "groups": 2 - } - } - }, - "dataset": { - "dir_path": "", - "instruction": { - "lang": "Pour water from the bottle into the cup." - }, - "robot_meta": { - "arm_dofs": 14, - "control_freq": 25, - "qpos_to_control": [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14], - "observation": { - "vision": { - "cam_high": ["mask"], - "cam_right_wrist": ["mask"], - "cam_left_wrist": ["mask"] - }, - "proprioception": ["qpos"], - "exteroception": ["cam_high", "cam_right_wrist", "cam_left_wrist"] - }, - "action": "qpos_with_eef_pose", - "min_len_steps": 30 - } - }, - "success_params": { - "strict": false - } - }, - "robot": { - "uid": "dexforce_w1", - "init_pos": [0.14, 0.0, 0.04], - "init_qpos": [0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.57923,0.0,-1.57003,-1.2,0.4,0.0,0.0,0.57923,0.0,1.57003,1.2,-0.4,0.0,2.5,0.0,0.0,0.0,0.0,0.0,2.5,0.0,0.0,0.0,0.0,0.0], - "solver_cfg": { - "left_arm": { - "ik_nearest_weight": [5, 5, 1, 5, 1, 1, 1] - }, - "right_arm": { - "ik_nearest_weight": [5, 5, 1, 5, 1, 1, 1], - "tcp": [[ 1.0 , 0.0 , 0.0 , 0.0 ], - [ 0.0 , 0.0 , -1.0 , -0.04], - [ 0.0 , 1.0 , 0.0 , 0.14], - [ 0.0 , 0.0 , 0.0 , 1.0 ]] - } - } - }, - "sensor": [ - { - "sensor_type": "Camera", - "uid": "cam_left_wrist", - "sensor_name": "cam_left_wrist", - "width": 640, - "height": 480, - "intrinsics": [487.39422607421875, 487.39422607421875, 320.3005676269531, 210.7530517578125], - "enable_mask": true, - "attach_link": "left_ee", - "attach_xpos": [ - [ 0.70711, -0.40558, 0.57923, 0.09 ], - [-0.0 , -0.81915, -0.57358, -0.05 ], - [ 0.70711, 0.40558, -0.57923, 0.04 ], - [ 0.0 , 0.0 , 0.0 , 1.0 ] - ], - "set_near": 0.005, - "set_far": 50 - }, - { - "sensor_type": "Camera", - "uid": "cam_right_wrist", - "sensor_name": "cam_right_wrist", - "width": 640, - "height": 480, - "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], - "enable_mask": true, - "attach_link": "right_ee", - "attach_xpos": [ - [-0.70711, -0.40558, 0.57923, 0.09 ], - [-0.0 , 0.81915, 0.57358, 0.05 ], - [-0.70711, 0.40558, -0.57923, 0.04 ], - [ 0.0 , 0.0 , 0.0 , 1.0 ] - ], - "set_near": 0.005, - "set_far": 50 - }, - { - "sensor_type": "StereoCamera", - "uid": "cam_high", - "sensor_name": "cam_high", - "width": 960, - "height": 540, - "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], - "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], - "enable_mask": true, - "enable_depth": true, - "relativate_T": [ - [ - 0.99996440327, - 0.000856048544, - 0.008394008265, - 0.059684025824163614 - ], - [ - -0.00085599875, - 0.999999633588, - -9.524764e-06, - 1.064844737251626e-05 - ], - [ - -0.008394013343, - 2.339165e-06, - 0.999964769647, - 0.0002219304982263564 - ], - [ - 0, - 0, - 0, - 1 - ] - ], - "set_near": 0.005, - "set_far": 50, - "camera_position": [ - 0.35368482807598, - 0.014695524383058989, - 1.4517046071614774 - ], - "camera_look_at": [ - 0.7186357573287919, - -0.054534732904795505, - 0.5232553674540066 - ], - "up_vector": [ - 0.9306678549330372, - -0.0005600064212467153, - 0.3658647703553347 - ] - } - ], - "light": { - "direct": [ - { - "uid": "light1", - "light_type": "point", - "color": [1.0, 1.0, 1.0], - "intensity": 100, - "init_pos": [0, 0, 2], - "radius": 10.0 - } - ] - }, - "background": [ - { - "uid": "table", - "shape": { "shape_type": "Mesh", "fpath": "static_scenes/static_scene_3/circle_table_simple.ply", "compute_uv": false }, - "body_scale": [1.0, 0.8, 0.8], - "init_local_pose": [ - [2.220446049250313e-16, 0.0, 1.0, 0.7], - [0.0, 1.0, 0.0, 0.0], - [-1.0, 0.0, 2.220446049250313e-16, 0.92], - [0.0, 0.0, 0.0, 1.0] - ], - "body_type": "kinematic", - "max_convex_hull_num": 1 - } - ], - "rigid_object": [ - { - "uid": "bottle", - "shape": { "shape_type": "Mesh", "fpath": "objects/object_6/xingbake_processed.ply" }, - "attrs": { - "mass": 0.005, - "contact_offset": 0.003, - "rest_offset": 0.001, - "restitution": 0.1, - "max_depenetration_velocity": 1e1 - }, - "body_scale": [1, 1, 1], - "init_local_pose": [ - [1.0, 0.0, 0.0, 0.59013], - [0.0, 1.0, 0.0, -0.02475], - [0.0, 0.0, 1.0, 1.06664], - [0.0, 0.0, 0.0, 1.0] - ], - "max_convex_hull_num": 8 - }, - { - "uid": "cup", - "shape": { "shape_type": "Mesh", "fpath": "objects/object_7/paper_cup.ply" }, - "attrs": { - "mass": 0.005, - "contact_offset": 0.003, - "rest_offset": 0.001, - "restitution": 0.1, - "max_depenetration_velocity": 1e1 - }, - "body_scale": [0.75, 0.75, 1.0], - "init_local_pose": [ - [0.9986, -0.00476, 0.05268, 0.66128], - [0.01116, 0.99248, -0.12189, 0.1], - [-0.0517, 0.12231, 0.99114, 1.0], - [0.0, 0.0, 0.0, 1.0] - ], - "max_convex_hull_num": 8 - } - ], - "task": { - "name": "pour_water_single", - "data": { - "0": { - "trajectory": { - "path": "demo1", - "sample_ratio": 0.1, - "scope": { - "right_arm": [ - 8, - 9, - 10, - 11, - 12, - 13, - 14 - ], - "left_arm": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "left_eef": [ - 7 - ], - "right_eef": [ - 15 - ] - } - }, - "node": { - "right_arm": [ - { - "0": { - "affordance_name": "grasp_qpos", - "master": "", - "slaver": "bottle", - "timestep": 122, - "mimicable": true, - "trajectory": { - "name": "load_trajectory", - "kwargs": {} - } - }, - "1": { - "affordance_name": "after_pour_qpos", - "master": "bottle", - "slaver": "", - "timestep": 436, - "trajectory": { - "name": "load_trajectory", - "kwargs": {} - } - }, - "3": { - "affordance_name": "place_qpos", - "master": "bottle", - "slaver": "", - "timestep": 502, - "trajectory": { - "name": "load_trajectory", - "kwargs": {} - } - }, - "4": { - "affordance_name": "pour_qpos", - "master": "bottle", - "slaver": "cup", - "timestep": 327, - "trajectory": { - "name": "load_trajectory", - "kwargs": {} - } - }, - "5": { - "affordance_name": "before_pour_qpos", - "master": "bottle", - "slaver": "", - "timestep": 207, - "trajectory": { - "name": "load_trajectory", - "kwargs": {} - } - } - } - ], - "left_arm": [], - "right_eef": [ - { - "0": { - "affordance_name": "right_close", - "master": "", - "slaver": "bottle", - "timestep": 123, - "mimicable": false, - "duration": 20, - "trajectory": { - "name": "execute_close", - "kwargs": {} - } - }, - "1": { - "affordance_name": "right_open", - "master": "", - "slaver": "bottle", - "timestep": 502, - "mimicable": false, - "duration": 20, - "trajectory": { - "name": "execute_open", - "kwargs": {} - } - } - - } - ], - "left_eef": [] - }, - "sync": { - "right_eefhand_init_qpos": { - "depend_tasks": [ - "grasp_qpos" - ] - }, - "grasp_qpos": { - "depend_tasks": [ - "right_close" - ] - }, - "right_close": { - "depend_tasks": [ - "place_qpos" - ] - }, - "place_qpos": { - "depend_tasks": [ - "right_open" - ] - } - } - }, - "1": { - "trajectory": { - "path": "demo2", - "sample_ratio": 0.1, - "scope": { - "right_arm": [ - 8, - 9, - 10, - 11, - 12, - 13, - 14 - ], - "left_arm": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "left_eef": [ - 7 - ], - "right_eef": [ - 15 - ] - } - }, - "node": { - "right_arm": [ - { - "0": { - "affordance_name": "grasp_qpos", - "master": "", - "slaver": "bottle", - "timestep": 163, - "mimicable": true, - "trajectory": { - "name": "load_trajectory", - "kwargs": {} - } - }, - "1": { - "affordance_name": "pour_qpos", - "master": "bottle", - "slaver": "cup", - "timestep": 400, - "trajectory": { - "name": "load_trajectory", - "kwargs": {} - } - }, - "3": { - "affordance_name": "place_qpos", - "master": "bottle", - "slaver": "", - "timestep": 692, - "trajectory": { - "name": "load_trajectory", - "kwargs": {} - } - }, - "4": { - "affordance_name": "after_pour_qpos", - "master": "bottle", - "slaver": "", - "timestep": 532, - "trajectory": { - "name": "load_trajectory", - "kwargs": {} - } - }, - "5": { - "affordance_name": "before_pour_qpos", - "master": "bottle", - "slaver": "", - "timestep": 232, - "trajectory": { - "name": "load_trajectory", - "kwargs": {} - } - } - } - ], - "left_arm": [], - "right_eef": [ - { - "0": { - "affordance_name": "right_close", - "master": "", - "slaver": "bottle", - "timestep": 210, - "mimicable": false, - "duration": 20, - "trajectory": { - "name": "execute_close", - "kwargs": {} - } - }, - "1": { - "affordance_name": "right_open", - "master": "", - "slaver": "bottle", - "timestep": 692, - "mimicable": false, - "duration": 20, - "trajectory": { - "name": "execute_open", - "kwargs": {} - } - } - - } - ], - "left_eef": [] - }, - "sync": { - "right_eefhand_init_qpos": { - "depend_tasks": [ - "grasp_qpos" - ] - }, - "grasp_qpos": { - "depend_tasks": [ - "right_close" - ] - }, - "right_close": { - "depend_tasks": [ - "place_qpos" - ] - }, - "place_qpos": { - "depend_tasks": [ - "right_open" - ] - } - } - } - } - } -} diff --git a/configs/gym/scoop_ice/gym_config.json b/configs/gym/scoop_ice/gym_config.json index eed397ac..331f8db6 100644 --- a/configs/gym/scoop_ice/gym_config.json +++ b/configs/gym/scoop_ice/gym_config.json @@ -46,25 +46,6 @@ "target": [0.5, 0, 1] } } - }, - "dataset": { - "instruction": { - "lang": "Scoop ice." - }, - "robot_meta": { - "arm_dofs": 14, - "control_freq": 25, - "qpos_to_control": [6, 8, 10, 12, 14, 16, 18, 24, 7, 9, 11, 13, 15, 17, 19, 29], - "observation": { - "vision": { - "cam_high": [], - "cam_right_wrist": [], - "cam_left_wrist": [] - }, - "states": ["qpos"] - }, - "min_len_steps": 10 - } } }, "robot": { diff --git a/embodichain/data/__init__.py b/embodichain/data/__init__.py index f97508ac..9e152ab9 100644 --- a/embodichain/data/__init__.py +++ b/embodichain/data/__init__.py @@ -14,22 +14,5 @@ # limitations under the License. # ---------------------------------------------------------------------------- -import os - -database_dir = os.path.dirname(os.path.abspath(__file__)).replace("data", "database") -video_dir = os.path.join(database_dir, "video") -weights_dir = os.path.join(database_dir, "weights") -database_2d_dir = os.path.join(database_dir, "2dasset") -database_lang_dir = os.path.join(database_dir, "lang") -database_demo_dir = os.path.join(database_dir, "demostration") -database_tmp_dir = os.path.join(database_dir, "tmp") -database_train_dir = os.path.join(database_dir, "train") - - -if not os.path.exists(database_tmp_dir): - os.makedirs(database_tmp_dir, exist_ok=True) -if not os.path.exists(database_train_dir): - os.makedirs(database_train_dir, exist_ok=True) - from . import assets from .dataset import * diff --git a/embodichain/data/assets/demo_assets.py b/embodichain/data/assets/demo_assets.py index 8480d468..656c6bfa 100644 --- a/embodichain/data/assets/demo_assets.py +++ b/embodichain/data/assets/demo_assets.py @@ -15,7 +15,8 @@ # ---------------------------------------------------------------------------- import open3d as o3d -from pathlib import Path +import os + from embodichain.data.dataset import EmbodiChainDataset from embodichain.data.constants import ( EMBODICHAIN_DOWNLOAD_PREFIX, @@ -26,7 +27,7 @@ class ScoopIceNewEnv(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/demo/ScoopIceNewEnv.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "demo/ScoopIceNewEnv.zip"), "e92734a9de0f64be33a11fbda0fbd3b6", ) prefix = "ScoopIceNewEnv" @@ -38,7 +39,7 @@ def __init__(self, data_root: str = None): class MultiW1Data(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/demo/multi_w1_demo.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "demo/multi_w1_demo.zip"), "984e8fa3aa05cb36a1fd973a475183ed", ) prefix = "MultiW1Data" diff --git a/embodichain/data/assets/eef_assets.py b/embodichain/data/assets/eef_assets.py index fa1e9aae..7f52b9ee 100644 --- a/embodichain/data/assets/eef_assets.py +++ b/embodichain/data/assets/eef_assets.py @@ -15,6 +15,7 @@ # ---------------------------------------------------------------------------- +import os import open3d as o3d from embodichain.data.dataset import EmbodiChainDataset from embodichain.data.constants import ( @@ -43,7 +44,7 @@ class DH_PGC_140_50(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/eef_assets/DH_PGC_140_50.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "eef_assets/DH_PGC_140_50.zip"), "c2a642308a76e99b1b8b7cb3a11c5df3", ) prefix = "DH_PGC_140_50" @@ -72,7 +73,7 @@ class DH_PGI_140_80(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/eef_assets/DH_PGI_140_80.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "eef_assets/DH_PGI_140_80.zip"), "05a1a08b13c6250cc12affeeda3a08ba", ) prefix = "DH_PGI_140_80" @@ -102,7 +103,7 @@ class DH_PGC_140_50_M(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/eef_assets/DH_PGC_140_50_M.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "eef_assets/DH_PGC_140_50_M.zip"), "3a9ab5f32639e03afb38dc033b44bb62", ) prefix = "DH_PGC_140_50_M" @@ -131,7 +132,7 @@ class ZH_CTM2F110(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/eef_assets/ZH_CTM2F110.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "eef_assets/ZH_CTM2F110.zip"), "0e7c3310425609797fe010b2a76fe465", ) prefix = "ZH_CTM2F110" @@ -162,7 +163,9 @@ class BrainCoHandRevo1(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/eef_assets/BrainCoHandRevo01.zip", + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, "eef_assets/BrainCoHandRevo01.zip" + ), "ff9ac77e7e1493fd32d40c87fecbee6c", ) prefix = "BrainCoHandRevo1" @@ -197,7 +200,7 @@ class InspireHand(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/eef_assets/InspireHand.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "eef_assets/InspireHand.zip"), "c60132a6f03866fb021cca5b6d72845e", ) prefix = "InspireHand" @@ -226,7 +229,7 @@ class Robotiq2F85(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/eef_assets/Robotiq2F85.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "eef_assets/Robotiq2F85.zip"), "53ecbf2c953f43f1134aa7223e592292", ) prefix = "Robotiq2F85" @@ -255,7 +258,7 @@ class WheelTecFA2F(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/eef_assets/WheelTecFA2F.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "eef_assets/WheelTecFA2F.zip"), "feaf13f25b1c6ce58d011b1f2fa72f58", ) prefix = "WheelTecFA2F" diff --git a/embodichain/data/assets/materials.py b/embodichain/data/assets/materials.py index 784d6c6d..c40369dd 100644 --- a/embodichain/data/assets/materials.py +++ b/embodichain/data/assets/materials.py @@ -14,6 +14,7 @@ # limitations under the License. # ---------------------------------------------------------------------------- +import os import open3d as o3d from pathlib import Path @@ -30,7 +31,9 @@ class SimResources(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/materials/embodisim_resources.zip", + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, "materials/embodisim_resources.zip" + ), "53c054b3ae0857416dc52632eb562c12", ) prefix = "SimResources" @@ -98,7 +101,7 @@ def get_material_list(self) -> List[str]: class CocoBackground(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/materials/CocoBackground.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "materials/CocoBackground.zip"), "fda82404a317281263bd5849e9eb31a1", ) prefix = "CocoBackground" diff --git a/embodichain/data/assets/obj_assets.py b/embodichain/data/assets/obj_assets.py index 6c2310f8..5d7a63f8 100644 --- a/embodichain/data/assets/obj_assets.py +++ b/embodichain/data/assets/obj_assets.py @@ -15,6 +15,7 @@ # ---------------------------------------------------------------------------- +import os import open3d as o3d from embodichain.data.dataset import EmbodiChainDataset from embodichain.data.constants import ( @@ -26,7 +27,9 @@ class ShopTableSimple(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/shop_table_simple.zip", + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/shop_table_simple.zip" + ), "e3061ee024de7840f773b70140dcd43f", ) prefix = "ShopTableSimple" @@ -38,7 +41,9 @@ def __init__(self, data_root: str = None): class CircleTableSimple(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/circle_table_simple.zip", + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/circle_table_simple.zip" + ), "42ad2be8cd0caddcf9bfbf106b7783f3", ) prefix = "CircleTableSimple" @@ -50,7 +55,7 @@ def __init__(self, data_root: str = None): class PlasticBin(o3d.data.DownloadDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/plastic_bin.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/plastic_bin.zip"), "21e00083689a4a3c4e4ae3fd89c61e55", ) prefix = "PlasticBin" @@ -62,7 +67,7 @@ def __init__(self, data_root: str = None): class Chair(o3d.data.DownloadDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/chair.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/chair.zip"), "df3d7d1a05731d45fb2c678a40a39cd4", ) prefix = "Chair" @@ -74,7 +79,7 @@ def __init__(self, data_root: str = None): class ContainerMetal(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/container_metal.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/container_metal.zip"), "ceafb87f8177609f87aaa6779fcbb9a3", ) prefix = "ContainerMetal" @@ -86,7 +91,9 @@ def __init__(self, data_root: str = None): class SimpleBoxDrawer(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/simple_box_drawer.zip", + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/simple_box_drawer.zip" + ), "966b648bca16823ee91525847c183973", ) prefix = "SimpleBoxDrawer" @@ -98,7 +105,7 @@ def __init__(self, data_root: str = None): class AdrianoTable(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/adriano_table.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/adriano_table.zip"), "8453583a9a1a9d04d50268f8a3da554f", ) prefix = "AdrianoTable" @@ -110,7 +117,7 @@ def __init__(self, data_root: str = None): class CoffeeCup(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/CoffeeCup.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/CoffeeCup.zip"), "f05fce385826414c15e19df3b75dc886", ) prefix = "CoffeeCup" @@ -122,7 +129,9 @@ def __init__(self, data_root: str = None): class SlidingBoxDrawer(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/SlidingBoxDrawer.zip", + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/SlidingBoxDrawer.zip" + ), "b03d9006503d27b75ddeb06d31b2c7a5", ) prefix = "SlidingBoxDrawer" @@ -134,7 +143,7 @@ def __init__(self, data_root: str = None): class AiLiMu_BoxDrawer(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - EMBODICHAIN_DOWNLOAD_PREFIX + "AiLiMu_BoxDrawer_v3.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "AiLiMu_BoxDrawer_v3.zip"), "9a2889151a23d482f95f602cce9900c6", ) prefix = "AiLiMu_BoxDrawer" @@ -146,7 +155,7 @@ def __init__(self, data_root: str = None): class AluminumTable(o3d.data.DownloadDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - EMBODICHAIN_DOWNLOAD_PREFIX + "AluminumTable.glb", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "AluminumTable.glb"), "02991d36ca9b70f019ed330a61143aa9", ) prefix = "AluminumTable" @@ -158,7 +167,7 @@ def __init__(self, data_root: str = None): class ToyDuck(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - EMBODICHAIN_DOWNLOAD_PREFIX + "ToyDuck.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "ToyDuck.zip"), "2f5c00ba487edf34ad668f7257c0264e", ) prefix = "ToyDuck" @@ -170,7 +179,7 @@ def __init__(self, data_root: str = None): class PaperCup(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - EMBODICHAIN_DOWNLOAD_PREFIX + "PaperCup.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "PaperCup.zip"), "359d13af8c5f31ad3226d8994a1a7198", ) prefix = "PaperCup" @@ -182,7 +191,7 @@ def __init__(self, data_root: str = None): class ChainRainSec(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/lianguijie.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/lianguijie.zip"), "2387589040a4d3f2676b622362452242", ) prefix = "ChainRainSec" @@ -194,7 +203,7 @@ def __init__(self, data_root: str = None): class TableWare(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/tableware.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/tableware.zip"), "403e340fc0e4996c002ee774f89cd236", ) prefix = "TableWare" @@ -206,7 +215,7 @@ def __init__(self, data_root: str = None): class ScannedBottle(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/obj_assets/ScannedBottle.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/ScannedBottle.zip"), "d2b2d4deb7b463a734af099f7624b4af", ) prefix = "ScannedBottle" diff --git a/embodichain/data/assets/robot_assets.py b/embodichain/data/assets/robot_assets.py index 60a33678..6c2d47e5 100644 --- a/embodichain/data/assets/robot_assets.py +++ b/embodichain/data/assets/robot_assets.py @@ -15,6 +15,7 @@ # ---------------------------------------------------------------------------- +import os import open3d as o3d from embodichain.data.dataset import EmbodiChainDataset from embodichain.data.constants import ( @@ -49,7 +50,9 @@ class CobotMagicArm(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/CobotMagicArmV2.zip", + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/CobotMagicArmV2.zip" + ), "14af3e84b74193680899a59fc74e8337", ) prefix = "CobotMagicArm" @@ -78,7 +81,7 @@ class RidgeBack(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/RidgeBack.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/RidgeBack.zip"), "f03e1a6f4c781ad8957a88bdb010e9b6", ) prefix = "RidgeBack" @@ -109,7 +112,7 @@ class UnitreeH1(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/UnitreeH1.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/UnitreeH1.zip"), "339417cef5051a912693f3c64d29dddc", ) prefix = "UnitreeH1" @@ -140,7 +143,7 @@ class ABB(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/ABB.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/ABB.zip"), "ea6df4983982606c43387783e5fb8c05", ) prefix = "ABB" @@ -171,7 +174,7 @@ class Motoman(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/Motoman.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/Motoman.zip"), "ee5f16cfce34d8e2cb996fcff8a25986", ) prefix = "Motoman" @@ -202,7 +205,7 @@ class KUKA(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/KUKA.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/KUKA.zip"), "da7a2dfd0db3f486e407f038d25c7537", ) prefix = "KUKA" @@ -233,7 +236,7 @@ class Fanuc(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/Fanuc.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/Fanuc.zip"), "0a1c562f4719f7cdc1b24545fec4a301", ) prefix = "Fanuc" @@ -272,7 +275,9 @@ class UniversalRobots(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/UniversalRobots.zip", + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/UniversalRobots.zip" + ), "dbd12f7e36cef4e5025b82f748233b80", ) prefix = "UniversalRobots" @@ -303,7 +308,7 @@ class Rokae(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/Rokae.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/Rokae.zip"), "fbfb852d6139e94b7c422771542f988f", ) prefix = "Rokae" @@ -336,7 +341,7 @@ class Franka(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/Franka.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/Franka.zip"), "c2de367fe1da02eeb45a8129f903d0b6", ) prefix = "Franka" @@ -365,7 +370,7 @@ class Agile(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/Agile.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/Agile.zip"), "fd47d7ab8a4d13960fd76e59544ba836", ) prefix = "Agile" @@ -396,7 +401,7 @@ class Hans(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/Hans.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/Hans.zip"), "c867c406e3dffd6982fd0a15e7dc7e29", ) prefix = "Hans" @@ -425,7 +430,7 @@ class Aubo(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/Aubo.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/Aubo.zip"), "2574649cd199c11267cc0f4aeac65557", ) prefix = "Aubo" @@ -454,7 +459,7 @@ class RainbowY1(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/robot_assets/RainbowY1.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/RainbowY1.zip"), "5979a3aaadb5de6488b13765d523564f", ) prefix = "RainbowY1" diff --git a/embodichain/data/assets/scene_assets.py b/embodichain/data/assets/scene_assets.py index bd6e30a3..f1089bf7 100644 --- a/embodichain/data/assets/scene_assets.py +++ b/embodichain/data/assets/scene_assets.py @@ -14,6 +14,7 @@ # limitations under the License. # ---------------------------------------------------------------------------- +import os import open3d as o3d from pathlib import Path from embodichain.data.dataset import EmbodiChainDataset @@ -43,7 +44,7 @@ class SceneData(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/scene_assets/SceneData.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "scene_assets/SceneData.zip"), "fb46e4694cc88886fc785704e891a68a", ) prefix = "SceneData" @@ -54,7 +55,7 @@ def __init__(self, data_root: str = None): class EmptyRoom(o3d.data.DownloadDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/scene_assets/empty_room.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "scene_assets/empty_room.zip"), "612ffead4fac95114bec2e3812469f96", ) prefix = "EmptyRoom" diff --git a/embodichain/data/assets/w1_assets.py b/embodichain/data/assets/w1_assets.py index b46e807f..c3aeab79 100644 --- a/embodichain/data/assets/w1_assets.py +++ b/embodichain/data/assets/w1_assets.py @@ -14,6 +14,7 @@ # limitations under the License. # ---------------------------------------------------------------------------- +import os import open3d as o3d from embodichain.data.dataset import EmbodiChainDataset from embodichain.data.constants import ( @@ -61,7 +62,7 @@ class DexforceW1V021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/DexforceW1V021.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/DexforceW1V021.zip"), "3cc3a0bfd1c50ebed5bee9dadeee6756", ) prefix = "DexforceW1V021" @@ -83,7 +84,10 @@ class DexforceW1V021_INDUSTRIAL_DH_PGC_GRIPPER_M(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/DexforceW1V021_INDUSTRIAL_DH_PGC_GRIPPER_M.zip", + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, + "dexforce_w1/DexforceW1V021_INDUSTRIAL_DH_PGC_GRIPPER_M.zip", + ), "06ec5dfa76dc69160d7ff9bc537a6a7b", ) prefix = "DexforceW1V021_INDUSTRIAL_DH_PGC_GRIPPER_M" @@ -105,7 +109,10 @@ class DexforceW1V021_ANTHROPOMORPHIC_BRAINCO_HAND_REVO1(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/DexforceW1V021_ANTHROPOMORPHIC_BRAINCO_HAND_REVO1.zip", + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, + "dexforce_w1/DexforceW1V021_ANTHROPOMORPHIC_BRAINCO_HAND_REVO1.zip", + ), "ef19d247799e79233863b558c47b32cd", ) prefix = "DexforceW1V021_ANTHROPOMORPHIC_BRAINCO_HAND_REVO1" @@ -117,7 +124,9 @@ def __init__(self, data_root: str = None): class DexforceW1ChassisV021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/W1_Chassis_v021.zip", + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/W1_Chassis_v021.zip" + ), "6b0517a4d92a572988641d46269d063f", ) prefix = "DexforceW1ChassisV021" @@ -129,7 +138,7 @@ def __init__(self, data_root: str = None): class DexforceW1TorsoV021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/W1_Torso_v021.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/W1_Torso_v021.zip"), "4f762a3ae6ef2acbe484c915cf80da7b", ) prefix = "DexforceW1TorsoV021" @@ -141,7 +150,7 @@ def __init__(self, data_root: str = None): class DexforceW1EyesV021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/W1_Eyes_v021.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/W1_Eyes_v021.zip"), "80e0b86ef2e934f439c99b79074f6f3c", ) prefix = "DexforceW1EyesV021" @@ -153,7 +162,7 @@ def __init__(self, data_root: str = None): class DexforceW1HeadV021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/W1_Head_v021.zip", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/W1_Head_v021.zip"), "ba72805828c5fd62ad55d6a1458893d0", ) prefix = "DexforceW1HeadV021" @@ -165,7 +174,9 @@ def __init__(self, data_root: str = None): class DexforceW1LeftArm1V021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/W1_LeftArm_1_v021.zip", + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/W1_LeftArm_1_v021.zip" + ), "c3cacda7bd36389ed98620047bff6216", ) prefix = "DexforceW1LeftArm1V021" @@ -177,7 +188,9 @@ def __init__(self, data_root: str = None): class DexforceW1RightArm1V021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/W1_RightArm_1_v021.zip", + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/W1_RightArm_1_v021.zip" + ), "456c9495748171003246a3f6626bb0db", ) prefix = "DexforceW1RightArm2V021" @@ -189,7 +202,9 @@ def __init__(self, data_root: str = None): class DexforceW1LeftArm2V021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/W1_LeftArm_2_v021.zip", + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/W1_LeftArm_2_v021.zip" + ), "b99bd0587cc9a36fed3cdaa4f9fd62e7", ) prefix = "DexforceW1LeftArm2V021" @@ -201,7 +216,9 @@ def __init__(self, data_root: str = None): class DexforceW1RightArm2V021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/dexforce_w1/W1_RightArm_2_v021.zip", + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/W1_RightArm_2_v021.zip" + ), "d9f25b2d5244ca5a859040327273a99e", ) prefix = "DexforceW1RightArm1V021" diff --git a/embodichain/data/constants.py b/embodichain/data/constants.py index 3a4aa144..17264a80 100644 --- a/embodichain/data/constants.py +++ b/embodichain/data/constants.py @@ -17,5 +17,7 @@ from pathlib import Path -EMBODICHAIN_DOWNLOAD_PREFIX = "http://192.168.3.120/CoreEngine/Data/embodychain_data/" +EMBODICHAIN_DOWNLOAD_PREFIX = ( + "https://huggingface.co/datasets/dexforce/embodichain_data/resolve/main/" +) EMBODICHAIN_DEFAULT_DATA_ROOT = str(Path.home() / ".cache" / "embodichain_data") diff --git a/embodichain/data/data_engine/__init__.py b/embodichain/data/data_engine/__init__.py deleted file mode 100644 index e4655620..00000000 --- a/embodichain/data/data_engine/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---------------------------------------------------------------------------- diff --git a/embodichain/data/data_engine/data_dict_extractor.py b/embodichain/data/data_engine/data_dict_extractor.py deleted file mode 100644 index d56a5a94..00000000 --- a/embodichain/data/data_engine/data_dict_extractor.py +++ /dev/null @@ -1,1135 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---------------------------------------------------------------------------- - -from embodichain.utils.logger import log_warning, log_error - -try: - import h5ffmpeg as hf - - has_h5ffmpeg = True -except Exception as e: - has_h5ffmpeg = False - log_warning("Fail to import h5ffmpeg.") - -import h5py -import os -import random -import torch -import numpy as np - -from functools import cached_property -from typing import Dict, Any, List, Union, Optional -from embodichain.data.enum import ( - Modality, - PrivilegeType, - JointType, -) -from embodichain.lab.sim.objects import Robot -from embodichain.lab.sim.sensors import StereoCamera -from embodichain.lab.gym.envs import BaseEnv, EmbodiedEnv -from embodichain.lab.gym.utils.gym_utils import map_qpos_to_eef_pose -from embodichain.utils.utility import get_right_name -from embodichain.lab.gym.utils.misc import _data_key_to_control_part -from embodichain.utils import logger -from embodichain.data.data_engine.unified_state import ( - StateUnifier, -) -from embodichain.data.enum import ( - SUPPORTED_PROPRIO_TYPES, - SUPPORTED_ACTION_TYPES, - SUPPORTED_EXTRA_VISION_TYPES, -) -from tqdm import tqdm -from copy import deepcopy - -SCALE_FACTOR = 4e3 # Scale factor for depth data -FAR_CLIP = 4.0 # m - -DATA_FORMATS = { - "observations": { - Modality.IMAGES.value: {}, - Modality.GEOMAP.value: {}, - PrivilegeType.MASK.value: {}, - PrivilegeType.EXTEROCEPTION.value: {}, - Modality.STATES.value: {}, - }, - Modality.ACTIONS.value: {}, -} - - -class CompressedVideoHDF5: - def __init__(self, save_path: str, chunks: int = 20) -> None: - """ - Initializes the data dictionary extractor with the specified save path and number of chunks. - Attempts to configure video encoding settings based on the detected GPU model using the h5ffmpeg library. - Supported GPUs include NVIDIA A800 and NVIDIA GeForce RTX 3060, with specific encoding configurations for each. - If the GPU is unsupported or an error occurs during initialization, a warning is logged and default configuration is used. - - Args: - save_path (str): Path where extracted data will be saved. - chunks (int, optional): Number of chunks to split the data into. Defaults to 20. - - Raises: - ValueError: If the detected GPU is not supported. - """ - self.save_path = save_path - self.chunks = chunks - - try: - import h5ffmpeg as hf - import torch - - name = torch.cuda.get_device_name() - - if "A800" in name or name == "NVIDIA A800-SXM4-80GB": - self.conf = { - Modality.GEOMAP.value: hf.x264( - preset="veryfast", tune="fastdecode" - ), - Modality.IMAGES.value: hf.x264( - preset="veryfast", tune="fastdecode" - ), - PrivilegeType.MASK.value: hf.x264( - preset="veryslow", tune="ssim", crf=0 - ), - } - elif "3060" in name or name == "NVIDIA GeForce RTX 3060": - self.conf = { - Modality.GEOMAP.value: hf.h264_nvenc(), - Modality.IMAGES.value: hf.h264_nvenc(), - PrivilegeType.MASK.value: hf.h264_nvenc(), - } - elif "3090" in name or name == "NVIDIA GeForce RTX 3090": - self.conf = { - Modality.GEOMAP.value: hf.x264( - preset="veryfast", tune="fastdecode" - ), - Modality.IMAGES.value: hf.x264( - preset="veryfast", tune="fastdecode" - ), - PrivilegeType.MASK.value: hf.x264( - preset="veryslow", tune="ssim", crf=0 - ), - } - elif "4090" in name or name == "NVIDIA GeForce RTX 4090": - self.conf = { - Modality.GEOMAP.value: hf.x264( - preset="veryfast", tune="fastdecode" - ), - Modality.IMAGES.value: hf.x264( - preset="veryfast", tune="fastdecode" - ), - PrivilegeType.MASK.value: hf.x264( - preset="veryslow", tune="ssim", crf=0 - ), - } - else: - raise ValueError("Unsupported GPU: {}".format(name)) - - except Exception as e: - log_warning( - "{}. Please make sure h5ffmpeg is successfully installed.".format(e) - ) - self.conf = {} - - @staticmethod - def is_compressed_hdf5(data: Dict) -> bool: - images_group = data.get("observations", {}).get(Modality.IMAGES.value, {}) - has_compressed_keys = any( - (isinstance(k, str) and ("index" in k or "start" in k)) - for k in images_group.keys() - ) - return has_compressed_keys - - @staticmethod - def get_chunk_name(name: str, id: Union[int, str]) -> str: - """ - Generates a chunk name by concatenating the given name with the provided id, separated by an underscore. - Args: - name (str): The base name for the chunk. - id (Union[int, str]): The identifier to append to the name. - Returns: - str: The resulting chunk name in the format 'name_id'. - """ - - return name + "_{}".format(id) - - @staticmethod - def video_save( - f, - chunks: int, - data: Dict[str, np.ndarray], - key: str, - dtype=np.uint8, - conf: Dict = None, - ): - """ - Saves video data from multiple cameras into an HDF5 file, splitting the data into chunks for efficient storage. - Args: - f: An open HDF5 file handle where the video data will be saved. - data (Dict[str, np.ndarray]): Dictionary mapping camera names to their corresponding video data arrays. - key (str): Key under "observations" group in the HDF5 file to store the video data. - dtype (type, optional): Data type to convert the video frames to before saving (default: np.uint8). - conf (Dict, optional): Additional configuration parameters for HDF5 dataset creation. - Notes: - - Video data for each camera is processed and split into the specified number of chunks. - - Index and start datasets are created for each camera to map frame indices to chunk IDs and chunk start indices. - - Uses CompressedVideoHDF5 utility functions for data formatting and conversion. - - Progress is displayed using tqdm for each chunk being saved. - """ - import h5ffmpeg as hf - - f_images = f["observations"].create_group(key) - - for cam_name in data.keys(): - data_ = data[cam_name] - if len(data_) != 0: - data_ = CompressedVideoHDF5.to_bhw(data_) - - if dtype == np.uint16: - data_ = CompressedVideoHDF5.uint16_depth(data_) - else: - data_ = data_.astype(dtype) - - data_chunks = np.array_split(data_, chunks, axis=0) - data_chunk_ids = np.arange(data_.shape[0]) - data_chunk_ids_ = np.array_split(data_chunk_ids, chunks) - idtochunkid = np.zeros((data_.shape[0])) - chunkid2startid = np.zeros((chunks,)) - for chunkid, temp in enumerate(data_chunk_ids_): - chunkid2startid[chunkid] = min(temp) - for tempi in temp: - idtochunkid[tempi] = chunkid - _ = f_images.create_dataset( - CompressedVideoHDF5.get_chunk_name(cam_name, "index"), - data=idtochunkid, - ) - _ = f_images.create_dataset( - CompressedVideoHDF5.get_chunk_name(cam_name, "start"), - data=chunkid2startid, - ) - - for t, data_chunk in enumerate(tqdm(data_chunks)): - _ = f_images.create_dataset( - "{}/{}".format(cam_name, t), - data=data_chunk, - chunks=data_chunk.shape, - **conf, - ) - - @staticmethod - def uint16_depth( - data: np.ndarray, scale_factor: float = SCALE_FACTOR, far_clip: float = FAR_CLIP - ) -> np.ndarray: - """ - Converts a depth data array to a uint16 format after applying scaling and clipping. - Args: - data (np.ndarray): The input depth data as a NumPy array. - scale_factor (float, optional): The factor by which to scale the depth data. - Defaults to SCALE_FACTOR. - far_clip (float, optional): The maximum depth value (far clipping plane) - before scaling. Defaults to FAR_CLIP. - Returns: - np.ndarray: The scaled and clipped depth data as a NumPy array of type uint16. - """ - return (np.clip(data * scale_factor, 0, far_clip * scale_factor)).astype( - np.uint16 - ) - - @staticmethod - def float32_depth( - data: np.ndarray, scale_factor: float = SCALE_FACTOR, far_clip: float = FAR_CLIP - ) -> np.ndarray: - """ - Converts depth data to float32 and scales it by the given scale factor. - Args: - data (np.ndarray): The input depth data array. - scale_factor (float, optional): The factor by which to scale the depth values. Defaults to SCALE_FACTOR. - far_clip (float, optional): The far clipping distance (unused in this function). Defaults to FAR_CLIP. - Returns: - np.ndarray: The scaled depth data as a float32 numpy array. - """ - - return data.astype(np.float32) / scale_factor - - @staticmethod - def to_bhw(data: np.ndarray) -> np.ndarray: - """ - Reshapes a 4D numpy array from (vdepth, height, width, channels) to (vdepth, height, width * channels). - If the input is already a 3D array, returns it unchanged. - Args: - data (np.ndarray): Input array of shape (vdepth, height, width, channels) or (vdepth, height, width). - Returns: - np.ndarray: Reshaped array of shape (vdepth, height, width * channels) or the original array if 3D. - Raises: - Logs an error if the input array does not have 3 or 4 dimensions. - """ - - if len(data.shape) == 4: - vdepth, h, w, channels = ( - data.shape[0], - data.shape[1], - data.shape[2], - data.shape[3], - ) - return data.reshape(vdepth, h, w * channels) - elif len(data.shape) == 3: - return data - else: - log_error("Unsupported data shape: {}".format(data.shape)) - - @staticmethod - def to_bhwc(data: np.ndarray): - """ - Converts a numpy array to BHWC (Batch, Height, Width, Channels) format. - If the input array has 3 dimensions, it reshapes the array to have a channel dimension of size 3. - If the input array already has 4 dimensions, it returns the array unchanged. - Otherwise, logs an error for unsupported shapes. - Args: - data (np.ndarray): Input numpy array to be converted. - Returns: - np.ndarray: Array in BHWC format. - Raises: - Logs an error if the input array shape is not supported. - """ - - if len(data.shape) == 3: - vdepth, h, w = data.shape - return data.reshape(vdepth, h, -1, 3) - elif len(data.shape) == 4: - return data - else: - log_error("Unsupported data shape: {}".format(data.shape)) - - def dump( - self, - ret: Dict, - video_names: List[str] = [ - Modality.IMAGES.value, - PrivilegeType.MASK.value, - Modality.GEOMAP.value, - ], - dtypes: List = [np.uint8, np.uint8, np.uint16], - ): - """ - Dumps the provided data into an HDF5 file, saving specific video data with - compression and specified data types. - Args: - ret (Dict): The data dictionary containing observations and other metadata. - video_names (List[str], optional): A list of video names to extract from - the observations. Defaults to [Modality.IMAGES.value, PrivilegeType.MASK.value, Modality.GEOMAP.value]. - dtypes (List, optional): A list of data types corresponding to each video - name. Defaults to [np.uint8, np.uint8, np.uint16]. - Raises: - AssertionError: If the lengths of `video_names` and `dtypes` are not equal. - RuntimeError: If the configuration (`self.conf`) is empty, indicating that - `h5ffmpeg` is not installed or configured properly. - Notes: - - The method modifies the `ret` dictionary by temporarily removing the - specified video data during the HDF5 file creation process and then - restoring it afterward. - - The `hdfdict.dump` function is used to save the remaining data in the - dictionary, while the `CompressedVideoHDF5.video_save` function handles - the saving of video data with compression. - """ - - assert len(video_names) == len( - dtypes - ), "Inequal length of video names {} and dtypes {}.".format(video_names, dtypes) - import hdfdict - - if self.conf == {}: - raise RuntimeError( - "Please make sure h5ffmpeg is successfully installed before using `dump`." - ) - - pop_ret = {} - for video_name, dtype in zip(video_names, dtypes): - video_data = ret["observations"].pop(video_name) - pop_ret[video_name] = video_data - - # Open the file once and pass the open file object to hdfdict.dump so - # h5py doesn't try to truncate the same path while it is already open. - with h5py.File(self.save_path, "w") as f: - hdfdict.dump(ret, f) - for video_name, dtype in zip(video_names, dtypes): - CompressedVideoHDF5.video_save( - f, - self.chunks, - pop_ret[video_name], - video_name, - dtype=dtype, - conf=self.conf[video_name], - ) - - ret["observations"].update(pop_ret) - - @staticmethod - def decode_resources( - f: Dict, - ret: Dict, - name: str, - slice_id: int, - condition: callable, - function: callable, - padding: bool = True, - chunk_id: int = None, - ): - """ - Decodes and processes resources from a hierarchical data structure, applying - a condition and transformation function to the data, and optionally adding - zero-padding. - Args: - f (Dict): The input data dictionary containing observations and metadata. - ret (Dict): The output data dictionary where processed data will be stored. - name (str): The key name under "observations" to access specific data. - slice_id (int): The slice index used to retrieve the corresponding chunk ID. - condition (callable): A function that takes the data as input and returns - a boolean indicating whether the transformation function should be applied. - function (callable): A function to transform the data if the condition is met. - padding (bool, optional): Whether to add zero-padding to the data. Defaults to True. - chunk_id (int, optional): The chunk ID to use instead of deriving it from the slice ID. - Defaults to None. - Returns: - None: The function modifies the `ret` dictionary in place. - """ - - import time - - images = f["observations"][name] - - for cam_name in images.keys(): - if "index" in cam_name: - continue - if "start" in cam_name: - continue - - start_time = time.time() - sliceid2chunkid = images[ - CompressedVideoHDF5.get_chunk_name(cam_name, "index") - ][:] - chunkid = int(sliceid2chunkid[slice_id]) if chunk_id is None else chunk_id - data_ = images[cam_name][str(chunkid)][:] - # log_warning("".format(time.time() - start_time) - if condition(data_): - data_ = function(data_) - - if padding: - chunkid2startid = images[ - CompressedVideoHDF5.get_chunk_name(cam_name, "start") - ][:] - start_idx = chunkid2startid[chunkid] - zero_padding = np.zeros_like(data_)[0:1] - zero_padding = np.repeat(zero_padding, repeats=start_idx, axis=0) - ret["observations"][name][cam_name] = np.concatenate( - [zero_padding, data_], 0 - ) - else: - if ret["observations"][name][cam_name] is None: - ret["observations"][name][cam_name] = data_ - else: - ret["observations"][name][cam_name] = np.concatenate( - [ret["observations"][name][cam_name], data_], 0 - ) - - def safe_filter(self, f: Dict, slice_id: int = None) -> Dict: - """ - Filters and processes the input data dictionary based on the configuration - and specified slice ID. - Args: - f (Dict): The input data dictionary containing observations, including - images, masks, and geomap. - slice_id (int, optional): The specific slice ID to process. If None, - processes all chunks. Defaults to None. - Returns: - Dict: The filtered and processed data dictionary with updated - observations for images, masks, and geomap. - Notes: - - The method filters out camera names containing "index" or "start". - - It initializes the return dictionary with None values for images, - masks, and geomap for the filtered camera names. - - Depending on the `slice_id`, it either processes all chunks or a - specific slice using the `CompressedVideoHDF5.decode_resources` - method. - - The processed observations are updated in the input dictionary `f`. - """ - - if self.conf is {}: - return f - - cam_names = [] - for cam_name in f["observations"][Modality.IMAGES.value].keys(): - if "index" in cam_name: - continue - if "start" in cam_name: - continue - cam_names.append(cam_name) - - # Only build return structure for actually present modalities, avoid errors when real data lacks mask/geomap - present_modalities = [] - if Modality.IMAGES.value in f["observations"]: - present_modalities.append(Modality.IMAGES.value) - if PrivilegeType.MASK.value in f["observations"]: - present_modalities.append(PrivilegeType.MASK.value) - if Modality.GEOMAP.value in f["observations"]: - present_modalities.append(Modality.GEOMAP.value) - - ret = {"observations": {}} - for modality_key in present_modalities: - ret["observations"][modality_key] = { - cam_name: None for cam_name in cam_names - } - - if slice_id == None: - # For all chunks - for chunk_id_ in range(self.chunks): - if Modality.IMAGES.value in present_modalities: - CompressedVideoHDF5.decode_resources( - f, - ret, - Modality.IMAGES.value, - None, - lambda x: len(x.shape) == 3, - self.to_bhwc, - chunk_id=chunk_id_, - padding=False, - ) - if PrivilegeType.MASK.value in present_modalities: - CompressedVideoHDF5.decode_resources( - f, - ret, - PrivilegeType.MASK.value, - None, - lambda x: len(x.shape) == 3, - self.to_bhwc, - chunk_id=chunk_id_, - padding=False, - ) - if Modality.GEOMAP.value in present_modalities: - CompressedVideoHDF5.decode_resources( - f, - ret, - Modality.GEOMAP.value, - None, - lambda x: x.dtype == np.uint16 and len(x) != 0, - self.float32_depth, - chunk_id=chunk_id_, - padding=False, - ) - - else: - if Modality.IMAGES.value in present_modalities: - CompressedVideoHDF5.decode_resources( - f, - ret, - Modality.IMAGES.value, - slice_id, - lambda x: len(x.shape) == 3, - self.to_bhwc, - ) - if PrivilegeType.MASK.value in present_modalities: - CompressedVideoHDF5.decode_resources( - f, - ret, - PrivilegeType.MASK.value, - slice_id, - lambda x: len(x.shape) == 3, - self.to_bhwc, - ) - if Modality.GEOMAP.value in present_modalities: - CompressedVideoHDF5.decode_resources( - f, - ret, - Modality.GEOMAP.value, - slice_id, - lambda x: x.dtype == np.uint16 and len(x) != 0, - self.float32_depth, - ) - if Modality.IMAGES.value in present_modalities: - f["observations"][Modality.IMAGES.value] = ret["observations"][ - Modality.IMAGES.value - ] - if PrivilegeType.MASK.value in present_modalities: - f["observations"][PrivilegeType.MASK.value] = ret["observations"][ - PrivilegeType.MASK.value - ] - if Modality.GEOMAP.value in present_modalities: - f["observations"][Modality.GEOMAP.value] = ret["observations"][ - Modality.GEOMAP.value - ] - - return f - - -class ActStateStatistic: - def __init__(self, data_dict: Dict, min_len_steps: int) -> None: - self.data_dict = data_dict - self.min_len_steps = min_len_steps - - def prepare_state_and_action( - self, - ): - proprio = self.data_dict["observations"][Modality.STATES.value][:] - num_steps = proprio.shape[0] - # [Optional] We drop too-short episode - if num_steps < self.min_len_steps: - return False, None - # [Optional] We skip the first few still steps - EPS = 1e-2 - # Get the idx of the first qpos whose delta exceeds the threshold - proprio_delta = np.abs(proprio - proprio[0:1]) - indices = np.where(np.any(proprio_delta > EPS, axis=1))[0] - if len(indices) > 0: - first_idx = indices[0] - else: - raise ValueError("Found no qpos that exceeds the threshold.") - target_actions = self.data_dict[Modality.ACTIONS.value][:] - # Parse the state and action - state = proprio[first_idx - 1 :] - action = target_actions[first_idx - 1 :] - # Return the resulting sample - - return True, {Modality.STATES.value: state, Modality.ACTIONS.value: action} - - def statistic( - self, - ) -> Dict: - EPS = 1e-8 - episode_cnt = 0 - state_sum = 0 - state_sum_sq = 0 - z_state_sum = 0 - z_state_sum_sq = 0 - state_cnt = 0 - nz_state_cnt = None - state_max = None - state_min = None - _, episode = self.prepare_state_and_action() - episode_cnt += 1 - - states = episode[Modality.STATES.value] - - # Zero the values that are close to zero - z_states = states.copy() - z_states[np.abs(states) <= EPS] = 0 - # Compute the non-zero count - if nz_state_cnt is None: - nz_state_cnt = np.zeros(states.shape[1]) - nz_state_cnt += np.sum(np.abs(states) > EPS, axis=0) - - # Update statistics - state_sum += np.sum(states, axis=0) - state_sum_sq += np.sum(states**2, axis=0) - z_state_sum += np.sum(z_states, axis=0) - z_state_sum_sq += np.sum(z_states**2, axis=0) - state_cnt += states.shape[0] - if state_max is None: - state_max = np.max(states, axis=0) - state_min = np.min(states, axis=0) - else: - state_max = np.maximum(state_max, np.max(states, axis=0)) - state_min = np.minimum(state_min, np.min(states, axis=0)) - - # Add one to avoid division by zero - nz_state_cnt = np.maximum(nz_state_cnt, np.ones_like(nz_state_cnt)) - - result = { - "state_mean": (state_sum / state_cnt).tolist(), - "state_std": np.sqrt( - np.maximum( - (z_state_sum_sq / nz_state_cnt) - - (z_state_sum / state_cnt) ** 2 * (state_cnt / nz_state_cnt), - np.zeros_like(state_sum_sq), - ) - ).tolist(), - "state_min": state_min.tolist(), - "state_max": state_max.tolist(), - } - - return result - - -class DataDictExtractor: - def __init__( - self, - env: Union[BaseEnv, EmbodiedEnv], - save_path: str = None, - compression_opts: int = 9, - ): - self.env = env - self.save_path = save_path - self.data = {} - - # save all supported proprio and action types. - robot_meta_config = deepcopy(self.env.metadata["dataset"]["robot_meta"]) - robot_meta_config["observation"][ - Modality.STATES.value - ] = SUPPORTED_PROPRIO_TYPES - robot_meta_config[Modality.ACTIONS.value] = SUPPORTED_ACTION_TYPES - - self.state_unifier = StateUnifier(robot_meta=robot_meta_config) - self.compression_opts = compression_opts - - @cached_property - def robot_control_parts(self) -> List[str]: - """Get the robot's control parts. - - Note: - If control_parts is specified in the robot metadata, return those parts. - Otherwise, return all control parts. - - Returns: - List[str]: The robot's control parts. - """ - robot_meta_config = self.env.metadata["dataset"]["robot_meta"] - control_parts = robot_meta_config.get("control_parts", None) - if control_parts is None: - return [] - else: - return control_parts - - def _get_arm_control_parts(self) -> List[str]: - control_parts = self.robot_control_parts - arm_control_parts = [] - for part in control_parts: - if "arm" in part: - arm_control_parts.append(part) - return arm_control_parts - - def _has_exteroception(self) -> bool: - robot_meta_config = self.env.metadata["dataset"]["robot_meta"] - return PrivilegeType.EXTEROCEPTION.value in robot_meta_config["observation"] - - def extract( - self, - obs_list: List[Dict[str, Any]], - action_list: List[Dict[str, Any]], - data_dict: Dict = DATA_FORMATS, - save: bool = True, - ): - if save: - assert ( - self.save_path is not None - ), "Please provide a save path for the dataset." - data_dict = deepcopy(data_dict) - - self._init_data(data_dict) - - ret = {} - robot_meta_config = self.env.metadata["dataset"]["robot_meta"] - - for i, (obs, action) in enumerate(zip(obs_list, action_list)): - self._extract_vision_obs(obs, data_dict) - self._extract_proprioception(obs, data_dict) - self._extract_action(action, data_dict) - - action = self._collate_action(data_dict) - proprio = self._collate_proprio(data_dict) - robot_meta = self._collate_metainfo() - - extra_vision_config = robot_meta_config["observation"]["vision"] - obs = {"observations": {}} - images = self.collate_sub_anns( - data_dict, extra_vision_config, Modality.IMAGES.value - ) - obs["observations"].update(proprio) - obs["observations"].update(images) - - extra_vision_names = list( - set([name for list in extra_vision_config.values() for name in list]) - ) - for extra_vision_name in extra_vision_names: - extra_vision_obs = self.collate_sub_anns( - data_dict, extra_vision_config, extra_vision_name - ) - obs["observations"].update(extra_vision_obs) - - ret.update(robot_meta) - ret.update(obs) - ret.update(action) - - statistics = ActStateStatistic( - ret, self.env.metadata["dataset"]["robot_meta"]["min_len_steps"] - ).statistic() - ret.update(statistics) - - if save: - if has_h5ffmpeg: - cvhdf5 = CompressedVideoHDF5(self.save_path) - all_video_names = [Modality.IMAGES.value] + [ - name - for name in extra_vision_names - if name != PrivilegeType.EXTEROCEPTION.value - ] - all_dtypes = [ - np.uint16 if name == Modality.GEOMAP.value else np.uint8 - for name in all_video_names - ] - cvhdf5.dump(ret, video_names=all_video_names, dtypes=all_dtypes) - else: - logger.log_info( - "h5ffmpeg is not installed, saving dataset without compression." - ) - import hdfdict - - # Open the file once and pass the file object to hdfdict.dump to - # avoid opening/truncating the same file path twice which causes - # "unable to truncate a file which is already open" errors on - # some platforms and HDF5 builds. - with h5py.File(self.save_path, "w") as f: - hdfdict.dump(ret, f) - - return ret - - def _init_data(self, data_dict: Dict): - robot_meta_config = self.env.metadata["dataset"]["robot_meta"] - extra_vision_config = robot_meta_config["observation"]["vision"] - - for proprio_name in SUPPORTED_PROPRIO_TYPES: - data_dict["observations"][Modality.STATES.value][proprio_name] = [] - for action_name in SUPPORTED_ACTION_TYPES: - data_dict[Modality.ACTIONS.value][action_name] = [] - - for camera_name, extra_vision_list in extra_vision_config.items(): - is_stereo = isinstance(self.env.get_sensor(camera_name), StereoCamera) - - data_dict["observations"][Modality.IMAGES.value][camera_name] = [] - if is_stereo: - data_dict["observations"][Modality.IMAGES.value][ - get_right_name(camera_name) - ] = [] - - for extra_vision_name in extra_vision_list: - if extra_vision_name in SUPPORTED_EXTRA_VISION_TYPES: - data_dict["observations"][extra_vision_name][camera_name] = [] - else: - log_error( - f"Extra vision observation name {extra_vision_name} is not in SUPPORTED_EXTRA_VISION_TYPES {SUPPORTED_EXTRA_VISION_TYPES}, please check again." - ) - if is_stereo: - data_dict["observations"][extra_vision_name][ - get_right_name(camera_name) - ] = [] - - def _extract_vision_obs(self, obs: Dict[str, Any], data_dict: Dict): - robot_meta_config = self.env.metadata["dataset"]["robot_meta"] - extra_vision_config = robot_meta_config["observation"]["vision"] - - for camera_name, extra_vision_list in extra_vision_config.items(): - if camera_name in obs["sensor"]: - is_stereo = isinstance(self.env.get_sensor(camera_name), StereoCamera) - - data_dict["observations"][Modality.IMAGES.value][camera_name].append( - obs["sensor"][camera_name]["color"] - .squeeze(0)[:, :, :3] - .cpu() - .numpy() - ) - if is_stereo: - # save rgb right - data_dict["observations"][Modality.IMAGES.value][ - get_right_name(camera_name) - ].append( - obs["sensor"][camera_name]["color_right"] - .squeeze_(0)[:, :, :3] - .cpu() - .numpy() - ) - - for extra_vision_name in extra_vision_list: - if extra_vision_name in SUPPORTED_EXTRA_VISION_TYPES: - if extra_vision_name == PrivilegeType.EXTEROCEPTION.value: - if is_stereo: - data_dict["observations"][extra_vision_name][ - camera_name - ].append( - obs[extra_vision_name][camera_name]["l"] - .cpu() - .numpy() - ) - data_dict["observations"][extra_vision_name][ - get_right_name(camera_name) - ].append( - obs[extra_vision_name][camera_name]["r"] - .cpu() - .numpy() - ) - elif camera_name in obs.get(extra_vision_name, {}): - data_dict["observations"][extra_vision_name][ - camera_name - ].append( - obs[extra_vision_name][camera_name].cpu().numpy() - ) - elif extra_vision_name == PrivilegeType.MASK.value: - # save semantic mask for monocular cameras - data_dict["observations"][extra_vision_name][ - camera_name - ].append( - obs["sensor"][camera_name]["semantic_mask_l"] - .squeeze_(0) - .numpy() - .astype(np.uint8) - ) - if is_stereo: - data_dict["observations"][extra_vision_name][ - get_right_name(camera_name) - ].append( - obs["sensor"][camera_name]["semantic_mask_r"] - .squeeze_(0) - .numpy() - .astype(np.uint8) - ) - elif extra_vision_name == Modality.GEOMAP.value: - if not is_stereo: - log_error( - f"Camera {camera_name} is not stereo, while '{extra_vision_name}' is in gym_config.dataset.robot_meta.vision, please check again." - ) - if "depth" in obs["sensor"][camera_name]: - data_dict["observations"][extra_vision_name][ - camera_name - ].append( - obs["sensor"][camera_name]["depth"] - .squeeze_() - .numpy() - ) - else: - log_error( - f"obs['sensor'][{camera_name}] has no key named 'depth' while it's required in gym_config.dataset.robot_meta.vision, please check again." - ) - else: - log_error( - f"Extra vision observation name {extra_vision_name} is not in SUPPORTED_EXTRA_VISION_TYPES {SUPPORTED_EXTRA_VISION_TYPES}, please check again." - ) - else: - logger.log_error( - f"Camera {camera_name} not found in observations, please check your sensor configuration in gym_config.json" - ) - - def _extract_action( - self, - action: torch.Tensor, - data_dict: Dict, - ): - robot: Robot = self.env.robot - - for key in data_dict[Modality.ACTIONS.value].keys(): - part = _data_key_to_control_part( - robot=robot, - control_parts=self.env.metadata["dataset"]["robot_meta"].get( - "control_parts", [] - ), - data_key=key, - ) - if part is None: - continue - indices = robot.get_joint_ids(part, remove_mimic=True) - data_dict[Modality.ACTIONS.value][key].append( - action[0, indices].cpu().numpy() - if isinstance(action, torch.Tensor) - else action[0, indices] - ) - - eef_pose_dict = map_qpos_to_eef_pose( - robot, action, control_parts=self._get_arm_control_parts() - ) - for key, val in eef_pose_dict.items(): - data_dict[Modality.ACTIONS.value][key].append( - val.squeeze_(0).cpu().numpy() - if isinstance(val, torch.Tensor) - else val.squeeze_(0) - ) - - def _extract_proprioception( - self, - obs: Dict[str, Any], - data_dict: Dict, - ): - robot: Robot = self.env.robot - - qpos = obs["robot"][JointType.QPOS.value] - for key in data_dict["observations"][Modality.STATES.value].keys(): - part = _data_key_to_control_part( - robot=robot, - control_parts=self.env.metadata["dataset"]["robot_meta"].get( - "control_parts", [] - ), - data_key=key, - ) - if part is None: - continue - indices = robot.get_joint_ids(part, remove_mimic=True) - data_dict["observations"][Modality.STATES.value][key].append( - qpos[0][indices].cpu().numpy() - ) - - eef_pose_dict = map_qpos_to_eef_pose( - robot, qpos, control_parts=self._get_arm_control_parts() - ) - for key, val in eef_pose_dict.items(): - data_dict["observations"][Modality.STATES.value][key].append( - val.squeeze_(0).cpu().numpy() - ) - - def _collate_proprio(self, data_dict: Dict) -> Dict: - proprio_dict = {} - for proprio_name in self.state_unifier.proprio_meta: - proprio = np.array( - data_dict["observations"][Modality.STATES.value][proprio_name] - ) - proprio_dict[proprio_name] = proprio - proprios = self.state_unifier.fill_in_state(proprio_dict) - return {Modality.STATES.value: proprios} - - def _collate_metainfo( - self, - ) -> Dict: - meta_info = { - "arm_dofs": self.env.metadata["dataset"]["robot_meta"].get("arm_dofs", 12), - "observation": self.env.metadata["dataset"]["robot_meta"].get( - "observation", {} - ), - "min_len_steps": self.env.metadata["dataset"]["robot_meta"].get( - "min_len_steps", 125 - ), - } - return { - "robot_meta": meta_info, - "instruction": { - "lang": self.env.metadata["dataset"]["instruction"].get("lang", "") - }, - } - - def _collate_action(self, data_dict: Dict) -> Dict: - action_data_dict = data_dict[Modality.ACTIONS.value] - for k, v in action_data_dict.items(): - action_data_dict[k] = np.array(v) - - action_dict = {} - action_dict.update(action_data_dict) - action = self.state_unifier.fill_in_action(action_dict) - return {Modality.ACTIONS.value: action} - - @staticmethod - def collate_sub_anns( - data_dict: Dict, - extra_vision_config: Dict, - key: str = Modality.IMAGES.value, - ) -> Dict: - ret = {key: {}} - for camera_name in extra_vision_config: - images_list = data_dict["observations"][key].pop(camera_name, None) - if images_list is None: - continue - if len(images_list) > 0: - ret[key][camera_name] = np.empty( - (len(images_list),) + images_list[0].shape, - dtype=images_list[0].dtype, - ) - for idx, image in enumerate(images_list): - ret[key][camera_name][idx] = image - else: - ret[key][camera_name] = np.array([]) - - del images_list - if get_right_name(camera_name) in data_dict["observations"][key]: - images_right_list = data_dict["observations"][key].pop( - get_right_name(camera_name), None - ) - if images_right_list is None: - continue - if len(images_right_list) > 0: - ret[key][get_right_name(camera_name)] = np.empty( - (len(images_right_list),) + images_right_list[0].shape, - dtype=images_right_list[0].dtype, - ) - for idx, image in enumerate(images_right_list): - ret[key][get_right_name(camera_name)][idx] = image - else: - ret[key][get_right_name(camera_name)] = np.array([]) - del images_right_list - - return ret - - -def fetch_imitation_dataset( - env: BaseEnv, - obs_list: List[Dict[str, Any]], - action_list: List[Dict[str, Any]], - id: str, - folder_name: str, -) -> Dict: - """ - Save imitation dataset for a single episode. - - Args: - env (BaseEnv): Environment instance. - obs_list (List[Dict]): List of observation dicts. - action_list (List[Dict]): List of action dicts. - id (str): Unique identifier for the episode. - folder_name (str): Folder name for saving the dataset. - - Returns: - dict: Contains data_path, id, current_episode, and extracted data. - """ - # Get dataset save path - dataset_path = env.metadata["dataset"].get("save_path", None) - if dataset_path is None: - from embodichain.data import database_demo_dir - - dataset_path = database_demo_dir - - # Create folder if first episode - dataset_save_path = os.path.join(dataset_path, folder_name) - if env.curr_episode == 0 and id: - os.makedirs(dataset_save_path, exist_ok=True) - - # Check robot dof validity - try: - robot: Robot = env.robot - assert ( - env.metadata["dataset"]["robot_meta"]["arm_dofs"] <= robot.dof - ), f"Control dof {env.metadata['dataset']['robot_meta']['arm_dofs']} must be less than {robot.dof}." - except Exception as e: - logger.log_error(f"Robot DOF check failed: {e}") - return None - - # Select data format - data_format = DATA_FORMATS - - # Extract and save data - if id is None: - ret = DataDictExtractor(env).extract( - obs_list, action_list, save=False, data_dict=data_format - ) - save_path = None - else: - save_path = os.path.join(dataset_save_path, id + ".hdf5") - logger.log_info(f"Save episode {env.curr_episode} to '{save_path}'") - ret = DataDictExtractor(env, save_path).extract( - obs_list, action_list, save=True, data_dict=data_format - ) - - # Update episode count - env.curr_episode += 1 - - # Return result dict - return { - "data_path": dataset_save_path, - "id": id, - "current_episode": env.curr_episode, - "data": ret, - "save_path": save_path, - } diff --git a/embodichain/data/data_engine/datasets/vla_datasets.py b/embodichain/data/data_engine/datasets/vla_datasets.py deleted file mode 100644 index a3edb854..00000000 --- a/embodichain/data/data_engine/datasets/vla_datasets.py +++ /dev/null @@ -1,521 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---------------------------------------------------------------------------- - -import os -import fnmatch -from embodichain.utils.logger import log_warning, log_info - -try: - import h5ffmpeg as hf -except Exception as e: - log_warning("Fail to import h5ffmpeg.") -import h5py -import numpy as np -from typing import Dict, Callable, List, Tuple -from embodichain.utils.utility import get_right_name, pad_to_chunk, convert_bytes -from embodichain.utils.logger import log_warning, log_info -from embodichain.data.enum import Proprioception, Image, Exteroception, ModalInput -from copy import deepcopy -from typing import Dict -from embodichain.data.enum import ( - Modality, - PrivilegeType, - ActionMode, - JointType, - EefType, - CameraName, - TeleoperationData, -) -from embodichain.data.global_mapping import GlobalMapping -from scipy.ndimage import gaussian_filter1d -from embodichain.data.data_engine.unified_state import ActionIndicesGenerator - - -class VLADataset: - """ - This class is used to sample episodes from the embododiment dataset - stored in HDF5. - """ - - def __init__( - self, - data_path: str, - batch_size: int, - chunk_size: int, - state: List, - output: List, - img_history_size: int, - state_history_len: int, - precomp_lang_embed: bool = True, - online_config: Dict = None, - camera_used: List[str] = None, - indices_generator=None, - ) -> None: - # [Modify] The path to the HDF5 dataset directory - # Each HDF5 file contains one episode - - self.precomp_lang_embed = precomp_lang_embed - self.batch_size = batch_size - self.chunk_size = chunk_size - self.state = state - self.output = output - self.img_history_size = img_history_size - self.state_history_len = state_history_len - self.online_config = online_config - self.camera_used = camera_used - self.indices_generator = indices_generator - if self.camera_used is not None: - for cam in CameraName: - if cam.value not in camera_used: - log_warning( - "{} does not exist in {}".format(cam.value, camera_used) - ) - - if self.online_config is not None: - from embodichain.data.data_engine.online.engine import OnlineEngine - - log_info("Init online vla dataset.", color="purple") - self.engine = OnlineEngine(**self.online_config) - self.DATASET_NAME = "online_whatever" - else: - log_info("Init offline vla dataset.", color="purple") - self.engine = None - self.data_path = data_path - assert os.path.exists(self.data_path), "{} does not exist.".format( - self.data_path - ) - if os.path.isabs(self.data_path) is False: - self.data_path = os.path.join(os.getcwd(), self.data_path) - self.DATASET_NAME = os.path.basename(self.data_path) - self.file_paths = [] - for root, _, files in os.walk(self.data_path): - for filename in fnmatch.filter(files, "*.hdf5"): - file_path = os.path.join(root, filename) - self.file_paths.append(file_path) - log_info( - f"Init dataset with size of: {len(self.file_paths)}", color="purple" - ) - - def update_data_size(self): - """Interface for update validation dataset size generated on the fly.""" - self.file_paths = [] - for root, _, files in os.walk(self.data_path): - for filename in fnmatch.filter(files, "*.hdf5"): - file_path = os.path.join(root, filename) - self.file_paths.append(file_path) - log_info(f"Update dataset with size of: {len(self.file_paths)}", color="purple") - - def __len__(self): - return ( - len(self.file_paths) - if self.online_config is None - else np.maximum(self.engine.episode_limit, self.batch_size) - ) - - def get_item(self, index: int = None, chunk_size: int = None): - """Get a training sample at a random timestep. - - Args: - index (int, optional): the index of the episode. - If not provided, a random episode will be selected. - state_only (bool, optional): Whether to return only the state. - In this way, the sample will contain a complete trajectory rather - than a single timestep. Defaults to False. - - Returns: - sample (dict): a dictionary containing the training sample. - """ - chunk_size = self.chunk_size if chunk_size is None else chunk_size - while True: - if self.online_config is None: - # offline - if index is None: - file_path = np.random.choice(self.file_paths) - else: - file_path = self.file_paths[index] - valid, sample = self.parse_hdf5_file(file_path, chunk_size) - else: - data_dict = self.engine.sample_data() - valid, sample = self.parse_dict(data_dict, chunk_size) - - if valid: - return sample - else: - if self.online_config is None: - index = np.random.randint(0, len(self.file_paths)) - - @staticmethod - def parse_exteroception( - file: Dict, - step_id: int, - chunk_size: int, - camera_used: List[str] = [], - ) -> Exteroception: - exteroception = [] - for cam in camera_used: - exteroception_full = file["observations"][ - PrivilegeType.EXTEROCEPTION.value - ][cam] - exteroception.append(exteroception_full[step_id : step_id + chunk_size]) - - exteroception = np.concatenate(exteroception, 1) - _, cs, kn, _ = exteroception.shape - exteroception = pad_to_chunk(exteroception, chunk_size) - return Exteroception( - data=exteroception.reshape(chunk_size, cs, kn, 2).transpose( - 1, 0, 2, 3 - ) # cs, chunk_size, kn, 2 - ) - - @staticmethod - # Parse the images - def parse_img( - file: Dict, - step_id: int, - first_idx: int, - cam: str, - chunk_size: int, - key: str = Modality.IMAGES.value, - camera_used: List[str] = [], - np_ops: Callable = lambda x: x, - ) -> Image: - valid_len = min(step_id - (first_idx - 1) + 1, chunk_size) - cam_mask = np.array([False] * (chunk_size - valid_len) + [True] * valid_len) - if cam in camera_used: - temp = file["observations"][key][cam][0] - imgs = np.zeros((valid_len,) + temp.shape, dtype=temp.dtype) - for t, i in enumerate(range(max(step_id - chunk_size + 1, 0), step_id + 1)): - img = file["observations"][key][cam][i] - imgs[t] = img - imgs = np_ops(imgs) - imgs = pad_to_chunk(imgs, chunk_size=chunk_size) - mask = cam_mask.copy() - else: - imgs = np.zeros((chunk_size, 0, 0, 0)) - mask = np.zeros((chunk_size,), dtype=bool) - return Image(data=imgs, mask=mask, name=cam) - - def parse_hdf5_file(self, file_path, chunk_size: int) -> Dict[str, ModalInput]: - import hdfdict - from embodichain.data.data_engine.data_dict_extractor import ( - CompressedVideoHDF5, - ) - - with h5py.File(file_path, "r") as f: - data = hdfdict.load(f) - keyname = ( - JointType.QPOS.value - if VLADataset.is_real_datasets(data) - else Modality.STATES.value - ) - step_id = VLADataset.random_step_id(data, chunk_size, keyname) - if not VLADataset.is_real_datasets(data): - data = CompressedVideoHDF5(file_path, chunks=None).safe_filter( - data, step_id - ) - else: - # Real data: if compressed structure is detected (containing *_index/*_start), also perform decoding filtering - try: - if CompressedVideoHDF5.is_compressed_hdf5(data): - data = CompressedVideoHDF5(file_path, chunks=None).safe_filter( - data, step_id - ) - except Exception: - pass - - ret = self.parse_dict(data, chunk_size, step_id) - - return ret - - @staticmethod - def random_step_id( - f: Dict, chunk_size: int, key: str = Modality.STATES.value - ) -> int: - obs = f["observations"] - proprio = obs[key][:] - num_steps = proprio.shape[0] - # We randomly sample a timestep - first_idx = 1 - step_id = np.random.randint( - first_idx, np.maximum(first_idx + 1, num_steps - 1 - chunk_size) - ) - return step_id - - @staticmethod - def is_real_datasets(f: Dict): - return "robot_meta" not in f.keys() - - def parse_dict( - self, f: Dict, chunk_size: int, step_id: int = None - ) -> Dict[str, ModalInput]: - if not VLADataset.is_real_datasets(f): - log_warning("Using simulation hdf5 datasets.") - return self.parse_sim_dict(f, chunk_size, step_id) - else: - log_warning("Using real world offline hdf5 datasets.") - return self.parse_real_dict(f, chunk_size, step_id) - - def parse_real_dict( - self, f: Dict, chunk_size: int, step_id: int = None - ) -> Dict[str, ModalInput]: - - from embodichain.data.data_engine.unified_state import ( - StateUnifier, - ) - from embodichain.data.enum import ( - ControlParts, - EndEffector, - JointType, - ) - - if step_id is None: - step_id = VLADataset.random_step_id(f, chunk_size, "qpos") - obs = f["observations"] - first_idx = 1 - proprio = obs["qpos"][:] - num_steps = proprio.shape[0] - camera_used_in_real = list(obs[Modality.IMAGES.value].keys()) - camera_used_from_real_to_dualsys = { - "cam_hand_left": CameraName.LEFT_WRIST.value, - "cam_hand_right": CameraName.RIGHT_WRIST.value, - "cam_high_left": CameraName.HEAD.value, - } - camera_used_from_dualsys_to_real = { - val: key for key, val in camera_used_from_real_to_dualsys.items() - } - # Now assume it is from W1. - camera_used = [ - camera_used_from_real_to_dualsys[cam] - for cam in camera_used_in_real - if cam in camera_used_from_real_to_dualsys - ] - - # Assemble the meta - meta = { - "dataset_name": self.DATASET_NAME, - "#steps": num_steps, - "step_id": step_id, - "camera_used": camera_used, - "instruction": "", - } - # save all supported proprio and action types. - robot_meta_config = {"arm_dofs": 14, "observation": {}} - - REAL_SUPPORTED_PROPRIO_TYPES = [ - ControlParts.LEFT_ARM.value + JointType.QPOS.value, - ControlParts.RIGHT_ARM.value + JointType.QPOS.value, - ControlParts.HEAD.value + JointType.QPOS.value, - ControlParts.WAIST.value + JointType.QPOS.value, - ControlParts.LEFT_EEF.value + EndEffector.DEXTROUSHAND.value, - ControlParts.RIGHT_EEF.value + EndEffector.DEXTROUSHAND.value, - ] - REAL_SUPPORTED_ACTION_TYPES = REAL_SUPPORTED_PROPRIO_TYPES - - robot_meta_config["observation"][ - Modality.STATES.value - ] = REAL_SUPPORTED_PROPRIO_TYPES - robot_meta_config[Modality.ACTIONS.value] = REAL_SUPPORTED_ACTION_TYPES - state_unifier = StateUnifier(robot_meta=robot_meta_config) - - qpos_index_dict = { - ControlParts.LEFT_ARM.value - + JointType.QPOS.value: TeleoperationData.LEFT_ARM_QPOS_INDICES.value, - ControlParts.RIGHT_ARM.value - + JointType.QPOS.value: TeleoperationData.RIGHT_ARM_QPOS_INDICES.value, - ControlParts.LEFT_EEF.value - + EndEffector.DEXTROUSHAND.value: TeleoperationData.LEFT_EEF_DEXTROUSHAND_INDICES.value, - ControlParts.RIGHT_EEF.value - + EndEffector.DEXTROUSHAND.value: TeleoperationData.RIGHT_EEF_DEXTROUSHAND_INDICES.value, - ControlParts.HEAD.value - + JointType.QPOS.value: TeleoperationData.HEAD_QPOS_INDICES.value, - ControlParts.WAIST.value - + JointType.QPOS.value: TeleoperationData.WAIST_QPOS_INDICES.value, - } - qpos_dict = {} - for key, indices in qpos_index_dict.items(): - qpos_dict[key] = proprio[:, indices] - - actions = state_unifier.fill_in_action(qpos_dict) - proprio = state_unifier.fill_in_state(qpos_dict) - parse_dict = self.parse_core(proprio, actions, step_id, chunk_size) - parse_dict.update({"meta": meta}) - for cam in camera_used: - parse_dict[cam] = VLADataset.parse_img( - f, - step_id, - first_idx, - camera_used_from_dualsys_to_real[cam], - self.img_history_size, - Modality.IMAGES.value, - camera_used=camera_used_from_dualsys_to_real[cam], - ) - return True, parse_dict - - def parse_sim_dict( - self, f: Dict, chunk_size: int, step_id: int = None - ) -> Dict[str, ModalInput]: - - if step_id is None: - step_id = VLADataset.random_step_id(f, chunk_size) - - obs = f["observations"] - metadata = dict(f["robot_meta"]) - first_idx = 1 - - proprio = obs[Modality.STATES.value][:] - num_steps = proprio.shape[0] - min_len_step = metadata["min_len_steps"] - # [Optional] We drop too-short episode - if num_steps < min_len_step: - return False, None - - # We randomly sample a timestep - - camera_used = ( - convert_bytes(list(metadata["observation"]["vision"].keys())) - if self.camera_used is None - else self.camera_used - ) - - # Assemble the meta - meta = { - "dataset_name": self.DATASET_NAME, - "#steps": num_steps, - "step_id": step_id, - "instruction": "", - "camera_used": camera_used, - } - - assert ( - self.indices_generator.dof == metadata["arm_dofs"] - ), "Train dof {} but dataset dof {}.".format( - self.indices_generator.dof, metadata["arm_dofs"] - ) - parse_dict = self.parse_core( - proprio, f[Modality.ACTIONS.value], step_id, chunk_size - ) - parse_dict.update({"meta": meta}) - - for cam in camera_used: - cam_r = get_right_name(cam) - if cam_r in obs[Modality.IMAGES.value] and cam_r not in camera_used: - # insert camera name after cam - camera_used.insert(camera_used.index(cam) + 1, cam_r) - - for cam in camera_used: - parse_dict[cam] = VLADataset.parse_img( - f, - step_id, - first_idx, - cam, - self.img_history_size, - Modality.IMAGES.value, - camera_used=camera_used, - ) - - if PrivilegeType.MASK.value in obs: - parse_dict[ - cam + "_{}".format(PrivilegeType.MASK.value) - ] = VLADataset.parse_img( - f, - step_id, - first_idx, - cam, - self.img_history_size, - PrivilegeType.MASK.value, - camera_used=camera_used, - ) - if PrivilegeType.EXTEROCEPTION.value in obs: - if obs[PrivilegeType.EXTEROCEPTION.value][camera_used[0]].shape[0] != 0: - parse_dict[ - PrivilegeType.EXTEROCEPTION.value - ] = VLADataset.parse_exteroception( - f, - step_id, - chunk_size, - camera_used=camera_used, - ) - - if Modality.GEOMAP.value in obs: - if ( - hasattr(obs[Modality.GEOMAP.value][camera_used[0]], "shape") - and obs[Modality.GEOMAP.value][camera_used[0]].shape[0] != 0 - ): - parse_dict[Modality.GEOMAP.value] = VLADataset.parse_img( - f, - step_id, - first_idx, - CameraName.HEAD.value, - self.img_history_size, - Modality.GEOMAP.value, - camera_used=camera_used, - np_ops=lambda x: np.tile(np.expand_dims(x, -1), [1, 1, 1, 3]), - ) - - # Return the resulting sample - # For unavailable images, return zero-shape arrays, i.e., (IMG_HISORY_SIZE, 0, 0, 0) - # E.g., return np.zeros((self.img_history_size, 0, 0, 0)) for the key "cam_left_wrist", - # if the left-wrist camera is unavailable on your robot - return True, parse_dict - - def parse_core( - self, proprio: np.ndarray, actions: np.ndarray, step_id: int, chunk_size: int - ): - # Parse the state and action - state = proprio[np.maximum(step_id - self.state_history_len, 0) : step_id] - state = np.concatenate( - [np.tile(state[0:1], [self.state_history_len - state.shape[0], 1]), state], - 0, - ) - self.indices_generator: ActionIndicesGenerator - global_mapping = self.indices_generator.global_mapping - state_indices = global_mapping.get_indices( - convert_bytes(self.state), - ) - state_indicator = np.zeros_like(state, dtype=np.int8) - state_indicator[:, state_indices] = 1 - state *= state_indicator - proprio *= state_indicator[0:1] - state_std = np.std(proprio, axis=0) - state_mean = np.mean(proprio, axis=0) - state_norm = np.sqrt(np.mean(proprio**2, axis=0)) - action_indices = self.indices_generator.get( - self.output, - ) - actions = deepcopy(actions[step_id : step_id + chunk_size]) - # FIXME: handness injection - delta_qpos_indices = self.indices_generator.get_all_delta_qpos() - qpos_indices = self.indices_generator.get_all_qpos() - # NOTE: Ops `cumsum` equal to action[:horizon]-action[0:1]. - # TODO: action = action_chunk - current_obs. - actions[:, delta_qpos_indices] = ( - actions[:, qpos_indices] - state[-1:, qpos_indices] - ) - - actions = pad_to_chunk(actions, chunk_size=chunk_size) - action_indicator = np.zeros_like(actions, dtype=np.int8) - action_indicator[:, action_indices] = 1 - actions *= action_indicator[0:1] - - parse_dict = { - "state_std": state_std, - "state_mean": state_mean, - "state_norm": state_norm, - Modality.STATES.value: Proprioception(data=state, mask=state_indicator), - Modality.ACTIONS.value: Proprioception(data=actions, mask=action_indicator), - PrivilegeType.PROGRESS.value: step_id / proprio.shape[0], - } - return parse_dict diff --git a/embodichain/data/data_engine/online/engine.py b/embodichain/data/data_engine/online/engine.py deleted file mode 100644 index 8b49e391..00000000 --- a/embodichain/data/data_engine/online/engine.py +++ /dev/null @@ -1,525 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---------------------------------------------------------------------------- - -import time -import sys -import numpy as np -from threading import Thread -from typing import Dict, Tuple, Any, List, Callable, Optional -from copy import deepcopy -import threading -from embodichain.data.data_engine.online.enum import ( - ConsumerTeleEnum, - ProducerTeleEnum, -) - -import torch -import torch.multiprocessing as mp -import copy -from embodichain.utils.logger import ( - log_info, - log_warning, - decorate_str_color, - log_debug, -) - -# Must call cuda init to prevent cuda error in subprocess. -torch._C._cuda_init() - -from dexsim.utility import NumpyRNG - -import threading -from multiprocessing import shared_memory -import pickle -from datetime import datetime -import zmq - -__all__ = ["MaiDataEngine"] - -rng = NumpyRNG.get_rng() - -log_info_produce = lambda x: log_info(decorate_str_color(x, "cyan")) -log_info_consume = lambda x: log_info(decorate_str_color(x, "orange")) - -MAX_LOOP_TIMES = 40000 - - -def init_context(port): - context = zmq.Context() - socket = context.socket(zmq.REQ) - socket.connect("tcp://localhost:{}".format(port)) - return socket - - -class DataPoolCont: - data: Any - count: int = 0 - tag: str - - @staticmethod - def from_list(data_pool: List[Dict]) -> List["DataPoolCont"]: - ret = [] - for data in data_pool: - dcnt = DataPoolCont() - dcnt.data = data - dcnt.count = 0 - dcnt.tag = str(datetime.now()).split(".")[0] - ret.append(dcnt) - return ret - - @staticmethod - def clean_data_pool_in_place( - data_pool: List["DataPoolCont"], clean_indices: List[int] - ): - if clean_indices is None: - data_pool = [] - else: - if len(clean_indices) > 0: - log_debug( - "Clean data pool with data indices {}, counts {}.".format( - clean_indices, - [data_pool[index].count for index in clean_indices], - ), - color="purple", - ) - for i in list(np.sort(clean_indices)[::-1]): - data_pool.pop(i) - - -def fetch_data( - queue_data: mp.Queue, data_pool: List[DataPoolCont], worker_info, debug: bool = True -) -> bool: - start_time = time.time() - try: - existing_shm = queue_data.get(timeout=5) - except Exception as error: - log_debug("Timeout! {}.".format(str(error)), color="red") - return False - log_debug( - "[Thread {}][Worker {}][Get] Cost {}s.".format( - threading.current_thread().ident, - worker_info.id, - time.time() - start_time, - ) - ) - start_time = time.time() - scene_data = pickle.loads(existing_shm.buf[:]) - log_debug( - "[Thread {}][Worker {}][Pickle] Cost {}s.".format( - threading.current_thread().ident, - worker_info.id, - time.time() - start_time, - ) - ) - - if np.random.random() > 0.5 or queue_data.qsize() == 0: - start_time = time.time() - queue_data.put(existing_shm) # put back - log_debug( - "[Thread {}][Worker {}][Put] Cost {}s.".format( - threading.current_thread().ident, - worker_info.id, - time.time() - start_time, - ) - ) - - assert isinstance(scene_data, list), "Invalid data format {}.".format( - type(scene_data) - ) - start_time = time.time() - data = DataPoolCont.from_list(scene_data) - data_pool.extend(data) - - log_debug( - "[Thread {}][Worker {}][Other] Cost {}s.".format( - threading.current_thread().ident, - worker_info.id, - time.time() - start_time, - ) - ) - return True - - -class RestockCriterion: - def __init__(self, data_pool_limit: int, buffer_size: int, max_sample_num: int): - self.data_pool_limit = data_pool_limit - self.buffer_size = buffer_size - self.max_sample_num = max_sample_num - - def restock_condition(self, data_pool: List, queue: mp.Queue) -> bool: - return len(data_pool) < self.data_pool_limit - - def expired_condition( - self, data_pool: List[DataPoolCont], inverse: bool = False - ) -> List[bool]: - - if len(data_pool) == 0: - return [] - - if inverse: - return [data.count <= self.max_sample_num for data in data_pool] - else: - return [data.count > self.max_sample_num for data in data_pool] - - -class OnlineEngine: - """Data manager for online data production and training. - - The objectives of this class are: - - Manage the fetch data in a separate thread. - - Perform data synchronization between the data production process and - the training process (main process). - - Provide data sampling interface for the training process, which is designed - to return a batch of synthetic data with the different scene id. - - Data lifecycle management. - - To achieve the above objectives, the following functions should be implemented: - - from_shm_thread (static method) - - Args: - insight_config (List[CfgNode]): The config of insight pipeline. - episode_limit (int, optional): The maximum number of frames in the data pool. Defaults to 24. - max_sample_num (int, optional): The maximum number of times that a data can be sampled. - Defaults to 2. - target_device (torch.device, optional): The target device of the data. Defaults to torch.device('cpu'). - annos_param (Dict[str, Any], optional): The parameters of the annotations. Defaults to None. - data_gen_func (Callable, optional): The data generation function. Defaults to None. - unique_scene_frame (int, optional): The number of unique scene frame to be sampled. Defaults to None. - port (int, optional): The ZeroMQ socket port. Defaults to 5555. - buffer_size(int, optional): The number of max data queue size. Defaults to 10. - """ - - def __init__( - self, - episode_limit: int = 24, - max_sample_num: int = 2, - port: int = 5555, - buffer_size: int = 10, - multiprocess: bool = False, - **kwargs, - ) -> None: - - self.episode_limit = episode_limit - self._max_sample_num = max_sample_num - self.port = port - - self._data_pool = [] - - self._duration = 0.01 - - self._context = mp.get_context("forkserver") - - self._queue_data = self._context.Queue() - self._queue_data.cancel_join_thread() - - self.buffer_size = buffer_size - - self._data_gen_proc = None - self._fetch_data_thread = None - self._restock_data_pool = None - - self._is_started = False - self._is_restocked = False - self._socket = init_context(port + 1 if multiprocess else port) - - self._restock_criterion = RestockCriterion( - data_pool_limit=episode_limit, - buffer_size=buffer_size, - max_sample_num=max_sample_num, - ) - self._lock = threading.RLock() - - def start( - self, - ) -> None: - """Start the data production process and the data synchronization thread. - - Args: - wait_for_limit (bool, optional): Whether to wait for the data pool to reach - the frame limit. Defaults to False. - """ - - self._signal_gen = self._context.Value("b", True) - self._signal_fetch = self._context.Value("b", True) - - self._fetch_data_thread = Thread( - target=self.from_shm_thread, - args=( - self._socket, - self._queue_data, - self._duration, - self.buffer_size, - ), - daemon=True, - ) - self._fetch_data_thread.start() - self._is_started = True - log_info( - "Now start the thread to fetch data from share memory.", color="purple" - ) - - def start_restock(self, static: bool = False): - if static: - self._restock_data_pool = Thread( - target=self.restock_data_pool_static, - args=( - self._data_pool, - self._queue_data, - self._duration, - self._restock_criterion, - self._context, - self._lock, - ), - daemon=True, - ) - else: - self._restock_data_pool = Thread( - target=self.restock_data_pool, - daemon=True, - ) - - self._restock_data_pool.start() - self._is_restocked = True - - def stop(self) -> None: - if self.is_started: - self._is_started = False - self._signal_fetch.value = 2 - self._fetch_data_thread.join() - self.empty_queue(self._queue_data, self._context) - self.clean_data_pool_in_place() - self._signal_gen.value = 2 - else: - log_info( - "The data generation process has not been started.", color="purple" - ) - - @property - def is_started(self) -> bool: - return self._is_started - - @property - def data_size(self) -> int: - with self._lock: - return len(self._data_pool) - - @property - def queue_size(self) -> int: - return self._queue.qsize() - - @property - def unique_scene_frame(self) -> int: - return self._unique_scene_frame - - @staticmethod - def empty_queue(queue: mp.Queue, context: mp) -> None: - while queue.qsize() > 0: - try: - queue.get() - except Exception as e: - log_info("queue put invaild data format") - queue.close() - queue.join_thread() - queue = context.Queue() - break - return queue - - @staticmethod - def empty_share_memory(queue: mp.Queue) -> None: - while queue.qsize() > 0: - shm_name = queue.get() - shm = shared_memory.SharedMemory(shm_name) - shm.close() - shm.unlink() - - def restock_data_pool(self): - return OnlineEngine.restock_data_pool_static( - self._data_pool, - self._queue_data, - self._duration, - self._restock_criterion, - self._context, - self._lock, - ) - - @staticmethod - def restock_data_pool_static( - data_pool: List[DataPoolCont], - queue_data: mp.Queue, - duration: float, - restock_criterion: RestockCriterion, - context, - thread_lock, - ): - counts = 0 - - worker_info = torch.utils.data.get_worker_info() - if worker_info is None: - - class FakeWorkerInfo: - num_workers = 1 - id = 0 - - worker_info = FakeWorkerInfo() - - while True: - time.sleep(duration) - # always clean the data pool first. - - start_time = time.time() - with thread_lock: - # delete - clean_indices = list( - np.argwhere(restock_criterion.expired_condition(data_pool)).reshape( - -1 - ) - ) - DataPoolCont.clean_data_pool_in_place( - data_pool, - clean_indices, - ) - if len(clean_indices) > 0: - log_debug( - "[Thread {}][Delete][Cost {}s]".format( - threading.current_thread().ident, time.time() - start_time - ) - ) - - # after clean, we check whether to restock data. - while restock_criterion.restock_condition(data_pool, queue_data): - - prev_data_size = len(data_pool) - should_fetch = False - for i in range(worker_info.num_workers): - if queue_data.qsize() > 0 and worker_info.id == i: - should_fetch = True - if should_fetch: - start_time = time.time() - with thread_lock: - # add - fetch_data( - data_pool=data_pool, - queue_data=queue_data, - worker_info=worker_info, - ) - log_debug( - "[Thread {}][Worker {}][ToDataPool] Produce data: {}->{}. Cost {}s.".format( - threading.current_thread().ident, - worker_info.id, - prev_data_size, - len(data_pool), - time.time() - start_time, - ) - ) - counts = 0 - else: - counts += 1 - - if counts % MAX_LOOP_TIMES == 0 and counts != 0: - log_info("Can not find the shm after {} times.".format(counts)) - # queue_data = OnlineEngine.empty_queue(queue_data, context) - - @staticmethod - def from_shm_thread( - socket, - queue_data: mp.Queue, - duration: float = 0.001, - buffer_size: int = 10, - ) -> None: - """The data fetching thread for data synchronization. - - The queue_data_size is used to control the data fetching thread. - If queue_data_size < buffer_size, the data fetching thread will fetch data from the queue. - If queue_data_size >= buffer_size, the data fetching thread will stop fetch data. - - Args: - socket (zmq.Context): The socket send signal for connect fetch and generator. - queue_data (mp.Queue): This queue contains information about shared memory. - duration (float, optional): _description_. Defaults to 0.001. - port (int, optional): The ZeroMQ socket port. Defaults to 5555. - buffer_size(int, optional): The number of max data queue size. Defaults to 10. - """ - counts = 0 - while True: - time.sleep(duration) - counts += 1 - if queue_data.qsize() < buffer_size: - socket.send_string(ConsumerTeleEnum.SHAKEHAND.value) - message = socket.recv() - try: - message_str = message.decode() - except Exception as e: - log_debug(str(e), color="red") - message_str = "" - if message_str != ProducerTeleEnum.NOREADY.value: - log_debug("Receive data.", color="purple") - shm_name = pickle.loads(message).popleft() - existing_shm = shared_memory.SharedMemory(name=shm_name) - queue_data.put(existing_shm) - log_debug( - "[FromShmThread] Produce queue: {}->{};".format( - queue_data.qsize() - 1, queue_data.qsize() - ) - ) - else: - if counts % MAX_LOOP_TIMES == 0: - log_debug("Queue is full. Skip this stage.", "purple") - - def sample_data( - self, - ): - - if self._is_restocked: - pass - else: - log_debug("Now start the thread to restock data.", color="purple") - self.start_restock(static=False) - - worker_info = torch.utils.data.get_worker_info() - if worker_info is None: - - class FakeWorkerInfo: - num_workers = 1 - id = 0 - - worker_info = FakeWorkerInfo() - - counts = 0 - while True: - time.sleep(self._duration) - if len(self._data_pool) > 0: - start_time = time.time() - with self._lock: - index = rng.integers(0, len(self._data_pool)) - data = self._data_pool[index] - self._data_pool[index].count += 1 - log_debug( - "[SampleData, worker {}] Consume data {}: index {}; times: {}->{}; Show queue size: {}; Cost time: {}s.".format( - worker_info.id, - data.tag, - index, - data.count, - data.count + 1, - self._queue_data.qsize(), - np.round(time.time() - start_time, 4), - ) - ) - counts = 0 - return data.data - else: - counts += 1 - if counts % MAX_LOOP_TIMES == 0: - log_info("Data pool is always empty after {} times.".format(counts)) diff --git a/embodichain/data/data_engine/online/enum.py b/embodichain/data/data_engine/online/enum.py deleted file mode 100644 index a93b00d6..00000000 --- a/embodichain/data/data_engine/online/enum.py +++ /dev/null @@ -1,34 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---------------------------------------------------------------------------- - -from enum import Enum - - -class ConsumerTeleEnum(Enum): - SHAKEHAND = "Data is ready?" - CONSUME = "Fetch data!" - NOCONSUME = "Data_pool is full." - GOTDATA = "Feched data!" - NOGOTDATA = "Not fetching data." - - -class ProducerTeleEnum(Enum): - READY = "Yes" - NOREADY = "No ready" - FULL = "Data_pool is full" - FAIL = "Failed" - SEND = "Send!" - EMPTYSTR = "Empty String." diff --git a/embodichain/data/data_engine/online/online_generator.py b/embodichain/data/data_engine/online/online_generator.py deleted file mode 100644 index 979f3543..00000000 --- a/embodichain/data/data_engine/online/online_generator.py +++ /dev/null @@ -1,191 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---------------------------------------------------------------------------- - -import torch -import time -import zmq -import random -from multiprocessing import shared_memory -import pickle -from collections import deque -from typing import List -from threading import Thread -import multiprocessing as mp -import traceback -from embodichain.utils.logger import log_info, log_warning, log_error, log_debug -from embodichain.data.data_engine.online.enum import ( - ConsumerTeleEnum, - ProducerTeleEnum, -) - -torch._C._cuda_init() - - -class OnlineGenerator: - """Callback collection for online training mode.""" - - def __init__( - self, port: int, max_limit_gb: int = 50, multiprocess: bool = False, **kwargs - ) -> None: - self.shm_val = None - max_limit = max_limit_gb * 1024**3 - self._context = mp.get_context("forkserver") - self.port = port - self.socket = self.init_context(self.port, multiprocess) - self._duration = 0.01 - self.queue = deque() - self.queue_memroy = deque() - self.max_limit = max_limit - - self.validation_config = kwargs.get("validation", {}) - - def get_validation_config(self): - return self.validation_config - - def init_context(self, port, multiprocess: bool = False): - context = zmq.Context() - socket = context.socket(zmq.REP) - if multiprocess: - socket.connect(f"tcp://127.0.0.1:{port}") - else: - socket.bind(f"tcp://*:{port}") - - return socket - - def generator(self, generate_func, loop_times: int = -1, **kwargs): - self.signal = self._context.Value("b", True) - - self._zmq_send = Thread( - target=self.zmq_send, args=(self.queue, self.signal), daemon=True - ) - self._zmq_send.start() - log_debug("Start zmq sending.") - scene_id = 0 - - # -1 means infinite loop - while scene_id < loop_times or loop_times == -1: - if self.signal.value == 1: - first_time = True - try: - t0 = time.time() - return_list = generate_func( - time_id=scene_id, **self.validation_config - ) - - # TODO: support multiple trajectories for each scene. - if len(return_list) > 1: - log_error( - "Only support one trajectory for each scene in online generation mode." - ) - - data_dict_list = [return_list[0]["data"]] - - if ( - scene_id == 0 - and self.validation_config.get("num_samples", 0) > 0 - and "data_path" in return_list[0] - ): - # create shared memory to store the validation dataset path, which will be accessed by training process. - import sys - - data_path = return_list[0]["data_path"] - - shared_name = self.validation_config.get( - "dataset_name", "val_data_path" - ) - log_info( - f"Create shared memory for validation data path: {shared_name}", - color="green", - ) - self.shm_val = shared_memory.SharedMemory( - name=shared_name, - create=True, - size=len(data_path.encode()) + sys.getsizeof(""), - ) - self.shm_val.buf[: len(data_path.encode())] = data_path.encode() - log_info( - f"Craete shared memory for validation data path: {data_path}" - ) - - log_info( - f"Generate scene {scene_id + 1} time cost: {time.time() - t0}" - ) - serialized_data = pickle.dumps(data_dict_list) - shm = shared_memory.SharedMemory( - create=True, size=len(serialized_data) - ) - self.queue.append(shm.name) - self.queue_memroy.append( - {"name": shm.name, "size": len(serialized_data)} - ) - shm.buf[: len(serialized_data)] = serialized_data - except Exception as e: - log_error(f"Error in data generation process: {e}.") - traceback.print_exc() - self._zmq_send.join() - break - scene_id += 1 - self.empty_memory() - elif self.signal.value == 0: - if first_time: - log_warning("zmq recive full signal, wait generator signal") - first_time = False - log_warning("Signal value is 0.") - time.sleep(self._duration) - continue - else: - log_error("Unknown signal, data generator stop") - break - - def zmq_send(self, queue, signal): - while True: - try: - message = self.socket.recv_string() - if message == ConsumerTeleEnum.SHAKEHAND.value: - if len(queue) > 0: - log_warning( - "Recieve {} and send [data] to consumer.".format(message) - ) - self.socket.send(pickle.dumps(queue)) - queue.clear() - else: - self.socket.send(ProducerTeleEnum.NOREADY.value.encode()) - signal.value = 1 - except Exception as e: - print(e) - traceback.print_exc() - break - - def empty_memory(self): - total_size = sum([x["size"] for x in self.queue_memroy]) - log_info(f"share memory size is {total_size/(1024**3)} GB") - while total_size >= self.max_limit: - shm_name = self.queue_memroy.popleft() - if shm_name["name"] in self.queue: - log_info(f"remove {shm_name['name']} from queue") - self.queue.remove(shm_name["name"]) - try: - shm = shared_memory.SharedMemory(shm_name["name"]) - except: - continue - shm.close() - shm.unlink() - total_size = sum([x["size"] for x in self.queue_memroy]) - - def __del__(self): - if self.shm_val: - self.shm_val.close() - self.shm_val.unlink() diff --git a/embodichain/data/data_engine/unified_state.py b/embodichain/data/data_engine/unified_state.py deleted file mode 100644 index fc430def..00000000 --- a/embodichain/data/data_engine/unified_state.py +++ /dev/null @@ -1,381 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---------------------------------------------------------------------------- - -from embodichain.data.global_indices import ( - GLOBAL_INDICES, - STATE_VEC_LEN, -) -from embodichain.data.global_mapping import GlobalMapping -import numpy as np -from typing import List, Dict, Tuple, Union -from embodichain.data.enum import ( - ArmEnum, - Modality, - JointType, - ActionMode, - EefType, - ControlParts, - EndEffector, - Modality, -) -from embodichain.utils.logger import log_info, log_warning - -DEFAULT_EMPTY_STATE = -1 - - -"""Unified state utilities for EmbodiChain. - -This module provides helpers to construct and query a unified state/action -vector representation used across EmbodiChain environments and agents. - -Classes: - StateUnifier: Fill sparse per-modality state/action dictionaries into a - fixed-length unified state vector where unspecified entries are set - to a sentinel value (DEFAULT_EMPTY_STATE). - - ActionIndicesGenerator: Query index ranges in the unified vector for - common action/state groups (e.g. qpos, delta qpos, end-effector pose). - -Constants: - DEFAULT_EMPTY_STATE (int): Sentinel value used to mark unspecified - entries in the unified vector. -""" - - -class StateUnifier: - """Convert per-modality state/action arrays into a unified vector. - - The StateUnifier is constructed with ``robot_meta`` (the robot's - metadata) which should contain an ``observation`` mapping with keys for - modalities (e.g. ``Modality.STATES``) and an ``actions`` specification. - - Attributes: - metadata (dict): Robot metadata passed at construction. - arm_dofs (int): Degrees of freedom for the arm (default: 12). - indices_generator (ActionIndicesGenerator): Helper for action indices. - proprio_meta: Metadata list for proprioceptive modalities. - global_mapping (GlobalMapping): Mapping from names to unified indices. - output: Action output specification from metadata. - state_dim (int): Fixed length of the unified state vector. - """ - - def __init__(self, robot_meta: Dict) -> None: - assert "arm_dofs" in robot_meta - assert "observation" in robot_meta - assert Modality.ACTIONS.value in robot_meta - - self.arm_dofs = robot_meta["arm_dofs"] - self.indices_generator = ActionIndicesGenerator(self.arm_dofs) - self.proprio_meta = robot_meta["observation"][Modality.STATES.value] - self.global_mapping = GlobalMapping(self.arm_dofs) - self.output = robot_meta[Modality.ACTIONS.value] - - self.state_dim = STATE_VEC_LEN - - def fill_in_state( - self, values: Union[np.ndarray, Dict[str, np.ndarray]] - ) -> np.ndarray: - """Fill a unified state vector from given values. - - Args: - values (np.ndarray or dict): If ``values`` is a numpy array it is - assumed to already be aligned to the unified layout and will - be placed into the output container. If it is a ``dict``, - keys should match entries from the robot metadata - ``observation[Modality.STATES]`` and values are numpy arrays - with a trailing dimension matching each state's width. - - Returns: - np.ndarray: An array with shape ``(..., STATE_VEC_LEN)`` containing - the unified state with unspecified entries set to - ``DEFAULT_EMPTY_STATE``. - """ - if isinstance(values, np.ndarray): - UNI_STATE_INDICES = self.global_mapping.get_indices(self.proprio_meta) - uni_vec = ( - np.ones(values.shape[:-1] + (self.state_dim,)) * DEFAULT_EMPTY_STATE - ) - uni_vec[..., UNI_STATE_INDICES] = values - return uni_vec - else: - shape_tuple_list = [] - for val in values.values(): - shape_tuple = val.shape[:-1] - if val.size != 0: - shape_tuple_list.append(shape_tuple) - - shape_tuple = list(set(shape_tuple_list)) - assert len(shape_tuple) == 1, "shape tuple {} is not unique.".format( - shape_tuple - ) - uni_vec = np.ones(shape_tuple[0] + (self.state_dim,)) * DEFAULT_EMPTY_STATE - for state_name in self.proprio_meta: - state_indices = self.global_mapping.get_indices([state_name]) - if values[state_name].size != 0: - uni_vec[..., state_indices] = values[state_name] - - return uni_vec - - def fill_in_action( - self, values: Union[np.ndarray, Dict[str, np.ndarray]] - ) -> np.ndarray: - """Fill a unified action vector from given action values. - - This mirrors :meth:`fill_in_state` but uses the metadata's action - output specification to determine which named outputs map into the - unified vector. - - Args: - values (np.ndarray or dict): Action values aligned to the unified - layout or a mapping from output names to numpy arrays. - - Returns: - np.ndarray: Unified vector shaped ``(..., STATE_VEC_LEN)`` with - unspecified entries filled with ``DEFAULT_EMPTY_STATE``. - """ - if isinstance(values, np.ndarray): - UNI_STATE_INDICES = self.indices_generator.get(self.output) - uni_vec = ( - np.ones(values.shape[:-1] + (self.state_dim,)) * DEFAULT_EMPTY_STATE - ) - uni_vec[..., UNI_STATE_INDICES] = values - return uni_vec - else: - shape_tuple_list = [] - for key, val in values.items(): - - shape_tuple = val.shape[:-1] - if val.size != 0: - shape_tuple_list.append(shape_tuple) - - shape_tuple = list(set(shape_tuple_list)) - assert len(shape_tuple) == 1, "shape tuple {} is not unique.".format( - shape_tuple - ) - - uni_vec = np.ones(shape_tuple[0] + (self.state_dim,)) * DEFAULT_EMPTY_STATE - for out_name in self.output: - state_indices = self.global_mapping.get_indices([out_name]) - if out_name in values and values[out_name].size != 0: - uni_vec[..., state_indices] = values[out_name] - return uni_vec - - -class ActionIndicesGenerator: - """Utility for generating index lists for action/state groups. - - The ActionIndicesGenerator wraps :class:`GlobalMapping` to provide - common queries like retrieving indices for all joint positions (qpos), - delta qpos (relative mode), end-effector transforms/poses, and - hand-specific selections (left/right/both). - - Args: - dof (int, optional): If provided, a :class:`GlobalMapping` is - constructed and reused for queries. - """ - - def __init__(self, dof: int = None): - self.global_mapping = None - self.dof = dof - if dof is not None: - self.global_mapping = GlobalMapping(dof) - - def get_all_qpos( - self, dof: int = None, handness: str = ArmEnum.DUAL_ARM.value - ) -> List[int]: - """Return indices covering all joint position entries. - - Args: - dof (int, optional): Degrees of freedom to construct a temporary - :class:`GlobalMapping` if the generator was not initialized - with a ``dof``. - handness (str): One of values from :class:`ArmEnum` specifying - which arm(s) to include. - - Returns: - List[int]: Ordered list of indices in the unified vector - corresponding to qpos entries for the requested arm - selection. - """ - qpos_name = JointType.QPOS.value - delta_qpos_name = ActionMode.RELATIVE.value + qpos_name - global_mapping = self.get_mapping(dof) - - all_names = list(global_mapping.mapping_from_name_to_indices.keys()) - if handness == ArmEnum.DUAL_ARM.value: - return self.get(all_names, dof, [qpos_name], [delta_qpos_name]) - elif handness == ArmEnum.LEFT_ARM_ONLY.value: - handness = ControlParts.LEFT_ARM.value - return self.get( - all_names, dof, [handness + qpos_name], [handness + delta_qpos_name] - ) - elif handness == ArmEnum.RIGHT_ARM_ONLY.value: - handness = ControlParts.RIGHT_ARM.value - return self.get( - all_names, dof, [handness + qpos_name], [handness + delta_qpos_name] - ) - - def get_all_delta_qpos( - self, dof: int = None, handness: str = ArmEnum.DUAL_ARM.value - ) -> List[int]: - """Return indices for delta (relative) joint position entries. - - Args and return are the same as :meth:`get_all_qpos` but select the - ``ActionMode.RELATIVE`` named entries. - """ - qpos_name = JointType.QPOS.value - delta_qpos_name = ActionMode.RELATIVE.value + qpos_name - global_mapping = self.get_mapping(dof) - - all_names = list(global_mapping.mapping_from_name_to_indices.keys()) - if handness == ArmEnum.DUAL_ARM.value: - return self.get(all_names, dof, [delta_qpos_name], []) - elif handness == ArmEnum.LEFT_ARM_ONLY.value: - handness = ControlParts.LEFT_ARM.value - return self.get(all_names, dof, [handness + delta_qpos_name], []) - elif handness == ArmEnum.RIGHT_ARM_ONLY.value: - handness = ControlParts.RIGHT_ARM.value - return self.get(all_names, dof, [handness + delta_qpos_name], []) - - def get_all_eef( - self, dof: int = None, handness: str = ArmEnum.DUAL_ARM.value - ) -> List[int]: - """Return indices covering end-effector (EEF) related entries. - - Args: - dof (int, optional): Degrees of freedom for mapping lookup. - handness (str): Which arm(s) to include (left/right/both). - - Returns: - List[int]: Indices corresponding to EEF-related entries. - """ - global_mapping = self.get_mapping(dof) - all_names = list(global_mapping.mapping_from_name_to_indices.keys()) - if handness == ArmEnum.DUAL_ARM.value: - return self.get( - all_names, - dof, - [ControlParts.LEFT_EEF.value, ControlParts.RIGHT_EEF.value], - [], - ) - elif handness == ArmEnum.LEFT_ARM_ONLY.value: - handness = ControlParts.LEFT_EEF.value - return self.get( - all_names, - dof, - [handness], - [], - ) - elif handness == ArmEnum.RIGHT_ARM_ONLY.value: - handness = ControlParts.RIGHT_EEF.value - return self.get( - all_names, - dof, - [handness], - [], - ) - - def get_all_eef_pose( - self, dof: int = None, handness: str = ArmEnum.DUAL_ARM.value - ) -> List[int]: - """Return indices specifically for EEF pose entries. - - Args: - dof (int, optional): Degrees of freedom for mapping lookup. - handness (str): Which arm(s) to include (left/right/both). - - Returns: - List[int]: Indices corresponding to EEF poses. - """ - global_mapping = self.get_mapping(dof) - all_names = list(global_mapping.mapping_from_name_to_indices.keys()) - - if handness == ArmEnum.DUAL_ARM.value: - return self.get(all_names, dof, [EefType.POSE.value], []) - elif handness == ArmEnum.LEFT_ARM_ONLY.value: - handness = ControlParts.LEFT_ARM.value - return self.get(all_names, dof, [handness + EefType.POSE.value], []) - elif handness == ArmEnum.RIGHT_ARM_ONLY.value: - handness = ControlParts.RIGHT_ARM.value - return self.get(all_names, dof, [handness + EefType.POSE.value], []) - - def get_mapping(self, dof: int = None): - """Return the :class:`GlobalMapping` used by this generator. - - If a mapping was created during initialization (because ``dof`` was - provided), ensure any provided ``dof`` argument matches it. Otherwise - construct and return a temporary :class:`GlobalMapping` for the - requested ``dof``. - - Args: - dof (int, optional): Degrees of freedom to construct a mapping - if one was not provided at initialization. - - Returns: - GlobalMapping: Mapping instance for name->index lookups. - """ - if self.global_mapping is not None: - assert dof is None or dof == self.dof - global_mapping = self.global_mapping - else: - assert ( - dof is not None - ), "Dof must be set when dof is not provided in initialization." - global_mapping = GlobalMapping(dof) - return global_mapping - - def get( - self, - output: List[str], - dof: int = None, - white_list: List[str] = None, - black_list: List[str] = None, - ) -> List[int]: - """Select and return indices from ``output`` names applying optional - white/black list filters. - - Args: - output (List[str]): Names (keys) in a :class:`GlobalMapping` - whose indices should be collected. - dof (int, optional): Degrees of freedom used to construct a - temporary :class:`GlobalMapping` if needed. - white_list (List[str], optional): If provided, only include names - that contain any of these substrings. - black_list (List[str], optional): If provided, exclude names - that contain any of these substrings. - - Returns: - List[int]: Ordered list of unified-vector indices for the - selected names. - """ - - action_indices = [] - global_mapping = self.get_mapping(dof) - - for action_type in output: - if isinstance(white_list, list) and isinstance(black_list, list): - if any([temp in action_type for temp in white_list]) and all( - [temp not in action_type for temp in black_list] - ): - action_indices += global_mapping.mapping_from_name_to_indices[ - action_type - ] - else: - action_indices += global_mapping.mapping_from_name_to_indices[ - action_type - ] - - return action_indices # keep order. diff --git a/embodichain/data/enum.py b/embodichain/data/enum.py index 5c31ed9e..853f08bf 100644 --- a/embodichain/data/enum.py +++ b/embodichain/data/enum.py @@ -14,93 +14,7 @@ # limitations under the License. # ---------------------------------------------------------------------------- -import torch -import numpy as np - -from typing import List, Tuple, Union, Dict -from enum import Enum, IntEnum -from itertools import product -from aenum import Enum as AEnum -from aenum import NoAlias - -from embodichain.utils.utility import get_right_name - - -class ModalInput: - def __init__( - self, - data: Union[torch.Tensor, np.ndarray] = None, - mask: Union[torch.Tensor, np.ndarray] = None, - name: str = "", - ): - self.data = data - self.mask = mask # indicator mask for the data, e.g., which part is valid. - self.name = name - - -class Privilege: - def __init__( - self, - data: Union[torch.Tensor, np.ndarray] = None, - mask: Union[torch.Tensor, np.ndarray] = None, - name: str = "", - ): - self.data = data - self.mask = mask # indicator mask for the data, e.g., which part is valid. - self.name = name - - -class Mask(Privilege): - pass - - -class Exteroception(Privilege): - pass - - -class State(Privilege): - pass - - -class Proprioception(ModalInput): - pass - - -class Image(ModalInput): - pass - - -class GeoMap(ModalInput): - pass - - -class Lang(ModalInput): - pass - - -class Modality(Enum): - STATES = "states" - STATE_INDICATOR = "state_indicator" - ACTIONS = "actions" - ACTION_INDICATOR = "action_indicator" - IMAGES = "images" - LANG = "lang" - LANG_INDICATOR = "lang_indicator" - GEOMAP = "geomap" # e.g., depth, point cloud, etc. - VISION_LANGUAGE = "vision_language" # e.g., image + lang - - -class JointType(Enum): - QPOS = "qpos" - - -class EefType(Enum): - POSE = "eef_pose" - - -class ActionMode(Enum): - ABSOLUTE = "" - RELATIVE = "delta_" # This indicates the action is relative change with respect to last state. +from enum import Enum class EndEffector(Enum): @@ -113,13 +27,6 @@ class EefExecute(Enum): CLOSE = "execute_close" -class CameraName(Enum): - HEAD = "cam_high" - HEAD_RIGHT = get_right_name("cam_high") - RIGHT_WRIST = "cam_right_wrist" - LEFT_WRIST = "cam_left_wrist" - - class ControlParts(Enum): LEFT_ARM = "left_arm" RIGHT_ARM = "right_arm" @@ -129,52 +36,6 @@ class ControlParts(Enum): WAIST = "waist" -class TeleoperationData(Enum): - """Enum for teleoperation data conversion script specific string constants""" - - # Camera types - HEAD_CAMERA = "head" - HAND_CAMERA = "hand" - - # Camera positions - LEFT_PLACE = "left" - RIGHT_PLACE = "right" - - # Camera name prefixes - CAM_HIGH_PREFIX = "cam_high" - CAM_HAND_PREFIX = "cam_hand" - - # File names and patterns - METADATA_FILE = "metadata.jsonl" - QPOS_PATTERN = "pose_record_*.json" - IMAGE_PATH_KEY = "image_path" - TIMESTAMP_KEY = "timestamp" - CAMERA_TYPE_KEY = "camera_type" - - # Data structure keys - OBSERVATIONS = "observations" - IMAGES = "images" - QPOS = "qpos" - ACTION = "action" - FRAMES = "frames" - DATA = "data" - - # Joint keys (common ones) - LEFT_GRIPPER = "LEFT_GRIPPER" - RIGHT_GRIPPER = "RIGHT_GRIPPER" - LEFT_HAND_PREFIX = "LEFT_HAND" - RIGHT_HAND_PREFIX = "RIGHT_HAND" - # Joint index mapping for real robot data - LEFT_ARM_QPOS_INDICES = [6, 7, 8, 9, 10, 11, 12] - RIGHT_ARM_QPOS_INDICES = [14, 15, 16, 17, 18, 19, 20] - LEFT_EEF_DEXTROUSHAND_INDICES = [22, 23, 24, 25, 26, 27] - RIGHT_EEF_DEXTROUSHAND_INDICES = [28, 29, 30, 31, 32, 33] - WAIST_QPOS_INDICES = [ - 3, - ] - HEAD_QPOS_INDICES = [4, 5] - - class Hints(Enum): EEF = ( ControlParts.LEFT_EEF.value, @@ -183,167 +44,3 @@ class Hints(Enum): EndEffector.DEXTROUSHAND.value, ) ARM = (ControlParts.LEFT_ARM.value, ControlParts.RIGHT_ARM.value) - - -class CameraLoc(AEnum): - # The difference between CameraLoc and CameraName is that CameraLoc allows duplicate values. - # And the value is used to indicate the sub-network ids, e.g. LEFT_WRIST and RIGHT_WRIST share the same sub-network feature extraction. - _settings_ = NoAlias - HEAD = 0 - RIGHT_WRIST = 1 - LEFT_WRIST = 1 - - -class CameraOrder(IntEnum): - # This is used to indicate the order of camera inputs, for both simulation and real deployment, training and inference. - # For dual system, the order is HEAD, RIGHT_WRIST, LEFT_WRIST. - HEAD = 0 - RIGHT_WRIST = 1 - LEFT_WRIST = 2 - - -DEFAULT_CAMERA_ORDER = {tmp.value: CameraName[tmp.name].value for tmp in CameraOrder} -DEFAULT_CAMERA_LOC = {CameraName[tmp.name].value: tmp.value for tmp in CameraLoc} - - -def link_type(*args) -> str: - l = len(args) - if l == 0: - return "" - elif l == 1: - return args[0] - elif l >= 2: - ret_str = "[{}]".format(args[0]) - for i in range(1, l): - ret_str += "_[{}]".format(args[i]) - return ret_str - - -combined_members = { - link_type(a.name + b.name, c.name + d.name, e.name): link_type( - a.value + b.value, c.value + d.value, e.value - ) - for a, b, c, d, e in product( - ActionMode, JointType, ActionMode, EefType, EndEffector - ) -} -ActionType = Enum("ActionType", combined_members) -combined_proprio_members = { - link_type(a.name, b.name, c.name): link_type(a.value, b.value, c.value) - for a, b, c in product(JointType, EefType, EndEffector) -} -ProprioType = Enum("ProprioType", combined_proprio_members) - - -def parse_action_type(action_type: str) -> Tuple[str, str, str]: - splits = action_type.split("[") - assert len(splits) == 3, "{} must contain 3-[].".format(action_type) - proprio_type = splits[0].split("]")[0] - eef_type = splits[1].split("]")[0] - end_effector = splits[2].split("]")[0] - return proprio_type, eef_type, end_effector - - -def parse_proprio_type(proprio_type: str) -> Tuple[str, str, str]: - return parse_action_type(proprio_type) - - -class PrivilegeType(Enum): - EXTEROCEPTION = "exteroception" - MASK = "mask" - STATE = "state" - PROGRESS = "progress" - - -SUPPORTED_PROPRIO_TYPES = [ - ControlParts.LEFT_ARM.value + EefType.POSE.value, - ControlParts.RIGHT_ARM.value + EefType.POSE.value, - ControlParts.LEFT_ARM.value + JointType.QPOS.value, - ControlParts.RIGHT_ARM.value + JointType.QPOS.value, - ControlParts.LEFT_EEF.value + EndEffector.DEXTROUSHAND.value, - ControlParts.RIGHT_EEF.value + EndEffector.DEXTROUSHAND.value, - ControlParts.LEFT_EEF.value + EndEffector.GRIPPER.value, - ControlParts.RIGHT_EEF.value + EndEffector.GRIPPER.value, -] -SUPPORTED_ACTION_TYPES = SUPPORTED_PROPRIO_TYPES + [ - ControlParts.LEFT_ARM.value + ActionMode.RELATIVE.value + JointType.QPOS.value, - ControlParts.RIGHT_ARM.value + ActionMode.RELATIVE.value + JointType.QPOS.value, -] -SUPPORTED_EXTRA_VISION_TYPES = [ - Modality.GEOMAP.value, - PrivilegeType.EXTEROCEPTION.value, - PrivilegeType.MASK.value, -] - - -def search_sub_str(sub_str: str, refs: List[str]): - ret = [False for _ in refs] - for i, ref in enumerate(refs): - ret[i] = sub_str in ref - return ret - - -class ArmEnum(IntEnum): - LEFT_ARM_ONLY = 1 - RIGHT_ARM_ONLY = 2 - DUAL_ARM = 3 - - -class ArmName(Enum): - LEFT_ARM_ONLY = "left_arm" - RIGHT_ARM_ONLY = "right_arm" - - -class SemanticMask(IntEnum): - BACKGROUND = 0 - FOREGROUND = 1 - ROBOT = 2 - - -def get_all_cond(suffix: str = "_cond") -> Dict[str, str]: - cond_dict = {} - for modality in Modality: - cond_dict[modality.value] = modality.value + suffix - for privilege in PrivilegeType: - cond_dict[privilege.value] = privilege.value + suffix - return cond_dict - - -def is_dual_arms(dofs: int) -> bool: - return dofs > 10 - - -from collections import deque - - -class HistoryChunks: - def __init__(self, history_len: int = 2) -> None: - self.deque = deque(maxlen=history_len) - self.history_len = history_len - - def inqueue(self, data: ModalInput) -> None: - self.deque.append(data) - - def __getitem__( - self, - index: int, - ) -> ModalInput: - return self.deque[index] - - def __len__( - self, - ) -> int: - return len(self.deque) - - def isfull( - self, - ) -> bool: - return len(self) == self.history_len - - def get_list( - self, - ) -> List[ModalInput]: - return list(self.deque) - - def clean(self) -> None: - self.deque.clear() diff --git a/embodichain/data/global_indices.py b/embodichain/data/global_indices.py deleted file mode 100644 index 518a2e4c..00000000 --- a/embodichain/data/global_indices.py +++ /dev/null @@ -1,132 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---------------------------------------------------------------------------- - -import numpy as np - -GLOBAL_INDICES = { - # [0, 10): right arm joint positions - **{"arm_joint_{}_pos".format(i): i for i in range(10)}, - **{"right_arm_joint_{}_pos".format(i): i for i in range(10)}, - # [10, 15): right gripper joint positions - **{"gripper_joint_{}_pos".format(i): i + 10 for i in range(5)}, - **{"right_gripper_joint_{}_pos".format(i): i + 10 for i in range(5)}, - "gripper_open": 10, # alias of right_gripper_joint_0_pos - "right_gripper_open": 10, - # [15, 25): right arm joint velocities - **{"arm_joint_{}_vel".format(i): i + 15 for i in range(10)}, - **{"right_arm_joint_{}_vel".format(i): i + 15 for i in range(10)}, - # [25, 30): right gripper joint velocities - **{"gripper_joint_{}_vel".format(i): i + 25 for i in range(5)}, - **{"right_gripper_joint_{}_vel".format(i): i + 25 for i in range(5)}, - "gripper_open_vel": 25, # alias of right_gripper_joint_0_vel - "right_gripper_open_vel": 25, - # [30, 33): right end effector positions - "eef_pos_x": 30, - "right_eef_pos_x": 30, - "eef_pos_y": 31, - "right_eef_pos_y": 31, - "eef_pos_z": 32, - "right_eef_pos_z": 32, - # [33, 39): right end effector 6D pose - "eef_angle_0": 33, - "right_eef_angle_0": 33, - "eef_angle_1": 34, - "right_eef_angle_1": 34, - "eef_angle_2": 35, - "right_eef_angle_2": 35, - "eef_angle_3": 36, - "right_eef_angle_3": 36, - "eef_angle_4": 37, - "right_eef_angle_4": 37, - "eef_angle_5": 38, - "right_eef_angle_5": 38, - # [39, 42): right end effector velocities - "eef_vel_x": 39, - "right_eef_vel_x": 39, - "eef_vel_y": 40, - "right_eef_vel_y": 40, - "eef_vel_z": 41, - "right_eef_vel_z": 41, - # [42, 45): right end effector angular velocities - "eef_angular_vel_roll": 42, - "right_eef_angular_vel_roll": 42, - "eef_angular_vel_pitch": 43, - "right_eef_angular_vel_pitch": 43, - "eef_angular_vel_yaw": 44, - "right_eef_angular_vel_yaw": 44, - # [45, 50): reserved - # [50, 60): left arm joint positions - **{"left_arm_joint_{}_pos".format(i): i + 50 for i in range(10)}, - # [60, 65): left gripper joint positions - **{"left_gripper_joint_{}_pos".format(i): i + 60 for i in range(5)}, - "left_gripper_open": 60, # alias of left_gripper_joint_0_pos - # [65, 75): left arm joint velocities - **{"left_arm_joint_{}_vel".format(i): i + 65 for i in range(10)}, - # [75, 80): left gripper joint velocities - **{"left_gripper_joint_{}_vel".format(i): i + 75 for i in range(5)}, - "left_gripper_open_vel": 75, # alias of left_gripper_joint_0_vel - # [80, 83): left end effector positions - "left_eef_pos_x": 80, - "left_eef_pos_y": 81, - "left_eef_pos_z": 82, - # [83, 89): left end effector 6D pose - "left_eef_angle_0": 83, - "left_eef_angle_1": 84, - "left_eef_angle_2": 85, - "left_eef_angle_3": 86, - "left_eef_angle_4": 87, - "left_eef_angle_5": 88, - # [89, 92): left end effector velocities - "left_eef_vel_x": 89, - "left_eef_vel_y": 90, - "left_eef_vel_z": 91, - # [92, 95): left end effector angular velocities - "left_eef_angular_vel_roll": 92, - "left_eef_angular_vel_pitch": 93, - "left_eef_angular_vel_yaw": 94, - # [95, 100): reserved - # [100, 102): base linear velocities - "base_vel_x": 100, - "base_vel_y": 101, - # [102, 103): base angular velocities - "base_angular_vel": 102, - # [103, 115): dextrous hand joint positions - **{"left_hand_joint_{}_pos".format(i): i + 103 for i in range(6)}, - **{"right_hand_joint_{}_pos".format(i): i + 109 for i in range(6)}, - # [115, 119): torso joint positions - **{"torso_joint_{}_pos".format(i): i + 115 for i in range(4)}, - # [119, 121): head joint positions - **{"head_joint_{}_pos".format(i): i + 119 for i in range(2)}, - "waist": 115, - # [121, 123): head joint velocities - **{"head_joint_{}_vel".format(i): i + 121 for i in range(2)}, - "waist_vel": 113, - # [124, 128): reserved -} - - -STATE_VEC_LEN = 128 - - -def get_all_left_related_indices(including_end: bool = True): - if including_end: - return np.arange(50, 128, step=1) - else: - return np.arange(50, 100) - - -def get_all_right_related_indices(): - return np.arange(0, 50) diff --git a/embodichain/data/global_mapping.py b/embodichain/data/global_mapping.py deleted file mode 100644 index 24ebcb34..00000000 --- a/embodichain/data/global_mapping.py +++ /dev/null @@ -1,161 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---------------------------------------------------------------------------- - -from embodichain.data.enum import ( - ControlParts, - ActionMode, - EndEffector, - JointType, - EefType, - is_dual_arms, -) -from embodichain.data.global_indices import GLOBAL_INDICES -import numpy as np -from typing import List - - -class GlobalMapping: - def __init__(self, dof: int): - self_attrs = GlobalMapping.__dict__ - num_arm = 2 if is_dual_arms(dofs=dof) else 1 - single_dof = dof // num_arm - function_dict = {} - for k, v in self_attrs.items(): - if isinstance(v, staticmethod) and "__" not in k: - function_dict.update(v.__func__(dof=single_dof, num_arm=num_arm)) - self.mapping_from_name_to_indices = function_dict - - @staticmethod - def get_qpos_indices(dof: int, num_arm, **kwrags): - - return { - ControlParts.LEFT_ARM.value - + JointType.QPOS.value: [ - GLOBAL_INDICES[f"left_arm_joint_{i}_pos"] for i in range(dof) - ], - ControlParts.RIGHT_ARM.value - + JointType.QPOS.value: [ - GLOBAL_INDICES[f"right_arm_joint_{i}_pos"] for i in range(dof) - ], - ControlParts.HEAD.value - + JointType.QPOS.value: [ - GLOBAL_INDICES["head_joint_{}_pos".format(i)] for i in range(2) - ], - ControlParts.WAIST.value + JointType.QPOS.value: [GLOBAL_INDICES["waist"]], - } - - @staticmethod - def get_gripper_open_state_indices(num_arm, **kwrags): - return { - ControlParts.LEFT_EEF.value - + EndEffector.GRIPPER.value: [GLOBAL_INDICES["left_gripper_open"]], - ControlParts.RIGHT_EEF.value - + EndEffector.GRIPPER.value: [GLOBAL_INDICES["right_gripper_open"]], - } - - @staticmethod - def get_hand_qpos_indices(num_arm: int, hand_dof: int = 6, **kwrags): - return { - ControlParts.LEFT_EEF.value - + EndEffector.DEXTROUSHAND.value: [ - GLOBAL_INDICES[f"left_hand_joint_{i}_pos"] for i in range(hand_dof) - ], - ControlParts.RIGHT_EEF.value - + EndEffector.DEXTROUSHAND.value: [ - GLOBAL_INDICES[f"right_hand_joint_{i}_pos"] for i in range(hand_dof) - ], - } - - @staticmethod - def get_gripper_open_vel_indices(num_arm, **kwrags): - return { - ControlParts.LEFT_EEF.value - + ActionMode.RELATIVE.value - + EndEffector.GRIPPER.value: [GLOBAL_INDICES["left_gripper_open_vel"]], - ControlParts.RIGHT_EEF.value - + ActionMode.RELATIVE.value - + EndEffector.GRIPPER.value: [GLOBAL_INDICES["right_gripper_open_vel"]], - } - - @staticmethod - def get_delta_qpos_indices(dof: int, num_arm, **kwrags): - return { - ControlParts.LEFT_ARM.value - + ActionMode.RELATIVE.value - + JointType.QPOS.value: [ - GLOBAL_INDICES[f"left_arm_joint_{i}_vel"] for i in range(dof) - ], - ControlParts.RIGHT_ARM.value - + ActionMode.RELATIVE.value - + JointType.QPOS.value: [ - GLOBAL_INDICES[f"right_arm_joint_{i}_vel"] for i in range(dof) - ], - ControlParts.HEAD.value - + ActionMode.RELATIVE.value - + JointType.QPOS.value: [ - GLOBAL_INDICES["head_joint_{}_vel".format(i)] for i in range(2) - ], - ControlParts.WAIST.value - + ActionMode.RELATIVE.value - + JointType.QPOS.value: [GLOBAL_INDICES["waist_vel"]], - } - - @staticmethod - def get_eef_pose_indices(num_arm, **kwrags): - return { - ControlParts.LEFT_ARM.value - + EefType.POSE.value: [ - GLOBAL_INDICES["left_eef_pos_x"], - GLOBAL_INDICES["left_eef_pos_y"], - GLOBAL_INDICES["left_eef_pos_z"], - GLOBAL_INDICES["left_eef_angle_0"], - GLOBAL_INDICES["left_eef_angle_1"], - GLOBAL_INDICES["left_eef_angle_2"], - GLOBAL_INDICES["left_eef_angle_3"], - GLOBAL_INDICES["left_eef_angle_4"], - GLOBAL_INDICES["left_eef_angle_5"], - ], - ControlParts.RIGHT_ARM.value - + EefType.POSE.value: [ - GLOBAL_INDICES["right_eef_pos_x"], - GLOBAL_INDICES["right_eef_pos_y"], - GLOBAL_INDICES["right_eef_pos_z"], - GLOBAL_INDICES["right_eef_angle_0"], - GLOBAL_INDICES["right_eef_angle_1"], - GLOBAL_INDICES["right_eef_angle_2"], - GLOBAL_INDICES["right_eef_angle_3"], - GLOBAL_INDICES["right_eef_angle_4"], - GLOBAL_INDICES["right_eef_angle_5"], - ], - } - - def get_indices(self, state_meta: List[str]): - state_indices = [] - - for proprio_name in state_meta: - state_indices += self.mapping_from_name_to_indices[proprio_name] - - return state_indices - - def ret_all_state( - self, - ): - state_indices = [] - - for val in self.mapping_from_name_to_indices.values(): - state_indices += val - - return state_indices diff --git a/embodichain/lab/gym/envs/action_bank/configurable_action.py b/embodichain/lab/gym/envs/action_bank/configurable_action.py index 9c285aa5..bdffc543 100644 --- a/embodichain/lab/gym/envs/action_bank/configurable_action.py +++ b/embodichain/lab/gym/envs/action_bank/configurable_action.py @@ -14,22 +14,23 @@ # limitations under the License. # ---------------------------------------------------------------------------- +import torch import numpy as np +import functools import networkx as nx +import matplotlib.pyplot as plt + from copy import deepcopy from typing import Dict, Tuple, Union, List, Callable, Any, Optional from tqdm import tqdm - -import torch -import matplotlib.pyplot as plt from functools import partial + from embodichain.utils.math import pose_inv from embodichain.utils.logger import log_info, log_warning, log_error from embodichain.lab.sim.cfg import MarkerCfg -from embodichain.lab.gym.utils.misc import resolve_env_params, _data_key_to_control_part +from embodichain.lab.gym.utils.misc import resolve_env_params, data_key_to_control_part from embodichain.data.enum import Hints, EefExecute from .utils import generate_affordance_from_src, get_init_affordance -import functools # https://stackoverflow.com/questions/41834530/how-to-make-python-decorators-work-like-a-tag-to-make-function-calls-by-tag @@ -995,7 +996,7 @@ def get_control_part(env, agent_uid): if agent_uid in control_parts: return agent_uid else: - return _data_key_to_control_part( + return data_key_to_control_part( robot=env.robot, control_parts=control_parts, data_key=agent_uid, diff --git a/embodichain/lab/gym/envs/embodied_env.py b/embodichain/lab/gym/envs/embodied_env.py index 4dcd2412..601055a0 100644 --- a/embodichain/lab/gym/envs/embodied_env.py +++ b/embodichain/lab/gym/envs/embodied_env.py @@ -452,45 +452,19 @@ def create_demo_action_list(self, *args, **kwargs) -> Optional[Sequence[EnvActio "The method 'create_demo_action_list' must be implemented in subclasses." ) - def to_dataset( - self, id: str, save_path: str = None, folder_name: str = None - ) -> Optional[str]: - """ - Convert the recorded episode data to a dataset format and save to disk. + def to_dataset(self, id: str, save_path: str = None) -> Optional[str]: + """Convert the recorded episode data to a dataset format. Args: id (str): Unique identifier for the dataset. save_path (str, optional): Path to save the dataset. If None, use config or default. - folder_name (str, optional): Folder name for saving. If None, auto-generate. Returns: Optional[str]: The path to the saved dataset, or None if failed. """ - # TODO: To be refactor data pipeline into more modularized and extendable way. - from embodichain.data.data_engine.data_dict_extractor import ( - fetch_imitation_dataset, - ) - from embodichain.lab.gym.utils.misc import camel_to_snake - - save_path = self.cfg.dataset.get("save_path", None) - if save_path is None: - from embodichain.data import database_demo_dir - - save_path = database_demo_dir - - if self.curr_episode == 0: - self.folder_name = f"{camel_to_snake(self.__class__.__name__)}_{camel_to_snake(self.robot.cfg.uid)}" - if os.path.exists(os.path.join(save_path, self.folder_name)): - self.folder_name = f"{self.folder_name}_{np.random.randint(0, 1000)}" - - dataset_path = fetch_imitation_dataset( - self, - self.episode_obs_list[:-1], - self.episode_action_list, - id, - self.folder_name, + raise NotImplementedError( + "The method 'to_dataset' will be implemented in the near future." ) - return dataset_path def is_task_success(self, **kwargs) -> torch.Tensor: """Determine if the task is successfully completed. This is mainly used in the data generation process diff --git a/embodichain/lab/gym/envs/managers/events.py b/embodichain/lab/gym/envs/managers/events.py index 1e089434..c6653ba1 100644 --- a/embodichain/lab/gym/envs/managers/events.py +++ b/embodichain/lab/gym/envs/managers/events.py @@ -241,7 +241,7 @@ def __call__( is_global_func = True ASSET_MODULES = [ - "embodichain.lab.gym.envs.object", + "embodichain.lab.gym.envs.managers.object", "embodichain.lab.gym.utils.misc", ] global_func = find_function_from_modules( diff --git a/embodichain/lab/gym/envs/object/__init__.py b/embodichain/lab/gym/envs/managers/object/__init__.py similarity index 100% rename from embodichain/lab/gym/envs/object/__init__.py rename to embodichain/lab/gym/envs/managers/object/__init__.py diff --git a/embodichain/lab/gym/envs/managers/object/geometry.py b/embodichain/lab/gym/envs/managers/object/geometry.py new file mode 100644 index 00000000..db26b18f --- /dev/null +++ b/embodichain/lab/gym/envs/managers/object/geometry.py @@ -0,0 +1,188 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + +from typing import Union + +from embodichain.utils import logger +from embodichain.lab.sim.objects import RigidObject +from embodichain.lab.gym.envs.managers.cfg import SceneEntityCfg +from embodichain.utils.utility import inv_transform + + +def get_pcd_svd_frame(pc: torch.Tensor) -> torch.Tensor: + """Computes the pose of a point cloud using Singular Value Decomposition (SVD). + + This function centers the point cloud, performs SVD to obtain the rotation, + and constructs a 4x4 transformation matrix representing the pose of the point cloud. + + Args: + pc (torch.Tensor): A 2D numpy array of shape (N, 3) representing the point cloud, + where N is the number of points. + + Returns: + torch.Tensor: A 4x4 transformation matrix that includes the rotation and translation + of the point cloud. + """ + if pc.ndim != 2: + logger.log_error( + f"get_pcd_svd_frame only support the pc of 1 object, which means that pc.ndim==2, but got {pc.ndim}" + ) + pc_center = pc.mean(axis=0) + pc_centered = pc - pc_center + u, s, vt = torch.linalg.svd(pc_centered) + rotation = vt.T + pc_pose = torch.eye(4, dtype=torch.float32) + pc_pose[:3, :3] = rotation + pc_pose[:3, 3] = pc_center + return pc_pose + + +def apply_svd_transfer_pcd( + geometry: Union[ + np.ndarray, + torch.Tensor, + RigidObject, + ], + sample_points: int = 1000, +) -> np.ndarray: + """Applies Singular Value Decomposition (SVD) transfer to a point cloud represented by geometry. + + Args: + geometry (Union[np.ndarray, torch.Tensor, RigidObject]): The input geometry, which can be a numpy array, + a torch tensor, or a RigidObject instance. + sample_points (int): The number of sample points to consider (default is 1000). + + Returns: + np.ndarray: The transformed vertices in standard position after applying SVD. + """ + if isinstance(geometry, RigidObject): + verts = torch.as_tensor(geometry.get_vertices()) + elif isinstance(geometry, (np.ndarray, torch.Tensor)): + verts = torch.as_tensor(geometry) + else: + logger.log_error( + f"Unsupported geometry type: {type(geometry)}. Expected np.ndarray, torch.Tensor, or RigidObject." + ) + + if verts.ndim < 3: + verts = verts[None] + + sample_ids = torch.randint(0, verts.shape[1], (sample_points,), device=verts.device) + verts = verts[:, sample_ids, :] + + # TODO: Can be optimized with fullly batch operations + standard_verts = [] + for object_verts in verts: + pc_svd_frame = get_pcd_svd_frame(object_verts) + inv_svd_frame = inv_transform(pc_svd_frame) + standard_object_verts = ( + object_verts @ inv_svd_frame[:3, :3].T + inv_svd_frame[:3, 3] + ) + standard_verts.append(standard_object_verts) + + return torch.stack(standard_verts) + + +def compute_object_length( + env, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + sample_points: int, + is_svd_frame: bool = True, +): + """Compute per-environment object extents (lengths) along principal axes. + + Computes the size of a rigid object's point cloud along the x, y and z axes + for each selected environment. The point cloud is first scaled by the + object's per-environment body scale. If requested, points are transformed + into an SVD-aligned coordinate frame prior to extent computation. + + Args: + env: Environment handle that must provide the following attributes: + - sim.get_rigid_object(uid) -> RigidObject-like object + - num_envs (int): total number of parallel environments + - device (torch.device): device for returned tensors + env_ids (torch.Tensor or None): Optional 1-D tensor of environment indices + (shape (k,)) to select a subset of environments. If None, all + environments are used. The number of selected environments + (num_envs_selected) is env.num_envs when env_ids is None or + env_ids.shape[0] otherwise. + entity_cfg (SceneEntityCfg): Scene entity configuration. Must contain + attribute `uid` used to fetch the RigidObject via env.sim. + sample_points (int): Number of points to sample per object when applying + SVD alignment, must be a positive integer. When not applying SVD, + this value is the expected number of sample points per object but + is not strictly required to match the input point count. + is_svd_frame (bool): If True, transform the scaled point cloud into an + SVD-aligned frame using apply_svd_transfer_pcd before computing + extents. If False, lengths are computed in the object's current + frame. + + Returns: + dict: Mapping with keys "x", "y", "z". Each value is a torch.Tensor of + shape (num_envs_selected,) with dtype torch.float32 located on + env.device. Each tensor contains the per-environment extent along that + axis computed as max_coordinate - min_coordinate over the sampled points. + + Raises: + ValueError: If sample_points <= 0. + TypeError: If env or entity_cfg do not provide the expected attributes. + + Notes: + - The RigidObject methods used are expected to return: + pcs = rigid_object.get_vertices(env_ids) + -> Tensor of shape (num_envs_selected, N, 3) (N is number of + points available per object; SVD sampling will draw with + replacement if sample_points > N). + body_scale = rigid_object.get_body_scale(env_ids) + -> Tensor broadcastable to pcs for per-environment scaling. + - After scaling, scaled_pcs has shape (num_envs_selected, N, 3). + If is_svd_frame is True, apply_svd_transfer_pcd(scaled_pcs, + sample_points) is expected to return a tensor of shape + (num_envs_selected, sample_points, 3). + - The returned per-axis lengths correspond to the first dimension of + the vertex tensor returned by get_vertices (num_envs_selected). + - Degenerate point clouds (all points identical along an axis) yield + zero length for that axis. + + Example: + # Use all environments and compute SVD-aligned lengths from 1024 samples + lengths = compute_object_length(env, None, entity_cfg, sample_points=1024, is_svd_frame=True) + # lengths['x'].shape -> torch.Size([num_envs_selected]) + """ + + rigid_object: RigidObject = env.sim.get_rigid_object(entity_cfg.uid) + object_lengths = {} + for axis in ["x", "y", "z"]: + object_lengths.update( + {axis: torch.zeros((env.num_envs,), dtype=torch.float32, device=env.device)} + ) + pcs = rigid_object.get_vertices(env_ids) + body_scale = rigid_object.get_body_scale(env_ids) + scaled_pcs = pcs * body_scale + + if is_svd_frame: + scaled_pcs = apply_svd_transfer_pcd(scaled_pcs, sample_points) + + for axis, idx in zip(["x", "y", "z"], [0, 1, 2]): + scaled_pos = scaled_pcs[..., idx] # (num_envs, sample_points) + length = scaled_pos.max(dim=1)[0] - scaled_pos.min(dim=1)[0] + object_lengths.update({axis: length}) + + return object_lengths diff --git a/embodichain/lab/gym/envs/object/geometry.py b/embodichain/lab/gym/envs/object/geometry.py deleted file mode 100644 index b95faf3c..00000000 --- a/embodichain/lab/gym/envs/object/geometry.py +++ /dev/null @@ -1,138 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---------------------------------------------------------------------------- - -import torch -import numpy as np -import open3d as o3d - -from typing import Union - -from dexsim.models import MeshObject -from embodichain.utils import logger -from embodichain.lab.sim.objects import RigidObject -from embodichain.lab.gym.envs.managers.cfg import SceneEntityCfg -from embodichain.utils.utility import inv_transform - - -def get_pc_svd_frame(pc: Union[np.ndarray, torch.Tensor]) -> np.ndarray: - """ - Computes the pose of a point cloud using Singular Value Decomposition (SVD). - - This function centers the point cloud, performs SVD to obtain the rotation, - and constructs a 4x4 transformation matrix representing the pose of the point cloud. - - Args: - pc (np.ndarray): A 2D numpy array of shape (N, 3) representing the point cloud, - where N is the number of points. - - Returns: - np.ndarray: A 4x4 transformation matrix that includes the rotation and translation - of the point cloud. - """ - if pc.ndim != 2: - logger.log_error( - f"get_pc_svd_frame only support the pc of 1 object, which means that pc.ndim==2, but got {pc.ndim}" - ) - pc_center = pc.mean(axis=0) - pc_centered = pc - pc_center - u, s, vt = torch.linalg.svd(pc_centered) - rotation = vt.T - pc_pose = torch.eye(4, dtype=torch.float32) - pc_pose[:3, :3] = rotation - pc_pose[:3, 3] = pc_center - return pc_pose - - -def apply_svd_transfer_pc( - geometry: Union[ - np.ndarray, - torch.Tensor, - o3d.cuda.pybind.geometry.TriangleMesh, - MeshObject, - RigidObject, - ], - sample_points: int = 1000, -) -> np.ndarray: - """ - Applies Singular Value Decomposition (SVD) transfer to a point cloud represented by geometry. - - Parameters: - geometry (Union[np.ndarray, MeshObject]): The input geometry, which can be a NumPy array of vertices - or a MeshObject containing vertex data. - sample_points (int): The number of sample points to consider (default is 1000). - - Returns: - np.ndarray: The transformed vertices in standard position after applying SVD. - """ - if isinstance(geometry, (RigidObject, MeshObject)): - verts = torch.as_tensor(geometry.get_vertices()) - elif isinstance(geometry, (np.ndarray, torch.Tensor)): - verts = torch.as_tensor(geometry) - elif isinstance(geometry, o3d.cuda.pybind.geometry.TriangleMesh): - verts = torch.as_tensor(geometry.vertices) - else: - logger.log_error( - f"Unsupported geometry type: {type(geometry)}. Expected np.ndarray, torch.Tensor, MeshObject, or RigidObject." - ) - - if verts.ndim < 3: - verts = verts[None] - - sample_ids = ( - np.random.choice(verts.shape[1], sample_points) - if isinstance(verts, np.ndarray) - else torch.randint(0, verts.shape[1], (sample_points,)) - ) - verts = verts[:, sample_ids, :] - - standard_verts = [] - for object_verts in verts: - pc_svd_frame = get_pc_svd_frame(object_verts) - inv_svd_frame = inv_transform(pc_svd_frame) - standard_object_verts = ( - object_verts @ inv_svd_frame[:3, :3].T + inv_svd_frame[:3, 3] - ) - standard_verts.append(standard_object_verts) - - return torch.stack(standard_verts) - - -def compute_object_length( - env, - env_ids: Union[torch.Tensor, None], - entity_cfg: SceneEntityCfg, - sample_points: int, - is_svd_frame: bool = True, -): - rigid_object: RigidObject = env.sim.get_rigid_object(entity_cfg.uid) - object_lengths = {} - for axis in ["x", "y", "z"]: - object_lengths.update( - {axis: torch.zeros((env.num_envs,), dtype=torch.float32, device=env.device)} - ) - pcs = rigid_object.get_vertices(env_ids) - body_scale = rigid_object.get_body_scale(env_ids) - scaled_pcs = pcs * body_scale - - if is_svd_frame: - scaled_pcs = apply_svd_transfer_pc(scaled_pcs, sample_points) - - for axis, idx in zip(["x", "y", "z"], [0, 1, 2]): - scaled_pos = scaled_pcs[..., idx] # (num_envs, sample_points) - length = scaled_pos.max(dim=1)[0] - scaled_pos.min(dim=1)[0] - object_lengths.update({axis: length}) - - return object_lengths diff --git a/embodichain/lab/gym/utils/gym_utils.py b/embodichain/lab/gym/utils/gym_utils.py index 42692190..1cf433a6 100644 --- a/embodichain/lab/gym/utils/gym_utils.py +++ b/embodichain/lab/gym/utils/gym_utils.py @@ -541,7 +541,6 @@ def map_qpos_to_eef_pose( Returns: Dict[str, torch.Tensor]: A dictionary containing the end-effector poses for each control part. """ - from embodichain.data.enum import EefType eef_pose_dict = {} for i, name in enumerate(control_parts): @@ -562,7 +561,7 @@ def map_qpos_to_eef_pose( eef_pose[:, 3:6] = part_eef_pose[:, :3, 0] eef_pose[:, 6:9] = part_eef_pose[:, :3, 1] - eef_pose_dict[name + EefType.POSE.value] = eef_pose + eef_pose_dict[name] = eef_pose return eef_pose_dict diff --git a/embodichain/lab/gym/utils/misc.py b/embodichain/lab/gym/utils/misc.py index 92098663..0f9cc5ee 100644 --- a/embodichain/lab/gym/utils/misc.py +++ b/embodichain/lab/gym/utils/misc.py @@ -41,31 +41,6 @@ def no_validation(*args, **kwargs): return True -def add_xy_random_offset( - pose: np.ndarray, max_offset: Union[float, List[float]] -) -> np.ndarray: - """ - Add a random offset to the x and y translation of a pose. - - Args: - pose (np.ndarray): 4x4 pose matrix. - max_offset (float or List[float]): If float, uniform in [-max_offset, max_offset] for both axes. - If list, [x_min, x_max, y_min, y_max]. - - Returns: - np.ndarray: Pose with random xy offset. - """ - shift_pose = deepcopy(pose) - if isinstance(max_offset, float): - xy_shift = np.random.uniform(-max_offset, max_offset, size=2) - else: - x_shift = np.random.uniform(max_offset[0], max_offset[1]) - y_shift = np.random.uniform(max_offset[2], max_offset[3]) - xy_shift = np.array([x_shift, y_shift]) - shift_pose[:2, 3] += xy_shift - return shift_pose - - def mul_linear_expand( arr: np.ndarray, expand_times: Union[int, List[int]], is_interp: bool = True ) -> np.ndarray: @@ -175,14 +150,7 @@ def is_pose_flip( return valid_ret -def is_qpos_exceed(qpos: np.ndarray, agent, uid: str): - return not ( - any(qpos < agent.get_joint_limits(uid)[:, 0]) - or any(qpos > agent.get_joint_limits(uid)[:, 1]) - ) - - -def is_qpos_exceed_new( +def is_qpos_exceed( qpos: Union[np.ndarray, torch.Tensor], robot: Robot, control_part: str ) -> bool: """ @@ -676,106 +644,6 @@ def get_changed_qpos( return qpos_to_change -def pose_shift(pose_in_cam: np.ndarray, axis: int, shift: float) -> np.ndarray: - shift_pose = np.copy(pose_in_cam) - shift_pose = np.linalg.inv(shift_pose) - shift_pose[axis, -1] += shift - shift_pose = np.linalg.inv(shift_pose) - return shift_pose - - -def expand_pose( - pose: np.ndarray, - x_interval: float, - y_interval: float, - kpnts_number: int, - grab_ratios: List = None, - ref_pose: np.ndarray = np.eye(4), -): - ret = [ref_pose @ pose] - - xoffset = np.linspace(-x_interval, x_interval, kpnts_number) - - if grab_ratios is None: - yoffset = np.linspace(-y_interval, y_interval, kpnts_number) - else: - yoffset = np.linspace( - -y_interval * grab_ratios[0], - y_interval * grab_ratios[1], - kpnts_number, - ) - - x_expand = [ref_pose @ pose_shift(pose, 0, x) for x in list(xoffset)] - y_expand = [ref_pose @ pose_shift(pose, 1, y) for y in list(yoffset)] - return ret + x_expand + y_expand - - -def parse_mask_by_uuids( - mask: np.ndarray, uuids: Dict[str, int] -) -> Dict[str, np.ndarray]: - from embodichain.data.enum import SemanticMask - - if len(uuids.keys()) == 0: - return {} - - robot_mask = np.zeros_like(mask, dtype=np.bool_) - robot_uuids = uuids["robot"] - for uuid in robot_uuids: - robot_mask[mask == uuid] = True - - object_uuids = uuids.get("object", []) - foreground_mask = np.zeros_like(mask, dtype=np.bool_) - for uuid in object_uuids: - foreground_mask[mask == uuid] = True - - background_mask = np.logical_not(np.logical_or(robot_mask, foreground_mask)) - - ret_masks = np.tile( - np.expand_dims(np.zeros_like(robot_mask), -1), [1, 1, len(SemanticMask)] - ) - ret_masks[:, :, SemanticMask.ROBOT.value] = robot_mask - ret_masks[:, :, SemanticMask.BACKGROUND.value] = background_mask - ret_masks[:, :, SemanticMask.FOREGROUND.value] = foreground_mask - - return ret_masks - - -def project_3d_to_2d( - cam, poses: List[np.ndarray], normalize: bool = True -) -> np.ndarray: - import dexsim.utility as dexutils - - cam_pose = cam._camera.get_world_pose() - cam_pose = dexutils.change_coordinate_stystem(cam_pose, ["X", "-Y", "-Z"]) - - intrinsic = cam._camera.get_intrinsic() - height = cam._camera.get_height() - width = cam._camera.get_width() - keypoints = [] - for pose in poses: - pose_ = np.matmul(np.linalg.inv(cam_pose), pose) - rvec, tvec = cv2.Rodrigues(np.eye(3))[0], np.zeros((3, 1)) - image_points, _ = cv2.projectPoints( - pose_[:3, -1], - rvec, - tvec, - np.array(intrinsic).reshape(3, 3), - np.zeros( - 5, - ), - ) - keypoints.append(image_points.reshape(1, 2)) - - keypoints = np.concatenate(keypoints, 0) - keypoints[:, 0] = np.clip(keypoints[:, 0], 0, width - 1) - keypoints[:, 1] = np.clip(keypoints[:, 1], 0, height - 1) - - if normalize: - keypoints[:, 0] = keypoints[:, 0] / width - keypoints[:, 1] = keypoints[:, 1] / height - return keypoints - - def camel_to_snake(name): # Insert underscores before each uppercase letter and convert to lowercase s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name) @@ -1463,7 +1331,7 @@ def get_fk_xpos( # FIXME: remove -def _data_key_to_control_part(robot, control_parts, data_key: str) -> Optional[str]: +def data_key_to_control_part(robot, control_parts, data_key: str) -> Optional[str]: # TODO: Temporary workaround, should be removed after refactoring data dict extractor. # @lru_cache(max_size=None) # NOTE: no way to pass a hashable parameter def is_eef_hand(robot, control_parts) -> bool: @@ -1492,73 +1360,3 @@ def is_eef_hand(robot, control_parts) -> bool: if "gripper" in data_key and is_eef_hand(robot, control_parts) is False: return "right_eef" return None - - -# FIXME: only for v3 W1 -def map_ee_state_to_env_actions( - robot, ee_state: np.ndarray, env_actions: np.ndarray -) -> np.ndarray: - """ - Map end-effector (gripper) state to environment joint actions. - - Args: - ee_state (np.ndarray): Normalized gripper state, shape (batch, 2). - env_actions (np.ndarray): Environment joint actions to be updated. - - Returns: - np.ndarray: Updated environment joint actions with gripper positions. - """ - from embodichain.data.enum import ControlParts, JointType, EndEffector - - left_eef_limits = ( - robot.body_data.qpos_limits.squeeze(0) - .cpu() - .numpy()[robot.get_joint_ids(name=ControlParts.LEFT_EEF.value)] - ) - right_eef_limits = ( - robot.body_data.qpos_limits.squeeze(0) - .cpu() - .numpy()[robot.get_joint_ids(name=ControlParts.RIGHT_EEF.value)] - ) - - def w1_gripper_mapping(normalized_state, eef_limits): - # Define normalized open/close positions for the gripper (range 0-1) - open_state_normalized = np.array([90.0, 0.0, 0.0, 0.0, 0.0, 0.0]) / 100.0 - close_state_normalized = np.array([90.0, 55.0, 30.0, 30.0, 30.0, 30.0]) / 100.0 - - # Convert normalized values to actual joint angles - open_state_actual = eef_limits[:, 0] + open_state_normalized * ( - eef_limits[:, 1] - eef_limits[:, 0] - ) - close_state_actual = eef_limits[:, 0] + close_state_normalized * ( - eef_limits[:, 1] - eef_limits[:, 0] - ) - - # Interpolate between open and close joint angles - if isinstance(normalized_state, np.ndarray) and normalized_state.ndim > 0: - return ( - open_state_actual * (1 - normalized_state[:, None]) - + close_state_actual * normalized_state[:, None] - ) - else: - return ( - open_state_actual * (1 - normalized_state) - + close_state_actual * normalized_state - ) - - if ee_state.ndim == 1: - ee_state = ee_state.reshape(1, -1) - if env_actions.ndim == 1: - env_actions = env_actions.reshape(1, -1) - - # Map normalized gripper state to actual joint positions - left_hand_qpos = w1_gripper_mapping(ee_state[:, 0], left_eef_limits) - right_hand_qpos = w1_gripper_mapping(ee_state[:, 1], right_eef_limits) - - # Get indices for left and right end-effector joints - left_eef_ids = robot.get_joint_ids(name=ControlParts.LEFT_EEF.value) - right_eef_ids = robot.get_joint_ids(name=ControlParts.RIGHT_EEF.value) - - env_actions[:, left_eef_ids] = left_hand_qpos - env_actions[:, right_eef_ids] = right_hand_qpos - return env_actions diff --git a/embodichain/lab/scripts/generate_video.py b/embodichain/lab/scripts/generate_video.py deleted file mode 100644 index 4b51b3dd..00000000 --- a/embodichain/lab/scripts/generate_video.py +++ /dev/null @@ -1,162 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---------------------------------------------------------------------------- - -from embodichain.utils.logger import log_info, log_warning - -import h5py -import argparse -import numpy as np -import os - -from tqdm import tqdm -from dexsim.utility import images_to_video -from typing import Dict, Callable, Tuple -from embodichain.utils.visualizer import draw_keypoints, draw_action_distribution -from embodichain.data.enum import EefType, JointType, Modality, PrivilegeType -from embodichain.data.data_engine.unified_state import ActionIndicesGenerator - - -class VideoCreator: - def __init__(self) -> None: - pass - - @staticmethod - def _sub_function( - images, - output_path, - video_key, - exteroceptions: Dict = None, - multiplier: int = 1, - drawer: Callable = lambda x: x, - ): - for key in images.keys(): - imgs = images[key] - if imgs is None: - log_warning(f"No images found for key: {key}. Skipping.") - continue - img_list = [] - for i in tqdm(range(imgs.shape[0])): - image_i = drawer(imgs[i] * multiplier) - if exteroceptions is not None and len(exteroceptions[key]) != 0: - image_i = draw_keypoints( - image_i, exteroceptions[key][i].reshape(-1, 2) - ) - img_list.append(image_i) - - images_to_video(img_list, output_path, f"{key}_{video_key}") - - @staticmethod - def monocular_save( - observations: Dict, - video_key: str, - output_path: str, - multiplier: int = 1, - drawer: Callable = lambda x: x, - draw_exteroception: bool = True, - ): - images = observations[video_key] - if ( - PrivilegeType.EXTEROCEPTION.value in observations.keys() - and draw_exteroception - ): - exteroceptions = observations[PrivilegeType.EXTEROCEPTION.value] - else: - exteroceptions = None - VideoCreator._sub_function( - images, - output_path, - video_key, - exteroceptions, - multiplier, - drawer, - ) - - -def visualize_data_dict(f: Dict, output_path: str): - observations = f["observations"] - - if PrivilegeType.MASK.value in observations.keys(): - VideoCreator.monocular_save( - observations, - PrivilegeType.MASK.value, - output_path, - 255, - draw_exteroception=False, - ) - - if Modality.GEOMAP.value in observations.keys(): - from embodichain.utils.img_utils import gen_disp_colormap - - VideoCreator.monocular_save( - observations, - Modality.GEOMAP.value, - output_path, - 1, - lambda x: (gen_disp_colormap(x).transpose(1, 2, 0) * 255).astype(np.uint8), - draw_exteroception=False, - ) - - VideoCreator.monocular_save(observations, Modality.IMAGES.value, output_path) - - -def main(args): - - data_path = args.data_path - output_path = args.output_path - assert data_path.endswith(".hdf5"), "Data path must have format of .hdf5" - with h5py.File(data_path, "r") as f: - from embodichain.data.data_engine.data_dict_extractor import ( - CompressedVideoHDF5, - ) - import hdfdict - - data = hdfdict.load(data_path) - data = CompressedVideoHDF5(output_path).safe_filter(data) - - visualize_data_dict(data, output_path) - robot_meta = data["robot_meta"] - arm_dofs = robot_meta["arm_dofs"][()] - indices_generator = ActionIndicesGenerator(arm_dofs) - - actions = f[Modality.ACTIONS.value][()] - key_names = indices_generator.global_mapping.mapping_from_name_to_indices.keys() - log_info(f"Arm dofs: {arm_dofs}", color="green") - indices_dict = {} - for key_name in key_names: - indices_dict[key_name] = indices_generator.get([key_name]) - draw_action_distribution(actions, indices_dict, output_path, smooth=args.smooth) - - -if __name__ == "__main__": - import argparse - - parser = argparse.ArgumentParser() - parser.add_argument("--data_path", type=str, help="Path to the data file.") - parser.add_argument( - "--output_path", - type=str, - help="Path to the output video file.", - default="./outputs", - ) - parser.add_argument( - "--smooth", - action="store_true", - default=False, - help="whether smooth joints.", - ) - args = parser.parse_args() - - main(args) diff --git a/embodichain/lab/scripts/preview_env.py b/embodichain/lab/scripts/preview_env.py index 9357584d..fde071bd 100644 --- a/embodichain/lab/scripts/preview_env.py +++ b/embodichain/lab/scripts/preview_env.py @@ -62,12 +62,6 @@ default=0, type=int, ) - parser.add_argument( - "--enable_sensors_in_step", - help="Whether to enable sensors in each step of the simulation.", - default=False, - action="store_true", - ) parser.add_argument("--gym_config", type=str, help="gym_config", default="") parser.add_argument( "--action_config", @@ -110,9 +104,6 @@ env = gymnasium.make(id=gym_config["id"], cfg=cfg, **action_config) - if args.enable_sensors_in_step is False: - pass - obs, info = env.reset() """ diff --git a/embodichain/lab/scripts/run_env.py b/embodichain/lab/scripts/run_env.py index 5fcb07fa..1ad5318f 100644 --- a/embodichain/lab/scripts/run_env.py +++ b/embodichain/lab/scripts/run_env.py @@ -19,6 +19,7 @@ import argparse import os import torch +import tqdm from threading import Thread @@ -28,46 +29,26 @@ from embodichain.lab.gym.utils.gym_utils import ( config_to_cfg, ) -from embodichain.lab.scripts.generate_video import visualize_data_dict -from embodichain.data.data_engine.online.online_generator import ( - OnlineGenerator, -) from embodichain.utils.logger import log_warning, log_info, log_error -from embodichain.lab.sim.cfg import MarkerCfg def generate_and_execute_action_list(env, idx, debug_mode): action_list = env.create_demo_action_list(action_sentence=idx) - # TODO: To be modified. - # if debug_mode: - # env.visual_action(action_list) - if action_list is None or len(action_list) == 0: log_warning("Action is invalid. Skip to next generation.") return False - for action in action_list: + for action in tqdm.tqdm( + action_list, desc=f"Executing action list #{idx}", unit="step" + ): # Step the environment with the current action obs, reward, terminated, truncated, info = env.step(action) - # TODO: To be modified. - # if debug_mode: - # xpos_dict = env.agent.get_debug_xpos_dict() - - # for key, val in xpos_dict.items(): - # env.scene.draw_marker(cfg=MarkerCfg( - # marker_type="axis", - # axis_xpos=val, - # axis_size=0.002, - # axis_len=0.005 - # )) + # TODO: May be add some functions for debug_mode - # for key, val in xpos_dict.items(): - # env.scene.remove_fixed_actor(key) - - # TODO: we may assume in export demonstration rollout, there is no truncation from the env. + # TODO: We may assume in export demonstration rollout, there is no truncation from the env. # but truncation is useful to improve the generation efficiency. return True @@ -75,16 +56,14 @@ def generate_and_execute_action_list(env, idx, debug_mode): def generate_function( env, - obj_num, + num_traj, time_id: int = 0, - online_training: bool = False, save_path: str = "", save_video: bool = False, debug_mode: bool = False, **kwargs, ): - """ - Generate and execute a sequence of actions in the environment. + """Generate and execute a sequence of actions in the environment. This function resets the environment, generates and executes action trajectories, collects data, and optionally saves videos of the episodes. It supports both online @@ -92,68 +71,31 @@ def generate_function( Args: env: The environment instance. - obj_num (int): Number of trajectories to generate per episode. + num_traj (int): Number of trajectories to generate per episode. time_id (int, optional): Identifier for the current time step or episode. - online_training (bool, optional): Whether to use online data generation. save_path (str, optional): Path to save generated videos. save_video (bool, optional): Whether to save episode videos. debug_mode (bool, optional): Enable debug mode for visualization and logging. **kwargs: Additional keyword arguments for data generation. Returns: - list or bool: Returns a list of data dicts if online_training is True, - otherwise returns True if generation is successful. + bool: True if data generation is successful, False otherwise. """ - def wait_for_threads(threads): - for t in threads: - t.join() - - vis_threads = [] valid = True while True: _, _ = env.reset() - ret = [] - for trajectory_idx in range(obj_num): + for trajectory_idx in range(num_traj): valid = generate_and_execute_action_list(env, trajectory_idx, debug_mode) if not valid: - log_warning("Invalid action, skipping trajectory.") break if not debug_mode and env.is_task_success().item(): - # Create a unique identifier for the dataset entry - dataset_id = f"time_{time_id}_trajectory_{trajectory_idx}" - if online_training: - dataset_id += "_online_generated" - num_samples = kwargs.get("num_samples", 0) - is_save_dataset = time_id < num_samples - - data_dict = env.to_dataset( - id=dataset_id if is_save_dataset else None, - ) - - ret.append(data_dict) - else: - data_dict = env.to_dataset( - id=dataset_id, - ) - - episode = getattr(env, "get_current_episode", lambda: time_id)() - - if save_video: - video_path = os.path.join(save_path, f"episode_{episode}") - if online_training: - vis_thread = Thread( - target=visualize_data_dict, - args=(data_dict["data"], video_path), - daemon=True, - ) - vis_thread.start() - vis_threads.append(vis_thread) - else: - visualize_data_dict(data_dict["data"], video_path) + pass + + # TODO: Add data saving and online data streaming logic here. else: log_warning(f"Task fail, Skip to next generation.") @@ -166,50 +108,23 @@ def wait_for_threads(threads): log_warning("Reset valid flag to True.") valid = True - wait_for_threads(vis_threads) - return ret if online_training else True + return True def main(args, env, gym_config): - is_online_training = os.path.exists(args.online_config) - if is_online_training: - - log_info("Start online data generation.", color="green") - assert os.path.exists(args.online_config), "{} does not exist.".format( - args.online_config - ) - - online_config = load_json(args.online_config) - online_callback = OnlineGenerator(**online_config) - obj_num = 1 - generator_func = lambda time_id, **kwargs: generate_function( + log_info("Start offline data generation.", color="green") + # TODO: Support multiple trajectories per episode generation. + num_traj = 1 + for i in range(gym_config["max_episodes"]): + generate_function( env, - obj_num, - time_id, - online_training=is_online_training, + num_traj, + i, save_path=args.save_path, save_video=args.save_video, - headless=args.headless, - **kwargs, + debug_mode=args.debug_mode, ) - online_callback.generator(generator_func, **online_config) - else: - log_info("Start offline data generation.", color="green") - obj_num = 1 - for i in range(gym_config["max_episodes"]): - generate_function( - env, - obj_num, - i, - online_training=is_online_training, - save_path=args.save_path, - save_video=args.save_video, - debug_mode=args.debug_mode, - ) - - if args.headless: - env.reset(options={"final": True}) if __name__ == "__main__": @@ -217,8 +132,6 @@ def main(args, env, gym_config): torch.set_printoptions(precision=5, sci_mode=False) parser = argparse.ArgumentParser() - # parser.add_argument("--task_type", help="Type of task to perform.") - # parser.add_argument("--robot_name", help="Name of the robot.") parser.add_argument( "--num_envs", help="The number of environments to run in parallel.", @@ -249,15 +162,15 @@ def main(args, env, gym_config): default=0, type=int, ) + parser.add_argument( + "--save_path", help="path", default="./outputs/thirdviewvideo", type=str + ) parser.add_argument( "--save_video", - help="Whether to save data as video.", + help="Whether to save the video of the episode.", default=False, action="store_true", ) - parser.add_argument( - "--save_path", help="path", default="./outputs/thirdviewvideo", type=str - ) parser.add_argument( "--debug_mode", help="Enable debug mode.", @@ -270,8 +183,6 @@ def main(args, env, gym_config): default=False, action="store_true", ) - - parser.add_argument("--online_config", type=str, help="online_config", default="") parser.add_argument("--gym_config", type=str, help="gym_config", default="") parser.add_argument("--action_config", type=str, help="action_config", default=None) diff --git a/embodichain/lab/sim/utility/mesh_utils.py b/embodichain/lab/sim/utility/mesh_utils.py index 4a30bd7c..2fba7e9b 100644 --- a/embodichain/lab/sim/utility/mesh_utils.py +++ b/embodichain/lab/sim/utility/mesh_utils.py @@ -1,95 +1,29 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + import os import dexsim.engine import numpy as np import open3d as o3d import trimesh -from typing import Tuple, List, Dict, Any, Optional, Union - import dexsim -from embodichain.utils import logger -from embodichain.data import get_data_path - - -def process_meshes( - mesh_config: Union[List[Dict], Dict], processor_config: Dict = None -) -> List[str]: - r"""Process a list of mesh files using the specified processor configuration. - - Args: - mesh_config (list): A list of dictionaries containing mesh file paths. - processor_config (dict): A dictionary containing the processor configuration. - - Returns: - list: A list of processed mesh file paths. - """ - from embodichain.toolkits.processor.function.mesh_processor import ( - build_mesh_processors, - ) - from embodichain.toolkits.processor.component import TriangleComponent - from embodichain.toolkits.processor.entity import MeshEntity - processors, replace = None, False - if processor_config is not None: - if "replace" in processor_config: - replace = processor_config.pop("replace") - processors = build_mesh_processors(processor_config) - - if isinstance(mesh_config, dict): - mesh_config_list = list(mesh_config.values()) - else: - mesh_config_list = mesh_config - batch_meshes, batch_index = [], [] - for idx, config in enumerate(mesh_config_list): - if "mesh_file" not in config and "mesh_path" not in config: - logger.log_error("Config must contain 'mesh_file' and 'mesh_path' keys.") - key = "mesh_file" if "mesh_file" in config else "mesh_path" - mesh_fpath = config[key] - mesh_fpath = get_data_path(mesh_fpath) - if not os.path.exists(mesh_fpath): - logger.log_error(f"Mesh file not found at path: {mesh_fpath}") - config[key] = mesh_fpath - save_fpath = ( - os.path.dirname(config[key]) - + "/mesh_processed_" - + os.path.basename(config[key]) - ) +from typing import Tuple, List, Dict, Any, Optional, Union - if processors is None and "mesh_processor" not in config: - # No processors specified, so just return - continue - elif os.path.exists(save_fpath) and not replace: - config[key] = save_fpath - continue - elif "mesh_processor" in config: - # Process the mesh file with the specified processor - mesh_processor = build_mesh_processors(config["mesh_processor"]) - tri_component = TriangleComponent.from_fpath(mesh_fpath) - mesh_entity = MeshEntity("mesh", tri_component) - mesh = mesh_processor.apply([mesh_entity])[0] - mesh.save_mesh(save_fpath) - # Update the mesh file path in the config - config[key] = save_fpath - else: - tri_component = TriangleComponent.from_fpath(mesh_fpath) - mesh_entity = MeshEntity("mesh", tri_component) - batch_meshes.append(mesh_entity) - batch_index.append(idx) - - # Process the batch of meshes with the default processors - if batch_meshes and processors is not None: - meshes = processors.apply(batch_meshes) - for idx, config in enumerate(mesh_config_list): - if idx in batch_index: - save_fpath = ( - os.path.dirname(config[key]) - + "/mesh_processed_" - + os.path.basename(config[key]) - ) - meshes[batch_index.index(idx)].save_mesh(save_fpath) - config[key] = save_fpath - if isinstance(mesh_config, dict): - mesh_config = {k: v for k, v in zip(mesh_config.keys(), mesh_config_list)} - return mesh_config +from embodichain.utils import logger def export_articulation_mesh( diff --git a/tests/datasets/test_online_training.py b/tests/datasets/test_online_training.py deleted file mode 100644 index aafb9c8a..00000000 --- a/tests/datasets/test_online_training.py +++ /dev/null @@ -1,101 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---------------------------------------------------------------------------- - -import unittest -import sys -from pathlib import Path - -sys.path.append(str(Path(__file__).parent.parent)) -from common import UnittestMetaclass, OrderedTestLoader -from embodichain.data.data_engine.online.engine import OnlineEngine -import numpy as np -from tqdm import tqdm -import time - - -class TestDataDictExtractor(unittest.TestCase, metaclass=UnittestMetaclass): - datacenter_backup = Path("/tmp/datacenter_test") - - def setUp(self) -> None: - pass - - def tearDown(self) -> None: - pass - - def test_online_generation( - self, - ): - from embodichain.utils.logger import log_warning - from embodichain.data.data_engine.online.online_generator import ( - OnlineGenerator, - ) - - log_warning("Start online data generation.") - - online_config = { - "episode_limit": 4, - "max_sample_num": 100, - "port": 5566, - "buffer_size": 4, - "max_limit_gb": 5, - } - online_callback = OnlineGenerator(**online_config) - generator_func = lambda **kwargs: [{"data": np.random.randn(1000, 1000)}] - online_callback.generator(generator_func, loop_times=2) - online_callback.empty_memory() - - def test_sample_data(self): - - from embodichain.utils.logger import log_warning - import threading - from embodichain.data.data_engine.online.online_generator import ( - OnlineGenerator, - ) - - log_warning("Start online data generation.") - - online_config = { - "episode_limit": 4, - "max_sample_num": 100, - "port": 7788, - "buffer_size": 4, - "max_limit_gb": 5, - } - online_callback = OnlineGenerator(**online_config) - data_o = np.random.randn(1000, 1000) - generator_func = lambda **kwargs: [{"data": data_o}] - - thread = threading.Thread( - target=online_callback.generator, - kwargs={"generate_func": generator_func, "loop_times": 2}, - daemon=True, - ) - thread.start() - time.sleep(1.0) - - callback = OnlineEngine(**online_config) - callback.start() - time.sleep(1.0) - for i in tqdm(range(5)): - data = callback.sample_data() - assert data.sum() == data_o.sum() - - -if __name__ == "__main__": - # `unittest.main()` is the standard usage to start testing, here we use a customed - # TestLoader to keep executing order of functions the same as their writing order - - unittest.main(testLoader=OrderedTestLoader()) From 91284a2a4e5eb464aa448a82770af2030900d595 Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Mon, 24 Nov 2025 13:56:51 +0000 Subject: [PATCH 07/92] Update default physics mode to manual (#6) --- .../overview/sim/planners/motion_generator.md | 1 - docs/source/resources/robot/dexforce_w1.md | 1 - .../envs/action_bank/configurable_action.py | 15 ++-- embodichain/lab/gym/envs/base_env.py | 1 - embodichain/lab/sim/cfg.py | 4 +- embodichain/lab/sim/robots/cobotmagic.py | 1 - embodichain/lab/sim/robots/dexforce_w1/cfg.py | 3 +- embodichain/lab/sim/sim_manager.py | 3 + embodichain/lab/sim/utility/sim_utils.py | 4 +- examples/sim/demo/grasp_cup_to_caffe.py | 6 +- examples/sim/demo/press_softbody.py | 80 ++++--------------- examples/sim/demo/scoop_ice.py | 2 - examples/sim/gizmo/gizmo_object.py | 3 - examples/sim/scene/scene_demo.py | 1 - .../sim/create_rigid_object_group.py | 3 - scripts/tutorials/sim/create_robot.py | 3 - scripts/tutorials/sim/create_scene.py | 3 - scripts/tutorials/sim/create_sensor.py | 3 - scripts/tutorials/sim/create_softbody.py | 3 - tests/sim/objects/test_articulation.py | 1 - tests/sim/objects/test_light.py | 2 +- tests/sim/objects/test_rigid_object.py | 1 - tests/sim/objects/test_rigid_object_group.py | 1 - tests/sim/objects/test_robot.py | 1 - tests/sim/objects/test_soft_object.py | 1 - tests/sim/solvers/test_differential_solver.py | 1 - tests/sim/solvers/test_pytorch_solver.py | 1 - tests/sim/solvers/test_srs_solver.py | 2 +- tests/sim/test_sim_manager.py | 63 --------------- 29 files changed, 38 insertions(+), 176 deletions(-) delete mode 100644 tests/sim/test_sim_manager.py diff --git a/docs/source/overview/sim/planners/motion_generator.md b/docs/source/overview/sim/planners/motion_generator.md index 5aa75a0b..05a41140 100644 --- a/docs/source/overview/sim/planners/motion_generator.md +++ b/docs/source/overview/sim/planners/motion_generator.md @@ -37,7 +37,6 @@ sim_cfg = SimulationManagerCfg( ) sim = SimulationManager(sim_cfg) -sim.set_manual_update(True) # Get UR10 URDF path urdf_path = get_data_path("UniversalRobots/UR10/UR10.urdf") diff --git a/docs/source/resources/robot/dexforce_w1.md b/docs/source/resources/robot/dexforce_w1.md index 69c4860e..e64e3624 100644 --- a/docs/source/resources/robot/dexforce_w1.md +++ b/docs/source/resources/robot/dexforce_w1.md @@ -22,7 +22,6 @@ from embodichain.lab.sim.robots.dexforce_w1.utils import build_dexforce_w1_cfg config = SimulationManagerCfg(headless=False, sim_device="cpu") sim = SimulationManager(config) sim.build_multiple_arenas(4) -sim.set_manual_update(True) hand_types = { DexforceW1ArmSide.LEFT: DexforceW1HandBrand.BRAINCO_HAND, diff --git a/embodichain/lab/gym/envs/action_bank/configurable_action.py b/embodichain/lab/gym/envs/action_bank/configurable_action.py index bdffc543..20f16d1f 100644 --- a/embodichain/lab/gym/envs/action_bank/configurable_action.py +++ b/embodichain/lab/gym/envs/action_bank/configurable_action.py @@ -1022,11 +1022,16 @@ def generate_trajectory_qpos( current_qpos = torch.as_tensor(trajectory[trajectory_id])[trajectory_index][ None, gather_index ] # TODO: only for 1 env - affordance_xpos = env.robot.compute_fk( - torch.as_tensor(current_qpos), - get_control_part(env, agent_uid), - to_matrix=True, - ) + control_part = get_control_part(env, agent_uid) + try: + affordance_xpos = env.robot.compute_fk( + torch.as_tensor(current_qpos), + control_part, + to_matrix=True, + ) + except RuntimeError as e: + log_warning(f"control part {control_part} has no solver.") + affordance_xpos = torch.zeros((1, 4, 4), device=current_qpos.device) if slaver != "": assert canonical_trajectory is not None assert canonical_trajectory_index is not None diff --git a/embodichain/lab/gym/envs/base_env.py b/embodichain/lab/gym/envs/base_env.py index 123c2c04..8ee19b6f 100644 --- a/embodichain/lab/gym/envs/base_env.py +++ b/embodichain/lab/gym/envs/base_env.py @@ -204,7 +204,6 @@ def _setup_scene(self, **kwargs): self.sim_cfg.headless = True self.sim = SimulationManager(self.sim_cfg) self.sim_cfg.headless = headless - self.sim.set_manual_update(True) logger.log_info( f"Initializing {self.num_envs} environments on {self.sim_cfg.sim_device}." diff --git a/embodichain/lab/sim/cfg.py b/embodichain/lab/sim/cfg.py index 396c71f3..d6825853 100644 --- a/embodichain/lab/sim/cfg.py +++ b/embodichain/lab/sim/cfg.py @@ -340,7 +340,7 @@ class JointDrivePropertiesCfg: If the drive type is "acceleration", then the joint is driven by an acceleration and the force is computed based on the acceleration applied. """ - stiffness: Union[Dict[str, float], float] = 1e3 + stiffness: Union[Dict[str, float], float] = 1e4 """Stiffness of the joint drive. The unit depends on the joint model: @@ -349,7 +349,7 @@ class JointDrivePropertiesCfg: * For angular joints, the unit is kg-m^2/s^2/rad (N-m/rad). """ - damping: Union[Dict[str, float], float] = 1e2 + damping: Union[Dict[str, float], float] = 1e3 """Damping of the joint drive. The unit depends on the joint model: diff --git a/embodichain/lab/sim/robots/cobotmagic.py b/embodichain/lab/sim/robots/cobotmagic.py index 93308f46..70859f90 100644 --- a/embodichain/lab/sim/robots/cobotmagic.py +++ b/embodichain/lab/sim/robots/cobotmagic.py @@ -210,7 +210,6 @@ def build_pk_serial_chain( config = SimulationManagerCfg(headless=False, sim_device="cuda") sim = SimulationManager(config) sim.build_multiple_arenas(2) - sim.set_manual_update(True) config = { "init_pos": [0.0, 0.0, 1.0], diff --git a/embodichain/lab/sim/robots/dexforce_w1/cfg.py b/embodichain/lab/sim/robots/dexforce_w1/cfg.py index c049a071..5ae4da8f 100644 --- a/embodichain/lab/sim/robots/dexforce_w1/cfg.py +++ b/embodichain/lab/sim/robots/dexforce_w1/cfg.py @@ -192,7 +192,7 @@ def _build_default_physics_cfgs() -> typing.Dict[str, any]: "(ANKLE|KNEE|BUTTOCK|WAIST)": 1e7, }, damping={ - "(RIGHT|LEFT)_J[0-2]": 1e3, + "(RIGHT|LEFT)_J[0-9]": 1e3, "(RIGHT|LEFT)_[A-Z|_]+": 1e1, "(ANKLE|KNEE|BUTTOCK|WAIST)": 1e4, }, @@ -322,7 +322,6 @@ def build_pk_serial_chain( config = SimulationManagerCfg(headless=True, sim_device="cpu") sim = SimulationManager(config) sim.build_multiple_arenas(1) - sim.set_manual_update(True) cfg = DexforceW1Cfg.from_dict( { diff --git a/embodichain/lab/sim/sim_manager.py b/embodichain/lab/sim/sim_manager.py index 7d2e216e..3114ec30 100644 --- a/embodichain/lab/sim/sim_manager.py +++ b/embodichain/lab/sim/sim_manager.py @@ -252,6 +252,9 @@ def __init__( self._create_default_plane() self.set_default_background() + # Set physics to manual update mode by default. + self.set_manual_update(True) + def _convert_sim_config( self, sim_config: SimulationManagerCfg ) -> dexsim.WorldConfig: diff --git a/embodichain/lab/sim/utility/sim_utils.py b/embodichain/lab/sim/utility/sim_utils.py index adcc53e4..256fa299 100644 --- a/embodichain/lab/sim/utility/sim_utils.py +++ b/embodichain/lab/sim/utility/sim_utils.py @@ -95,8 +95,8 @@ def get_drive_type(drive_pros): if drive_type == "force": drive_type = DriveType.FORCE - elif drive_type == "target": - drive_type == DriveType.FORCE + elif drive_type == "acceleration": + drive_type = DriveType.ACCELERATION else: logger.log_error(f"Unknow drive type {drive_type}") diff --git a/examples/sim/demo/grasp_cup_to_caffe.py b/examples/sim/demo/grasp_cup_to_caffe.py index c1073c3f..77f31fb9 100644 --- a/examples/sim/demo/grasp_cup_to_caffe.py +++ b/examples/sim/demo/grasp_cup_to_caffe.py @@ -15,8 +15,8 @@ # ---------------------------------------------------------------------------- """ -This script demonstrates the creation and simulation of a robot with dexterous hands, -and performs a scoop ice task in a simulated environment. +This script demonstrates the creation and simulation of dexforce w1 robot, +and performs a grasp cup to coffee machine task in a simulated environment. """ import argparse @@ -87,8 +87,6 @@ def initialize_simulation(args) -> SimulationManager: sim = SimulationManager(config) sim.build_multiple_arenas(args.num_envs, space=2.5) - # Set manual physics update for precise control - sim.set_manual_update(True) if args.enable_rt: light = sim.add_light( diff --git a/examples/sim/demo/press_softbody.py b/examples/sim/demo/press_softbody.py index 2d353aad..79c33133 100644 --- a/examples/sim/demo/press_softbody.py +++ b/examples/sim/demo/press_softbody.py @@ -15,49 +15,32 @@ # ---------------------------------------------------------------------------- """ -This script demonstrates the creation and simulation of a robot with dexterous hands, -and performs a scoop ice task in a simulated environment. +This script demonstrates the creation and simulation of a robot with a soft object, +and performs a pressing task in a simulated environment. """ import argparse import numpy as np import time import torch -from tqdm import tqdm -from scipy.spatial.transform import Rotation as R + +from dexsim.utility.path import get_resources_data_path from embodichain.lab.sim import SimulationManager, SimulationManagerCfg -from embodichain.lab.sim.objects import Robot, RigidObject, RigidObjectGroup -from embodichain.lab.sim.cfg import ( - JointDrivePropertiesCfg, - RobotCfg, - URDFCfg, - RigidObjectCfg, - RigidBodyAttributesCfg, - ArticulationCfg, - RigidObjectGroupCfg, - LightCfg, -) -from embodichain.lab.sim.material import VisualMaterialCfg +from embodichain.lab.sim.objects import Robot, SoftObject from embodichain.lab.sim.utility.action_utils import interpolate_with_distance_warp -from embodichain.lab.sim.shapes import MeshCfg, CubeCfg +from embodichain.lab.sim.shapes import MeshCfg from embodichain.lab.sim.solvers import PytorchSolverCfg from embodichain.data import get_data_path from embodichain.utils import logger -from dexsim.utility.path import get_resources_data_path -from embodichain.lab.sim import SimulationManager, SimulationManagerCfg from embodichain.lab.sim.cfg import ( - RigidBodyAttributesCfg, + RobotCfg, + LightCfg, + SoftObjectCfg, SoftbodyVoxelAttributesCfg, SoftbodyPhysicalAttributesCfg, ) -from embodichain.lab.sim.shapes import CubeCfg, MeshCfg -from embodichain.lab.sim.objects import ( - RigidObject, - RigidObjectCfg, - SoftObject, - SoftObjectCfg, -) +from embodichain.lab.sim.shapes import MeshCfg def parse_arguments(): @@ -98,8 +81,6 @@ def initialize_simulation(args): cfg=LightCfg(uid="main_light", intensity=50.0, init_pos=(0, 0, 2.0)) ) - # Set manual physics update for precise control - sim.set_manual_update(True) return sim @@ -115,44 +96,16 @@ def create_robot(sim: SimulationManager): """ # Retrieve URDF paths for the robot arm and hand ur10_urdf_path = get_data_path("UniversalRobots/UR10/UR10.urdf") - hand_urdf_path = get_data_path( - "BrainCoHandRevo1/BrainCoLeftHand/BrainCoLeftHand.urdf" - ) - - # Define transformation for attaching the hand to the arm - hand_attach_xpos = np.eye(4) - hand_attach_xpos[:3, :3] = R.from_rotvec([90, 0, 0], degrees=True).as_matrix() # Configure the robot with its components and control properties cfg = RobotCfg( - uid="ur10_with_brainco", - urdf_cfg=URDFCfg( - components=[ - {"component_type": "arm", "urdf_path": ur10_urdf_path}, - ] - ), - control_parts={ - "arm": ["Joint[0-9]"], - }, - drive_pros=JointDrivePropertiesCfg( - stiffness={ - "Joint[0-9]": 1e4, - }, - damping={ - "Joint[0-9]": 1e3, - }, - max_effort={ - "Joint[0-9]": 1e5, - }, - drive_type="force", + uid="UR10", + fpath=ur10_urdf_path, + solver_cfg=PytorchSolverCfg( + end_link_name="ee_link", + root_link_name="base_link", + tcp=np.eye(4), ), - solver_cfg={ - "arm": PytorchSolverCfg( - end_link_name="ee_link", - root_link_name="base_link", - tcp=np.eye(4), - ) - }, init_qpos=[ 0.0, -np.pi / 2, @@ -190,7 +143,6 @@ def create_soft_cow(sim: SimulationManager) -> SoftObject: poissons=0.45, density=100, dynamic_friction=0.1, - min_position_iters=30, ), ), ) diff --git a/examples/sim/demo/scoop_ice.py b/examples/sim/demo/scoop_ice.py index 941f6d6d..1baee81c 100644 --- a/examples/sim/demo/scoop_ice.py +++ b/examples/sim/demo/scoop_ice.py @@ -68,8 +68,6 @@ def initialize_simulation(): cfg=LightCfg(uid="main_light", intensity=50.0, init_pos=(0, 0, 2.0)) ) - # Set manual physics update for precise control - sim.set_manual_update(True) return sim diff --git a/examples/sim/gizmo/gizmo_object.py b/examples/sim/gizmo/gizmo_object.py index 31967277..6b664eff 100644 --- a/examples/sim/gizmo/gizmo_object.py +++ b/examples/sim/gizmo/gizmo_object.py @@ -70,9 +70,6 @@ def main(): # Create the simulation instance sim = SimulationManager(sim_cfg) - # Enable manual physics update for precise control - sim.set_manual_update(True) - # Build multiple arenas if requested if args.num_envs > 1: sim.build_multiple_arenas(args.num_envs, space=3.0) diff --git a/examples/sim/scene/scene_demo.py b/examples/sim/scene/scene_demo.py index 6efa3b13..20ff70aa 100644 --- a/examples/sim/scene/scene_demo.py +++ b/examples/sim/scene/scene_demo.py @@ -124,7 +124,6 @@ def main(): enable_rt=not args.disable_rt, ) sim = SimulationManager(sim_cfg) - sim.set_manual_update(True) if args.num_envs > 1: sim.build_multiple_arenas(args.num_envs, space=10.0) diff --git a/scripts/tutorials/sim/create_rigid_object_group.py b/scripts/tutorials/sim/create_rigid_object_group.py index f8ae262f..223c72d4 100644 --- a/scripts/tutorials/sim/create_rigid_object_group.py +++ b/scripts/tutorials/sim/create_rigid_object_group.py @@ -71,9 +71,6 @@ def main(): # Create the simulation instance sim = SimulationManager(sim_cfg) - # Enable manual physics update for precise control - sim.set_manual_update(True) - # Build multiple arenas if requested if args.num_envs > 1: sim.build_multiple_arenas(args.num_envs, space=3.0) diff --git a/scripts/tutorials/sim/create_robot.py b/scripts/tutorials/sim/create_robot.py index 6a504f70..1c8012bb 100644 --- a/scripts/tutorials/sim/create_robot.py +++ b/scripts/tutorials/sim/create_robot.py @@ -76,9 +76,6 @@ def main(): if args.num_envs > 1: sim.build_multiple_arenas(args.num_envs) - # Set manual physics update for precise control - sim.set_manual_update(True) - # Create robot configuration robot = create_robot(sim) diff --git a/scripts/tutorials/sim/create_scene.py b/scripts/tutorials/sim/create_scene.py index 3f1082e6..823586ad 100644 --- a/scripts/tutorials/sim/create_scene.py +++ b/scripts/tutorials/sim/create_scene.py @@ -68,9 +68,6 @@ def main(): # Create the simulation instance sim = SimulationManager(sim_cfg) - # Enable manual physics update for precise control - sim.set_manual_update(True) - # Build multiple arenas if requested if args.num_envs > 1: sim.build_multiple_arenas(args.num_envs, space=3.0) diff --git a/scripts/tutorials/sim/create_sensor.py b/scripts/tutorials/sim/create_sensor.py index 380852a5..d35e2cd7 100644 --- a/scripts/tutorials/sim/create_sensor.py +++ b/scripts/tutorials/sim/create_sensor.py @@ -110,9 +110,6 @@ def main(): if args.num_envs > 1: sim.build_multiple_arenas(args.num_envs) - # Set manual physics update for precise control - sim.set_manual_update(True) - # Create robot configuration robot = create_robot(sim) diff --git a/scripts/tutorials/sim/create_softbody.py b/scripts/tutorials/sim/create_softbody.py index af6b5cc8..55a368dd 100644 --- a/scripts/tutorials/sim/create_softbody.py +++ b/scripts/tutorials/sim/create_softbody.py @@ -71,9 +71,6 @@ def main(): # Create the simulation instance sim = SimulationManager(sim_cfg) - # Enable manual physics update for precise control - sim.set_manual_update(True) - # Build multiple arenas if requested if args.num_envs > 1: sim.build_multiple_arenas(args.num_envs, space=3.0) diff --git a/tests/sim/objects/test_articulation.py b/tests/sim/objects/test_articulation.py index d233f8f9..f159f2c3 100644 --- a/tests/sim/objects/test_articulation.py +++ b/tests/sim/objects/test_articulation.py @@ -40,7 +40,6 @@ def setup_simulation(self, sim_device): config = SimulationManagerCfg(headless=True, sim_device=sim_device) self.sim = SimulationManager(config) self.sim.build_multiple_arenas(NUM_ARENAS) - self.sim.set_manual_update(True) art_path = get_data_path(ART_PATH) assert os.path.isfile(art_path) diff --git a/tests/sim/objects/test_light.py b/tests/sim/objects/test_light.py index 8f61fce3..fe6ef551 100644 --- a/tests/sim/objects/test_light.py +++ b/tests/sim/objects/test_light.py @@ -26,7 +26,7 @@ def setup_method(self): config = SimulationManagerCfg(headless=True, sim_device="cpu") self.sim = SimulationManager(config) self.sim.build_multiple_arenas(10) - # sim.set_manual_update(True) + # Create batch of lights cfg_dict = { "light_type": "point", diff --git a/tests/sim/objects/test_rigid_object.py b/tests/sim/objects/test_rigid_object.py index f57f8a91..56cbe7ad 100644 --- a/tests/sim/objects/test_rigid_object.py +++ b/tests/sim/objects/test_rigid_object.py @@ -43,7 +43,6 @@ def setup_simulation(self, sim_device): config = SimulationManagerCfg(headless=True, sim_device=sim_device) self.sim = SimulationManager(config) self.sim.build_multiple_arenas(NUM_ARENAS) - self.sim.set_manual_update(True) duck_path = get_data_path(DUCK_PATH) assert os.path.isfile(duck_path) diff --git a/tests/sim/objects/test_rigid_object_group.py b/tests/sim/objects/test_rigid_object_group.py index 7ca12fb3..8acff650 100644 --- a/tests/sim/objects/test_rigid_object_group.py +++ b/tests/sim/objects/test_rigid_object_group.py @@ -38,7 +38,6 @@ def setup_simulation(self, sim_device): config = SimulationManagerCfg(headless=True, sim_device=sim_device) self.sim = SimulationManager(config) self.sim.build_multiple_arenas(NUM_ARENAS) - self.sim.set_manual_update(True) duck_path = get_data_path(DUCK_PATH) assert os.path.isfile(duck_path) diff --git a/tests/sim/objects/test_robot.py b/tests/sim/objects/test_robot.py index 78a5ac3a..0177543f 100644 --- a/tests/sim/objects/test_robot.py +++ b/tests/sim/objects/test_robot.py @@ -54,7 +54,6 @@ def setup_simulation(self, sim_device): config = SimulationManagerCfg(headless=True, sim_device=sim_device) self.sim = SimulationManager(config) self.sim.build_multiple_arenas(10) # NUM_ARENAS = 10 - self.sim.set_manual_update(True) cfg = DexforceW1Cfg.from_dict( { diff --git a/tests/sim/objects/test_soft_object.py b/tests/sim/objects/test_soft_object.py index 9cbc31af..88ea2d25 100644 --- a/tests/sim/objects/test_soft_object.py +++ b/tests/sim/objects/test_soft_object.py @@ -48,7 +48,6 @@ def setup_simulation(self): assert os.path.isfile(COW_PATH) # Enable manual physics update for precise control - self.sim.set_manual_update(True) self.n_envs = 4 # Build multiple arenas if requested self.sim.build_multiple_arenas(self.n_envs, space=3.0) diff --git a/tests/sim/solvers/test_differential_solver.py b/tests/sim/solvers/test_differential_solver.py index c9adc24e..4103f109 100644 --- a/tests/sim/solvers/test_differential_solver.py +++ b/tests/sim/solvers/test_differential_solver.py @@ -34,7 +34,6 @@ def setup_simulation(self, solver_type: str): config = SimulationManagerCfg(headless=True, sim_device="cpu") self.sim = SimulationManager(config) self.sim.build_multiple_arenas(1) - self.sim.set_manual_update(True) # Load robot URDF file urdf = get_data_path("DexforceW1V021/DexforceW1_v02_1.urdf") diff --git a/tests/sim/solvers/test_pytorch_solver.py b/tests/sim/solvers/test_pytorch_solver.py index 75129f10..630a787c 100644 --- a/tests/sim/solvers/test_pytorch_solver.py +++ b/tests/sim/solvers/test_pytorch_solver.py @@ -34,7 +34,6 @@ def setup_simulation(self, solver_type: str): config = SimulationManagerCfg(headless=True, sim_device="cpu") self.sim = SimulationManager(config) self.sim.build_multiple_arenas(1) - self.sim.set_manual_update(True) # Load robot URDF file urdf = get_data_path("DexforceW1V021/DexforceW1_v02_1.urdf") diff --git a/tests/sim/solvers/test_srs_solver.py b/tests/sim/solvers/test_srs_solver.py index 13860485..4d2a356a 100644 --- a/tests/sim/solvers/test_srs_solver.py +++ b/tests/sim/solvers/test_srs_solver.py @@ -133,7 +133,6 @@ def setup_simulation(self, solver_type: str, device: str = "cpu"): config = SimulationManagerCfg(headless=True, sim_device=device) self.sim = SimulationManager(config) self.sim.build_multiple_arenas(1) - self.sim.set_manual_update(True) # Load robot URDF file urdf = get_data_path("DexforceW1V021/DexforceW1_v02_1.urdf") @@ -296,6 +295,7 @@ def setup_method(self): self.setup_simulation(solver_type="SRSSolver", device="cpu") +@pytest.mark.skip(reason="Skipping CUDA tests temporarily") class TestSRSCUDARobotSolver(BaseRobotSolverTest): def setup_method(self): self.setup_simulation(solver_type="SRSSolver", device="cuda") diff --git a/tests/sim/test_sim_manager.py b/tests/sim/test_sim_manager.py deleted file mode 100644 index 72b2a254..00000000 --- a/tests/sim/test_sim_manager.py +++ /dev/null @@ -1,63 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---------------------------------------------------------------------------- - -import os -import dexsim.environment -import numpy as np -import dexsim -from embodichain.lab.sim import SimulationManager, SimulationManagerCfg -from dexsim.utility.path import get_resources_data_path - - -def test_sim_init(): - config = SimulationManagerCfg() - config.headless = True - - sim = SimulationManager(config) - sim.get_env().clean() - - assert isinstance(sim.get_env(), dexsim.environment.Env) - assert isinstance(sim.get_world(), dexsim.World) - - # test add_sensor - intrinsic = np.array([[600, 0, 320], [0, 600, 240], [0, 0, 1]]) - cam1 = sim.add_sensor( - "MonocularCam", sensor_uid="cam1", resolution=(640, 480), intrinsic=intrinsic - ) - assert sim.get_sensor("cam1") == cam1 - assert len(sim.get_sensor_uid_list()) == 1 - assert sim.get_sensor_uid_list()[0] == "cam1" - - # TODO: test add_robot - - # test_add_fixed_actor. - model_path = get_resources_data_path("Model", "lego", "lego.ply") - - actor = sim.add_fixed_actor(fpath=model_path, init_pose=np.eye(4)) - assert sim.get_fixed_actor_uid_list() == ["lego.ply"] - assert sim.get_fixed_actor("lego.ply") == actor - - sim.remove_fixed_actor("lego.ply") - assert sim.get_fixed_actor_uid_list() == [] - - # test add_dynamic_actor - actor = sim.add_dynamic_actor(fpath=model_path, init_pose=np.eye(4)) - assert sim.get_dynamic_actor_uid_list() == ["lego.ply"] - assert sim.get_dynamic_actor("lego.ply") == actor - - -if __name__ == "__main__": - test_sim_init() From 75b8546b7e3a2baf2f87130bcd3ef19e91ca553b Mon Sep 17 00:00:00 2001 From: ZhaoRunyi <160689220+ZhaoRunyi@users.noreply.github.com> Date: Tue, 25 Nov 2025 17:12:38 +0800 Subject: [PATCH 08/92] Simple Modification t o the documentation (#7) --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index f2d11c7d..0c42b189 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -7,4 +7,4 @@ myst-parser sphinx-autosummary-accessors sphinxcontrib-bibtex sphinx-design -sphinx_autodoc_typehints +sphinx_autodoc_typehints \ No newline at end of file From bd87a430c9cddae5121c0d1350f9069657a95e93 Mon Sep 17 00:00:00 2001 From: Sheng Xu <111360578+Jasonxu1225@users.noreply.github.com> Date: Tue, 25 Nov 2025 17:37:21 +0800 Subject: [PATCH 09/92] Minor modification on docs (#8) --- LICENSE | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 261eeb9e..b8d50b19 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright [2025] [DexForce Technology] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index cf83ecbe..cf45e5f2 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ If you use EmbodiChain in your research, please cite our work: ```bibtex @misc{EmbodiChain, author = {EmbodiChain Developers}, - title = {EmbodiChain: An end-to-end, GPU-accelerated, and modular platform for building generalized Embodied Intelligence.}, + title = {EmbodiChain: An end-to-end, GPU-accelerated, and modular platform for building generalized Embodied Intelligence}, month = {November}, year = {2025}, url = {https://github.com/DexForce/EmbodiChain} From f542f69be9f5f706689832e68956768a5a64e9f3 Mon Sep 17 00:00:00 2001 From: yhnsu Date: Wed, 26 Nov 2025 14:37:06 +0800 Subject: [PATCH 10/92] fix gizmo solver size mismatch (#9) Co-authored-by: yuanhaonan --- embodichain/lab/sim/objects/gizmo.py | 22 +++++++++++++--------- embodichain/lab/sim/sim_manager.py | 2 -- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/embodichain/lab/sim/objects/gizmo.py b/embodichain/lab/sim/objects/gizmo.py index 137fe20d..1bf720ae 100644 --- a/embodichain/lab/sim/objects/gizmo.py +++ b/embodichain/lab/sim/objects/gizmo.py @@ -245,17 +245,19 @@ def _proxy_gizmo_callback(self, node, translation, rotation, flag): target_transform[:3, :3] = torch.tensor( R.from_euler("xyz", proxy_rot).as_matrix(), dtype=torch.float32 ) + # Ensure _pending_target_transform is (1, 4, 4) + if isinstance(target_transform, torch.Tensor) and target_transform.shape == ( + 4, + 4, + ): + target_transform = target_transform.unsqueeze(0) self._pending_target_transform = target_transform def _update_camera_pose(self, target_transform: torch.Tensor): """Update camera pose to match target transform""" try: # Set camera pose using set_local_pose method - # target_transform shape: (4, 4), but set_local_pose expects (N, 4, 4) - target_transform_batch = target_transform.unsqueeze( - 0 - ) # Add batch dimension - self.target.set_local_pose(target_transform_batch) + self.target.set_local_pose(target_transform) return True except Exception as e: logger.log_error(f"Error updating camera pose: {e}") @@ -301,7 +303,8 @@ def _update_robot_ik(self, target_transform: torch.Tensor): return False # Get current joint positions as seed using proprioception - current_qpos_full = self.target.get_qpos() + proprioception = self.target.get_proprioception() + current_qpos_full = proprioception["qpos"] # Full joint positions # Get joint IDs for this arm current_joint_ids = self.target.get_joint_ids(self._robot_arm_name) @@ -326,10 +329,11 @@ def _update_robot_ik(self, target_transform: torch.Tensor): if ik_success: # Ensure correct dimensions for setting qpos + # new_qpos from IK solver may be (1, N, dof) or (N, dof), flatten to (dof,) for single env + if new_qpos.dim() > 1: + new_qpos = new_qpos.squeeze() # Remove all singleton dimensions if new_qpos.dim() == 1: - new_qpos = new_qpos.unsqueeze(0) - elif new_qpos.dim() == 3: - new_qpos = new_qpos[:, 0, :] + new_qpos = new_qpos.unsqueeze(0) # Make it (1, dof) for set_qpos # Update robot joint positions self.target.set_qpos(qpos=new_qpos, joint_ids=current_joint_ids) diff --git a/embodichain/lab/sim/sim_manager.py b/embodichain/lab/sim/sim_manager.py index 3114ec30..39c5c9e0 100644 --- a/embodichain/lab/sim/sim_manager.py +++ b/embodichain/lab/sim/sim_manager.py @@ -1052,8 +1052,6 @@ def enable_gizmo( else None ) self._gizmo_controller = GizmoController(windows) - print("GizmoController attributes and methods:") - print(dir(self._gizmo_controller)) except Exception as e: logger.log_error( From 698121bc2dba2e8cac71b71f250827ebe170b5be Mon Sep 17 00:00:00 2001 From: Jietao Chen <61959467+chase6305@users.noreply.github.com> Date: Wed, 26 Nov 2025 15:10:50 +0800 Subject: [PATCH 11/92] Add usage documentation for DexforceW1 and CobotMagic, and optimize DexforceW1 config construction (#10) Co-authored-by: Jietao Chen --- docs/source/_static/robots/cobotmagic.jpg | Bin 0 -> 572902 bytes .../robots/dexforcew1_anthropomorphic.jpg | Bin 0 -> 604579 bytes .../_static/robots/dexforcew1_industrial.jpg | Bin 0 -> 604678 bytes docs/source/resources/robot/cobotmagic.md | 19 +++-- docs/source/resources/robot/dexforce_w1.md | 76 +++++++++++++++-- embodichain/lab/sim/robots/dexforce_w1/cfg.py | 78 ++++++++++++------ 6 files changed, 138 insertions(+), 35 deletions(-) create mode 100644 docs/source/_static/robots/cobotmagic.jpg create mode 100644 docs/source/_static/robots/dexforcew1_anthropomorphic.jpg create mode 100644 docs/source/_static/robots/dexforcew1_industrial.jpg diff --git a/docs/source/_static/robots/cobotmagic.jpg b/docs/source/_static/robots/cobotmagic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0f4891ff71e5d12f9c03e36f381a57fa16825c73 GIT binary patch literal 572902 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

  • L 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 V(jN0eLut-RL|Qy%S$%sj^dF>Q(CYvI literal 0 HcmV?d00001 diff --git a/docs/source/_static/robots/dexforcew1_anthropomorphic.jpg b/docs/source/_static/robots/dexforcew1_anthropomorphic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e119d54a61319e03542937315cbf7a1eace2d6c5 GIT binary patch literal 604579 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

    S$67|{XH^+gd~w?xp;`j`agt!sQVtfDy3^2 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 z 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

  • A1CBVqD3g4;Y5l8TZUInW=Mz1=&pvy4(QMv8<#a|R2OsnBEpXZ} z^J{sza=H@zYr2b)fbh;wfnc%2tzv;gV+HaOF2||@f$QhbS*H}fW7fhNqs)eRx4d05y!?qPi+URiDGO~4vRNMSR^^ny1Mq8 zT$`A6@<((gb7n8pR4#!cXv2EfmFommT(!9m_vz6LUKi_6lr{nfHI~C#T@wvvGP+hy z5M}S5OXh``x2D+cW)?-N?{s7boA)L3{W5&4Ztl0w{W|GVp#!_q*AI;{@_o#=*dVOx zl?FURS$TIr+-yiWp!i<;0lL&4?eN>Ljr@=#kIB$YlxSJAu+L0#5hrb8hqFM`KW$Bmqb#l= z{|T>@VgQr|PF0$5#0U=${W~5P58(hYGi$Lq}At3x!z=FEo<^hq6;v2c50)&^tp%PY1O{SgAJzvZP-Zb>nCIc6*N+_4rGB- zSRT70G%V`jvt#;^5YeSmN0&yM)I zAF`K$MqshIN%wOAcQaOl-`-_ zHKlVcaX2D>;*K9nF2(%EhBzgJ1au6-4JW9~^3gg`SENH=rfJWN0_@|{0=;qKsxRHn zfwfHfidE@(Kydjn6-+ub+t}i4oDE;>bJ2=Y1JKugKzL}NuVV?@`^Jr=jHh7BzFR7Y`uIDYF30H^I#I; zz~9=Qqu&HtL5@vUN>o)9-;$1mP`6f_^nxUDJe+L-|DJJ%SQN5@su9!<4GktOt3gDf zarPKFZLm$Tt; zRk^vV8Le2=HSFwEroYRDe=feA)mC@@!ZMnD^|XpDCrWPD*E5;LmB;X>a3i)oosjU# z+1$s|=%dKd+>D!UM-Vf9%_bBL(=6l7(zWS47;Dt9e$>SeloElo9teR2FlBfpe6&~zQ zo0MXmbd|}}l!-}ewW^%o^ER{4r_rlEeiXm6omYsdbwnWu1|;}VtjsE~9J=s~3R;mA zfoge9K{|gxjJY-{`Z5qj|DY-8Qp0|xqJLYRPl-( z64^%_!I=JB+W6wmQ7r&i9&o_jbf+QykQS!BBx>Sl(+f+4nK zEEor@Mr6ft+IXI4>bd$TP(dK=g+3Ppv>1Le>oNcB^0VozE%zW>apmDh@|G70W&p9Q zPL3#Vc60FUU`wSG%1(((6WC+fzI!*=n1kSuC zy-KE%?f=&9glARFOa*!c{+0^3M8>Fr-8TCgjNDl9I5phZ9DHRZa*Br@g;lyd02g{Us<6ab73NuZ0S_5|C} zRWCnkmXN%D)T`xEe>OdB7kpA;=nMbYk+3_SCwyfOK-s6T>le|Y!ezQ8VU>x!fbq5z z)iYw%Im+5?7};XOWjR~GJ4XfEEI)$5*l{SJ;J#b+Z9XqY2*@d2(vU9~DJY^9fvN*$ z1VH|o=AY&P*5`-imV9FRMkSRv;IecTYzsEtHx`6d041qCLeJwh+2ffGlgFx4He42b zUOcOh@Kp;1<3F)&b-4!-g%19zwXL#^{$LT}xCu+A!JAsc0WHlNcAPx^eE>1CY42uH z>8M2ukx24UfV-^~t`84&h*3UF?E=RyKlO zo;k;ZlY7d*ZmxI*BP2z&mcy^BL9_jA$`pN=`SpT{e!7I-5%y$0v%L{b3HF?_#je{8 zY>bV}^(N$owPo6eQJ2Q8OU1=n$s*vW5a z-S{6LPx$hPTwj&>P3Y&=Y}*lYe7NP@itrznAc&Mk?L;g3KsI5xCLXA; z%qa1YhpFYlKR&aT_YZUMAMIN0bUW3Y>Q_-HTtx6_M?AY8^N>Wzn+FOLbD&p~GVaJc z)j&W1QBAbbG1Cv@>`5$CUsb(2Yu=R*+&*olgx-x9gt=wO@rz8gG1^S$aR86drSq*5 zNzt=((zLRZ$;X(_i0^Ap%T?ZFNJ>-<=sa)pZOUKiJIAk@nEHUxBh4~Sg2GjdYh!D6 z$CqpZoQJJCbstU^$q#~>y^j)vdYCgw4>mWh7#q8Z+gRIvfuB~!EIGTGy%AJ&KuO-h z-VS_opQ@s%5tx(5g^5*HfBv$4*S+B{$ob~#Xy)MB&arKEMbMxXdv;`OG_L=X>z#b0 zA7PAF$CJ~Pa70IAsK$6#Gt3=Q0Y*qE}Z6bXe zZcR;18oNrZ19P!>pu6uC%*c=(9j4f2-{n>l>Je5uyF`?^eoTjib8cpj;7_#6DT>_M z2c1HM(OhyH^c@beLw2I{MByC52`-YC9mE&{9dEKrG+;vx=Te~2W6tBnVTnV(kI1cjywmIlU}zDxJ~}fSSvhLZN7MKp6z~8}aaEtW;VAyrwUex^)XZ?$ zAOc@7+<23pme^?zBsS9?ea79lOg}wpUU^=PBoja1{8h(sKO;OEvfH!F1+ml|&mP?L z-1?$`>K|Jt$KdOW1oajs1iLnKn{~)SIY+1=HlJ)CT^}2chRk<@;sPWe(ME&6y{B7d zd3&&MUVu1k-l(qV_0aQ`1}ftM`4V2e$Aaqabb+CRZ$Fd|@l}dj!uTAeu_JGbaUcJU z1uALe%O2vLewjg*1EcpJgi?|BN-Lirgu(NiST1!R^$SF}vvJjpoGO-$k9V*!Wv4pS zE!;wslwg(m;%X4j2D7#~x;oXZ_+1E*Vn?s~UAC``?w;w*J1hG1I_`|D5ZWEM5g$w! z237+&BE2PLoIaE{^a*rfnOoOQea5dqKUh#Vn2E&ldi2&cUFOEL#fgMM!zC;(pFMjaWJQS&kB4_Ij;?m&hPAf}p}@S{)j z=Yp2m`Q?Fm89-+De!|!#He16CHE>jw-O>)>I~|4XuY;Qx<;&^`;B%IoC!ze1gWu;j z9JKDsO3T;-CB8PBdd@u7`B8_jnR$*HLOK-Favsc_7d@-qUw^3UsB}_Ruo^%aZKir6K$O09!d*+5SJ51{&@b2&PeM@wJ7FZpg6`imYNow7M#3*%5;d=#qD|rE z^1<)HOZeU4F*t6nxbB1q?y`AanSLGOSzM0N>WAka^*DuJCeoPzc#KO2( zu#KQ{5!}`d^1N--q`EcTE7Co~&Z*1q7dp-Yi=>{m`*(u94{ldTYZ5TA zR*V)qBU*SbKfh)KbbZ||xnh^FU7m85w|vwp9%eG1C*MCh@}8|XLVdsRBG#N}{ttjs z)_b<%S;+bK-9+p5KS08eonG6XeK&#`!K?Or@z2GeL@U9|^B)f#rc-slpMgFYd|LE# zg`CCcQ+J{=Q8l&n49w9KERhaO_KOkBvXKN=qTf?KCg!2CBl^MW%l`mZPFw0Ihc`?_ zda$pakKXE9)RvjnGbQXH?ZJr6y!V;N1=?XE;nsQFGfa34Y>17);g3HqaUY9si-ls> z4((r6-2)3vP*v50MhYz^`~4#=zaazrv@}Pb2kAK4^l3V)8l-KT41p>oKZ{ppwRcos zr3Z>Fm9i2S-&;B3l{WA7KqCW9ipITp>Em(CveVi%#ZBAonW2^VH86o)&SPH(djICd zjH0XC2C-k}kISiu!&a@2U+o~5?@o`jp>3h7Z3WcwxPd9;Ya_-{1AaFCtrNTOiLrfU ziLcoTF#5VZ9y;^f|A`L)){sH)`a8fqNU(dyD7}!7h|iK z6%9IeHLhrP0)|M#cxLjMB`pmG7>0jkw*{WlI6^M_n!_(`iDTvM^qpYl)4}E9~&bi7A z6mH`=9`b)$p1SnqnnIM^P2lA_c6oKwy?ECCKKT^QNC${Udlacuy1? z42mBp(+&`OJQ}q^*M3QqGG>|7H<29gmPp~OLu~`O7ZXoZhOt|hQMT}L5jpFff=+7q+OdZ?=^I!g1P`fJ|6C2Z}meF(kA771YB0z^HJa>--@UC~* zxK^y76$OQzF8uKLN%t!eeoGrXL?DNz?>Rl(Yvg_(-pOIStaNwC61H#aH7!ef>xmci!B?oRc)Q-@)pa5ntn3rm|^mUHI9i|Q>auXhMt_#pwlX7{;ksb zHa{?cqB#FEA$omtE`$#LTY86bwzi~FfnerzdX9kcW~?G6C=`o0c`cxs^W{8=HH%h)siSTnuj;Lq`DopreFtei02 zwD$NM0!SB34*~vZs26a`^vw(x@n=GpM9S*n>owY46LM{H0Thk?tsigouPsQ{{mxyr z@?C?Qk*ST&%m*~$(5Bl?=Xpk3XTT&)Ck%$nUBIJ-qQ(5~^ZxyP?nv_KWr|Q%EfuLn z-`gU6HFOaUCY1)P1UM6WIUzPYz?16Z3LyRC$|ZnoYCO1+wB3|n8wJO@P>~9Bp0r2UZ3=$zT27~6u#~_G-pS8 zaUKp2>=lU5B3>R}asV`(iZ*XNTyIxqP)W|O$)D)O#y8w(!sP+?BAgel754hw9WT-~ zUDW%V10Skrb{9XLQMbI7Q5P}WjzrmZEZ=NoJqgy`%aDrR= zm6$|Mt>jM$_|tPb{?^zJ0FY{~m-G^@y##ce12FEMe7k)mt7F6Pku@0-i5QE7Dv&oE2}{$#@iua z?fGk5Hl<8F-u5bX6WUgs{{V9YpY!hXFQFXkFsSq?JsYFdchzO3Y_D1{mdA8*8_o%7 zvF&Z+my4WG8e^B87GpXbm4(OZ$!lc|v4vFg>twg3%N$r9obP`C57}kn4&Y2| zt1nf7Ut}c`)=iMWc1b4XPWaT$(Nr~u7Y-@{M=oBgRW9~a)?`Z>V+k+f6`sPQ_Kf<+ z*HW$9cBXthVlV{PM?>A#r|bGYx^w@+Jf4VJqm~wOGAo~#?A3s2&A_bm3w3^>CkiqeT zl*gKi2fJ9Ao>2w}-M{n-XWWOn>Y;!X=#FJN;0iCxf*9QU5nkhSNU)$!*?NiD8kyomUR;?Z3h$y#q|%F2B*J_~uWQ4mnyz84lS%+m{dz{V zL15LStKA@i2!YR>33{g5QQqh+RtqvR zxurJRCWSa=#mNBAch*$G=uH-VL$^jhJta!qQwe)_#k z4v$0IlLZU|p3Y^HZ{p&mDu-Vpd+cMsaGn$D#Os}a=+$1wTP@=wl?&Mc?6#C?<^T;U zsW5o#>}q%%LmjWUil=UGrkQkL4>?41cDx&^JO+3Az$ns%S`r`9zArg%<=66C+C-|T zgQdUeG4zq%+lSit00ak1%ml$O{})+r85Y$a_3sWa#30>W4joE&hs-e4Fd!-2-3THf zHH6~8(B0h)A|+kYDN-T`5=w)=Gtd8e{^!LxFZOlK`@Pq9&tB_Z_h*TqK6E(E3fqX2 zozKR!2)6n(g!=tgl1bInqd_f^x2!V8j~hoO+s;^8WqGt86NI5Cv?3c8(J~$%^An#q zZZsz$+)YJUa)Wu@=%%06rH{=1yRks)Td=j15A{x#G_N8#kPbWkOn_Q_(^!Y0Xn!J0 zn(M$fB=_?FK!alC{{hlwZdC5j4T_^?v^V9BVX8%)4noRb&Xs2V13+H7utGC?t{(pO z*o;GDO#0deb%lb(?7h7)VGcH*ZyW1w7PS?PE)u;3&u-fn{3Tn9BR~Jy{MY1~)t7?Zo=Ve5jrfaLO!`A1K$wX4`P&}{PWFPC3uJ{Ym`cs<(h8 z|CbvUmcb6RVjc+x-WRR$xGW|2_B$zS>Y2}i3zgEE4(wi7ekqW}0UEL;jFqCY5laT+ zY!od}*m!2aJG+7jrQ}xLcdR`?e4&!x;jMhbpLS`+i$jM%y*R&0($yfkY2j^#;1YJ5PILLPf}H*0N_Pw!fm}6ZQ*R(V@MG}iX?v8rw7El-K{P8Ky>?LpJSHal2wa{a26u445qe^ zSk&SbGLT3!K^5SXcdpd`V-H#~w1oe7>Eyf+P1Xsw=SnVB+Q9V6cskg-zo!!i@$&Ok zI0P*CV|*Kpk9)}KwCYVH1Xz*`(up-{aZ~)oly%N2_ab_Jryuyv1pGKbF{+6pcZ*3u z`RJ3}fSui|3BVmue47`XOC^Xv6+t-FvQg&UzKiRbF;w`()Bn1Hh1<&kg+uca9$0Z@ zF2nZaL_<_rE_GDyyQTcxH@Ik)@w#6oocNz@E7c%6M|q z{cY*t(e=syKJF@(yJw!$1Zl*N7)9ADJrxSP&z5HW6oZ5@`3dC($}!~M*rc~=PxlYX z&Z30fuK=CbPadANkSj`K-Yedg2lMhSf6UkR)Bm zZa&SFT3D?CN?}wyg-X_LPaJ(ktW#ufFkQ!PRWQRzu^38dA{0vtO}11woxQYeRp+Fd ztE@-{32Jllat>lb2n$wokk&eQeOMHJECH;FHhieFH_Fz0i1+=3`kEFhDMH_+UVAt+ zk_=7QY!vNy)yQZVSjJD_E@o+io29K2MAF|x*G;75#pZDp)m0TOQkG58H)9FgL-4ku z6c9fJlJT_}7y$qrUPl0>@7sV?Ou+U>nR{|K*0=qYp!+tus&)|crFjEXiTOGWIHoqq zt(TgN+k~>I)sQw52Bq^imZYVo0_WLz?NAtWgleDpYr0^R^}-U)*5~}XcU8oeM%}(Q ztcg!y_rK#I&1KWlWmB2ru+=hwTGN!u4ibnvQ%WVW^4Bk3C0IN%PRS?J-ekXAq9*!> z=C4%n1=}}%GVQ*<>&8wa+jXaGSOpymokHqup>O2a5}eRO@N(c&s=>X5iP>5K0=owJ ztbrIS%bv_QdMz=&3aPgZf_|-{ytHT_)L1deo@PQUXOHMQU6jY}+m5(ZM0dAk`oz-N z4(q|gqdPecg!vnTefboPO?fQ;Ue_MIp$O71Re-}mWsetP_?f_mqLl341J#faG@hH? zClv&QK~oBCJm|X)=?R1Hx*U(WVQF~bP07Fa_Vjp#f{FcG?DlqxUc`zT1X_3=@j{8EVkT-Fj7v5B;^CIw-y$zg{u6R_`p5!5ZBWim%q(sFD~n! zl}l}Claku-yxiojN_&mZhfpi2RKLg@cV4|4t$M;tx^{ zvvWdDmeh@pp>yN3{yfSlzC8P%pBjJ8os9oSn?~1s0@Um~2_vnfjT={TZI25}Pt_tQ z*vDi7~2TFdwI|EcHGa>CBHSDVD8+ACF_Izzez^}?*kUX@uw!y zJ1&C`u>8RsPBRXBxg(brZwX--(l8@bA1&05RWK6iaD_re{|5-WA))2S;S03Obj~Ph zz=qQCLV>^vRKKzkzL!V`$=8S3e^aEkH{1=RHpYmWK;oS@j7d^EhTL@LMv8+$Xa({i zsZjG<*MA@SX`hh|@;f^kSQ*=V39|L?o+e35xpQ)i@E!| z^H;1w@#a-f583TfE2)cA^d!6ChVB5`FbK0?rGe;Om7}AoL1s%6X0Fu*4l6D?ubmVh z^3MtJuFFy#<>nnPiZ)6}FvaIpRaY*MteI(`q1x4Ivdjq{KPycZo-_oxF~8r<2~GJq z(p+wJ1~MKNEcItstJ181!XXB*dC5HBHh!;5x29dD zr8TS+>A8izd1X{T@?aAm>=MoAMUWPa`|1kl!E)m1?d5(^zrNi1nwPplTZ;(e7gQr- zO2VtPBJk)Qd3&{Z!e=NhZk~$R8p`!m>Z$EqHc?QM^Njv8d2V+ouvIEab5G=bqYZq&e!?10YoJhm z9j%0>43y-I=v=N_^JG!q$->x{T7Pi&Ahb>cJ-yDt=&l`Y+c@P&SW;92t!wADJ~2OV zo7vO*{a785`ShYA6PU6sIe#WenRyU&0xjcp^eyZ8dpZA-eE)+-<&d`mapmAyr$3%^ zE=N<7T6a}7X{jk@zK{$sEGwkO;m^zu6iG(&*(m=dk&Sy?<%cJuE3Gi9dTomFGM-$j z0wn@X#C*N?6EImiQ*j(OLs#B6^QNrVsL}utXgI}QC5T5WoO%-iV#9hcpSUh}JiAGx zHfLFsdR_Q}N?sfK?y4#y9y?c6OE#_b#9LY{6F-QegKMrWdGmR*k8`H!eXrvhOMvoP;H93uuK0 zUx;Nq?MNWgwOA~=qh^MDkCl)LS1+8}VS2`K8>!rcjAaJ^oH*2qRs8lp*DH=Q6_|tr zTqp9fC5;zomE(TxRAO@o4o)aYyA*=k(kBg4tMjus**RAk2~z}WWl z;~3G9wU#k`nV{>AMb!zj{D-IjmUn9>rST=_v1Ouzty6+`+Hh_^v6Q1MwZ#fH;-ybh z-y}39rPfZW4Wq1i5uP>vpWVF#6-v{4;O2 zh5fivx*&ljn3F&gq)CG%(c<1x6&e<^Y`c3<_s_d(mU>0>)6_^_Qr$^q=&oCts*~I& zNxj|F*K<9dw2UYScmrjH(s{j+@~xXaDwzYO6k%-z28hMsYZ{rkN&auqWyIr<>^V$<5 z6-kkg3LoL7_#?Y}5_^hyP&mjVa^}zFwAeFAoS3)Io1ZJ49tH0uv#rjg>rQh5jGg4q z*))B2l_YO&Ti8JjQ(mVwfj6F1FX5%N6Y08^(;Vh~DD4bvM)cp+zqEf2Nc7mBmi=Cr z$o2cr zS33He9fF4dTgSs+^Do#dcleM)IU|8blAj*@Q6c*KjujUeQ5!QtGm0Dx4o z(@>Dm{{Vu!N>}~9I)SvEy}diFlYxu)x>6Ggzh>A!nx)|;TDSQ24`I&T3kVi;3S~n- z5w3zNl4dG2RXG1u@0jzVA5F2(4Wz25Bp@^tSQXh{Vz*;D)P(y^Ld{IO4qeTJU z)SO{=KAkoaD*pfhO|PAHk`U*7ku)R5p|Sh1bTA|(o{eNBDzQS_ynzCpOcyXF9fu>s z#e*J>h9pgVJQ2yKNSFWl3oVm6IZm%q3WR9q^N52|z5zvrtq>%OZ50gn&sfz9@=cRStA+)@+G?TVF&nQFk?o^gWlSnpt5ZGtTcP77}C&KL9?Ikj!8}Ln6i>lT#S|z z8egZr^i00~MZa1jJBTb<&;P4D>yqfQftRjpN7^EaUukH-PaG+kHU7k`w`Q2CPN%0ZnCTy! zTe?fpo-__^Q00H#zWI9;)?M5>?#O4OluA|Nz+4C+ts>}McDnUFd3mBdv|#*A^n~>k z-uRx^&_nV=R@cHretMkC5x0?njd+Y-C1&TKyxzR>$48&Ut|(4KzsS72>-!M?_#;Y~ z9rBiSf=%O@(otdd2Fi=J2i#(EkVU;MG-`a*Pl}yPSpT1Vg4S8faiSC zwB4M21GuDuL!9vEeZ5pC_f*V<3frfXB#gm0 z9VmbILimffZR`%U-&jTg(idSb&3)~{=>)7gO^prc&VEPj7jdbyr%3AODt|E#9_tPL zL%%MJ`eo2KW<_DdauO=ncJos$puS1Bg+YN9vjCOTk>-Xpj>;pu`hwva5|4g5f?U%L zRR_!=%0vDau+BpG4}m%Blz2|E5OrV)F0V58z~TnnzRG`%>h0S8$i}Sgx+PbdC&HDW46Y7FmHZ+wr=iBVuix+vRx11QX25 z>vrq`RQyFYQ@UMceVxl#Cx~6r#WYV(W>p)2Pxd@$gGHdF$GTBW7&j6tu(E0`8B7M+ zj9^1{lH1=I?0)t*waRz;P5vcF6|_5ZtGMF^@!LuE#6xI*gmVFUBhqC;T-llimz-wn{oL!_EB|&4p*DR zyh(?DKrH12%XX#_YPKa{W(ZJdn0biBwX=hn0=VrIKAIogQZi)n+=*Gy8(xD z9kTeWHQth|W@?#cVrbdYJWoX-&TnMx6JOD$R5I4hys3Z7qE57G^^Uz8{Py(r&Se8X zJCJ^cgyk8j=m{N=rHG-DsEW^2s#8;=sgds$l2zhr=E$OYb$s#c@AHoGZCq8;cjs;+ zy}5jKuBICrr0#B6E$?vJ>F{Wsx38kv@E*;DZozl;Hg~qvP6ob~vCbP*zrL1ubuaQd z92t5^-T5KFG4p|0#VMw!`gpO~2Ez)fl{3 zp>^WQ&-p#)^|PpR!Ynf0c_9m%=lfrc42#Mv#K!(`)|A(K&75HER*E_qMu*m)P1+>! zq;bu`uG$Ay*0>Q%IjMdw1+_!`A31CQg!dh=uBge>)+#7XDf+>u^xi7Oa|l@SYzj7IoGD(eN^mSMIRm@|l zl!Q%{)6G`w%^+bZ0<-w3c8-TLxY$DNqAemT6Q5P3roYR)H{r)m`h{mtkgb*njubg8 zzA6im9B~2bTz$QI`Q3jPHJ9Jx{Q(bFSX`g4S46>AdDf#79|}7}QOXodq?jd5ra|B- z`a-4)q<@~Bc&;zE!&FJ&=R{_tDf+O6=!IFUAU^IYyKn$+r3KYp&Y{Z0enw6y#4xo; zH~c31MDRp1+GW`w-h1OvdU1`x+|*s{_aZzES(VO__V)E8I%T6+)A&RLAge^O-SF9f zncWW9yeFX^C0@~drgebZj=>&5v z9XmXF>o~HVt@90nlD--)(vVl*?xh%>5&WWX6^WRK81`T2{p%%<|lg)^Gx&wqfnnbrAKM~o0=#pvm= z?*~T#L{%jd=KRs;fI8U7F@N#%6HmSIkc0@-Db<#X{NkRoS+O~QqT{SDeM=5f;8{?l z;%MN??#ZVw56thqW?CKqbvetWL5`GPYkAOGiPrOc%MhfNT0v_HpH-Qwd_CAt3a9qzq~^@e+-RmT@0o~%sjzle?`1%uU!dBhmyzM!W5G|>=D6VZwELrbWl zKOh3qzlJ$K(gb{VbPtVfY3vB@7G)AP!x*ZnEkCTTtK#a>ZvR?z4RpC{mptk`ahKD^ z@5(jRajF{e+00)PM6cy08Q`}(UpShtS88fys8uMZjUIZAXXII<(10&K@0e~7qB^)I zR=<<7cG`5eW%F%O>enhQQ^1WSwHGbf4wG~oaDK6zw2sO^vt-z7-cVQ9K$c(_g8(F0 zi&K`&SCtdhmR5?CUKI+@lv}}5sj38^@eKgl)Mw4vRmzX6liQ;Nc!%w;-f6NIbjE6l9y=D>4~Qu8OX1Gv(VG%lIgyR>=Cq zP?|GR!{&v5*Vg#18SNSQ<^5MjH;eV@fvd2VMdw5bNyezl5G|thruSb5I<^}N!^6#> zwJr{yXfl1BjLPO9z0P_f$u8kyldT zScLz;XzP{~7fe>X$Uau4YL6&2kPSOstI`Fkx{o8iBKP`Ne8(q)15Er5wmmh69wCs; z)4M7uGTp`)%L?fB?Q6%dg*c(tYf7|4cN=UhekPY{4AvPpnrt4B*u4U>XOr+8{89Cw zR=UtiQA*)qp5Ez7xjVa=C(B$f79m0MRH|F~6a|`I9wi#zl`Sg7zHbr?$%X96cAS|& zk0A!4m~a$x)HV2S^B;$}GbTdo)~{u5Ss_$y2%5rY%$F%)_XWsKpy`7d0Rf0DT4MD^ zhZ@)J+!Tq*vtPbMv`l=|6>JuS27)W1*g-fV%fb*9GOE(#WQ2U?asA3S`oV>`5$_xu z^uZ2a5`B4MKbPbv3a}sK!eO#awS2!9vZu#QnZw!uNBqG zX_p)SB6vuCNZ%ZJL8prrF%kOW1XuQevZHrEp~!@!b-;_JFlyBvU;K6F?S74dBmLQp zH@Z9@da$g9u&jixKGk6CK^u%}QN5*CpA*FI`YEdEozt5{t`b{MQvpd@x&LQK)R5>N zz=AbXPk`lJeff7**;Tz)F-)Kv)emF`Kf!+vkNo}YbN`1=|5!BWG$%1K&-cMeoeAxE z$&Zjd!Gq89JLi>+@7rI}%2qt?^V`DwLPLS)28<>8r<_BGE`C zPH;&_7rekz;K4KvWn4Z0263{dn@Q7Gm8GCZr;Rwvh7voK14mIn@)yr=s4ni`*c9I> z=&19G0AS;XRal(7+6s1=%IZqglU*J@WGD{lm7z|Yh5_Cr3Xy#ai1bmpab!^`Zh%#H zAVly%i6&8QteIP2GF#Y}1|zno=4rs*L-_%M2<*uDQcEjpUEoVa(A1(MeHoPYnA|po z7KuwTVmk`$9~5qnXn_F9*#dwGtB-HY#-C1ZBcFLF*U$Y6JUd_){Q0YGxks(0-d%Ei z^PwPK&y6YJ(a)17(Vnm2reW^N^I)6sh5uDwo0y+b9;Rb z+t%Q6@&BDAehPQ^@%rvsne3#H?NRX8CI#1c{8>Ps%&Ca<{Rp{C&Is<=1m1l=`hIXX=z= z#h2=gWq*V_a5%N*wz^~atEr2{yEQv#ffHbUiYE9f&hE&*gbu>~4t zB&jNs*wY05yxW@JQer1yz~_2=!?64dsLG=8NZLyUPMP>}^6BK)#u3V*1?w-#7XEVH zT@RrN*AmX|^500VYzpb%L(s3~X9xf5LQ?wfVm%5?D~JMDy0G(VE<(Woz(#J%j}yi= z(m~LRhhG#bMx}V_(tNzij*mZ#CYu{@Qx-bngmCtkgOfoDfBG@49zuVYk1~aPXlTFE zTk2_22UaAHfCUW1V0zwWWTa;`M=6MfZKF4LSem5u96lNvMsB)M{gN}HHenZ$@upB) zNnfT?{);D{DmIA?^HMIh7~av>_Yo3qV}EF6T*iOEq|=%!6&SG!7yxv}>Hr}TpY4(E zgV{#*Hd>jCi8|UJwM$EgmpU`@9yqCN3JCl+l{g~?A>EyyL_Rk9=q5A!&&~ct^`9<& zm{Hv!{cLQ8t^IpMwY5{>Up+lF84juHvXl$zT1K+lB5QZPMS(0faP}tn(jk(a{awg| zwH2oLFa?+#3-l!>($rfp)5Qz9aXl>3{6FDHm@ck)W9aYuzt(M!>}MF~+zau0@#jpd@*FRi`)ttVz6b(`RXStp~!l--a?x&1(*~5nK6S!ZzuDw(3 zsP#Wiq5toNbMim7ok%Wixl4drW&|I7WGX5uwNbj67d1(|S!AslZjWpg(WAmfCue@a z8ns=;1=qfda`f7j&~sDQA!sX97mU<~T|jfyIC9yX@bnzfm~2e3xS{W8o+9&>QjLBH zB>_pXo`fhqq7ry!uR((k4D7}N4D~IM3$8b@}#T)rlS`* zo*dcvJ-IP8K&Lvj0~&|)7hTGU&lM|%Wlk$Guds=z_elW!;@INX?B|~HX3My2opZnn z-QDwCP$OD<99Osrqb@wCRHPWNS|q;AaG}ndeHam?sV+i67nm;%PGbWsutoCkl2t&V zoRuOJ2r6~C76@na^XVvLG>$M9p+1qv9yXt#gEc(06obx#JM|?wjk?=K-|92TSsVkF ztzG{E41V*>A%EU`|BVXU?HNfZo*AwD?y_wGGs8n?p_Q8-V{iLDrUV~2>|*|DH~b{6 z^CV|%aIh|Wc(C48_>9k@?J7~8LoQXqc>0}mW`GfOkV5nI+mZwlKVeXlTh+D0>TQ?- zP_I!2+qxfocX^If!deeA3zKp|(lV}VneF~O1wxZmnW@BN6FO|3%IgkYUg%|+9{PC4 zvr)X$eMPvC$%e9r<}lcO9x95Kx!~!bby@~-8-v1@mk)NaIk6JcCazzx4Ea1xS9wq( z3R2@umoqg>_vxDq@sCl4Hz7*j6$7q@jjS@#SY)B`_Vj%6<46qj+u%V(6AJ>8tv02& z`VNy_2?r!l4)KIE@o|Bk1;38xPi}a!k7&}gQJUukq_JgiRKQI($mhr+#V-$w9n@dp z$KlnMXU8JagR_*lM&;K7P_k8;gxw`P=|U|D@y!j;ezt{CP)#|YqAnx47UYBP%tOr! z#F+hTL+Es4Uzry5E0gl*EszJ;5U{s;DY3VQByC4rg*}TRCu3CkYjgTjRB7ZRiBd-k zId{F$%?VJ7EiX?Zyo7k;!gC3e{>@Jl#v1!4%Ek}aPZ=3U{9CT>>`ciMC-G=1F?Ki9rE1dg>>`;Xl zF91*BXKM9_7zp$Kz8EPsqOS#i{>5afah88nsEE+!vb)gH{|JtCv?&^6h<)ZrN-t*B z%FdfX_AeGBfO32kwr>YGUv@5Q-?@ojd%V{0N32jwGuIlb zzZt4K{P?UX70&$L9$=jI_Leh4sz=0u9TtW33wnbDL0b0n=7Ph8m{M2LFs&qju`)G1 z71|JAppp_{Tsf|Sh52hlRa3BbCFxGGG)*j`Pgq@5R`LX*H`y~m+c6IC*~oF&*sO-t zR%O@h7XXwf;?e-@alZkY9Lrowb6@pae6(mgL;gfxs%I+omEgl&`OEf!4#sG1h41@3 z(iU~t8z!ybSI_lOSx`QxS_6HGAYZ1V?b>r6=D}!MtTC$~xJj1P^1jN~)BXHfLt z`+gv~N`ZMp+oVkJO&^816#Is(pX(4NxKqV#_-e7uVR`HOS&0-*iuvEI8UZr3a8VM~ zk=^}^wqy*(p(X}?5<&7mCp>Z3_^H!pZRAV1{jm!d7;FNLE*t}1(-3-S6yPlJ^aIV@ z^0-e7RxuJq$8p8D5^44tSZf!;^39>6caT10a3$WTlA5rnLa2}@bwVqDn;?tOXl*~W zXAPjetKYhM_qO4=Ol(|4$@^a+B3Iy>HK8`?4dJ*F>UnzqIJZ71yQt3}9zOVM6H!oy zz?v18!Gb}xpju@U`Y{tVE;uzxLNY`_D%A-=F3m<wD_$M_LGy*j8Zn?B#G0O#$F187uUS)f$bakx%X-5=^yd?XXYq% zmn8dj2Ud{!>Cy&|lU@ZwJOf_O~WCzRTdcS2uV zLKTJQM^%z+oLYTW@x%fgV@sX=Dr=}hdz`-Ii2lK%_2?@@I0LKTqw`O-*@1L}2gZrP zk@R7LV%(lLy=tLWoP9)spX*K460l+-cmBOdeq_&&R$dz!xon@t)G%34KRJ-su`M}S ztq=)F3)5yEJl;HB!R#+BV;ZQD)Zm4$J9H0~H!UC6idzSsclrv$pt`O+Wp=Fy{ja)Z zY72EH=?Z>Lzm?>a+0(-BlO(}3r0(t^K0){G_w2nh;u%>tgXGYc3F{_oVdi#-)JCmUt zWkdFJT94kcxe?Z4>ri7>li_!H$A(Jl@nU?kTqtQp+csvM*{cMHg*N3=>PlvSUdgD%WXyUm!j-J2TD1KK7NpiNvDgY&hhXc_Ms^R8UbND&EYqRG}`s=QH|b} z+G-S%tkO1A`zLbcsvFB48}yF4GE*Y>sAGNAgPqG0@0{u={`QaSxxh=(;{KrcMwbfE z7fP8Tzr{mzkk~>&Oy{Q+7SGlP{{*R5j57K@bXeWeLfQ{n=EfS!arT4@RWu#&P>tX6 zCqx{jvaByn(MG*7eDBLik;SGFlKvc4iQj5^V&ptU{UV%w9Y6wp6my!4>m{B_-*B51 zCj0*_tmHQbJG0)A({a(i7`UXwm1k|&b(}l;^(l8cqp6w0lfi2rF}9(9JXiK6D)dL8 z|1R@3l#B|wVNQa`x88nZ7;YOBiYFYtv*IBfwc`ipKRY%cs4E$2IM#?MgLBWn)Hj-) zswk}}sY12rlvkt(!yUEs%u6ddXU3|`U$XQWRVDH@D)XmuBH+4eRaMYT`pBWog+-oh zU17GUWG*eZ@~oWoSr0>eEagke5Ui^R%uT(@zs^cjW!TQTgIOYbr}7q-^-5t?WxLND zkVA)HFC%`L*XbgbjQ6s+k+#lLCZhBj5}Bw{t!?9P<8BY;i{%Knqw=7xRzC4_#^)X3 zKR#1N6$#Tl=7C5^Y9mTpp0EFQqGQgFb%!Rdw#5t-?C@<@8h!(dFQ{gKgalp9r%sm0 zxPOJysVWDNin6{ECi12zr8vxPS@pJ>>( z&aGHBR#-IlT%8~%x|*n>1kPXfdU-v)rG&oKr*x4MqM3oH^i`SlKoGzY=KIYZZ*{3w zEZ&b07ptT_BlYAqenK!bnOPFEpkVfB|GIy45emSTC_csVHs)du6u$T zy|Tc+beYPxg9)X+H`G8}>TJ693psPV8fpByp-{cDt)D&RYu@pqZN?=&SEf}l*gDHf zH>i0v>HYA!(~g44z3#3(VycSktxZvTZ?7b?Tye#{=`LEQvPv(H5K;OwfIDR6VO{gg zlF^%KtU4z|Whm`bHsL1|sjB9cr?sr0E=VJS2oTc@`>^<1PQY=0SvJh2t9nc5V~@jL z;!t3Ov%=)E^sa!{WUjc1H9hhO^kAxx)~zV$zfJd>jT;ni-WQ%)>B5;&;==0auJ!7l ztR#hvmVQRh7bRSpo1b?-4}$(IGk8;^up?Uj5IQ1weU{dcYJvCtqgI8*7RsF;w5}|z zme!g}!XeUjJ+uiRHTm7&M+W-~D>@SldD$U2OX4rK<6qCVfX=OhN+64X?xz z*M+WEQI@i*!Vo+Z|5}tJ)oF7w6kcl`(KqKu-IoY{v#w&#UVYi4M!LzVV zg0yAsFj8#a9r zkmE2PgAhu_v?s@kjCuA8wkxH$%+hdQ_*XuELzi$<-w8rF7D#Aq&a2kNM1dBee7VY3S5m80S%qk^ z!+W#HFA`1&k1E+u5!AA@7sOIysg2Quij;6>U}YpjwshWF7aI;tHnpsdxk_*8PT1Oh z4;BYzsC>hIy+rvIrWD(xU~glNzVmj6Gyy1{_c50;*)09@bjQtvA%ae zbPl|_l22;%(6dXc8N=pr{e#ugJWE2x#N}=5%;nqe-ty3_?%$r9LpLu-1w~EUB!jjR zN$$BPl9?EPH5`2I9#Ji^(|@+J&iK%ic^O*-0X}z)6!1KF*qO5zAoIiDo!2F4EPN(o z?0a3S@jby2d(D5BurS?b=#S9}@VC;CpAo+aJ%Ggmd-L2B&L zpc1~@8i2PWi~F?5tJ$DC3t(r42Br9~mzxziAWR1VjFrhNL!B+$0br*8kn5;}*yn{} zK6|C%snGaT?Tzd|p^6H&jS^b9-N>P4|GIaO_q1LgFE{3s7rU}koXl9h4g<9LJn;R# zym%6B7pkWu;wU1*A)3*N+(~gjiK0M02R2uC!ws#O@gbE@D zzJsYL=olNU@XCk9A=dEORBjC*$*cbWG|%=K)iEHd9U!s_$z=-t^Bg{>;cFo@}TQarq5A&Cs6|n_l~AHa@L|7m^WO2m$l* z;}T*5#r3=}4@1x(Xd(aA&tw1L`GM){8&#^J@2KU6W9i^OFNp3#*-id=smG2y7Z8oB zK&!^jbCu=3kkYYd*UZ2IWePg+!fDbaAtWF|KNKlSYHRhk;K2Nkh0%18W?VizLmL2p zGL7P<5tLSCzk({DFF;hbiV(WITE2P?+?&W2^jS)+<)ek7sL;MpRDnu_Yb1ei(%-dz zYIaJWy?3ZrE(TqbH1fTF^uCUcH2HwR?U+nw_8Tv@Hd%6abZw1|_{IH=1s1IqMQKXw z^ptZ|iY#6T#6Ce0wx#t>Nq|z5O{H15k3X!jFwlxKNn6CvMW+@ugHTlTAKCh!uL|>ERu!e*84=9bA0gLd!*bt^a#)+|Pko?6}!%i94TIxWWkm`Uo=}LDx($;SDcdYRePym}ky$jb}xJn@}x+yl_NH1;-S9 zk7#s9Hl2Bk^^Fj_yeI^eS7m~#RKZMRkVvh}xQyfiiUw2@>I;cVe2igr ziT|;C^==*=6Ia2ql4`SR#QeoWJjpEcsSfzRTvKEHl%_XnV=1nPRhW^)Mz8< ziz|wBO}5@qr%DIxejlX2Tq`}e_RC^wQ#LBXYkQ@|`%R#2c3k>)wM5E>);qqIG;B|- z)XG?T*=Xhm`P2?HQ-GGd8IN2jZ3<@;pe(pC3?tXicFfV;Tugkk4m+hr=TW z+>&S%$RUs=HoZ&yKR~CB%6wMv4{!wl&4~rkqT$tpD%;bZVry~>gRw>ZMm0s|TKBnm zr1eV4nhNNe!$AUv`s28xv`o*Ou5?|kO9x5+7E|&|;^u8JY)0WR(>QV;J_XLd_V5rRF&kL&y2Elhf5Ef_tEjE3(8s*~;U@n9 z0>SpAPC?`_+)`uv0kgIE7~WWGx) zcHXVr@!Cn^>usRv(PCoS{El}BHU;I`4%12z71qW5I=u}Vq+oh*V@;KS$0zGq@T)9D z7aH-xL4*+EM&PTZ&{G*@hTPb+wwn?6#28a^`fNwJW#VthPh&K~65$R@(gz-(N=?V* z5l^AFJ$8=GvL}Q%X^dZxK4WZv`;_@Wr2Z#tP2gk%TVGq3{g37iMLlO&e?|$#l|;xp zPjBnrNd^h$talJs(};i=G+C1Se(o# z(n=#81$?u__odxTCfGh>dgHlSf>yGfq#XVN&sMOTgQj}ky|tVcvUUpYR7(;iZw^GT zUN{wmLuk0icC7|^Tvo;7%W|?DP095tU16o#Am9Wg!Ke|1c>%3!^DCayYQ`bSpgt5Z zrC{f^}d*kz|u&jVRyH^`Z2*x!=;Ow_!XDPsm=Y z0f3|mE?~NuU#25Z-TE_5nf#~hy?Q(u`y;2x6Lva0o#3?BL@IU3HJs~`n?EK3e5Q~0 zoQx0l@0EAQtQg*k@2uHJE4*e>PZ&2g9E{egQ3m2vCJQ>J}(rP3D||MDa0u)4y;NJYL|&b z#MkJJqlFRg3DZip?W$n6zBG}-IQl|%;av!UTl8aG>Du(tBMxIMU2VR}&1Pv*#rLyu ztHrxI*DO=@7YkJkfUqSYl%(ka$;QxC^tzMKhFfz2%TAxE>B4`FqJN8D^LlJ(OOS| zS;&w*E`-xLyNg-ZwuVZ(M-RDh>g!c~0!?3nP$e-SUS7fH%n(9p)4mN?mgM8lj#rNM zSN6mo8XI<>gb$t~F0DG}uKOzuzf6l9ba4kTh&`#4Xj7zY^?o*N%g4}>m0e2`u25|y z9*L(-L+S6+TkHQM(?G!)o(AF5Z)XF1jc~yJ=3QbV?i-mw)sO+HkN^9&@+(0sv6@1O_P1WD%Yf+Ma{@ssv$JBR&+2Y(2s56%6j%}3VNe=>;-t%iQh2HLOmDivR6bHN^($^b^3$crBwCg89h70TyC zgA#DHV51L6sa(JO*Mw;E%mONePzHcZ$x7kKZrqh(ABmuBJ$5 z%4!QAgOF@^4+Y^e9n!hKPS;(h4xs!fRAglTq=Lf*p%_Jjm3O??yB+C|-&)kIP)QOi zT+lVzs;UyNau7(%u^$5 zxu2me-gw^EW5&!jWG!nBpfA=FrBI~+T(-Dz_8@VWv9hX)5+EwI4qiTC z1#&wCC%b{*gN)6zAK0~b>#$P8Gyev~bMvaD&O@Qgm28ovWoGv5&vG}MCNIJF8UqzZ z(bjaIDfIwG`nuQPMNM}18e|HZ4drRa8wZXBFpHioWMMh*rPOeCpQ#PMXS!&-akMvm z|8OLZFS3ds{pG=NMEpd2n{c#r-Uz-3Y%UStaPs3NMbN=y@Ri)wQ#<^GiRQ=C$E)p|_xJo$1#pd_`eE2O& zDhnj=W=5uti@1xZo6B59jBB=8uX)T@pz|+%GoS%V8 zRMhvg=;zVcLkw&1>8~g88^6SYg7O@M^Z!HDSp~J#M|(TCyA^Gq!Gb#!4OS97xVsmZ z(o%{$Ef5Iq1a~d&6p9zO;!>bMDFup@_scmK-^{t#li9aBGk;lY{hsHNKuNh&j6ir{ zKU8`c0I}6qR5BeIVrwwn=Pjj7kqR?((IZD4;11(B$e!EqZbhH70v&CDxsf$~?Lv&9#>q0;=;So{SwLU62cGfRyv-uj{2DcZ=t2Jb^AqFG z+t@ga%ps(C+qOFekm$7FIklQ9HCBHEZYYw^d>`h62$)p0?l09)3+LkY0(ZvQmX$(_ zO2AkbG#F`x3VN{gno=!7PiqllSK`CA7!rD~Rr~_c@asi2qRc2ftR{#bFcgZ%C14lu z+CtMo(=>5BYa+XBHvh!En4F%Q7PDU(uUi-FLptP{D}8_WAe~}dS(OKG>bRm2d-XTX zqP0mitN>CnV(e4z#Vg^dIlt#i^8aJ(AW%Z+Ke^tHet}=h%M1M%Wg|&RwHJWk)q4ne zu;(8khSVS*+#$2J0>%#wyVWUPDtQHleKA@kgE&$FUdz&wz0vsD3Yf#G*b^)YB6j;c)O@OQ>< zAt6@JTv*2%yv$qwu>Y}@+5DwKO@7#%aE>2fvWT^r6?^OO`5{Y&v|r`f&ZgHEDW zMmQTa-h6r2klq27XT?#FUldLb-}KGjK+?Ro1C(jPRsr)fznADQZ||SXTeGfwNh+?e z>ClVt!yYh{sOvv~{HH!aU@SM>^LL=C4`BJt;q#J*VeWv1AH43>tJ(L`z3EGgr@zCw z@l}&Pyb50MIP2_5QA# zLi@IIpXp3AM`qRMumZ4zYu{Q4lx_gN9ZC^~g3nx(xF^OlE5T4N_bd_efj&~rpGwL= z^VBzv-rlFjq_QEBY&qm!P^=8T{Que0C{m!0bCa2~ek+BDQymJon=0+GK6 z;1N{gQGhF@ap6gfn<>#4BG4HYzB)JmebH_y9yl!$l;r^8X2(WFROq}=BpIM1nUpax zWHm&g^|MawZ;Uo6_=|5lHPA_MnQ<6Yx*eMWo{;88Lo=VsmWQK9y}xpxsNhptb*BLM z37sW1!zGKJ`oi(1qS8T)0Mp%A<5(T!Am0gdEQ6IDbo|>?4kaM%zu?Y@vQ8TnE*(>( zRLl?zZLMHeUGlG0PKQ~ZU@pZ=eX}X(x-@iyb~NlQ_pv7oHo(j|bPFWQ9AI$$swhF_ zVhnaJF!SuRh@9KU=e*Y5`K%^W>JUMDLN*6D1V^P0yKo?xU!-yJ87`^1&}-v8dX(Ps zyc+6JEk#l@RoDj+!)8Cv^_6)CiQ$`^!MgD#y5rVlf?M&GYpWv=%AE~W^Otbczf(et zDnQ$kmr~!neV$}F!aghUiu;A$xNH^j`taZ`Z^rDDl&)=N{3t{IRhq1iBQP0N$+7GqsV=Nm&0T9j)DoGrCGpC0tz~Jk@L4SH{ ziLlXKa&mOM{j|Pb(uLQowWgn9RD5~up4vv_uk6hJ0~CnZ zG1D{s-*+Y&w9)C}I`4w#(9=0&;=%Xto(o!hREM7O0k`=FZ4! z<4~q6=EbUG)owHpf7uTOfL0*Xua*mcDW8;bk2`9Yr&|uSoN0w0HBc$4{0E2)-%g+) z#Y}k~r+1Xm4pEL2`B}>5nzr-tpzxzaBaO2Uyz~QgrP(b+{K(qYTPKZ%9vu`V!oCTe zhQCfOCZ65_+j{awBAJTB0S4v=(L9FcMXanQI)DZY0t}!aEx-jEdJFxxu|ui2f||;V zWUBugPcV}{5(}LiChB)kQ|p14^pwI(h#Bt6ZcK0cB14xC$fcg%+zlqDV>AAKyn7yl z+|CQ?{ctUnr4jxc1-3bob3--q3d1yNP|+cqJVA}bJ7%)nBD0Zjj-NjC^h*wR*UT)<0{CIzN<^Yl%O4jZ&5}yrxo6{L8PxJ9B z?S1p3*bxrZFQ$5yw?_=ri-4Q9dPiD!zHZTo^BaHTINyY0aR5KXka%Xqt9f-WFu%j_ z#AP|NdG@frSKf>Emt9md)93o!p3N<@0^j72IlbXi)IWdQ!0^atO&}|0ujAHMb_5rw z2xfU4iB1l6RvEhby)P=z7PIjSu$uSOdEb_-JEZA3xO5OG!f_0sllcm4%l@&;j7@Gx zds=Uco*iRjV^7wK`qInrC@TZ)(|mt%5pvWbWWDlpI8gowTX%r){p!!BtZhIZHU&V+ zrdyh|`QqD+@8xG>{e--=t-KX^f#7;d2(^^{&#jEUtGMH`>9VXfXqK>ke+VT3Da&>^ zp_+6!zH~&O8Zbd7*YQ&kcWT1U@1ycg91HHBuCtSbnIFzx&m)ZXBp_r#_Opg2g(aJ)DQC z;)L6fLKke0%)^|8u#S0Ywqi?yd^lJ^;pWB|AA05f;qlL5hxNyFVED`}eVZ`g z6OEHnWK_sVTDWlx3AJ&;Sy^Yq;X`Z|-U~3*96ra5uP5!&M)ylIqhV(ON6clJKXLy% z!514&;B%;HX@a)b=Ks)WK^BC2qLGEK=_o2}?f-oT2Ux&Tc`5l<^|CysJyPs*Rt9Ln zv5y=-FSjJPF(T#$+*NU3N z4Q1fU?2K825A2K@z)NbKXKb;`aY+m8u+`81f-vLa(i!=!>$`ifQ+0rh53!|=LgJWs7qqoC^hzcW=!}VVP;V~jeR1zzbSsO z#3q&c^H%w9@tD@g>0y_)FueFc7?37VO??}YlYg1$6PH;tPi@$<)TCdsTYPZc)vrV; z^-L{InH-JSvh~8Ld0x1MqNZAg2WMMAur-vrez$fqt3Oxpu<5|bTo0L>h0^<%6YP1s zcvcYa-w;( zkCb0{DCAm#NBGUx3m;eB zCrSduJ(Gq92Vl;`lYrLgCkB!?cRp|C@a6hgl9fe%?uFoYL1PVd=t?Sb*!GjDsS*0m z5K&R=_s#!!!qVDMpR8uGdZ&oeC_b2nx}RAqQ@E#XSP8+06Jhb1_T>ujh$4p<2Gl&l z)FtiodJUM{8yfjkBVA2|6`a+=X#~Ow_6?7oz|PErSMQ(52PT~z#NRaZ?%cWmYCj!= z*h;KCeGpOv^$i&{iE=%~lJUC3`=fK3>zg#9_h z#^VXc#ZvUN#i8O3g`vCCG=J4j2O0gdMP6vA)B~oPy@+oI}(UW8L{# zkG~l4QYdL_#sG`pfxj;!INRA~eidL`zM}QU z#T!~-p%X8m+vRm4>2G)^R!PZexSQE(UIivJ!OuoG(|0G4m23(2UM8< zVR%_%MpC0DVqY$B{m`Gu+sVtF9$q;?Xy|~M!v|vMaJgK~S%Xx@qaxuV;Y3u&ey zP5!40aL(C1e}Erqsa)8jHlJ zOQ-stf9m@pYy{Ne6xPdwswsdF4`Sz7q(9ZOU2-xxWon=;2@W1O?t!CiIcgtFNqDh|J0=79jn4Y$2mcO536T=+#xrO* z;pC>P$ZAv)X1$WruS6W5R#Z8vo1gG1B4JdOJTCE^V+CN1J2#D0_)2#B-v<# z5XhyaNaBOSjj^c#9{D1F0Q>MGA8-=J4jVn8R^HHx&ZE~8p>RP$pLbXAC`=|nAE3J< zYGTf45@=d!?rPpePz*5v_VIJse`R)xU7u4$s;d;*h^K3N{_Qw_ z;I)PnYLY{QM4KkG;==Tvl%mUECv?}Vm34Y(*QVs=i)kT7YvrOfiG{@)Z?I~H+($iF zI{+_2_)98vRm=B3`vq0jEm=0Wr*C#IoZCYv)U>!Gm&fW0YtysiU9(LFgJo9r;8}5S zj>5Fc!7wLYbz1%xQ@NU-_&r@Vzg^3kTRHt%zuOGf68O1JpJz05#aSJB>R4->K^7&; z_p+=4Y=1)VS~)7}!xgAI&V*iVw%oCH*Y&+&wuL4R%yA+&w2&z(TmhR8OrQg7=g;$C z-s@=y&M9qJ40cS#mZ&>*f3>TWqr>2DsupCQ zjxH3KFx}s{D2WG40V2=V0=vjl4Mfgcu86+^F<>AxK=L43kKfbF2&0hR#{>L5diFR+CThG4xg8>oUv(`zL3Vtc?-0c;- z^J~sj=kK+E*2gk0)0w6e=UK1S#&VOYX%hgu5X3jk%yn(f2GS+0q83mQST_?&Uk)6D z=zf0px)nfVqFe~_^QmA>)QVt2$3<8nP+zZp6tjSr|EJ(q z!9I=EzultHTE!B2luVq>uRxb=A8~VE0;2_6=f!VG25rBgz9)qKIJ({PgNQ^kZ28I~ ztjKV3&FA;^4sAIgXbi4Togzl46~&`wss;jy8-RY`X&J9pbM#{xOVhUg3w-ti50eQ( zZe|ONO`yl!70WZS5t{{>GbScZs{A$6_>(xFIE%L{{`-TG&6SW@o34&P`)$y_^>s59 zmjs~f#>rG!fi5*tD(>?BVmU`;T}xRRA!W8H6FmNA@^^|nOHXy+pxc8~MDM@Dj`_RR zs6TCuiw)V|gt+~M`0yzMe~+VX`JQ+Ik#P9c^%AE&fs{~hmSOWE*xeV_K5(KKTmw*DVX|NP!uI}c~~ z14uW`{I>RJ4$*MjSi_B)Cr+#Ss1gmAj&B9L#h1ImeK;Ax#gc9)|N0U8D!0-`H75nm z^z0Z%n_cy{uc&Sk&X{ce9FYwk{s)*zM`TUV{X`U{MbC@md(h9oy5Ela2>LO&FrTaz zL4*gR9eoI=;s|i+dlNl2eJZLehdDJX^P4K0X-l~fI}^$MIi>@((^9HmRx~SIb{jSR zRhGZYdH%eO5#p7~+cFR*5lDBVDkaQwM57B@xT5z*@$}ut3gVV>R`NPme=W z*L0!y044#txU;G;pao+acgz;V{&>pgr*~z|-c$0N33N{L>uUbV_u+%($Br&Fas~ww zT1+5*0&!>pU)bP#Urw{nR$dF^qtsHI+6n8U%afE_iosj*)8CRG+H7A3kN)_;S7VBV zX_csY=BIm>wg!&5wh-_C{&lhUbH`s{XxN|mO^vI|0OscVC(;jQDvesgE0_v>;!jT6 z!v2X(TxaE0%PD^@o#6n2iN}}nG0C1R7B48!(!xoPzO z%zd5C(sP=|Q0DA~XT75ZOK||?!&t4>0tXI>`&Tx4I&%E(nn&N>u*FoZ=)0OTshD1? z36mWWx(oX8p@?ipP;c_FK0ohi0gKz~xjmCK_sm?DfaF1puO1C zt8)PN{{eXXK_7B^+=^MI?=004X;9}N~zs)T9J7eyrUxM&582ccKaugT6vl2x7YKA!ca93@%Q3TLTl)F zXlnx}7a()fYx-I7Ac&#cjP9W+UWC9WV`bvSTUU5&me|ls%E(kN0ss|!TP$^GXK^7q z^?eN0Md#ty)R(T|?Bh9Num(~lRi<{>254u=Ly334L#sLZDDM5uOTx@QLo*{-iTFohYx`ksf%+>=|9$C@_ zHNfmOs6ffknKjl@4PbPGNo(f!QvoUbypZR}KZeo7lh+f6O~Mro#2_re__au?96>7F zVH6Cn8JmklDRkK4`!$ocaSOe^ODdH8D>ex1jSUEzO2)*EgSd-OI4|jO@#c^FWfit} zCL$|gFR3*MSZtJC&`OIOuwVE*g%BVe2P&oYeKAI{8*a+WAR-}ie>?thFS+61O5H$k zQA>FZ!7-@@;Df3+Kw;_){J0+rY1>=$X!z{7t#Jz?T_&3g1aH=W@c0WKtj3Pd@+7jq zrfkQnbkf4C@!4ybwuC%WP@6sd<^B}HlES6SHu-QeNQk}Z8RSFTWUZ9Y zeoV@cQV8{KAbxm!U(}zs@|^jVJbuKRQ|!|(-&K2WDrFa$icBWR71+)-lRm9ksSO*U z&zz<#{=}gzy#_^?reS(ggz50YZ4BGBW+^<;hu7y@b)AaXsGJ1Xhr6}M9JMd^qE)K@ z#AUDq4_k-EB9>{ak0h?l(Mwg8+N}WpgVMIiivHKkClYSgQqHFol&VX7n&qNPP?iHb zcdqmaA#>$<%vFSTFh8uC~~3Fl}Dq)qLl6Xm@a}E5hYDS?@EBNW|ldiM@+JcIdqah8 z`tOB(3c}RPExS>0JHOlGvR8H2nM*cwUfo*d9Dk38X0%?( z728jKIW_Gg)boKhDPU~g05Ai(9e>F?$*3psP8Dd>@PCvt5H9Q0AJ#C1?MK|YDuWgl zctHEL#Bo0Q$%RgZv43ue(AkX`FS&6CewMgJsG?#O8cuU00t*Gy%2seCx00KWDL0HN z+-yi=r`^~CFioPOTJABtp5eNw`bGz3b%NhDDd0>wdwVj^{xXvx%H9@pYcdW-_jUTW zfuXyqI@af#Aagv-z^DPiK6`3E-+6I&Xdb(4v!!3pdc^WDK6 z>j*}&mPf5Zuk+_onmHWyExQ)ALTItZBta^;NJO|6DB8TP?q`kz&`YCyQNy1_K)b(r z__=eaKy5dF2|=DqBJRLLu4BEb_E3^KwdM4S@yE&QMAl$lO~)>(*dfcP_mHh%&X){F z^CaKPMkSrvzl8GP9B3V0^Tj)vNc5Pxz1W)%&ol6dDA-11|{^?eW z2w3;D{2OFYwlR=$c`!8gcO9o+kVk3zgU*8UD=RCmx3m8NB%2{QmJ-_S!^fA2X}lIT zF0Mav0yo86-^28_(k=_8^;BmB8VftlIf$)!~k z_X$|CIp&*I6u7hw_x3MJBgYHT@SuzOcnw)^GK{A|_j zm9X{O>iO>i)^EQ%KDP4L z9O$h<)tw^b?%r32pP$!^c=NuZtIe-$U8(hVWH*ylG^Kf2*Y$TE_za%`vD(tISYBe5Zy;6yPw683sxBFj3rX)u-wsug&* z%TXZ-`e!vW`-vOv>x*CgbLo$6qw5YY`HPD#@bUXIIGoeEcw@}G<;VVbwuAtR)}FfW zIolRMGfk(eRl=rOb7q&@g&OPuHnsPSLi|*q+H^;7Tx{0E#&|kH_%^rlQw|-cn>pk8 z-S^g4WbvXA!mlf%-vYu*vRqATprFK&tnU#P1%|NjGN4#mOT^?>@M~0xt>yJ3}g6G_Y%NBhl{ z5`e@_=h z$mK)y?wEorns)J1=eu8?eryUlw#>0Qm$omk5s+mbC(oqMD|OYArWrCv0lWZl-lfy} z7uN}r{uY|-eo;lUBA@PT%ey4`(*r;v%%Xwel~6^fZU-LMhS*kNTlXGwcIg~yQWx0i z*SaCzE4axAj02I|8&9?0X@5juklT_J?)Pviokb+Mfa0hw*EV1u0c0IUbruF33Y6)T zVD_mD-T)W;w@}5VkH*hh(ZB_MCJJrc0cx5ns7{uot?!R9c6I@7eZQ}1uL8+;Z7pa) z+%cF#-h^2qrB!Y4qd6pSN7`;cGTG>TIM~M8#$tvQ)krtZD@1pY3k@!5zl>o94J@+LUi>JLGAl~5M zW;~>#v&~mXzeyXr-7wFO`ZhejS$^n}p8xaW>@@II3$Ib)#*X@MgD-1XS;jE+q6$6$ zsi7kJ2Uca?5}NWoy}#3!%KoMXi(+_QMJrbsHmsjzVqm7B&sl?P>Fd#>_Zj5CrjDvJ zJ#=~@98r<7f6Vf={gZKOob@6#O$7`sHy}Y5@_jP+U;rEq{qR-+RxV17K|j_>C+GIA z_&~!t^IS&*e<@zmQY!X<3dp#A?f`doa$!*xJCuEZO#s$I7%r5yIrrLC#J{%N%DcwR zYy(4vjRsAw3-OgjDMU*LwgYfJCnUtaqyo5!Teg=EyHq)$)g=zuX_O8cuu|SnKiIi5 zDfLq_-^^!WH*;_D!?Iq&7dk}B#!cv<>8*6v^zjZz z96*Ot`6cNUrpKsv;8~_^h1anNrvc}^0ynp$Pg-H&KCcE+A91XkCR|Ge)yOvWTOD4pvJW?6@O=W^6ou7BIeu!N|ElZoDs)&#Ry_U*uA1&oo89n3u}9{q1S{28XJ_5G|2t_C*jaDv%OGXwK?Mtqv+`~Cz`?gN(r-Y%Z zu7$u{R15%CsfK7O7M+AaX(jMC+*)SX5-h?+7MbK@)%9S?RiRt)$_w1=VGV?1R-I}X z5?<44i5e%Sad@{)juT6#>8J$P;phfnSMzgxwtDOr*B`7HC7H=Ya0fSPPtz#SX=H3Q zrO%qA{{hm((x}xi(f5?sdo%ra?J*lk_>9QGaTUYl}yR6M2$m8h8 z>r+CB54E#_*G}@|wD>9L^7v@!V_R6R_-3z};s7=@&3Pd2iR5&vMisR=xb(NLgmM5| zcb|VhY$u4hzAzLNe!g}b5@87ni{WBpyguEdNE69>OJ@3+Z@mW1mJxbk@$7e>#C18B z!^F?$s=SXi^fznlp1u-AC|2UB&ic~L$F^lRGJLkg!l(RNqLi#__Sz3YX6{>g#hO-k z>ysb67R3sTR-}GCCkatwb5X(zDL6g-@=Qs&kaBt|h#bpj{r6RLTAuMwfO{yNyk-43 zK9ZaG9I{pRAAmz%b{GgkQq+z$d@wzAGYe#{4f+Y71-@45D}Ol@uEua$_wkac(|mv& zA3*fUkbU#UCfJlk_E+El+TKDzZ*f*G`|s^DzYYDhXIRCbH(zMdTi(u$)ZNs zN*9+SH7l)AdML_l|DNzM3~+9aTm=+_rxQ44$E3|en&wg|tX<2G+2Jj(<1W8he`HLkQ zbZHM(%2@T{^#c~c#HkM*Tpy<4>L$Pq#I0$ZuEaiDkH+z}@1g#JrvC9ff&K{MzQbCS z0ALJY82ZA8lW^#C$mp3g$X<)pm-H3lEfW*c7w;KU?0GuP?8W?Xx;sbp^5{GUdquYH zY_>J2>)W?8#~)6 z<-&+slBK8&j{OnLaMAg_-*?J!#EcnB=;(=awwN3L`&4w8Vp`3IiJDqnS3P7{pG?xp zPOEP~C#+c$DFk}{cpySKGX>pTlM#&Ca@<-Y=T;v$l^{rWMosF)iWoj<}@fc?mKUMo>5L64j2s zbXz5!Q-tabcpHOT_zj(|S<3WHoaziRUsdS305G-LyCkkqR46|$(b+!lk;UD0I0zUz zn)*ZP%4xpttXrH#F)N9+Fj$lnFKLMZ!jNQT%$8=sdg1x}=+syTGQV6ulSXSzx~Kl< zsyQhafMJ8Jj;~KSjN*=MTe>~L2x9h&iqz#&M`5n2)2@VLZG6Ptz9v^$`GxlsK44LB z&q)&S?dgb9)q0}_7=a-Wwq2U_D_8O}X9>bguRQKj@Rdx-6FB2RJYue6Rcc-#fN)L zCLhGwP#frRbKZ(JC4U8gZL*}auxK1~DK}2On9x1)V|*e+7XaVfPv0W1BwDPFa5tVL z*Fxsqss;$z5rlEgAWF!7|NFk&-E?cx2K4#8q}9~nwuUH*+?c9btaXW@Dr>yWC#{iQ zhl-C^{W}){cJIDqLjypWAwxpuwioS`s^-v-Ovx_-uf*Y-#-7j!3D3TV=(Mwr6dgKH z68tEMtC>S9v+dM6DYWBpD z@)nz%SfL};kp2SLfqDB~>O_jk}iY(=Ln)ZL_Ip_!DNgf~0yUl3)_n#~o zb-PTWBwlmF-I-0t-+`B>D>;N1a#od(+q^gP%aZRzn=|JPCN?Rwj8ws$n z8do3h-&x-*4kzyneU8y4G3nS)AONoCJ@WEykwt$RRLMWcjApw}O5(V5gK*eBO=D{d z1}`s4^G8pgqp|3P*ON*$ctF-l+mUm;f)|CiRue{slLE8hVs~y+wK&FJZ2S9U!C^Pr#cj|TVsi}rH^L@?mVZ@32Zg%+#j#+A)04&53vQ$ z3V2*IhVpLi-yKaArK$J%9i4h3>2b{*9U)S0AaE2cOSZ{++2_A9Np z`k&zKt6k2k`H}13g*E(YZ72B1E2@c;8Tj$$H`(vysW%e8KU?NsNLpF;l0!7SA3m9C zHYLe%p}%D*dV{4PC%+Lyj|#xe8yY-0LvpA9^bq#eySAIFm_hQL9^XH*lprs4tcBKs znfa^3AI|Ep`OupRE#BQk#73aDQ>Ccyu(0c9t!R|3 zpRAW@IS29W;*-)G>Q+f&5#~(qcIEeuxf~) zdv`&JtC)l89gTwH?}=y&kQImO^x@Q%2f~V;{@grlHfp3=%3Q0V9N$u9^u*CaVA5p8 zg=wmYWW$;}MU7DxXE4yU(kYcWUozU_b*g6EL{^H{HFY)IG1aZkcnmS{eW`_6S{9mw z);pJfar(lyUtpB`*FQgh(deEQkydcbq@`ROv6ZSN?NYoCSkh^jgr+MH(#2)S$2iZ; zaa9Qs#J+BJr9qf(wFMo-bof6xRXBmP!8o^s=#t~yu^4knHprKyF` zhD0&ttT|d;IrCL@vWJceI7u8SleuiJ^yVSRN)L4$h*$TUn)l>yJgO94X%GLV&fZ_1 zmRz>442IsfvD@^#(CpO+A7b}&}vV#H(79TbS*wHz9#pIH1k6ONw}byhn` zEDo@mS(-v0$=GZW_aqzNTb;;~d37Pbb~MWM2u14i4lG@COk>M&<+gVb}fjufKyH zkf5zX29nleZ>J+1^@vT8%xR3C>$ocl?#S0U(I48p_YS7c@CEFO_Hn!1k9QT4i5h7C z1W#Q?0Z4%5??#OQe^;0e)mol?gP_O{PCx6&dLCSJz|ZPBefz`@&coZ;FvL@2B;U^g zp7sbRi_S^6$c}>g8=dA~Nz5ZVGr<>@FG8_dghF2YJ*FnFk=jaS#OnJUipMJv-u)oC zUiT+iDIB^qw3OUI>UJD-ahmg_quVWceL15%#=670b`yMq{mGKy`8W$D){2`uN%zqG zrO(G>K@2G?^?{l8aa+p=xu_0#Rk=$twn;uh1=hCfli3Ef?om03&!1z6@@yn{qIvht zLuKEsQO7KAJ#NzCa|1}bx<&E-cahkpX&c>mB~NBLl)Opg$N%fFUy`tT<-Y(8~8Na4Fy{bk5e$Ho98PbN4kP}?NEH}69|uFm<;vL>4gHIfF# zmao5xT1f*Y^Dmn@sL}f91DZ3xmJlMj=}#{SO$Ddff&b16Q@tN5aiD6_0jU(NS#jLP z0WWlBkNvJ(jSw0gsYc_bgk!x`)}{vu$z&6p!XEUjPUmxuOAQKCJO-=ic%^>b7ia+3 zuN0iEY6!+|r{JNkflG^OP&(jYnn$w1j1e9VrC<|M1sPP6N$yCq62cH>Q<}R=0Op5+ zPN1NNNzusEsqS9O&&~azzJS}}4Uo6rAwfkMQrK8_b3z!V8ii=+9?f_wL3-g!I74Pf z$gXtmPxQ@=Lotri=LCUvrrJWkpZklM@Z$7Zd|)U@RA_WNe`RsKRb%Am@}j+RQ;P9+ ztK|IK>&0Adaq~v;PgMpmC{R6f%rrN#5{A%^s%R%I{73*K%JBM(<*ohf(umB< zEiftGdr~6C%M?^)ilfSzU^rG-f&g>yTL@EjTvHB~Y2?QF%)t)%@CkL64we>m9e#4w z852>_kEdpmz=%*eJ_61Uix12nCN^|Ob1g*9D8A(K2ztekjn@v!7T6jz(XbhE4#$gB zT;_U&(nQD^lDudgjNIe)JE<84Dvnw zUB3JbR?FAFT`AfTT~f6eV?cfI=hvUprSLW7Pb#Y(Gs|ak>jSTIrCl*BtF<^v7|aF# zs-mS5U7t=Pu#DAQLKgjv^z0`FA7XAqAGp1aR5y&2&Q*|lM|YB6^*~_wyDiFpYsd!^rgM0Kl5}E&u|f+{vS5Ta|rnX)RXBkmUW{ndJ45f-}+91CNtUn;{-aZ5@uRN(>~C}4N>b(2XS*A@h-%vPX-4-Iz|?j4WN#K}l@ z7;%{%c|Te3bYxJXMFz0e75fPrVQ{|e(RP4tz_}*dr`Y99zml0@ulm5%Y9D{j4Gfe^{~_KRF3Q5ATdbw5&RfdPHEzxa1A*vdXAk1sOdm!qN96XR zxBr$&BP};qBxCwc{v}^KaBAzG+^^RG48E;`A?5cRcRzN)vj0F2o zh(gQq_+O(QR0&G6bcNj&+f8A|>^qOz7OPKj|DFYWo||!AZwwL$^>?)CF|ep^6(Xrt zxBvNGdSiBN<lO*CwFO4>twJ{SFVJBe z6xL;6RRdXdiI&Rmt)L0+ITzB3hsOHrkh2&6YAh$@Cf$aEvw{SlNwjXcM;gNSM2#H< z3$EQ(r<6NRgB|8l*2*WVe`QY#7j2_7do=A$ zvc)^O@=!g=snoFTZq^}R!F$ne1p8RQ$DNfgyeJwdYk)FNN`jYyE+aI?L(l5xuD;vFJOV%6;b{^b3t$)~6?Yg}rxECjFuZ>z=dFOO8 zTN>k3Lkuvgx2*Jk^;V=MKc!23jmZHvHEJvFNG_Quhv&3h2}#Q$mvwh_Kzh?K0ecpi zJ9^~m^2CQ;&3QT$w9Gu;y+5&}zB%9_DatX7oSXM9qvO)m`FF&nk!EN7R&j*E)v?l| zj+3pFT7O%e%GqA+%(e7>{n-fno@i6G%h5z0+xrgRQuIBRib7a_A!@?ZFp9jeC9Q&@ zak=2CIdP{5REsm{YmR&8HgmvI^dK2ra=A%A{A|>sv^3yGSQybXbK?<`*+G1(cAjxA z%8<U*4_iXqT-u_?x2B+TyJ(qC-c{Fg_h>PKqS%rr+eprv1mb z3-;B?YFfZVpmN9sF18j+l59mN!pC#ry^DI5<{kE24w)DYw)|L922Bx_7~tc;bXi4i zq?w)=8WHXO*-rDXX}e1SU~4NrFrGKynDni$>fc5;dj!Gjt(G8I zI%d+D2OfOUrGf z5l2Z=S-E{^3fDMqVX-u&19ATcN>mY#gOI;-zbXT|s(`h8;F(v#$q{J4tY4XT99KyM zrE^h*k*Dj4bT<*c3Un=mVDCCnG`{IOy7bVUUDqS^deC!*`>K5(G2}~Dxb|mp)x(4~ zn{Hz)0Q}AW1K{Zx4DM_Krx>h9?=_v>lHPiOKCf!nAw`< zodh{EeJ-fW7lMmUl5-|mg~Tt=C*yrgYR=9!A4CYexlIa5UkjTS|H<~5Ep^itpCRcv z?uPG@XxG)&@|Vlx(hA`v1QDm;^4Qka`KTuHCZPiqi}j~F`rn`G zjEcNul(~RT-k!L#fo+fdpUR^aS1{dMzjW7n^qx|&c=b2Z!h<$FJo?|=#-6ro0nu2e z6$$ykkkH3^CLR~-322+%rtnMSw<>j?H~4|%Qm+^ZXxTR88Ify0%ATCj_pTj^x0IEI1dNkOzBlWO0InEV?82ma3wX3_on3h=|e)e6P!d8#EwN_vMN`H-mVJJO*C zMO-*eR!kX-kxa|S%_L$Nr3i`%&xoq6vu%`9z=N_KF*XaK-St;IoJW=#%qts*jb3Vx_N}yv>X74vZE2Ez*?d0X=8STO<8*k)Zjrs=OVlgk z-Mv4%d%shihL_*=WOuM_?M>zR!PJRGUfSa1{rli7jLXAD=W>$5`Q@WR@+w5JFe`tt zFiL#)V%c4$59a9dugsm4|lZl-{BNYS%o9SCgbq4n>>mfW=sJM^d2HIufU)D6(cJt zm&F`-DZ{dq&jDB&T3wRs2Ro8%90t3{tF%ac1MO<_;)ck$)FXZ$gho?kf`se>SH-OY zxViHUm9B2#*MZ}dWK7J32yPq`2rM2J1kJF94bnLB^9Ms3eYJ#VaZGvoTaF3;gB*(cN){w|DTT2tJV$c)7;m~l=;!9@Y zTxH<<%4hE*kg`Hy7u>h=s9 zRzD0q^n2kMazq^TxrmD0C+NfQnv*GnrM(OS0A6zR0Mz zlx4O3F?cfVf=G@}0}xoqtoj<$cBH4Saq38arE4qW=AJD^h9fZ{gg79IU3BfK?wwiT zV_&Y=klgZL#Zzq9EyuKfgS=M5B4*L&cK_SJ!2xW8F*`3NiKAbEAE9(|?>z4dOovB6 zQl9noj7s=;#%y&;9}Ap5(Vx8`tux<{piqPV0I8YBh0$qbU2z}-64Z?~UO7gHD4=h9 z{5mhX_nCv=s=ONqzx&FQq6;=Z_GM4wrXoj{LQRcJAqwI6yeb8O)$84Jt8stn4c$JQ z6Ke>NZ+-3FIv~}IMF*jem`9)Az&JF`&!6XKdnskVM3h3IjN`ednIdNGEj2{RZ9q~x zvw`;}3iVsoS7qhmI#ntYRqPRcPONU(X~_^AC>EqT_FJ}=jlAK8LP|Nt>(<2Ii>^7k zD58P3fSz=EoTS*l!;MV$Or~+{{(*+R+Iit#*%Wv-49e=NRw=}wag$G z0aHT8J48hefj@q>6ef5KH}_2HlK?oAQ@d*;6!tq=?oMCASBD9fsa73yv*^SFc;P5awnDAGX zZMlIeP+F{%A7cVWwy9qRDu2mdq@iGJ!xFPyhd&qy%bhI84Pcjp+bhX`_k1HTCnm?XBge99k8KyI$-%nHX5XQ1 z-pF69V}gC-FC6Zq-i|ZZF!@3j7PJis=a3}#lb0U(TcdyCLB$4{Ia&y!n`)^B&(^6w z*S-FgI9V!p!+I~To%k+?{z3lNfs=~}VO8Cr1(3toYRewjx`fjIe|)`VP@B=$?j0bw zYjJA=1eZdgxD%WZDDE!BiWMmYC|ZgHcZvmfDQ+!Ji)--~m$o>xC;#U>&zy5+-g!Ul zNoF$nw(foJy{>irE~!hRje+dQcf>Xp;$LWkWU4leoAL525>&FgMRD>A_4$*nUstAc zjG3ir<^nKZmzFwb`b3ezQgSwlf}qLHm}qoz;DP579qC(1>wWw}=RtT6t(P_{Pm@hO+HRMffdK#HQ$ zeum(>9bpIN?(NB$jGixq2>;3YU#;7J0M!PTuYGn!db%(8bECq>W2JV&@8?8HuVUSb)R*$Q zm^bqCsSLQSv%}IfPLuxu(&ShJsIeJ-;qFm#yC6#`M&&%|ck5X#zwAp4%vfvGRb=p+ z8$3gFrcGz13ICR)Mn;hbIlHgwMxdNOf~lwWjOHEZ&?Sqsi2o#buNxt1pMkP-)tYW_&s%UTe#`KB~LTz8Ir%m><6@S9D2)yRTap|7x*MiIfI5W~URv*>%x?c^1W9AQJwXe|?J186*K*5*$t z@*M=WXG3vF6&1FKEMahE0KaVTiuX(Fk{vPQB*4bB_0!B0*9qIN`rK+{`?k&}i5E>r{# zJcL7KI(cI0n!}M3&z2$^*yS_3(oiXp<2o*zFJ8%}>gm=(l)@t)$N7kssgcwp6)1EE zS!r3{$#IU7S51Auuth^XvOiU%N+7vJ2QMp4ZY=Zo6%0)SjGAt z^qxuTSLK`HWMQS*{Cq!UZ16z%@!VFbn1w;)4>f&=+~L0T6lN;7MA1J0yqTq9+Xlle zo&pr^B}B(dZGy4E=gc>f3{rxUke4&;>yW-2S?Y{_WiIn^xOmOhi96W<;sZ7+wpRb< z3*-g!KqllolM2VI?u>&^R25ZLUh<3nBsqaW13O3rS&dx5FIUIoMw~huBTQrU{^wo&F{{3 zTqf?%2B8>hqP#J9cC#cBdJ;CR9>l#8CsCz~L0MYq){Lnf3&3%85c!nZm#4ihAy58f z;$DVLO)C8CzOH!sZPjc!hjmF+afP}WxGWOl!ZMJA`4#`P)j1Yd@C*lJ>#!B@Ub<{% zlK25O!%;rzjfNJIY+aJ7VW!$Fax(}unK^w?>1`iApe+Nl{W8?Dw+HjEJDs+gY7sbC zm-F$`hjgPyNBb2%N2IOyuRXyY>}+p(h5zFoPq+Ts^Q1fc;lq?j@62Omcui@lA^mL% zS+N`|nVc@kZW0Cmq!m!A4uB4UKvg<9KH-6Y}EQ~PvZv*pxtBsL-J^9_i&!gTY5!W(&3}Nso z7iaer2v7muI0J}i75XU^KNYC9)x8$KbG);_lYVoK;Mi+_kt5Om)!Rd|2hXpD;?@ zrSTG7VzBg}GDnH%)YUPgPfOpekK=-t@W00KQXoOVk@WZ)j9EEIOkHA^|x{gabfjO6`r|wKc4{sh}mr5AX1xqv*$m(ex8#3Cqe)%PX1>p zcl$nU;d#FKK$^fyrp&BB+*S9xA%KeX{fTS%_S#f_@HQHt04lxo+N%~XBs2Lk^!s{n z6Tty?RiH{Z#5With*gg>L%_l;=W1RoR2$8G;R=Gcbbqj5A)~L=fg}0qnZV z4yz(8%=ikyc{Kx1&dv+`{HtsaN^ef6Fe>n1eB}@{I0KoR7IUjIt2KO0B8MWF9vw;d zAXgwGP9Qg?3b&%8JSd|kD#dX^7J1oZ6&r(2kjW$Iky#r05Qz+S7s^6IWvX99g#~CSY?``*;PVenoCbizYCe)w~@ za8O+r-%p+Fg%E2k*Pkmo6@J#gaz# zup}Y4icD5M5cZD$i6vk>slV;0UrhgQ7zH7kEbra*J^wX>SA<}MtxXn8{oR`QYr_Ck zf;@3w|3vxoNQWY66aQCeg8S^I3_~&oDD`U_nuR+!fK$>Neem`*u2@MJZM^Yc`kO$- zFzcfo>tBe9)U0XwHOZJM-qv_`@7;wLbIU=%g0@`Aa>>Gl6d zNDx}F{6E1#EYst;_?n~9yjl7jIiWy^$?>M(bD9^@xAGK%yR0FP-U+!~%(XTO<$kYG zL6zQvk*8&9ti-tJ@xoUV+e%-zycOpbwNOS9o!qbYplYNUf`lDS%|q#IS>v4i!2+ks z(cEesY|Z}Pc{NHZE7ag|f#dRgEBG!H*9$gbDytP(lldZ8WW{K;e@O5)u$L?cJ@jRx zL4^zpQWhf6#TDlm&c)=`90F$*F1gl}cnCPszJ>Dc=O<+;e_UKN>vK zAL)05uo>v@!k+TmpyGkivzisXygL@j>~>aEsK?#I>}AB5I*yV9$sU;9xWnu3FDt-` zV7#s|j~;iXdzMmK(5+}s(un1U^d6rx+ zBIbilx;e2gwTLRSP+H5v3%Y<8;c4+?bOmbV$a?m(I-LY@_Fb~=#oKy+2GYQNIgFj1 zGi5S>rGCeAj?=#af1+XuBv@WPO6hQEMy;lzPbwr{T-jLnAL?)y$Ui)Ff1}jT>T_fH zdGWG?zXqrW)<`dGrien|!GbD*P6|=|3}m+AxqhYIsX8%ZDo?@3oF;FK0K%I1o{Hj4 z8T?gfLIOixNT5OzAtqB-kER%c_s=IH?)DxQIM6}AD z45PEJ8V4hcmn3`zuOULLwd2X0U`Y0KZ{lL?Q%PYzVl!|m#K>NKTnmP84$;P2Wv#2>s=vXdD6)k5?Y(LLBo8 z0scRw`rl=Xr*h&|_O)JKo)WdS(1zZ2Y# zQ5OEBSv-aIly9#7xx2YETrF6@V+~Id>3JtSo}cV`mY}LI2QuK-Y{h zD3CEsmLP#=#9IE^`y9x8o01&OMu;X>0NL?a5lDF;O=l9V^kY!Rz5sf7F{OOK^-wn} zrrfN9d#1P~&c(|ybiogvwD`JXmpK1VB`<%P;@M5~ciP+;&t-cTs~t#1E>Z*fwOwi5 zJTXZ*LfxPxw*Jx0_Nmr88|s(I8ZT_{yXHBYkYQ6tIf7*-Fs$5RdA?5Ni@2GY5+YgR zvW#bh^9IspKY#L3zV+eCTQRBSHIB4(TwFAGheBnEvVPKq&&=9LHqKCl87158o8Z+l z$|NdR2|?Jb^Yat9%bXj)>`pGPlO}YWYRtraG40KPX`<95-n6mvsgec`M7v{Z6q!kG zV?Y{KSK0!LZVw>k`<_ehP&Q*2fy1E50{^3_Ggv_{W9T@v1la7|W(8 z+#DowbMo*|#HOycy7`u`4G}^A>x%p$GD#jtRpQ>!`~UksbGh9n>%crEB{*1G^GIqzZZ@W&b{s2t61fkw zHa>#tl+UdHbSJ}*dJ?X%pOHU6FUG1HX{$@0cBzM9e4LWW3n4K0Gj);^_T{RLY56g= z0R0`oYiRPoly10-h`UA7kBBaqoANA+Y=J-)2ALFmbodKWkP;ZaI2S-bWb_sG> zD2s-mYj*-nfREt(`AzYn>2FK;=3bf3PeI0Lk-N07TDhf>bZ#x;tR40ay1YS!i3j|5 z5b!sw`#fqS5P#rxz&fl)7_pkl|TneFb_hw#!1o%*q0FCA5`O?%RDt-?f zZX23DslNIa$Q(Mf7Ic%k>bOFAf^n6%9cyNOa=$XocyGK-=aS1+Dc(e1Ib>(O5d?41 zNsHJDOpe;3D6cg8D5mm6S%cdqDPdm%w$v$c7k;mA>AE%T7Gz&9xJsNx`(PU+CYC7T zvJGkJpBmg+Z@%)w#gFn;8OMR_&~T;pc(&|#?zjFddrY>(hr7K`Zr0{IeitHcU17a+ z>n1%lXmcT2DcZo1YN`>s`LdjC@Tl#C^RcnliDe~Z`11RRI7Rlyr7z1oM4t^LiLQbo zbn-Z3ZvLi{W+zAQYAT;i4l zY4WNNidk-$ZZVk%pTcg9rU-@q^)s80G*5dL+|AfJR625px-nJw;|n=BvPL46O{^jP zxbfOF!;1ZyV*9|@6fz1lEvq{_`pvoDYa7I{oY?0kCEy?lZWLT)v9nrv?qt29rK#*M z`o1du^R|V#CByrg_E}5nSd?Ll!UE!Pp`qsYkGYl1$ENsDS!Wv;n+9rL#$!~Ye~$Wl z*~wC9=}=1oz(e9p)_BV6rC+$|Hq7b|zaHfB|MP3?!?iNR958JN-y_`p*M3pK{OrWEALLtTX#co66Fpvh*LA(Sd>Z#Vy zk7-m6e@ePZ*&JL`6XjisK*hs{fnbOl3A~hy0?@%q*c`&RN$PNP#ng`sFfb|o_(429 zu7GA+f+r~`m_7TG!h2>KM+XT`Xxc`8B%nyldO~h2x!K+2jJLeWv({twD*cfjFiPdr z=6@hQ7KRyO$dpK?DSBC;f{f7RbD&PJ&5Ns+bsE6wDUsU<={CSg%{i1P&vB0agy;Oe ziVBq->qug5lq04BpM;V~DwVL7lt8SLGX&N2u~YC~gA%x@l;?aX_*Kxk4X>IcRJ%TU zPNGLM+XlXtI+KP-2dJP~H)4Ja_M7`#g3T*quU9}}7!|*8E>)9&-Mbne!omOyGCb6# zbmo^w;vHw8wG{ew+U3z28fJ&xH1-(q;K|wLMU3HV=C|Tz2QNN^T%G?szm`*1<3B!r zeB=7-eZTX(FT%L%Z-Hg764Oa{_q}pVlx4y?&X!c2X+yj;GVM) zRa(+`^1WZCjU~FKD%L@r>3>8Yl`6{RJuUwBinrR|d|*K;*;5w!Odl$uHD<=yYX4;# zSNv*t3!;Y6EVZWx4d35!Iu>X0G|}^F+K^j!cgMeWW#l)8x4H_gEG%ZkEPo8>^TIAE zGuAgF`KbC<<;3rOos;#jp+p}(vx({&AEP&+esrbDrc`(O&e^ZD@B2rJxOxq9m6JQ2 zG~Ut|8KMbEg(?OlZf7CJ@2mS5Boc#EVMM*d^;Xwjp>{&OmXd=!7s*gi30GR>h~mC+ z57UeF6Gnq2g}a(t2C_{$Kj0As2nK?|*y9Tc337W-6>lM)vL2jQz#%B;=tZD`j`vWBvC66q=U(g9YW3a#^rdIk&NL1 z<8ZCTF5VQK2#+(F_vmgswZWBw7G3kF`m}09xh_)a4`A%c2_>Hr5}72N!!7Z|(J%0e zyLrL8nKF*7P}Qqeap?=zjro=Z1W{}Q*gZ&x@=!1{?o(@OTcE@MJsRg$ie~6x zZVOmLPe0n*JQm<&-u&bB%-6Xnn#C_VEDF5Z*qTM{-!`;AiGO?Wn50NqTQ$5q(r3;o z!!r8H3kYB1l^(Bxf>M0AY+rryjU6HSq7hnv6os(G9u5w-T)W>XZXcGtzBror&$%0a zae3>@mR$nV-SgT8`aYrwSt*eh?XpM=tf-XJJsf4Mil@`dbOQfkgB_KK+N_ z$QEa6dO!brcNZ&|V$I?bSQ#I#R|5b+NM=UvkkI?*M03=}++Btx21HaiuLq@^iT2Yne_;n-O3ipS zFS7DgIUJPace=jbV-nu#XO(WTjx?pJeh13-(oA`q?JPG%6};a+{P4e&tpl z9}fV!8xkG?9&sRc|5BG>)N2s^@*Aph|IiMjcuWM^GvF@xzhaSi0O{P*S9hl48$<{W4tQrfGZ6D+n{TVg8%uG9 z0?VEyvP6)fLCm!SkngZ}LIL{mT)Fll0~}+tKXr21-McPUpi7*)etq&Tin{qSp2x4wkO81r33~O=hAYjsYym zV&$C!!>#J`tE~R`?e9!E9PjZgc%lW)mb}$4eA1D7IcjOi>-Q7Y69g#{GG&Ip!ZluA(!D4c-tkkBK^U$CNKGI_OujAwU8|uS^QQI6PlDU^%SEh5PJTZ zygeE$CwaPIbfrTd^t8XdwPah^akBqHnT;#wC5KtZ+-0CTEXn|u%3JB8w@zt4nO@4t zm1&U1H{3vKm20iplKtYC`I8a%@fUYJ9Z@JtWDTXAA8f81(6yZe^{wX+8q8q_sY(52 z;V0zs(bS6BnOeSicy0E+|7*lgLI$n3O`%c)rIqfEr1KDb-cs0PX`OC6?)7V*@`(oB z(9MNwATi7>JKLZVjcb{kO)~Z_A2UP6Jhh39RZn$opbt=PYez`_%m4?Xk)0Cbco>6c zfBuH*4ps26$&nG)RmDGHkO0OcI!_os1Ycf%cx@=g@`_CIXI#{{o}*r!kF?NHCwlZv{mk46GE%EUx3Im%6om;r#JU+2tafYWQYZ zCswG&FmDIb@1{p&KC$3>la4u z67n4JON*3QTp8x(gO@FooY>z`t{=5#s3K9K6qV<@{!KuQlB)D5TqFf`@~`$er!{`| zTkb{Z-D)bP#uz|9SNz-^$QGrah4Tnn_ z3Lln4p#2NYH`%REL=CKYd^Upb=!ta%E56fAnS~q)VNYcv$@bA3!(OfLiU)A02;kaZ6SE%ubP=s+p)iGmb15$aEA<}cH)NW^_M))+H0B1V0Fp~57 ztd4DWF+nAv0q=-V8Va`nuk*Gy$Xd*+up*96ac0%puXL^(^;BcIMv-LH{H=L!e}{!B z=tJ}kOYy-zATS;@(Kr5FfZEgd^;j2kz6Y5#zC;Ne1{UGjEmcma%vK70m`u^&_m%2M zF-*K42gCOE=L}F4xxnMbxlOJo^2#m5p6(Uyb>lPnQw?JiuW;=Xe4STH| zZqICrtkTX|GJ7t5YyO5L)WV^Jh8$m&=3nQet;`Xh=GFJ<60JvQft*Bdod0Q$uW_#< z{$~ zdU9KB+j~~`+4TxT{Np-?hdMq(CoZ^)F#rGn87@)d48J%S{f47X{=XW!R4!`%KhAbq zGLOou8s6WzUOW^BBorRzUDCf{VvP->IA$thHvml6&xifI`HIRc?WyeBw=?_xbzE7Prb8b{Pre0US zfHww>nRDU8en{r{;}LkDwupt%kjHok(6X}1E=~9KU5^2c zYZK@yJ87>aX0s_H4}M8?iI35*@C)UbqW>N3!oGOU-@dP_uBHnjn^2B%VBe|09gZx-03kMwzW@h3# z?R?gD39MJ4JC{xqKl@y$5OxN771!w~JAMlrOLlo~d^LKq@Y3OJ#mH}ypl>$b)OllI z9bL^Yo_PB9HYV%eBeAM#i_t*_D&|Ja>=^J4Xg)Gby`)NX#1p^^l?3drW(L1r3H*ge zxjUH>sFhwqxm!qbp5!eYN6Xrq{tuw`e<_0)3+M6_OqnfrzCZ5-8Y15e3dSz z^J{0^X20wC(=T~rS@8mOG4DHha^aNZ!0|KR+P;^x*^Bt%@9bzaHr6!CYHkK?ynv z9E}i0FXnD3a&-BUlVu1v?0LNnUz{TB2~WK5wM0Hk!}aoO)${l;+I&OK4h6+^0zgjZx9z^Dk|Ij;ys5Zhw8Ph(J(3t&U4nJMnEGzZKqm7y04Z~eW^ z_-1H7odTV2+W!Gcy~O?j_U;D9{{d_`SY#E1ssUpD9rQO}fE8aY4yFSa>3;M$`h_L0 z5O?7I10=XhI^VZ89#Y>haXig-fgz`jn{ORI6;FQ0#}(weX<4J#ekP@gUp;83bnDpY zO)kNYa$(ZIOszp;G&nvHJI`mW9#q#={qAfENflM%HgUssC9GS1<%TqSat_vUKJ;TX)jgeM9o<4H>f@1YR*; z;SYac&_95*)K-aTu|lFH%ihs$7FG2YcZbG3AR6QM;9_I)C);k{M z=Aneh?_^Y0-P_mlVwVKmNKev_i)pG5+vpo_7#+Tl` zJW z6_L7N7e^MiXnQ41Np4;qx56A1%k!=2Op`IYoZmo3-ovr%==-7D*;qpx4oyAnSAmvX z=lC%&im8<&cb)O|-{dmV0b{)TwF8h*Eq+E9MxiWtp?SDHkZNM=RD_UONj$Ep;nQ-u zs=YQc6{(hvtY;;p##D|l&IRajeFjDggfN)8-YVI3c$KYnZ_vbqZ*07M+Yg%XJl|sa z2N3kt$r7`hr=G~{h~qyriF-euXC5u@-W>BKUa3#Koy6BuBGV8{4yc~+#avZf4`3GG zfjjl(hsxJqsc8j4sqOwpqzD4m%p4_q)UEf<8dXSvrD;I0bvP*9Myfe>6OnU~-`UbT z%1T84WKsOTWTyYwLdc-;M*vT`$8KK1Ud-sdwMEo{(2vW~uNH$m!3stwIl(uC*aS>BX^ zAfrTv5#AIm-b2eE9DZ^2%DDMx?F@MMcZxNRP(yETuJ>5&o@NXxR0#T2*$m6~Q>mFmqClVgGunw471~)l-_|BfyR^QP*h?KYs_fvk;>* z8u$T*H9#OWDbdB0j!Mo$2FEY+EbqiF7h!X z=i|vlKiv2{dVGagh8svS?S`$JvVJ-{Yib-zXNlK;yyM^{wUxomeAX{wy;BTCm6Fq> zKZE;ZW6PDQX|h0*1}aaV+l_OiXPPQ=Md=t^tEsUs%q7u%O}vb-Z3}4H(?~tV{O-3P z3_FiI2%a(nXt+sf_iB6$OD9Zz@F}H1Tw$Y}F!k5~h%q*7>)EDXi_eim+Z%IsU>2LAt)3`1 zEc_{4;{olX7orVI&eYSJg{@Id!YB>&+$RnWbaBqs)05O_u)jx=Df1ruKBUese!V>A z9~ck9a>w1mTmj&;#uWZfZa_rn%X24oRvW(FkCY%B?5N>msVyVPv%Oo{T3z_Y9^Lgw zym#yoXsB#T_1!&F-7gukJ+d!-(YAH*Vqf=dQvALizUcXQR9aZ&E&n>a9AM}FB|(Rp zinvY+FogYFWJPv^{uAmf-h-dTZkxVRmaha@WbhZZRSc*3qxdie2v!JOTObp+txN` zv%^f6w<^nj%&D*5`*rC$CwFVdIDH>_2^cNcIjm2AbB8p!LZ2#Ff-&xe-a6H-N)i=Y zF83a{oiN1R@P8z>5X_hS@()ndo$ZP9oKG~S_`V1C^Y>XVZIZ1}_B^O~gjh6SxIw)+ zf5mOgi$BGC_Yb4%Bc0AFmg)fQ^pow-!5j9(P^zp{%Ko{(OWpZ9!KUc&8b1A(&xw); zGpB^YCos5RN|jxHiADN!cquIqh-~>a>2`r%QF##>_fhgOnL9g~0_+D((*omXaOkF! zD3!rWO7ZdW)bQ&&i3jpql}^uLaHd%7rJhKJh`IX}nSc|P`RfBpXLs&s`(v5UZoG80 zgV9CJo9-uWT5bER~z8xk%v zR^Ylq&~Os8>_N2M1r<)Qi_;cNmgi4pNq*iyfyyw~)3oDcKpRJR8cRQ8n{{}XW(gCE zo20Sy_nx#p#{8BUT*@tQw;1@Lz0G3VzM9XzHCL)J+%6VeGNQEhMl)6o-r_lFcbk_7 z&vI2icNq>nRjjXE$Gbu4MaIX4>N#9#nD} z1@Lv@#r48EwSX)r)=gvzrKtQ!a9zWT@00^AOFdxKci;4D-ObJB)YBl43Amy1AAV%% zT&WWUl?I5Cc_KA@WQ!Lk6{8#RG;ZnBrH6~;0=zy-D zZNm562_B4!MhayK1H+1z(u6|4*FS#Pp0`Vrpl|J+TKy1d`{ZfXb$-iBlhdcV(C2*TsoUy@LVzDW`d$=QF3AMRPp^X1`Xm}ept zva*wD=%D`2N6ZaH^(!c_h@hgPB2U;Xmg>*1-#QfqFYG#CB}M8cDHuX7^Qf(ZPc<*! z>6gu1cYmI=#qe3%>8}B%mQ_N8=9w8ZpGZs*xhjq4ZZCuZFn9Cm@?qTqS29<&(Q`Jm zU)rW#lq&tDyz(;DPQW6mR7mLI+L>23aKJ@C<+Y7}InBie3!1bRq`mnOs7MvhQPsffZZ**3F5G~yp+DFwx(OCT#=l1ph-<|C$cpgGvWrk zNs#cV?3FFC$-}JC|D1zmsuK1sK~$!yvYjN{vQGrqAW1lcI!e*Fay?A~Xr+q1bmq5) zA%)Y?)Tf;A(#6g8TKZxh!Mj*iTpo3zWjRTSECFHt%`&#Zux$n{OH-xlIbWZH5gSQ~ zIDBp*6}u#i@dJa>_WI)1o3z||gCPt(hEtDWDT*>tlANuzD=(se{DCJjNoILtk z$mxo=c+DzdTLgUa56~EV`PUHLxTpd;unF6BM6;zc$wR+s6=COMPHqO{#r-awJfY6y z-sGzOp*x`+(`<7IzGx-;^zmI?v44majj%DsCItquCxseez|vCL)&)+U>Z{pW zEW2H9tV{e&;#DcN8ADF?nxfWj|G#o9v;hkKUD^PCxu&G4y_~#SfjgQg&8{hBS7^O}=*HZKB>$MKs4f7WHAHOf*^V6v$)lTdfPtYl z(}UiQjS}}pG78+P^_Jg9v=RWY^w-I^eEDe0wpg>>-ei;X!@EwS`_IR=Hq{yvzdjHW z4h21qTZ}l-G!wO>(R458ig~gBW?Tl;wj^)Ag07;26<_(xF6PP$DW#BVto${7^OH7v z#wze0_@xgb^!v&`(77lfsyapS59ij{+%#!D5p2{H?Zs_9J>ZXaNby&H;5${_Kef8Zx2kEt9Bcth=K-~|xQVZ2VY zk#n`n7sECCWn!`v2haWquUHUj`yLcwf};Sv$x}vN`gn7dx%Kk`9rQf=iM`RP_N;u{ z^P$7iZEBwM>WXx%x@MdTffW3~6@Jh$@_e z-!h-%^$ICKf7o%iAm|Z48as3^!@x)W?5Gw(#rV92NI{Y2&o?2!(ZN;}Fg4^_(kJAN z^KHLDD@a>GC!}P$ASIDGO{6FLc7=}cBc-SB!q!8bBckI-`&0X*w)9^z1Bj*@3 z{9y)o5Xe#V=WGl_n3lI9NU*$14~8vrvSsV(=<$gpA^-CJa=g-KBuoky`qXSwELX#? zNIE1MYJpqF(@)8%KQ}|c4JjW5_lel^u`lwf8#P7S?vR(HF!eL>hce?<+oK`g3i&3b z?4>HO)QrY#q;|R@6>={-4Fp2SYX}jEkxNaeAc|OicQI#HmqI8j9BN~&h}BC${CVm= znW?;z_Vo^s*8GiVd8<*3g3x!kvvs>VGa}q21Dv3cMY24d=iKtimfHI~^%5>1Y7ltz z)jYlxi9JR@%x23lw^^)HWqNYvL`e>Rz|7-N{d-Hpz|Sl};8^^PMMpbKWk1N0 zB2l!OMKV^6M?VXH>SIzbM@5eruS3<%j7iE9h?NfJ^(CRdsfDaFD|#YP5la9lD+nM) z*0C#o82s!abyO{U`kl=~z-n9`3o55#uE*~o-^#X=T zt23YcbZlnBxw^nTvL$c-&iv=QKg$P_UWzWi4_0f&>{gJWdPoJ=#A7RK?k9hpN5*;@ zj8F2AAcuwo3&`=u_w^;*Z@ADS2w*yB&O1%b+gKP969%El@~yJX5H6kNH=6WKp`tut z<9&~*@+msBH)GG{%Fqx5c%`D}aO7cPlz|h*O2Jv%iWqNwSZ8oviyE$&)tR={jlD>yi~ov^JeiVrW+L;>nc45< ze}Lvtw*H>8Xg29&sBN;k|NR&080yv(VwU3T2)u5R9c1Xah5YJF{ zG83htXK0+lIgXdd;RL9J50NRrlay!RX+`qhbIp99TlKeuJNc7dmAndN@GeDC&0n8f zZei)pWhhWGN14gYpWnX{mZ=O83Z0N9Vczo2b4&913v)ldIL(x}H#U{V-m~m49iO%+ zaAbw^BFmfck2?)JA*61FE{YIFiO^ejw7qb?pS8*FXArA=7%mARVSJP>7Dkx~G4U@2WAJ#Ic2+o^Qj@UPgn^h%dXr!~9tOllN0qd^N}g6m zqH6TPMpdBie%3qM?`diD_(t^$Jk~-ynSP(N=JEdsCI3%@8NHL@zwo+YX9bV)u6?nL z)FI>1-?mB-&N+wvXMZKpa3I~kd)VR|x&N|<6;B*-7A;2C#IQ{9z!j%wq zCANB5|4`J|l->{|(zDXK91_;|wv8uAP6L+7bfEiT9eHVP1Ev^k47a zg;;+jejS>m>|kyWPns#8O2@!X6_V$F4*8n#S%BFb~Cngv%b-Izs$$ z!_kHp>f;lX*_Vb@Ecc?rcG2s|$&K8tcgDy-=dVx{y8@H|Co5#r3`asAtjzh6+cU89 z-QzeGDs-&J{n;=zS?s=a%Bw97o0KHJA`!wojdc1uep83p^`kLdU(uK#;;bI`a&tbQ zDMlYh1+_jL1}{bG>IoscP}~q2m=77A+LT$#t?i*;uzIFLmZ}s0Ggg6UGwHRjI-%Ov zW#tnuD%~Ja>~UBU%*Rn40)x}Vu*LWC^kl2((O&U@!CckZFg4ER$1Ov1tO+RZ^X`o? z_TMEzs@^7|dE&m?^(8_iw9$=uoStrqHv@M<^$8&&1oP(aW)`SJG3DjuLDYimR`#Mx zpa{>`!=&QBD7Q)bc_*O8 zZtz-&-&d61o+2w2-jRB0tU)AZ$j~Y zhW;@kWXYKR&^?Y1i%YvfYUGVRU-UT(aDmgs0xFO zp`#{)8vMc1TFVLg(xrgIzcte7)4qmjIolvu{Y(-QN*c1XsuMb4eSi^8T=wy;>hum! z3-2^zQSWZ~x=WR!V!7k;VtU8*412Muk`(F@ol3?}eje10q<;wm8=x%0k{*4)Y1qJ;BOzf_udcVoZ z+e{2p`(U8{5AYv6u#D|wh~^RiO$ct4-ObB;B#E8~jGDU8C4t1Q{sY(^p8W&NQa-!; zEM7F#o4>*2v9%x^Q1|E@`}XkB@o%tZ9C^Rx?dd;&@%LXn4t~)Oy=}6IVg-Lz4#D6| zT!FfbIxS41l|aPnv`Y9_72}jSSRL*Y8+@QgNIp1{ZSc+A!-vn@t-ftrW||okUhMJ` z-g997G(mjnO4ThtU=kjvA}9TQ%BN`3p@SK!SbYkLU*%9d0(t!^VFxfG9D4**s@f&b zN;wuJh4DyWtPqN>!VtG=fk=vX&_Nzh%8;q$@6axdCBAO|UNu?ARrS8=kM2+Ap@HiKQSs1DPvnC<62kf&fwpuevPttD#5)WU@M@*kPClA)W zUzB0%8tkWW**~msq!Wd`gjf!glI-?BqFhPRh@bI4$K-}sF_4%(ob;4^OOYQLD@NP( zfNFgwXnk9rf{e5<)HdV+i2hFgUlShxi>$v4YWw@6f6?GpXmE!>g9I&5T#7@22X|?K z;_ijw?gV$2;!g2Gp?HhC6-se;`JVj#XU@5I?tPFM9uQ{8e0KKU@3q!zu|h>;qVdvt z@+9)GGtvAV+8tdIlfreUkWd$7u@eduf-PN(g5rj&t}@Vw#Fza}{tuwbmYBrbT9g%s z()3pyo@|8qJ_x;|1CPtSzENH?0K4U{U&P_erdYO_X%Xsf*qA8Z;(m#JDUGnaWJbsJ zr5@8KDH|tOo#5cmM0aj}l}gNQy7)J8yd<&j@k`21QOS8&Gg`oyl)+4e@wXWb9&WGl z6nekjhw60*Nw5ev!c|~eL~i4#2KtgM^TU$H;ekC<9u&Bimc{{ZR8&!iY+OfmT0p>i z7$OZ!j?Scve?kSB`ydpij$Rm^#3m5?$u5b~-aDG_O%Sc&NP zFx*$TOkv}4Q{Ehbs2Q)fW*w>cgD3k|>gr0sZ^XvW$G-7u939pLkEs1Prz$@_*yDf* z!%#cl5qgbBnM1hn$jJ#_eOMF4qy6kF`uL*0=nUnav3j3=NR&eB{TU8;JONxDHj5FZ zQ~guRwmE&~^g<76+CRJgCxxJu^aQ-*%S>a3cyhd+seAL3g)AADm2q8ro=3?y=0`@= zfcV?b9&7)*K>h#j)!31q@JVj#jkWUkbA=;{3{&Yv;toVo>fdf=#ChW-Ogw*9;3{4K zPJ7eq-k_1Wly@ai`!*}fJiNG2C4XP0wHIq9J73!jnl|g>s|yX961&Iy_tUW5PL%)t z&X-C$nAnwW+4XmPPP28?d*GdsBR`0KuKNsbjBc>1$y>3Q@6&eKTZoG|bv9Lc_IdF3 z#vf1VSlGbBKvmYmydV@AbOzt`tBlzh)*hX#)723KW3vM=jlIqlB?aC_f%Mq^d?nxS zRafYt#X*?X_Vh@+g*RTcx5y%*+@ftug85(-v;}avXz55cKnV}l+qJl?hf*_&3LBp@ z-{~S#US0Y6Dfh388ik&`Cz7ZO^C7Qi=6c>rk;xZh)|Ltn_I5!n{A``AK;=fmtYGkA zw!8%ieDF_P?o9)}vyVW7YdWyHNXJ(Hl4rlyok)84bYDdz?lWZ!nOemhPig z{J-jA9rb!Wt85N%?1-7sO@f~=K6z``#f|?9c1!yki~NC0vJ_Fge0E^+h_L0jWL|Jd z*hiyAsc{rQNn?{C`%o_rF?d|7vT=dU!b5r*UULH?+i@3_EiylIJG{O!$HvkqJli{^ z$JQo73pzxWp{t9(u0h`QNo246`KQLB-5Fk=`eWtwNIZW3j;gfOLFexX3jNHxqrT$1 zi_iMyOIXd!+Id7aUwqr{)YdeIrpDYnJ15h-{oOuy&@TE$S0gVNu#*bx6Rrmn2^oeu zw|(9{)55m1+kBzvxClLuy?7fs3f|Uk{B&eu)Not5xfr^G&?k7`+_V2AX%wY=M3npH zJk=THV&DY@D5d|mYLHbgxQlM|TvBwRry^(lSaV`Vu8uk?Sjb*H60i<##e~Dm35ttt~m<$pzg5v!2!uEGrMD zKJJ<_p%!&msUp#*l0?+f=~3CPC8+wu+b|Uk|I0vkJIo)B8+Bv*M4{!i=~y-QcK+FW z81N7A3JhzP3+J};r4^O3$;7UAZ!MMh0={6gZqOiC zs7MMfW1V1Sgxi9uU4ie89&5z zRm73t-MUa!aFrURODnym!hp@!R9*w;9^71scz^J{ zYbuvMX^w)XeANuUaU*%~D>h5UoubwjzK5n6@{($nqMm_ciRoEO4*B0}LMl;#RjMa~ zw%Q-o-<5>8nA zsp2pByJoElqhI$Z>~sEe+%v+wof~`WC*3da^w$LyH>E={Nnnc{ zwfHilT{Z<9UZdqKG2&N`;}7;M*m9CdY7k8}<}!Z=6&2-;ns#Y#Z$j*E zI-99Ao2k91BbP-DZ7r%ST)fAX*5JkK7lIVihmB#l=FQGm1{fkFkeOnY*s`H!U!=Z# zlp`?peaq8i{JZ9W`CH`4_fu;On*1M0UPYo?@e{WL@xhL3Hi_aWw;VP3Qr*wNowQs7 zCfUyvL!No|m2A?0ScP6zb8Nb!4XMXkiXTBYl}s6DMB(o8n--CILhB1 zya|&?iJb_Fx^ZQ^;j^p7k6LQUQ#}I-NfCYuu{c{#nb+nOx@+m7S$0{m!_!k@aoDLL`T7hS?x4=kwzY^3J}DGi50G1nf!MQ zR{FJb%ezPuL288&+)VK9FBd=Nro{QTpIOXIY?!0%{`x;9-fK`DCp5bl^3jJ3Zn^N+ zdyg|S=doZ!muxR1*rz!?MB>0p6K`@tCUwcYrd#DXELbI-Uz?LsuxWmU72}IE+s=41 zTpeh-WoncQ5TgrWagVPYGd*$!{5CaL72AGtOAt?R@fE@sI$@7E(``253i_}98?#Me$&>j^8OM${#8hPTwCIavLoa^!z3^2>xWO)KNh*^KTv1aL zC|6w|CDKVJbG`Mv{7bz)wN$bcs*b@1b(TW6RA(F{_v`xn>t^_o_KVd@1ZF8oGiwnHn1Wuv`(_zm-bw z)kJX~TEgkA&7Ie}jwab@BL}u14UdM6sTJCTf2!WTbJAH7HKh!Tv&4TNsfUDa7i&2(-6q7I z*dxygxCXTOZ4^FMJ#oj`@>E54@RBgocmDc7p}e$Z=6_%!nff0Lb!RQ2(v! z$#jVTZy?{604-%@G9~g+Vz9#7FW%-;$w*>jwc*k&i3LfEo9*ApY~H-AgwO^@&iwcF zTH8@L2Jn1oPnK)F2jb&!h77Em)U}l5RO`8;mu2&zezy}Us{=J^4weg^~9gqkK7y4LDvee-?`$X08RGeNRpsGE7M=r0`li3`NH z%pW*_CeaR+6V#dx0Ab+-@|SPO2W+;g-;->A>tGd{=av)28zAZUI8icShl}B_&GB6- zU7!)hyoJ;R5H>7xN|fk3)qk;;oZ`gOT)^wpH$VD6Ya-cw;VP0pgw$f{#gxL&efg{O z^;P6BS=7|DfMF#{$FJ(63jSxU`t{-KM45_Mlq;licO*p>F)A&os#OTV!BP5xjk+wV z$EQ$yc4teit}*0$K#_x%4Qr*?I+&@GAz8B2(c*`s&s0jCEdUnCW~m#!m}<8@8o0kZ zslTdJ0^%)c&DvG=B*hKCP(3$Muf);c>HaO7dx9scrFXJC1Exd3eP+$<>SeIqLVwERvEA#K%)5tw zrr())*gY(fK{uS3FJsSD07Q=UYdn65x*cD5h+aHSV+X1FWbl`aumLRPLep^ zL>E^l>UN9WZ=BaqelV$NU*f&&I$@F-%)R#Aq1=evq&Rn(DL8NNt5e{0P0<|z6l&G} zMSjIwL9}QHRl!GjO>QNi({@Eq9xA4y#=0hTLQ`QgHM}TPwgNPOQD}X3&SUE3AeIfziS}Hs3Z+QA$LkmohW7@aB*T!-?wm4CBGn+xP>x zyI6EB)oH+oK{GW{3%y99ofby2R^sSz`_dc`E!En#z+wh`>3S7!Ooo!M>k&HMmnpJ{ z&mW~=0ck!7>H1S}Hl9;v|1C_;0?Y)Qn~%z8h!LS!_=J2?9|d>ybp8Pin6Ua5!w~r zyxEQ)SG)(LCikki4%~3>OjUpDt zF3;k2^icXRiUe+bDibH2{ITlXl}NYXCw)zWRUJ*v3e=B#p%5u7hy0PB*Q2zAtmFg> zODluo3B9>RQUzyZyBN}p*z@N(9%pkL3>-KQZIfhgK$Y?jg3@d6-c+3A`L{?5Y3WsUA7lz+X0CVk^1eNMVr#n$Pe0_lWMc&dVr)5S;H8)Y0iH^4Y+GZU_i?2h_L@YZ6mzb{3qP z{QMJOhUE94J;<>K(&J9xtgc8|)=v})FkUMpK{2CTtGRA_Uza55%#3OD zxyM$>SxQ{o_j0aCwgm5F-GuSisY$m3hG3GN-Ee1J*fy(qM=!U*!!ocWs5rgTG;jRR z#@Og5Q2HMUT93blqdvZEduMMe2%ehX%}dynk!8?L#}EH7Q(`7%B+zjO0#C3leM)U$ZQWc}g0-3hMr9MU6Wj zGW3mSnaa<{R0?W}X__?M}elx6Ga}8BM!=BTg{qBJA1aBa-_Rv$DZ;K^w$U~O|- z`4hye36VDdbOMlmcTu8pu>M5Rt9`T{>#@Hj@{MY*BBJ!)L~aS;c8byE@?Q^#=$ab6 z8Z1c1XVXwj(@F=isY}B*;y(;^8%OF|@S%?$giYzOureh^%rfAh;JiW$L`$R{w^9Sn zsVK^M@RNZ914Ew=(oAhQ40&Yl8MSsQLW44@D^E@=x<=aZ)%CQQ9LbsxOj_5djq(=S znXpuK#DwCg)XAhywwNTLD|nZWZ}Q$Fi&!iIB|U+7yvB_;x3590m&*mjMPK{1w1e^7x2ZMhstt`~mCzcc}F)gj{_Rk90`E?oU$pMoW_AUMcFkC!s zMh26RxlAqWJuMSqXCj1~I`d?{PfeAp489{p)%+@GV)BZ5tn8fQ4VM2^Fx#BgziPxs zt3Curey9% z2kIaf&i{)qJgg1=pVM6W*!&BbV?7?qeeV#-Kd=2s{FQ|ovxe*>W+_nYJ@zlT%LIoM zEgCnwwxoX+{HT42Q+0xSzqcJ2K~gOI_dxuJ)aA#111HAw57pzA-lxjJXonZef4o7} zkvd}CzIV%Xyh{VFUhM~JduM_u)aj1#T$@J^eCy99t%X>=k*fwuG>>?Ed`hwDRyh(H2;j> zOYR7*BprJF@)zR=1`^4*-O64-%4a8tN*FYmIsWCTxt9GFoUMOlf?YW3F#Zn!&I<&1 z+};n(g_-H5Y8WL-N7%6CjiTd~Ok%7p=1m0sqBY?a3c$?*m)UPxY1Lc6f2P}&qMmq; zJNn|u&fR@`dkrCAnS%fTuRWm_1RjJQKq(x2E4Ho=TwG0`AAYij2YGqpt3?bcqzFr0Kc>~GzJr8s+S34@PdX+pW@hDN$seLz?#{X z3#HZML>;5UfRrMfRIJ5{Iw_LDeGJFhRJ6p?N2vj2_STJp36o1ke387j^YTH);&=JC z^wDVqVdR!fyZkaG!ZNyv6G{%vH)@c8RcznOut)6{@+g4!~83NoLp zg6J3S!zI9B9e;N?4>5-9>?|)6c6Zxs1*mdILG4?V^qgT<&A*DM2CE@vKmZdPvQs*O zhBz3*5`$9`$~=O@Avf&9#xx6y@a6%p=$WdE5d=8LprKp$Z#@K}CTYrkC2FSG%pLGr z#S(Q#sUhUXEzc-mJ;%}HOZ_O_hX*k73?+j_wr$NV(xwc3ZoeeEDf-?|Nx8@cVVW{u zF0rj-m+dpzN>0g0TZ+rM`0QIcfpDFa{#AEWgA2VS2|3h5{2wJ99Vy&k-~PHgzDE+~ z75n>FrThOsY9LTLP&J=^$KM7UNuWduJe=8em(LjY_o2azbQAz3;0`^H6TN?7q7=zy zNZD^8XhtxqafE32DrQd>*#Q+h$ku0nx2`tHRkI{m08}{<>AdwsKXQtJ#m##6@!Ja^ zt*>5Vt(7?9^#D@(bM+y-0Ls*py@d4Zy?u!q$S@f=adq%}Je@p~f0`P1dZ@X@xE^Q< z{IYc%=JbN!h_vpj-@j%W<1u}hA^Hz6_b~Nzmq~G9n4cIM&i)_3z{2#QSN}giJ~3mc zz0=d}m+Dg=Q#MhV7t@veVQRGp2ltTL&d2UgXY~=^A8hBvJ@)|qD`N|S(KWdoz?qC} zJp#Wc`agL7D|<-DWXX=Y0TdR5iwk9dzL8GO4!(8qUaEh2lgY%IqL;U<$G}>l=u=4^ zFbfz1B*HSPBRU|2)pS|Mf3Q*fl1KkXgHgskoD$(UlpgEfHdExHe-|preyb$b z%mf{s;2%}mQDIsV7|N$cpT(*0l50i~YqA>65dH@cP78O1E228115v+tk4p-^p$%Wq z(%@7o&$3KT$^?gS`anUPSQ@o~i6_`1PK%~M#kw(OGZlV)s1iq4Dd!?3n>qum$1H3$ zfJ~>HM!1cf)=Glyf)=p2Pe*Gy;mW(E4`q;SOfG2*YKb(HLergIktwdVFyfPn1XV({ zqH~IwlxwtLfi_VfoJb2rKp3hFBt}7S@U5~8u0hW^D;o?^J6WVL!6|89cvt$>(?ZL=n3&%rnTEGzeucbd933%5(I)lz7 zFTHO0h^W1E?aq^Vj3`5$u?RvMz_I&mq=8fpG7KB>E1MZNDxk{CcZrqgpiS z_m!W-e2Bg6A!y9M1F6Ye05%J;wT6h5g# ziP@Br>w^>PE5qIUP#B;%yeD{}IVCKCEKA1_@(#3>lho=N_4&D^TLb;ekXCn?sTF=N z$uxTN!F!@m>z%VSkmj-)>Dknn}+ef;I@Y28GYb_WG#M_#I%9+Xg#Dyv% zM0|ijv>djrAotMAT?(qK<*ZVxihO~Bhz}wb^D-CXO8ATXtA~Ww2`I;JHiP-m@A~eZ zkTo*|V1-p6&`4jFxdqh}7YMnnlj-fkPM!QzFE>Ez^ z>8iX@eROoFqNJh*0a10wz%F`n`N8in14FW2j4TthPRl~Bx=NCC(!!KFEblxz`+=b05}@{()Ic89+oZC%s{Y^-HYd?Q?^l5 zK>!hEd1~1G#wFEY?9pa>%Sv%B#bZxmls_8qbzac(XY&EK@n^t;lw7&!S>7?02`&>j z#Jo0cZ>B6?$d1gv$d%r0clZ9Y^1H$*RiiFY=&)D5SAM)kChlAMLyG`uCMz@Aj+Ht! z{4U=hkZC}t@8v#0Frk1Toe}3$f)p^8cKK<`EZA$G#*J_<;6K3sUxqc3LGME19|iKo zhzgws|D*^ycglWWN3Ip_=Ty75an&~d4Udv(2vg@aChyNS|D3#roxQNp+V!pAH$Y5C z>mQTP!{Mt}%}{g_r4k%QYo3zVPR%ZxNO4pbA5HA)f}SP`Tjuca^0Ju&sLjzH+tU5x z@|z7zbz%#tKSJ_`1QMYNk&d7HInDvV8^4JHZCXmqX8e?^lX_n86K zD3iWO-b5gI>F+2!q?3;_SXQ9=SXHVBhxc}A?Ut8g!?Tws-9R+qw%A#$U&0H5ZNNpt|3n< zuIM?(3p5F@C9brIHN)W*&kL`Q5i~g0hs1HGYl(@OP=*kq9aH1NiXV0d#_SaamT5Nd z;E$syTzxPEFc9sC+iUIoF_BBkvFEr@??UWqB?ksx&4te9`k(#6IPUO5ySV?nPK!<` z$l8QN#yRbd>5-&Q57DBN5LRE;nW2@;k#JsfL({{ z<#h!lU|E~feT7|ao00ntX5)FXGPHqteJTBJ{ZG1a-;6@D1UBoMbAq_lxrGCLv?PTf ztDe}4DFUcYWp(Ky_T(|S@xPNhd-#gUK8X6&Q0~G#As(=}=1Qc)S!(*$+HUZdlosk5 z3p>u`nBq+lHYm8>45&QSUIdu(^F=l~zm|EQT2QTws)c0ceF6YF1uw5J!sfv^0Fkhb zAKmi~n^k~@*+7+viP)sNfE?VF?mXw}6X8FTB%2RDL;262?Ax#iKG#p-zG zRd=CQMAw%RdAe}gf=tf!3S{Z?`ju%RjN~lC$nlpu?qZkHC$z^??Fc(X`~62tSZH4` z8kC3d`ZnaQkk}Fi&D&uBbz)k1N^reCz&UExd(a96)-MZ*EOo3*^=F9@_IIh4GGJ&L zp$BeHxtuU@%)C?9R*6N9~jmg3y94#4MZLZ!gTVr4Ajs7 zF#@h9lMZ&I|FUS@Ss-jyO=y=6_ls?@?)LPNK`88ca77e^J$K96>ZM)UE}c%{(DYXN zn7@c12xS^Oxt-v%xGCNxLJ2w{HxP0P3=1mhTd0z#d4L(QqaEJJj=o(IvQvsed zUBWLuZPC|q68uWMYZX#E#SZ+=;wJ=ILsr@_Qs)xHB|7j0l)W*W@#*3ykJ*CiL*)h> zyTP+3=d@gJiM4&mJ(*YKeWcZ?ezV=dJHg#TLLqzk>Avo=RBPcHP`Fq!C+!ZNf%RVB zd2Z~WfC@+@E(avn$OH1(^Vcn!5oeo4JDmScGFqNR3$;+#R*7_I20T63(G27K5hj)6 zJ&=Yg5|nhu@01OgsC0D7pEI^BM0psff;$3IY z*021GZp`~lemRS5@wF9f+he^R47RGlm8>ku7m+@2epr%%X$vq&iKKl?v+cC?jnb4f z`poC8c{edX_`L0PAjblkhsVm>!5j|OMyO9LT$YMJ^o_?@}a{JJGC~H)9So+**7xN){dgDV+;JLJnNb}v4{=68p~MNAGtMj(o;u1 zl+eicFFX7=$|@`fSTg9LTrW#|l)`6rGZ)a|ZobQrn5YadZZ_I#r;q($^fto;rHoW?8eA)|zzDegz9|p%X!pltmZwYYq-Box99F4K{9BE!#)A)El0cV< zJ)URn(par}nn(0GEIHeNw2ck&%cUmsR zGaIC#(l|4@ZteN{(}aMdkL~f_(l4^zqybeg>;F>#ol4e6?4NW5vLXH~HlD7v=QnzP)g7Q&l6j^7s?XNP=mB5mlDd2}(~D2*Brzr#&k z`Gy2dGqo5;7pj!blm6SbCCl9tPP2V+A?M+O=S<>}V^z$462$zKnL4)Vzo9lS{^2;` z=qQgSMI-J}w5sNZ^EY!t&B!h7!^Ce7xCUS(a?qR9QX>CSHYu*DrxD-rMAWRNM>GJ#1D_yHD<=)hLhFx%zA~J ziBf%73Mv3kHHeTg3TQv)BP#Vv&y8y5LNKPn=F?B>^sxi=iKbv6 z!9Ta64}oHS9cRAlZGzV(RWb$$0bO zhta#RseI+E2RxGbUl=Md)O<)qYNB%Drcni(VPewTj5Db2~YhmDQ_dlX=FQr;Z<^pG8_Ldrnn5g4EXS zE6Dt6l(XHLAB3A7zK7rp#LOa8vJjmUOmasAP>74`Ll|`cD|GP^kR=SkmK4^iC!$sY zq3VkgxdZs{RL|dMiK#?voT~idlR(|8vrv8?a!D`)toWHoGnNPkFeLc8_B&5*VUx8R z*EDdG_Bm6Er{Zz>0^ycFVP#fKsgFwslzNq1)m0j*L5zL>T96;Lq|FSX6!JfN6-C>Ikwp=w_f2?_N+%WPlZ*_5S+$YKJ|4|}}JV$=HZJO{cDqc~= zV|w47sSn>DRS^sSi6kKR8YLR{14IJ{QNKgDS0w1)1^i7QQvdlwQ-jd}QDcOzrGg@| zmZ1J&l4uuooN9x>I`Qn{Ffo-CKdOx{pu8;5{UWxx^G(B#HPx>_{{z6PRZai#cRdd? z={kHi2ht411yrxkWb*L%?e=>t_u6S|CRf7Wc0>w)PZF^-gOAD$6lm5v&l76_T>J>7 zOy<0&Er8L!OG2(d(aO@Yv=+S5=rV2GFj7pW--%X?{UL4*9Qe;0nce~FeXd+$AKc38 zJ>|p~`+f!NCmk9dh7KxgbE6?p@DyDZ+e{Z`iSzbX+rszXOl5UPZ7=3=sp_eru|V)SLtvRtMiFe+dFSo=w4o4D zC|stbv^p;Ng~t``Geumn#|KK4Ld5bsPXT620e=l@9{>ap!sBF*$%DGMCws-zLQi>} zgs14(SFv$nL|RMLO8f{Zw$`ALdZZ0alSPG26%jG~e~47O}nY;~@FB*wzK^OMY~ z@H&~9b`Zvff97!K7Ik7|vwTwWFT2@tJ9K&6K*3j>{;ewuLqJZ$jkT*_b{lZae*mE* zt{YCfT!;OlZ(2rJZ4sSyyJQ-*HP`#|xMh9ghU|)Q7}qy=pYq_38xDf6Oje!*!ap*e z4418c^NUqNC&j#xVYgo8tfQy7L`d_G>|G&+w0gPry@7;AZW=;-oh(t)x%jN7V}f8D zjC!>%uL|eUi{&Bb(*_(GMcm=79a`f4Gb=L~M7;bnW-``A4WG$5Mf4A@W33*YjMc$aP z|L@nOlh-UoCp26~mlf9sW*|jbMy6aMJZEeEaW#>qbv3f$>iWWZpAz=!4RDas{o=J5 z9#@gg(N1Yd-nsn_9-@FYHz>BqroNii#@K$=f zqG_be&4sCh(z&)Wz!^gp6gAr3IGKDLB`-Kcf$0#?CklYp{FCeu&&YzQ;VC-E`q#A?!D&A{BX<7=GTIl+6h?H9FdEbsviSODYS6i|wtB>?iBXBde;^eI_-Gu;_~&NmtS3GFFA>^kv!Bem7SK zgfUP?YBz&&_^qgoBb1L0D-Qn6;|7wxyR@`oI0uSO0us6$*xe_}bA^yCzaDhyIg zkR++G5a!r~1S!D@bzwBfuxTludbS=SsDKOG`R2NAYcs|aZrX+YVeiDugtE!4cjoeT zXjn7W{F+ViYac5t+O^h`n%9%|ZQePba&zWv$7w|}u^9#Cr#ZF2+1|Cos`~q|H{hy= zk5dRFi`)9teGmdlLxGhxB^Oa5|1`(VH1>E79uT56>aH{hE^Ja6_{&_(_31W zx~x8w@B;?=XVH%Pol(`@K{`WjY67vK!BA*dSz$*r`V9DvV`6n$)!P$oS1-~OSp8>IsCnPoa z?CmZF04Q`ejg@p;F?S~u?nGxo)|-|d&cEnp{o%Z&L-yZXyF1*1q(Jc7Zggp97o|rHGTu1UEFhm`my%)FNt-xn4J?{JL0sAq4_0T?pR+ zY6+Yq3?SNMO=@K641@nzlirMNKo5^%CJBTFHY|G5YD6mIq#@^qNxZ%(tExwMUTN+) zZaZ`$s?<_y;hNPjfVKKD%lOzb2YQ2B6`V^F9W2bDGG19;KJY0zljLezT?&^&3sYSZ z^Dv{>nw+~BjY^d}u8xpV7EzU#1X?6BT0oh58%MO+C@O1i!Eg8Ye&dv7$(vc0Z;@kn;zt;ZM!edE9{^3YnYu!|q{ zGa%=_jU`giV)zrIBAj~i@mXP%h=gxLkrCVM>4Cn&DHbdi=qNz`41VMAw4L;y z47plKw_}$LGC`S*%wT|)Hlh-QI+)7Bs|OtHE%6f9Ma&l7* zCd_(?PT><=`&u#~0D(P5Ks?8#7>@n$-3ifG8NX?!LdO$n*bJuYW$b@ki*;>ld;mpR zL9-!p#K00(`w~Q+0q}Kqvse);u~ia#_M zyHv^<>0c!OSYb`T*O;sqjuF!)z%g9NZSKoD`*7W?{Eqn~8QVfiWcioI0@4{X;u#C* z!3fTd`0l(ttbXOHa>TtOh7Me(;|?^l%sl)2u8pNA#fkMzfc0O&XPw93hpnZlOFy&! z0L1pa|K5>v{&;^Vrt}{`fVB7iQh@cxljckFVDEK66B6gaEQh_g@&BacwEn+Ra{oe^ zg7&XN;lTlk^W!p@=tsA0%nnB4r=*4=Mo$r4$H-aHnKNirni)R&T|JB=8K8&(W74q# zBs-0sXC)2Xm24)n?y-mj!pcfu)~NS7V^$pyrMF&P;8&wk!Z>=tXsCjF<95Fb0J&J@ z*H5AL8wXe4Jl;IW0Lx0p6JBUR^!*oU~wApE3QRW)T%2!Ng^^cRn7cV zM<}JQ;FfvE;a1}x`~q3p4X2oRhSpxFtgGgCVc9(TmW&^N5G`32)X3#7f{E;nQp~t1 z55&-b6%4!nt5~PnbU#tG%`{RqWg0##tw3B+2vXYfe2FTxNVE{VT055VK2a4? zzCK*p%vJfAWy)1gCdyA0(4%N$*O*rQkE9bhF)O!bfkgJ4WF_;zw;Pc>{^%%&^)&Sz ze1K7AAT{F`9KIcK=CcEtOHRY{ffc~f!iZjVOxavMbq@Z_U zxnTC?<=LOw=>Bs+3<}Kxyf!x)K7-h*O5uoM7c0;L28uSWF#+mFQ4{6XrqMs~x7>wk zj@9I=cg3(Dl|!U(1Y9%C6Dg=kO7!ATdd4DLl#%X8_8Bhe7_b^ldud!JL_FbRDebVE zI?QWgesk743k@8EfbdxYNN51qdJRxJWRAeaPExe&&tK65lWPmX(2xbRg?`t@>Pg>x zwcc3yl4O;8zNgO;+!s?8LKqI19)-+Bl5FDD^#_vl4@m$a2Us7Z!E*&?CN&{)Zz1O+ zI!!OZb!;#nFbg%T<>0}=+RH&9N9O6-uL%AXxbUIDOnBAEhbP<;{BQDwzFZ+nJ<-mq z{XPM$P7x;{7c->KW1R-*Wlr!@tY+*$Orl=4QvCN!39c7@XHOPp%dlwztNR-QY3w+K zJ*UqMN~?=kP8DuWT#5fckrHiZ$TKEVi~$uyP1U}zB7Z0a`d*&|6Mk#?7GP3`0arG7 z!4lrek?(^4zy210u%j~%Q(IJWPI2WtZmql5KM9*4tn%Hn-rh+%A}mv~r@~)SQUrWp zls=EStN&SIR%xb;eTtCVdOhGH@+^yFhOj~ffgPlNHV3~n-b7xi1k)xN^)S8)%ilWu zcc!v6=u_5DfTOXpftPp*RQY>O_aDIZBY?Q%J;T#RzLL$svdnZMmhn_gL6r&Pf{6c9 z3Q_WrTw7aw#MCEv@^B(JsXW9m{m1$_m|to*?7?TTUv30*S=m&mgKCNpVQu+Jj7j>q z!O3O$q!NalmGvM)T`D7kVj`t*fvV zgfDWf54tGHBU~YsuEv%ZhpPxZ0vAj`pe|Xy(;b7|Ba=8FAu~{B06i0W4&66LZ8igl zC9T!mL^{&Ul~chQ*18!=R9N8M$(D{?)-9*CydMbJg@Z>E$r5>AUMyf`43^&!p`dW* zzXK$dDa;kAl}a4c!V|qusw-*u-n_R_znh(Q#^=wG0jy2VIs(s@^7xdhiC7P<$sEzw zg#|D*PiwR2Z-thDDspgLPq3A2b7EgPTXG6TRaRBioM)=ro)%<8(O@*0Mm*^b&RHaR zMm1>9y`X!2_*1%H{#^J~tKGXMbni@e#H=KX@d>cc$4xlv094lVg7b1!uDJE`bL0~MwUzwF?cA_xkP-a(|X zVd^`hFz#~H>dsfcAyCD?;tENIpD&clezX|KU4%qv*|7LS+g^*)YB>SHdj zW)*r^y->s#qY8@}Nfc6qrlDtA3eRM1l9W`l%{Mk#HAuEoEm)lfAd@?sl=+5TN=gzQ z90R<0_9N_emADK8!J||V=3(T{)y_yr>#~Ce49r~x|Ic71D}{$xsYT`zk&DO9pZdos29Z$0yG4c{U^1u7^JQ`dJCDD6#r(~8 zhv`gwM5eJ;t&$>)4J*z!x7}NtRV2VFVqFkk7+veyXllfw*FRL{tl=X3Za5SCwLlbEw)RL?oLryVLp*`#%-OzHx5Oi`BGZ)D0XqE`?DAdycsI zx*j!^Dif<11Ku;0=%gzF@sHBZLSCE82Db3(gX0p_fBsZKDV>#^ZmL&kC==PF&roM> ziX!`xOgBv)2EgC6>XA_tmM;9Cc5zY|&FBv-XxpS!a26)xX%zIdhJ}Ehv;Ln6yC1@O zX6P2X6Q5VlHh|-qYK#`qXGe}O9vGzZ>#jBj{4clOU3q-yX$1>oVB_k?Qhr@4>9wXJ6Sr6C> zV>r3(G_z!JWVr$%S{#j3$%0T!OLNs6v&E}K(M#)_Jxf8)Jf3UkRCH)1bPh6-@Lc-# z4`A`MA%yGtnP%DrwYsRy`5|a((5ZH{_RYuAZFeNboX`_vgr;L zt5_rhJTOf*<&7@$_7(yrCivc8t;}r?QaRaTW@HA8*<9CJMDLiXQjtr<(BX#9{>Y## zeqr%Z##*SorB~&<&H(?Jfndf%^#|K`84+zhC1l7`CrkFGz&ajH-w~Z4ezfC1@UQC8 zu%aQF`HmkYILM7ML=f0*9^oP_6L3XjsQLBjVdxKZa9>zTNB5lCsW$sH!h3?oz_Ny& zoq@}BH8lAF^~m7lcXsOVSE;mO{$!Xv!M)GgSZ~)ATJ*xvWu9gAI9lCH9u;)-_Qr8y z89y>$p9rH*fXBi2+l_MV8<~Xl)s=I5e(tip)IU5d^qM76g*k6==?t<@uvhKqxD=YT zMp5KlK-3*x3$-t=twJctomx3V1!cIuQy z^#J`9NB-tkab;1XgIUEg^zlJhci*}M+F3f;W zl`frE(fyC1Ya%tTDbv0l=wmbuXlD25x4C zOy=58Nr$br^}?KCdrIl7%6T2|${Bw6FD59PzC{fRo-jg-q?kwU%kS4My^ZC|A;+%= zGyMNAw$3sruI}CPjk{}bcL?t8-FV|J!3hot1SdE_(zt5_jk^T*-~@*d2p-%C{!YLD znLBms&V1N)`de3>>b*~&^{n+<%*=*ZPaJoi(N(QE@t4eY_N+rIljATDR#x;y4-wlP zp)J!yvh5`*dxRd$-YWyt0ZfnW340QMotCkt=|6V7FCiG%ds4rPRpVDu&*$Cl5>Eqr zjIRpVYmu1A4DRXck*ja%@Ci5_IZO>TPzdRQv(4nea2B(Fh)rwl^of$?c;afB@buEq ztmA;yAEALrR6W*Xo4W*%*1+t$HS%q?PNEnqzMGF?wT`Qv0c!QXvR8b0jWmknYk$CW zrbp&hUCFcWv#W`xI1~s+v86afKla`&E!564R8`E?-eEdC=sk%C&lI$kw@SW4-Jv1) z&84+Eil&trS4rzA>B3VPDddw9C(r2-OslFX5~o{Dtd(NmbjZfx)Nd9yR>7w8s2}&* zf9|>tzONOz%h~e3Kee6dF{DUD9k$i2Ep`U&BTs%!T-3}|pOsMJ(JO>>L}FwnBfJ*s zvh$x1qA~pRkt~{W_^G;=*$e9K9)9;GX<%vPC(5Kl6|u0}Xur+Tr-a{kjXe_1x+B{h z-DT&3%A}w3aP4Wb@Wq=be^Ru^so<#~kIddCR#L_eZy&ddMup*&=wis5Am#KplC?`5 zizZ{f%JJ2$VB9V1Jsd=Lw*}?cs!5f02=HNUIsQT_H} zo7075LOn}TM=jjo?KvSPOq+Ea_=0~LB>viP)ppwUWD-2`55N|dx!fepJ)+X;?(8cX z%ox2bJ$#Q?fV=H<^;KM73CDnFbR|u1*kcAqcOic%iD9?lkVV_iBkWgl3X-Y;{w6$RzxqrsilSWsPi5S zNdwViA#m72%+D*3$rzzY5n5}gbS?1(Ujaf%I;Gk*wetJZ6@;&6uxm1Hr@_54_4zfH zJmiiEW+o7VVoI`@2rFT=5|7%Mn$x+fdlUKNqN@A+yY+!lsT%)xy<(Al)XPfH4w?_< z_J5o_kVOT*a(@rCBH**(k^W%H3sY~dfU%o3_Dz80!vOUt94LeDU3*oxEN0uq1Z)>} zBt=XJ)j$j=lOWq9RXKES7^c zCnX@yEWe&<1^eeC_tu1qE2RkemSg!4^0RQZ^9ZXbgFd%l%Opdi^*avrRJw}0aoq{U zdSy6a^t=j<`t`lD zWOt6Ew)uSDe6v(T2`}S-hm)M5(e%nAii}UJH@y{j8mvFKiBRe<)VF_J^kxj&)K6WZ z3WmW9O0q!tcN&`kwkwG5dnhL5V?1&P{(j`%f(6^P&9P}I>yZKJdL_J8t`VO`Z}+sG z2zu?x>r1y+Le|{xBA4H-163q-CI>_nXzm>P^xHKQn^PCY>bBlMq-s2wR{!K>F)RCG zI`t8Ik$u~UBA#`OTvUUT|?ZRky@F(8Yn1YF_0_xS;0YB`(wuGgy6c3>ezI8 z6!2c+7x$y?8^f47aQ@`#M)HRxYG_ZDubqi^l{zCR{;`{#^aW}F80;!XhCUKrt0Ks*M~jb{+T zvMkrOWMgy6Z{ePvKd<-uufugK?suhIS?k;M3Is(ZTe0g3rvj_a$IEe( z6{!((RjYM`PjJdY(j@~Y)526qX-cG_byH;EnlD48UwMv#?)ChsDT#8CDvd2KQ8QrI4m0qoNgNr>`wP)buUr5zXXWZK810Dk2t%FE}oB8(TUi3 zH@ha4uw6bl997*2wFt+oX1;VMoaFzgI2|`~TR8~~?#D%#w61*C|D@Ho<%A}QCP5iD z=!V*Hj$^f9bo4>X_4lffN3`EWn{C4`YJI}Uk}ISBke(AZv{ySE-3giK`K#=j@0>VU zbBNu>>`U@xFTs=W9kf4CqmL@2|2}n{GR{vT{=)egEyjaOQx&wV7HjR78t44YF3X!h z7+eNKFVGU!P>fXnDr`3Fga~R?lM#7UxVcDtEQuN1u9zFzs?w>8uG7qOCi$ahXChRw zXcffKT-h*f2l6G~?@n@ww^&9KOqMfcFMD+NcGmT_7%$ME{Jh zM~@WnG`hqLvh4fhXfdTZ{FyX1IU(w^F1)^>MEeJeIMve)QmmeU$n?f}c(w`3w}e(4 zYqDejLN@}*Y&wlF4b8bhd@MrW&ntpdbSm+?5m4#n`PI{wDE%O0=y2<}`mICFvy2f0 zJx#7hj{j|jiSI@c8)L@a@&Gq@Pf4F4%>&Lk_;HdIrl~+iH4;IH6YICtG0zOlHbTzb z5OagKqjI+&cIofC{m);&@#PieobmiHN$AAB9~4Y8_^ZnDeax{j#ks68?|Zt z()_zFydf0u{l_mbrpmpTzkfFGttuvCPhO|EgYPNgPo=-fPoldn;vVCs0W;^RY95LK>ZT|-4>t$?#j#8*Cs zY&%evrGQjN5Ujf_zi^6mb?VV_L2h$x(q5 z;t?+mF_$EK@4v`~%sTU?e-UQr(jUAtbZ_moZOxx9F+`I!JVmitZX=8Ec5>rAJAc)E zgto*Ivd{l|RG?yAnlI282vT z8&sj%(>sFn{MYYxW%wkDSLBaYKooTQA3(O76~wiCYc3im$-6C)`3v%-TMC&|%m!dh za9+x=dr<+t7pCim9i1S|X;2a(IA|vpg&mZRnT{LV(L~v0Q$J~nH?%0JqYo-r(a?kL zny8A&f(^)1zB=(h3RAp5r*Bb%|Xs0xfCg@u0FCygglzHdJQ4lhkA1&`)w zTbFK2Lhb*cDh-b{%spJ2-=TZ*^#AIB_fnYW_`P>bFM=y<{{roZWn<#;{&lXht-F8Z z1$`;(&g%Aw;_KBgVU4i%T01^In8vt`<}1@(4`g``Or;|{5ezL&P}D*uG|$D|cE7sT z@AF#U8s?ysdht`7m6LAxE#|OeBfe9Lz;qHgBudwPLrXh9Tx>*FV047$lX7u9_3xL4 z0dUd(BO5A&!Vfyt*7a|_<-FVRH<$0O+#?7-9e1lBOK{}nT>X9Zv`L2q>Gks{rcE3F zVAHfeDwcpD$?M7D?iI$h>VE(84*)Gb)i20A@CQe_;@A;WBr$+6Dgfq8k3qWdwF+xw z<}K>r#i~?~2>3dNIuC~()3{xxOFSNt`zu{rV0Wc~C-zL|%RDY5SG<6)t5Cw%IQkrb zLc4bMx8VK;Vc}1l;?{}F)`Unk*p@dLEpw72gIF4aGCxhhz8A9t`kle+1 zupYxy@hz6=2c7(J|6Fmrdzx~G_J<)nhS6k`ljuiySJGX1$V3+9 zbtssKkor;*dfCrem|$Y^m2e0;-5+1iIsQMx$Fqp6>Pqj^-3B@^D&!%AvIrnVtMOfE z832nqo3C7_#C@j3{}{dSmB#JwE}kk|zNBoMw6xXLeq&h`b}pK`oN%6E*VsZzKjI|+ z{8W0OQBxS7I6kK3x5~jk2c;B}nrR@q{OKA2C;PCM+;Pw@%#`2W{BeXjhGjL3tTRMl zu^_+=8u`5?##Qb(h&HXKbc4oq&Cd zc~v92*e`pHq4@z1-OoN!{w=_FR>nOR1YGoZyCDT#a>V!w3wac~>9awCb5vyrF-*Z` z(=#Qvyh_Ba{eD$irxoAczUd&%F#C!bJo9H< z)HsajCdxS85Dr5E(h%&ai4i@6aYd2$@InLxcTK3#f0JB z7I~0>sS0I78$r62WAZtKjL&C3bc&nBvzW zTgrz|(#clfVhd%5EIT>f4BdM0#%~GI+=(qJ!LR&5%G_eibSygB>AyR4OPUmn zeu}r?a=nA|u553!Qqnt8h|SghP0lqr7i-OoFd`@58C4TyNt4pbIIpp0l;1?o&6RR~gMK+;w++h#TxdU-fz(B+ z*kj;{rks(kgRH*;@@UxY>kk$8Fj7!_hYlm34zuE>7f@Q_*%~o-Q=a_QuIt9pmVm94 z6LH|wA!LrW0{Kkv=ewI2Kv3*O?C58&i+e!=dR1<37uU9o-W&W#T+KD%+z!{aQ8fkl zX)vzFODf)TTJl0UQ|5v(T2cYsWA-IW$70CQ}yFhDy8>6{$L2 zgiZIP!eBKse7W|3b@WmNqfuL<(jmJD7{7C=25vGOi1xlWmP2D8RD^CHi2C~wYV*v^ zujzmPY4T7kR$n})IXz!h_w@$xHx`@85&iGwKY_2#Sm@)ga0sO{es;oO64IkWdYYOs z9H?2Ssx3_4@j1v9;|&P`GPb|Z^&X}iML1pT|8{}=>je34%SH$XnGLxm|23~irXoBb z1(NYGi2IKuh~n_mV`h6YoZ6qn|2 zfKN#JPye>j<-VZ@75YEDwEfj9};&N<|z-inuZMu=)<`bTWi3Ur9&< z9L^3qSm0`6P=rp2H#HI(S%L@n?aMLCanzLfYphuRE*=3;n5cGjfoFF5S)3;0vUGV{ zDGk{Vu_qCmoxpLxS5WHw1f3&#Is#*nu4|K=^07Bk=0V!<>uzP=ku6lMuBvn}&MSq% zXL_j`su)b+&+rZ(YcIRQ*~&=jOY|dV8vDua(zbUff-}tWm(%s?LMo8D7;?rBGgNb| z7#1`13kNcFy!D3hSekdwo>LCiemj@_jV()Ke9_XSg>G2(jzo^doWsugDl>69f%+?5 zJH0MYZ%>qo%p$R1K=liJr^4XP0L8m7CB+mkAX83eRx~~Q2a_h*9VD5JiM7q-FiAr* zx%0&_nIDYUcDcE?h0S~daNzpcTU&rYB#)0<^t-4OqE58qic*tFb)_L|br2HOn=7+i zrv)eSQi^=Af0h*Q{Ws@o06=1l2>M0 zE8*PizKzIXh^I??D4H}Nef?|8KLAGLu)NOax|6JVY4%9Eo1-^dV?Oxs=^)sY0|L^6 zP{+{6@R*OB_(qE7)dmN549KZ|_dPTI7ED*0#-^($6eRTz;3Ie(tiXqn307ktjI^(B z{Ti&nf)tPR*Z*kHc^t^kN*s&wfdfu)v*eFQW_F^FSF_sDkFXL1_$$s9iQElNZABW%b*n#x@w&A6suX9SLbG#j@oAS#jn-%ZgRC3w(;;|E!r-5*#&qaFK zdYSUC)RN6nn0O@+`Bf|X8kh)T=3fR%4|PBg<`lQ90dK0I9xIqLHj?@pS-wfoOVC-# z#E8F-Pyn0I&%q&H&nr?#1MHtJ*9SY4IF>kzWtQ$r;>wJga=P;{j_lOZCV0n1v9B#V zh-cLo$r5bHZO4fT1hRt-AZg4B+H$HqBBbtY9B!lJ$+F)M1MBLdj91CMXe|S|s2)Bo zp|jyYT-^e>3BFR}V8Rar&ZtmEEeKsWDx>zS{<>@X--8SbsqZnVi6$atw_Ak$D3rBM zk8QNkA3u&M;%m0X3c7z3HKHqw7RUZ*cdgKyR#d5Jy`WGS9!f1tKv1A?p~J*RjmPLB z^5t!yXvd1vuK#WDr%VVs=U~EjH2WX+ zhy_@Y!C_-hPej1Si2$T4RZl14!vN1kGO-)OV7UJ8ZNw^&Q32*H(ycc?%7?9aS5BnV zd3YkZG-;YXI_p%AER@}S=iL{@w+j93?Gow{j$rI$2$P4xv6j+l23hY`)XbJmug%a~ ztq$mh`#;Y&oHv&t$tlrGx<(sXxs@gz0ts2SGhOxe0R+N{pmJRv7nBb|K34<8O+4m` zH|5QSj3cje!IRGTa8BvIm+D#FnNg?_6XA$S#ds|0P$U~wza|e7=f&fDaN-Br7~S#8 zlKk-4Mpk+(`8nAJOf=|lKQ6j9s$|J2)=G^s3eN|jL5#c@>mrvdo#+UXCF{m@PJVO_ zeSNlh0gO3Fzl{yJ_&jYZj=Fo%e^E+I@gTl58T8659ve~; z77Z3kZWl-?gKa7s@r&l2<&(ne)W+iLsS0DFlOHQZ&6KbO$;kQOl^uIu1}N9L%%+|_ zg;Y}yDF&)*kHU=Zl^l{NV@5jz5A{VgOwh=|##ud}RPV8~&U41cobS7upT zo6xg=N5?eu1RLmbHiA>qa3LAE=$v8h239J-;F57WappW7;Ci;or$PcfBhHtd;uTLpgx3U^{T zf2Z%GsI5X$d3!4I5?E3VN>eabF{ejiBXZ(&s@$FQ*tX5Oxi)0+fj02(PnbX_HTBiN zkirspKGMWFqJv2tET<~sA&8~}t(`<~?^Lnpseysu{rOK1#)VMIlZwi zw-9*-_VVIHd4<+ao}qs9w%|PBn1(c&m}1PI{2!k%PD#hhPLxONaDQ0C!gtiLO{3Q& z3Nbte3`43aT_sZagq*)^HOGbqpxMEl4ffmXYevg5_ImyR>DF6y!A!=xN7oH2reI%? zx)quC@bdcR?SqdM%okadVJJ_bzB4iSuSjCj$@!`EDdlS5+EEW)LG(mUj9Laza$As) z53MXsphYe{>ySlfrdAE#*n}x5kLY!_XXNsgK&3g6a)*m21bI3|hhOupKEE4HsV1ZY zmIai-t5c6V)Sp{q_L^dVO|DkyHPLCPA2J7P4fQ$}G&z5INcDS*^R9guAG|v`%u%j7 z0O=}c%TtqA(oh_t20N&ify3h`NLlMVdJ;UJf-=8I1c=2Bzt9wxe<_I@#AL*?Na?>7 zilUptuG2V4QEfMHS(PZB2p&0oM!|F~j~}tNj2_lSsSe&}Nn}ZB`)Gdj*SWEV%&0k? zlxi%wxBLw70+oEH#ao_m!9^Rx1aOy4316~j{D!@1Q=BE1RdB{>qv9hl+WnFmRQHk+ zprIke^|&)&GzF5&P)c0TohZ$1)%5pS$<%|Xv9pZSYLI?Zl?A6Fyh^m=o$8z{uVFGX zqK#<2iJhjSVk9wPuf*;nR?Xl8sl)mJNNPIVtx1~|-4#4(s_JnMjd0GnS2TD-BgL@_=oS9#OKr*K`dO=(a=2ml2CFg`=gzkEKzD>E+{UYas>`0&nU z&iiLnk*YZg{DA;#amH*>OJf zvtgOEyg_9t-EQX^Lbx?E#<3{BCVPI+TQ%vrHj7{ir6q_Duuvk_t3W|Y*cQbpm_ zqc-(#N30K*OCJv$dcC0U1vvO_4=LQC;8qH#v+TSbNU-4*I^!xoUKCj#zjPAClc20W zumEko=q-#H0+zq4j36;3)~I8)NQ)bwrYySdwfJRSbE70 z3Y#o9NBM~5q5M{#GyWa|sWdmMthC_Y=@7hkldy>U2CRbCZargANenLf1@^1OX>Tj4 z!}6|b9nJq(qL5mmgE4l zAgex2Q44Wp$q)uFS~g&v_MXUB5e>a$UhJW*8HPGBY1Jyrob36mxKn`V7~aPcIvu~H zZ?D9)Lz+l(J0{?JEcD=V4TY($OT7xxAe^uAV@6IoRYtdVeD&Tua`ms(6JG0-ufHlHxA0oPhZaM3!}Kj{OxriNw-BxaHoRNvw+zTjc)5TF49fkkB!|Tao9fd z{a{y+Rx!uA?vB({)ORv-xyhN2((DAyK z!6SdynIG|HP7$7O5qC1%Fg(i;5-+0RQMso2=YVL@9JHbK5So5Z3g1d|W!gBam2M## zMma+Ut1;pH%6z?5XOHHnL{GywJ4_uT47Cg<94Q=sIPC4I8T{yxnauNY*{cpSq>TQ76P7l;#t4TaS-YYM~_7&pqu>6?~bfqeQUtr zc5Fo@Biy;M)EnKyzcJNa5CFV8KV^;RP70vjqB2YjD!%MtXT{h$qZz=D)X0-|skJkA zHQNIf4b*32py!y!?}$P*Xh=)G{n6`%izfqdD2uiLT`W^N^FpO{lXt^ z+Vzk}QA@jNz;E}4KTkS!XoH@#&aWGuuiS%V!%eoeZrl-1;=gNIDz-l1;uRGLc{A(G zE_ssS+T<$5W@CU!;x+Rk)P`B~v9Yi+6y{&^rMPu(#8#*bo#E{-EyA^L->BG}P>~pl zWrA`n$)e$1(t4xakuAztIFbD}m-?%Ut*wj;B3PPGG(++@)7p{M&rUWL<4Ig4(a@V* zIqSIEQcj)1H>&NVaY-=qgbfdGr~00m_oD}o+-X(-EhDBlu#}F zS(`cb!+FLS_Dc);A&+MTY{kbc-Ccu;!QNuWvgyKHMAd4O3{DoMs>lGzmu53p6*=>P z;LUD`$7u62X=|*JzOMsL%HU#VB#9y{wY@sm8*!MuVVZiBd1+ofi^Goi>)?$pbFD25 zW|jtHdr(qn2~G~MTT93}lxfxD?d}|Y;m_yKAFI1DBPDo}K{396FN}s07DQpB&O?MP z<@=t*gjN-%MY9RrzF3*G8lrd&9r!@@M$P`Dro28c+E=_?>M`@J5xf4N{!qiyOo>H{ zf@Y2UD1XBTmKKWCBk>#xbB!$UD((OMAaFdU2~7 z*gz7^g$iEWmpx|->cO7xL9mHFD2O8)ng-l5Q4Eh{v289hk^6Ixx1#$(aq^L0r%zPg zUT+NK^)A=-u5v&zk{ul7-ZisrA};0)TKdwjkM$-%o&rp&dvs)3iPn&5KmYi#q!&o+ zLdv^vONnJ?I57WVM{QWrPNO55gnUjFFNgxy6X~w(yYo(aLgX5YyI6amLTJU2tBaF< zjqwm^zpo@EpSqO*cXq8yPItRGQoy}V!6_yFl<+rYW@!z1d_x}FjtTWKXW-;#_`hFB z_#3YM6ItZrmtP^px2J7C4_fP*WZE!Z7w^w0b~F)wzjdTy?|U8J-C2pg$uq>AD%(0y zAl+W)NUtn@zb}qcH(>|@uV-R64Ah=5Lfm@fA{xfJesWV_gm+C2i&dp zlP_Ax!z`**IsMYJ7nAoEoI{eFtOQ^AJENy~q*QeK@AEkmw*745#{5QvBDZ_<(0(4@ z*#ySexv9Vsq}Zn*glg%#DMrU7A< zTZ!z0ej)LWY?T!*F7*_jsN|!{%5U1AXf9Y!74JMpiJ#xz72PGA5Um|Fd^6+k5b*0s z2vlNRTbKm$H(Fc%m?+umB0{Py76Nb*{R1#!+cU@pv*<2m7k7BxAg#?bB-!?C`eBjZ zS)R77_M$xL-vuR25MH_w?DWtK`lTSjvbZ^kZ!1cM4vz?cv9laD<<^-kWWO%eIVu>M zaI2t|X*^yZWE5yC@mho9JoO~_zKpzoUAkik^EEhmd|UO3xUO%~;?is5Dt@od@)pBv z*}FkBA+Nc9vA)()IhoZ%2h zywz`>lcp&B9+O%z?R6)0L*$9{LtUUaXR&z>XQC6<7*<{VcY*3o^(EN_tLNm)+quRu zlY^CTaN{fYwwXKWfT)tpu)aO5u9A*$eqihz%UEWIZs~M-hj-~zYIO>;Mrt$EYhTTX z-GmeoQYeQ|a<~cK>D`c(po{4vr`X2}uV5i(!U&?r&Ol_B{=N|Pu?`0no94jfV zqldPRwt0=dYE}%|IA;qfh#%924q2J~Fs|YDlddhHqSn|dMfzqXR*Nce!}1RR_Y8QU5Dr}J za>dl{%b1nU@6nc(4YN*bn(5rEv=!EPyXlYxG61rn+CJp47|BGCO6@tKu`VDX=7p;I zvPFbV<^%;64pl<8nv1iI5#RS`e~MgyQtmR(_@H8=udk=P`J;>H$+(Chbhx6jC1U5prozk}HZ*&G)V*DCeGgrj3!Dt~C@mlF;h6qgl{4RapwRMs}= zMNH-^^XhJZOb-aZ=!3A9ngR zi|4;SM6UQvT8xjLegN>cBdLqaZC0ygb7afYeUUI*USx{FrEFAa3nust2Y-!{z*6JZ z-mGx*r+*c;`$Qa?`!@6eoxJA}U#k2Axl#D4PJHb@-X${}9XWzY_=N)dpsLIFIK zRY^(ZQ4tV~AD`R!LdJj8>sbpqF_*&R#F9KV+18oW)&7j3C?<%A`WC7ggTjEcu}pSG ze}{+^}OYC2AvpnPp%j@y+ zv7hi?aKrzzP#Xk0i0miTJ5=>nwmX94p4R;t9OE_3a zMX{jscj_S|`S;?Kf@bD!1KvmbZ<}C#mLEiYTAed{Y=Dl5wZQUSNxg*?6mF(w{dX;@ z<>@}9>DBX#R;!I2HfqGB-po#pi68ORzA~P*EAg{IBO)pTkfdE`hl|EF_dwugVR4rf zhw1zl9-m=#aC{mY1o#~FQ&BrXGf?pA;fbjBQ($!gzs)`b7RL#WQv%&{~knMDpWb9`FBH;#cs@Ad1Ro8&+w9 zaj6o${|NkjxjVJp558`paO*2g@NdPPB`!WFST3|znVLQ zk}^2B3-TZANG4P``|+WVlxt^nxlYsxw^caUtlPaUG_){mIoPnJV40197|7^m;h_5` z>Pru0g#LE?%PdAY5F=7H8kHc4P16m?HG#b45^W@$uC>WIa$=!My))-wS2 zHLVNaov17$Y&+!7kJl^nDICe7T*lret7%@~JY(bxGLiaafOq|6jEj)e<@Ez&L1CLr zs$)tQlwB7Coa#-&wy(po3o*;t9LmYFwhHIxV1N%K|9^{#ju4N{h%UTv1GVpLZD^NK z!?o`t13@(R<}`ukwD9f0fg^^lvB<8!<<7iCGMEZI#bqRDQzo0ZpSw`9%W`>ueq;T# zSxjkqt9sK?MzN0&NZL}+_qc|sEdR1GZLh@(rNFbWFo9#M;bjTuUH_+ult|NRDq!9J zhVj4*P2X5bPsm<;lbF={SkeAT_JPmHRX}W@~>(1C|8v_ z%T%GyJyyheqCnDd|-h3 z1K1hN<;}!w8?uHFS-q-J?LWeS&M;HfiJ4#MFv}y`&XL-t>TP2j>tdXcxI5J7bWsWW zgI-~xX+Oq4Q-OU5Wc|M0y<-6iiCsYxUfK|TxQZuaMb?l{sY(den#xTy>u-lM7!Ec$ z9Fngd9Cn6kS3ge>)_>svYg)g>ElMYz%4Em}%em&Fxi*Kt39FLE_*|XAF>rB96tG_k zvH070?#CGNUnGHFtDDy$)*=6b1oX(5hhs!*nM>jx`w%u?Jw+* zO$_%Dq4ryWifOYd07*;5h$92%ZAb=I?#)5J5aQ7F!>0$hI|1`u!Z~AFNuB7w$01ud zNxbyt%vCHt5*pe5+U@NvzP7q|mud9_+gjh_?ODV`PL)(VU&w?z5>Y4sDU}Ofvxj=k zhh$QQplZ;b*=HO9?PWKzBefGBs1c`M!p`;KoB7{r8EWWIuaAl1bGcwkKHOFUZ>{AE zHP}Vkz@0SZJCOc12*y-y`{-$ZA^tF|Cb#P!s6QC9FUpe^YqgLW-g!t^X2(oIh@V=) z$%fRdia@0BD|MWH#7b=>-ZDbZ`k28c0I2wS_KCc-+@`dHP3H$tn~n^S?l)$=uAl>& zb8ga`4^{Ts_o)W}n7ohA}IP2*7x^9kM7H8 zVjK+Hbf>0!P~&mX`b1CG9v~cjgf>FV@V9;M;jvdW4O5s^_TnN#Ey4fO?R6{wNe&Bz zOw9D>);+b@8mg-+22s6uXkZbh98P&;_hWC>djH#stEZhENX*UaN0C=ckqCRYUbYOD zq(W>;OA*hi!AxG9vSb}TQgNjBv^e z1yZv2rRWC_&*+cOCwCOQZW?f#gIfya2(A_OO#!Xvm1>_OAo5>MGeN)_Uelf%1p_+$ z7%1JCokJ3W!P zw97OD7^P~uWXMs9DB~SXSCNDC`shWNfZLbhG3CdOh^ljXSFLFFHF|M@iN`Dr!?w+d zHx@kd*K8p5)`97SVY{jn#4ISt&lEk$s`U>bcLrf4qzeUu`#a^INeZZvh6eEEW_YrL zegRS81RtP^l#I~o$i`fFC{22PExZ$KCB#1Y!FH^;yQl)<56rW)h%8`6CE{aL!Div0Alt0Yrrpk1)SCaTQ93YAg#) z02hD*hZeQ|SyK0WDh{;67x3Rerz`RC`1^b{zV`1k1A@@-uV*?G0YVpw#y!ofN`}HH zw|LvD0f&CeaFr2jSDR=3OxxB@XBo7g+d$}e^u!G>3PBjOIPdbs?4qTwyMEpVr*48@ zU5~5a2Hent6w`T^cfB!P#OH}YN=-9WWe8Sk_!up(TzFck9GS^zVNEW35BJ{5@Xj9r zIF7gFO8R^c#e7R3Sb^Rz>oR4=EY;acd4Fc2DoXqjKTeGlY4GEHzz}Ht{CIGg9<|#1 z)>VdEI>;*Ql5~9JWy9FEc-)`X^LT!6aCjB)wn%a`szCywFskL(&rF;;Q_D#?)ewBC zUdEYUQ_7{u8+Fe;^aw?sO4K<`~(?mHiSlKb! zC&MxIhTO2cJ|sk0h^Uxy^Yc|p5&dv~SQH(TB*iWSs8M^{(Q|zGzWrDg%(UTd@U%UPur)0n!ko85~+#k9Rag4IE4=dK0cyXW#&M3 zltbo2Q)oy?%!qSFF42eqrdVnk(fmTtHNr_Zv&WX0Bn@dbi{a$fL;P_2hul-n^ZV_G zd-R_Pq$u%hahL^v4#zQGCVwLm7Z>xFvRj!YOT-HYA2!)=UZ`tfTb>^-^J|(71V&^v zUhRRx6Seh15kIGe3U%1Xs~BAE{4Sh+CzlbkFDdmk@Lxmg z^a=iU<-V-urnheN@EBs+Z^PWTo<*7`{URt(87qr}H@GpX#r7Ul+7tB>{K?NB*CUK- z>YMjpIWtkEsoOueUBn&=<5(*ptRm9QE(-F%Stk^yH{XwwkdyiTqFu#;!)$zaeWLO2 zo_pXBkxSmULw``q>zu=hqqsiAW||EALWVn|+cyu6f6dCNda`Vz(S9h1b2e4ziO!Jn zKOM)1wzP|TF;IWiXlcDYI95SUR%pU{I-i)v#3stUN^r$@rEo#jlQ)gW!3v*zyuxV; zu6I0br#m^XkixyRA=joNaOrrVgP(YA_v0#JiAeebFGT@VgMP6@d|ZfT)gn|T8RA|* z_TnMpMtHzj*~A}itC*IxgQ)NBTX^nDnxYPQfR4UM5J7WP4AmQBA?3`mbgN!V)I`h` ze2PQtszy9%_#@I;UmY0xnwtJBxteb7QIr!r2@Q(A0*ms1(!Pq#Y4iH?OcZhK5uvbf z>o)-;lp1M*cOYcK36Mdq5Id45j`$zE&GY4$$?*u;k4v*IZ~WsGW%(c%A*h$Z%>AMZ z)h1!=xselsi#I8hO;tr%e3&_`e3&Qu;Ssg!yKsyFz}Rb{`R$*#*q)?l!=f5I+@BYU zg9H!RPHka85<%So6(==)E|NFicJQvFPF}%PkQuZ{Wz5X(F7PgCph|Dmh+0`Jn%&<{ z|96bgHJDnFr7TMMQwJ8h+N5?Gem?o?O(3un7lg27i;H0!LU#We9(X-BhQl zw-wH@!>Py?hD%Pb>UwK%6W*f+lPsD+3i60D@X>J9z8wRsYBi2Ms`4NJc{Jf`Ay#GO zk*h$N*qoWj&%L>BL%y780bVnW4c{B|wB`*Mn)8D^{9{2G8<{YD_7n#H)N~wrLL*VB zZOh*IZ4!Y)=rpV}i+zEbgWYU$T-oMJ3^-NqtFK*P8_H^u=}xCetFRLfEZX}JVBdms zl=@p~QXxm?aZufx0<~-vx#<=ZT0JS^*bish6&_HUxUb_Vm zx34~-4xbW9d!Br%p`jQf2QWQy7lN*nk?kDb`$^H783bgvxnt@)Lc+t54lJQ$@iU9% zqzx@%BEzL}ToykZ%R0ME`O5#h-c2s@=k-sumUAjz9b%-Fk*Fz93oYt?jY>xMG|S$! zKhv1FQuxM{ik`RGw$|c1%E0W|*;&C*KwIKRV|DSe+9;147N0Tm>}zIK6G)-yH+XXz zaZWhyH=mm}Kv4001|W+eg}e?n#Kydro+9m(C9PgBOD{kSN=?T5t;6NRaJkPY(k@Hk zP-JJ!V)4Z>wJx!j$5TXgzn(J-mpY*)MKzPu1541HlH7$|YJiD~8D%967vl{K0{;Ibm|9;Jg_hZ=&r7BF5MbBLh1U(`jFkYhdInIY8j;i z@zRs7^;r?$Z?9%~{XN#&2LUB>jaciI1PyL;25lz2c|G+MVIwVnG5c|_Mv`vDBsz0X z@)OZZS@7Duv>hqskZ2MPYyMjIVBj7?Vp!H2sY|`KkT)YY-bdtuj~!9}$0p;!qAm zjP#=W&eQR5WA+XWPw!je>}p9+4Oh9L&wOQ{D(m7>nXwMUYD%OvP}QtB|Hr`2A*Syz zwmzXkg7}o3LCX+oM!hKE=x|%kx8MBSmUF#to?M>*L9G`sD*C(fJH~;`>?7VSC6$EB zC=5p8nm*g0D-EAD9_qW4!K;fN$t@wR%G5|b&Ax-*jg__>fpJGEYC5_s?vw7#4v)ec zLsAXe+h+cEluxR-cxk#nwFd5K6FHcll`l}WCbH!uxrL2)Pk{t+?3Kb8QcoQ9RE6}JDBh@qced#q=Q%Ye5YMPf|?@xkbB$KCDAO*4l58 zJ6xgZ>_g_rW5YI%i|7t7cFL_00pb)PK0vqr$-{*cDai=0NEgPbO_^Mg<9~qnb9zN3 z=~b&3!*^cyYySXlZ^e%VF5dPAHO`%}i=O~17-w0!)0HSUW~{z5I`^Dw8u_4R&-ti@ zYHDTmw&z&|61@5fa1Q@ysC?FJ%3KS_3p*<;cCfI z)4~l8x(o9zlT{8)9%#nG@N@1HB8tsBkJ17Nf=2OmRT9)C(NPOs1fKzWj;kwt_+3+f zW-{ylgr@r7!aE-N*-Pg6OdaKi`9EF_PLr7Dsie^bv5QOMv^RdDf4oe-Ci+{#$NspN zeJpow$$Ax(Rew>0w?F?uQK|y)V%mVtwcfB;x4?PTL8>KbU#zMk)~^vmn%gjnve;vI zBmN<{Z_VTRgU==9TUE7rGzNvKg>UGj!(^%!)>tNuz@(WmMnH&XE|0o24_OjK)3k0+q9evEVz|MTAyMZV*_g%jG0mPO}IPkHDY({3i3 zogBB_`Fq*F%~o!el11q)^|y3gu4)Snqz2EIrFfxU^rNsC%Oj3Qu5%bJUSc0L z6<-eu=O+y^FN{COF3vBWNJLB*zjtTVs-awQ3!eO&74862IL;A!!u z)}JB9wq7y_d+s_o61~BQBO3-XGBKPa;#AG5rf@z%I^H2Y$V=5*iobPAZsT=Q+)+~- z_j6@`(VmfVCHSlO7kQAk<{^J4V-cv~&a>kuz>+7xvp-xsmk$-0`#m$@2)$3tiIOKl3HvFnfrQHpF8=I2 z6*}b-I^1y&O-DaYOg*8ovO6C74Gl7GGb)74xQ1KIA!k3;xVO){-HZz5yBgcA9VtBL zBY>x}YasXZWR_joT1BP9qW~*PdK?SAw+3IMf+tq#DvCA+Uxa+EKSNWMZY9{Kw{vrS z`SO@5H`c4CjVFfJ60)gFpCRQZpBbCbtZyqL^!B%&ZN1p`c-Oh0`N5tGL2omINATD4 zYqFrk`}y|o?c=%2P11|~wa+D=kq16rZ`p{k8A=fnKk$kL@@n*Y%B!d7JdNH6XlIcN zq8E9uttTntyRb7!#moJB>6YVuLdoGD!1bv$EA>e+zC}5(im_X9ukWphVx{5Y7;sBl zl0PM3y)HQwvHxAR%rkbdcDu5bxIDiMyGe~%pk8zTQGUaU8DtsZ#Y}g-p$yh!qb^slrp+YE{QI7!sgoDotYX*B>r z*5=#^;9{=hAHW6ca>M@pZ@iZyk8s|DewlYPw{0!WAGyi;_faFI9bVP67}6YR;$Dms zj6_U(8~yH;AtuthlvgvOCb&3w@nXCtH|Yz5Geo~vyzWow$E-z{hY2OHKuX44v8H9< z)-xibdf1iiWXG{FFpm9~<_zP>Ez|xlHte1=yS4JZv(2W|xN{O?T2yylf6zS5Y|`}@ z;@Iv=J*>iY^gAiUM%Q4T*Zg+(J65Y`vT-|eD`MtwtN0XnUX<(p(5F0Jd zlTz!c!>=^#<+N7lrc$AF6bV#EoAS%02e;s^Hk>6i3wrvPtv?D6@#N-W#liOmjeo4b zdA%JCW_!SXW+(g)z=IN2dDMEf)cusLVfVYGGuHp_>&4#IUfT;79+v8N&sp;ZTl$0$ zDKO3CFofAhzqd9u!dX_<{o)}c?+JpKH)v-UZl`UtR=Xa2_7?o!Xy=y`Hl>V$Dkn1zo6$znxmbx3j=%7} zT==ZsQxuv1-qXW;ZRA_mQr|iwWHRJsMp8yi`;(4-MrP;GRZp1f6HeL1C*7+xhb9Vp zUUlAbuX|%3DAv(q9t+W?jAg3Z(iBn=lcqO_^KkZ#T~KHcQSe3z0l!}*qtGA^O%j~T z=Bw3*jpR19XD)OgSP2IHOkeylJ==nHT?Eg};Gn)-y>p&kr@YWE{;$b^-l8K>pt4+g zZiAKfeMd?*Lw5l7ifQ8u)bIHTE#b3kLiLLL@SA+0!Iqr@%zsF#`Rz^0QyyYsq$AS@ zOx>P##_u1CL$t#BbAc=)jY-m7}H_>Bum< z^?!hcs5pl1;OP|INC-E3K`GiCf@~O8D~$o8yNsJ%6B``$z_`j2pDsj5x0uTE(PWvb zs<_4^s$JnQw-I75&-LZsu&sXpO%^`7xv&Zxp3gd)PF>VM!qvvbz}1Y|T#stgmuK{Ci;A#sl32UtAWn>< zU5c`0^b6cQb@$%L-c3^nL|U#{awIM>1c7`MK;7E+guNi?yS)7I#yY102&c&R0AGnnN@pCbd zohrFt^O&PPGrjTPtVH5E#`y7*JAa0DKOa`cNBWJ>Z7>zYS*M3;R2CgiE3x}B#RLX3 zA#2NV9}f}(i15uM0{mSU$17HDR>kS#sa~6(8c~2AN3VO(pH{MTo#R6tSxg`U);K05 z$$vLh!;*PXKbek&ANN@AowW;S8>^v=c!Yfh3{u-m%puc6XS>^{W}^F<7<;H$nvm^6 zVqy3usm6!D479d}A5w%Q#X0~*0e*>W{Z3iU4bzk<8x%}TKhBPJ4Tp7YWfRgYhfT91 zwbC7gNRv_XSgSEw;vm%!#UnK}nCt5&nz~Bio7{ChSiqmQ8tarBV*_W>qDn+1AJPIi z2l2(b#y37-&7(5j8~XF{z2ymNYa5~TBjvF^)EHCt>>#9CO&G)Xl8tYhsOK03{ghIi zx0oGyz0ltNEg9@Kb!AQqe{dicsg}Q<;ezWLN0eH)ohq122OKRU?$9mH;&M(>v=|fz zP{hU0Iq+hnX{AAnQdbup(>CjGTtbe6p08g_j%%L7!QkTvT` zI$KI-w_v;)sF{lw(?It@wvtOeA3saAre~N*ltBso zscamypWhS1n}v_oOn)RmolTNyNcc?Gnzjf;MPaJE3wgX{T3%URY2|EWAm)- zTj*oS0dOq1!S59+eb(lq5$u0?bzcKS_WSQ$_n?(ca;sU@!;)F6p3qO>@IA>$K{*eR#EtjN>No7zIxolMKgBYb@bsmc#r!=&?jy(Kw8lqx7Nw99j!{x{JoV^-v1f2^7m*n*r2?vM+aV9vQv|8_s zJp7w>#rMpFm|N-tlOzPOUqh)uGT$P2sl!w(~m*q|bP8#7lFqiQjQ9 zwZb`;4T5+uuMbTvqr=f7cVPpJ1S>^(iVCa0Zw?PF$HR zQ;1ifgiq0q(KUJ9Q+(6K zFP7MPNt(1Na6KcGA7H_|$|6;i92N1*yZ9(sZuqNcj z6rHC_hue2m?(FPyLAnWa=E8qB`&;g~w_s4JaqsRqjdTDWF{3y8H>?ptry+8a@VV4c z`G1rt(~7u}+ZOy_{QuCzmj8;@o0lun%vY}0(P>>=%EGsA4zAsSopxMSc&Zfb;v;tr z*kVZV>AxL_T2kWrw~zLr>3i)i#^l6d`r65S#N$Q^rHJUrXpa^Z{8RH&nuLMe_M!S1 zniviEP?T-^J|Hp?mn@Fw-Qt5n?HA{yP_rA)n4d|Kf<{m$x1U29$uapr8~}ZbAtP-n zp)5%7rB~C3UABaoiTgvl=_wNuA6lOw7Jn!xA_TxhhK{UV&UVOb#HP!8{$-dAT@jUDWg=A0o)QGbsv&d6*qlW%~`0-neY@y32PIfrQ~* zYSYLO1`$sQ-xf{RPn7~R9S|=n%yh@(tXvET2WlI2u@mB<^XoITa$7`$s5g2?NhzUO z(|)D-#k;80<~C~oM#{48U4K7sBmP!Sd-gGF@1fLMfS%B%1Q$eIS!K{pjYf8n z+IBJQ?9b5-0e-0Wr*bR}Hv5i!RZ;YVZb*8vLz9i&tCjNm#`D$?JS`PNne5P!7h{Td zwY4rJc12&7szf*v_}@bH{OON=oOAv4i?N>?FUeTYNN%1Y592A&(w7g>0N-YkDmR1G zc8;Z|l;Uk3k*YknT~_y!A+W$W=U9nlQKV`#7#`TVgok(!!ea+Dq=^Ki+S2Pn5s5%o z7&fpxaWg)3NE5=7BHsi@l3FfPxmlwqUg!AUhIL0k;BW*I%^#ACqT^4>w{LE<-?46( zdN^eOjn(sZoYMvZ0UYxp;t0U0Me2NgTtC!%8}&&uYUn!zjl^F@N0XJ98t#-(U&V$t zgaq_H&5}YpI;agMrTQ7pU>p}M(*3UPd9cd(U#2!9L@2!zm!eHq!hICd-XIKF`QxQz zG75<^F2n%;qBl%W-2+9DGCt>c6qSOTyCOEDZ-`JPCG`E7j~il374ciH9S6Yhk$ zCk_Xa>?naFeBb%~b)V&y!iQ04a_}lB`~Y?vrUkpdWPdgh;Mzu8-}hQKm^+&s+;fdm z7JA3GbIop*vqr9AGs}iwVe|?1}WryX3V9E^2p_|LeXW3J0{9_ zrZ?x<>3(o}8uxbe^q%MLWxeBm%^f^Su-T6+hllBjjr>J4_RCYnjTuYKK>+g;mC5UE zt*vhPhNR!AGhoD>a zh{dh#9c7hX%Eyh`faRku^TUnnEJbhmNa6b7bxW_9`@#1Dd}h;3Nkjb$k22MAev}3qm3e8 zUy)mSr%u|OHONHu_y=_wjMtl)KP;MPS=#a4*ivADfv5#TW5$#YVcX`YB)O5x3PlhFNn#Lqk2g05N~%G0&g0Td)K-qd zJ#cC;=xtJGf;vdC2#Mp8s2cF_r|B|1W9rh>lk(#sCB6U75O1kORZ(tYq;_4W?m$If zh#;->EEr9n#bL}j3*FCwW6m7{bLu~+gH2qDlg`%i7Ep+Q6{9`@| z4Rhs*X%em+M5G`KDmtcGxJ}aOvV}qsn&3ndVa7X=*7RhGqs6{8_Oxc^Zd+wMP@!hl zh}q@W=IhcUm2^!#-tMeJg1khAU3q--;?!g?J&hQD$#6OlRYEmKMhXaVTd!eRrOIEb zTyBgSKCL_*{ULNJ^zMTuU_OSGv_zgb7f*mnMkD9piIiy@HQp%%=~4PBIU;oBc%qP} zj>REWkN9hNtGd2`MT2CRxyp}Aa!Ed8Sm-CS7@EnpT{B)zev5ik+Q62qO=(??^*X?# zx7H<-UOddZgi!Et3u>96G4*`!`IOsY)`u5p?0HFJ4G=$`Yu!w$qHtVYr61?X zEw0Sr)G%zo5P)IuXizifeA;AhRQvf{z{|yP8qe#L`DZ#=LIg@JnYH!&WDZO*ptz97 zzb9o7d;mW$yLX>&w*BG?F$5r-;8%Fo<|?P|Qq0aU6IMl`)|CC)GKvIO%WSi)fdjwX zcrG+eTYqyrz6ySV%ow-ncBrbK8S5gbOw#N&U@DHHTk>$C~_U*+c=M7(0G~ZJ<#l{bmmXyDS~6MEyZHO;RH=iccFZILjP$A|Bv7}< zc?KfBC*-7};a!B#iHyr?jM_P1r@qL${KO+()Fg{|II^NiUzaE^+2(h;bSz5iVo;%; z%llDXHihv*>N9&kU=B7KAjCNemaW8RiE|$C%<^h*s2uEQ7{!W;LMU8|RGfjtpeQ`T zo~l#vV96i1KFiyB?|vi^X) z4q>RY&ri*s5JtE`C;)E9;QmnJn4B`(DV z)2!kQDN&n09ZHMBG&v@sPHb*@Z^iyrD%Cw?@A;awF)goiLPU=3V_v)6il6g2z+uOH zAI~zuwv15(!oDpBVkI+u>6XGg$G5Sfr9*>P?u0PKCR^P?8CmdyPPo5d&~t|-yeRFHVJv9>&J`~xYG5sLQ|09MgixOV%VTC%s0-B0 zN~_<5#PUH#MDJk2z4JSt0U&oeC zX*;>hLU$qUhJlizEV0}|?d@dkBsusZ$mE!J_od|V#@sxzOCluxaDDwvR z$I&UaQ^%TFcFd>VeKvoB7uNms`&ob)(EcV{0ct_?gK?D%e*E}N#GAz#sKfOi*8OVk zUmxFFlp7qlLY)qs4-fdXi_6eC&>#ghG=|20JP9Vwqmx=+1D~izt0=dI*xl&<&02HK z<+%vzR*#QwFAB%Gh*5*F!qqTnG00V2)SPJ))IOOm^eI=RMa!TwuS<%glDBwR8iYV; zR8#9qv9cetlZ2P!`DOovQr%PPXEwnj0;WFNnZg1+pEUB(+%*K~ zE)ytYLMr=F`DBkQ;x+uS+v0G+8p7L4q|gDc@;;P!9-=i>`LtAvji1qxghKHs3m)s( zChqfyE1sfC-s4jhDoO-CzkR&f^fsy6gplvyjklMX7s0SutGux4B%DT8%eS(^I+9DH ztv+HTlgS2p&dV9CliQMcxELEdlz}#If$~9o4tXnb;AS%!aA}a0DqvBrtR@e0>Cm3# zHGh-hX{gPrATPl5l-daOgs3r+bT%f$)soxD+FJ&h&X7zF^HX?ifBiG%7s908B`CUN=8VFQZka+!iq95 zrouP`I0PczMezxdHcfAvIce2Rp+gL?q(yCzxhw!E4ph$vKJspTNS0oZ0Rewx?lzug z4`#6n*qK-Or1ODJ08jrE(BVbys76_;!l&xJE+&xhY*E_PIc82Xg9gc?*|$sB#qq;Pyu^6WymVh;jf$ z9?|3Abmp@zcMy8vR|gr4c8SY_uB(VXXGzl`W1_k1GBT`>d9r)QQ<_UYvOh$XBJ~on zn?GSoWAt_Ugnqa!BO#ZLpWGbONo>j_MEi4wN^Eim&*KbD0~Vm%39y*8V3@F>?JMEm zfD>bdc%eWojjaq(dHL4a(|*Yg*~*L%&;i%txTtoh(~R#^N271P7kQoHlZClcEGgO= zo(Cn^+8N4qjHt`^?(0*m-Y_ZD=MkfWsnPL)aIklOq#$|QLNo>U_A>xU+}0_%1u7Ey zT!||{1H^INhAD%3>+1Wgy2^k>6HpTJPb4{C$0QqN%w!X2;(g5lC(7;}`5{ zBL?6G_C?14DSCnk{rKOV1`?hDaNUoGCN8uqxP-qTl9i$8&f24!v9$`*Ek2`?jXu`R zqrE`1>)P5M)(uW&?^XNXF=BXLXH#qM6zmYyX#ndKT54gHxw*8;M0?ip?w?^9={4Vk zf8of&E|U0wf&?J06sO!dxO|_NOvP@g-oBGtxS5T} zkmZG18rDZ#z6hfqG+4AHHPqzYc^wlp;#M2*nWTs3A^<~(A> zK)BBd31t^F6ra4*89JK*ONIs~9JI-EwN`Af%^I)5Xt+CW=iqtWGVEOOa}=2wP@D9r z(GxTv|L=h-B32X7fVkiO!^WuY-#4ljj+iiU6 zJN*=$=Valm^~fa4=wiri&)8iC+%EePiApNciwn~fAXWY##S>?28{z-!K{IEqfu`?} z1`d+(RjPUcoDVUQ#F!7fSy?70f>kd~sgjI!hkVPp=5M6rNLy1RgGAfay@xHx?Pji?MVJGeaGiSHt_Gz_rA)CvMO=qZamSsF1~Fo%YEQJQGB1g;n&p6dO7~%U0%w!*hFO&QiS@7 zY#R=EU;b|ps7OsadaF=fzF_FV8vFC-RltzW0(#bf=cHLbm6^0(jg>NTYGAD!6HTeH z?WOILq~oS@v+s8 zY`99je)F@H*!BrOBzh3~s5PqQ^8HjfzgByXc;HyoMnk*afH%CJ$cn-WMXjN{&4`t0 zIxY=c`Z*Hd?{kd&Uic~+w%&CF=o`tpc!42eO0=bR zD;bglN^Q(&f-Dg~_1%teY=`9Up)#Lv>y)Q6UHW!)IXo=YT?Sm*fC&C!Ai?vK*J99A zJTV`L#*g1O-c~=-($Z4lt1V8>0CpncXuKZ}6+xyeJdAbMC0BorO0r^A)@hngdCkG} z+Vz|`+)(9)aC|i9pcH=VFZow7ytAbaJk(-N1N?{%=M)y;Nru?;UK3;DhFJ)VYA^TM zbVuX2l4<*!a@MEycTvv-6k<0e>3}2UTz(RVA%^IP@kGah2fdoAv%tbboK7%X?pD@# zQB{(pW9?&AdNijiLh;{?5N!CpaMy$HH|k~$?vE9nFE_oZ@zs3;-}ee&E;`le=XRN za(^G;+CKV@{7t$i`J6jpmV2NX05BmzXPsj!7B4C?{{E3(ViViS*Edu9HgQzgKu+tq zR`PZ$0|J1@Uge8y*WrihAAM37wZbgSEB>+-a9&%QzIJ(~l=ft*XJrHA`f67}f;I`) zhhEmn`o+m+K^VKZZq zv6iY&l7T8mm7L)J2}S>3;zWqwpS%1p(gYyB_V~91ia(_P0Q7BbUtP&#NHvuZzB3){ zZ8i}w1u_*ajSxw|Te(fF*B;hl`G4Ry<@3z{slWeQ+5bJ+;j3)!M`PeDQ81_RDFi>P zcRo&9NOG_K5!D!vCPLZAmNmzJ@~&m+5dk%J|NddZc4oo)9`8nkvU=j(DEI)4B`V!! z6XEkLZ!o&HS6xDcZ&vR=zk`~3UI(+T(aDK~f6*6+hb&zSa_-8X;s zu%bz7qq>Hg+;^duN5do7`cwgU{RFG)r^R&xp~2K3O_tC`rQC}shgPIjZkA-Tiosi} zg`B^6bPuR`)#dvuBk!p;6aD`jWmC2JDEO$Vuv|;eWZ$qn%D0xFQeh+?oJ;n(I9H>3 zgk-%^F-a6QuuDTF=x$t<1}1eF+Sl@`wReb`Hgo&k@gcv z_+=5ts}EGijm^xvZd!LKq#gQCsj}wYiH;y@Uq8hi?;_F^0QbcNs zF0!vnQ5{j?HcVVcHGvYcY z2HN_^qm>BCb)lA5GhiU4c9&O+pgyrGufGweh**w20s8UsuoMkqOf{*FjuRZ+OJQ@h zD?VKEkzUiauIA#3BW&A66aXpj&dY6t+5{CSM6ebtz?!E+<3b-cwi zR;PnREsC3A_7wo}n999#!T_$$Nj;;Pa^B2b-#^fT-)OC)1jP6E{N}+Lfx5RN4HBkr+=xKH-+r zU-34E*k(a5#)rOq$ZXme4YWWS{@D8&0U&2S=T&ikb3ie~Nd)9ocwmF2z;KwO;sfB5Jj&7cmtX+44DJ)ez zwc--{i$5+$y_zciAOoiOswFQ&SRF=20v;Xl%QpKD3NsO%&u((P9u^ zFw)kryPrF0U;g`Dnq}nA(0>OSGJLcCUMxaRFC+W7cLO^Bk_@mEVy9Kx$S$p7s~{N& z-~@KXlTab;&8Z;4D)Nazg+vqi?UR-gdP0OEel}H-yX7 z5*23h=LZLNB2eezPxZGhTwlpx0_}0I)wu*5_(}oIuD+jPl(p;kK!# z#bM;qzo?F99asK7{09(FF^?d*c#^kuW=G^tImUyvwu=dK!%}`Fl_I^T5e2rAM4z~R zPMW8);&5sNm<6aB`VpL|lUO!dEBT6JC~QX7$79Bq`@tJS3cuwYItxuKru) z<=@d$hehIP!Ep0IRE#7;eB3amzdrfq8mGIl0hReu(jeZd&Av4WBg67G!;W?;X3@y z;x25$0KQg10&UqZvbdVA4SnBry5@D+^~>5w{x~T^ zS|k}%lJuUt*L5hgMB=BfcIk`c?8X|S*<$=K(rEcFjG(aMU=Ox_J)x?H-IJ-_1;t7q zu{ns_ z{CYu7jA}YmG7sE1)>-TVl4d136m2C$e!U<2Jqr+*!Fy`ng%7ZL9$9dv!aV1qLAZM< z>r=Bw(@V9H{9bRae^XKIEz?Hz?r9S~GH6xj+mvN~1;880C3JO^eVfc>tbLe@=CKc> z$4l((_@NLV!9b)+Or4x&h#F3Ysv;bLNM*Jiq<11v3mfSMP6e1`c7{`UtbUX6J%FZ1 zFsVQ@1XFg*!R2u~WS|`=+r)+nn73DiRjFYK?`I!1){38^&*m}?1h^TA`@UMA!7|+) zfBJi+b&M}ye(A}+U!03fES&~LlH(`5w;w76H-+)lI*e0f2xx1p{e@+*g0fkr#paqh zE%U8!;~TVKUGZO3q;z?lX`&7Yx|b^}YP%ZNk6J&~h9br?7Jw9E^8JW4y*b!qLU&8n zsN4s^k}i`A1(ZUidmJ|SaNSL%N#U&d$faSF!kGdKZE*XBVQ+8)F`!>_l1Vhmt2b=I zZ~p;Ah(2&o*?8A166oui?Zi(SPHU?;aM?Ey@F<6lE%|ub>MNX*D5?sQR0{h&7_D>t z{(Emcy^Q%##C3u5gmaWj_kitCEAt|8KMeF?+k7op-g`{W2$};#(Fr*x2?4uiE#U*W zfkV^CF)PFm*FHT#esaae>$~e?ZrZ}_PcJ#D4p1hkt*|9a_q#=ie(S`R?NQPkQ~K0A zy6E=n#A~xP?keQ)P~Jivf9|VbwLI>|-Sf2K9;!lsK9Sa`MC0?|2$x=KCl$HdmbED* znc`@}5mW)DJUKvcaYk?mgFE+pJO@*20E zZ(DPae-xvoIC{RUFO!0g)*2}nVakp1oe9%!+u(ZqHU{CSt@6MHf-Vs&8X3RaUBA=L zPevP*C%gttNCwB-7QRXiiVQsg7ktn75~>AdwK8A=X-|75_qLpp!0_S%^d_^MED$`DB!ss$=CKd{ zrrXZme86G*&Y6L2I#BOI>o~WLu`JIj&Xa*=)7J!>a2S(G6Lzl7!sXzG8RGOA`uKu! zqZElA9Y|OUNnz^d>-(w9@Y`;B^?hD_*8WzV33*M7zqqrT8`FHsx!;57-pPfhGV=7i zWgpkfzToCk|5^P}ezRK^15RVFKgsg^T%QI1f}2*-xp^eb1P|BrM0sgDm`!JD6?-*B z8M!}9w|3eFWfxinHcsC?3V4jm_-UYbF!E0GUEbco2ZUVO9@}U7pXXzLhhwfif5u() z*P|IgK3ocqj*mXlb=>y^R56>r&N~vaq@dxkW)iQ7J?5rJ(-tcMw0DZlJX0V+(ApbR zagN}yKiB=-qplTQvtG&25nxF?kZEDX)L&Wz0AMnr5gQV;G3joF5bF0c{?-eGr7lUY zV`23t?zt<)Psk%n77D%Q-!xn!K7TX(_`uM|TwUeU5g*975ieHeiE-(i$28-c@?sjE zKRR-D$r3b(>r?f{p3n59d5Z2jSnk51i(_Swj@nMC+rh7*@{uelw;3cRiB|}Ym@S0I zfOE7RsiTWI5d#m%POMq8r1M%N27Lf4jfe8h9Om7-V-{1w8Tj$vEq_u(Gv_EsymYsA zay0`H1IWk$05TkFzyO(jJ$P3$M^jqq&64MD?fydp#daHAI!)NlROm`JDmgUWguf)1 zhog%XXWTCwkd0a9c@mK3e%BR`K0+b%QLyH*&xaVPE=s9XfW~ zxA#>1K`+%q5@c-hCtJiu=P$mraeXGM$j&VsKuynw4=-_WpHQ#;`pRTQ{T`bJ^!E3N z_5s^Z*=+{8^=vT@qF!3MKfkDjb(o<>!uchfTrNAb_@7{5K4_PrM?e)K{vRCrRlsr` z+Ln-{c_SeNk2V58s*s)zCzGp1Bc^quY4lXW`3KLGeQHTHs?Qk-D*hB}DFy4_DjwK5AJRw!gUci*AIXK*H3~JqcdR2D5caF_ z_HF(XsD9F7N)GxWgs*N9`(695wLMw7xH#M0T>ul;5Ml98Y#5*7U&+13*5`SQ5qSQS zb_4{qJ{&AKb1A22$|jG@u5Mudh}(!lkbjhn9F;Y?mV~JLeHc+5 zhYOZ>N2(PPHWh5Ldn-nMr``pW*GZ$?h!6 zHj(SVEgqFfV_P5mQiwpNRa@OkYKSD%EJVY`pTb<(ooQ`t4=xqt9 z{6ebNk6_@2!!ig8#`_EzDSyjvq@ zpGkVQF^>V0Ftb{ZkT!14ty+nQxM?@|+xo1SU2JvRV_scu4UDE>N(+HnBw!8%)^2s; zDWP!ell@U?CD0{`6B$+YoJ!Dn@?py*W>wyvU7G0h)Kbv;?ZcSQlC;~Jrewx%oI9OH zs!0(oei+O22bG6vS@WI#0_~;ZEPfvz7M_^gGv#% znl1=h)<{rt33UNJ%&Vc>JlS351;gf50I|4%IhgRcw9_Yn3sr zR|n6qZQ$yG46(5^!iiPxU!kmhmR99SzO304rc1*Krj`5}5EknEgAw|J@t$-iFaN2P zqu=q7(Vo1VV2q(SwMpom07-GChBOWok!aTY3w^;_zc`}!C2_kHoyYmqW6}(n0<%RF zik0|jf{wK{K--2?>ehd*N?&(-+PU5KWue4)VMK_YG3ARW8rs`6a}~!OIZNRWRXPW8AfC)pRG8)cQYbR6S+c zKj+#A&9$VrRtJ9;Sph7RzJgSG=1xf*Q5iMAbU1r^Pu?lvPOLLy&98hQV&a!?aj~t$ z{|{a79nSV2{{P0_M2yyIg9NdKTCEYQi7i6yRn)Fgt44`k9Y*ZE#ooI$TYD5m&8kg{ zQZ=f2@;SeA&hv?8TU8s3-gY-To+mHEwUe8TXZm9gZZt?SRthRTY{mSl=;6SInV#= zrBAi+r~PQ1gfJ+3@JZZ&cjd=01XyMI`{spG`3`{n*Y(oq1QqYn9T?$nhN*F%oL=3(aljM*&5upa9Z*S3BD13qxJ5`;q(>3HMk=8Y_ImMtVKyqza$}WAYv0& zr})k{3QYclyV?ER2|$3xspYJlQ6|e6V1|-_F&1b zQD*@X!CBGK63VS#QIV1|AxiX#Qe#L(833Vix?WEI&+PhEam)MbClZOzCmmytZ*MtD zNbCsnsIY2h+LNo0^`PVB=QN6Ue-q%oRo{<-eqB91jvRXi9jrb(^N;?h3;?qJFUPCq ze-{kG^_dKU7bNRNfw5B3%dQ&%@5F!=D%#E3+IuekX$q8?NmnbXlHLyF^Tsav2$l~< z2HO11`QI@p-)S8*dE~2xQpdE5%${(Zq#R_x*|~K4&pTsvaUM&w3Z;lw4!>Z0OOLMv zDNr3=w>Vou^PS}$4SmWGESs4KoB&M`pdj@RlkR#XfYy@GjKHS6sv!Fi`(!C7Hid~# z)7aVPmdK+H*5a&aaQ#fN{ik>gjM!4o!AL|H6nB!;LOZ9=77>5H^E~H>)Z`idx9jtz zgR>Y7H8HA8E==<7e7Zk=J7egvT@b9M$096>{!u;6IhEv7Elb@7Eh?YYT<=&%fDl}( z4baxv%PI~0^KJ9HVoNs6(0LBWE0`id(ws^h3#hQKE2bTY#2VpAjDrI+zD|rG{P!8E z#~6|1EhObD*O9^+%q3hVPoM6bGD4V%?kb51cL0g4Jy$&?TlI2RcL|QQCWpzjoTJG@ z9)s=~CzmA3rxM#YujDDY-7?7OeZC*)3bH`T%6F)6C-RChE2Z@k437^!e|44Fy3S8) zZSj>Jxj(+4PDEG5D1p2$6LuFT0B}B9rM5p#zVQDTd?KTdU}BD6vbGE*`N#|7`F&0} z`Bs4f7S;Z|Yk2;tj__y}bKeC24U{-w#Bo^;^UsT=2@TXCFt63+F5Cd;Taum&-&+Q%rs}p}VvGv<_v49;j4wB= z&&0QXh1DW%x^m-KMSG&6W{|4k`I0eND6*^r`~3fw0Hg zY&H%weRXG~2?JzklrX}Z?Mut_|1L;0Qg3{dGSL3_rurY?>YJpa$E`R_fKGlw}ycNxx#4$p& zadijnR{^TTG;10!W=`X5>f4ThQ$ZV|F^|*;y&>)hYvHrwJTWN*!I?-$f|#ejLy6_Y zC0EBx&ToMt!^`wycDk5vSpkwqzdheB5|BQq6-yJd*aVQbjPEuH1C3$`wfI(!SKp=- zojEM?`cE#qXzwD50^(f{3GhhMG1{FDwII^fr`ws6&2PIuWLYcmM+)3}5>(e1Oeh;6 zor(Fx)}-%9fRFW=6RTt)iRFz;wf$uUAke(c`qIh^hOMAJNc4g@!)V^={*AaHWT6K< z5FfWbU^2K`M8#j^6SHOOu6`!GF+7QAeb-apt_X2G{L9Vi*2A%H@}^tQoFyR(t8?^= zLoLpLni_>>#WF_~3c(f7ZyPBLEfMA8AQPe?3nYj%mbxqinc%czdkuJHFo3u~45XRd8xMfL_;m zSUM*~cwg5@+?NbCybH_FvDW6(v}ix!8#R=KQENunr^EN3p)p*ex3}?q7cQ|WcIjRF zU*b?MZagSn`Rx3c!zc4FCo1~-BvXekw#rSr-{j4}?Xr9N;RM^l+Q8f!87HS-_d=8fA+h%%_1;4kcExYbV$MLu)8%%A%J0{I_l z!5|4=lx<^fvyc%lu@7t&`pycJLv`{LoG8avGw~tWNhknWesPqni5>5=KH2Cu4Hg+p zvoFn>+dy;0kySfHJZACoX&Df3L+7}kM0#yM-iwVo*_4|JO*AYipna*kvL^`;M1hGv z^b)wP^{;oNiRAoITvrD;&rc@JHR*8&y3L=x_b%QrX%}V-QKWj~94ZDJ1uI-$q9uh6 z&r^g`+7E?`Bc7!)s#LOn5RA~PG)>J{P7xB0Qw9>TL7@Pw@JNt3a>TAn%rqt=c@J9& z17&YHBbkaLt|cAfYem8{geB}Spdak`u~NFCc++=_!R&BixSTwN%HA9I*CdFa;} z!QC(Gd?viZ_!O3t0KL&ubqF%_1m`fng8b>XSi%Wl+|6@F^soa8M3Ay1k^=MPSmk4m z#nr`W$yYmw2-6xSfK|nrmH&Q}hVN@mNFGF`SPsyiM6+x5^*ZoieLN4D0HNT0!C)21 zI1$JGp>}Xt!#RWG*XjKDP39sqgid+p<6+<%?JH}iV4%rp+D>PRTzNLr6qX0<<+k?=0V(fzaDuPyaF$&=2Kyr`6P5fXglHGve0gA=6om zhbKGRJ7fLcCeQdMQ$Ms^3?v{(vf=W79$U3!_ypKZRvPRwn)d?&f!~vdFkLr$oRQeQ$3=tkxaiGk;m&m5yL4Qt!#BG>ZM z@{^WC;r~Uz#wMV$I5HqliXU?S9OI7e%`19-8deOVary_i<5~BLJgZkt*6Os_I&4Oi zWLOyZ^w%P#z$iFK9yq zPjdS@Zj8Av03zZ~c%At+lF!n2=8#C?RTh9#(YZqB3n52^5MHx);Z2C4R11~%<+1_t!1CB)y?YjL+1=M4$O zs*|DyBMoB#9Dz60?ul<5>5Zc?c^|eb{@KFFxKxL>$q+(Y_+%r~SNd)^S+h;i905M$ z4V29b+r1-bTL@jXhBy4`x*w%azxduJQ-7eM)Xo6nLT?HKh{+t6gcN)c-_I53FQ<4C zJ^W+Hh8)4C3Cbb1l#2%l1G&!J1Fx@MzKqI9VJg)zuJzVOe0-z6S2`b?La+%l9ITGlfdjr<|0U_3FKxL)4J6n?MdTE1I z*M85Am-mMqizq7+%|%q<&U3}1<*K_eb%OLHFaaOCK-V)6|EH?a%4B%19g2(zfvSH( zp-wUmc~eJ_xX+Ah?*}$QbhI2SN^s>e((~o=7pu}&p&}V@w6j+x>UMS#JflKI?H92{ zDwx}acH?;MqQ=&1av|s?l8WMC+GGsIIx5we;HO@Z;Y?Vv1B& z70*kwMNk;SbSy~4WDBO1#KrCWIX-sIi&k6VNowV)W zS3YYe!~mJ@w1Z2lyQIvoPo2SDygM(FV)NS_-J7oqP5e~XN2mNwV3D`wTIo$mfm3>!&1>J1-_(rL=JFuCAev`?u*PrutIkJoRGU z=IzyBDW^q(BdsWC8z;m94;!K#1k1p24&II|AU>iz*r+#CNRKCcf#%BwiDDK@8CWpK z2sBOok`N6PgYnDQGdognke0vZv~0=O6{T_jozr{lJ4$&sx@RA zF)6pwQj{UGq*zt1h|_sxdMkAU11f4kT1p%Bj@+E!OO0_Qx`F{B7Uo?~>PS4UDJ3&-y_8$|3uuQVP3&9n$*^6}R>ZM8exb^N{Cz1U zVIPv8I-N7J-Pa>;vO^@nK$_7!_YV-c)Z_wO{4dp+E)WjGns*N~j==s{@!5<0@P^tj^gz%=KnI-hSeJ`SdeE3N@4YFxnJx z$T}L+oiudk!K*dljkGpXmlNm2{?BKI>t)t3oI8%BD_Q%zPw^41!wI5K7Wt&uwjlu`s$M{{ zAqlo?-joe!$=`ghj;e=Yu6t>wqP|iY7v2MPQE^c!9ct|%8&Y9te0!WGxeZ(E9b(8) zYt~s~H~-e1cfZ$7;ntK|YR&w7+%IQlbdG@D1(KEMVLxt3Si&KVBLyztuYGB6E5|i& z>wTseW@*I(Wja66#w^7;_Zd}6K@1|0uhQ(jB zT9pc@O=~gD>shI;1q`iCP}dHfm76nnq-e>Z%aCIJjcZv?>uxQM-%2(yv9@}V6>7y8 zh7hJ%JBx><_gIj4TkBdsoV%w}uC}J+Xtul;JpAUYOoZZI28-JMa@F8`2fvOfo#(2| z#Z6)alRV?>U2EBN;fuFcwQOW6cIRL9{4IR8i#&Zp@0i|IBC8v%cGr4-k=%Z9I;1&p zJ4QG-WOB&;+b29#METjwNgR{ZYnr{?n_4yw{kNSuQmA6E0#L8AoBN~bDK?xk>A&Ap2WcXB4p03u#Hu70NNGc49hC$TWwKDpnc9KrKItX8b> z`W`RYH*NY9ZwYpJH_c47V$4u3C_>+%gxe5W1*dSz|0*{^U1P!`$x)OMzJ7MQEBo^^ zDHLXL0A=<>J6VLvx3Ue>RKVL+5?KvXCevpAdAb_$M&h{?Ze~swCk3N1Ix3Rgn(vcr z2r2XuvAY$OZC9F^+F>!w!p(%soij@!FiHuD05c7h;rmdDnqWI#=G7IXU^$%~dq!G`oekVXne@`=1$oen((|SR@#YaqM zoF%AUK@I2fwU}nPX862W;AS|aeTgG_c0EBW{1Y=ZC5?R&C$ajV#EkhV-5s)iLA-!V z6a5=LO3KVbLm)+hXH|e2Ab zs&WRJoyGCwkapIf{@r>`N*%LX118#M+}(coM*AnCiD@ks1>DPDQdfV=S~p6#G3_sE zWHrM;?n)SnB=^4ShV0iLY==pn^Bd|GdBjYK}dR?FJPnwl;m?Fn9HEY*M5 z?$V#BhUKIMBARYLXgs*@b}#s$p#*hVLFy~Tj3KHrB1vjCtY#P+f)=TItKC3Ux6M)w zPxxv_*Pylu3M^X;Javv4l0Z4ts}`G4zhS??ZL&L<@Uy-fCxC)5Xw%#sp#r-w*~C%H z1&4&1`9|Xsh}`{FsY$};6&S2G`|kR6{>kU=C0+&AAx!T6)Co$1BI~8r0wUVP9@AneTL?kF4|~M=70IT;#BgK!sTk33PE_eg*C*(R!E^(nc?RLf z6OtlY1(n z-?qLZ2c&)Fb9IXulBS~s&@ zNf~R$RMbis-f!-;&*Oy1AJ-8r{yzUxOBV9eJz$%6P4Kq4^q&C5e}Ezxla!?I9?16l z7opi5Ds`I*Q~K5^u|pTZzDIY4OcqR6I+8cabZqxjWA6VAAv9IEzjG}-5N5uW40uxe zf@pN@$VQdR!uxFZBx;1~n#MF+H6I(|Gq_Uzp#2%J$BCV>`CxtibnP?>OV#EJ=G&s3 zm#4`!Q`Tr9&7*fbO3Bl*K79r>?D)R@bl_xL){Bj%ocVSu;s9|FfPDU8rG>*hM6ZL5 z%+sFXDR2KzHEw!#R!W!wP8@RoZCb6l3RKy<+wk&kBvOm+&iB>u=*Vqw{g))NQ*WZ0 ze*n-AQcX1Fr>r#ozrnBEZp$!W?1Y&3nD~;mwDh}rxCUCbH7o`@sDkPlvwPYcTq!FD zpbZ>S6%MlKiIL3yC2ME^k;Fs9Sv`r-Qtaa7675$q zl5Ez|25Y%5e>m2(iseCtD_k_$pP`D9GSJhi;f1lbnRc_ANxicrjCHoQ6&nw-?Q0+6g2?)jjjBGz&?F3 zMm@ZBu==JbC4bJvXPpqosvX-cnf&x_=H#GVw>>_yL^~Z*A~M@7u$+v)e|cTlB$SNj zp8#;yt-^(!!7)HIr43>wZ)0OJz>S%h-qK+!S7R6Z{};cBBq={Ta54eEbT(qz#AX+I za@}Szkd$nwR+P_u4}|Waw{sso8d4~DQN*wFqWv@4SoT>76D@vh;)TCBL%(Ox#MecM z}o*@>^B|$%=O^uOIXBGS!xj zKxW5~I@3`O8N$wmd}I*f-USK(Wu_x9Pl@Keba(hLjY5e4bG(q*OI$NE85w@~2|!{r zpH}@P7OtYpCQCn3T9{$qqFKyice{~E-V{maSt0;$1Mp0$a2+zTMjz!rymvOtG z8i}#!R#CR(`Yrpj)x@7iJInP`s@upM@MfNfTNhGcOoqt7+Ho5EN7(80{Wn$%;zvgo!_HW)B#Sp6MXhPACGBMAbFfb9gcjDx% z;@6}|DR}rA;(zA{e1=d0BYC$re;PHy_Wu6Iq%sBcC#tCQQ^?G%*iiBwKFY zO}#|P5W1y5>(26L`-%$H#K{tftf-;{!t(|56aL#3oZJCw zTu+WYy{bMZI~#1w+y32m!}sOIRJrJrmym2j#;x-!!d%;53CRr>V&%UkfA7w}vL5KS z3y9mXd~}=#hiQEL2blD~nmA86$!b#0opN95xvpsMgX zZe2fY!V^e>+B9rmu#`$_njfPhs@4vlmr#$`O$gckl#|wfZ+N6j#X*`0jIEh_@2!s^ zR*6+>ckp3uKx*o%prG-tq-LuYgAeP^PA`0b_yl~sCbYoSEG0!CHK`e<-UEPuw62TX zNuqY8?wKtA00sS$N)-wMJb9O-x`Uu!pB?hPXsFTWr711woo4ODNDb)_pdOO50xRMvppALde9^0jkv5=D^DS!7{|sen!5c)E6`V4-lwmS6bad zqzQ?{Zc=zeAWIK7_ubn(-tW+z#zx>zTHou%MkdV3TIYQWaRK-B};mit5fWiofQPTnBgITR$C)vUl;ZgOg)qcOL1BX1o<2;`V9K*bu&mtq z-mZ@DIhES%w$v$=eVB)KAxbQ(V{(-&{G*wfLp$Y3i`U_u4+(NLjfKzWbzSr3ZJPt! zwlphJzThX+OHa1T97atV!e?(-=$I4KjE0cp{d3)ACvR3BY3V!?YRD6jEJ<)P*(N34 z)Bp4vrs!2<7Yvowb-r-MY)U`YZv4};gVM5LB_Dni9Dc2i_&z`3cOEo??Sr@dt|qiO zZX+|C^a&&nyek5RW@ba_&k8W6b0Ihfk#Tnl=x9V z`aPCFc;~-%DH?GLd`1YMAjsGVJGfi&ttLW;=1Onr+2hZbAP8y%`_G1kLPQQVlQ`mWi7&W71D`yn2S?D6PKrAMs_++QB{w*1^8G)fu#8B&V+h04Kk z4HQB9H?4EW8BBB34HFbgTbVB@^9cXoR0im9)%^Jd0-D(>);T%2K`o9|U1TSGUS|l; z08bdtAMg1Q%DV%UoA86l<@~4-_xXbB_j=TIK#h-_q#8Th4t{M-P@mF~ z6$a3S1?h z6%>!qdpIDewq2r2nQe^_DtMm59uwi^(p8ZKlY%!JWLr7w|h$BY{|~@Z_RYpge4>cf5;)s16vzIp%#=se2*6y*d^YxM&A&yA%5P z-JF*@qzNyD?(~HKla$jS4pWig>G9$Kh{yG>t1%x?&9m`bf;xWMfi@PfPvf6@mA!8e zvM3Qn=jA8=Z0q1DO}=I}2i>*2jGn(q!W8_DeEC_D=s{r6z2C)@VqTrOUDwvxngCW{ zomv%o=ZOai7|C1nQY9hOFFdN_){-SbD(E3Qko9CmVm@G-aFbGVE*xG8xfZ8*`ahDsVsZ2`b=(j;|#v$7k8IE3T-tpA|wj}` zDRdacfT#6d3*H$bkM^gpaiP5yEYxvJm=w@PW+$jFG&tZ}x%xQGjrHz!PJRh^(C~=o zBdu=7rJm)185WwSXF%}1out7~UMbEn$S=MDvjJI|cZERfPgmify3~w11wv95ySVbJ zwOWCuuTNp|dhIEti2&A3H1sa*(XpBU#6m@-{)ydMHgj|aNW|^tAHXj-dAh{ucVo9$ zt&WH7K9V-Sa?QL|ga1QD>kd$*y;TQX-J!ir8gHIP;}G06g;x%<0BWTnmEsLo{VswQ zC1%9qv^2->sf`$=9r{1wwp&?_dX>M(EI^}Zb^0nZ^(%dvlEigEWD-2t_1gOMwWttD zT?!VJn78;LSV^^J<8w^-I%2sQe^O@n zrEyIVmuLfzCYspl@soC|DUPtheDOhhSHX}((=V73@vOX7)+S4AFnS_Vi~2oRpPy4_ z60h<3Dfi{K@<+{j$k0P5fA2zoon@~uW`e7E{l02l)1B!bIhM1zD8-ug)w1RJ=FT6S zG7*0Us{hcn?h}*q<(|5q;bXlLBuT>p5@-T`n!qb@5DEFCy=M2zRWJ-@)LT#X_vr?` z)!n#Z%mvBi|GC(?74()^4zlnJ=9ZEPdq_pbL1n&4y?p0T4)U3@}+|Vqm1LQx1(4V7@z z({mCdNIRi5OWz+x{dvwlFgLC;aH)_{2yYxU?>Pk3zGA zNQh>Dd|!_AQQNzMs2+rmGlj?1NP^qkLg#)G6?L=p8~Uuwd1J@ZY<3deU)li6yP03) z5^W&0pdiC9c>MJoS@mjhSK=IS$jZ zW`fbXAKltJelxz{(W~TW%N6E#!)dr;tCaJ8h9%_jvvR?sr>{A+&3(PDovM~~tgU#8 zhu1rlS61X({lLc)wBbg!gHhjD`IUd#H1|y3?1FM)rew^CI69^awL3eSy8F}KRuAYI z!I+%4k!Xa^p3jB9P^J%NB{^Z~)Os;^J9v;wS-}QSv1&K({`e-x6`8J{?lodL3>3$TaW!i52 z@h7gLpOnB%AJ)e)BeYVO!$|P)2?-Wf->oxVnT36muTn|D%c{+DYiju^}k$;KE);T(5_Pe-iOm{+n1#U~VzF;Y-$#g5( z$`Wyc@&6>_pZKx2@bRpVGh|?y#Z)wu>ZM*XOp+1qOQ(vN!Z@HY2GXgn`F`Qtf>}b1 zIk@ab^zY~*wiHw66Md3f+%g6&Rh+Crok_Z>uXG?4@?B<`Dw!5hV}X%**O^3SNjoa} z)PWRJ&bR-Xn{8jUl5{Ck@bHmc&_CF@2iFR1v?J@e-#34{1$?I@_WE!9A2nRl&u*GK z%-^WCKEJUs{iFpiv|%e7g98M7xAoJEP>)2-P=O-~r&_GPDWnUOUi|hQSn$8C586v! zLMEF-1tG;SJKIF567C%qKHMk-GCDRn;^;XJRTeC)#2r#NA|DV+>usFBNxuxmI+wRq z0ze=nzGw(Uw}l0L4ZzSD?dtwl`|qbx-TQ zq{uv536Lmx-(p44A=*;$)?RUXceygg5&wEDb6L@e)CHhpo+@^Mps+LDz*P0hmQjzN z6LPm@nwpIwn8pU$7BLAbv@)&5wj=%bkMe6YfAa&%NYJo=B6?0$&7_s$t&mAjs<4=p zrbS0sl4R&_lXPR05o89; z=4QVzeIiZ#&19!Ij8Wx8Dfl5jZK2dwO7-YHPp(9#2a9grI}d6k+jdSFu2k%-WntiY ze>#tc{bf6jx&n1U$rvi$i;S$IR%^hf($6`2kM~D7 zO(j;`KHBy9Oj=zx9DmRDXwXEZp;cw+^Yi6gzRE2PS{CID$YO`c@tWHMGB+LaFsvheGx1V6RGg7VPqTl}V{i&#x`G-8`wUKQ=#Q~Gjm547o zbYqdlUNTYCsnR098dT^!RYC~7rmn@Z{sL$Pf}VaIr-3=CHEAXDVF*RZ4D^mSeVLA$QG|&7wrgpI}Iu9($Ro;PME_n zk7?lh9}(EW^q!-Wm#GnDNeSO*Nm7%g4=q_kZ-v{9 z-t~hgwdZ`RxW|VM7q&#Bv*W}rPDlNNKJry!U8Yk+-xOkgD||5|Xy5I|BqJ-#UN3+g zuwSaOK2{{*U^JR9jZZRyJI z56Idd_#B7{7>dZn9$pIH(`AY^014vxQAg4akP5RmIbUMOqTKFR+>Zz-)Gyeo>BjlW zTiwggWa4|D=xqU2DDG+oQ9uQ))W)dlo{?51n7B|SIo|4TYojjxp3olGUYwpGse%oI zdf#?{r2399R3_4WQ<7yIbC{3QnR+1=F|?DkS*LMs+I!Cw=R`2_B0HeEnk72mcKa$a zEdyGF;PM~!r(^`8#(+1-13o-|T&@<~IOlU_{#{HpgL^CJR;2Sb)l z{m(AdAmKis0%4#s+fnJU8iL5Z>EJ(U1od)uuFn2y7cz?^Q@aw8==g zz?eGcyv95w7s82Ih&((kx18`E0RqK92~q0T3Ti$J5P;B*Y1#u%qUrVGUq~D{cFDkO zl=;?-uk*tqJOlX>Hhu-zs!HAkS?9CUdqJdygmTcRNxN~?6)6bklg*Cv_83CydqoEDH-g5^qBSz7f8LcSx=_1BZ%-`4hL&n zR08xQM=OJ6E0}-z?3eOk;vDT}O~EAFC`TmGa$e$_aD2 z66fQRkt{NTmGadlLfNcEf;Ph)=c&9xvb>apfBo*6hvKB9P?L&B8N0$MR{W^wVf4Nu z=@yDIHR8{Q@-P*B>}}JihR8782{|jV*GAt)xEdNzxWrM=u5Fk6F|&)wEoyAXw4HB9DYgYo4q^{{fgQaHZaq zn^paiiV@OpZO$8n#4{t`S+PRKrX~w=@emF`5LuMwgW1Eweqo!aA7lN~N#|3pl^k50 zmidLs2kCc#4S8PqxyX_M(h?B0gYhUR{@$P))}eE6TPLb8D{@{FWrE|^yu}0&kwl|a zqX5Ynv83(DsS^q9u-aHI`aC3)v|EZJu006{U@NIcc~#0ju50{323LIa`}DT}5?oIh z*^RJc;Je?)LDJ=582{NGzR$#0PnM1u(VR^ZNf+T398<+&jA|16F6^h&7Uh}__+?!6 zB;g*Sv?U8fZUqY4jY)^s}k>7X$X)Z?>ZT0a7EmG2h-%^eCb8#%QIbjZ7oHc@zCo0Zv7V-@R3ude&wL*1k29orN5Rv z@SD547O`?+Wh{9CuKrH?`o9s zAK>$T_w_{v^JDJVm=6;4DW9MG12o(^ZtFgMSt7bBs+xMRbGRxka}(4(=igO}TPgJ9 z%3lim2cUH)@Jp`U9cUS0%I6C2evB=RFCjq*^X>Z^D`nkVEQEe%V0l5W*n0b>%-K;K z96Q1F&ayxmAZb3=b$x}q}+b{dsBAG>}#BUcdnil*+;O}|R4r_)PB*tarlF|+GNKEr6{W@0=H(}aWTBLvxI zmzc=-i;muSHeVMs-#>Ut(OMSYgkfpJ4s@`ao@r6FC5vcL(NYQOYjKPGM+MqZW$U-@ zZ*rz8>KzaMl>YYsl-ta$zMuf9gEmS41b_%%0mjr4J*IDGlv2ax%uPM#uw94IVq5~6 z{1Fb=3=Ja^GHZ&ljzNfgv^&k_&>2&EatN&Ajo};CbAD-e+m9W`oPxCYHT$_5YHA6x zPolY>z=|YM*~-Ls$stygbqrtWkw%H)H8Nj`Lzst^h0-M*$Rt6a9;|M~+}u_inOasd zzGdg2q+Ml8%lUKmUpeRQY!?3y?>Bz7ig{1WdP(z2z*2M;Y?DB@QT@)v)8wKk^j5Ks zps^#QwkrXbMx|x*L@!H0-Oy1xv(Tc#Ze%uCGdoAO_<)g1C(G|AmU_?P^ni*~7CJOv zs~1zqPN{8C+848+lzeri7ETg$wKf$KwusR04CBvcR9Fej59lHka_QVRkB46CiFPJZ z6Nzf9ioXiHoe>X>C#v~yJ*Z%9A_U?9n1%G+pD@<%8BDVl^%6h^t*Pd7eqYU7qqntN ze13M7E+9sNx|Yu_!oKEKJ|w?+dm2aS_cLfML?J+>m(13a0mxAAc3W4;C|asPM_oEP z$Kj;Y3cY~iFcmfMULPIQDEJ`Y1yjeIl6$UWW~dDngh{f)k_`Q5R9}0rUpqnwny$FG z9GGj`J+e;{)G#wWb(%{jyBeDZZ@ar|E{z!?m?X+9t%YjpW4~f#6NNG(L<6+=3avLt zL2Neuj(|lFOK<^7=8gNyuPF=YzOqqC7*1Cc?>sK>9XAFJJ+x&nF}^R*_;DrD%dLS- zQQ+H$N@&6CCicFwGitdU@BQIBoFjcTA?_Z0MuHe~6*w%s8?2;_G|Jl5%}?6g=;6 zhV>|g+S}gIm$VKZ4uFF`O}fAYo%z{VydUX_gW%N=M>`FBq2n?DpLd(bSn@qQVtu8ou``s^BQiP zoO>N<5w_&%&tc!PX^qs04bT3>>QK*}uaW!~JxJlwl+2+#Ii8zZvooB&;I73C_A! zz7zn*Ed*b${sZK_XQd8#BKCAS|MAeD|6YV=iTUXX(}iB=O11!&{>Ry+D)x5gkC7`k zznES!vO~$>Uy+}oLy8ak*d0y?V;_X`Iv7hK>zdYC+b#tmzyH?a^7-a2!45Oek#!MC z*uWdK9meiY$AY7lCbw!W|GGV*WnT@+@j_9Pq;mAB#Ueb-CVDTgj(5oPDf!ffB>Hvk zZ$vsKb8kzDGjlav1}yCryP5dYZQL%PqX3<(Gjp$z`G zCwX`MJy%l2bE)A!eP}cu%H+Zs~RfQ6e!7IPRK}Z zVHHHFxE&5d7qCer#{XxaA?;fg`^N)?7& zGEyWFIlqlxp4j~U($sczLqa>AHd0=(hU}(wz zIz9Ls5*(J8Xt3G*`iAcCIGQ;D`NTty@L4t|lHH9lJ%Yz-AHX*W4tiqQ%tun;k3HBQ zzFk``B>J^^oG1%$;+W5-rSD%>@Wnoj8<{&gz{Uu^8Qda71bh^aW(jgSOxGTXxmT<8 zgBcams~@c~CaG$BvyG&S&NGA^B8=LV3$ajqVi?ic55~UUp&7pB-E0Ybpqz0DwVO?H zh3-0Xb2E{&@x!Q5hNjc{%F_^8dXAS-+P$u%?O_e&6+w+euFNn8LGJG+0wCoO`NzVwZ!zZLEBZkRd z65wKIPozEv#Vc#??-t=R=najfOJ|PP49s>?-eYke?oBfUHR6dhJ>ln$%t;nNHe0)4 z5vOjRw5XqF{sUt?%{D1`VQ5O79mSspt{z%!QK?BBuf#V+(@V_+c8{6dt?s%9f036tgt z?F~?Ro312K?QPFae((;FxKG<@fh8$YS2U$zJj>3yuYn7w{(+n_E2{>njF|ZCv>% zMhbwJ5f-=QlK3`V%TMRdIkC@hg=W2)Ae#L}*Mnkv#>Buzfljkc;%6kk>Y5(+0GDMvC zY|?31M&unw){#Uo*b6qVwE8Y9ti^Xd5*05hwp4tZTkW++rV0HmUFNmtsgz(%gpo=R zepGJO@Q1KErIZgmU(oK+5`|qpu3@(Lj7l>MEX#ni5{Hjq($ce7SV=6OiE=u>&-I!O zvMLp8=rn6~Bc&C+*Ux;#LVhN5)cJeS1}U;qZuPspq{hid?QrP93;_1S4Jz+T0Juy& ztzdA^=Jog5dHXp`wHQPfS)1i6)d(vU)&3=l`JxHS5_Dk^wfoO5RZT-+vV)_b%D}Ow zw$z}M`|hrEN43g>r*8|>TWLJ!kmH#2MDH z#8Q!ez+dB-h>LBU*-)dowZKeKy?_#5n$$wNFf-<8ez;ET+|-Xbs$T>Gz2`!vubsd1 zRoRR*6TQz~2cM)fx1byQdjDrk>2G9bYxwj4d7`4C*2fDginxt?Jjrw=8Afu-mBL*G zFysv^nYDN{HLb;=93nta(J58D%MOyvi_laXNfdQ=JL5K@QLzN$uml3}M3YuKwNHjx zIpFf4ao>dxLlLp1h}26Am{}`XRMVk=ieHj+6iGBb>njMz>hiU^(_hTn)$4mA=81|0BiCl0@aTlA&?}MfH(MXMC^T4 z-6l@Dd@A!QtldQO|6uC9QnlveFov_@6YYCli<{r;Zk`TcQTdA;&FNzOUB@9Vy=>w1qD5-i><{ImEvy#I65 z`k1x~YSGI+eQ!Gc=aZZBZxk;)Iwsi*aY9z&`LdbL4y_ZE+JsT}jANQgWGbP`o7uF& z4<*ds(|AZO>-C4@fxWXHJ^WQDYDbeSlj@TJcL;qRiFf3a&qfzBF>y!yA|8?r2ao(Y zKR-+TxyK^Uam1HfAK_1Bws>h$rBowAyjPB(=AM4MPjWUs;=JWAN%t$!q8%(%#i}Th1P5peP4avPHJ}c%F$HXQYOfM zKOZ(Q#tMR`H>feVkT@8enA|Y+!=LVf z#}Sp?=HQ7%J4*xF_)0^3VOZjr6|Xq)saL}5Tx2Tx?nb)MBj4r~mx2|F!=->=3n!Y| zgFEZFyfFq#W8g^f^x-tajCsYXu)CwZ`F@Q0G)eyfW&|0f{RSnHB&*6Z8L(>c$mYR$ zO5CAZx(CcG%#z&j7PXj^ynp^##zv3Qg)2>n!nCc%{E-K$X2|v4GRMkRX1+>*4TTNS zbE5bUm8iG}^R@F6m{qHvg#%oJ_kb3OkaUxAQBvvN(;e#MzqD{Np5NB53q9;d&kDl6 zOC%Y&24Rb69vy;bK7V3>?`GNyYa+#M>OKO2g)d66P+vycXF{pGsH`yZuDQ) zQR&>*dOJ5omtkCOpo8VHLYe6O9?^`kX#!+!^1Py<@qB!^^nRF2Lu0nrB0GC5`=h@7 zzRVa;VA67*-|shkdc3Fn8lN!bcvy8h5H6bg&M2?6%3nBo}VR)gtS7+y<5b*7ka z;2eeZKrZ;4u!*H911SauP)FA*3j+OKCOD4j#PDdm4HARS;eX!{I zMb@w#X=D_2u!W8)9YAqCl%sX=3dXmy;96NdUYQRVqdW=?AVWa1@!as@)ZWV!e@}PK zN^XV`pA{%y<&-~r2L*Q}cXfc~0Hd8$_=fa@#lfQQSLapbvb%J$thDVj)U&c~mKxc_oQKY}Tr zVKTF`O49SV!+~gAl>@Z1k@leLmObeVr3H(2 zY$brhzQF~Lj9}VGQTn@+U$d%etk9MNE-ws6Tp@d?r7Z6w$91;vSI4aER#8z$j?_`v zMIy4Zxm<86cx+6M?l~ZFiwz`Q*jw@0M8Wx`0fzE01Uhnl^K-2 zStn#An#MaqK99SQ@vtIOAJ>Am>H;y*+ArEDTp;nxOpd2pyN@!{ZS)MgKRqy-E13`} z=B3Vv0TVY@aNAU{=8{N(G?-m}>?AzzE-GW~L*X zF8uBI5*@Q7vD)8iYpY&K?rLXe>E=l~j%kCF+^9`V)PZSLO7XrUiq4`0F$-p0p0Kki zB|VghTCxXpenMmSK&Mi-6(<{SU*(GsW0R{&3ViSW=-K;#lr(iomE-8KCB;eXD}YO z#iOq^2l#$dP!5iIa=T?89S2rjU%n3b!%c3%`Pe{g`q$xEj~5D>B7;M zc}f{Q2D%UW-!e9kL1p%xosHC(CHU#(@hAuqH7ly5a*Ij!J#g zO?DudHKPFS_M)b&M_3^DJ7*Jlrvku$W)%fsK!~Vv@|y{VC$~L+SCM~rjm`v5cw72_ zmZJ&g6|Bh+pl3Lxe#$XJ%B%JswN%90HKCrkJp0=Jn7-!PoQvq>Fg*!NxnG!Ud17+R zuR}RZC)%lDTbL?t@sgm%*^J#<)R8%_@&g}giN%u8gAWI{^rVZe91jw(m}}V+-9t!$N{cGQo|GMO=ISvs7;CGG%H9*IVu2e9h5d zpmlsgj#X`22p3F+!K3CtM~#9NN9dFTe0hbwfRIvh#4I=@LsCQAOAH>e9Lqf8MAf4B zwi#OZ1Oag~=!Q=e)6Ove2}3LicmKB%bEcGlnh*o7tQ7=9mE&{S!?DU*?eSCiL)fgo_>KHknI1Dq#-L4avhX2?N`H#H49TJF8)L8)LEJpc~r{k%&O8<7*(pBB>U`1 zw)cfakuq)nxs7xN+Uhc|EM{krl5KqAC?T>E2D}CC3&|Xpi$(7hHzliFC;_hVdFWO(>vJNs zNjd=@V6xPxT*wXi)_oInUs+MFHHq*sK{xZ|=_OVR+tk<+rGPjFvStGHTOOrzzRRG` zCqzEE`WpBvEJcAE$u`^%U{M)72=KA{A}Gp3oxokM@-j(UfdS7ZR&SB-9gVSOZ+p`| z!ONZURNRc3WGys_EjC@kb%hHPEqb;4**lWxW~c$(Pgg>Eu4G5)^H0ecWpB2Vd#U?yUSh~7{K;0=j zm|y~bd1g?T2wM}7^2TBCUo@s_jo!{sSmp z%@KsS0n-)m%3{PKx%8fADH=A`31}vA_Fx*XyvswMg?y;1uwZ0b+}Gs%8;>UxIgoVXmx0qayJ4JK?}-Q6;hXdh%aV<`%G3r8 zift-3wbl$ZFY53DIh#XD53f@@IUiLT%`d#yrgMUFgV^M$i1wkjqqU0O(#3(}cjp79 zY&sEY>Nrm_Z3~OwdfQwI^kV|Pih@TrdXn|imF0MN3^PTMpJY%29Sehw*n16t4xNUh z{H!d?Pa5zumJ>_if!WX3!b`FvWa*WttqJV|DczdK^Sc?hk^_{LRN8$Y-mrG%TwEpw zFV_jvvE=hG@-Npx`{4Yqyvf1au(r#{9mNHxkWYQ(D_v7#7FqY zet^o7e4}MxwilWD^~ceIXCijbH&B6R-pgTUS~d9CVQC4RA&UsM|J$pe)zat^tfbUe z$UusWy4yQU{Uz@hI)+CEeu)P8>Lf&bUj80U&ssG==hSELvidsceI+@&axA0z^X1vK z^#Xjfw8Y2B|D`ynu;ZmKLx&0__N^z2KYv;65jBjoTR7AEKauc%Pf{fpa|!Evsh4ZL z2h;~eyqo=TJ@BdcQT6KsIvRjj`wSBW_3x}Fm(M0=2Zc4*pZhg^wvG4`dNVv!l}$9z z_3KyG#_xr}KUbWgl~Jp-GayJk}-Lsd{kCp>BSh*phqQC>iY1zk6>&(l&Z90*~edqr_jiw z&5KXOms@2jPgtk;VdRPh0rVN!m~{=5Rm~Tk&37+1@Lk6g{II`;)@eqdAf0Nh?S%%| z%u;i+(p{+HRe7zxVSQ1vvjLz6K#7ZcPEE#|1ZX<7lDL$K@ZvjyRcq^fal0;4dHnV4*FjskAKkS#Md$(3Hyn$og&M&z3xmrJyX@v_Cb_d!u&1rtV4(y}Z)XY13EZ!(e^d2GnyIqF+Bi?+p(GY#eqQypMEmVEtZ}Dcy(+m6m zdwBT#-yR-C+vbqF`+tRxiUi}SB>ho=5 zC$;*IG+yK7A2p*aiuEYu&sa1_YuY=!Z8RU84Bcz{l~S+iihK6 zHNa#uB5R?95iMKg%dsuF1XC8rv)_*oSS?wk`HTehbC6PvPy#u(ug)C9fXO@zZ0&cM zzVr*UM3)t94#gl2TEmD>cxo$?C(82R*=WkI&RH+1b?8BzM)HX`Nj1oOD)C()cqf60)q7~Mm6b}mFyLl)T#t| zte80VgSEX?rNi7u#d{PD;x}6}UHGCs{P^Gvjs^Em!@$P;CjB4)Z}%E;A?~u7srdlc zr+8D)Z&VTb_ROe9#4nO0{MSu=miPU{<&F|%I7LsVpaw=FSVu=YtbPavwfdDaJX}T; z5lM5rF;5xAd>s^>`tyg>@z!cAU}kwPB=B;E>+>lPtU@NKlC;0qHIT}DUQYVfVqL@AqYJpGTDELrj2mm^V)l7wR z7lU6VRon&{G8Prvmn;7R6lj!vROUXt{4($`1Qb&g8#MFlyKMs5JGUl=ax0AU5<^ag z`12xlW07DAre-9?e}II5jQY~bVeC&+IwOhuC^O^VpFDhqlb&OWQiuUon<)=y{5Ly+ zHeduKdNW#--Gw`K*qg|0w`qBN=9RvZp;`lOs$pYN0uBa~;TJ zc+*nRw_mqiC}FN)E|(=G1VbI6;*F)PQ~{O#^8|*>r&wl31iL4Y@GHobczxJ|x;{LT zigO-ao8Mpshq+Yw^OH`Y$<$Y?95v@k|LnrIekBZV-%4mEDU5U94buDj9i<#_x9_i& z1;O~E-~DQZo#FMWzwRiP*nuqT3=+mJ*E?=$Glv_KzrsVa%mpCICkN0tWNuEAM*sFt zSsh`;1(s=Eo>8sX5a(Gaeg|#}h<4#MaP0tn;Q`^>50bkN9&(*gC*oI-a^4Gju9H*l zISmCU_{96c@SC^!tn~4`T3_ZKu%!LIqLRBV#p6ElqefT|fBL_V{5!CBi@#|@;t>Ap z*I6*4*EvFW5-)MW2|-eClY= zo3p*6KWqV1!HZFfGiyA?E^oSm1Pq?Vx}L2wkDME3A*;vvG!zaGn$=YQLTFAISSQPb zMCKBOT4hG6q<|0AAAc3u*<$cygbSDbb7lBe&vBTu!FcYo~ZhNalqH|K0f5*Aue`5SlS#9fC9Rh83Wu;?&0 zR&EX4SZF4`Ri6Y9+=l~*vT`-=p91K=9*;8VjdjXbsCpZ_T`c-r=`(-*O8f9o+u26%qMzT!DC#uA zD44m3cA%EcGflT3h(V4;ma`R%& ztd2vO5AbNJ7?u%yNL8$}s=P`>$LBy?jG#~4TwU$WOe{R~w&T0jr^8lwLDXD7d#|qC z_j%M+4%TZtW}M!Ee*f6dr!zsi1S`b+ejzVl_GKk-i3`963Q<+S%dcksqIFi=)+?oa z&3sz8lfwvBSwGtZ%z^N&E$%Qyj_be0hPoFK9b~CIOUI+U(flBy*DtH$9O^)Vzj|gH z@4UFvIniNvnhY~T4x#gXfvRK@9p|7Tdyn^c4DKM;hikx282S3sNwfGPUa$oSTLQGHEUq8bzPSVg;w>LB+skPqriA^3-;W05@LD3}X z2x+iSwau#$y+>hOZ^4_EzoL2QvM8uH{{s{k_Hc2etM^Uc+Lr@5d?j*PU)R~eLSnXWCa2R#gLxc|NbKX{j$U2!Xww~E} z0)_DHZyDTq&h=pL#GD=f*nAsP2EZ=E-~0Hc$)kiFg3>aSW5vTQ@@{35b+QqpCyXhg z=#jas;A+aMAvq?h?&W~0?GS!}SRs)h=r|J2EtL?d9skLNZ~nkcxWSzUpnAIbI6S>^ zw6ceQG?r{$hQ5ElNnA}Blcv$c{_7&%^<0{xZDZ^gtq|8vN04_9IT~~?n!IL-Uxz{_ z;`Hs`d|qwj7e#k!?fXg(Yj_O;8HWi1fZ#{Qm~gM1@*)*cON2^ZMKp0#@Z$Yp_qtY3 z`>7cmA2CcDGXX>RGGNgvMt>(23uFARK5ChCr_k+oKkbgV_rf{g&z2B6ims8tjQ%=1 z4hj=@Mt=Rt`@wNq zQr8?z&?x4!L}W91#%gmORZa{u6np!dkm$1)%|KGv49l0sO~K;tvm}2)n7!n4cd^wglmd%M{s7HNu}btRKzX`5N$1jC3Nu z=V7W4uD?>Tw5l#Q$z%k=h<}7u<`TKpg5=%A0EV2|xJslp+7_;+O<_@~A{BPI+;BF6 z(}AhYIPs~(qP1-=AGtDjTl73W8Q#$%ucDwy#>G0jo|@ngkt7c)RW6Tkez(`VDx&y$_4Jl(LCYedJN>k$<}K z6LQr%O1)(fg&~tM%hD~Rs@vh*eA?s{)wwV9iwOG83l)g-;$)vsKaecNL8eSPRRjgP zp3r#z)c=%xZ~W88CaTMjg!V;Ket|{v?AE+Ldq&9Jbk<`j8>u^uej&=Q4Q}~U@s0^4 z7X6^xU%~eaKiUZgw?Aesn#dlGdTJ3qmN>1dv#(CF==pY}GqTCc&8DrvW>M5;+~eQf znZ%X33uAE%`S*39(?%oI#Tpu2yZd6#sMXA3m=!*76zY zBB4nhf9Jgw5La~5JHanP;Mt-KT4_ZOhg3LUEo1Kmq&K3N&{d8Ul`2QWT-NC(Clue< z%Fi^w0?4rf=ZupVX?0+Cpz5p<-syy_onhtK+pSCgy2f9)#Y=_@dPz;Zd=1)FI~V;0 zWfGmmt&#$MvaU!R6;atSNm-q#p1O7SR;5!#ThD60A-cgH0V64Q>XdSt&dU*$l4pR0 zs^(U5jLJasam@sDgK?`@cIyiDCkHO;!Y}lFx#!WpF&o)c{{cw$7^v>_2IR>mW>lU8 zZ1KFup|-?1=C;am^LPb23UtLheGgXTV2y+*H|nv z-9Ymlku`?zxpIclzvEA?*M3H6t`7lDHI!p2al(h>y1xutyU}Ih6u9XD+AZL=PULs` z$f)+ARpN3ZrDE5oPI(%~f&8a4%Wv9ucO3lg91=de1hGBrTW?~sXZN|EE;Tf&pj#m3 zGoJaCmzn%`eHzH*3_&+1e&nb9k6*yB-XOtsy2LmhWz64z znX(s@)9~j?ICp(vlv1kJf#c5MRE`%LimiqV|iXWcQVwh2>6u zUKMYk+zO|2uNf5ARi-X%#lW5KCb{K0qp9^5M147kuG5}>-IjL3LV;LuO2CcA^ZNjQ zlE1IyFsJ+sa(pwOLp8Rb z?Ee_tX+qQrWkQnj{@!c07I)J?Bv=GM304$>Nk_cKC zIU7>acBhCL7d_LF4^CnK0iFqdtsk?{p3iU`YCWPL-B)RUtr4o8KJ(D_tr*@LY+k+| zuLbp3!OKT1YAa}QIl*^bk^!fdWz2-GgrlbKsld%cwK3^&S;Ta9jtoT;+6al~4V$5f zNV7X8c@^hmLA*TCRy%EK+IkyezC@j*wlXmNt*;15Z@C!nXGWD5m>$g(RBY@Acwpmy zfUX)sw}}T^Q)MfB^0AfnL~WD(?mqh+??`QEI8Lu&>m*JO6KC~hKRJ4c7pkS)Uw3!m z<29`i{^T{)U}@~l8j9#n84)}1ynSmm`kOZiFNflZdr@xi`_r8sb+k9m6+Woq37vw{ z<6Op)ZD^PQWhM(Qq7xukCQ3bF3Qc>r2|$Rl$n@u8AC3$#2sz$Pr`F#B94H34+YAi+ zQN1Jc@a6n{s~I{(fTjZ0IdHP3<9@fkieHVrp>+_uQnz``wu!q?5mJ1T=J&XsEYo7m z16hJZvKhTVi+;eFyK2hdN8x)5>rOb5UZLhPxAUn|( zFcMMn%Iy@kES9?WG4_RARzNL35K4Wd&YFpoR-+5zYimR}>UgTtj~@EQGB6dHm3~P_ z%lCY^+fv3!6KdvZC;KYGON-aAD>?3GG89vpN0%91gLi}A&a1uIpIMWT-t+Ii{VYQ8;zSS)@QRY9W2j<}C#Kvf6fI^4S4hi%nQP zsfgtdfs%Qaipq_(1z%FB+Z{oGQ{yR;*Jie5UzQ&~D^aQT^B_pg7b0#s&?HPEyT}$i z!uP3jeS`Us1}{qiWhL+CGJ@ztQMI?N{rYRRfTxiQF&Bv}TTZwkICX{aC|&Rl$$l8# zPx$A*R4N+O$>~yV(U82v9YM>(cN&L``-nC%U|E z-MQ1A2_PIqn-~q2fms8F&pgn?kz^mUpq0jFW4s@;pb4N+yre){=PLW$WC9els>*^u%~^O@UmL9+O{nir{Z5GU zg~PHa-aXkpPXsB9)zePLrVkz(QoZ`K(veiDSHNw#JDms9ofYv=^|bENtQVP=JbZVo zEf2>UFHfFadF+-ucE9!$ceZ;}W@ID~!qea6m%ron=g&qSrya*8wTiVm>$&kz5Qry| z^I?J>A5gChM~`hAyg(G^AlA4knwo%a6{KagT2CpxlRV%M<0azvGu+P+isj_w7#$Kr z1h>A0EWhW&Fs0So;2!e=VL=A83Pg(TSDM|`r=CZO%7i0M+*168(qasMjD#}f4yghcc1x@18d*!gx#O$&)`$wRW+4XPy;2Oq6`J9zau+wn2 z94UvlBH0?}wo#12jZH^yIp_MQLoO69DsxlC$A+pF4*{{X>L$->?&pDm`Bwl1p7&2?=)G0dmh zYDe$CS~SERi{?3u``SMD&TsP*qfCF-T4Gnqmt)7|4IC_bCT7Lmy_%U27kNSm0qGpqD)i}sBz&jq*0_Ufnqq%*LtNYuSI(OY|>Vo zl`~%wJAK~BPd4e&#Fjro_Y_y$C1K!x0vMoS+-J01v`#Um=!u6^j`Y)u>0Deg@40Xm z_%o^eji%WQg5;pM*R2^*J#aWVTcXru-;`tUJCEC-EVtCGH6FsyB$o{!{NOl<7MoZRl$%!!dt#*P;k#T*5OpIvYx{!hW;oH z_U^!i84dtj$SDPoKCp0V=8@3nSN|3YD^frrB$}*?qzHsB`52PTDab(5_t)eiXkLKR zrMM+Qe#qY3ke2~H3M7F0<{uK-50{_JlT$>cg^yGy-QTNC24P;jv!-wh%{jb?1%0>) zkMP(TBzt?WX)7Wecpajh2Fh&Njd=LudN7u1^0u_#+s;=(ZL8nyuX^quP)+NQh-iVV*nC;DsN*P#|mH#+d=>?|G!C1VQR-YJHtBFSi5zyCX?BaTJ%Uvn@n0@d2?z%S@`M{v#<9h-M zuc~do*S~jU%nf`mm*&4)lTpO|qBF`%+N!&bEhSn#d+Cn=XuIpNs#|q^ZoXWWBuW^n z7uX);!OBNhEo=6508^c2W8^9S>&^PLyDI5}v+Km@xqyogwrzm1s~B%i1N3PYVSc$0 zwn)_G##nV))J=N;Ns#CZc(!HHox7)Vh5*i&(#v)JzfywI))Ia9Ig_>dYYjDy^Md^2k>h~)>DFO9TC~(6l2Cf@x{trI9!e0X=>O*js(O?ol*sX(o?4)J}+zr(6}Rky+8tGphYi> z$_`aYwtf;6O}>c@Z;yWS*QZ4Rstj)#p5+j-g!79b+I8}I`BaOO>_}{-aJvS3TF^cMIBl-FT ziA{;`bME2LWWgtVP%uk0$8g6k#7~(z(LC8}>Ln;8K=#_n)wGkBdh08-O=pYJDclXA z*sC`6X~Ju7(n#?e-a%~XFAvWvS9aqGeH*2cHp7#u$7jxy4qeXBebY}ZFgaPu_tRC= zd5W3=W}UTs6Z?WVrwcgWAKQuQwrnCeMRceA?U*PoeKaXEr@IA25gBVtTSt1`EeqRzF~h#&e?4{>Pb1X%zhgh(Y{6=qPy$95_AtOJQ`$7770+4f7MAoOh3mW&R zj%k0+p#IrY63ZwVt_}rDTpW4?^MYzG%i5?ljx7XvnVOtjd|40?FnR$wlWR)=au-?0Z2(~ah8Vxz2>-!Id zZ-^i8phT4BtDP_RM`l0Z{pPoz`i5eXBGOl}NwXsE1)`3XQ)(^TZboY8GGBa&U6o_t zZBv&+p;yxT>c&@i+D(=^eD4Dm=7jgnIbn24c?B24b*3uBw)FmaJh&F=!bVhd$0C|w zO1s-ewNuvF-iy?tC}2ydq9G<)CXde~fZx6Y-94%{$G4CLAkYR|sa??d$Kq4Lw(cXD zYT_N1P$^o7*#g)sY0*iKn=Ne~MV=j#l_ZSfpqyp#ls-N4DRlMy3mx$tj2*+79O5(3 zF%w4J>=ki=o^)X?RR3D)7SPExqc3AB%ybVMh+HEPiqhN#Ju)Sg!n%tfPVR8;)NQozGjJpM#P-j4$2ez*GInn&3SH+ZF1 z4eof2!Acp>KK@s1VSn5w;O2zTyd!;|ZWui}0i`iDJYgjJtU0OHx^^bYV2jE}LRxg` z{>A0NJbW9Lr<5I-j;{aCz#2AkYDTxqWGuCbE#4=Q7$Iy!PBdl&B z&(+MaC|gs7U8)geq2}F}XX33lDjj_kg*g2w2Gek?%s$y1Smj{i>#so)2p!1x?;nMP zgWVf}Qxv*Iu%cDP63I6J#T)OILTv!Hx#<(I!1R8igN27LkGVW+?!%SxZjZc$C2~GU z$QA??KV@90=bomfQ;+g3+>FwS(b%nLXSySX7wOB5Ru)@c3#kV@Ss4GzsjFKuD2mTr z#XEbHjz25MUDw3`xk$`W{l}?hcLW8Su~4KT-#GJxwVC5g;32DhJKrSO>fqv!)m?Aa z8pWQKVDEWLl&bKNI=i*mmtX74pD$7e4%zv6viDryfPm4mq&6%5d2ERt6V%Ol>-I`q zw!}f7b(AW6#Q2Y?eD6U*hsi8G?}!>44{Z7eiLvxr78Ha&FZkX{JF8Q*Q(Kc zB(`wzYZz&ocUpDD86N4oX_GPeg=GPNhSS++V?m} zoIn>xjk0><+gDZlVnsa>=M0AsC`_)XbvbK&{d!U(>b#k z(47^ZroZIdpRTQzV;0_E!YH#IG?sZ3SsrUS9`}&w9_k8HjNffQo$|M<-fv~jZ zqDt{6DnI#Ye({~{Mfl@3g%?uHLph?3{Sbyaa7B?U@#E?Tx8r0GK|yTP->q$6?4rY| zaM=e_OiI)~Mnp5N4H3W8QrI5S-XjRWWU%L|N@ei7ob?FB{>kac3PPEt zIbPqb7vH}}N{y?{v%_Fv-Ll4KyAxBD&YYJ~gvl{`ki*-sukV;QU#L}@v@*6_d$!_r zrq9KnD_Lk+df0T0j0@ep$hhYWSR}LU;KVkTdi~H0O;rBGYj)5laa?F_I1xvERBs7a zGoiV!jaK!mi@^n_S+S9rP23cOx-O--Up6$!W1Tcuq}bMX?3mjIZ_Fx#6IXvUDx{sQ zgrZy-^;nVQV^x9CP20a@yq~-bJ%83TL$@8<5MHaX+0lGKpJ+%Jt80gvs4Yh_Ts+SW zfcY=LpT<0p(vK(RaXd|7=w$yc^9}cI_$j9TeJ*EnPGsFDAwOYa3*ZkiJ@usHy6?E&1l}T z_m2tzu-F$m39h=ROqfuv6E`;;!R@K3si=WFgm%@RJaK9+t^aBIjXK(@N^h&SGfCx? zKP`eUaLHG`x#nOdzm!5rgNa$X$KA9;Um~G?{Po~D8!WcZ)l}1%Tld*k9*i&VlXZfZ zNKqRRKap(@57+c2uWAPU{g|_Srqh0E9?D7EF1`L)3kjyhmE+)ogx^wixwz)KCSf_$ zb66&1s*tV>15mnzKc0Lse2`xSedzRVa1}OiYm~~tsGw&XZK7|e#VPqFUe77{2HTj< zuU&%3qc@?L&|Mw3Jc%O))5uHiM~&J{+I=zp?xjTA?i);Wu1vp;i6I}VGu9KW)vn&| zP2NMj=avFjPJi2Hb+h?|PRAndSM<(F?*(pz6BknY|9(&Fq^S5Gpt`|Nn4?$m1*57+ zyKVS&?U_a#_1ADB>*cCgkl2&U&4+u$nV~&TkE88@hXg<-2}crA!!y&%oQd`I&M?yu z9!*}qlQSltsKm_%4w}i=Pw`s-VSRAeb$A9Ctopu0r*Bl?`SV3pwr>lkrki;Cn31>2 z7LpXFJA30L%Ys6u?Iq}x<<}2Fc+{S^5C2u4oW(xCGR8drhn~Y*-Qx2@^=5YI?!F(?TFv4~K;Kg|k$4d0AtiBo>&8y= zd%y6E)%r>lMQ0xOzJSC@v@TE>2~2#FzAxiS)(G6%yO;p2{o%>NY#pFFk<{& z$7;}KbqL4s1>0^ZuK(QXZk9nszM+)DC*C(IM5cnJj1W>%$@wCmW#(LY8!ipn3);EE zkQwbkV_RJ;lW3Pcv&clfE-slI0ie@zK4P)DVi2cv){kA#wZe>ySJh0>9i99=@`#@q zAvOb|b?+BS`6Pb%J?I^CQ{DgZcSC2WA@R$imwO;H>At z;xxaPdywFbf63A9P4HEZOBoUooef)_eI06z@jGvU1VPRSDY|sdMJ&`kq|sNdMub;= zlSvj%I?}+tLB45SfZsGJ%6_9HgWdNA8{O?R=7$NYnM!yXYSUrRm4fL2 z1T_-c_LhAj7Dzu9(tTU;ctGZfv%RLCy-Bhf`5YRQXGlP~5nBe#hC>8j4pPLhzF?0J zBgFT=tOTY23=0+$7`<7Kz&vqz=f_FPD{@}P1ayn##&DaaJP*7;XBmumwYHz6@ypaM zX!zjEh7yWj{`m(d&wEM_@7ZOW-~@H^P?@48O<5qs$yE^l3{q4($sZZOwl6=7ax>}D zRaEmbhS3YinZgS*Zh`T65@PK^0_XI8Ea5&$riv8Up<+|HG|M)sY%evfvA;0?BxHmC^ShL{s3QEYHZsLzq}FMq!RZ6qtgWV|2EE(q zA0(gV#{t$dO{FDRye=u!-uvkiR%~a`P_>P>!TsA44yoY{L2K+)CrEm|?xMF(;FIkN z4cn?(if&Ef{g)DuQ>aQB;ZqQ;&Fz0LDh?Uh!6)DU#i5LUvz(TPmdNLL5Cmy-`ggM9 zLJ7;l+okJr5FQUSls7V|G-SY)a}^X1e`kJid9?h9E?ZjUnOUL<%a`@Gi|DbT2+2)Z zo5F*SX#5Ap@ZSLXpMzUPK$RLK|Ly#&Z&6hh;_~3#xFiGVDpe#`pMZ1%48r_g z=mcxQa$2LQ7=ZG0$RIY2%L7V!znkh$P?BUqSjyjL_xp~?|EbuT1SH9g+THmV+~EH% zj9)O7Iw9=R`>FVCxnS1gwI{!BGz={*X=`p$A3Pht-_`$UhN;po-nlz+c<}w%3{TP+ zP$GVpQg;3CpDv~=RYUM6QrUUL!pn9kxFFuTa{2z@Z810=xgizk67VDX&GkYemxm1g zag6=T@8X}huPVP#0`au*bT#K<7ZztSG5Z7*+@jNgYyABbF{OLVGs;T7pjTB@wPaJe zBS>x6bld*ibQU^1U2pmui(8!M*BO7(pwufz)?e1@+p}O5*;wF80^+CS3>mwuSwOE`5c%3!%x9IxuS)`}1JQ5?*lW~Me;B8nBB zaE#prWOFTI1 z^s?wwXy={VP};`l_WuAo^7^Z93#`OSq`vMyhq!UuN5kL5zkwEHzEft$r<6kBc-t9! zvc|XWkT}9kW}4aMhI~Asgnjvy;vhN4msHouX)QcY%tIfBjhbMX6b3$}g8 z(&(z2V&j~L348=d_P~GXH@;LjeIg+Y*1H(vcjA~G`X2XBEWlw-RYg>m{(wX2B>67> zS;sYOedzl6??3kLetz{o%O!9vnBwgBcl?|9L4^?VCdj*{?m?;2j6DUBQ%~8~Q%JUk zDRx%jha0r1k^QgX*OEvB`cD4D5K4B8 zFn%ro4~wh!@dK6uVvje(1FF2sNK(@>>z#gQ)Uc++q_8@aetA1vL2T(Zrt7&@Gp(6^ zy>YR>Q7@k-L4ilEYH$<36Y4lPyBZuImT+(Po4E;^ zQ1doC?d}s3QMPNkr*OEKnQ3Hj59KOwHl>c2j`2d->?4~SK#r|QMyvlbI zzvn(bJz@RQB}zZ)zn^4so%^+lvW5|X_*w<)S8NWk2{|a zI8EUdP{9@qIC4@Q>~}G)a2Sx8DOkzj_0IW=6WW*N4ipHC#xGREAK_)mG1-z9!_x_) zDFjR;FBx6RvJ)iRG5e{kJ@E$Ia_>MO{5nj2_|-es&E%(9x-~IlsfZGSPF3foht(koRA4RK8j^F*;@tV5HuCTM20C6+ zjqp{1EOHFNjCfZ|HKr_C$^?KOVv*G;ouv*2p-lB=S52Py>Iqv=vQV72mEtS;rjws- zr3_*c4uqs=22WDTSi`n*Vtq^eo7{pv6RlkZIUiuKvE8Ymw+R({gbg&Y-X9Nu+cHm{ z<^#HZLCBk-iZ&U!e`Vc)QwU0_QpF@e%JYg>aB@eG=rA)-;xA;$ThDXUP_;v{Q8r$6 zZ0c$+JDY3$dwCKafcnAW4M}@Ng&GF0rk0AIG}Y^KrP8~HuYT;^Xw-Hjro5q{QPk>vyd zD(R!mHAP>1ALwI^j1K*)aq&rpW){KeVii=vEnUJX+2SfRh$;4YUYz6Fm!{kW-M4;z zLRNsz&i(1q1+&|N=^efYs-|Y8`R){j1m#YzCudEy#gO*%tHZuj%)41mH_QeOKx-fWmZ+Lo2|--t5U~4MU#_#a@ErK`uJL z@uP!zP9UAW8GWJE)7c&@gi}RHyit`HDceLUbOZ}q_epawVKh>Hotqs5WXq0;{t z?`EKp#7w^~ccOtOTmA1s>yA)V;GR=u&?NP|<;K$1xD|u(&10TuPzgNH;kco3{&^Gc z@~h2cLGC?L&tJ!688&ZuFJgmu8#)>EqB*l{dOeTV>iJFmmA*W%dnlfSr}y)El`JRJ z;X~mSORnO>gee{bx7F}>*NX%oeL(d{=dUGhdO!pusUINDrRdw*BV`)2*#ZE`2Zz2@fSnp3JR~ zsPvBw^d+ykcU0woL6z^$ZcG_|8hFAuf6xud(--kCOYYNL8#g`v%QWN%sN7`SJ``g3 zpz(1{&B}y!MWCzS71_6KE+PSQ)c+iCTfT@}*cJSLsQT-uDBt%B7@eV;A*C5$NNEuS zX;8X`knRvk>5idGU>LfQR2pe%kd&705D)|@N%@?I@9#b5toM&+&6*k36T^L9xv#xd zk&UDJ1mqDmnmgZvU;TZ%8ejFB!HnY#F-8w)H?vdr`51%VPjimLKk;&ehT29-g0e~= zRf!uecInKD@7#HrInFG!FUUE2Sok@`q6p8x-&-jKIyK+xT7QY5ivKb{gQR~(iYkXa z>!=^Y(2u~DT0)z=&0?S(q*&7C-t^=pht;Y!cEtL#WHRZApxjnjcu(PbLZn78bdu!e zfX~khlCgyT2n;68@l;kDsfT2e_7_xdv5soN3@ljqLHgeLnuO~{)jg3r?)bSAWmx3i0~6l8;&GgZRGK(u02?ukht|rqTqHO(aR@o%mU9FHV^47 z-Nc!fx+9i+TwmeQF5Z>~_X^!r*9B&Bd9e(|od+@wxAqT9)6_|JP&JYH6T3!c`lk~Y z{1Z+Pc+V_IIhro{RZrI+M?b|#Lui?MHdmN6Mp$@%)hb}tmWE!`bbFI-D+4tq!wu3G z`H8dq{_=}QQsH7jZJUgxnDK=a59UXg0g*$2r6h$gMV6(lMj^tSHLQT&e>z&&x^Zdf zC4w}IJLADtE;!*NnJX(#f+uemOqXT6(QMI(PZ4d~J6)xy61WT$jR{A;AIdUJ(joAwZn!M4t zz5FEZiw&NTc%$=sUj4^FJ747x$wM3!U=OYbp*k4HUX0+ww;@RNrsZBXrXIR2QmW(; zQRSsjc8=sEQSj*YC@*gJ%eSDqsfnJG?QvMAaV7N)sAoMrO2quHPdKU2WzA1Zb7RR` zUDs%S&~D)@S=9sQqBK~~n_xTr+4sL!aw*KRA3T|e>u_n1baC!9^Z`ssqI;#e(9iUW z8YYBzC|fW1c}1?QAzBWoA65Kh2CkN{B^b`$hAL)-7W0E6H$d1C*)pWI$8qbyd~$~* z$ew>eN!sp?7ZW}5#f^O;HNofM1Xoj?c^UUjx*VVTP{MfsfwCrXS~uVBi7P-Pt$_%! zTs2csS}ZD(lQt2MJe0w}h);}+B}JekrTAXYMGV_vUM_?=Wq)G@^y&RBJP=Jc+fV*{ zAjxmifymY88A*NbG|LfDeA=gh7T6ZJN)EJ5bXG)0*4Dv~7`w6`%P;T5_KpC%ix9oP z0YW%gd=35rDB>F_J16$}};(^5CL7WmocQ9xwSmVufzz$6q+?PCjN~wAKGpd@^z! zl%)450<3=_N!B|gvD~4)Y@VFA12MoYw8V%5BA)Nt$Djy{p68BqPi_129bJvKj6)xa zNF%grSz5G~lvD&BpdO6&?D3qO5$Kuc9h)TtaxPtFOctbZx0kyZWP__`n&inY^Osj= z{0XkUE+cGCruUU}0a9syVkbjzSC%t_8BGXCtU2Gu>t%|v>Z)aOLWL@d)uhqo%U*sm zbi{tIWG-Bn5E&PTc*Fe$&dG_(`I~dxmX|KmfwRGx((7KUw4j0ugE+9wp{kSa`_MM>}^f2X; zDvrW`L1dsY__I}cwf;<-pK`{*-h~ZVe6#e@r{^CMb$iM)ewE}^C~H6ba;PBEUzB08 zS0TNLjW&N>Mbqd)xHW5@I`el3n-{_#TLSUrmA<)TYRqHaKqnVk z|2!BprK-x#Nj$LzjMrVaTMRKYCt@aM?7hK>PQ`z0q>>46|81}3JDCa6xWt3wd(7-& zVC0GiY3G&B#m8vM5X1EsD6iJ{@KA=g|AF{SA=*+AW$Tn$J)}DXMkX)(_aDA0ZNQ;arshzBA4xxTbwK!IN`YF; z_TSoF`SjaJhw#lENmj2~V1?t8zPdME`Ic9M8UH1dO$J8DjEk<$$SOoagUfsDeR;7& zhdJyjb0L*|{)GYuAv1HV4s6>3_ruLSYv3|^@0}6i%y!i{;n&Vi_ierbl*CkA<+!ZJ zo4+l7G=<+vd-7mVx`HUL6#kzIEf6aL7Nd9D?S-LGoISk}f~nXbawSSuve{zO#{;4z zl6PX~!J(}9=Q1dfFph*YR3*7En4Nh&J+~P#G*6dM#xfuXoS+S;tS}q#cU)cHUcNgg z%Yal7hQbK@JQxYLe8~73vsno?-ANI2*kjV*A(58>8*%Nf>kla{*bnxuRlEQwjP?XW zDFiy&U29-1kRHBS4#l#}66IvdcqSZA`x+t>m~%9E)4X`HC6V$Eov8H#3n1nG=7rVO zNEx=)-Q~i-i>}zn{yL(@A3?{fPL~W?van3pDeNZo^y*89$QL8uqRn=Pcf$U4KL#I* zJF<)L5cQD0dPH^*^jP99AUilLiKq0o_QEJ1C0eZ^d@W<;UXa|&vPEoA`pgEp*iHPI zY#^@1J;Wv+tO|^U zl^iQXndt$nhhyT!*lCV%`Vfz$yDt;aiNEMr6Pc5nUcUK1?l(~X{XdSl3dIyUq7 z_$A>)3?js?G1b&G#R&BojoMtjD#a*Xk*Wc7ON+ta(SzEq&jFq@27svFX~zV?ZI=*e z?y=bQc;BidWs+Z~fYAHkQ2QbjB`kUDb=k2|ETnd=*yY)Bc&3D*k_359_xJiOi7H-UkCBYqq)+)sLG;J3nG}_9#`Ni z;VDnU`yp}&Uhd}!cNp8c!#Zt_20xXdOwW;%1Uud#zGvO^1$JX!;*Zlu>Wf%pI!2dM z{McAHp&b)>1twqheVriE!Ys$f@WCW!=|rMGZlk;1R|7l3k@dRRCJzHUwAf z+?J*NO4w5e`quivHH|**;Z{+N-ar0$q542i~n9UV~vy`>caS0l)O}aD@(Z>EckN_O=sW*NGYQzXIGs_ z7Aw-l`@&%JkYeoud1co7w)AH4;TZ!sYhzj4i58x!c^C z9#0eQxV4cZi*zJxzCLL#WXR3sePx`&RismKmgYZQTA(T$Sv`ui5y#10Tx*H1AoT4T zbGW>RQf<~&^Sf#2Fj|&n2+UZJEgeRhij=kdUIB~3+1u^4>M!?{d=mGqX>)SZbCimZ zXV*pV@~tc`^A7e@TR^~(P-n8lE1@NuYMqNuI{loem@qD6fd@3o>G`sni~uWsMllmL zppXvckX1&NaMa=|%OQ6|XgYK1xxtZ+fhm2-dkl2i$aImJ`Rez~T5g7Yc}vbg1Shnw zse7(}c$rSid{pq9hf_NmUs;!3CE6IsfGF`e{au9UoYzr;WI%20 z{G@T&52xB_hI>90?ynnGJ(INA+|fh%g-*K|C{xGY)_%HwZD}(FA20XzETOhx4a+%C zn@(AzvsEh zy*%psTX8utnM6l4lj2DI`3uH91wOqwb!OK~RYGdLVp2aq{>o~0RsLBu9+3%V>0jyQ z^^ykn?_J#}Jm>!wm!yFYF0C7~sSb59@CimwJB#3R zLhV6P_2zw+bS7`?>-QPq6M1-aCbOCL?UWc49Hd9uwjcaT$}5yv<;#&pMLI<)t+3W$ zQVo53Ehu_(;y1!ljA34++OXt5Q6ejbsKfkJEvq7MIL7(@mV4OlsL=e&R-Ii(?HMP~J}^RBA@K#H!4^cq#7 z@@b)&4Ag(5XwQbprO7NvF$ho2Zsj(@Lz7POs{C(E$lS`(#~}qzmJfhWW7fsNf9|G4 zxO^Sg+AbqT^5j8q`|4rIPeI@CZ^)13Fpm**a8sXK z-@bJru>Ad_ljl5gv#Fu4#tnv`N43^9s|EUX6xLxD8;1i9jl2O6+Vx$ zp2@rVCt=@?U<2)KT+OfUT|$ncGA?VTVYuir=TQPcdQlKdUV26A8<27LpvBFBkp?M& z;omZdNo7orZ{bNJF)sY}*#_(n>(RiRU>Bt9xXDGq^wA2nI2F~Dp==s z3Rd~0UcKxS^tEk`)eym^H1Y;DqpW(tBdYjmByTarvd0&p)LIv=h$-Kk;%K@mN$cwy z#(4RDVM_-6z$c7O%E=YI`f{1dy+e-pp*LybSqmvEi}YV2(EWJUWhi_#N3u<#V@k{> zs@A!=;o#PP%XEBvx2d^CgNF26cr-6?ouZr&_Liso>mK#_gcN3?;J9@I;=m$ss3Y;` z+V#GQqWl-8V@PP>6jJUCMrydyantWAPc=Ca{uE8IS+F(4w)jB1oP4lad{mskk&MZ)X!udtB6~SKz zn|~(jON2EK*)>5=KY48=e2xR11bW4vg)DS!ZhTG}Zp@xP{PRVQQd#9C<>gOtOVY^c zhpO8_4kK-~=nS@vTu+4GM65Lj%>H=qa2>b!DOmyg2%aI~9v>Rp)QR?oW&{l`)7qFX zp_Eh@{;&PRox2rc_m}@nCw1epLm3$KG=RJuNPvw|Tq-_tmTq(;<4l|^T0lmf?2{iX z)dLt1OiZK`x|zoWk+l2&g4{GTtf=TeH~)*&;Jt!f#**-8%cR}4hYlBF1YWcKhSfsR z@T|u#Uk4m`-Y%pa%Y$|EesBJ<0-<~9Yu0uA2w8_1hykV+8hv>_{q) zdnre~77wd3yBergeAHJ#q34AKc@M?&3bJ>Kn4}7Kt*}mjoW`fgPAdFqCK}fs)=$6d zr_YO*$1d^F5w2fd5MtjvSr{TJpbb}$mUamOFySrs#S6%CY?BgTE1$|AEj+4vwMMaMoA*v;82lRa1> z_{G~v$@Xu0Uxf6DY$>0Jsr}A(9sS9hQ6xjxwD+U$66Sdt&ehH;e4S_gOgJjPm#&l> z*TuBsehI=ayz5~4_k8LecZs`5A&Oq?h9a$W@VyxCm{LVnaY0M^^VjdFf^qT3q!)JJ z>hZ7Z8m3Nj>J2-S0hJbC)yjWYG)fr*2{Fu;(Ti+Cm}G@l2hC9u%Nbt$lZ|)DHa_-$Tau22QktruLCUx94JpBA+O)6&gQ) zF9FCve>gZE1263=H+`F!7-FzkNbnP3`?1Zb5O1lYnn|IJ2Lh>N_!~IlH|a)@m*fp` zI%Pd=Q~23(#n1^z3MW2wJ>IbEoUGLS^OIBgP-x5J%b}nwV%hd+R4tGmDNV_G#Bak2 zi@<~-`Z;0bpI<{mWR|BA#ucbk*;!4XLnia;MaOdJiyX_|OnynFFoE%rPn-89)K9K_ z<3#;aLQ=&!9dDl5z%$jsX&;^LdTGZQbJlqiO%6ai0YvWeZ<={vq4Vav+pBZr5V>2Q z{nQ+484E(&N2>nlRxx}2}b(2&IoB>*vYLPk{6$sYuF;r|?MIC@PyH$;~Z0yC3z zuSm+iHV*x4v_Z4-(CM11F{8opI9+Eit0Az7iT>+*OiD&a2#FLT7Vyb5$%KfOXRgse zatIuF1Op$x1wC%Zx?=_z;LK#Mrwr>zSvuh)pjfuv4@gLd(19m?hy%!{ljK0)%j#1S zC0c)gtEE`9+nDrOisU5-XoLXP?Z*EiX7TF@jgB=7G3 z?h=_F5oWI5IO`MV*7!$jCgCU0Zr}JnXl{4z#`*Th1Znx(I=M4Yo}EzFqTx#xuGVay zEL?u!LPu}E``UVafVs+=H>UP``-Y_Y&ou{c-WJA!T3eIi`;Y4=656NFF1dex4}O8f z!-;MY6i>#0$lwU)y8R6tTA!boA7O^aCGi~2S6RdGGs4@`f1F_2;!hB?Kb%A>VL%E* zY0(UpeYh*2Q7Dp=a~$!vy^$dWNlX#!7S zcVOOZIes7BEO=yJKGPYYG6X?M8cTdvJY=ncAuPafC zSc9}v(kr#^KM={^sI--(kN<(@5APi_F;tQzEP9~+>+>Pa=ZJ;4Zy_icKl;2>C4fk< z96RR#R$MieVn?gz|0X9RLno?RKX3q@#@prd=5Gw7qUbd>^QN`3f3L1MGIGIJvf<^w zPcCo!yPt#9cyqY_ABbmjL!_p<^UOlp0oXC=q<(kX|C>0I1r`j< zW}>SGCe16ohoMT!;}WuVADL~xiRt5Do}Dr#J#@XdqAf_qH~dP&gnqHx7||%V>sA`;b&fcaI*-!IjL;FNpEZZBkM4&`qn>dw=QoVKFX7d1JIC z;lMx-X60aTG!I#k?9WQ&R9?s7SXY#aa$2(!5`}!#mxS-XZCkKO_qrlgLa9(1SL+!# z`$ch-RBM`|62YP^4~%S06#!G|y+%ma)uLB-B&pW8Kcpp&H8s*3DIW~zz?+~{i|E)?V**tnmfvf8z#?HePG)Wp0 z%A~Hfq=IWI`*Xq$CR|#y&+mw*l+Be%j@rk4#-<`aJcDBNL{K*DN@2 zvjoK!l39zBmOQkhoL=!!40}&j0coxBX7F-=^M86-vG%Fqs|;Y#WOXgf2j0O_uBAb* zlTBi`UZhzWy%7!^X%{R-A;*xJO1RQY!Wb~BgBM+xiWR@PT(@EkKW1dAG>UJj>kY_D|yNwIybL{^-qpAt1eo0g;z4 zWC`*j+&|kb{4p#bAEV_ZCeqrPKhFEz>imOtUnPLuXAkM=@NWu-o2dl@`zZ#xVwW=n zaDQaHGLEc6u)*Cu<1Be*??{UEg}@Wv~<^4eg(;ki39C|5jzy*da9nkWNIqe~|w7 zAmQ%_xC8RX%RYg=mj{#^*>2Gfw~28<&w_%khp78+0yoL|kp(E5yJA3DmhhT)u z*yVYb8wb_>1I_(LOgFk(VJkY)dFOWTl!UcP)Squ^zbF>REsVj%zt4&qVnG5t5;GGH zM%V}?PLkr#<)pkEdAfTGBS!!U)B1riE%jAV4Tg9@$CuOl&1Bj#mAz!_)iojDmi`Bp zfFYhW6MgyrzWYD;#G|Wc0^l7nXdnQ_HsgkXDXSm?m(RWe?hp7&0$&;OX#cc7d%O34 zBU)J(L#`RBrfwyxxi_eY92tj%@RXxnaVcHVQvxe@E*Qt{PS1W#`WB46_G1fAGJb24 zsA8<2$VcSbs?@;olN$s|6{sbkLweC|n*(wekQ$tf3frulwBL3FpLLJ5xa*uhaiUk$ zO{i9FK2Xaq>QuaDiTSXfvt^#v>{dM$3mLep@79jgq#3Y#(Mscq9GatBh5CC)7*l-c zd+`)fi2?$54vtmW-x6lONoRH0!bL2`*tZyBDlTMOR96IlmeeG1VU`pXGV+TX6r*?} zs8s4hYYtN5(j1IP5ahJd65!jg;?n$_R|rFDGb?eRaBK0DjYKUh3%nbL65yVq9GR&p zwqE}DX_Wq=^jK|SnCiPEc3Q9Ky}iRbqY=Bn@lp>vFb*8`SRrONOlxyE)axRU$ zqNr#B^n;y>&+3~YzCT_2lC?*LAxujX8&mG}DgxL1J9j}w_Gmi@aF=>#TlBJoMe=2} z(?p;60<|NF^o<&H1Az*O`J0_2$=ywh1N9yKXfHD;VHk1l)!y;0 z!Of1?pJC+~PTujI3#Tr{24w_!32A@W<`AWuQ}B+Q5bQSr=&Lj6k;yUFAy@2{UCv!t7{n+~{l923}cMiRGYp=b}3tZlb_d=CHyo2ZOS#~owTUX4m>9PTk-pL9n;4eZRn}xu)WY*O25shRH(k}PNl-6Hd~Wdi z(A_uHZRNV~sa;?Y{Do7qawOGN{~K6qAwY$e_@mBD`ACAp((0{?)iRIk)6aKu;R6<4 zsmd8S5{5#j(r@}CO9ZJ6;|hyP*r|z~&y9Nx)epm>_Rz?bKxQ`=(afG8Cog}$YyT~@ zN7zHwf>mNo;wx2g@*1pNcaPwCoj5)holJT z?~Ua^Xw@M$S|NfR7hUlk@(M6zWdURuMx0U%${b9K6r+ITu4Y(Ahu?j{C&QJisy?A1 zrbTIQZ_6dmxxMsXa#W5K&4zAy55m~n-OP}v$!0UdN94iunpM32xhjWO$Hk=C?&Y-{ zo}#e(?oCi0i4a8kO!NalNTMk}LPR^}(=R4tO+=LKWBd3#CF#u@(Nu0guPZIN_{xNZ zP+v+IphM*d>;7{#^S@>k?6HuF11I{vNrb?&PS7w5(IO|=m=|xo{1ZOnG%x3MBL(0` zj?5i|mt>3ruJ2yn?MaAo!~#EKB~(T{Dz0mU4S~aO)F3ghiAoMEq)L!;IGpd(&m)oP zfxzhw6(Ndb>pw200U#SwrMc~WK|M1LlTmKv)fW4Pk#Rsk?5ke+#OI90q%A|nD?#mg)&f8~0QAyU z8?8u1Sh#K?>LvFM!=d|Ew`x7?CWbsZm zdQ7L&0?}7nYyW{z{MVZlJl zJw*L$GlO`3f3OIHDy{c}+Gvnh1j2=CY+{pPdx}di&d6^6zNYJZM$uf66(ycIyxMxs ze@TJ8@K*e4UXQ`JhUE52#@e1;ka$B({9mSFfMI7etI*{$c%)Q2yj>o&vG@!P;nJr6 zOC%vSEcSX9LT_}**=-VD`$U= zms(kIhcug;AVO%rH47Rqa&cs&7AkSWzm$`V^b4oceYNucxGh?)spj+|11b2oUR@Vv zGhc7OspSu$40Utnp}u)hL%h|^=4U@!ihJ~FGUnY08Xb@0FYXB*>&T}5<{YUPM%tr^ zMB?J)$6t0_y01Met2JEHSqA5&qEH-NhxE)1k^Cd6jIG~wIiQg;cm1_Rj>Coxxjp}W zW_8}K+TmNG2HvG|>#9h@J}Ld%u$=>nF=q0q#6 zZ6Xe)(Ks2^%XvR*h`{duqY>~pcLD{HS|C%5Bpc=9m2#8tyF6>f5O}qmZTo}~qVf5R zR~PM%(_s2$4gMdEa2U9J{~-?okq!*{s1FAdm?vZX?YKV(`1UY7Kr`;En4&_Ch>{bSJ*Vo^WUfdW>ZQ~P|$lO9-nx` z$Dc+?^xlDOB!LA9?9pgf;!f#O;U&1}M%M>b9e=!yMMU0PINf*zPm|*d01To=vgg;A z_ct=Q<4U66!jcnNC`WaEaP{N=-Z(jJN~X_NISxu7(zKXO5Au5X?s?}#XHuq0Gjz{v z^!yajZca@7WP+(Q<*mr096~izyPPphx`qi(&h(EL>A7H{lkxF*$LWa8bm>Io&)ugpI}R=eO0dhR>pH` zN_O|L9_lBHd1JxZCV3Ami&B&PhxuD(mkGfS)jxtyeUp`W|6lL$x99CMH0)nW+ex%G zw*Ch?x&Cm{o(24NJc&Q@Sn>_;NC4c!f-Gc?{|yL-GC3#^@aTS|_(*X{K1^5$tTbe| zNHa;I_pW2Tmm*{mjE@;J&bCOX1(d>cfwCUu>jr=!&L4PN2-}C&fK2;x+rNsF%1x(R zdhAZjf1`t7HQ&f>l<)0}KPU;7CEWx7G&2Ab*5m4Z3>*GmM~MGd04)xvr>x!i$LzU^ zccCa{F6DCuHWZkGMJIA#%AVLp%_a&7ZSrjZa08dUT5bo(KiJjtsi=U40cV&611Y=e z9%lx_F|&RepTFPbNfgR>J=-bpYk?wd3rk6(laZ!IX;cVS5_}sAV+r$^hhfU4UB6eZ z;X?Slv5mph%78la%jKb2P&ddo-9Hd?p~_96lo$Da$cIP?*TwJx5+P05>SW}?NVus8 z3nAKep~n~LD$Q;sW&3Vw@HSJx=9_^%mzH>YLD%OV6+CZI@6uQZGOTF!vv&vU+b1>U&era-w8a1y=<+J7lEE93Xzow-pFB=8&r}UaLn$!@wbS(L>Tt1*PRPd!gutyJ zDZZM4A|K|Fh<<|p?}IpF`lk%gPmAz=eyf@J{hlo09Q@e#1O$cPLk{PQls714FY1b) zHt-}F;zguQ_7$nhw>A);MUCvX)gE5&KWAr49IOGw3T$S=M!H1rd|u%TB9afA`YRs= z(|mq|?NKvsMMYXr2cEm(7O>kY46(b$)?d3MuB@orI=z5e<3!WGHjv7= zD)BPf$Wu4KN;gBL-d6EiKqBB-%e9UQrS7Z{Dq{x9Gph~b2!*Q zd@IGnE}Nq#fucDx`lR7RyXh~q=i*#H)Y$G4M#1WubEDD+9VD_&ZTIF)#c(HJ+JMW$ zekS32&;t}qWPi`|3rb1^#4-b>N?v*(H_m+tCmGi8tnRks{&~YM=HG8~i4-LL5aPj* zn0TkT2jk5Hl_-F4=l~A{yR37F^lBhV_?~kaH86hY(u>{B3B=Q`@*!Xg0P7Ink|zUP z;+588-vxj_kZ|$@%B$gcywv~p8hL=V^=#JjYCjeSir|o^5@QAo_9J=%Lta2S*SY%G#?SckK1=tx`rf@x=)i?vzfMU(gQ#2Q)v&v|Nm{Nxhpsb{BvHKpLa}&%=fu zt-WWKG!}onPbH6mkhtYU69ZDjzyl+3uo+bb2R$=)Np2xp<^tjK%R>#ZqCA{10XNe< z{TxvSjknC26M@X;SXC!aXnpZt9X-SBf3M5fHp2-I;gfKVQQ{r^Dm^AshwCOn(i}^~ zuvuJW%cm(oCxh|%7@#U~LxxOPWPY&E$>+4hAbmLj&R<>AQyT{5f5LK4OHT}H8aDrv z$5=g}mp6c>(@=SEjKZ2N7WQ20gEB3UVt$(td_&|~PrSxPr$DZFJR&QLP%lXHb#q>i z=d%6n^P`SPu>UiIE|kiXMBS`?Sn4a>S1qTz;tCfmLGW(ZA*-mQJiQ&clfG)0ea<)A zi#tEMcNRbHTih7gt8Od*%>d_vNIr7H(pVwpO=hEO~R52(Ji zWd~Sthm_M5hbR($t|J;}OiP%a64FmfwNoKfBy=LW?Z`QBbs=gy9DR-*J|UNwj%ek1 zS6+-t-Ni{u3Rh9ohN^fZX{RzB;aE6Is&a$@X zz|LyLC_q0Iz zwKqxSYxBdi?-Vel&VTgzqv`s!vARL9WBte`lM9*;Ss6paC5A&_BBf<%(E~uUHX$!A z>eoBX58v_Hdc0t!JjIdX%Y(f}{0%Nh7>FwojC!C9N0plKkcNx2GRgms{{ICF9=M zYrpuNwx?@L=HR&Wr}MV<+rle@D^qH;65R zB0IvhZ>!s)DtzGiZprM*zQEVXr7wM1T-s@*xDHXLBLyH$TK9P?e+MrYj%v+g)4j5f zr)Ptw(6a+iCfp4p(qjC6!kv%UZ4Eb5S}E zJ*rK)A6{zxW9qxH&!QsSWI=d-{pQ5yHf1qy>S%nBEJ22(2arRuWOO-thGSry-aI@Z{~L|g(A~d4 zXpy0`Q$H=)=}e+`odSju@;<6-U&7f!kilyEMn;B4S81gER8I z#6R4>90f6WqKqs6eC>s5?7_|LAtr5+)C-^J>pN{|1T;Y=9O0Ztwi?v-h^!-**$8;V zbHm6A4^ILAf{BacBb)1DHRHc}E2Uxxw4)KPO+3M`wQQg8)o7T0i5_yGsw33&a!Tx* zo78g{>lymxafjlUFCqHvl74V;jfE0EnQFZ`M?hvE=6^c9CWMA8lWvX7MD_r<5!3f) z=>{CJMDy2jLU9loMc-NUBY;=s?1Pa=dd&+9nZ-`Ck9P%+l)YL#c>RLVH0iJia9wyf zY=V2E?MoRYFiOrK+qJ}AOj>+2!mo4&t^V;`-41~6XpFtRo$gpVv+NUL%h_RB>6h7g z(#}dC2Ta;#k_?uFn-5;2o20{T%A>5XbX;%@4A~9B92O%yn)NN}ZUnp9v zrJ^CqIpukjCks3ZkF|k6AqBjd=>aDDEU59>wJ=qxJ^4Qno?KGnf1r03gyxXvTFZvU z1+8&<@&y!C@3_NDm_}j~LcnXs$IGvu%>Fxc_E}r>hVW&L&sm%7o*#B0tYZ{QQ+W+R z%9^C85>CfLi79g-bd|S!G=q@$s#!wSS)qYd7SwNqKsG~vppc3hbE$}9V=$F!aBTc8 zZwf(1tD6$sPUk?-oT+}Kp@i|&K%NqW%`R&^@DizLi90o6T6J>OoBQJB_=J>X3lX)g zryT7^Uag~1rK=B|m(R&Qu~i3LRyz))>kO15HFo_$>mbYAVd3RB*OIkcMV{dfT_{^a z?_E0oZPkBWoGl@dK$bDd^OQSHW&yA=(_=a*kaqd1_57|}=QKeSN3AsBo(e@GBj z{)Dyp>frYG_)lug%sR9e{+^HP*7~tyCyN-k@q;AEP%Ih0Zj0}Dt~%_E{WOB92Wwv+ z?q%6cxh5QIDwvZB)0@G>A{Nek1tX8+7&d?+<#HNG=~@)cSyY}d9YLXCJ{51p6g*K; z5OYRCNi&K$R;vs)uDp?gA;bE5o7qCabT{r)RXg2iCOjA+6;+8r?+Yho)e+nVPL%#G z#so@cozun)X$u}Q6wL&+uYJGu+hP9A#u}};lveLiOvw6kg2SP>@u%XvCV1{DdX?o| z)lJmD^{ES>7CKrJJ2LN@#-of^QmSiR`)dN4H^qq=>Fc1ZgG&poQAxI-**SP-{gk_( z*D#{K3X`klN32}r+G*SL`-oR1bBe0-0ElEnOF6{lh@0c7f5b-<0$VKB2ut&lz}OgE zdkRGvxFgvL8JIduf0UON-m?sVjd=P!87LL)hk7;wSCx0eQ!1jM=}yg;zosVb{)|(@ zf97geC@GG>&sl$RzqaN&nz+^zsud$3d_(wV8fjx)ktQQra>WMX9+B@xKSt9j@*q;7 zCbpmdE@Mxl;W>x784IQ7vpixn?PMHbsL;0IE`4XKqRHMWz@;>sK#tke@ByGLZ)ixr z5@k>N`8?1oj!U|uG5`J5haf#7B|`IgsORkRHZYF!I`k%V?#ijdBdV@reN<+C65+Wz zT7$4mFGtVt`M{>>FB00dvvPDwt<+$;k_qTeO=Li1&?W;aopP&=+Z-W~*R_vK?>LW< zG&2*G|LNg45-#UR^V;vab$W5Mp`pKIA338%#j^&}ygNe)A-d=zT^tP+?28ZJdgK%Oj(09hgVwe8`k_isx zGr9;V>GQDra~9}#w>c@Jx;r${zVkUr#tK7Olh>QC=1t`8k0!Boxk*Cb9$>z#bLQwe zLlr@ecn-1QzI%3ib9Ro%q>}}94IWToxhOe))#1MpljrXTkuL$o=_kHfV*!u)(VNG> zk&PI|Vkl|F6{Ivscqii^!-kZ9i5#;8%eo&oB@Mk|!CQ&Xnh?Z&WoJQiLS!NFWyVAt zolS{ZStox`hySDXZ~jdJy}>MqQMYY!3P4Y@SpNPPQuoanB^ zUx{&;z6$>b`gIHfX4Ygk)o;62ti?&59_`smeXpJfCOOLAr}8Y^0tG9+SzN0xUUAPC zTnBfxagt-zb|psD1eo;)AL5<-Gye1+XzMW6)r{e#`u2aI7=O9o2hm2SlDf;m-d}=9 zX#zU*UT+81E6D7?~)63sOd*d;xu6GwclR3e-SEC7O6cA_MUhPaP+)?LLxwR zIw9Fox~suN1aygz>ehJ|kCq2G-Z-cZQ|_JJlMoG6=lv58RtN`=njSq6|5;*3G~~$3 zdroO#)Pc^MHJ=C5%7;LXO?RU80jv*Me&1r>V?B-oFk}CRh5!G*Vwz9ON6SM5epHRa zWDWP;zvV>tQVOHS{kmL(aD%U#Y5;)S7ck_QLTZPPIE8t3t|!df`|f3mg{<jN#RX z<}e%5_u;xt|89NTzm?+WmGzX9U z(Aj8#6*F-al|oB)rmLRWy&#fJ;o$Th_2eCw9@~);>u>q|WPnoP9fvgtlp;?7gW#d? zej+PI;IT1U<6!#9q$CW7VZyeUsaYj<@4)rE>OZUO=P{jO<$rz3pVN#ADUm$uOPAZ7 z{CvISDqCWKd%CajEU{6L z`CT52ZNv~d7-m$R_lAugZ_dpd3Jw(OsaSP~H!mweg}j z`T*~pj6pHMx7I(S6?b#)ID>U`^z!g=_zuIx2xs`eH49s>2h9CZ6ng06q#u0O3$S^pE9Mfs@7(uV+uJtwDLfzi zmwWZZsIL_Tmo43FNCSgsf2O(3j*1CYWMMN|N5*FG(W;l?mJJ}=GI>FtHT;S+!I2)6 zWJnyMqJmm-eU3rB;_8y>(pS3l@@<*;xS}N-WB|Mqr7C@*l96s10pob$kM{b7JMOIg zMCxTTb?b>}=jTDVXng`EU=zB*T!*eec3yXLbmN>*Uc$CJ6>z+gQhJO9$ulb?J6cm)3<RSJpcTu)+A*F=YUglvW~eyEwAc-kMa(2cUFIf=zn(W#y9 zKY>bzf+$c^(j317SOrav=l@$dX+k4B@665Of~P+qY}q~(2bISAwBH_~;wNGCY!Vkr z@FQd*82*MX$hJ!tCTEiS3*l(=V=1_`)(42mLm4rn=i=Aoz8(}E-;g$uW+n*!U5AaW z;du8GC&QLxT>83gZ#ywjU)Kl%*9X^!p(GiI>eooGbbVJ@6O`PbfZ?89uF%$}AsS1Z zPNlZU8?2)n4C&_yE?=D^&PxMD-$ve|w9hTEb8IPgj+-HMW$CN1No zkg6JI0`M>J)nmHeI|uUn#?PBf&KR^P84q!uzC_&3?h2r&bb4fWOXQYJ<7iLWDD?xx z;H^HJ{ib&+Ge%*UA|tv}zid;9#i*kh(e%*_$dFXknIIYKwLur-R5`Y!Lvaj|4ZxT< z$0A-{@|?+XNoHp4Ng4?x5K?BHwHDpVDeZgH;RCL>t1tx>g4CeYY3gz-K*BCts(o>D zlKaM8^a7EXUHMFQX9_(Lcp0<^Gg)LDIgJ;&YwU2Pg#W|?3-j@!sm8Bb*{anjb@0u|*h)?f!OBVtT*f3D1(E5PZXGbv~*pXg65;gHoZN)cF1(sF)%u$BHk8Y(6O zo}4L9NA~Vm3>|~BcQn{M{&g)zuscJmbs{1ZK_}cfO_3k+7f*D)H_*4%5e(Jc;U)~VD2!|OwVr=Dzadz)!CL$N z9r^dex!Xyp(Wn6q1XAv-nbpT?{S_O2y;xfv4}zws!P1xK`;~ujB)(fRD6xKQe9>`g z^QT~6?2%QKun=r~#y(adNFF8OP16xwLtChgh4fqAbHPzvBV?qEQETCy@o|+FH(;Mx zxz!r8k~*sUsoN?eGAV>GuBi44af9`^f(*0Frq9-gzhC7R4IIu;QzLc*HVp6gMZ%kj0}+IZ6j9TSFC6{@2s=P0o3BTa zrgDCvLQpM|6fvH~54;+W0jn&KXpnvOfNoGRin$hL z{4i@3qvn+~#!7q}MBYKiO{s%B?>jXVKT)mA$(C|dHIIOuhLsNLhwlXn$31j?T)|Qq zOj%KM3`u02jhDZ>H-)*JyZo8K;IJSG3kj_A*8=cpPSja^RCzv2{D_aEP2Fc+&>Q%3K!tfalSOhX#0DXWG=&mVz| z=Sx{XqBZ|Az^Qx^9$n`Szk#Cf`t!!ZJ@~^Wyjzqh6SQDQO11PtRH*|Ml+5r_F-wH9 z60aBP7yA+K(3KIUJ~C}yH-U_m3lE!jP}QmOmzGwx5)AbzZsiQVJX@pIxG}E9F+(M= z29&&JrQ*vrho5KEe}E}IV_$E~@}CIMZO->(o`H<$PU4tRyc|my5dEk^hSL@{{l>;` z{W|qQUoZV-xuXV>Q13lX-tpst_JdYa2kqJwt(2mv?l$Kh?Fsry$KDIHkrBmg z+ZpY!@;rVg$WCF_v0}x$)hTjoI0-R7pNkn*L%pz?RDY~Y-S)1{vda#Z*5@(@1&L;& zfl|X09$aJ?3DHmuL+iGT0!nYp1+tG6@{`I`HK;21{kR5`$~e0j!wDM#hWx|-1WU7H z?FBLvRiManaoR5N+**av8)d!U;hl$_(%e&kYUio-yW@FD+NpjY?|B^1Rszxz&zHP} zmozHW?93$D(uq1-T&6l%G2QaQ{fOrPUiB_WvvlrWWg?2#`T%4Jd?4+N>k5LK+dJ~+BLJraB)ua#Jg(Sq5fK#-Q) zYN>t@q^Kz*i0Y0%?gEQH+PsWDy~qmHX+xO~{Kq}Wo$`+YrE!9eXov+&MK{{8!)znv7u*>4#t5j8#5YG!ZAZ)qbvk=($jHblTU0-iX{KZMz zpFSq3vxC*LE6b)Qnp-Ds$Uco5!qr=7gX$-U?I2ed(iGwJNmq?8&lir9PgH9DL_J_$ z;p}sg}5&nyOXEe$3YYed01drNb*w9W8#w* zhfrjg`IsLp+#nqhxdufX2yXrE5%I?+bL;M}j|U8Ak#~d{D0WXFIrV(JrDqg)YLpfVR6)oMAyH!buaEM3|3+OHHB#;5yKfILsA7r#4RHT8tD`LHI9mGqx`-n^ zfi=W$dVspK zEg$x8y&Q;k7tQ)_pLVWRfuVCDkR$s^6&Z@|MIU~ljkQ6utx3lywv;)8zT1FSG4@Mu z-xeF2_C(cu{xBsz-HxRm-k2@rZqZgRKDu zmL3t7MsFP?{n*8FZ2@=#rRn^3ys{uvLD(RpT(p|^ZHq@7cjU=+r(y<;0mcAa4%lca zv*@wT7(&{W`e0~szsIShMw6i2|fy`7a ziii=nH%FCgHW5QZguYy7e(iP%oFxrfJ?^iJ2=|EsBhJB~K? zu1N3gw*`x|mfGm|n(9GDRF!OcY}$|XNDN@TgY^+lU4khMl$!Dk4$*Q24XL2sO3gA5 z{XuH5AIhR@?v$xv`d@Jc<+4eH-tS^I1GFAJ$ldEr$fH*+`5JpxbIFF`y9hMpN*?@| zr|Mx`wf)QRirpMQ;~-9{`pDAC!=(J-_?Y+k;9U3|9BI-9Nrfl5%p-Z$$Sa522Fom|X=NX5HBV1fQ(%8-wbE{N zE`*~%{MAE?&nI&NV#*As?t4`P>+wzxKfT3$`c%HFIDWaL0Gii7RCHHf^lD<<2i`IH zar0OWTYoTQp_)oRC4bUJ0TElzF{wgSV(Da#`y4Ych7xG&)8pYhUBD#$``NN-V-AJcq$P07RJl|Pn#bBj@bbK5y-)SGJ>IeagS9vU|z3p-2 ztTgwlK^|~YS|b)p^ya8kUk93u8gQxmZm*i6giy&MjV)WffSpR`tPTb*Irq?!u|nh9 z*1A=Ho>EPP<)XL?{^>y`76hoZ}~s zfdfEv|2ID;sl|oyI4Yj*kJ1EtHkh2#Gf$6UJ&T57*h2$QRYY-V&!sUAeJ1yPUWN_G z4=Ve8%BB36DXK(}x4OYg_lo)50XO-2c{JWRHRX1zC6SHIi%19m@UDFpv5S6e`T%SDe^rt zT!DA1q%2>XFVlX=nFcTqC&+JtZ3^D!>N2MG;FZ*G>&Ss0_a_G$f;^RKcFLL>pi}9C z>pGWUIO+S(t3>wNGr_a6p3zi34=i!R3+6n4f{o&Qeas>aK$F47LG>HM)?_tv`SPN2 zWp1%9M+kX$l@cPAp$rf}s^fad$Hp+^=Q9waX_-{JfF7dL#zHJy21xHtBS!%#EG0c0 z+((%$9tQlXa_Payu>!&=seUOH#6Tw{+DCs1y$`{&70r$zXGVQBAjrUwBz+9ssWn!A z{k}`|WhYwJpLcN5nS0wCloj8su9<%8O#{W~@^*@xM}-rhz)PZ(E3Ck@rr4&64}OvA z@ayvkje`G>1cPSDvpW^64ENl z03svJ*v!Pg=EkrcZ<^_=v5PAI{f%GCH{_PQBJTeHqn_<|u%a{!s7}P(Nz9tmU~scl z?`cYq1ZzGzQqX?%dQC>e*-j(xr9oSZ|4<5vx|2F_3FWMg+SH1eHC z6Dw>@414*sUJ?RiBqfa4*JUl3Tl#Yo(%|MDyye(~pZp_L5d{H2ZPq9-P6xZ){zt<4 zw-EoktfOGJ8tg*bX@FLKtzxsezMP-HEfUwwMsQt&ii{N30dU)U%^8jbJDCgL-b{aA&Ekf3(w z%s#8;uYybU-sm&G)0E)|yN3F*?lfMNrD~Nv%e++@+>#OkjUia85YT;sWHEmnJi&YY z!HVQoJM=4?pUfaPvdSL-o|**UkktNHn3Fphf-X03U9N~=esQz`vS5Rw$CbX3jSj)m zOEl2nDxjj)BxCYHD)w&1sFkm(YD=abRNVq@!UrL2ADIVS+YY`svKD z_h(vHJ3Q|`F$}Ru43Qbvs!joB;Gdd+Kjh6r@_(9V#egM&k?W4BB1F>E@$SPq_0p`= zu9l%*b7l6QI>FL*DIbia6B_JHmUSqZ9jQ62rHI~k3pn`n3`b8mw5-@f0(5SR=*>#l ztRKEe9|G4q8jt!ua%vz#{3bM96&E`@w+a}YC9q4#1>=2&A}}3&?jfOC`&0m)mV@$7 zf=7Y(blMIM?lbdEcjWOc~G1WG#_Sqv3?VJ<)4CtE_j z=-i{q0;`v)(@cD47SZVgzuOiz?ay0mFh2r-#0ebC%lOSAu7QSOW(~Hk4kgl;4OvJ^{AYI$|IgTfZg&Oec|MlbGEmlM9(ZCLYI*j3L zYQlcD0Vg4(_k3@S6XeQ2Cok6VP#gx+Gf(&L`)>W_2w!P{dOf~;tLxRE*B0h}{eHa? z_VRrFQz|uO%46TBIdn=ILa^L?dicl1-f&h*P$o%|06^rhl{ZM*ZtAawh@(RLV~r9x zkIvDY!T;uxG}tI~PVZ_nx5x$xerExnXe9vnWj*PsPBZ%$G&f94RR@*pdJUVUeym#y zaY-Yj{iRTQeq0j`g4a^0$ZcZN;FX;_B~%_@PZLb*y<~tt$D2?}0uw|B-La)1p+lx5 zezYPX8%1B~%0wtA5BTY${4A}T0XXjF@xepm*vt4GqF!2O zRmJJ@(j;fQ-Y7X;kf$A9W&0L8B7AE(!OqW1@XbJAd4g-S>xqPDNb2RWs>*~>k1N`` z*bj_KZPoyu3EM&ld=_{)=b>y0E3LFSoKD8g;^x?&o2Ymg7@hh%Y#ObsGHfPY|K)bp z+YTX;B*`n*<58CIBNeE&LRO}mAp9Me*NXa6PdL^mr4CjcXlDa7*5wByS@W{M$8_ES z`3`ygc+nl7OaLlcd&;ZR^}{Mq(d(u?%t=JLZ)xSLt#%}xwtKqE}A z;DfSW`78;r=WvLV5UfD0Xm5nGJLR|fjy`w==` zBTVM^zx9iNF@AP-+Z;@GNAi5%qkxBO(w$HsKADySk9FtTtGU!+j2{tvzX?+@=M=-1 zw|~9b6j>?7KEr~k}>_wHy5JDG1ERNSn(Uqstk}GTzIV88!ss8zIRn6x5;>UDnA-7M0z9Wv(YWZ76rxIfvvr4Z(HZS!=T<`0_U)UcCMnD3j5_FD^Hg@ z0FbK=9}I|;BId+WwdziJl$OiV)(|T<&(Yx3v}Qgv7zgKeuODL#!oDiV;b=gde5&x) zx9Rgu_A~GQwY*68b5`VnOnyH4c~`@917fgwE$NKot#1#}F=Q+4a(~UkfgWVL+Nxm! z`A^AEc1OEL421(!JQhs<9vHd$_H{2Ll#tfwWk@aeJ}Df;<|skfcz-&#UnAk4a0P`P zzZQ)jJ@FP*DIg7={7B4TQ`bo!k_%0{;NQCn7s4tzySpzH=aLq5N}Qlg&j6nG!?q3+ z+gho-D?L>L#TAnS2avALmT|@0C!JD7&~jmxLRM0-L-gO@@&&{PsCy1KE6*$-f)1!bPohIxpYzEFm@Kca;O8c@V+5HYHcH&K4ddDhS)2^bnZ;e%O%TNb zfihD+aGHRw%Ews}d88McKhfcP?klbAq~n7&b*@l8Fq2(aL>}iyyexqvedP)O*-j8x zLV>ymdct7kYj&5{(5Oc-?cnt+@=N?c9c=>4o$t(QxV7Efsqf!X1@ zqp^6VI}E16f}YngH0GtO^0)}A!Ees*G4;QUX z6Yd2C_x}OHuIHJqh3qhB(b6J!?o7K&OYqe3m1qfXZc+>bG1|wHTAWAGVaZ*MtnT7=MC| z6K~$3VYFyjEaF+|?o=jcp&8g!9WKobSt6#R8PLrjhE=Laq$ey~={9|}dz=2=^gKJNG69Fr%vX@fdjKZ9sN3OyQzZic^H@$BF6wJ_ANp=PCHfp?=bR*6MZceKE?OQuK>v0@bRXFZr}9 z#p?MoO}f(RKwU-h69_)bWES^xz+SW#*tv6{$%6wA2uaI|QnjMx(vk|c!cSYVo?`Dv z%nAJIY{b1+1*(u= zdXXe|4AwMEi{^(#irJ}^L1B}GuHzUKt0xVPDx}yg^)~DFf4=S+h>`D}v*XGm-H@Gz zIj0MnL@U!P>6nKv&Q#E=*Co>_V3bb2M}22m8dsy-8$OuJlf7R`S59Mgfg>@6Wrg6{ z7qX`mdwFv{oz}wG6iybvym&**;s9re8eM+<>|yKluCoahvqo`y;hXYc)uMg&cF)5q zdA^~>qi5(D$C51b^g1i`@HanWM1+p(i$j4HcoeQqUN$%(x4`3#%mY8tW6b{mO26Yr zk+)Byf8!<7$%y}P_v0qo%7N!Opa|&?$g6gpPn`gE1YSmF9rae2sFCL&{s~Y~VqpS9 zs^U-qfZ5w#%YN#ZY zLgE)o7S}!cUkrtlr3%WWVL^Fv=}rr3x%Mj&ENDx4P8kyKOZ4kDkiVA@#qH662qplL z^!skz=$}~^JrWe-T@+FYi+J!%euZ|w*{u8TX0qmK;%s010%mds0B5`?0+9@Q>00`~ z1mjq^b`b3qpsPS7hB~4^j@L*cV+qJB-KIdaY=ws41Cmdn%pwy$hbtNHs5|a_Fe;B5Al|9$t1->N1b~D z=O5!Cyrasx#OPD!+VQ4t42x(5tuoS&G#N@P)lY^JuA|~B0r|WUAJM^?9xRRsM3NWI z97j!=!{%{TJySXqvHgOSj)SqQ`L*-aQ0Xe2(i;-q8G>qrv4zT~UBU3vK>pofEgj`- zYv7?ld~5_WFbB7z6K;B(dT;1$KAFu1AFVXWT5D&XezB!6Nhhn7%j!@QzN}oPQ@Te> z4?W00XqkFQlYU0SU}8Nh=GgdQg&U7l>0OKS8+{$`N}lpwX7uM|)$osCF#WX7QP+a{ zyM)pl!~@(7u_z8+4&&ldCN2^Vy$Ed@19Yr?l_soE@=?e(dCL%A@3e~#cX?J8JWO;7h^gMdJZQsj-Y=p2NG}lLa0ZBDIKj zX&zcBh!eKIE!jDfjW5h`CoB*0mMSFg&`In@e>2*D(J z3MA-*#VE*}zkg2~iL?#ua*0^pWFb(0^sel4R@S4p#@5OfjA5RpG3UmiyvB&RD!+tC zrSeemmgo#QV`!o?T=AS5g(%2s1z9Ul=?N;JN&g2JK@PQ7K{skengl1cWT3$iYrhdq zR!1h~hrPq8Kn%EsOno#?djS3&oeT#p0-l?w5H9Ymo%({NUo}pgzoHHit?*QX9&k&K z9ORj78p*bPf3_tXHB5|i|8Tlf>t5J&{ajW?ZLO!A`pt1hPJtLlUkU_l#Al()bm}48wZE5?n@r!{q^9>(<82iM?+NuleAmn8`7d zd1x)UU>X6=HpKI{Sg(2*Ze>UYDh-W7M>6fvGE9Yo${-1cXh&7p5-%yjdwZ7X3M-ds zhj8O$t79uU{Eqk&5J))z3_+95<$|3v{UXj5(%z7jf-y;8XG)x%maj%bG!mr9n4Txl zk+-0aPAK1Jv2-4fMmuG|l5=8P3nsTJPUc~)4hp}1nb6ExF7E3V)FnwoK}Fii zqo+Z$!l;gpy=xIP8r}+LAs=_jjBXebi;BZa3hdBHy_Qj*SJe1Vk%Oa)y(@Hfqb`YW zrTXn`Pyr3>funLbHQGI}aG?%EqglfQNc5rqvK zOW1eocedrU9eMj&Rwk!0YtTUeh!7>fyMv3H7QNEqs&AD9ck|Y&xrJJI$(BKbLa9@* z%zhaT>vWt)E>UFFwKFq)ve=K0;Z@Y&li$E_dIjp-92;5=YXuwM&i>A$LVc0}Gg};Q zw^u=kj~NFR-b9vmN3|A_)mX_Cn-M{E`9!l32$5-Qs*j+ia6BCkMqYS_YW7Pu6dle! z=-sk|`K|>Qv->bTtiNx~Y8noIskma_wmc`6nBc;gDa#8#L5Gab5Hw+s@I5CIBr%uH z0Fj-c{HDnPxVofe6SL`HnP0~8=Vqv9Q(}#Gp<{*DrH`>-SSCW#(M_Z3evc=CuD1w; zM=<)8$WoKXS8jJSlUbEQk5|SjJ1(+v{2}u*0y>Y7@9(saZdFU;%P((Ewc2i%^W3~e z#mLc%_a9iWeLSrNDYkuX@VRa07{}B}AkSM)6^5@DWUBhHCp~gaEYr?^eI3p=2(|6Y zf9|a#8`a{&4w8)CV>h$g#U>>KAMle<*e7*<938;2;-3&H^&C@NE)eQ1OJOyrY6IEd zsMQK$BCs5tIsgL+*3paR#J7SE#h-MVgf8Q;NTb1tMAo|#O570rp7A}dER1d{%Zh|< zQjO)C;y?BCk0P8uRhorUM?bi|c2cM(=}vhS!^(9dw%1~x|M&OhdDdZbAmgOnmp-R6 z*T>Y=gsy*)Jd4GKmFh3$Y1#UR_8LBpf^C6ha(Fw8?9Alj&eHrp#e@U zBJVJNh#UH~&t-ljlJmKKTs8AaoeCe>8$Eg!mT8bgit5PB!^1)O(YyT6Cuo1*1mEAQ z-ViakRiCxui=|B9dUTZtVc$6mETBXog_;DyY+HB$gf-&;*WjSFaXY+CVOb*vIt`PuASt<`C}uV5k_vam>h;zt;mC%r z;B1gKos6+7{d<~cvPdq{VvtGyzd3Pl&bWqXC?!%MU%c#Cwu*`X^OZFrRT6WUc)AE%|)<-3RMBXAjnXl?y6v{XNZShVL1r)eN! zpTsdDb|NUyaHW40H}nx6ka%%GBry3svM~m`J z8xy?HqsRYbAdIkgMhkIR-#d^(>>uCM@bM7Dt|3;ic0e>2SeNTdA5IeaxZfQ> zkU;{DK>_wDiOuV(E>O@aD!@7og}WB(1WKPQNY0M?nxi%vW1hSna2craLk4NPDzO^k9GjxdjBb9sZRN29@FIc61;n={~hm|L6;jzIjE@xo*}WMCK` z3g}%mANfJ`;qoinIBrycm*SZ1+~SLHy7ax_)QiyMhz^CL6(bBPZ&YQ_>8i+3)17DD z2S9ND-PW*_j(L*R)B4v!IEb%pdHw9#{&kOeq#_)FgK6R^(_0Wa)+mN+eEIU%XQ;{p z9S5zrwBHAkXw2W4FSODk|AjSYh}TjR{#H>3br(#t}g#o%5g9$RRyOOmZ8$%|9=tp$OVfZ+7x~zMoD8e*d#@hGb!>w?1OL>$BDkJZ~ow z*1vGfSC2(VW{`9e&oBwFIAA3=_Me%F$#wt*Q)Ss+(gk;wGnEz3KBkK}Qo0mvcMdb< zM9t#m3RUeRaGG&i)_FkE2zzB};hfv&Q4zSr#6TpY#Pn`EV>W~N4J`y^O4L+>LO{Cl zKncueljV879`?|iIGMs~iP9wL=q1x`AmJ-skk%Sf)E6tmF1T8 zihlih^jO;+k9>wZf=nT(_xI${6n;)a8FU6ZTgH1LyglhhHklR*_G7g}L@$4s(B2c^ zLky+X1S*12#XU+ugoWo|NEXvXIG$5(#Ydw^%qbT!`Vki^T)rwWa2=JW4VxQ_z=xTx0Ab*8Z-Tl<6>)2h_e*3@NMFKf+IWh%1sS)?MIr>3Ma?WYFO)TyJl z?nngC^uZOaoR9L(PdyCN4 zza9|>n!=Rz-Fgj@lw*Gl@IEGY?ARw%?8fxq3SyDaGSW(22U%dwWcj)N2~&;?!y{k0 z73)okR%GZe_!(U&`QeOjnKjVVmA(|WDu9F>Mmwz4Tv98`jft_1O%WtfmbCI9;Y5}~ z4`Gp(*X;9Nm0FDP*Z%6Mfuc|~acj+(ThGrd0Z|IgVUu?)Z*esX@%4RndRirFM#NEy zTuXX>?HUp+T!~%#5p}lP)K+&6VEr~u{^~pJ>w|Bl2GU6@`V1yVmqeEe#zFxrI{W|q z6E9D`0~2DPXG(px$6U~*(WAD+8}LsJLycyyv<>};m1ym`o9p=Qvdim)=d3!9izs zjDk&^KlS;Y!`4pQ7ILEcR5DF5_+Tc5%|E)5$*8Il4b;B~Gc`0&32%+&?TG-w!?nyp zY4RU^m-kP1^X%9+bs$R{KRhJ3EG{ZBf5pfA_JRww+Yf z*me70@N2{%;h0gv>~-gQF=+}b|A&D4d)O-0=2#C^OH}|In%PBB#Rmjtghe(`;XSZc zeN7H{Q@t)D>t(om9**_KaRR8^oplKmC!jb>dM?y$s>fjHZ!$P%#_FjB_WlR3j)E|d zV8b|{cs%S^ZJPliaVkVW9*jqiB$*(1<9ev6DIqLJHFV@;3xTD*Pn2?QJ%7}@ll&b8+JY`esJa#r`{ZyVafvwr8BDk zdKLA37zh&`cg$~zNji_3?4I!0r-MD3O+lo47J)Q?B%#Lvz~Ad53PK9&{{a33EIyL3 zoO_`ZL4+CdC^S707qI`Sm%BaPe;ZRnLOOzDAlBe$IhhI39%VEYl@obDew0Uh%_O_O zR<-Y3toKnO=nvvur<3UfHG#5|1HzN<6R|?Ww6$Z>e3IdiKjp$jTZ3v>yUFuGsDM{n z;@P1&7T8g-SDj?w`SX^}{006WJ1``S&K|soms*Bo#|-2Ez$*f8f5-p8-kvxamsRn3 ziRVPsOYbT6UnE~tM1`QNca8p$7J(sowO2>UI`p1g4$Mhb&9>Al%Cm$ltQ6B>ka~Sa z1rO3@j*jP%8_9kUSGW$lD38|mArrb}COE^ntP>>C%={PquzZjB9URrdj@JCC9VE9} zkE*ctxGE)zIa87lB&X9ry>h(N(MBE3DpzOAH9nQa=&qPigIM8-0mo(m%$JUyomBgv zkG03$xy_y`liP!6N$tSx9f~%XpXJ=g%!8t7E6?(|$VpY%3v(tu}#M z)Og6c>wYV%SLooBSnn@a+L}-x(4<}j9UzvVc{8Ra^T)~`FF@4NN(YjQC4Yc*TwiJC zQ!0gJK#Jt@d{MG`uz|uLe+yT*acNg6Szt2Twp^KOL0MmBKR1g}X6QlfGJ_=~Ylxw-_8Y3fyi%!<$D(m9 zlx5KEIuZB9x2`7nf{3Wl7-aW8V&2SM|KQ_;h0`4?rizY4!2qVQtW@ShOgiXgmQ-w^ zOby=@A)=b(u=U=hJg1!U&Qxc_356YLu2HmLLl;gi zu|p2?$qFbPe$NWh%wR)*d1I($$x5+ZCStZr0vi#ei~a5C#mxmEq9Z{pZ+b1%5d7># z*P$I9ZgKSH_b54R7BO1=5;a{FR2fRATWmUFaeqEtBqj!=-0;+YHW?R4uLq1A78t(O7^?uQ{)% ztz>9^@;Zldfa3X~LavmK0Y03**FQ&rM|fX1+RX?8Ls^6R`wZ^qA6# z7CX*8_mEL|xM-?is&!nent@N80%&(P0-z<1`{N$5JOecrKeBlg>gmu-Jd6+)Nz-3f zD?}H#=L{E1kw34uh_rOg-mv9{FddSLf z0_ixPX8gqdd>hUmd4yStMH^p)hnX7!>2_A1K{3Bl0co=t%C)z4XxwGoM5^3Hikju_ zA)RixJkiDl$7+ALUkshwSN{W?-}H+u+1A)%iSwhD7VcJ~`Il<$aRDb(l;@J*@4%& zlgwFkpIXy65njmmm^jXm!LwHuUboyr4~8-N%Fz?oOtuYRN)*dQHZ#XY8Ar9B|M#sN!r!`;f4j{ z+CL;t?*)9jv{jKJpp)uZY8vu1?wx(`;bor{mHQ-FcF+I*9N$A9GE$5DIZ3rh#gvxw zeL+b8T4lyw>M3DO(@VX$bLH%od5oB43kdCtT^Y(Dt;17dY7n>#287xl_#LtVua%;9 zTW-NEX{Fp9bl-Mg`;W%=;%+EED3pPdnQS$X)|vVm8{mEmJIwQnG3;rpYTb=z!h@px zp-jj{`|_i+(Yq@rnXT{Hxld0U4vucb*l4rQ^Fmb5PFsc(j^ICu4<355IR2dCNO*C5 z>3%hLc!ZM7lLk~X0R}k$w{<62qQ(2GaGjj|KtxEWCflZR7q1_*y-te9_meCHp z$EV3GEANx29SPNJi2JTekD|c<{&L|&>EeB`bRS8uYs3XsU>t-B`S!En^EZ#BR8lJ< zZvNr>9x3`OlTf32H75v7>ojZbZTT?BI|C1pr?}n5B5NbsNN;3-9QfN6a0}7(e9Nu^ zl`C`03{Oizv``d3L|l{ zgIdi+Kgpf@lra=KnGCAj;pzK@QTtK*XRco= zr7kZD!E6` z02NG7t#t#Tg@$|1k`1Pv{1oqod3Af&-tJXgSE{}2@#|Mt35Q&d}&^=oNiI;nWu zMiNz%P*97U*}7AaN_4l@3GCgoRC3ud%u?Nnh#;+hLY2a%#R|!IpuSH}=J`EZ9k3#ZBvSPhfa?5|Iv0KL~gi-(X{c-kv z#N-F!P$hx#sui;t<%xF{2Us(h3$vpf4!mynlLx{zNWqG?2r&OGlJUZ2Z0wBs zze&q5X@bZO^9ASu3^yZ5H3l;_x8-aU(G2l3x-D-~kaZc(p!KzD9E=Qp#H5pk(e6X- zpSPg<@DT{EFSb4S9&OLRUf#$@r@2swZ%>XUP?%TYN6 zCE#qRGxU`B>G{^^MC5OPPXG-UaRJ`uqpuZ&o1Dd8zD^Bs1BcCfmYe*hlpb)<^~{;s ze=St26R6L`2+`iER2Rg7TDI>Re$Kbvm-CA300+{@8r$irNlAd=ELAF9iK&PtSwdi2 zZ229eadN5bbXk^E%>^apDsXp|)E8nq)l&^GaH4l5nmfT#wXh7A$7>$?o;wVEKRq2}lmk(OR2Qe`E9PkmfKoP*WFAt% zm`S|gXaJXNfrAB$E^*<2W!kiXuBaltwh+uKLH^F#KkBf=kK>)7s3((l)Qr~nnR@yu z*8#jtr&*E$$T*tagNVV6coiygB_wgE#tMuZWsDtb@xB3S&uc;G`z`Jd39i z>U0RLw?Y$*5kufnmQfhjZ3(Zr{xL(C18= zMQQ&ru?j;!hZb|Ui#+<-48Wx!5C(pOO&vF%m8@+PwG00TV2mqlWd zCqzE23I2uYgEgz}p9UoLVMRAW20mb12dzT1)vvl`KA~q4|6M(*YK#xla!JFJ@PFnn zSNRKH^Y%kfsJUTQC|H>eCYHnrt%RyL>`FU$TSNl{fm>32u$Fp3&Rs|nJ$qJy|EyR1 zd|HwM?Eo2iEO$McGs~RyxCQeg)_kEH?*)*N}*=+JW(63P^bn0-3h%K0y7nS&9ev8s8Qra7W z@-aW?(d*zcoR@;yP_DtY+IqtEfJxW+${h#nNU>+4(W>e4Wj~d^4rJYcIF(u(>rBci zIThk)$|T`EAA{0y>tJ5%g}iQog3KW%W+&Z2@vQ=KdbchgW`Q>qJplqu?=Kb7(f32N zYUfiGG1ItFg^?q)otM$|LOR_Cvh1!yu3D1jT=jlEaT@4#294=`eRD?i^S!;&KkY@Wm-CpL zP0?k+L2OOzp3&%3SJ2=}OL4WP9v+bGTdJ-+V@!ior#lG2iq(>1CDv9!R<$@oIAsFt zrH%w-hPte9yspXWv0h1jOffb{c4nna1~_PV! z(#wmr^IiMtKrHt%kg2L@gP+H8WS|pcSw-8;^2;sQ#)Am-MY!mafY!LbVLUUa8olECLUJ!^YF;#!~aQnNg`x07!@-eRv3%o-rbC zch+u?J~b_YkNcv3{dAg#R_YX`Lcp*QfHv+ipjB%AEm#Tpqcwk%G|mL#v0?9x$kT5- z8|BJuPzJ9oNTZ{3&K1BVu}`Wb^M9Cn?`XKb2kLt;dheaV3`TTOqqofH28rIg=)Lz| z!st;WxLL_nx!Q-upvtpFn=NS*ww+ z1K;R6sR8axUM#~BhZ83!pBNfNr4z9BLU45rFEKJc z!t|c#tPTv(cndKZ-;iBv6v$t))rRpzVG$AhAi(DvZ(&ojPHiEh9p^zh4VBiHjr>0~TEi4f4mx0xGySMx`$nO+1~$Igu}IT> z^_;S&cHF-l$Cd1$6m8KRsO*NUr_0ie=O<&FKqf&x;hW3rzR;y>Ihw)7p;h{7AFfVq z4T@&rxKTxV;fe2MXrpr*hSTTNi<+PLGca>>iPw19edcnoR5;kxLBGsCC)uD}IvhCn zzFgnkDh|hCO!w_oyGZO?jgM&a1px5s>Y5TgAw3?h&&ACzYLa*$FDM?XJ%vU{0SFC{ z*T&8S^M?10p-I;YpmwqJ1OPKxoX)Lo z4$|PUR}4RV`SE=gI066H#4D@}M0w-jq@FI0LqFpOXh`~&I>hd!@BkY)6;>#bVCiX? zMMLEUFQK0o1p0v6`vo=l~hRR zA60*XPo6|9js;3GNX5}pTZ(MtD^``)S{Qpx*-k6%9UJ{_ysqCNw{~HVp74A-m0JFC zYPL){;PKthc>nn*a~TT!D*r`NzKR%8lP?=2yz9A7K?ajeV#gD*0Z#fk#U>(2B(^Ap zU8b;(1A9nTb`1vS>RI$dsVg%Vc;`;q0Fl*R_Rb_0k=L~Pwy69wBo^+rO+>Yy*Tm&@ zN}P;|qw}_(o2r_ONeIli66g2ivCXEh^l)nMyKSyVfyOx2OMSejxy_*&4PI9{&s!W1 zGrjk|SPk%#ih0P~e~N$Y=DBej9q~;_{zEtKL}|UjWFwmUu%@}13KF(&8>P0-#Vy$a z=}Hq#*j`DaL^(AP0BznXnR!?|mWMpn!O7}z9zdPk4^aREG1M@UV92b6V`S&e5UAZ+ z3l`eDKi@6qR*w!9Th7e6xcM#LRuNtBW4+G(=NwBm4pu<(pu#pwP+%z;9gRN?X;1I- z%ifDyOZcRcMTzdjZm?6gEHoc$WS!oFsca)akqr-5mk^A>zICNMlTP^MS8wqLAejr! zd<85fjA0MBkn;WIJ9*oRq-p&^8HHtGk$ZBH_&5r${jz9jM1bVw06AC^&ht(3I)0C7 zy6@*Em>#W!yh&j8P@y8{mJi+tTB2nSrAv7EHF85sRgTr&Qwgj^fm8gjO+evy6ZCVF zKf>Fi$aY=Ri|ZY^5*CXpCmyIzz_dMHaGxAYk1N`J$Reu@U;>9iY(~G`w8f`rcyQ$3}Vp{ z+>@DQw?mgoo_+dDvphcAW);F^kpR}p%RnOJ1Lq^B8gIVuNA0bA$j+9Ynk7&|%F$gK zN2=O81cN|f5g@FR6jwuS+#QJsjk|IN0_CPhd7vUeceD`+hW%udg9rZn3pa*s9|0Z} zH?~cRue?XU5ww%P;R8@1&?CMU?kC5F4U{__`KFD1ALh9M)5euLCd=wU7>uR~1HD!i zP_xO29Zz{d2qALauuTQyjoL6nsXO)m0>{*b;|;;jIIOs;N% zx)F{PZd&CVU*joDB0d`|;y2!vt@@6PY}EMy*0=_4OaX8Al6{&alpl*uBv$afbX#&l z&j=jHr?9(ii4Uf$2%;eql!^!`>jyajxm4V7&hYDuZ5LIGc>1Y*5U~|lYbZS;!Z+cr z?}&bvc~iP&zLWYNF`7(~nO}_e*)LnyjAsBCFED7nQ1xTc+tWju{}sOy7=9bEVD;4ZAze{< zLyLu4m&7i*UXu+C)=PH^IA^Rh)UpvP4jc#JwwG1r;p`bH4vs-yzqR>hJVURxSQtmN ziR(U(xa3;H!ZBz4)Owo^9{YH)=KCuaDx)bR%%$$-rre@c=1)k3a~E`4wCpTi0HpL3 z{sa9|T-;7^ClNn%%u8OO{B8}e<>weQ=>ZElWMb5wiRu!Us3bet2uvwjq?)C#QLE*v8iJs`QU1*Ru^C6g=VE* z8BNVo49FLeyxi_B;&3SXm{&z;!zB9YmiMT+NsH#=H&3`Xj4ZppSVg&QDx;c!66SzZ zfRY70#rc`K(o?d&IeMD*`IO-Cu?S;qz);_ILgBj6Y4~tB1xu_XQCCw66cP8e^cxr}s#w{>!pfX{qw68UpnUi1Jk2 zM;|~c?w|h39}%n<+hTza9BQLKm^$Dz3?8bPc6uWA$DUbHUW&Kj`%1Vf zzxvR|3nw_ErV$}*#5mi_m{6DP6A*j;#<_shc|KUYzyddwIM{f`bi9=(k&G9Q4@XrC zN0@Nowtk_7ImW|>!S~w)l9SL`^!*ef+RBM=(tJ#&cGu##dlT;?z{~`aB9C|)>3`6a zacXAAeKwHJ=6%wXo*1a!u9MCSqPaZdBYcD`)HhQ`msR<%thH|gBoS&+YZvq|{Xhil0x6xiSue#VUT`8w? zX%n3n2W5T+{K)1$_s9ApUWlHlKNi2~7I=8FnoWQD@AnnIDM^T_E+*$wFA!9h$LiJZ zm;7?KuJ`VhC_%S^FTerQ*X7H~)+V81G>t5z;LHC$1#(FJ70cQF8HADl@Qp@tm~uko zP|9mW7Js4_IgwU)CQJOODOxR7J?riKLXMh3NV_=ymK(o&lOOrZZ31|v!}Qx?@9MX& z)p>s}VJ7%5zTaEkTWvj}7)MO*)d`WjvF6ttI}FcM-5p$TQYC4&i+eT6@gVEEcJ>+GK6e9 z!TULh@qSQ2FCyt07`&^I*yW{}_S};tZ9}(5P&fGNxfQ4R4hP-sj2OA-c<{81|$#ONkuVe9E4k zH!sPQr9Z5>#v}&KSlmxY%g}XfEv}k#z;}CFmlW4Oz_4CDXQR@%BMnQO#nwV+EzZ-7 zcZwTgj}qiezh;f7k+Cr}rsY#1R6{peXJb;4vg3j2RvkMsDc&ID3)a;Tw&R7zi16>Z zlQ|2fX&Hst$y;1%Ytt)C;{$QyDJs+7_F<%w)D+`I!UyU3u}}&I%QI%a0**MT6{j}+#m6lguWCf# zOX!c3I^~_?~nQ2(W`kF9pvaru!%A&wRrc(irMd;POLxx zD<^o#Q%@Gi)Ny-VM)&0W>iWbHX#TBDwLU+;K0%~$LC8MQr*Hlx9s3aUwVZmuiPc1- zWqgCmLurs?k2FQV-cL?@iU9A$>d^Z6L<2Pw*$!Gx%VUM}Xm0mqZcb1cFxyRC_TYB3 zvgF4e>*M;eZc!-9VZIrT;Bb379d8l!au;vAKltjpqWf`dvJaiFW~iF2o|=fghSxw8 zDx)^1OkPbX9vaV!m5H5EF}&|y7znJaCdKK;YU`+xJ!|7;!$-i>ba^RoYGL1TdcPgz zk>XaW*)3UrBg~^mITp>3`owBmD~@^p=^NxLq=lzO#|O9-5I*e9BwiamJ@-1$C_|;c z=H?dU>Lys>2Kr>(o2MvH+4a`*a6DY81x1~7tWM4`jMQK57<6Vj1&^6_ytd!%jCAjR zEz0Vj9{;s_Yqwb)nZd>bGD^pepaEgb2x5M=T>n&*>d9Nn^z)~S@^K@=C}eJLag&hSdY$R#N?r=uAQRl6cmd3>P*b&V}-Duu#I`K9Ym>^Ot7KPC>%g=W@pd71AG zw-?*3J#3n-t{|J^_34QYT z_b=l5H^W%?z*IeDP-D`*(gf>|@h=Aw<+wx0^l|W{slepbf*IEAD0i!dGSKZtWGnSh z^jrDe{Ss4|xBtJ)%qwN;v^)lUpQ#ZXLW{jtWOM0$HbAj28KR^3KM?Oje)YeuDMUWf zbHV9%&?Y;|>kQJ|)*m_YmEn3i3IWI^2wVlX4}WF>4MnFV@*?dY8jX-1?68c=D@U7J zRP9%#HPK{Plf^ehbp+Cgvuu9I29uSOX*b{@cstWn{--?)^9yee0S0C=g=ZulHYx1D z2^gbDw&&#L|NgL?mrULU`hT>Ve|pU`C&(3(1_qa$$Ul{sdgB`=USCO!Ke;R-3J+4M zq?|YPG{sK*{9^In)<_ZDM6A?~kuPXAk~NpUd4SYz;DH8RO5>u+xcLo@9s-rr5W!BA z1K7e_{1}b9(uZ=gyJMnotA!Kb(=xvmUAV)P4h>uxOj-7j5^os&8HJ12*O(>^Exz{3 z`B0x|R8#AKblF!d0!MAt8W#~Pbig6!j70VPb@FP?w&OK3^a+6?n%8VuQ9eXjrADW( z7YciGT*KM=>R-~IGZTtnwSPFeSb{`&W9=TiW$pjex#E8$-N~Ped}&3UIY%q1f7pF> zT#@MX{A?xVtcJJjh*Xf;4aBxrJK*8Gkc|&W+{*OcP6(v6hy)&vaq;gKD4I~h@cxzkgF$yU^3F*I@9oBDopm_Syf;wH+TAris;)XA( zC5ER$>WGJ2C+d{PIT)T=XW!jM<8{tU=>>LKl<@Usu642>XTY}mEFf>Fp)|o&s_QBW zCQd3zeq>j{U7N`hgu)}xKC48ZQ5o_WCn;D8vz>-oSZ569Y3e~Hg{fN8bqxe~2=dPb z9kMXBJ$t#T;o2p1phmQNw#ETTV ztNq#hXhoS3c2Ta8#lJz3^5`|fzOKA^S4#lhw8RvXT?0n|_y$5WvJuO>6r=41EY8oA zT5!!A$Vihq6en1`={d|*`ilae0Mq9R59cMktuv5rlaYbzfS>R?g&bo9d@IO%3?0=w~#Y^ori$gib z|3EL>`yQ0Yfa{qkp*5&5=K5d!08Gqve(^g-0Ze-Ztfr06f*gH2@5#ZBC`-Az_m((}{5CK*`O^)x4t+fQB%bk*!L(P3_AjKp!`8Y_?b_vW^s99CRK9A+Gn03!I)gj3bY?D zhv9I?4N0Z(Y&;@Ap_)cxHD-S93t(ty9kATxeNTcxa%pzR`k95R`lc>Uv@^q1^!J8G zEI;Fbgs53a z5l=KRY(JZqSXcsr3mV}WmWZbvUaDWJK~-?q)YQDRfx?W-o2CW5Piaa6O?%0cTTF9Z z$D}gv?q7FkA5sJz#Ff&xsAdXf*SiY}j10K>-dmWV+L8htD|3+e0>y478y%zQ(kV$Sd*=P1ouq3`Ne;|WFWgf)d%V~zNBbwa4^*R*wh6bXkqN~a2RfY`7>)&@C&JV(( zKnYP?amAEFvge+HP~6}zBRMaD3Pmu}Q3M!cxe3sgm646xx&J6~5#T(awJ8=<1V&g% zckP9cL&-X|InLw^1D?wH7z!TS)OP^(;{rgb(}=ur(|r=1f3lUt&Gr%M%hDcWJ@xT* zhveZ5(1U~JGRLu)#+?9(OjvlVV3kMVy1f;SnE=#~lqulWCqZ4hOha6|dC63g$M%3{ zb(k7AdBEusdCKX^ud#yHcTbif5UkGYZd)SIBD3XFW$Bm0Hp4YR`~zN`@ya zPdBXfqXs_Si+i^i^T>;FoSi*)*_da)Pt%bNT8}hO8fr>nQp_i;C{C=_?N!8_F+VbG z7GYBu*;&5C9H#3uiJ!G@9j|cHMznG=jryrVq-rjti_DZIIUdw~pr>_1j1 zr&+_hwU;$IZsV(7HeS17s*)QjT51?(nRc#LJNAeaZqAd+)@aT&fbqLU(CNd(Uc70Y zsKv+DEv4ckfb(ZVnwj%#Q<{~#&EKZk3PbPcoxOG7B{dX`KN2zQ;D%+f2DX*^l2z$0+}qx0w5fQ=5Y?2)|U z%xWQLdL0SJ{Bt@J7P8}7^PcyiCj=SE5FmNq6Q;{crksn2fCS(D;7$lq_`JQ_C$Q{@ zi2$dEh|A?ppFnKSk9pcuLfv(%cQ(WUezMRf$;g#8pt}oZ;{?noPCD@^YzS0- za0+=#t~g>*^%{$^sW*dDzhJ{O8Cafvq&gCP(Jquq6*^Y}lS(A0t(GZ_iGw!1m?y4> zRj7P-GZ#XOjQU?U?AE5wd4b>AzSiPv7#hAiVpOFZG_2&0naX{1_Om>`wlEvULlgFy z<`J(#FxOwMfNvBY{50E=c(o&(?CqU!pK(JdHuDo69VD*;hPSE2Uq*~~I~)FH&oVhk zp8gEwQBXuo+{8lu(puV$gK=%8qW_9?BP9b%A}0S(-x#lVOf|0jntmU{X!}fA*JGIg zMp(yFH*6OR=hjs`fE&@-p)=4ZZ!(lUrjn6ev1o{PvZsc!MmF?eFyBVNf%AtxNoQs8 z1(!!eRx1BA!`eb;CasX2%d6%STtauEk#0stGNGMz`}yN)r5;h6_@CC|Luhe-cymY`{@&0d&#^k zXi=%n=%3d^$0q$7*IpsIDywP!H(?(1Aus!WJg_6!pRDeO(Lem&uTf#OmmH*GPQI6I z;w8(;%NZdFbh+GqH!H8ekbo$RP@+pIJ@q^>%u9aHr+oP3_C7;VN9_H?kAwtqoGJD( zurmW)dB;hsNVi)Taych+s4VGKX4cO&c5YmC*7&1+n$ZPTiB!Z!a36O9E_Y^uX2XQ; zS@an7i}q2h~~~D8|WD0GRgP~^7R7pb-k8Hgv>~RZG(L4KM<>2h=;rT2A4S9 zw($#NMTNTl0}TMYhGR#blWCk4d7I5gv9F&CpWsnG@G_RcYxkT!I@&ecaiTaD{7p4K zNDcQ*Bveb!u6)tiyv*js$p*-#m7Fe`xsMaQ$&U1*M%>o2wOBC{hg*?DdZN2`C7xlOG^ex(ks`%^`bQ>vQAloS-xj;S@$OJd4b&jspa>yEP{Y`gRH=stX zO>Ds??wtqNM3Ix}u}?Huaaq6o*nnBU=S#yey|VDRE^|HK zKf`)sE=~Q*VZ^z*!-29Yr;W3?(q}7crTpdxZ)8i&z(TJpbG%*s@WQi7BL^gI3mdZYu?(#hUQSe-a5heNjzIq`i>fUCR9m+H1F8(|TSXi)uClR@* z7mrgNokiH2IMVNNWR0B(N*=sPQ+<DehgmEJyr#&22a>UZ8`66O*O1CGDjTS;$bK9a}D zbN#Z#4^O)+@<`P>8ZQ`DTugqKfAd^%~nEd0{}uN`$M54(tzMmjEQYOET(t<2}l zeuR&hPRN3dd9ERgD`;r2K8P?LgFMQJkZLFjba;%ZcV2k^U>mCuW z+)plyq@)jEb^lVMlHR8kUQU3(7%6FBEmS8qd>^|7iFO$fk>=p9dc_Sm0BgCka%M;G zhS-Ni6-J^B>M5?CG<`zv1KmsE`Wj4Z7C8KZ%@bIn_b2 zRI;`dk9}%JI^TnuQa|M;emk*y_{vn7)9K8b!Xf1?fo(*khBon`<;Vp2;IZT3YL}Em zbyPns`qS}r>e+)_tVbcrs3dX`hVcX6*|30ng(-$|P3`$k6F8X$bGB-E%P@zbB6KI) zDTiv%3)cx6As=!SQu<8<6oN=gJ%VLZ`Qg~-8Ft##C*S1#st8=kZtqzHhj|~d z@$}sw=1p2wtt{3MkzC2melPR%oBUxCHZ39~`O6P^x|H=YtSVqXZoIdblZb_s^sd|Nch2kBVVU#4} zP}wsH_KSb2o7T~k%o}}0mKTTf0GAF-o;NWu$w?J;m=`Ydefruzq0DQ0bpP_=Xm`(* zj53^6V2+@F?O>JYN8}(MgXV4$#G&QMV2ijJ-_f-8l(;#|Hgd5i+YJ&s_J&IsMyqjj zgdJ%~f>i6`POsoRB2o}UU}~FY7ii?VVAbq^|FGld8%lGON- z+E-JQ*C>a=;6#tHf`NWia!9UF(kIUk8Z4;FX%wxf_R3s&>sT$M34*JL)A>0<%%3!( zXBvXx!gAjbaJVVF@J`*B4q9-a9dXPd$CgoDTV9%8o0LDA&2I=>s(b`7<0d-R4W(cW zWs&#~MCQq-#a%I$70kmll`n6n-%p=1NPq5uHuUAUp-;9E&FenftauSq*lY`FtwHug zAwDE5svepUs?wo-Q{GxS9-jTVEl#6dC_b8hq8j89yxs>1`m6n0n(W2bDZCGZ-x{Y5 zY&TtPsVKG`czn``Y0NSX6!RIug zk@I_*YG6+wfa^<+Pjot&)_#?^71d(KG(tkqO;*lQA95zz`&WAxA3JOF_sZHb?mvbp z4F%qOn*3#IXnq-aJlk1p6afVYgUg$EVl<;+(#y>Pkd#sQ4EJ6WvJ9MAQFJDY#q4a! zLDzF!F%V|Ua_N*anI53+UpW?Yf2zBeF-&Qfe83Knq7eW75F<&GoDwfOW~Cvje+GH& z-1^2_NK=%F=cFft_TVw*Kj8YX5E3jw%k(~~Bb=P+ZdL{OFt&i+f{j`#!u?kO!RF#V zwfZ}RF)|Hal}+aG2feSuok|2s#cw;WE%c%=+iSSBw_z=+hK*L-6p%f9+9uoRR7uUFbUF2Ep!o}X z(3I1!pLw%*(F)jsC1SA?SD0s|0)3q?hqQXXb!tA>L#Wj_d?bD&#`2H5*$k0|tUX|2YH7fhe)5iBj!?tnnA(QS-WBn zRwbm{S{u`@!|>@vqhg{M>jy=7f9dsIBLZ=f^x&igk2_>`8^zJSi;#w9oPHdSNe)J4 zQxh*18thxcUP4l?NMhtwvro}%Xavb-bk@A?lzI|Lx5+Y)M$h?Tbxgjl*o#cKt|bc{ zT!XT>tad;}Vl>BrX+K`tS?j=N)KH0XJ+*9kFbz9(oMFn_B}pn!IF&y73jA~^r4Hi* z^l)f<=@s8o@_KWakyM3kR&~}m_Mc{@n20l_c+UIZDipjQN2Yg4Kxr4mdplM@^Qiyv-6%EtQuFb#4#+xm~{7^d(rlx-T8j<$MN8>l0paqb4#x8kR*zL{m0Hz z7UtO{B=7fS$am?7^X+TB>_q;pD4E@nr3+;MTODf}&+x7P?81PU-JU2TH$1k}qD$o{ zjK=-iCZ19I8xvc%+?%7VxQpzL=W$A19)F3wYyJbhsc9(vO^N~bwF|$z?ps^<50pA_ zCSVs1xWdE9zK7q1F?(%<|LytI_rnz+-5lCa1 zXNOKO&Mhg#rum|zQ?T#sXZU_w$g@+eZ>Qpp2LkWgdyOK0E0N+c76vgwF7xd}LOh0`ZIWyJ~tt_}w*6YY%ddWx?1 z*6vwo^lRD(zwfCPNLkHNRJ?QMdxs{(=#+YDKJ-vDJEq2E-DV#&rfTeLX;)exVLJa6 zj`L+EDlo2h%c=1Nj<%y7GEQ#-i3q7Noum66Y*c4WQ20(cGp~SB^Rg6rz5Cq=iwGZL zS2HIoGoN9aOSBc@LWZFSO@iCv>hEKTbN}W4%s-6T&mAlK`c0YD=CsF}rTuhX;zziE zSb0Sx2u&$)0XhD3++zP^*Hg|hD{Ij9EsJ99f{xw8K?P4Xl=2>tQ=V8CY!><|ZuWEC zZ8Ysif>>AE#feEoR+JsGXPupp=HTu4G28W&$L9CDOM-A0%iWwXR$0%C*tJ@Tmoc|N z7Iy0ozsigiG-WU;1u>C<_LlJUIJVJ8lj+-qG&4f(jw{*5IVt?Fp3!ozQsSv-8X;kc z#xtes44s2~Yokbx=bPT~5^lCv;)6?}s*>mBnrpV<3lXHy6 z_a4$UqbKhXf#6jMtWNw_Bkl|Ja4po1Tro{>jd%hlEIG zAXdN*)GK|J#x)Ba1#I^@^NR&nk#K?W_3P_N@;)QW`b?;qC8sVavG zexA&*8q=ZiQZJ_)sC3At4;z#!dO}g0aNPaNxGcx7tWO>uC-Q-fg~Hqx#yN=cKi zUzVwq+5GtG6bGnXO2-zScI_o~OF|DWTL0xczGwvg4GEoMnP0sR5=#qKJ1q>e!5b$#{=mDN~9SE)LeY*F|-hdsW<6b&wEJ)Zk-o4tTO2UY{e z%Qb@WbJAGd#8|MWoyf!Wn(*1C6*Hc++F{c20tJlRa4^r&GusX^NJkUN+GDG`h2i8h z`u)R;c3m9rsO6M_vq?Mg>v*C0vvCPJB3Y^84vQn1UVjeMsB$2G?sHWv8{|y?eG&0--g1J-u#2`_ssiRo}#)qu>Zq8E=Nn>7s6$ zigXGK?~|QNdLonA`22jMn@i%EwT*heE_3EDx?r=OaQy$JKAz!n<+7l-!t(xo8r-k@c$w80f5TkQVqQ41J$$$`%k+QB{y)$<1;}mo{6Q+I}j-=T*>e#i@N8?GXUmNDTyo(uxYPJjvuSuJMr4ACo_;EVHJ_D#ysZK~V@t>~X{0 z{W0LMafiby^N*qZ;Es#-?$h02|3g~tTZi~tKgCBKab^0yf0=d?aJ2x|bX_gXTp0!b zK95MBNYAv7GOzXFJXHg>oJopic!i~zPk7KDQ8Nm_z}lm`Z%`%0`*`i{)zK$k)BUNu z@T+9#vCj%d2M8o!MQt*&X~|gAF%3XeDM2@zFv2Y*)o;HF@QZI3vLD|i0zK}>`SV<# zb$vAo%i1#k1398U&n?B3(ti8mzTL_r&%PVh+uesi^MlAV_Ye`@?f&yQE({Pg(+3lI zfMZ&53P7(-egGyYKzm5>zy9WxjL&hR>@ckq%8>+tlG3=RNa4}_X-n3=6S|n+B=rI= zC^3ZzmtgXX8~=Y-J|u7{lzgF`F;J>7BQsC(yKEU*>ZOk zKS1a#y_;*c`$3His7M z1%OX5$D5V0J;j0YCh1a^BC%$s$#j?QNG^*klK<&Wc=99R(%8v)h)dJ7^{u+_0#+_^ zDp$v)JVG%l(Si6&bIdTAVe)XMPGp?56EGW13mJ2Qu6j|_MwRwQsKMTGr0cSO|0BEJ zKDy>ta=~QKcTf4STD)Jk3ao%P=Dxg05(k1+>*uD7X&nNjyV8QQ3lR0X>_3xoWcW^5 znFtQys|vMzm=bphr14c2Ea_RIOYZhx$o9Q<+$DU)?GX&+4C~A(&88O>R$!y1`azZT z3tcH>4dT{8al$Am%Bzm-nDPnGoHf{soL_eK#}1aoTS5ewMpAo9tU@fbg;k6fwI5Ro zzxsfBqLzd#rK&&@z)$Tuom%&ul=uDvQFSKfidpFV@@}nPHAthRF#k?i1jXn+=7+k= zW-1rWx&2bkd2j{x?bfeH zOT6QScImHc7{!bJf+*h_z#y{joL$~T=TqXn_*;|O33X1#mAaE!M2SiIYq4Y{-F{kE z<{4p;KnM(lM~~Er0t(HT_-L0Jbl=)AXfLr<4C50y`p`;@EIKX^*P+Vp8eHh+ zc6Ol25l~DGTMThw+P0pA?Gc=o+H?a^Gb4xvwF2ldTC?Ro+X>xZonr;5Gex6#k8cOv_Zcl&Ez-juQ`T6IwxuJ z6|AO=GAZV%NS?uS1oGjhI*QFZC)8q96vf$fk6S+*D#}j+z4?I%g|3(hi1XQAL=_gB z&|LAc2n0%@m`p}!XZ=gy^}Khtad}Q`wH8$RBa~Z`S5Z+B3EKc;DuM0{CHKu*SAxYY zUxd)k!fCB}tc%z3UNs(1zmm_%jliPA%V}!lMDmN9xI6fzi8#9w9JH*hX_PGsCqsoA zw>a^IuSl0XMWn$z&2SXeAM%~uOv&qu@rg>c2-}E}%=CfxCzYR>-Z4<_E*>uWv>)pAY93?chgKmLqPaS%ba@Q4QlnuzSnW(!3;Z zcr_S0lWa#M%GdX1-i)oT3?iY;$MBW*F652f?C)#;rkmC^0!%S<!^pu_ zK;IxQaet&2M%&Jybm%eF3^3lu#p9A=*-D6c7T7KcZd zsz9a+1xC|gO*mK(Yd_ro-Q$=sH@h|RAp2b|xxO@cGh@yVU zaTYtVAagTYU_$fNVh$g_5unDXDh^1R-+1)LomexvA2MRoQttRv;G;h3x2C+N{4)## zx{WOD)~(A*NlIHSw*mKWIS^SV4eAJ_H-_MCyD*;6-=FqO)@^V2;$=UF>o3}Z%bc6l z4EbN=f3qwv7gV#4V*uIEn+&v}r=8-aHD5G~&{I<7d(ZmWPI~fKx+JUf)wO)8u1Gf| zm7ADN{wdMs#u9#TO-X?d9_RVY7wF?t#JfHBv1r2hAK@==&rLSem_~kU`#J&#Bi*O% z)*kyEy3RmT7b%FWt;*LFErBjjp_gFLIFyA4LMobiLINw@D=dtqf$>_LVrJPkGj(2_ zn}a7eODiWAhJ;dOm#$wzm`&6N7cSbc15EEJYT!9j`Ocg#O6&YJhO6uKOq-o#m+Vk*^A;r=@ zMtkgYlEU^|?<$OaQRs2YFRSv|RBRhvQ9b%b5pRka2LlVU+6xb}zA6MX(r$klQ2}^7 zZ2Xyg&p63tt0DYmGTA)&K{ua=$D;aMDzL9QJ2uIHg0BknAEQ=ALQ;Rj!Ww++aTLfG zt_ zUu|68{s%IMuJ0ujNxgjB%_oyBTw(AmD;LyV10<}CwCZ^AatNDzMVj`heML?j_{(aX z3&gBo>bjwBnBmPJd(3{L_Jk?RGWEjYPS|+jlgyefv~SP$M|n*AP(R$Q{^09Wc}F*O zts9BFWG~Jc{13h~s#$Vl29z)LE&HK1>@UoE*M+ei-Zw5D|vjC&=(REBR zImW_mNg=fcx<2M0=m_R{N4HrHNn)czU?xlc=Rc5K8EhqHG5IotS>Pqat-cx=SxPs;Afd(Ts{fe|n28DT z#{d2VRCWVCzG;0WHHG!X8+SQ6A2OX%wnV1a>?&NIhm(JUPXd4mq@dBOE%~0maA0)F z<|t_r4+dUln85M)W3pUjU&F$%t~JL*!;tGs3*xw9!RIce3Ky3$l)g;laD)qCTW6oe z($FCLPe?tUBrsNu%KG=7-nMBU{%2_xC*I|gyx#gJYa2er`f~ekk1BIV;7BC^kGH0p zZ-Gq&SPA2R^GgBgDINdPs0`Spg|P;ceg1!k#&um@);~Eq_n)i|#{~cT1!N>al{J#x z$|7t>C*!aveDW)uUk+6Q9QAA77ZH#nD|bGh_r24XiKS85G%8}fY!7%YX36Wi4p*$Q z8Pcj{;}=9h(V-)~e;Eg;nt7_`1w^G+(M3oeiX{})a5_~ST6bPXqsv9|CRYtpvH75|k>cc4U3HENVPp+H$gEgsA=&fR_wu>z*c8X0>*=#9ePnu8 zZJEz2pKN?b{keQ6RJLW|xYfZO?i0LE`c`?aL8uC~TtRJU{*{&;&$5nw*|D45$5%Jx z6`nNQLIm^tI&yxMocc}HG)+#Ku1z|&>4g+T1`ah<(P4pBR9%L z$l$_#Im+#9HB7IAIc^Xp*TflxuT%A8Vbu1L4uTc|E3?~09+rGPpi&}f4E`H7?RB7r zw6WRlI(79;z;pS&7yg8_+|RgBoM0I0_uEzzmEd%hF!i?V;Ww1JCGB{OR=xKw+XAm< zQ5YTk|1tH}L2Z5Q_jd5$PH_SREmE|&OAS!&_m@Wqq?^8_4gEwao!X1GEdPQTil6Xit1|kX)7KW<{dcl)H}H1zFXedcOuQ0 ze;hg@QZw|4y2bRNwkIj+nI15LtX5BpzGF3F>g?5?`Oe@vf)S_eC^f_?0uFj&DCMVNFx1IWe%LRp-3 zAD{ELm;!%^N{Zhr0wGF!*WTmqJJiR5pPvo7Gl+zAPA<9zBr$!Z(i7}9us%q)Ih*T} z{GS;(`&)vw2VVa8 zHKk0TiN7~{dFBwytZH}m=L|y7A7Fz1tE~5Omo}I-sB{g0NL~h&2wc z*G*ORcF!R;1xzb$0qk%-CQ>x}5ws|sLVdS`4-88pv3`AEU8UJ4q8_S)R&S_lJi z%r4y)sZ&pqgf>*)vQ0SdIXNw`A%}s8GbK15biS3on!=gUUO&`G z#iaJ#rxH7sCGFx-xRv~PI~C}Oz_h+3UQaQ%nUje`I>s|KG+g8K9)b#(P$`!I6`mxD zI(uG#$w6=n`Vl{+VysP9NA}7A_5>3Fs#1qz2*~psQU3I-C!PB2C(nIX^$Ly>K5yP6 z`||2}R4ose7I%gSc}dLOpd+~*C14Xpgr@Oee}Ox4HDr*SX;E$B;bHwn?&8LyDOjLV zYPXv05->%JvqlF5>ch4vzaMkOQGP0_cluVpgCMqrKJfv|5&ht@MM#z(P+Oq%^ggHg zc)VUX+CO7{zegkeAIPg*1k_+*Vm#|NY`b9jT7ShiegdWp)_{P5FH=Q5ny~jZmBg6C zk+APw?@Tq6Of9$XK%JvR78wUbe+q2Jx<)eorasv7@?ddidd;0K%5zarLYU zk^H&PfhHBq{p=8@EXMW)r=Q%D=eJCiGHllDJ%&Sdt6A;L+$2#9xnE}o;?(?34i-{= zLyBBTa2PoTt{lNp8p92@H*y2NB_3GxN@}J)zMMSO&g)MHe)E*1pe;*Dw*iNN?<>VQ zsW{A3wY+3_RE{R!5Ya!90QH`wJT{eU2-(h|N18p$3NIJMMnTCw$h2z}yz-JR;}zC-yS;?m*{czQJb74lug1#F#Y=LsRA614*Y!7PZ8k8&wprj_a_hHiK9Mo2Cfxz<36P&RWp?b z!rS&=HMxx+Q+I3nptX*#oj8{s-8t2W=~8@}{sZw7wtiA1Hf3lt23mQTlcCT+pJ z-%Gr{8|Ac=V_%c>3$n68n*)O^rX`EKA@nV|@UFmVIg^*EE!RwCZKCu~7;5^c-nXky zFe}ld&#E}8v8FtS^IoG=*;`2?xIDl+yR%I0%|i_79;;Ui0-3SnGzre6&*{@+sB*BM z1oT{I5e|Zf8)20eVH(f54fJ}R*6B$9DNjClD#o0iVwj)XC?t=^)UGWXE5@uzfd{k2 z@Wtx=eYX84gV`ZF3h))bbTH_XPRY!z}A2LX|> zL$C`{dgmTKqRZ*{&bB38z4OkV8hguRHLqL6>h*&^YPUma#U1U{3cN>;IlQbhzM{T(me#migS8k-X{R&cu~{4t3)AsivCoad=p$LI!R= zA!ha8hV8siPS5ADlqNG6G5$OL1&mUZ6QV6-Vt$U|p2wrE3g;K4n@H?J08Dxx)tbg- z|NF7+Hb7Nwg9udlftIgMOZ5=}dRc-Sc92Hs0U0LYOl_L_}iQ&a>8EYWIgsnlDB;+Xx~7$xr4kG zQD}#hs+2JP_@hAA7(nti%!iih|w`va&HTz`BCdgYM63S;1um5|s}{et@^8m(tG(MU+T9 zHN?S5$27Ls#bPBwh^Y^_h%pF|Xf1Wy&3jaM^r*wrK@Kj$50^K}8c{v0IvG`@tLsJF z#jjLTqbWeRoiQJ8j;LbYf=Nw&2NKAQquWSqc;cM?EvhWSkd^f{&zf>5F_N*VATJ%2 zHxhJ$QlMk}t+#`Dpl~5Rtr_VpxX?^&KAxB5G6j(QX9&H|p}4SDC7O~-TyjQo5@eNw za8b{4(l0IsF|SqvOmJ~_QK9ZXplNx3cQV%?>4&`eRx-O^E&%Lu#G|r7Qjv)yNFfhLkuUX5R4!ccVBVy!a`9J0?kjRF-a^!ffGB3hSUT}{RDw*}Xec$jo0?r2q5e8>U z8$YOgJNxrPe(mML^ymIf0WqW|9jQT>sLZF2dudfy^fOl8qXrz`O7zfl5-UjQj+~2x z;&8-Fy50jlXbqnn<8t_8*rJLB^p;mtDu@PrOZ4V7)2mGEGUe*jIKj))(YoIX5hV(w z+{Q|+a0GbITb3r~u_LrIaQ(g@)%cByoNx=(g-nOlrTh1BwU`+J{euCtgHLmx zum)o)`9eLy7!g$;RAPNU7Z1^yRubm(x05MfY<~K!H1Y1~P0oy!Cb%K0R!l&+$MKjD&f3`b2SQ zb7!V}w%b9Vz;5fm42Py?Us&rmW}A`2_2aC(8@6<&wZ9GL=o{(3&=H20rE0Mt^+jLp zrDd{>WriBGMzV21LxZax-aqzSiUr>DCqC3nP0-)@t%RN9%CnnW|%TGWL;At@Y1tC@SgBr)tKu?APm^+2EDNcWa`mub`- zj@(I?-8uDgomJ{4IJVeDkeBH#GwUejq}hECB1zu5R9DY3dWtaF(XxRf!Ys>zfS4Bh zm?m>85fKq#FuiSmx!&MMiaxf9Tp7J)L^wB>c21-^vrR|SxI9`f8a$+e;`>b>=iX@t zi&CBt@y9Igg3N*>a4O$BrAS=Ck};*mGHzrf1d3*X^&KQFaQOKLBc+Us493@MZ$9b% z**-3g_z|*Q3WOo2@v6sYy5LhjlV0;kti(d5JnH{Ii2U|m7l}KwxRT^0$w>}Ni6l~O z?bJ5Mjdu&u^UK4|5phJ`!;sKU`^ZCs-ik;&(jR~7Qt;h>Os(=mUW?2nBq-7!7NeuJ z=GJV@*pcfXnsl|w^7&phQK)B$8m9{2;czL;6o+R(Ga)fpz0aoFL~S@hUZS#v*Fi6D zv+q=c$KTop&%1SKEx)L}ZL|~-LAPVpjhy~VDdu3Zl@qCkLb1oec( z*8E_q>tg<^ku=qNwl7lZVXtwxKg$bGlR$#e=4<-6cHIc(jUM7LeSwi6Ra*> zI$56m=~v;fw_0|zs=b6fX_|0f4KS7`*Emi=iy9JbwyS&jogg>dMa z<)ObL(W)C6(FNQQ^F}uoit9CI2-=1}4?>4K3k5u!g{}R~iPo16t1<0Qz=V=4njB-{)n|Yv-GdKKKg7d5G&2~|> zm~Zl&O=s#-46s#^JdIjDSr2DN5{v|7crtykIEtuvAa=h)M zZuLqTWyeay}ds>;Hj1|LvJs|7oo1XUe+lp*dgSAFmgd zBvUR>LCSJPqmaplC>Z$V+FhxK&qx0wgg8%we%pQX89%G0NzM9*VK^&3p|2Y--L914 zWPp4y#AIN$0=>*?QOF>lT|A(IQs;vBSXX~d3M#Y2VrUaCPX#f{6Wn=T>`&v&fLj8y z6VDGe50ySy!LfcVRwr$xlw2+U>>LJEFz$bf*#Dl<71=Gp?_LvygA1Fb zANq42QwlnRYq!w}!{|G2e`r)Sw~>U4Y#*%Ne+f@rm6AN#U7diE6bo46V&RE!xDhR& z_pgtw?mBFE+yzvHgvF+t+!8kDMoSBaw{*s4FSuew#pni(#_k3<3^v|3O?SN+Y%^Z| zr0kR4P^w$r@X0tHk(15oQ2ZaLud-*)&8mZit-=Pxkifnu75#P#>tP7b82&|0b@Z=L zx}&4S%b>pNE?2iiq}ET8kLgpHBvdJ6FNIO$d=`A8-bFn|#tfM+h%F2c>tc1_`G~kr zX5I*FO{<6u#d>3c`T@Ez8h8u)S^Rnzp1z!h8BYWseAH$-OMPh|1yKfK09)FG=fntb zaLWZ(a2rD-5t(rgnURr2CdHV{V6z$}xT32rqm|(9WBlB#rH?x) zOCbNkn@Uq`8jTp3dc2X9F$tf>LPOg^sW)d`>-2XJEm>QUK1Igd+=NmN7|RJ6iy0~m zn@32nLCDlV^r1#?t-Yw(xbl&evzZ$OnaHqwu^3R~FKF%JyW%Y>h7GwSQ9JSedu3*_ zrwUuVxjZwrIci+@9=j#mReVMaAMLbH5cZ@hF=8Xw(7op=-rYu@QPYm-;>iZ5f2*t+ zHjESXoia2jwUl8TNt&g~8Z6_Va>y%6->&8J!k{K%<0;@3lC^|z`6M-8 zt6w4Uvu#@FE`37Vule7^T*Fw_C&u!|sixuc4M#>Q} zz3e`}?uUfcLrGjVr6i^Xfki$gl7y(M(Fs6dgz2v>;+|fZww7l^oedoWu0xH2p zLa9`+oapP)0+L#JCHfxG#qh+BsppqBieOglX(?btyI2n zMV>ZX%Ay{f2w;+6kQe%K{oBs_x08U04*55v!4?~Q^ReB-#2PO^k5`y2l)Af7`Bz-3 z7h+qwd=I|+|9e-;_Z;*yhxOePam4=`t)*B7FFk&Cy*=(AX~7S`F?IMDP7%%H6B%9) zoSlE>lmGWjEN=(q?i1(NheQ==KCAIUYt{ij z6z86@aK`&iJvOtB0 zdM76?cKfniQAA!_Nfpd}xQ-@zT%LZ#xmMTRHb~}mhgyaa@1LBz)=={L?ND5ZQ!&FY z!-Xs#R<-*do4>({tqtGz#SboDdnW=$dJ-~0C|{QHpr5TgZf-%QRjir@Ot9A%st$@? zI2ffpzWw#7|Flwvp)N~HxaRqZ<6LBAEes2h$&jzAEw3%HqRIlc4tQ&vY(@-VsI^KB z-uTZ#Kj)RCOZT==u`H9WO`A?)Mg?6sf|3vJGdFenh{!%kltPJDC*jOP9~(78k5)Ny zmY<1G^RY6+@k)&}UH7-j8llB+*J0d*6?ht7^K7^P?v)O#9KoG>FE1~cX~f<$27^mV zpfs*5X~Y9Hw8Tw|8j#~`;&Pi&X#4Mfp!#3`7XqpJF9gy+O!d!>i1U9SH7kAq#5|UkyO=zk;J&%_*y%}{ z`xTmD?Kh;CW$-js43szZLefR^KTxr8|Ftf44Z2O62rNZjy6VL-gD4hqn@hT}cSONV zLDAmtu!9)`H!6*3?SHoK7e|Wt?OMw~#O>G*bGYm_fhwU`AXOt-k%>5Vk9Sbj*k+Ab zfij^j@=n5^oP#r;B-~KaHyr~iX{y9_!XWcDg0mvv^0SB&{MAR{3b_=pO+?;Ro6}jvwF_7)%eE4pQ zJ^I3&kMjUWQ4*f+C-u4?dNx?kp+qC%Va@*bFA1%Ei`FaY@U@(|fgM>+GAE~W4s`LanbXnWah!|8Y}^f-{;0b zjcvh?rfOWKOIB;>=)ZheMrWS-O_5iOb0Om?xVT_QW1GLQSqT)n$x37~sbzMJrkl{%N6mtx`H-)pZO{p3=Hah zygAcauLdwZ|9q>k?~3_z>ELH|DDpgjVTns%ub5O}!}DB838CXT%&7R9Uo4Xr ziGTR-X0stP7QP0&^jGrAM72u2%sDZ;iwh}H7?!>}ULA0U=RyL3HB*MC0CiUkhSvFD zF-nu$b1bz+i}mo}%^A7((fPIPi(iI@kT@v8@bwLg3c)Xa(?Dj6aIWqiEz^HfW)A

    +7hf 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 -HtbUGGXN*lR9w5*3FBZ3z*&3gh@Z3FmvEtG* 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

    -dg|NuOE{0yB9PiW6{0)ft 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 Ty(+G;Tp47+B=kTg*AC?`q@7ed literal 0 HcmV?d00001 diff --git a/docs/source/_static/robots/dexforcew1_industrial.jpg b/docs/source/_static/robots/dexforcew1_industrial.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a3c4b9bbcd60d5c4847b2aefe9c47c54169c24dc GIT binary patch literal 604678 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

    xBkD>Xc}EaC6A3*LOA`$LCH}7Ci(5q6+mVePye- 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 +F5 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%0DY9R+c4%#39Mf{U^zy6`_-s`oy5+0%C4)B_ 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 F`XAPQ5&QrE literal 0 HcmV?d00001 diff --git a/docs/source/resources/robot/cobotmagic.md b/docs/source/resources/robot/cobotmagic.md index ac7a959f..dd93f419 100644 --- a/docs/source/resources/robot/cobotmagic.md +++ b/docs/source/resources/robot/cobotmagic.md @@ -2,6 +2,12 @@ CobotMagic is a versatile dual-arm collaborative robot developed by AgileX Robotics. It is widely used in simulation, education, industry, and service scenarios. All examples in this document are based on the latest PourWater task environment. +

    + CobotMagic +

    CobotMagic

    +
    + + ## Key Features - **Dual-arm parallel structure** supporting multiple layouts (standard, face-to-face, custom) @@ -25,7 +31,6 @@ CobotMagic is a versatile dual-arm collaborative robot developed by AgileX Robot > **Note:** The current version of CobotMagic does **not** support a mobile base. All examples and environments assume a fixed base configuration. - --- ## Quick Initialization Example @@ -95,9 +100,9 @@ control_parts = { - [AgileX CobotMagic Product Page](https://global.agilex.ai/products/cobot-magic) - Related URDF file path: `CobotMagicArm/` - - CobotMagicWithGripperV70.urdf - - CobotMagicWithGripperV100.urdf - - CobotMagicNoGripper.urdf + - CobotMagicWithGripperV70.urdf + - CobotMagicWithGripperV100.urdf + - CobotMagicNoGripper.urdf - [embodichain Simulation Platform Documentation](https://github.com/dexforce/embodichain) --- @@ -106,7 +111,7 @@ control_parts = { - [AgileX CobotMagic Product Page](https://global.agilex.ai/products/cobot-magic) - Related URDF file paths (located in `CobotMagicArm/`): - - `CobotMagicWithGripperV70.urdf` - - `CobotMagicWithGripperV100.urdf` - - `CobotMagicNoGripper.urdf` + - `CobotMagicWithGripperV70.urdf` + - `CobotMagicWithGripperV100.urdf` + - `CobotMagicNoGripper.urdf` - [embodichain Simulation Platform Documentation](https://github.com/dexforce/embodichain) diff --git a/docs/source/resources/robot/dexforce_w1.md b/docs/source/resources/robot/dexforce_w1.md index e64e3624..d37f42c7 100644 --- a/docs/source/resources/robot/dexforce_w1.md +++ b/docs/source/resources/robot/dexforce_w1.md @@ -1,7 +1,19 @@ + # Dexforce W1 Dexforce W1 is a versatile robot developed by DexForce Technology Co., Ltd., supporting both industrial and anthropomorphic arm types. It is suitable for various simulation and real-world application scenarios. +
    +
    + Anthropomorphic Version +
    Anthropomorphic Version
    +
    +
    + Industrial Version +
    Industrial Version
    +
    +
    + ## Key Features - Supports multiple arm types (industrial, anthropomorphic) @@ -9,10 +21,9 @@ Dexforce W1 is a versatile robot developed by DexForce Technology Co., Ltd., sup - Flexible URDF assembly and simulation configuration - Compatible with SimulationManager simulation environment - ## Usage in Simulation Environment -""" +"""python from embodichain.lab.sim import SimulationManager, SimulationManagerCfg from embodichain.lab.sim.robots.dexforce_w1.types import ( DexforceW1HandBrand, DexforceW1ArmSide, DexforceW1ArmKind, DexforceW1Version @@ -21,8 +32,21 @@ from embodichain.lab.sim.robots.dexforce_w1.utils import build_dexforce_w1_cfg config = SimulationManagerCfg(headless=False, sim_device="cpu") sim = SimulationManager(config) -sim.build_multiple_arenas(4) +sim.build_multiple_arenas(1) +sim.set_manual_update(False) +""" + +## Method 1: Fine-grained configuration with `build_dexforce_w1_cfg` + +This method allows you to specify detailed parameters for each arm and hand. Recommended for advanced users who need full control over robot hardware options. + +**Parameters:** +- `arm_kind`: Arm type, e.g., `DexforceW1ArmKind.ANTHROPOMORPHIC` or `DexforceW1ArmKind.INDUSTRIAL`. +- `hand_types`: Dict specifying hand brand for each arm side (`LEFT`/`RIGHT`). +- `hand_versions`: Dict specifying hand version for each arm side. + +"""python hand_types = { DexforceW1ArmSide.LEFT: DexforceW1HandBrand.BRAINCO_HAND, DexforceW1ArmSide.RIGHT: DexforceW1HandBrand.BRAINCO_HAND, @@ -31,19 +55,61 @@ hand_versions = { DexforceW1ArmSide.LEFT: DexforceW1Version.V021, DexforceW1ArmSide.RIGHT: DexforceW1Version.V021, } - cfg = build_dexforce_w1_cfg( arm_kind=DexforceW1ArmKind.ANTHROPOMORPHIC, hand_types=hand_types, hand_versions=hand_versions, ) +robot = sim.add_robot(cfg=cfg) +print("DexforceW1 robot added to the simulation.") +""" + +## Method 2: Quick configuration with `DexforceW1Cfg.from_dict` + +This method allows fast setup using a dictionary, suitable for simple scenarios or when default options are sufficient. Recommended for rapid prototyping or when only basic parameters are needed. +**Parameters:** + +- `uid`: Unique robot identifier (string). +- `version`: Robot version, e.g., `v021`. +- `arm_kind`: Arm type, e.g., `anthropomorphic` or `industrial` (string). + +"""python +from embodichain.lab.sim.robots import DexforceW1Cfg +cfg = DexforceW1Cfg.from_dict( + {"uid": "dexforce_w1", "version": "v021", "arm_kind": "anthropomorphic"} +) robot = sim.add_robot(cfg=cfg) print("DexforceW1 robot added to the simulation.") +""" + +## Arm Joint Design: Mirrored Configuration + +DexforceW1's left and right arms are designed with mirrored joint configurations. This means the joint angles for the left and right arms are symmetric but opposite in sign for certain axes, making it easier to coordinate bimanual tasks and maintain natural robot postures. + +### Example: Setting Arm Joint Positions + +```python +import numpy as np +# Set left arm joint positions (mirrored) +robot.set_qpos(qpos=[0, -np.pi/4, 0.0, -np.pi/2, -np.pi/4, 0.0, 0.0], joint_ids=robot.get_joint_ids("left_arm")) +# Set right arm joint positions (mirrored) +robot.set_qpos(qpos=[0, np.pi/4, 0.0, np.pi/2, np.pi/4, 0.0, 0.0], joint_ids=robot.get_joint_ids("right_arm")) ``` -## Type Descriptions +This mirrored design simplifies motion planning and ensures that both arms can perform coordinated or symmetric actions efficiently. + +## Configuration Method Selection + +Choose `build_dexforce_w1_cfg` for maximum flexibility and hardware customization. Use `DexforceW1Cfg.from_dict` for quick setup and prototyping. Both methods produce a configuration object (`cfg`) that can be passed to `sim.add_robot(cfg=cfg)` to add the robot to the simulation. +**Note:** + +- Ensure parameter types match the expected enums or strings. +- For advanced simulation scenarios, prefer the fine-grained method. +- For most demos or simple tasks, the quick method is sufficient. + +## Type Descriptions | Type | Options / Values | Description | |-------------------------|-------------------------------------------------------|------------------------------------| diff --git a/embodichain/lab/sim/robots/dexforce_w1/cfg.py b/embodichain/lab/sim/robots/dexforce_w1/cfg.py index 5ae4da8f..673eb609 100644 --- a/embodichain/lab/sim/robots/dexforce_w1/cfg.py +++ b/embodichain/lab/sim/robots/dexforce_w1/cfg.py @@ -73,7 +73,7 @@ def from_dict( version=version, arm_kind=arm_kind ) - default_physics_cfgs = cls()._build_default_physics_cfgs() + default_physics_cfgs = cls()._build_default_physics_cfgs(arm_kind=arm_kind) for key, value in default_physics_cfgs.items(): setattr(cfg, key, value) @@ -181,27 +181,51 @@ def _build_default_solver_cfg(is_industrial: bool) -> SolverCfg: } @staticmethod - def _build_default_physics_cfgs() -> typing.Dict[str, any]: + def _build_default_physics_cfgs(arm_kind: str) -> typing.Dict[str, typing.Any]: + """Build default physics configurations for DexforceW1. + + Args: + arm_kind: Type of arm, either "industrial" or "anthropomorphic" + + Returns: + Dictionary containing physics configuration parameters + """ + # Define common joint patterns + arm_joints = "(RIGHT|LEFT)_J[0-9]" + body_joints = "(ANKLE|KNEE|BUTTOCK|WAIST)" + + # Hand/gripper pattern differs by arm type + hand_pattern = ( + "(LEFT|RIGHT)_FINGER[1-2]" + if arm_kind == "industrial" + else "(RIGHT|LEFT)_[A-Z|_]+" + ) + + # Define physics parameters for different joint types + joint_params = { + "stiffness": { + arm_joints: 1e4, + hand_pattern: 1e2, + body_joints: 1e7, + }, + "damping": { + arm_joints: 1e3, + hand_pattern: 1e1, + body_joints: 1e4, + }, + "max_effort": { + arm_joints: 1e5, + hand_pattern: 1e3, + body_joints: 1e10, + }, + } + + drive_pros = JointDrivePropertiesCfg(**joint_params) + return { "min_position_iters": 32, "min_velocity_iters": 8, - "drive_pros": JointDrivePropertiesCfg( - stiffness={ - "(RIGHT|LEFT)_J[0-9]": 1e4, - "(RIGHT|LEFT)_[A-Z|_]+": 1e2, - "(ANKLE|KNEE|BUTTOCK|WAIST)": 1e7, - }, - damping={ - "(RIGHT|LEFT)_J[0-9]": 1e3, - "(RIGHT|LEFT)_[A-Z|_]+": 1e1, - "(ANKLE|KNEE|BUTTOCK|WAIST)": 1e4, - }, - max_effort={ - "(RIGHT|LEFT)_J[0-9]": 1e5, - "(RIGHT|LEFT)_[A-Z|_]+": 1e3, - "(ANKLE|KNEE|BUTTOCK|WAIST)": 1e10, - }, - ), + "drive_pros": drive_pros, # TODO: we may use the some properties from URDF as default values # eg. mass, friction, damping, etc. "attrs": RigidBodyAttributesCfg( @@ -221,10 +245,18 @@ def _build_default_physics_cfgs() -> typing.Dict[str, any]: def _build_default_cfg( version: str = "v021", arm_kind: str = "anthropomorphic" ) -> DexforceW1Cfg: - hand_types = { - DexforceW1ArmSide.LEFT: DexforceW1HandBrand.BRAINCO_HAND, - DexforceW1ArmSide.RIGHT: DexforceW1HandBrand.BRAINCO_HAND, - } + + if arm_kind == "industrial": + hand_types = { + DexforceW1ArmSide.LEFT: DexforceW1HandBrand.DH_PGC_GRIPPER_M, + DexforceW1ArmSide.RIGHT: DexforceW1HandBrand.DH_PGC_GRIPPER_M, + } + else: + hand_types = { + DexforceW1ArmSide.LEFT: DexforceW1HandBrand.BRAINCO_HAND, + DexforceW1ArmSide.RIGHT: DexforceW1HandBrand.BRAINCO_HAND, + } + hand_versions = { DexforceW1ArmSide.LEFT: DexforceW1Version(version), DexforceW1ArmSide.RIGHT: DexforceW1Version(version), From 691c7636468ce021e6e2a3b405917eca13ca6315 Mon Sep 17 00:00:00 2001 From: Chen Jian Date: Wed, 26 Nov 2025 15:58:27 +0800 Subject: [PATCH 12/92] Remove gizmo collision body (#11) Co-authored-by: chenjian --- embodichain/lab/sim/objects/gizmo.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/embodichain/lab/sim/objects/gizmo.py b/embodichain/lab/sim/objects/gizmo.py index 1bf720ae..27ebf5bf 100644 --- a/embodichain/lab/sim/objects/gizmo.py +++ b/embodichain/lab/sim/objects/gizmo.py @@ -196,11 +196,6 @@ def _create_proxy_cube( proxy_cube.set_location(position[0], position[1], position[2]) proxy_cube.set_rotation_euler(euler[0], euler[1], euler[2]) - # Add kinematic physics to proxy cube - attr = PhysicalAttr() - attr.mass = 0.05 - proxy_cube.add_rigidbody(ActorType.KINEMATIC, RigidBodyShape.CONVEX, attr) - # Connect gizmo to proxy cube self._gizmo.node.update_gizmo_follow(proxy_cube.node) From db02df5fdc15c32aa463d346ae2829048c88f56d Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Wed, 26 Nov 2025 14:46:57 +0000 Subject: [PATCH 13/92] Updata docs (#12) --- docker/docker_run.sh | 105 +++++++++++++++++++++ docs/source/quick_start/install.md | 6 ++ docs/source/resources/roadmap.md | 16 +++- docs/source/resources/robot/cobotmagic.md | 23 ----- docs/source/resources/robot/dexforce_w1.md | 23 +---- 5 files changed, 129 insertions(+), 44 deletions(-) create mode 100755 docker/docker_run.sh diff --git a/docker/docker_run.sh b/docker/docker_run.sh new file mode 100755 index 00000000..65fd791e --- /dev/null +++ b/docker/docker_run.sh @@ -0,0 +1,105 @@ +#!/bin/bash +# Usage: ./docker_run.sh [container_name] [data_path] + +# Check if the correct number of arguments are provided +if [ "$#" -ne 2 ]; then + echo "Usage: $0 [container_name] [data_path]" + exit 1 +fi + +container_name=$1 +data_path=$2 + +echo "image_name: $container_name" +echo "data_path: $data_path" + +# Initialize error flag and paths +error_flag=0 +VK_DRIVER_PATH="" +GL_DRIVER_PATH="" + +# Check Vulkan driver paths +if [ -f /etc/vulkan/icd.d/nvidia_icd.json ] && [ -f /etc/vulkan/implicit_layer.d/nvidia_layers.json ] && + ! [ -d /etc/vulkan/icd.d/nvidia_icd.json ] && ! [ -d /etc/vulkan/implicit_layer.d/nvidia_layers.json ]; then + VK_DRIVER_PATH=/etc +elif [ -f /usr/share/vulkan/icd.d/nvidia_icd.json ] && [ -f /usr/share/vulkan/implicit_layer.d/nvidia_layers.json ] && + ! [ -d /usr/share/vulkan/icd.d/nvidia_icd.json ] && ! [ -d /usr/share/vulkan/implicit_layer.d/nvidia_layers.json ]; then + VK_DRIVER_PATH=/usr/share +else + if [ -d /etc/vulkan/icd.d/nvidia_icd.json ] || [ -d /etc/vulkan/implicit_layer.d/nvidia_layers.json ]; then + echo "Warning: /etc/vulkan/icd.d/nvidia_icd.json or /etc/vulkan/implicit_layer.d/nvidia_layers.json is a directory, not a file." + elif [ -d /usr/share/vulkan/icd.d/nvidia_icd.json ] || [ -d /usr/share/vulkan/implicit_layer.d/nvidia_layers.json ]; then + echo "Warning: /usr/share/vulkan/icd.d/nvidia_icd.json or /usr/share/vulkan/implicit_layer.d/nvidia_layers.json is a directory, not a file." + else + echo "Warning: Required Vulkan driver files not found." + fi + error_flag=$((error_flag + 1)) +fi +echo "VK_DRIVER_PATH: $VK_DRIVER_PATH" + +# Check OpenGL driver paths +if [ -f /etc/glvnd/egl_vendor.d/10_nvidia.json ] && ! [ -d /etc/glvnd/egl_vendor.d/10_nvidia.json ]; then + GL_DRIVER_PATH=/etc +elif [ -f /usr/share/glvnd/egl_vendor.d/10_nvidia.json ] && ! [ -d /usr/share/glvnd/egl_vendor.d/10_nvidia.json ]; then + GL_DRIVER_PATH=/usr/share +else + if [ -d /etc/glvnd/egl_vendor.d/10_nvidia.json ]; then + echo "Warning: /etc/glvnd/egl_vendor.d/10_nvidia.json is a directory, not a file." + elif [ -d /usr/share/glvnd/egl_vendor.d/10_nvidia.json ]; then + echo "Warning: /usr/share/glvnd/egl_vendor.d/10_nvidia.json is a directory, not a file." + else + echo "Warning: Required OpenGL driver files not found." + fi + error_flag=$((error_flag + 1)) +fi +echo "GL_DRIVER_PATH: $GL_DRIVER_PATH" + +# Check error flag and exit if necessary +if [ $error_flag -eq 2 ]; then + echo "No driver paths were found to be directories instead of files. Please check the paths." + exit 1 +fi + +# Build the docker run command with conditional volume mounts +docker_cmd="docker run -itd --gpus all \ + -e NVIDIA_DRIVER_CAPABILITIES=all \ + -e NVIDIA_VISIBLE_DEVICES=all \ + -e NVIDIA_DISABLE_REQUIRE=1 \ + --device /dev/dri \ + --name $container_name \ + -v /usr/share/nvidia:/usr/share/nvidia \ + -v $data_path:/root/workspace" + +# Add Vulkan driver mounts if VK_DRIVER_PATH is set +if [ -n "$VK_DRIVER_PATH" ]; then + docker_cmd="$docker_cmd \ + -v ${VK_DRIVER_PATH}/vulkan/icd.d/nvidia_icd.json:${VK_DRIVER_PATH}/vulkan/icd.d/nvidia_icd.json \ + -v ${VK_DRIVER_PATH}/vulkan/implicit_layer.d/nvidia_layers.json:${VK_DRIVER_PATH}/vulkan/implicit_layer.d/nvidia_layers.json" +fi + +# Add OpenGL driver mounts if GL_DRIVER_PATH is set +if [ -n "$GL_DRIVER_PATH" ]; then + docker_cmd="$docker_cmd \ + -v ${GL_DRIVER_PATH}/glvnd/egl_vendor.d/10_nvidia.json:${GL_DRIVER_PATH}/glvnd/egl_vendor.d/10_nvidia.json" +fi + +# Add remaining common volume mounts and environment variables +docker_cmd="$docker_cmd \ + -v /tmp/.X11-unix:/tmp/.X11-unix \ + -v ~/.Xauthority:/root/.Xauthority:rw \ + -e DISPLAY=$DISPLAY \ + -e WORK=~/workspace \ + --shm-size 50G \ + --network=host \ + -v /dev/shm:/dev/shm \ + dexforce/embodichain:ubuntu22.04-cuda12.8 /bin/bash" + +# Execute the docker run command +eval $docker_cmd + +# Print success message +if [ $? -eq 0 ]; then + echo "Docker container $container_name started successfully." +else + echo "Failed to start Docker container $container_name." +fi diff --git a/docs/source/quick_start/install.md b/docs/source/quick_start/install.md index 7641687e..892e99cd 100644 --- a/docs/source/quick_start/install.md +++ b/docs/source/quick_start/install.md @@ -33,6 +33,12 @@ We strongly recommend using our pre-configured Docker environment, which contain docker pull dexforce/embodichain:ubuntu22.04-cuda12.8 ``` +After pulling the Docker image, you can run a container with the provided [scripts](../../../docker/docker_run.sh). + +```bash +./docker_run.sh [container_name] [data_path] +``` + --- diff --git a/docs/source/resources/roadmap.md b/docs/source/resources/roadmap.md index 89bf504a..f248a8f2 100644 --- a/docs/source/resources/roadmap.md +++ b/docs/source/resources/roadmap.md @@ -10,6 +10,7 @@ Currently, EmbodiChain is under active development. Our plan for the feature roa - Add a new rasterization backend for basic rendering tasks. - Support 3DGS rendering mode (If we have enough bandwidth). - Physics: + - Improve GPU physics throughput. - Improve soft body simulation stability and add more examples and tasks. - We are also exploring how to integrate [newton physics](https://github.com/newton-physics/newton) into EmbodiChain as an alternative physics backend. - Sensors: @@ -20,6 +21,17 @@ Currently, EmbodiChain is under active development. Our plan for the feature roa - Add more advanced motion generation methods and examples. - Useful Tools: - Add a robot workspace analysis tool for better visualization and sampling of robot accessible workspace. - - We are working on USD support for EmbodiChain to enable better scene creation and asset management. + - We are working on USD support for EmbodiChain to enable better scene creation and asset management. + - We will release a simple Real2Sim pipeline, which enables automatic task generation from real-world data. + - Robots Integration: + - Add support for more robot models (eg: LeRobot, Unitree H1/G1, etc). -- Models and Training Workflows: +- Agents: + - Add more Reinforcement Learning examples and environments. + - We will release a Modular VLA framework for fast prototyping and training of embodied agents. + - We will release a simple online data streaming pipeline for Imitation Learning. + +- Tasks: + - We will release a set of Real2Sim tasks as examples for EmbodiChain. + - We will release a set of tableware manipulation tasks for demonstration of data generation pipeline. + \ No newline at end of file diff --git a/docs/source/resources/robot/cobotmagic.md b/docs/source/resources/robot/cobotmagic.md index dd93f419..63eb6b65 100644 --- a/docs/source/resources/robot/cobotmagic.md +++ b/docs/source/resources/robot/cobotmagic.md @@ -84,28 +84,6 @@ control_parts = { } ``` ---- - -## Common Issues & Notes - -- **URDF Path**: Ensure the corresponding URDF files exist in the data path (e.g., `CobotMagicArm/CobotMagicWithGripperV100.urdf`). -- **Simulation Device**: Supports CPU/GPU simulation. Set `sim_device` according to your hardware. -- **Multi-arena Simulation**: Use `build_multiple_arenas(n)` to quickly create n parallel simulation environments. -- **Gripper Model Switching**: To switch gripper models, modify the URDF path in `urdf_cfg`. -- **Mobile Base**: Not supported in the current version; related parameters will be ignored. - ---- - -## References - -- [AgileX CobotMagic Product Page](https://global.agilex.ai/products/cobot-magic) -- Related URDF file path: `CobotMagicArm/` - - CobotMagicWithGripperV70.urdf - - CobotMagicWithGripperV100.urdf - - CobotMagicNoGripper.urdf -- [embodichain Simulation Platform Documentation](https://github.com/dexforce/embodichain) - ---- ## References @@ -114,4 +92,3 @@ control_parts = { - `CobotMagicWithGripperV70.urdf` - `CobotMagicWithGripperV100.urdf` - `CobotMagicNoGripper.urdf` -- [embodichain Simulation Platform Documentation](https://github.com/dexforce/embodichain) diff --git a/docs/source/resources/robot/dexforce_w1.md b/docs/source/resources/robot/dexforce_w1.md index d37f42c7..7160825b 100644 --- a/docs/source/resources/robot/dexforce_w1.md +++ b/docs/source/resources/robot/dexforce_w1.md @@ -21,21 +21,6 @@ Dexforce W1 is a versatile robot developed by DexForce Technology Co., Ltd., sup - Flexible URDF assembly and simulation configuration - Compatible with SimulationManager simulation environment -## Usage in Simulation Environment - -"""python -from embodichain.lab.sim import SimulationManager, SimulationManagerCfg -from embodichain.lab.sim.robots.dexforce_w1.types import ( - DexforceW1HandBrand, DexforceW1ArmSide, DexforceW1ArmKind, DexforceW1Version -) -from embodichain.lab.sim.robots.dexforce_w1.utils import build_dexforce_w1_cfg - -config = SimulationManagerCfg(headless=False, sim_device="cpu") -sim = SimulationManager(config) -sim.build_multiple_arenas(1) -sim.set_manual_update(False) -""" - ## Method 1: Fine-grained configuration with `build_dexforce_w1_cfg` This method allows you to specify detailed parameters for each arm and hand. Recommended for advanced users who need full control over robot hardware options. @@ -46,7 +31,7 @@ This method allows you to specify detailed parameters for each arm and hand. Rec - `hand_types`: Dict specifying hand brand for each arm side (`LEFT`/`RIGHT`). - `hand_versions`: Dict specifying hand version for each arm side. -"""python +```python hand_types = { DexforceW1ArmSide.LEFT: DexforceW1HandBrand.BRAINCO_HAND, DexforceW1ArmSide.RIGHT: DexforceW1HandBrand.BRAINCO_HAND, @@ -62,7 +47,7 @@ cfg = build_dexforce_w1_cfg( ) robot = sim.add_robot(cfg=cfg) print("DexforceW1 robot added to the simulation.") -""" +``` ## Method 2: Quick configuration with `DexforceW1Cfg.from_dict` @@ -74,14 +59,14 @@ This method allows fast setup using a dictionary, suitable for simple scenarios - `version`: Robot version, e.g., `v021`. - `arm_kind`: Arm type, e.g., `anthropomorphic` or `industrial` (string). -"""python +```python from embodichain.lab.sim.robots import DexforceW1Cfg cfg = DexforceW1Cfg.from_dict( {"uid": "dexforce_w1", "version": "v021", "arm_kind": "anthropomorphic"} ) robot = sim.add_robot(cfg=cfg) print("DexforceW1 robot added to the simulation.") -""" +``` ## Arm Joint Design: Mirrored Configuration From e3f40ce422b8dcdeb148f26da603ae7f1e59f3da Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Fri, 28 Nov 2025 15:47:05 +0000 Subject: [PATCH 14/92] Misc update (#17) --- README.md | 20 +++--- docs/source/introduction.rst | 13 ++-- embodichain/data/dataset.py | 1 - .../envs/action_bank/configurable_action.py | 18 ++---- embodichain/lab/gym/envs/managers/events.py | 2 +- embodichain/lab/sim/cfg.py | 6 ++ embodichain/lab/sim/objects/articulation.py | 61 ++++++++++++++++++- embodichain/lab/sim/utility/sim_utils.py | 1 + tests/datasets/run_pourwater_env_offline.py | 4 +- 9 files changed, 93 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index cf45e5f2..41e0a197 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,13 @@ + # EmbodiChain ![teaser](assets/imgs/teaser.jpg) -**📘 [Documentation](https://6921c7e19027fbac6753678c--astounding-horse-770602.netlify.app/introduction)** + +[![Version](https://img.shields.io/badge/version-0.0.1-blue.svg)](https://github.com/DexForce/EmbodiChain/releases) +[![License](https://img.shields.io/github/license/DexForce/EmbodiChain)](LICENSE) +[![Docs](https://img.shields.io/badge/docs-online-blue)](https://6921c7e19027fbac6753678c--astounding-horse-770602.netlify.app/introduction) +[![Build Status](https://img.shields.io/github/actions/workflow/status/DexForce/EmbodiChain/ci.yml?branch=main)](https://github.com/DexForce/EmbodiChain/actions) + --- EmbodiChain is an end-to-end, GPU-accelerated framework for Embodied AI. It streamlines research and development by unifying high-performance simulation, real-to-sim data pipelines, modular model architectures, and efficient training workflows. This integration enables rapid experimentation, seamless deployment of intelligent agents, and effective Sim2Real transfer for real-world robotic systems. @@ -14,11 +20,11 @@ EmbodiChain is an end-to-end, GPU-accelerated framework for Embodied AI. It stre ## Key Features -- **High-Fidelity, GPU-Accelerated Simulation**: Combines realistic physics for both rigid and deformable objects with advanced ray-traced sensor modeling, all accelerated on the GPU for high-throughput batched simulations. -- **Unified Robot Learning Environment**: Offers standardized interfaces for a wide range of robot learning tasks, including Imitation Learning and Reinforcement Learning. -- **Scalable Data Pipeline**: Features a comprehensive toolkit for automated data collection, efficient processing, and large-scale data generation to fuel your models. -- **Efficient Training & Evaluation**: Supports modern training paradigms like online data streaming for Imitation Learning and massively parallel environment rollouts for Reinforcement Learning. -- **Modular and Extensible**: Designed with modularity in mind to easily integrate new robot platforms, environments, and learning algorithms. +- 🚀 **High-Fidelity GPU Simulation**: Realistic physics for rigid & deformable objects, advanced ray-traced sensors, all GPU-accelerated for high-throughput batch simulation. +- 🤖 **Unified Robot Learning Environment**: Standardized interfaces for Imitation Learning, Reinforcement Learning, and more. +- 📊 **Scalable Data Pipeline**: Automated data collection, efficient processing, and large-scale generation for model training. +- ⚡ **Efficient Training & Evaluation**: Online data streaming, parallel environment rollouts, and modern training paradigms. +- 🧩 **Modular & Extensible**: Easily integrate new robots, environments, and learning algorithms. ## Getting Started @@ -32,7 +38,7 @@ To get started with EmbodiChain, follow these steps: ## Citation -If you use EmbodiChain in your research, please cite our work: +If you use EmbodiChain in your research, please cite: ```bibtex @misc{EmbodiChain, diff --git a/docs/source/introduction.rst b/docs/source/introduction.rst index f82c0afc..2c974cd7 100644 --- a/docs/source/introduction.rst +++ b/docs/source/introduction.rst @@ -25,12 +25,11 @@ EmbodiChain is an end-to-end, GPU-accelerated framework for Embodied AI. It stre Key Features ------------ -* **High-Fidelity, GPU-Accelerated Simulation**: Combines realistic physics for both rigid and deformable objects with advanced ray-traced sensor modeling, all accelerated on the GPU for high-throughput batched simulations. -* **Unified Robot Learning Environment**: Offers standardized interfaces for a wide range of robot learning tasks, including Imitation Learning and Reinforcement Learning. -* **Scalable Data Pipeline**: Features a comprehensive toolkit for automated data collection, efficient processing, and large-scale data generation to fuel your models. -* **Efficient Training & Evaluation**: Supports modern training paradigms like online data streaming for Imitation Learning and massively parallel environment rollouts for Reinforcement Learning. -* **Modular and Extensible**: Designed with modularity in mind to easily integrate new robot platforms, environments, and learning algorithms. - +* 🚀 **High-Fidelity GPU Simulation**: Realistic physics for rigid & deformable objects, advanced ray-traced sensors, all GPU-accelerated for high-throughput batch simulation. +* 🤖 **Unified Robot Learning Environment**: Standardized interfaces for Imitation Learning, Reinforcement Learning, and more. +* 📊 **Scalable Data Pipeline**: Automated data collection, efficient processing, and large-scale generation for model training. +* ⚡ **Efficient Training & Evaluation**: Online data streaming, parallel environment rollouts, and modern training paradigms. +* 🧩 **Modular & Extensible**: Easily integrate new robots, environments, and learning algorithms. Getting Started --------------- @@ -45,7 +44,7 @@ To get started with EmbodiChain, follow these steps: Citation -------- -If you use EmbodiChain in your research, please cite our work: +If you use EmbodiChain in your research, please cite: .. code-block:: bibtex diff --git a/embodichain/data/dataset.py b/embodichain/data/dataset.py index f5c775fd..02dc698c 100644 --- a/embodichain/data/dataset.py +++ b/embodichain/data/dataset.py @@ -20,7 +20,6 @@ import hashlib import open3d as o3d - from embodichain.utils import logger diff --git a/embodichain/lab/gym/envs/action_bank/configurable_action.py b/embodichain/lab/gym/envs/action_bank/configurable_action.py index 20f16d1f..2631cd02 100644 --- a/embodichain/lab/gym/envs/action_bank/configurable_action.py +++ b/embodichain/lab/gym/envs/action_bank/configurable_action.py @@ -65,7 +65,6 @@ class ActionBank: _function_type: Dict[str, Callable] def __init__(self, conf: Dict): - # 轨迹可以是qpos或者xpos,不同方法检查一下shape,每个姿态qpos是1维(16维),xpos是2维(4x4的矩阵) self.conf = conf @property @@ -1261,9 +1260,7 @@ def plan_trajectory( vis: bool = False, **kwargs, ) -> np.ndarray: - from embodichain.lab.gym.motion_generation.action.arm_action import ( - ArmAction, - ) + from embodichain.lab.sim.planners.motion_generator import MotionGenerator # Retrieve the start and end positions start_qpos = env.affordance_datas[keypose_names[0]] @@ -1311,14 +1308,13 @@ def plan_trajectory( filtered_keyposes = [start_qpos] if len(filtered_keyposes) == 1 and len(ref_poses) == 0: - # 只有一个点,返回静止轨迹 + ret = np.array([filtered_keyposes[0]] * duration) else: - # 生成轨迹 + mo_gen = MotionGenerator(robot=env.robot, uid=agent_uid) + if len(ref_poses) == 0: - ret, _ = ArmAction.create_discrete_trajectory( - agent=env.robot, - uid=get_control_part(env, agent_uid), + ret, _ = mo_gen.create_discrete_trajectory( qpos_list=filtered_keyposes, sample_num=duration, qpos_seed=filtered_keyposes[0], @@ -1326,9 +1322,7 @@ def plan_trajectory( **getattr(env, "planning_config", {}), ) else: - ret, _ = ArmAction.create_discrete_trajectory( - agent=env.robot, - uid=get_control_part(env, agent_uid), + ret, _ = mo_gen.create_discrete_trajectory( xpos_list=[start_xpos] + ref_poses + [end_xpos], sample_num=duration, is_use_current_qpos=False, diff --git a/embodichain/lab/gym/envs/managers/events.py b/embodichain/lab/gym/envs/managers/events.py index c6653ba1..041b9faa 100644 --- a/embodichain/lab/gym/envs/managers/events.py +++ b/embodichain/lab/gym/envs/managers/events.py @@ -457,7 +457,7 @@ def register_info_to_env( "Calling env.sim.update(100) for after-physics-applied object attributes..", color="green", ) - env.sim.update(100) + env.sim.update(step=100) for entity_registry in registry: entity_cfg = SceneEntityCfg(**entity_registry["entity_cfg"]) logger.log_info(f"Registering {entity_cfg.uid}..", color="green") diff --git a/embodichain/lab/sim/cfg.py b/embodichain/lab/sim/cfg.py index d6825853..3dc37e1b 100644 --- a/embodichain/lab/sim/cfg.py +++ b/embodichain/lab/sim/cfg.py @@ -918,6 +918,9 @@ class ArticulationCfg(ObjectBaseCfg): drive_pros: JointDrivePropertiesCfg = JointDrivePropertiesCfg() """Properties to define the drive mechanism of a joint.""" + body_scale: Union[tuple, list] = (1.0, 1.0, 1.0) + """Scale of the articulation in the simulation world frame.""" + attrs: RigidBodyAttributesCfg = RigidBodyAttributesCfg() """Physical attributes for all links . """ @@ -947,6 +950,9 @@ class ArticulationCfg(ObjectBaseCfg): min_velocity_iters: int = 1 """Number of velocity iterations the solver should perform for this articulation. Range: [0,255].""" + build_pk_chain: bool = True + """Whether to build pytorch-kinematics chain for forward kinematics and jacobian computation.""" + @configclass class RobotCfg(ArticulationCfg): diff --git a/embodichain/lab/sim/objects/articulation.py b/embodichain/lab/sim/objects/articulation.py index c9f56090..7698fc11 100644 --- a/embodichain/lab/sim/objects/articulation.py +++ b/embodichain/lab/sim/objects/articulation.py @@ -20,7 +20,7 @@ from dataclasses import dataclass from functools import cached_property -from typing import List, Sequence, Optional, Dict, Union +from typing import List, Sequence, Optional, Dict, Union, Tuple from dexsim.engine import Articulation as _Articulation from dexsim.types import ( @@ -456,6 +456,26 @@ def qf_limits(self) -> torch.Tensor: device=self.device, ) + @cached_property + def link_vert_face(self) -> Dict[str, Tuple[torch.Tensor, torch.Tensor]]: + """Get the vertices and faces of all links in the articulation. + + Returns: + Dict[str, Tuple[torch.Tensor, torch.Tensor]]: + - key (str): The name of the link. + - vertices (torch.Tensor): The vertices of the specified link with shape (V, 3). + - faces (torch.Tensor): The faces of the specified link with shape (F, 3). + """ + link_vert_face = dict() + for link_name in self.link_names: + verts, faces = self.entities[0].get_link_vert_face(link_name) + vertices_tensor = torch.as_tensor( + verts, dtype=torch.float32, device=self.device + ) + faces_tensor = torch.as_tensor(faces, dtype=torch.int32, device=self.device) + link_vert_face[link_name] = (vertices_tensor, faces_tensor) + return link_vert_face + class Articulation(BatchEntity): """Articulation represents a batch of articulations in the simulation. @@ -536,7 +556,11 @@ def __init__( ) self._set_default_joint_drive() - self.pk_chain = create_pk_chain(urdf_path=self.cfg.fpath, device=self.device) + self.pk_chain = None + if self.cfg.build_pk_chain: + self.pk_chain = create_pk_chain( + urdf_path=self.cfg.fpath, device=self.device + ) # For rendering purposes, each articulation can have multiple material instances associated with its links. self._visual_material: List[Dict[str, VisualMaterialInst]] = [ @@ -804,6 +828,25 @@ def get_local_pose(self, to_matrix=False) -> torch.Tensor: pose[:, :3, :3] = mat return pose + def get_link_vert_face(self, link_name: str) -> Tuple[torch.Tensor, torch.Tensor]: + """Get the vertices and faces of a specific link in the articulation. + + Args: + link_name (str): The name of the link. + + Returns: + Tuple[torch.Tensor, torch.Tensor]: + - vertices (torch.Tensor): The vertices of the specified link with shape (V, 3). + - faces (torch.Tensor): The faces of the specified link with shape (F, 3). + """ + if link_name not in self.link_names: + logger.log_error( + f"Link name {link_name} not found in {self.__class__.__name__}. Available links: {self.link_names}" + ) + + verts, faces = self.body_data.link_vert_face[link_name] + return verts, faces + def get_link_pose( self, link_name: str, env_ids: Optional[Sequence[int]] = None, to_matrix=False ) -> torch.Tensor: @@ -1280,12 +1323,19 @@ def compute_fk( to_dict (bool, optional): If True, returns the FK result as a dictionary of Transform3d objects. Defaults to False. **kwargs: Additional keyword arguments for customization. + Raises: + RuntimeError: If the pk_chain is not initialized. + TypeError: If an invalid type is provided for `link_names`. + ValueError: If the shape of the resulting matrices is unexpected. + Returns: torch.Tensor: The homogeneous transformation matrix/matrices for the specified links. Shape is (batch_size, 4, 4) for batched input or (4, 4) for single input. If `to_dict` is True, returns a dictionary of Transform3d objects instead. """ frame_indices = None + if self.pk_chain is None: + logger.log_error("pk_chain is not initialized for this articulation.") # Adapt link_names to work with get_frame_indices if link_names is not None: @@ -1381,12 +1431,19 @@ def compute_jacobian( - 'rot': Returns only the rotational part (3, dof) or (batch_size, 3, dof). Defaults to 'full'. + Raises: + RuntimeError: If the pk_chain is not initialized. + ValueError: If an invalid `jac_type` is provided. + Returns: torch.Tensor: The Jacobian matrix. Shape depends on the input: - For a single link: (6, dof) or (batch_size, 6, dof). - For multiple links: (num_links, 6, dof) or (num_links, batch_size, 6, dof). The shape also depends on the `jac_type` parameter. """ + if self.pk_chain is None: + logger.log_error("pk_chain is not initialized for this articulation.") + if qpos is None: qpos = torch.zeros(self.dof, device=self.device) diff --git a/embodichain/lab/sim/utility/sim_utils.py b/embodichain/lab/sim/utility/sim_utils.py index 256fa299..c6914807 100644 --- a/embodichain/lab/sim/utility/sim_utils.py +++ b/embodichain/lab/sim/utility/sim_utils.py @@ -101,6 +101,7 @@ def get_drive_type(drive_pros): logger.log_error(f"Unknow drive type {drive_type}") for art in arts: + art.set_body_scale(cfg.body_scale) art.set_physical_attr(cfg.attrs.attr()) art.set_articulation_flag(ArticulationFlag.FIX_BASE, cfg.fix_base) art.set_articulation_flag( diff --git a/tests/datasets/run_pourwater_env_offline.py b/tests/datasets/run_pourwater_env_offline.py index 80da0d4e..548b0165 100644 --- a/tests/datasets/run_pourwater_env_offline.py +++ b/tests/datasets/run_pourwater_env_offline.py @@ -32,10 +32,8 @@ from embodichain.lab.gym.envs import EmbodiedEnvCfg from embodichain.lab.gym.utils.gym_utils import config_to_cfg -os.environ["HDF5_USE_FILE_LOCKING"] = "FALSE" - -class TestPourWaterv3OfflineRunEnv(unittest.TestCase, metaclass=UnittestMetaclass): +class TestPourWaterOfflineRunEnv(unittest.TestCase, metaclass=UnittestMetaclass): datacenter_backup = Path("/tmp/datacenter_test") def setUp(self) -> None: From 8bf13c41e8fa219b04336282895fa59bd2adb3db Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Mon, 1 Dec 2025 14:20:16 +0000 Subject: [PATCH 15/92] Upgrade dependencies version (#24) --- .gitignore | 25 ----- embodichain/__init__.py | 1 + .../envs/action_bank/configurable_action.py | 12 +- .../lab/gym/envs/managers/observations.py | 8 +- embodichain/lab/gym/utils/misc.py | 1 + embodichain/lab/gym/utils/registration.py | 26 +++-- embodichain/lab/sim/objects/soft_object.py | 18 +-- .../lab/sim/planners/motion_generator.py | 13 ++- embodichain/lab/sim/planners/utils.py | 1 + .../lab/sim/robots/dexforce_w1/params.py | 18 +-- .../lab/sim/solvers/pinocchio_solver.py | 6 +- embodichain/lab/sim/solvers/srs_solver.py | 4 +- .../toolkits/graspkit/pg_grasp/antipodal.py | 18 +-- .../toolkits/urdf_assembly/component.py | 6 +- embodichain/toolkits/urdf_assembly/sensor.py | 6 +- .../toolkits/urdf_assembly/signature.py | 8 +- .../urdf_assembly/urdf_assembly_manager.py | 1 + embodichain/utils/math.py | 43 +------ embodichain/utils/visualizer.py | 7 +- pyproject.toml | 31 ++---- tests/common.py | 1 + tests/datasets/run_pourwater_env_offline.py | 105 ------------------ .../action_bank}/test_configurable_action.py | 2 +- tests/gym/envs/test_base_env.py | 4 + tests/gym/envs/test_embodied_env.py | 4 + tests/sim/objects/test_robot.py | 1 + tests/unitest.sh | 93 ---------------- 27 files changed, 107 insertions(+), 356 deletions(-) delete mode 100644 tests/datasets/run_pourwater_env_offline.py rename tests/{datasets => gym/action_bank}/test_configurable_action.py (99%) delete mode 100755 tests/unitest.sh diff --git a/.gitignore b/.gitignore index 4857c898..dc87025b 100644 --- a/.gitignore +++ b/.gitignore @@ -176,8 +176,6 @@ cache *.csv materials -!embodichain/agents/dexforce_vla/data/empty_lang_embed.pt -!resources/Arch.png embodichain/toolkits/outputs/* embodichain/toolkits/outputs/* @@ -185,38 +183,15 @@ embodichain/database/* 3rdparty/ Log/ -embodichain/deploy/h1/sim/unitree_h1 -embodichain/deploy/inspire/inspire_hand -embodichain/devices/camera/king_fisher/kingfisher # tensorboard logs embodichain/agents/policy/runs/* -embodichain/agents/dexrdt/wandb *.pth outputs test_configs/* wandb/ -embodichain/deploy/mobile_aloha/collect_data/data *.mp4 # vscode settings .vscode/ - -# web server backend -*/backend/datas/ -*/backend/logs/ -*/backend/__pycache__/ - -# web server frontend -*/backend/export_datas/ -*/backend/**/__pycache__/ - -# web server frontend -!web_server/frontend/**/* -!web_server/frontend/**/event* -*/frontend/node_modules -*/frontend/.DS_Store -*/frontend/*.local -*/frontend/.eslintcache -*/frontend/.stylelintcache diff --git a/embodichain/__init__.py b/embodichain/__init__.py index 1b3998b6..f818cf7b 100644 --- a/embodichain/__init__.py +++ b/embodichain/__init__.py @@ -18,6 +18,7 @@ embodichain_dir = os.path.dirname(__file__) + # Read version from VERSION file def _get_version(): version_file = os.path.join(os.path.dirname(embodichain_dir), "VERSION") diff --git a/embodichain/lab/gym/envs/action_bank/configurable_action.py b/embodichain/lab/gym/envs/action_bank/configurable_action.py index 2631cd02..97a73da0 100644 --- a/embodichain/lab/gym/envs/action_bank/configurable_action.py +++ b/embodichain/lab/gym/envs/action_bank/configurable_action.py @@ -1400,12 +1400,12 @@ def mimic(self, id=None) -> ActionBank: temp_graph2id = action_bank_mimic_for_this_node.graph2id() if node in mimic_node_names[scope]: - ret_acb.conf["node"][scope][ret_node_grap2id[scope][node]][ - node - ] = deepcopy( - action_bank_mimic_for_this_node.conf["node"][scope][ - temp_graph2id[scope][node] - ][node] + ret_acb.conf["node"][scope][ret_node_grap2id[scope][node]][node] = ( + deepcopy( + action_bank_mimic_for_this_node.conf["node"][scope][ + temp_graph2id[scope][node] + ][node] + ) ) edges = ret_acb.get_edge_names(node_name=node) diff --git a/embodichain/lab/gym/envs/managers/observations.py b/embodichain/lab/gym/envs/managers/observations.py index c628384c..86280c60 100644 --- a/embodichain/lab/gym/envs/managers/observations.py +++ b/embodichain/lab/gym/envs/managers/observations.py @@ -135,9 +135,11 @@ def compute_semantic_mask( # cat assets uid (num_envs, n) into dim 1 foreground_uids = torch.cat( [ - asset.get_user_ids().unsqueeze(1) - if asset.get_user_ids().dim() == 1 - else asset.get_user_ids() + ( + asset.get_user_ids().unsqueeze(1) + if asset.get_user_ids().dim() == 1 + else asset.get_user_ids() + ) for asset in foreground_assets ], dim=1, diff --git a/embodichain/lab/gym/utils/misc.py b/embodichain/lab/gym/utils/misc.py index 0f9cc5ee..b95e0ce5 100644 --- a/embodichain/lab/gym/utils/misc.py +++ b/embodichain/lab/gym/utils/misc.py @@ -797,6 +797,7 @@ def resolve_formatted_string(obj, local_vars=None, global_vars=None): {"__builtins__": None}, # eval with given locals & globals {**global_vars, **local_vars}, ) + # par tof the string is ${expr}:replace ...${expr}.. -> str(...eval(expr)..) def _sub(m): return str( diff --git a/embodichain/lab/gym/utils/registration.py b/embodichain/lab/gym/utils/registration.py index a3e9c61f..b2fe5b62 100644 --- a/embodichain/lab/gym/utils/registration.py +++ b/embodichain/lab/gym/utils/registration.py @@ -189,16 +189,20 @@ def register_env_function(cls, uid, override=False, max_episode_steps=None, **kw max_episode_steps=max_episode_steps, disable_env_checker=True, # Temporary solution as we allow empty observation spaces kwargs=deepcopy(kwargs), - additional_wrappers=[ - WrapperSpec( - "MSTimeLimit", - entry_point="embodichain.lab.gym.utils.registration:TimeLimitWrapper", - kwargs=dict(max_episode_steps=max_episode_steps) - if max_episode_steps is not None - else {}, - ) - ] - if max_episode_steps is not None - else [], + additional_wrappers=( + [ + WrapperSpec( + "MSTimeLimit", + entry_point="embodichain.lab.gym.utils.registration:TimeLimitWrapper", + kwargs=( + dict(max_episode_steps=max_episode_steps) + if max_episode_steps is not None + else {} + ), + ) + ] + if max_episode_steps is not None + else [] + ), ) return cls diff --git a/embodichain/lab/sim/objects/soft_object.py b/embodichain/lab/sim/objects/soft_object.py index fcbf1c95..84617d1c 100644 --- a/embodichain/lab/sim/objects/soft_object.py +++ b/embodichain/lab/sim/objects/soft_object.py @@ -85,9 +85,9 @@ def __init__( ) for i, softbody in enumerate(softbodies): - self._rest_sim_position_buffer[ - i - ] = softbody.get_sim_position_inv_mass_buffer() + self._rest_sim_position_buffer[i] = ( + softbody.get_sim_position_inv_mass_buffer() + ) self._collision_position_buffer = torch.zeros( (self.num_instances, self.n_collision_vertices, 4), @@ -139,18 +139,18 @@ def collision_position_buffer(self): def sim_vertex_position_buffer(self): """Get the current sim vertex position buffer of the soft bodies.""" for i, softbody in enumerate(self.soft_bodies): - self._sim_vertex_position_buffer[ - i - ] = softbody.get_sim_position_inv_mass_buffer() + self._sim_vertex_position_buffer[i] = ( + softbody.get_sim_position_inv_mass_buffer() + ) return self._sim_vertex_position_buffer.clone() @property def sim_vertex_velocity_buffer(self): """Get the current vertex velocity buffer of the soft bodies.""" for i, softbody in enumerate(self.soft_bodies): - self._sim_vertex_velocity_buffer[ - i - ] = softbody.get_sim_position_inv_mass_buffer() + self._sim_vertex_velocity_buffer[i] = ( + softbody.get_sim_position_inv_mass_buffer() + ) return self._sim_vertex_velocity_buffer.clone() diff --git a/embodichain/lab/sim/planners/motion_generator.py b/embodichain/lab/sim/planners/motion_generator.py index 165844f7..72248314 100644 --- a/embodichain/lab/sim/planners/motion_generator.py +++ b/embodichain/lab/sim/planners/motion_generator.py @@ -28,6 +28,7 @@ class PlannerType(Enum): r"""Enumeration for different planner types.""" + TOPPRA = "toppra" """TOPPRA planner for time-optimal trajectory planning.""" @@ -188,12 +189,12 @@ def _create_state_dict( position = position.squeeze() return { - "position": position.tolist() - if isinstance(position, np.ndarray) - else position, - "velocity": velocity.tolist() - if isinstance(velocity, np.ndarray) - else velocity, + "position": ( + position.tolist() if isinstance(position, np.ndarray) else position + ), + "velocity": ( + velocity.tolist() if isinstance(velocity, np.ndarray) else velocity + ), "acceleration": [0.0] * self.dof, } diff --git a/embodichain/lab/sim/planners/utils.py b/embodichain/lab/sim/planners/utils.py index 154e8529..6f62841e 100644 --- a/embodichain/lab/sim/planners/utils.py +++ b/embodichain/lab/sim/planners/utils.py @@ -25,6 +25,7 @@ class TrajectorySampleMethod(Enum): This enum defines various methods for sampling trajectories, providing meaningful names for different sampling strategies. """ + TIME = "time" """Sample based on time intervals.""" diff --git a/embodichain/lab/sim/robots/dexforce_w1/params.py b/embodichain/lab/sim/robots/dexforce_w1/params.py index 6dfdf349..6082daed 100644 --- a/embodichain/lab/sim/robots/dexforce_w1/params.py +++ b/embodichain/lab/sim/robots/dexforce_w1/params.py @@ -228,14 +228,16 @@ def from_dict(cls, data: dict) -> "W1ArmKineParams": inst, "dh_params", np.array(data["dh_params"], dtype=float) ) if "qpos_limits" in data: - object.__setattr__( - inst, - "qpos_limits", - np.deg2rad(np.array(data["qpos_limits"], dtype=float)), - ) if np.max( - np.abs(np.array(data["qpos_limits"])) - ) > 2 * np.pi else object.__setattr__( - inst, "qpos_limits", np.array(data["qpos_limits"], dtype=float) + ( + object.__setattr__( + inst, + "qpos_limits", + np.deg2rad(np.array(data["qpos_limits"], dtype=float)), + ) + if np.max(np.abs(np.array(data["qpos_limits"]))) > 2 * np.pi + else object.__setattr__( + inst, "qpos_limits", np.array(data["qpos_limits"], dtype=float) + ) ) if "link_lengths" in data: object.__setattr__( diff --git a/embodichain/lab/sim/solvers/pinocchio_solver.py b/embodichain/lab/sim/solvers/pinocchio_solver.py index 719fabbe..5e5167f2 100644 --- a/embodichain/lab/sim/solvers/pinocchio_solver.py +++ b/embodichain/lab/sim/solvers/pinocchio_solver.py @@ -463,9 +463,9 @@ def get_ik( # Fix the rotation part of the pose fixed_pose = np.eye(4) fixed_pose[:3, :3] = compute_xpos[:3, :3] # Use target rotation - fixed_pose[ - :3, 3 - ] = current_pose_se3.translation.T # Use current position + fixed_pose[:3, 3] = ( + current_pose_se3.translation.T + ) # Use current position fixed_pose_SE3 = self.pin.SE3(fixed_pose) current_pose_se3 = self.pin.SE3(fixed_pose_SE3) diff --git a/embodichain/lab/sim/solvers/srs_solver.py b/embodichain/lab/sim/solvers/srs_solver.py index 44fa894f..56c979ae 100644 --- a/embodichain/lab/sim/solvers/srs_solver.py +++ b/embodichain/lab/sim/solvers/srs_solver.py @@ -236,9 +236,7 @@ def _calculate_arm_joint_angles( joints[0] = 0 euclidean_norm = np.hypot(P26[0], P26[1]) - angle_phi = np.arccos( - (d_se**2 + norm_P26**2 - d_ew**2) / (2 * d_se * norm_P26) - ) + angle_phi = np.arccos((d_se**2 + norm_P26**2 - d_ew**2) / (2 * d_se * norm_P26)) joints[1] = np.arctan2(euclidean_norm, P26[2]) + elbow_config * angle_phi return True diff --git a/embodichain/toolkits/graspkit/pg_grasp/antipodal.py b/embodichain/toolkits/graspkit/pg_grasp/antipodal.py index 56239749..5ccf5152 100644 --- a/embodichain/toolkits/graspkit/pg_grasp/antipodal.py +++ b/embodichain/toolkits/graspkit/pg_grasp/antipodal.py @@ -483,15 +483,15 @@ def _sample_grasp_pose( shape=(antipodal_sample_num * antipodal_num,), dtype=float ) for i in range(antipodal_num): - grasp_poses[ - i * antipodal_sample_num : (i + 1) * antipodal_sample_num - ] = antipodal_list[i].sample_pose(antipodal_sample_num) - scores[ - i * antipodal_sample_num : (i + 1) * antipodal_sample_num - ] = antipodal_list[i].score - open_length[ - i * antipodal_sample_num : (i + 1) * antipodal_sample_num - ] = antipodal_list[i].dis + grasp_poses[i * antipodal_sample_num : (i + 1) * antipodal_sample_num] = ( + antipodal_list[i].sample_pose(antipodal_sample_num) + ) + scores[i * antipodal_sample_num : (i + 1) * antipodal_sample_num] = ( + antipodal_list[i].score + ) + open_length[i * antipodal_sample_num : (i + 1) * antipodal_sample_num] = ( + antipodal_list[i].dis + ) return grasp_poses, scores, open_length def get_all_grasp(self) -> List[AntipodalGrasp]: diff --git a/embodichain/toolkits/urdf_assembly/component.py b/embodichain/toolkits/urdf_assembly/component.py index 603225a3..9b98f67b 100644 --- a/embodichain/toolkits/urdf_assembly/component.py +++ b/embodichain/toolkits/urdf_assembly/component.py @@ -64,9 +64,9 @@ class URDFComponent: "base_link" # Default link name for attachment (usually the first link) ) params: Dict = None # Component-specific parameters (e.g., wheel_type for chassis) - transform: Optional[ - np.ndarray - ] = None # Optional 4x4 transformation matrix for positioning + transform: Optional[np.ndarray] = ( + None # Optional 4x4 transformation matrix for positioning + ) def __post_init__(self): # Convert path to Path object for better path handling diff --git a/embodichain/toolkits/urdf_assembly/sensor.py b/embodichain/toolkits/urdf_assembly/sensor.py index 6cf87829..5bf30710 100644 --- a/embodichain/toolkits/urdf_assembly/sensor.py +++ b/embodichain/toolkits/urdf_assembly/sensor.py @@ -64,9 +64,9 @@ class SensorAttachment: sensor_urdf: str # Path to the sensor's URDF file parent_component: str # Name of the component to which the sensor is attached parent_link: str # Specific link name within the parent component for attachment - transform: Optional[ - np.ndarray - ] = None # Optional 4x4 transformation matrix for sensor positioning + transform: Optional[np.ndarray] = ( + None # Optional 4x4 transformation matrix for sensor positioning + ) sensor_type: Optional[str] = None # Optional sensor type field diff --git a/embodichain/toolkits/urdf_assembly/signature.py b/embodichain/toolkits/urdf_assembly/signature.py index d0b5de9e..3ec627c1 100644 --- a/embodichain/toolkits/urdf_assembly/signature.py +++ b/embodichain/toolkits/urdf_assembly/signature.py @@ -101,9 +101,11 @@ def to_serializable(obj): "urdf_path": str(comp_obj.urdf_path), "file_md5": file_md5, "params": to_serializable(comp_obj.params or {}), - "transform": comp_obj.transform.tolist() - if comp_obj.transform is not None - else None, + "transform": ( + comp_obj.transform.tolist() + if comp_obj.transform is not None + else None + ), } signature_data["components"][comp_type] = comp_data diff --git a/embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py b/embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py index 80bcd90f..81b356c3 100644 --- a/embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py +++ b/embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py @@ -78,6 +78,7 @@ class URDFAssemblyManager: r""" A class to manage the assembly of URDF files and their components. """ + # Supported wheel types for chassis components SUPPORTED_WHEEL_TYPES = [ "omni", diff --git a/embodichain/utils/math.py b/embodichain/utils/math.py index c42f4374..4146a6a1 100644 --- a/embodichain/utils/math.py +++ b/embodichain/utils/math.py @@ -869,45 +869,6 @@ def quat_apply_yaw(quat: torch.Tensor, vec: torch.Tensor) -> torch.Tensor: return quat_apply(quat_yaw, vec) -def quat_rotate(q: torch.Tensor, v: torch.Tensor) -> torch.Tensor: - """Rotate a vector by a quaternion along the last dimension of q and v. - .. deprecated v2.1.0: - This function will be removed in a future release in favor of the faster implementation :meth:`quat_apply`. - - Args: - q: The quaternion in (w, x, y, z). Shape is (..., 4). - v: The vector in (x, y, z). Shape is (..., 3). - - Returns: - The rotated vector in (x, y, z). Shape is (..., 3). - """ - # deprecation - omni.log.warn( - "The function 'quat_rotate' will be deprecated in favor of the faster method 'quat_apply'." - " Please use 'quat_apply' instead...." - ) - return quat_apply(q, v) - - -def quat_rotate_inverse(q: torch.Tensor, v: torch.Tensor) -> torch.Tensor: - """Rotate a vector by the inverse of a quaternion along the last dimension of q and v. - - .. deprecated v2.1.0: - This function will be removed in a future release in favor of the faster implementation :meth:`quat_apply_inverse`. - Args: - q: The quaternion in (w, x, y, z). Shape is (..., 4). - v: The vector in (x, y, z). Shape is (..., 3). - - Returns: - The rotated vector in (x, y, z). Shape is (..., 3). - """ - omni.log.warn( - "The function 'quat_rotate_inverse' will be deprecated in favor of the faster method 'quat_apply_inverse'." - " Please use 'quat_apply_inverse' instead...." - ) - return quat_apply_inverse(q, v) - - @torch.jit.script def quat_error_magnitude(q1: torch.Tensor, q2: torch.Tensor) -> torch.Tensor: """Computes the rotation difference between two quaternions. @@ -1052,8 +1013,8 @@ def rigid_body_twist_transform( - The transformed linear velocity in frame 1. Shape is (N, 3). - The transformed angular velocity in frame 1. Shape is (N, 3). """ - w1 = quat_rotate_inverse(q01, w0) - v1 = quat_rotate_inverse(q01, v0 + torch.cross(w0, t01, dim=-1)) + w1 = quat_apply_inverse(q01, w0) + v1 = quat_apply_inverse(q01, v0 + torch.cross(w0, t01, dim=-1)) return v1, w1 diff --git a/embodichain/utils/visualizer.py b/embodichain/utils/visualizer.py index 0b24a362..6ce28932 100644 --- a/embodichain/utils/visualizer.py +++ b/embodichain/utils/visualizer.py @@ -541,7 +541,12 @@ def visualize_trajectory(poses: np.ndarray): # positions of the trajectory positions = poses[:, :3, 3] ax.plot( - positions[:, 0], positions[:, 1], positions[:, 2], "r-", linewidth=3, label="轨迹" + positions[:, 0], + positions[:, 1], + positions[:, 2], + "r-", + linewidth=3, + label="轨迹", ) # direction of z-axis diff --git a/pyproject.toml b/pyproject.toml index 109b0baa..77f568cf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,44 +28,29 @@ requires-python = ">=3.9" # specified using PEP 508 direct references where present. dependencies = [ "dexsim_engine @ http://pyp.open3dv.site:2345/packages/dexsim_engine-0.3.6-cp310-cp310-manylinux_2_31_x86_64.whl", - "setuptools==69.5.1", + "setuptools>=78.1.1", "gymnasium==0.29.1", - "langchain==0.2.14", - "langchain-openai==0.1.22", - "pillow==9.5.0", - "ffmpeg-python==0.2.0", - "pytransform3d", - "uvicorn", - "fastapi", "casadi==3.7.1", "pin==2.7.0", "toppra==0.6.3", "qpsolvers==4.8.1", "pin-pink==3.4.0", + "py_opw_kinematics==0.1.6", + "pytorch_kinematics==0.7.5", + "polars==1.31.0", "PyYAML>=6.0", - "transformers==4.48.0", - "diffusers==0.32.1", - "balanced-loss", "accelerate==1.2.1", "wandb==0.20.1", "tensorboard", - "pydantic==2.7.1", - "deepspeed==0.16.2", - "py_opw_kinematics==0.1.6", - "pytorch_kinematics==0.7.5", - "polars==1.31.0", + "transformers>=4.53.0", + "diffusers>=0.32.1", + "deepspeed>=0.16.2", "cvxpy==1.4.0", "ortools", "prettytable", - "transforms3d==0.4.2", "hdfdict@git+http://69.235.177.182:8081/externalrepo/hdfdict", - "OmegaConf", - "dill", - "black==22.3", - "aenum", + "black==24.3.0", "h5py", - "dacite==1.9.2", - "zmq", ] [tool.setuptools.packages.find] diff --git a/tests/common.py b/tests/common.py index 9d80e5c6..54f2d67a 100644 --- a/tests/common.py +++ b/tests/common.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ---------------------------------------------------------------------------- + from unittest import TestLoader from fnmatch import fnmatchcase diff --git a/tests/datasets/run_pourwater_env_offline.py b/tests/datasets/run_pourwater_env_offline.py deleted file mode 100644 index 548b0165..00000000 --- a/tests/datasets/run_pourwater_env_offline.py +++ /dev/null @@ -1,105 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---------------------------------------------------------------------------- - -import unittest -import sys -from pathlib import Path - -sys.path.append(str(Path(__file__).parent.parent)) -from common import UnittestMetaclass, OrderedTestLoader - -import os -import tempfile -import gymnasium -from pathlib import Path - -from embodichain.utils.utility import dict2args -from embodichain.utils.utility import load_json -from embodichain.lab.sim import SimulationManagerCfg -from embodichain.lab.gym.envs import EmbodiedEnvCfg -from embodichain.lab.gym.utils.gym_utils import config_to_cfg - - -class TestPourWaterOfflineRunEnv(unittest.TestCase, metaclass=UnittestMetaclass): - datacenter_backup = Path("/tmp/datacenter_test") - - def setUp(self) -> None: - pass - - def tearDown(self) -> None: - pass - - def test_offline_run_env(self): - from embodichain.lab.scripts.run_env import main - import os - - with tempfile.TemporaryDirectory(prefix=self.__class__.__name__) as temp_dir: - gym_conf_path = os.path.join( - "configs", - "gym", - "pour_water", - "gym_config.json", - ) - action_conf_path = os.path.join( - "configs", - "gym", - "pour_water", - "action_config.json", - ) - input_dict = { - "num_envs": 1, # TODO: change it to >1 as v3 supports it. but now CobotMagic use cpu-OPWSolver. Wait @Chenjian for gpu version. - "device": "cpu", # TODO: test both cpu and cuda device - "headless": True, - "enable_rt": False, - "gpu_id": 0, - "save_video": False, - "save_path": temp_dir, - "debug_mode": False, - "filter_visual_rand": False, - "online_config": "", - "gym_config": gym_conf_path, - "action_config": action_conf_path, - } - args = dict2args(input_dict) - gym_config = load_json(args.gym_config) - gym_config["env"]["dataset"]["save_path"] = temp_dir - gym_config["max_episodes"] = 1 - - cfg: EmbodiedEnvCfg = config_to_cfg(gym_config) - cfg.filter_visual_rand = args.filter_visual_rand - - action_config = {} - if args.action_config is not None: - action_config = load_json(args.action_config) - action_config["action_config"] = action_config - - cfg.num_envs = args.num_envs - cfg.sim_cfg = SimulationManagerCfg( - headless=args.headless, - sim_device=args.device, - enable_rt=args.enable_rt, - gpu_id=args.gpu_id, - ) - - env = gymnasium.make(id=gym_config["id"], cfg=cfg, **action_config) - main(args, env, gym_config) - - -if __name__ == "__main__": - # `unittest.main()` is the standard usage to start testing, here we use a customed - # TestLoader to keep executing order of functions the same as their writing order - - unittest.main(testLoader=OrderedTestLoader()) diff --git a/tests/datasets/test_configurable_action.py b/tests/gym/action_bank/test_configurable_action.py similarity index 99% rename from tests/datasets/test_configurable_action.py rename to tests/gym/action_bank/test_configurable_action.py index 16593ca0..48656790 100644 --- a/tests/datasets/test_configurable_action.py +++ b/tests/gym/action_bank/test_configurable_action.py @@ -30,7 +30,7 @@ import sys from pathlib import Path -sys.path.append(str(Path(__file__).parent.parent)) +sys.path.append(str(Path(__file__).parent.parent.parent)) from common import UnittestMetaclass, OrderedTestLoader diff --git a/tests/gym/envs/test_base_env.py b/tests/gym/envs/test_base_env.py index beab6a89..4857b1bd 100644 --- a/tests/gym/envs/test_base_env.py +++ b/tests/gym/envs/test_base_env.py @@ -170,6 +170,10 @@ def test_env_rollout(self): ), "Expected 'cube_position' in the obs dict" assert obs.get("robot") is not None, "Expected 'robot' in the obs dict" + def teardown_method(self): + """Clean up resources after each test method.""" + self.env.close() + class TestBaseEnvCPU(BaseEnvTest): def setup_method(self): diff --git a/tests/gym/envs/test_embodied_env.py b/tests/gym/envs/test_embodied_env.py index feb4bc5b..075bdcda 100644 --- a/tests/gym/envs/test_embodied_env.py +++ b/tests/gym/envs/test_embodied_env.py @@ -151,6 +151,10 @@ def test_env_rollout(self): ), f"Expected truncated shape ({self.env.num_envs},), got {truncated.shape}" assert obs.get("robot") is not None, "Expected 'robot' info in the info dict" + def teardown_method(self): + """Clean up resources after each test method.""" + self.env.close() + class TestCPU(EmbodiedEnvTest): def setup_method(self): diff --git a/tests/sim/objects/test_robot.py b/tests/sim/objects/test_robot.py index 0177543f..282abed1 100644 --- a/tests/sim/objects/test_robot.py +++ b/tests/sim/objects/test_robot.py @@ -47,6 +47,7 @@ ], } + # Base test class for CPU and CUDA class BaseRobotTest: def setup_simulation(self, sim_device): diff --git a/tests/unitest.sh b/tests/unitest.sh deleted file mode 100755 index d827e1cb..00000000 --- a/tests/unitest.sh +++ /dev/null @@ -1,93 +0,0 @@ -echo "exec python ..." - -export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -log_info() { - echo -e "${BLUE}[INFO] $1${NC}" -} - -log_success() { - echo -e "${GREEN}[SUCCESS] $1${NC}" -} - -log_warn() { - echo -e "${YELLOW}[WARN] $1${NC}" -} - -log_error() { - echo -e "${RED}[ERROR] $1${NC}" -} - -run_python_script() { - local script_name="$1" - local script_path="$2" - - log_info "Running: ${script_name}" - - if python "$script_path"; then - log_success "${script_name} succeeded" - return 0 - else - log_error "${script_name} failed" - return 1 - fi -} - -run_pytest() { - local test_path="$1" - log_info "Running pytest: ${test_path}" - - local pytest_args=( - "--durations=1000" # record the slowest 1000 tests - "--tb=long" # long traceback - "-vv" # verbose - "--disable-warnings" # disable warnings - "--color=yes" # enable color output - ) - - pytest "${pytest_args[@]}" "$test_path" - local status=$? - - # Check if no tests were collected - if pytest --collect-only "$test_path" | grep -q "collected 0 items"; then - log_warn "No tests collected: ${test_path}" - return 0 - fi - - # Check pytest return code - if [ $status -ne 0 ]; then - log_error "pytest failed: ${test_path}" - exit 1 - fi -} - -main() { - echo "Starting scripts..." - - run_python_script "pourwater_offline_test" "tests/datasets/run_pourwater_env_offline.py" || exit 1 - - echo "Starting pytest unit tests..." - - for test_dir in tests/*/; do - # Check whether the directory contains any recursive test_*.py files; do not skip if top-level has none (supports subdirectory structures) - if ! find "$test_dir" -type f -name 'test_*.py' | grep -q .; then - log_warn "Skipping empty directory or no test files: ${test_dir}" - continue - fi - run_pytest "$test_dir" - done - - log_success "All test scripts and unit tests completed!" -} - -main "$@" - -# # demo -# ./demo/origin_demo.sh CI -# echo -e "\e[32morigin_demo executed successfully\e[0m" From 74a2324ef55c1d5e111f0331ca709d4beb55761d Mon Sep 17 00:00:00 2001 From: kerwan-zeng <501217100@qq.com> Date: Mon, 1 Dec 2025 23:10:01 +0800 Subject: [PATCH 16/92] NEW: init workflow file (#13) Co-authored-by: zengkehuan Co-authored-by: yuecideng --- .github/workflows/main.yml | 102 ++++++++++++++++++++++++++++ README.md | 9 ++- docs/source/introduction.rst | 8 +-- tests/gym/envs/test_embodied_env.py | 4 +- 4 files changed, 112 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..cc30ffa7 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,102 @@ +name: CI/CD Pipeline + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + lint: + if: github.event_name == 'pull_request' + runs-on: Linux + env: + NVIDIA_DRIVER_CAPABILITIES: all + NVIDIA_VISIBLE_DEVICES: all + NVIDIA_DISABLE_REQUIRE: 1 + container: &container_template + image: 192.168.3.13:5000/dexsdk:ubuntu22.04-cuda12.8.0-h5ffmpeg-v3 + volumes: + - "/cache:/cache" + - "/usr/share/vulkan/icd.d:/usr/share/vulkan/icd.d" + - "/usr/share/vulkan/implicit_layer.d:/usr/share/vulkan/implicit_layer.d" + - "/usr/share/glvnd/egl_vendor.d:/usr/share/glvnd/egl_vendor.d" + - "/tmp/.X11-unix:/tmp/.X11-unix" + - "/dev/shm/shared:/dev/shm/shared" + options: --memory 100g --gpus device=1 --shm-size 53687091200 + steps: + - uses: actions/checkout@v4 + - name: (CI) Code Style check + run: | + echo "Workspace: ${GITHUB_WORKSPACE}" + ls + pip install black==24.3.0 + black --check --diff --color ./ + if [ $? -ne 0 ]; then + echo "Code style check failed, please run [black ./] before commit!" + exit 1 + fi + + build: + needs: lint + runs-on: Linux + env: + NVIDIA_DRIVER_CAPABILITIES: all + NVIDIA_VISIBLE_DEVICES: all + NVIDIA_DISABLE_REQUIRE: 1 + container: *container_template + steps: + - uses: actions/checkout@v4 + - name: (CI) Build docs + run: | + pip install -e . + pip install -r docs/requirements.txt + cd ${GITHUB_WORKSPACE}/docs + echo "Start Building docs..." + make html + - name: Upload pkg + uses: actions/upload-pages-artifact@v3 + with: + path: ${{ github.workspace }}/docs/build/html + retention-days: 3 + + test: + if: github.event_name == 'pull_request' + needs: lint + runs-on: Linux + env: + NVIDIA_DRIVER_CAPABILITIES: all + NVIDIA_VISIBLE_DEVICES: all + NVIDIA_DISABLE_REQUIRE: 1 + container: *container_template + steps: + - uses: actions/checkout@v4 + - name: (CI) Run tests + run: | + # pip install -e . + echo "Unitest Start" + # export HF_ENDPOINT=https://hf-mirror.com + # pytest tests + + publish: + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + needs: build + runs-on: Linux + permissions: + pages: write + id-token: write + env: + NVIDIA_DRIVER_CAPABILITIES: all + NVIDIA_VISIBLE_DEVICES: all + NVIDIA_DISABLE_REQUIRE: 1 + container: *container_template + steps: + - uses: actions/checkout@v4 + - name: (CI) Publish package + run: echo "start publish stage" + - name: (CI) Download docs artifact + uses: actions/download-artifact@v4 + with: + name: github-pages + - name: (CI) Deploy GitHub Pages + uses: actions/deploy-pages@v4 \ No newline at end of file diff --git a/README.md b/README.md index 41e0a197..a72f0e77 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,7 @@ [![Version](https://img.shields.io/badge/version-0.0.1-blue.svg)](https://github.com/DexForce/EmbodiChain/releases) [![License](https://img.shields.io/github/license/DexForce/EmbodiChain)](LICENSE) -[![Docs](https://img.shields.io/badge/docs-online-blue)](https://6921c7e19027fbac6753678c--astounding-horse-770602.netlify.app/introduction) -[![Build Status](https://img.shields.io/github/actions/workflow/status/DexForce/EmbodiChain/ci.yml?branch=main)](https://github.com/DexForce/EmbodiChain/actions) +[![GitHub Pages](https://img.shields.io/badge/GitHub%20Pages-docs-blue?logo=github&logoColor=white)](https://dexforce.github.io/EmbodiChain/introduction.html) --- @@ -31,9 +30,9 @@ EmbodiChain is an end-to-end, GPU-accelerated framework for Embodied AI. It stre To get started with EmbodiChain, follow these steps: -- [Installation Guide](https://6921c7e19027fbac6753678c--astounding-horse-770602.netlify.app/quick_start/install) -- [Quick Start Tutorial](https://6921c7e19027fbac6753678c--astounding-horse-770602.netlify.app/tutorial/) -- [API Reference](https://6921c7e19027fbac6753678c--astounding-horse-770602.netlify.app/api_reference/) +- [Installation Guide](https://dexforce.github.io/EmbodiChain/quick_start/install.html) +- [Quick Start Tutorial](https://dexforce.github.io/EmbodiChain/tutorial/index.html) +- [API Reference](https://dexforce.github.io/EmbodiChain/api_reference/index.html) ## Citation diff --git a/docs/source/introduction.rst b/docs/source/introduction.rst index 2c974cd7..07807094 100644 --- a/docs/source/introduction.rst +++ b/docs/source/introduction.rst @@ -9,7 +9,7 @@ EmbodiChain .. image:: ../../assets/imgs/teaser.jpg :alt: teaser -📘 `Documentation `_ +📘 `Documentation `_ --- @@ -36,9 +36,9 @@ Getting Started To get started with EmbodiChain, follow these steps: -* `Installation Guide `_ -* `Quick Start Tutorial `_ -* `API Reference `_ +* `Installation Guide `_ +* `Quick Start Tutorial `_ +* `API Reference `_ Citation diff --git a/tests/gym/envs/test_embodied_env.py b/tests/gym/envs/test_embodied_env.py index 075bdcda..29ea0d85 100644 --- a/tests/gym/envs/test_embodied_env.py +++ b/tests/gym/envs/test_embodied_env.py @@ -97,10 +97,10 @@ ], "rigid_object": [ { - "uid": "paper_cup", + "uid": "duck", "shape": { "shape_type": "Mesh", - "fpath": "PaperCup/paper_cup.ply", + "fpath": "ToyDuck/toy_duck.glb", }, "body_scale": (0.75, 0.75, 1.0), "init_pos": (0.0, 0.0, 1.0), From d1524f8790f05c24265fb304f57b69eac4e95091 Mon Sep 17 00:00:00 2001 From: kerwan-zeng <501217100@qq.com> Date: Tue, 2 Dec 2025 11:06:04 +0800 Subject: [PATCH 17/92] FIX: fix main branch rule (#25) Co-authored-by: zengkehuan --- .github/workflows/main.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cc30ffa7..f4962e5a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,7 +8,6 @@ on: jobs: lint: - if: github.event_name == 'pull_request' runs-on: Linux env: NVIDIA_DRIVER_CAPABILITIES: all @@ -74,7 +73,7 @@ jobs: - name: (CI) Run tests run: | # pip install -e . - echo "Unitest Start" + echo "Unit test Start" # export HF_ENDPOINT=https://hf-mirror.com # pytest tests From 1929efc5e67051a28d18674c79cdc296407f7f52 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Dec 2025 00:07:32 +0800 Subject: [PATCH 18/92] Fix performance issues: remove duplicates, fix broken deprecation warnings, optimize loops (#19) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: yuecideng --- .../lab/sim/solvers/differential_solver.py | 9 ++-- .../toolkits/graspkit/pg_grasp/antipodal.py | 43 +++++++++-------- embodichain/utils/math.py | 39 ++------------- embodichain/utils/utility.py | 47 +++++++------------ 4 files changed, 46 insertions(+), 92 deletions(-) diff --git a/embodichain/lab/sim/solvers/differential_solver.py b/embodichain/lab/sim/solvers/differential_solver.py index 5bbb8028..7cf52788 100644 --- a/embodichain/lab/sim/solvers/differential_solver.py +++ b/embodichain/lab/sim/solvers/differential_solver.py @@ -15,7 +15,6 @@ # ---------------------------------------------------------------------------- import torch -from copy import deepcopy from typing import Optional, Union, Tuple, Any, Literal, TYPE_CHECKING from scipy.spatial.transform import Rotation @@ -245,11 +244,13 @@ def get_ik( current_xpos = self.get_fk(qpos_seed, to_matrix=True) # Transform target_xpos by TCP + # Note: torch.as_tensor does not modify the input, so deepcopy is unnecessary tcp_xpos = torch.as_tensor( - deepcopy(self.tcp_xpos), device=self.device, dtype=torch.float32 + self.tcp_xpos, device=self.device, dtype=torch.float32 ) - current_xpos = current_xpos @ torch.inverse(tcp_xpos) - compute_xpos = target_xpos @ torch.inverse(tcp_xpos) + tcp_xpos_inv = torch.inverse(tcp_xpos) + current_xpos = current_xpos @ tcp_xpos_inv + compute_xpos = target_xpos @ tcp_xpos_inv # Ensure compute_xpos is a batch of matrices if current_xpos.dim() == 2 and current_xpos.shape == (4, 4): diff --git a/embodichain/toolkits/graspkit/pg_grasp/antipodal.py b/embodichain/toolkits/graspkit/pg_grasp/antipodal.py index 5ccf5152..32dfbd07 100644 --- a/embodichain/toolkits/graspkit/pg_grasp/antipodal.py +++ b/embodichain/toolkits/graspkit/pg_grasp/antipodal.py @@ -187,12 +187,11 @@ def get_dis_arr(self, others) -> np.ndarray: Returns: np.ndarray: distance array """ - other_num = len(others) - other_a = np.empty(shape=(other_num, 3), dtype=float) - other_b = np.empty(shape=(other_num, 3), dtype=float) - for i in range(other_num): - other_a[i] = others[i].point_a - other_b[i] = others[i].point_b + if not others: + return np.array([], dtype=float) + # Vectorized extraction of points using list comprehension and np.array + other_a = np.array([o.point_a for o in others], dtype=float) + other_b = np.array([o.point_b for o in others], dtype=float) aa_dis = np.linalg.norm(other_a - self.point_a, axis=1) ab_dis = np.linalg.norm(other_a - self.point_b, axis=1) ba_dis = np.linalg.norm(other_b - self.point_a, axis=1) @@ -382,22 +381,26 @@ def _generate_cache( # self.antipodal_visual(nms_antipodal_list) grasp_num = grasp_poses.shape[0] logger.log_debug(f"Write {grasp_num} poses to pickle file {cache_file}.") - grasp_list = [None for i in range(grasp_num)] - for i in range(grasp_num): - grasp_list[i] = AntipodalGrasp(grasp_poses[i], open_length[i], score[i]) + # Use list comprehension for efficient list construction + grasp_list = [ + AntipodalGrasp(grasp_poses[i], open_length[i], score[i]) + for i in range(grasp_num) + ] return grasp_list def _load_cache(self, cache_file: str): data_dict = pickle.load(open(cache_file, "rb")) grasp_num = data_dict["grasp_poses"].shape[0] logger.log_debug(f"Load {grasp_num} poses from pickle file {cache_file}.") - grasp_list = [None for i in range(grasp_num)] - for i in range(grasp_num): - grasp_list[i] = AntipodalGrasp( + # Use list comprehension for efficient list construction + grasp_list = [ + AntipodalGrasp( data_dict["grasp_poses"][i], data_dict["open_length"][i], data_dict["score"][i], ) + for i in range(grasp_num) + ] return grasp_list def _get_pc_size(self, vertices): @@ -521,13 +524,11 @@ def select_grasp( """ grasp_num = len(self._grasp_list) all_idx = np.arange(grasp_num) - grasp_poses = np.empty(shape=(grasp_num, 4, 4), dtype=float) - scores = np.empty(shape=(grasp_num,), dtype=float) - position = grasp_poses[:, :3, 3] - for i in range(grasp_num): - grasp_poses[i] = self._grasp_list[i].pose - scores[i] = self._grasp_list[i].score + # Vectorized extraction of poses and scores using list comprehension + grasp_poses = np.array([g.pose for g in self._grasp_list], dtype=float) + scores = np.array([g.score for g in self._grasp_list], dtype=float) + position = grasp_poses[:, :3, 3] # mask acoording to table up direction grasp_z = grasp_poses[:, :3, 2] @@ -557,10 +558,8 @@ def select_grasp( best_valid_idx = sort_valid_idx[:result_num] best_idx = valid_id[best_valid_idx] - result_grasp_list = [] - for idx in best_idx: - result_grasp_list.append(self._grasp_list[idx]) - return result_grasp_list + # Use list comprehension for faster list construction + return [self._grasp_list[idx] for idx in best_idx] def _antipodal_nms( self, antipodal_list: List[Antipodal], nms_ratio: float = 0.02 diff --git a/embodichain/utils/math.py b/embodichain/utils/math.py index 4146a6a1..d35e3656 100644 --- a/embodichain/utils/math.py +++ b/embodichain/utils/math.py @@ -18,6 +18,7 @@ from __future__ import annotations import math +import warnings import torch import numpy as np import torch.nn.functional @@ -394,10 +395,8 @@ def _sqrt_positive_part(x: torch.Tensor) -> torch.Tensor: Reference: https://github.com/facebookresearch/pytorch3d/blob/main/pytorch3d/transforms/rotation_conversions.py#L91-L99 """ - ret = torch.zeros_like(x) - positive_mask = x > 0 - ret[positive_mask] = torch.sqrt(x[positive_mask]) - return ret + # Use torch.where for vectorized operation instead of indexed assignment + return torch.where(x > 0, torch.sqrt(x), torch.zeros_like(x)) @torch.jit.script @@ -508,38 +507,6 @@ def trans_matrix_to_xyz_quat(matrix: torch.Tensor) -> torch.Tensor: return vec -@torch.jit.script -def quat_from_euler_xyz( - roll: torch.Tensor, pitch: torch.Tensor, yaw: torch.Tensor -) -> torch.Tensor: - """Convert rotations given as Euler angles in radians to Quaternions. - - Note: - The euler angles are assumed in XYZ convention. - - Args: - roll: Rotation around x-axis (in radians). Shape is (N,). - pitch: Rotation around y-axis (in radians). Shape is (N,). - yaw: Rotation around z-axis (in radians). Shape is (N,). - - Returns: - The quaternion in (w, x, y, z). Shape is (N, 4). - """ - cy = torch.cos(yaw * 0.5) - sy = torch.sin(yaw * 0.5) - cr = torch.cos(roll * 0.5) - sr = torch.sin(roll * 0.5) - cp = torch.cos(pitch * 0.5) - sp = torch.sin(pitch * 0.5) - # compute quaternion - qw = cy * cr * cp + sy * sr * sp - qx = cy * sr * cp - sy * cr * sp - qy = cy * cr * sp + sy * sr * cp - qz = sy * cr * cp - cy * sr * sp - - return torch.stack([qw, qx, qy, qz], dim=-1) - - def _axis_angle_rotation( axis: Literal["X", "Y", "Z"], angle: torch.Tensor ) -> torch.Tensor: diff --git a/embodichain/utils/utility.py b/embodichain/utils/utility.py index d5506df6..c7015476 100644 --- a/embodichain/utils/utility.py +++ b/embodichain/utils/utility.py @@ -352,13 +352,6 @@ def save_json(path: str, data): json.dump(data, f, indent=4) -def save_json(path: str, data): - import json - - with open(path, "w") as f: - json.dump(data, f, indent=4) - - def load_json(path: str) -> Dict: import json @@ -455,14 +448,22 @@ def postprocess_small_regions( min_area: int, max_area: int, ) -> List[int]: - keep_idx = [] + """Filter masks based on area constraints. + + Args: + masks: Array of binary masks or list of masks. + min_area: Minimum area threshold (exclusive - areas must be strictly greater). + max_area: Maximum area threshold (inclusive - areas can equal this value). + + Returns: + List of indices for masks that meet the area constraints (min_area < area <= max_area). + """ n = len(masks) if isinstance(masks, list) else masks.shape[0] - for i in range(n): - area = masks[i].astype(np.uint8).sum() - keep = area > min_area and area <= max_area - if keep: - keep_idx.append(i) - return keep_idx + # Use list comprehension for more efficient filtering + # Logic: area > min_area and area <= max_area (original behavior preserved) + return [ + i for i in range(n) if min_area < masks[i].astype(np.uint8).sum() <= max_area + ] def mask_to_box(mask: np.ndarray) -> np.ndarray: @@ -478,27 +479,13 @@ def mask_to_box(mask: np.ndarray) -> np.ndarray: return bbox -def postprocess_small_regions( - masks: np.ndarray, - min_area: int, - max_area: int, -) -> List[int]: - keep_idx = [] - n = len(masks) if isinstance(masks, list) else masks.shape[0] - for i in range(n): - area = masks[i].astype(np.uint8).sum() - keep = area > min_area and area <= max_area - if keep: - keep_idx.append(i) - return keep_idx - - def remove_overlap_mask( masks: List[np.ndarray], keep_inner_threshold: float = 0.5, eps: float = 1e-5 ) -> List[int]: keep_ids = [] - areas = [mask.astype(np.uint8).sum() for mask in masks] + # Pre-compute areas once for efficiency + areas = np.array([mask.astype(np.uint8).sum() for mask in masks]) for i, maskA in enumerate(masks): keep = True From 976c8d5bcb764c63a6f47848bf263a473faac60f Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Dec 2025 00:36:16 +0800 Subject: [PATCH 19/92] Refactor duplicated code in solver modules (#20) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: yuecideng --- embodichain/lab/sim/solvers/base_solver.py | 13 ++ .../lab/sim/solvers/differential_solver.py | 6 +- embodichain/lab/sim/solvers/opw_solver.py | 6 +- embodichain/lab/sim/solvers/pink_solver.py | 57 ++------ .../lab/sim/solvers/pinocchio_solver.py | 80 ++--------- embodichain/lab/sim/solvers/pytorch_solver.py | 27 +--- embodichain/lab/sim/solvers/srs_solver.py | 6 +- embodichain/lab/sim/utility/solver_utils.py | 132 +++++++++++++++++- 8 files changed, 174 insertions(+), 153 deletions(-) diff --git a/embodichain/lab/sim/solvers/base_solver.py b/embodichain/lab/sim/solvers/base_solver.py index af7433cc..f04d40b4 100644 --- a/embodichain/lab/sim/solvers/base_solver.py +++ b/embodichain/lab/sim/solvers/base_solver.py @@ -76,6 +76,19 @@ class SolverCfg: def init_solver(self, device: torch.device, **kwargs) -> "BaseSolver": pass + def _get_tcp_as_numpy(self) -> np.ndarray: + """Convert TCP to numpy array. + + This helper method handles the conversion of TCP from torch.Tensor to numpy + if needed. Used by subclass init_solver methods to set TCP on the solver. + + Returns: + np.ndarray: The TCP as a numpy array. + """ + if isinstance(self.tcp, torch.Tensor): + return self.tcp.cpu().numpy() + return self.tcp + @classmethod def from_dict(cls, init_dict: Dict[str, Any]) -> "SolverCfg": """Initialize the configuration from a dictionary.""" diff --git a/embodichain/lab/sim/solvers/differential_solver.py b/embodichain/lab/sim/solvers/differential_solver.py index 7cf52788..f3c4c4ea 100644 --- a/embodichain/lab/sim/solvers/differential_solver.py +++ b/embodichain/lab/sim/solvers/differential_solver.py @@ -89,11 +89,7 @@ def init_solver( ) # Set the Tool Center Point (TCP) for the solver - if isinstance(self.tcp, torch.Tensor): - tcp = self.tcp.cpu().numpy() - else: - tcp = self.tcp - solver.set_tcp(tcp) + solver.set_tcp(self._get_tcp_as_numpy()) return solver diff --git a/embodichain/lab/sim/solvers/opw_solver.py b/embodichain/lab/sim/solvers/opw_solver.py index 1dfd751e..0ddecff8 100644 --- a/embodichain/lab/sim/solvers/opw_solver.py +++ b/embodichain/lab/sim/solvers/opw_solver.py @@ -95,11 +95,7 @@ def init_solver( solver = OPWSolver(cfg=self, device=device, **kwargs) # Set the Tool Center Point (TCP) for the solver - if isinstance(self.tcp, torch.Tensor): - tcp = self.tcp.cpu().numpy() - else: - tcp = self.tcp - solver.set_tcp(tcp) + solver.set_tcp(self._get_tcp_as_numpy()) return solver diff --git a/embodichain/lab/sim/solvers/pink_solver.py b/embodichain/lab/sim/solvers/pink_solver.py index b9d74a5f..b7ab7b08 100644 --- a/embodichain/lab/sim/solvers/pink_solver.py +++ b/embodichain/lab/sim/solvers/pink_solver.py @@ -24,6 +24,10 @@ lazy_import_pinocchio, lazy_import_pink, ) +from embodichain.lab.sim.utility.solver_utils import ( + build_reduced_pinocchio_robot, + compute_pinocchio_fk, +) from embodichain.utils import configclass, logger from embodichain.lab.sim.solvers import SolverCfg, BaseSolver @@ -111,12 +115,7 @@ def init_solver(self, **kwargs) -> "PinkSolver": solver = PinkSolver(cfg=self, **kwargs) # Set the Tool Center Point (TCP) for the solver - if isinstance(self.tcp, torch.Tensor): - tcp = self.tcp.cpu().numpy() - else: - tcp = self.tcp - - solver.set_tcp(tcp) + solver.set_tcp(self._get_tcp_as_numpy()) return solver @@ -162,7 +161,7 @@ def __init__(self, cfg: PinkSolverCfg, **kwargs): ) # Degrees of freedom of robot joints # Get reduced robot model - self.robot = self._get_reduce_robot() + self.robot = build_reduced_pinocchio_robot(self.entire_robot, self.joint_names) # Initialize Pink configuration self.pink_cfg = self.pink.configuration.Configuration( @@ -207,26 +206,6 @@ def __init__(self, cfg: PinkSolverCfg, **kwargs): self.dexsim_to_pink_ordering = None self.pink_to_dexsim_ordering = None - def _get_reduce_robot(self) -> "pin.RobotWrapper": - """Build a reduced robot model by locking all joints except those in self.joint_names. - - Returns: - pin.RobotWrapper: The reduced robot model with specified joints unlocked. - """ - pink_joint_names = self.entire_robot.model.names.tolist() - - # Lock all joints except those in self.joint_names and 'universe' - fixed_joint_names = [ - name - for name in pink_joint_names - if name not in self.joint_names and name != "universe" - ] - - reduced_robot = self.entire_robot.buildReducedRobot( - list_of_joints_to_lock=fixed_joint_names - ) - return reduced_robot - def reorder_array( self, input_array: List[float], reordering_array: List[int] ) -> List[float]: @@ -393,25 +372,7 @@ def _get_fk( Returns: torch.Tensor: The homogeneous transformation matrix (4x4) of the end-effector (after applying TCP). """ - if isinstance(qpos, torch.Tensor): - qpos_np = qpos.detach().cpu().numpy() - else: - qpos_np = np.array(qpos) - - qpos_np = np.squeeze(qpos_np) - if qpos_np.ndim != 1: - raise ValueError(f"qpos shape must be (nq,), but got {qpos_np.shape}") - - self.pin.forwardKinematics(self.robot.model, self.robot.data, qpos_np) - - # Retrieve the pose of the specified link - frame_index = self.robot.model.getFrameId(self.end_link_name) - joint_index = self.robot.model.frames[frame_index].parent - xpos_se3 = self.robot.data.oMi.tolist()[joint_index] - - xpos = np.eye(4) - xpos[:3, :3] = xpos_se3.rotation - xpos[:3, 3] = xpos_se3.translation.T - - result = np.dot(xpos, self.tcp_xpos) + result = compute_pinocchio_fk( + self.pin, self.robot, qpos, self.end_link_name, self.tcp_xpos + ) return torch.from_numpy(result) diff --git a/embodichain/lab/sim/solvers/pinocchio_solver.py b/embodichain/lab/sim/solvers/pinocchio_solver.py index 5e5167f2..8c945635 100644 --- a/embodichain/lab/sim/solvers/pinocchio_solver.py +++ b/embodichain/lab/sim/solvers/pinocchio_solver.py @@ -29,6 +29,11 @@ lazy_import_casadi, # lazy_import_pinocchio_casadi, ) +from embodichain.lab.sim.utility.solver_utils import ( + build_reduced_pinocchio_robot, + validate_iteration_params, + compute_pinocchio_fk, +) if TYPE_CHECKING: @@ -72,12 +77,7 @@ def init_solver(self, **kwargs) -> "PinocchioSolver": solver = PinocchioSolver(cfg=self, **kwargs) # Set the Tool Center Point (TCP) for the solver - if isinstance(self.tcp, torch.Tensor): - tcp = self.tcp.cpu().numpy() - else: - tcp = self.tcp - - solver.set_tcp(tcp) + solver.set_tcp(self._get_tcp_as_numpy()) return solver @@ -121,7 +121,7 @@ def __init__(self, cfg: PinocchioSolverCfg, **kwargs): ) # Degrees of freedom of robot joints # Build reduced robot model (only relevant joints unlocked) - self.robot = self._get_reduce_robot() + self.robot = build_reduced_pinocchio_robot(self.entire_robot, self.joint_names) self.joint_names = self.robot.model.names.tolist()[ 1: ] # Exclude 'universe' joint @@ -221,26 +221,6 @@ def __init__(self, cfg: PinocchioSolverCfg, **kwargs): self.root_base_xpos[:3, :3] = root_base_pose.rotation self.root_base_xpos[:3, 3] = root_base_pose.translation.T - def _get_reduce_robot(self) -> "pin.RobotWrapper": - """Build a reduced robot model by locking all joints except those in self.joint_names. - - Returns: - pin.RobotWrapper: The reduced robot model with specified joints unlocked. - """ - all_joint_names = self.entire_robot.model.names.tolist() - - # Lock all joints except those in self.joint_names and 'universe' - fixed_joint_names = [ - name - for name in all_joint_names - if name not in self.joint_names and name != "universe" - ] - - reduced_robot = self.entire_robot.buildReducedRobot( - list_of_joints_to_lock=fixed_joint_names - ) - return reduced_robot - def set_tcp(self, tcp: np.ndarray): self.tcp = tcp @@ -290,25 +270,10 @@ def set_iteration_params( Returns: bool: True if all parameters are valid and set, False otherwise. """ - # TODO: Check which parameters are no longer needed. # Validate parameters - if pos_eps <= 0: - logger.log_warning("Pos epsilon must be positive.") - return False - if rot_eps <= 0: - logger.log_warning("Rot epsilon must be positive.") - return False - if max_iterations <= 0: - logger.log_warning("Max iterations must be positive.") - return False - if dt <= 0: - logger.log_warning("Time step must be positive.") - return False - if damp < 0: - logger.log_warning("Damping factor must be non-negative.") - return False - if num_samples <= 0: - logger.log_warning("Number of samples must be positive.") + if not validate_iteration_params( + pos_eps, rot_eps, max_iterations, dt, damp, num_samples + ): return False # Set parameters if all are valid @@ -620,25 +585,6 @@ def _get_fk( Returns: np.ndarray: The resulting end-effector pose as a (4, 4) homogeneous transformation matrix. """ - if isinstance(qpos, torch.Tensor): - qpos_np = qpos.detach().cpu().numpy() - else: - qpos_np = np.array(qpos) - - qpos_np = np.squeeze(qpos_np) - if qpos_np.ndim != 1: - raise ValueError(f"qpos shape must be (nq,), but got {qpos_np.shape}") - - self.pin.forwardKinematics(self.robot.model, self.robot.data, qpos_np) - - # Retrieve the pose of the specified link - frame_index = self.robot.model.getFrameId(self.end_link_name) - joint_index = self.robot.model.frames[frame_index].parent - xpos_se3 = self.robot.data.oMi.tolist()[joint_index] - - xpos = np.eye(4) - xpos[:3, :3] = xpos_se3.rotation - xpos[:3, 3] = xpos_se3.translation.T - - result = np.dot(xpos, self.tcp_xpos) - return result + return compute_pinocchio_fk( + self.pin, self.robot, qpos, self.end_link_name, self.tcp_xpos + ) diff --git a/embodichain/lab/sim/solvers/pytorch_solver.py b/embodichain/lab/sim/solvers/pytorch_solver.py index 238e8912..d8da6952 100644 --- a/embodichain/lab/sim/solvers/pytorch_solver.py +++ b/embodichain/lab/sim/solvers/pytorch_solver.py @@ -23,6 +23,7 @@ from embodichain.utils import configclass, logger from embodichain.lab.sim.solvers import SolverCfg, BaseSolver from embodichain.lab.sim.solvers.qpos_seed_sampler import QposSeedSampler +from embodichain.lab.sim.utility.solver_utils import validate_iteration_params if TYPE_CHECKING: from typing import Self @@ -90,11 +91,7 @@ def init_solver( solver = PytorchSolver(cfg=self, device=device, **kwargs) # Set the Tool Center Point (TCP) for the solver - if isinstance(self.tcp, torch.Tensor): - tcp = self.tcp.cpu().numpy() - else: - tcp = self.tcp - solver.set_tcp(tcp) + solver.set_tcp(self._get_tcp_as_numpy()) return solver @@ -227,23 +224,9 @@ def set_iteration_params( bool: True if all parameters are valid and set, False otherwise. """ # Validate parameters - if pos_eps <= 0: - logger.log_warning("Pos epsilon must be positive.") - return False - if rot_eps <= 0: - logger.log_warning("Rot epsilon must be positive.") - return False - if max_iterations <= 0: - logger.log_warning("Max iterations must be positive.") - return False - if dt <= 0: - logger.log_warning("Time step must be positive.") - return False - if damp < 0: - logger.log_warning("Damping factor must be non-negative.") - return False - if num_samples <= 0: - logger.log_warning("Number of samples must be positive.") + if not validate_iteration_params( + pos_eps, rot_eps, max_iterations, dt, damp, num_samples + ): return False # Set parameters if all are valid diff --git a/embodichain/lab/sim/solvers/srs_solver.py b/embodichain/lab/sim/solvers/srs_solver.py index 56c979ae..aadab28b 100644 --- a/embodichain/lab/sim/solvers/srs_solver.py +++ b/embodichain/lab/sim/solvers/srs_solver.py @@ -93,11 +93,7 @@ def init_solver( solver = SRSSolver(cfg=self, num_envs=num_envs, device=device, **kwargs) # Set the Tool Center Point (TCP) for the solver - if isinstance(self.tcp, torch.Tensor): - tcp = self.tcp.cpu().numpy() - else: - tcp = self.tcp - solver.set_tcp(tcp) + solver.set_tcp(self._get_tcp_as_numpy()) return solver diff --git a/embodichain/lab/sim/utility/solver_utils.py b/embodichain/lab/sim/utility/solver_utils.py index 976462f2..d510cc2d 100644 --- a/embodichain/lab/sim/utility/solver_utils.py +++ b/embodichain/lab/sim/utility/solver_utils.py @@ -15,9 +15,10 @@ # ---------------------------------------------------------------------------- import torch +import numpy as np from embodichain.lab.sim.utility.io_utils import suppress_stdout_stderr -from typing import Optional, Union, Tuple, Any, TYPE_CHECKING +from typing import Optional, Union, Tuple, Any, List, TYPE_CHECKING from copy import deepcopy from embodichain.utils import configclass, logger @@ -109,3 +110,132 @@ def create_pk_serial_chain( return pk.SerialChain( chain=chain, end_frame_name=end_link_name, root_frame_name=root_link_name ) + + +def build_reduced_pinocchio_robot( + entire_robot: "pin.RobotWrapper", + joint_names: List[str], +) -> "pin.RobotWrapper": + """Build a reduced robot model by locking all joints except those specified. + + This utility function creates a reduced Pinocchio robot model by locking all joints + except those in the provided joint_names list and the 'universe' joint. + + Args: + entire_robot: The full Pinocchio RobotWrapper model. + joint_names: List of joint names to keep unlocked in the reduced model. + + Returns: + pin.RobotWrapper: The reduced robot model with specified joints unlocked. + """ + all_joint_names = entire_robot.model.names.tolist() + + # Lock all joints except those in joint_names and 'universe' + fixed_joint_names = [ + name + for name in all_joint_names + if name not in joint_names and name != "universe" + ] + + reduced_robot = entire_robot.buildReducedRobot( + list_of_joints_to_lock=fixed_joint_names + ) + return reduced_robot + + +def validate_iteration_params( + pos_eps: float, + rot_eps: float, + max_iterations: int, + dt: float, + damp: float, + num_samples: int, +) -> bool: + """Validate iteration parameters for IK solvers. + + This helper validates common iteration parameters used by IK solvers. Returns + True if all parameters are valid, False otherwise, and logs warnings for invalid + parameters. + + Args: + pos_eps: Position convergence threshold, must be positive. + rot_eps: Rotation convergence threshold, must be positive. + max_iterations: Maximum number of iterations, must be positive. + dt: Time step size, must be positive. + damp: Damping factor, must be non-negative. + num_samples: Number of samples, must be positive. + + Returns: + bool: True if all parameters are valid, False otherwise. + """ + if pos_eps <= 0: + logger.log_warning("Pos epsilon must be positive.") + return False + if rot_eps <= 0: + logger.log_warning("Rot epsilon must be positive.") + return False + if max_iterations <= 0: + logger.log_warning("Max iterations must be positive.") + return False + if dt <= 0: + logger.log_warning("Time step must be positive.") + return False + if damp < 0: + logger.log_warning("Damping factor must be non-negative.") + return False + if num_samples <= 0: + logger.log_warning("Number of samples must be positive.") + return False + return True + + +def compute_pinocchio_fk( + pin_module: Any, + robot: "pin.RobotWrapper", + qpos: Union[torch.Tensor, "np.ndarray"], + end_link_name: str, + tcp_xpos: "np.ndarray", +) -> "np.ndarray": + """Compute forward kinematics using Pinocchio for the specified end-effector. + + This utility function computes FK using the Pinocchio library and applies + the TCP transformation. + + Args: + pin_module: The imported pinocchio module. + robot: The Pinocchio RobotWrapper model. + qpos: Joint positions, shape should be (nq,). + end_link_name: The name of the end-effector link. + tcp_xpos: The TCP transformation matrix (4x4). + + Returns: + np.ndarray: The resulting end-effector pose as a (4, 4) homogeneous + transformation matrix. + + Raises: + ValueError: If qpos shape is not (nq,) or if the end_link_name is not found. + """ + if isinstance(qpos, torch.Tensor): + qpos_np = qpos.detach().cpu().numpy() + else: + qpos_np = np.array(qpos) + + qpos_np = np.squeeze(qpos_np) + if qpos_np.ndim != 1: + raise ValueError(f"qpos shape must be (nq,), but got {qpos_np.shape}") + + pin_module.forwardKinematics(robot.model, robot.data, qpos_np) + + # Retrieve the pose of the specified link + frame_index = robot.model.getFrameId(end_link_name) + if frame_index >= robot.model.nframes: + raise ValueError(f"End link name '{end_link_name}' not found in robot model.") + joint_index = robot.model.frames[frame_index].parent + xpos_se3 = robot.data.oMi.tolist()[joint_index] + + xpos = np.eye(4) + xpos[:3, :3] = xpos_se3.rotation + xpos[:3, 3] = xpos_se3.translation.T + + result = np.dot(xpos, tcp_xpos) + return result From 5fe1aa794f38e2f2308463923d8662979738a2e7 Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Thu, 4 Dec 2025 09:56:51 +0000 Subject: [PATCH 20/92] Enable unit test in workflow (#29) --- .github/workflows/main.yml | 6 +-- .readthedocs.yaml | 25 ------------- docs/source/quick_start/install.md | 1 - embodichain/data/assets/demo_assets.py | 8 +++- embodichain/data/assets/eef_assets.py | 21 +++++++---- embodichain/data/assets/materials.py | 9 ++++- embodichain/data/assets/obj_assets.py | 49 +++++++++++-------------- embodichain/data/assets/robot_assets.py | 31 +++++++++------- embodichain/data/assets/scene_assets.py | 7 +++- embodichain/data/assets/w1_assets.py | 29 ++++++++------- pyproject.toml | 2 +- tests/sim/objects/test_articulation.py | 2 +- tests/sim/sensors/test_camera.py | 4 +- 13 files changed, 93 insertions(+), 101 deletions(-) delete mode 100644 .readthedocs.yaml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f4962e5a..40431a98 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -72,10 +72,10 @@ jobs: - uses: actions/checkout@v4 - name: (CI) Run tests run: | - # pip install -e . + pip install -e . echo "Unit test Start" - # export HF_ENDPOINT=https://hf-mirror.com - # pytest tests + export HF_ENDPOINT=https://hf-mirror.com + pytest tests publish: if: github.event_name == 'push' && github.ref == 'refs/heads/main' diff --git a/.readthedocs.yaml b/.readthedocs.yaml deleted file mode 100644 index 0aa6b2f0..00000000 --- a/.readthedocs.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# Read the Docs configuration file -# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details - -# Required -version: 2 - -# Set the OS, Python version, and other tools you might need -build: - os: ubuntu-22.04 - tools: - python: "3.10" - -# Build documentation in the "docs/" directory with Sphinx -sphinx: - configuration: docs/source/conf.py - -# Optionally, but recommended, -# declare the Python requirements required to build your documentation -# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html -python: - install: - - requirements: docs/requirements.txt - - method: pip - path: . - \ No newline at end of file diff --git a/docs/source/quick_start/install.md b/docs/source/quick_start/install.md index 892e99cd..58f0bb6c 100644 --- a/docs/source/quick_start/install.md +++ b/docs/source/quick_start/install.md @@ -14,7 +14,6 @@ The following minimum system requirements are recommended to run EmbodiChain rel - Python: - Supported Python versions: - - Python 3.9 - Python 3.10 - Use a virtual environment (venv, virtualenv, or conda) to isolate dependencies diff --git a/embodichain/data/assets/demo_assets.py b/embodichain/data/assets/demo_assets.py index 656c6bfa..71b390cb 100644 --- a/embodichain/data/assets/demo_assets.py +++ b/embodichain/data/assets/demo_assets.py @@ -23,11 +23,15 @@ EMBODICHAIN_DEFAULT_DATA_ROOT, ) +demo_assets = "demo" + class ScoopIceNewEnv(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "demo/ScoopIceNewEnv.zip"), + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, demo_assets, "ScoopIceNewEnv.zip" + ), "e92734a9de0f64be33a11fbda0fbd3b6", ) prefix = "ScoopIceNewEnv" @@ -39,7 +43,7 @@ def __init__(self, data_root: str = None): class MultiW1Data(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "demo/multi_w1_demo.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, demo_assets, "multi_w1_demo.zip"), "984e8fa3aa05cb36a1fd973a475183ed", ) prefix = "MultiW1Data" diff --git a/embodichain/data/assets/eef_assets.py b/embodichain/data/assets/eef_assets.py index 7f52b9ee..5da40a40 100644 --- a/embodichain/data/assets/eef_assets.py +++ b/embodichain/data/assets/eef_assets.py @@ -24,6 +24,9 @@ ) +eef_assets = "eef_assets" + + class DH_PGC_140_50(EmbodiChainDataset): """Dataset class for the DH Robotics PGC-140-50 end-effector gripper. @@ -44,7 +47,7 @@ class DH_PGC_140_50(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "eef_assets/DH_PGC_140_50.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, eef_assets, "DH_PGC_140_50.zip"), "c2a642308a76e99b1b8b7cb3a11c5df3", ) prefix = "DH_PGC_140_50" @@ -73,7 +76,7 @@ class DH_PGI_140_80(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "eef_assets/DH_PGI_140_80.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, eef_assets, "DH_PGI_140_80.zip"), "05a1a08b13c6250cc12affeeda3a08ba", ) prefix = "DH_PGI_140_80" @@ -103,7 +106,9 @@ class DH_PGC_140_50_M(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "eef_assets/DH_PGC_140_50_M.zip"), + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, eef_assets, "DH_PGC_140_50_M.zip" + ), "3a9ab5f32639e03afb38dc033b44bb62", ) prefix = "DH_PGC_140_50_M" @@ -132,7 +137,7 @@ class ZH_CTM2F110(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "eef_assets/ZH_CTM2F110.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, eef_assets, "ZH_CTM2F110.zip"), "0e7c3310425609797fe010b2a76fe465", ) prefix = "ZH_CTM2F110" @@ -164,7 +169,7 @@ class BrainCoHandRevo1(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( os.path.join( - EMBODICHAIN_DOWNLOAD_PREFIX, "eef_assets/BrainCoHandRevo01.zip" + EMBODICHAIN_DOWNLOAD_PREFIX, eef_assets, "BrainCoHandRevo01.zip" ), "ff9ac77e7e1493fd32d40c87fecbee6c", ) @@ -200,7 +205,7 @@ class InspireHand(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "eef_assets/InspireHand.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, eef_assets, "InspireHand.zip"), "c60132a6f03866fb021cca5b6d72845e", ) prefix = "InspireHand" @@ -229,7 +234,7 @@ class Robotiq2F85(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "eef_assets/Robotiq2F85.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, eef_assets, "Robotiq2F85.zip"), "53ecbf2c953f43f1134aa7223e592292", ) prefix = "Robotiq2F85" @@ -258,7 +263,7 @@ class WheelTecFA2F(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "eef_assets/WheelTecFA2F.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, eef_assets, "WheelTecFA2F.zip"), "feaf13f25b1c6ce58d011b1f2fa72f58", ) prefix = "WheelTecFA2F" diff --git a/embodichain/data/assets/materials.py b/embodichain/data/assets/materials.py index c40369dd..cd6a7f5a 100644 --- a/embodichain/data/assets/materials.py +++ b/embodichain/data/assets/materials.py @@ -28,11 +28,14 @@ ) +material_assets = "materials" + + class SimResources(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( os.path.join( - EMBODICHAIN_DOWNLOAD_PREFIX, "materials/embodisim_resources.zip" + EMBODICHAIN_DOWNLOAD_PREFIX, material_assets, "embodisim_resources.zip" ), "53c054b3ae0857416dc52632eb562c12", ) @@ -101,7 +104,9 @@ def get_material_list(self) -> List[str]: class CocoBackground(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "materials/CocoBackground.zip"), + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, material_assets, "CocoBackground.zip" + ), "fda82404a317281263bd5849e9eb31a1", ) prefix = "CocoBackground" diff --git a/embodichain/data/assets/obj_assets.py b/embodichain/data/assets/obj_assets.py index 5d7a63f8..30bbb662 100644 --- a/embodichain/data/assets/obj_assets.py +++ b/embodichain/data/assets/obj_assets.py @@ -24,11 +24,14 @@ ) +obj_assets = "obj_assets" + + class ShopTableSimple(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( os.path.join( - EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/shop_table_simple.zip" + EMBODICHAIN_DOWNLOAD_PREFIX, obj_assets, "shop_table_simple.zip" ), "e3061ee024de7840f773b70140dcd43f", ) @@ -42,7 +45,7 @@ class CircleTableSimple(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( os.path.join( - EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/circle_table_simple.zip" + EMBODICHAIN_DOWNLOAD_PREFIX, obj_assets, "circle_table_simple.zip" ), "42ad2be8cd0caddcf9bfbf106b7783f3", ) @@ -55,7 +58,7 @@ def __init__(self, data_root: str = None): class PlasticBin(o3d.data.DownloadDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/plastic_bin.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, obj_assets, "plastic_bin.zip"), "21e00083689a4a3c4e4ae3fd89c61e55", ) prefix = "PlasticBin" @@ -67,8 +70,8 @@ def __init__(self, data_root: str = None): class Chair(o3d.data.DownloadDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/chair.zip"), - "df3d7d1a05731d45fb2c678a40a39cd4", + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, obj_assets, "chair.zip"), + "2a971a92e0956e72f262308a1054dc73", ) prefix = "Chair" path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root @@ -79,7 +82,9 @@ def __init__(self, data_root: str = None): class ContainerMetal(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/container_metal.zip"), + os.path.join( + EMBODICHAIN_DOWNLOAD_PREFIX, obj_assets, "container_metal.zip" + ), "ceafb87f8177609f87aaa6779fcbb9a3", ) prefix = "ContainerMetal" @@ -92,7 +97,7 @@ class SimpleBoxDrawer(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( os.path.join( - EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/simple_box_drawer.zip" + EMBODICHAIN_DOWNLOAD_PREFIX, obj_assets, "simple_box_drawer.zip" ), "966b648bca16823ee91525847c183973", ) @@ -105,7 +110,7 @@ def __init__(self, data_root: str = None): class AdrianoTable(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/adriano_table.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, obj_assets, "adriano_table.zip"), "8453583a9a1a9d04d50268f8a3da554f", ) prefix = "AdrianoTable" @@ -117,7 +122,7 @@ def __init__(self, data_root: str = None): class CoffeeCup(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/CoffeeCup.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, obj_assets, "CoffeeCup.zip"), "f05fce385826414c15e19df3b75dc886", ) prefix = "CoffeeCup" @@ -130,7 +135,7 @@ class SlidingBoxDrawer(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( os.path.join( - EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/SlidingBoxDrawer.zip" + EMBODICHAIN_DOWNLOAD_PREFIX, obj_assets, "SlidingBoxDrawer.zip" ), "b03d9006503d27b75ddeb06d31b2c7a5", ) @@ -140,22 +145,10 @@ def __init__(self, data_root: str = None): super().__init__(prefix, data_descriptor, path) -class AiLiMu_BoxDrawer(EmbodiChainDataset): - def __init__(self, data_root: str = None): - data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "AiLiMu_BoxDrawer_v3.zip"), - "9a2889151a23d482f95f602cce9900c6", - ) - prefix = "AiLiMu_BoxDrawer" - path = EMBODICHAIN_DEFAULT_DATA_ROOT if data_root is None else data_root - - super().__init__(prefix, data_descriptor, path) - - class AluminumTable(o3d.data.DownloadDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "AluminumTable.glb"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, obj_assets, "AluminumTable.glb"), "02991d36ca9b70f019ed330a61143aa9", ) prefix = "AluminumTable" @@ -167,7 +160,7 @@ def __init__(self, data_root: str = None): class ToyDuck(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "ToyDuck.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, obj_assets, "ToyDuck.zip"), "2f5c00ba487edf34ad668f7257c0264e", ) prefix = "ToyDuck" @@ -179,7 +172,7 @@ def __init__(self, data_root: str = None): class PaperCup(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "PaperCup.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, obj_assets, "PaperCup.zip"), "359d13af8c5f31ad3226d8994a1a7198", ) prefix = "PaperCup" @@ -191,7 +184,7 @@ def __init__(self, data_root: str = None): class ChainRainSec(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/lianguijie.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, obj_assets, "lianguijie.zip"), "2387589040a4d3f2676b622362452242", ) prefix = "ChainRainSec" @@ -203,7 +196,7 @@ def __init__(self, data_root: str = None): class TableWare(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/tableware.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, obj_assets, "tableware.zip"), "403e340fc0e4996c002ee774f89cd236", ) prefix = "TableWare" @@ -215,7 +208,7 @@ def __init__(self, data_root: str = None): class ScannedBottle(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "obj_assets/ScannedBottle.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, obj_assets, "ScannedBottle.zip"), "d2b2d4deb7b463a734af099f7624b4af", ) prefix = "ScannedBottle" diff --git a/embodichain/data/assets/robot_assets.py b/embodichain/data/assets/robot_assets.py index 6c2d47e5..5251621e 100644 --- a/embodichain/data/assets/robot_assets.py +++ b/embodichain/data/assets/robot_assets.py @@ -24,6 +24,9 @@ ) +robot_assets = "robot_assets" + + class CobotMagicArm(EmbodiChainDataset): """Dataset class for the Cobot Magic Arm robot. @@ -51,7 +54,7 @@ class CobotMagicArm(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( os.path.join( - EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/CobotMagicArmV2.zip" + EMBODICHAIN_DOWNLOAD_PREFIX, robot_assets, "CobotMagicArmV2.zip" ), "14af3e84b74193680899a59fc74e8337", ) @@ -81,7 +84,7 @@ class RidgeBack(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/RidgeBack.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, robot_assets, "RidgeBack.zip"), "f03e1a6f4c781ad8957a88bdb010e9b6", ) prefix = "RidgeBack" @@ -112,7 +115,7 @@ class UnitreeH1(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/UnitreeH1.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, robot_assets, "UnitreeH1.zip"), "339417cef5051a912693f3c64d29dddc", ) prefix = "UnitreeH1" @@ -143,7 +146,7 @@ class ABB(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/ABB.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, robot_assets, "ABB.zip"), "ea6df4983982606c43387783e5fb8c05", ) prefix = "ABB" @@ -174,7 +177,7 @@ class Motoman(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/Motoman.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, robot_assets, "Motoman.zip"), "ee5f16cfce34d8e2cb996fcff8a25986", ) prefix = "Motoman" @@ -205,7 +208,7 @@ class KUKA(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/KUKA.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, robot_assets, "KUKA.zip"), "da7a2dfd0db3f486e407f038d25c7537", ) prefix = "KUKA" @@ -236,7 +239,7 @@ class Fanuc(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/Fanuc.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, robot_assets, "Fanuc.zip"), "0a1c562f4719f7cdc1b24545fec4a301", ) prefix = "Fanuc" @@ -276,7 +279,7 @@ class UniversalRobots(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( os.path.join( - EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/UniversalRobots.zip" + EMBODICHAIN_DOWNLOAD_PREFIX, robot_assets, "UniversalRobots.zip" ), "dbd12f7e36cef4e5025b82f748233b80", ) @@ -308,7 +311,7 @@ class Rokae(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/Rokae.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, robot_assets, "Rokae.zip"), "fbfb852d6139e94b7c422771542f988f", ) prefix = "Rokae" @@ -341,7 +344,7 @@ class Franka(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/Franka.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, robot_assets, "Franka.zip"), "c2de367fe1da02eeb45a8129f903d0b6", ) prefix = "Franka" @@ -370,7 +373,7 @@ class Agile(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/Agile.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, robot_assets, "Agile.zip"), "fd47d7ab8a4d13960fd76e59544ba836", ) prefix = "Agile" @@ -401,7 +404,7 @@ class Hans(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/Hans.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, robot_assets, "Hans.zip"), "c867c406e3dffd6982fd0a15e7dc7e29", ) prefix = "Hans" @@ -430,7 +433,7 @@ class Aubo(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/Aubo.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, robot_assets, "Aubo.zip"), "2574649cd199c11267cc0f4aeac65557", ) prefix = "Aubo" @@ -459,7 +462,7 @@ class RainbowY1(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "robot_assets/RainbowY1.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, robot_assets, "RainbowY1.zip"), "5979a3aaadb5de6488b13765d523564f", ) prefix = "RainbowY1" diff --git a/embodichain/data/assets/scene_assets.py b/embodichain/data/assets/scene_assets.py index f1089bf7..a715a7b6 100644 --- a/embodichain/data/assets/scene_assets.py +++ b/embodichain/data/assets/scene_assets.py @@ -24,6 +24,9 @@ ) +scene_assets = "scene_assets" + + class SceneData(EmbodiChainDataset): """Dataset class for the Scene. @@ -44,7 +47,7 @@ class SceneData(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "scene_assets/SceneData.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, scene_assets, "SceneData.zip"), "fb46e4694cc88886fc785704e891a68a", ) prefix = "SceneData" @@ -55,7 +58,7 @@ def __init__(self, data_root: str = None): class EmptyRoom(o3d.data.DownloadDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "scene_assets/empty_room.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, scene_assets, "empty_room.zip"), "612ffead4fac95114bec2e3812469f96", ) prefix = "EmptyRoom" diff --git a/embodichain/data/assets/w1_assets.py b/embodichain/data/assets/w1_assets.py index c3aeab79..a3e7875f 100644 --- a/embodichain/data/assets/w1_assets.py +++ b/embodichain/data/assets/w1_assets.py @@ -48,6 +48,9 @@ # ====================================================================== +w1_assets = "dexforce_w1" + + class DexforceW1V021(EmbodiChainDataset): """Dataset class for the Dexforce W1 V021. @@ -62,7 +65,7 @@ class DexforceW1V021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/DexforceW1V021.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, w1_assets, "DexforceW1V021.zip"), "3cc3a0bfd1c50ebed5bee9dadeee6756", ) prefix = "DexforceW1V021" @@ -86,7 +89,8 @@ def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( os.path.join( EMBODICHAIN_DOWNLOAD_PREFIX, - "dexforce_w1/DexforceW1V021_INDUSTRIAL_DH_PGC_GRIPPER_M.zip", + w1_assets, + "DexforceW1V021_INDUSTRIAL_DH_PGC_GRIPPER_M.zip", ), "06ec5dfa76dc69160d7ff9bc537a6a7b", ) @@ -111,7 +115,8 @@ def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( os.path.join( EMBODICHAIN_DOWNLOAD_PREFIX, - "dexforce_w1/DexforceW1V021_ANTHROPOMORPHIC_BRAINCO_HAND_REVO1.zip", + w1_assets, + "DexforceW1V021_ANTHROPOMORPHIC_BRAINCO_HAND_REVO1.zip", ), "ef19d247799e79233863b558c47b32cd", ) @@ -124,9 +129,7 @@ def __init__(self, data_root: str = None): class DexforceW1ChassisV021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join( - EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/W1_Chassis_v021.zip" - ), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, w1_assets, "W1_Chassis_v021.zip"), "6b0517a4d92a572988641d46269d063f", ) prefix = "DexforceW1ChassisV021" @@ -138,7 +141,7 @@ def __init__(self, data_root: str = None): class DexforceW1TorsoV021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/W1_Torso_v021.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, w1_assets, "W1_Torso_v021.zip"), "4f762a3ae6ef2acbe484c915cf80da7b", ) prefix = "DexforceW1TorsoV021" @@ -150,7 +153,7 @@ def __init__(self, data_root: str = None): class DexforceW1EyesV021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/W1_Eyes_v021.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, w1_assets, "W1_Eyes_v021.zip"), "80e0b86ef2e934f439c99b79074f6f3c", ) prefix = "DexforceW1EyesV021" @@ -162,7 +165,7 @@ def __init__(self, data_root: str = None): class DexforceW1HeadV021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( - os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/W1_Head_v021.zip"), + os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, w1_assets, "W1_Head_v021.zip"), "ba72805828c5fd62ad55d6a1458893d0", ) prefix = "DexforceW1HeadV021" @@ -175,7 +178,7 @@ class DexforceW1LeftArm1V021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( os.path.join( - EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/W1_LeftArm_1_v021.zip" + EMBODICHAIN_DOWNLOAD_PREFIX, w1_assets, "W1_LeftArm_1_v021.zip" ), "c3cacda7bd36389ed98620047bff6216", ) @@ -189,7 +192,7 @@ class DexforceW1RightArm1V021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( os.path.join( - EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/W1_RightArm_1_v021.zip" + EMBODICHAIN_DOWNLOAD_PREFIX, w1_assets, "W1_RightArm_1_v021.zip" ), "456c9495748171003246a3f6626bb0db", ) @@ -203,7 +206,7 @@ class DexforceW1LeftArm2V021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( os.path.join( - EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/W1_LeftArm_2_v021.zip" + EMBODICHAIN_DOWNLOAD_PREFIX, w1_assets, "W1_LeftArm_2_v021.zip" ), "b99bd0587cc9a36fed3cdaa4f9fd62e7", ) @@ -217,7 +220,7 @@ class DexforceW1RightArm2V021(EmbodiChainDataset): def __init__(self, data_root: str = None): data_descriptor = o3d.data.DataDescriptor( os.path.join( - EMBODICHAIN_DOWNLOAD_PREFIX, "dexforce_w1/W1_RightArm_2_v021.zip" + EMBODICHAIN_DOWNLOAD_PREFIX, w1_assets, "W1_RightArm_2_v021.zip" ), "d9f25b2d5244ca5a859040327273a99e", ) diff --git a/pyproject.toml b/pyproject.toml index 77f568cf..9653c7b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ version = "0.0.1" description = "An end-to-end, GPU-accelerated, and modular platform for building generalized Embodied Intelligence." readme = "README.md" authors = [ { name = "EmbodiChain Developers" } ] -requires-python = ">=3.9" +requires-python = ">=3.10" # Core install dependencies (kept from requirements.txt). Some VCS links are diff --git a/tests/sim/objects/test_articulation.py b/tests/sim/objects/test_articulation.py index f159f2c3..b3ecae8b 100644 --- a/tests/sim/objects/test_articulation.py +++ b/tests/sim/objects/test_articulation.py @@ -29,7 +29,7 @@ from embodichain.data import get_data_path from dexsim.types import ActorType -ART_PATH = "AiLiMu_BoxDrawer/AiLiMu_BoxDrawer.urdf" +ART_PATH = "SlidingBoxDrawer/SlidingBoxDrawer.urdf" NUM_ARENAS = 10 diff --git a/tests/sim/sensors/test_camera.py b/tests/sim/sensors/test_camera.py index 8e578177..b8999949 100644 --- a/tests/sim/sensors/test_camera.py +++ b/tests/sim/sensors/test_camera.py @@ -26,7 +26,7 @@ NUM_ENVS = 4 -ART_PATH = "AiLiMu_BoxDrawer/AiLiMu_BoxDrawer.urdf" +ART_PATH = "SlidingBoxDrawer/SlidingBoxDrawer.urdf" class CameraTest: @@ -113,6 +113,7 @@ def test_attach_to_parent(self): self.art: Articulation = self.sim.add_articulation( cfg=ArticulationCfg.from_dict(cfg_dict) ) + # from IPython import embed; embed() self.camera: Camera = self.sim.add_sensor( sensor_cfg=CameraCfg( uid="test", extrinsics=CameraCfg.ExtrinsicsCfg(parent="handle_xpos") @@ -151,3 +152,4 @@ def setup_method(self): if __name__ == "__main__": test = CameraTest() test.setup_simulation("cpu", enable_rt=False) + test.test_attach_to_parent() From d45503f76c3fa416138f96a47eda3682b9a6b794 Mon Sep 17 00:00:00 2001 From: Haonan Yuan Date: Fri, 5 Dec 2025 19:47:02 +0800 Subject: [PATCH 21/92] add solver and motion generator docs (#31) Co-authored-by: yuanhaonan --- docs/source/tutorial/motion_gen.rst | 16 ++- docs/source/tutorial/solver.rst | 54 +++++----- examples/sim/planners/motion_generator.py | 16 +++ scripts/tutorials/sim/motion_generator.py | 121 ++++++++++++++++++++++ scripts/tutorials/sim/srs_solver.py | 85 +++++++++++++++ 5 files changed, 264 insertions(+), 28 deletions(-) create mode 100644 scripts/tutorials/sim/motion_generator.py create mode 100644 scripts/tutorials/sim/srs_solver.py diff --git a/docs/source/tutorial/motion_gen.rst b/docs/source/tutorial/motion_gen.rst index 712a314a..b8d7ee5c 100644 --- a/docs/source/tutorial/motion_gen.rst +++ b/docs/source/tutorial/motion_gen.rst @@ -6,9 +6,6 @@ Motion Generator .. currentmodule:: embodichain.lab.sim.planners.motion_generator -Overview -~~~~~~~~ - The ``MotionGenerator`` class in EmbodiChain provides a unified and extensible interface for robot trajectory planning. It supports time-optimal trajectory generation (currently via TOPPRA), joint/Cartesian interpolation, and is designed for easy integration with RL, imitation learning, and classical control scenarios. Key Features @@ -20,6 +17,19 @@ Key Features - **Extensible**: Easy to add new planners (RRT, PRM, etc.) - **Integration Ready**: Can be used in RL, imitation learning, or classical pipelines + +The Code +~~~~~~~~ + +The tutorial corresponds to the ``motion_generator.py`` script in the ``scripts/tutorials/sim`` directory. + +.. dropdown:: Code for motion_generator.py + :icon: code + + .. literalinclude:: ../../../scripts/tutorials/sim/motion_generator.py + :language: python + :linenos: + Typical Usage ~~~~~~~~~~~~~ diff --git a/docs/source/tutorial/solver.rst b/docs/source/tutorial/solver.rst index dd190f01..b3c95807 100644 --- a/docs/source/tutorial/solver.rst +++ b/docs/source/tutorial/solver.rst @@ -19,17 +19,26 @@ Key Features - **Batch and Single Query**: Supports both batch and single FK/IK/Jacobian queries. - **Extensible**: New solvers can be added by subclassing `BaseSolver` and implementing required methods. -Example: Using PinkSolver -~~~~~~~~~~~~~~~~~~~~~~~~~ +The Code +~~~~~~~~ +The tutorial corresponds to the ``srs_solver.py`` script in the ``scripts/tutorials/sim`` directory. -.. code-block:: python +.. dropdown:: Code for srs_solver.py + :icon: code + + .. literalinclude:: ../../../scripts/tutorials/sim/srs_solver.py + :language: python + :linenos: - from embodichain.lab.sim.solvers import PinkSolverCfg - from embodichain.lab.sim.objects.robot import Robot +Typical Usage +~~~~~~~~~~~~~~~~~~~~~~~~ - # 1. Configure PinkSolver - pink_cfg = PinkSolverCfg( +**Step 1: Configure solver** + +.. code-block:: python + + srs_cfg = SrsSolverCfg( urdf_path="/path/to/robot.urdf", joint_names=[ "shoulder_pan_joint", "shoulder_lift_joint", "elbow_joint", @@ -38,17 +47,21 @@ Example: Using PinkSolver end_link_name="ee_link", root_link_name="base_link" ) - # 2. Assign solver config to robot config - robot_cfg.solver_cfg = pink_cfg - # 3. Instantiate robot (solver will be initialized automatically) + +**Step 2: Instantiate the robot with solver** + +.. code-block:: python + + robot_cfg.solver_cfg = srs_cfg robot = Robot(cfg=robot_cfg, entities=[], device="cpu") - # 4. Use FK/IK/Jacobian - qpos = [0.0, -1.57, 1.57, 0.0, 1.57, 0.0] # 6-DOF joint angles (radians) - ee_pose = robot.compute_fk(qpos) # Forward kinematics, returns 4x4 matrix - print("End-effector pose (FK):\n", ee_pose) +**Step 3: Use FK/IK/Jacobian** + +.. code-block:: python + + qpos = [0.0, -1.57, 1.57, 0.0, 1.57, 0.0] + ee_pose = robot.compute_fk(qpos) - import numpy as np target_pose = np.array([ [0, -1, 0, 0.5], [1, 0, 0, 0.2], @@ -56,11 +69,8 @@ Example: Using PinkSolver [0, 0, 0, 1.0] ]) success, qpos_sol = robot.compute_ik(target_pose, joint_seed=qpos) - print("IK success:", success) - print("IK solution:", qpos_sol) - J = robot.get_solver().get_jacobian(qpos) - print("Jacobian:\n", J) + **Note** @@ -88,12 +98,6 @@ API Reference - **set_position_limits / get_position_limits**: Set or get joint position limits. - **set_tcp / get_tcp**: Set or get the tool center point (TCP) transformation. -**PinkSolver** - -- Implements all BaseSolver methods using the Pink library. -- Supports custom task lists, solver type selection, and joint limit handling. -- See PinkSolverCfg for all configuration options. - Configuration ~~~~~~~~~~~~~ diff --git a/examples/sim/planners/motion_generator.py b/examples/sim/planners/motion_generator.py index 4557f6d1..d767aba3 100644 --- a/examples/sim/planners/motion_generator.py +++ b/examples/sim/planners/motion_generator.py @@ -1,3 +1,19 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + import time import torch import numpy as np diff --git a/scripts/tutorials/sim/motion_generator.py b/scripts/tutorials/sim/motion_generator.py new file mode 100644 index 00000000..c09a1ed3 --- /dev/null +++ b/scripts/tutorials/sim/motion_generator.py @@ -0,0 +1,121 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import time +import torch +import numpy as np +from copy import deepcopy +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim.robots import CobotMagicCfg +from embodichain.lab.sim.planners.utils import TrajectorySampleMethod +from embodichain.lab.sim.planners.motion_generator import MotionGenerator + + +def move_robot_along_trajectory( + robot: Robot, arm_name: str, qpos_list: list[torch.Tensor], delay: float = 0.1 +): + """ + Set the robot joint positions sequentially along the given joint trajectory. + Args: + robot: Robot instance. + arm_name: Name of the robot arm. + qpos_list: List of joint positions (torch.Tensor). + delay: Time delay between each step (seconds). + """ + for q in qpos_list: + robot.set_qpos(qpos=q.unsqueeze(0), joint_ids=robot.get_joint_ids(arm_name)) + time.sleep(delay) + + +def create_demo_trajectory( + robot: Robot, arm_name: str +) -> tuple[list[torch.Tensor], list[np.ndarray]]: + """ + Generate a three-point trajectory (start, middle, end) for demonstration. + Args: + robot: Robot instance. + arm_name: Name of the robot arm. + Returns: + qpos_list: List of joint positions (torch.Tensor). + xpos_list: List of end-effector poses (numpy arrays). + """ + qpos_fk = torch.tensor( + [[0.0, np.pi / 4, -np.pi / 4, 0.0, np.pi / 4, 0.0]], dtype=torch.float32 + ) + xpos_begin = robot.compute_fk(name=arm_name, qpos=qpos_fk, to_matrix=True) + xpos_mid = deepcopy(xpos_begin) + xpos_mid[0, 2, 3] -= 0.1 # Move down by 0.1m in Z direction + xpos_final = deepcopy(xpos_mid) + xpos_final[0, 0, 3] += 0.2 # Move forward by 0.2m in X direction + + qpos_begin = robot.compute_ik(pose=xpos_begin, name=arm_name)[1][0] + qpos_mid = robot.compute_ik(pose=xpos_mid, name=arm_name)[1][0] + qpos_final = robot.compute_ik(pose=xpos_final, name=arm_name)[1][0] + return [qpos_begin, qpos_mid, qpos_final], [ + xpos_begin[0], + xpos_mid[0], + xpos_final[0], + ] + + +def main(): + np.set_printoptions(precision=5, suppress=True) + torch.set_printoptions(precision=5, sci_mode=False) + + # Initialize simulation + sim = SimulationManager(SimulationManagerCfg(headless=False, sim_device="cpu")) + sim.build_multiple_arenas(1) + sim.set_manual_update(False) + + # Robot configuration + cfg_dict = {"uid": "CobotMagic"} + robot: Robot = sim.add_robot(cfg=CobotMagicCfg.from_dict(cfg_dict)) + arm_name = "left_arm" + + # # Generate trajectory points + qpos_list, xpos_list = create_demo_trajectory(robot, arm_name) + + # Initialize motion generator + motion_generator = MotionGenerator( + robot=robot, + uid=arm_name, + planner_type="toppra", + default_velocity=0.2, + default_acceleration=0.5, + ) + + # Joint space trajectory + out_qpos_list, _ = motion_generator.create_discrete_trajectory( + qpos_list=[q.numpy() for q in qpos_list], + is_linear=False, + sample_method=TrajectorySampleMethod.QUANTITY, + sample_num=20, + ) + move_robot_along_trajectory(robot, arm_name, out_qpos_list) + + # Cartesian space trajectory + out_qpos_list, _ = motion_generator.create_discrete_trajectory( + xpos_list=[x.numpy() for x in xpos_list], + is_linear=True, + sample_method=TrajectorySampleMethod.QUANTITY, + sample_num=20, + ) + move_robot_along_trajectory(robot, arm_name, out_qpos_list) + + +if __name__ == "__main__": + main() diff --git a/scripts/tutorials/sim/srs_solver.py b/scripts/tutorials/sim/srs_solver.py new file mode 100644 index 00000000..5d9922b3 --- /dev/null +++ b/scripts/tutorials/sim/srs_solver.py @@ -0,0 +1,85 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import time +import numpy as np +import torch + +from IPython import embed + +from embodichain.lab.sim.objects import Robot +from embodichain.lab.sim import SimulationManager, SimulationManagerCfg +from embodichain.lab.sim.robots import DexforceW1Cfg + + +def main(): + # Set print options for better readability + np.set_printoptions(precision=5, suppress=True) + torch.set_printoptions(precision=5, sci_mode=False) + + # Initialize simulation + sim_device = "cpu" + sim = SimulationManager( + SimulationManagerCfg( + headless=False, sim_device=sim_device, width=2200, height=1200 + ) + ) + + sim.build_multiple_arenas(1) + sim.set_manual_update(False) + + robot: Robot = sim.add_robot(cfg=DexforceW1Cfg.from_dict({"uid": "dexforce_w1"})) + arm_name = "left_arm" + # Set initial joint positions for left arm + qpos_fk_list = [ + torch.tensor([[0.0, 0.0, 0.0, -np.pi / 2, 0.0, 0.0, 0.0]], dtype=torch.float32), + ] + robot.set_qpos(qpos_fk_list[0], joint_ids=robot.get_joint_ids(arm_name)) + + time.sleep(0.5) + + fk_xpos_batch = torch.cat(qpos_fk_list, dim=0) + + fk_xpos_list = robot.compute_fk(qpos=fk_xpos_batch, name=arm_name, to_matrix=True) + + start_time = time.time() + res, ik_qpos = robot.compute_ik( + pose=fk_xpos_list, + name=arm_name, + # joint_seed=qpos_fk_list[0], + return_all_solutions=True, + ) + end_time = time.time() + print( + f"Batch IK computation time for {len(fk_xpos_list)} poses: {end_time - start_time:.6f} seconds" + ) + + if ik_qpos.dim() == 3: + first_solutions = ik_qpos[:, 0, :] + else: + first_solutions = ik_qpos + robot.set_qpos(first_solutions, joint_ids=robot.get_joint_ids(arm_name)) + + ik_xpos_list = robot.compute_fk(qpos=first_solutions, name=arm_name, to_matrix=True) + + print("fk_xpos_list: ", fk_xpos_list) + print("ik_xpos_list: ", ik_xpos_list) + + embed(header="Test SRSSolver example. Press Ctrl-D to exit.") + + +if __name__ == "__main__": + main() From c458918e85b65a8bbc481e59840f5845ef468c6c Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Mon, 8 Dec 2025 03:12:44 +0000 Subject: [PATCH 22/92] Add camera extrinsics randomization functor (#32) --- README.md | 4 +- configs/gym/cobotmagic.json | 1 + embodichain/lab/gym/envs/managers/events.py | 8 +- .../lab/gym/envs/managers/observations.py | 11 +- .../envs/managers/randomization/rendering.py | 129 +++++++++++++++++- .../envs/managers/randomization/spatial.py | 3 + embodichain/lab/sim/objects/gizmo.py | 2 +- embodichain/lab/sim/objects/rigid_object.py | 17 +++ embodichain/lab/sim/sim_manager.py | 57 ++------ pyproject.toml | 1 - 10 files changed, 176 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index a72f0e77..5e3a0215 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ - # EmbodiChain ![teaser](assets/imgs/teaser.jpg) -[![Version](https://img.shields.io/badge/version-0.0.1-blue.svg)](https://github.com/DexForce/EmbodiChain/releases) [![License](https://img.shields.io/github/license/DexForce/EmbodiChain)](LICENSE) [![GitHub Pages](https://img.shields.io/badge/GitHub%20Pages-docs-blue?logo=github&logoColor=white)](https://dexforce.github.io/EmbodiChain/introduction.html) +[![Python](https://img.shields.io/badge/python-3.10-blue.svg)](https://docs.python.org/3/whatsnew/3.10.html) +[![Version](https://img.shields.io/badge/version-0.0.1-blue.svg)](https://github.com/DexForce/EmbodiChain/releases) --- diff --git a/configs/gym/cobotmagic.json b/configs/gym/cobotmagic.json index 6eef0718..a12c749a 100644 --- a/configs/gym/cobotmagic.json +++ b/configs/gym/cobotmagic.json @@ -59,6 +59,7 @@ }, "sensor": [ { + "uid": "camera_1", "sensor_type": "Camera", "width": 640, "height": 480, diff --git a/embodichain/lab/gym/envs/managers/events.py b/embodichain/lab/gym/envs/managers/events.py index 041b9faa..0b65d49f 100644 --- a/embodichain/lab/gym/envs/managers/events.py +++ b/embodichain/lab/gym/envs/managers/events.py @@ -111,13 +111,13 @@ def __init__(self, cfg: FunctorCfg, env: EmbodiedEnv): # remove regular expression from patterns patterns = remove_regex_chars(patterns) - full_path = get_data_path(f"{folder_path}/") + self._full_path = get_data_path(f"{folder_path}/") self._asset_group_path = get_all_files_in_directory( - full_path, patterns=patterns + self._full_path, patterns=patterns ) else: - full_path = get_data_path(folder_path) - self._asset_group_path = get_all_files_in_directory(full_path) + self._full_path = get_data_path(folder_path) + self._asset_group_path = get_all_files_in_directory(self._full_path) def __call__( self, diff --git a/embodichain/lab/gym/envs/managers/observations.py b/embodichain/lab/gym/envs/managers/observations.py index 86280c60..2e48d47b 100644 --- a/embodichain/lab/gym/envs/managers/observations.py +++ b/embodichain/lab/gym/envs/managers/observations.py @@ -40,6 +40,9 @@ def get_rigid_object_pose( ) -> torch.Tensor: """Get the world poses of the rigid objects in the environment. + If the rigid object with the specified UID does not exist in the environment, + a zero tensor will be returned. + Args: env: The environment instance. obs: The observation dictionary. @@ -49,6 +52,9 @@ def get_rigid_object_pose( A tensor of shape (num_envs, 4, 4) representing the world poses of the rigid objects. """ + if entity_cfg.uid not in env.sim.get_rigid_object_uid_list(): + return torch.zeros((env.num_envs, 4, 4), dtype=torch.float32) + obj = env.sim.get_rigid_object(entity_cfg.uid) return obj.get_local_pose(to_matrix=True) @@ -130,7 +136,10 @@ def compute_semantic_mask( robot_mask = (mask_exp == robot_uids_exp).any(-1).squeeze_(-1) - foreground_assets = [env.sim.get_asset(uid) for uid in foreground_uids] + asset_uids = env.sim.asset_uids + foreground_assets = [ + env.sim.get_asset(uid) for uid in foreground_uids if uid in asset_uids + ] # cat assets uid (num_envs, n) into dim 1 foreground_uids = torch.cat( diff --git a/embodichain/lab/gym/envs/managers/randomization/rendering.py b/embodichain/lab/gym/envs/managers/randomization/rendering.py index 7c0aed82..d0626917 100644 --- a/embodichain/lab/gym/envs/managers/randomization/rendering.py +++ b/embodichain/lab/gym/envs/managers/randomization/rendering.py @@ -31,7 +31,11 @@ VisualMaterialCfg, ) from embodichain.utils.string import resolve_matching_names -from embodichain.utils.math import sample_uniform +from embodichain.utils.math import ( + sample_uniform, + quat_from_euler_xyz, + euler_xyz_from_quat, +) from embodichain.utils import logger from embodichain.data import get_data_path @@ -40,12 +44,135 @@ __all__ = [ + "randomize_camera_extrinsics", "randomize_light", "randomize_camera_intrinsics", "randomize_visual_material", ] +def randomize_camera_extrinsics( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + pos_range: Optional[tuple[list[float], list[float]]] = None, + euler_range: Optional[tuple[list[float], list[float]]] = None, + eye_range: Optional[tuple[list[float], list[float]]] = None, + target_range: Optional[tuple[list[float], list[float]]] = None, + up_range: Optional[tuple[list[float], list[float]]] = None, +) -> None: + """ + Randomize camera extrinsic properties (position and orientation). + + Behavior: + - If extrinsics config has a parent field (attach mode), pos_range/euler_range are used to perturb the initial pose (pos, quat), + and set_local_pose is called to attach the camera to the parent node. In this case, pose is related to parent. + - If extrinsics config uses eye/target/up (no parent), eye_range/target_range/up_range are used to perturb the initial eye, target, up vectors, + and look_at is called to set the camera orientation. + + Args: + env: The environment instance. + env_ids: The environment IDs to apply the randomization. + entity_cfg (SceneEntityCfg): The configuration of the scene entity to randomize. + pos_range: Position perturbation range (attach mode). + euler_range: Euler angle perturbation range (attach mode). + eye_range: Eye position perturbation range (look_at mode). + target_range: Target position perturbation range (look_at mode). + up_range: Up vector perturbation range (look_at mode). + """ + camera: Union[Camera, StereoCamera] = env.sim.get_sensor(entity_cfg.uid) + num_instance = len(env_ids) + + extrinsics = camera.cfg.extrinsics + + if extrinsics.parent is not None: + # If extrinsics has a parent field, use pos/euler perturbation and attach camera to parent node + init_pos = getattr(extrinsics, "pos", [0.0, 0.0, 0.0]) + init_quat = getattr(extrinsics, "quat", [0.0, 0.0, 0.0, 1.0]) + new_pose = torch.tensor( + [init_pos + init_quat], dtype=torch.float32, device=env.device + ).repeat(num_instance, 1) + if pos_range: + random_value = sample_uniform( + lower=torch.tensor(pos_range[0]), + upper=torch.tensor(pos_range[1]), + size=(num_instance, 3), + ) + new_pose[:, :3] += random_value + if euler_range: + # 1. quat -> euler + init_quat_np = ( + torch.tensor(init_quat, dtype=torch.float32, device=env.device) + .unsqueeze_(0) + .repeat(num_instance, 1) + ) + init_euler = euler_xyz_from_quat(init_quat_np) + # 2. Sample perturbation for euler angles + random_value = sample_uniform( + lower=torch.tensor(euler_range[0]), + upper=torch.tensor(euler_range[1]), + size=(num_instance, 3), + ) + # 3. Add perturbation to each environment and convert back to quaternion + new_quat = quat_from_euler_xyz(init_euler + random_value) + new_pose[:, 3:7] = new_quat + + camera.set_local_pose(new_pose, env_ids=env_ids) + + elif extrinsics.eye is not None: + # If extrinsics uses eye/target/up, use perturbation for look_at mode + init_eye = ( + torch.tensor(extrinsics.eye, dtype=torch.float32, device=env.device) + .unsqueeze(0) + .repeat(num_instance, 1) + ) + init_target = ( + torch.tensor(extrinsics.target, dtype=torch.float32, device=env.device) + .unsqueeze(0) + .repeat(num_instance, 1) + ) + init_up = ( + torch.tensor(extrinsics.up, dtype=torch.float32, device=env.device) + .unsqueeze(0) + .repeat(num_instance, 1) + ) + + if eye_range: + eye_delta = sample_uniform( + lower=torch.tensor(eye_range[0]), + upper=torch.tensor(eye_range[1]), + size=(num_instance, 3), + ) + new_eye = init_eye + eye_delta + else: + new_eye = init_eye + + if target_range: + target_delta = sample_uniform( + lower=torch.tensor(target_range[0]), + upper=torch.tensor(target_range[1]), + size=(num_instance, 3), + ) + new_target = init_target + target_delta + else: + new_target = init_target + + if up_range: + up_delta = sample_uniform( + lower=torch.tensor(up_range[0]), + upper=torch.tensor(up_range[1]), + size=(num_instance, 3), + ) + new_up = init_up + up_delta + else: + new_up = init_up + + camera.look_at(new_eye, new_target, new_up, env_ids=env_ids) + + else: + logger.log_error("Unsupported extrinsics format for camera randomization.") + + def randomize_light( env: EmbodiedEnv, env_ids: Union[torch.Tensor, None], diff --git a/embodichain/lab/gym/envs/managers/randomization/spatial.py b/embodichain/lab/gym/envs/managers/randomization/spatial.py index 70bcabe8..65ab422e 100644 --- a/embodichain/lab/gym/envs/managers/randomization/spatial.py +++ b/embodichain/lab/gym/envs/managers/randomization/spatial.py @@ -121,6 +121,9 @@ def randomize_rigid_object_pose( relative_rotation (bool): Whether to randomize the rotation relative to the object's initial rotation. Default is False. """ + if entity_cfg.uid not in env.sim.get_rigid_object_uid_list(): + return + rigid_object: RigidObject = env.sim.get_rigid_object(entity_cfg.uid) num_instance = len(env_ids) diff --git a/embodichain/lab/sim/objects/gizmo.py b/embodichain/lab/sim/objects/gizmo.py index 27ebf5bf..1caa1102 100644 --- a/embodichain/lab/sim/objects/gizmo.py +++ b/embodichain/lab/sim/objects/gizmo.py @@ -331,7 +331,7 @@ def _update_robot_ik(self, target_transform: torch.Tensor): new_qpos = new_qpos.unsqueeze(0) # Make it (1, dof) for set_qpos # Update robot joint positions - self.target.set_qpos(qpos=new_qpos, joint_ids=current_joint_ids) + self.target.set_qpos(qpos=new_qpos[0], joint_ids=current_joint_ids) return True else: logger.log_warning("IK solution not found") diff --git a/embodichain/lab/sim/objects/rigid_object.py b/embodichain/lab/sim/objects/rigid_object.py index d5b4bb6e..047df410 100644 --- a/embodichain/lab/sim/objects/rigid_object.py +++ b/embodichain/lab/sim/objects/rigid_object.py @@ -516,6 +516,23 @@ def get_visual_material_inst( ids = env_ids if env_ids is not None else range(self.num_instances) return [self._visual_material[i] for i in ids] + def share_visual_material_inst(self, mat_insts: List[VisualMaterialInst]) -> None: + """Share material instances for the rigid object. + + Args: + mat_insts (List[VisualMaterialInst]): List of material instances to share. + """ + if len(self._entities) != len(mat_insts): + logger.log_error( + f"Length of entities {len(self._entities)} does not match length of material instances {len(mat_insts)}." + ) + + for i, entity in enumerate(self._entities): + if mat_insts[i] is None: + continue + entity.set_material(mat_insts[i].mat) + self._visual_material[i] = mat_insts[i] + def get_body_scale(self, env_ids: Optional[Sequence[int]] = None) -> torch.Tensor: """ Retrieve the body scale for specified environment instances. diff --git a/embodichain/lab/sim/sim_manager.py b/embodichain/lab/sim/sim_manager.py index 39c5c9e0..0489fde0 100644 --- a/embodichain/lab/sim/sim_manager.py +++ b/embodichain/lab/sim/sim_manager.py @@ -143,21 +143,12 @@ class SimulationManager: This class is used to manage the global simulation environment and simulated assets. - assets loading, creation, modification and deletion. - - assets include robots, fixed actors, dynamic actors and background. + - assets include rigid objects, soft objects, articulations, robots, sensors and lights. - manager the scenes and the simulation environment. - parallel scenes simulation on both CPU and GPU. - - sensors arrangement - - lighting and indirect lighting - - physics simulation parameters control - - ... - - Note: - 1. The arena is used as a standalone space for robots to simulate in. When :meth:`build_multiple_arenas` is called, - it will create multiple arenas in a grid pattern. Meanwhile, each simulation assets adding interface will - take an additional parameter `arena_index` to specify which arena to place the asset. The name of the asset to - be added will be appended with the arena index to avoid name conflict. - 2. In GUI mode, the physics will be set to a fps (or a wait time for manual mode) for better visualization. - + - create and setup the rendering related settings, eg. environment map, lighting, materials, etc. + - physics simulation management, eg. time step, manual update, etc. + - interactive control via gizmo and window callbacks events. Args: sim_config (SimulationManagerCfg, optional): simulation configuration. Defaults to SimulationManagerCfg(). @@ -199,11 +190,8 @@ def __init__( self._world.set_delta_time(sim_config.physics_dt) self._world.show_coordinate_axis(False) - if sys.platform == "linux": - dexsim.set_physics_config(**sim_config.physics_config.to_dexsim_args()) - dexsim.set_physics_gpu_memory_config( - **sim_config.gpu_memory_config.to_dict() - ) + dexsim.set_physics_config(**sim_config.physics_config.to_dexsim_args()) + dexsim.set_physics_gpu_memory_config(**sim_config.gpu_memory_config.to_dict()) self._is_initialized_gpu_physics = False self._ps = self._world.get_physics_scene() @@ -216,9 +204,10 @@ def __init__( self._default_resources = SimResources() # set unique material path to accelerate material creation. + # TODO: This will be removed. if self.sim_config.enable_rt is False: self._env.set_unique_mat_path( - os.path.join(self._material_cache_dir, "dexsim_mat") + os.path.join(self._material_cache_dir, "default_mat") ) # arena is used as a standalone space for robots to simulate in. @@ -661,6 +650,8 @@ def get_asset( return self._rigid_objects[uid] if uid in self._rigid_object_groups: return self._rigid_object_groups[uid] + if uid in self._soft_objects: + return self._soft_objects[uid] if uid in self._articulations: return self._articulations[uid] @@ -1261,34 +1252,6 @@ def remove_asset(self, uid: str) -> bool: return False - def get_asset( - self, uid: str - ) -> Optional[Union[RigidObject, Articulation, Robot, Light, BaseSensor]]: - """Get an asset by its UID. - - The asset can be a rigid object, articulation or robot. - - Args: - uid (str): The UID of the asset. - """ - if uid in self._rigid_objects: - return self._rigid_objects[uid] - - if uid in self._articulations: - return self._articulations[uid] - - if uid in self._robots: - return self._robots[uid] - - if uid in self._lights: - return self._lights[uid] - - if uid in self._sensors: - return self._sensors[uid] - - logger.log_warning(f"Asset {uid} not found.") - return None - def draw_marker( self, cfg: MarkerCfg, diff --git a/pyproject.toml b/pyproject.toml index 9653c7b4..d95744c7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,6 @@ dependencies = [ "cvxpy==1.4.0", "ortools", "prettytable", - "hdfdict@git+http://69.235.177.182:8081/externalrepo/hdfdict", "black==24.3.0", "h5py", ] From 85feeb92432a3919211b0dcff62f1aad89b2802b Mon Sep 17 00:00:00 2001 From: Chen Jian Date: Fri, 12 Dec 2025 10:14:44 +0800 Subject: [PATCH 23/92] upgrade to dexsim 0.3.7 (#33) Co-authored-by: chenjian --- embodichain/lab/sim/objects/gizmo.py | 5 ++--- embodichain/lab/sim/sim_manager.py | 7 ++++--- examples/sim/demo/press_softbody.py | 25 +++++++++++++++++-------- examples/sim/gizmo/gizmo_w1.py | 5 +++-- examples/sim/solvers/pink_solver.py | 4 +--- pyproject.toml | 2 +- 6 files changed, 28 insertions(+), 20 deletions(-) diff --git a/embodichain/lab/sim/objects/gizmo.py b/embodichain/lab/sim/objects/gizmo.py index 1caa1102..8456e295 100644 --- a/embodichain/lab/sim/objects/gizmo.py +++ b/embodichain/lab/sim/objects/gizmo.py @@ -40,7 +40,6 @@ RigidBodyShape, PhysicalAttr, ) -from dexsim.render import GizmoController from embodichain.lab.sim.utility.gizmo_utils import create_gizmo_callback @@ -421,7 +420,7 @@ def toggle_visibility(self) -> bool: # Apply the visibility setting to the gizmo node if self._gizmo and hasattr(self._gizmo, "node"): - self._gizmo.node.set_physical_visible(self._is_visible, self._is_visible) + self._gizmo.node.set_visible(self._is_visible) return self._is_visible @@ -436,7 +435,7 @@ def set_visibility(self, visible: bool): # Apply the visibility setting to the gizmo node if self._gizmo and hasattr(self._gizmo, "node"): - self._gizmo.node.set_physical_visible(self._is_visible, self._is_visible) + self._gizmo.node.set_visible(self._is_visible) def is_visible(self) -> bool: """ diff --git a/embodichain/lab/sim/sim_manager.py b/embodichain/lab/sim/sim_manager.py index 0489fde0..b5efce4d 100644 --- a/embodichain/lab/sim/sim_manager.py +++ b/embodichain/lab/sim/sim_manager.py @@ -46,7 +46,7 @@ from dexsim.engine import CudaArray, Material from dexsim.models import MeshObject from dexsim.render import Light as _Light, LightType -from dexsim.render import GizmoController +from dexsim.engine import GizmoController from embodichain.lab.sim.objects import ( RigidObject, @@ -1037,12 +1037,13 @@ def enable_gizmo( # Initialize GizmoController if not already done. if not hasattr(self, "_gizmo_controller") or self._gizmo_controller is None: - windows = ( + window = ( self._world.get_windows() if hasattr(self._world, "get_windows") else None ) - self._gizmo_controller = GizmoController(windows) + self._gizmo_controller = GizmoController() + window.add_input_control(self._gizmo_controller) except Exception as e: logger.log_error( diff --git a/examples/sim/demo/press_softbody.py b/examples/sim/demo/press_softbody.py index 79c33133..9f4ff44e 100644 --- a/examples/sim/demo/press_softbody.py +++ b/examples/sim/demo/press_softbody.py @@ -39,6 +39,7 @@ SoftObjectCfg, SoftbodyVoxelAttributesCfg, SoftbodyPhysicalAttributesCfg, + URDFCfg, ) from embodichain.lab.sim.shapes import MeshCfg @@ -100,12 +101,19 @@ def create_robot(sim: SimulationManager): # Configure the robot with its components and control properties cfg = RobotCfg( uid="UR10", - fpath=ur10_urdf_path, - solver_cfg=PytorchSolverCfg( - end_link_name="ee_link", - root_link_name="base_link", - tcp=np.eye(4), + urdf_cfg=URDFCfg( + components=[{"component_type": "arm", "urdf_path": ur10_urdf_path}] ), + control_parts={ + "arm": ["Joint[0-9]"], + }, + solver_cfg={ + "arm": PytorchSolverCfg( + end_link_name="ee_link", + root_link_name="base_link", + tcp=np.eye(4), + ) + }, init_qpos=[ 0.0, -np.pi / 2, @@ -133,13 +141,14 @@ def create_soft_cow(sim: SimulationManager) -> SoftObject: shape=MeshCfg( fpath=get_resources_data_path("Model", "cow", "cow2.obj"), ), - init_pos=[0.5, 0.0, 0.3], + init_rot=[0, 90, 0], + init_pos=[0.45, -0.1, 0.12], voxel_attr=SoftbodyVoxelAttributesCfg( simulation_mesh_resolution=8, maximal_edge_length=0.5, ), physical_attr=SoftbodyPhysicalAttributesCfg( - youngs=1e4, + youngs=5e3, poissons=0.45, density=100, dynamic_friction=0.1, @@ -162,7 +171,7 @@ def press_cow(sim: SimulationManager, robot: Robot): arm_start_xpos = robot.compute_fk(arm_start_qpos, name="arm", to_matrix=True) press_xpos = arm_start_xpos.clone() - press_xpos[:, :3, 3] = torch.tensor([0.5, -0.1, 0.01], device=press_xpos.device) + press_xpos[:, :3, 3] = torch.tensor([0.5, -0.1, 0.005], device=press_xpos.device) approach_xpos = press_xpos.clone() approach_xpos[:, 2, 3] += 0.05 diff --git a/examples/sim/gizmo/gizmo_w1.py b/examples/sim/gizmo/gizmo_w1.py index 791582a0..90d73edc 100644 --- a/examples/sim/gizmo/gizmo_w1.py +++ b/examples/sim/gizmo/gizmo_w1.py @@ -104,8 +104,9 @@ def main(): ), }, drive_pros=JointDrivePropertiesCfg( - stiffness={"LEFT_J[1-7]": 1e4, "RIGHT_J[1-7]": 1e4}, - damping={"LEFT_J[1-7]": 1e3, "RIGHT_J[1-7]": 1e3}, + stiffness={"(LEFT|RIGHT)_J[1-7]": 1e4, "(ANKLE|KNEE|BUTTOCK|WAIST)": 1e7}, + damping={"(LEFT|RIGHT)_J[1-7]": 1e3, "(ANKLE|KNEE|BUTTOCK|WAIST)": 1e4}, + max_effort={"(LEFT|RIGHT)_J[1-7]": 1e5, "(ANKLE|KNEE|BUTTOCK|WAIST)": 1e10}, ), ) robot = sim.add_robot(cfg=robot_cfg) diff --git a/examples/sim/solvers/pink_solver.py b/examples/sim/solvers/pink_solver.py index 8ad325fe..aea419cd 100644 --- a/examples/sim/solvers/pink_solver.py +++ b/examples/sim/solvers/pink_solver.py @@ -149,9 +149,7 @@ def main(): if ik_qpos.dim() == 3: robot.set_qpos(qpos=ik_qpos[0][0], joint_ids=robot.get_joint_ids(arm_name)) else: - robot.set_qpos( - qpos=ik_qpos.unsqueeze(0), joint_ids=robot.get_joint_ids(arm_name) - ) + robot.set_qpos(qpos=ik_qpos, joint_ids=robot.get_joint_ids(arm_name)) # Visualize current pose ik_xpos = robot.compute_fk(qpos=ik_qpos, name=arm_name, to_matrix=True) diff --git a/pyproject.toml b/pyproject.toml index d95744c7..ff55dae3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,7 @@ requires-python = ">=3.10" # Core install dependencies (kept from requirements.txt). Some VCS links are # specified using PEP 508 direct references where present. dependencies = [ - "dexsim_engine @ http://pyp.open3dv.site:2345/packages/dexsim_engine-0.3.6-cp310-cp310-manylinux_2_31_x86_64.whl", + "dexsim_engine @ http://pyp.open3dv.site:2345/packages/dexsim_engine-0.3.7-cp310-cp310-manylinux_2_31_x86_64.whl", "setuptools>=78.1.1", "gymnasium==0.29.1", "casadi==3.7.1", From cfa0fa0044d1c1ab3525b45eae72d87a3209789f Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Sun, 14 Dec 2025 04:50:46 +0000 Subject: [PATCH 24/92] Update rendering related functors (#34) --- .github/workflows/main.yml | 3 +- embodichain/data/enum.py | 17 ++++- .../lab/gym/envs/managers/observations.py | 15 ++++- .../envs/managers/randomization/rendering.py | 26 ++++---- embodichain/lab/sim/__init__.py | 5 ++ embodichain/lab/sim/cfg.py | 8 ++- embodichain/lab/sim/objects/__init__.py | 48 ++++++++++++++ embodichain/lab/sim/utility/dynamic_pybind.py | 65 +++++++++++++++++++ embodichain/lab/sim/utility/sim_utils.py | 11 +++- 9 files changed, 182 insertions(+), 16 deletions(-) create mode 100644 embodichain/lab/sim/utility/dynamic_pybind.py diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 40431a98..84ed7706 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -53,7 +53,8 @@ jobs: cd ${GITHUB_WORKSPACE}/docs echo "Start Building docs..." make html - - name: Upload pkg + - name: Upload docs artifact + if: github.event_name == 'push' && github.ref == 'refs/heads/main' uses: actions/upload-pages-artifact@v3 with: path: ${{ github.workspace }}/docs/build/html diff --git a/embodichain/data/enum.py b/embodichain/data/enum.py index 853f08bf..3716b840 100644 --- a/embodichain/data/enum.py +++ b/embodichain/data/enum.py @@ -14,7 +14,22 @@ # limitations under the License. # ---------------------------------------------------------------------------- -from enum import Enum +from enum import Enum, IntEnum + + +class SemanticMask(IntEnum): + """ + SemanticMask is an enumeration representing different semantic regions in an image or scene. + + Attributes: + BACKGROUND (int): Represents the background region (value: 0). + FOREGROUND (int): Represents the foreground objects (value: 1). + ROBOT (int): Represents the robot region (value: 2). + """ + + BACKGROUND = 0 + FOREGROUND = 1 + ROBOT = 2 class EndEffector(Enum): diff --git a/embodichain/lab/gym/envs/managers/observations.py b/embodichain/lab/gym/envs/managers/observations.py index 2e48d47b..faf65100 100644 --- a/embodichain/lab/gym/envs/managers/observations.py +++ b/embodichain/lab/gym/envs/managers/observations.py @@ -116,6 +116,7 @@ def compute_semantic_mask( Returns: A tensor of shape (num_envs, height, width) representing the semantic mask. """ + from embodichain.data.enum import SemanticMask sensor: Union[Camera, StereoCamera] = env.sim.get_sensor(entity_cfg.uid) if sensor.cfg.enable_mask is False: @@ -160,7 +161,19 @@ def compute_semantic_mask( background_mask = ~(robot_mask | foreground_mask).squeeze_(-1) - return torch.stack([robot_mask, background_mask, foreground_mask], dim=-1) + masks = [None, None, None] + masks_ids = [member.value for member in SemanticMask] + assert len(masks) == len( + masks_ids + ), "Different length of mask slots and SemanticMask Enum {}.".format(masks_ids) + mask_id_to_label = { + SemanticMask.BACKGROUND.value: background_mask, + SemanticMask.FOREGROUND.value: foreground_mask, + SemanticMask.ROBOT.value: robot_mask, + } + for mask_id in masks_ids: + masks[mask_id] = mask_id_to_label[mask_id] + return torch.stack(masks, dim=-1) class compute_exteroception(Functor): diff --git a/embodichain/lab/gym/envs/managers/randomization/rendering.py b/embodichain/lab/gym/envs/managers/randomization/rendering.py index d0626917..77d39604 100644 --- a/embodichain/lab/gym/envs/managers/randomization/rendering.py +++ b/embodichain/lab/gym/envs/managers/randomization/rendering.py @@ -379,16 +379,19 @@ def __init__(self, cfg: FunctorCfg, env: EmbodiedEnv): if self.entity_cfg.uid == "default_plane": pass else: - self.entity: Union[RigidObject, Articulation] = env.sim.get_asset( - self.entity_cfg.uid - ) - - if not isinstance(self.entity, (RigidObject, Articulation)): - raise ValueError( - f"Randomization functor 'randomize_visual_material' not supported for asset: '{self.entity_cfg.uid}'" - f" with type: '{type(self.entity)}'." + if self.entity_cfg.uid not in env.sim.asset_uids: + self.entity = None + else: + self.entity: Union[RigidObject, Articulation] = env.sim.get_asset( + self.entity_cfg.uid ) + if not isinstance(self.entity, (RigidObject, Articulation)): + raise ValueError( + f"Randomization functor 'randomize_visual_material' not supported for asset: '{self.entity_cfg.uid}'" + f" with type: '{type(self.entity)}'." + ) + # TODO: Maybe need to consider two cases: # 1. the texture folder is very large, and we don't want to load all the textures into memory. # 2. the texture is generated on the fly. @@ -483,9 +486,7 @@ def _randomize_mat_inst( getattr(mat_inst, f"set_{key}")(value[idx].item()) # randomize texture or base color based on the probability. - if random_texture_prob <= 0.0 or len(self.textures) == 0: - return - if random.random() < random_texture_prob: + if random.random() < random_texture_prob and len(self.textures) != 0: self._randomize_texture(mat_inst) else: # set a random base color instead. @@ -507,6 +508,9 @@ def __call__( ): from embodichain.lab.sim.utility import is_rt_enabled + if self.entity_cfg.uid != "default_plane" and self.entity is None: + return + # resolve environment ids if env_ids is None: env_ids = torch.arange(env.num_envs, device="cpu") diff --git a/embodichain/lab/sim/__init__.py b/embodichain/lab/sim/__init__.py index 9ec8105a..94cfcfc5 100644 --- a/embodichain/lab/sim/__init__.py +++ b/embodichain/lab/sim/__init__.py @@ -16,4 +16,9 @@ from .material import VisualMaterialCfg, VisualMaterial, VisualMaterialInst from .common import BatchEntity + from .sim_manager import * + +from .utility.dynamic_pybind import init_dynamic_pybind + +init_dynamic_pybind() diff --git a/embodichain/lab/sim/cfg.py b/embodichain/lab/sim/cfg.py index 3dc37e1b..55bdfb59 100644 --- a/embodichain/lab/sim/cfg.py +++ b/embodichain/lab/sim/cfg.py @@ -953,6 +953,12 @@ class ArticulationCfg(ObjectBaseCfg): build_pk_chain: bool = True """Whether to build pytorch-kinematics chain for forward kinematics and jacobian computation.""" + compute_uv: bool = False + """Whether to compute the UV mapping for the articulation link. + + Currently, the uv mapping is computed for each link with projection uv mapping method. + """ + @configclass class RobotCfg(ArticulationCfg): @@ -1008,7 +1014,7 @@ def from_dict(cls, init_dict: Dict[str, Union[str, float, tuple]]) -> RobotCfg: setattr( cfg, key, attr.from_dict(value) ) # Call from_dict on the attribute - elif "class_type" in value: + elif isinstance(value, dict) and "class_type" in value: setattr( cfg, key, diff --git a/embodichain/lab/sim/objects/__init__.py b/embodichain/lab/sim/objects/__init__.py index 9c4ba945..d452f453 100644 --- a/embodichain/lab/sim/objects/__init__.py +++ b/embodichain/lab/sim/objects/__init__.py @@ -26,3 +26,51 @@ from .robot import Robot, RobotCfg from .light import Light, LightCfg from .gizmo import Gizmo + + +from dexsim.engine import RenderBody +import numpy as np + + +def set_projective_uv(self: RenderBody, proj_direct: np.ndarray = None): + """Set projective uv mapping to render body. + + Args: + proj_direct (np.ndarray, optional). UV project direction. Default to be None, using svd. + """ + import numpy as np + import open3d as o3d + from dexsim.kit.meshproc import get_mesh_auto_uv + + n_mesh = self.get_mesh_count() + if n_mesh <= 0: + return + n_vert_list = [] + verts = np.empty((0, 3), dtype=np.float32) + faces = np.empty((0, 3), dtype=np.int32) + # gather all vertices + for i in range(n_mesh): + mesh_verts = self.get_vertices(mesh_id=i) + n_vert_list.append(mesh_verts.shape[0]) + verts = np.vstack((verts, mesh_verts)) + + mesh_faces = self.get_triangles(mesh_id=i) + faces = np.vstack((faces, mesh_faces)) + if (verts.shape[0] == 0) or (faces.shape[0] == 0): + return + # project uv for all vertices + mesh_o3dt = o3d.t.geometry.TriangleMesh() + mesh_o3dt.vertex.positions = o3d.core.Tensor(verts, dtype=o3d.core.Dtype.Float32) + mesh_o3dt.triangle.indices = o3d.core.Tensor(faces, dtype=o3d.core.Dtype.Int32) + is_success, vert_uvs = get_mesh_auto_uv(mesh_o3dt, proj_direct) + + # set uv mapping for each mesh + start_idx = 0 + for i in range(n_mesh): + mesh_vert_uvs = vert_uvs[start_idx : start_idx + n_vert_list[i], :] + self.set_uv_mapping(uvs=mesh_vert_uvs, mesh_id=i) + start_idx += n_vert_list[i] + + +# bind this method to dexsim.engine.RenderBody +RenderBody.set_projective_uv = set_projective_uv diff --git a/embodichain/lab/sim/utility/dynamic_pybind.py b/embodichain/lab/sim/utility/dynamic_pybind.py new file mode 100644 index 00000000..e2ad6037 --- /dev/null +++ b/embodichain/lab/sim/utility/dynamic_pybind.py @@ -0,0 +1,65 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import dexsim +import numpy as np + +from dexsim.engine import RenderBody + + +def set_projective_uv(self: RenderBody, proj_direct: np.ndarray | None = None) -> None: + """Set projective uv mapping to render body. + + Args: + proj_direct: UV project direction. Default to be None, using svd. + """ + import open3d as o3d + from dexsim.kit.meshproc import get_mesh_auto_uv + + n_mesh = self.get_mesh_count() + if n_mesh <= 0: + return + n_vert_list = [] + verts = np.empty((0, 3), dtype=np.float32) + faces = np.empty((0, 3), dtype=np.int32) + # gather all vertices + for i in range(n_mesh): + mesh_verts = self.get_vertices(mesh_id=i) + n_vert_list.append(mesh_verts.shape[0]) + verts = np.vstack((verts, mesh_verts)) + + mesh_faces = self.get_triangles(mesh_id=i) + faces = np.vstack((faces, mesh_faces)) + if (verts.shape[0] == 0) or (faces.shape[0] == 0): + return + # project uv for all vertices + mesh_o3dt = o3d.t.geometry.TriangleMesh() + mesh_o3dt.vertex.positions = o3d.core.Tensor(verts, dtype=o3d.core.Dtype.Float32) + mesh_o3dt.triangle.indices = o3d.core.Tensor(faces, dtype=o3d.core.Dtype.Int32) + is_success, vert_uvs = get_mesh_auto_uv(mesh_o3dt, proj_direct) + + # set uv mapping for each mesh + start_idx = 0 + for i in range(n_mesh): + mesh_vert_uvs = vert_uvs[start_idx : start_idx + n_vert_list[i], :] + self.set_uv_mapping(uvs=mesh_vert_uvs, mesh_id=i) + start_idx += n_vert_list[i] + + +def init_dynamic_pybind() -> None: + """Initialize dynamic pybind interface.""" + + RenderBody.set_projective_uv = set_projective_uv diff --git a/embodichain/lab/sim/utility/sim_utils.py b/embodichain/lab/sim/utility/sim_utils.py index c6914807..de98ce22 100644 --- a/embodichain/lab/sim/utility/sim_utils.py +++ b/embodichain/lab/sim/utility/sim_utils.py @@ -100,7 +100,7 @@ def get_drive_type(drive_pros): else: logger.log_error(f"Unknow drive type {drive_type}") - for art in arts: + for i, art in enumerate(arts): art.set_body_scale(cfg.body_scale) art.set_physical_attr(cfg.attrs.attr()) art.set_articulation_flag(ArticulationFlag.FIX_BASE, cfg.fix_base) @@ -118,6 +118,15 @@ def get_drive_type(drive_pros): inertia = np.maximum(inertia, 1e-4) physical_body.set_mass_space_inertia_tensor(inertia) + if i == 0 and cfg.compute_uv: + render_body = art.get_render_body(name) + if render_body: + render_body.set_projective_uv() + + # TODO: will crash when exit if not explicitly delete. + # This may due to the destruction of render body order when exiting. + del render_body + def is_rt_enabled() -> bool: """Check if Ray Tracing rendering backend is enabled in the default dexsim world. From afbe1616301bac189f153c3bb518df9aac90da94 Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Sun, 14 Dec 2025 06:38:32 +0000 Subject: [PATCH 25/92] Change typing `Optional` to `|` to consistent with python 3.10 (#35) --- embodichain/agents/rl/algo/base.py | 4 +- embodichain/agents/rl/algo/ppo.py | 6 +- embodichain/agents/rl/models/mlp.py | 2 +- embodichain/agents/rl/utils/trainer.py | 2 +- .../envs/action_bank/configurable_action.py | 2 +- embodichain/lab/gym/envs/action_bank/utils.py | 6 +- embodichain/lab/gym/envs/base_env.py | 8 +- embodichain/lab/gym/envs/embodied_env.py | 14 +-- .../lab/gym/envs/managers/observations.py | 10 +- .../envs/managers/randomization/rendering.py | 50 ++++----- .../envs/managers/randomization/spatial.py | 34 +++--- .../lab/gym/envs/tasks/rl/push_cube.py | 4 +- .../tasks/tableware/pour_water/action_bank.py | 6 +- .../lab/gym/envs/tasks/tableware/scoop_ice.py | 4 +- embodichain/lab/gym/utils/gym_utils.py | 4 +- embodichain/lab/gym/utils/misc.py | 34 +++--- embodichain/lab/sim/cfg.py | 34 +++--- embodichain/lab/sim/common.py | 11 +- embodichain/lab/sim/material.py | 12 +-- embodichain/lab/sim/objects/articulation.py | 100 +++++++++--------- embodichain/lab/sim/objects/gizmo.py | 6 +- embodichain/lab/sim/objects/light.py | 26 ++--- .../lab/sim/objects/rigid_object_group.py | 24 ++--- embodichain/lab/sim/objects/robot.py | 93 ++++++++-------- embodichain/lab/sim/objects/soft_object.py | 18 ++-- embodichain/lab/sim/planners/base_planner.py | 10 +- .../lab/sim/planners/motion_generator.py | 22 ++-- .../lab/sim/planners/toppra_planner.py | 2 +- embodichain/lab/sim/robots/cobotmagic.py | 6 +- .../lab/sim/robots/dexforce_w1/params.py | 4 +- .../lab/sim/robots/dexforce_w1/utils.py | 26 ++--- embodichain/lab/sim/sensors/base_sensor.py | 6 +- embodichain/lab/sim/sensors/camera.py | 27 +++-- embodichain/lab/sim/sensors/stereo.py | 12 +-- embodichain/lab/sim/shapes.py | 4 +- embodichain/lab/sim/sim_manager.py | 74 ++++++------- embodichain/lab/sim/solvers/base_solver.py | 26 +++-- .../lab/sim/solvers/differential_solver.py | 16 +-- .../sim/solvers/null_space_posture_task.py | 6 +- embodichain/lab/sim/solvers/opw_solver.py | 4 +- embodichain/lab/sim/solvers/pink_solver.py | 22 ++-- .../lab/sim/solvers/pinocchio_solver.py | 22 ++-- embodichain/lab/sim/solvers/pytorch_solver.py | 26 ++--- embodichain/lab/sim/solvers/srs_solver.py | 6 +- embodichain/lab/sim/utility/mesh_utils.py | 14 +-- embodichain/lab/sim/utility/sim_utils.py | 6 +- embodichain/lab/sim/utility/solver_utils.py | 8 +- embodichain/lab/sim/utility/tensor.py | 4 +- .../toolkits/urdf_assembly/component.py | 4 +- .../toolkits/urdf_assembly/logging_utils.py | 3 +- embodichain/toolkits/urdf_assembly/sensor.py | 56 +++++----- .../urdf_assembly/urdf_assembly_manager.py | 8 +- embodichain/utils/cfg.py | 22 ++-- embodichain/utils/configclass.py | 4 +- embodichain/utils/file.py | 10 +- embodichain/utils/math.py | 6 +- embodichain/utils/module_utils.py | 10 +- embodichain/utils/utility.py | 8 +- pyproject.toml | 1 + 59 files changed, 500 insertions(+), 499 deletions(-) diff --git a/embodichain/agents/rl/algo/base.py b/embodichain/agents/rl/algo/base.py index 1cb23309..8d74a918 100644 --- a/embodichain/agents/rl/algo/base.py +++ b/embodichain/agents/rl/algo/base.py @@ -16,7 +16,7 @@ from __future__ import annotations -from typing import Dict, Any, Optional, Callable +from typing import Dict, Any, Callable import torch @@ -42,7 +42,7 @@ def collect_rollout( policy, obs: torch.Tensor, num_steps: int, - on_step_callback: Optional[Callable] = None, + on_step_callback: Callable | None = None, ) -> Dict[str, Any]: """Collect trajectories and return logging info (e.g., reward components).""" raise NotImplementedError diff --git a/embodichain/agents/rl/algo/ppo.py b/embodichain/agents/rl/algo/ppo.py index 2ecc195e..afd636e7 100644 --- a/embodichain/agents/rl/algo/ppo.py +++ b/embodichain/agents/rl/algo/ppo.py @@ -15,7 +15,7 @@ # ---------------------------------------------------------------------------- import torch -from typing import Dict, Any, Tuple, Callable, Optional +from typing import Dict, Any, Tuple, Callable from embodichain.agents.rl.utils import AlgorithmCfg from embodichain.agents.rl.buffer import RolloutBuffer @@ -41,7 +41,7 @@ def __init__(self, cfg: PPOCfg, policy): self.policy = policy self.device = torch.device(cfg.device) self.optimizer = torch.optim.Adam(policy.parameters(), lr=cfg.learning_rate) - self.buffer: Optional[RolloutBuffer] = None + self.buffer: RolloutBuffer | None = None # no per-rollout aggregation for dense logging def _compute_gae( @@ -76,7 +76,7 @@ def collect_rollout( policy, obs: torch.Tensor, num_steps: int, - on_step_callback: Optional[Callable] = None, + on_step_callback: Callable | None = None, ) -> Dict[str, Any]: """Collect a rollout. Algorithm controls the data collection process.""" if self.buffer is None: diff --git a/embodichain/agents/rl/models/mlp.py b/embodichain/agents/rl/models/mlp.py index d839f63d..327e96b6 100644 --- a/embodichain/agents/rl/models/mlp.py +++ b/embodichain/agents/rl/models/mlp.py @@ -17,7 +17,7 @@ from __future__ import annotations from functools import reduce -from typing import Iterable, List, Optional, Sequence, Tuple, Union +from typing import Iterable, List, Sequence, Tuple, Union import torch import torch.nn as nn diff --git a/embodichain/agents/rl/utils/trainer.py b/embodichain/agents/rl/utils/trainer.py index 0ae1fb1e..88c04908 100644 --- a/embodichain/agents/rl/utils/trainer.py +++ b/embodichain/agents/rl/utils/trainer.py @@ -16,7 +16,7 @@ from __future__ import annotations -from typing import Dict, Any, Tuple, Callable, Optional +from typing import Dict, Any, Tuple, Callable import time import numpy as np import torch diff --git a/embodichain/lab/gym/envs/action_bank/configurable_action.py b/embodichain/lab/gym/envs/action_bank/configurable_action.py index 97a73da0..62144cfc 100644 --- a/embodichain/lab/gym/envs/action_bank/configurable_action.py +++ b/embodichain/lab/gym/envs/action_bank/configurable_action.py @@ -21,7 +21,7 @@ import matplotlib.pyplot as plt from copy import deepcopy -from typing import Dict, Tuple, Union, List, Callable, Any, Optional +from typing import Dict, Tuple, Union, List, Callable, Any from tqdm import tqdm from functools import partial diff --git a/embodichain/lab/gym/envs/action_bank/utils.py b/embodichain/lab/gym/envs/action_bank/utils.py index 52fb7c08..255e5b8f 100644 --- a/embodichain/lab/gym/envs/action_bank/utils.py +++ b/embodichain/lab/gym/envs/action_bank/utils.py @@ -16,7 +16,7 @@ import numpy as np from copy import deepcopy -from typing import List, Union, Optional +from typing import List from embodichain.utils import logger from embodichain.lab.gym.utils.misc import validation_with_process_from_name @@ -33,7 +33,7 @@ def generate_affordance_from_src( env, src_key: str, dst_key: str, - valid_funcs_name_kwargs_proc: Optional[List] = None, + valid_funcs_name_kwargs_proc: list | None = None, to_array: bool = True, ) -> bool: """Generate a new affordance entry in env.affordance_datas by applying a validation and processing @@ -43,7 +43,7 @@ def generate_affordance_from_src( env: The environment object containing affordance data. src_key (str): The key of the source affordance in env.affordance_datas. dst_key (str): The key to store the generated affordance in env.affordance_datas. - valid_funcs_name_kwargs_proc (Optional[List]): A list of validation or processing functions (with kwargs) + valid_funcs_name_kwargs_proc (list | None): A list of validation or processing functions (with kwargs) to apply to the source affordance. Defaults to an empty list. to_array (bool): Whether to convert the result to a numpy array before storing. Defaults to True. diff --git a/embodichain/lab/gym/envs/base_env.py b/embodichain/lab/gym/envs/base_env.py index 8ee19b6f..244a94a7 100644 --- a/embodichain/lab/gym/envs/base_env.py +++ b/embodichain/lab/gym/envs/base_env.py @@ -17,7 +17,7 @@ import torch import gymnasium as gym -from typing import Dict, List, Union, Tuple, Any, Optional, Sequence +from typing import Dict, List, Union, Tuple, Any, Sequence from functools import cached_property from embodichain.lab.sim.types import EnvObs, EnvAction @@ -41,7 +41,7 @@ class EnvCfg: sim_cfg: SimulationManagerCfg = SimulationManagerCfg() """Simulation configuration for the environment.""" - seed: Optional[int] = None + seed: int | None = None """The seed for the random number generator. Defaults to -1, in which case the seed is not set. Note: @@ -272,7 +272,7 @@ def _update_sim_state(self, **kwargs): # TODO: Add randomization event here. pass - def _initialize_episode(self, env_ids: Optional[Sequence[int]] = None, **kwargs): + def _initialize_episode(self, env_ids: Sequence[int] | None = None, **kwargs): """Initialize the simulation assets before each episode. Randomization can be performed at this stage. Args: @@ -427,7 +427,7 @@ def _step_action(self, action: EnvAction) -> EnvAction: pass def reset( - self, seed: Optional[int] = None, options: Optional[Dict] = None + self, seed: int | None = None, options: dict | None = None ) -> Tuple[EnvObs, Dict]: """Reset the SimulationManager environment and return the observation and info. diff --git a/embodichain/lab/gym/envs/embodied_env.py b/embodichain/lab/gym/envs/embodied_env.py index 601055a0..afb01a0f 100644 --- a/embodichain/lab/gym/envs/embodied_env.py +++ b/embodichain/lab/gym/envs/embodied_env.py @@ -20,7 +20,7 @@ import gymnasium as gym from dataclasses import MISSING -from typing import Dict, Union, Optional, Sequence, Tuple, Any, List +from typing import Dict, Union, Sequence, Tuple, Any, List from embodichain.lab.sim.cfg import ( RobotCfg, @@ -253,7 +253,7 @@ def get_affordance(self, key: str, default: Any = None): return self.affordance_datas.get(key, default) def reset( - self, seed: Optional[int] = None, options: Optional[Dict] = None + self, seed: int | None = None, options: dict | None = None ) -> Tuple[EnvObs, Dict]: obs, info = super().reset(seed=seed, options=options) @@ -297,7 +297,7 @@ def _update_sim_state(self, **kwargs) -> None: self.event_manager.apply(mode="interval") def _initialize_episode( - self, env_ids: Optional[Sequence[int]] = None, **kwargs + self, env_ids: Sequence[int] | None = None, **kwargs ) -> None: # apply events such as randomization for environments that need a reset if self.cfg.events: @@ -439,20 +439,20 @@ def preview_sensor_data( plt.imshow(view) plt.savefig(f"sensor_data_{data_type}.png") - def create_demo_action_list(self, *args, **kwargs) -> Optional[Sequence[EnvAction]]: + def create_demo_action_list(self, *args, **kwargs) -> Sequence[EnvAction] | None: """Create a demonstration action list for the environment. This function should be implemented in subclasses to generate a sequence of actions that demonstrate a specific task or behavior within the environment. Returns: - Optional[Sequence[EnvAction]]: A list of actions if a demonstration is available, otherwise None. + Sequence[EnvAction] | None: A list of actions if a demonstration is available, otherwise None. """ raise NotImplementedError( "The method 'create_demo_action_list' must be implemented in subclasses." ) - def to_dataset(self, id: str, save_path: str = None) -> Optional[str]: + def to_dataset(self, id: str, save_path: str = None) -> str | None: """Convert the recorded episode data to a dataset format. Args: @@ -460,7 +460,7 @@ def to_dataset(self, id: str, save_path: str = None) -> Optional[str]: save_path (str, optional): Path to save the dataset. If None, use config or default. Returns: - Optional[str]: The path to the saved dataset, or None if failed. + str | None: The path to the saved dataset, or None if failed. """ raise NotImplementedError( "The method 'to_dataset' will be implemented in the near future." diff --git a/embodichain/lab/gym/envs/managers/observations.py b/embodichain/lab/gym/envs/managers/observations.py index faf65100..db0dc220 100644 --- a/embodichain/lab/gym/envs/managers/observations.py +++ b/embodichain/lab/gym/envs/managers/observations.py @@ -19,7 +19,7 @@ import torch import os import random -from typing import TYPE_CHECKING, Literal, Union, Optional, List, Dict, Sequence +from typing import TYPE_CHECKING, Literal, Union, List, Dict, Sequence from embodichain.lab.sim.objects import RigidObject, Articulation, Robot from embodichain.lab.sim.sensors import Camera, StereoCamera @@ -388,7 +388,7 @@ def _project_3d_to_2d( return points_2d def _get_gripper_ratio( - self, control_part: str, gripper_qpos: Optional[torch.Tensor] = None + self, control_part: str, gripper_qpos: torch.Tensor | None = None ): robot: Robot = self._env.robot gripper_max_limit = robot.body_data.qpos_limits[ @@ -402,11 +402,11 @@ def _get_gripper_ratio( def _get_robot_exteroception( self, - control_part: Optional[str] = None, + control_part: str | None = None, x_interval: float = 0.02, y_interval: float = 0.02, kpnts_number: int = 12, - offset: Optional[Union[List, torch.Tensor]] = None, + offset: list | torch.Tensor | None = None, follow_eef: bool = False, ) -> torch.Tensor: """Get the robot exteroception poses. @@ -468,7 +468,7 @@ def _get_object_exteroception( y_interval: float = 0.02, kpnts_number: int = 12, is_arena_coord: bool = False, - follow_eef: Optional[str] = None, + follow_eef: str | None = None, ) -> torch.Tensor: """Get the rigid object exteroception poses. diff --git a/embodichain/lab/gym/envs/managers/randomization/rendering.py b/embodichain/lab/gym/envs/managers/randomization/rendering.py index 77d39604..b1e378d8 100644 --- a/embodichain/lab/gym/envs/managers/randomization/rendering.py +++ b/embodichain/lab/gym/envs/managers/randomization/rendering.py @@ -19,7 +19,7 @@ import torch import os import random -from typing import TYPE_CHECKING, Literal, Union, Optional, Dict +from typing import TYPE_CHECKING, Literal, Union, Dict from embodichain.lab.sim.objects import Light, RigidObject, Articulation from embodichain.lab.sim.sensors import Camera, StereoCamera @@ -55,11 +55,11 @@ def randomize_camera_extrinsics( env: EmbodiedEnv, env_ids: Union[torch.Tensor, None], entity_cfg: SceneEntityCfg, - pos_range: Optional[tuple[list[float], list[float]]] = None, - euler_range: Optional[tuple[list[float], list[float]]] = None, - eye_range: Optional[tuple[list[float], list[float]]] = None, - target_range: Optional[tuple[list[float], list[float]]] = None, - up_range: Optional[tuple[list[float], list[float]]] = None, + pos_range: tuple[list[float], list[float]] | None = None, + euler_range: tuple[list[float], list[float]] | None = None, + eye_range: tuple[list[float], list[float]] | None = None, + target_range: tuple[list[float], list[float]] | None = None, + up_range: tuple[list[float], list[float]] | None = None, ) -> None: """ Randomize camera extrinsic properties (position and orientation). @@ -177,9 +177,9 @@ def randomize_light( env: EmbodiedEnv, env_ids: Union[torch.Tensor, None], entity_cfg: SceneEntityCfg, - position_range: Optional[tuple[list[float], list[float]]] = None, - color_range: Optional[tuple[list[float], list[float]]] = None, - intensity_range: Optional[tuple[float, float]] = None, + position_range: tuple[list[float], list[float]] | None = None, + color_range: tuple[list[float], list[float]] | None = None, + intensity_range: tuple[float, float] | None = None, ) -> None: """Randomize light properties by adding, scaling, or setting random values. @@ -205,9 +205,9 @@ def randomize_light( env (EmbodiedEnv): The environment instance. env_ids (Union[torch.Tensor, None]): The environment IDs to apply the randomization. entity_cfg (SceneEntityCfg): The configuration of the scene entity to randomize. - position_range (Optional[tuple[list[float], list[float]]]): The range for the position randomization. - color_range (Optional[tuple[list[float], list[float]]]): The range for the color randomization. - intensity_range (Optional[tuple[float, float]]): The range for the intensity randomization. + position_range (tuple[list[float], list[float]] | None): The range for the position randomization. + color_range (tuple[list[float], list[float]] | None): The range for the color randomization. + intensity_range (tuple[float, float] | None): The range for the intensity randomization. """ light: Light = env.sim.get_light(entity_cfg.uid) @@ -259,10 +259,10 @@ def randomize_camera_intrinsics( env: EmbodiedEnv, env_ids: Union[torch.Tensor, None], entity_cfg: SceneEntityCfg, - focal_x_range: Optional[tuple[float, float]] = None, - focal_y_range: Optional[tuple[float, float]] = None, - cx_range: Optional[tuple[float, float]] = None, - cy_range: Optional[tuple[float, float]] = None, + focal_x_range: tuple[float, float] | None = None, + focal_y_range: tuple[float, float] | None = None, + cx_range: tuple[float, float] | None = None, + cy_range: tuple[float, float] | None = None, ) -> None: """Randomize camera intrinsic properties by adding, scaling, or setting random values. @@ -289,10 +289,10 @@ def randomize_camera_intrinsics( env (EmbodiedEnv): The environment instance. env_ids (Union[torch.Tensor, None]): The environment IDs to apply the randomization. entity_cfg (SceneEntityCfg): The configuration of the scene entity to randomize. - focal_x_range (Optional[tuple[float, float]]): The range for the focal length x randomization. - focal_y_range (Optional[tuple[float, float]]): The range for the focal length y randomization. - cx_range (Optional[tuple[float, float]]): The range for the principal point x randomization. - cy_range (Optional[tuple[float, float]]): The range for the principal point y randomization. + focal_x_range (tuple[float, float] | None): The range for the focal length x randomization. + focal_y_range (tuple[float, float] | None): The range for the focal length y randomization. + cx_range (tuple[float, float] | None): The range for the principal point x randomization. + cy_range (tuple[float, float] | None): The range for the principal point y randomization. """ camera: Union[Camera, StereoCamera] = env.sim.get_sensor(entity_cfg.uid) @@ -500,11 +500,11 @@ def __call__( env_ids: Union[torch.Tensor, None], entity_cfg: SceneEntityCfg, random_texture_prob: float = 0.5, - texture_path: Optional[str] = None, - base_color_range: Optional[tuple[list[float], list[float]]] = None, - metallic_range: Optional[tuple[float, float]] = None, - roughness_range: Optional[tuple[float, float]] = None, - ior_range: Optional[tuple[float, float]] = None, + texture_path: str | None = None, + base_color_range: tuple[list[float], list[float]] | None = None, + metallic_range: tuple[float, float] | None = None, + roughness_range: tuple[float, float] | None = None, + ior_range: tuple[float, float] | None = None, ): from embodichain.lab.sim.utility import is_rt_enabled diff --git a/embodichain/lab/gym/envs/managers/randomization/spatial.py b/embodichain/lab/gym/envs/managers/randomization/spatial.py index 65ab422e..a63c5fa7 100644 --- a/embodichain/lab/gym/envs/managers/randomization/spatial.py +++ b/embodichain/lab/gym/envs/managers/randomization/spatial.py @@ -17,7 +17,7 @@ from __future__ import annotations import torch -from typing import TYPE_CHECKING, Literal, Union, Optional, List +from typing import TYPE_CHECKING, Literal, Union, List from embodichain.lab.sim.objects import RigidObject, Robot from embodichain.lab.gym.envs.managers.cfg import SceneEntityCfg @@ -32,8 +32,8 @@ def get_random_pose( init_pos: torch.Tensor, init_rot: torch.Tensor, - position_range: Optional[tuple[list[float], list[float]]] = None, - rotation_range: Optional[tuple[list[float], list[float]]] = None, + position_range: tuple[list[float], list[float]] | None = None, + rotation_range: tuple[list[float], list[float]] | None = None, relative_position: bool = True, relative_rotation: bool = False, ) -> torch.Tensor: @@ -42,8 +42,8 @@ def get_random_pose( Args: init_pos (torch.Tensor): The initial position tensor of shape (num_instance, 3). init_rot (torch.Tensor): The initial rotation tensor of shape (num_instance, 3, 3). - position_range (Optional[tuple[list[float], list[float]]]): The range for the position randomization. - rotation_range (Optional[tuple[list[float], list[float]]]): The range for the rotation randomization. + position_range (tuple[list[float], list[float]] | None): The range for the position randomization. + rotation_range (tuple[list[float], list[float]] | None): The range for the rotation randomization. The rotation is represented as Euler angles (roll, pitch, yaw) in degree. relative_position (bool): Whether to randomize the position relative to the initial position. Default is True. relative_rotation (bool): Whether to randomize the rotation relative to the initial rotation. Default is False. @@ -103,8 +103,8 @@ def randomize_rigid_object_pose( env: EmbodiedEnv, env_ids: Union[torch.Tensor, None], entity_cfg: SceneEntityCfg, - position_range: Optional[tuple[list[float], list[float]]] = None, - rotation_range: Optional[tuple[list[float], list[float]]] = None, + position_range: tuple[list[float], list[float]] | None = None, + rotation_range: tuple[list[float], list[float]] | None = None, relative_position: bool = True, relative_rotation: bool = False, ) -> None: @@ -114,8 +114,8 @@ def randomize_rigid_object_pose( env (EmbodiedEnv): The environment instance. env_ids (Union[torch.Tensor, None]): The environment IDs to apply the randomization. entity_cfg (SceneEntityCfg): The configuration of the scene entity to randomize. - position_range (Optional[tuple[list[float], list[float]]]): The range for the position randomization. - rotation_range (Optional[tuple[list[float], list[float]]]): The range for the rotation randomization. + position_range (tuple[list[float], list[float]] | None): The range for the position randomization. + rotation_range (tuple[list[float], list[float]] | None): The range for the rotation randomization. The rotation is represented as Euler angles (roll, pitch, yaw) in degree. relative_position (bool): Whether to randomize the position relative to the object's initial position. Default is True. relative_rotation (bool): Whether to randomize the rotation relative to the object's initial rotation. Default is False. @@ -157,8 +157,8 @@ def randomize_robot_eef_pose( env: EmbodiedEnv, env_ids: Union[torch.Tensor, None], entity_cfg: SceneEntityCfg, - position_range: Optional[tuple[list[float], list[float]]] = None, - rotation_range: Optional[tuple[list[float], list[float]]] = None, + position_range: tuple[list[float], list[float]] | None = None, + rotation_range: tuple[list[float], list[float]] | None = None, ) -> None: """Randomize the initial end-effector pose of a robot in the environment. @@ -171,8 +171,8 @@ def randomize_robot_eef_pose( env_ids (Union[torch.Tensor, None]): The environment IDs to apply the randomization. robot_name (str): The name of the robot. entity_cfg (SceneEntityCfg): The configuration of the scene entity to randomize. - position_range (Optional[tuple[list[float], list[float]]]): The range for the position randomization. - rotation_range (Optional[tuple[list[float], list[float]]]): The range for the rotation randomization. + position_range (tuple[list[float], list[float]] | None): The range for the position randomization. + rotation_range (tuple[list[float], list[float]] | None): The range for the rotation randomization. The rotation is represented as Euler angles (roll, pitch, yaw) in degree. """ @@ -220,9 +220,9 @@ def randomize_robot_qpos( env: EmbodiedEnv, env_ids: Union[torch.Tensor, None], entity_cfg: SceneEntityCfg, - qpos_range: Optional[tuple[list[float], list[float]]] = None, + qpos_range: tuple[list[float], list[float]] | None = None, relative_qpos: bool = True, - joint_ids: Optional[List[int]] = None, + joint_ids: List[int] | None = None, ) -> None: """Randomize the initial joint positions of a robot in the environment. @@ -230,9 +230,9 @@ def randomize_robot_qpos( env (EmbodiedEnv): The environment instance. env_ids (Union[torch.Tensor, None]): The environment IDs to apply the randomization. entity_cfg (SceneEntityCfg): The configuration of the scene entity to randomize. - qpos_range (Optional[tuple[list[float], list[float]]]): The range for the joint position randomization. + qpos_range (tuple[list[float], list[float]] | None): The range for the joint position randomization. relative_qpos (bool): Whether to randomize the joint positions relative to the current joint positions. Default is True. - joint_ids (Optional[List[int]]): The list of joint IDs to randomize. If None, all joints will be randomized. + joint_ids (List[int] | None): The list of joint IDs to randomize. If None, all joints will be randomized. """ if qpos_range is None: return diff --git a/embodichain/lab/gym/envs/tasks/rl/push_cube.py b/embodichain/lab/gym/envs/tasks/rl/push_cube.py index 412877e7..4aef16c8 100644 --- a/embodichain/lab/gym/envs/tasks/rl/push_cube.py +++ b/embodichain/lab/gym/envs/tasks/rl/push_cube.py @@ -16,7 +16,7 @@ import torch import numpy as np -from typing import Dict, Any, Optional, Sequence +from typing import Dict, Any, Sequence from gymnasium import spaces from embodichain.lab.gym.utils.registration import register_env @@ -101,7 +101,7 @@ def _init_sim_state(self, **kwargs): ) def _initialize_episode( - self, env_ids: Optional[Sequence[int]] = None, **kwargs + self, env_ids: Sequence[int] | None = None, **kwargs ) -> None: super()._initialize_episode(env_ids=env_ids, **kwargs) cube = self.sim.get_rigid_object("cube") diff --git a/embodichain/lab/gym/envs/tasks/tableware/pour_water/action_bank.py b/embodichain/lab/gym/envs/tasks/tableware/pour_water/action_bank.py index 8938aeb6..321c28ae 100644 --- a/embodichain/lab/gym/envs/tasks/tableware/pour_water/action_bank.py +++ b/embodichain/lab/gym/envs/tasks/tableware/pour_water/action_bank.py @@ -17,7 +17,7 @@ import torch import numpy as np from copy import deepcopy -from typing import Dict, Tuple, Union, List, Any, Optional, Callable +from typing import Dict, List from embodichain.lab.gym.envs.action_bank.configurable_action import ( ActionBank, tag_node, @@ -44,7 +44,7 @@ class PourWaterActionBank(ActionBank): @resolve_env_params def generate_left_arm_aim_qpos( env, - valid_funcs_name_kwargs_proc: Optional[List] = None, + valid_funcs_name_kwargs_proc: List | None = None, ): # FIXME FIXME FIXME FIXME logger.log_warning( @@ -69,7 +69,7 @@ def generate_left_arm_aim_qpos( # DONE: valid & process qpos & fk def generate_right_arm_aim_qpos( env, - valid_funcs_name_kwargs_proc: Optional[List] = None, + valid_funcs_name_kwargs_proc: list | None = None, ): # FIXME FIXME FIXME FIXME logger.log_warning( diff --git a/embodichain/lab/gym/envs/tasks/tableware/scoop_ice.py b/embodichain/lab/gym/envs/tasks/tableware/scoop_ice.py index 46f6afad..6a3c4c50 100644 --- a/embodichain/lab/gym/envs/tasks/tableware/scoop_ice.py +++ b/embodichain/lab/gym/envs/tasks/tableware/scoop_ice.py @@ -20,7 +20,7 @@ import pickle from copy import deepcopy -from typing import Optional, Sequence +from typing import Sequence from scipy.spatial.transform import Rotation as R from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg @@ -134,7 +134,7 @@ def pack_qpos(self): return all_qpos def _initialize_episode( - self, env_ids: Optional[Sequence[int]] = None, **kwargs + self, env_ids: Sequence[int] | None = None, **kwargs ) -> None: left_arm_ids = self.robot.get_joint_ids(name="left_arm") diff --git a/embodichain/lab/gym/utils/gym_utils.py b/embodichain/lab/gym/utils/gym_utils.py index 1cf433a6..0f92abb7 100644 --- a/embodichain/lab/gym/utils/gym_utils.py +++ b/embodichain/lab/gym/utils/gym_utils.py @@ -18,7 +18,7 @@ import torch import dexsim -from typing import Dict, Any, List, Tuple, Union, Sequence, Optional +from typing import Dict, Any, List, Tuple, Union, Sequence from gymnasium import spaces from copy import deepcopy @@ -124,7 +124,7 @@ def batch(*args: Tuple[Union[np.ndarray, Dict]]): return tuple(x) -def to_tensor(array: Array, device: Optional[Device] = None): +def to_tensor(array: Array, device: Device | None = None): """ Maps any given sequence to a torch tensor on the CPU/GPU. If physx gpu is not enabled then we use CPU, otherwise GPU, unless specified by the device argument diff --git a/embodichain/lab/gym/utils/misc.py b/embodichain/lab/gym/utils/misc.py index b95e0ce5..b669e6cf 100644 --- a/embodichain/lab/gym/utils/misc.py +++ b/embodichain/lab/gym/utils/misc.py @@ -28,7 +28,7 @@ from collections import OrderedDict from importlib import import_module from scipy.spatial.transform import Rotation as R -from typing import Any, Dict, List, Tuple, Union, Sequence, Callable, Optional, Mapping +from typing import Any, Dict, List, Tuple, Union, Sequence, Callable, Mapping import numpy as np @@ -1063,7 +1063,7 @@ def validation_with_process_from_name( env, input: List[np.ndarray], valid_funcs_name_kwargs_proc: List[Dict[str, Any]], - module_names: Optional[List[str]] = None, + module_names: List[str] | None = None, ): """Apply a sequence of validation and processing functions (by name) to the input data. @@ -1095,28 +1095,34 @@ def _get_valid_grasp( grasp_list: List[np.ndarray], valid_funcs_name_kwargs_proc: List[Union[str, Dict[str, Any]]], ) -> np.ndarray: - """TODO 懒狗了,总而言之言而总之就是一个函数,可以集成一堆validation function,检验grasp_pose是否valid,也可以再特定的alidatrion function后面跟一堆process + """ + Validate a list of grasp poses using a sequence of validation and processing functions. + + This function iterates through each grasp in `grasp_list`, applies a series of validation + and processing functions (specified in `valid_funcs_name_kwargs_proc`), and returns the first + grasp pose that passes all validations. If no valid grasp is found, returns None. Args: - env: TODO - grasp_list (List[np.ndarray]): TODO - validation_func_names_kwargs (Dict[str, dict]): TODO - validation_func_names_process (Optional[Dict[str, Dict[str, dict]]], optional): TODO. Defaults to None. + env: The environment object, used for method lookup and as context for validation functions. + grasp_list (List[np.ndarray]): List of grasp objects or poses to be validated. + valid_funcs_name_kwargs_proc (List[Union[str, Dict[str, Any]]]): List of validation function + specifications. Each item can be a function name (str) or a dict specifying the function + name, kwargs, and optional processing steps. Returns: - np.ndarray: TODO + np.ndarray or None: The first valid grasp pose, or None if none are valid. """ valid_func_kwargs_proc = find_funcs_with_kwargs( valid_funcs_name_kwargs_proc, instances=[env], module_names=[__name__] ) for grasp in grasp_list: - grasp_pose = grasp.pose # TODO: be a func? + grasp_pose = grasp.pose # TODO: Should this be a method? grasp_pose = validate_with_process(env, grasp_pose, valid_func_kwargs_proc) - # The loop is broken as ONE validation results is False + # Skip if any validation fails if grasp_pose is None: continue - # All validation results are True in the loop + # Return the first valid grasp pose else: return grasp_pose return None @@ -1174,8 +1180,8 @@ def wrapper(*args, **kwargs): def multi_output_factory_function( func_name: Union[str, Callable], - instances: Optional[List] = None, - module_names: Optional[List[str]] = None, + instances: List | None = None, + module_names: List[str] | None = None, output_num: int = 1, ) -> Callable: """ @@ -1332,7 +1338,7 @@ def get_fk_xpos( # FIXME: remove -def data_key_to_control_part(robot, control_parts, data_key: str) -> Optional[str]: +def data_key_to_control_part(robot, control_parts, data_key: str) -> str | None: # TODO: Temporary workaround, should be removed after refactoring data dict extractor. # @lru_cache(max_size=None) # NOTE: no way to pass a hashable parameter def is_eef_hand(robot, control_parts) -> bool: diff --git a/embodichain/lab/sim/cfg.py b/embodichain/lab/sim/cfg.py index 55bdfb59..9fef7b58 100644 --- a/embodichain/lab/sim/cfg.py +++ b/embodichain/lab/sim/cfg.py @@ -19,7 +19,7 @@ import numpy as np import torch -from typing import Sequence, Union, Dict, Literal, List, Optional, Any +from typing import Sequence, Union, Dict, Literal, List, Any from dataclasses import field, MISSING from dexsim.types import ( @@ -403,7 +403,7 @@ class ObjectBaseCfg: init_rot: tuple[float, float, float] = (0.0, 0.0, 0.0) """Euler angles (in degree) of the root in simulation world frame. Defaults to (0.0, 0.0, 0.0).""" - init_local_pose: Optional[np.ndarray] = None + init_local_pose: np.ndarray | None = None """4x4 transformation matrix of the root in local frame. If specified, it will override init_pos and init_rot.""" @classmethod @@ -554,7 +554,7 @@ class RigidObjectGroupCfg: body_type: Literal["dynamic", "kinematic"] = "dynamic" """Body type for all rigid objects in the group. """ - folder_path: Optional[str] = None + folder_path: str | None = None """Path to the folder containing the rigid object assets. This is used to initialize multiple rigid object configurations from a folder. @@ -641,10 +641,10 @@ class URDFCfg: base_link_name: str = "base_link" """Name of the base link in the assembled robot.""" - fpath: Optional[str] = None + fpath: str | None = None """Full output file path for the assembled URDF. If specified, overrides fname and fpath_prefix.""" - fname: Optional[str] = None + fname: str | None = None """Name used for output file and directory. If not specified, auto-generated from component names.""" fpath_prefix: str = EMBODICHAIN_DEFAULT_DATA_ROOT + "/assembled" @@ -652,10 +652,10 @@ class URDFCfg: def __init__( self, - components: Optional[List[Dict[str, Union[str, np.ndarray]]]] = None, - sensors: Optional[Dict[str, Dict[str, Union[str, np.ndarray]]]] = None, - fpath: Optional[str] = None, - fname: Optional[str] = None, + components: list[dict[str, str | np.ndarray]] | None = None, + sensors: dict[str, dict[str, str | np.ndarray]] | None = None, + fpath: str | None = None, + fname: str | None = None, fpath_prefix: str = EMBODICHAIN_DEFAULT_DATA_ROOT + "/assembled", use_signature_check: bool = True, base_link_name: str = "base_link", @@ -664,14 +664,14 @@ def __init__( Initialize URDFCfg with optional list of components and output path settings. Args: - components (Optional[List[Dict]]): List of component configurations. Each dict should contain: + components (list[dict[str, str | np.ndarray]] | None): List of component configurations. Each dict should contain: - 'component_type' (str): The type/name of the component (e.g., 'chassis', 'arm', 'hand'). - 'urdf_path' (str): Path to the component's URDF file. - - 'transform' (Optional[np.ndarray]): 4x4 transformation matrix (optional). + - 'transform' (np.ndarray | None): 4x4 transformation matrix (optional). - Additional params can be included as extra keys. - sensors (Optional[Dict]): Sensor configurations for the robot. - fpath (Optional[str]): Full output file path for the assembled URDF. If specified, overrides fname and fpath_prefix. - fname (Optional[str]): Name used for output file and directory. If not specified, auto-generated from component names. + sensors (dict[str, dict[str, str | np.ndarray]] | None): Sensor configurations for the robot. + fpath (str | None): Full output file path for the assembled URDF. If specified, overrides fname and fpath_prefix. + fname (str | None): Name used for output file and directory. If not specified, auto-generated from component names. fpath_prefix (str): Output directory prefix for the assembled URDF file. use_signature_check (bool): Whether to use signature check when merging URDFs. base_link_name (str): Name of the base link in the assembled robot. @@ -763,7 +763,7 @@ def add_component( self, component_type: str, urdf_path: str, - transform: Optional[np.ndarray] = None, + transform: np.ndarray | None = None, **params, ) -> URDFCfg: """Add a robot component to the assembly configuration. @@ -772,7 +772,7 @@ def add_component( component_type (str): The type/name of the component. Should be one of SUPPORTED_COMPONENTS (e.g., 'chassis', 'torso', 'head', 'left_arm', 'right_hand', 'arm', 'hand', etc.). urdf_path (str): Path to the component's URDF file. - transform (Optional[np.ndarray]): 4x4 transformation matrix for the component in the robot frame (default: None). + transform (np.ndarray | None): 4x4 transformation matrix for the component in the robot frame (default: None). **params: Additional keyword parameters for the component (e.g., color, material, etc.). Returns: @@ -983,7 +983,7 @@ class RobotCfg(ArticulationCfg): After initialization of robot, the names will be expanded to a list of full joint names. """ - urdf_cfg: Optional[URDFCfg] = None + urdf_cfg: URDFCfg | None = None """URDF assembly configuration which allows for assembling a robot from multiple URDF components. """ diff --git a/embodichain/lab/sim/common.py b/embodichain/lab/sim/common.py index d129b5a6..4e5b9b33 100644 --- a/embodichain/lab/sim/common.py +++ b/embodichain/lab/sim/common.py @@ -20,8 +20,7 @@ from dataclasses import dataclass from abc import ABC, abstractmethod -from typing import List, TypeVar, Sequence, Optional -from functools import cached_property +from typing import List, TypeVar, Sequence from embodichain.lab.sim.cfg import ObjectBaseCfg from embodichain.utils import logger @@ -43,7 +42,7 @@ class BatchEntity(ABC): """ - uid: Optional[str] = None + uid: str | None = None cfg: ObjectBaseCfg = None _entities: List[T] = None device: torch.device = None @@ -79,7 +78,7 @@ def num_instances(self) -> int: @abstractmethod def set_local_pose( - self, pose: torch.Tensor, env_ids: Optional[Sequence[int]] = None + self, pose: torch.Tensor, env_ids: Sequence[int] | None = None ) -> None: pass @@ -92,11 +91,11 @@ def pose(self) -> torch.Tensor: return self.get_local_pose(to_matrix=False) @abstractmethod - def reset(self, env_ids: Optional[Sequence[int]] = None) -> None: + def reset(self, env_ids: Sequence[int] | None = None) -> None: """Reset the entity to its initial state. Args: - env_ids (Optional[Sequence[int]]): The environment IDs to reset. If None, reset all environments. + env_ids (Sequence[int] | None): The environment IDs to reset. If None, reset all environments. """ pass diff --git a/embodichain/lab/sim/material.py b/embodichain/lab/sim/material.py index fe6ad0db..c66c2c38 100644 --- a/embodichain/lab/sim/material.py +++ b/embodichain/lab/sim/material.py @@ -21,7 +21,7 @@ import dexsim import numpy as np -from typing import Optional, Dict, Union +from typing import Dict, Union from functools import cached_property from dexsim.engine import MaterialInst, Material @@ -227,7 +227,7 @@ def set_emissive_intensity(self, intensity: float) -> None: logger.log_error("Unimplemented: set_emissive_intensity") def set_base_color_texture( - self, texture_path: str = None, texture_data: Optional[torch.Tensor] = None + self, texture_path: str = None, texture_data: torch.Tensor | None = None ) -> None: """Set base color texture from file path or texture data. @@ -257,7 +257,7 @@ def set_base_color_texture( inst.set_base_color_map(color_texture) def set_metallic_texture( - self, texture_path: str = None, texture_data: Optional[torch.Tensor] = None + self, texture_path: str = None, texture_data: torch.Tensor | None = None ) -> None: """Set metallic texture from file path or texture data. @@ -287,7 +287,7 @@ def set_metallic_texture( inst.set_metallic_map(metallic_texture) def set_roughness_texture( - self, texture_path: str = None, texture_data: Optional[torch.Tensor] = None + self, texture_path: str = None, texture_data: torch.Tensor | None = None ) -> None: """Set roughness texture from file path or texture data. @@ -317,7 +317,7 @@ def set_roughness_texture( inst.set_roughness_map(roughness_texture) def set_normal_texture( - self, texture_path: str = None, texture_data: Optional[torch.Tensor] = None + self, texture_path: str = None, texture_data: torch.Tensor | None = None ) -> None: """Set normal texture from file path or texture data. @@ -347,7 +347,7 @@ def set_normal_texture( inst.set_normal_map(normal_texture) def set_ao_texture( - self, texture_path: str = None, texture_data: Optional[torch.Tensor] = None + self, texture_path: str = None, texture_data: torch.Tensor | None = None ) -> None: """Set ambient occlusion texture from file path or texture data. diff --git a/embodichain/lab/sim/objects/articulation.py b/embodichain/lab/sim/objects/articulation.py index 7698fc11..b20650ac 100644 --- a/embodichain/lab/sim/objects/articulation.py +++ b/embodichain/lab/sim/objects/articulation.py @@ -20,7 +20,7 @@ from dataclasses import dataclass from functools import cached_property -from typing import List, Sequence, Optional, Dict, Union, Tuple +from typing import List, Sequence, Dict, Union, Tuple from dexsim.engine import Articulation as _Articulation from dexsim.types import ( @@ -670,20 +670,20 @@ def body_state(self) -> torch.Tensor: return torch.cat((body_pose, body_vel), dim=-1) @property - def mimic_ids(self) -> List[Optional[int]]: + def mimic_ids(self) -> List[int | None]: """Get the mimic joint ids for the articulation. Returns: - List[Optional[int]]: The mimic joint ids. + List[int | None]: The mimic joint ids. """ return self._mimic_info.mimic_id.tolist() @property - def mimic_parents(self) -> List[Optional[int]]: + def mimic_parents(self) -> List[int | None]: """Get the mimic joint parent ids for the articulation. Returns: - List[Optional[int]]: The mimic joint parent ids. + List[int | None]: The mimic joint parent ids. """ return self._mimic_info.mimic_parent.tolist() @@ -715,7 +715,7 @@ def _set_default_collision_filter(self) -> None: self.set_collision_filter(collision_filter_data) def set_collision_filter( - self, filter_data: torch.Tensor, env_ids: Optional[Sequence[int]] = None + self, filter_data: torch.Tensor, env_ids: Sequence[int] | None = None ) -> None: """set collision filter data for the rigid object. @@ -725,7 +725,7 @@ def set_collision_filter( If 2nd element is 0, the object will collision with all other objects in world. 3rd and 4th elements are not used currently. - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. Defaults to None. + env_ids (Sequence[int] | None, optional): Environment indices. If None, then all indices are used. Defaults to None. """ local_env_ids = self._all_indices if env_ids is None else env_ids @@ -739,13 +739,13 @@ def set_collision_filter( self._entities[env_idx].set_collision_filter_data(filter_data_np[i]) def set_local_pose( - self, pose: torch.Tensor, env_ids: Optional[Sequence[int]] = None + self, pose: torch.Tensor, env_ids: Sequence[int] | None = None ) -> None: """Set local pose of the articulation. Args: pose (torch.Tensor): The local pose of the articulation with shape (N, 7) or (N, 4, 4). - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + env_ids (Sequence[int] | None, optional): Environment indices. If None, then all indices are used. """ local_env_ids = self._all_indices if env_ids is None else env_ids @@ -848,13 +848,13 @@ def get_link_vert_face(self, link_name: str) -> Tuple[torch.Tensor, torch.Tensor return verts, faces def get_link_pose( - self, link_name: str, env_ids: Optional[Sequence[int]] = None, to_matrix=False + self, link_name: str, env_ids: Sequence[int] | None = None, to_matrix=False ) -> torch.Tensor: """Get the pose of a specific link in the articulation. Args: link_name (str): The name of the link. - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + env_ids (Sequence[int] | None, optional): Environment indices. If None, then all indices are used. to_matrix (bool, optional): If True, return the pose as a 4x4 matrix. If False, return as (x, y, z, qw, qx, qy, qz). Defaults to False. Returns: @@ -889,16 +889,16 @@ def get_qpos(self) -> torch.Tensor: def set_qpos( self, qpos: torch.Tensor, - joint_ids: Optional[Sequence[int]] = None, - env_ids: Optional[Sequence[int]] = None, + joint_ids: Sequence[int] | None = None, + env_ids: Sequence[int] | None = None, target: bool = True, ) -> None: """Set the joint positions (qpos) or target positions for the articulation. Args: qpos (torch.Tensor): Joint positions with shape (N, dof), where N is the number of environments. - joint_ids (Optional[Sequence[int]], optional): Joint indices to apply the positions. If None, applies to all joints. - env_ids (Optional[Sequence[int]]): Environment indices to apply the positions. Defaults to all environments. + joint_ids (Sequence[int] | None, optional): Joint indices to apply the positions. If None, applies to all joints. + env_ids (Sequence[int] | None): Environment indices to apply the positions. Defaults to all environments. target (bool): If True, sets target positions for simulation. If False, updates current positions directly. Raises: @@ -986,16 +986,16 @@ def get_qvel(self) -> torch.Tensor: def set_qvel( self, qvel: torch.Tensor, - joint_ids: Optional[Sequence[int]] = None, - env_ids: Optional[Sequence[int]] = None, + joint_ids: Sequence[int] | None = None, + env_ids: Sequence[int] | None = None, target: bool = True, ) -> None: """Set the velocities (qvel) or target velocities of the articulation. Args: qvel (torch.Tensor): The velocities with shape (N, dof). - joint_ids (Optional[Sequence[int]], optional): Joint indices to apply the velocities. If None, applies to all joints. - env_ids (Optional[Sequence[int]], optional): Environment indices. Defaults to all indices. + joint_ids (Sequence[int] | None, optional): Joint indices to apply the velocities. If None, applies to all joints. + env_ids (Sequence[int] | None, optional): Environment indices. Defaults to all indices. If True, sets target positions for simulation. If False, updates current positions directly. Raises: @@ -1041,15 +1041,15 @@ def set_qvel( def set_qf( self, qf: torch.Tensor, - joint_ids: Optional[Sequence[int]] = None, - env_ids: Optional[Sequence[int]] = None, + joint_ids: Sequence[int] | None = None, + env_ids: Sequence[int] | None = None, ) -> None: """Set the generalized efforts (qf) of the articulation. Args: qf (torch.Tensor): The generalized efforts with shape (N, dof). - joint_ids (Optional[Sequence[int]], optional): Joint indices to apply the efforts. If None, applies to all joints. - env_ids (Optional[Sequence[int]], optional): Environment indices. Defaults to all indices. + joint_ids (Sequence[int] | None, optional): Joint indices to apply the efforts. If None, applies to all joints. + env_ids (Sequence[int] | None, optional): Environment indices. Defaults to all indices. """ local_env_ids = self._all_indices if env_ids is None else env_ids @@ -1080,14 +1080,14 @@ def set_qf( def set_drive( self, - stiffness: Optional[torch.Tensor] = None, - damping: Optional[torch.Tensor] = None, - max_effort: Optional[torch.Tensor] = None, - max_velocity: Optional[torch.Tensor] = None, - friction: Optional[torch.Tensor] = None, + stiffness: torch.Tensor | None = None, + damping: torch.Tensor | None = None, + max_effort: torch.Tensor | None = None, + max_velocity: torch.Tensor | None = None, + friction: torch.Tensor | None = None, drive_type: str = "force", - joint_ids: Optional[Sequence[int]] = None, - env_ids: Optional[Sequence[int]] = None, + joint_ids: Sequence[int] | None = None, + env_ids: Sequence[int] | None = None, ) -> None: """Set the drive properties for the articulation. @@ -1098,8 +1098,8 @@ def set_drive( max_velocity (torch.Tensor): The maximum velocity of the joint drive with shape (len(env_ids), len(joint_ids)). friction (torch.Tensor): The joint friction coefficient with shape (len(env_ids), len(joint_ids)). drive_type (str, optional): The type of drive to apply. Defaults to "force". - joint_ids (Optional[Sequence[int]], optional): The joint indices to apply the drive to. If None, applies to all joints. Defaults to None. - env_ids (Optional[Sequence[int]], optional): The environment indices to apply the drive to. If None, applies to all environments. Defaults to None. + joint_ids (Sequence[int] | None, optional): The joint indices to apply the drive to. If None, applies to all joints. Defaults to None. + env_ids (Sequence[int] | None, optional): The environment indices to apply the drive to. If None, applies to all environments. Defaults to None. """ local_env_ids = self._all_indices if env_ids is None else env_ids local_joint_ids = np.arange(self.dof) if joint_ids is None else joint_ids @@ -1135,11 +1135,11 @@ def get_user_ids(self) -> torch.Tensor: device=self.device, ) - def clear_dynamics(self, env_ids: Optional[Sequence[int]] = None) -> None: + def clear_dynamics(self, env_ids: Sequence[int] | None = None) -> None: """Clear the dynamics of the articulation. Args: - env_ids (Optional[Sequence[int]]): Environment indices. If None, then all indices are used. + env_ids (Sequence[int] | None): Environment indices. If None, then all indices are used. """ local_env_ids = self._all_indices if env_ids is None else env_ids if self.device.type == "cpu": @@ -1205,7 +1205,7 @@ def reallocate_body_data(self) -> None: device=self.device, ) - def reset(self, env_ids: Optional[Sequence[int]] = None) -> None: + def reset(self, env_ids: Sequence[int] | None = None) -> None: local_env_ids = self._all_indices if env_ids is None else env_ids num_instances = len(local_env_ids) self.cfg: ArticulationCfg @@ -1304,13 +1304,13 @@ def _set_default_joint_drive(self) -> None: def compute_fk( self, - qpos: Optional[Union[torch.tensor, np.ndarray]], - link_names: Optional[Union[str, list[str], tuple[str]]] = None, - end_link_name: Optional[str] = None, - root_link_name: Optional[str] = None, + qpos: torch.Tensor | np.ndarray | None, + link_names: str | list[str] | tuple[str] | None = None, + end_link_name: str | None = None, + root_link_name: str | None = None, to_dict: bool = False, **kwargs, - ) -> Union[torch.tensor, dict[str, "pk.Transform3d"]]: + ) -> Union[torch.Tensor, dict[str, "pk.Transform3d"]]: """Compute the forward kinematics (FK) for the given joint positions. Args: @@ -1406,10 +1406,10 @@ def compute_fk( def compute_jacobian( self, - qpos: Optional[Union[torch.Tensor, np.ndarray]], + qpos: torch.Tensor | np.ndarray | None, end_link_name: str = None, root_link_name: str = None, - locations: Optional[Union[torch.Tensor, np.ndarray]] = None, + locations: torch.Tensor | np.ndarray | None = None, jac_type: str = "full", ) -> torch.Tensor: """Compute the Jacobian matrix for the given joint positions using the pk_serial_chain. @@ -1482,15 +1482,15 @@ def compute_jacobian( def set_visual_material( self, mat: VisualMaterial, - env_ids: Optional[Sequence[int]] = None, - link_names: Optional[List[str]] = None, + env_ids: Sequence[int] | None = None, + link_names: List[str] | None = None, ) -> None: """Set visual material for the rigid object. Args: mat (VisualMaterial): The material to set. - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. - link_names (Optional[List[str]], optional): List of link names to apply the material to. If None, applies to all links. + env_ids (Sequence[int] | None, optional): Environment indices. If None, then all indices are used. + link_names (List[str] | None, optional): List of link names to apply the material to. If None, applies to all links. """ local_env_ids = self._all_indices if env_ids is None else env_ids link_names = self.link_names if link_names is None else link_names @@ -1505,14 +1505,14 @@ def set_visual_material( def get_visual_material_inst( self, - env_ids: Optional[Sequence[int]] = None, - link_names: Optional[List[str]] = None, + env_ids: Sequence[int] | None = None, + link_names: List[str] | None = None, ) -> List[Dict[str, VisualMaterialInst]]: """Get visual material instances for the rigid object. Args: - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. - link_names (Optional[List[str]], optional): List of link names to filter materials. If None, returns materials for all links. + env_ids (Sequence[int] | None, optional): Environment indices. If None, then all indices are used. + link_names (List[str] | None, optional): List of link names to filter materials. If None, returns materials for all links. Returns: List[Dict[str, VisualMaterialInst]]: A list where each element corresponds to an environment and contains a dictionary mapping link names to their VisualMaterialInst. """ diff --git a/embodichain/lab/sim/objects/gizmo.py b/embodichain/lab/sim/objects/gizmo.py index 8456e295..28053a7f 100644 --- a/embodichain/lab/sim/objects/gizmo.py +++ b/embodichain/lab/sim/objects/gizmo.py @@ -21,7 +21,7 @@ import numpy as np import torch import dexsim -from typing import Callable, Optional +from typing import Callable from scipy.spatial.transform import Rotation as R from embodichain.lab.sim.common import BatchEntity @@ -109,8 +109,8 @@ class Gizmo: def __init__( self, target: BatchEntity, - cfg: Optional[GizmoCfg] = None, - control_part: Optional[str] = "arm", + cfg: GizmoCfg | None = None, + control_part: str | None = "arm", ): """ Args: diff --git a/embodichain/lab/sim/objects/light.py b/embodichain/lab/sim/objects/light.py index fb085e88..7670b901 100644 --- a/embodichain/lab/sim/objects/light.py +++ b/embodichain/lab/sim/objects/light.py @@ -1,6 +1,6 @@ import torch import numpy as np -from typing import List, Optional, Sequence +from typing import List, Sequence from dexsim.render import Light as _Light from embodichain.lab.sim.cfg import LightCfg from embodichain.lab.sim.common import BatchEntity @@ -27,7 +27,7 @@ def __init__( super().__init__(cfg, entities, device) def set_color( - self, colors: torch.Tensor, env_ids: Optional[Sequence[int]] = None + self, colors: torch.Tensor, env_ids: Sequence[int] | None = None ) -> None: """Set color for one or more lights. @@ -35,14 +35,14 @@ def set_color( colors (torch.Tensor): Tensor of shape (M, 3) or (3,), representing RGB values. - If shape is (3,), the same color is applied to all targeted instances. - If shape is (M, 3), M must match the number of targeted instances. - env_ids (Optional[Sequence[int]]): Indices of instances to set. If None: + env_ids (Sequence[int] | None): Indices of instances to set. If None: - For colors.shape == (3,), applies to all instances. - For colors.shape == (M, 3), M must equal num_instances, applies per-instance. """ self._apply_vector3(colors, env_ids, "set_color") def set_intensity( - self, intensities: torch.Tensor, env_ids: Optional[Sequence[int]] = None + self, intensities: torch.Tensor, env_ids: Sequence[int] | None = None ) -> None: """Set intensity for one or more lights. @@ -50,14 +50,14 @@ def set_intensity( intensities (torch.Tensor): Tensor of shape (M,), (1,), or scalar (0-dim). - If scalar or shape (1,), the same intensity is applied to all targeted instances. - If shape (M,), M must match the number of targeted instances. - env_ids (Optional[Sequence[int]]): Indices of instances to set. If None: + env_ids (Sequence[int] | None): Indices of instances to set. If None: - For scalar/shape (1,), applies to all instances. - For shape (M,), M must equal num_instances, applies per-instance. """ self._apply_scalar(intensities, env_ids, "set_intensity") def set_falloff( - self, falloffs: torch.Tensor, env_ids: Optional[Sequence[int]] = None + self, falloffs: torch.Tensor, env_ids: Sequence[int] | None = None ) -> None: """Set falloff (radius) for one or more lights. @@ -65,7 +65,7 @@ def set_falloff( falloffs (torch.Tensor): Tensor of shape (M,), (1,), or scalar (0-dim). - If scalar or shape (1,), the same falloff is applied to all targeted instances. - If shape (M,), M must match the number of targeted instances. - env_ids (Optional[Sequence[int]]): Indices of instances to set. If None: + env_ids (Sequence[int] | None): Indices of instances to set. If None: - For scalar/shape (1,), applies to all instances. - For shape (M,), M must equal num_instances, applies per-instance. """ @@ -74,7 +74,7 @@ def set_falloff( def set_local_pose( self, pose: torch.Tensor, - env_ids: Optional[Sequence[int]] = None, + env_ids: Sequence[int] | None = None, to_matrix: bool = False, ) -> None: """Set local pose (translation) for one or more lights. @@ -83,7 +83,7 @@ def set_local_pose( pose (torch.Tensor): - If to_matrix=False: shape (3,) or (M, 3), representing (x, y, z). - If to_matrix=True: shape (4, 4) or (M, 4, 4); translation extracted automatically. - env_ids (Optional[Sequence[int]]): Indices to set. If None: + env_ids (Sequence[int] | None): Indices to set. If None: - For vector input (3,) broadcast to all, or (M,3) with M == num_instances. - For matrix input (4,4) broadcast to all, or (M,4,4) with M == num_instances. to_matrix (bool): Interpret `pose` as full 4x4 matrix if True, else as vector(s). @@ -157,12 +157,13 @@ def get_local_pose(self, to_matrix: bool = False) -> torch.Tensor: def _apply_vector3( self, tensor: torch.Tensor, - env_ids: Optional[Sequence[int]], + env_ids: Sequence[int] | None, setter_name: str, ) -> None: """ Generic helper for 3-element vectors (color, location). Expects tensor shape: (3,), or (M,3) with M == num_instances or M == len(env_ids). + env_ids: Sequence[int] | None """ # Validate tensor type if not torch.is_tensor(tensor): @@ -221,12 +222,13 @@ def _apply_vector3( def _apply_scalar( self, tensor: torch.Tensor, - env_ids: Optional[Sequence[int]], + env_ids: Sequence[int] | None, setter_name: str, ) -> None: """ Generic helper for scalar floats (intensity, falloff). Accepts tensor shape: () (0-dim), (1,), or (M,) with M == num_instances or M == len(env_ids). + env_ids: Sequence[int] | None """ if not torch.is_tensor(tensor): logger.log_error( @@ -273,7 +275,7 @@ def _apply_scalar( f"(expected scalar, (1,), ({self.num_instances},) or ({len(all_ids)},))." ) - def reset(self, env_ids: Optional[Sequence[int]] = None) -> None: + def reset(self, env_ids: Sequence[int] | None = None) -> None: self.cfg: LightCfg self.set_color(torch.as_tensor(self.cfg.color), env_ids=env_ids) self.set_intensity(torch.as_tensor(self.cfg.intensity), env_ids=env_ids) diff --git a/embodichain/lab/sim/objects/rigid_object_group.py b/embodichain/lab/sim/objects/rigid_object_group.py index 2db3053f..d5102339 100644 --- a/embodichain/lab/sim/objects/rigid_object_group.py +++ b/embodichain/lab/sim/objects/rigid_object_group.py @@ -19,7 +19,7 @@ import numpy as np from dataclasses import dataclass -from typing import List, Sequence, Optional, Union +from typing import List, Sequence, Union from dexsim.models import MeshObject from dexsim.types import RigidBodyGPUAPIReadType, RigidBodyGPUAPIWriteType @@ -266,7 +266,7 @@ def _set_default_collision_filter(self) -> None: self.set_collision_filter(collision_filter_data) def set_collision_filter( - self, filter_data: torch.Tensor, env_ids: Optional[Sequence[int]] = None + self, filter_data: torch.Tensor, env_ids: Sequence[int] | None = None ) -> None: """set collision filter data for the rigid object group. @@ -276,7 +276,7 @@ def set_collision_filter( If 2nd element is 0, the object will collision with all other objects in world. 3rd and 4th elements are not used currently. - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. Defaults to None. + env_ids (Sequence[int] | None, optional): Environment indices. If None, then all indices are used. Defaults to None. """ local_env_ids = self._all_indices if env_ids is None else env_ids @@ -293,16 +293,16 @@ def set_collision_filter( def set_local_pose( self, pose: torch.Tensor, - env_ids: Optional[Sequence[int]] = None, - obj_ids: Optional[Sequence[int]] = None, + env_ids: Sequence[int] | None = None, + obj_ids: Sequence[int] | None = None, ) -> None: """Set local pose of the rigid object group. Args: pose (torch.Tensor): The local pose of the rigid object group with shape (num_instances, num_objects, 7) or (num_instances, num_objects, 4, 4). - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. - obj_ids (Optional[Sequence[int]], optional): Object indices within the group. If None, all objects are set. Defaults to None. + env_ids (Sequence[int] | None, optional): Environment indices. If None, then all indices are used. + obj_ids (Sequence[int] | None, optional): Object indices within the group. If None, all objects are set. Defaults to None. """ local_env_ids = self._all_indices if env_ids is None else env_ids local_obj_ids = self._all_obj_indices if obj_ids is None else obj_ids @@ -401,11 +401,11 @@ def get_user_ids(self) -> torch.Tensor: device=self.device, ) - def clear_dynamics(self, env_ids: Optional[Sequence[int]] = None) -> None: + def clear_dynamics(self, env_ids: Sequence[int] | None = None) -> None: """Clear the dynamics of the rigid bodies by resetting velocities and applying zero forces and torques. Args: - env_ids (Optional[Sequence[int]]): Environment indices. If None, then all indices are used. + env_ids (Sequence[int] | None): Environment indices. If None, then all indices are used. """ if self.is_non_dynamic: return @@ -446,13 +446,13 @@ def clear_dynamics(self, env_ids: Optional[Sequence[int]] = None) -> None: ) def set_visual_material( - self, mat: VisualMaterial, env_ids: Optional[Sequence[int]] = None + self, mat: VisualMaterial, env_ids: Sequence[int] | None = None ) -> None: """Set visual material for the rigid object group. Args: mat (VisualMaterial): The material to set. - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + env_ids (Sequence[int] | None, optional): Environment indices. If None, then all indices are used. """ local_env_ids = self._all_indices if env_ids is None else env_ids @@ -465,7 +465,7 @@ def set_visual_material( # If needed, we should create a visual material dict to store the material instances, and # implement a get_visual_material method to retrieve the material instances. - def reset(self, env_ids: Optional[Sequence[int]] = None) -> None: + def reset(self, env_ids: Sequence[int] | None = None) -> None: local_env_ids = self._all_indices if env_ids is None else env_ids num_instances = len(local_env_ids) diff --git a/embodichain/lab/sim/objects/robot.py b/embodichain/lab/sim/objects/robot.py index d15f50fb..d53a04e0 100644 --- a/embodichain/lab/sim/objects/robot.py +++ b/embodichain/lab/sim/objects/robot.py @@ -17,7 +17,7 @@ import torch import numpy as np -from typing import List, Dict, Optional, Tuple, Union, Sequence +from typing import List, Dict, Tuple, Union, Sequence from dataclasses import dataclass, field from dexsim.engine import Articulation as _Articulation @@ -90,17 +90,17 @@ def __str__(self) -> str: ) @property - def control_parts(self) -> Union[Dict[str, List[str]], None]: + def control_parts(self) -> Dict[str, List[str]] | None: """Get the control parts of the robot.""" return self.cfg.control_parts def get_joint_ids( - self, name: Optional[str] = None, remove_mimic: bool = False + self, name: str | None = None, remove_mimic: bool = False ) -> List[int]: """Get the joint ids of the robot for a specific control part. Args: - name (str, optional): The name of the control part to get the joint ids for. If None, the default part is used. + name (str | None): The name of the control part to get the joint ids for. If None, the default part is used. remove_mimic (bool, optional): If True, mimic joints will be excluded from the returned joint ids. Defaults to False. Returns: @@ -141,25 +141,25 @@ def get_proprioception(self) -> Dict[str, torch.Tensor]: def compute_fk( self, - qpos: Optional[Union[torch.tensor, np.ndarray]], - name: Optional[str] = None, - link_names: Optional[List[str]] = None, - end_link_name: Optional[str] = None, - root_link_name: Optional[str] = None, - env_ids: Optional[Sequence[int]] = None, + qpos: torch.Tensor | np.ndarray | None, + name: str | None = None, + link_names: List[str] | None = None, + end_link_name: str | None = None, + root_link_name: str | None = None, + env_ids: Sequence[int] | None = None, to_matrix: bool = False, ) -> torch.Tensor: """Compute the forward kinematics of the robot given joint positions and optionally a specific part name. The output pose will be in the local arena frame. Args: - qpos (Optional[Union[torch.tensor, np.ndarray]]): Joint positions of the robot, (n_envs, num_joints). - name (str, optional): The name of the control part to compute the FK for. If None, the default part is used. - link_names (List[str], optional): The names of the links to compute the FK for. If None, all links are used. - end_link_name (str, optional): The name of the end link to compute the FK for. If None, the default end link is used. - root_link_name (str, optional): The name of the root link to compute the FK for. If None, the default root link is used. - env_ids (Sequence[int], optional): The environment ids to compute the FK for. If None, all environments are used. - to_matrix (bool, optional): If True, returns the transformation in the form of a 4x4 matrix. + qpos (torch.Tensor | np.ndarray | None): Joint positions of the robot, (n_envs, num_joints). + name (str | None): The name of the control part to compute the FK for. If None, the default part is used. + link_names (List[str] | None): The names of the links to compute the FK for. If None, all links are used. + end_link_name (str | None): The name of the end link to compute the FK for. If None, the default end link is used. + root_link_name (str | None): The name of the root link to compute the FK for. If None, the default root link is used. + env_ids (Sequence[int] | None): The environment ids to compute the FK for. If None, all environments are used. + to_matrix (bool): If True, returns the transformation in the form of a 4x4 matrix. Returns: torch.Tensor: The forward kinematics result with shape (n_envs, 7) or (n_envs, 4, 4) if `to_matrix` is True. @@ -215,25 +215,25 @@ def compute_fk( def compute_ik( self, - pose: Union[torch.Tensor, np.ndarray], - joint_seed: Optional[Union[torch.Tensor, np.ndarray]] = None, - name: Optional[str] = None, - env_ids: Optional[Sequence[int]] = None, + pose: torch.Tensor | np.ndarray, + joint_seed: torch.Tensor | np.ndarray | None = None, + name: str | None = None, + env_ids: Sequence[int] | None = None, return_all_solutions: bool = False, - ) -> Optional[Tuple[torch.Tensor, torch.Tensor]]: + ) -> Tuple[torch.Tensor, torch.Tensor] | None: """Compute the inverse kinematics of the robot given joint positions and optionally a specific part name. The input pose should be in the local arena frame. Args: pose (torch.Tensor): The end effector pose of the robot, (n_envs, 7) or (n_envs, 4, 4). - joint_seed (torch.Tensor, optional): The joint positions to use as a seed for the IK computation, (n_envs, dof). + joint_seed (torch.Tensor | None): The joint positions to use as a seed for the IK computation, (n_envs, dof). If None, the zero joint positions will be used as the seed. - name (str, optional): The name of the control part to compute the IK for. If None, the default part is used. - env_ids (Optional[Sequence[int]]): Environment indices to apply the positions. Defaults to all environments. - return_all_solutions (bool, optional): Whether to return all IK solutions or just the best one. Defaults to False. + name (str | None): The name of the control part to compute the IK for. If None, the default part is used. + env_ids (Sequence[int] | None): Environment indices to apply the positions. Defaults to all environments. + return_all_solutions (bool): Whether to return all IK solutions or just the best one. Defaults to False. Returns: - Tuple[torch.Tensor, torch.Tensor]: The success Tensor with shape (n_envs, ) and qpos Tensor with shape (n_envs, max_results, dof). + Tuple[torch.Tensor, torch.Tensor] | None: The success Tensor with shape (n_envs, ) and qpos Tensor with shape (n_envs, max_results, dof), or None if solver not found. """ local_env_ids = self._all_indices if env_ids is None else env_ids @@ -302,19 +302,19 @@ def compute_ik( def compute_batch_fk( self, - qpos: torch.tensor, + qpos: torch.Tensor, name: str, - env_ids: Optional[Sequence[int]] = None, + env_ids: Sequence[int] | None = None, to_matrix: bool = False, ): """Compute the forward kinematics of the robot given joint positions and optionally a specific part name. The output pose will be in the local arena frame. Args: - qpos (Optional[Union[torch.tensor, np.ndarray]]): Joint positions of the robot, (n_envs, n_batch, num_joints). - name (str, optional): The name of the control part to compute the FK for. If None, the default part is used. - env_ids (Sequence[int], optional): The environment ids to compute the FK for. If None, all environments are used. - to_matrix (bool, optional): If True, returns the transformation in the form of a 4x4 matrix. + qpos (torch.Tensor | np.ndarray | None): Joint positions of the robot, (n_envs, n_batch, num_joints). + name (str | None): The name of the control part to compute the FK for. If None, the default part is used. + env_ids (Sequence[int] | None): The environment ids to compute the FK for. If None, all environments are used. + to_matrix (bool): If True, returns the transformation in the form of a 4x4 matrix. Returns: torch.Tensor: The forward kinematics result with shape (n_envs, batch, 7) or (n_envs, batch, 4, 4) if `to_matrix` is True. @@ -367,19 +367,19 @@ def compute_batch_fk( def compute_batch_ik( self, - pose: Union[torch.Tensor, np.ndarray], - joint_seed: Optional[Union[torch.Tensor, np.ndarray]], + pose: torch.Tensor | np.ndarray, + joint_seed: torch.Tensor | np.ndarray | None, name: str, - env_ids: Optional[Sequence[int]] = None, + env_ids: Sequence[int] | None = None, ): """Compute the inverse kinematics of the robot given joint positions and optionally a specific part name. The input pose should be in the local arena frame. Args: pose (torch.Tensor): The end effector pose of the robot, (n_envs, n_batch, 7) or (n_envs, n_batch, 4, 4). - joint_seed (torch.Tensor, optional): The joint positions to use as a seed for the IK computation, (n_envs, n_batch, dof). If None, the zero joint positions will be used as the seed. - name (str): The name of the control part to compute the IK for. If None, the default part is used. - env_ids (Optional[Sequence[int]]): Environment indices to apply the positions. Defaults to all environments. + joint_seed (torch.Tensor | None): The joint positions to use as a seed for the IK computation, (n_envs, n_batch, dof). If None, the zero joint positions will be used as the seed. + name (str | None): The name of the control part to compute the IK for. If None, the default part is used. + env_ids (Sequence[int] | None): Environment indices to apply the positions. Defaults to all environments. Returns: Tuple[torch.Tensor, torch.Tensor]: @@ -542,14 +542,14 @@ def init_solver(self, cfg: Union[SolverCfg, Dict[str, SolverCfg]]) -> None: solver_cfg.joint_names = self.cfg.control_parts[part_name] self._solvers[name] = solver_cfg.init_solver(device=self.device) - def get_solver(self, name: Optional[str] = None) -> Optional[BaseSolver]: + def get_solver(self, name: str | None = None) -> BaseSolver | None: """Get the kinematic solver for a specific control part. Args: - name (str, optional): The name of the control part to get the solver for. If None, the default part is used. + name (str | None): The name of the control part to get the solver for. If None, the default part is used. Returns: - Optional[BaseSolver]: The kinematic solver for the specified control part, or None if not found. + BaseSolver | None: The kinematic solver for the specified control part, or None if not found. """ if not self._solvers: @@ -562,16 +562,15 @@ def get_solver(self, name: Optional[str] = None) -> Optional[BaseSolver]: def get_control_part_base_pose( self, - name: Optional[str] = None, - env_ids: Optional[Sequence[int]] = None, + name: str | None = None, + env_ids: Sequence[int] | None = None, to_matrix: bool = False, ) -> torch.Tensor: """Retrieves the base pose of the control part for a specified robot. Args: - name (Optional[str]): The name of the control part the solver adhere to. If None, the default solver is used. - env_ids (Optional[Sequence[int]]): A sequence of environment IDs to specify the environments. - If None, all indices are used. + name (str | None): The name of the control part the solver adhere to. If None, the default solver is used. + env_ids (Sequence[int] | None): A sequence of environment IDs to specify the environments. If None, all indices are used. to_matrix (bool): If True, returns the pose in the form of a 4x4 matrix. Returns: diff --git a/embodichain/lab/sim/objects/soft_object.py b/embodichain/lab/sim/objects/soft_object.py index 84617d1c..62e45c8a 100644 --- a/embodichain/lab/sim/objects/soft_object.py +++ b/embodichain/lab/sim/objects/soft_object.py @@ -20,7 +20,7 @@ from functools import cached_property from dataclasses import dataclass -from typing import List, Sequence, Optional, Union +from typing import List, Sequence, Union from dexsim.models import MeshObject from dexsim.engine import PhysicsScene @@ -189,9 +189,9 @@ def _set_default_collision_filter(self) -> None: self.set_collision_filter(collision_filter_data) def set_collision_filter( - self, filter_data: torch.Tensor, env_ids: Optional[Sequence[int]] = None + self, filter_data: torch.Tensor, env_ids: Sequence[int] | None = None ) -> None: - """set collision filter data for the rigid object. + """Set collision filter data for the rigid object. Args: filter_data (torch.Tensor): [N, 4] of int. @@ -199,7 +199,7 @@ def set_collision_filter( If 2nd element is 0, the object will collision with all other objects in world. 3rd and 4th elements are not used currently. - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. Defaults to None. + env_ids (Sequence[int] | None): Environment indices. If None, then all indices are used. """ local_env_ids = self._all_indices if env_ids is None else env_ids @@ -215,22 +215,22 @@ def set_collision_filter( ) @property - def body_data(self) -> Optional[SoftBodyData]: + def body_data(self) -> SoftBodyData | None: """Get the soft body data manager for this rigid object. Returns: - SoftBodyData: The rigid body data manager. + SoftBodyData | None: The rigid body data manager. """ return self._data def set_local_pose( - self, pose: torch.Tensor, env_ids: Optional[Sequence[int]] = None + self, pose: torch.Tensor, env_ids: Sequence[int] | None = None ) -> None: """Set local pose of the rigid object. Args: pose (torch.Tensor): The local pose of the rigid object with shape (N, 7) or (N, 4, 4). - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + env_ids (Sequence[int] | None): Environment indices. If None, then all indices are used. """ local_env_ids = self._all_indices if env_ids is None else env_ids @@ -339,7 +339,7 @@ def get_local_pose(self, to_matrix: bool = False) -> torch.Tensor: """ raise NotImplementedError("Getting local pose for SoftObject is not supported.") - def reset(self, env_ids: Optional[Sequence[int]] = None) -> None: + def reset(self, env_ids: Sequence[int] | None = None) -> None: local_env_ids = self._all_indices if env_ids is None else env_ids num_instances = len(local_env_ids) diff --git a/embodichain/lab/sim/planners/base_planner.py b/embodichain/lab/sim/planners/base_planner.py index d85e026d..624b7099 100644 --- a/embodichain/lab/sim/planners/base_planner.py +++ b/embodichain/lab/sim/planners/base_planner.py @@ -16,7 +16,7 @@ import numpy as np from abc import ABC, abstractmethod -from typing import Dict, List, Tuple, Union, Optional +from typing import Dict, List, Tuple, Union import matplotlib.pyplot as plt from embodichain.lab.sim.planners.utils import TrajectorySampleMethod @@ -46,10 +46,10 @@ def plan( **kwargs, ) -> Tuple[ bool, - Optional[np.ndarray], - Optional[np.ndarray], - Optional[np.ndarray], - Optional[np.ndarray], + np.ndarray | None, + np.ndarray | None, + np.ndarray | None, + np.ndarray | None, float, ]: r"""Execute trajectory planning. diff --git a/embodichain/lab/sim/planners/motion_generator.py b/embodichain/lab/sim/planners/motion_generator.py index 72248314..41209da1 100644 --- a/embodichain/lab/sim/planners/motion_generator.py +++ b/embodichain/lab/sim/planners/motion_generator.py @@ -16,7 +16,7 @@ import torch import numpy as np -from typing import Dict, List, Tuple, Union, Optional, Any +from typing import Dict, List, Tuple, Union, Any from enum import Enum from scipy.spatial.transform import Rotation, Slerp @@ -170,7 +170,7 @@ def _get_constraints( } def _create_state_dict( - self, position: np.ndarray, velocity: Optional[np.ndarray] = None + self, position: np.ndarray, velocity: np.ndarray | None = None ) -> Dict: r"""Create a state dictionary for trajectory planning. @@ -207,10 +207,10 @@ def plan( **kwargs, ) -> Tuple[ bool, - Optional[np.ndarray], - Optional[np.ndarray], - Optional[np.ndarray], - Optional[np.ndarray], + np.ndarray | None, + np.ndarray | None, + np.ndarray | None, + np.ndarray | None, float, ]: r"""Plan trajectory without collision checking. @@ -290,15 +290,15 @@ def plan_with_collision( def create_discrete_trajectory( self, - xpos_list: Optional[List[np.ndarray]] = None, - qpos_list: Optional[List[np.ndarray]] = None, + xpos_list: list[np.ndarray] | None = None, + qpos_list: list[np.ndarray] | None = None, is_use_current_qpos: bool = True, is_linear: bool = False, sample_method: TrajectorySampleMethod = TrajectorySampleMethod.QUANTITY, - sample_num: Union[float, int] = 20, - qpos_seed: Optional[np.ndarray] = None, + sample_num: float | int = 20, + qpos_seed: np.ndarray | None = None, **kwargs, - ) -> Tuple[List[np.ndarray], List[np.ndarray]]: + ) -> tuple[list[np.ndarray], list[np.ndarray]]: r"""Generate a discrete trajectory between waypoints using cartesian or joint space interpolation. This method supports two trajectory planning approaches: diff --git a/embodichain/lab/sim/planners/toppra_planner.py b/embodichain/lab/sim/planners/toppra_planner.py index 0a37b783..abf6ef6c 100644 --- a/embodichain/lab/sim/planners/toppra_planner.py +++ b/embodichain/lab/sim/planners/toppra_planner.py @@ -19,7 +19,7 @@ from embodichain.lab.sim.planners.utils import TrajectorySampleMethod from embodichain.lab.sim.planners.base_planner import BasePlanner -from typing import TYPE_CHECKING, Union, Optional, Tuple +from typing import TYPE_CHECKING, Union, Tuple try: import toppra as ta diff --git a/embodichain/lab/sim/robots/cobotmagic.py b/embodichain/lab/sim/robots/cobotmagic.py index 70859f90..ec393312 100644 --- a/embodichain/lab/sim/robots/cobotmagic.py +++ b/embodichain/lab/sim/robots/cobotmagic.py @@ -19,7 +19,7 @@ import torch import numpy as np -from typing import Dict, List, Optional, Any, Union +from typing import Dict, List, Any, Union from embodichain.lab.sim.cfg import ( RobotCfg, @@ -36,8 +36,8 @@ @configclass class CobotMagicCfg(RobotCfg): urdf_cfg: URDFCfg = None - control_parts: Optional[Dict[str, List[str]]] = None - solver_cfg: Optional[Dict[str, "SolverCfg"]] = None + control_parts: Dict[str, List[str]] | None = None + solver_cfg: Dict[str, "SolverCfg"] | None = None @classmethod def from_dict(cls, init_dict: Dict[str, Union[str, float, int]]) -> CobotMagicCfg: diff --git a/embodichain/lab/sim/robots/dexforce_w1/params.py b/embodichain/lab/sim/robots/dexforce_w1/params.py index 6082daed..4d5c9faa 100644 --- a/embodichain/lab/sim/robots/dexforce_w1/params.py +++ b/embodichain/lab/sim/robots/dexforce_w1/params.py @@ -16,7 +16,7 @@ import torch import numpy as np -from typing import Optional + from dataclasses import dataclass, field from embodichain.lab.sim.robots.dexforce_w1.types import ( DexforceW1HandBrand, @@ -257,7 +257,7 @@ def from_dict(cls, data: dict) -> "W1ArmKineParams": return inst def to_torch( - self, device: Optional[torch.device] = None, dtype: torch.dtype = torch.float32 + self, device: torch.device | None = None, dtype: torch.dtype = torch.float32 ) -> dict: dev = torch.device("cpu") if device is None else device return { diff --git a/embodichain/lab/sim/robots/dexforce_w1/utils.py b/embodichain/lab/sim/robots/dexforce_w1/utils.py index 1bfbeb6d..63402377 100644 --- a/embodichain/lab/sim/robots/dexforce_w1/utils.py +++ b/embodichain/lab/sim/robots/dexforce_w1/utils.py @@ -15,7 +15,7 @@ # ---------------------------------------------------------------------------- import numpy as np from scipy.spatial.transform import Rotation as R -from typing import List, Dict, Optional +from typing import List, Dict from embodichain.lab.sim.robots.dexforce_w1.types import ( DexforceW1ArmKind, @@ -296,17 +296,17 @@ def build_dexforce_w1_assembly_urdf_cfg( DexforceW1ArmSide.LEFT, DexforceW1ArmSide.RIGHT, ], - fname: Optional[str] = "DexforceW1V021", - hand_types: Optional[Dict[DexforceW1ArmSide, DexforceW1HandBrand]] = None, - hand_versions: Optional[Dict[DexforceW1ArmSide, DexforceW1Version]] = None, - hand_attach_xposes: Optional[Dict[DexforceW1ArmSide, np.ndarray]] = None, + fname: str | None = "DexforceW1V021", + hand_types: dict[DexforceW1ArmSide, DexforceW1HandBrand] | None = None, + hand_versions: dict[DexforceW1ArmSide, DexforceW1Version] | None = None, + hand_attach_xposes: dict[DexforceW1ArmSide, np.ndarray] | None = None, include_chassis: bool = True, include_torso: bool = True, include_head: bool = True, include_hand: bool = True, include_eyes: bool = True, include_wrist_cameras: bool = True, - component_versions: Optional[Dict[DexforceW1Type, DexforceW1Version]] = None, + component_versions: dict[DexforceW1Type, DexforceW1Version] | None = None, ) -> URDFCfg: """ Assemble DexforceW1 robot urdf configuration. @@ -515,8 +515,8 @@ def build_dexforce_w1_solver_cfg( DexforceW1ArmSide.LEFT, DexforceW1ArmSide.RIGHT, ], - component_versions: Optional[Dict[DexforceW1Type, DexforceW1Version]] = None, - urdf_cfg: Optional[URDFCfg] = None, + component_versions: dict[DexforceW1Type, DexforceW1Version] | None = None, + urdf_cfg: URDFCfg | None = None, ) -> Dict[DexforceW1Type, SolverCfg]: """ Build DexforceW1 solver configuration dict. @@ -607,15 +607,15 @@ def build_dexforce_w1_cfg( DexforceW1ArmSide.LEFT, DexforceW1ArmSide.RIGHT, ], - hand_types: Optional[Dict[DexforceW1ArmSide, DexforceW1HandBrand]] = None, - hand_versions: Optional[Dict[DexforceW1ArmSide, DexforceW1Version]] = None, - hand_attach_xposes: Optional[Dict[DexforceW1ArmSide, np.ndarray]] = None, + hand_types: dict[DexforceW1ArmSide, DexforceW1HandBrand] | None = None, + hand_versions: dict[DexforceW1ArmSide, DexforceW1Version] | None = None, + hand_attach_xposes: dict[DexforceW1ArmSide, np.ndarray] | None = None, include_chassis: bool = True, include_torso: bool = True, include_head: bool = True, include_hand: bool = True, - component_versions: Optional[Dict[DexforceW1Type, DexforceW1Version]] = None, - solver_cfg: Optional[Dict[DexforceW1Type, SolverCfg]] = None, + component_versions: dict[DexforceW1Type, DexforceW1Version] | None = None, + solver_cfg: dict[DexforceW1Type, SolverCfg] | None = None, ) -> "DexforceW1Cfg": """ Build DexforceW1 robot configuration object. diff --git a/embodichain/lab/sim/sensors/base_sensor.py b/embodichain/lab/sim/sensors/base_sensor.py index 70f78c6e..bdc35c7c 100644 --- a/embodichain/lab/sim/sensors/base_sensor.py +++ b/embodichain/lab/sim/sensors/base_sensor.py @@ -19,7 +19,7 @@ import torch from abc import abstractmethod -from typing import Dict, List, Any, Optional, Sequence, Tuple, Union +from typing import Dict, List, Any, Sequence, Tuple, Union from embodichain.lab.sim.cfg import ObjectBaseCfg from embodichain.lab.sim.common import BatchEntity from embodichain.utils.math import matrix_from_quat @@ -43,7 +43,7 @@ class OffsetCfg: quat: Tuple[float, float, float, float] = (1.0, 0.0, 0.0, 0.0) """Orientation of the sensor in the parent frame as a quaternion (w, x, y, z). Defaults to (1.0, 0.0, 0.0, 0.0).""" - parent: Optional[str] = None + parent: str | None = None """Name of the parent frame. If not specified, the sensor will be placed in the arena frame. This is usually the case when the sensor is not attached to any specific object, eg, link of a robot arm. @@ -171,5 +171,5 @@ def get_data(self, copy: bool = True) -> Dict[str, torch.Tensor]: return {key: value.clone() for key, value in self._data_buffer.items()} return self._data_buffer - def reset(self, env_ids: Optional[Sequence[int]] = None) -> None: + def reset(self, env_ids: Sequence[int] | None = None) -> None: return super().reset(env_ids) diff --git a/embodichain/lab/sim/sensors/camera.py b/embodichain/lab/sim/sensors/camera.py index 11f05bbb..a4aeb749 100644 --- a/embodichain/lab/sim/sensors/camera.py +++ b/embodichain/lab/sim/sensors/camera.py @@ -23,7 +23,7 @@ import warp as wp from functools import cached_property -from typing import Union, Tuple, Optional, Sequence, List +from typing import Union, Tuple, Sequence, List from embodichain.lab.sim.sensors import BaseSensor, SensorCfg from embodichain.utils.math import matrix_from_quat, quat_from_matrix, look_at_to_pose @@ -45,9 +45,9 @@ class ExtrinsicsCfg(SensorCfg.OffsetCfg): Otherwise, the position and orientation will be set to the defaults. """ - eye: Union[Tuple[float, float, float], None] = None - target: Union[Tuple[float, float, float], None] = None - up: Union[Tuple[float, float, float], None] = None + eye: Tuple[float, float, float] | None = None + target: Tuple[float, float, float] | None = None + up: Tuple[float, float, float] | None = None """Alternative way to specify the camera extrinsics using eye, target, and up vectors.""" @property @@ -354,7 +354,7 @@ def _attach_to_entity(self) -> None: entity.attach_node(parent) def set_local_pose( - self, pose: torch.Tensor, env_ids: Optional[Sequence[int]] = None + self, pose: torch.Tensor, env_ids: Sequence[int] | None = None ) -> None: """Set the local pose of the camera. @@ -362,7 +362,7 @@ def set_local_pose( Args: pose (torch.Tensor): The local pose to set, should be a 4x4 transformation matrix. - env_ids (Optional[Sequence[int]]): The environment IDs to set the pose for. If None, set for all environments. + env_ids (Sequence[int] | None): The environment IDs to set the pose for. If None, set for all environments. """ if env_ids is None: local_env_ids = range(len(self._entities)) @@ -435,16 +435,16 @@ def look_at( self, eye: torch.Tensor, target: torch.Tensor, - up: Optional[torch.Tensor] = None, - env_ids: Optional[Sequence[int]] = None, + up: torch.Tensor | None = None, + env_ids: Sequence[int] | None = None, ) -> None: """Set the camera to look at a target point. Args: eye (torch.Tensor): The position of the camera (eye) with shape (N, 3). target (torch.Tensor): The point the camera should look at (target) with shape (N, 3). - up (Optional[torch.Tensor]): The up direction vector. If None, defaults to [0, 0, 1]. - env_ids (Optional[Sequence[int]]): The environment IDs to set the look at for. If None, set for all environments. + up (torch.Tensor | None): The up direction vector. If None, defaults to [0, 0, 1]. + env_ids (Sequence[int] | None): The environment IDs to set the look at for. If None, set for all environments. """ if up is None: up = torch.tensor([[0.0, 0.0, 1.0]]).repeat(eye.shape[0], 1) @@ -458,15 +458,14 @@ def look_at( def set_intrinsics( self, intrinsics: torch.Tensor, - env_ids: Optional[Sequence[int]] = None, + env_ids: Sequence[int] | None = None, ) -> None: """ Set the camera intrinsics for both left and right cameras. Args: intrinsics (torch.Tensor): The intrinsics for the left camera with shape (4,) / (3, 3) or (N, 4) / (N, 3, 3). - env_ids (Optional[Sequence[int]], optional): The environment ids to set the intrinsics. - If None, set for all environments. Defaults to None. + env_ids (Sequence[int] | None): The environment ids to set the intrinsics. If None, set for all environments. """ ids = env_ids if env_ids is not None else range(self.num_instances) @@ -503,7 +502,7 @@ def get_intrinsics(self) -> torch.Tensor: return torch.stack(intrinsics, dim=0).to(self.device) - def reset(self, env_ids: Optional[Sequence[int]] = None) -> None: + def reset(self, env_ids: Sequence[int] | None = None) -> None: self.cfg: CameraCfg if self.cfg.extrinsics.eye is not None: diff --git a/embodichain/lab/sim/sensors/stereo.py b/embodichain/lab/sim/sensors/stereo.py index d8b8e51d..bdfd9d8e 100644 --- a/embodichain/lab/sim/sensors/stereo.py +++ b/embodichain/lab/sim/sensors/stereo.py @@ -23,7 +23,7 @@ import warp as wp import dexsim.render as dr -from typing import Dict, Tuple, List, Optional, Sequence +from typing import Dict, Tuple, List, Sequence from dexsim.utility import inv_transform from embodichain.lab.sim.sensors import Camera, CameraCfg @@ -466,18 +466,16 @@ def get_left_right_arena_pose(self) -> torch.Tensor: def set_intrinsics( self, intrinsics: torch.Tensor, - right_intrinsics: Optional[torch.Tensor] = None, - env_ids: Optional[Sequence[int]] = None, + right_intrinsics: torch.Tensor | None = None, + env_ids: Sequence[int] | None = None, ) -> None: """ Set the camera intrinsics for both left and right cameras. Args: intrinsics (torch.Tensor): The intrinsics for the left camera with shape (4,) / (3, 3) or (B, 4) / (B, 3, 3). - right_intrinsics (Optional[torch.Tensor], optional): The intrinsics for the right camera with shape 4,) / (3, 3) or (B, 4) / (B, 3, 3). - If None, use the same intrinsics as the left camera. Defaults to None. - env_ids (Optional[Sequence[int]], optional): The environment ids to set the intrinsics. If None, set for all environments. - Defaults to None. + right_intrinsics (torch.Tensor | None): The intrinsics for the right camera with shape (4,) / (3, 3) or (B, 4) / (B, 3, 3). If None, use the same intrinsics as the left camera. + env_ids (Sequence[int] | None): The environment ids to set the intrinsics. If None, set for all environments. """ ids = env_ids if env_ids is not None else range(self.num_instances) diff --git a/embodichain/lab/sim/shapes.py b/embodichain/lab/sim/shapes.py index d7cb1eea..8c0fe208 100644 --- a/embodichain/lab/sim/shapes.py +++ b/embodichain/lab/sim/shapes.py @@ -16,7 +16,7 @@ from __future__ import annotations -from typing import Optional, List, Dict, Union, TYPE_CHECKING, Any +from typing import List, Dict, Union, TYPE_CHECKING, Any from dataclasses import MISSING from embodichain.utils import configclass, is_configclass, logger @@ -62,7 +62,7 @@ class ShapeCfg: shape_type: str = MISSING """Type of the shape. Must be specified in subclasses.""" - visual_material: Optional[VisualMaterialCfg] = None + visual_material: VisualMaterialCfg | None = None """Configuration parameters for the visual material of the shape. Defaults to None.""" @classmethod diff --git a/embodichain/lab/sim/sim_manager.py b/embodichain/lab/sim/sim_manager.py index b5efce4d..b0f4ceb5 100644 --- a/embodichain/lab/sim/sim_manager.py +++ b/embodichain/lab/sim/sim_manager.py @@ -25,7 +25,7 @@ from pathlib import Path from copy import deepcopy from functools import cached_property -from typing import List, Union, Optional, Dict, Tuple, Union, Sequence +from typing import List, Union, Dict, Union, Sequence from dataclasses import dataclass, asdict, field, MISSING # Global cache directories @@ -411,11 +411,11 @@ def render_camera_group(self) -> None: "This interface is only valid when Ray Tracing rendering backend is enabled." ) - def update(self, physics_dt: Optional[float] = None, step: int = 10) -> None: + def update(self, physics_dt: float | None = None, step: int = 10) -> None: """Update the physics. Args: - physics_dt (Optional[float], optional): the time step for physics simulation. Defaults to None. + physics_dt (float | None, optional): the time step for physics simulation. Defaults to None. step (int, optional): the number of steps to update physics. Defaults to 10. """ if self.is_use_gpu_physics and not self._is_initialized_gpu_physics: @@ -501,14 +501,14 @@ def close_window(self) -> None: self._world.close_window() self.is_window_opened = False - def build_multiple_arenas(self, num: int, space: Optional[float] = None) -> None: + def build_multiple_arenas(self, num: int, space: float | None = None) -> None: """Build multiple arenas in a grid pattern. This interface is used for vectorized simulation. Args: num (int): number of arenas to build. - space (float, optional): The distance between each arena. Defaults to the arena_space in sim_config. + space (float | None, optional): The distance between each arena. Defaults to the arena_space in sim_config. """ if space is None: @@ -543,13 +543,13 @@ def set_indirect_lighting(self, name: str) -> None: self._env.set_IBL(ibl_path) def set_emission_light( - self, color: Optional[Sequence[float]] = None, intensity: Optional[float] = None + self, color: Sequence[float] | None = None, intensity: float | None = None ) -> None: """Set environment emission light. Args: - color (Sequence[float]): color of the light. - intensity (float): intensity of the light. + color (Sequence[float] | None): color of the light. + intensity (float | None): intensity of the light. """ if color is None: self._env.set_env_light_emission(color) @@ -609,15 +609,15 @@ def set_texture_cache( self._texture_cache[key] = texture def get_texture_cache( - self, key: Optional[str] = None - ) -> Optional[Union[torch.Tensor, List[torch.Tensor]]]: + self, key: str | None = None + ) -> torch.Tensor | list[torch.Tensor] | None: """Get the texture from the global texture cache. Args: - key (str, optional): The key of the texture. If None, return None. Defaults to None. + key (str | None, optional): The key of the texture. If None, return None. Defaults to None. Returns: - Optional[Union[torch.Tensor, List[torch.Tensor]]]: The texture if found, otherwise None. + torch.Tensor | list[torch.Tensor] | None: The texture if found, otherwise None. """ if key is None: return self._texture_cache @@ -629,7 +629,7 @@ def get_texture_cache( def get_asset( self, uid: str - ) -> Optional[Union[Light, BaseSensor, Robot, RigidObject, Articulation]]: + ) -> Light | BaseSensor | Robot | RigidObject | Articulation | None: """Get an asset by its UID. The asset can be a light, sensor, robot, rigid object or articulation. @@ -697,7 +697,7 @@ def add_light(self, cfg: LightCfg) -> Light: return batch_lights - def get_light(self, uid: str) -> Optional[Light]: + def get_light(self, uid: str) -> Light | None: """Get a light by its UID. Args: @@ -780,14 +780,14 @@ def add_soft_object(self, cfg: SoftObjectCfg) -> SoftObject: self._soft_objects[uid] = soft_obj return soft_obj - def get_rigid_object(self, uid: str) -> Optional[RigidObject]: + def get_rigid_object(self, uid: str) -> RigidObject | None: """Get a rigid object by its unique ID. Args: uid (str): The unique ID of the rigid object. Returns: - Optional[RigidObject]: The rigid object instance if found, otherwise None. + RigidObject | None: The rigid object instance if found, otherwise None. """ if uid not in self._rigid_objects: logger.log_warning(f"Rigid object {uid} not found.") @@ -844,14 +844,14 @@ def add_rigid_object_group(self, cfg: RigidObjectGroupCfg) -> RigidObjectGroup: return rigid_obj_group - def get_rigid_object_group(self, uid: str) -> Optional[RigidObjectGroup]: + def get_rigid_object_group(self, uid: str) -> RigidObjectGroup | None: """Get a rigid object group by its unique ID. Args: uid (str): The unique ID of the rigid object group. Returns: - Optional[RigidObjectGroup]: The rigid object group instance if found, otherwise None. + RigidObjectGroup | None: The rigid object group instance if found, otherwise None. """ if uid not in self._rigid_object_groups: logger.log_warning(f"Rigid object group {uid} not found.") @@ -903,14 +903,14 @@ def add_articulation( return articulation - def get_articulation(self, uid: str) -> Optional[Articulation]: + def get_articulation(self, uid: str) -> Articulation | None: """Get an articulation by its unique ID. Args: uid (str): The unique ID of the articulation. Returns: - Optional[Articulation]: The articulation instance if found, otherwise None. + Articulation | None: The articulation instance if found, otherwise None. """ if uid not in self._articulations: logger.log_warning(f"Articulation {uid} not found.") @@ -925,14 +925,14 @@ def get_articulation_uid_list(self) -> List[str]: """ return list(self._articulations.keys()) - def add_robot(self, cfg: RobotCfg) -> Optional[Robot]: + def add_robot(self, cfg: RobotCfg) -> Robot | None: """Add a Robot to the scene. Args: cfg (RobotCfg): Configuration for the robot. Returns: - Optional[Robot]: The added robot instance handle, or None if failed. + Robot | None: The added robot instance handle, or None if failed. """ uid = cfg.uid @@ -965,14 +965,14 @@ def add_robot(self, cfg: RobotCfg) -> Optional[Robot]: return robot - def get_robot(self, uid: str) -> Optional[Robot]: + def get_robot(self, uid: str) -> Robot | None: """Get a Robot by its unique ID. Args: uid (str): The unique ID of the robot. Returns: - Optional[Robot]: The robot instance if found, otherwise None. + Robot | None: The robot instance if found, otherwise None. """ if uid not in self._robots: logger.log_warning(f"Robot {uid} not found.") @@ -989,13 +989,13 @@ def get_robot_uid_list(self) -> List[str]: return list(self._robots.keys()) def enable_gizmo( - self, uid: str, control_part: Optional[str] = None, gizmo_cfg: object = None + self, uid: str, control_part: str | None = None, gizmo_cfg: object = None ) -> None: """Enable gizmo control for any simulation object (Robot, RigidObject, Camera, etc.). Args: uid (str): UID of the object to attach gizmo to (searches in robots, rigid_objects, sensors, etc.) - control_part (Optional[str], optional): Control part name for robots. Defaults to "arm". + control_part (str | None, optional): Control part name for robots. Defaults to "arm". gizmo_cfg (object, optional): Gizmo configuration object. Defaults to None. """ # Create gizmo key combining uid and control_part @@ -1050,12 +1050,12 @@ def enable_gizmo( f"Failed to create gizmo for {object_type} '{uid}' with control_part '{control_part}': {e}" ) - def disable_gizmo(self, uid: str, control_part: Optional[str] = None) -> None: + def disable_gizmo(self, uid: str, control_part: str | None = None) -> None: """Disable and remove gizmo for a robot. Args: uid (str): Object UID to disable gizmo for - control_part (Optional[str], optional): Control part name for robots. Defaults to None. + control_part (str | None, optional): Control part name for robots. Defaults to None. """ # Create gizmo key combining uid and control_part gizmo_key = f"{uid}:{control_part}" if control_part else uid @@ -1087,12 +1087,12 @@ def disable_gizmo(self, uid: str, control_part: Optional[str] = None) -> None: f"Failed to disable gizmo for '{uid}' with control_part '{control_part}': {e}" ) - def get_gizmo(self, uid: str, control_part: Optional[str] = None) -> object: + def get_gizmo(self, uid: str, control_part: str | None = None) -> object: """Get gizmo instance for a robot. Args: uid (str): Object UID - control_part (Optional[str], optional): Control part name for robots. Defaults to None. + control_part (str | None, optional): Control part name for robots. Defaults to None. Returns: object: Gizmo instance if found, None otherwise. @@ -1101,12 +1101,12 @@ def get_gizmo(self, uid: str, control_part: Optional[str] = None) -> object: gizmo_key = f"{uid}:{control_part}" if control_part else uid return self._gizmos.get(gizmo_key, None) - def has_gizmo(self, uid: str, control_part: Optional[str] = None) -> bool: + def has_gizmo(self, uid: str, control_part: str | None = None) -> bool: """Check if a gizmo exists for the given UID and control part. Args: uid (str): Object UID to check - control_part (Optional[str], optional): Control part name for robots. Defaults to None. + control_part (str | None, optional): Control part name for robots. Defaults to None. Returns: bool: True if gizmo exists, False otherwise. @@ -1139,7 +1139,7 @@ def update_gizmos(self): logger.log_error(f"Error updating gizmo '{gizmo_key}': {e}") def toggle_gizmo_visibility( - self, uid: str, control_part: Optional[str] = None + self, uid: str, control_part: str | None = None ) -> bool: """ Toggle the visibility of a gizmo by uid and optional control_part. @@ -1151,7 +1151,7 @@ def toggle_gizmo_visibility( return None def set_gizmo_visibility( - self, uid: str, visible: bool, control_part: Optional[str] = None + self, uid: str, visible: bool, control_part: str | None = None ) -> None: """ Set the visibility of a gizmo by uid and optional control_part. @@ -1191,7 +1191,7 @@ def add_sensor(self, sensor_cfg: SensorCfg) -> BaseSensor: return sensor - def get_sensor(self, uid: str) -> Optional[BaseSensor]: + def get_sensor(self, uid: str) -> BaseSensor | None: """Get a sensor by its UID. Args: @@ -1420,11 +1420,11 @@ def clean_materials(self): self._visual_materials = {} self._env.clean_materials() - def reset_objects_state(self, env_ids: Optional[Sequence[int]] = None) -> None: + def reset_objects_state(self, env_ids: Sequence[int] | None = None) -> None: """Reset the state of all objects in the scene. Args: - env_ids: The environment IDs to reset. If None, reset all environments. + env_ids (Sequence[int] | None): The environment IDs to reset. If None, reset all environments. """ for robot in self._robots.values(): robot.reset(env_ids) diff --git a/embodichain/lab/sim/solvers/base_solver.py b/embodichain/lab/sim/solvers/base_solver.py index f04d40b4..aa313341 100644 --- a/embodichain/lab/sim/solvers/base_solver.py +++ b/embodichain/lab/sim/solvers/base_solver.py @@ -16,7 +16,7 @@ import torch import numpy as np -from typing import List, Optional, Dict, Any, Union, TYPE_CHECKING, Tuple +from typing import List, Dict, Any, Union, TYPE_CHECKING, Tuple from abc import abstractmethod, ABCMeta from embodichain.utils import configclass, logger @@ -34,10 +34,10 @@ class SolverCfg: class_type: str = "BaseSolver" """The class type of the solver to be used.""" - urdf_path: Optional[str] = None + urdf_path: str | None = None """The file path to the URDF model of the robot.""" - joint_names: Optional[list[str]] = None + joint_names: list[str] | None = None """List of joint names for the solver. If None, all joints in the URDF will be used. @@ -65,7 +65,7 @@ class SolverCfg: This represents the position and orientation of the tool in the robot's end-effector frame. """ - ik_nearest_weight: Optional[List[float]] = None + ik_nearest_weight: List[float] | None = None """Weights for the inverse kinematics nearest calculation. The weights influence how the solver prioritizes closeness to the seed position @@ -166,7 +166,7 @@ def __init__(self, cfg: SolverCfg = None, device: str = None, **kwargs): ) def set_ik_nearest_weight( - self, ik_weight: np.ndarray, joint_ids: np.ndarray = None + self, ik_weight: np.ndarray, joint_ids: np.ndarray | None = None ) -> bool: r"""Sets the inverse kinematics nearest weight. @@ -299,8 +299,8 @@ def get_tcp(self) -> np.ndarray: def get_ik( self, target_pose: torch.Tensor, - joint_seed: Optional[torch.Tensor] = None, - num_samples: Optional[int] = None, + joint_seed: torch.Tensor | None = None, + num_samples: int | None = None, **kwargs, ) -> Tuple[torch.Tensor, torch.Tensor]: r"""Computes the inverse kinematics for a given target pose. @@ -311,8 +311,8 @@ def get_ik( Args: target_pose (torch.Tensor): The target pose represented as a 4x4 transformation matrix. - joint_seed (Optional[torch.Tensor]): The initial joint positions used as a seed. - num_samples (Optional[int]): The number of random joint seeds to generate. + joint_seed (torch.Tensor | None): The initial joint positions used as a seed. + num_samples (int | None): The number of random joint seeds to generate. **kwargs: Additional keyword arguments for customization. Returns: @@ -372,17 +372,15 @@ def get_fk(self, qpos: torch.tensor, **kwargs) -> torch.Tensor: def get_jacobian( self, qpos: torch.Tensor, - locations: Optional[Union[torch.Tensor, np.ndarray]] = None, + locations: torch.Tensor | np.ndarray | None = None, jac_type: str = "full", ) -> torch.Tensor: r"""Compute the Jacobian matrix for the given joint positions. Args: qpos (torch.Tensor): The joint positions. Shape: (dof,) or (batch_size, dof). - locations (Optional[torch.Tensor]): The offset points (relative to the end-effector coordinate system). - Shape: (batch_size, 3) or (3,) for a single offset. - jac_type (str, optional): 'full', 'trans', or 'rot' for full, translational, or rotational Jacobian. - Defaults to 'full'. + locations (torch.Tensor | np.ndarray | None): The offset points (relative to the end-effector coordinate system). Shape: (batch_size, 3) or (3,) for a single offset. + jac_type (str): 'full', 'trans', or 'rot' for full, translational, or rotational Jacobian. Defaults to 'full'. Returns: torch.Tensor: The Jacobian matrix. Shape: diff --git a/embodichain/lab/sim/solvers/differential_solver.py b/embodichain/lab/sim/solvers/differential_solver.py index f3c4c4ea..a5d894d6 100644 --- a/embodichain/lab/sim/solvers/differential_solver.py +++ b/embodichain/lab/sim/solvers/differential_solver.py @@ -15,7 +15,7 @@ # ---------------------------------------------------------------------------- import torch -from typing import Optional, Union, Tuple, Any, Literal, TYPE_CHECKING +from typing import Union, Tuple, Any, Literal, TYPE_CHECKING from scipy.spatial.transform import Rotation from embodichain.utils import configclass, logger @@ -55,7 +55,7 @@ class DifferentialSolverCfg(SolverCfg): ik_method: Literal["pinv", "svd", "trans", "dls"] = "pinv" # Parameters for the inverse-kinematics method. - ik_params: Optional[dict] = None + ik_params: dict | None = None def __post_init__(self): # Default parameters for different inverse kinematics approaches @@ -142,11 +142,11 @@ def action_dim(self) -> int: else: return 7 # (x, y, z, qw, qx, qy, qz) - def reset(self, env_ids: Optional[torch.Tensor] = None): + def reset(self, env_ids: torch.Tensor | None = None): """Reset the internal buffers for the specified environments. Args: - env_ids (Optional[torch.Tensor]): The environment indices to reset. If None, reset all. + env_ids (torch.Tensor | None): The environment indices to reset. If None, reset all. """ if env_ids is None: env_ids = torch.arange(self.num_envs, device=self.device) @@ -158,15 +158,15 @@ def reset(self, env_ids: Optional[torch.Tensor] = None): def set_command( self, command: torch.Tensor, - ee_pos: Optional[torch.Tensor] = None, - ee_quat: Optional[torch.Tensor] = None, + ee_pos: torch.Tensor | None = None, + ee_quat: torch.Tensor | None = None, ) -> bool: """Set the target end-effector pose command. Args: command (torch.Tensor): The command tensor. - ee_pos (Optional[torch.Tensor]): Current end-effector position (for relative mode). - ee_quat (Optional[torch.Tensor]): Current end-effector quaternion (for relative mode). + ee_pos (torch.Tensor | None): Current end-effector position (for relative mode). + ee_quat (torch.Tensor | None): Current end-effector quaternion (for relative mode). Returns: bool: True if the command was set successfully, False otherwise. diff --git a/embodichain/lab/sim/solvers/null_space_posture_task.py b/embodichain/lab/sim/solvers/null_space_posture_task.py index 13d4e590..549df7f7 100644 --- a/embodichain/lab/sim/solvers/null_space_posture_task.py +++ b/embodichain/lab/sim/solvers/null_space_posture_task.py @@ -16,7 +16,7 @@ import numpy as np -from typing import List, Optional, Union, TYPE_CHECKING +from typing import List, Union, TYPE_CHECKING from embodichain.utils import logger try: @@ -103,8 +103,8 @@ def __init__( cost: float, lm_damping: float = 0.0, gain: float = 1.0, - controlled_frames: Optional[List[str]] = None, - controlled_joints: Optional[List[str]] = None, + controlled_frames: list[str] | None = None, + controlled_joints: list[str] | None = None, ) -> None: r"""Initialize the null space posture task. diff --git a/embodichain/lab/sim/solvers/opw_solver.py b/embodichain/lab/sim/solvers/opw_solver.py index 0ddecff8..4526af79 100644 --- a/embodichain/lab/sim/solvers/opw_solver.py +++ b/embodichain/lab/sim/solvers/opw_solver.py @@ -17,7 +17,7 @@ import torch import numpy as np from itertools import product -from typing import Optional, Union, Tuple, Any, Literal, TYPE_CHECKING +from typing import Union, Tuple, Any, Literal, TYPE_CHECKING from scipy.spatial.transform import Rotation from embodichain.utils import configclass, logger @@ -76,7 +76,7 @@ class OPWSolverCfg(SolverCfg): has_parallelogram = False # Parameters for the inverse-kinematics method. - ik_params: Optional[dict] = None + ik_params: dict | None = None def init_solver( self, device: torch.device = torch.device("cpu"), **kwargs diff --git a/embodichain/lab/sim/solvers/pink_solver.py b/embodichain/lab/sim/solvers/pink_solver.py index b7ab7b08..fea414a0 100644 --- a/embodichain/lab/sim/solvers/pink_solver.py +++ b/embodichain/lab/sim/solvers/pink_solver.py @@ -17,7 +17,7 @@ import os import torch import numpy as np -from typing import List, Optional, Tuple, Union, TYPE_CHECKING +from typing import List, Tuple, Union, TYPE_CHECKING from embodichain.utils import logger from embodichain.lab.sim.utility.import_utils import ( @@ -60,17 +60,17 @@ class PinkSolverCfg(SolverCfg): ) # Path to the mesh files associated with the robot. These files are also loaded by Pinocchio's `robot_wrapper.BuildFromURDF`. - mesh_path: Optional[str] = None + mesh_path: str | None = None # A list of tasks for the Pink IK controller. These tasks are controllable by the env action. # These tasks can be used to control the pose of a frame or the angles of joints. # For more details, visit: https://github.com/stephane-caron/pink - variable_input_tasks: List["pink.tasks.FrameTask"] = None + variable_input_tasks: list["pink.tasks.FrameTask"] | None = None # A list of tasks for the Pink IK controller. These tasks are fixed and not controllable by the env action. # These tasks can be used to fix the pose of a frame or the angles of joints to a desired configuration. # For more details, visit: https://github.com/stephane-caron/pink - fixed_input_tasks: List["pink.tasks.FrameTask"] = None + fixed_input_tasks: list["pink.tasks.FrameTask"] | None = None # Show warning if IK solver fails to find a solution. show_ik_warnings: bool = True @@ -240,16 +240,16 @@ def update_null_space_joint_targets(self, current_qpos: np.ndarray): def get_ik( self, - target_xpos: Optional[Union[torch.Tensor, np.ndarray]], - qpos_seed: Optional[Union[torch.Tensor, np.ndarray]] = None, + target_xpos: torch.Tensor | np.ndarray | None, + qpos_seed: torch.Tensor | np.ndarray | None = None, return_all_solutions: bool = False, **kwargs, - ) -> Tuple[torch.Tensor, torch.Tensor]: + ) -> tuple[torch.Tensor, torch.Tensor]: """Compute target joint positions using inverse kinematics. Args: - target_pose (Optional[Union[torch.Tensor, np.ndarray]]): Target end-effector pose - qpos_seed (Optional[Union[torch.Tensor, np.ndarray]]): Seed joint positions + target_pose (torch.Tensor | np.ndarray | None): Target end-effector pose + qpos_seed (torch.Tensor | np.ndarray | None): Seed joint positions return_all_solutions (bool, optional): Whether to return all IK solutions or just the best one. Defaults to False. **kwargs: Additional keyword arguments for future extensions. @@ -360,13 +360,13 @@ def get_ik( def _get_fk( self, - qpos: Optional[Union[torch.Tensor, np.ndarray]], + qpos: torch.Tensor | np.ndarray | None, **kwargs, ) -> torch.tensor: """Compute the forward kinematics for the robot given joint positions. Args: - qpos (torch.Tensor or np.ndarray): Joint positions, shape should be (nq,). + qpos (torch.Tensor | np.ndarray | None): Joint positions, shape should be (nq,). **kwargs: Additional keyword arguments (not used). Returns: diff --git a/embodichain/lab/sim/solvers/pinocchio_solver.py b/embodichain/lab/sim/solvers/pinocchio_solver.py index 8c945635..0068a4a1 100644 --- a/embodichain/lab/sim/solvers/pinocchio_solver.py +++ b/embodichain/lab/sim/solvers/pinocchio_solver.py @@ -17,7 +17,7 @@ import os import torch import numpy as np -from typing import Optional, Union, Tuple, Any, List, TYPE_CHECKING +from typing import Union, Tuple, Any, List, TYPE_CHECKING from itertools import product from copy import deepcopy @@ -372,23 +372,23 @@ def qpos_to_limits( def get_ik( self, - target_xpos: Optional[Union[torch.Tensor, np.ndarray]], - qpos_seed: np.ndarray = None, - qvel_seed: np.ndarray = None, + target_xpos: torch.Tensor | np.ndarray | None, + qpos_seed: np.ndarray | None = None, + qvel_seed: np.ndarray | None = None, return_all_solutions: bool = False, **kwargs, - ) -> Tuple[bool, np.ndarray]: + ) -> tuple[bool, np.ndarray]: """Solve inverse kinematics (IK) for the robot to achieve the specified end-effector pose. Args: - target_xpos (torch.Tensor or np.ndarray): Desired end-effector pose as a (4, 4) homogeneous transformation matrix. - qpos_seed (np.ndarray, optional): Initial joint positions used as the seed for optimization. If None, uses zero configuration. - qvel_seed (np.ndarray, optional): Initial joint velocities (not used in current implementation). + target_xpos (torch.Tensor | np.ndarray | None): Desired end-effector pose as a (4, 4) homogeneous transformation matrix. + qpos_seed (np.ndarray | None): Initial joint positions used as the seed for optimization. If None, uses zero configuration. + qvel_seed (np.ndarray | None): Initial joint velocities (not used in current implementation). return_all_solutions (bool, optional): If True, return all valid IK solutions found; otherwise, return only the best solution. Default is False. **kwargs: Additional keyword arguments for future extensions. Returns: - Tuple[bool, np.ndarray]: + tuple[bool, np.ndarray]: - success (bool or torch.BoolTensor): True if a valid solution is found, False otherwise. - qpos (np.ndarray or torch.Tensor): Joint positions that achieve the target pose. If no solution, returns the seed joint positions. """ @@ -573,13 +573,13 @@ def get_ik( def _get_fk( self, - qpos: Optional[Union[torch.Tensor, np.ndarray]], + qpos: torch.Tensor | np.ndarray | None, **kwargs, ) -> np.ndarray: """Compute the forward kinematics for the robot given joint positions. Args: - qpos (torch.Tensor or np.ndarray): Joint positions, shape should be (nq,). + qpos (torch.Tensor | np.ndarray | None): Joint positions, shape should be (nq,). **kwargs: Additional keyword arguments (not used). Returns: diff --git a/embodichain/lab/sim/solvers/pytorch_solver.py b/embodichain/lab/sim/solvers/pytorch_solver.py index d8da6952..ed3ee655 100644 --- a/embodichain/lab/sim/solvers/pytorch_solver.py +++ b/embodichain/lab/sim/solvers/pytorch_solver.py @@ -16,7 +16,7 @@ import torch -from typing import Optional, Union, Tuple, List, TYPE_CHECKING +from typing import Union, Tuple, List, TYPE_CHECKING from dataclasses import MISSING from copy import deepcopy @@ -68,7 +68,7 @@ class PytorchSolverCfg(SolverCfg): A higher number of samples increases the chances of finding a valid solution """ - ik_nearest_weight: Optional[List[float]] = None + ik_nearest_weight: list[float] | None = None """Weights for the inverse kinematics nearest calculation. The weights influence how the solver prioritizes closeness to the seed position @@ -389,11 +389,11 @@ def _qpos_to_limits( def get_ik( self, target_xpos: torch.Tensor, - qpos_seed: torch.Tensor = None, - num_samples: int = None, + qpos_seed: torch.Tensor | None = None, + num_samples: int | None = None, return_all_solutions: bool = False, **kwargs, - ) -> Tuple[torch.Tensor, torch.Tensor]: + ) -> tuple[torch.Tensor, torch.Tensor]: r"""Computes the inverse kinematics for given target poses. This function generates random joint configurations within the specified limits, @@ -403,18 +403,18 @@ def get_ik( Args: target_xpos (torch.Tensor): A tensor representing the target positions. It can be of shape (batch_size, 3) for multiple positions or (3,) for a single position. - qpos_seed (torch.Tensor, optional): Initial joint positions used as seed for IK solving. - Can be: - - 1D tensor of shape (dof,): Single seed for all target positions - - 2D tensor of shape (batch_size, dof): Individual seed per position - If None, defaults to zero configuration. Defaults to None. - num_samples (int, optional): The number of random samples to generate. Must be positive. - Defaults to None. + qpos_seed (torch.Tensor | None): Initial joint positions used as seed for IK solving. + Can be: + - 1D tensor of shape (dof,): Single seed for all target positions + - 2D tensor of shape (batch_size, dof): Individual seed per position + If None, defaults to zero configuration. Defaults to None. + num_samples (int | None): The number of random samples to generate. Must be positive. + Defaults to None. return_all_solutions (bool, optional): If True, returns all valid solutions found. **kwargs: Additional arguments for future extensions. Returns: - Tuple[List[bool], torch.Tensor]: A tuple containing: + tuple[list[bool], torch.Tensor]: A tuple containing: - A tensor of booleans indicating whether valid solutions were found for each target pose. (Shape: (batch_size,)) - A tensor of shape (batch_size, 1, dof) containing joint positions for each target pose, or an empty tensor if no valid solutions were found. diff --git a/embodichain/lab/sim/solvers/srs_solver.py b/embodichain/lab/sim/solvers/srs_solver.py index aadab28b..8558ea22 100644 --- a/embodichain/lab/sim/solvers/srs_solver.py +++ b/embodichain/lab/sim/solvers/srs_solver.py @@ -18,7 +18,7 @@ import numpy as np import warp as wp from itertools import product -from typing import Optional, Union, Tuple, Any, Literal, TYPE_CHECKING +from typing import Union, Tuple, Any, Literal, TYPE_CHECKING from embodichain.utils import configclass, logger from embodichain.lab.sim.solvers import SolverCfg, BaseSolver @@ -286,7 +286,7 @@ def _skew(self, vector: np.ndarray) -> np.ndarray: def _compute_reference_plane( self, target_pose: np.ndarray, elbow_config: int - ) -> Tuple[Optional[np.ndarray], Optional[np.ndarray], Optional[np.ndarray]]: + ) -> tuple[np.ndarray | None, np.ndarray | None, np.ndarray | None]: """ Calculate the reference plane vector, rotation matrix, and joint values. @@ -411,7 +411,7 @@ def _process_single_solution( def _get_each_ik( self, target_pose: np.ndarray, nsparam: float, config: np.ndarray - ) -> Tuple[bool, Optional[np.ndarray]]: + ) -> tuple[bool, np.ndarray | None]: """ Computes the inverse kinematics for a given target pose, normalization parameter, and configuration. diff --git a/embodichain/lab/sim/utility/mesh_utils.py b/embodichain/lab/sim/utility/mesh_utils.py index 2fba7e9b..204c125e 100644 --- a/embodichain/lab/sim/utility/mesh_utils.py +++ b/embodichain/lab/sim/utility/mesh_utils.py @@ -21,7 +21,7 @@ import trimesh import dexsim -from typing import Tuple, List, Dict, Any, Optional, Union +from typing import Tuple, List, Dict, Any, Union from embodichain.utils import logger @@ -29,9 +29,9 @@ def export_articulation_mesh( articulation: Union[dexsim.engine.Articulation, list], output_path: str = "./articulation.obj", - link_names: Optional[Union[List[str], Dict[Any, List[str]]]] = None, - base_xpos: Optional[np.ndarray] = None, - base_link_name: Optional[str] = None, + link_names: Union[List[str], Dict[Any, List[str]]] | None = None, + base_xpos: np.ndarray | None = None, + base_link_name: str | None = None, **kwargs: Any, ) -> o3d.geometry.TriangleMesh: r"""Export a combined mesh from all links of one or more articulations to a mesh file format. @@ -45,11 +45,11 @@ def export_articulation_mesh( articulation (dexsim.engine.Articulation or list): The articulation object or list of articulations. output_path (str): The output file path including the file name and extension. Supported extensions: .obj, .ply, .stl, .glb, .gltf. - link_names (list[str] or dict[Any, list[str]], optional): + link_names (list[str] or dict[Any, list[str]] | None): Specify which links to export. If None, export all links. - base_xpos (np.ndarray, optional): 4x4 homogeneous transformation matrix. + base_xpos (np.ndarray | None): 4x4 homogeneous transformation matrix. All meshes will be transformed into this base pose coordinate system. - base_link_name (str, optional): If specified, use the pose of this link as the base pose. + base_link_name (str | None): If specified, use the pose of this link as the base pose. The link will be searched from all link_names of all articulations. Returns: diff --git a/embodichain/lab/sim/utility/sim_utils.py b/embodichain/lab/sim/utility/sim_utils.py index de98ce22..6bf1d5fc 100644 --- a/embodichain/lab/sim/utility/sim_utils.py +++ b/embodichain/lab/sim/utility/sim_utils.py @@ -18,7 +18,7 @@ import dexsim import open3d as o3d -from typing import List, Union, Optional +from typing import List, Union from dexsim.types import DriveType, ArticulationFlag, LoadOption, RigidBodyShape from dexsim.engine import Articulation @@ -186,7 +186,7 @@ def create_sphere( def load_mesh_objects_from_cfg( - cfg: RigidObjectCfg, env_list: List[Arena], cache_dir: Optional[str] = None + cfg: RigidObjectCfg, env_list: List[Arena], cache_dir: str | None = None ) -> List[MeshObject]: """Load mesh objects from configuration. @@ -194,7 +194,7 @@ def load_mesh_objects_from_cfg( cfg (RigidObjectCfg): Configuration for the rigid object. env_list (List[Arena]): List of arenas to load the objects into. - cache_dir (Optional[str], optional): Directory for caching convex decomposition files. Defaults to None + cache_dir (str | None, optional): Directory for caching convex decomposition files. Defaults to None Returns: List[MeshObject]: List of loaded mesh objects. """ diff --git a/embodichain/lab/sim/utility/solver_utils.py b/embodichain/lab/sim/utility/solver_utils.py index d510cc2d..00cc84ea 100644 --- a/embodichain/lab/sim/utility/solver_utils.py +++ b/embodichain/lab/sim/utility/solver_utils.py @@ -18,7 +18,7 @@ import numpy as np from embodichain.lab.sim.utility.io_utils import suppress_stdout_stderr -from typing import Optional, Union, Tuple, Any, List, TYPE_CHECKING +from typing import Union, Tuple, Optional, Any, List, TYPE_CHECKING from copy import deepcopy from embodichain.utils import configclass, logger @@ -42,7 +42,7 @@ def create_pk_chain( Args: urdf_path (str): Path to the URDF file. end_link_name (str): Name of the end-effector link. - root_link_name (Optional[str]): Name of the root link. If None, the chain starts from the base. + root_link_name (str | None): Name of the root link. If None, the chain starts from the base. device (torch.device): The device to which the chain will be moved. is_serial (bool): Whether the chain is serial or not. @@ -61,7 +61,7 @@ def create_pk_serial_chain( urdf_path: str = None, device: torch.device = None, end_link_name: str = None, - root_link_name: Optional[Union[str, None]] = None, + root_link_name: str | None = None, chain: Optional["pk.SerialChain"] = None, **kwargs, ) -> "pk.SerialChain": @@ -71,7 +71,7 @@ def create_pk_serial_chain( Args: urdf_path (str): Path to the URDF file. end_link_name (str): Name of the end-effector link. - root_link_name (Optional[str]): Name of the root link. If None, the chain starts from the base. + root_link_name (str | None): Name of the root link. If None, the chain starts from the base. device (torch.device): The device to which the chain will be moved. is_serial (bool): Whether the chain is serial or not. diff --git a/embodichain/lab/sim/utility/tensor.py b/embodichain/lab/sim/utility/tensor.py index 3b8553cf..cb2e2a8c 100644 --- a/embodichain/lab/sim/utility/tensor.py +++ b/embodichain/lab/sim/utility/tensor.py @@ -17,13 +17,13 @@ import torch import numpy as np -from typing import Union, Optional +from typing import Union def to_tensor( arr: Union[torch.Tensor, np.ndarray, list], dtype: torch.dtype = torch.float32, - device: Optional[torch.device] = None, + device: torch.device | None = None, ) -> torch.Tensor: """Convert input to torch.Tensor with specified dtype and device. diff --git a/embodichain/toolkits/urdf_assembly/component.py b/embodichain/toolkits/urdf_assembly/component.py index 9b98f67b..56ec16e7 100644 --- a/embodichain/toolkits/urdf_assembly/component.py +++ b/embodichain/toolkits/urdf_assembly/component.py @@ -19,7 +19,7 @@ from pathlib import Path from dataclasses import dataclass import xml.etree.ElementTree as ET -from typing import Dict, Optional +from typing import Dict from embodichain.toolkits.urdf_assembly.logging_utils import ( URDFAssemblyLogger, @@ -64,7 +64,7 @@ class URDFComponent: "base_link" # Default link name for attachment (usually the first link) ) params: Dict = None # Component-specific parameters (e.g., wheel_type for chassis) - transform: Optional[np.ndarray] = ( + transform: np.ndarray | None = ( None # Optional 4x4 transformation matrix for positioning ) diff --git a/embodichain/toolkits/urdf_assembly/logging_utils.py b/embodichain/toolkits/urdf_assembly/logging_utils.py index 63c17d0c..4c95b483 100644 --- a/embodichain/toolkits/urdf_assembly/logging_utils.py +++ b/embodichain/toolkits/urdf_assembly/logging_utils.py @@ -15,7 +15,6 @@ # ---------------------------------------------------------------------------- import logging -from typing import Optional __all__ = ["URDFAssemblyLogger"] @@ -70,7 +69,7 @@ class URDFAssemblyLogger: _initialized = False @classmethod - def get_logger(cls, name: Optional[str] = None) -> logging.Logger: + def get_logger(cls, name: str | None = None) -> logging.Logger: r"""Get or create a URDF assembly-specific logger Args: diff --git a/embodichain/toolkits/urdf_assembly/sensor.py b/embodichain/toolkits/urdf_assembly/sensor.py index 5bf30710..87fcd5e9 100644 --- a/embodichain/toolkits/urdf_assembly/sensor.py +++ b/embodichain/toolkits/urdf_assembly/sensor.py @@ -22,7 +22,7 @@ import xml.etree.ElementTree as ET from scipy.spatial.transform import Rotation as R -from typing import Dict, List, Optional, Union, Tuple +from typing import Dict, List, Union, Tuple from embodichain.toolkits.urdf_assembly.logging_utils import ( URDFAssemblyLogger, @@ -64,10 +64,10 @@ class SensorAttachment: sensor_urdf: str # Path to the sensor's URDF file parent_component: str # Name of the component to which the sensor is attached parent_link: str # Specific link name within the parent component for attachment - transform: Optional[np.ndarray] = ( - None # Optional 4x4 transformation matrix for sensor positioning + transform: np.ndarray | None = ( + None # 4x4 transformation matrix for sensor positioning, or None ) - sensor_type: Optional[str] = None # Optional sensor type field + sensor_type: str | None = None # Sensor type field, or None class URDFSensorManager: @@ -91,10 +91,10 @@ def attach_sensor( ], parent_component: str, parent_link: str, - transform: Optional[np.ndarray] = None, - sensor_type: Optional[str] = None, - extract_links: Optional[List[str]] = None, - extract_joints: Optional[List[str]] = None, + transform: np.ndarray | None = None, + sensor_type: str | None = None, + extract_links: list[str] | None = None, + extract_joints: list[str] | None = None, ) -> bool: r"""Attach a sensor to a specific component and link with multiple input format support. @@ -179,7 +179,7 @@ def _validate_sensor_params( sensor_source, parent_component: str, parent_link: str, - transform: Optional[np.ndarray], + transform: np.ndarray | None, ) -> bool: r"""Validate input parameters for sensor attachment. @@ -241,10 +241,10 @@ def _validate_sensor_params( def _process_sensor_source( self, sensor_source, - extract_links: Optional[List[str]], - extract_joints: Optional[List[str]], + extract_links: list[str] | None, + extract_joints: list[str] | None, sensor_name: str, - ) -> Optional[Tuple[List[ET.Element], List[ET.Element], str]]: + ) -> tuple[list[ET.Element], list[ET.Element], str] | None: r"""Process sensor source based on input type and extract relevant elements. Args: @@ -290,9 +290,9 @@ def _process_sensor_source( def _process_urdf_file_source( self, file_path: str, - extract_links: Optional[List[str]], - extract_joints: Optional[List[str]], - ) -> Optional[Tuple[List[ET.Element], List[ET.Element], str]]: + extract_links: list[str] | None, + extract_joints: list[str] | None, + ) -> tuple[list[ET.Element], list[ET.Element], str] | None: r"""Process URDF file source and extract specified elements. Args: @@ -321,10 +321,10 @@ def _process_urdf_file_source( def _process_urdf_element_source( self, urdf_element: ET.Element, - extract_links: Optional[List[str]], - extract_joints: Optional[List[str]], + extract_links: list[str] | None, + extract_joints: list[str] | None, sensor_name: str, - ) -> Tuple[List[ET.Element], List[ET.Element], str]: + ) -> tuple[list[ET.Element], list[ET.Element], str]: r"""Process pre-loaded URDF element source. Args: @@ -344,7 +344,7 @@ def _process_urdf_element_source( def _process_config_dict_source( self, config: Dict, sensor_name: str - ) -> Tuple[List[ET.Element], List[ET.Element], str]: + ) -> tuple[list[ET.Element], list[ET.Element], str]: r"""Process configuration dictionary source and create URDF elements. Args: @@ -361,8 +361,8 @@ def _process_config_dict_source( return links, joints, generated_path def _process_element_tuple_source( - self, element_tuple: Tuple, sensor_name: str - ) -> Optional[Tuple[List[ET.Element], List[ET.Element], str]]: + self, element_tuple: tuple, sensor_name: str + ) -> tuple[list[ET.Element], list[ET.Element], str] | None: r"""Process direct element tuple source. Args: @@ -397,9 +397,9 @@ def _process_element_tuple_source( def _extract_elements_from_urdf( self, urdf_element: ET.Element, - extract_links: Optional[List[str]] = None, - extract_joints: Optional[List[str]] = None, - ) -> Tuple[List[ET.Element], List[ET.Element]]: + extract_links: list[str] | None = None, + extract_joints: list[str] | None = None, + ) -> tuple[list[ET.Element], list[ET.Element]]: r"""Extract specified links and joints from URDF element. Args: @@ -443,7 +443,7 @@ def _extract_elements_from_urdf( return links, joints def _validate_sensor_elements( - self, sensor_links: List[ET.Element], sensor_joints: List[ET.Element] + self, sensor_links: list[ET.Element], sensor_joints: list[ET.Element] ) -> bool: r"""Validate extracted sensor elements for completeness and consistency. @@ -526,10 +526,10 @@ def _is_valid_homogeneous_transform(self, transform: np.ndarray) -> bool: def _process_and_rename_sensor_elements( self, - sensor_links: List[ET.Element], - sensor_joints: List[ET.Element], + sensor_links: list[ET.Element], + sensor_joints: list[ET.Element], sensor_name: str, - ) -> Optional[Tuple[List[ET.Element], List[ET.Element]]]: + ) -> tuple[list[ET.Element], list[ET.Element]] | None: r"""Process and rename sensor link and joint elements to avoid name conflicts. Args: diff --git a/embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py b/embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py index 81b356c3..3dd4303c 100644 --- a/embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py +++ b/embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py @@ -23,7 +23,7 @@ import xml.etree.ElementTree as ET from scipy.spatial.transform import Rotation as R -from typing import Dict, List, Optional, Union, Tuple +from typing import Union, Tuple from embodichain.toolkits.urdf_assembly.logging_utils import ( setup_urdf_logging, @@ -209,7 +209,7 @@ def add_component( self, component_type: str, urdf_path: Union[str, Path], - transform: Optional[np.ndarray] = None, + transform: np.ndarray | None = None, **params, ) -> bool: r"""Add a URDF component to the component registry. @@ -249,7 +249,7 @@ def attach_sensor( sensor_source, parent_component: str, parent_link: str, - transform: Optional[np.ndarray] = None, + transform: np.ndarray | None = None, **kwargs, ) -> bool: r"""Attach a sensor to a specific component and link, and register it in the sensor registry. @@ -308,7 +308,7 @@ def get_attached_sensors(self): """ return self.sensor_registry.all() - def _load_urdf(self, urdf_path: str) -> Optional[ET.Element]: + def _load_urdf(self, urdf_path: str) -> ET.Element | None: r"""Load a URDF file and return its root element. Args: diff --git a/embodichain/utils/cfg.py b/embodichain/utils/cfg.py index 47faa48b..c33a4fa9 100644 --- a/embodichain/utils/cfg.py +++ b/embodichain/utils/cfg.py @@ -22,7 +22,7 @@ from copy import deepcopy from pathlib import Path -from typing import Dict, List, Optional, Union +from typing import Dict, List, Union from fvcore.common.config import BASE_KEY from fvcore.common.config import CfgNode as _CfgNode @@ -38,17 +38,17 @@ def _flatten_dict( src: Dict, - prefix: Optional[str] = prefix, - sep: Optional[str] = sep, - dct: Optional[Dict] = {}, + prefix: str | None = prefix, + sep: str | None = sep, + dct: Dict | None = {}, ) -> Dict: """Traverse a dictionary and return all keys including nested ones. Args: src (Dict): an instance of :class:`Dict`. - prefix (Optional[str], optional): [description]. Defaults to prefix. - sep (Optional[str], optional): [description]. Defaults to sep. - dct (Optional[Dict], optional): [description]. Defaults to {}. + prefix (str | None, optional): [description]. Defaults to prefix. + sep (str | None, optional): [description]. Defaults to sep. + dct (Dict | None, optional): [description]. Defaults to {}. Returns: Dict: flatten dictionary with all keys. @@ -151,9 +151,9 @@ def _open_cfg(cls, filename): @classmethod def load_cfg_from_file( cls, - filename_or_str_content: Union[str, Path], + filename_or_str_content: str | Path, new_allowed: bool = True, - root_path: str = None, + root_path: str | None = None, ) -> CfgNode: """load configration from a yaml file. Modified from function load_yaml_with_base() of fvcore.common.config.CfgNode. @@ -289,11 +289,11 @@ def save(self, filepath): def depth(self): return _dict_depth(self) - def unvisited_keys(self, inverse: Optional[bool] = False) -> List[str]: + def unvisited_keys(self, inverse: bool | None = False) -> List[str]: """Return all unvisited keys. Args: - inverse (Optional[bool], optional): return all visited keys if `inverse` is True. Defaults to False. + inverse (bool | None, optional): return all visited keys if `inverse` is True. Defaults to False. Returns: List[str]: list of all unvisited/visited keys. diff --git a/embodichain/utils/configclass.py b/embodichain/utils/configclass.py index 61727d60..16c9a943 100644 --- a/embodichain/utils/configclass.py +++ b/embodichain/utils/configclass.py @@ -17,7 +17,7 @@ from collections.abc import Callable, Mapping, Iterable, Sized from copy import deepcopy from dataclasses import MISSING, Field, dataclass, field, replace -from typing import Any, ClassVar, Optional +from typing import Any, ClassVar from .string import callable_to_string, string_to_callable @@ -545,7 +545,7 @@ class State: setattr(cls, key, value) -def _skippable_class_member(key: str, value: Any, hints: Optional[dict] = None) -> bool: +def _skippable_class_member(key: str, value: Any, hints: dict | None = None) -> bool: """Check if the class member should be skipped in configclass processing. The following members are skipped: diff --git a/embodichain/utils/file.py b/embodichain/utils/file.py index cd089491..2a894137 100644 --- a/embodichain/utils/file.py +++ b/embodichain/utils/file.py @@ -17,20 +17,20 @@ import os import re -from typing import Optional, List +from typing import List def get_all_files_in_directory( directory: str, - exts: Optional[List[str]] = None, - patterns: Optional[List[str]] = None, + exts: List[str] | None = None, + patterns: List[str] | None = None, ) -> List[str]: """Get all files in a directory with optional filtering by extensions or regex patterns. Args: directory (str): The directory to search for files. - exts (Optional[List[str]]): List of file extensions to filter by. If None, all files are returned. - patterns (Optional[List[str]]): List of regex patterns to match file names. If None, no pattern matching is applied. + exts (List[str] | None): List of file extensions to filter by. If None, all files are returned. + patterns (List[str] | None): List of regex patterns to match file names. If None, no pattern matching is applied. Returns: List[str]: List of file paths in the directory matching the specified extensions or patterns. diff --git a/embodichain/utils/math.py b/embodichain/utils/math.py index d35e3656..238767a8 100644 --- a/embodichain/utils/math.py +++ b/embodichain/utils/math.py @@ -22,7 +22,7 @@ import torch import numpy as np import torch.nn.functional -from typing import Literal, Optional, Union +from typing import Literal, Union def look_at_to_pose( @@ -914,8 +914,8 @@ def is_identity_pose(pos: torch.tensor, rot: torch.tensor) -> bool: def combine_frame_transforms( t01: torch.Tensor, q01: torch.Tensor, - t12: Optional[torch.Tensor] = None, - q12: Optional[torch.Tensor] = None, + t12: torch.Tensor | None = None, + q12: torch.Tensor | None = None, ) -> tuple[torch.Tensor, torch.Tensor]: r"""Combine transformations between two reference frames into a stationary frame. diff --git a/embodichain/utils/module_utils.py b/embodichain/utils/module_utils.py index a62eb41c..b0868056 100644 --- a/embodichain/utils/module_utils.py +++ b/embodichain/utils/module_utils.py @@ -15,12 +15,12 @@ # ---------------------------------------------------------------------------- import importlib -from typing import List, Union, Optional, Callable, Any +from typing import List, Union, Callable, Any def find_function_from_modules( function_name: str, modules: List[Union[str, Any]], raise_if_not_found: bool = True -) -> Optional[Callable]: +) -> Callable | None: """ Find a function from multiple Python modules. @@ -30,7 +30,7 @@ def find_function_from_modules( raise_if_not_found (bool): Whether to raise an exception if function is not found Returns: - Optional[Callable]: The function if found, None otherwise + Callable | None: The function if found, None otherwise Raises: AttributeError: If function is not found and raise_if_not_found is True @@ -62,7 +62,7 @@ def find_function_from_modules( def find_class_from_modules( class_name: str, modules: List[Union[str, Any]], raise_if_not_found: bool = True -) -> Optional[type]: +) -> type | None: """ Find a class from multiple Python modules. @@ -72,7 +72,7 @@ def find_class_from_modules( raise_if_not_found (bool): Whether to raise an exception if class is not found Returns: - Optional[type]: The class if found, None otherwise + type | None: The class if found, None otherwise Raises: AttributeError: If class is not found and raise_if_not_found is True diff --git a/embodichain/utils/utility.py b/embodichain/utils/utility.py index c7015476..bcfb3afd 100644 --- a/embodichain/utils/utility.py +++ b/embodichain/utils/utility.py @@ -27,7 +27,7 @@ from tqdm import tqdm from PIL import Image from functools import wraps -from typing import Dict, List, Tuple, Optional, Callable, Any +from typing import Dict, List, Tuple, Callable, Any from embodichain.utils.string import callable_to_string @@ -263,13 +263,13 @@ def reset_all_seeds(seed: int = 0): def do_process_decorator( - pre_process: Optional[bool] = True, post_process: Optional[bool] = True + pre_process: bool | None = True, post_process: bool | None = True ): """A decorator to decorate :meth:`inference`. Usage and example is comming soon. Args: - pre_process (Optional[bool], optional): whether do pre-process. Defaults to True. - post_process (Optional[bool], optional): whether do post-process. Defaults to True. + pre_process (bool | None, optional): whether do pre-process. Defaults to True. + post_process (bool | None, optional): whether do post-process. Defaults to True. """ def inner_decorator(func: Callable): diff --git a/pyproject.toml b/pyproject.toml index ff55dae3..85506d9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ dependencies = [ "ortools", "prettytable", "black==24.3.0", + "fvcore", "h5py", ] From 3afdfa785de389bd006570bcc86109fb7386d92b Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Mon, 15 Dec 2025 16:54:05 +0000 Subject: [PATCH 26/92] Update simulation manager resources init (#37) --- embodichain/lab/sim/sim_manager.py | 91 +++++++++++++++--------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/embodichain/lab/sim/sim_manager.py b/embodichain/lab/sim/sim_manager.py index b0f4ceb5..86579eed 100644 --- a/embodichain/lab/sim/sim_manager.py +++ b/embodichain/lab/sim/sim_manager.py @@ -201,8 +201,6 @@ def __init__( self._env = self._world.get_env() - self._default_resources = SimResources() - # set unique material path to accelerate material creation. # TODO: This will be removed. if self.sim_config.enable_rt is False: @@ -235,8 +233,7 @@ def __init__( # The structure is keys to the loaded texture data. The keys represent the texture group. self._texture_cache: Dict[str, Union[torch.Tensor, List[torch.Tensor]]] = dict() - # TODO: maybe need to add some interface to interact with background and layouts. - # background and layouts are 3d assets that can has only render body for visualization. + self._init_sim_resources() self._create_default_plane() self.set_default_background() @@ -244,6 +241,48 @@ def __init__( # Set physics to manual update mode by default. self.set_manual_update(True) + @property + def num_envs(self) -> int: + """Get the number of arenas in the simulation. + + Returns: + int: number of arenas. + """ + return len(self._arenas) if len(self._arenas) > 0 else 1 + + @cached_property + def is_use_gpu_physics(self) -> bool: + """Check if the physics simulation is using GPU.""" + world_config = dexsim.get_world_config() + return self.device.type == "cuda" and world_config.enable_gpu_sim + + @property + def is_rt_enabled(self) -> bool: + """Check if Ray Tracing rendering backend is enabled.""" + return self.sim_config.enable_rt + + @property + def is_physics_manually_update(self) -> bool: + return self._world.is_physics_manually_update() + + @property + def asset_uids(self) -> List[str]: + """Get all assets uid in the simulation. + + The assets include lights, sensors, robots, rigid objects and articulations. + + Returns: + List[str]: list of all assets uid. + """ + uid_list = ["default_plane"] + uid_list.extend(list(self._lights.keys())) + uid_list.extend(list(self._sensors.keys())) + uid_list.extend(list(self._robots.keys())) + uid_list.extend(list(self._rigid_objects.keys())) + uid_list.extend(list(self._rigid_object_groups.keys())) + uid_list.extend(list(self._articulations.keys())) + return uid_list + def _convert_sim_config( self, sim_config: SimulationManagerCfg ) -> dexsim.WorldConfig: @@ -295,47 +334,9 @@ def get_default_resources(self) -> SimResources: """ return self._default_resources - @property - def num_envs(self) -> int: - """Get the number of arenas in the simulation. - - Returns: - int: number of arenas. - """ - return len(self._arenas) if len(self._arenas) > 0 else 1 - - @cached_property - def is_use_gpu_physics(self) -> bool: - """Check if the physics simulation is using GPU.""" - world_config = dexsim.get_world_config() - return self.device.type == "cuda" and world_config.enable_gpu_sim - - @property - def is_rt_enabled(self) -> bool: - """Check if Ray Tracing rendering backend is enabled.""" - return self.sim_config.enable_rt - - @property - def is_physics_manually_update(self) -> bool: - return self._world.is_physics_manually_update() - - @property - def asset_uids(self) -> List[str]: - """Get all assets uid in the simulation. - - The assets include lights, sensors, robots, rigid objects and articulations. - - Returns: - List[str]: list of all assets uid. - """ - uid_list = ["default_plane"] - uid_list.extend(list(self._lights.keys())) - uid_list.extend(list(self._sensors.keys())) - uid_list.extend(list(self._robots.keys())) - uid_list.extend(list(self._rigid_objects.keys())) - uid_list.extend(list(self._rigid_object_groups.keys())) - uid_list.extend(list(self._articulations.keys())) - return uid_list + def _init_sim_resources(self) -> None: + """Initialize the default simulation resources.""" + self._default_resources = SimResources() def enable_physics(self, enable: bool) -> None: """Enable or disable physics simulation. From c07e4be6a031c65c74a40f4cef426cb1447c277a Mon Sep 17 00:00:00 2001 From: Chen Jian Date: Tue, 16 Dec 2025 13:47:48 +0800 Subject: [PATCH 27/92] support collision body visualization for rigid object and articulation (#27) Co-authored-by: chenjian Co-authored-by: Yueci Deng --- embodichain/lab/sim/objects/articulation.py | 46 ++++++++ embodichain/lab/sim/objects/gizmo.py | 2 +- embodichain/lab/sim/objects/rigid_object.py | 107 +++++++++++++----- .../lab/sim/objects/rigid_object_group.py | 51 +++++++++ embodichain/lab/sim/objects/robot.py | 59 ++++++++++ embodichain/lab/sim/sim_manager.py | 2 +- scripts/tutorials/sim/create_robot.py | 2 +- scripts/tutorials/sim/create_scene.py | 3 +- tests/sim/objects/test_articulation.py | 9 ++ tests/sim/objects/test_rigid_object.py | 13 +++ tests/sim/objects/test_rigid_object_group.py | 8 ++ tests/sim/objects/test_robot.py | 15 +++ 12 files changed, 283 insertions(+), 34 deletions(-) diff --git a/embodichain/lab/sim/objects/articulation.py b/embodichain/lab/sim/objects/articulation.py index b20650ac..f1325a6c 100644 --- a/embodichain/lab/sim/objects/articulation.py +++ b/embodichain/lab/sim/objects/articulation.py @@ -579,6 +579,11 @@ def __init__( # set default collision filter self._set_default_collision_filter() + # flag for collision visible node existence + self._has_collision_visible_node_dict = dict() + for link_name in self.link_names: + self._has_collision_visible_node_dict[link_name] = False + def __str__(self) -> str: parent_str = super().__str__() return parent_str + f" | dof: {self.dof} | num_links: {self.num_links}" @@ -1535,6 +1540,47 @@ def get_visual_material_inst( result.append(mat_dict) return result + def set_physical_visible( + self, + visible: bool = True, + link_names: List[str] | None = None, + rgba: Sequence[float] | None = None, + ): + """set collision + + Args: + visible (bool, optional): is collision body visible. Defaults to True. + link_names (List[str] | None, optional): links to set visibility. Defaults to None. + rgba (Sequence[float] | None, optional): collision body visible rgba. It will be defined at the first time the function is called. Defaults to None. + """ + rgba = rgba if rgba is not None else (0.8, 0.2, 0.2, 0.7) + if len(rgba) != 4: + logger.log_error(f"Invalid rgba {rgba}, should be a sequence of 4 floats.") + rgba = np.array( + [ + rgba[0], + rgba[1], + rgba[2], + rgba[3], + ] + ) + link_names = self.link_names if link_names is None else link_names + + # create collision visible node if not exist + if visible: + for i, env_idx in enumerate(self._all_indices): + for link_name in link_names: + if self._has_collision_visible_node_dict[link_name] is False: + self._entities[env_idx].create_physical_visible_node( + rgba, link_name + ) + self._has_collision_visible_node_dict[link_name] = True + + # set visibility + for i, env_idx in enumerate(self._all_indices): + for link_name in link_names: + self._entities[env_idx].set_physical_visible(visible, link_name) + def destroy(self) -> None: env = self._world.get_env() arenas = env.get_all_arenas() diff --git a/embodichain/lab/sim/objects/gizmo.py b/embodichain/lab/sim/objects/gizmo.py index 28053a7f..b3f8dc37 100644 --- a/embodichain/lab/sim/objects/gizmo.py +++ b/embodichain/lab/sim/objects/gizmo.py @@ -424,7 +424,7 @@ def toggle_visibility(self) -> bool: return self._is_visible - def set_visibility(self, visible: bool): + def set_visible(self, visible: bool): """ Set the visibility of the gizmo. diff --git a/embodichain/lab/sim/objects/rigid_object.py b/embodichain/lab/sim/objects/rigid_object.py index 047df410..f6fc48c2 100644 --- a/embodichain/lab/sim/objects/rigid_object.py +++ b/embodichain/lab/sim/objects/rigid_object.py @@ -19,7 +19,7 @@ import numpy as np from dataclasses import dataclass -from typing import List, Sequence, Optional, Union +from typing import List, Sequence, Union from dexsim.models import MeshObject from dexsim.types import RigidBodyGPUAPIReadType, RigidBodyGPUAPIWriteType @@ -177,7 +177,7 @@ def __init__( ) # data for managing body data (only for dynamic and kinematic bodies) on GPU. - self._data: Optional[RigidBodyData] = None + self._data: RigidBodyData | None = None if self.is_static is False: self._data = RigidBodyData(entities=entities, ps=self._ps, device=device) @@ -196,6 +196,9 @@ def __init__( # set default collision filter self._set_default_collision_filter() + # reserve flag for collision visible node existence + self._has_collision_visible_node = False + def __str__(self) -> str: parent_str = super().__str__() return ( @@ -204,7 +207,7 @@ def __str__(self) -> str: ) @property - def body_data(self) -> Optional[RigidBodyData]: + def body_data(self) -> RigidBodyData | None: """Get the rigid body data manager for this rigid object. Returns: @@ -266,7 +269,7 @@ def _set_default_collision_filter(self) -> None: self.set_collision_filter(collision_filter_data) def set_collision_filter( - self, filter_data: torch.Tensor, env_ids: Optional[Sequence[int]] = None + self, filter_data: torch.Tensor, env_ids: Sequence[int] | None = None ) -> None: """set collision filter data for the rigid object. @@ -276,7 +279,7 @@ def set_collision_filter( If 2nd element is 0, the object will collision with all other objects in world. 3rd and 4th elements are not used currently. - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. Defaults to None. + env_ids (Sequence[int] | None, optional): Environment indices. If None, then all indices are used. Defaults to None. """ local_env_ids = self._all_indices if env_ids is None else env_ids @@ -292,13 +295,13 @@ def set_collision_filter( ) def set_local_pose( - self, pose: torch.Tensor, env_ids: Optional[Sequence[int]] = None + self, pose: torch.Tensor, env_ids: Sequence[int] | None = None ) -> None: """Set local pose of the rigid object. Args: pose (torch.Tensor): The local pose of the rigid object with shape (N, 7) or (N, 4, 4). - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + env_ids (Sequence[int] | None, optional): Environment indices. If None, then all indices are used. """ local_env_ids = self._all_indices if env_ids is None else env_ids @@ -395,10 +398,10 @@ def get_local_pose_cpu( def add_force_torque( self, - force: Optional[torch.Tensor] = None, - torque: Optional[torch.Tensor] = None, - pos: Optional[torch.Tensor] = None, - env_ids: Optional[Sequence[int]] = None, + force: torch.Tensor | None = None, + torque: torch.Tensor | None = None, + pos: torch.Tensor | None = None, + env_ids: Sequence[int] | None = None, ) -> None: """Add force and/or torque to the rigid object. @@ -409,10 +412,10 @@ def add_force_torque( - if not `pos` is specified, the force and torque are applied at the center of mass of the rigid body. Args: - force (Optional[torch.Tensor] = None): The force to add with shape (N, 3). Defaults to None. - torque (Optional[torch.Tensor], optional): The torque to add with shape (N, 3). Defaults to None. - pos (Optional[torch.Tensor], optional): The position to apply the force at with shape (N, 3). Defaults to None. - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + force (torch.Tensor | None = None): The force to add with shape (N, 3). Defaults to None. + torque (torch.Tensor | None, optional): The torque to add with shape (N, 3). Defaults to None. + pos (torch.Tensor | None, optional): The position to apply the force at with shape (N, 3). Defaults to None. + env_ids (Sequence[int] | None, optional): Environment indices. If None, then all indices are used. """ if force is None and torque is None: logger.log_warning( @@ -463,13 +466,13 @@ def add_force_torque( def set_attrs( self, attrs: Union[RigidBodyAttributesCfg, List[RigidBodyAttributesCfg]], - env_ids: Optional[Sequence[int]] = None, + env_ids: Sequence[int] | None = None, ) -> None: """Set physical attributes for the rigid object. Args: attrs (Union[RigidBodyAttributesCfg, List[RigidBodyAttributesCfg]]): The physical attributes to set. - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + env_ids (Sequence[int] | None, optional): Environment indices. If None, then all indices are used. """ local_env_ids = self._all_indices if env_ids is None else env_ids @@ -487,13 +490,13 @@ def set_attrs( self._entities[env_idx].set_physical_attr(attrs[i].attr()) def set_visual_material( - self, mat: VisualMaterial, env_ids: Optional[Sequence[int]] = None + self, mat: VisualMaterial, env_ids: Sequence[int] | None = None ) -> None: """Set visual material for the rigid object. Args: mat (VisualMaterial): The material to set. - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + env_ids (Sequence[int] | None, optional): Environment indices. If None, then all indices are used. """ local_env_ids = self._all_indices if env_ids is None else env_ids @@ -503,12 +506,12 @@ def set_visual_material( self._visual_material[env_idx] = mat_inst def get_visual_material_inst( - self, env_ids: Optional[Sequence[int]] = None + self, env_ids: Sequence[int] | None = None ) -> List[VisualMaterialInst]: """Get material instances for the rigid object. Args: - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + env_ids (Sequence[int] | None, optional): Environment indices. If None, then all indices are used. Returns: List[MaterialInst]: List of material instances. @@ -533,12 +536,12 @@ def share_visual_material_inst(self, mat_insts: List[VisualMaterialInst]) -> Non entity.set_material(mat_insts[i].mat) self._visual_material[i] = mat_insts[i] - def get_body_scale(self, env_ids: Optional[Sequence[int]] = None) -> torch.Tensor: + def get_body_scale(self, env_ids: Sequence[int] | None = None) -> torch.Tensor: """ Retrieve the body scale for specified environment instances. Args: - env_ids (Optional[Sequence[int]]): A sequence of environment instance IDs. + env_ids (Sequence[int] | None): A sequence of environment instance IDs. If None, retrieves the body scale for all instances. Returns: @@ -553,13 +556,13 @@ def get_body_scale(self, env_ids: Optional[Sequence[int]] = None) -> torch.Tenso ) def set_body_scale( - self, scale: torch.Tensor, env_ids: Optional[Sequence[int]] = None + self, scale: torch.Tensor, env_ids: Sequence[int] | None = None ) -> None: """Set the scale of the rigid body. Args: scale (torch.Tensor): The scale to set with shape (N, 3). - env_ids (Optional[Sequence[int]], optional): Environment indices. If None, then all indices are used. + env_ids (Sequence[int] | None, optional): Environment indices. If None, then all indices are used. """ local_env_ids = self._all_indices if env_ids is None else env_ids @@ -575,12 +578,12 @@ def set_body_scale( else: logger.log_error(f"Setting body scale on GPU is not supported yet.") - def get_vertices(self, env_ids: Optional[Sequence[int]] = None) -> torch.Tensor: + def get_vertices(self, env_ids: Sequence[int] | None = None) -> torch.Tensor: """ Retrieve the vertices of the rigid objects. Args: - env_ids (Optional[Sequence[int]]): A sequence of environment IDs for which to retrieve vertices. + env_ids (Sequence[int] | None): A sequence of environment IDs for which to retrieve vertices. If None, retrieves vertices for all instances. Returns: @@ -607,11 +610,11 @@ def get_user_ids(self) -> torch.Tensor: device=self.device, ) - def clear_dynamics(self, env_ids: Optional[Sequence[int]] = None) -> None: + def clear_dynamics(self, env_ids: Sequence[int] | None = None) -> None: """Clear the dynamics of the rigid bodies by resetting velocities and applying zero forces and torques. Args: - env_ids (Optional[Sequence[int]]): Environment indices. If None, then all indices are used. + env_ids (Sequence[int] | None): Environment indices. If None, then all indices are used. """ if self.is_non_dynamic: return @@ -648,7 +651,51 @@ def clear_dynamics(self, env_ids: Optional[Sequence[int]] = None) -> None: data_type=RigidBodyGPUAPIWriteType.TORQUE, ) - def reset(self, env_ids: Optional[Sequence[int]] = None) -> None: + def set_physical_visible( + self, + visible: bool = True, + rgba: Sequence[float] | None = None, + ): + """set collion render visibility + + Args: + visible (bool, optional): is collision body visible. Defaults to True. + rgba (Sequence[float] | None, optional): collision body visible rgba. It will be defined at the first time the function is called. Defaults to None. + """ + rgba = rgba if rgba is not None else (0.8, 0.2, 0.2, 0.7) + if len(rgba) != 4: + logger.log_error(f"Invalid rgba {rgba}, should be a sequence of 4 floats.") + + # create collision visible node if not exist + if visible: + if not self._has_collision_visible_node: + for i, env_idx in enumerate(self._all_indices): + self._entities[env_idx].create_physical_visible_node( + np.array( + [ + rgba[0], + rgba[1], + rgba[2], + rgba[3], + ] + ) + ) + self._has_collision_visible_node = True + + # create collision visible node if not exist + for i, env_idx in enumerate(self._all_indices): + self._entities[env_idx].set_physical_visible(visible) + + def set_visible(self, visible: bool = True) -> None: + """Set the visibility of the rigid object. + + Args: + visible (bool, optional): Whether the rigid object is visible. Defaults to True. + """ + for i, env_idx in enumerate(self._all_indices): + self._entities[env_idx].set_visible(visible) + + def reset(self, env_ids: Sequence[int] | None = None) -> None: local_env_ids = self._all_indices if env_ids is None else env_ids num_instances = len(local_env_ids) self.set_attrs(self.cfg.attrs, env_ids=local_env_ids) diff --git a/embodichain/lab/sim/objects/rigid_object_group.py b/embodichain/lab/sim/objects/rigid_object_group.py index d5102339..bcf13852 100644 --- a/embodichain/lab/sim/objects/rigid_object_group.py +++ b/embodichain/lab/sim/objects/rigid_object_group.py @@ -204,6 +204,10 @@ def __init__( # set default collision filter self._set_default_collision_filter() + # reserve flag for collision visible node existence + n_instances = len(self._entities[0]) + self._has_collision_visible_node_list = [False] * n_instances + def __str__(self) -> str: parent_str = super().__str__() return ( @@ -503,6 +507,53 @@ def reset(self, env_ids: Sequence[int] | None = None) -> None: self.clear_dynamics(env_ids=local_env_ids) + def set_physical_visible( + self, + visible: bool = True, + rgba: Sequence[float] | None = None, + ): + """set collion render visibility + + Args: + visible (bool, optional): is collision body visible. Defaults to True. + rgba (Sequence[float] | None, optional): collision body visible rgba. It will be defined at the first time the function is called. Defaults to None. + """ + rgba = rgba if rgba is not None else (0.8, 0.2, 0.2, 0.7) + if len(rgba) != 4: + logger.log_error(f"Invalid rgba {rgba}, should be a sequence of 4 floats.") + + # create collision visible node if not exist + if visible: + for i, env_idx in enumerate(self._all_indices): + for intance_id, entity in enumerate(self._entities[env_idx]): + if not self._has_collision_visible_node_list[intance_id]: + entity.create_physical_visible_node( + np.array( + [ + rgba[0], + rgba[1], + rgba[2], + rgba[3], + ] + ) + ) + self._has_collision_visible_node_list[intance_id] = True + + # create collision visible node if not exist + for i, env_idx in enumerate(self._all_indices): + for entity in self._entities[env_idx]: + entity.set_physical_visible(visible) + + def set_visible(self, visible: bool = True) -> None: + """Set the visibility of the rigid object group. + + Args: + visible (bool, optional): Whether the rigid object group is visible. Defaults to True. + """ + for i, env_idx in enumerate(self._all_indices): + for entity in self._entities[env_idx]: + entity.set_visible(visible) + def destroy(self) -> None: env = self._world.get_env() arenas = env.get_all_arenas() diff --git a/embodichain/lab/sim/objects/robot.py b/embodichain/lab/sim/objects/robot.py index d53a04e0..aebcd5cb 100644 --- a/embodichain/lab/sim/objects/robot.py +++ b/embodichain/lab/sim/objects/robot.py @@ -586,6 +586,24 @@ def get_control_part_base_pose( link_name=root_link_name, env_ids=local_env_ids, to_matrix=to_matrix ) + def get_control_part_link_names(self, name: str | None = None) -> List[str]: + """Get the link names of the control part. + + Args: + name (str | None): The name of the control part. If None, return all link names. + Returns: + List[str]: link names of the control part. + """ + if name is None: + return self.link_names + if name in self._control_groups: + return self._control_groups[name].link_names + else: + logger.log_warning( + f"The control part '{name}' does not exist in the robot's control parts." + ) + return [] + def _extract_control_groups(self) -> Dict[str, ControlGroup]: r"""Extract control groups from the active joint names. @@ -648,5 +666,46 @@ def build_pk_serial_chain(self) -> None: """ self.pk_serial_chain = self.cfg.build_pk_serial_chain(device=self.device) + def set_physical_visible( + self, + visible: bool = True, + control_part: str | None = None, + rgba: Sequence[float] | None = None, + ): + """set collision of the robot or a specific control part. + + Args: + visible (bool, optional): is collision body visible. Defaults to True. + control_part (str | None, optional): control part to set visibility. Defaults to None. If None, all links are set. + rgba (Sequence[float] | None, optional): collision body visible rgba. It will be defined at the first time the function is called. Defaults to None. + """ + rgba = rgba if rgba is not None else (0.8, 0.2, 0.2, 0.7) + if len(rgba) != 4: + logger.log_error(f"Invalid rgba {rgba}, should be a sequence of 4 floats.") + rgba = np.array( + [ + rgba[0], + rgba[1], + rgba[2], + rgba[3], + ] + ) + link_names = self.get_control_part_link_names(name=control_part) + + # create collision visible node if not exist + if visible: + for i, env_idx in enumerate(self._all_indices): + for link_name in link_names: + if self._has_collision_visible_node_dict[link_name] is False: + self._entities[env_idx].create_physical_visible_node( + rgba, link_name + ) + self._has_collision_visible_node_dict[link_name] = True + + # set visibility + for i, env_idx in enumerate(self._all_indices): + for link_name in link_names: + self._entities[env_idx].set_physical_visible(visible, link_name) + def destroy(self) -> None: return super().destroy() diff --git a/embodichain/lab/sim/sim_manager.py b/embodichain/lab/sim/sim_manager.py index 86579eed..a11626d0 100644 --- a/embodichain/lab/sim/sim_manager.py +++ b/embodichain/lab/sim/sim_manager.py @@ -1159,7 +1159,7 @@ def set_gizmo_visibility( """ gizmo = self.get_gizmo(uid, control_part) if gizmo is not None: - gizmo.set_visibility(visible) + gizmo.set_visible(visible) def add_sensor(self, sensor_cfg: SensorCfg) -> BaseSensor: """General interface to add a sensor to the scene and returns a handle. diff --git a/scripts/tutorials/sim/create_robot.py b/scripts/tutorials/sim/create_robot.py index 1c8012bb..29a46064 100644 --- a/scripts/tutorials/sim/create_robot.py +++ b/scripts/tutorials/sim/create_robot.py @@ -46,7 +46,7 @@ def main(): description="Create and simulate a robot in SimulationManager" ) parser.add_argument( - "--num_envs", type=int, default=1, help="Number of environments to simulate" + "--num_envs", type=int, default=4, help="Number of environments to simulate" ) parser.add_argument( "--device", diff --git a/scripts/tutorials/sim/create_scene.py b/scripts/tutorials/sim/create_scene.py index 823586ad..be353d29 100644 --- a/scripts/tutorials/sim/create_scene.py +++ b/scripts/tutorials/sim/create_scene.py @@ -24,8 +24,9 @@ from embodichain.lab.sim import SimulationManager, SimulationManagerCfg from embodichain.lab.sim.cfg import RigidBodyAttributesCfg -from embodichain.lab.sim.shapes import CubeCfg +from embodichain.lab.sim.shapes import CubeCfg, MeshCfg from embodichain.lab.sim.objects import RigidObject, RigidObjectCfg +from dexsim.utility.path import get_resources_data_path def main(): diff --git a/tests/sim/objects/test_articulation.py b/tests/sim/objects/test_articulation.py index b3ecae8b..fe93e631 100644 --- a/tests/sim/objects/test_articulation.py +++ b/tests/sim/objects/test_articulation.py @@ -175,6 +175,15 @@ def test_remove_articulation(self): self.art.uid not in self.sim.asset_uids ), "FAIL: Articulation UID still present after removal" + def test_set_physical_visible(self): + self.art.set_physical_visible( + visible=True, + rgba=(0.1, 0.1, 0.9, 0.4), + ) + self.art.set_physical_visible(visible=False) + all_link_names = self.art.link_names + self.art.set_physical_visible(visible=True, link_names=all_link_names[:3]) + def teardown_method(self): """Clean up resources after each test method.""" self.sim.destroy() diff --git a/tests/sim/objects/test_rigid_object.py b/tests/sim/objects/test_rigid_object.py index 56cbe7ad..86ed73d3 100644 --- a/tests/sim/objects/test_rigid_object.py +++ b/tests/sim/objects/test_rigid_object.py @@ -67,6 +67,7 @@ def setup_simulation(self, sim_device): uid="table", shape=MeshCfg(fpath=table_path), body_type="static" ), ) + self.chair: RigidObject = self.sim.add_rigid_object( cfg=RigidObjectCfg( uid="chair", shape=MeshCfg(fpath=chair_path), body_type="kinematic" @@ -253,6 +254,18 @@ def test_remove(self): self.duck.uid not in self.sim.asset_uids ), "Duck UID still present after removal" + def test_set_physical_visible(self): + self.table.set_physical_visible( + visible=True, + rgba=(0.1, 0.1, 0.9, 0.4), + ) + self.table.set_physical_visible(visible=True) + self.table.set_physical_visible(visible=False) + + def test_set_visible(self): + self.table.set_visible(visible=True) + self.table.set_visible(visible=False) + def teardown_method(self): """Clean up resources after each test method.""" self.sim.destroy() diff --git a/tests/sim/objects/test_rigid_object_group.py b/tests/sim/objects/test_rigid_object_group.py index 8acff650..e9a818ee 100644 --- a/tests/sim/objects/test_rigid_object_group.py +++ b/tests/sim/objects/test_rigid_object_group.py @@ -107,6 +107,14 @@ def test_remove(self): self.obj_group.uid not in self.sim.asset_uids ), "Object group UID still present after removal" + def test_set_physical_visible(self): + self.obj_group.set_physical_visible(visible=True) + self.obj_group.set_physical_visible(visible=False) + + def test_set_visible(self): + self.obj_group.set_visible(visible=True) + self.obj_group.set_visible(visible=False) + def teardown_method(self): """Clean up resources after each test method.""" self.sim.destroy() diff --git a/tests/sim/objects/test_robot.py b/tests/sim/objects/test_robot.py index 282abed1..e5c28ca8 100644 --- a/tests/sim/objects/test_robot.py +++ b/tests/sim/objects/test_robot.py @@ -245,6 +245,21 @@ def teardown_method(self): """Clean up resources after each test method.""" self.sim.destroy() + def test_set_physical_visible(self): + self.robot.set_physical_visible( + visible=True, + rgba=(0.1, 0.1, 0.9, 0.4), + control_part="left_arm", + ) + self.robot.set_physical_visible( + visible=True, + control_part="left_arm", + ) + self.robot.set_physical_visible( + visible=False, + control_part="left_arm", + ) + class TestRobotCPU(BaseRobotTest): def setup_method(self): From c4ccdeb3ed8e78e1a12e102d6fb1d27329d7a114 Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Tue, 16 Dec 2025 06:26:31 +0000 Subject: [PATCH 28/92] Enable unit test for soft object (#39) --- embodichain/lab/sim/sim_manager.py | 23 +++++++++++++++++++++++ tests/sim/objects/test_soft_object.py | 1 - 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/embodichain/lab/sim/sim_manager.py b/embodichain/lab/sim/sim_manager.py index a11626d0..d31e2c65 100644 --- a/embodichain/lab/sim/sim_manager.py +++ b/embodichain/lab/sim/sim_manager.py @@ -280,6 +280,7 @@ def asset_uids(self) -> List[str]: uid_list.extend(list(self._robots.keys())) uid_list.extend(list(self._rigid_objects.keys())) uid_list.extend(list(self._rigid_object_groups.keys())) + uid_list.extend(list(self._soft_objects.keys())) uid_list.extend(list(self._articulations.keys())) return uid_list @@ -795,6 +796,20 @@ def get_rigid_object(self, uid: str) -> RigidObject | None: return None return self._rigid_objects[uid] + def get_soft_object(self, uid: str) -> SoftObject | None: + """Get a soft object by its unique ID. + + Args: + uid (str): The unique ID of the soft object. + + Returns: + SoftObject | None: The soft object instance if found, otherwise None. + """ + if uid not in self._soft_objects: + logger.log_warning(f"Soft object {uid} not found.") + return None + return self._soft_objects[uid] + def get_rigid_object_uid_list(self) -> List[str]: """Get current rigid body uid list @@ -803,6 +818,14 @@ def get_rigid_object_uid_list(self) -> List[str]: """ return list(self._rigid_objects.keys()) + def get_soft_object_uid_list(self) -> List[str]: + """Get current soft body uid list + + Returns: + List[str]: list of soft body uid. + """ + return list(self._soft_objects.keys()) + def add_rigid_object_group(self, cfg: RigidObjectGroupCfg) -> RigidObjectGroup: """Add a rigid object group to the scene. diff --git a/tests/sim/objects/test_soft_object.py b/tests/sim/objects/test_soft_object.py index 88ea2d25..3099c2da 100644 --- a/tests/sim/objects/test_soft_object.py +++ b/tests/sim/objects/test_soft_object.py @@ -92,7 +92,6 @@ def teardown_method(self): self.sim.destroy() -@pytest.mark.skip(reason="Skipping SoftObject test now") class TestSoftObjectCUDA(BaseSoftObjectTest): def setup_method(self): self.setup_simulation() From 806c4a24cda3818791f79fb5c4eeedbd80b2d99e Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Thu, 18 Dec 2025 07:56:55 +0000 Subject: [PATCH 29/92] Update project setup method (#40) --- .github/release.yml | 32 +++++++++ .github/workflows/main.yml | 62 ++++++++++++++--- .gitignore | 2 + MANIFEST.in | 1 + docs/source/quick_start/install.md | 2 +- embodichain/__init__.py | 2 +- embodichain/lab/sim/objects/articulation.py | 12 ++-- embodichain/lab/sim/objects/rigid_object.py | 12 ++-- .../lab/sim/objects/rigid_object_group.py | 15 ++-- embodichain/lab/sim/objects/soft_object.py | 3 +- embodichain/lab/sim/sim_manager.py | 8 +-- pyproject.toml | 11 +-- setup.py | 69 +++++++++++-------- 13 files changed, 169 insertions(+), 62 deletions(-) create mode 100644 .github/release.yml create mode 100644 MANIFEST.in diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 00000000..d0a04950 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,32 @@ +# .github/release.yml + +changelog: + categories: + - title: "🚀 New Features" + labels: + - feature + + - title: "🐛 Bug Fixes" + labels: + - bug + + - title: "🔧 Improvements" + labels: + - refactor + - enhancement + + - title: "⚠️ Breaking Changes" + labels: + - breaking + + - title: "📚 Documentation" + labels: + - docs + + - title: "🛠 Internal / CI" + labels: + - ci + + exclude: + labels: + - skip-release-notes \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 84ed7706..7d819218 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,7 +25,7 @@ jobs: options: --memory 100g --gpus device=1 --shm-size 53687091200 steps: - uses: actions/checkout@v4 - - name: (CI) Code Style check + - name: Code Style check run: | echo "Workspace: ${GITHUB_WORKSPACE}" ls @@ -46,12 +46,14 @@ jobs: container: *container_template steps: - uses: actions/checkout@v4 - - name: (CI) Build docs + - name: Build docs run: | - pip install -e . + pip install -e . --extra-index-url http://pyp.open3dv.site:2345/simple/ --trusted-host pyp.open3dv.site pip install -r docs/requirements.txt cd ${GITHUB_WORKSPACE}/docs echo "Start Building docs..." + pip uninstall pymeshlab -y + pip install pymeshlab==2023.12.post3 make html - name: Upload docs artifact if: github.event_name == 'push' && github.ref == 'refs/heads/main' @@ -71,11 +73,13 @@ jobs: container: *container_template steps: - uses: actions/checkout@v4 - - name: (CI) Run tests + - name: Run tests run: | - pip install -e . + pip install -e . --extra-index-url http://pyp.open3dv.site:2345/simple/ --trusted-host pyp.open3dv.site echo "Unit test Start" export HF_ENDPOINT=https://hf-mirror.com + pip uninstall pymeshlab -y + pip install pymeshlab==2023.12.post3 pytest tests publish: @@ -92,11 +96,49 @@ jobs: container: *container_template steps: - uses: actions/checkout@v4 - - name: (CI) Publish package - run: echo "start publish stage" - - name: (CI) Download docs artifact + - name: Download docs artifact uses: actions/download-artifact@v4 with: name: github-pages - - name: (CI) Deploy GitHub Pages - uses: actions/deploy-pages@v4 \ No newline at end of file + + - name: Deploy GitHub Pages + uses: actions/deploy-pages@v4 + + + release: + if: startsWith(github.ref, 'refs/tags/v') + runs-on: Linux + permissions: + contents: write + id-token: write # PyPI Trusted Publishing + + container: *container_template + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: (Release) Install build tools + run: | + python -m pip install --upgrade pip + pip install build + + - name: (Release) Build sdist and wheel + run: | + python -m build --wheel + + - name: (Release) Create GitHub Release (draft) + uses: softprops/action-gh-release@v2 + with: + draft: true + generate_release_notes: true + files: | + dist/* + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: (Release) Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index dc87025b..cbe06491 100644 --- a/.gitignore +++ b/.gitignore @@ -195,3 +195,5 @@ wandb/ # vscode settings .vscode/ + +embodichain/VERSION diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..ceeea233 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include VERSION diff --git a/docs/source/quick_start/install.md b/docs/source/quick_start/install.md index 58f0bb6c..63891019 100644 --- a/docs/source/quick_start/install.md +++ b/docs/source/quick_start/install.md @@ -53,7 +53,7 @@ git clone https://github.com/DexForce/EmbodiChain.git Install the project in development mode: ```bash -pip install -e . +pip install -e . --extra-index-url http://pyp.open3dv.site:2345/simple/ --trusted-host pyp.open3dv.site ``` ### Verify Installation diff --git a/embodichain/__init__.py b/embodichain/__init__.py index f818cf7b..c0b0271e 100644 --- a/embodichain/__init__.py +++ b/embodichain/__init__.py @@ -21,7 +21,7 @@ # Read version from VERSION file def _get_version(): - version_file = os.path.join(os.path.dirname(embodichain_dir), "VERSION") + version_file = os.path.join(embodichain_dir, "VERSION") try: with open(version_file, "r") as f: return f.read().strip() diff --git a/embodichain/lab/sim/objects/articulation.py b/embodichain/lab/sim/objects/articulation.py index f1325a6c..e92a56b8 100644 --- a/embodichain/lab/sim/objects/articulation.py +++ b/embodichain/lab/sim/objects/articulation.py @@ -71,10 +71,14 @@ def __init__( # get gpu indices for the entities. # only meaningful when using GPU physics. - self.gpu_indices = torch.as_tensor( - [np.int32(entity.get_gpu_index()) for entity in self.entities], - dtype=torch.int32, - device=self.device, + self.gpu_indices = ( + torch.as_tensor( + [entity.get_gpu_index() for entity in self.entities], + dtype=torch.int32, + device=self.device, + ) + if self.device.type == "cuda" + else None ) self.dof = self.entities[0].get_dof() diff --git a/embodichain/lab/sim/objects/rigid_object.py b/embodichain/lab/sim/objects/rigid_object.py index f6fc48c2..a9e88a96 100644 --- a/embodichain/lab/sim/objects/rigid_object.py +++ b/embodichain/lab/sim/objects/rigid_object.py @@ -60,10 +60,14 @@ def __init__( self.device = device # get gpu indices for the entities. - self.gpu_indices = torch.as_tensor( - [entity.get_gpu_index() for entity in self.entities], - dtype=torch.int32, - device=self.device, + self.gpu_indices = ( + torch.as_tensor( + [entity.get_gpu_index() for entity in self.entities], + dtype=torch.int32, + device=self.device, + ) + if self.device.type == "cuda" + else None ) # Initialize rigid body data. diff --git a/embodichain/lab/sim/objects/rigid_object_group.py b/embodichain/lab/sim/objects/rigid_object_group.py index bcf13852..a9eb0ea8 100644 --- a/embodichain/lab/sim/objects/rigid_object_group.py +++ b/embodichain/lab/sim/objects/rigid_object_group.py @@ -58,10 +58,17 @@ def __init__( self.device = device # get gpu indices for the rigid bodies with shape of (num_instances, num_objects) - self.gpu_indices = torch.as_tensor( - [[entity.get_gpu_index() for entity in instance] for instance in entities], - dtype=torch.int32, - device=self.device, + self.gpu_indices = ( + torch.as_tensor( + [ + [entity.get_gpu_index() for entity in instance] + for instance in entities + ], + dtype=torch.int32, + device=self.device, + ) + if self.device.type == "cuda" + else None ) # Initialize rigid body group data tensors. Shape of (num_instances, num_objects, data_dim) diff --git a/embodichain/lab/sim/objects/soft_object.py b/embodichain/lab/sim/objects/soft_object.py index 62e45c8a..161aafa8 100644 --- a/embodichain/lab/sim/objects/soft_object.py +++ b/embodichain/lab/sim/objects/soft_object.py @@ -43,7 +43,7 @@ class SoftBodyData: """Data manager for soft body Note: - 1. The pose data managed by dexsim is in the format of (qx, qy, qz, qw, x, y, z), but in EmbodySim, we use (x, y, z, qw, qx, qy, qz) format. + 1. The pose data managed by dexsim is in the format of (qx, qy, qz, qw, x, y, z), but in EmbodiChain, we use (x, y, z, qw, qx, qy, qz) format. """ def __init__( @@ -171,7 +171,6 @@ def __init__( self._data = SoftBodyData(entities=entities, ps=self._ps, device=device) - # TODO: soft body physical attribute is already set in soft body creation(embodichain/lab/sim/utility/sim_utils.py load_soft_object_from_cfg) self._world.update(0.001) super().__init__(cfg=cfg, entities=entities, device=device) diff --git a/embodichain/lab/sim/sim_manager.py b/embodichain/lab/sim/sim_manager.py index d31e2c65..21024950 100644 --- a/embodichain/lab/sim/sim_manager.py +++ b/embodichain/lab/sim/sim_manager.py @@ -373,7 +373,7 @@ def init_gpu_physics(self) -> None: rigid_body_num = ( 0 if self._get_non_static_rigid_obj_num() == 0 - else len(self._ps.gpu_rigid_indices) + else len(self._ps.get_gpu_rigid_indices()) ) self._rigid_body_pose = torch.zeros( (rigid_body_num, 7), dtype=torch.float32, device=self.device @@ -383,7 +383,7 @@ def init_gpu_physics(self) -> None: articulation_num = ( 0 if len(self._articulations) == 0 and len(self._robots) == 0 - else len(self._ps.gpu_articulation_indices) + else len(self._ps.get_gpu_articulation_indices()) ) max_link_count = self._ps.gpu_get_articulation_max_link_count() self._link_pose = torch.zeros( @@ -452,14 +452,14 @@ def _sync_gpu_data(self) -> None: if len(self._rigid_body_pose) > 0: self._ps.gpu_fetch_rigid_body_data( data=CudaArray(self._rigid_body_pose), - gpu_indices=self._ps.gpu_rigid_indices, + gpu_indices=self._ps.get_gpu_rigid_indices(), data_type=RigidBodyGPUAPIReadType.POSE, ) if len(self._link_pose) > 0: self._ps.gpu_fetch_link_data( data=CudaArray(self._link_pose), - gpu_indices=self._ps.gpu_articulation_indices, + gpu_indices=self._ps.get_gpu_articulation_indices(), data_type=ArticulationGPUAPIReadType.LINK_GLOBAL_POSE, ) diff --git a/pyproject.toml b/pyproject.toml index 85506d9a..da8ca266 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ # is still executed during build. This is a minimal, non-opinionated pyproject # that modernizes the package while preserving the custom extension build steps. requires = ["setuptools>=61.0", "wheel"] -build-backend = "setuptools.build_meta:__legacy__" +build-backend = "setuptools.build_meta" # Note: @@ -17,17 +17,16 @@ build-backend = "setuptools.build_meta:__legacy__" [project] name = "embodichain" -version = "0.0.1" description = "An end-to-end, GPU-accelerated, and modular platform for building generalized Embodied Intelligence." readme = "README.md" authors = [ { name = "EmbodiChain Developers" } ] requires-python = ">=3.10" - +dynamic = ["version"] # Core install dependencies (kept from requirements.txt). Some VCS links are # specified using PEP 508 direct references where present. dependencies = [ - "dexsim_engine @ http://pyp.open3dv.site:2345/packages/dexsim_engine-0.3.7-cp310-cp310-manylinux_2_31_x86_64.whl", + "dexsim_engine", "setuptools>=78.1.1", "gymnasium==0.29.1", "casadi==3.7.1", @@ -45,7 +44,6 @@ dependencies = [ "transformers>=4.53.0", "diffusers>=0.32.1", "deepspeed>=0.16.2", - "cvxpy==1.4.0", "ortools", "prettytable", "black==24.3.0", @@ -53,6 +51,9 @@ dependencies = [ "h5py", ] +[tool.setuptools.dynamic] +version = { file = ["VERSION"] } + [tool.setuptools.packages.find] where = ["."] exclude = ["docs"] diff --git a/setup.py b/setup.py index ae041d57..8325ffbf 100644 --- a/setup.py +++ b/setup.py @@ -19,6 +19,7 @@ import os import shutil import sys +import argparse from os import path as osp from pathlib import Path @@ -94,30 +95,44 @@ def get_data_files_of_a_directory(source_dir, target_dir=None, ignore_py=False): return filelist -# Extract version -here = osp.abspath(osp.dirname(__file__)) -version = None -with open(os.path.join(os.path.dirname(__file__), "VERSION")) as f: - full_version = f.read().strip() - version = ".".join(full_version.split(".")[:3]) - -ignore_py = sys.argv[1] == "bdist_nuitka" if len(sys.argv) > 1 else False -data_files = [] -data_files += get_data_files_of_a_directory("embodichain", ignore_py=ignore_py) - -cmdclass = {"clean": CleanCommand} -if BuildExtension is not None: - cmdclass["build_ext"] = BuildExtension.with_options(no_python_abi_suffix=True) - -setup( - name="embodichain", - version=version, - url="https://github.com/DexForce/EmbodiChain", - author="EmbodiChain Developers", - description="An end-to-end, GPU-accelerated, and modular platform for building generalized Embodied Intelligence.", - packages=find_packages(exclude=["docs"]), - data_files=data_files, - entry_points={}, - cmdclass=cmdclass, - include_package_data=True, -) +def get_version(): + with open(os.path.join(os.path.dirname(__file__), "VERSION")) as f: + full_version = f.read().strip() + version = ".".join(full_version.split(".")[:3]) + return version + + +def main(): + # Extract version + version = get_version() + + data_files = [] + data_files += get_data_files_of_a_directory("embodichain", ignore_py=False) + + cmdclass = {"clean": CleanCommand} + if BuildExtension is not None: + cmdclass["build_ext"] = BuildExtension.with_options(no_python_abi_suffix=True) + + setup( + name="embodichain", + version=version, + url="https://github.com/DexForce/EmbodiChain", + author="EmbodiChain Developers", + description="An end-to-end, GPU-accelerated, and modular platform for building generalized Embodied Intelligence.", + packages=find_packages(exclude=["docs"]), + data_files=data_files, + entry_points={}, + cmdclass=cmdclass, + include_package_data=True, + ) + + # Copy VERSION file into the package directory for wheel/sdist + src_version = os.path.join(THIS_DIR, "VERSION") + dst_version = os.path.join(THIS_DIR, "embodichain", "VERSION") + if os.path.exists(src_version): + shutil.copyfile(src_version, dst_version) + logger.info(f"Copied VERSION to {dst_version}") + + +if __name__ == "__main__": + main() From 474ed574b8ed246dbb6de86defe63869653210e7 Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Thu, 18 Dec 2025 09:42:18 +0000 Subject: [PATCH 30/92] Fix camera extrinsics functor (#43) --- embodichain/lab/gym/envs/managers/randomization/rendering.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/embodichain/lab/gym/envs/managers/randomization/rendering.py b/embodichain/lab/gym/envs/managers/randomization/rendering.py index b1e378d8..535ebd66 100644 --- a/embodichain/lab/gym/envs/managers/randomization/rendering.py +++ b/embodichain/lab/gym/envs/managers/randomization/rendering.py @@ -106,7 +106,7 @@ def randomize_camera_extrinsics( .unsqueeze_(0) .repeat(num_instance, 1) ) - init_euler = euler_xyz_from_quat(init_quat_np) + init_euler = torch.stack(euler_xyz_from_quat(init_quat_np), dim=1) # 2. Sample perturbation for euler angles random_value = sample_uniform( lower=torch.tensor(euler_range[0]), @@ -114,7 +114,8 @@ def randomize_camera_extrinsics( size=(num_instance, 3), ) # 3. Add perturbation to each environment and convert back to quaternion - new_quat = quat_from_euler_xyz(init_euler + random_value) + roll, pitch, yaw = (init_euler + random_value).unbind(dim=1) + new_quat = quat_from_euler_xyz(roll, pitch, yaw) new_pose[:, 3:7] = new_quat camera.set_local_pose(new_pose, env_ids=env_ids) From 37b84d943d7016cb902d2a96829ee5b901f4f8d1 Mon Sep 17 00:00:00 2001 From: Chen Jian Date: Thu, 18 Dec 2025 17:54:26 +0800 Subject: [PATCH 31/92] upgrade pytorch kinematic to 076 (#42) Co-authored-by: chenjian --- embodichain/lab/sim/utility/import_utils.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embodichain/lab/sim/utility/import_utils.py b/embodichain/lab/sim/utility/import_utils.py index 0630a48e..09212108 100644 --- a/embodichain/lab/sim/utility/import_utils.py +++ b/embodichain/lab/sim/utility/import_utils.py @@ -33,7 +33,7 @@ def lazy_import_pytorch_kinematics(): return pk except ImportError as e: logger.log_warning( - "pytorch_kinematics not installed. Install with `pip install pytorch_kinematics==0.7.5`" + "pytorch_kinematics not installed. Install with `pip install pytorch_kinematics==0.7.6`" ) raise e diff --git a/pyproject.toml b/pyproject.toml index da8ca266..7ce70560 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ dependencies = [ "qpsolvers==4.8.1", "pin-pink==3.4.0", "py_opw_kinematics==0.1.6", - "pytorch_kinematics==0.7.5", + "pytorch_kinematics==0.7.6", "polars==1.31.0", "PyYAML>=6.0", "accelerate==1.2.1", From 9251591125794b12a6510936ce997ee8c0ccaed1 Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Sat, 20 Dec 2025 09:53:14 +0000 Subject: [PATCH 32/92] Fix Articulation GPU issue (#44) --- embodichain/lab/sim/cfg.py | 1 - embodichain/lab/sim/objects/articulation.py | 10 +++++-- embodichain/lab/sim/objects/rigid_object.py | 30 +++++++++++++++++-- .../lab/sim/objects/rigid_object_group.py | 8 ++--- embodichain/lab/sim/objects/soft_object.py | 4 +-- 5 files changed, 38 insertions(+), 15 deletions(-) diff --git a/embodichain/lab/sim/cfg.py b/embodichain/lab/sim/cfg.py index 9fef7b58..1e325e01 100644 --- a/embodichain/lab/sim/cfg.py +++ b/embodichain/lab/sim/cfg.py @@ -165,7 +165,6 @@ def attr(self) -> PhysicalAttr: attr.mass = self.mass attr.contact_offset = self.contact_offset attr.rest_offset = self.rest_offset - attr.enable_collision = self.enable_collision attr.dynamic_friction = self.dynamic_friction attr.static_friction = self.static_friction attr.angular_damping = self.angular_damping diff --git a/embodichain/lab/sim/objects/articulation.py b/embodichain/lab/sim/objects/articulation.py index e92a56b8..5b45072f 100644 --- a/embodichain/lab/sim/objects/articulation.py +++ b/embodichain/lab/sim/objects/articulation.py @@ -511,9 +511,7 @@ def __init__( self.device = device # Store all indices for batch operations - self._all_indices = torch.arange( - len(entities), dtype=torch.int32, device=device - ) + self._all_indices = torch.arange(len(entities), dtype=torch.int32).tolist() if device.type == "cuda": self._world.update(0.001) @@ -799,6 +797,7 @@ def set_local_pose( # we should keep `pose_` life cycle to the end of the function. pose_ = torch.cat((quat, xyz), dim=-1) indices = self.body_data.gpu_indices[local_env_ids] + torch.cuda.synchronize(self.device) self._ps.gpu_apply_root_data( data=pose_, gpu_indices=indices, @@ -978,6 +977,7 @@ def set_qpos( indices = self.body_data.gpu_indices[local_env_ids] qpos_set = self.body_data._qpos[local_env_ids] qpos_set[:, local_joint_ids] = qpos + torch.cuda.synchronize(self.device) self._ps.gpu_apply_joint_data( data=qpos_set, gpu_indices=indices, @@ -1041,6 +1041,7 @@ def set_qvel( self.body_data.qvel qvel_set = self.body_data._qvel[local_env_ids] qvel_set[:, joint_ids] = qvel + torch.cuda.synchronize(self.device) self._ps.gpu_apply_joint_data( data=qvel_set, gpu_indices=indices, @@ -1081,6 +1082,7 @@ def set_qf( self.body_data.qf qf_set = self.body_data._qf[local_env_ids] qf_set[:, joint_ids] = qf + torch.cuda.synchronize(self.device) self._ps.gpu_apply_joint_data( data=qf_set, gpu_indices=indices, @@ -1161,11 +1163,13 @@ def clear_dynamics(self, env_ids: Sequence[int] | None = None) -> None: (len(local_env_ids), self.dof), dtype=torch.float32, device=self.device ) indices = self.body_data.gpu_indices[local_env_ids] + torch.cuda.synchronize(self.device) self._ps.gpu_apply_joint_data( data=zeros, gpu_indices=indices, data_type=ArticulationGPUAPIWriteType.JOINT_VELOCITY, ) + torch.cuda.synchronize(self.device) self._ps.gpu_apply_joint_data( data=zeros, gpu_indices=indices, diff --git a/embodichain/lab/sim/objects/rigid_object.py b/embodichain/lab/sim/objects/rigid_object.py index a9e88a96..a6b650c8 100644 --- a/embodichain/lab/sim/objects/rigid_object.py +++ b/embodichain/lab/sim/objects/rigid_object.py @@ -176,9 +176,7 @@ def __init__( self._world = dexsim.default_world() self._ps = self._world.get_physics_scene() - self._all_indices = torch.arange( - len(entities), dtype=torch.int32, device=device - ) + self._all_indices = torch.arange(len(entities), dtype=torch.int32).tolist() # data for managing body data (only for dynamic and kinematic bodies) on GPU. self._data: RigidBodyData | None = None @@ -200,6 +198,12 @@ def __init__( # set default collision filter self._set_default_collision_filter() + # TODO: Must be called after setting all attributes. + # May be improved in the future. + if cfg.attrs.enable_collision is False: + flag = torch.zeros(len(entities), dtype=torch.bool) + self.enable_collision(flag) + # reserve flag for collision visible node existence self._has_collision_visible_node = False @@ -614,6 +618,26 @@ def get_user_ids(self) -> torch.Tensor: device=self.device, ) + def enable_collision( + self, enable: torch.Tensor, env_ids: Sequence[int] | None = None + ) -> None: + """Enable or disable collision for the rigid bodies. + + Args: + enable (torch.Tensor): A tensor of shape (N,) representing whether to enable collision for each rigid body. + env_ids (Sequence[int] | None): Environment indices. If None, then all indices are used. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + if len(local_env_ids) != len(enable): + logger.log_error( + f"Length of env_ids {len(local_env_ids)} does not match enable length {len(enable)}." + ) + + enable_list = enable.tolist() + for i, env_idx in enumerate(local_env_ids): + self._entities[env_idx].enable_collision(bool(enable_list[i])) + def clear_dynamics(self, env_ids: Sequence[int] | None = None) -> None: """Clear the dynamics of the rigid bodies by resetting velocities and applying zero forces and torques. diff --git a/embodichain/lab/sim/objects/rigid_object_group.py b/embodichain/lab/sim/objects/rigid_object_group.py index a9eb0ea8..baf62f49 100644 --- a/embodichain/lab/sim/objects/rigid_object_group.py +++ b/embodichain/lab/sim/objects/rigid_object_group.py @@ -187,12 +187,10 @@ def __init__( self._world = dexsim.default_world() self._ps = self._world.get_physics_scene() - self._all_indices = torch.arange( - len(entities), dtype=torch.int32, device=device - ) + self._all_indices = torch.arange(len(entities), dtype=torch.int32).tolist() self._all_obj_indices = torch.arange( - len(entities[0]), dtype=torch.int32, device=device - ) + len(entities[0]), dtype=torch.int32 + ).tolist() # data for managing body data (only for dynamic and kinematic bodies) on GPU. self._data = RigidBodyGroupData(entities=entities, ps=self._ps, device=device) diff --git a/embodichain/lab/sim/objects/soft_object.py b/embodichain/lab/sim/objects/soft_object.py index 161aafa8..be9bd57d 100644 --- a/embodichain/lab/sim/objects/soft_object.py +++ b/embodichain/lab/sim/objects/soft_object.py @@ -165,9 +165,7 @@ def __init__( ) -> None: self._world = dexsim.default_world() self._ps = self._world.get_physics_scene() - self._all_indices = torch.arange( - len(entities), dtype=torch.int32, device=device - ) + self._all_indices = torch.arange(len(entities), dtype=torch.int32).tolist() self._data = SoftBodyData(entities=entities, ps=self._ps, device=device) From 6b300a23eb5d9b997618205f3139adea6cb54264 Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Sun, 21 Dec 2025 08:09:20 +0000 Subject: [PATCH 33/92] Fix Rigid Object/Group CUDA memory issue (#46) --- embodichain/lab/sim/objects/rigid_object.py | 3 +++ embodichain/lab/sim/objects/rigid_object_group.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/embodichain/lab/sim/objects/rigid_object.py b/embodichain/lab/sim/objects/rigid_object.py index a6b650c8..c701236c 100644 --- a/embodichain/lab/sim/objects/rigid_object.py +++ b/embodichain/lab/sim/objects/rigid_object.py @@ -350,6 +350,7 @@ def set_local_pose( # we should keep `pose_` life cycle to the end of the function. pose = torch.cat((quat, xyz), dim=-1) indices = self.body_data.gpu_indices[local_env_ids] + torch.cuda.synchronize(self.device) self._ps.gpu_apply_rigid_body_data( data=pose.clone(), gpu_indices=indices, @@ -458,6 +459,7 @@ def add_force_torque( else: indices = self.body_data.gpu_indices[local_env_ids] + torch.cuda.synchronize(self.device) if force is not None: self._ps.gpu_apply_rigid_body_data( data=force, @@ -658,6 +660,7 @@ def clear_dynamics(self, env_ids: Sequence[int] | None = None) -> None: (len(local_env_ids), 3), dtype=torch.float32, device=self.device ) indices = self.body_data.gpu_indices[local_env_ids] + torch.cuda.synchronize(self.device) self._ps.gpu_apply_rigid_body_data( data=zeros, gpu_indices=indices, diff --git a/embodichain/lab/sim/objects/rigid_object_group.py b/embodichain/lab/sim/objects/rigid_object_group.py index baf62f49..f22a2453 100644 --- a/embodichain/lab/sim/objects/rigid_object_group.py +++ b/embodichain/lab/sim/objects/rigid_object_group.py @@ -362,6 +362,7 @@ def set_local_pose( indices = self.body_data.gpu_indices[local_env_ids][ :, local_obj_ids ].flatten() + torch.cuda.synchronize(self.device) self._ps.gpu_apply_rigid_body_data( data=pose.clone(), gpu_indices=indices, @@ -433,6 +434,7 @@ def clear_dynamics(self, env_ids: Sequence[int] | None = None) -> None: device=self.device, ) indices = self.body_data.gpu_indices[local_env_ids].flatten() + torch.cuda.synchronize(self.device) self._ps.gpu_apply_rigid_body_data( data=zeros, gpu_indices=indices, From c2e38f3ffe33f9ead72367ac3ffbc11fae66610f Mon Sep 17 00:00:00 2001 From: Jietao Chen <61959467+chase6305@users.noreply.github.com> Date: Tue, 23 Dec 2025 14:48:25 +0800 Subject: [PATCH 34/92] Fix: add component type check on add_component (#50) Co-authored-by: Jietao Chen --- embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py b/embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py index 3dd4303c..6637b99c 100644 --- a/embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py +++ b/embodichain/toolkits/urdf_assembly/urdf_assembly_manager.py @@ -230,6 +230,11 @@ def add_component( raise ValueError("component_type must be a string") if not isinstance(urdf_path, (str, Path)): raise ValueError("urdf_path must be a string or Path") + if component_type not in self.SUPPORTED_COMPONENTS: + raise ValueError( + f"Unsupported component_type: {component_type}. " + f"Supported types: {self.SUPPORTED_COMPONENTS}" + ) component = URDFComponent( urdf_path=urdf_path, params=params, transform=transform From fdfc283f9fcc7775d65f6f653c423b530b48d5b7 Mon Sep 17 00:00:00 2001 From: Chen Yang <115123709+yangchen73@users.noreply.github.com> Date: Thu, 25 Dec 2025 10:10:41 +0800 Subject: [PATCH 35/92] Add StackBlocksTwo environment (#45) --- configs/gym/stack_blocks_two/gym_config.json | 384 ++++++++++++++++++ embodichain/lab/gym/envs/__init__.py | 1 + .../envs/tasks/tableware/stack_blocks_two.py | 112 +++++ 3 files changed, 497 insertions(+) create mode 100644 configs/gym/stack_blocks_two/gym_config.json create mode 100644 embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py diff --git a/configs/gym/stack_blocks_two/gym_config.json b/configs/gym/stack_blocks_two/gym_config.json new file mode 100644 index 00000000..34a50cbf --- /dev/null +++ b/configs/gym/stack_blocks_two/gym_config.json @@ -0,0 +1,384 @@ +{ + "id": "StackBlocksTwo-v1", + "max_episodes": 5, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "init_block_1_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_1"}, + "position_range": [[-0.08, -0.08, 0.0], [0.08, 0.08, 0.0]], + "rotation_range": [[0, 0, -0.75], [0, 0, 0.75]], + "relative_position": true + } + }, + "init_block_2_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_2"}, + "position_range": [[-0.08, -0.08, 0.0], [0.08, 0.08, 0.0]], + "rotation_range": [[0, 0, -0.75], [0, 0, 0.75]], + "relative_position": true + } + }, + "prepare_extra_attr": { + "func": "prepare_extra_attr", + "mode": "reset", + "params": { + "attrs": [ + { + "name": "object_lengths", + "mode": "callable", + "entity_uids": "all_objects", + "func_name": "compute_object_length", + "func_kwargs": { + "is_svd_frame": true, + "sample_points": 5000 + } + }, + { + "name": "left_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "left_arm_base", + "to_matrix": true + } + }, + { + "name": "right_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "right_arm_base", + "to_matrix": true + } + } + ] + } + }, + "register_info_to_env": { + "func": "register_info_to_env", + "mode": "reset", + "params": { + "registry": [ + { + "entity_cfg": { + "uid": "block_1" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "block_2" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["left_arm"] + }, + "attrs": ["left_arm_base_pose"], + "pose_register_params": { + "compute_relative": "block_1", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["right_arm"] + }, + "attrs": ["right_arm_base_pose"], + "pose_register_params": { + "compute_relative": "block_2", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + } + ], + "registration": "affordance_datas", + "sim_update": true + } + }, + "random_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_robot_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 5, + "params": { + "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_camera_intrinsics": { + "func": "randomize_camera_intrinsics", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "focal_x_range": [-50, 50], + "focal_y_range": [-50, 50] + } + }, + "random_robot_init_eef_pose": { + "func": "randomize_robot_eef_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, + "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + } + }, + "observations": { + "norm_robot_eef_joint": { + "func": "normalize_robot_joint_data", + "mode": "modify", + "name": "robot/qpos", + "params": { + "joint_ids": [12, 13, 14, 15] + } + }, + "block_1_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_1_pose", + "params": { + "entity_cfg": {"uid": "block_1"} + } + }, + "block_2_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_2_pose", + "params": { + "entity_cfg": {"uid": "block_2"} + } + }, + "cam_high_semantic_mask_l": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["block_1", "block_2"] + } + }, + "cam_high_semantic_mask_r": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_r", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["block_1", "block_2"], + "is_right": true + } + }, + "cam_left_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_left_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_left_wrist"}, + "foreground_uids": ["block_1", "block_2"] + } + }, + "cam_right_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_right_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_right_wrist"}, + "foreground_uids": ["block_1", "block_2"] + } + } + }, + "dataset": { + "robot_meta": { + "arm_dofs": 12, + "control_freq": 25, + "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], + "min_len_steps": 5 + } + } + }, + "robot": { + "uid": "CobotMagic", + "robot_type": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] + }, + "sensor": [ + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "width": 960, + "height": 540, + "enable_mask": true, + "enable_depth": true, + "left_to_right_pos": [0.059684025824163614, 0, 0], + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "extrinsics": { + "eye": [0.35368482807598, 0.014695524383058989, 1.4517046071614774], + "target": [0.7186357573287919, -0.054534732904795505, 0.5232553674540066], + "up": [0.9306678549330372, -0.0005600064212467153, 0.3658647703553347] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "right_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "left_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + } + ], + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [2, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "CircleTableSimple/circle_table_simple.ply" + }, + "attrs" : { + "mass": 10.0, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.01 + }, + "body_scale": [1, 1, 1], + "body_type": "kinematic", + "init_pos": [0.725, 0.0, 0.825], + "init_rot": [0, 90, 0] + } + ], + "rigid_object": [ + { + "uid":"block_1", + "shape": { + "shape_type": "Cube", + "size": [0.05, 0.05, 0.05] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.75, -0.1, 0.9], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + }, + { + "uid":"block_2", + "shape": { + "shape_type": "Cube", + "size": [0.05, 0.05, 0.05] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.75, 0.1, 0.9], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + } + ] +} + diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py index 286d7824..48d9646d 100644 --- a/embodichain/lab/gym/envs/__init__.py +++ b/embodichain/lab/gym/envs/__init__.py @@ -26,6 +26,7 @@ PourWaterEnv, ) from embodichain.lab.gym.envs.tasks.tableware.scoop_ice import ScoopIce +from embodichain.lab.gym.envs.tasks.tableware.stack_blocks_two import StackBlocksTwoEnv # Reinforcement learning environments from embodichain.lab.gym.envs.tasks.rl.push_cube import PushCubeEnv diff --git a/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py b/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py new file mode 100644 index 00000000..5f543869 --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py @@ -0,0 +1,112 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.utils import logger + +__all__ = ["StackBlocksTwoEnv"] + + +@register_env("StackBlocksTwo-v1", max_episode_steps=600) +class StackBlocksTwoEnv(EmbodiedEnv): + def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): + super().__init__(cfg, **kwargs) + + action_config = kwargs.get("action_config", None) + if action_config is not None: + self.action_config = action_config + + def is_task_success(self, **kwargs) -> torch.Tensor: + """Determine if the task is successfully completed. This is mainly used in the data generation process + of the imitation learning. + + The task is successful if: + 1. Block2 is stacked on top of Block1 + 2. Both blocks haven't fallen over + 3. Both grippers are open + + Args: + **kwargs: Additional arguments for task-specific success criteria. + + Returns: + torch.Tensor: A boolean tensor indicating success for each environment in the batch. + """ + try: + block1 = self.sim.get_rigid_object("block_1") + block2 = self.sim.get_rigid_object("block_2") + except: + logger.log_warning("Block1 or Block2 not found, returning False.") + return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) + + # Get poses + block1_pose = block1.get_local_pose(to_matrix=True) + block2_pose = block2.get_local_pose(to_matrix=True) + + # Extract positions + block1_pos = block1_pose[:, :3, 3] # (num_envs, 3) + block2_pos = block2_pose[:, :3, 3] + + # Check if blocks haven't fallen + block1_fallen = self._is_fall(block1_pose) + block2_fallen = self._is_fall(block2_pose) + + # Block2 should be on top of block1 + expected_block2_pos = torch.stack( + [ + block1_pos[:, 0], + block1_pos[:, 1], + block1_pos[:, 2] + 0.05, # block1 z + block height + ], + dim=1, + ) + + # Tolerance + eps = torch.tensor( + [0.025, 0.025, 0.012], dtype=torch.float32, device=self.device + ) + + # Check if block2 is within tolerance of expected position + position_diff = torch.abs(block2_pos - expected_block2_pos) # (num_envs, 3) + within_tolerance = torch.all( + position_diff < eps.unsqueeze(0), dim=1 + ) # (num_envs,) + + # RoboTwin check if grippers are open + # This requires checking robot gripper state, which may need to be implemented + + # Task succeeds if blocks are stacked correctly and haven't fallen + success = within_tolerance & ~block1_fallen & ~block2_fallen + + return success + + def _is_fall(self, pose: torch.Tensor) -> torch.Tensor: + # Extract z-axis from rotation matrix (last column, first 3 elements) + pose_rz = pose[:, :3, 2] + world_z_axis = torch.tensor([0, 0, 1], dtype=pose.dtype, device=pose.device) + + # Compute dot product for each batch element + dot_product = torch.sum(pose_rz * world_z_axis, dim=-1) # Shape: (batch_size,) + + # Clamp to avoid numerical issues with arccos + dot_product = torch.clamp(dot_product, -1.0, 1.0) + + # Compute angle and check if fallen + angle = torch.arccos(dot_product) + return angle >= torch.pi / 4 From ae72ce62386b71c6ae65610cd439ebf7da483f02 Mon Sep 17 00:00:00 2001 From: Chen Yang <115123709+yangchen73@users.noreply.github.com> Date: Thu, 25 Dec 2025 10:10:41 +0800 Subject: [PATCH 36/92] Add StackBlocksTwo environment (#45) --- configs/gym/stack_blocks_two/gym_config.json | 384 ++++++++++++++++++ embodichain/lab/gym/envs/__init__.py | 1 + .../envs/tasks/tableware/stack_blocks_two.py | 112 +++++ 3 files changed, 497 insertions(+) create mode 100644 configs/gym/stack_blocks_two/gym_config.json create mode 100644 embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py diff --git a/configs/gym/stack_blocks_two/gym_config.json b/configs/gym/stack_blocks_two/gym_config.json new file mode 100644 index 00000000..34a50cbf --- /dev/null +++ b/configs/gym/stack_blocks_two/gym_config.json @@ -0,0 +1,384 @@ +{ + "id": "StackBlocksTwo-v1", + "max_episodes": 5, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "init_block_1_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_1"}, + "position_range": [[-0.08, -0.08, 0.0], [0.08, 0.08, 0.0]], + "rotation_range": [[0, 0, -0.75], [0, 0, 0.75]], + "relative_position": true + } + }, + "init_block_2_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_2"}, + "position_range": [[-0.08, -0.08, 0.0], [0.08, 0.08, 0.0]], + "rotation_range": [[0, 0, -0.75], [0, 0, 0.75]], + "relative_position": true + } + }, + "prepare_extra_attr": { + "func": "prepare_extra_attr", + "mode": "reset", + "params": { + "attrs": [ + { + "name": "object_lengths", + "mode": "callable", + "entity_uids": "all_objects", + "func_name": "compute_object_length", + "func_kwargs": { + "is_svd_frame": true, + "sample_points": 5000 + } + }, + { + "name": "left_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "left_arm_base", + "to_matrix": true + } + }, + { + "name": "right_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "right_arm_base", + "to_matrix": true + } + } + ] + } + }, + "register_info_to_env": { + "func": "register_info_to_env", + "mode": "reset", + "params": { + "registry": [ + { + "entity_cfg": { + "uid": "block_1" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "block_2" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["left_arm"] + }, + "attrs": ["left_arm_base_pose"], + "pose_register_params": { + "compute_relative": "block_1", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["right_arm"] + }, + "attrs": ["right_arm_base_pose"], + "pose_register_params": { + "compute_relative": "block_2", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + } + ], + "registration": "affordance_datas", + "sim_update": true + } + }, + "random_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_robot_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 5, + "params": { + "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_camera_intrinsics": { + "func": "randomize_camera_intrinsics", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "focal_x_range": [-50, 50], + "focal_y_range": [-50, 50] + } + }, + "random_robot_init_eef_pose": { + "func": "randomize_robot_eef_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, + "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + } + }, + "observations": { + "norm_robot_eef_joint": { + "func": "normalize_robot_joint_data", + "mode": "modify", + "name": "robot/qpos", + "params": { + "joint_ids": [12, 13, 14, 15] + } + }, + "block_1_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_1_pose", + "params": { + "entity_cfg": {"uid": "block_1"} + } + }, + "block_2_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_2_pose", + "params": { + "entity_cfg": {"uid": "block_2"} + } + }, + "cam_high_semantic_mask_l": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["block_1", "block_2"] + } + }, + "cam_high_semantic_mask_r": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_r", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["block_1", "block_2"], + "is_right": true + } + }, + "cam_left_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_left_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_left_wrist"}, + "foreground_uids": ["block_1", "block_2"] + } + }, + "cam_right_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_right_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_right_wrist"}, + "foreground_uids": ["block_1", "block_2"] + } + } + }, + "dataset": { + "robot_meta": { + "arm_dofs": 12, + "control_freq": 25, + "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], + "min_len_steps": 5 + } + } + }, + "robot": { + "uid": "CobotMagic", + "robot_type": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] + }, + "sensor": [ + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "width": 960, + "height": 540, + "enable_mask": true, + "enable_depth": true, + "left_to_right_pos": [0.059684025824163614, 0, 0], + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "extrinsics": { + "eye": [0.35368482807598, 0.014695524383058989, 1.4517046071614774], + "target": [0.7186357573287919, -0.054534732904795505, 0.5232553674540066], + "up": [0.9306678549330372, -0.0005600064212467153, 0.3658647703553347] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "right_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "left_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + } + ], + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [2, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "CircleTableSimple/circle_table_simple.ply" + }, + "attrs" : { + "mass": 10.0, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.01 + }, + "body_scale": [1, 1, 1], + "body_type": "kinematic", + "init_pos": [0.725, 0.0, 0.825], + "init_rot": [0, 90, 0] + } + ], + "rigid_object": [ + { + "uid":"block_1", + "shape": { + "shape_type": "Cube", + "size": [0.05, 0.05, 0.05] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.75, -0.1, 0.9], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + }, + { + "uid":"block_2", + "shape": { + "shape_type": "Cube", + "size": [0.05, 0.05, 0.05] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.75, 0.1, 0.9], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + } + ] +} + diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py index 286d7824..48d9646d 100644 --- a/embodichain/lab/gym/envs/__init__.py +++ b/embodichain/lab/gym/envs/__init__.py @@ -26,6 +26,7 @@ PourWaterEnv, ) from embodichain.lab.gym.envs.tasks.tableware.scoop_ice import ScoopIce +from embodichain.lab.gym.envs.tasks.tableware.stack_blocks_two import StackBlocksTwoEnv # Reinforcement learning environments from embodichain.lab.gym.envs.tasks.rl.push_cube import PushCubeEnv diff --git a/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py b/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py new file mode 100644 index 00000000..5f543869 --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py @@ -0,0 +1,112 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.utils import logger + +__all__ = ["StackBlocksTwoEnv"] + + +@register_env("StackBlocksTwo-v1", max_episode_steps=600) +class StackBlocksTwoEnv(EmbodiedEnv): + def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): + super().__init__(cfg, **kwargs) + + action_config = kwargs.get("action_config", None) + if action_config is not None: + self.action_config = action_config + + def is_task_success(self, **kwargs) -> torch.Tensor: + """Determine if the task is successfully completed. This is mainly used in the data generation process + of the imitation learning. + + The task is successful if: + 1. Block2 is stacked on top of Block1 + 2. Both blocks haven't fallen over + 3. Both grippers are open + + Args: + **kwargs: Additional arguments for task-specific success criteria. + + Returns: + torch.Tensor: A boolean tensor indicating success for each environment in the batch. + """ + try: + block1 = self.sim.get_rigid_object("block_1") + block2 = self.sim.get_rigid_object("block_2") + except: + logger.log_warning("Block1 or Block2 not found, returning False.") + return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) + + # Get poses + block1_pose = block1.get_local_pose(to_matrix=True) + block2_pose = block2.get_local_pose(to_matrix=True) + + # Extract positions + block1_pos = block1_pose[:, :3, 3] # (num_envs, 3) + block2_pos = block2_pose[:, :3, 3] + + # Check if blocks haven't fallen + block1_fallen = self._is_fall(block1_pose) + block2_fallen = self._is_fall(block2_pose) + + # Block2 should be on top of block1 + expected_block2_pos = torch.stack( + [ + block1_pos[:, 0], + block1_pos[:, 1], + block1_pos[:, 2] + 0.05, # block1 z + block height + ], + dim=1, + ) + + # Tolerance + eps = torch.tensor( + [0.025, 0.025, 0.012], dtype=torch.float32, device=self.device + ) + + # Check if block2 is within tolerance of expected position + position_diff = torch.abs(block2_pos - expected_block2_pos) # (num_envs, 3) + within_tolerance = torch.all( + position_diff < eps.unsqueeze(0), dim=1 + ) # (num_envs,) + + # RoboTwin check if grippers are open + # This requires checking robot gripper state, which may need to be implemented + + # Task succeeds if blocks are stacked correctly and haven't fallen + success = within_tolerance & ~block1_fallen & ~block2_fallen + + return success + + def _is_fall(self, pose: torch.Tensor) -> torch.Tensor: + # Extract z-axis from rotation matrix (last column, first 3 elements) + pose_rz = pose[:, :3, 2] + world_z_axis = torch.tensor([0, 0, 1], dtype=pose.dtype, device=pose.device) + + # Compute dot product for each batch element + dot_product = torch.sum(pose_rz * world_z_axis, dim=-1) # Shape: (batch_size,) + + # Clamp to avoid numerical issues with arccos + dot_product = torch.clamp(dot_product, -1.0, 1.0) + + # Compute angle and check if fallen + angle = torch.arccos(dot_product) + return angle >= torch.pi / 4 From 30802554c5c4aca7a919484d43bd18e6b4b74f1c Mon Sep 17 00:00:00 2001 From: Yueci Deng Date: Thu, 25 Dec 2025 15:00:18 +0800 Subject: [PATCH 37/92] Add cpu num to SimulationCfg & Add some interfaces to robot (#51) --- embodichain/lab/sim/objects/articulation.py | 6 +- embodichain/lab/sim/objects/robot.py | 286 ++++++++++++++++++++ embodichain/lab/sim/sim_manager.py | 15 +- tests/sim/objects/test_robot.py | 14 + 4 files changed, 311 insertions(+), 10 deletions(-) diff --git a/embodichain/lab/sim/objects/articulation.py b/embodichain/lab/sim/objects/articulation.py index 5b45072f..00a03deb 100644 --- a/embodichain/lab/sim/objects/articulation.py +++ b/embodichain/lab/sim/objects/articulation.py @@ -891,7 +891,11 @@ def get_link_pose( return link_pose def get_qpos(self) -> torch.Tensor: - """Get the current positions (qpos) of the articulation.""" + """Get the current positions (qpos) of the articulation. + + Returns: + torch.Tensor: Joint positions with shape (N, dof), where N is the number of environments. + """ return self.body_data.qpos def set_qpos( diff --git a/embodichain/lab/sim/objects/robot.py b/embodichain/lab/sim/objects/robot.py index aebcd5cb..9edb9826 100644 --- a/embodichain/lab/sim/objects/robot.py +++ b/embodichain/lab/sim/objects/robot.py @@ -123,6 +123,107 @@ def get_joint_ids( else [i for i in self._joint_ids[name] if i not in self.mimic_ids] ) + def get_link_names(self, name: str | None = None) -> Union[List[str], None]: + """Get the link names of the robot for a specific control part. + + If no control part is specified, return all link names. + + Args: + name (str, optional): The name of the control part to get the link names for. If None, the default part is used. + + Returns: + List[str]: The link names of the robot for the specified control part. + """ + if not self.control_parts or name is None: + return self.link_names + + if name not in self.control_parts: + logger.log_error( + f"The control part '{name}' does not exist in the robot's control parts {self.control_parts}." + ) + return self._control_groups[name].link_names + + def get_qpos_limits( + self, name: str | None = None, env_ids: Sequence[int] | None = None + ) -> torch.Tensor: + """Get the joint position limits (qpos) of the robot for a specific control part. + + It returns all joint position limits if no control part is specified. + + Args: + name (str | None): The name of the control part to get the qpos limits for. + env_ids (Sequence[int] | None): The environment ids to get the qpos limits for. If None, all environments are used. + + Returns: + torch.Tensor: Joint position limits with shape (N, dof, 2), where N is the number of environments. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + qpos_limits = self.body_data.qpos_limits + if name is None: + return qpos_limits[local_env_ids, :] + else: + if not self.control_parts or name not in self.control_parts: + logger.log_error( + f"The control part '{name}' does not exist in the robot's control parts." + ) + part_joint_ids = self.get_joint_ids(name=name) + return qpos_limits[local_env_ids][:, part_joint_ids, :] + + def get_qvel_limits( + self, name: str | None = None, env_ids: Sequence[int] | None = None + ) -> torch.Tensor: + """Get the joint velocity limits (qvel) of the robot for a specific control part. + + It returns all joint velocity limits if no control part is specified. + + Args: + name (str | None): The name of the control part to get the qvel limits for. + env_ids (Sequence[int] | None): The environment ids to get the qvel limits for. If None, all environments are used. + + Returns: + torch.Tensor: Joint velocity limits with shape (N, dof, 2), where N is the number of environments. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + qvel_limits = self.body_data.qvel_limits + if name is None: + return qvel_limits[local_env_ids, :] + else: + if not self.control_parts or name not in self.control_parts: + logger.log_error( + f"The control part '{name}' does not exist in the robot's control parts." + ) + part_joint_ids = self.get_joint_ids(name=name) + return qvel_limits[local_env_ids][:, part_joint_ids, :] + + def get_qf_limits( + self, name: str | None = None, env_ids: Sequence[int] | None = None + ) -> torch.Tensor: + """Get the joint effort limits (qf) of the robot for a specific control part. + + It returns all joint effort limits if no control part is specified. + + Args: + name (str | None): The name of the control part to get the qf limits for. + env_ids (Sequence[int] | None): The environment ids to get the qf limits for. If None, all environments are used. + + Returns: + torch.Tensor: Joint effort limits with shape (N, dof, 2), where N is the number of environments. + """ + local_env_ids = self._all_indices if env_ids is None else env_ids + + qf_limits = self.body_data.qf_limits + if name is None: + return qf_limits[local_env_ids, :] + else: + if not self.control_parts or name not in self.control_parts: + logger.log_error( + f"The control part '{name}' does not exist in the robot's control parts." + ) + part_joint_ids = self.get_joint_ids(name=name) + return qf_limits[local_env_ids][:, part_joint_ids, :] + def get_proprioception(self) -> Dict[str, torch.Tensor]: """Gets robot proprioception information, primarily for agent state representation in robot learning scenarios. @@ -139,6 +240,191 @@ def get_proprioception(self) -> Dict[str, torch.Tensor]: qpos=self.body_data.qpos, qvel=self.body_data.qvel, qf=self.body_data.qf ) + def set_qpos( + self, + qpos: torch.Tensor, + joint_ids: Sequence[int] | None = None, + env_ids: Sequence[int] | None = None, + target: bool = True, + name: str | None = None, + ) -> None: + """Set the joint positions (qpos) or target positions for the articulation. + + Args: + qpos (torch.Tensor): Joint positions with shape (N, dof), where N is the number of environments. + joint_ids (Sequence[int] | None, optional): Joint indices to apply the positions. If None, applies to all joints. + env_ids (Sequence[int] | None): Environment indices to apply the positions. Defaults to all environments. + target (bool): If True, sets target positions for simulation. If False, updates current positions directly. + name (str | None): The name of the control part to set the qpos for. If None, the default part is used. + + Raises: + ValueError: If the length of `env_ids` does not match the length of `qpos`. + """ + if name is None: + super().set_qpos( + qpos=qpos, + joint_ids=joint_ids, + env_ids=env_ids, + target=target, + ) + else: + if not self.control_parts or name not in self.control_parts: + logger.log_error( + f"The control part '{name}' does not exist in the robot's control parts." + ) + part_joint_ids = self.get_joint_ids(name=name) + if joint_ids is not None: + logger.log_warning(f"`joint_ids` is ignored when `name` is specified.") + + super().set_qpos( + qpos=qpos, + joint_ids=part_joint_ids, + env_ids=env_ids, + target=target, + ) + + def get_qpos(self, name: str | None = None) -> torch.Tensor: + """Get the joint positions (qpos) of the robot. + + Args: + name (str | None): The name of the control part to get the qpos for. If None, the default part is used. + Returns: + torch.Tensor: Joint positions with shape (N, dof), where N is the number of environments. + """ + + qpos = super().get_qpos() + if name is None: + return qpos + else: + if not self.control_parts or name not in self.control_parts: + logger.log_error( + f"The control part '{name}' does not exist in the robot's control parts." + ) + part_joint_ids = self.get_joint_ids(name=name) + return qpos[:, part_joint_ids] + + def set_qvel( + self, + qvel: torch.Tensor, + joint_ids: Sequence[int] | None = None, + env_ids: Sequence[int] | None = None, + target: bool = True, + name: str | None = None, + ) -> None: + """Set the joint velocities (qvel) or target velocities for the articulation. + + Args: + qvel (torch.Tensor): Joint velocities with shape (N, dof), where N is the number of environments. + joint_ids (Sequence[int] | None, optional): Joint indices to apply the velocities. If None, applies to all joints. + env_ids (Sequence[int] | None): Environment indices to apply the velocities. Defaults to all environments. + target (bool): If True, sets target velocities for simulation. If False, updates current velocities directly. + name (str | None): The name of the control part to set the qvel for. If None, the default part is used. + + Raises: + ValueError: If the length of `env_ids` does not match the length of `qvel`. + """ + if name is None: + super().set_qvel( + qvel=qvel, + joint_ids=joint_ids, + env_ids=env_ids, + target=target, + ) + else: + if not self.control_parts or name not in self.control_parts: + logger.log_error( + f"The control part '{name}' does not exist in the robot's control parts." + ) + part_joint_ids = self.get_joint_ids(name=name) + if joint_ids is not None: + logger.log_warning(f"`joint_ids` is ignored when `name` is specified.") + + super().set_qvel( + qvel=qvel, + joint_ids=part_joint_ids, + env_ids=env_ids, + target=target, + ) + + def get_qvel(self, name: str | None = None) -> torch.Tensor: + """Get the joint velocities (qvel) of the robot. + + Args: + name (str | None): The name of the control part to get the qvel for. If None, the default part is used. + Returns: + torch.Tensor: Joint velocities with shape (N, dof), where N is the number of environments. + """ + + qvel = super().get_qvel() + if name is None: + return qvel + else: + if not self.control_parts or name not in self.control_parts: + logger.log_error( + f"The control part '{name}' does not exist in the robot's control parts." + ) + part_joint_ids = self.get_joint_ids(name=name) + return qvel[:, part_joint_ids] + + def set_qf( + self, + qf: torch.Tensor, + joint_ids: Sequence[int] | None = None, + env_ids: Sequence[int] | None = None, + name: str | None = None, + ) -> None: + """Set the joint efforts (qf) for the articulation. + + Args: + qf (torch.Tensor): Joint efforts with shape (N, dof), where N is the number of environments. + joint_ids (Sequence[int] | None, optional): Joint indices to apply the efforts. If None, applies to all joints. + env_ids (Sequence[int] | None): Environment indices to apply the efforts. Defaults to all environments. + name (str | None): The name of the control part to set the qf for. If None, the default part is used. + + Raises: + ValueError: If the length of `env_ids` does not match the length of `qf`. + """ + if name is None: + super().set_qf( + qf=qf, + joint_ids=joint_ids, + env_ids=env_ids, + ) + else: + if not self.control_parts or name not in self.control_parts: + logger.log_error( + f"The control part '{name}' does not exist in the robot's control parts." + ) + part_joint_ids = self.get_joint_ids(name=name) + if joint_ids is not None: + logger.log_warning(f"`joint_ids` is ignored when `name` is specified.") + + super().set_qf( + qf=qf, + joint_ids=part_joint_ids, + env_ids=env_ids, + ) + + def get_qf(self, name: str | None = None) -> torch.Tensor: + """Get the joint efforts (qf) of the robot. + + Args: + name (str | None): The name of the control part to get the qf for. If None, the default part is used. + Returns: + torch.Tensor: Joint efforts with shape (N, dof), where N is the number of environments. + """ + + qf = super().get_qf() + if name is None: + return qf + else: + if not self.control_parts or name not in self.control_parts: + logger.log_error( + f"The control part '{name}' does not exist in the robot's control parts." + ) + part_joint_ids = self.get_joint_ids(name=name) + return qf[:, part_joint_ids] + def compute_fk( self, qpos: torch.Tensor | np.ndarray | None, diff --git a/embodichain/lab/sim/sim_manager.py b/embodichain/lab/sim/sim_manager.py index 21024950..b41a1d83 100644 --- a/embodichain/lab/sim/sim_manager.py +++ b/embodichain/lab/sim/sim_manager.py @@ -75,7 +75,6 @@ RobotCfg, ) from embodichain.lab.sim import VisualMaterial, VisualMaterialCfg -from embodichain.data.assets import SimResources from embodichain.utils import configclass, logger __all__ = [ @@ -123,6 +122,9 @@ class SimulationManagerCfg: - RENDER_SCENE_SHARE_ENGINE: The rendering thread and scene update thread share the same thread with the simulation engine. """ + cpu_num: int = 1 + """The number of CPU threads to use for the simulation engine.""" + arena_space: float = 5.0 """The distance between each arena when building multiple arenas.""" @@ -291,6 +293,7 @@ def _convert_sim_config( win_config = dexsim.WindowsConfig() win_config.width = sim_config.width win_config.height = sim_config.height + world_config.cpu_num = sim_config.cpu_num world_config.win_config = win_config world_config.open_windows = not sim_config.headless self.is_window_opened = not sim_config.headless @@ -327,16 +330,10 @@ def _convert_sim_config( return world_config - def get_default_resources(self) -> SimResources: - """Get the default resources instance. - - Returns: - SimResources: The default resources path. - """ - return self._default_resources - def _init_sim_resources(self) -> None: """Initialize the default simulation resources.""" + from embodichain.data.assets import SimResources + self._default_resources = SimResources() def enable_physics(self, enable: bool) -> None: diff --git a/tests/sim/objects/test_robot.py b/tests/sim/objects/test_robot.py index e5c28ca8..54200207 100644 --- a/tests/sim/objects/test_robot.py +++ b/tests/sim/objects/test_robot.py @@ -241,6 +241,20 @@ def test_mimic(self): len(right_eef_ids_without_mimic) == 6 ), f"Expected 6 right eef joint IDs without mimic, got {len(right_eef_ids_without_mimic)}" + def test_setter_and_getter_with_control_part(self): + left_arm_qpos = self.robot.get_qpos(name="left_arm") + assert left_arm_qpos.shape == (10, 7) + + left_qpos_limits = self.robot.get_qpos_limits(name="left_arm") + assert left_qpos_limits.shape == (10, 7, 2) + + dummy_qpos = torch.randn(10, 7, device=self.sim.device) + # Clamp to limits + dummy_qpos = torch.max( + torch.min(dummy_qpos, left_qpos_limits[:, :, 1]), left_qpos_limits[:, :, 0] + ) + self.robot.set_qpos(qpos=dummy_qpos, name="left_arm") + def teardown_method(self): """Clean up resources after each test method.""" self.sim.destroy() From a35b110309b0d5c1f93f04570d0955b76aaaee19 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Thu, 25 Dec 2025 15:43:26 +0800 Subject: [PATCH 38/92] Remove grippers check --- embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py b/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py index 5f543869..9e06dd21 100644 --- a/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py +++ b/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py @@ -40,7 +40,6 @@ def is_task_success(self, **kwargs) -> torch.Tensor: The task is successful if: 1. Block2 is stacked on top of Block1 2. Both blocks haven't fallen over - 3. Both grippers are open Args: **kwargs: Additional arguments for task-specific success criteria. @@ -88,9 +87,6 @@ def is_task_success(self, **kwargs) -> torch.Tensor: position_diff < eps.unsqueeze(0), dim=1 ) # (num_envs,) - # RoboTwin check if grippers are open - # This requires checking robot gripper state, which may need to be implemented - # Task succeeds if blocks are stacked correctly and haven't fallen success = within_tolerance & ~block1_fallen & ~block2_fallen From e17c08b9dd839cecfde17b95f1e66867cf89dbb5 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Thu, 25 Dec 2025 15:43:26 +0800 Subject: [PATCH 39/92] Remove grippers check --- embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py b/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py index 5f543869..9e06dd21 100644 --- a/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py +++ b/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py @@ -40,7 +40,6 @@ def is_task_success(self, **kwargs) -> torch.Tensor: The task is successful if: 1. Block2 is stacked on top of Block1 2. Both blocks haven't fallen over - 3. Both grippers are open Args: **kwargs: Additional arguments for task-specific success criteria. @@ -88,9 +87,6 @@ def is_task_success(self, **kwargs) -> torch.Tensor: position_diff < eps.unsqueeze(0), dim=1 ) # (num_envs,) - # RoboTwin check if grippers are open - # This requires checking robot gripper state, which may need to be implemented - # Task succeeds if blocks are stacked correctly and haven't fallen success = within_tolerance & ~block1_fallen & ~block2_fallen From 48621af923a470f65597f0d8baaf9d3a33c1be18 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Thu, 25 Dec 2025 21:26:09 +0800 Subject: [PATCH 40/92] Refactor: Recursively resolve nested SceneEntityCfg params at play --- .../lab/gym/envs/managers/manager_base.py | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/embodichain/lab/gym/envs/managers/manager_base.py b/embodichain/lab/gym/envs/managers/manager_base.py index d89503bc..2db673be 100644 --- a/embodichain/lab/gym/envs/managers/manager_base.py +++ b/embodichain/lab/gym/envs/managers/manager_base.py @@ -379,13 +379,17 @@ def _process_functor_cfg_at_play(self, functor_name: str, functor_cfg: FunctorCf functor_name: The name of the functor. functor_cfg: The functor configuration. """ - for key, value in functor_cfg.params.items(): + + def _resolve_scene_entities(value, key_path: str): + # Resolve SceneEntityCfg anywhere in nested params (dict/list/tuple). if isinstance(value, SceneEntityCfg): # load the entity try: value.resolve(self._env.sim) except ValueError as e: - raise ValueError(f"Error while parsing '{functor_name}:{key}'. {e}") + raise ValueError( + f"Error while parsing '{functor_name}:{key_path}'. {e}" + ) # log the entity for checking later msg = f"[{functor_cfg.__class__.__name__}:{functor_name}] Found entity '{value.uid}'." if value.joint_ids is not None: @@ -394,8 +398,27 @@ def _process_functor_cfg_at_play(self, functor_name: str, functor_cfg: FunctorCf msg += f"\n\tBody names: {value.body_names} [{value.body_ids}]" # print the information print(f"[INFO]: {msg}") + return value + if isinstance(value, list): # recursively resolve the list + return [ + _resolve_scene_entities(v, f"{key_path}[{i}]") + for i, v in enumerate(value) + ] + if isinstance(value, tuple): # recursively resolve the tuple + return tuple( + _resolve_scene_entities(v, f"{key_path}[{i}]") + for i, v in enumerate(value) + ) + if isinstance(value, dict): # recursively resolve the dict + return { + k: _resolve_scene_entities(v, f"{key_path}.{k}") + for k, v in value.items() + } + return value + + for key, value in list(functor_cfg.params.items()): # store the entity - functor_cfg.params[key] = value + functor_cfg.params[key] = _resolve_scene_entities(value, key) # initialize the functor if it is a class if inspect.isclass(functor_cfg.func): From b6b0ce40c5374e22374baf999020755d4ecb2ae4 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Thu, 25 Dec 2025 21:26:09 +0800 Subject: [PATCH 41/92] Refactor: Recursively resolve nested SceneEntityCfg params at play --- .../lab/gym/envs/managers/manager_base.py | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/embodichain/lab/gym/envs/managers/manager_base.py b/embodichain/lab/gym/envs/managers/manager_base.py index d89503bc..2db673be 100644 --- a/embodichain/lab/gym/envs/managers/manager_base.py +++ b/embodichain/lab/gym/envs/managers/manager_base.py @@ -379,13 +379,17 @@ def _process_functor_cfg_at_play(self, functor_name: str, functor_cfg: FunctorCf functor_name: The name of the functor. functor_cfg: The functor configuration. """ - for key, value in functor_cfg.params.items(): + + def _resolve_scene_entities(value, key_path: str): + # Resolve SceneEntityCfg anywhere in nested params (dict/list/tuple). if isinstance(value, SceneEntityCfg): # load the entity try: value.resolve(self._env.sim) except ValueError as e: - raise ValueError(f"Error while parsing '{functor_name}:{key}'. {e}") + raise ValueError( + f"Error while parsing '{functor_name}:{key_path}'. {e}" + ) # log the entity for checking later msg = f"[{functor_cfg.__class__.__name__}:{functor_name}] Found entity '{value.uid}'." if value.joint_ids is not None: @@ -394,8 +398,27 @@ def _process_functor_cfg_at_play(self, functor_name: str, functor_cfg: FunctorCf msg += f"\n\tBody names: {value.body_names} [{value.body_ids}]" # print the information print(f"[INFO]: {msg}") + return value + if isinstance(value, list): # recursively resolve the list + return [ + _resolve_scene_entities(v, f"{key_path}[{i}]") + for i, v in enumerate(value) + ] + if isinstance(value, tuple): # recursively resolve the tuple + return tuple( + _resolve_scene_entities(v, f"{key_path}[{i}]") + for i, v in enumerate(value) + ) + if isinstance(value, dict): # recursively resolve the dict + return { + k: _resolve_scene_entities(v, f"{key_path}.{k}") + for k, v in value.items() + } + return value + + for key, value in list(functor_cfg.params.items()): # store the entity - functor_cfg.params[key] = value + functor_cfg.params[key] = _resolve_scene_entities(value, key) # initialize the functor if it is a class if inspect.isclass(functor_cfg.func): From 9c4ea37c6f880e61648f5e77b14a5ec2fd82d2e6 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Thu, 25 Dec 2025 21:27:29 +0800 Subject: [PATCH 42/92] Feat: Add scale randomization API with shared_sample --- .../envs/managers/randomization/__init__.py | 2 + .../gym/envs/managers/randomization/scale.py | 182 ++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 embodichain/lab/gym/envs/managers/randomization/scale.py diff --git a/embodichain/lab/gym/envs/managers/randomization/__init__.py b/embodichain/lab/gym/envs/managers/randomization/__init__.py index 6483181f..ad24fe91 100644 --- a/embodichain/lab/gym/envs/managers/randomization/__init__.py +++ b/embodichain/lab/gym/envs/managers/randomization/__init__.py @@ -16,6 +16,8 @@ from .rendering import * from .spatial import * +from .scale import * + """ Randomization are all implemented as Event functors. diff --git a/embodichain/lab/gym/envs/managers/randomization/scale.py b/embodichain/lab/gym/envs/managers/randomization/scale.py new file mode 100644 index 00000000..5e9ee874 --- /dev/null +++ b/embodichain/lab/gym/envs/managers/randomization/scale.py @@ -0,0 +1,182 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +from typing import TYPE_CHECKING, List, Union + +import torch + +from embodichain.lab.gym.envs.managers.cfg import SceneEntityCfg +from embodichain.lab.sim.objects import RigidObject +from embodichain.utils import logger +from embodichain.utils.math import sample_uniform + +if TYPE_CHECKING: + from embodichain.lab.gym.envs import EmbodiedEnv + + +def _normalize_env_ids( + env: EmbodiedEnv, env_ids: Union[torch.Tensor, None] +) -> torch.Tensor: + # Target all active environments if no specific IDs are provided + if env_ids is None: + return torch.arange(env.num_envs, device=env.device) + return env_ids + + +def _sample_body_scale( + env: EmbodiedEnv, + env_ids: torch.Tensor, + scale_factor_range: tuple[list[float], list[float]], + same_scale_all_axes: bool, +) -> torch.Tensor: + """Sample per-env body scale factors. + + Returns: + torch.Tensor: Shape (num_envs_selected, 3) scale factors for x/y/z. + """ + num_instance = len(env_ids) + if same_scale_all_axes: + low = torch.tensor(scale_factor_range[0][0], device=env.device) + high = torch.tensor(scale_factor_range[1][0], device=env.device) + s = sample_uniform(lower=low, upper=high, size=(num_instance,)) + return torch.stack([s, s, s], dim=1) + low = torch.tensor(scale_factor_range[0], device=env.device) + high = torch.tensor(scale_factor_range[1], device=env.device) + return sample_uniform(lower=low, upper=high, size=(num_instance, 3)) + + +def randomize_rigid_object_scale( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + scale_factor_range: tuple[list[float], list[float]] | None = None, + same_scale_all_axes: bool = True, +) -> None: + """Randomize a rigid object's *body scale factors* (multiplicative, not absolute size). + + Args: + env: Environment instance. + env_ids: Target env ids. If None, applies to all envs. + entity_cfg: Scene entity config of the rigid object. + scale_factor_range: If same_scale_all_axes is True, should be [[s_min], [s_max]]. + Otherwise [[sx_min, sy_min, sz_min], [sx_max, sy_max, sz_max]]. + same_scale_all_axes: Whether to use same factor on x/y/z. + """ + if scale_factor_range is None: + return + if entity_cfg.uid not in env.sim.get_rigid_object_uid_list(): + return + + env_ids = _normalize_env_ids(env, env_ids) + rigid_object: RigidObject = env.sim.get_rigid_object(entity_cfg.uid) + scale = _sample_body_scale(env, env_ids, scale_factor_range, same_scale_all_axes) + rigid_object.set_body_scale(scale, env_ids=env_ids) + + +def randomize_rigid_objects_scale( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfgs: List[SceneEntityCfg], + scale_factor_range: tuple[list[float], list[float]] | None = None, + same_scale_all_axes: bool = True, + shared_sample: bool = False, +) -> None: + """Randomize body scale factors for multiple rigid objects. + + Args: + env: Environment instance. + env_ids: Target env ids. If None, applies to all envs. + entity_cfgs: List of scene entity configs (rigid objects). + scale_factor_range: Scale factor sampling range. + same_scale_all_axes: Whether to use same factor on x/y/z. + shared_sample: If True, sample one scale per-env and apply to *all* objects (sync). + If False, each object samples its own scales independently. + """ + if scale_factor_range is None: + return + + if not isinstance(entity_cfgs, list) or len(entity_cfgs) == 0: + return + + env_ids = _normalize_env_ids(env, env_ids) + + if shared_sample: + scale = _sample_body_scale( + env, env_ids, scale_factor_range, same_scale_all_axes + ) + for entity_cfg in entity_cfgs: + if entity_cfg.uid not in env.sim.get_rigid_object_uid_list(): + continue + rigid_object: RigidObject = env.sim.get_rigid_object(entity_cfg.uid) + rigid_object.set_body_scale(scale, env_ids=env_ids) + return + + for entity_cfg in entity_cfgs: + randomize_rigid_object_scale( + env=env, + env_ids=env_ids, + entity_cfg=entity_cfg, + scale_factor_range=scale_factor_range, + same_scale_all_axes=same_scale_all_axes, + ) + + +def randomize_rigid_object_body_scale( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + scale_range: tuple[list[float], list[float]] | None = None, + same_scale_all_axes: bool = True, +) -> None: + """Deprecated. Use `randomize_rigid_object_scale` + `scale_factor_range`.""" + if scale_range is not None: + logger.log_warning( + "`randomize_rigid_object_body_scale` is deprecated. " + "Please migrate to `randomize_rigid_object_scale` with `scale_factor_range`." + ) + return randomize_rigid_object_scale( + env=env, + env_ids=env_ids, + entity_cfg=entity_cfg, + scale_factor_range=scale_range, + same_scale_all_axes=same_scale_all_axes, + ) + + +def randomize_rigid_objects_body_scale_sync( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfgs: List[SceneEntityCfg], + scale_range: tuple[list[float], list[float]] | None = None, + same_scale_all_axes: bool = True, +) -> None: + """Deprecated. Use `randomize_rigid_objects_scale(shared_sample=True)` + `scale_factor_range`.""" + if scale_range is not None: + logger.log_warning( + "`randomize_rigid_objects_body_scale_sync` is deprecated. " + "Please migrate to `randomize_rigid_objects_scale` with `shared_sample=true` " + "and `scale_factor_range`." + ) + return randomize_rigid_objects_scale( + env=env, + env_ids=env_ids, + entity_cfgs=entity_cfgs, + scale_factor_range=scale_range, + same_scale_all_axes=same_scale_all_axes, + shared_sample=True, + ) From f7ae260571ca288cabc5cb66dafc1369314aaadd Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Thu, 25 Dec 2025 21:27:29 +0800 Subject: [PATCH 43/92] Feat: Add scale randomization API with shared_sample --- .../envs/managers/randomization/__init__.py | 2 + .../gym/envs/managers/randomization/scale.py | 182 ++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 embodichain/lab/gym/envs/managers/randomization/scale.py diff --git a/embodichain/lab/gym/envs/managers/randomization/__init__.py b/embodichain/lab/gym/envs/managers/randomization/__init__.py index 6483181f..ad24fe91 100644 --- a/embodichain/lab/gym/envs/managers/randomization/__init__.py +++ b/embodichain/lab/gym/envs/managers/randomization/__init__.py @@ -16,6 +16,8 @@ from .rendering import * from .spatial import * +from .scale import * + """ Randomization are all implemented as Event functors. diff --git a/embodichain/lab/gym/envs/managers/randomization/scale.py b/embodichain/lab/gym/envs/managers/randomization/scale.py new file mode 100644 index 00000000..5e9ee874 --- /dev/null +++ b/embodichain/lab/gym/envs/managers/randomization/scale.py @@ -0,0 +1,182 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +from __future__ import annotations + +from typing import TYPE_CHECKING, List, Union + +import torch + +from embodichain.lab.gym.envs.managers.cfg import SceneEntityCfg +from embodichain.lab.sim.objects import RigidObject +from embodichain.utils import logger +from embodichain.utils.math import sample_uniform + +if TYPE_CHECKING: + from embodichain.lab.gym.envs import EmbodiedEnv + + +def _normalize_env_ids( + env: EmbodiedEnv, env_ids: Union[torch.Tensor, None] +) -> torch.Tensor: + # Target all active environments if no specific IDs are provided + if env_ids is None: + return torch.arange(env.num_envs, device=env.device) + return env_ids + + +def _sample_body_scale( + env: EmbodiedEnv, + env_ids: torch.Tensor, + scale_factor_range: tuple[list[float], list[float]], + same_scale_all_axes: bool, +) -> torch.Tensor: + """Sample per-env body scale factors. + + Returns: + torch.Tensor: Shape (num_envs_selected, 3) scale factors for x/y/z. + """ + num_instance = len(env_ids) + if same_scale_all_axes: + low = torch.tensor(scale_factor_range[0][0], device=env.device) + high = torch.tensor(scale_factor_range[1][0], device=env.device) + s = sample_uniform(lower=low, upper=high, size=(num_instance,)) + return torch.stack([s, s, s], dim=1) + low = torch.tensor(scale_factor_range[0], device=env.device) + high = torch.tensor(scale_factor_range[1], device=env.device) + return sample_uniform(lower=low, upper=high, size=(num_instance, 3)) + + +def randomize_rigid_object_scale( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + scale_factor_range: tuple[list[float], list[float]] | None = None, + same_scale_all_axes: bool = True, +) -> None: + """Randomize a rigid object's *body scale factors* (multiplicative, not absolute size). + + Args: + env: Environment instance. + env_ids: Target env ids. If None, applies to all envs. + entity_cfg: Scene entity config of the rigid object. + scale_factor_range: If same_scale_all_axes is True, should be [[s_min], [s_max]]. + Otherwise [[sx_min, sy_min, sz_min], [sx_max, sy_max, sz_max]]. + same_scale_all_axes: Whether to use same factor on x/y/z. + """ + if scale_factor_range is None: + return + if entity_cfg.uid not in env.sim.get_rigid_object_uid_list(): + return + + env_ids = _normalize_env_ids(env, env_ids) + rigid_object: RigidObject = env.sim.get_rigid_object(entity_cfg.uid) + scale = _sample_body_scale(env, env_ids, scale_factor_range, same_scale_all_axes) + rigid_object.set_body_scale(scale, env_ids=env_ids) + + +def randomize_rigid_objects_scale( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfgs: List[SceneEntityCfg], + scale_factor_range: tuple[list[float], list[float]] | None = None, + same_scale_all_axes: bool = True, + shared_sample: bool = False, +) -> None: + """Randomize body scale factors for multiple rigid objects. + + Args: + env: Environment instance. + env_ids: Target env ids. If None, applies to all envs. + entity_cfgs: List of scene entity configs (rigid objects). + scale_factor_range: Scale factor sampling range. + same_scale_all_axes: Whether to use same factor on x/y/z. + shared_sample: If True, sample one scale per-env and apply to *all* objects (sync). + If False, each object samples its own scales independently. + """ + if scale_factor_range is None: + return + + if not isinstance(entity_cfgs, list) or len(entity_cfgs) == 0: + return + + env_ids = _normalize_env_ids(env, env_ids) + + if shared_sample: + scale = _sample_body_scale( + env, env_ids, scale_factor_range, same_scale_all_axes + ) + for entity_cfg in entity_cfgs: + if entity_cfg.uid not in env.sim.get_rigid_object_uid_list(): + continue + rigid_object: RigidObject = env.sim.get_rigid_object(entity_cfg.uid) + rigid_object.set_body_scale(scale, env_ids=env_ids) + return + + for entity_cfg in entity_cfgs: + randomize_rigid_object_scale( + env=env, + env_ids=env_ids, + entity_cfg=entity_cfg, + scale_factor_range=scale_factor_range, + same_scale_all_axes=same_scale_all_axes, + ) + + +def randomize_rigid_object_body_scale( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + scale_range: tuple[list[float], list[float]] | None = None, + same_scale_all_axes: bool = True, +) -> None: + """Deprecated. Use `randomize_rigid_object_scale` + `scale_factor_range`.""" + if scale_range is not None: + logger.log_warning( + "`randomize_rigid_object_body_scale` is deprecated. " + "Please migrate to `randomize_rigid_object_scale` with `scale_factor_range`." + ) + return randomize_rigid_object_scale( + env=env, + env_ids=env_ids, + entity_cfg=entity_cfg, + scale_factor_range=scale_range, + same_scale_all_axes=same_scale_all_axes, + ) + + +def randomize_rigid_objects_body_scale_sync( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfgs: List[SceneEntityCfg], + scale_range: tuple[list[float], list[float]] | None = None, + same_scale_all_axes: bool = True, +) -> None: + """Deprecated. Use `randomize_rigid_objects_scale(shared_sample=True)` + `scale_factor_range`.""" + if scale_range is not None: + logger.log_warning( + "`randomize_rigid_objects_body_scale_sync` is deprecated. " + "Please migrate to `randomize_rigid_objects_scale` with `shared_sample=true` " + "and `scale_factor_range`." + ) + return randomize_rigid_objects_scale( + env=env, + env_ids=env_ids, + entity_cfgs=entity_cfgs, + scale_factor_range=scale_range, + same_scale_all_axes=same_scale_all_axes, + shared_sample=True, + ) From f540bd050283cb3b5662ae3668684675c17ea218 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Thu, 25 Dec 2025 21:29:00 +0800 Subject: [PATCH 44/92] Feat: Add set_rigid_object_visual_material; migrate blocks_ranking configs --- .../envs/managers/randomization/rendering.py | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/embodichain/lab/gym/envs/managers/randomization/rendering.py b/embodichain/lab/gym/envs/managers/randomization/rendering.py index 535ebd66..ae315104 100644 --- a/embodichain/lab/gym/envs/managers/randomization/rendering.py +++ b/embodichain/lab/gym/envs/managers/randomization/rendering.py @@ -47,10 +47,53 @@ "randomize_camera_extrinsics", "randomize_light", "randomize_camera_intrinsics", + "set_rigid_object_visual_material", "randomize_visual_material", ] +def set_rigid_object_visual_material( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + base_color: list[float] | None = None, + metallic: float = 0.0, + roughness: float = 0.5, + uid: str | None = None, +) -> None: + """Set a rigid object's visual material (deterministic, non-random). + + This helper exists to support configs that want fixed colors/materials during reset. + + Args: + env: Environment instance. + env_ids: Target env ids. If None, applies to all envs. + entity_cfg: Scene entity config (must point to a rigid object). + base_color: RGBA list, e.g. [1.0, 0.0, 0.0, 1.0]. If None, keeps default base color. + metallic: PBR metallic factor. + roughness: PBR roughness factor. + uid: Visual material uid. If None, uses "{entity_uid}_mat". + """ + if entity_cfg.uid not in env.sim.get_rigid_object_uid_list(): + return + + if env_ids is None: + env_ids = torch.arange(env.num_envs, device="cpu") + else: + env_ids = env_ids.cpu() + + mat_uid = uid or f"{entity_cfg.uid}_mat" + cfg = VisualMaterialCfg( + uid=mat_uid, + base_color=base_color if base_color is not None else [0.5, 0.5, 0.5, 1.0], + metallic=metallic, + roughness=roughness, + ) + mat = env.sim.create_visual_material(cfg) + obj: RigidObject = env.sim.get_rigid_object(entity_cfg.uid) + obj.set_visual_material(mat, env_ids=env_ids) + + def randomize_camera_extrinsics( env: EmbodiedEnv, env_ids: Union[torch.Tensor, None], From 1dd594f563345c9f3b525392c5a7968f587f8274 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Thu, 25 Dec 2025 21:29:00 +0800 Subject: [PATCH 45/92] Feat: Add set_rigid_object_visual_material; migrate blocks_ranking configs --- .../envs/managers/randomization/rendering.py | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/embodichain/lab/gym/envs/managers/randomization/rendering.py b/embodichain/lab/gym/envs/managers/randomization/rendering.py index 535ebd66..ae315104 100644 --- a/embodichain/lab/gym/envs/managers/randomization/rendering.py +++ b/embodichain/lab/gym/envs/managers/randomization/rendering.py @@ -47,10 +47,53 @@ "randomize_camera_extrinsics", "randomize_light", "randomize_camera_intrinsics", + "set_rigid_object_visual_material", "randomize_visual_material", ] +def set_rigid_object_visual_material( + env: EmbodiedEnv, + env_ids: Union[torch.Tensor, None], + entity_cfg: SceneEntityCfg, + base_color: list[float] | None = None, + metallic: float = 0.0, + roughness: float = 0.5, + uid: str | None = None, +) -> None: + """Set a rigid object's visual material (deterministic, non-random). + + This helper exists to support configs that want fixed colors/materials during reset. + + Args: + env: Environment instance. + env_ids: Target env ids. If None, applies to all envs. + entity_cfg: Scene entity config (must point to a rigid object). + base_color: RGBA list, e.g. [1.0, 0.0, 0.0, 1.0]. If None, keeps default base color. + metallic: PBR metallic factor. + roughness: PBR roughness factor. + uid: Visual material uid. If None, uses "{entity_uid}_mat". + """ + if entity_cfg.uid not in env.sim.get_rigid_object_uid_list(): + return + + if env_ids is None: + env_ids = torch.arange(env.num_envs, device="cpu") + else: + env_ids = env_ids.cpu() + + mat_uid = uid or f"{entity_cfg.uid}_mat" + cfg = VisualMaterialCfg( + uid=mat_uid, + base_color=base_color if base_color is not None else [0.5, 0.5, 0.5, 1.0], + metallic=metallic, + roughness=roughness, + ) + mat = env.sim.create_visual_material(cfg) + obj: RigidObject = env.sim.get_rigid_object(entity_cfg.uid) + obj.set_visual_material(mat, env_ids=env_ids) + + def randomize_camera_extrinsics( env: EmbodiedEnv, env_ids: Union[torch.Tensor, None], From f2f2e7d2b34198a35fc578b386ef7b719cbab29e Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Thu, 25 Dec 2025 21:41:17 +0800 Subject: [PATCH 46/92] Add BlocksRankingRGB environment --- .../gym/blocks_ranking_rgb/gym_config.json | 480 ++++++++++++++++++ embodichain/lab/gym/envs/__init__.py | 3 + .../tasks/tableware/blocks_ranking_rgb.py | 88 ++++ 3 files changed, 571 insertions(+) create mode 100644 configs/gym/blocks_ranking_rgb/gym_config.json create mode 100644 embodichain/lab/gym/envs/tasks/tableware/blocks_ranking_rgb.py diff --git a/configs/gym/blocks_ranking_rgb/gym_config.json b/configs/gym/blocks_ranking_rgb/gym_config.json new file mode 100644 index 00000000..4a455b59 --- /dev/null +++ b/configs/gym/blocks_ranking_rgb/gym_config.json @@ -0,0 +1,480 @@ +{ + "id": "BlocksRankingRGB-v1", + "max_episodes": 5, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "init_block_1_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_1"}, + "position_range": [[0.445, -0.08, 0.86], [1.005, 0.05, 0.86]], + "rotation_range": [[0, 0, -43.0], [0, 0, 43.0]], + "relative_position": false + } + }, + "init_block_2_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_2"}, + "position_range": [[0.445, -0.08, 0.86], [1.005, 0.05, 0.86]], + "rotation_range": [[0, 0, -43.0], [0, 0, 43.0]], + "relative_position": false + } + }, + "init_block_3_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_3"}, + "position_range": [[0.445, -0.08, 0.86], [1.005, 0.05, 0.86]], + "rotation_range": [[0, 0, -43.0], [0, 0, 43.0]], + "relative_position": false + } + }, + "init_block_sizes": { + "func": "randomize_rigid_objects_scale", + "mode": "reset", + "params": { + "entity_cfgs": [ + {"uid": "block_1"}, + {"uid": "block_2"}, + {"uid": "block_3"} + ], + "scale_factor_range": [[0.75], [1.25]], + "same_scale_all_axes": true, + "shared_sample": true + } + }, + "set_block_1_color": { + "func": "set_rigid_object_visual_material", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_1"}, + "base_color": [1.0, 0.0, 0.0, 1.0], + "metallic": 0.0, + "roughness": 0.5, + "uid": "red_block_mat" + } + }, + "set_block_2_color": { + "func": "set_rigid_object_visual_material", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_2"}, + "base_color": [0.0, 1.0, 0.0, 1.0], + "metallic": 0.0, + "roughness": 0.5, + "uid": "green_block_mat" + } + }, + "set_block_3_color": { + "func": "set_rigid_object_visual_material", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_3"}, + "base_color": [0.0, 0.0, 1.0, 1.0], + "metallic": 0.0, + "roughness": 0.5, + "uid": "blue_block_mat" + } + }, + "prepare_extra_attr": { + "func": "prepare_extra_attr", + "mode": "reset", + "params": { + "attrs": [ + { + "name": "object_lengths", + "mode": "callable", + "entity_uids": "all_objects", + "func_name": "compute_object_length", + "func_kwargs": { + "is_svd_frame": true, + "sample_points": 5000 + } + }, + { + "name": "left_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "left_arm_base", + "to_matrix": true + } + }, + { + "name": "right_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "right_arm_base", + "to_matrix": true + } + } + ] + } + }, + "register_info_to_env": { + "func": "register_info_to_env", + "mode": "reset", + "params": { + "registry": [ + { + "entity_cfg": { + "uid": "block_1" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "block_2" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "block_3" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["left_arm"] + }, + "attrs": ["left_arm_base_pose"], + "pose_register_params": { + "compute_relative": "block_1", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["right_arm"] + }, + "attrs": ["right_arm_base_pose"], + "pose_register_params": { + "compute_relative": "block_2", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + } + ], + "registration": "affordance_datas", + "sim_update": true + } + }, + "random_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_robot_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 5, + "params": { + "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_camera_intrinsics": { + "func": "randomize_camera_intrinsics", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "focal_x_range": [-50, 50], + "focal_y_range": [-50, 50] + } + }, + "random_robot_init_eef_pose": { + "func": "randomize_robot_eef_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, + "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + } + }, + "observations": { + "norm_robot_eef_joint": { + "func": "normalize_robot_joint_data", + "mode": "modify", + "name": "robot/qpos", + "params": { + "joint_ids": [12, 13, 14, 15] + } + }, + "block_1_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_1_pose", + "params": { + "entity_cfg": {"uid": "block_1"} + } + }, + "block_2_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_2_pose", + "params": { + "entity_cfg": {"uid": "block_2"} + } + }, + "block_3_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_3_pose", + "params": { + "entity_cfg": {"uid": "block_3"} + } + }, + "cam_high_semantic_mask_l": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["block_1", "block_2", "block_3"] + } + }, + "cam_high_semantic_mask_r": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_r", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["block_1", "block_2", "block_3"], + "is_right": true + } + }, + "cam_left_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_left_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_left_wrist"}, + "foreground_uids": ["block_1", "block_2", "block_3"] + } + }, + "cam_right_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_right_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_right_wrist"}, + "foreground_uids": ["block_1", "block_2", "block_3"] + } + } + }, + "dataset": { + "robot_meta": { + "arm_dofs": 12, + "control_freq": 25, + "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], + "min_len_steps": 5 + } + } + }, + "robot": { + "uid": "CobotMagic", + "robot_type": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] + }, + "sensor": [ + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "width": 960, + "height": 540, + "enable_mask": true, + "enable_depth": true, + "left_to_right_pos": [0.059684025824163614, 0, 0], + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "extrinsics": { + "eye": [0.0, -0.5, 1.2], + "target": [0.75, 0.0, 0.85], + "up": [0.0, 0.0, 1.0] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "right_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "left_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + } + ], + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [2, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "CircleTableSimple/circle_table_simple.ply" + }, + "attrs" : { + "mass": 10.0, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.01 + }, + "body_scale": [1, 1, 1], + "body_type": "kinematic", + "init_pos": [0.725, 0.0, 0.825], + "init_rot": [0, 90, 0] + } + ], + "rigid_object": [ + { + "uid":"block_1", + "shape": { + "shape_type": "Cube", + "size": [0.04, 0.04, 0.04] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.725, -0.015, 0.86], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + }, + { + "uid":"block_2", + "shape": { + "shape_type": "Cube", + "size": [0.04, 0.04, 0.04] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.725, -0.015, 0.86], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + }, + { + "uid":"block_3", + "shape": { + "shape_type": "Cube", + "size": [0.04, 0.04, 0.04] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.725, -0.015, 0.86], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + } + ] +} + diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py index 48d9646d..a40761df 100644 --- a/embodichain/lab/gym/envs/__init__.py +++ b/embodichain/lab/gym/envs/__init__.py @@ -27,6 +27,9 @@ ) from embodichain.lab.gym.envs.tasks.tableware.scoop_ice import ScoopIce from embodichain.lab.gym.envs.tasks.tableware.stack_blocks_two import StackBlocksTwoEnv +from embodichain.lab.gym.envs.tasks.tableware.blocks_ranking_rgb import ( + BlocksRankingRGBEnv, +) # Reinforcement learning environments from embodichain.lab.gym.envs.tasks.rl.push_cube import PushCubeEnv diff --git a/embodichain/lab/gym/envs/tasks/tableware/blocks_ranking_rgb.py b/embodichain/lab/gym/envs/tasks/tableware/blocks_ranking_rgb.py new file mode 100644 index 00000000..fc7eb442 --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/blocks_ranking_rgb.py @@ -0,0 +1,88 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.utils import logger + +__all__ = ["BlocksRankingRGBEnv"] + + +@register_env("BlocksRankingRGB-v1", max_episode_steps=600) +class BlocksRankingRGBEnv(EmbodiedEnv): + def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): + super().__init__(cfg, **kwargs) + + action_config = kwargs.get("action_config", None) + if action_config is not None: + self.action_config = action_config + + def is_task_success(self, **kwargs) -> torch.Tensor: + """Determine if the task is successfully completed. + + The task is successful if: + 1. Three blocks are arranged in RGB order from left to right: + - Red block (block_1) x < Green block (block_2) x < Blue block (block_3) x + 2. All blocks are close together (within tolerance) + + Args: + **kwargs: Additional arguments for task-specific success criteria. + + Returns: + torch.Tensor: A boolean tensor indicating success for each environment in the batch. + """ + try: + block1 = self.sim.get_rigid_object("block_1") # Red + block2 = self.sim.get_rigid_object("block_2") # Green + block3 = self.sim.get_rigid_object("block_3") # Blue + except Exception as e: + logger.log_warning(f"Blocks not found: {e}, returning False.") + return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) + + # Get block poses + block1_pose = block1.get_local_pose(to_matrix=True) + block2_pose = block2.get_local_pose(to_matrix=True) + block3_pose = block3.get_local_pose(to_matrix=True) + + # Extract positions (x, y, z) + block1_pos = block1_pose[:, :3, 3] # (num_envs, 3) + block2_pos = block2_pose[:, :3, 3] + block3_pos = block3_pose[:, :3, 3] + + # Tolerance for checking if blocks are close together + eps = torch.tensor([0.13, 0.03], dtype=torch.float32, device=self.device) + + # Check if blocks are close together in x-y plane + # block1 and block2 should be close + block1_block2_diff = torch.abs(block1_pos[:, :2] - block2_pos[:, :2]) + blocks_close_12 = torch.all(block1_block2_diff < eps.unsqueeze(0), dim=1) + + # block2 and block3 should be close + block2_block3_diff = torch.abs(block2_pos[:, :2] - block3_pos[:, :2]) + blocks_close_23 = torch.all(block2_block3_diff < eps.unsqueeze(0), dim=1) + + # Check RGB order: block1 (red) x < block2 (green) x < block3 (blue) x + rgb_order = (block1_pos[:, 0] < block2_pos[:, 0]) & ( + block2_pos[:, 0] < block3_pos[:, 0] + ) + + # Task succeeds if blocks are close together and in RGB order + success = blocks_close_12 & blocks_close_23 & rgb_order + + return success From 0fddcbdd3ab17c7b2087f506ec9b4d08f6a3c7ef Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Thu, 25 Dec 2025 21:41:17 +0800 Subject: [PATCH 47/92] Add BlocksRankingRGB environment --- .../gym/blocks_ranking_rgb/gym_config.json | 480 ++++++++++++++++++ embodichain/lab/gym/envs/__init__.py | 3 + .../tasks/tableware/blocks_ranking_rgb.py | 88 ++++ 3 files changed, 571 insertions(+) create mode 100644 configs/gym/blocks_ranking_rgb/gym_config.json create mode 100644 embodichain/lab/gym/envs/tasks/tableware/blocks_ranking_rgb.py diff --git a/configs/gym/blocks_ranking_rgb/gym_config.json b/configs/gym/blocks_ranking_rgb/gym_config.json new file mode 100644 index 00000000..4a455b59 --- /dev/null +++ b/configs/gym/blocks_ranking_rgb/gym_config.json @@ -0,0 +1,480 @@ +{ + "id": "BlocksRankingRGB-v1", + "max_episodes": 5, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "init_block_1_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_1"}, + "position_range": [[0.445, -0.08, 0.86], [1.005, 0.05, 0.86]], + "rotation_range": [[0, 0, -43.0], [0, 0, 43.0]], + "relative_position": false + } + }, + "init_block_2_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_2"}, + "position_range": [[0.445, -0.08, 0.86], [1.005, 0.05, 0.86]], + "rotation_range": [[0, 0, -43.0], [0, 0, 43.0]], + "relative_position": false + } + }, + "init_block_3_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_3"}, + "position_range": [[0.445, -0.08, 0.86], [1.005, 0.05, 0.86]], + "rotation_range": [[0, 0, -43.0], [0, 0, 43.0]], + "relative_position": false + } + }, + "init_block_sizes": { + "func": "randomize_rigid_objects_scale", + "mode": "reset", + "params": { + "entity_cfgs": [ + {"uid": "block_1"}, + {"uid": "block_2"}, + {"uid": "block_3"} + ], + "scale_factor_range": [[0.75], [1.25]], + "same_scale_all_axes": true, + "shared_sample": true + } + }, + "set_block_1_color": { + "func": "set_rigid_object_visual_material", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_1"}, + "base_color": [1.0, 0.0, 0.0, 1.0], + "metallic": 0.0, + "roughness": 0.5, + "uid": "red_block_mat" + } + }, + "set_block_2_color": { + "func": "set_rigid_object_visual_material", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_2"}, + "base_color": [0.0, 1.0, 0.0, 1.0], + "metallic": 0.0, + "roughness": 0.5, + "uid": "green_block_mat" + } + }, + "set_block_3_color": { + "func": "set_rigid_object_visual_material", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_3"}, + "base_color": [0.0, 0.0, 1.0, 1.0], + "metallic": 0.0, + "roughness": 0.5, + "uid": "blue_block_mat" + } + }, + "prepare_extra_attr": { + "func": "prepare_extra_attr", + "mode": "reset", + "params": { + "attrs": [ + { + "name": "object_lengths", + "mode": "callable", + "entity_uids": "all_objects", + "func_name": "compute_object_length", + "func_kwargs": { + "is_svd_frame": true, + "sample_points": 5000 + } + }, + { + "name": "left_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "left_arm_base", + "to_matrix": true + } + }, + { + "name": "right_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "right_arm_base", + "to_matrix": true + } + } + ] + } + }, + "register_info_to_env": { + "func": "register_info_to_env", + "mode": "reset", + "params": { + "registry": [ + { + "entity_cfg": { + "uid": "block_1" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "block_2" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "block_3" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["left_arm"] + }, + "attrs": ["left_arm_base_pose"], + "pose_register_params": { + "compute_relative": "block_1", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["right_arm"] + }, + "attrs": ["right_arm_base_pose"], + "pose_register_params": { + "compute_relative": "block_2", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + } + ], + "registration": "affordance_datas", + "sim_update": true + } + }, + "random_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_robot_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 5, + "params": { + "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_camera_intrinsics": { + "func": "randomize_camera_intrinsics", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "focal_x_range": [-50, 50], + "focal_y_range": [-50, 50] + } + }, + "random_robot_init_eef_pose": { + "func": "randomize_robot_eef_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, + "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + } + }, + "observations": { + "norm_robot_eef_joint": { + "func": "normalize_robot_joint_data", + "mode": "modify", + "name": "robot/qpos", + "params": { + "joint_ids": [12, 13, 14, 15] + } + }, + "block_1_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_1_pose", + "params": { + "entity_cfg": {"uid": "block_1"} + } + }, + "block_2_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_2_pose", + "params": { + "entity_cfg": {"uid": "block_2"} + } + }, + "block_3_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_3_pose", + "params": { + "entity_cfg": {"uid": "block_3"} + } + }, + "cam_high_semantic_mask_l": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["block_1", "block_2", "block_3"] + } + }, + "cam_high_semantic_mask_r": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_r", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["block_1", "block_2", "block_3"], + "is_right": true + } + }, + "cam_left_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_left_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_left_wrist"}, + "foreground_uids": ["block_1", "block_2", "block_3"] + } + }, + "cam_right_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_right_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_right_wrist"}, + "foreground_uids": ["block_1", "block_2", "block_3"] + } + } + }, + "dataset": { + "robot_meta": { + "arm_dofs": 12, + "control_freq": 25, + "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], + "min_len_steps": 5 + } + } + }, + "robot": { + "uid": "CobotMagic", + "robot_type": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] + }, + "sensor": [ + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "width": 960, + "height": 540, + "enable_mask": true, + "enable_depth": true, + "left_to_right_pos": [0.059684025824163614, 0, 0], + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "extrinsics": { + "eye": [0.0, -0.5, 1.2], + "target": [0.75, 0.0, 0.85], + "up": [0.0, 0.0, 1.0] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "right_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "left_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + } + ], + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [2, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "CircleTableSimple/circle_table_simple.ply" + }, + "attrs" : { + "mass": 10.0, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.01 + }, + "body_scale": [1, 1, 1], + "body_type": "kinematic", + "init_pos": [0.725, 0.0, 0.825], + "init_rot": [0, 90, 0] + } + ], + "rigid_object": [ + { + "uid":"block_1", + "shape": { + "shape_type": "Cube", + "size": [0.04, 0.04, 0.04] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.725, -0.015, 0.86], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + }, + { + "uid":"block_2", + "shape": { + "shape_type": "Cube", + "size": [0.04, 0.04, 0.04] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.725, -0.015, 0.86], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + }, + { + "uid":"block_3", + "shape": { + "shape_type": "Cube", + "size": [0.04, 0.04, 0.04] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.725, -0.015, 0.86], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + } + ] +} + diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py index 48d9646d..a40761df 100644 --- a/embodichain/lab/gym/envs/__init__.py +++ b/embodichain/lab/gym/envs/__init__.py @@ -27,6 +27,9 @@ ) from embodichain.lab.gym.envs.tasks.tableware.scoop_ice import ScoopIce from embodichain.lab.gym.envs.tasks.tableware.stack_blocks_two import StackBlocksTwoEnv +from embodichain.lab.gym.envs.tasks.tableware.blocks_ranking_rgb import ( + BlocksRankingRGBEnv, +) # Reinforcement learning environments from embodichain.lab.gym.envs.tasks.rl.push_cube import PushCubeEnv diff --git a/embodichain/lab/gym/envs/tasks/tableware/blocks_ranking_rgb.py b/embodichain/lab/gym/envs/tasks/tableware/blocks_ranking_rgb.py new file mode 100644 index 00000000..fc7eb442 --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/blocks_ranking_rgb.py @@ -0,0 +1,88 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.utils import logger + +__all__ = ["BlocksRankingRGBEnv"] + + +@register_env("BlocksRankingRGB-v1", max_episode_steps=600) +class BlocksRankingRGBEnv(EmbodiedEnv): + def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): + super().__init__(cfg, **kwargs) + + action_config = kwargs.get("action_config", None) + if action_config is not None: + self.action_config = action_config + + def is_task_success(self, **kwargs) -> torch.Tensor: + """Determine if the task is successfully completed. + + The task is successful if: + 1. Three blocks are arranged in RGB order from left to right: + - Red block (block_1) x < Green block (block_2) x < Blue block (block_3) x + 2. All blocks are close together (within tolerance) + + Args: + **kwargs: Additional arguments for task-specific success criteria. + + Returns: + torch.Tensor: A boolean tensor indicating success for each environment in the batch. + """ + try: + block1 = self.sim.get_rigid_object("block_1") # Red + block2 = self.sim.get_rigid_object("block_2") # Green + block3 = self.sim.get_rigid_object("block_3") # Blue + except Exception as e: + logger.log_warning(f"Blocks not found: {e}, returning False.") + return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) + + # Get block poses + block1_pose = block1.get_local_pose(to_matrix=True) + block2_pose = block2.get_local_pose(to_matrix=True) + block3_pose = block3.get_local_pose(to_matrix=True) + + # Extract positions (x, y, z) + block1_pos = block1_pose[:, :3, 3] # (num_envs, 3) + block2_pos = block2_pose[:, :3, 3] + block3_pos = block3_pose[:, :3, 3] + + # Tolerance for checking if blocks are close together + eps = torch.tensor([0.13, 0.03], dtype=torch.float32, device=self.device) + + # Check if blocks are close together in x-y plane + # block1 and block2 should be close + block1_block2_diff = torch.abs(block1_pos[:, :2] - block2_pos[:, :2]) + blocks_close_12 = torch.all(block1_block2_diff < eps.unsqueeze(0), dim=1) + + # block2 and block3 should be close + block2_block3_diff = torch.abs(block2_pos[:, :2] - block3_pos[:, :2]) + blocks_close_23 = torch.all(block2_block3_diff < eps.unsqueeze(0), dim=1) + + # Check RGB order: block1 (red) x < block2 (green) x < block3 (blue) x + rgb_order = (block1_pos[:, 0] < block2_pos[:, 0]) & ( + block2_pos[:, 0] < block3_pos[:, 0] + ) + + # Task succeeds if blocks are close together and in RGB order + success = blocks_close_12 & blocks_close_23 & rgb_order + + return success From 23fc0827af7800ac976a4d13ed9a87c2d3b58f4e Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Thu, 25 Dec 2025 21:42:52 +0800 Subject: [PATCH 48/92] Fix: Support entity_cfgs in envent params --- embodichain/lab/gym/utils/gym_utils.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/embodichain/lab/gym/utils/gym_utils.py b/embodichain/lab/gym/utils/gym_utils.py index 0f92abb7..3eb5d6f7 100644 --- a/embodichain/lab/gym/utils/gym_utils.py +++ b/embodichain/lab/gym/utils/gym_utils.py @@ -474,6 +474,12 @@ class ComponentCfg: **event_params_modified["params"]["entity_cfg"] ) event_params_modified["params"]["entity_cfg"] = entity_cfg + if "entity_cfgs" in event_params["params"]: + entity_cfgs = [ + SceneEntityCfg(**cfg) + for cfg in event_params_modified["params"]["entity_cfgs"] + ] + event_params_modified["params"]["entity_cfgs"] = entity_cfgs # Find the function from multiple modules using the utility function event_func = find_function_from_modules( From 4ff06533d23e4ef878e90fae17030fef98ab8af6 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Thu, 25 Dec 2025 21:42:52 +0800 Subject: [PATCH 49/92] Fix: Support entity_cfgs in envent params --- embodichain/lab/gym/utils/gym_utils.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/embodichain/lab/gym/utils/gym_utils.py b/embodichain/lab/gym/utils/gym_utils.py index 0f92abb7..3eb5d6f7 100644 --- a/embodichain/lab/gym/utils/gym_utils.py +++ b/embodichain/lab/gym/utils/gym_utils.py @@ -474,6 +474,12 @@ class ComponentCfg: **event_params_modified["params"]["entity_cfg"] ) event_params_modified["params"]["entity_cfg"] = entity_cfg + if "entity_cfgs" in event_params["params"]: + entity_cfgs = [ + SceneEntityCfg(**cfg) + for cfg in event_params_modified["params"]["entity_cfgs"] + ] + event_params_modified["params"]["entity_cfgs"] = entity_cfgs # Find the function from multiple modules using the utility function event_func = find_function_from_modules( From 5d3115ec7e6826aa90346dc28a0405361eaf33e7 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Thu, 25 Dec 2025 21:59:08 +0800 Subject: [PATCH 50/92] Add BlocksRankingSize environment --- .../gym/blocks_ranking_size/gym_config.json | 460 ++++++++++++++++++ embodichain/lab/gym/envs/__init__.py | 3 + .../tasks/tableware/blocks_ranking_size.py | 89 ++++ 3 files changed, 552 insertions(+) create mode 100644 configs/gym/blocks_ranking_size/gym_config.json create mode 100644 embodichain/lab/gym/envs/tasks/tableware/blocks_ranking_size.py diff --git a/configs/gym/blocks_ranking_size/gym_config.json b/configs/gym/blocks_ranking_size/gym_config.json new file mode 100644 index 00000000..1eadb9d0 --- /dev/null +++ b/configs/gym/blocks_ranking_size/gym_config.json @@ -0,0 +1,460 @@ +{ + "id": "BlocksRankingSize-v1", + "max_episodes": 5, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "init_block_1_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_1"}, + "position_range": [[0.445, -0.08, 0.86], [1.005, 0.05, 0.86]], + "rotation_range": [[0, 0, -43.0], [0, 0, 43.0]], + "relative_position": false + } + }, + "init_block_2_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_2"}, + "position_range": [[0.445, -0.08, 0.86], [1.005, 0.05, 0.86]], + "rotation_range": [[0, 0, -43.0], [0, 0, 43.0]], + "relative_position": false + } + }, + "init_block_3_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_3"}, + "position_range": [[0.445, -0.08, 0.86], [1.005, 0.05, 0.86]], + "rotation_range": [[0, 0, -43.0], [0, 0, 43.0]], + "relative_position": false + } + }, + "init_block_1_size": { + "func": "randomize_rigid_object_scale", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_1"}, + "scale_factor_range": [[0.95238095], [1.04761905]], + "same_scale_all_axes": true + } + }, + "init_block_2_size": { + "func": "randomize_rigid_object_scale", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_2"}, + "scale_factor_range": [[0.94117647], [1.05882353]], + "same_scale_all_axes": true + } + }, + "init_block_3_size": { + "func": "randomize_rigid_object_scale", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_3"}, + "scale_factor_range": [[0.92307692], [1.07692308]], + "same_scale_all_axes": true + } + }, + "prepare_extra_attr": { + "func": "prepare_extra_attr", + "mode": "reset", + "params": { + "attrs": [ + { + "name": "object_lengths", + "mode": "callable", + "entity_uids": "all_objects", + "func_name": "compute_object_length", + "func_kwargs": { + "is_svd_frame": true, + "sample_points": 5000 + } + }, + { + "name": "left_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "left_arm_base", + "to_matrix": true + } + }, + { + "name": "right_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "right_arm_base", + "to_matrix": true + } + } + ] + } + }, + "register_info_to_env": { + "func": "register_info_to_env", + "mode": "reset", + "params": { + "registry": [ + { + "entity_cfg": { + "uid": "block_1" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "block_2" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "block_3" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["left_arm"] + }, + "attrs": ["left_arm_base_pose"], + "pose_register_params": { + "compute_relative": "block_1", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["right_arm"] + }, + "attrs": ["right_arm_base_pose"], + "pose_register_params": { + "compute_relative": "block_2", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + } + ], + "registration": "affordance_datas", + "sim_update": true + } + }, + "random_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_robot_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 5, + "params": { + "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_camera_intrinsics": { + "func": "randomize_camera_intrinsics", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "focal_x_range": [-50, 50], + "focal_y_range": [-50, 50] + } + }, + "random_robot_init_eef_pose": { + "func": "randomize_robot_eef_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, + "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + } + }, + "observations": { + "norm_robot_eef_joint": { + "func": "normalize_robot_joint_data", + "mode": "modify", + "name": "robot/qpos", + "params": { + "joint_ids": [12, 13, 14, 15] + } + }, + "block_1_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_1_pose", + "params": { + "entity_cfg": {"uid": "block_1"} + } + }, + "block_2_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_2_pose", + "params": { + "entity_cfg": {"uid": "block_2"} + } + }, + "block_3_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_3_pose", + "params": { + "entity_cfg": {"uid": "block_3"} + } + }, + "cam_high_semantic_mask_l": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["block_1", "block_2", "block_3"] + } + }, + "cam_high_semantic_mask_r": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_r", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["block_1", "block_2", "block_3"], + "is_right": true + } + }, + "cam_left_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_left_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_left_wrist"}, + "foreground_uids": ["block_1", "block_2", "block_3"] + } + }, + "cam_right_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_right_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_right_wrist"}, + "foreground_uids": ["block_1", "block_2", "block_3"] + } + } + }, + "dataset": { + "robot_meta": { + "arm_dofs": 12, + "control_freq": 25, + "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], + "min_len_steps": 5 + } + } + }, + "robot": { + "uid": "CobotMagic", + "robot_type": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] + }, + "sensor": [ + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "width": 960, + "height": 540, + "enable_mask": true, + "enable_depth": true, + "left_to_right_pos": [0.059684025824163614, 0, 0], + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "extrinsics": { + "eye": [0.0, -0.5, 1.2], + "target": [0.75, 0.0, 0.85], + "up": [0.0, 0.0, 1.0] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "right_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "left_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + } + ], + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [2, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "CircleTableSimple/circle_table_simple.ply" + }, + "attrs" : { + "mass": 10.0, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.01 + }, + "body_scale": [1, 1, 1], + "body_type": "kinematic", + "init_pos": [0.725, 0.0, 0.825], + "init_rot": [0, 90, 0] + } + ], + "rigid_object": [ + { + "uid":"block_1", + "shape": { + "shape_type": "Cube", + "size": [0.063, 0.063, 0.063] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.725, -0.015, 0.86], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + }, + { + "uid":"block_2", + "shape": { + "shape_type": "Cube", + "size": [0.051, 0.051, 0.051] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.725, -0.015, 0.86], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + }, + { + "uid":"block_3", + "shape": { + "shape_type": "Cube", + "size": [0.039, 0.039, 0.039] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.725, -0.015, 0.86], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + } + ] +} + diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py index a40761df..68fc6aa2 100644 --- a/embodichain/lab/gym/envs/__init__.py +++ b/embodichain/lab/gym/envs/__init__.py @@ -30,6 +30,9 @@ from embodichain.lab.gym.envs.tasks.tableware.blocks_ranking_rgb import ( BlocksRankingRGBEnv, ) +from embodichain.lab.gym.envs.tasks.tableware.blocks_ranking_size import ( + BlocksRankingSizeEnv, +) # Reinforcement learning environments from embodichain.lab.gym.envs.tasks.rl.push_cube import PushCubeEnv diff --git a/embodichain/lab/gym/envs/tasks/tableware/blocks_ranking_size.py b/embodichain/lab/gym/envs/tasks/tableware/blocks_ranking_size.py new file mode 100644 index 00000000..45b66997 --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/blocks_ranking_size.py @@ -0,0 +1,89 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.utils import logger + +__all__ = ["BlocksRankingSizeEnv"] + + +@register_env("BlocksRankingSize-v1", max_episode_steps=600) +class BlocksRankingSizeEnv(EmbodiedEnv): + def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): + super().__init__(cfg, **kwargs) + + action_config = kwargs.get("action_config", None) + if action_config is not None: + self.action_config = action_config + + def is_task_success(self, **kwargs) -> torch.Tensor: + """Determine if the task is successfully completed. + + The task is successful if: + 1. Three blocks are arranged in size order from left to right: + - Large block (block_1) x < Medium block (block_2) x < Small block (block_3) x + 2. All blocks are close together (within tolerance) + + Args: + **kwargs: Additional arguments for task-specific success criteria. + + Returns: + torch.Tensor: A boolean tensor indicating success for each environment in the batch. + """ + try: + block1 = self.sim.get_rigid_object("block_1") # Large + block2 = self.sim.get_rigid_object("block_2") # Medium + block3 = self.sim.get_rigid_object("block_3") # Small + except Exception as e: + logger.log_warning(f"Blocks not found: {e}, returning False.") + return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) + + # Get block poses + block1_pose = block1.get_local_pose(to_matrix=True) + block2_pose = block2.get_local_pose(to_matrix=True) + block3_pose = block3.get_local_pose(to_matrix=True) + + # Extract positions (x, y, z) + block1_pos = block1_pose[:, :3, 3] # (num_envs, 3) + block2_pos = block2_pose[:, :3, 3] + block3_pos = block3_pose[:, :3, 3] + + # Tolerance for checking if blocks are close together + # Same as RoboTwin: eps = [0.13, 0.03] + eps = torch.tensor([0.13, 0.03], dtype=torch.float32, device=self.device) + + # Check if blocks are close together in x-y plane + # block1 and block2 should be close + block1_block2_diff = torch.abs(block1_pos[:, :2] - block2_pos[:, :2]) + blocks_close_12 = torch.all(block1_block2_diff < eps.unsqueeze(0), dim=1) + + # block2 and block3 should be close + block2_block3_diff = torch.abs(block2_pos[:, :2] - block3_pos[:, :2]) + blocks_close_23 = torch.all(block2_block3_diff < eps.unsqueeze(0), dim=1) + + # Check size order: block1 (large) x < block2 (medium) x < block3 (small) x + size_order = (block1_pos[:, 0] < block2_pos[:, 0]) & ( + block2_pos[:, 0] < block3_pos[:, 0] + ) + + # All conditions must be satisfied + success = blocks_close_12 & blocks_close_23 & size_order + + return success From 27ffbc180d9e2da02c5b6a40de149d32fb1b5333 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Thu, 25 Dec 2025 21:59:08 +0800 Subject: [PATCH 51/92] Add BlocksRankingSize environment --- .../gym/blocks_ranking_size/gym_config.json | 460 ++++++++++++++++++ embodichain/lab/gym/envs/__init__.py | 3 + .../tasks/tableware/blocks_ranking_size.py | 89 ++++ 3 files changed, 552 insertions(+) create mode 100644 configs/gym/blocks_ranking_size/gym_config.json create mode 100644 embodichain/lab/gym/envs/tasks/tableware/blocks_ranking_size.py diff --git a/configs/gym/blocks_ranking_size/gym_config.json b/configs/gym/blocks_ranking_size/gym_config.json new file mode 100644 index 00000000..1eadb9d0 --- /dev/null +++ b/configs/gym/blocks_ranking_size/gym_config.json @@ -0,0 +1,460 @@ +{ + "id": "BlocksRankingSize-v1", + "max_episodes": 5, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "init_block_1_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_1"}, + "position_range": [[0.445, -0.08, 0.86], [1.005, 0.05, 0.86]], + "rotation_range": [[0, 0, -43.0], [0, 0, 43.0]], + "relative_position": false + } + }, + "init_block_2_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_2"}, + "position_range": [[0.445, -0.08, 0.86], [1.005, 0.05, 0.86]], + "rotation_range": [[0, 0, -43.0], [0, 0, 43.0]], + "relative_position": false + } + }, + "init_block_3_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_3"}, + "position_range": [[0.445, -0.08, 0.86], [1.005, 0.05, 0.86]], + "rotation_range": [[0, 0, -43.0], [0, 0, 43.0]], + "relative_position": false + } + }, + "init_block_1_size": { + "func": "randomize_rigid_object_scale", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_1"}, + "scale_factor_range": [[0.95238095], [1.04761905]], + "same_scale_all_axes": true + } + }, + "init_block_2_size": { + "func": "randomize_rigid_object_scale", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_2"}, + "scale_factor_range": [[0.94117647], [1.05882353]], + "same_scale_all_axes": true + } + }, + "init_block_3_size": { + "func": "randomize_rigid_object_scale", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_3"}, + "scale_factor_range": [[0.92307692], [1.07692308]], + "same_scale_all_axes": true + } + }, + "prepare_extra_attr": { + "func": "prepare_extra_attr", + "mode": "reset", + "params": { + "attrs": [ + { + "name": "object_lengths", + "mode": "callable", + "entity_uids": "all_objects", + "func_name": "compute_object_length", + "func_kwargs": { + "is_svd_frame": true, + "sample_points": 5000 + } + }, + { + "name": "left_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "left_arm_base", + "to_matrix": true + } + }, + { + "name": "right_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "right_arm_base", + "to_matrix": true + } + } + ] + } + }, + "register_info_to_env": { + "func": "register_info_to_env", + "mode": "reset", + "params": { + "registry": [ + { + "entity_cfg": { + "uid": "block_1" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "block_2" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "block_3" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["left_arm"] + }, + "attrs": ["left_arm_base_pose"], + "pose_register_params": { + "compute_relative": "block_1", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["right_arm"] + }, + "attrs": ["right_arm_base_pose"], + "pose_register_params": { + "compute_relative": "block_2", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + } + ], + "registration": "affordance_datas", + "sim_update": true + } + }, + "random_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_robot_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 5, + "params": { + "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_camera_intrinsics": { + "func": "randomize_camera_intrinsics", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "focal_x_range": [-50, 50], + "focal_y_range": [-50, 50] + } + }, + "random_robot_init_eef_pose": { + "func": "randomize_robot_eef_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, + "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + } + }, + "observations": { + "norm_robot_eef_joint": { + "func": "normalize_robot_joint_data", + "mode": "modify", + "name": "robot/qpos", + "params": { + "joint_ids": [12, 13, 14, 15] + } + }, + "block_1_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_1_pose", + "params": { + "entity_cfg": {"uid": "block_1"} + } + }, + "block_2_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_2_pose", + "params": { + "entity_cfg": {"uid": "block_2"} + } + }, + "block_3_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_3_pose", + "params": { + "entity_cfg": {"uid": "block_3"} + } + }, + "cam_high_semantic_mask_l": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["block_1", "block_2", "block_3"] + } + }, + "cam_high_semantic_mask_r": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_r", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["block_1", "block_2", "block_3"], + "is_right": true + } + }, + "cam_left_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_left_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_left_wrist"}, + "foreground_uids": ["block_1", "block_2", "block_3"] + } + }, + "cam_right_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_right_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_right_wrist"}, + "foreground_uids": ["block_1", "block_2", "block_3"] + } + } + }, + "dataset": { + "robot_meta": { + "arm_dofs": 12, + "control_freq": 25, + "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], + "min_len_steps": 5 + } + } + }, + "robot": { + "uid": "CobotMagic", + "robot_type": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] + }, + "sensor": [ + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "width": 960, + "height": 540, + "enable_mask": true, + "enable_depth": true, + "left_to_right_pos": [0.059684025824163614, 0, 0], + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "extrinsics": { + "eye": [0.0, -0.5, 1.2], + "target": [0.75, 0.0, 0.85], + "up": [0.0, 0.0, 1.0] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "right_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "left_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + } + ], + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [2, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "CircleTableSimple/circle_table_simple.ply" + }, + "attrs" : { + "mass": 10.0, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.01 + }, + "body_scale": [1, 1, 1], + "body_type": "kinematic", + "init_pos": [0.725, 0.0, 0.825], + "init_rot": [0, 90, 0] + } + ], + "rigid_object": [ + { + "uid":"block_1", + "shape": { + "shape_type": "Cube", + "size": [0.063, 0.063, 0.063] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.725, -0.015, 0.86], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + }, + { + "uid":"block_2", + "shape": { + "shape_type": "Cube", + "size": [0.051, 0.051, 0.051] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.725, -0.015, 0.86], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + }, + { + "uid":"block_3", + "shape": { + "shape_type": "Cube", + "size": [0.039, 0.039, 0.039] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.725, -0.015, 0.86], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + } + ] +} + diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py index a40761df..68fc6aa2 100644 --- a/embodichain/lab/gym/envs/__init__.py +++ b/embodichain/lab/gym/envs/__init__.py @@ -30,6 +30,9 @@ from embodichain.lab.gym.envs.tasks.tableware.blocks_ranking_rgb import ( BlocksRankingRGBEnv, ) +from embodichain.lab.gym.envs.tasks.tableware.blocks_ranking_size import ( + BlocksRankingSizeEnv, +) # Reinforcement learning environments from embodichain.lab.gym.envs.tasks.rl.push_cube import PushCubeEnv diff --git a/embodichain/lab/gym/envs/tasks/tableware/blocks_ranking_size.py b/embodichain/lab/gym/envs/tasks/tableware/blocks_ranking_size.py new file mode 100644 index 00000000..45b66997 --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/blocks_ranking_size.py @@ -0,0 +1,89 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.utils import logger + +__all__ = ["BlocksRankingSizeEnv"] + + +@register_env("BlocksRankingSize-v1", max_episode_steps=600) +class BlocksRankingSizeEnv(EmbodiedEnv): + def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): + super().__init__(cfg, **kwargs) + + action_config = kwargs.get("action_config", None) + if action_config is not None: + self.action_config = action_config + + def is_task_success(self, **kwargs) -> torch.Tensor: + """Determine if the task is successfully completed. + + The task is successful if: + 1. Three blocks are arranged in size order from left to right: + - Large block (block_1) x < Medium block (block_2) x < Small block (block_3) x + 2. All blocks are close together (within tolerance) + + Args: + **kwargs: Additional arguments for task-specific success criteria. + + Returns: + torch.Tensor: A boolean tensor indicating success for each environment in the batch. + """ + try: + block1 = self.sim.get_rigid_object("block_1") # Large + block2 = self.sim.get_rigid_object("block_2") # Medium + block3 = self.sim.get_rigid_object("block_3") # Small + except Exception as e: + logger.log_warning(f"Blocks not found: {e}, returning False.") + return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) + + # Get block poses + block1_pose = block1.get_local_pose(to_matrix=True) + block2_pose = block2.get_local_pose(to_matrix=True) + block3_pose = block3.get_local_pose(to_matrix=True) + + # Extract positions (x, y, z) + block1_pos = block1_pose[:, :3, 3] # (num_envs, 3) + block2_pos = block2_pose[:, :3, 3] + block3_pos = block3_pose[:, :3, 3] + + # Tolerance for checking if blocks are close together + # Same as RoboTwin: eps = [0.13, 0.03] + eps = torch.tensor([0.13, 0.03], dtype=torch.float32, device=self.device) + + # Check if blocks are close together in x-y plane + # block1 and block2 should be close + block1_block2_diff = torch.abs(block1_pos[:, :2] - block2_pos[:, :2]) + blocks_close_12 = torch.all(block1_block2_diff < eps.unsqueeze(0), dim=1) + + # block2 and block3 should be close + block2_block3_diff = torch.abs(block2_pos[:, :2] - block3_pos[:, :2]) + blocks_close_23 = torch.all(block2_block3_diff < eps.unsqueeze(0), dim=1) + + # Check size order: block1 (large) x < block2 (medium) x < block3 (small) x + size_order = (block1_pos[:, 0] < block2_pos[:, 0]) & ( + block2_pos[:, 0] < block3_pos[:, 0] + ) + + # All conditions must be satisfied + success = blocks_close_12 & blocks_close_23 & size_order + + return success From e1f002bfd3365f50505073f7b9b634e83402c590 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Fri, 26 Dec 2025 13:41:31 +0800 Subject: [PATCH 52/92] Add PlaceObjectDrawer environment --- .../gym/place_object_drawer/gym_config.json | 320 ++++++++++++++++++ embodichain/lab/gym/envs/__init__.py | 3 + .../tasks/tableware/place_object_drawer.py | 83 +++++ 3 files changed, 406 insertions(+) create mode 100644 configs/gym/place_object_drawer/gym_config.json create mode 100644 embodichain/lab/gym/envs/tasks/tableware/place_object_drawer.py diff --git a/configs/gym/place_object_drawer/gym_config.json b/configs/gym/place_object_drawer/gym_config.json new file mode 100644 index 00000000..eb98c176 --- /dev/null +++ b/configs/gym/place_object_drawer/gym_config.json @@ -0,0 +1,320 @@ +{ + "id": "PlaceObjectDrawer-v1", + "max_episodes": 5, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "init_object_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "object"}, + "position_range": [[0.66, -0.15, 0.86], [0.70, -0.10, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "prepare_extra_attr": { + "func": "prepare_extra_attr", + "mode": "reset", + "params": { + "attrs": [ + { + "name": "object_lengths", + "mode": "callable", + "entity_uids": ["object"], + "func_name": "compute_object_length", + "func_kwargs": { + "is_svd_frame": true, + "sample_points": 5000 + } + }, + { + "name": "left_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "left_arm_base", + "to_matrix": true + } + }, + { + "name": "right_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "right_arm_base", + "to_matrix": true + } + } + ] + } + }, + "register_info_to_env": { + "func": "register_info_to_env", + "mode": "reset", + "params": { + "registry": [ + { + "entity_cfg": { + "uid": "object" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + } + ] + } + }, + "random_table_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_robot_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 5, + "params": { + "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_camera_intrinsics": { + "func": "randomize_camera_intrinsics", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "focal_x_range": [-50, 50], + "focal_y_range": [-50, 50] + } + }, + "random_robot_init_eef_pose": { + "func": "randomize_robot_eef_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, + "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + } + }, + "observations": { + "norm_robot_eef_joint": { + "func": "normalize_robot_joint_data", + "mode": "modify", + "name": "robot/qpos", + "params": { + "joint_ids": [12, 13, 14, 15] + } + }, + "object_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "object_pose", + "params": { + "entity_cfg": {"uid": "object"} + } + }, + "cam_high_semantic_mask_l": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["object", "drawer"] + } + }, + "cam_high_semantic_mask_r": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_r", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["object", "drawer"], + "is_right": true + } + }, + "cam_left_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_left_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_left_wrist"}, + "foreground_uids": ["object", "drawer"] + } + }, + "cam_right_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_right_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_right_wrist"}, + "foreground_uids": ["object", "drawer"] + } + } + }, + "dataset": { + "robot_meta": { + "arm_dofs": 12, + "control_freq": 25, + "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], + "min_len_steps": 5 + } + } + }, + "robot": { + "uid": "CobotMagic", + "robot_type": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] + }, + "sensor": [ + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "width": 960, + "height": 540, + "enable_mask": true, + "enable_depth": true, + "left_to_right_pos": [0.059684025824163614, 0, 0], + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "extrinsics": { + "eye": [0.35368482807598, 0.014695524383058989, 1.4517046071614774], + "target": [0.7186357573287919, -0.054534732904795505, 0.5232553674540066], + "up": [0.9306678549330372, -0.0005600064212467153, 0.3658647703553347] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "right_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "left_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + } + ], + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [2, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "CircleTableSimple/circle_table_simple.ply" + }, + "attrs" : { + "mass": 10.0, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.01 + }, + "body_scale": [1, 1, 1], + "body_type": "kinematic", + "init_pos": [0.725, 0.0, 0.825], + "init_rot": [0, 90, 0] + } + ], + "rigid_object": [ + { + "uid":"object", + "shape": { + "shape_type": "Mesh", + "fpath": "ToyDuck/toy_duck.glb" + }, + "attrs" : { + "mass": 0.01, + "static_friction": 1.0, + "dynamic_friction": 1.0, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 2.0, + "linear_damping": 2.0, + "angular_damping": 2.0, + "max_linear_velocity": 5.0, + "max_angular_velocity": 10.0, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.725, -0.1, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[0.2, 0.2, 0.2], + "max_convex_hull_num": 8 + } + ], + "articulation": [ + { + "uid": "drawer", + "fpath": "SimpleBoxDrawer/simple_box_drawer/simple_box_drawer.urdf", + "init_pos": [0.725, 0.16, 1.025], + "init_rot": [0, 180, 0] + } + ] +} + diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py index 68fc6aa2..71852b56 100644 --- a/embodichain/lab/gym/envs/__init__.py +++ b/embodichain/lab/gym/envs/__init__.py @@ -33,6 +33,9 @@ from embodichain.lab.gym.envs.tasks.tableware.blocks_ranking_size import ( BlocksRankingSizeEnv, ) +from embodichain.lab.gym.envs.tasks.tableware.place_object_drawer import ( + PlaceObjectDrawerEnv, +) # Reinforcement learning environments from embodichain.lab.gym.envs.tasks.rl.push_cube import PushCubeEnv diff --git a/embodichain/lab/gym/envs/tasks/tableware/place_object_drawer.py b/embodichain/lab/gym/envs/tasks/tableware/place_object_drawer.py new file mode 100644 index 00000000..f83a4b70 --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/place_object_drawer.py @@ -0,0 +1,83 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + + +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.utils import logger + +__all__ = ["PlaceObjectDrawerEnv"] + + +@register_env("PlaceObjectDrawer-v1", max_episode_steps=600) +class PlaceObjectDrawerEnv(EmbodiedEnv): + def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): + super().__init__(cfg, **kwargs) + + action_config = kwargs.get("action_config", None) + if action_config is not None: + self.action_config = action_config + + def is_task_success(self, **kwargs) -> torch.Tensor: + """Determine if the task is successfully completed. + + The task is successful if: + 1. Object is within drawer inner_box area + 2. Drawer has been closed + + Args: + **kwargs: Additional arguments for task-specific success criteria. + + Returns: + torch.Tensor: A boolean tensor indicating success for each environment in the batch. + """ + try: + object_obj = self.sim.get_rigid_object("object") + drawer = self.sim.get_articulation("drawer") + except Exception as e: + logger.log_warning(f"Object or drawer not found: {e}, returning False.") + return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) + + # Get poses + object_pose = object_obj.get_local_pose(to_matrix=True) + # Get drawer inner_box (drawer interior) pose, not outer_box + inner_box_pose = drawer.get_link_pose("inner_box", to_matrix=True) + + # Extract positions + object_pos = object_pose[:, :3, 3] # (num_envs, 3) + inner_box_pos = inner_box_pose[:, :3, 3] # (num_envs, 3) + + # Get drawer joint position + drawer_qpos = drawer.get_qpos() # (num_envs, num_joints) + drawer_joint_pos = drawer_qpos[:, 0] + + # Check if drawer has been closed + drawer_closed = drawer_joint_pos < 0.05 + + # Check if object is within drawer inner_box area + xy_diff = torch.abs(object_pos[:, :2] - inner_box_pos[:, :2]) # (num_envs, 2) + xy_tolerance = torch.tensor( + [0.03, 0.03], dtype=torch.float32, device=self.device + ) + object_in_drawer_xy = torch.all(xy_diff < xy_tolerance.unsqueeze(0), dim=1) + + # Object must be in drawer and drawer must be closed + success = drawer_closed & object_in_drawer_xy + + return success From d91b5316175e239a569b1949dfb494ac8e2ab97f Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Fri, 26 Dec 2025 13:41:31 +0800 Subject: [PATCH 53/92] Add PlaceObjectDrawer environment --- .../gym/place_object_drawer/gym_config.json | 320 ++++++++++++++++++ embodichain/lab/gym/envs/__init__.py | 3 + .../tasks/tableware/place_object_drawer.py | 83 +++++ 3 files changed, 406 insertions(+) create mode 100644 configs/gym/place_object_drawer/gym_config.json create mode 100644 embodichain/lab/gym/envs/tasks/tableware/place_object_drawer.py diff --git a/configs/gym/place_object_drawer/gym_config.json b/configs/gym/place_object_drawer/gym_config.json new file mode 100644 index 00000000..eb98c176 --- /dev/null +++ b/configs/gym/place_object_drawer/gym_config.json @@ -0,0 +1,320 @@ +{ + "id": "PlaceObjectDrawer-v1", + "max_episodes": 5, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "init_object_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "object"}, + "position_range": [[0.66, -0.15, 0.86], [0.70, -0.10, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "prepare_extra_attr": { + "func": "prepare_extra_attr", + "mode": "reset", + "params": { + "attrs": [ + { + "name": "object_lengths", + "mode": "callable", + "entity_uids": ["object"], + "func_name": "compute_object_length", + "func_kwargs": { + "is_svd_frame": true, + "sample_points": 5000 + } + }, + { + "name": "left_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "left_arm_base", + "to_matrix": true + } + }, + { + "name": "right_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "right_arm_base", + "to_matrix": true + } + } + ] + } + }, + "register_info_to_env": { + "func": "register_info_to_env", + "mode": "reset", + "params": { + "registry": [ + { + "entity_cfg": { + "uid": "object" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + } + ] + } + }, + "random_table_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_robot_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 5, + "params": { + "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_camera_intrinsics": { + "func": "randomize_camera_intrinsics", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "focal_x_range": [-50, 50], + "focal_y_range": [-50, 50] + } + }, + "random_robot_init_eef_pose": { + "func": "randomize_robot_eef_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, + "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + } + }, + "observations": { + "norm_robot_eef_joint": { + "func": "normalize_robot_joint_data", + "mode": "modify", + "name": "robot/qpos", + "params": { + "joint_ids": [12, 13, 14, 15] + } + }, + "object_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "object_pose", + "params": { + "entity_cfg": {"uid": "object"} + } + }, + "cam_high_semantic_mask_l": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["object", "drawer"] + } + }, + "cam_high_semantic_mask_r": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_r", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["object", "drawer"], + "is_right": true + } + }, + "cam_left_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_left_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_left_wrist"}, + "foreground_uids": ["object", "drawer"] + } + }, + "cam_right_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_right_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_right_wrist"}, + "foreground_uids": ["object", "drawer"] + } + } + }, + "dataset": { + "robot_meta": { + "arm_dofs": 12, + "control_freq": 25, + "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], + "min_len_steps": 5 + } + } + }, + "robot": { + "uid": "CobotMagic", + "robot_type": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] + }, + "sensor": [ + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "width": 960, + "height": 540, + "enable_mask": true, + "enable_depth": true, + "left_to_right_pos": [0.059684025824163614, 0, 0], + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "extrinsics": { + "eye": [0.35368482807598, 0.014695524383058989, 1.4517046071614774], + "target": [0.7186357573287919, -0.054534732904795505, 0.5232553674540066], + "up": [0.9306678549330372, -0.0005600064212467153, 0.3658647703553347] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "right_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "left_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + } + ], + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [2, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "CircleTableSimple/circle_table_simple.ply" + }, + "attrs" : { + "mass": 10.0, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.01 + }, + "body_scale": [1, 1, 1], + "body_type": "kinematic", + "init_pos": [0.725, 0.0, 0.825], + "init_rot": [0, 90, 0] + } + ], + "rigid_object": [ + { + "uid":"object", + "shape": { + "shape_type": "Mesh", + "fpath": "ToyDuck/toy_duck.glb" + }, + "attrs" : { + "mass": 0.01, + "static_friction": 1.0, + "dynamic_friction": 1.0, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 2.0, + "linear_damping": 2.0, + "angular_damping": 2.0, + "max_linear_velocity": 5.0, + "max_angular_velocity": 10.0, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.725, -0.1, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[0.2, 0.2, 0.2], + "max_convex_hull_num": 8 + } + ], + "articulation": [ + { + "uid": "drawer", + "fpath": "SimpleBoxDrawer/simple_box_drawer/simple_box_drawer.urdf", + "init_pos": [0.725, 0.16, 1.025], + "init_rot": [0, 180, 0] + } + ] +} + diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py index 68fc6aa2..71852b56 100644 --- a/embodichain/lab/gym/envs/__init__.py +++ b/embodichain/lab/gym/envs/__init__.py @@ -33,6 +33,9 @@ from embodichain.lab.gym.envs.tasks.tableware.blocks_ranking_size import ( BlocksRankingSizeEnv, ) +from embodichain.lab.gym.envs.tasks.tableware.place_object_drawer import ( + PlaceObjectDrawerEnv, +) # Reinforcement learning environments from embodichain.lab.gym.envs.tasks.rl.push_cube import PushCubeEnv diff --git a/embodichain/lab/gym/envs/tasks/tableware/place_object_drawer.py b/embodichain/lab/gym/envs/tasks/tableware/place_object_drawer.py new file mode 100644 index 00000000..f83a4b70 --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/place_object_drawer.py @@ -0,0 +1,83 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + + +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.utils import logger + +__all__ = ["PlaceObjectDrawerEnv"] + + +@register_env("PlaceObjectDrawer-v1", max_episode_steps=600) +class PlaceObjectDrawerEnv(EmbodiedEnv): + def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): + super().__init__(cfg, **kwargs) + + action_config = kwargs.get("action_config", None) + if action_config is not None: + self.action_config = action_config + + def is_task_success(self, **kwargs) -> torch.Tensor: + """Determine if the task is successfully completed. + + The task is successful if: + 1. Object is within drawer inner_box area + 2. Drawer has been closed + + Args: + **kwargs: Additional arguments for task-specific success criteria. + + Returns: + torch.Tensor: A boolean tensor indicating success for each environment in the batch. + """ + try: + object_obj = self.sim.get_rigid_object("object") + drawer = self.sim.get_articulation("drawer") + except Exception as e: + logger.log_warning(f"Object or drawer not found: {e}, returning False.") + return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) + + # Get poses + object_pose = object_obj.get_local_pose(to_matrix=True) + # Get drawer inner_box (drawer interior) pose, not outer_box + inner_box_pose = drawer.get_link_pose("inner_box", to_matrix=True) + + # Extract positions + object_pos = object_pose[:, :3, 3] # (num_envs, 3) + inner_box_pos = inner_box_pose[:, :3, 3] # (num_envs, 3) + + # Get drawer joint position + drawer_qpos = drawer.get_qpos() # (num_envs, num_joints) + drawer_joint_pos = drawer_qpos[:, 0] + + # Check if drawer has been closed + drawer_closed = drawer_joint_pos < 0.05 + + # Check if object is within drawer inner_box area + xy_diff = torch.abs(object_pos[:, :2] - inner_box_pos[:, :2]) # (num_envs, 2) + xy_tolerance = torch.tensor( + [0.03, 0.03], dtype=torch.float32, device=self.device + ) + object_in_drawer_xy = torch.all(xy_diff < xy_tolerance.unsqueeze(0), dim=1) + + # Object must be in drawer and drawer must be closed + success = drawer_closed & object_in_drawer_xy + + return success From a8f084f5b146db5b566d7ca8994c3726975cf047 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Fri, 26 Dec 2025 14:06:30 +0800 Subject: [PATCH 54/92] Align PlaceObjectDrawer's config with PourWater --- .../gym/place_object_drawer/gym_config.json | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/configs/gym/place_object_drawer/gym_config.json b/configs/gym/place_object_drawer/gym_config.json index eb98c176..02811af4 100644 --- a/configs/gym/place_object_drawer/gym_config.json +++ b/configs/gym/place_object_drawer/gym_config.json @@ -80,8 +80,36 @@ "compute_pose_object_to_arena": true, "to_matrix": true } + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["left_arm"] + }, + "attrs": ["left_arm_base_pose"], + "pose_register_params": { + "compute_relative": "object", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["right_arm"] + }, + "attrs": ["right_arm_base_pose"], + "pose_register_params": { + "compute_relative": "object", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false } - ] + ], + "registration": "affordance_datas", + "sim_update": true } }, "random_table_material": { From afae5a5ee1a478a32d8e518b10ec0586c11857c2 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Fri, 26 Dec 2025 14:06:30 +0800 Subject: [PATCH 55/92] Align PlaceObjectDrawer's config with PourWater --- .../gym/place_object_drawer/gym_config.json | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/configs/gym/place_object_drawer/gym_config.json b/configs/gym/place_object_drawer/gym_config.json index eb98c176..02811af4 100644 --- a/configs/gym/place_object_drawer/gym_config.json +++ b/configs/gym/place_object_drawer/gym_config.json @@ -80,8 +80,36 @@ "compute_pose_object_to_arena": true, "to_matrix": true } + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["left_arm"] + }, + "attrs": ["left_arm_base_pose"], + "pose_register_params": { + "compute_relative": "object", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["right_arm"] + }, + "attrs": ["right_arm_base_pose"], + "pose_register_params": { + "compute_relative": "object", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false } - ] + ], + "registration": "affordance_datas", + "sim_update": true } }, "random_table_material": { From 77189ca7b01340e8c54a9473e9fbe58d894ffbe8 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Fri, 26 Dec 2025 14:12:21 +0800 Subject: [PATCH 56/92] Add OrganizeTableware environment --- .../gym/organize_tableware/gym_config.json | 394 ++++++++++++++++++ embodichain/lab/gym/envs/__init__.py | 3 + .../tasks/tableware/organize_tableware.py | 98 +++++ 3 files changed, 495 insertions(+) create mode 100644 configs/gym/organize_tableware/gym_config.json create mode 100644 embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py diff --git a/configs/gym/organize_tableware/gym_config.json b/configs/gym/organize_tableware/gym_config.json new file mode 100644 index 00000000..d372f0f9 --- /dev/null +++ b/configs/gym/organize_tableware/gym_config.json @@ -0,0 +1,394 @@ +{ + "id": "OrganizeTableware-v1", + "max_episodes": 5, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "init_fork_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "fork"}, + "position_range": [[0.66, -0.15, 0.86], [0.74, -0.05, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "init_spoon_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "spoon"}, + "position_range": [[0.76, -0.15, 0.86], [0.84, -0.05, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "prepare_extra_attr": { + "func": "prepare_extra_attr", + "mode": "reset", + "params": { + "attrs": [ + { + "name": "object_lengths", + "mode": "callable", + "entity_uids": "all_objects", + "func_name": "compute_object_length", + "func_kwargs": { + "is_svd_frame": true, + "sample_points": 5000 + } + }, + { + "name": "left_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "left_arm_base", + "to_matrix": true + } + }, + { + "name": "right_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "right_arm_base", + "to_matrix": true + } + } + ] + } + }, + "register_info_to_env": { + "func": "register_info_to_env", + "mode": "reset", + "params": { + "registry": [ + { + "entity_cfg": { + "uid": "fork" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "spoon" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["left_arm"] + }, + "attrs": ["left_arm_base_pose"], + "pose_register_params": { + "compute_relative": "spoon", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["right_arm"] + }, + "attrs": ["right_arm_base_pose"], + "pose_register_params": { + "compute_relative": "fork", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + } + ], + "registration": "affordance_datas", + "sim_update": true + } + }, + "random_table_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_robot_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 5, + "params": { + "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_camera_intrinsics": { + "func": "randomize_camera_intrinsics", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "focal_x_range": [-50, 50], + "focal_y_range": [-50, 50] + } + }, + "random_robot_init_eef_pose": { + "func": "randomize_robot_eef_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, + "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + } + }, + "observations": { + "norm_robot_eef_joint": { + "func": "normalize_robot_joint_data", + "mode": "modify", + "name": "robot/qpos", + "params": { + "joint_ids": [12, 13, 14, 15] + } + }, + "fork_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "fork_pose", + "params": { + "entity_cfg": {"uid": "fork"} + } + }, + "spoon_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "spoon_pose", + "params": { + "entity_cfg": {"uid": "spoon"} + } + }, + "cam_high_semantic_mask_l": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["fork", "spoon"] + } + }, + "cam_high_semantic_mask_r": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_r", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["fork", "spoon"], + "is_right": true + } + }, + "cam_left_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_left_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_left_wrist"}, + "foreground_uids": ["fork", "spoon"] + } + }, + "cam_right_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_right_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_right_wrist"}, + "foreground_uids": ["fork", "spoon"] + } + } + }, + "dataset": { + "robot_meta": { + "arm_dofs": 12, + "control_freq": 25, + "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], + "min_len_steps": 5 + } + } + }, + "robot": { + "uid": "CobotMagic", + "robot_type": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] + }, + "sensor": [ + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "width": 960, + "height": 540, + "enable_mask": true, + "enable_depth": true, + "left_to_right_pos": [0.059684025824163614, 0, 0], + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "extrinsics": { + "eye": [0.35368482807598, 0.014695524383058989, 1.4517046071614774], + "target": [0.7186357573287919, -0.054534732904795505, 0.5232553674540066], + "up": [0.9306678549330372, -0.0005600064212467153, 0.3658647703553347] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "right_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "left_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + } + ], + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [2, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "CircleTableSimple/circle_table_simple.ply" + }, + "attrs" : { + "mass": 10.0, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.01 + }, + "body_scale": [1, 1, 1], + "body_type": "kinematic", + "init_pos": [0.725, 0.0, 0.825], + "init_rot": [0, 90, 0] + } + ], + "rigid_object": [ + { + "uid":"fork", + "shape": { + "shape_type": "Mesh", + "fpath": "TableWare/tableware/fork/standard_fork_scale.ply" + }, + "attrs" : { + "mass": 0.01, + "static_friction": 1.0, + "dynamic_friction": 1.0, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 2.0, + "linear_damping": 2.0, + "angular_damping": 2.0, + "max_linear_velocity": 5.0, + "max_angular_velocity": 10.0, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.70, -0.1, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[0.75, 0.75, 1.0], + "max_convex_hull_num": 8 + }, + { + "uid":"spoon", + "shape": { + "shape_type": "Mesh", + "fpath": "TableWare/tableware/spoon/standard_spoon_a_rescale.ply" + }, + "attrs" : { + "mass": 0.01, + "static_friction": 1.0, + "dynamic_friction": 1.0, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 2.0, + "linear_damping": 2.0, + "angular_damping": 2.0, + "max_linear_velocity": 5.0, + "max_angular_velocity": 10.0, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.80, -0.1, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[0.75, 0.75, 1.0], + "max_convex_hull_num": 8 + } + ] +} + diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py index 71852b56..533d9295 100644 --- a/embodichain/lab/gym/envs/__init__.py +++ b/embodichain/lab/gym/envs/__init__.py @@ -36,6 +36,9 @@ from embodichain.lab.gym.envs.tasks.tableware.place_object_drawer import ( PlaceObjectDrawerEnv, ) +from embodichain.lab.gym.envs.tasks.tableware.organize_tableware import ( + OrganizeTablewareEnv, +) # Reinforcement learning environments from embodichain.lab.gym.envs.tasks.rl.push_cube import PushCubeEnv diff --git a/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py b/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py new file mode 100644 index 00000000..b42d905f --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py @@ -0,0 +1,98 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.utils import logger + +__all__ = ["OrganizeTablewareEnv"] + + +@register_env("OrganizeTableware-v1", max_episode_steps=600) +class OrganizeTablewareEnv(EmbodiedEnv): + def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): + super().__init__(cfg, **kwargs) + + action_config = kwargs.get("action_config", None) + if action_config is not None: + self.action_config = action_config + + # Define target positions for different tableware types + # Left side: fork, Right side: spoon + self.fork_target_pos = torch.tensor( + [0.65, -0.1, 0.86], dtype=torch.float32, device=self.device + ) + self.spoon_target_pos = torch.tensor( + [0.85, -0.1, 0.86], dtype=torch.float32, device=self.device + ) + + def is_task_success(self, **kwargs) -> torch.Tensor: + """Determine if the task is successfully completed. + + The task is successful if: + 1. Fork is placed in the left target area + 2. Spoon is placed in the right target area + + Args: + **kwargs: Additional arguments for task-specific success criteria. + + Returns: + torch.Tensor: A boolean tensor indicating success for each environment in the batch. + """ + try: + fork = self.sim.get_rigid_object("fork") + spoon = self.sim.get_rigid_object("spoon") + except Exception as e: + logger.log_warning(f"Fork or spoon not found: {e}, returning False.") + return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) + + # Get poses + fork_pose = fork.get_local_pose(to_matrix=True) + spoon_pose = spoon.get_local_pose(to_matrix=True) + + # Extract positions + fork_pos = fork_pose[:, :3, 3] # (num_envs, 3) + spoon_pos = spoon_pose[:, :3, 3] # (num_envs, 3) + + # Tolerance for checking if objects are in target area + xy_tolerance = torch.tensor( + [0.08, 0.05], dtype=torch.float32, device=self.device + ) + z_tolerance = 0.05 + + # Check if fork is in left target area + fork_target = self.fork_target_pos.unsqueeze(0).repeat(self.num_envs, 1) + fork_xy_diff = torch.abs(fork_pos[:, :2] - fork_target[:, :2]) + fork_z_diff = torch.abs(fork_pos[:, 2] - fork_target[:, 2]) + fork_in_target = torch.all(fork_xy_diff < xy_tolerance.unsqueeze(0), dim=1) & ( + fork_z_diff < z_tolerance + ) + + # Check if spoon is in right target area + spoon_target = self.spoon_target_pos.unsqueeze(0).repeat(self.num_envs, 1) + spoon_xy_diff = torch.abs(spoon_pos[:, :2] - spoon_target[:, :2]) + spoon_z_diff = torch.abs(spoon_pos[:, 2] - spoon_target[:, 2]) + spoon_in_target = torch.all( + spoon_xy_diff < xy_tolerance.unsqueeze(0), dim=1 + ) & (spoon_z_diff < z_tolerance) + + # Both must be in their target areas + success = fork_in_target & spoon_in_target + + return success From 5b975314e906b1b9bd346d879c42df5f13d46da8 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Fri, 26 Dec 2025 14:12:21 +0800 Subject: [PATCH 57/92] Add OrganizeTableware environment --- .../gym/organize_tableware/gym_config.json | 394 ++++++++++++++++++ embodichain/lab/gym/envs/__init__.py | 3 + .../tasks/tableware/organize_tableware.py | 98 +++++ 3 files changed, 495 insertions(+) create mode 100644 configs/gym/organize_tableware/gym_config.json create mode 100644 embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py diff --git a/configs/gym/organize_tableware/gym_config.json b/configs/gym/organize_tableware/gym_config.json new file mode 100644 index 00000000..d372f0f9 --- /dev/null +++ b/configs/gym/organize_tableware/gym_config.json @@ -0,0 +1,394 @@ +{ + "id": "OrganizeTableware-v1", + "max_episodes": 5, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "init_fork_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "fork"}, + "position_range": [[0.66, -0.15, 0.86], [0.74, -0.05, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "init_spoon_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "spoon"}, + "position_range": [[0.76, -0.15, 0.86], [0.84, -0.05, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "prepare_extra_attr": { + "func": "prepare_extra_attr", + "mode": "reset", + "params": { + "attrs": [ + { + "name": "object_lengths", + "mode": "callable", + "entity_uids": "all_objects", + "func_name": "compute_object_length", + "func_kwargs": { + "is_svd_frame": true, + "sample_points": 5000 + } + }, + { + "name": "left_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "left_arm_base", + "to_matrix": true + } + }, + { + "name": "right_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "right_arm_base", + "to_matrix": true + } + } + ] + } + }, + "register_info_to_env": { + "func": "register_info_to_env", + "mode": "reset", + "params": { + "registry": [ + { + "entity_cfg": { + "uid": "fork" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "spoon" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["left_arm"] + }, + "attrs": ["left_arm_base_pose"], + "pose_register_params": { + "compute_relative": "spoon", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["right_arm"] + }, + "attrs": ["right_arm_base_pose"], + "pose_register_params": { + "compute_relative": "fork", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + } + ], + "registration": "affordance_datas", + "sim_update": true + } + }, + "random_table_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_robot_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 5, + "params": { + "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_camera_intrinsics": { + "func": "randomize_camera_intrinsics", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "focal_x_range": [-50, 50], + "focal_y_range": [-50, 50] + } + }, + "random_robot_init_eef_pose": { + "func": "randomize_robot_eef_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, + "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + } + }, + "observations": { + "norm_robot_eef_joint": { + "func": "normalize_robot_joint_data", + "mode": "modify", + "name": "robot/qpos", + "params": { + "joint_ids": [12, 13, 14, 15] + } + }, + "fork_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "fork_pose", + "params": { + "entity_cfg": {"uid": "fork"} + } + }, + "spoon_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "spoon_pose", + "params": { + "entity_cfg": {"uid": "spoon"} + } + }, + "cam_high_semantic_mask_l": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["fork", "spoon"] + } + }, + "cam_high_semantic_mask_r": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_r", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["fork", "spoon"], + "is_right": true + } + }, + "cam_left_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_left_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_left_wrist"}, + "foreground_uids": ["fork", "spoon"] + } + }, + "cam_right_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_right_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_right_wrist"}, + "foreground_uids": ["fork", "spoon"] + } + } + }, + "dataset": { + "robot_meta": { + "arm_dofs": 12, + "control_freq": 25, + "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], + "min_len_steps": 5 + } + } + }, + "robot": { + "uid": "CobotMagic", + "robot_type": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] + }, + "sensor": [ + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "width": 960, + "height": 540, + "enable_mask": true, + "enable_depth": true, + "left_to_right_pos": [0.059684025824163614, 0, 0], + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "extrinsics": { + "eye": [0.35368482807598, 0.014695524383058989, 1.4517046071614774], + "target": [0.7186357573287919, -0.054534732904795505, 0.5232553674540066], + "up": [0.9306678549330372, -0.0005600064212467153, 0.3658647703553347] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "right_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "left_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + } + ], + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [2, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "CircleTableSimple/circle_table_simple.ply" + }, + "attrs" : { + "mass": 10.0, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.01 + }, + "body_scale": [1, 1, 1], + "body_type": "kinematic", + "init_pos": [0.725, 0.0, 0.825], + "init_rot": [0, 90, 0] + } + ], + "rigid_object": [ + { + "uid":"fork", + "shape": { + "shape_type": "Mesh", + "fpath": "TableWare/tableware/fork/standard_fork_scale.ply" + }, + "attrs" : { + "mass": 0.01, + "static_friction": 1.0, + "dynamic_friction": 1.0, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 2.0, + "linear_damping": 2.0, + "angular_damping": 2.0, + "max_linear_velocity": 5.0, + "max_angular_velocity": 10.0, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.70, -0.1, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[0.75, 0.75, 1.0], + "max_convex_hull_num": 8 + }, + { + "uid":"spoon", + "shape": { + "shape_type": "Mesh", + "fpath": "TableWare/tableware/spoon/standard_spoon_a_rescale.ply" + }, + "attrs" : { + "mass": 0.01, + "static_friction": 1.0, + "dynamic_friction": 1.0, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 2.0, + "linear_damping": 2.0, + "angular_damping": 2.0, + "max_linear_velocity": 5.0, + "max_angular_velocity": 10.0, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.80, -0.1, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[0.75, 0.75, 1.0], + "max_convex_hull_num": 8 + } + ] +} + diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py index 71852b56..533d9295 100644 --- a/embodichain/lab/gym/envs/__init__.py +++ b/embodichain/lab/gym/envs/__init__.py @@ -36,6 +36,9 @@ from embodichain.lab.gym.envs.tasks.tableware.place_object_drawer import ( PlaceObjectDrawerEnv, ) +from embodichain.lab.gym.envs.tasks.tableware.organize_tableware import ( + OrganizeTablewareEnv, +) # Reinforcement learning environments from embodichain.lab.gym.envs.tasks.rl.push_cube import PushCubeEnv diff --git a/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py b/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py new file mode 100644 index 00000000..b42d905f --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py @@ -0,0 +1,98 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.utils import logger + +__all__ = ["OrganizeTablewareEnv"] + + +@register_env("OrganizeTableware-v1", max_episode_steps=600) +class OrganizeTablewareEnv(EmbodiedEnv): + def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): + super().__init__(cfg, **kwargs) + + action_config = kwargs.get("action_config", None) + if action_config is not None: + self.action_config = action_config + + # Define target positions for different tableware types + # Left side: fork, Right side: spoon + self.fork_target_pos = torch.tensor( + [0.65, -0.1, 0.86], dtype=torch.float32, device=self.device + ) + self.spoon_target_pos = torch.tensor( + [0.85, -0.1, 0.86], dtype=torch.float32, device=self.device + ) + + def is_task_success(self, **kwargs) -> torch.Tensor: + """Determine if the task is successfully completed. + + The task is successful if: + 1. Fork is placed in the left target area + 2. Spoon is placed in the right target area + + Args: + **kwargs: Additional arguments for task-specific success criteria. + + Returns: + torch.Tensor: A boolean tensor indicating success for each environment in the batch. + """ + try: + fork = self.sim.get_rigid_object("fork") + spoon = self.sim.get_rigid_object("spoon") + except Exception as e: + logger.log_warning(f"Fork or spoon not found: {e}, returning False.") + return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) + + # Get poses + fork_pose = fork.get_local_pose(to_matrix=True) + spoon_pose = spoon.get_local_pose(to_matrix=True) + + # Extract positions + fork_pos = fork_pose[:, :3, 3] # (num_envs, 3) + spoon_pos = spoon_pose[:, :3, 3] # (num_envs, 3) + + # Tolerance for checking if objects are in target area + xy_tolerance = torch.tensor( + [0.08, 0.05], dtype=torch.float32, device=self.device + ) + z_tolerance = 0.05 + + # Check if fork is in left target area + fork_target = self.fork_target_pos.unsqueeze(0).repeat(self.num_envs, 1) + fork_xy_diff = torch.abs(fork_pos[:, :2] - fork_target[:, :2]) + fork_z_diff = torch.abs(fork_pos[:, 2] - fork_target[:, 2]) + fork_in_target = torch.all(fork_xy_diff < xy_tolerance.unsqueeze(0), dim=1) & ( + fork_z_diff < z_tolerance + ) + + # Check if spoon is in right target area + spoon_target = self.spoon_target_pos.unsqueeze(0).repeat(self.num_envs, 1) + spoon_xy_diff = torch.abs(spoon_pos[:, :2] - spoon_target[:, :2]) + spoon_z_diff = torch.abs(spoon_pos[:, 2] - spoon_target[:, 2]) + spoon_in_target = torch.all( + spoon_xy_diff < xy_tolerance.unsqueeze(0), dim=1 + ) & (spoon_z_diff < z_tolerance) + + # Both must be in their target areas + success = fork_in_target & spoon_in_target + + return success From 5f86d4f269259d21a2a128e955c034f1c46c1920 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Fri, 26 Dec 2025 15:03:41 +0800 Subject: [PATCH 58/92] Add StackCups environment --- configs/gym/stack_cups/gym_config.json | 394 ++++++++++++++++++ embodichain/lab/gym/envs/__init__.py | 3 + .../gym/envs/tasks/tableware/stack_cups.py | 118 ++++++ 3 files changed, 515 insertions(+) create mode 100644 configs/gym/stack_cups/gym_config.json create mode 100644 embodichain/lab/gym/envs/tasks/tableware/stack_cups.py diff --git a/configs/gym/stack_cups/gym_config.json b/configs/gym/stack_cups/gym_config.json new file mode 100644 index 00000000..6bc0c791 --- /dev/null +++ b/configs/gym/stack_cups/gym_config.json @@ -0,0 +1,394 @@ +{ + "id": "StackCups-v1", + "max_episodes": 5, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "init_cup_1_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cup_1"}, + "position_range": [[0.66, -0.15, 0.86], [0.74, -0.05, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "init_cup_2_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cup_2"}, + "position_range": [[0.76, -0.15, 0.86], [0.84, -0.05, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "prepare_extra_attr": { + "func": "prepare_extra_attr", + "mode": "reset", + "params": { + "attrs": [ + { + "name": "object_lengths", + "mode": "callable", + "entity_uids": "all_objects", + "func_name": "compute_object_length", + "func_kwargs": { + "is_svd_frame": true, + "sample_points": 5000 + } + }, + { + "name": "left_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "left_arm_base", + "to_matrix": true + } + }, + { + "name": "right_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "right_arm_base", + "to_matrix": true + } + } + ] + } + }, + "register_info_to_env": { + "func": "register_info_to_env", + "mode": "reset", + "params": { + "registry": [ + { + "entity_cfg": { + "uid": "cup_1" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "cup_2" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["left_arm"] + }, + "attrs": ["left_arm_base_pose"], + "pose_register_params": { + "compute_relative": "cup_2", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["right_arm"] + }, + "attrs": ["right_arm_base_pose"], + "pose_register_params": { + "compute_relative": "cup_1", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + } + ], + "registration": "affordance_datas", + "sim_update": true + } + }, + "random_table_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_robot_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 5, + "params": { + "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_camera_intrinsics": { + "func": "randomize_camera_intrinsics", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "focal_x_range": [-50, 50], + "focal_y_range": [-50, 50] + } + }, + "random_robot_init_eef_pose": { + "func": "randomize_robot_eef_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, + "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + } + }, + "observations": { + "norm_robot_eef_joint": { + "func": "normalize_robot_joint_data", + "mode": "modify", + "name": "robot/qpos", + "params": { + "joint_ids": [12, 13, 14, 15] + } + }, + "cup_1_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "cup_1_pose", + "params": { + "entity_cfg": {"uid": "cup_1"} + } + }, + "cup_2_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "cup_2_pose", + "params": { + "entity_cfg": {"uid": "cup_2"} + } + }, + "cam_high_semantic_mask_l": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["cup_1", "cup_2"] + } + }, + "cam_high_semantic_mask_r": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_r", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["cup_1", "cup_2"], + "is_right": true + } + }, + "cam_left_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_left_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_left_wrist"}, + "foreground_uids": ["cup_1", "cup_2"] + } + }, + "cam_right_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_right_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_right_wrist"}, + "foreground_uids": ["cup_1", "cup_2"] + } + } + }, + "dataset": { + "robot_meta": { + "arm_dofs": 12, + "control_freq": 25, + "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], + "min_len_steps": 5 + } + } + }, + "robot": { + "uid": "CobotMagic", + "robot_type": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] + }, + "sensor": [ + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "width": 960, + "height": 540, + "enable_mask": true, + "enable_depth": true, + "left_to_right_pos": [0.059684025824163614, 0, 0], + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "extrinsics": { + "eye": [0.35368482807598, 0.014695524383058989, 1.4517046071614774], + "target": [0.7186357573287919, -0.054534732904795505, 0.5232553674540066], + "up": [0.9306678549330372, -0.0005600064212467153, 0.3658647703553347] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "right_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "left_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + } + ], + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [2, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "CircleTableSimple/circle_table_simple.ply" + }, + "attrs" : { + "mass": 10.0, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.01 + }, + "body_scale": [1, 1, 1], + "body_type": "kinematic", + "init_pos": [0.725, 0.0, 0.825], + "init_rot": [0, 90, 0] + } + ], + "rigid_object": [ + { + "uid":"cup_1", + "shape": { + "shape_type": "Mesh", + "fpath": "PaperCup/paper_cup.ply" + }, + "attrs" : { + "mass": 0.01, + "static_friction": 1.0, + "dynamic_friction": 1.0, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 2.0, + "linear_damping": 2.0, + "angular_damping": 2.0, + "max_linear_velocity": 5.0, + "max_angular_velocity": 10.0, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.70, -0.1, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[0.75, 0.75, 1.0], + "max_convex_hull_num": 8 + }, + { + "uid":"cup_2", + "shape": { + "shape_type": "Mesh", + "fpath": "PaperCup/paper_cup.ply" + }, + "attrs" : { + "mass": 0.01, + "static_friction": 1.0, + "dynamic_friction": 1.0, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 2.0, + "linear_damping": 2.0, + "angular_damping": 2.0, + "max_linear_velocity": 5.0, + "max_angular_velocity": 10.0, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.80, -0.1, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[0.75, 0.75, 1.0], + "max_convex_hull_num": 8 + } + ] +} + diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py index 533d9295..741399c7 100644 --- a/embodichain/lab/gym/envs/__init__.py +++ b/embodichain/lab/gym/envs/__init__.py @@ -39,6 +39,9 @@ from embodichain.lab.gym.envs.tasks.tableware.organize_tableware import ( OrganizeTablewareEnv, ) +from embodichain.lab.gym.envs.tasks.tableware.stack_cups import ( + StackCupsEnv, +) # Reinforcement learning environments from embodichain.lab.gym.envs.tasks.rl.push_cube import PushCubeEnv diff --git a/embodichain/lab/gym/envs/tasks/tableware/stack_cups.py b/embodichain/lab/gym/envs/tasks/tableware/stack_cups.py new file mode 100644 index 00000000..b025e3f0 --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/stack_cups.py @@ -0,0 +1,118 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.utils import logger + +__all__ = ["StackCupsEnv"] + + +@register_env("StackCups-v1", max_episode_steps=600) +class StackCupsEnv(EmbodiedEnv): + def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): + super().__init__(cfg, **kwargs) + + action_config = kwargs.get("action_config", None) + if action_config is not None: + self.action_config = action_config + + def is_task_success(self, **kwargs) -> torch.Tensor: + """Determine if the task is successfully completed. + + The task is successful if: + 1. Both cups haven't fallen over + 2. Cups are aligned in xy plane + 3. Top cup is only slightly higher than base cup + + Args: + **kwargs: Additional arguments for task-specific success criteria. + + Returns: + torch.Tensor: A boolean tensor indicating success for each environment in the batch. + """ + try: + cup1 = self.sim.get_rigid_object("cup_1") + cup2 = self.sim.get_rigid_object("cup_2") + except Exception as e: + logger.log_warning(f"Cups not found: {e}, returning False.") + return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) + + # Get cup poses + cup1_pose = cup1.get_local_pose(to_matrix=True) + cup2_pose = cup2.get_local_pose(to_matrix=True) + + # Extract positions + cup1_pos = cup1_pose[:, :3, 3] # (num_envs, 3) + cup2_pos = cup2_pose[:, :3, 3] # (num_envs, 3) + + # Check if cups haven't fallen (orientation check) + cup1_fallen = self._is_fall(cup1_pose) + cup2_fallen = self._is_fall(cup2_pose) + + # Determine which cup is lower (should be cup1) + cup1_is_lower = cup1_pos[:, 2] < cup2_pos[:, 2] + + # Use the lower cup as base, calculate expected position of top cup + base_cup_pos = torch.where( + cup1_is_lower.unsqueeze(1).expand_as(cup1_pos), cup1_pos, cup2_pos + ) + top_cup_pos = torch.where( + cup1_is_lower.unsqueeze(1).expand_as(cup2_pos), cup2_pos, cup1_pos + ) + + # Top cup should be slightly higher than base cup + cup_rim_offset = 0.015 + expected_top_pos = torch.stack( + [ + base_cup_pos[:, 0], + base_cup_pos[:, 1], + base_cup_pos[:, 2] + cup_rim_offset, + ], + dim=1, + ) + + # Tolerance + eps = torch.tensor([0.04, 0.04, 0.02], dtype=torch.float32, device=self.device) + + # Check if top cup is within tolerance of expected position + position_diff = torch.abs(top_cup_pos - expected_top_pos) # (num_envs, 3) + stacked_correctly = torch.all( + position_diff < eps.unsqueeze(0), dim=1 + ) # (num_envs,) + + # Task succeeds if cups are stacked correctly and haven't fallen + success = stacked_correctly & ~cup1_fallen & ~cup2_fallen + + return success + + def _is_fall(self, pose: torch.Tensor) -> torch.Tensor: + # Extract z-axis from rotation matrix (last column, first 3 elements) + pose_rz = pose[:, :3, 2] + world_z_axis = torch.tensor([0, 0, 1], dtype=pose.dtype, device=pose.device) + + # Compute dot product for each batch element + dot_product = torch.sum(pose_rz * world_z_axis, dim=-1) # Shape: (batch_size,) + + # Clamp to avoid numerical issues with arccos + dot_product = torch.clamp(dot_product, -1.0, 1.0) + + # Compute angle and check if fallen + angle = torch.arccos(dot_product) + return angle >= torch.pi / 4 From ec7efc113367d60040ff7c5ce831c17dd271bb7e Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Fri, 26 Dec 2025 15:03:41 +0800 Subject: [PATCH 59/92] Add StackCups environment --- configs/gym/stack_cups/gym_config.json | 394 ++++++++++++++++++ embodichain/lab/gym/envs/__init__.py | 3 + .../gym/envs/tasks/tableware/stack_cups.py | 118 ++++++ 3 files changed, 515 insertions(+) create mode 100644 configs/gym/stack_cups/gym_config.json create mode 100644 embodichain/lab/gym/envs/tasks/tableware/stack_cups.py diff --git a/configs/gym/stack_cups/gym_config.json b/configs/gym/stack_cups/gym_config.json new file mode 100644 index 00000000..6bc0c791 --- /dev/null +++ b/configs/gym/stack_cups/gym_config.json @@ -0,0 +1,394 @@ +{ + "id": "StackCups-v1", + "max_episodes": 5, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "init_cup_1_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cup_1"}, + "position_range": [[0.66, -0.15, 0.86], [0.74, -0.05, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "init_cup_2_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cup_2"}, + "position_range": [[0.76, -0.15, 0.86], [0.84, -0.05, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "prepare_extra_attr": { + "func": "prepare_extra_attr", + "mode": "reset", + "params": { + "attrs": [ + { + "name": "object_lengths", + "mode": "callable", + "entity_uids": "all_objects", + "func_name": "compute_object_length", + "func_kwargs": { + "is_svd_frame": true, + "sample_points": 5000 + } + }, + { + "name": "left_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "left_arm_base", + "to_matrix": true + } + }, + { + "name": "right_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "right_arm_base", + "to_matrix": true + } + } + ] + } + }, + "register_info_to_env": { + "func": "register_info_to_env", + "mode": "reset", + "params": { + "registry": [ + { + "entity_cfg": { + "uid": "cup_1" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "cup_2" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["left_arm"] + }, + "attrs": ["left_arm_base_pose"], + "pose_register_params": { + "compute_relative": "cup_2", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["right_arm"] + }, + "attrs": ["right_arm_base_pose"], + "pose_register_params": { + "compute_relative": "cup_1", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + } + ], + "registration": "affordance_datas", + "sim_update": true + } + }, + "random_table_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_robot_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 5, + "params": { + "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_camera_intrinsics": { + "func": "randomize_camera_intrinsics", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "focal_x_range": [-50, 50], + "focal_y_range": [-50, 50] + } + }, + "random_robot_init_eef_pose": { + "func": "randomize_robot_eef_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, + "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + } + }, + "observations": { + "norm_robot_eef_joint": { + "func": "normalize_robot_joint_data", + "mode": "modify", + "name": "robot/qpos", + "params": { + "joint_ids": [12, 13, 14, 15] + } + }, + "cup_1_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "cup_1_pose", + "params": { + "entity_cfg": {"uid": "cup_1"} + } + }, + "cup_2_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "cup_2_pose", + "params": { + "entity_cfg": {"uid": "cup_2"} + } + }, + "cam_high_semantic_mask_l": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["cup_1", "cup_2"] + } + }, + "cam_high_semantic_mask_r": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_r", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["cup_1", "cup_2"], + "is_right": true + } + }, + "cam_left_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_left_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_left_wrist"}, + "foreground_uids": ["cup_1", "cup_2"] + } + }, + "cam_right_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_right_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_right_wrist"}, + "foreground_uids": ["cup_1", "cup_2"] + } + } + }, + "dataset": { + "robot_meta": { + "arm_dofs": 12, + "control_freq": 25, + "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], + "min_len_steps": 5 + } + } + }, + "robot": { + "uid": "CobotMagic", + "robot_type": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] + }, + "sensor": [ + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "width": 960, + "height": 540, + "enable_mask": true, + "enable_depth": true, + "left_to_right_pos": [0.059684025824163614, 0, 0], + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "extrinsics": { + "eye": [0.35368482807598, 0.014695524383058989, 1.4517046071614774], + "target": [0.7186357573287919, -0.054534732904795505, 0.5232553674540066], + "up": [0.9306678549330372, -0.0005600064212467153, 0.3658647703553347] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "right_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "left_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + } + ], + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [2, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "CircleTableSimple/circle_table_simple.ply" + }, + "attrs" : { + "mass": 10.0, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.01 + }, + "body_scale": [1, 1, 1], + "body_type": "kinematic", + "init_pos": [0.725, 0.0, 0.825], + "init_rot": [0, 90, 0] + } + ], + "rigid_object": [ + { + "uid":"cup_1", + "shape": { + "shape_type": "Mesh", + "fpath": "PaperCup/paper_cup.ply" + }, + "attrs" : { + "mass": 0.01, + "static_friction": 1.0, + "dynamic_friction": 1.0, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 2.0, + "linear_damping": 2.0, + "angular_damping": 2.0, + "max_linear_velocity": 5.0, + "max_angular_velocity": 10.0, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.70, -0.1, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[0.75, 0.75, 1.0], + "max_convex_hull_num": 8 + }, + { + "uid":"cup_2", + "shape": { + "shape_type": "Mesh", + "fpath": "PaperCup/paper_cup.ply" + }, + "attrs" : { + "mass": 0.01, + "static_friction": 1.0, + "dynamic_friction": 1.0, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 2.0, + "linear_damping": 2.0, + "angular_damping": 2.0, + "max_linear_velocity": 5.0, + "max_angular_velocity": 10.0, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.80, -0.1, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[0.75, 0.75, 1.0], + "max_convex_hull_num": 8 + } + ] +} + diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py index 533d9295..741399c7 100644 --- a/embodichain/lab/gym/envs/__init__.py +++ b/embodichain/lab/gym/envs/__init__.py @@ -39,6 +39,9 @@ from embodichain.lab.gym.envs.tasks.tableware.organize_tableware import ( OrganizeTablewareEnv, ) +from embodichain.lab.gym.envs.tasks.tableware.stack_cups import ( + StackCupsEnv, +) # Reinforcement learning environments from embodichain.lab.gym.envs.tasks.rl.push_cube import PushCubeEnv diff --git a/embodichain/lab/gym/envs/tasks/tableware/stack_cups.py b/embodichain/lab/gym/envs/tasks/tableware/stack_cups.py new file mode 100644 index 00000000..b025e3f0 --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/stack_cups.py @@ -0,0 +1,118 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.utils import logger + +__all__ = ["StackCupsEnv"] + + +@register_env("StackCups-v1", max_episode_steps=600) +class StackCupsEnv(EmbodiedEnv): + def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): + super().__init__(cfg, **kwargs) + + action_config = kwargs.get("action_config", None) + if action_config is not None: + self.action_config = action_config + + def is_task_success(self, **kwargs) -> torch.Tensor: + """Determine if the task is successfully completed. + + The task is successful if: + 1. Both cups haven't fallen over + 2. Cups are aligned in xy plane + 3. Top cup is only slightly higher than base cup + + Args: + **kwargs: Additional arguments for task-specific success criteria. + + Returns: + torch.Tensor: A boolean tensor indicating success for each environment in the batch. + """ + try: + cup1 = self.sim.get_rigid_object("cup_1") + cup2 = self.sim.get_rigid_object("cup_2") + except Exception as e: + logger.log_warning(f"Cups not found: {e}, returning False.") + return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) + + # Get cup poses + cup1_pose = cup1.get_local_pose(to_matrix=True) + cup2_pose = cup2.get_local_pose(to_matrix=True) + + # Extract positions + cup1_pos = cup1_pose[:, :3, 3] # (num_envs, 3) + cup2_pos = cup2_pose[:, :3, 3] # (num_envs, 3) + + # Check if cups haven't fallen (orientation check) + cup1_fallen = self._is_fall(cup1_pose) + cup2_fallen = self._is_fall(cup2_pose) + + # Determine which cup is lower (should be cup1) + cup1_is_lower = cup1_pos[:, 2] < cup2_pos[:, 2] + + # Use the lower cup as base, calculate expected position of top cup + base_cup_pos = torch.where( + cup1_is_lower.unsqueeze(1).expand_as(cup1_pos), cup1_pos, cup2_pos + ) + top_cup_pos = torch.where( + cup1_is_lower.unsqueeze(1).expand_as(cup2_pos), cup2_pos, cup1_pos + ) + + # Top cup should be slightly higher than base cup + cup_rim_offset = 0.015 + expected_top_pos = torch.stack( + [ + base_cup_pos[:, 0], + base_cup_pos[:, 1], + base_cup_pos[:, 2] + cup_rim_offset, + ], + dim=1, + ) + + # Tolerance + eps = torch.tensor([0.04, 0.04, 0.02], dtype=torch.float32, device=self.device) + + # Check if top cup is within tolerance of expected position + position_diff = torch.abs(top_cup_pos - expected_top_pos) # (num_envs, 3) + stacked_correctly = torch.all( + position_diff < eps.unsqueeze(0), dim=1 + ) # (num_envs,) + + # Task succeeds if cups are stacked correctly and haven't fallen + success = stacked_correctly & ~cup1_fallen & ~cup2_fallen + + return success + + def _is_fall(self, pose: torch.Tensor) -> torch.Tensor: + # Extract z-axis from rotation matrix (last column, first 3 elements) + pose_rz = pose[:, :3, 2] + world_z_axis = torch.tensor([0, 0, 1], dtype=pose.dtype, device=pose.device) + + # Compute dot product for each batch element + dot_product = torch.sum(pose_rz * world_z_axis, dim=-1) # Shape: (batch_size,) + + # Clamp to avoid numerical issues with arccos + dot_product = torch.clamp(dot_product, -1.0, 1.0) + + # Compute angle and check if fallen + angle = torch.arccos(dot_product) + return angle >= torch.pi / 4 From 291fef3ddcdc76ccfe4c50217ac61726fdbf9ec5 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Fri, 26 Dec 2025 19:57:45 +0800 Subject: [PATCH 60/92] Add MatchObjectContainer environment --- .../match_object_container/gym_config.json | 576 ++++++++++++++++++ embodichain/lab/gym/envs/__init__.py | 3 + .../tasks/tableware/match_object_container.py | 178 ++++++ 3 files changed, 757 insertions(+) create mode 100644 configs/gym/match_object_container/gym_config.json create mode 100644 embodichain/lab/gym/envs/tasks/tableware/match_object_container.py diff --git a/configs/gym/match_object_container/gym_config.json b/configs/gym/match_object_container/gym_config.json new file mode 100644 index 00000000..00257446 --- /dev/null +++ b/configs/gym/match_object_container/gym_config.json @@ -0,0 +1,576 @@ +{ + "id": "MatchObjectContainer-v1", + "max_episodes": 5, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "init_block_cube_1_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_cube_1"}, + "position_range": [[0.55, -0.10, 0.86], [0.58, -0.05, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "init_block_sphere_1_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_sphere_1"}, + "position_range": [[0.62, -0.10, 0.86], [0.65, -0.05, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "init_block_cube_2_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_cube_2"}, + "position_range": [[0.55, 0.05, 0.86], [0.58, 0.10, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "init_block_sphere_2_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_sphere_2"}, + "position_range": [[0.62, 0.05, 0.86], [0.65, 0.10, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "prepare_extra_attr": { + "func": "prepare_extra_attr", + "mode": "reset", + "params": { + "attrs": [ + { + "name": "object_lengths", + "mode": "callable", + "entity_uids": "all_objects", + "func_name": "compute_object_length", + "func_kwargs": { + "is_svd_frame": true, + "sample_points": 5000 + } + }, + { + "name": "left_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "left_arm_base", + "to_matrix": true + } + }, + { + "name": "right_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "right_arm_base", + "to_matrix": true + } + } + ] + } + }, + "register_info_to_env": { + "func": "register_info_to_env", + "mode": "reset", + "params": { + "registry": [ + { + "entity_cfg": { + "uid": "block_cube_1" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "block_sphere_1" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "container_cube" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "container_sphere" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "block_cube_2" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "block_sphere_2" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["left_arm"] + }, + "attrs": ["left_arm_base_pose"], + "pose_register_params": { + "compute_relative": "container_cube", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["right_arm"] + }, + "attrs": ["right_arm_base_pose"], + "pose_register_params": { + "compute_relative": "container_sphere", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + } + ], + "registration": "affordance_datas", + "sim_update": true + } + }, + "random_table_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_robot_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 5, + "params": { + "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_camera_intrinsics": { + "func": "randomize_camera_intrinsics", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "focal_x_range": [-50, 50], + "focal_y_range": [-50, 50] + } + }, + "random_robot_init_eef_pose": { + "func": "randomize_robot_eef_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, + "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + } + }, + "observations": { + "norm_robot_eef_joint": { + "func": "normalize_robot_joint_data", + "mode": "modify", + "name": "robot/qpos", + "params": { + "joint_ids": [12, 13, 14, 15] + } + }, + "block_cube_1_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_cube_1_pose", + "params": { + "entity_cfg": {"uid": "block_cube_1"} + } + }, + "block_sphere_1_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_sphere_1_pose", + "params": { + "entity_cfg": {"uid": "block_sphere_1"} + } + }, + "container_cube_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "container_cube_pose", + "params": { + "entity_cfg": {"uid": "container_cube"} + } + }, + "container_sphere_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "container_sphere_pose", + "params": { + "entity_cfg": {"uid": "container_sphere"} + } + }, + "block_cube_2_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_cube_2_pose", + "params": { + "entity_cfg": {"uid": "block_cube_2"} + } + }, + "block_sphere_2_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_sphere_2_pose", + "params": { + "entity_cfg": {"uid": "block_sphere_2"} + } + }, + "cam_high_semantic_mask_l": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["block_cube_1", "block_sphere_1", "block_cube_2", "block_sphere_2", "container_cube", "container_sphere"] + } + }, + "cam_high_semantic_mask_r": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_r", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["block_cube_1", "block_sphere_1", "block_cube_2", "block_sphere_2", "container_cube", "container_sphere"], + "is_right": true + } + }, + "cam_left_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_left_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_left_wrist"}, + "foreground_uids": ["block_cube_1", "block_sphere_1", "block_cube_2", "block_sphere_2", "container_cube", "container_sphere"] + } + }, + "cam_right_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_right_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_right_wrist"}, + "foreground_uids": ["block_cube_1", "block_sphere_1", "block_cube_2", "block_sphere_2", "container_cube", "container_sphere"] + } + } + }, + "dataset": { + "robot_meta": { + "arm_dofs": 12, + "control_freq": 25, + "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], + "min_len_steps": 5 + } + } + }, + "robot": { + "uid": "CobotMagic", + "robot_type": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] + }, + "sensor": [ + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "width": 960, + "height": 540, + "enable_mask": true, + "enable_depth": true, + "left_to_right_pos": [0.059684025824163614, 0, 0], + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "extrinsics": { + "eye": [0.35368482807598, 0.014695524383058989, 1.4517046071614774], + "target": [0.7186357573287919, -0.054534732904795505, 0.5232553674540066], + "up": [0.9306678549330372, -0.0005600064212467153, 0.3658647703553347] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "right_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "left_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + } + ], + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [2, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "CircleTableSimple/circle_table_simple.ply" + }, + "attrs" : { + "mass": 10.0, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.01 + }, + "body_scale": [1, 1, 1], + "body_type": "kinematic", + "init_pos": [0.725, 0.0, 0.825], + "init_rot": [0, 90, 0] + } + ], + "rigid_object": [ + { + "uid":"block_cube_1", + "shape": { + "shape_type": "Cube", + "size": [0.04, 0.04, 0.04] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.565, -0.075, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + }, + { + "uid":"block_sphere_1", + "shape": { + "shape_type": "Sphere", + "radius": 0.025 + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.635, -0.075, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + }, + { + "uid":"container_cube", + "shape": { + "shape_type": "Mesh", + "fpath": "ContainerMetal/container_metal.obj" + }, + "body_type": "dynamic", + "attrs" : { + "mass": 0.5, + "static_friction": 1.0, + "dynamic_friction": 1.0, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 2.0, + "linear_damping": 2.0, + "angular_damping": 2.0, + "max_linear_velocity": 5.0, + "max_angular_velocity": 10.0, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.875, -0.25, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 8 + }, + { + "uid":"container_sphere", + "shape": { + "shape_type": "Mesh", + "fpath": "ContainerMetal/container_metal.obj" + }, + "body_type": "dynamic", + "attrs" : { + "mass": 0.5, + "static_friction": 1.0, + "dynamic_friction": 1.0, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 2.0, + "linear_damping": 2.0, + "angular_damping": 2.0, + "max_linear_velocity": 5.0, + "max_angular_velocity": 10.0, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.875, 0.25, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 8 + }, + { + "uid":"block_cube_2", + "shape": { + "shape_type": "Cube", + "size": [0.04, 0.04, 0.04] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.565, 0.075, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + }, + { + "uid":"block_sphere_2", + "shape": { + "shape_type": "Sphere", + "radius": 0.025 + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.635, 0.075, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + } + ] +} + diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py index 741399c7..8bc96da9 100644 --- a/embodichain/lab/gym/envs/__init__.py +++ b/embodichain/lab/gym/envs/__init__.py @@ -42,6 +42,9 @@ from embodichain.lab.gym.envs.tasks.tableware.stack_cups import ( StackCupsEnv, ) +from embodichain.lab.gym.envs.tasks.tableware.match_object_container import ( + MatchObjectContainerEnv, +) # Reinforcement learning environments from embodichain.lab.gym.envs.tasks.rl.push_cube import PushCubeEnv diff --git a/embodichain/lab/gym/envs/tasks/tableware/match_object_container.py b/embodichain/lab/gym/envs/tasks/tableware/match_object_container.py new file mode 100644 index 00000000..903221b5 --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/match_object_container.py @@ -0,0 +1,178 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.utils import logger + +__all__ = ["MatchObjectContainerEnv"] + + +@register_env("MatchObjectContainer-v1", max_episode_steps=600) +class MatchObjectContainerEnv(EmbodiedEnv): + def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): + super().__init__(cfg, **kwargs) + + action_config = kwargs.get("action_config", None) + if action_config is not None: + self.action_config = action_config + + def is_task_success(self, **kwargs) -> torch.Tensor: + """Determine if the task is successfully completed. + + This is a classification task: place blocks into matching shaped containers. + The task is successful if: + 1. Both cube blocks are inside container_cube (block_cube_1 and block_cube_2 -> container_cube) + 2. Both sphere blocks are inside container_sphere (block_sphere_1 and block_sphere_2 -> container_sphere) + 3. Both containers are up + + Args: + **kwargs: Additional arguments for task-specific success criteria. + + Returns: + torch.Tensor: A boolean tensor indicating success for each environment in the batch. + """ + try: + block_cube_1 = self.sim.get_rigid_object("block_cube_1") + block_sphere_1 = self.sim.get_rigid_object("block_sphere_1") + block_cube_2 = self.sim.get_rigid_object("block_cube_2") + block_sphere_2 = self.sim.get_rigid_object("block_sphere_2") + container_cube = self.sim.get_rigid_object("container_cube") + container_sphere = self.sim.get_rigid_object("container_sphere") + except Exception as e: + logger.log_warning(f"Blocks or containers not found: {e}, returning False.") + return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) + + # Get poses + block_cube_1_pose = block_cube_1.get_local_pose(to_matrix=True) + block_sphere_1_pose = block_sphere_1.get_local_pose(to_matrix=True) + block_cube_2_pose = block_cube_2.get_local_pose(to_matrix=True) + block_sphere_2_pose = block_sphere_2.get_local_pose(to_matrix=True) + container_cube_pose = container_cube.get_local_pose(to_matrix=True) + container_sphere_pose = container_sphere.get_local_pose(to_matrix=True) + + # Extract positions + block_cube_1_pos = block_cube_1_pose[:, :3, 3] # (num_envs, 3) + block_sphere_1_pos = block_sphere_1_pose[:, :3, 3] + block_cube_2_pos = block_cube_2_pose[:, :3, 3] + block_sphere_2_pos = block_sphere_2_pose[:, :3, 3] + container_cube_pos = container_cube_pose[:, :3, 3] + container_sphere_pos = container_sphere_pose[:, :3, 3] + + container_cube_up = ~self._is_fall(container_cube_pose) + container_sphere_up = ~self._is_fall(container_sphere_pose) + + # Check if blocks are inside their matching containers + # Note: container_pos[:, 2] is the geometric center (center of mass) of the container + container_bottom_radius = 0.1067 # Bottom inner radius in meters + z_tolerance = 0.05 # Vertical tolerance for bottom check + container_height = 0.068 # Container height in meters + container_half_height = ( + container_height / 2 + ) # Half height for center-based calculation + + # Check if blocks are in their matching containers + cube_1_in_container = self._is_block_in_container( + block_cube_1_pos, + container_cube_pos, + container_bottom_radius, + container_half_height, + z_tolerance, + ) + cube_2_in_container = self._is_block_in_container( + block_cube_2_pos, + container_cube_pos, + container_bottom_radius, + container_half_height, + z_tolerance, + ) + sphere_1_in_container = self._is_block_in_container( + block_sphere_1_pos, + container_sphere_pos, + container_bottom_radius, + container_half_height, + z_tolerance, + ) + sphere_2_in_container = self._is_block_in_container( + block_sphere_2_pos, + container_sphere_pos, + container_bottom_radius, + container_half_height, + z_tolerance, + ) + + # Task success if cubes and spheres are in containers and containers are up + success = ( + cube_1_in_container + & cube_2_in_container + & sphere_1_in_container + & sphere_2_in_container + & container_cube_up + & container_sphere_up + ) + + return success + + def _is_block_in_container( + self, + block_pos: torch.Tensor, + container_pos: torch.Tensor, + container_bottom_radius: float, + container_half_height: float, + z_tolerance: float, + ) -> torch.Tensor: + """Check if a block is inside a container. + + Args: + block_pos: Block position (num_envs, 3) + container_pos: Container center position (num_envs, 3) + container_bottom_radius: Inner radius of container bottom in meters + container_half_height: Half height of container in meters + z_tolerance: Vertical tolerance for bottom check in meters + + Returns: + Boolean tensor indicating if block is in container (num_envs,) + """ + # XY plane distance check + xy_diff = torch.norm(block_pos[:, :2] - container_pos[:, :2], dim=1) + + # Z coordinate check: container center is at container_pos[:, 2] + # Container bottom = container_pos[:, 2] - container_half_height + # Container top = container_pos[:, 2] + container_half_height + z_above_bottom = ( + block_pos[:, 2] > container_pos[:, 2] - container_half_height - z_tolerance + ) + z_within_height = block_pos[:, 2] < container_pos[:, 2] + container_half_height + + return (xy_diff < container_bottom_radius) & z_above_bottom & z_within_height + + def _is_fall(self, pose: torch.Tensor) -> torch.Tensor: + # Extract z-axis from rotation matrix (last column, first 3 elements) + pose_rz = pose[:, :3, 2] + world_z_axis = torch.tensor([0, 0, 1], dtype=pose.dtype, device=pose.device) + + # Compute dot product for each batch element + dot_product = torch.sum(pose_rz * world_z_axis, dim=-1) # Shape: (batch_size,) + + # Clamp to avoid numerical issues with arccos + dot_product = torch.clamp(dot_product, -1.0, 1.0) + + # Compute angle and check if fallen + angle = torch.arccos(dot_product) + return angle >= torch.pi / 4 From d8baf7d3fcd85389ee6ffac5f40d355ca58f32ef Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Fri, 26 Dec 2025 19:57:45 +0800 Subject: [PATCH 61/92] Add MatchObjectContainer environment --- .../match_object_container/gym_config.json | 576 ++++++++++++++++++ embodichain/lab/gym/envs/__init__.py | 3 + .../tasks/tableware/match_object_container.py | 178 ++++++ 3 files changed, 757 insertions(+) create mode 100644 configs/gym/match_object_container/gym_config.json create mode 100644 embodichain/lab/gym/envs/tasks/tableware/match_object_container.py diff --git a/configs/gym/match_object_container/gym_config.json b/configs/gym/match_object_container/gym_config.json new file mode 100644 index 00000000..00257446 --- /dev/null +++ b/configs/gym/match_object_container/gym_config.json @@ -0,0 +1,576 @@ +{ + "id": "MatchObjectContainer-v1", + "max_episodes": 5, + "env": { + "events": { + "random_light": { + "func": "randomize_light", + "mode": "interval", + "interval_step": 10, + "params": { + "entity_cfg": {"uid": "light_1"}, + "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], + "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], + "intensity_range": [50.0, 100.0] + } + }, + "init_block_cube_1_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_cube_1"}, + "position_range": [[0.55, -0.10, 0.86], [0.58, -0.05, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "init_block_sphere_1_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_sphere_1"}, + "position_range": [[0.62, -0.10, 0.86], [0.65, -0.05, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "init_block_cube_2_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_cube_2"}, + "position_range": [[0.55, 0.05, 0.86], [0.58, 0.10, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "init_block_sphere_2_pose": { + "func": "randomize_rigid_object_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "block_sphere_2"}, + "position_range": [[0.62, 0.05, 0.86], [0.65, 0.10, 0.86]], + "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], + "relative_position": false + } + }, + "prepare_extra_attr": { + "func": "prepare_extra_attr", + "mode": "reset", + "params": { + "attrs": [ + { + "name": "object_lengths", + "mode": "callable", + "entity_uids": "all_objects", + "func_name": "compute_object_length", + "func_kwargs": { + "is_svd_frame": true, + "sample_points": 5000 + } + }, + { + "name": "left_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "left_arm_base", + "to_matrix": true + } + }, + { + "name": "right_arm_base_pose", + "mode": "callable", + "entity_cfg": { + "uid": "CobotMagic" + }, + "func_name": "get_link_pose", + "func_kwargs": { + "link_name": "right_arm_base", + "to_matrix": true + } + } + ] + } + }, + "register_info_to_env": { + "func": "register_info_to_env", + "mode": "reset", + "params": { + "registry": [ + { + "entity_cfg": { + "uid": "block_cube_1" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "block_sphere_1" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "container_cube" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "container_sphere" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "block_cube_2" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "block_sphere_2" + }, + "pose_register_params": { + "compute_relative": false, + "compute_pose_object_to_arena": true, + "to_matrix": true + } + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["left_arm"] + }, + "attrs": ["left_arm_base_pose"], + "pose_register_params": { + "compute_relative": "container_cube", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + }, + { + "entity_cfg": { + "uid": "CobotMagic", + "control_parts": ["right_arm"] + }, + "attrs": ["right_arm_base_pose"], + "pose_register_params": { + "compute_relative": "container_sphere", + "compute_pose_object_to_arena": false, + "to_matrix": true + }, + "prefix": false + } + ], + "registration": "affordance_datas", + "sim_update": true + } + }, + "random_table_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 2, + "params": { + "entity_cfg": {"uid": "table"}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_robot_material": { + "func": "randomize_visual_material", + "mode": "interval", + "interval_step": 5, + "params": { + "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, + "random_texture_prob": 0.5, + "texture_path": "CocoBackground/coco", + "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] + } + }, + "random_camera_intrinsics": { + "func": "randomize_camera_intrinsics", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "focal_x_range": [-50, 50], + "focal_y_range": [-50, 50] + } + }, + "random_robot_init_eef_pose": { + "func": "randomize_robot_eef_pose", + "mode": "reset", + "params": { + "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, + "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] + } + }, + "record_camera": { + "func": "record_camera_data", + "mode": "interval", + "interval_step": 1, + "params": { + "name": "cam1", + "resolution": [320, 240], + "eye": [2, 0, 2], + "target": [0.5, 0, 1] + } + } + }, + "observations": { + "norm_robot_eef_joint": { + "func": "normalize_robot_joint_data", + "mode": "modify", + "name": "robot/qpos", + "params": { + "joint_ids": [12, 13, 14, 15] + } + }, + "block_cube_1_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_cube_1_pose", + "params": { + "entity_cfg": {"uid": "block_cube_1"} + } + }, + "block_sphere_1_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_sphere_1_pose", + "params": { + "entity_cfg": {"uid": "block_sphere_1"} + } + }, + "container_cube_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "container_cube_pose", + "params": { + "entity_cfg": {"uid": "container_cube"} + } + }, + "container_sphere_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "container_sphere_pose", + "params": { + "entity_cfg": {"uid": "container_sphere"} + } + }, + "block_cube_2_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_cube_2_pose", + "params": { + "entity_cfg": {"uid": "block_cube_2"} + } + }, + "block_sphere_2_pose": { + "func": "get_rigid_object_pose", + "mode": "add", + "name": "block_sphere_2_pose", + "params": { + "entity_cfg": {"uid": "block_sphere_2"} + } + }, + "cam_high_semantic_mask_l": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["block_cube_1", "block_sphere_1", "block_cube_2", "block_sphere_2", "container_cube", "container_sphere"] + } + }, + "cam_high_semantic_mask_r": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_high/semantic_mask_r", + "params": { + "entity_cfg": {"uid": "cam_high"}, + "foreground_uids": ["block_cube_1", "block_sphere_1", "block_cube_2", "block_sphere_2", "container_cube", "container_sphere"], + "is_right": true + } + }, + "cam_left_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_left_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_left_wrist"}, + "foreground_uids": ["block_cube_1", "block_sphere_1", "block_cube_2", "block_sphere_2", "container_cube", "container_sphere"] + } + }, + "cam_right_semantic_mask": { + "func": "compute_semantic_mask", + "mode": "add", + "name": "sensor/cam_right_wrist/semantic_mask_l", + "params": { + "entity_cfg": {"uid": "cam_right_wrist"}, + "foreground_uids": ["block_cube_1", "block_sphere_1", "block_cube_2", "block_sphere_2", "container_cube", "container_sphere"] + } + } + }, + "dataset": { + "robot_meta": { + "arm_dofs": 12, + "control_freq": 25, + "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], + "min_len_steps": 5 + } + } + }, + "robot": { + "uid": "CobotMagic", + "robot_type": "CobotMagic", + "init_pos": [0.0, 0.0, 0.7775], + "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] + }, + "sensor": [ + { + "sensor_type": "StereoCamera", + "uid": "cam_high", + "width": 960, + "height": 540, + "enable_mask": true, + "enable_depth": true, + "left_to_right_pos": [0.059684025824163614, 0, 0], + "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], + "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], + "extrinsics": { + "eye": [0.35368482807598, 0.014695524383058989, 1.4517046071614774], + "target": [0.7186357573287919, -0.054534732904795505, 0.5232553674540066], + "up": [0.9306678549330372, -0.0005600064212467153, 0.3658647703553347] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_right_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "right_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + }, + { + "sensor_type": "Camera", + "uid": "cam_left_wrist", + "width": 640, + "height": 480, + "enable_mask": true, + "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], + "extrinsics": { + "parent": "left_link6", + "pos": [-0.08, 0.0, 0.04], + "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] + } + } + ], + "light": { + "direct": [ + { + "uid": "light_1", + "light_type": "point", + "color": [1.0, 1.0, 1.0], + "intensity": 50.0, + "init_pos": [2, 0, 2], + "radius": 10.0 + } + ] + }, + "background": [ + { + "uid": "table", + "shape": { + "shape_type": "Mesh", + "fpath": "CircleTableSimple/circle_table_simple.ply" + }, + "attrs" : { + "mass": 10.0, + "static_friction": 0.95, + "dynamic_friction": 0.9, + "restitution": 0.01 + }, + "body_scale": [1, 1, 1], + "body_type": "kinematic", + "init_pos": [0.725, 0.0, 0.825], + "init_rot": [0, 90, 0] + } + ], + "rigid_object": [ + { + "uid":"block_cube_1", + "shape": { + "shape_type": "Cube", + "size": [0.04, 0.04, 0.04] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.565, -0.075, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + }, + { + "uid":"block_sphere_1", + "shape": { + "shape_type": "Sphere", + "radius": 0.025 + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.635, -0.075, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + }, + { + "uid":"container_cube", + "shape": { + "shape_type": "Mesh", + "fpath": "ContainerMetal/container_metal.obj" + }, + "body_type": "dynamic", + "attrs" : { + "mass": 0.5, + "static_friction": 1.0, + "dynamic_friction": 1.0, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 2.0, + "linear_damping": 2.0, + "angular_damping": 2.0, + "max_linear_velocity": 5.0, + "max_angular_velocity": 10.0, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.875, -0.25, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 8 + }, + { + "uid":"container_sphere", + "shape": { + "shape_type": "Mesh", + "fpath": "ContainerMetal/container_metal.obj" + }, + "body_type": "dynamic", + "attrs" : { + "mass": 0.5, + "static_friction": 1.0, + "dynamic_friction": 1.0, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 2.0, + "linear_damping": 2.0, + "angular_damping": 2.0, + "max_linear_velocity": 5.0, + "max_angular_velocity": 10.0, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.875, 0.25, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 8 + }, + { + "uid":"block_cube_2", + "shape": { + "shape_type": "Cube", + "size": [0.04, 0.04, 0.04] + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.565, 0.075, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + }, + { + "uid":"block_sphere_2", + "shape": { + "shape_type": "Sphere", + "radius": 0.025 + }, + "attrs" : { + "mass": 0.05, + "static_friction": 0.5, + "dynamic_friction": 0.5, + "restitution": 0.0, + "contact_offset": 0.003, + "rest_offset": 0.001, + "max_depenetration_velocity": 1e1, + "min_position_iters": 32, + "min_velocity_iters": 8 + }, + "init_pos": [0.635, 0.075, 0.86], + "init_rot": [0, 0, 0], + "body_scale":[1, 1, 1], + "max_convex_hull_num": 1 + } + ] +} + diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py index 741399c7..8bc96da9 100644 --- a/embodichain/lab/gym/envs/__init__.py +++ b/embodichain/lab/gym/envs/__init__.py @@ -42,6 +42,9 @@ from embodichain.lab.gym.envs.tasks.tableware.stack_cups import ( StackCupsEnv, ) +from embodichain.lab.gym.envs.tasks.tableware.match_object_container import ( + MatchObjectContainerEnv, +) # Reinforcement learning environments from embodichain.lab.gym.envs.tasks.rl.push_cube import PushCubeEnv diff --git a/embodichain/lab/gym/envs/tasks/tableware/match_object_container.py b/embodichain/lab/gym/envs/tasks/tableware/match_object_container.py new file mode 100644 index 00000000..903221b5 --- /dev/null +++ b/embodichain/lab/gym/envs/tasks/tableware/match_object_container.py @@ -0,0 +1,178 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +import torch +import numpy as np + +from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg +from embodichain.lab.gym.utils.registration import register_env +from embodichain.utils import logger + +__all__ = ["MatchObjectContainerEnv"] + + +@register_env("MatchObjectContainer-v1", max_episode_steps=600) +class MatchObjectContainerEnv(EmbodiedEnv): + def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): + super().__init__(cfg, **kwargs) + + action_config = kwargs.get("action_config", None) + if action_config is not None: + self.action_config = action_config + + def is_task_success(self, **kwargs) -> torch.Tensor: + """Determine if the task is successfully completed. + + This is a classification task: place blocks into matching shaped containers. + The task is successful if: + 1. Both cube blocks are inside container_cube (block_cube_1 and block_cube_2 -> container_cube) + 2. Both sphere blocks are inside container_sphere (block_sphere_1 and block_sphere_2 -> container_sphere) + 3. Both containers are up + + Args: + **kwargs: Additional arguments for task-specific success criteria. + + Returns: + torch.Tensor: A boolean tensor indicating success for each environment in the batch. + """ + try: + block_cube_1 = self.sim.get_rigid_object("block_cube_1") + block_sphere_1 = self.sim.get_rigid_object("block_sphere_1") + block_cube_2 = self.sim.get_rigid_object("block_cube_2") + block_sphere_2 = self.sim.get_rigid_object("block_sphere_2") + container_cube = self.sim.get_rigid_object("container_cube") + container_sphere = self.sim.get_rigid_object("container_sphere") + except Exception as e: + logger.log_warning(f"Blocks or containers not found: {e}, returning False.") + return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) + + # Get poses + block_cube_1_pose = block_cube_1.get_local_pose(to_matrix=True) + block_sphere_1_pose = block_sphere_1.get_local_pose(to_matrix=True) + block_cube_2_pose = block_cube_2.get_local_pose(to_matrix=True) + block_sphere_2_pose = block_sphere_2.get_local_pose(to_matrix=True) + container_cube_pose = container_cube.get_local_pose(to_matrix=True) + container_sphere_pose = container_sphere.get_local_pose(to_matrix=True) + + # Extract positions + block_cube_1_pos = block_cube_1_pose[:, :3, 3] # (num_envs, 3) + block_sphere_1_pos = block_sphere_1_pose[:, :3, 3] + block_cube_2_pos = block_cube_2_pose[:, :3, 3] + block_sphere_2_pos = block_sphere_2_pose[:, :3, 3] + container_cube_pos = container_cube_pose[:, :3, 3] + container_sphere_pos = container_sphere_pose[:, :3, 3] + + container_cube_up = ~self._is_fall(container_cube_pose) + container_sphere_up = ~self._is_fall(container_sphere_pose) + + # Check if blocks are inside their matching containers + # Note: container_pos[:, 2] is the geometric center (center of mass) of the container + container_bottom_radius = 0.1067 # Bottom inner radius in meters + z_tolerance = 0.05 # Vertical tolerance for bottom check + container_height = 0.068 # Container height in meters + container_half_height = ( + container_height / 2 + ) # Half height for center-based calculation + + # Check if blocks are in their matching containers + cube_1_in_container = self._is_block_in_container( + block_cube_1_pos, + container_cube_pos, + container_bottom_radius, + container_half_height, + z_tolerance, + ) + cube_2_in_container = self._is_block_in_container( + block_cube_2_pos, + container_cube_pos, + container_bottom_radius, + container_half_height, + z_tolerance, + ) + sphere_1_in_container = self._is_block_in_container( + block_sphere_1_pos, + container_sphere_pos, + container_bottom_radius, + container_half_height, + z_tolerance, + ) + sphere_2_in_container = self._is_block_in_container( + block_sphere_2_pos, + container_sphere_pos, + container_bottom_radius, + container_half_height, + z_tolerance, + ) + + # Task success if cubes and spheres are in containers and containers are up + success = ( + cube_1_in_container + & cube_2_in_container + & sphere_1_in_container + & sphere_2_in_container + & container_cube_up + & container_sphere_up + ) + + return success + + def _is_block_in_container( + self, + block_pos: torch.Tensor, + container_pos: torch.Tensor, + container_bottom_radius: float, + container_half_height: float, + z_tolerance: float, + ) -> torch.Tensor: + """Check if a block is inside a container. + + Args: + block_pos: Block position (num_envs, 3) + container_pos: Container center position (num_envs, 3) + container_bottom_radius: Inner radius of container bottom in meters + container_half_height: Half height of container in meters + z_tolerance: Vertical tolerance for bottom check in meters + + Returns: + Boolean tensor indicating if block is in container (num_envs,) + """ + # XY plane distance check + xy_diff = torch.norm(block_pos[:, :2] - container_pos[:, :2], dim=1) + + # Z coordinate check: container center is at container_pos[:, 2] + # Container bottom = container_pos[:, 2] - container_half_height + # Container top = container_pos[:, 2] + container_half_height + z_above_bottom = ( + block_pos[:, 2] > container_pos[:, 2] - container_half_height - z_tolerance + ) + z_within_height = block_pos[:, 2] < container_pos[:, 2] + container_half_height + + return (xy_diff < container_bottom_radius) & z_above_bottom & z_within_height + + def _is_fall(self, pose: torch.Tensor) -> torch.Tensor: + # Extract z-axis from rotation matrix (last column, first 3 elements) + pose_rz = pose[:, :3, 2] + world_z_axis = torch.tensor([0, 0, 1], dtype=pose.dtype, device=pose.device) + + # Compute dot product for each batch element + dot_product = torch.sum(pose_rz * world_z_axis, dim=-1) # Shape: (batch_size,) + + # Clamp to avoid numerical issues with arccos + dot_product = torch.clamp(dot_product, -1.0, 1.0) + + # Compute angle and check if fallen + angle = torch.arccos(dot_product) + return angle >= torch.pi / 4 From c078188773a5b16c638d0e805ac0b1ec1e5b2940 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Fri, 26 Dec 2025 20:08:12 +0800 Subject: [PATCH 62/92] Enhance the sucess condition of OrganizeTableware --- .../tasks/tableware/organize_tableware.py | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py b/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py index b42d905f..8284525f 100644 --- a/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py +++ b/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py @@ -36,10 +36,10 @@ def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): # Define target positions for different tableware types # Left side: fork, Right side: spoon self.fork_target_pos = torch.tensor( - [0.65, -0.1, 0.86], dtype=torch.float32, device=self.device + [0.725, -0.1, 0.86], dtype=torch.float32, device=self.device ) self.spoon_target_pos = torch.tensor( - [0.85, -0.1, 0.86], dtype=torch.float32, device=self.device + [0.825, 0.1, 0.86], dtype=torch.float32, device=self.device ) def is_task_success(self, **kwargs) -> torch.Tensor: @@ -48,6 +48,7 @@ def is_task_success(self, **kwargs) -> torch.Tensor: The task is successful if: 1. Fork is placed in the left target area 2. Spoon is placed in the right target area + 3. Both fork and spoon are oriented towards x-axis Args: **kwargs: Additional arguments for task-specific success criteria. @@ -68,7 +69,7 @@ def is_task_success(self, **kwargs) -> torch.Tensor: # Extract positions fork_pos = fork_pose[:, :3, 3] # (num_envs, 3) - spoon_pos = spoon_pose[:, :3, 3] # (num_envs, 3) + spoon_pos = spoon_pose[:, :3, 3] # Tolerance for checking if objects are in target area xy_tolerance = torch.tensor( @@ -92,7 +93,29 @@ def is_task_success(self, **kwargs) -> torch.Tensor: spoon_xy_diff < xy_tolerance.unsqueeze(0), dim=1 ) & (spoon_z_diff < z_tolerance) - # Both must be in their target areas - success = fork_in_target & spoon_in_target + # Check orientation: both fork and spoon should be oriented towards x-axis + fork_oriented = self._is_oriented_towards_x(fork_pose) + spoon_oriented = self._is_oriented_towards_x(spoon_pose) + + # Both must be in their target areas and correctly oriented + success = fork_in_target & spoon_in_target & fork_oriented & spoon_oriented return success + + def _is_oriented_towards_x(self, pose: torch.Tensor) -> torch.Tensor: + # Extract x-axis from rotation matrix (first column, first 3 elements) + pose_rx = pose[:, :3, 0] # (num_envs, 3) + world_x_axis = torch.tensor([1, 0, 0], dtype=pose.dtype, device=pose.device) + + # Compute dot product for each batch element + dot_product = torch.sum(pose_rx * world_x_axis, dim=-1) # (num_envs,) + + # Clamp to avoid numerical issues with arccos + dot_product = torch.clamp(dot_product, -1.0, 1.0) + + # Compute angle between object x-axis and world x-axis + angle = torch.arccos(dot_product) + + # Angle difference should be less than pi/6 + orientation_tolerance = torch.pi / 6 + return angle < orientation_tolerance From 89ec072ee0207c39bea1d273001f40b29b2cc097 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Fri, 26 Dec 2025 20:08:12 +0800 Subject: [PATCH 63/92] Enhance the sucess condition of OrganizeTableware --- .../tasks/tableware/organize_tableware.py | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py b/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py index b42d905f..8284525f 100644 --- a/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py +++ b/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py @@ -36,10 +36,10 @@ def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): # Define target positions for different tableware types # Left side: fork, Right side: spoon self.fork_target_pos = torch.tensor( - [0.65, -0.1, 0.86], dtype=torch.float32, device=self.device + [0.725, -0.1, 0.86], dtype=torch.float32, device=self.device ) self.spoon_target_pos = torch.tensor( - [0.85, -0.1, 0.86], dtype=torch.float32, device=self.device + [0.825, 0.1, 0.86], dtype=torch.float32, device=self.device ) def is_task_success(self, **kwargs) -> torch.Tensor: @@ -48,6 +48,7 @@ def is_task_success(self, **kwargs) -> torch.Tensor: The task is successful if: 1. Fork is placed in the left target area 2. Spoon is placed in the right target area + 3. Both fork and spoon are oriented towards x-axis Args: **kwargs: Additional arguments for task-specific success criteria. @@ -68,7 +69,7 @@ def is_task_success(self, **kwargs) -> torch.Tensor: # Extract positions fork_pos = fork_pose[:, :3, 3] # (num_envs, 3) - spoon_pos = spoon_pose[:, :3, 3] # (num_envs, 3) + spoon_pos = spoon_pose[:, :3, 3] # Tolerance for checking if objects are in target area xy_tolerance = torch.tensor( @@ -92,7 +93,29 @@ def is_task_success(self, **kwargs) -> torch.Tensor: spoon_xy_diff < xy_tolerance.unsqueeze(0), dim=1 ) & (spoon_z_diff < z_tolerance) - # Both must be in their target areas - success = fork_in_target & spoon_in_target + # Check orientation: both fork and spoon should be oriented towards x-axis + fork_oriented = self._is_oriented_towards_x(fork_pose) + spoon_oriented = self._is_oriented_towards_x(spoon_pose) + + # Both must be in their target areas and correctly oriented + success = fork_in_target & spoon_in_target & fork_oriented & spoon_oriented return success + + def _is_oriented_towards_x(self, pose: torch.Tensor) -> torch.Tensor: + # Extract x-axis from rotation matrix (first column, first 3 elements) + pose_rx = pose[:, :3, 0] # (num_envs, 3) + world_x_axis = torch.tensor([1, 0, 0], dtype=pose.dtype, device=pose.device) + + # Compute dot product for each batch element + dot_product = torch.sum(pose_rx * world_x_axis, dim=-1) # (num_envs,) + + # Clamp to avoid numerical issues with arccos + dot_product = torch.clamp(dot_product, -1.0, 1.0) + + # Compute angle between object x-axis and world x-axis + angle = torch.arccos(dot_product) + + # Angle difference should be less than pi/6 + orientation_tolerance = torch.pi / 6 + return angle < orientation_tolerance From a8112864bf54d140dbb0a74701176a88552a2d02 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Fri, 26 Dec 2025 20:15:35 +0800 Subject: [PATCH 64/92] Remove OrganizeTableware since it have --- .../gym/organize_tableware/gym_config.json | 394 ------------------ embodichain/lab/gym/envs/__init__.py | 3 - .../tasks/tableware/organize_tableware.py | 121 ------ 3 files changed, 518 deletions(-) delete mode 100644 configs/gym/organize_tableware/gym_config.json delete mode 100644 embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py diff --git a/configs/gym/organize_tableware/gym_config.json b/configs/gym/organize_tableware/gym_config.json deleted file mode 100644 index d372f0f9..00000000 --- a/configs/gym/organize_tableware/gym_config.json +++ /dev/null @@ -1,394 +0,0 @@ -{ - "id": "OrganizeTableware-v1", - "max_episodes": 5, - "env": { - "events": { - "random_light": { - "func": "randomize_light", - "mode": "interval", - "interval_step": 10, - "params": { - "entity_cfg": {"uid": "light_1"}, - "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], - "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], - "intensity_range": [50.0, 100.0] - } - }, - "init_fork_pose": { - "func": "randomize_rigid_object_pose", - "mode": "reset", - "params": { - "entity_cfg": {"uid": "fork"}, - "position_range": [[0.66, -0.15, 0.86], [0.74, -0.05, 0.86]], - "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], - "relative_position": false - } - }, - "init_spoon_pose": { - "func": "randomize_rigid_object_pose", - "mode": "reset", - "params": { - "entity_cfg": {"uid": "spoon"}, - "position_range": [[0.76, -0.15, 0.86], [0.84, -0.05, 0.86]], - "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], - "relative_position": false - } - }, - "prepare_extra_attr": { - "func": "prepare_extra_attr", - "mode": "reset", - "params": { - "attrs": [ - { - "name": "object_lengths", - "mode": "callable", - "entity_uids": "all_objects", - "func_name": "compute_object_length", - "func_kwargs": { - "is_svd_frame": true, - "sample_points": 5000 - } - }, - { - "name": "left_arm_base_pose", - "mode": "callable", - "entity_cfg": { - "uid": "CobotMagic" - }, - "func_name": "get_link_pose", - "func_kwargs": { - "link_name": "left_arm_base", - "to_matrix": true - } - }, - { - "name": "right_arm_base_pose", - "mode": "callable", - "entity_cfg": { - "uid": "CobotMagic" - }, - "func_name": "get_link_pose", - "func_kwargs": { - "link_name": "right_arm_base", - "to_matrix": true - } - } - ] - } - }, - "register_info_to_env": { - "func": "register_info_to_env", - "mode": "reset", - "params": { - "registry": [ - { - "entity_cfg": { - "uid": "fork" - }, - "pose_register_params": { - "compute_relative": false, - "compute_pose_object_to_arena": true, - "to_matrix": true - } - }, - { - "entity_cfg": { - "uid": "spoon" - }, - "pose_register_params": { - "compute_relative": false, - "compute_pose_object_to_arena": true, - "to_matrix": true - } - }, - { - "entity_cfg": { - "uid": "CobotMagic", - "control_parts": ["left_arm"] - }, - "attrs": ["left_arm_base_pose"], - "pose_register_params": { - "compute_relative": "spoon", - "compute_pose_object_to_arena": false, - "to_matrix": true - }, - "prefix": false - }, - { - "entity_cfg": { - "uid": "CobotMagic", - "control_parts": ["right_arm"] - }, - "attrs": ["right_arm_base_pose"], - "pose_register_params": { - "compute_relative": "fork", - "compute_pose_object_to_arena": false, - "to_matrix": true - }, - "prefix": false - } - ], - "registration": "affordance_datas", - "sim_update": true - } - }, - "random_table_material": { - "func": "randomize_visual_material", - "mode": "interval", - "interval_step": 2, - "params": { - "entity_cfg": {"uid": "table"}, - "random_texture_prob": 0.5, - "texture_path": "CocoBackground/coco", - "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] - } - }, - "random_robot_material": { - "func": "randomize_visual_material", - "mode": "interval", - "interval_step": 5, - "params": { - "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, - "random_texture_prob": 0.5, - "texture_path": "CocoBackground/coco", - "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] - } - }, - "random_camera_intrinsics": { - "func": "randomize_camera_intrinsics", - "mode": "reset", - "params": { - "entity_cfg": {"uid": "cam_high"}, - "focal_x_range": [-50, 50], - "focal_y_range": [-50, 50] - } - }, - "random_robot_init_eef_pose": { - "func": "randomize_robot_eef_pose", - "mode": "reset", - "params": { - "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, - "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] - } - }, - "record_camera": { - "func": "record_camera_data", - "mode": "interval", - "interval_step": 1, - "params": { - "name": "cam1", - "resolution": [320, 240], - "eye": [2, 0, 2], - "target": [0.5, 0, 1] - } - } - }, - "observations": { - "norm_robot_eef_joint": { - "func": "normalize_robot_joint_data", - "mode": "modify", - "name": "robot/qpos", - "params": { - "joint_ids": [12, 13, 14, 15] - } - }, - "fork_pose": { - "func": "get_rigid_object_pose", - "mode": "add", - "name": "fork_pose", - "params": { - "entity_cfg": {"uid": "fork"} - } - }, - "spoon_pose": { - "func": "get_rigid_object_pose", - "mode": "add", - "name": "spoon_pose", - "params": { - "entity_cfg": {"uid": "spoon"} - } - }, - "cam_high_semantic_mask_l": { - "func": "compute_semantic_mask", - "mode": "add", - "name": "sensor/cam_high/semantic_mask_l", - "params": { - "entity_cfg": {"uid": "cam_high"}, - "foreground_uids": ["fork", "spoon"] - } - }, - "cam_high_semantic_mask_r": { - "func": "compute_semantic_mask", - "mode": "add", - "name": "sensor/cam_high/semantic_mask_r", - "params": { - "entity_cfg": {"uid": "cam_high"}, - "foreground_uids": ["fork", "spoon"], - "is_right": true - } - }, - "cam_left_semantic_mask": { - "func": "compute_semantic_mask", - "mode": "add", - "name": "sensor/cam_left_wrist/semantic_mask_l", - "params": { - "entity_cfg": {"uid": "cam_left_wrist"}, - "foreground_uids": ["fork", "spoon"] - } - }, - "cam_right_semantic_mask": { - "func": "compute_semantic_mask", - "mode": "add", - "name": "sensor/cam_right_wrist/semantic_mask_l", - "params": { - "entity_cfg": {"uid": "cam_right_wrist"}, - "foreground_uids": ["fork", "spoon"] - } - } - }, - "dataset": { - "robot_meta": { - "arm_dofs": 12, - "control_freq": 25, - "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], - "min_len_steps": 5 - } - } - }, - "robot": { - "uid": "CobotMagic", - "robot_type": "CobotMagic", - "init_pos": [0.0, 0.0, 0.7775], - "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] - }, - "sensor": [ - { - "sensor_type": "StereoCamera", - "uid": "cam_high", - "width": 960, - "height": 540, - "enable_mask": true, - "enable_depth": true, - "left_to_right_pos": [0.059684025824163614, 0, 0], - "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], - "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], - "extrinsics": { - "eye": [0.35368482807598, 0.014695524383058989, 1.4517046071614774], - "target": [0.7186357573287919, -0.054534732904795505, 0.5232553674540066], - "up": [0.9306678549330372, -0.0005600064212467153, 0.3658647703553347] - } - }, - { - "sensor_type": "Camera", - "uid": "cam_right_wrist", - "width": 640, - "height": 480, - "enable_mask": true, - "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], - "extrinsics": { - "parent": "right_link6", - "pos": [-0.08, 0.0, 0.04], - "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] - } - }, - { - "sensor_type": "Camera", - "uid": "cam_left_wrist", - "width": 640, - "height": 480, - "enable_mask": true, - "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], - "extrinsics": { - "parent": "left_link6", - "pos": [-0.08, 0.0, 0.04], - "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] - } - } - ], - "light": { - "direct": [ - { - "uid": "light_1", - "light_type": "point", - "color": [1.0, 1.0, 1.0], - "intensity": 50.0, - "init_pos": [2, 0, 2], - "radius": 10.0 - } - ] - }, - "background": [ - { - "uid": "table", - "shape": { - "shape_type": "Mesh", - "fpath": "CircleTableSimple/circle_table_simple.ply" - }, - "attrs" : { - "mass": 10.0, - "static_friction": 0.95, - "dynamic_friction": 0.9, - "restitution": 0.01 - }, - "body_scale": [1, 1, 1], - "body_type": "kinematic", - "init_pos": [0.725, 0.0, 0.825], - "init_rot": [0, 90, 0] - } - ], - "rigid_object": [ - { - "uid":"fork", - "shape": { - "shape_type": "Mesh", - "fpath": "TableWare/tableware/fork/standard_fork_scale.ply" - }, - "attrs" : { - "mass": 0.01, - "static_friction": 1.0, - "dynamic_friction": 1.0, - "restitution": 0.0, - "contact_offset": 0.003, - "rest_offset": 0.001, - "max_depenetration_velocity": 2.0, - "linear_damping": 2.0, - "angular_damping": 2.0, - "max_linear_velocity": 5.0, - "max_angular_velocity": 10.0, - "min_position_iters": 32, - "min_velocity_iters": 8 - }, - "init_pos": [0.70, -0.1, 0.86], - "init_rot": [0, 0, 0], - "body_scale":[0.75, 0.75, 1.0], - "max_convex_hull_num": 8 - }, - { - "uid":"spoon", - "shape": { - "shape_type": "Mesh", - "fpath": "TableWare/tableware/spoon/standard_spoon_a_rescale.ply" - }, - "attrs" : { - "mass": 0.01, - "static_friction": 1.0, - "dynamic_friction": 1.0, - "restitution": 0.0, - "contact_offset": 0.003, - "rest_offset": 0.001, - "max_depenetration_velocity": 2.0, - "linear_damping": 2.0, - "angular_damping": 2.0, - "max_linear_velocity": 5.0, - "max_angular_velocity": 10.0, - "min_position_iters": 32, - "min_velocity_iters": 8 - }, - "init_pos": [0.80, -0.1, 0.86], - "init_rot": [0, 0, 0], - "body_scale":[0.75, 0.75, 1.0], - "max_convex_hull_num": 8 - } - ] -} - diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py index 8bc96da9..47935c4f 100644 --- a/embodichain/lab/gym/envs/__init__.py +++ b/embodichain/lab/gym/envs/__init__.py @@ -36,9 +36,6 @@ from embodichain.lab.gym.envs.tasks.tableware.place_object_drawer import ( PlaceObjectDrawerEnv, ) -from embodichain.lab.gym.envs.tasks.tableware.organize_tableware import ( - OrganizeTablewareEnv, -) from embodichain.lab.gym.envs.tasks.tableware.stack_cups import ( StackCupsEnv, ) diff --git a/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py b/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py deleted file mode 100644 index 8284525f..00000000 --- a/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py +++ /dev/null @@ -1,121 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---------------------------------------------------------------------------- - -import torch -import numpy as np - -from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg -from embodichain.lab.gym.utils.registration import register_env -from embodichain.utils import logger - -__all__ = ["OrganizeTablewareEnv"] - - -@register_env("OrganizeTableware-v1", max_episode_steps=600) -class OrganizeTablewareEnv(EmbodiedEnv): - def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): - super().__init__(cfg, **kwargs) - - action_config = kwargs.get("action_config", None) - if action_config is not None: - self.action_config = action_config - - # Define target positions for different tableware types - # Left side: fork, Right side: spoon - self.fork_target_pos = torch.tensor( - [0.725, -0.1, 0.86], dtype=torch.float32, device=self.device - ) - self.spoon_target_pos = torch.tensor( - [0.825, 0.1, 0.86], dtype=torch.float32, device=self.device - ) - - def is_task_success(self, **kwargs) -> torch.Tensor: - """Determine if the task is successfully completed. - - The task is successful if: - 1. Fork is placed in the left target area - 2. Spoon is placed in the right target area - 3. Both fork and spoon are oriented towards x-axis - - Args: - **kwargs: Additional arguments for task-specific success criteria. - - Returns: - torch.Tensor: A boolean tensor indicating success for each environment in the batch. - """ - try: - fork = self.sim.get_rigid_object("fork") - spoon = self.sim.get_rigid_object("spoon") - except Exception as e: - logger.log_warning(f"Fork or spoon not found: {e}, returning False.") - return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) - - # Get poses - fork_pose = fork.get_local_pose(to_matrix=True) - spoon_pose = spoon.get_local_pose(to_matrix=True) - - # Extract positions - fork_pos = fork_pose[:, :3, 3] # (num_envs, 3) - spoon_pos = spoon_pose[:, :3, 3] - - # Tolerance for checking if objects are in target area - xy_tolerance = torch.tensor( - [0.08, 0.05], dtype=torch.float32, device=self.device - ) - z_tolerance = 0.05 - - # Check if fork is in left target area - fork_target = self.fork_target_pos.unsqueeze(0).repeat(self.num_envs, 1) - fork_xy_diff = torch.abs(fork_pos[:, :2] - fork_target[:, :2]) - fork_z_diff = torch.abs(fork_pos[:, 2] - fork_target[:, 2]) - fork_in_target = torch.all(fork_xy_diff < xy_tolerance.unsqueeze(0), dim=1) & ( - fork_z_diff < z_tolerance - ) - - # Check if spoon is in right target area - spoon_target = self.spoon_target_pos.unsqueeze(0).repeat(self.num_envs, 1) - spoon_xy_diff = torch.abs(spoon_pos[:, :2] - spoon_target[:, :2]) - spoon_z_diff = torch.abs(spoon_pos[:, 2] - spoon_target[:, 2]) - spoon_in_target = torch.all( - spoon_xy_diff < xy_tolerance.unsqueeze(0), dim=1 - ) & (spoon_z_diff < z_tolerance) - - # Check orientation: both fork and spoon should be oriented towards x-axis - fork_oriented = self._is_oriented_towards_x(fork_pose) - spoon_oriented = self._is_oriented_towards_x(spoon_pose) - - # Both must be in their target areas and correctly oriented - success = fork_in_target & spoon_in_target & fork_oriented & spoon_oriented - - return success - - def _is_oriented_towards_x(self, pose: torch.Tensor) -> torch.Tensor: - # Extract x-axis from rotation matrix (first column, first 3 elements) - pose_rx = pose[:, :3, 0] # (num_envs, 3) - world_x_axis = torch.tensor([1, 0, 0], dtype=pose.dtype, device=pose.device) - - # Compute dot product for each batch element - dot_product = torch.sum(pose_rx * world_x_axis, dim=-1) # (num_envs,) - - # Clamp to avoid numerical issues with arccos - dot_product = torch.clamp(dot_product, -1.0, 1.0) - - # Compute angle between object x-axis and world x-axis - angle = torch.arccos(dot_product) - - # Angle difference should be less than pi/6 - orientation_tolerance = torch.pi / 6 - return angle < orientation_tolerance From 809e0f716777b2950bdc895bd7c31b26cc0e62be Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Fri, 26 Dec 2025 20:15:35 +0800 Subject: [PATCH 65/92] Remove OrganizeTableware since it have --- .../gym/organize_tableware/gym_config.json | 394 ------------------ embodichain/lab/gym/envs/__init__.py | 3 - .../tasks/tableware/organize_tableware.py | 121 ------ 3 files changed, 518 deletions(-) delete mode 100644 configs/gym/organize_tableware/gym_config.json delete mode 100644 embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py diff --git a/configs/gym/organize_tableware/gym_config.json b/configs/gym/organize_tableware/gym_config.json deleted file mode 100644 index d372f0f9..00000000 --- a/configs/gym/organize_tableware/gym_config.json +++ /dev/null @@ -1,394 +0,0 @@ -{ - "id": "OrganizeTableware-v1", - "max_episodes": 5, - "env": { - "events": { - "random_light": { - "func": "randomize_light", - "mode": "interval", - "interval_step": 10, - "params": { - "entity_cfg": {"uid": "light_1"}, - "position_range": [[-0.5, -0.5, 2], [0.5, 0.5, 2]], - "color_range": [[0.6, 0.6, 0.6], [1, 1, 1]], - "intensity_range": [50.0, 100.0] - } - }, - "init_fork_pose": { - "func": "randomize_rigid_object_pose", - "mode": "reset", - "params": { - "entity_cfg": {"uid": "fork"}, - "position_range": [[0.66, -0.15, 0.86], [0.74, -0.05, 0.86]], - "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], - "relative_position": false - } - }, - "init_spoon_pose": { - "func": "randomize_rigid_object_pose", - "mode": "reset", - "params": { - "entity_cfg": {"uid": "spoon"}, - "position_range": [[0.76, -0.15, 0.86], [0.84, -0.05, 0.86]], - "rotation_range": [[0, 0, -0.52], [0, 0, 0.52]], - "relative_position": false - } - }, - "prepare_extra_attr": { - "func": "prepare_extra_attr", - "mode": "reset", - "params": { - "attrs": [ - { - "name": "object_lengths", - "mode": "callable", - "entity_uids": "all_objects", - "func_name": "compute_object_length", - "func_kwargs": { - "is_svd_frame": true, - "sample_points": 5000 - } - }, - { - "name": "left_arm_base_pose", - "mode": "callable", - "entity_cfg": { - "uid": "CobotMagic" - }, - "func_name": "get_link_pose", - "func_kwargs": { - "link_name": "left_arm_base", - "to_matrix": true - } - }, - { - "name": "right_arm_base_pose", - "mode": "callable", - "entity_cfg": { - "uid": "CobotMagic" - }, - "func_name": "get_link_pose", - "func_kwargs": { - "link_name": "right_arm_base", - "to_matrix": true - } - } - ] - } - }, - "register_info_to_env": { - "func": "register_info_to_env", - "mode": "reset", - "params": { - "registry": [ - { - "entity_cfg": { - "uid": "fork" - }, - "pose_register_params": { - "compute_relative": false, - "compute_pose_object_to_arena": true, - "to_matrix": true - } - }, - { - "entity_cfg": { - "uid": "spoon" - }, - "pose_register_params": { - "compute_relative": false, - "compute_pose_object_to_arena": true, - "to_matrix": true - } - }, - { - "entity_cfg": { - "uid": "CobotMagic", - "control_parts": ["left_arm"] - }, - "attrs": ["left_arm_base_pose"], - "pose_register_params": { - "compute_relative": "spoon", - "compute_pose_object_to_arena": false, - "to_matrix": true - }, - "prefix": false - }, - { - "entity_cfg": { - "uid": "CobotMagic", - "control_parts": ["right_arm"] - }, - "attrs": ["right_arm_base_pose"], - "pose_register_params": { - "compute_relative": "fork", - "compute_pose_object_to_arena": false, - "to_matrix": true - }, - "prefix": false - } - ], - "registration": "affordance_datas", - "sim_update": true - } - }, - "random_table_material": { - "func": "randomize_visual_material", - "mode": "interval", - "interval_step": 2, - "params": { - "entity_cfg": {"uid": "table"}, - "random_texture_prob": 0.5, - "texture_path": "CocoBackground/coco", - "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] - } - }, - "random_robot_material": { - "func": "randomize_visual_material", - "mode": "interval", - "interval_step": 5, - "params": { - "entity_cfg": {"uid": "CobotMagic", "link_names": [".*"]}, - "random_texture_prob": 0.5, - "texture_path": "CocoBackground/coco", - "base_color_range": [[0.2, 0.2, 0.2], [1.0, 1.0, 1.0]] - } - }, - "random_camera_intrinsics": { - "func": "randomize_camera_intrinsics", - "mode": "reset", - "params": { - "entity_cfg": {"uid": "cam_high"}, - "focal_x_range": [-50, 50], - "focal_y_range": [-50, 50] - } - }, - "random_robot_init_eef_pose": { - "func": "randomize_robot_eef_pose", - "mode": "reset", - "params": { - "entity_cfg": {"uid": "CobotMagic", "control_parts": ["left_arm", "right_arm"]}, - "position_range": [[-0.01, -0.01, -0.01], [0.01, 0.01, 0]] - } - }, - "record_camera": { - "func": "record_camera_data", - "mode": "interval", - "interval_step": 1, - "params": { - "name": "cam1", - "resolution": [320, 240], - "eye": [2, 0, 2], - "target": [0.5, 0, 1] - } - } - }, - "observations": { - "norm_robot_eef_joint": { - "func": "normalize_robot_joint_data", - "mode": "modify", - "name": "robot/qpos", - "params": { - "joint_ids": [12, 13, 14, 15] - } - }, - "fork_pose": { - "func": "get_rigid_object_pose", - "mode": "add", - "name": "fork_pose", - "params": { - "entity_cfg": {"uid": "fork"} - } - }, - "spoon_pose": { - "func": "get_rigid_object_pose", - "mode": "add", - "name": "spoon_pose", - "params": { - "entity_cfg": {"uid": "spoon"} - } - }, - "cam_high_semantic_mask_l": { - "func": "compute_semantic_mask", - "mode": "add", - "name": "sensor/cam_high/semantic_mask_l", - "params": { - "entity_cfg": {"uid": "cam_high"}, - "foreground_uids": ["fork", "spoon"] - } - }, - "cam_high_semantic_mask_r": { - "func": "compute_semantic_mask", - "mode": "add", - "name": "sensor/cam_high/semantic_mask_r", - "params": { - "entity_cfg": {"uid": "cam_high"}, - "foreground_uids": ["fork", "spoon"], - "is_right": true - } - }, - "cam_left_semantic_mask": { - "func": "compute_semantic_mask", - "mode": "add", - "name": "sensor/cam_left_wrist/semantic_mask_l", - "params": { - "entity_cfg": {"uid": "cam_left_wrist"}, - "foreground_uids": ["fork", "spoon"] - } - }, - "cam_right_semantic_mask": { - "func": "compute_semantic_mask", - "mode": "add", - "name": "sensor/cam_right_wrist/semantic_mask_l", - "params": { - "entity_cfg": {"uid": "cam_right_wrist"}, - "foreground_uids": ["fork", "spoon"] - } - } - }, - "dataset": { - "robot_meta": { - "arm_dofs": 12, - "control_freq": 25, - "control_parts": ["left_arm", "left_eef", "right_arm", "right_eef"], - "min_len_steps": 5 - } - } - }, - "robot": { - "uid": "CobotMagic", - "robot_type": "CobotMagic", - "init_pos": [0.0, 0.0, 0.7775], - "init_qpos": [-0.3,0.3,1.0,1.0,-1.2,-1.2,0.0,0.0,0.6,0.6,0.0,0.0,0.05,0.05,0.05,0.05] - }, - "sensor": [ - { - "sensor_type": "StereoCamera", - "uid": "cam_high", - "width": 960, - "height": 540, - "enable_mask": true, - "enable_depth": true, - "left_to_right_pos": [0.059684025824163614, 0, 0], - "intrinsics": [453.851402686215, 453.8347628855552, 469.827725021235, 258.6656181845155], - "intrinsics_right": [453.4536601653505, 453.3306024582175, 499.13697412367776, 297.7176248477935], - "extrinsics": { - "eye": [0.35368482807598, 0.014695524383058989, 1.4517046071614774], - "target": [0.7186357573287919, -0.054534732904795505, 0.5232553674540066], - "up": [0.9306678549330372, -0.0005600064212467153, 0.3658647703553347] - } - }, - { - "sensor_type": "Camera", - "uid": "cam_right_wrist", - "width": 640, - "height": 480, - "enable_mask": true, - "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], - "extrinsics": { - "parent": "right_link6", - "pos": [-0.08, 0.0, 0.04], - "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] - } - }, - { - "sensor_type": "Camera", - "uid": "cam_left_wrist", - "width": 640, - "height": 480, - "enable_mask": true, - "intrinsics": [488.1665344238281, 488.1665344238281, 322.7323303222656, 213.17434692382812], - "extrinsics": { - "parent": "left_link6", - "pos": [-0.08, 0.0, 0.04], - "quat": [0.15304635, 0.69034543, -0.69034543, -0.15304635] - } - } - ], - "light": { - "direct": [ - { - "uid": "light_1", - "light_type": "point", - "color": [1.0, 1.0, 1.0], - "intensity": 50.0, - "init_pos": [2, 0, 2], - "radius": 10.0 - } - ] - }, - "background": [ - { - "uid": "table", - "shape": { - "shape_type": "Mesh", - "fpath": "CircleTableSimple/circle_table_simple.ply" - }, - "attrs" : { - "mass": 10.0, - "static_friction": 0.95, - "dynamic_friction": 0.9, - "restitution": 0.01 - }, - "body_scale": [1, 1, 1], - "body_type": "kinematic", - "init_pos": [0.725, 0.0, 0.825], - "init_rot": [0, 90, 0] - } - ], - "rigid_object": [ - { - "uid":"fork", - "shape": { - "shape_type": "Mesh", - "fpath": "TableWare/tableware/fork/standard_fork_scale.ply" - }, - "attrs" : { - "mass": 0.01, - "static_friction": 1.0, - "dynamic_friction": 1.0, - "restitution": 0.0, - "contact_offset": 0.003, - "rest_offset": 0.001, - "max_depenetration_velocity": 2.0, - "linear_damping": 2.0, - "angular_damping": 2.0, - "max_linear_velocity": 5.0, - "max_angular_velocity": 10.0, - "min_position_iters": 32, - "min_velocity_iters": 8 - }, - "init_pos": [0.70, -0.1, 0.86], - "init_rot": [0, 0, 0], - "body_scale":[0.75, 0.75, 1.0], - "max_convex_hull_num": 8 - }, - { - "uid":"spoon", - "shape": { - "shape_type": "Mesh", - "fpath": "TableWare/tableware/spoon/standard_spoon_a_rescale.ply" - }, - "attrs" : { - "mass": 0.01, - "static_friction": 1.0, - "dynamic_friction": 1.0, - "restitution": 0.0, - "contact_offset": 0.003, - "rest_offset": 0.001, - "max_depenetration_velocity": 2.0, - "linear_damping": 2.0, - "angular_damping": 2.0, - "max_linear_velocity": 5.0, - "max_angular_velocity": 10.0, - "min_position_iters": 32, - "min_velocity_iters": 8 - }, - "init_pos": [0.80, -0.1, 0.86], - "init_rot": [0, 0, 0], - "body_scale":[0.75, 0.75, 1.0], - "max_convex_hull_num": 8 - } - ] -} - diff --git a/embodichain/lab/gym/envs/__init__.py b/embodichain/lab/gym/envs/__init__.py index 8bc96da9..47935c4f 100644 --- a/embodichain/lab/gym/envs/__init__.py +++ b/embodichain/lab/gym/envs/__init__.py @@ -36,9 +36,6 @@ from embodichain.lab.gym.envs.tasks.tableware.place_object_drawer import ( PlaceObjectDrawerEnv, ) -from embodichain.lab.gym.envs.tasks.tableware.organize_tableware import ( - OrganizeTablewareEnv, -) from embodichain.lab.gym.envs.tasks.tableware.stack_cups import ( StackCupsEnv, ) diff --git a/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py b/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py deleted file mode 100644 index 8284525f..00000000 --- a/embodichain/lab/gym/envs/tasks/tableware/organize_tableware.py +++ /dev/null @@ -1,121 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright (c) 2021-2025 DexForce Technology Co., Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ---------------------------------------------------------------------------- - -import torch -import numpy as np - -from embodichain.lab.gym.envs import EmbodiedEnv, EmbodiedEnvCfg -from embodichain.lab.gym.utils.registration import register_env -from embodichain.utils import logger - -__all__ = ["OrganizeTablewareEnv"] - - -@register_env("OrganizeTableware-v1", max_episode_steps=600) -class OrganizeTablewareEnv(EmbodiedEnv): - def __init__(self, cfg: EmbodiedEnvCfg = None, **kwargs): - super().__init__(cfg, **kwargs) - - action_config = kwargs.get("action_config", None) - if action_config is not None: - self.action_config = action_config - - # Define target positions for different tableware types - # Left side: fork, Right side: spoon - self.fork_target_pos = torch.tensor( - [0.725, -0.1, 0.86], dtype=torch.float32, device=self.device - ) - self.spoon_target_pos = torch.tensor( - [0.825, 0.1, 0.86], dtype=torch.float32, device=self.device - ) - - def is_task_success(self, **kwargs) -> torch.Tensor: - """Determine if the task is successfully completed. - - The task is successful if: - 1. Fork is placed in the left target area - 2. Spoon is placed in the right target area - 3. Both fork and spoon are oriented towards x-axis - - Args: - **kwargs: Additional arguments for task-specific success criteria. - - Returns: - torch.Tensor: A boolean tensor indicating success for each environment in the batch. - """ - try: - fork = self.sim.get_rigid_object("fork") - spoon = self.sim.get_rigid_object("spoon") - except Exception as e: - logger.log_warning(f"Fork or spoon not found: {e}, returning False.") - return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) - - # Get poses - fork_pose = fork.get_local_pose(to_matrix=True) - spoon_pose = spoon.get_local_pose(to_matrix=True) - - # Extract positions - fork_pos = fork_pose[:, :3, 3] # (num_envs, 3) - spoon_pos = spoon_pose[:, :3, 3] - - # Tolerance for checking if objects are in target area - xy_tolerance = torch.tensor( - [0.08, 0.05], dtype=torch.float32, device=self.device - ) - z_tolerance = 0.05 - - # Check if fork is in left target area - fork_target = self.fork_target_pos.unsqueeze(0).repeat(self.num_envs, 1) - fork_xy_diff = torch.abs(fork_pos[:, :2] - fork_target[:, :2]) - fork_z_diff = torch.abs(fork_pos[:, 2] - fork_target[:, 2]) - fork_in_target = torch.all(fork_xy_diff < xy_tolerance.unsqueeze(0), dim=1) & ( - fork_z_diff < z_tolerance - ) - - # Check if spoon is in right target area - spoon_target = self.spoon_target_pos.unsqueeze(0).repeat(self.num_envs, 1) - spoon_xy_diff = torch.abs(spoon_pos[:, :2] - spoon_target[:, :2]) - spoon_z_diff = torch.abs(spoon_pos[:, 2] - spoon_target[:, 2]) - spoon_in_target = torch.all( - spoon_xy_diff < xy_tolerance.unsqueeze(0), dim=1 - ) & (spoon_z_diff < z_tolerance) - - # Check orientation: both fork and spoon should be oriented towards x-axis - fork_oriented = self._is_oriented_towards_x(fork_pose) - spoon_oriented = self._is_oriented_towards_x(spoon_pose) - - # Both must be in their target areas and correctly oriented - success = fork_in_target & spoon_in_target & fork_oriented & spoon_oriented - - return success - - def _is_oriented_towards_x(self, pose: torch.Tensor) -> torch.Tensor: - # Extract x-axis from rotation matrix (first column, first 3 elements) - pose_rx = pose[:, :3, 0] # (num_envs, 3) - world_x_axis = torch.tensor([1, 0, 0], dtype=pose.dtype, device=pose.device) - - # Compute dot product for each batch element - dot_product = torch.sum(pose_rx * world_x_axis, dim=-1) # (num_envs,) - - # Clamp to avoid numerical issues with arccos - dot_product = torch.clamp(dot_product, -1.0, 1.0) - - # Compute angle between object x-axis and world x-axis - angle = torch.arccos(dot_product) - - # Angle difference should be less than pi/6 - orientation_tolerance = torch.pi / 6 - return angle < orientation_tolerance From 738af8c8136f315e66540f93980b0c704e3324b7 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Sat, 27 Dec 2025 11:24:03 +0800 Subject: [PATCH 66/92] Enhance sucess condition --- configs/gym/stack_cups/gym_config.json | 1 + .../tasks/tableware/match_object_container.py | 20 +++++++++---------- .../envs/tasks/tableware/stack_blocks_two.py | 4 ++-- .../gym/envs/tasks/tableware/stack_cups.py | 2 +- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/configs/gym/stack_cups/gym_config.json b/configs/gym/stack_cups/gym_config.json index 6bc0c791..61e5881d 100644 --- a/configs/gym/stack_cups/gym_config.json +++ b/configs/gym/stack_cups/gym_config.json @@ -392,3 +392,4 @@ ] } + diff --git a/embodichain/lab/gym/envs/tasks/tableware/match_object_container.py b/embodichain/lab/gym/envs/tasks/tableware/match_object_container.py index 903221b5..2af1d374 100644 --- a/embodichain/lab/gym/envs/tasks/tableware/match_object_container.py +++ b/embodichain/lab/gym/envs/tasks/tableware/match_object_container.py @@ -75,17 +75,15 @@ def is_task_success(self, **kwargs) -> torch.Tensor: container_cube_pos = container_cube_pose[:, :3, 3] container_sphere_pos = container_sphere_pose[:, :3, 3] - container_cube_up = ~self._is_fall(container_cube_pose) - container_sphere_up = ~self._is_fall(container_sphere_pose) + container_cube_fallen = self._is_fall(container_cube_pose) + container_sphere_fallen = self._is_fall(container_sphere_pose) # Check if blocks are inside their matching containers - # Note: container_pos[:, 2] is the geometric center (center of mass) of the container - container_bottom_radius = 0.1067 # Bottom inner radius in meters - z_tolerance = 0.05 # Vertical tolerance for bottom check - container_height = 0.068 # Container height in meters - container_half_height = ( - container_height / 2 - ) # Half height for center-based calculation + # I got radius and height from the container_metal.obj file + container_bottom_radius = 0.1067 # Inner radius + z_tolerance = 0.05 # Vertical tolerance + container_height = 0.068 # Container height + container_half_height = container_height / 2 # Check if blocks are in their matching containers cube_1_in_container = self._is_block_in_container( @@ -123,8 +121,8 @@ def is_task_success(self, **kwargs) -> torch.Tensor: & cube_2_in_container & sphere_1_in_container & sphere_2_in_container - & container_cube_up - & container_sphere_up + & ~container_cube_fallen + & ~container_sphere_fallen ) return success diff --git a/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py b/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py index 9e06dd21..065e96a7 100644 --- a/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py +++ b/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py @@ -50,8 +50,8 @@ def is_task_success(self, **kwargs) -> torch.Tensor: try: block1 = self.sim.get_rigid_object("block_1") block2 = self.sim.get_rigid_object("block_2") - except: - logger.log_warning("Block1 or Block2 not found, returning False.") + except Exception as e: + logger.log_warning(f"Block1 or Block2 not found: {e}, returning False.") return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) # Get poses diff --git a/embodichain/lab/gym/envs/tasks/tableware/stack_cups.py b/embodichain/lab/gym/envs/tasks/tableware/stack_cups.py index b025e3f0..99c3937d 100644 --- a/embodichain/lab/gym/envs/tasks/tableware/stack_cups.py +++ b/embodichain/lab/gym/envs/tasks/tableware/stack_cups.py @@ -62,7 +62,7 @@ def is_task_success(self, **kwargs) -> torch.Tensor: cup1_pos = cup1_pose[:, :3, 3] # (num_envs, 3) cup2_pos = cup2_pose[:, :3, 3] # (num_envs, 3) - # Check if cups haven't fallen (orientation check) + # Check if cups haven't fallen cup1_fallen = self._is_fall(cup1_pose) cup2_fallen = self._is_fall(cup2_pose) From ca1f37e51b65b9e8f66ebee6ac9a50e936552143 Mon Sep 17 00:00:00 2001 From: yangchen73 <122090643@link.cuhk.edu.cn> Date: Sat, 27 Dec 2025 11:24:03 +0800 Subject: [PATCH 67/92] Enhance sucess condition --- configs/gym/stack_cups/gym_config.json | 1 + .../tasks/tableware/match_object_container.py | 20 +++++++++---------- .../envs/tasks/tableware/stack_blocks_two.py | 4 ++-- .../gym/envs/tasks/tableware/stack_cups.py | 2 +- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/configs/gym/stack_cups/gym_config.json b/configs/gym/stack_cups/gym_config.json index 6bc0c791..61e5881d 100644 --- a/configs/gym/stack_cups/gym_config.json +++ b/configs/gym/stack_cups/gym_config.json @@ -392,3 +392,4 @@ ] } + diff --git a/embodichain/lab/gym/envs/tasks/tableware/match_object_container.py b/embodichain/lab/gym/envs/tasks/tableware/match_object_container.py index 903221b5..2af1d374 100644 --- a/embodichain/lab/gym/envs/tasks/tableware/match_object_container.py +++ b/embodichain/lab/gym/envs/tasks/tableware/match_object_container.py @@ -75,17 +75,15 @@ def is_task_success(self, **kwargs) -> torch.Tensor: container_cube_pos = container_cube_pose[:, :3, 3] container_sphere_pos = container_sphere_pose[:, :3, 3] - container_cube_up = ~self._is_fall(container_cube_pose) - container_sphere_up = ~self._is_fall(container_sphere_pose) + container_cube_fallen = self._is_fall(container_cube_pose) + container_sphere_fallen = self._is_fall(container_sphere_pose) # Check if blocks are inside their matching containers - # Note: container_pos[:, 2] is the geometric center (center of mass) of the container - container_bottom_radius = 0.1067 # Bottom inner radius in meters - z_tolerance = 0.05 # Vertical tolerance for bottom check - container_height = 0.068 # Container height in meters - container_half_height = ( - container_height / 2 - ) # Half height for center-based calculation + # I got radius and height from the container_metal.obj file + container_bottom_radius = 0.1067 # Inner radius + z_tolerance = 0.05 # Vertical tolerance + container_height = 0.068 # Container height + container_half_height = container_height / 2 # Check if blocks are in their matching containers cube_1_in_container = self._is_block_in_container( @@ -123,8 +121,8 @@ def is_task_success(self, **kwargs) -> torch.Tensor: & cube_2_in_container & sphere_1_in_container & sphere_2_in_container - & container_cube_up - & container_sphere_up + & ~container_cube_fallen + & ~container_sphere_fallen ) return success diff --git a/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py b/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py index 9e06dd21..065e96a7 100644 --- a/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py +++ b/embodichain/lab/gym/envs/tasks/tableware/stack_blocks_two.py @@ -50,8 +50,8 @@ def is_task_success(self, **kwargs) -> torch.Tensor: try: block1 = self.sim.get_rigid_object("block_1") block2 = self.sim.get_rigid_object("block_2") - except: - logger.log_warning("Block1 or Block2 not found, returning False.") + except Exception as e: + logger.log_warning(f"Block1 or Block2 not found: {e}, returning False.") return torch.zeros(self.num_envs, dtype=torch.bool, device=self.device) # Get poses diff --git a/embodichain/lab/gym/envs/tasks/tableware/stack_cups.py b/embodichain/lab/gym/envs/tasks/tableware/stack_cups.py index b025e3f0..99c3937d 100644 --- a/embodichain/lab/gym/envs/tasks/tableware/stack_cups.py +++ b/embodichain/lab/gym/envs/tasks/tableware/stack_cups.py @@ -62,7 +62,7 @@ def is_task_success(self, **kwargs) -> torch.Tensor: cup1_pos = cup1_pose[:, :3, 3] # (num_envs, 3) cup2_pos = cup2_pose[:, :3, 3] # (num_envs, 3) - # Check if cups haven't fallen (orientation check) + # Check if cups haven't fallen cup1_fallen = self._is_fall(cup1_pose) cup2_fallen = self._is_fall(cup2_pose) From 62026602ccaf739f6c49e83a580aff1ee0c8c4ba Mon Sep 17 00:00:00 2001 From: Jietao Chen <61959467+chase6305@users.noreply.github.com> Date: Sat, 27 Dec 2025 17:59:32 +0800 Subject: [PATCH 68/92] Add workspace analyzer and user docs (#14) Co-authored-by: Jietao Chen Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: yuecideng --- .../workspace_analyzer/joint_workspace.jpg | Bin 0 -> 1100402 bytes .../workspace_analyzer/plane_workspace1.jpg | Bin 0 -> 641119 bytes .../workspace_analyzer/plane_workspace2.jpg | Bin 0 -> 494331 bytes .../workspace_analyzer/pose_workspace1.jpg | Bin 0 -> 670952 bytes .../workspace_analyzer/pose_workspace2.jpg | Bin 0 -> 488181 bytes .../features/workspace_analyzer/caches.md | 212 ++ .../features/workspace_analyzer/configs.md | 648 +++++ .../workspace_analyzer/constraints.md | 415 ++++ .../features/workspace_analyzer/index.rst | 16 + .../features/workspace_analyzer/metrics.md | 169 ++ .../features/workspace_analyzer/samplers.md | 156 ++ .../workspace_analyzer/visualizers.md | 146 ++ .../workspace_analyzer/workspace_analyzer.md | 230 ++ docs/source/index.rst | 7 + docs/source/resources/roadmap.md | 1 - embodichain/lab/sim/robots/dexforce_w1/cfg.py | 50 +- .../utility/workspace_analyzer/__init__.py | 67 + .../workspace_analyzer/caches/__init__.py | 31 + .../workspace_analyzer/caches/base_cache.py | 76 + .../caches/cache_manager.py | 105 + .../workspace_analyzer/caches/cache_utils.py | 277 +++ .../workspace_analyzer/caches/disk_cache.py | 197 ++ .../workspace_analyzer/caches/memory_cache.py | 78 + .../workspace_analyzer/configs/__init__.py | 52 + .../configs/cache_config.py | 41 + .../configs/dimension_constraint.py | 45 + .../configs/metric_config.py | 114 + .../configs/sampling_config.py | 81 + .../configs/visualization_config.py | 96 + .../constraints/__init__.py | 24 + .../constraints/base_constraint.py | 199 ++ .../constraints/workspace_constraint.py | 280 +++ .../workspace_analyzer/metrics/__init__.py | 35 + .../workspace_analyzer/metrics/base_metric.py | 83 + .../metrics/density_metric.py | 152 ++ .../metrics/manipulability_metric.py | 151 ++ .../metrics/reachability_metric.py | 137 ++ .../workspace_analyzer/samplers/__init__.py | 64 + .../samplers/base_sampler.py | 242 ++ .../samplers/gaussian_sampler.py | 265 ++ .../samplers/halton_sampler.py | 281 +++ .../samplers/importance_sampler.py | 274 +++ .../samplers/iniform_sampler.py | 169 ++ .../samplers/lhs_sampler.py | 226 ++ .../samplers/random_sampler.py | 112 + .../samplers/sampler_factory.py | 276 +++ .../samplers/sobol_sampler.py | 216 ++ .../visualizers/__init__.py | 56 + .../visualizers/axis_visualizer.py | 478 ++++ .../visualizers/base_visualizer.py | 331 +++ .../visualizers/point_cloud_visualizer.py | 265 ++ .../visualizers/sphere_visualizer.py | 310 +++ .../visualizers/visualizer_factory.py | 274 +++ .../visualizers/voxel_visualizer.py | 342 +++ .../workspace_analyzer/workspace_analyzer.py | 2151 +++++++++++++++++ embodichain/toolkits/urdf_assembly/sensor.py | 8 +- .../analyze_cartesian_workspace.py | 99 + .../analyze_joint_workspace.py | 56 + .../analyze_plane_workspace.py | 106 + tests/sim/utility/test_workspace_analyze.py | 332 +++ 60 files changed, 11283 insertions(+), 21 deletions(-) create mode 100644 docs/source/_static/workspace_analyzer/joint_workspace.jpg create mode 100644 docs/source/_static/workspace_analyzer/plane_workspace1.jpg create mode 100644 docs/source/_static/workspace_analyzer/plane_workspace2.jpg create mode 100644 docs/source/_static/workspace_analyzer/pose_workspace1.jpg create mode 100644 docs/source/_static/workspace_analyzer/pose_workspace2.jpg create mode 100644 docs/source/features/workspace_analyzer/caches.md create mode 100644 docs/source/features/workspace_analyzer/configs.md create mode 100644 docs/source/features/workspace_analyzer/constraints.md create mode 100644 docs/source/features/workspace_analyzer/index.rst create mode 100644 docs/source/features/workspace_analyzer/metrics.md create mode 100644 docs/source/features/workspace_analyzer/samplers.md create mode 100644 docs/source/features/workspace_analyzer/visualizers.md create mode 100644 docs/source/features/workspace_analyzer/workspace_analyzer.md create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/__init__.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/caches/__init__.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/caches/base_cache.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/caches/cache_manager.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/caches/cache_utils.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/caches/disk_cache.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/caches/memory_cache.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/configs/__init__.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/configs/cache_config.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/configs/dimension_constraint.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/configs/metric_config.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/configs/sampling_config.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/configs/visualization_config.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/constraints/__init__.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/constraints/base_constraint.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/constraints/workspace_constraint.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/metrics/__init__.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/metrics/base_metric.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/metrics/density_metric.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/metrics/manipulability_metric.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/metrics/reachability_metric.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/samplers/__init__.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/samplers/base_sampler.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/samplers/gaussian_sampler.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/samplers/halton_sampler.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/samplers/importance_sampler.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/samplers/iniform_sampler.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/samplers/lhs_sampler.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/samplers/random_sampler.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/samplers/sampler_factory.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/samplers/sobol_sampler.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/visualizers/__init__.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/visualizers/axis_visualizer.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/visualizers/base_visualizer.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/visualizers/point_cloud_visualizer.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/visualizers/sphere_visualizer.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/visualizers/visualizer_factory.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/visualizers/voxel_visualizer.py create mode 100644 embodichain/lab/sim/utility/workspace_analyzer/workspace_analyzer.py create mode 100644 examples/sim/utility/workspace_analyzer/analyze_cartesian_workspace.py create mode 100644 examples/sim/utility/workspace_analyzer/analyze_joint_workspace.py create mode 100644 examples/sim/utility/workspace_analyzer/analyze_plane_workspace.py create mode 100644 tests/sim/utility/test_workspace_analyze.py diff --git a/docs/source/_static/workspace_analyzer/joint_workspace.jpg b/docs/source/_static/workspace_analyzer/joint_workspace.jpg new file mode 100644 index 0000000000000000000000000000000000000000..130afba55873fd193481cbc15948b95dd109a295 GIT binary patch literal 1100402 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

    Q4`>*_F*soMM(P2{zbvu*uhv|B$N0Ta1yaiN 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%0D>MFkokr>JrDSItwE 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


    6=8lvKEwNRGqgJl%*o&DHJpU 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�xsBc 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

    b*bX)_*rp@H8bcNi+cz?@ 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 z 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

    o zoLKv{s-L#UbwYHKKUDkWinx`?dEU@Ak@#th_%{i}Up5<$`@-2X{Nl|wc}ox=t`R>l z6(R>9H&Fotc7b`|zMOT;{XXo0;c=+oXnk(gW4fNtojw5M+#xDSpY-@fggsPPNY1Vb z?GZtQ~SAXAKK)grHd~L0@{c!%oH<=qQuFcSglaGJ2c*l8{ zR>d=X9uKeBM#5?X$I$Wr1Hd+$+8>vnZW=a&MBk;6{&-X-U7A^5k6Z&iRZa>}o?;Nn z<#ykBx;k4e zx9A!b6n>m#hJ8geybW*2|6~O7u?=!$U*k!?;g8l~o7-u9HW$P1O@z0VDI5mAt9>AuK0A09foec z%T7`n`#{YX_#^tu`FIejTYKc9a|Z;IKSZw{LMIwr;KS%W)Z?h7o^q(P)Fy!rYmmOv}edAMv{2COBc*8%lpPw`Mm181@|zyA5J z(C$!S!sX3hd*h*NheN;4ZqYdE6b38b&2YhE$3K`t#SRj*FxhjHtQ9t)9Gl z!xV2Us+}9;I>>HmsHX?M>q#B-q!;T5((V^Go}a3+`WHZCZ7zFK`~ny(CUi?B@k{yI z)>L4cw#058Jl#n+d;xHE->p8gv=;%`@y-}9tsQs0t&h-ahba?^Y>w^>nC=eV=SCat zu=)`!vt>Cgx?CPlbq>D%cccH+V$a_-uhMD4i}gURUbV!<=19ifcvGo*GGwjHpF#Mf zO1J<@x2z)K45=N>cqsiL_(+@Yie$AY9_EftdEkCxboTLP^W=;Q!nT+UcrQH00qIJ zG3R|A`$5OUofU;T%+rGXHYTWp7sY}vb~?K(%>ofN%Afp!1WB|3*uiHKqAb8!rR4I# zHldM?XIS=knQ`q)IoFwb3f`-t+v(-&X}x`cMuf3rejhpAAc{0(Es6GquUGw()EQ{h z{yo-wDKyry&>M&mu1o|66PmT|6>a8W@k5W?lMb73-sK!I!FqZ)H6_OymsWb0sVPvE z0BseT#eJYJ))G0w`rA93w~=!p)pVJEm){<~d~ow7M@zx=;d$$#v&VJp5_A>SyYg@m zjv*=4cRS~Gjy(+D*e{VD@@qqJI`*7u_;1yxYW7kiQRS*5X>vNh`)&U!E^Hjr7O5Rm zz2-FX7>EmhJ$ljV;QW~?&mLLM2lx;O^#6NO1Bh-qsEV3t@8zW;p?30p!^Z1}?VgLAPkDCb>D+z+wHC(j8oL#jpy-lWD9((pzX(_rj=+!vrgI5VXVfanUYF(c z1cedv2Kxb|O5~8ey=_V9!2t(%s|e0>ECPX!3W^f++`uRaBrJ|HP$c&rP8Ow73n;sf zZuBbK80RPy&C~JYeElXX`GQ=<=YnJm2-?m(qF<*_ZurDeo zC5e4Epa@LmctK$ki}!SP;;h%QVVuzr>r_V22+fRum7^+H^6kUraB2n=B5sz{Jxqc* z<6!va^VHo=!yCgKP5^co-GO8VTRCZoLbjDj3@vIQ2HRKd0Yf@Q2MnpMZB1ixQI>*} z##9`ph8E$VW#g32(wDn^_S)4ctMhu7XKJ;rAXrzbLMHl_H@c<)=r!fV)S_rTW1t%l z*c>eEps0kOJ|B&y0a8oTV9I2ipl}NG_w_m&pH&T@Nf3*8ByvtBE8-%!uXA#=gV8Js zT)~ihrtY#j97GWoWMj3RwV1%+kTFBaD~mmC~RQM z(K=Wk3t>-CkH+L3^1w`;4Hc&(L!P{}*ZeM2HK=k>{k4k#jv#Jgg&2HN&ImkWK0phV z(duL2L->E64+ePic%zJ0(7;G4OO$=3nqtV0eY+%>ST}Af&l~sH)IR5C3d;>W{`)7TKb`89|6~41tVmwYAslhqVcb z@0U>AkF|TZ7*tI+xoG7!s7F-&ApO806Kcy+t$uB@IVaP9Zfi#VS^1w3saRyy?JqLt z&ZrJ9$|0W&S{ziYO8c<)EaU~DZ>`pIwib-0nI56uU&GDtZ^c`|>&R`3vyE7j%q?bS z=VV5?z{KSL;hM@&cy;d7i63GYr9Qa|C$!Q*UhCA zk1~ia?jyILPK(al-SdUEbUgJCFzqnhL~r7U`)iVxA>u%TnZoRLKKc%Yo9rM0x{tjb{H%1sgRO*~<$GKHBF1(jyoSi6&PEml*Q%&RF!R~AdYvgGpsJiz zfcv1F<&Mn}tC$E;FW-|war5xHdNPvSPw`oAbpT=ge?#hb#&+wyYPFKAYMbMrhiee&2zePP=r z&8v$|GpF%@&ZIc4LO9cHM^2rqB6k`fcE^u^Qr(Zf`pd2Q*FiWy_I=*e#9$Gq zX0dhkSO*BUy&$NxbJvg15UkXBXyR$WC^vKep-`>m83}QQ;2Lprxo{SB_nUdYW>tOz zQS)`!l`kGrKj*s(b(hxOCZ|p7sIcOPlXwH6mHi-LQTS|Q7}J1qq`5!9SxMd=aJRnW z;i@EjFoE`F)mM8K8GP|<)=1Fi;MK{>TaV0as$p48(`**0YDXXO>v-i>Qd3Jw&`p>?wO zt3oo65-AW+ja%#_%JxEh>`64RgeXdI(@!2E<2+IJ03_H+NMfkKWYc^_B~al37HR$EBfR5iRD~I6Ad!1j z{Vsw~_eUC!qtTjMm!gI#ELFl7LO?eV3WFAhy0Cq)8;YE4Z0V{{-IO@*ZG(&|gTvp_5n;77F_w_K-oBa&9h%2>_ZHo! zp&XR)@6p5-na zzH67wq=GW-y$^flq||Q>X=&Lwhmdvdu`TVllhB#Qb~o=eq_k8V@2wcrbdi{UT=D1U z+ohXb=_g()mT+X2w{2c(fLI^-%DmJe;isaW!e5#9%TejoSO+_d6OGDNux&^Z$p32H z0NKe=yA#1kcnLK1kTf{T$BD^prfe0|DQY_{UyxVz_-!!~YVifRuz7#r_7gp8doeL9 zho`z;?*wGI0f41p}MX%no9t#Imug4S>UZ_E;~?E(c?WA&rBOb8Ses`95gYT<)pot+;tJhmW#6l;ol?wwqO7TAHm6TD|{a(_eo6kt0woXOH*Ll862qCwLe`m@5iD;6ad8;#3)H^oeGd z;DHgtXdd4Q;6_JVI(hrEqDH++W66uN>lB?a0XK3dj!W^U3LHAFDAw&#diF7RqT#_ zf}I2-q!tcw|cn`LEgd>TP9Lg?!AC|oDX z);tqC)1ANbqUfT_bItF^K9QfLE7Qph8BIw?+jarI{32hE#ZizsjO7sd&fakKJs-=* z9yx&<=6`{3s?itPIX?7idm=+vP28K%YXIvI;kIe+}n z-v0nC?1PPL+B#_54D_$T=0vhs>12Q&DBH%wviLEtrM~+13wbR50g9$v;wC7LrJOAw zHCyNby?ut?1EI6-86;hU@?$O@5>+`H;=dB`H`FWr)*~F zZh#2N$R>{lOq9+x`F}Hwhn>1xIKkz12A%c};&Le#!4xGWQA#GIVn0p_Lp}30%q^kh{%bvBmsy4y zz7BZftH zd;P~j+ord7LH)tcw-*yqFS#a)oDqx4|1YPwt47b78?paiFrxy3lsOPBCkW=#Y@n_T zPtR4Fwk!Nrx9)&Ku_B9xjx_zsxBTjDq&4MJ0atv7ASx9$KMO%%-7`Lcm_s$myXU@r zWnty6SjlTFKYXHEq>GqW)wJ*T_;&4Dg%}`(E@7eOBdAy1_jKDl5dfS#EV<2Gt?Z^Z z+^S10@nR1X)U_WG-u#F+3y<3iZ4-85K!ORS^BC5x^LP37=i7>3q@y#th*|6dUPHSi zPwEnZOP2eJh>G;bP+y-@&>i6;3SRVFv{L^Tj?!Hgd-*Hpcgx_3uTh0r zVb%^tbZR7yi?k0z0$ZBHpP&geU1rr5RiF9urdWPX|4l}F+xYX~;Hfe4aIE#K>Vmvk z^r?43QRp~nX2V<=FT2v+{V5W(EiTPB7S2{oJ8YLMLR>zbedtNxc{;aVs&$ABjaDOY zqE^d2nd^BOS{&BubSCT>98)?5_5VUsnKK1_#dy8J@Y_DxIGcgZY#e2%^%EKqWb<{S zdM~QQbgm$Vmq3vm29~66l!Ja=QL7uhQriB}ayn4<)M;!yx3arKe=MN7%YvevCQCc= zkR2dWhvnbp(*>>5s{WbH4)fhZdD%h9J1eWF5_d`&8i|vB@R|5YWmFZhkA)84qXaJo z4M_c4A2h7++an)_1wgYInQm?A~Yi~itCoQAy6Pwt0Y&k()H&x8c=G8?Z_=8EYB4@~SO|U>uNYd=3Evh0 zma7Ff?nu9@xKyYx_*iB`oqaf7bF-%G?ppWCcD9X1L*Tak%C@ln-FuAHZQwb^Do|A% z`E}0TW@%dfq}53AoJDz1XjEJ&DBGvbZ);Yow8R(_NHpsDB&Au#^XBFaXknud)ya@~ zKDJB36=kUPl|EHAdy5wh2{>EI{*a!5gY>i5YRSc3V^N8pBKhwbuD$UCzgGb27nNe! zUMb5u?bk}~&nKt|l&?Z3Yi92%YF`xqvC8MJ5pl12I4un%QgNm)ev-vmg%|)0+4J#p zweI9G3}mg)-#H59hfTR3RHxYtm7w}zl-rv?FenC;Nu@>Nm=GvZ2#N6!*LDz5DG}PN z1^iHdj=J0`cXhDj@utYK$Y&WD3uo_z7uSoA392!#|Ap!2Ld>#KjiZjQab?QN)FgKsmp*5efb0p% z^?^v*>94elHLCjseC$Tn@7;a}LVSDsr_#AalCtD&-i+GcH{#Gp12f$Aqt}^5N{IG! zCBbO4$vA`u6>fy9+}v56KXa`1gO$ty+|SzZ7hT66KGi>bDdfzphV!5!ZGmTp5gpln zad=<5U_7Si&2D_h9cZo;6EI#l$R=Cd&V6qpYw}~P3IEtM%rwYxyG&5$t zBRH%Gm^yvWY5HiHDrTsNW=TtxE2Yd4LG>HoL-2~F>6$nTDks{{Z6-Q z=5)ia=$*-`w!M*M^?PfzaejHe@?JbhIzu@c3PmJ3@Szpla7fx=tmpMU`14ysNxts9 zT*)bk3o|uU7q*S{Jw+G{%FL>wC(Vtm2B^gwQX3g5Qw@u!Ozq5H znK>SGD{>&oxP7%782q}crt$Rn!P_|lfI;Du*&k=#x&q{d2BO~YZZ1E8iU1ORZ!YJb zy)rA{vzP(#W$qJ3EVL2qj~|05yiD3S|L-^~LiGX{y5=+8_o=Zw&}5hVDzH#gN22

    eY>7 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 z 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%0D11(PC%S-U~V0#Y){X<(1jZzp`77>ltQi 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%0A`60(|NF~-|IG?lZnM=UOm_bg>M;77 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

    #SIWmGb|Mt=ZQH$65K-^>w;pRdv9bm8y>S{{8yr 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

  • n@K-X2PTMF+iZn-Dk98^$~xuv#RL(E9cg8guD z3|ExF0t0=qEVWG4S-zHQT{zymoC-?PJ$+?j>*koOKVmH0*`Z@8Gj~P}itQB|oOvt$ZL3iKd$@pDkE~bP>^2L)W&?svP*Q%97wc|kp z$SIp9AR+Hm8+mhdzDxpqenSW&2R%?e-}|q74i0opy&e;D{ix-?k2xfrCb_IveRn*} zNiX8-z7AhHA6ffOdRIf^KN0Bu#rJwBs-SF&J&v~PZp+ae3fU4wk=PfIT#1#JQik-Nwuw-&gL(mhinX7pQ zL@GO7M8_+gVr*D7dW43+@7;43HSK^Z%Eb9FVX{$RL!qpew&Xv~6kuLV4P0B~|? zVLD1(%Uo0Hj#ie^uf&*FVkWoF<@e+)HEnBbCCIAInK;N(idboFS;S#LtAI$8&^`GP zxT6D+X(^dNgKW~e-Uv-cAsGVKw8zj^S0W3Gb?dIsF?9Kxh-@>s9enGtTNRDTI)%1W z7{p-l8pPGa4vgTu4tA>qGTiZ~p>eIdBa z4?k-+$f5ME8NnMl>?p`E*zIgk{K6d*`^|#>HxkjkT-(*xfZwQ7P!JU)PgBxK0mzNy z<+_#Vemd?x@>61`>*^%i$J}M z`88UFe{RfK3^nFi;rq)R-#!jLcCL+O?R6@0j;YnQEr^Hy!24~^nOL4^YQVb2;VCBf zcR(#PL75>7h=(WmwyNAXuXs`9-bYJL!RoaF>C*rII9}Hz{0tI1JDgo$8j#Pf&6D(xO=|W%;K{0cI|K(~vm0nqIoYsk3@DHG4uno6K!I0l$Y671AcA0en zJ9@5~X2FmD%vZ!eI)qf_vF0n(ifXJL;@0Czl;wioEi$nUhvuY+~D16SvO@B0|`e-dFgTf|T z0mw;X8suK-t5L~Yc6og4&kNZgx8;IT$8zQ9#Qglb3LWMnXR6}vy@%b3=o2uI;R$~V zvI%G8X=g!z7B=WG%>ksSAm2Z(Bytj+_wDdZ5MuC~!(>2c;wO;-w{Q0fbiIF0UEo_m zbXtBuL;E);`{%+J{Gf}j#8{JBsy-VCW~FdoYfdMAZs1_Q{{Ba|Khww8E>{|PCi1zp zyt?9#00)(K+%uH%>n@*T{bWdVQ@lc_THV>VDhs z*PC-9@obmbQz)dNSV+!XTU~dDu;yls@=P1RZ-+W~H=>Xle@ZK4UMHmQH%AByY=`sa z^pLo?g2ugZ-v+j$FIs=jYZFNk=SyGc<}l^&78J-WlzqSU=#84n9I>+SpT5b9ZuRHR zr(95u#a%wTbS=9w>&Wk~;yDw)b81}kY%^={gD-`*gu4d_%BTLH^-&KogueTS{YCVD z&l;?jW`yskwV0g^x-ddp7o)Tt2TCyCRpy^&JP)DplNBVY~eL@8{)ruXOm z1}CyqJ)@3N@LI#V@~qt&RGUeshST0P%-IK#Sa`^A_nJEn7&SNFST1V9gkkM}vS}yk zYS-c#{U(GpZ@*OvS5dNZmC^)P;T0jXL4Y)xLkU0;AoVl`Rdw9sDCbhE%4aP-)sw

    FISg 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 z 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

  • 2Sy{d|eHazt8W9h$EdRgY}_m>))lC`Q4QCDB2Ywk*=6}P=Cs<)c9U20K8 zO)?#*Ww4roOtsUBls?mI>Se%=Q2aev<(8!9jjD^CobkSLPfO^VJ#M_x8o@fsgG|s_ z^=_80x81Gu)URJEe}|g-r&&!+6}py+wyNs=5Tk01_nd4F)OyhMm&tx?@t?O>1<@JwNqPo}gHTKms%_?rzRw*iKX(%aEZK`>eU-!XchKiFx z$$Tnf21}u~WG33$*mTSnS3K)2Bff3MZnl)_)DH=VyjA~D`D`UNX5|DhO zZGkEnZw_W*^>+@m@EzOemqJQriC21P-5UUv$Ci3hvs&|aQu5oA_pV}JTho_)S*CQI zf}c@pDyq#Xq@TT4Q|am(gLD_G)eVx-Z?_`63Yw8oZl|KQ{X*93Orb$s&M?5t_DnBsq#N5@}7anLI6*C)k{A-ry^icv7RuWx z0ZVi%)C%A(PWpo8m!{5l@{gDtim}-BUppVwpV>}ZX`Mofmu;83-n6ycbhT~0=BWbe z98G18?{%XghLuvIRFqqnOLSEYbw4mwda=`7hxL`}i(39N9*s2B)0)1Z`G29RG_Htu zOmf>L->9v%!mghDIuKIR?Nrm#E}ah{Y$>MNZQpSZ zI?A}a)K{tQdit{0h~{^wU4LE7&3cPPC50NA?QXGK?n2FPQ>(Yz9CpWRwWgwyg-^a| z5mJ|w!F}~1K~KD;{k`%_@@X}J_GUz4jJGcCH75M#DpKsswk;^RiHS$B`6d?0OKqVH zO0?wZaChP5mJ*`c2p>Im`?L&WIP2?`QdY#5cPB35KvEt{J7wo~$*Dq~b->U`*isYT zQ)ytIsz1SlKx%$kdLQNoJiSfpEeELo01K{bGp@APIdnsse^R$`uk^HcmSD18gp`ki?{h&@ZJ z@-3cRYIiL(sCMa1OLOK!_f0u((^NMrji&Kue%C^qZEm5i{v%TDO}UEN8bsV#qoPyy zdtO)5f8otf&;I~K-l6?x)%uI&=7Of=1=m+w9^}<+19x6!YgFk?8Km`p@hc@8nvTZX z7VD|iBGqoFQ#DClRgU<$CWth@I2fe8+ZmwLOwrtFDU({$mg~u*scwx`)ULSWe@j~9 zKTPAyyGH8z5Vfr;r*=UNxRmzEc4cN{@k}OL7Q~!&x8IkUnp5rx*+=FQ9t}&(t&{+k zkhF$NVbIbDNLf;Cw0-^!eor@}D|C*v{@3aSa_)xa-oLBmuB5Tv^t~l}O>-woS*~nr%~hs#3DdN} zRMZw)s%zzTlR^0L{7wBtdSvxE>PDZLzLYs7XXGy}f86U!>Dz{mv)UQ5i`$%{pfF6dOhWrCcQ{{bLSU5 zb=NHUT}NisDA)Q+N$Xt({;aoIo}o9C)ze;TTvnb-j9b@j)OQ^_XVkVYp;bi{5-aWW zw|f3Mp{ zK`^i$c@l_q#X7dpF4O9D#O;(kp6M!ZtR3U^m?OCt*GBpyl_bA5t}X!kYg8uC*U3wY`aYlHshho}bg&oq8{t zD|*>ta^YR0)ut%iUA$cyddl^fRa4d5YZz*)w%>$DBfV2-zf4}M{{RvH07-tR?Yx=R zzM1LuWxrVRqVdZ`Ys)`4w04-~vs}Y&#aR2!y-QD7bh@~UO^Sh5TbKS8exCT{*GxTT zpsTp=--_Qmxxvp}dCA|xi;((W+pYN*$~|MteFN#ITG{J$4aZXRChJe4?fMGcYSp*2 zQCal$;;P?xqtq0%&Q)6LE;JwU+peb7nxeT6YD90oko|9Zfcy~bnxoKftG`2Zdd1#g z-A6X{U6z+z=^L)0ujQVsuvh8FZEscRHu;^VHHC`0?_#E-rnO!!OlkL%aMjvs^Gj_t z*9)86l+*K5SR1Ru@Z2rDXBnAi5_<{{NUiKk3PbIOA92B?% zc~5AmrKh)Y-m6+x>*}3A^%dHx?yHSWCZ?~duDd8z+M1}hHEU(0uHj|27yXy@L(f0M zi_@2`-C44tL;=ZH!FpGvcX0CQv2@L(cUlh7y6cU zC7(yJQ9|YF!CRrK_Q*UAw2hJgDgfl7Xfo9Bj^KVSex0sb*Va~uo zxav!b>+%Os>ppVS3wI;=jm&+2Po{Lu+TEud(E6)aUap#JLO*S(Zh=(I>5GNgc54-8 zn@M_-qKTHR)fSaAS!$^IB_gea`VY#l#*5YWFTGaPde7B0Iy;+O_J5TQa#gG5y0O!n zT^}#qyEA=Vwu;YcO&b=v)^2poKTUP8xn`{l)ZQrTow!loE=)ViABU%`-$>lQ=69^# zbb9vmxu$vMpHWU-bxxV1r_tJFZE1~3e!J`KQ>tv5X^VwrmdT}T8n*4IEH=m9vs#l; zXQ8yxS6P)x-Jn?Sor+LnSWX<4rf|0LA&1FI8F42xxrxb{<-Acc8&)8#poS2z>Rx%! zYIYz1KU+`q+=Os1gr7lzQrn8ilzHI&>eu{Pdn@!YuM!8<G$oiwzR&5Ap9I#$}>_g{B? zguRHWY1votEI$%zMTIjw>uoAu5Jo2B-TN)OF4?G@{5-Y9&qbTb*k?4 zi_=`ku{g~Q+S>bi<5KDkLwBsy)X&*(_GD@LW}2_6yxx^Zr)>I0&uF~edgsY6!YlCw z<~tPH>eK1BSJLVIKHi3xs8m>hr3340p4)t5<$CR3zkUX{KWy06VO>2E;Q0k6frjFPtD{h|k1C{mG`>)Wd z?`OH(o3&b+s<={B`;H>hY(mhsD4S&c9)28ujlRG2JI~D@%a2yxpgBS5OVd{^xm^9W zw#`(=khNHOwwe`MEbM5_PpElH9@4y&D4Z&EzJTT3i)fGW+Ia2G-KJwS<$KlcVb$Vy@pXt|~H{ECI1sV(0ZKqVO z!|BhG^&HLR292TT6V&=e+p26PhhO~_#-j0Xzpb{A{ku_H*Ke`gtLs;2u4bjHjSr;F z_YyK};vJQa z=lnVJudmL1U%5b@Yx38Sj#&9=e&$E^x0z~wro(hLO-H0O@AhibYj*Q$rK!Eu{{U)@ z*``Cu2(?*m^&Z=v%95=o)i$h*yo{F7~|b=FYh zH(fb#yV9GUX**on7xVFs-mH@Fv+L2Lf8WBw?ZPCa)-{n2Kk-X#P z=O}0{`d?K40J(=VHRmoBtn_ovmdb+Of2o~^94-EDfB!*sQ*qMrL>yIJk^ z6v?_Q&~*yxIXnQeHKB^NAsSamLr{&9H-_rKPQdap2XKQ>NH-Xr{(oU=AkXE zyJaq~dfeTHs!GLoGi=|8r9Y@$9amLy*H<~XN^29gR92dWBzKi2;0jRs z*@02MyR(lexp|~CzK`bzFSVASvL{z^*G_XAOX>|%p)OxZaIVxEBGaiT>+d>Y_o|to zwO#5j7CLwBwJNJ((Qm49q29KbV1y5Kza73`eixj^Ayc%Whh8H=Jr>$IVYl z+@-7K4T{^#I~|`(Jn+3=`8&%yO}^=&FXHz`x@x<%^@;^*hAu5vyKSa^oxqP1dl4sb zGGxyE$@_vk9l^&OnaNIE4svsol)R$;)7dmv`>Jy{LGt7KWvQL^G~SUK<5b$T&-R~C zJ=WK=WUz~;@msUL>wet@B}1J^j-j!iz~!8pl*H3FH7E0WCKT!$QkKNTyN#0K9%$_o zva})4qyoC5Wgu-^a*5YRs-TtBfC;hEmjaYI5^Oo;=Vw;K=R1Am?YSH7P6?66(MRBS zp}AkpD}|$%{N>k(<+m(u{N}!^TkB(Zvg!W-?ER^F8%l}?#qUwES7f#ujqREXK)Bo~ zYbfpFx9jTZ{+6A^4iWrKzYhH$=vUNTqmfo#b7+rK)LNUC`e&Fl8uvwM+Fd(X!`g=Z zs?0n$8q-QUanOe9>IPcevz%ehlaA{)84ba zI&)iDT{ZPrGkJ%n`9Ddg=y{Q$u3V<&evYKo7yWxvW!2UCV$VTyYK?U|jf-Pij_p-l zV6a@;)><(wIZn+tlzgkmF^_f~w8>3N%qD7PPZO1DW4)I%Qj#tu>BYFqscvB`vn{sc z+bHi6C=`@}Ry%)XF_cJRs&Q$UZEBR8l}gyyTc~qqM7Q4epad5HY#XYe1gq!6 z@owbCf#i>`9((BiP;1MtHu*_Ie6t-L%{zs{)qHPNQ&wrKO-(~o_pLiiN2jhd+G@RZ zdOn)E$4yCRxFb!uS8AoCq;V8<+{5WNPx2icnC0fK(N135=cB0R7MSNfEyCeyddmG3 zE~mBKbRE-7+Ue*iFE-|0)76yri^I1ni zhcE2BrsYPUa6O_ly~@X@?ev-jLe);vs~EM}o)%gqt5DQj?v%8a`ju1DD&UGbLYA9p zgm};CYfaiYd3fe^nwwHlUQI>v*-LAA6t1-8+TUkhq-m?AB857TVXpRZLfC-MW^S#H)jEh1%Hm4CA8M2oJrryP)*WJ$j(Ci5)c!hErIdS?mj{KUb1P8>~^CcCxwXq#=q{JQ5FnL-q?R3xo#yo$EslBVhwL5fvX z&Q{gb)>JR8`ns2@UQz!5IoI7TIJrNV%GRPuCP$IIKYBY(K|XQ$wt*A+XC8R6t!evx zWmUeZ9^FkF?$f^6-7Yq@B#>h%Jv~TQ`RGtskU=m@sVDyA_Uv}YV<3IVC+y&CDVCSD zENw#`3Ib@InrzT)(=D43P80&1BP1Rl6O3#!U`YeP5JW&9GsRHiNFyR}PUFCg$cfIt z?;XZ8DJNwD4E>3j1||kO6CQTYYP~Z0C-qC~AoCCX?Hr=K^HB1t%WuBxvue9(dq?nE z8^7^i;OsOtJ@UwJH=D?@-bI^D*guKtE5Go{{{Z3Ey04~pr$TOiQx2ALZhmfBMp2!P z_G)qVrKQ^M7KWP+KKhW;du}ZaqiI8F#iatOPzN+Hx7L=~ZO0r{c3WvGTGc>QXoP}I z5(%x^L_w7tlixqBtC4WkSDJ>>v?NqFN~E|UVah6IXx{2i zpLUs0G6dkL2|K?ct;)J{8qieAAEmdmS#qmGhzm$fD+&~jkf5P0T-=~iPfiq=3Yg=^ zF`1=e7}Vm_u%wxlu+adK+_J9eqMLvLNDDLq>QbmlHTA3_Su$8mq7sS`E{C0{p)R_R zDVpL#n8!aI%#z zqNS!(LP-F}9O3ETNmJ^2%|m&iH7SPUqMn7N#s!QUuqoqY4)Ka3Er&|2DQdwO}lA==v0X&Ut)p~C7rqgY`TdEy* zEz|u#W~~1JF4S-PRa5zg^D-ouo~Z+NrrLC&N=0*{Y6=8kZz8nZKVZERfWl)D|@%Qpf7)({CtQo0GjDGEJ3 zQUns1R>0-}1CIV-Xedxhkf1?Az*}kx0V)bYf|8)5z)&E9BVZ$qLgk>eebf)Buu(SQ z3nl6ht81!S!pL!EiFE08T}lciPZkr*{KGYnw*<$Zx?5M9J-esacv~aHd;Yt zr6{4Dq#wffX&vH%RH~>}GODNnp$V-hC{1&%P52T`1whU^UXKJL7Ok+m6Uwc_V6j^IC6p)Jpv7_Uo8txw-ts4WVqBH(NpciRxIWQgb~- zgU1WrG=1*PdlnaI#Z6<0LzK&>>RVM5?kPz{LR7S)p|q(ECDP(i?J2c|o|K+91te#d z_?#$o&b&3fNay3MYi%~;&ZU;nw;g$CLv0}iOIp-mAt*{^N>P9UK`K!LJ8{k$TSZdZ zTWaNZOK#j!68J*YlTAYqLW+s#apuqFE}3nm2x@vm%D&UuX4|GIKDxDRF1aXD>T8}M zEmO!HZBv&34YrUQfX46in{iX=BQRdYMDTSmJ=|iQhJ_0l>{;hp5ocs z1o+^D{qUJbvdgN#K$^kJDmuV{Y35 zW+!8UiSY2;dhrn{j^0utPTn`}4&Z*k@J=T?j7cXFOy?)#aRNsXILFS1k&`5ir2I(X3gx)sCQi||A~O(F%$z|OG5SyGCTF*AE3|A3 zpD;6wV1jm^v}1$@y=Xf7;y}*e2pj(Le#QiLIPhWbwlF7u^%J-th@6}axPUVza|g~w zcK-m#@7@5H+DFcJIU-{*zQRoX!37QU_UmDOKXfvoIoQV75J@AxM)G_>&tL)uMDO-6 zHt`U9fM>{vk8>C!w(?-f0(?YcI2hs1KqT)cIKlIn9izwsdz4t0Vt#Stj02Md81LWy zcTDh1$%&D;5t$xDOb+KcFnElJFee!!5(YOpj2|=D$S}@v1F<8)CP#DgJMIaQJYCn! z(DD@GE#;PRIrZ!vdn8Z&=K~X;={?7f2$4Vc!Tt8n>JH*WpmsO_e%-u`h&UMW9vqFq z#@X+U;2aJ2@I>Nx497ozTG}i*@N+rO+i$VX*~TRBm|*kgEu0QTD%2VuToMk5il57b9)&_K!0Y(z;QvHEY@ zy!gnRZ`{P-aL+n*LC1H$SarXV_`{Jifwl*K@$x^c{IX1wwqwTAk>J2F^Z9%60V8kA zG2}*Oe_yo5V3-^k#2)!3F&UoZ0ge8A0v=&n1Kd+XR!Ezu#x%>BQYeLWSj`|G3IAKI1(~^c{@%FnA^P1fJuN)ZWqhP zE%eKscvjpY)|Kn(iGHvT>E3(%0B{80VrPetekZxuK_DNz2_42JaAP|T=Mj>jwD=u{ zC*XJBCS&a&hy!h~3}+Um?%I}76)77DGj6p(p*ewR1{SgD%yG~L>DS5TnKDt0VEYI zak3joQ;Sp%l%$x9amw1Fwx3DZY4pXh!S$6)l~z8I1EHmp?>e#!hicW-gaakE5~PBk z?&VXSwa=FQcW};-848`;KCNQH{me_6Zq6po^C`DetJ)oO?L3;rCQ`SSw-8pA`lK`& zaj8rxMO{#wa`mMZ!`%KkrR^1}aDuvuFy#eEN$y`FqM>90qtcp&*H+*phymcp%84N$ z9ys=Lsl<-s;vAZ!RDa(E^tJLh8{XC^-4BLjSKY3FU)(~Y{{XPB+;;pO$z(8kqQ zqcuGkmu(deCVD}nQ&puz5CIKRIPmrATol3qipF zNgx#NFjMETjxuyQg76|bOZch&(TYIi=UpsE#&tAIfk)mz510E)0dBy<1 znC~O80sC#ZKX9)f`nLU~lM}xS-iWv@)m${qMYY!i1r)&(!MKkIN z03|BNOa1|)tJfCISZPPL6k5B|mdRO85^9z$?2LjBwwF%8bsy)q6sR`J_Q-3BNBs8}~pXO0XBUY`m-EE;py4_hyfUci)>UE`paVc%$lFIU={{SM);9$gs zO|5$lbx+k(TN}h0^;-@U^7`Vy9q>EuB;?{i#ANr*{&+s$0C+#JKe&O|?ZQ3&(qtS0 zGt;(r++>sU!Vn~FxZIDi*vD-6?oPp_vZXg^ncbbVCNJIX>hU6b9Bq(%Z`x1X05=%N z0PJQq0s)`UXB!X)jP1mH9iRe4Mt^Yx@7hFQ@Wf^|p7JJOP9x7~>~S-~)EB;aie8qX z&YbCN?LjNMth^1i2hJuoBRPTjrx=ZlnSZL_zP3%o*@8x%mKNh3R~b ze7#%S>eo}1h6w{{K0M<&kVlWc;s+AX&N2H*Bpm1953utQjf8>!0BMh~+qa1XaHQbL z7%`E*&I~{vBomM2JOxduxNf(qJ_AkgiOhUXCSy2``~C6za6vtR{kxb41Z^;T!7^uv zPwY-UGB8f@AQ(Fw08Th#01-Hx48%rEleWZ|0!$b<0&HqYu36TU*1uj*`1S6I_nZTh z`se2x2;Y48;m^oDw*+G|nURy)HjKv*?XV_31d%=?IPW`n;GM+GZek>75hTvX{TaY- zwFNzeKHHCNB3M(%do5osaOcE`*vT`Upng!oeX ziKgtt_}<-K9w7FN4aCgv1GwAz$laVzpCtG*6Nx7tV;go;84?MP8-HH=WZ*#n%%Vr= zPDfxj&&D^8A8sb=*CGD^;mlIwPBh_r*Ij+`nCwVMfs!-1@vxD%kB%Q!273|X#1Y#c zBxZAtBOqfV86bo4f=Qeh9mH?EfRaeZi0o!Nh=Jb+CvC{$`~Ww|{Ths|UE@05#wT1x zT>SL*#DSBve3|}T^PfMY7~6heQ#r_;~WsR1gjxV*O3XZyw&ZKe@2AoRY9l#balNgW}3 zQuL*cSEshVV}+rfTs862qZb_1t6LgrrV`|RWzLS|wNX+?1~7-(V4Ohwzmy)B z>#2_b5@TVRiNF|;Oa*5rAYgL`H)_(lnIf|r#!^mah4twoSk5-QBXh8$bS& z>G(KWSN{MNeK-FAo(n(zld1ks_@BQA7)R_sX8!=q+ynTR3jY9+Vmha)NdD7mA=~)v z+-@WjaH#VcBoQ!RV>sgkOzqzUj86G8AJj+38NE( zPkaz?Q{Nr3eq+21vl+*I&l=+)$VcRtX({`n$NvD1u}}Hu>HA^i000p<-)`U&1mii_ zK#llAu)y5Jciad`AVH7JN6Cyxc9Ae6=6iV(KIb{X!Qo8r*vaksZ!;!-;so(}>pr~W zg&yD8UG(rLonQyXK{94$cg8b;ffK_j-?8`;IT;xJ0ox_M2_%t1R3ET@rmCsXK_1ZWE{wyhya!Pcg&4}$76wrg9L0QCyCFmZo9nU&-R;B zm3M3AB4^B>)X3U)&Oj5Hlipy6k^nf3#=ve21GWco_Bq_0U#|0y(l2f_sp1_ey|BVAb;9y(?q?sMaUdPo8Ul1FKnKj$3h zwqT4CA|o&X&L&`YA3u3B18w^h3}8kkL`nG{BM~MD7)(s?u2j8rCzURDaIN^mmHGHy z_q8V%n1fbIRuTwnfS*6K}*zRGRV+w85hbb`ihjy2U6KhI3WK3Dym#9)20l73xI$X*ei|2 ztpwEq68@#WTkS28)G6C=KUC$=-$VEEF!23@prg0>H4nc)Rf0Z^B+{3=Uk79(<+9^^B z5X}P#O2T)KdBC!hCw36Q`~G66ElvC{`8u410M9zw^o34|r!&g@XS4r%}{8RHXFvM@-^)Z&TcjODNu#~f2t)X_SMidWsHeX=@TWyK-DMnMHC%5a$k5TQ6ca($1P)ok?B-xxJ) zh)>p2grcP)QaYV#LodhXQ7HD7N!euZvCpfEUY91rTO5v9?2&Po?6#M#>Kcs=ql%R% zQjkKDq>>0yOoak^q#S|{Gm#lFAgS|_1~G~3JnbFK9rKacs*7fm*3{~$VNAJDQVFS~ zhAWv-NhuXA5i209NO`ge!d3=H7~eU4c(sMUMg`7{bttKXf5ux(sYl$VB&kFs0;M!v z2768^@$k=0*W+#85s+A|#Sb43E{teXxEoBwZ@E5TKpnqL_;Dv-dw@xkjpq|P?b-}* zlnP3cxk*8S2!aT~3Lnf0NXRLX02m{P&JT=dIT7A-`WQGQ&LbW9gOy3jyEUb$P4vr3 zR8uc~MR-<(itgxXN3?D*c0Kdo$J%k;cyrv5x1F=N$hG;ciHY69!-b z5_Tssv4Obr1B6UY*gqpbCv1(TAY_afmCEAOx0dS**1GAGJ+%9?ws{ekfUHVS?c2U~ z+{{2Qa|SpHkH??6Ac6b*;&u}e5^!g}AbFjHfOGm|<2)_9$%y#x9&<7TkWPE=ElY~n zf#jNJLrz=GEfX+;6zSfZ5a&yfaBG90Ou2-fNFJo2gC3KO1mt+b&Bao3IfsVR@w{5}tT@#LIGWgr2Axezm% z^NjC4Wbedh9fbGaX#f+q{)`WdMtEm&BXJNSB5|=XI2(Wuk;1pFO{jRA3hTHMPq!$v zu6g@(tu+IGmgsXm`xzh20B%0hC-uhXgJMo&Vh-LngNZ(8bD82Zxtw_4aT(Z|z{b%g zW_VIgc993R-#LMix%k>Rd$rQ!B-+{3S9O6lt!8|!ZP^i!vEftgw9m|7z{HHf%z*$6 z&+GRo%1_M26F_!fKF$y+p(A{jEyKa z?*h4dJOH>5%9P7p2jYQGfUgSLkjd@8oE*$=m?Y;iWbGU9=lUG@g9Jx$x8;u$jw2)B z>_G#x3X9{-Azcb11T=(nK?ziJjy31%YAT&u)h{~xswb(}TvLl9aypbr z10(@3nK86*%Q_u$%jo7UpcmG;-puK7rnS^(U3^Y?6;%^@apLVI^${SCle=&THQf%t4bR~jnJ@!7LiMDZ|K<#stS;Ov+g>TbbzmQ z#mPbxpi}`EGDN_iCj{&^1jz9u4atEq#7y8$Oqi27l1RsW_8Iaq!nYbyhV|i1{&dU0 zLiy=z`6m0Vdic`!hB8jZcgY|bf(ATf$^QTu;3W5rpc&YJPC?#geBw!o93v7=N!mdX z=68kS)20p}m3=RbQhU21b%GUPl7NGI1`BI0&I^XJtB0e*>nIc9z z@BaWh#$p`Aj6m&xApPPt*d4|Jgq|TkKWL5TBmhZ2;9$=D5)Q``pSdtUZr!%t4-)z3 zt$eo~=btE)%Z_C4^+3G=6{ic|NR-U{ZT)g~#`~Btj?#&Z{{S+!j~R~`ji+*PwggFt zm?m=__aDE4HZn2Xk~bhhBWXJfh|h72yOBIA`!{8J@3r#bO)2(eON~V-;xwSWVrSzZ z#ysc0#2oqG5DyC{qye|v>|-N%8w`Rz+(c|hp2iL~G9%#q@g4Xe<8hAy2FDp4_d9mj zVatb(RrbW!Kz!?!eYVp}SVW0G;%CA0=N-Yp_#}f`ny#vi(Df_tQ#_L?ai@Z-+z#wix!5k~_&xJW|>o`-DC~2rUXQi#~76!S?j-I^Qx{X~Ep^=o-G(GxdB*_Qg zYpnnfMjR+G4gpCc39uUj;0cTl-bn+r3H^A@TXhxQ)tn0Eye((eKnD zPuOeduWTk&(8H*1wX_3(zSZYy<-)Ndc7q_qtHcu`MkE=>f^!3f zAP{hIoOzLvBzBm`#Bm;=eC9F-^8!x(4&Fy|zYLQk7>?v0fJqbNABmWZ4iMx%?5#^u zzREu)KwS1_2pY1iz?)EA4*hWVuJw0d&IOMbW9C~md&6gTUg@~Ym1(^aCyr>|FLo-JBx z7=NKW{m>R(RP)E29JJFnONIMO=uTy8T`8q6mvmbhyI(Z5mr-13blvLg#hS9=YNff| ztc=iHE9mGes;Ow}Dqf~-_Y&0cux}EScM+MwkhK}fNp>clL2Y3PW@SrDN)8dQqNO&l zQV!6i#9fjS7x=0)2BPF_*4kz?-%FU{Uz~Y?x$Jxh?q&cJx8{Qx6M#X_d=ZS}&fX^z z#7cybxh7|{&SFS7{+K+H~D5W7n&rGz>dbx*95^tQ)qSf;x_Oyljkn>|v+HQ6aNsZ~Od^|9)vUTLJQPPDfg z4Y(FktQ-q1tTv*Blqex#Aw>%*J1Pk_QAwc*HZ-Bk#Tr_mQll-$EX6#=<7n@P;yLIh z=lFQ@uEEL+k2kbuI+Lh04Ub*Z>a7z;QE#AOo9e0^rMFa4KXAH$PGywTL6y=bns z-RSDtWx981-l+5J?EuG|@7ze(VmCWM9(ecjnOv~^Dm@(fi}Y=-xqZy#deh`97EMWg z^)IH&`fr$&^%w8p6t?&mg&pG#kcYW+=m67^y0Wsgu=OF<{n#Z}$A zpDOPfHv4tC>e?%Ihi6q=pKDc6+!>;>Rch73hX{u=5H1$;P(!7K=wKG!Fj5?G$(qCn2 zZPcY!Fjo^6&|3Xs-o01Z_(CPU2nH0LsuFbbF?&-v}>xld9#oR$id9c*^}SF z13P|+Qe*EKAL#M>LH__a?Fv8!VO&07#$!Cb|K8)`ZZLrB50}fuA2>Ng&K*K_*E# z69WK5aHlvkh?(3EKOn|Fe`OfgdyVfV7FHC6lSI#|K$ePU( zimeYrbJ99XQ}Y(9nD#2&c;gIP=ij$oI-fPt( z)9=DF@frLqy$|vRo17fLs^%@j*6SKt{{W-)#i4eMQ+Zyd($%`8-B=o8>v&rEe%tgE z7At*BR9+}`9Ygom?RM%~idu_{Hh)dEN3LH*{{V_NqhD59W0zi^b@j!|1^VRXowHc< z6OZdXU#RVss=wKFt@`ytV7OZ-YW1}%DRTF3y1%Nf&ePUin7KQ5xm8lO@5Mi%E>Utz zp5ClEL&|SaoX>BQe4Exa`kI$m^Bw;HZ47DiZqWLk@uypL=Url+jhp7Gw^;P*?iDXJ zNo_^g*VZgkQ@D8g5A-c;^+oB=)X%OjPG5vG9KZE1$QoyPc}>h7W$PV5r7Q0>^mhv# z!ox*;({I`Dm6n=UbdIUjI<<=ht>!B0wJw>{H`=?UuD<4=y(i{i5^R8Dt7U9y9;nR#NR%mk?^+6}2IPVJXmDMAj78Ha;r|;uKIIc+3r^F>`uMErsb+F z`ddoVs@ri*2llq6-+yNC#YNJxq1*GyMb+wbT}QNQe1r6@Mfhjd`aJaj$Ejp%X8mbZ z-8Ee|rZ?@kZA3H;W5Yyg)1z&=-jd&O(^`8@THn`>+^MeGyHsjcsG77~9jz3|YfMzL zbov|hwdyy}f8pckH=mw{G)FnF{;{>6sDyKIdS2mXzUZBAr@1rCrLNs#Cf64_X|$-V>;F-I|k9X}apSwSCIJ;*y=jvimML!*wmR>uxTc^*okpQiY*P zVdYahPg0g%0HMQAP{ZL1CAXSiO2;$VCZ_QW75Qgh#bu=B@m0NqPM2PnoSBdgCS|ss zRL0c9jiuE)EdKy}ln2@yDG3x%(|Dy00s;wA09tHP6hH=)usIP-iJ+`+Ur$Kw)n9TQgX@m>a|tM>!@^-PtzjdNd02hUrdUM%4Qc+M_BW9FDXewtN!8s zwpOJB)Xc4CvL3xZ67NvIh`0NRFQ1mKSg{$q8oR~S+P*{et>}Bwe=q+44ew4~p!pHcZAr|} zP}=f>hUe-lmW$MSF8=^x<;6N_>gwuH&YsiyX5XpwW0rf>zLwQo&Z^W`+K1C|w%iL= z`a7MyReGJIX9dMDc`P@!_+*No#oT&HmV zLX2`aG}b30I+>g$`G(fXO5H6jN!x88scChzs*W|Xm6atxqybwJBh{Z(+|2wqxtFIo z7pcDvn#<+Vj;l)Ek2tAsw_QzFUvIi5s?|-T(|Tu8*WD3r)^)AYYI@y6Y_K^^r`V!; zz^Y0r8kN>lBf56`c8T<1={H$&^VRpHs^&Sl&5MQczEE>JQ0aXaajDa*r?Wd*O1ov= z=U6pfpQ*Q9nYBLkHL8}I_<}CVr@y;LPi}3BuZPVS>Ce_)kpBR3?Q5iYMb14tN6q`K zs?EwxMAe4(W3lsIzTsZ|Gd5ixbg2|}&2dWV>8c&QTWys$DmrU0cIA9(p332?SJg+Q z@5d6!q_k^ZoxdC|NcxS{9L#@GCG9Dy^|vc68anCAeG7Q9-d%rCQQLK;UW?UhsWlX~ zI!ddXXsf(e&{w1QLat)o)vBxJOn2m2*-5GFN3)aCSc`8YH!C8`3+B2uKND0H2Sg9M$skMSMHqV=E5=e;S?`YEUyQq#(6y;o0n zt-mvAs;AUKncZOCvUR)7O}eQmzEV=(`Ys7oT^&_oX=rWK3@@hJKpDhWX-`jIh_9_1 z-y**VJ8qY_=^ZV~OD3+=nyZ-l-(2$hNHcf(i-j%nxu+}iUbNInw$Zs)qb&lC&!eud z8v4ui&68Z!I_N03{{X@_k~gk%dhzCNmFF)e7`<{U(-x=K+D}&V4)0&5wYMhqFEF`y z%_DdHJA8I2t?IVhKZvH~NcB}E>cepiF-?B{4_c(#o$_JwciPz(rqSGbGiaAeXI8nn zHe5`U%GgOR$}VLy#V!{cJ<*m!s{pJgyF#2D=3}vK&d z)i6@$cBy2%HdYd@^=L^TE7nj%W<70HdK0T>lXV`8RjHe({sX9(=FKjkXHv2luBLj% z#*|VQsV(#k)?Mn7)~2hw)>#`>t;$#IfTE7DRM68;)D!-KDg7pL4Dvne@%2iot4o~j za^T*-W`(LHY3stZ6*X|wPrITXsAE&E$4{o}^cZ2f>pK?;%hesWvG%AK=}+QE&ii$* zo1FLO7pHGX+}pSMZqb^Bb`z|$zKNu^@?P6{wkn2({Zm1xtn+2H*q+pP6|--qw^?ZE zY3=H!crg7c*}B}mcX^lUW1pPzOY~F?UM+fI{{X6FShQ6Q(QMQ<(pVKt+^$r}e!k!k z)qNr>>6G&p)e4$5xovGvv{l*gFOnYC_J)3OZb@MnRvP$emnY^LPRl7mT3369$Tsq( zTbOkT3qAN{Dh@0uZIu+KjeE8j6qX-`7V#Wna%xpenDj)g;VFLQA2YpI>g_jj1p0Y{u2KHh>d?U^lpjd-iFis=H-T& z)HbbA%L`SKvy}iSc>y@18<|iom>7=xeHFSQ7rJ=Fu3-*h-Y3&(q(>MBS)$YTn zC@+@nPi?EdP-^`+i#DS}P15QMeJ-UI2I_RilfB-)d-Z2JxudQ%?y=@(qt;hyooTQ2 zOS;ooTzwi(}%6=KQMhX^7Bw?`|h9By7sP~&2PI{eu}}W?|Nq3_M=^+P-*IG zhOw{HP3ih7^2N^8M608kl?LHvwz?}Uy)^zcUx=rs2P&DD(ZRcS2`dk(>MwA!Qp(v9^V{ z66r`lT2D?|<<^uGqhV+@*eR%XstO@WACqti%w?2f{b_y?Hy%z{^>3(uPCDk@&5uKL z?bs2^zfl(*S);4j*SAZXG!%DR3p#&J)En)d;cL~8-1Pke*IPv`vi|@}YhvwfxV&yc zj+>r6S@X-*cdAdr%hNZc);|uOVA;7<$f{0X)AFyK8aGPo?SEORYBbiCtkQ^0WAu7f zhSzVd*4EGC7rVl!X}+eq`E04BwNX*f(%qS3xLn-iU#RcH%g`sI3pYJE<7L#|o^@9; zG;Ob(-jwwpD((99%`17;Ox?9+tFaa?tGeCa)Hdo%qt>=<9?dFruBsGQDoYhLaY42H z1p21@L9gDGdAaC!(^iY*o{?68^`Cao8Usq)ueT~o8`=Z=M^{Hj?&H73P_ig$K7Uc7jq886EQU+m9vCPfa8-W zJ8trKYUkxW-%nI(jSI{a^2UzGL(R&>YW58k%DU%z zvr*UG4ZZp*(Q{`{Q(G)oD@_YJZJxn@lndzp0Px!7mXOw5+M(2%W0l^jzq48vzew^U zO}T5gP;(~NS_&fUM^%g*cY*{LiS z+6x8l(DiMnSZN9^B}u4FFY!7{Tl%s3Z8C0mJ8iYT&+<$Bp$|*^tkSogP}id?zPI%? zsIS`o?@g#{ZrXa=V{(&S>YJOinhkek(^u8nt!>$Bo1l7y=T+*=8814 zen0wu_4n$F(Ov)NlYm2v}<HZkN*Vp==_bGpqwVL9N zhNDlpPolLQKDpMFwwoQo`EzSPEv0D7cAKaohQU*9{wGUpvUX;V)_11wO*&K4H{yNI zj%{iWSe)nPM=Pxyq314|x81pQQ)T7dw^>^>=Al&vfYBBm8BJ`q-7MD&C9vNpulmv3 zrQx~@o!YEdUYv5KhCZ!*O8VOMN%%5ZG*-0qQ_LIpFgeqpEDfhu@?Sz-`IDy=WYZ35 zO+i7c>-6=K$*Znw;zJu&!i>1($r zxrgbN*UbGpf7kb2Rj74Euu#zRI@I%Ynt8iTp4`pqnN(Fvwd#F0ZodRqRM0Mpw$E=g z$^IhUJ$<{cOJOf!l6Zz7&J`@YN?#XpUT#YZ#1XfMVeQJbDyG#vH0;q~C|gVQ8B0QG z#t^3%slKUNTU%f_LN-vOt!T4uR4Th54XRf&wWzQlM-lTvx6&uB@5S2ZRO;$|IeI?k zUofdvdbn0l*|}d`p|s=nw#`M-s+Q)e+eMlEQLZX!%dM(`rl^srjTJ38O%pe_eRHNhc@&zC-7En zHtSu-Lh0>5n+>;A-!At3I>o`2IZu12zUoW;Rk^CypAT2PLYiu1(z4IIw7-NeqOMEx z)A+Wx(){%1=i&LN`3kF^m*)QfFDvg_p5=VzMMj{pUKe+~v&&sONqA>L+BEH!?8|qn z5xFq!b;XM7`Y5bMg5<7u8C0Z_Fon%Oh)K^&;2_~Ls*`6C^cm)o%2zU#IJO#`#gN*S zE@k_`myj0VK-mrrByA|Jfh8()*C6a|B%0EKv_UtrZI=V`sm_jFX`fI0+~!{`joFQP zaL^j-RcT5Ktubub?o?I_?R~b}e@d8BjK58Jp{1s}QY8yqPs@)Ft>()iJ|_KD{I z06FSzM?z=~d(0zYX^M-jCWO*Dhg36QrmFXoO8t8pe&1eg%~YCdgfmfE8~4pS;4Nj9 z1agkAA#4Yu;mWqekofR*g1vrIS$W8-;_GXusXq(i($Uy-b^(b*_o~ z9RoENeNA{(HHo_6S2fhEdo3ruAB9J&KV80*t^T8(^jpbV&T6At*fiT5*|}S+H;qsI zlecN3sA;s;r)@Te%{8@pcB52YlTWA~ZTnRd_xg5j;-mP5k+a=qr)C(#RP3*#Oiwh_ zp;J@SD3C_e%4jIfEO)+)r8cFl2-#NCfh{DEt)ZZlf~qQ^B%7oa8UdiSK-QXHJ4cq* zu4eO7Na?LX%eyBqIf140h5Dksy;Y&DdZ$rX^yTKJrk$&8&AmgWsOzb%mnYw(q+;J% zo1GiWa-NmCM}nGR4JXhaQQwBR^!w-&(yNFdx{XV6{x|#+_+Yi_YH#3HVP^i&=!)NZtNTo8Ex%73qWm4XLCrtGS58DI#apc1F7H~{ zxnGT%&+xMSmgb5@-I%uB*I_TM6t|j-Wko$3?WUp1X3FXkYAD)yZltufTdaL8R0Y$e z=M;{k#9=twJ)xPJ7+lYw{Lzaoj7h&oVeyHw5bI2ozgjYv*4c3jLX|L-vJkX{xGSip zi%AK3#7MR~*PCz1Y)zYqR+-ZW;C^zq3Jd&>)F_TrUo zSv4gVmD3t#o0XQ^mGb*~xE(arE``uHEm2c#T}7+v9ILs$n#!u$W^MEg@n_;&$UjUz zn*B<<%MVFh@zegHIaN!bw5{phV(EQfrggoU{Zn>b(c8tIp8cdQS9>F_TIpK0CZd|2 z<52Z8?>OB@wC__b`ScHX#N%-T$n7yZW@PY$4Yq?jAGz<0Y+`X3o;j&}DXA%jmn7ko zlR{?H?jFhzCFUlk-9xIIbwn3C)D)~FB!r&zRTcs?%F2NXs+H=|WSW4HO`X&_>#d?g zX_5dRBM0YlcMvdf9Bmp$N!|6G_R(at&|K=(b-!3_1^Z>Ls_43Uy+d=SwOgC|dSI11 zRaaK{VuFv|Y0CP5npPBCP>%BY3j8&B?f8i^&k@MWri-Px@-s@=HBIi(sxGfm-8B+* z3NCJ{jU9|XO@IGW!rUtr82UG zA!`8&QY*AGX`r$;)|QY$h+3<9W)cO|NuV^Y^O22TM1Pat=&P0%-6+0ydh^m;!sZ6I zsAj*GdUHWrZLV4Mj-b){dZSkAjSWdbN2>34Jz;0K(AplZcDjgZyStihy5UDnPeWa9 zV*OR%KjInqiu0%O0n~i7cbt~J2SEP-BdoXm2c>Fs3sniXTx?IjXJIv!wU0jXE_L;4 z)9qaAF4SnDw_GdkHPtqYE}ye5-C?(V8Y7>)!u%3FC)8OzMe>JA`jM&iiOl_P&Awe~ z8hui0o#pKgs?+*DzS~8qTh(k`E*E-(PSthFl8S<_>umSC8?Rh7#rl@}Wv9|UEBfvA ztLRIgzLGf;$}UCvX4HJV=gx|6PHG-wbF%rTv}J+ae|t@`9 z*!J;>5;KwjKVj{s;LGc$(eI+Yb+7M!srd<0&3nz#qe@*lGpp^IZ%%4k=Pk8uwzAI%14W!dn(_3mNMSIGt@g%{CJ@7}|W=O;cIS~;MF~T#9 z?oY&KCvar^nTh+4LB#Osd|F0h51KC}iG-yt79Lv;fR&|VW!A`2K`8-aC7`Ja1u7yo z$WcO)p+ZJg6&0qS*W0eOkGOAHT$}tHJ$2oj=l=jb{{R&BFPzS_a^Fu{Xeep9m&q$# z#ir;imwi)hvp1nFboQ$Q*IJ=ZQE1fG{Vj2_+fD7tds^<+Jx_b2xmNsQ@@}V>)O_CM zU0*iot7`dEOU#WAQ_RXsbBkucR-ZQ;giU(<-WHA?C&7gZtkp-Hz^ zs0vp&(o7Sa2<$}TIPW>k{+ttozhHMJGY5Esk&GOljyT*80bUI%{F%jPXJyvgZA&)t zW!Vx9p)Mq*P)oGfKv#GT!PzaNX8T21xaW96wi1;L$f+vJ>1`8SylcvzL!XJa;!Ekl z{zKTm4!^^8-(hpml_reS?%(UR4u;fp8v5bQ`wuoQI_A4sTQvtT?XBwNQR*5>I}5e9 zTGUWqtNy<4V>Ehp!ALDvf1agO)G3DPRP)QGWyhUnoVv2ZZ&W3O)H=&uMGd&}DVR&{ zBn3K}b`r9n(m<_kw%l(w3JXQ1hO+5(y4KTMZFbvzGu5^C8-;W2(@{`R(bFO7ipt8m zml~(0rl)OhJo?bnNLz{k`VHxu@Vxb5>TA@K{*`UoTHDHAZc%6#d8J)o=VfJPfviS{ zrM}s$b(bm%3Y&FR%IRK(UfZ}+S?TEoZEdQG<#A*RDjJG}YRXIDU7CR?fkz7ezq!KDl%2E;z$fY(?k)RZ?u2(gWJEz2L z1QCEc<|KcP#|aragyT8+fN}v5kF;(~cRYJB_+0)Sw!cyT0EunF8O7kAWrge6Zw<6D6?H-`F>OZQkG&Qsrq}%Fk6wh2#{aq52!<=vU z%<2zJmv3IY(z5zc03igZTk1sUeD4W*WubFy#S=j1ye={px)Zp)}Xg& z+bw0P^=YrTIZ;Pvuu&}|;I4O1W8lch*a#qZ?mqbA@AH^{iT6Fd8GabvgEa>w{W7yj zXuERz(-$r%HTI*nH+bcZbq1l)^|p$%(p6gTIxd>aeW$l+WZlhXqr2HOJw~P0dNk=B zPt7eiY}eHmuA$q>dBx85dD$dNOt|CoQf5aGYE5#J4ZegI+fwEmTaB59LfUY$3cH=M z08mPkxs+bOaP6%HAuCGT+6oH_8zgLzLJh$rihu-sn0meRt@wp<50sh@m|m*%jq62n z&>1W{REKq@v`=1r+YNPPZ9BaP+R#%1(Au z=t0iQFD&_#d1Y^_W|_`v+jMrLsL)p1gOwLrMrbQ_oi(-HJwb4N>m}h0+v_e2)V!N* zYSO~mVa1Q7Z^vgr`q8@EeI;_gn7*dd>i1D|?&EgmCoefq%l=L2%LCS`wb^an?b}FF z*eGAZ6I7&V$7G=dr-XHEn}A+uzEK26|S{bhSL84gYT>RHIvhir5ek{ zW~%2tvDF%T`xnj~A6aj!xa*5jZ1ozlqR7RDuTtI^wA%Geu-mJ3ZEX!b-ll;y)IZwI z0jxFqJ2;Fpvy!t|Mj6@ZR*c*8lQLbOm0lSv)*RE$H8VFUCFt_+%+8>&8y|pdOgsV* zt0ps_ef&aUOP`sVopnv6qU`g_n{i|DTU(B)YVPQ(q^U_BwWw(xAhW4;E}~|p=XBH6 zdWotOtLv|HG?lGCNZVAzfmu~X+t${Yr)46jq3TA+C{wC+C~@U4zrLV94{mRA1JgIB z?^Rlc`=sl%7pcpY1-F%UJ2k@PTd562(uvER3p$wHta@RaJxZuqsP~cduCmMY#iw6w zPoXL9_b+{8@(1va=g+L}M|yhFx?k3xBKf1E?6w;RHR(Brr8SF|)-9IXrHR|c4f{`N z+pd~vHFbCEg7q-AF+p#-2uZHp<$jt*B?ZO7^F; z&p6xi#ZtIK23~ACHWM>5iAg;ow_IhpZJ$Vzn3tF>1tH}XxDrx;g(#Hu<=}W-Y{F2W zl7NO(w%S44O$bU<8m7oJ*Z?G&8v|a`ejwh1ufBjOJw4W5d7-8Grg`Vf*7dDx8bOwy zrO?%l(OA~~hPwGla=6=XPgPaiE-JTFQ3`5jsI9AZo$B-l9~>>|Z}9;2E$H}j2|k-S z$9m-=xvgcOvFp)6Xwvsj;}kY;;-A6aZOu<(zcpsPS^ofzUJaK~SQl&5R)KV`{u^|p zH80L<@h0T|0Htn7bDK?Q-$~x4YrR$Imoz;U+Vjk+>#a52+FRXi(&X9GCbrtk7P+=D zPAbb(scpm};Dc1sTv}hK>R%$c70sVh9NE#ljpSyHuI2|db^UE!ze#Bub!Dd8QFMOW zX}DkRYjWj&ueDh1ls3yHs^xdN-0t@)eYV|gpsTE{t74j+#g0P{?Ht7B0^ja|QdrcJ z%&KB@=d3B2HWtfI8J5>GB>3*wOsZOKNmRmAQd$!Wqm)u~*MUkU(5X`~DDp@Ma#`h- zB$VtZ1$x!n3L#qsHK|B6+6SuF^B3#5Q84YwvG$hi1v<<1F1pjCfRL|swS`C!X8>$D zLy|hO$)ojsO?CRIRCE=#TB~AeOHR6mpLV+2RN9 zLHe}(Ke78UXcBs>uikg!3aDLaRTcfihPBl=?vdo)@ z)@jX2sBOiYrLl(V)o^a&ux7**UtrS-l>CL*Yg%eCZ%h=27T>;R<*+ zwxu;L5NP_?-YUtR)nanCu0gqR3=CmCph|*?kFWh2u=ZjKml1D;Y6H_8Sr@E z{{UGO-kGR3jTt`~G_rtVh_KEy>I3w3)YTO0 z(^TqZ>Ni%}-lckt_d4rr=Ps739Tn)Wv^moyZ&RA8UZX#iE28&bS;T&7R3=CpPfeAY zm7bSoZdKGjFEH9&W#m_7#?}E!l1K)Gc)+Bjl#o(ExE7(@X=Ck-b=O5}eKe{Qq4h=P z`q89eRg~8>P*5V4xnKwBC@Cv$w>nD7MpSx{Uh-{^RRyIV!&_TQE@73-?Qf?`ZR(va zg*HiPFBWR8YN&M}sQYz=6_hWOg#tx02>~Jw1QqMCY!*6K(* zI>0G?q5+T;w@@Ah!|@03qW^B&2mQsZs2TSHR9Qm31!WIE95D(MYB zPNkKD87pa}NXi0XMwX?zTd1lYxYX3srk%D~Lr;(jiVJCVOg2C+DP_XoEQw!OP*Oky z4M9&>^ku0Hl?GZ$No}#xy2|Ime>&hnan+Cll%ST7IurfdX-ZSU_x(Xvf2{hNgV4)m zLY9>)DsG*!U;&TL>co4lsWP%41fd9RI295oY4!8GSlaKpve&4>n5sqAik+n^={}uo zEvJ^Ef$vtZq9dU_T?uJVDX}36QCi0uqn4Uy1B$oZsH%{F-%D@x&{VqPgZ@pHY615M zBqXRi(bRBCLX0^~Co}PP+BVU7`kUl?Ifgpi_IFBQPVc{YE`U?*ZoAD5)8(-v>2GjFe+t#u{h;03GlBMq&tpdqA0x37#Cp{{T^moNeR-G6~2( zelIF*mkKnkRa8|CHifCO>1g`}#Ha-!52jjLlA{Nu#T2UwAc4h>{{W=te03hcm?OB5 z2^cvCgiCus<-6ewnDK+$0~_GuAV&LSAGD`w#`C{p1ZO0JB#DFfJV5u(NF>Jj6Zgb| zcmDuS0VDSq0|yZ^{{U=B{kTIs{g(ZoRb2AfJW(L^HKQR*%ylxIL*bVdFbA=;g-@(ZMK*8_an3$YL3lcY; z(Ib5S0HgqNVouoM4-dO5Tid0t5}lGx(j)DICP9qGF%jNJ1m`9qAPEu-W5E4ze82~S zW_N-J8U3JmF&{n#+yLzp0|0F^2Uj6DD>OCxtkV+-xVRbNT=#ar*G58~DkCpCcV#Vot-(I7RE-*NjR?-?0&y zJ@RuCnft`zIAobU!21r-Cpi-{h#B$3JoOyy+JEo%7#)n^PQ;9ThWn4uoc6?xhYqrY zPEKY9e8lcB4#IaL4~+2S!1I{wbMQd!1~>c3nB#aE83dfkIUDU0jQ#Pz57ny1PI#(0Q*dj{{ZWT56@x# zkRZt3JB)*z7!i^V@-lLFBw%(JkZ@q+j{qO{2lH>72r=Iz6Sm-)d%U-G`(YB#dF|#z zp8o(T9t`6rXe7*c++t2~oF4xG5%-cfK%be~a!$bb_%n|LgWVJ097ImSCU=31_df?1 zSI5um>&hlp(@whjtg&9eb<7y>E&4Kj^{n_DqS`8U6T2efAj1obNkec8P)j zlf-aAleCOXfsvD$oEY!(#_OVV=)PQo)hR#2XjF%42@scDo~Eh6I6mP8Zun^=7%CHM z?x&SJ_2s7E9$YQMcJHrBM&G4qDYUJQqf}i`KBe{|jg@{^64RJzw1pWC)v6YvB(}mr zi~!){itFwbH%iKi`o)#hRJvSnZ<0A*tJ*Iscj zVqB4=RYN%$=yoB zl|H__Vsno<1kZmH82vkD3=#o31~$&y>_N;x7yy05gCmG|$TL5_3=O6-C*!_iMC6hq zBthH2BOS4U-x%!c?)UQ$9Dw*`Za&O_;};CoR8qK?sh@tC<%R(r3*sq7%M$8KuE87X&;;Uo@QW@ zkpUx*cY!h_4X5Yt;BE*JjuiOXW_> z`P)f?Nk|}(s`oR3d*pW@;2q`+eetyBD0LO~+tKuQTGmk5JuMg1^)NU&rhnY0RD`5u zvLgcojuoeYuD^HJ#vDIoy0l{*ZN`?So^5S7g+kEcRE41L3kwM;FlG*5#tEJv58OwL zhSrK?%;ss9B2xlE;;-?&3vdfv zew(YeJmCY}wbXUA&@29M*Skc@U}h6Yvlt0IBZtEI?*r=Rp*5sGW&QbiX;Vz{K*$$GD(my(%pi3LX`?UI`>z3 z>%tvVc3-wMVf&ce0}(Og9^QL?UJm&QIM1AslZcbpXS^Rd8tXOI*h#Oq)>0rIkn_~; zrJ}FP0WXx6SNy;pg^?x?ZZWcC6N4ZT2g!*2B+uzENZ<~e=mz}9o>m0VMeDA$hayOl zOhTK>fs#IcGyO6#+>bmT7#Q1f0FXaPgZiHQLmrbnDdk2_8>e8}(jU4bNa-y2B+PG?~TVhj>< z!H{5lk)HE1W6Tl;PWuS~y7||ADrs7r>UGRtOu{9NzetQ@7(KxPPyONGf$`dB8|DT^ zPH{0fBQONulm7sJ+a#IW;wExT=WfTi_!0me_mFUYPYN9l?Q6ISP-$H&PkY1e;S>Iu zBQvqie2{yb{r2D(ob4EygXi||Cq1muw27kAHdY%m)j-WrnUJc| zYnGhsLh2MC_%Q%L>cu-QRX)WtDeHEn)|hB-E;_Wf*pVkHP#YPX0|q;Y(`ad=G}s7j zw$joPG7yH+5`=?{B_Iv_p4>Rn))b(nsaoEobK!Wg*KTH3eNL&UXn+L;9Tg%~pUxa? z)`AXZ4Pj1T{#c9y#)Fxk1AVYJhy+9!{g0kA8j`E)H3jCQ-1k!D%B?Lg{&Nk!w%8(j z22j|H92{l_6i#!KBR&TC$H^Oj0TTcMKUb9nH08p%M6Z|Z-KSYcb~La4D*A8#06Z3b z_x}LIbw2zY8c>s^w9z}81)QJ1@ak?3F^|}O&Hn(KxCikr75@Mt#C1PZpZqzsA?`2N zj7*RGpQsW<{O7WAc8L8%5=@>ofw1H``D<#PG_-z6c98!7^%g(;b&Bt={yF_A&&!R7 z+6bJF+?)w8Ny!_^0?wJCgw)|B$dWs#+g4H-~%YJJ&K_{W$eC^zQ!mlDC zaB~^J07iQNd%!Wb5hopk3YE)gC}_ee=(f*B#{A7DV|o>a2oNZ z?8)B`XO%Rk)oW+MB`16kBL*{{yqNx&lhY%DXA_iwHv_rz`vY!9sJ{C0wzpA5j;6smdklg>gQe+;Yx=A?9(m>j_mwIvHfEoe$$C2 zMn{Rs5V~g_L(GigOcN2{8H@qnBZdAO%nXzFJ+gDO4;ciFz#d4Ej1REbZQ6Dtg?Qg~ zroxu77t9?qpvmLm<;&l#;hg^fT;RYSB4kg4ljLxxzUDANIod~Pg8+~q{iYQ6fhTkE zxxrAz+r}fv91>^wz6Lv<$L+q^$c@JejydqJ;@s}yEo#(S9w$t^Gx*Y$t)fL(IG7#& z_`%*xXh=5w9K`yBYei6c2|(^t#ENujq?I?~7@p~MC$qXdyq`E9j;Gt%0e zS4jaWQk0N)2J{^TwISV4sA(ufB}S5!#F~Wzk`UwLtgEMR-6O*?7E+m91m#L_r73a3 zoAj->+{%GLmjUjeu79#P%0_%PsXbBdrLx^PJy1gG zoam=X-}#+M{Hi$#Jv-914u-M7ve=b%sZ4=cUI=by3rVRQT_W0e`Ty@1d>x*$~B(24$sl}26lBJTh z830Kp0Nh4tPh+-D2>CtdGv_heIh=(6AXMCn&{I2d-KaK+O48(t zOInE=sY;cc2n9sM8SNDQWcJ$`*Z~K`#y?0rN5B2!{doTXyzsd+Cn2Gw#WSVF$>2rl zzahX=miuRsuI=Lbh?mEF_c8&=pYT7f2|N>k35eTyBwzLf{*%N6c~H`|-F&NIZWOiZKvPVKQS>k{sE5g>1j#Qd1V#K4{Q zMefw z5#Dk$K7Kz*5KQo>&(4CC`Zcceo>k8=SRS(8DW5a&zIRl0wR8_As*0i7XWRZq8CgQI zHZg@HozSU5fc(J7j#sjCIF5!dwD=G{x|IN^&ru3~pL5t1GJbuoICRO}Phmf|XgTlN z1OXW@{_&g>vH1c{!{ZQ77}Si2uHlxJB%Y0LQy7pG0rz-T`A}Z_?Y_N`t+Hv2T*0bj zvg4{Bmf=98w@{Tz;69L;Q3@oKK8~PL2j$<6Cco%gwUjOPLAcP2`|Ke5ttYp>!IcOR z)U*|#9;t|qH7YBGZMET3K~(iKp#K0nOCzX35VVj|;$WFd(y_QA2032A%(S>sPkv}1 zk^rx#K@F2Q_t*sV0!RgH$ibGt&lwsT*4bYz#{09N&s*mh(1UB`T8-4-z}r!jaPiDX z&wm6FOYteM;uRk(Ko9u$Vdj00H-c zMn(b1nUVI%kU#P}PZ5&`5eIBWa3lanZt=FjnJ4&ScNmfPJ*Hq}@17Mj6|Dt5!;J=F zmgjhTJaWp%>K3JMcwoVTb3Z12@<+zljpu_iCNOaum@;>a4W>_gPIyBR8~&bT2#M|p zIh=PGK1Kx0;2idu@DIt{@5IkqTRLY-4sqCoMG z3}eO))4U(PK7Y^%1kOGq+y4Im=>7iyrU)a4J%)eMJNU-gfPO{?7N^~nv!S3Q+l{?| zQSi6BE*tWtJYo3l{t`EgfoM+@_MmzWW{Ljw@Nyx_Md=vV9Q-TPI7~CAM z@W90OgBiv?HpU1u#IE{j$8}G#{LdJIz*OGb_kphZ@TGWG9x`^`Aa;U3Vqj+{ycyt; zF}T48v}1S%Oh@bb@Q;ZZC&!Z_1~Mjh*m);{e)u!oOu)&5z6W^hI98^_o%$SxwA9;q zr7u`&IURS>xq065!yrw8M?;biV71e{0!XUIR$$?ORbckpr`5O$Lo z?F5`gB#=9!jm|d!{9r-*81Xp#qls@3etBA>jcM}C$c zM|nR!d+<&^f#`gB#g{S5Jp5qV{d~eZ10(%u-z^rshVXqPXL;_ zqx95hNl86L_dsljNq~-}91fU*Ze&vVTKp|~k39#Pqn_?m8jS8mYvW-Ue1Zhb$tS)K ze%=A^u^d!ww;ftqX|=fG$p}IcR;6T^N)swk!8is;IPJ#Bid{2q1l%iXZuLON(%O^l zQ4h)wOO>yrEyNGZCY_*qw#QK7-R(Aud8sSBc!=n_gzBN3Ic+g zEke3VV5Up%)CyQvPXW4zbO!;QI1GjL($wGLVyZOFLkagUHFTC{ib?6JSaz{#0Vn&q z8gk`9Frfi{*(Cn}&6sMg)ArRZHv4++?vxa!uI^Hrbf~2#t*QpVO41CFDjh10-73bk za5lPvFgb!tpV}xwSo`*xoIEQ18D3p;XBN;hX#xc%uD9$mC)iAQ-44h+R z=jf0)Hs9a*{rCR={kZSzzFyb$dcH)z-s&-?iTbb}@XWkZ5Q=^Ya($Zq-xbi4r$Let z5D<9|&=(?>r69TNbxZNr=-OJ>36HuM>ncnCuu1=suitCM4@_TP0M^v+$ggTY3yy8M zDMC#Y51Q|JTq5Zj*M+X**xBFk(l<|sm^xCT1Fw!RUimP`{Pybi$06jWoF0@VrZJCe zXWHi!p1yn#7pm|$@h+oRsLVViJ1K~T32VN@tVT%&jQ-=~Yk0gs)LfYV4sh7zogj=R zxl9erw_eLs@Kx(u+IlzhLin`nFzX3TT+qTobL%zi0?XaVFY~O5pM*7EmvB-|vNcbZ zPE<>IzJCecmzVJ{U zJlrasxgh=MA@`Li<}p~i`PxmumxV~4M1|)s*jOav1&lQ>0E|{f245f#OdHL&$*SAD2#52P(4p}TSCAsexzpgsf+$jT~N_?DW-m@4+-V&wF-@2tZ zRrFr|?YU*$fgba*EZzRqu@6hk=l)%J!F*CW?{`aUi~(Z<2)^4p-q&G%sIBJchQ8YB zBeR4%D*DCjdu#Y~DZa?pgNdW*>;Bug&cAW-UKD`o>D#xzu6+H=Ho#)|lj*JH<$e#0 z$WJB~&8@7fl1Z%m5x^tIg*mR z9ccNi;=C3dgW&uaae**v2FpL6X}Qyy&$q+Q&L4l;7YQ(WDbFGqmb&nCXJ4`H;DZ{g zKxDtQzPoQf^296ZNJ#2wqOM!JkZsmQp)Y*vmvC<-c(YCQUS8X5wKM#!Q}hp7w4nYj^&9sNWS0Jn?PB!8abJQB zud>?}%tUWKd_5rlaw>8u40zTbk>md7w+Hc&>wg14#R**#+u_#w6!x#uROc5lE=&@F z66-4d?>E=}CTD3la9YneVa6?z27b~A1?0-gYF*?7+oBLn zqz(+e78xmA6Y)xTm$Lof?xD({w1gK=7koPX<-k;FA>Hcx8gC4! zDE*9f|8B@JIyT`rFk)4(Dw^UwH)(C=VqOhF3RQ)WK{>pij?<+~VZ=%TiM-*uBV!B3 zHpoY0peB#{4sGbM`wkmm-6&!VeA{UU6;s|wi|Zme&Ia;Y+G#G066}c`8<`p{f}lJs zPtWj>=cZ?9(2%G3kVnABf;JxUl+vO|)VVv}{wDbW62|r}CT^5)fQd8vh{QSO>)cJd z_Lzspbbq^L;OjB5VlVriGZ?NSsI-ms2O#SBnt}ogz?juT)Q62l{2Jz$uo$4=boBw_ zHLh!NYfk>~sS~pZ=2p*n!?4m1Z-x8gKo9m@BAxy7yQi-#r@s^nYCXX-Tinsv)Yodi zBHZVBRrG&M%YZ+etO-m7nKuUxbnY4r3ku6j*w{PZZdF!AB8Y;wb7Y~znIlX|n7XzGp`xn_L$39o}`<27`1fw428!TJhK_$hg+)zk90u^-XM$}cP`qP< zDO6+&9g~qa9_)i`?2pp-fHmodSDFzlYkLT{Il9a+4Jy}%ihrCKYsLGGfi#b+*I3>! z#}zLpOR&89{F@A8MMT`e8em8uXalb@Jfmy3Sh*6GuoiwMW~pm6l4%ZF@5SN$fu=HY z#`QSI!{~5=>a%YH=(^x$^E96vP_?lr8;44aeU^@5GW1<*(SnI&*IaP0BG2)Arc^-~ z-|c(L8#mL)cSFG`-qX)I!kHD0vZ}AmUVN2fS1F#1z61*7s!YDefBj>2Iy>`}Yr21^ z;$Ztudd3d&zG}Ix%^|eFeaOth%>0}<(Z!a9-Q%>1Iw0Y~EzIO1`1qXD zIthFn&CL0U_Oc(D5hq!)wcxLN;1}Q7l2>UB1$6G8{%vs8nhnleELv#XiJEJf)@d3! zy;>1jR%>CaP6)yA5X9yK>Z! zJ@4*sE(N=_hJ*S%-H8`kcVF1W-WqHrjodJ~bBW2;+r^#<*%N>yT41Xpe*C>g8>>Bq ztbcbq<3CBB&`j8s9R+jNwOO4dxvQVL*@b?g97YYJoi+Gzw`s@30uU11sUt%vPv z3Ns(^yfJ~<*()9he9qRmswupG0~qU8*CAbN=EE@Ebl6HAbsDyBE7EU=?(&!&gpnpf z2P?92S}=3tVPOWfo8HfI$P>f{S%Nt=rGArw-rXCbp$T{g5Qcv7Uls9b2S{%JO)>6s zvs5eUXSK@Vg&*AxuJF}a zYjv7p;0xYF_vu+(u!#@h{J@FuniWwfY{>GW>?>&y$m6h0(#QRKh@ctww*r5z5AZlI z7-Ihkny!%4DL)2^Im*E(YBLzc>!c%D zvB;(kRQ|SBgkQYzrA{>lMjQ-v!VuhkE6Yv-K|$aL^vn@$tFR`*q?$VVhqmLyKbIVh zc^hoZxF)*1ah(P*D5q^Sxj5BfCY*K)&PH7z9K^IEWQ@NCf4ROr+da<@+25b>>eO%9 z{fV)+EKd$IZDe@QWy#HSzm;C^_ZD`FUajB;Wn9`O%Km_CTgzY3I#;hM@IG&_5NqF@ z(X|xX3i?gkznmKjG!oM&vWV2PSMcDL14_MoEwL~7h)`KblbLvb_s?f33-NC`FTSTq zB%v=kQ_e{_uuqw0OxE#$;Y_-sX|M}=R*>L(eh<^SS^`Q6{W=Z&8EjZ*Z0!B2@XI!B zvB5;;NdVnGR!ggK+%mp3Ua(aGzll#b0j)^a&TZJ2)Gj-N>)O=5I|5RyjJMi~0-oLc z!gR98qC0FUj0Jb|7zW0tNb7JMaheNuwSd;8(Da6#s&u8ARff4b7VN(o_p!Cpyi?h# zd1T0TD%T{sO#mOo`)fFO@QDOCY=a?$G`Y`Nz7ii})!B<;(OU}{O2kr2Z^n7-erDj|P zjn5kdsFa{IZ1!tp>I{+J{hBE>6=>o^S1je8)IGnvURgyBv6l?ebjlR$UDp!}V^)!{ zEAQXNtHRoUOr50w9=~QPKAQIKRcYae^Gi`-P4rz|d!~P5)h#WaOD-smxNB80ob$=fzrUO0yaSjiSdNi&&I3F@AD)sbq?0EA$ zX;aG=xLOAJuQf;E9-IjQua&fx0J4y>D(jN3*WKf?F&uf>S|e_k&0!w;KPCxvur*bY zAR>2Y^rXJU50??VBRyV;jvy)xp|R@->d?f!-?MQgIo5LJucn|`xpxbcdd)Ghl}eYa z08s}uae^^#{(hkgdG4OpL?fQ8vF=sm<^={!VPW~^ju7quJ{qI}1LNr0c#LkJ@9p}R zvdiloVWyOiLJI^;;*~}s^a?|u^E#Jd-~$+hKjS(0e@tBRD8Gh1Gr0u9T!Avn8(&vD zH<;%4#(BA+u2^Nc42**dbwkjb1^`=hM!Su^EB}a{v+HeKs6_@uIE=EaSjwI1AI-0s z(Q}keCf8_9x#63$5iF?C@3n{N(Vza26Rp8PDs*TX)hrfFf{)nRI=j6R?qVqMXm}bj zvg=hsmaTkC&*%5aovEHY8Ro{np0Ws6SLd93{BKMuAcYdf`QcoD)r}G6#t%W>{sm4D zSseCGd#bZN5Z6<|X1ZE6uWw%RS6sAK_j(xgwH`1sXOY02^#53SZWRlMqZ_LdWs$|U zRMz~XAw8%2|8=`p{DJ57Mt))hdYM__Gzy6qzaij}{(r91)7wn8$fY$v1DC+tL7yhL zr2!YIEG5(a%T>tn<~070NYb8ao5x3`kxR}{2<5kJ&GlCqr zA)lIG&pEy>qsv&PZ=p!>Jfg0{FoSWGo&OGzT2H8eYLvE3SiZ&hG#;`%uZRh(9B-C& zYDVpLdXa4%T(+*$aU~g_(+X`#WHS7QQ0oNo=Ol$_ntTVBw`5ukaop|`Q6^{Rb?Q$Qz=6e>+7#;KuA-P(QkPRVPBHb^yV3IZh`vMBvH2HI zx&&f;cduA0emwFw8QB90kGq_E^N5j#@8R&+a z|H14i(WO=fG8K(v33N;&xYYc<$8hS3=tmlY_XUHv;=t9@9~d)EhX~=Ctk~%nJ*)gb zBJ>~xHPC&&Qd64*K-J!hi*A~Ti}$j$T&_^{bS;^TmmUJ4UcWE@eMLV!&^Th--KdDw z-BI~Eg34cHFDoLc_}8cYBph|#81oBlSx1>H4;V)fjPjne+E7lvSHc!*{jO?{1MrfO#iFdzB>`qB$tp=phIfvq6@khzy z@I*(IbY>z4Z`{jgmQ5A&ao>?>7!+*~ifD-D|5iFxi>hq4BIxJ_SGQ;d$0htGw!6^f z4{DB3bg%WWcXOGCC~(=kfqBb7r~ERh@cKgZCwHh}F+M^AG%;7*diT)YC_b=c+OC=l zDx0n`>klLo{}^h@yN^j%5|oTO!NA|20_Y28&xE6I;%O*ypu!QuS_Z7|9b z2*=UT7RVMT%%q$L7+OP!6f$|%3ZQg`*A8E^8yLES7=1}(e1b@nV!Olo+!Bn`h9P9R%gbA)6pavrb~>DC%!H{aLjZYs|^+A+^Fe-D302O7f($jKfdA z-Ep0G+?2Ar95(I^s@d9RrXVH(Mdht=woTVYdY8!_@2UzI^uhsXk#)-Oma%(E|Dt_a zn=I9r&>(|8N-hccCuUkK1S64m?EC<4V)P4d6bd8CKQ=_^Q%^Ngux8gC$$&6NkXa|V zZ%!D<%kWTCX?0ao)D0iZKux~OZQOiB@sEk%h8Pk~$gAy#&8d-rZkgySW?4&5WN$yN z_N(?VgI~(E`gtDW@8m`tOk5BtUK5SKHSZ{hJJHz^c@>$&Z)q8-x9vUI?9zvfOk0nd zyfpEAuxlnrW8c8pKalSt`9BAkvwcmFe=F7u7O{(;i@05(G&XB(uTPM(3+=ZLt0*8} z&Vk>CtI|^xlwofSA$|4s=@i=Pc8%PBE>gT;*IzbLe&m>s0Gk8YB-fC?tinbo$Nk;F z@uDPBcM_j$Cy=@Y?8=YkjoSSmQ#rAQ-dFP3CQQ-(r~j$W;H(w`TJMN771Bk^#^ljr zItZkx-Hm)1-nnD*k-pW@Dv~{a`Qg*J1Y*dc?XLfU&(6}e0o}d+@F?v~cSVNnPND6N zW${eYYV)g~bx_$`Fx+edmYhKOxO;xL>+{5Qr6?h_LK^28PkiQ2@H@}unK_qNT?PC3 z^Phw#7g!wm;T)zOHpB5r0L?%6FitI%BRea~zyHLC`E2wEE|4JJ>uNbxL?aKi?{8ep z1pLV;kJ~E7LEfeU5mGno{~@43`GRp0-3f7>CyH&HgPX80p3)aU$f3T+H(^dQ=?UK4KNfyNK+KAdp?Grj=!@zC&*` z`*&wJ%wzW-fCFe+W5+8gNNr^9T;z#h_tpDA;c|u*vXO4Kp>G5= zYq{Gd58;H!kWxtG?C-U`R3a2NLx){!f*i}*Dr0uT!}laX4Q-R%W`U8b`AAx73$m-N z_~`R3lZ-y;AimzxK18*!zFT4Pz*`LuIzaQ)%F2p2_zDWrqUQo~6$mW53PV67B%$0G zbB`rgIeIzs%28@=k-(BL5K?(KD1MO0%3s&I7{iuIy|>N-UV_d)^xf+bR2{W z+bn|(B&!#Ya%97-(D8KT%8f&Z7i!b1B~=$EXbLm2D!o`OH27> z@<82|)MFl8+G+H}AE!XR<0idQd;e4SAfJISJWiK!QzII1lhW`tBxb%F92{3iYF~3i zkJ)y;jqcnid@s1PJ2^Pn7POvkWE+ZzNy*LShZSr7MdIPj$p0}7KT-F>bcZ!-Y}P6B znt@}5V*U5`kwEehL=H>eB^+@sP7ZfotdEV4`4IL#XWySw7LA*Z5zgyFeXeipID6re zr!k0<{=Mah((=iV+cydBfV9X)G)$!{N0FuoD;#FL_CjBGR}MILGKo41M_Qi$9Nm9z zoIROA1(lEd5V+X*{-B`p^W>e<-~L#R!7W34OvZwtQv(7EHxvkjZ$pq^y_#&AOHt)( zU(WBr0Y(_7imqIRv5%iVeiOg>u-A(6BQM6rSla&T;44zjNC}N2y~!^5PZ68#8<&6z zKRf;l%@vG}q~l`U{-nH8{2?$^>4t{qP}$3$-n%>6n;z_p;Z*#LUD#>8Q5gkdQX#vfTu_aaV`+W|4nlR!Uo zmou<9Err1iFpH>e=zi_{E2XmYdW`Ds_85n(`zW=+=K11kU&4x(qb!|wN#6znmO{~Q zWOPBpZGSoz8WwkJJq5-kbWgY-i6Hp1PKz>39-8dEVW!0QXKo->32oSP3en9&=h;c#50%!>be;sqgO9SY(ZlRw3(GaR8sn8Ti5W8=j^GaXh5Uy-btiwK1dMcRYkYm^;Ja41CRis5$}d(2)rdoj}6-h&-!F#-gFy0>e-t;?>zpVWBsI2 zOOKKEl=5KXg>&2z`*4$I6L*U*X`R|2)Rv$y@i^`@P#$s-kF~iKB3noMliY3}kYFQg z_JWNGUTD(+7@#WtO*_%RluE`v-at!HeO>JR>rDY+&vHm+^<6(X!OAOr_0wTpPP-%E zu5~|*YD7&{qcYG=iI)531_IekaUAAO*rNz0v`G|~FP&XJx2{(+N5b^us{-7Z`yv1z7hJ^JBvTzmo z*sKf=?jYb@U27`ar93k-zM*1qpRsQ4JM(|rSB=Wge4w3{>+{>3YmyI?_^Lr8?AD&+ zAeI$mgGNx^4YXT&FgnbJPWip=KQ*DuhP%6EZT74g;E9ggiV98GaG>#e<gF zDa@QHB&G(8nl8$`D}L{F3$AA6!O{9)@oT4HtoQ+s)pv(09*~xtv*L7LRE!+S(#%7T+w2!=$04A z-g~sSEFzBaMG5<_&zr;?19vWGrL{ZxNBh>&EZWSfH)#3A_dVOd_s~(G!9fzrZ+En| zt_vdl24Uc3w?&weMizyK-F5ge6OeCTm3R+dVgS8*UxS}>y(H_ght!-(0{NGXhe2S2c=q^}@ zqtsT$$uVq1Rj)YuX=nS$kF=Kh0OG{dZ&=P%IrNQRG~ced z26f-xzT3U@bAy-SbYqg5Lp8R1R^H(H;W4Y-`IG*eaQs_v-EIzPRt47bW=uMOEtXG) z<6qOdX+9#76+ET8|ACl z-rVQOF80MJs+m%vXDr-chlrt1i-NF%8`V}nLIQ6iU{c(3P3ZTtxyzl6?Xm*Wmf<(p z*hQIu26i?;q@Q$@o91)EO!4Y!I(}E9$&mqzi19U z=wXl?kkDM&W=i9Ap%E~Zt>5yJn=8z6KpXX0_{^RAAK>@%|4=Uv?dIe? zPe09$h+z3 zt!ON&aWfy4B=KGYD=YCd{;3bQ-mAev(;|MT_rr@4GB)?vC6o{sfh^C&{;iu*6*8UM z91otJiHana>VW97>-GUhJ?vl+9!Bj3$9!n{H=AMM9?=WTTaTU~jbc8V zA?xhkl2Ka$$TA%#|N2~&zIs(h8KGFZ+hnlQf40Zh!{;zD-gMrB^0TW^aqhq6Afa8y zbsK>tIr{$F16=Vyp zUlNsJYyG=ZIc{b1t&w3V3EtJ!HKHdK1S*cy(zhFt)dG6)r5gk{Pdab5Tu!J>?`(LL z0fJ`u9?8+gJ}SF4jN?kaqSfVxwN%lYf*sxVbK%KgaK8oNR8KZ43IEJKok38ocsuJm?W=^mwpDORX$vJW-Nov+$P7@9X9O&p&l@aZg zfo3_uFBVk@{H|kKdkF#$M>hU)46Cx&0#fHs43}x%tJyQ(-@*VU$+u(6zu*0QYoKB} zAF--+>t>7@ck8p?`DSH7>UYstrD_4ib-0r$SLJ?$%^eI<>C=mn-D_Y}ttY0LME#Q` z=MQ@Q_wu%m<;UG4#>)O?luk%|R(337QBCXA@6s$7*M%;Dp!o4Qdl(9KDKP#QZv z!qP$NjW-}FrV!nkCXsg0HBk8N8L!Su)LdhzkUL z2f9UAR2Y^J0w%iNT#ibkwu4OzkhLfo8-V#nt$)*>JNlUP!N%{QsUP}$^JWNR<>nuo z@ozv0=Y4!`Y)E?(5f>j>i%aQ3CJX=*4x_V?HDqX(gTi1{LcT>g@mkf{U7Y*)vl677 zO6m6$3rEEt8bUmkla9u-@$wBDSbxXO3`pmr*@!5GEyq)%pbFKNKjG=|JZPU>RhRbg z-OX4na96Pq2dU`us-tZ0#~q%0+?p0{riy@21%uci+#~;}T}R=X)EuAVfBbTMJPLs7$p=f`##;YW zY8dj{nA7Aa0M>HTrpN zu9?*;c^@TOPaz$UrfJf1@Mnm|T%vS#BfL_Ab*jc=F5i0gzKuxg8tT4{cI8dFJGc&V zs6I-H4)RC(-Yk5@4besgs;p$%IJn8~0=sAooDfjgzg^MU zqxDYJbPS$EtpM&unLZ+t10yNP?q-_VcLBFjSuB1&e95ZTXSnnpQYUkrdkO^`vS5{P zn8D0_36`^YQWmJfAmUNd^e$zU!2{3Ld76&f5vr276MvG`u>B%nbAg9DD>0-ILwF1_-K)Y#nwgSuJF5k zbwPta8kR&^cfA5vfIE@P4)!EUkQ|;u_MCShirkCYJOQ4Xp54iLUQ|ZERLoqZ&ga`f zR?@>nyxM`*g~XIhSHQ^iw3>RyPP1A$$BogdC_SgZNmC^5(~#pMQvEm(R#6v|+rbvqwOs_Os#p0R2==NZ*UHZ} zGo;zM1xRhHoihb%<)W4vEvTEnvK^9Q((=|)+D88dOmVZoBtROxMi9z5VcPQHo(@1{ zzhW?mvcUKJq@r`h6VfX_!E0Hcz<9IXH3oSUZ+yhk*37>!azZKD@oSHkFha+)Zv0y1 zRu5{TwARv)<4ErWC=;HS_ft40I=)IK_JJazPH?Q6P}D;d?8M)vDA7y7;N95Rg|xv0 zjIzEy5Yh;_WJ>XE2i63|JMcQk?~GZUv6r;{7nl8?8)p4KIIDeV;7(P&#ss!g5*g?S zhA>W5GnqI(bXJBBgy0nJ2|sM8f~kNuh%US;Y4{LCc~uSO~Js z75qvR{5<}!0p#DQUfJL{d%sfZTXv!gvVISzfdm3zoKm>>#i*2fjE2~5DZJYTDg;A7 z$CMKyGhEMUXVpp(Uim&*b%8=nBV;xQ`9nN(TZ%34O82BeH=ecU)SL^c0B4_n56-Rp zgJ!i+zVINlzOBD9?j5G3PQ+}VL-n986#sr~2k>sDbrRQZWyQ#)SnQ0HPODND0>b~% zP6ImH(XuWX6#g?wtE2JIT5lvM#bE)guARGcyseEsiEb-fcN~{-E5hnX|EB9`@e@EV zXW5Z;Ghc}Jr=-GX7wb}2_d}o~DAveMtG4<};0JYbta}xj!Vs z0D?weMLzGQ{~O8w3=GttfcQ~m7%=8EmO5|xU3N0flw!{d{zz(xZV7I(u>_7Sjt&3X zaFb6M9PXYTHUuj|a-yqmJ~jS~Y02v8yMrHeDhR-Ektk5J9I!Rqu`x;fzkPq3X9R9( zHmS=>jHKmTf+P0~D*h-shsyl@wbCu#hC0v<%Pb^Y=4xCT_rS-rTkJ%EcldJcTqjUf z1pY;0czqdm3Nn%Q2FA#18ut?t(FY^x$%&Rz5xxE-#s;X;945*FI{)W?OnqC6nd?gv zs#T0^q#eit@{m;IsVSP@7S^T(Rr_0&RIIIqD;8Vse^%aN=a4W!W$@$qLh&41Ec`c-g zioUO3t<;;5uo1X|klnG@Mz-5?fu;Y;D@@j^s~qoinuTW|o2$QOJOvEqNB0i*hN_g% zfCJ;`h)dB=Ms|tFzu{)8d}REV>&RCsd<$LMA^}gqJN&NIo4vhSJ7fAG$f!}xbvJ36 zNAV_EFw*3$(Y5@7JU@>hPuoA3)E6^EyQTMU)xO$}RJ7}v4klQUe@->1@YMO>f>2x3J6HPZd{tn8-(1W;RVPQrs{`)Z z)qrZ4i1{|F4{g(e*5W{c4l;=rlpxYEI%CZ!;`7XAb73)Z3)aAx(qXZfh@4Ek<_2`} z9`lQHT%I8x-nZVg+L_@j(J`HO7f#T*df(My-t44fHAP#=QkD)1&s{V6$1*=yNPKT( z2c>LwG{RA4d9!@M?Q@3Z%`OeE!<-0)CR9y`!B`&V7r^EF!*%837n(xII_@jl^Nwe5j# zCJ28D(E~WBmZ}HV#-<5uYYDU%0i+r6#T9nmjDgd`=em%)^uagt^5~-4W=fFYV22Bp zcKt^2HNSRS=p{;QEVXef+qws0!ro+68HCk}E2tr=wC7T{>Z8N_s(sA_>@)S6oU3W%f?4JA zdW~wUIp9ghK}C=`DDG*j($NTAa{b(>r--HIkD8U^=VW|1S+(H$pD88uHh;C54WZlS z4PXo^BSdN(y@5nFJBH#T99(`>)zwx(mnlJLNljIr!%5~)uO^#xlUH*J6Zd)$xiWW_ zU}}?3cVq{p%oK*aE!ZPOMfZP9hp@3*y>&=WPU>hxoku6zdy<$-`_M99rew}*@fE^Ht`jZ-G+^PB4_!tE+j!a@37Qy5U__) zVWG>CroHf>mqW$f<}>c?&VRPX{ml#!7$k|waf)Now&yFJ~2VOaM&9}~T zK43fJs>aK6?jO!S&M93?V{54$ZE!IRUYnW;^3B-Mnn$^JPWKW+Z}|8fOsX>A3ywUm04r; zTdzlQCgd{Ps*pZPsxD{bPBVgx%fZBDBz05^IOSJ@VtK`20Jm4!ukKNV{4LGThl#hA3@9da;yPddMSBN3M>~MC1C=T* z;_j01U!uZ;ET(hpdJoz4&RZoR*z|02UiK^BjA&>|aap9UN7QvVw1GiuE~p1wS^DP9 zm(p%Rn6qAGajp!=h@-zD(57mOCgSgfPDWW1xwIby%g?ECUFk6d42Ztp-)zbcBE9sBY(ng6EzIXF0*lfUx%zCjs$g?|42Z{>nJ`HFZmC)O@+ekV*c+^CzB9^%Qm;htRFn zzc;9GQ-xPU$>EFFbK{rWzXl*RxF5>$yd*!xsa7FlE)L>#ohR(7-MlY-tc&)4ZHv9$ zUzzldkacT4o985T@8FB4?x=X_U&{V*6t`D0QNB4;M}Mz`(of^I+Ca~Syj^tpZ1>FM z2)O|rYpu>ZzK5;~lmM1xeKjy`w8?JaDnD=fL)yx?K3(0}E(-+%b}ifG3(DF$sLYxH zUtoDPdvzaI=2Vs>NqsY6zi4PY`6&IxjFI21KTlHCi^s^i@@g5&FPIC2KDR_C7DZ-o zO^%fmi?FrFr8U0)NWj}Y$Y=lUQrDWJ#(Fr?Y9kPGm;I8ijomrXK49JO!G&Ki#Zvt6 z5ACpA&*P{n<~yBqaiuCf5gTaMD~Fggu31wzJ?^@DNfHWrCb{C*>}LJu6Ayp?lG5uv}ONMJkj{j}g`W=418^vK1CnUh*jiebGy=S8E^kH?PK5VN|rjz{=Lyk5?u4^dn8Ef z_;vNKXnNla(~m=O3*FPGgSp28l-KDk!wGkuo&DABfBx(IW#-6|=T)&{(7|M<(I3EIn{2;-xB&O`RV4{3xXGT?p*En%2<*w zpm?=?8M|Z*IFO%-Dx!6b7n%G`$#hsEK3`_%@?^nZTk7cXj1pQ^xG>)w`cVDD;r1`~ zqMj?SljD_QE5foY0Q-Ia7>0-=lhc8_;-@Jv2EFI+o5>Wr6ft$3-(w!11m1~19C-Un z#4}Fwk7%NrQ1j`YTV(oY_0k02xZ`uo>HVyZqj)@7$Gr5s=C8j=W)OzcJ!q2Qczpl< z4yWgn;L)&|M`N!g=>oL#I@=%asQr&g@NDOk=()dm$WaP6nWx**;Zja8cM|7lQzQ3v^K<>OPz`dd zNc9vxueUeCMVx3S%JmE8RaIVQ#cEn=*ErgHrA+s(jT)j7O&~)@Y?1W?>=7jP3W(7T zBAJnECn2PFfmqL#WAv|yIV-nryLZwo7f9}^TCi)2-q-k5I+zqdF&;Z9^h*+DGGXG8 zFqPmbbI+XIdc)NASUpx=;hJ!musufgl9x8c8ZhCgCs)%MY?Z`hR?t4 zf1$mz%DfC~?f;U<{O+CBac0|tXFnVR86)6tTzyNyhVwO>Dgtawn?{_>S4386`vm~6 zQAVx}Sv}#=wdT{8jK1os(O6*LvB_!sSTJ+Im4Pu&-36W@B%}{ls`k#oL_zbGLcIR1 zcK}$If-Z(l)Tkiwy?Z_W93JnAp$r+-aUT;7&S9e%j|`Ug#IFmC*{&XE6P z?jhVws=H~*pL2Lin@w@PZPPQP_y^C|-g^{--LG}d2z@?!F@uVpso@vxcDE*=mGIeR>dF#$38>v_#6r{LGyi(qb8bieCM~@x9^bQfYSry_%h&7q7LR1h!6RR8 zK!D_?*S}4>{+IIF4@?9Ew=fBjnnux?I#pNiN~#ro9WZ{tzG$fF1=ttX{`Ewa}Aa*$Z)p^mEzap>Q++p^*#u7Cp*tmU+Q_pAc0v zc1HuE@qzJWom``tSR=(W(hJENAF+%z(Lk1M9l$aV`P`Rx&5w)Q<6zsEw}uaQxSo6Z zrle%%8x^TOb#zB|?5`Jvs|Re z62)Hviq6`vy-YAk+%G~+%5`jUUPb3N{u}C3fsgRj{>ICZrQIy8&)JpCLUYBxC5C5c z|1$l^WtYSyS;J=M?+*)Ttt!?dhe!*-TCvIts`b>REyK7bXNk<4V=_ za`q*MhNf9`C42+sEv>u0?^Yf0U#-(csppjnpTy&(i65Bv&Jp{zi^JD~?nSgm7T{x} z{crv`tr)Xl(Y?d;*W%$jz}6Q_vUZqGE!Q~~cE(BjMYZZrA1L}oTVv=pn|wRETgySB zMI5jCj6!ZLEL4H*Cg4-sqjH_kI_K2=Zx{9L?EO)t-PJtnVBSmm6~Oj7F*Wfu)B6`D zbD|-)n9bL`1Xcl20~Eh^Q^F$g0Is`nVd9z1XODC>FQNup77b3KC?(cv8+j+|An zMwL!pV;N;&0phW$9kQ02&Hl25!$)qhivbdMEPU8BBYkjarR&PMDD(1+?DAT@t2WPU`*|tj85Zd zGZ~5FJ*toX9U6>(?t1UyNd6&H{Q*1fcGwOuGOTU1f@XXY0o!w&kYnT>U}y%m9u@d; zzPbqfk?kR;XtDi&@2pdRAK}mW4?13!7CVFb86N||k1}&437o)A=Q|GFfIacx!2bYI zC1y_J01d_tBpi|sVo4L3jgO!3$P+OW=6A@)#|qTxkgy`6wAQyC7xBLh;q4lc$A6s< zi;_$fm@s?DfuFQ^?GwBLlt$igBfn@re2($CgTP~G9mJC#VYd5`07T;iaEXk^eC>ch zkB->wh}@nP0My!}&n&1;cAy#STSCJ;&$QTmR);VIgZ3N22OY5=8)7FsAVxMPzUBn& zCv&mzduBL9#sq$b06%HZZRB>09vC3Vh?Cwo?lB%a@85AWnq&@NR-QaE@rCzwZ@mU9w!GUU5-KXk(y`Ki&Ov?@>P7)9CDR~|$|>6uqAZqxmvv5}VWof+ zXsC=jp&d~xLzPaUM1lR?3u*}<1$8YUFk1Ek*SM}*>um>+I>g#Yxi~ClS8?0I7*1jP<`uU+$ehNo%V1)C4~I1v4EdbMHP|Lf{D@vf<1Gl@x=ye`~a@ zk`bpg@?U)>1;W4btSD!#3UJg_s3^pwDv>iCDN0*NI?c~q>PwkY7hI}VjDp1gG_8PD z1tr82RJ54@rOJmAQcR?RvTd@dtwvq~`W*?@`9!JEP-<14g5YF#Z_+cPL)$GtIjS`k zB@gB5RTT*jRjDLSI*?uJ1AlIXoS0{$jp0Dk@TxugtQpr4nUIDkPqwK~jk%&r!_IOz{$Y?U>sU8Nnw237){8 zo**}%;BTD{$=0z3EB{@x8P@G*cmOewt^k>v)hq)C}a}ClY*i z*!*y$AGFChzyfyLZ-|J%6U2VN3GzTPGJ9?epT06@g`7$IeuMK7gPiT){>pgP+v;s| zeJE|E4e4lp&G+S9DSg-D6YMeZFl1nuGxp5pU~D*#QI9)}9Kb#dZ5fPYK$(MY*bm%} z{{Z4X->7qp3EnsIBM=~ih?peE1~`Dym$pKpo2y<`-$PDB2Anx-P1eg!1A%~<^D+-{ zzub3>{-PxCW8<;;f_xvCK5%e*EzE)6yulF=Vte@lGcZm0W&L27d~F!<^!cMUSOwcKxdGyec!F_E4AJ5ER=<8n`9xf_CDL_rb+VsbYg zcvylaM&r3XrZMD=f!v+X3v-_!12eQ_0gug_ zMsxNMe0Icn+~+vqOaf$#=Q9x`t9r#jUZQtW?M#Fyj0GY;dE%n?o6t}BN>EUbZcy6u8%v(|@FIsuri&sa2aUH)* zf#+!e4w7(5`-jFOzQaBY5F~aJ@<I~}d`x&a;m*L$WaOUvOhzXszWDP2 zrbmYzE3K`S^tB?^hwtUb%PZQ|sma?fH!DM->wROi>LeAU8D-E2kmE{}EFO?Df~-g) zPaLmg=3Ohr6!*4`BZd?8jDXSX$fbvs&8v-^!ZGS20Uo*Qo<5cxB2v4|CFbdr~p= zl!dmPbaf)Ofk-X8gpj9NN%q_@09W!lB+9(;757NptVK(8qftRF; zm5!5-&7LuKoBh(t_q%VZTR}!#WpcJ1$NpSs{!(*2L#1iNC>$PLvvU&HUX;__n-mW% zJt}chXIp z)@5v^T>upy%(hg6fFSM16W(;K=Ek)urkuM^R<(8tKT!VAh&cS1k0;%Z^+`Yox@+Phr|4CJFD{$q;tzW4!Gh6H=Q}{&4-&W1r+5cFN%HpVTHScxl`1Q|*5mGpXSo6l<1quV5gq;{ncVRnq1+D9 zoaFaRWQdU&5(eftQ`nrqfuFobXqgA{{Fwys%trqJsoFb?LC)jOJdQ6rn-6s;EvEWc zePUC1^2*eq;i%p+3KoOEZ<&nt_&Mq`+v737JnTt=WNcvn04zYrf+K(2sXxA3kxs;z`Ei zfS>!onaLfGVT^sjJ7?(h&DN!#t9hhQP{N91gWfT=r<`sw$n^p_Z2Fz*fax*ilM%B}#;(0#3w?-}ZSFNL!bioh7-( zz$u|Z(^qg=B}oZWEU99iVE$)M<&vU>1oW6x>U*20H1uj_(?+lThP5^+5~P{Kk2n46 zr=*^;wSeTPl>TEn>XcM^mZGI7^(jg+rAf@0lA>gibCV>&o8@kFIat_hzkscTLB^VS zkTTvk8t|o~YW_86w}gu|oeHP{GjO}ODxd2csk%guq-%2o2M$0ar6Y_recI)9T32wY zdZ3^}5TX*(VhA4F4W$h>2T{Th2?T&52*)41LC7%!FaV5=w$3~GQ;{-9dCmYcBep=1 z1mb6DnsEJ<+zo53?Q^|jP8-QI$oTWG)ecDpa3VqMXKxenv=ApeBaw*t#xp;zG5>ERWoW$=Rf3WSmaQDfHmZm9jEwmJZ3E|d7#YuejBUdPaWV!0IUaWs1kdz=;N3Le$CM9_V}|ay z-kDM#>jGkCeh9(I&tNzE@ZGH?Ih-R^B5ScmffH}9#`=?-T*#kRvkT;((IhcVU1Bl7YgE@$hHtjgucoF6f;tn`MzX718 zR`NC1bUD~<;9z6U-v%c=j0lDPk0MFlJMa3;_7j&NObL(MY3zFwF@e7Q(ZrK8jBkuc z{{WjLWRKQkWGmN}b;~@nrceU{az@5xa58dnoFCp}f_C}&JIDtI#&HMq;Sx{!AbF38 z?iDyPK!Y3rlfM0<1os;O0PatI{{Sex7;-=+dyn;Jup|;P2KkMGk^UgW3{K~`!0a+e zj@&PupaUXjG2itj37qd70MBxBxEaI(e?WY7Ym~#p;Q908Ai!in z#FMm~jps3unDOV#z?_rh2tT)c{DYY7*bW{H#v`yBj{6ahJ)j8f!WaF%-ydW%_sA0< z?=ka?Nq|HRr-p^81uH>XRE&isN=lMJ!3qQrM0SqeCxwsH`2!+O4oZm`fg>PdVq#Cs z0zuz0Gq%~pOvxD}4597lZ_j>aHp)F;b!CxFT3WkM^z^Ely|g_kf`~)vNpuhoR&;6Q}s#8e^NIdSJ=6Z*DdZkhN8EX+QzN1r8P}1q|v&EN7XdDoAzx$ z)vDobYf!m)u-z(bcPe{r`rU1=a@STELkFXW6ZZW(4>{a{IDl|-#zx(0xLqCgXenHM zK~S}U47V@|b=44r0U+e{#2kW08Z!(vH7@+C=-Xmtmu22Y($H4Z$Wv}4Ewv$NDngW< zq$w&*YLx{5MM)_jjKKsGLvczPTxX>K;lH*XwfV`ZJy`mf=I^Phtru$2uJeCUx2fwi z)|a@sf3?|alWDeFs*ufk=x8e{kyP~ymlvOUiMKuKr@hA=QVm1BOQfK!uYc*ODPE|2 zstajElo2vqI74tkr`%FT4^ixUXX&%kPc=E+%}pc9E>YR5HP1CQO6S?2p{jkVeDu>A*VAt{^_L_$ zy`!sir!qNvbrxM|U>7S5*>;8i@jOQxwb?zEt^Y0Dth{{Tl{sqJ^BZnX4t?=e|RN9JW-wzOHBG+J`r(!vQJP*Pc7 zkfjcw0!#12b#*MD5Pz7!oPE}btyc1??RtR~E~q58X0B1Cb-t6*Lm_SyDM}=$^fnVJ zgsCV}5RD$;X}Ma}?blJgPOL(d0@_z$((7ext|3qov-cxBB&FV#X>Gqa^y<|6&WB%1 zNm?6m!lu|rX$VfkC?T|x3X}y@Z$ME5*&#Ln(3_9|B-E2rovb3}>3_Q3S2fjZS_vgA zqx-fHaWK+9DJB7xbu1DHQH{6x8;J%EKc~+O_a6su+yF`3?b*ng%>os3{aZgw&Oz!(B1 zcbVV5CP&+aoPUf-?0(oCqaFLmP7c$9Ct(wT-(v$Eq7EewcRg)S*{_^95HX(}qwkHg zkN}Sv;rJ#98*M*h;$v?8q|Y9lRC=5AF8=`Gr$y)%zCu;D(qkf%ZIiV`g)3wqS0X{Eupf+W zHycM#KVm0iGZ`ib8=Ow~fsQY2*87d(;X`S(P*zK}2onL?JdrCyuAVcIwCP5%H5ZJNDZsq604HLYEmskdD&RC-$A>ukE3%{f5&6w-X=&^p%d z%Z+!Uxre8dMCJbgLF(N(tt@D`vgJ*^SA8vbqrKZxT~5>V&Ob(~+7<;2U}83(_q_Z0w_sIC|1ga2%tL9 z8XW6;5KRxZGQ7>@H#IpcsvgkX3^Tzt+my6Ej>8$zfp5%T-vnFezUo0?KEx3tD(~N%ax+fUwf*0>0NK5W`>sO zf3naiZd4$yuH{I}Xj0uA7?^db2BvXeMv{3fA<57mPom4YLEZrSn+fjHqd>I~IGo6& zZ4ip8r0m<)R_i1io&vGy&o{pqx{hsr8Co~+?sL=Si%VAM-8IVXJm)-VwOd!sORF5v zIh)CIU7^)=)GY8NWB&k$3cn1CLkfEM ze-b)wVO>YHM@g?+)9B^ZMzgcku>IcR)gyeoud8=Qy;RMmzv30QYkTy!dTWh61xd6e z{{TAmzKzv9xYl~Nmzv_qU8c3JgVfjU8?1EQ%?W1ZVAVQe>sMsd7F&x+TF~8frtLvl zK~~xpq@ng4NKpxste6-R0~4LQ9{u0}{SO;P@OdOQ*Py#ICeg%Ei!8~^tR`*JfR#4- z)?F^izMYce2`NJMQ?gP84r*~~HC+@!17e_hsZ9W&6uLm5CZ^`KH-|eJ?;G!k?>HEp zhW-x$Ip1@fcAdrv`-l-HPQ)n_gC=&LfiOGZl1KRV6mj}*+(yPeKXHyZh|=qwDZ}bD z7PL7V1Lik^2#j{yw~Y22A2}x(`|evYX`-r4o~5eYLv^OR1zoK*w2$2AS4xH5s8dYu z%%>>5YWj%ehaA#oS*jqU-&w#)8QPEFYt<^Nzlis$qX?UBLu#43Je%{43Grz;G zRKaMcL_t%%e&Tv{^^46t6Zn1TKSy>ec8sUxwa$T!X<2_Z>(BP{_=c}+-|mzY*Ou?? z+Nmvzs<}86l-QMVaR#E5%aZMNPTP3!AD0f(P4<7YWtsIhCGk9IrsNxuO2e}fQgVi6 z$$8gZ4kf1?oekB-P!bqO2_eF1-Fp>*J&sSh+_D-`VpMnTOcS#&-#nChOHHJsy<14y z*=b4vOEokAMy38xzPR*-$_*=}d2i_X+vT@b>pQNx(|qPb^*V~O#%Nf3PSnyXOI@{1 zMb56ao~0_jTdy?gxYkySRp!=;(%oZ~&nLk@Lm!3z0ICnfHpkArN$L5W0GlTuY!q6L zU)JlLTCFwh+v}+BHR(m3o|@NqtGQIOM`EmX=FL4iKRq*Sy7P;14dVX*5nW#O_ntKR zbxUx!q%_sBhY;d|fv&x@o7>ebuj$aTYACAh=y}CD;@0Bcznc{xE*bJLIWk&8ZvF$-O>-V8nV?fNo;NH7pa@7 zyRBB|{{V*4sW%sP-zT!j!FvHCiMAy0ncmU8FN!$gWS)LqD#RRNi5B~ba$F&D4a=k~ zuVD_jx0FIQgmN9Ibz>HGNmFwZZQ(=E8+vKN>&jDWQsDXZiF<_Ua6{m zZ`3#$Weu{}an}~UhMR4)Pf8GkfyJTQVX)h|+!%}>^hg3Ek6op1MaaD}(zI2oGNx9q zDC>hUbEP@dbI5yzqFbCCcgVpxoMH!(a74@w7zQ#AbCEtVk1{g^9pI8CBW(G}B1h>s z{Y>PaJbg9)0FzhAo^)S%x9VrqHz>JN$zE}zlANM$#i=x3I}=Y$Nm_N)Yu76Zv_)k~ zpG8IG4(OYcnvm4f(OYbm6g5=s&ZhNq)0%eq$KtqycwQefKC~fWgdl`1)UbuE#i6Fq zURp|93tEzpwI^f}0llIgJ!DPtHLZ>9P7(7mJdk`wbD7M*A3gpF6UWnkHF-hH`(L2% zNqWoD2jV;G3tD=XRkxH{rvCuw{M@abF-K!u+wS!u3~e8nA*hYi%k`>j)uuqt2LG8 z`0b9@Y}53VmRcGsbJfbCptsqnDebg$%(F{xWi-t)k@QXYQu51_-jTJ>EIGH&u2s`> zX_noty=$!#UWzN#70sIa71EB+XBNAtqq99rYOJrd-YYG)AFa37*V@`eak$YbG<qtLaLm9=y?3ba3`uNT_pF9FKSeYM)BF8=^n)qQQUg68Ei zD(LN|huZH*zPIjLYm*#<^j&P_qS~lqo3^U^cDtgzS6(j{Yo4an)zox)bZENA=_%W{ zxnjSurCMF1QdkWI4Lv*56f}1xm2-E^FIoKg^?WuCb;S?^IP()3f|B`;!$6E}q`U z)zSRX*$IB!cGI*oxPyJ8myyF8ns!CpT45=c!{;dTYcg0gf?4j;^R1<~36^EG%CzEC z>cZSY9`ydu4$I(pI}(p!N%W`LL+wbRK+H1g+EZzMdSEz}IEK`38i_R|gz=v%lVty#Q(d07!bnTR+M!W@x9q1#^|#x~aJW z9!=`SVsu(7t$zJZsMU2>YTaW^Uq@uM*)>hN?RR$Vd2*uYtwnIV(Y1M^x%@5b4@Z8b zu0Mx9j{IG9x33$gGj)wK*2@cAoW1HBhPu|&_R5`EUuQ+0`+a{}-4xq@*}8YNUDnfl zu$uO50KZ*AXc}s?^@EwduDRK)xqm@o(tOnBrkvzoGOVbmxbm=Ti;wml>+J#=v+9Jk zr|2shwILNx(YA}Hxo)ATyVSdJt+-K^?(ZtE-!N>0-l)7EPF&&jElX+V z7bopjYkkK^+H^G=15n)C<a4dV$-oTlu5- zTKZP}NIg#KYbW5vtTaZS!x?1n)&(k+FG(M)T zu~;ZB6*tXqqcqh$c9^(n{ZmbGy|rh)+-_XGyY z{{Y^{_^*B@`prI-H5aH~N1U0Y^uc1i>unv%3za7>M=^D8FZGp8qME;4P+9I(w%Yq$ z4KFb5$fT-OC0gw_8-1C!9&Wc%t=m_jDZbI*ICD?pGx&mLaNIu<3dDQCJA?^z&a>#A zn}?t!*_qQSrKVlN=`9gQR-x+-usgRDLK2;oDHKjl6SM1VsGB4ks-pTwP`x;RlXL1% zT->#b{;c(No6_}?!&7g*S@jm6)x5pbPixIC-PMz-YFxD2^-X2>Lshe9ro6vJeARaM zs8w)ixl?U+-$t5?uc~~u(;R^OIXSoK$J1w|PsBo|(a1h>>TYdoUsJl)$Emb0FfQ5! zt5$%$+_X5a)YN)f{iEy}Ub5+;H6@yj;EgAK(W<1pYb|L}tZbDFUYq&K{7t=8bIVfm z*O(lM=GQs(k3J}UKl4*r>5T(@*6iEpuJqJ4ikB>Ol^3IBOHJJCg*`Pz!i_g-o8`j8 zReaPf+V4!YeY=~Lm!~hqJn{$8*E+o=)%s-RmoePuVl{&|Zfa^e->1~}HuY_djXbk! zpjMu_u%~Ud>Sh|GBD$T0eLE%Ub*V16?)qm5?KUYU#O&rE)cR&pg5D7!FD)w~!*eVa zk%$+uBJ0n)CKie2*jiCZr1xkY)s87~w$^q5K~Mf-i7O>0r6Xd2J6BCX`X;9F><8mf z_}rscbBB`rtn~Fyq4l+&(q}yRJ?cA`yxXI`Ts4k{=5Ddkwk=5IGu5oo>J}cZvs&&~ z8$C_E=I+&%cTrP+rhfDEO|@C5y$Qojose z{{Ypty07J@rw&)@9&GEIR+z5VcP%}p&AAnH8dlkIv)U`~m2cfE=qTBuV&{LdP%X!5 zP*quTq+tkB+yjm|*IEl&a=TUPEg7w>mmN8(G_~U8rZo+=t+!iUy8CTywy!p4YEVrx z^%R1s4OJRP-==-1+kTn)ni{Hlm$#E0k;9#0Qw_uMF(rw}xBd|{fZWa??3~IrCQ#!p zJw{PDw4vVdO|7)8u$J2`Z8mSDxTUGbM|c;Zs7}&A2{i)yBTaRWaX%LCRo{mvGx=4f zITh&>leb^@U(h_=wbgS2)a84|wZ3g>T??T#9)oVMthXjK)y()}y9N2y!7Pzt|1F*|@HpP0mtlZie4(>!_z zkHsI?#aE{KKSwR|^6clQmid2C%35Anv7otLTYE!XYiKH*)2?a;bTHPH&ik}9)YLaR zjY9qQhK1_OO}^tzZMod2>iMK$n2r-AB_)BoEcz2QwLb1R{OrT3mtEdevYIB3R8gi^ zu`YmZvJyhHc9OECEEJueR5lU?ZAy*X&CeL`*Wrcut@0Dlx25k?8Y5rww^egXpSK!?vwKvdM8njyUWz$dJ1DZbhtE;PP^&qp>>znJkvZBvPWL3KFQ(t|lx>Zot+U(1{ z`ce2$ejJ)(l|F>MTl%l{;py{5^D~zkheBJqnag@jPh)3MYO3uuXw&x{S9a9amYZU# z?&FK4Rie7a&@R-}T^Dw@+rFK3w?`|w>t+7{CmTaE&F))rdsF)4wA|{sgQ2Q*(bxRG zR|UPhc|@2M=eeqvegb+_#^VWgzxrmAY^={Kt% z#cR-4rC-C(U49(gx8~-e=chOHpDcC1r%Jn>yG*t%)=T>oHJWm!{{X4)R0^Wf7tdn0 z;?-S67cMT>>t#c&*IJpoP}Ey4YPWPOT5?Mfb=Es5XQt+{>DdXqW#$>gTU#=6uB8(0 zu=|ZP+?z#BI@-!;qg4V@r6xB_q@-2-l!lvFY!Z)I!U3TGt7y=JL8l7G!v)s(r!^Jo z^JH?Wf||bZaj&Cp6Hd12s%u`TreWq8TdXIgrve;cE$VP(0ZuoSeUWlA*8QIS=>Gta zp18T&>PuDnwe`u%4MBC%ytMR`?y1oh9WioVywo(>BI4$?& zK`07Q1CM|Cq4-?$d+_%49r$|Q{XP1C(ERxI4b84;=$%)f=&afzsof!*gY z6puo^baH2qoT>ax`C;le@hQ`qAC|m>^*y3>4xqGXUQpEDnAJS8V@YWSzLlMGMP}1l zLsFebbGf3DpI%ki=yg3!!&U1$&A!8OQ*F?u*X7qVKMd7+#`Po5s$ar~mG`Y<>Fbl0 zZ9P_K8Sr{ zdYaX@Z5gY55&HS`Yo>it`qaL1Q<(bKOI|%Q==-(q#h^64r>}aul=lrkd90_X*Ay2z zO>L$cp-t}3{hO#YS`q5)MQ*a&E9kDelfPtFNPSn}&b*x^hF7~QA7AdulUkUt1Jq+^ammh{# zsIGKq-Al@=ou13h8*YlUIcn89YS(hTYjkQ_G}UWOQKu+1BaB#Y)GwmG-%_eQDBZ@l zRj!`fd7!IjR9=39e-58tAA{bo<*tF%+`!Wup7g)!3)6j*OxE2whpug0wB_pg*Q#jr zrkb~3^#!RE7FRABs+PL_sVhx`NwcBqtGQWYWpx~@XHVGd^y{MeW%cXpJ+E4Rt$Cx* zPGsp?J4I#Q>ua%4St+j1;FB`O(<+J`*vdUl`I_cs3k7LHWwpGDm8_3ftXt*Yfs*4KRW z+f#kCa^jWC&8tRT?bTOWApV_V?{a3crMqRI>NjMZ(ulbZ=~?unb2AM6}qIZxD5iYC>JE&M^Fw&#@x$n#ANV#-|%> zth(A#nY5^Pb4qd0(#vjz04^bQ71^t6J?R8`zyzs8ZYHTYiVBMn9I42^!%vuhk3~nU zFI|@IZ&-Ol%~pAjbY;B({^!;AT?fpo(rhVzPA5%YE;`1`c;)7wO_JSZu~k*xsriFg zW^fYt(N!wLdi&{#IBA%B`F?+S! zs^6q>A40;Y=@V2MZMG?^RLi;tC%J;IQ*&pQT+1@4QYV8*qi+fbJN=o}p#*VUq+KOtbN1AnMK81cNe~MPM{84$I%iVLR z`B$g8L#O#&r*HaeNa<@XqPS}6^Gm2NP2FoM@7k8O*I;hvToFlbqY9$a_If}mT&P7N z6;iY}%Sm9e*evT(ct!^*j52u+yNb^)XKlp1#Z@HHVdCSn8%`}{D%#j(HKxhg2T4vT zz*M&sR+?-kmZADaqJUTpFC43{xo!Awb92-G0H97>dUU-rW%Ys0j%jlDLi)7TRVe0L zwp}*O?zZ`BziUbzJ#(d~wc4z7RoAL|`szIirdhYAPigy8wDuNj67!c2Lj6ns0F!l1 z>4%m))8~$w{6aZ@Pj%$yEpA-r(v}@Zq?^%NgHuy!Mz2?zdh2$ipyoYAMwhI(R9ft| z%^h8Bv+5?RwM}y9k#VGQo|W3a2E7XU8Rs|R6VB!G6OmUgUs|=5K9acWimL8p>W8$o zf}2j+uNr>Kbg6CX8%_H0bgZIxQPEd9Xt7x?mu1?iZnp*~U1r-*Q^mA?nz_%Yxy!A2 z3CoQOsd=}|?F)9)_DjZ@<%Nd#tM0Y6nmXugnvGT)J-XhzHS)l7r6M4+UpBB@9R)gMTjf^sDDpyPdQ%q@G&tGieJV{3h1ukW<upVW z)i-7>lh++eXg#pZh@MLy0_V*L&1jLs;F@dg}&mI>DS>4>RX*Yjd|^;{YCP7 z(gv~hV*Qgy+_bg!-==IDvE*qB4P`sJhg4k})!Ji4>vicnnbUf9y~Wp7THT^*#?|V+ z<4;pTMEVa?eHZfslm4H5UvigTdZ^`H+nBtl<<7FYo@Mf}%U!VDYhR|bUo7-=cN-q5 zrCk%s(|WDzUE1+uuVR+2shd4rww|WjadnE?Z==t`ukjc3m0tMakU-Bz7@&F*CDdaDxjfz~|1)q0}grrD@!>U7mb{{T=| zT`o47SA{j1nzn6K6?GJ}NGws0VTM?7VL-gEq*ZHA!E5m(=jSMND|!u|!_$*mJCe^( z>T9Kv%ga7k+qFM7-n`mrbd8fyYRVT`8ou{WXnRo8QR>}CL44F#bfV<_LoHL(T<>;| zIr)XkK1cJv@ipd+*VC6Pb-y>g5NV!x+UhlJ%axX`bF81Xa<1UwUDUeT<6Tu(SE#9N zNP3%6SKDX4}?BC)^_-*nPew~lvGx&JW>DvdPs#mRcI;u@i z%-gm1n0F0jeAl%)60+N7)B3Lce!kODX`AwGw1UBPu3oJE1zB0D>m9mU=^S>8Z-_l3 zI_3>7UB$4O$0W97rdUu*czgJRETOqc=9KEvXVip`MQ!$-C@6JlT77bA60jUl2yrPp zN(D74N-0%>1$F@=Xo3bnUEl{{ZKwsc*vvlfJzv^iQWdZjI(;i$J@n9e+`1 zt$ko;QdsnMnr_Wcsp=>-Eq%hS-*nSfYhIeO+;rV*+GVP*cTAgIn(e0?;{JN-AH(?+JqK#-F`}6C@#>17n|4ZVc~?!PwFPf6G={g*N0;~7-630NywoDrYTpmZwvuuXg)=c9pu)HP>5RaMd=GPi=0uo&7Iz+t)|q@y`aiJ7P|WleSKZ>sZ9zB`iCzUpxq67)s8(% zD=R6sjrOYk&8}A8Atsr``om%1kPOSGoU<5yEy#f??Z(h345flx zr<@$5rPOwPV@=BLXmbOXH2S{5R*Qv$RWYJ20fRw$o8X zRKv(ZLc&KL+pV`7)y9U=X`!pS-EOtC*863$f}PsR`;Ee_)YH;XP*Jdzzgb;bP~s`6 zDQVkwqNb(B*k!jJT2OoD(jQ}OD^go|ous&uP^6*6R4pWcP@s|&2>_(riiq1#iVW$W zF-_WMQQ^Wp4E#`B{5{v|Wi5UhGFnx7I ztv~{TDv2s5WFn{NfwBfxrTJd^agFa<^1qp!w-%AiUR~?01^jxM>bn>A(@9_Sukor{ ze`DXNw0|A9(Ek7tr)1UA`>#>^?X~qRb*(<~3bD4$ZL94SwhNWBRA1=pw6(_HcGGnY zU8_Q@cRNFkIc%)8rB4>niDPH1zfNn_EhH zktH?M&Ls|~O}A%0Z&UNKZJE?E`-_s4bUv39g5hnJU3D!5E#}gJ>!k?`SxGx0ruw^7 zO1)A=6h#QFEaKTj`At_E$z%T=cG=_p7PvE+4|IHwvq5AJuy_@2vP^0ENRol#}UZ*G20-iwC@ew$XIv9cAg>W6^yU zly=XhD0KCr*w&M-VWUw~M@4g@e(R_(GjBC5hb^oz@@AcsY3XLmDOMWX!U~;r@wAkd zYJ`-6MW7{hSQ{Xkn$c9yaU&vVH|0q3_q523fQ`O3?LCBk!;aE=DD@mY zBYLIe=czC3vpUu8QfgPVJsy^+d)Z>`Tx{1%Z3-TE61GysRl%CT^L;Ni6_EXFnw5a&zHWQxmddrHU9uJZnYL|GQCT2devk4+G|yH*=V@jS);C9BTiG>-EFr% znbeom(iPB^scGyFKD`@rBhgnnwPz!_<4>p6%?%vYj;7|FJ9lpVU}BR|SZ&&p(DlCH zDd~gmRNC&ekGQ88Y3gMxu%?-H4N2%3c$Aj9Z zTrq18TdideTv7{5d=9256$C0UL$9}y&^nuGVEds(3U7|y=$}M>x4HSGZ`z-c{+l_Q zskCL1$xW#4y5;*aH0GZga<-15<4bt5-E}=hnu_aht)Zi-s-?Nwo~&k~nwp}bg-(W4 z`aIKDL99QFD6tKnFlARfgp^KWbJUKlPtN(R`E7x8JAqTC1jgRA$UxxWzgF) zj;#*3^TmDAolDa@F0P~vpqj=@$t0kpkZPk}T-KzDfCVZA2gWAjt~}!1b!v6jR;L|t zYEqV^sFf*dStO}yR#c;cb1}p_;KnBdFai5_5!e%$#}S>!cmw@1F&F^M$@7CC+{by& zzzvLTi~@c)A^-=Nj3QDZM$%#lgE9ayne#b`p2L7|Fgufp+kWwr<8AOajDj;i=8==O z!gJ*O>~_pC5kGuR4{;dUdzl6>42}^v_<7T+!vq7kF`eQdkCVDb_(br@iH{~s&hrEq zAQL`h#^CQAz@4%O&Q2rmGvIdGPcmb80y1Jd556`zB;as{d3=8EtaT9l=VK{9c=6&p z0z4RiT2Fr)iN|s=zCT|-b@TQl9kNd3WS-*_9nTB(k2?|Z`u2_TcP2PPue*O6?}<-s zZ^|&tOdL;v@ZMxrFwd{Cr|MV`X3w z{utqcM{kiN57)K{KXNf72;mk99fVH!#w5-@`5DF}4jE7?0zB>{?VJO&ZZVzskIp0c zb~%Fwu#z{E5=K5A<~NAO!afX~?svckv5pY;^~xWe<|22;azTg~%-|CTVmKs$CkOV) z1I9;^L>b$>!}j|@{{T#40LeH8cj83EgTG;rAkOpWbNQxXcHsz= zv;)MFqLn11l&L0CK_G<#Ac8;6NfRL8nFd6fa(0=LLCoNG6P$y9cibHC1GoTu_7HcC zzBfIfM8^n5VY}tg4Y=Csmr&Eb-@4UUO;B|$fDnb3!;4BFbObiEeqN;D5)Ie!J4Hxe z*V&qF#}gE8cH+>#^u#sYJaa8F^m zJ>=vF8;F25;Rx9kLtv@vRSn_lRVmaVic76DETvKlwH4IGRLrFqDoIIEO!W1vhD8_j z_06!SSZ$kw0no}{w$wFN+l!I{P?nTlStMiopbQu?76u3tkpply1F#TB=p+vWd~s2y zTxm#gr&iO6JxFo2DGN!+l&vKsWXwp;HY0=}aSk-KG~;V&Xdo>PB(}61o|Pp+K-lz= z5e6a%Q!yKT<|DU#@_R(*JLZ|xcP7J4)D~_O%)Ftp0Ot|8~>QmiaF1ij>Lfk3p z9dYg<3QfSc*eZ)jt+P8sr8(C9RidR`N=zgKF-2BaOx8hBA;oS}j5w4|w{FkNUQw=h z>;z=M-v?~x6S4mQ4hfy2KX7nnK=0h(5^?f#skU0`dOn8o%Pu&l38%R>ix$m?^aolZEG(jci$B^@D2 zkUEnndwjI`{aQvRU|{VMNs&7q`@qiGkB$kS(2STHLE96EKWQX+2rZJ80+I;@D+Cm% z9HfFJBoVO_G9q|Vd*lH)$=GN7M``f@o)LQL@W~=0?SOm8QIUzA_Kd`00A&9Fi5c=i zB2IDe2+sK71K+tIlM%dm`}s0tj~pI8^MQkjk&;Q?f25d%B17*OpWm=E*ck?3_TB-V zh%hEMF`tYBk&n>lJSjNFbKks9K_U!Ki2z_=a2)p_{<(v(`2PSHAAS)!^5x<2hBt}% z`$>{O7(Z-Ab37gU0C&fH?nXOi1Wb7lq)0eB5hEUajesXRNbkT8Z`KL(+XHR;{?mkC z+vU)QykdXT+77}e8QZ*>Cv?$zbl+}%?LtrR>Jo=))I=rKq=MBbI3&7KONkpamF%L9 zH99Ic>+0#~>6imJ1mE!6_eHhPeR%1p8eMEG@2VBs3RywqarTrIR~Pw?Av$_Gdu)71d^KnA}_ z9@5<%Ka{r6{^gy)9cxL2h|o;!k2(DbA09CharTKMkOUd;89nf4C-f(BOhlc#7|h9$ zIFUFxIlzE69nhuz9zxrxe=`yUZYSq`hT?PZJ49!G2^ibs$lh>#NZ)cu>8hU>tDq@!!7DKfK7> zc>A6adh4siwh%$U@i_0^M|sR2BtYN;Gdq#?-ULsBw(kJIYGPo=-^uvc7|1_ylQFp9+YkUJVh5ez z4EBM(PT)@woy_={B<2Z#1~$j$+9PP;lfFFWK+o7uc+Bq-al$M}l1_52=k1U@iR~s2 zfe=7JI6r6|hCl5SjQ1mm7Q$j|GYhiNkg zM`Q?qF+G4gPtTF?bLL3kGxMI)zBZ1;=3;j3xVdM*_2CvIOlNEYCu2K#p8E`lJ5LD2 zM4z$yZRG7SGv)~+fI%NSPGlJ%V+3w-u$+0}3}j@<8QknZ{RHo^o+n*bF0_gFXRluP zkux47e0h>PY(DA-X(NDR;K!JayT?e|x7>&Wi1s7mGGGv7j6e`0F$V;8%Oq{LY?0z} zGl}vyjq}5=ssneHhSbv3<@+JdM&5o*0C0QfBQQU6#EIK)nT@|#=@>B)yyQejK1bLM z$e#VY{+sz*`2PSA``~9e+aMF=4c7azw~xXkNrS&^W;{=SkM!@uk>m-%0DiOg8^?j< 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�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

  • Z`~v&DGCs(8bJN86>rT)8s3Z(1NI2ho(Bn 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

    3{DR3!Gg97PN6bddU!laU-G}IXY-wNA1 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