From 0bc81a90eb932910a9b7eae0bb1897a5830e967a Mon Sep 17 00:00:00 2001 From: Abhiram824 Date: Sat, 31 Aug 2024 16:00:00 -0500 Subject: [PATCH 01/17] updates to allow numpy v2 to work --- robosuite/utils/binding_utils.py | 3 ++- robosuite/utils/transform_utils.py | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/robosuite/utils/binding_utils.py b/robosuite/utils/binding_utils.py index 563477eebb..7a51911bc9 100644 --- a/robosuite/utils/binding_utils.py +++ b/robosuite/utils/binding_utils.py @@ -172,7 +172,8 @@ def read_pixels(self, width, height, depth=False, segmentation=False): ret_img = rgb_img if segmentation: - seg_img = rgb_img[:, :, 0] + rgb_img[:, :, 1] * (2**8) + rgb_img[:, :, 2] * (2**16) + uint32_rgb_img = rgb_img.astype(np.int32) + seg_img = uint32_rgb_img[:, :, 0] + uint32_rgb_img[:, :, 1] * (2**8) + uint32_rgb_img[:, :, 2] * (2**16) seg_img[seg_img >= (self.scn.ngeom + 1)] = 0 seg_ids = np.full((self.scn.ngeom + 1, 2), fill_value=-1, dtype=np.int32) diff --git a/robosuite/utils/transform_utils.py b/robosuite/utils/transform_utils.py index ac371c09da..da1dd7b34b 100644 --- a/robosuite/utils/transform_utils.py +++ b/robosuite/utils/transform_utils.py @@ -411,7 +411,7 @@ def mat2euler(rmat, axes="sxyz"): j = _NEXT_AXIS[i + parity] k = _NEXT_AXIS[i - parity + 1] - M = np.array(rmat, dtype=np.float32, copy=False)[:3, :3] + M = np.asarray(rmat, dtype=np.float32)[:3, :3] if repetition: sy = math.sqrt(M[i, j] * M[i, j] + M[i, k] * M[i, k]) if sy > EPS: @@ -713,7 +713,7 @@ def rotation_matrix(angle, direction, point=None): M[:3, :3] = R if point is not None: # rotation not around origin - point = np.array(point[:3], dtype=np.float32, copy=False) + point = np.asarray(point[:3], dtype=np.float32) M[:3, 3] = point - np.dot(R, point) return M @@ -846,7 +846,7 @@ def unit_vector(data, axis=None, out=None): return data else: if out is not data: - out[:] = np.array(data, copy=False) + out[:] = np.asarray(data) data = out length = np.atleast_1d(np.sum(data * data, axis)) np.sqrt(length, length) From 4205f690dfc6ba7cd2783314482aa4937f5d7bc5 Mon Sep 17 00:00:00 2001 From: Kevin Lin Date: Fri, 6 Sep 2024 14:11:18 -0700 Subject: [PATCH 02/17] Add github issue bug report template --- .github/ISSUE_TEMPLATE/bug-report.yml | 49 +++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report.yml diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 0000000000..ea76325742 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,49 @@ +name: "\U0001F41B Bug Report" +description: Help us improve Robosuite by submitting a bug report +body: + - type: markdown + attributes: + value: | + Thanks submitting a bug report! + + - type: textarea + id: system-info + attributes: + label: System Info + description: Which version of Robosuite are you using? Which OS (e.g., Ubuntu, MacOS, Windows) are you using? If you think it'll help, you can also share the output of `pip list`. + render: Shell + placeholder: Robosuite version, OS. + validations: + required: true + + - type: checkboxes + id: information-scripts-examples + attributes: + label: Information + description: 'The problem arises when using:' + + - type: textarea + id: reproduction + validations: + required: true + attributes: + label: Reproduction + description: | + If possible, provide a minimal code sample or script that reproduces the problem you ran into. + Please use code tags to correctly format your code: https://help.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks#syntax-highlighting + Please avoid screenshots, as they don't allow copy-and-pasting. + + placeholder: | + Steps to reproduce the behavior: + + 1. `python robosuite/scripts/example_script.py` + 2. + 3. + + - type: textarea + id: expected-behavior + validations: + required: true + attributes: + label: Expected behavior + description: "A clear and concise description of what you would expect to happen." From cd7ba5727e07fa52be3c1420c3e9a00357e4fadd Mon Sep 17 00:00:00 2001 From: Kevin Lin Date: Fri, 6 Sep 2024 14:13:09 -0700 Subject: [PATCH 03/17] Update github issue bug report template --- .github/ISSUE_TEMPLATE/bug-report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index ea76325742..f4f2ac7a90 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -16,7 +16,7 @@ body: validations: required: true - - type: checkboxes + - type: textarea id: information-scripts-examples attributes: label: Information From 0eec95937c437b95d814cc9d774578b98f1aadbb Mon Sep 17 00:00:00 2001 From: Kevin Lin Date: Fri, 6 Sep 2024 14:14:25 -0700 Subject: [PATCH 04/17] Update github issue bug report template 3 --- .github/ISSUE_TEMPLATE/bug-report.yml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index f4f2ac7a90..57c8dfe4c5 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -35,10 +35,23 @@ body: placeholder: | Steps to reproduce the behavior: + 0. Use the following code-snippet `example_script.py`: + ``` + from robosuite import make + env = make( + "Lift", + robots="Panda", + gripper_types="TwoFinger", + use_camera_obs=False, + reward_shaping=True, + ) + + print(env) + ``` - 1. `python robosuite/scripts/example_script.py` - 2. - 3. + ``` + 1. `python example_script.py` + 2. ... - type: textarea id: expected-behavior From c6fe6ccd510ae38a6f3637ca39e9b3c1adf84833 Mon Sep 17 00:00:00 2001 From: Kevin Lin Date: Fri, 6 Sep 2024 14:15:59 -0700 Subject: [PATCH 05/17] Update github issue bug report template 4 --- .github/ISSUE_TEMPLATE/bug-report.yml | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 57c8dfe4c5..9c8ea7a8f7 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -21,6 +21,12 @@ body: attributes: label: Information description: 'The problem arises when using:' + placeholder: | + ``` + import robosuite + print(robosuite.__version__) + print("Tested script") + ``` - type: textarea id: reproduction @@ -35,22 +41,7 @@ body: placeholder: | Steps to reproduce the behavior: - 0. Use the following code-snippet `example_script.py`: - ``` - from robosuite import make - env = make( - "Lift", - robots="Panda", - gripper_types="TwoFinger", - use_camera_obs=False, - reward_shaping=True, - ) - - print(env) - ``` - - ``` - 1. `python example_script.py` + 1. Run the above provided code-snippet `python example_script.py` 2. ... - type: textarea From 5f8aa5e6179daac1115be08b457008642b41e64f Mon Sep 17 00:00:00 2001 From: Kevin Lin Date: Fri, 6 Sep 2024 14:24:40 -0700 Subject: [PATCH 06/17] Add PR template --- .github/PULL_REQUEST_TEMPLATE.md | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..980a718af0 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,35 @@ +## What this does +Explain what this PR does. Feel free to tag your PR with the appropriate label(s). + +Examples: +| Title | Label | +|----------------------|-----------------| +| Fixes #[issue] | (🐛 Bug) | +| Optimizes something | (⚡️ Performance) | +| Adds a new feature | (✨ Feature) | + + +## How it was tested +Explain/show how you tested your changes. + +Examples: +- Added `test_something` in `tests/test_stuff.py`. +- Added `new_feature` and checked that training converges with policy X on dataset/environment Y. +- Optimized `some_function`, it now runs X times faster than previously. + +## How to checkout & try? (for the reviewer) +Provide a simple way for the reviewer to try out your changes. + +Examples: +```bash +DATA_DIR=tests/data pytest -sx tests/test_stuff.py::test_something +``` +```bash +python lerobot/scripts/train.py --some.option=true +``` + +## SECTION TO REMOVE BEFORE SUBMITTING YOUR PR +**Note**: Anyone in the community is free to review the PR once the tests have passed. Feel free to tag +members/contributors who may be interested in your PR. Try to avoid tagging more than 3 people. + +**Note**: Before submitting this PR, please read the [contributor guideline](https://github.com/ARISE-Initiative/robosuite/blob/master/CONTRIBUTING.md). \ No newline at end of file From e614a15466882b0a5c69191528e5edf666b5e4c7 Mon Sep 17 00:00:00 2001 From: Kevin Lin Date: Fri, 6 Sep 2024 14:25:30 -0700 Subject: [PATCH 07/17] Update PR template --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 980a718af0..808ae13312 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -25,7 +25,7 @@ Examples: DATA_DIR=tests/data pytest -sx tests/test_stuff.py::test_something ``` ```bash -python lerobot/scripts/train.py --some.option=true +python robosuite/scripts/train.py --some.option=true ``` ## SECTION TO REMOVE BEFORE SUBMITTING YOUR PR From cbe7f8a33875383d3f86a7e8d3b6449f3f3cb7de Mon Sep 17 00:00:00 2001 From: kevin-thankyou-lin <33344633+kevin-thankyou-lin@users.noreply.github.com> Date: Sat, 7 Sep 2024 14:54:17 -0500 Subject: [PATCH 08/17] Update bug-report.yml --- .github/ISSUE_TEMPLATE/bug-report.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 9c8ea7a8f7..d9f0405f66 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -1,5 +1,5 @@ name: "\U0001F41B Bug Report" -description: Help us improve Robosuite by submitting a bug report +description: Help us improve Robosuite by submitting a bug report! body: - type: markdown attributes: @@ -20,7 +20,7 @@ body: id: information-scripts-examples attributes: label: Information - description: 'The problem arises when using:' + description: 'The problem arises when running ABC; the error message is XYZ' placeholder: | ``` import robosuite @@ -47,7 +47,7 @@ body: - type: textarea id: expected-behavior validations: - required: true + required: false attributes: label: Expected behavior description: "A clear and concise description of what you would expect to happen." From dfa5f314f559f73f4fd9d5183e46b4191998965e Mon Sep 17 00:00:00 2001 From: Kevin Lin Date: Fri, 13 Sep 2024 20:50:10 -0700 Subject: [PATCH 09/17] Update xmlobject docs --- docs/modules/objects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/objects.md b/docs/modules/objects.md index 99986df6d6..6bd907acb2 100644 --- a/docs/modules/objects.md +++ b/docs/modules/objects.md @@ -57,7 +57,7 @@ obj_xml = obj.get_obj().set("pos", array_to_string(pos)) # Set the top-level ``` ## Creating a XMLObject -One can use MuJoCo MJCF XML to generate an object, either as a composition of primitive [geoms](http://mujoco.org/book/modeling.html#geom) or imported from STL files of triangulated [meshes](http://www.mujoco.org/book/modeling.html#mesh). An example is `robosuite.models.objects.xml_objects.BreadObject`. Its [python definition](https://github.com/ARISE-Initiative/robosuite/blob/master/robosuite/models/objects/xml_objects.py#L49) is short. Note that all `MujocoXMLObject` classes require both a `fname` and `name` argument, the former which specifies the filepath to the raw XML file and the latter which specifies the in-sim name of the object instantiated. The optional `joints` argument can also specify a custom set of joints to apply to the given object (defaults to "default", which is a single free joint). Additionally, the type of object created can be specified via the `obj_type` argument, and must be one of (`'collision'`, `'visual'`, or `'all'`). Lastly, setting `duplicate_collision_geoms` makes sure that all collision geoms automatically have an associated visual geom as well. Generally, the normal use case is to define a single class corresponding to a specific XML file, as shown below: +One can use MuJoCo MJCF XML to generate an object, either as a composition of primitive [geoms](http://mujoco.org/book/modeling.html#geom) or imported from STL files of triangulated [meshes](http://www.mujoco.org/book/modeling.html#mesh). An example is `robosuite.models.objects.xml_objects.BreadObject`. Its [python definition](https://github.com/ARISE-Initiative/robosuite/blob/master/robosuite/models/objects/xml_objects.py#L49) is short. Note that all `MujocoXMLObject` classes require both a `fname` and `name` argument, the former which specifies the filepath to the raw XML file and the latter which specifies the in-sim name of the object instantiated. The optional `joints` argument can also specify a custom set of joints to apply to the given object (defaults to "default", which is a single free joint). This joint argument determines the DOF of the object as a whole and does not interfere with the joints already in the object. Additionally, the type of object created can be specified via the `obj_type` argument, and must be one of (`'collision'`, `'visual'`, or `'all'`). Lastly, setting `duplicate_collision_geoms` makes sure that all collision geoms automatically have an associated visual geom as well. Generally, the normal use case is to define a single class corresponding to a specific XML file, as shown below: ```python class BreadObject(MujocoXMLObject): def __init__(self, name): From b3ccef8be109afc1f0a2b6c00eeefc13b9a67c08 Mon Sep 17 00:00:00 2001 From: kevin-thankyou-lin <33344633+kevin-thankyou-lin@users.noreply.github.com> Date: Mon, 16 Sep 2024 20:00:54 -0500 Subject: [PATCH 10/17] Create github issue template for feature-request.yml --- .github/ISSUE_TEMPLATE/feature-request.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/feature-request.yml diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 0000000000..830521c437 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,16 @@ +--- +name: Feature Request Template +about: "For feature requests. Please search for existing issues first. Also see CONTRIBUTING." + +--- + +**Please Describe The Problem To Be Solved** +(Replace This Text: Please present a concise description of the problem to be addressed by this feature request. Please be clear what parts of the problem are considered to be in-scope and out-of-scope.) + +**(Optional): Suggest A Solution** +(Replace This Text: A concise description of your preferred solution. Things to address include: +* Details of the technical implementation +* Tradeoffs made in design decisions +* Caveats and considerations for the future + +If there are multiple solutions, please present each one separately. Save comparisons for the very end.) From 67d27c249077766b0fae8cd68439976c23ded855 Mon Sep 17 00:00:00 2001 From: kevin-thankyou-lin <33344633+kevin-thankyou-lin@users.noreply.github.com> Date: Mon, 16 Sep 2024 20:05:05 -0500 Subject: [PATCH 11/17] Update feature-request.yml --- .github/ISSUE_TEMPLATE/feature-request.yml | 44 ++++++++++++++++------ 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml index 830521c437..4b11698b88 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -1,16 +1,38 @@ --- -name: Feature Request Template -about: "For feature requests. Please search for existing issues first. Also see CONTRIBUTING." +name: 🛠️ Feature Request +description: Suggest an idea to help us improve Robosuite :heart: +title: "[Feature]: " +labels: + - "ty:feature" ---- +body: + - type: markdown + attributes: + value: > + **Thanks for taking the time to fill out this feature request report! :heart:** Please double check if an issue + [already exists](https://github.com/ARISE-Initiative/robosuite-dev/issues) for + your feature. -**Please Describe The Problem To Be Solved** -(Replace This Text: Please present a concise description of the problem to be addressed by this feature request. Please be clear what parts of the problem are considered to be in-scope and out-of-scope.) + We are also happy to accept contributions from our users. For more details see + [here](https://github.com/ARISE-Initiative/robosuite-dev/blob/master/CONTRIBUTING.md). -**(Optional): Suggest A Solution** -(Replace This Text: A concise description of your preferred solution. Things to address include: -* Details of the technical implementation -* Tradeoffs made in design decisions -* Caveats and considerations for the future + - type: textarea + attributes: + label: Description + description: | + A clear and concise description of the feature you're interested in. + value: | + + validations: + required: true -If there are multiple solutions, please present each one separately. Save comparisons for the very end.) + - type: textarea + attributes: + label: Suggested Solution + description: > + Describe the solution you'd like. A clear and concise description of what you want to happen. If you have + considered alternatives, please describe them. + value: | + + validations: + required: false From f681960f88a079a68180f1b2cd0dce1e07ca50a8 Mon Sep 17 00:00:00 2001 From: kevin-thankyou-lin <33344633+kevin-thankyou-lin@users.noreply.github.com> Date: Mon, 16 Sep 2024 20:05:21 -0500 Subject: [PATCH 12/17] Update feature-request.yml --- .github/ISSUE_TEMPLATE/feature-request.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml index 4b11698b88..2de61de1a0 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -1,6 +1,6 @@ --- name: 🛠️ Feature Request -description: Suggest an idea to help us improve Robosuite :heart: +description: Suggest an idea to help us improve Robosuite! title: "[Feature]: " labels: - "ty:feature" From 9036ace1dc82bf7c6a222600e754ed049a440021 Mon Sep 17 00:00:00 2001 From: Abhiram824 Date: Sun, 3 Nov 2024 16:54:56 -0600 Subject: [PATCH 13/17] changes to make demo scripts working --- .gitignore | 1 + .../composite/composite_controller_factory.py | 52 +++++++++++++++++++ .../controllers/config/parts/ik_pose.json | 7 +++ .../config/parts/joint_position.json | 15 ++++++ .../config/parts/joint_torque.json | 10 ++++ .../config/parts/joint_velocity.json | 11 ++++ .../controllers/config/parts/osc_pose.json | 18 +++++++ .../config/parts/osc_position.json | 16 ++++++ .../controllers/parts/controller_factory.py | 4 +- .../demos/demo_collect_and_playback_data.py | 2 + robosuite/demos/demo_control.py | 9 +++- robosuite/demos/demo_device_control.py | 4 +- robosuite/demos/demo_domain_randomization.py | 4 +- robosuite/utils/input_utils.py | 4 +- 14 files changed, 148 insertions(+), 9 deletions(-) create mode 100644 robosuite/controllers/config/parts/ik_pose.json create mode 100644 robosuite/controllers/config/parts/joint_position.json create mode 100644 robosuite/controllers/config/parts/joint_torque.json create mode 100644 robosuite/controllers/config/parts/joint_velocity.json create mode 100644 robosuite/controllers/config/parts/osc_pose.json create mode 100644 robosuite/controllers/config/parts/osc_position.json diff --git a/.gitignore b/.gitignore index a919c684d4..da7750031b 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ eggs/ lib/ lib64/ parts/ +!robosuite/controllers/config/parts !robosuite/controllers/parts sdist/ var/ diff --git a/robosuite/controllers/composite/composite_controller_factory.py b/robosuite/controllers/composite/composite_controller_factory.py index 3a67b227c5..14e5c60b2e 100644 --- a/robosuite/controllers/composite/composite_controller_factory.py +++ b/robosuite/controllers/composite/composite_controller_factory.py @@ -1,3 +1,4 @@ +import copy import json import os import pathlib @@ -18,6 +19,57 @@ def validate_composite_controller_config(config: dict): raise ValueError +def is_stale_controller_config(config: Dict): + """ + Checks if a controller config is in the format from robosuite versions <= 1.4.1. + Does not check for config validity, only the format type. + + Args: + config (dict): Controller configuration + + Returns: + bool: True if the config is in the old format, False otherwise + """ + + OLD_CONTROLLER_TYPES = ["JOINT_VELOCITY", "JOINT_TORQUE", "JOINT_POSITION", "OSC_POSITION", "OSC_POSE", "IK_POSE"] + if "body_parts_controller_configs" not in config and "type" in config: + return config["type"] in OLD_CONTROLLER_TYPES + return False + + +def refactor_composite_controller_config(controller_config, robot_type, arms): + """ + Checks if a controller config is in the format from robosuite versions <= 1.4.1. + If this is the case, converts the controller config to the new composite controller + config format in robosuite versions >= 1.5. If the robot has a default + controller config use that and override the arms with the old controller config. + If not just use the old controller config for arms. + + Args: + old_controller_config (dict): Old controller config + + Returns: + dict: New controller config + """ + if not is_stale_controller_config(controller_config): + return controller_config + + config_dir = pathlib.Path(robosuite.__file__).parent / "controllers/config/robots/" + name = robot_type.lower() + configs = os.listdir(config_dir) + if f"default_{name}.json" in configs: + new_controller_config = load_composite_controller_config(robot=name) + else: + new_controller_config = {} + new_controller_config["type"] = "BASIC" + new_controller_config["body_parts"] = {} + + for arm in arms: + new_controller_config["body_parts"][arm] = copy.deepcopy(controller_config) + new_controller_config["body_parts"][arm]["gripper"] = {"type": "GRIP"} + return new_controller_config + + def load_composite_controller_config(controller: Optional[str] = None, robot: Optional[str] = None) -> Optional[Dict]: """ Utility function that loads the desired composite controller and returns the loaded configuration as a dict diff --git a/robosuite/controllers/config/parts/ik_pose.json b/robosuite/controllers/config/parts/ik_pose.json new file mode 100644 index 0000000000..db6191e617 --- /dev/null +++ b/robosuite/controllers/config/parts/ik_pose.json @@ -0,0 +1,7 @@ +{ + "type" : "IK_POSE", + "ik_pos_limit": 0.02, + "ik_ori_limit": 0.05, + "interpolation": null, + "ramp_ratio": 0.2 + } \ No newline at end of file diff --git a/robosuite/controllers/config/parts/joint_position.json b/robosuite/controllers/config/parts/joint_position.json new file mode 100644 index 0000000000..bc25f5cb91 --- /dev/null +++ b/robosuite/controllers/config/parts/joint_position.json @@ -0,0 +1,15 @@ +{ + "type": "JOINT_POSITION", + "input_max": 1, + "input_min": -1, + "output_max": 0.05, + "output_min": -0.05, + "kp": 50, + "damping_ratio": 1, + "impedance_mode": "fixed", + "kp_limits": [0, 300], + "damping_ratio_limits": [0, 10], + "qpos_limits": null, + "interpolation": null, + "ramp_ratio": 0.2 + } \ No newline at end of file diff --git a/robosuite/controllers/config/parts/joint_torque.json b/robosuite/controllers/config/parts/joint_torque.json new file mode 100644 index 0000000000..8d648428ea --- /dev/null +++ b/robosuite/controllers/config/parts/joint_torque.json @@ -0,0 +1,10 @@ +{ + "type": "JOINT_TORQUE", + "input_max": 1, + "input_min": -1, + "output_max": 0.1, + "output_min": -0.1, + "torque_limits": null, + "interpolation": null, + "ramp_ratio": 0.2 + } \ No newline at end of file diff --git a/robosuite/controllers/config/parts/joint_velocity.json b/robosuite/controllers/config/parts/joint_velocity.json new file mode 100644 index 0000000000..4a9c7c86aa --- /dev/null +++ b/robosuite/controllers/config/parts/joint_velocity.json @@ -0,0 +1,11 @@ +{ + "type" : "JOINT_VELOCITY", + "input_max": 1, + "input_min": -1, + "output_max": 0.5, + "output_min": -0.5, + "kp": 3.0, + "velocity_limits": [-1,1], + "interpolation": null, + "ramp_ratio": 0.2 + } \ No newline at end of file diff --git a/robosuite/controllers/config/parts/osc_pose.json b/robosuite/controllers/config/parts/osc_pose.json new file mode 100644 index 0000000000..30b20677e7 --- /dev/null +++ b/robosuite/controllers/config/parts/osc_pose.json @@ -0,0 +1,18 @@ +{ + "type": "OSC_POSE", + "input_max": 1, + "input_min": -1, + "output_max": [0.05, 0.05, 0.05, 0.5, 0.5, 0.5], + "output_min": [-0.05, -0.05, -0.05, -0.5, -0.5, -0.5], + "kp": 150, + "damping_ratio": 1, + "impedance_mode": "fixed", + "kp_limits": [0, 300], + "damping_ratio_limits": [0, 10], + "position_limits": null, + "orientation_limits": null, + "uncouple_pos_ori": true, + "control_delta": true, + "interpolation": null, + "ramp_ratio": 0.2 + } \ No newline at end of file diff --git a/robosuite/controllers/config/parts/osc_position.json b/robosuite/controllers/config/parts/osc_position.json new file mode 100644 index 0000000000..c75e51238c --- /dev/null +++ b/robosuite/controllers/config/parts/osc_position.json @@ -0,0 +1,16 @@ +{ + "type": "OSC_POSITION", + "input_max": 1, + "input_min": -1, + "output_max": [0.05, 0.05, 0.05], + "output_min": [-0.05, -0.05, -0.05], + "kp": 150, + "damping_ratio": 1, + "impedance_mode": "fixed", + "kp_limits": [0, 300], + "damping_ratio_limits": [0, 10], + "position_limits": null, + "control_delta": true, + "interpolation": null, + "ramp_ratio": 0.2 + } \ No newline at end of file diff --git a/robosuite/controllers/parts/controller_factory.py b/robosuite/controllers/parts/controller_factory.py index b5c6331852..48be504e0b 100644 --- a/robosuite/controllers/parts/controller_factory.py +++ b/robosuite/controllers/parts/controller_factory.py @@ -52,7 +52,7 @@ def load_part_controller_config(custom_fpath=None, default_controller=None): # Store the default controller config fpath associated with the requested controller custom_fpath = os.path.join( - os.path.dirname(__file__), "..", "controllers/config/parts/{}.json".format(default_controller.lower()) + os.path.dirname(__file__), "..", "config/parts/{}.json".format(default_controller.lower()) ) # Assert that the fpath to load the controller is not empty @@ -122,7 +122,7 @@ def arm_controller_factory(name, params): ori_interpolator = deepcopy(interpolator) ori_interpolator.set_states(dim=4, ori="quat") - from robosuite.controllers.arm.ik import InverseKinematicsController + from robosuite.controllers.parts.arm.ik import InverseKinematicsController return InverseKinematicsController( interpolator_pos=interpolator, diff --git a/robosuite/demos/demo_collect_and_playback_data.py b/robosuite/demos/demo_collect_and_playback_data.py index 1bb71c316a..fb798fb075 100644 --- a/robosuite/demos/demo_collect_and_playback_data.py +++ b/robosuite/demos/demo_collect_and_playback_data.py @@ -61,10 +61,12 @@ def playback_trajectory(env, ep_dir): for state in states: env.sim.set_state_from_flattened(state) env.sim.forward() + env.viewer.update() env.render() t += 1 if t % 100 == 0: print(t) + env.close() if __name__ == "__main__": diff --git a/robosuite/demos/demo_control.py b/robosuite/demos/demo_control.py index 32d0dafd01..0b27f01cf7 100644 --- a/robosuite/demos/demo_control.py +++ b/robosuite/demos/demo_control.py @@ -47,6 +47,7 @@ from typing import Dict import robosuite as suite +from robosuite.controllers.composite.composite_controller_factory import refactor_composite_controller_config from robosuite.utils.input_utils import * if __name__ == "__main__": @@ -89,10 +90,14 @@ joint_dim = 6 if options["robots"] == "UR5e" else (16 if options["robots"] == "GR1" else 7) # Choose controller - controller_name = choose_controller() + controller_name = choose_controller(part_controllers=True) # Load the desired controller - options["controller_configs"] = suite.load_part_controller_config(default_controller=controller_name) + arm_controller_config = suite.load_part_controller_config(default_controller=controller_name) + robot = options["robots"][0] if isinstance(options["robots"], list) else options["robots"] + options["controller_configs"] = refactor_composite_controller_config( + arm_controller_config, robot, ["right", "left"] + ) # Define the pre-defined controller actions to use (action_dim, num_test_steps, test_value) controller_settings = { diff --git a/robosuite/demos/demo_device_control.py b/robosuite/demos/demo_device_control.py index 1788cc2c14..225a5cbc59 100644 --- a/robosuite/demos/demo_device_control.py +++ b/robosuite/demos/demo_device_control.py @@ -198,9 +198,9 @@ # If action_dict is none, then this a reset so we should break if action_dict is None: break - - action = action_dict[action_key] + arm_action = action_dict[action_key] grasp = action_dict[gripper_key] + action = np.concatenate([arm_action, grasp]) # If the current grasp is active (1) and last grasp is not (-1) (i.e.: grasping input just pressed), # toggle arm control and / or camera viewing angle if requested diff --git a/robosuite/demos/demo_domain_randomization.py b/robosuite/demos/demo_domain_randomization.py index 5f5503cf96..e1113ec5ad 100644 --- a/robosuite/demos/demo_domain_randomization.py +++ b/robosuite/demos/demo_domain_randomization.py @@ -2,6 +2,8 @@ Script to showcase domain randomization functionality. """ +import mujoco + import robosuite.macros as macros from robosuite.utils.input_utils import * from robosuite.wrappers import DomainRandomizationWrapper @@ -10,7 +12,7 @@ macros.USING_INSTANCE_RANDOMIZATION = True if __name__ == "__main__": - + assert mujoco.__version__ == "3.1.1", "Script requires mujoco-py version 3.1.1 to run" # Create dict to hold options that will be passed to env creation call options = {} diff --git a/robosuite/utils/input_utils.py b/robosuite/utils/input_utils.py index 1931b7539b..a7f6860323 100644 --- a/robosuite/utils/input_utils.py +++ b/robosuite/utils/input_utils.py @@ -39,7 +39,7 @@ def choose_environment(): return envs[k] -def choose_controller(): +def choose_controller(part_controllers=False): """ Prints out controller options, and returns the requested controller name @@ -47,7 +47,7 @@ def choose_controller(): str: Chosen controller name """ # get the list of all controllers - controllers = list(suite.ALL_COMPOSITE_CONTROLLERS) + controllers = list(suite.ALL_PART_CONTROLLERS) if part_controllers else list(suite.ALL_COMPOSITE_CONTROLLERS) # Select controller to use print("Here is a list of controllers in the suite:\n") From 60f09668e51e3873b9bd13d3c1c96d13e4c5fae7 Mon Sep 17 00:00:00 2001 From: Abhiram824 Date: Sun, 3 Nov 2024 17:35:56 -0600 Subject: [PATCH 14/17] updated device usage to match collect human demos script --- robosuite/demos/demo_device_control.py | 101 ++++++++++++------------- 1 file changed, 50 insertions(+), 51 deletions(-) diff --git a/robosuite/demos/demo_device_control.py b/robosuite/demos/demo_device_control.py index 225a5cbc59..3e35c32ff6 100644 --- a/robosuite/demos/demo_device_control.py +++ b/robosuite/demos/demo_device_control.py @@ -94,6 +94,7 @@ import robosuite as suite from robosuite import load_composite_controller_config +from robosuite.controllers.composite.composite_controller import WholeBody from robosuite.wrappers import VisualizationWrapper if __name__ == "__main__": @@ -107,7 +108,12 @@ parser.add_argument("--arm", type=str, default="right", help="Which arm to control (eg bimanual) 'right' or 'left'") parser.add_argument("--switch-on-grasp", action="store_true", help="Switch gripper control on gripper action") parser.add_argument("--toggle-camera-on-grasp", action="store_true", help="Switch camera angle on gripper action") - parser.add_argument("--controller", type=str, default="BASIC", help="Choice of controller. Can be 'ik' or 'osc'") + parser.add_argument( + "--controller", + type=str, + default=None, + help="Choice of controller. Can be generic (eg. 'BASIC' or 'WHOLE_BODY_MINK_IK') or json file (see robosuite/controllers/config for examples)", + ) parser.add_argument("--device", type=str, default="keyboard") parser.add_argument("--pos-sensitivity", type=float, default=1.0, help="How much to scale position user inputs") parser.add_argument("--rot-sensitivity", type=float, default=1.0, help="How much to scale rotation user inputs") @@ -161,6 +167,10 @@ from robosuite.devices import SpaceMouse device = SpaceMouse(env=env, pos_sensitivity=args.pos_sensitivity, rot_sensitivity=args.rot_sensitivity) + elif args.device == "mjgui": + from robosuite.devices.mjgui import MJGUI + + device = MJGUI(env=env) else: raise Exception("Invalid device choice: choose either 'keyboard' or 'spacemouse'.") @@ -178,61 +188,50 @@ # Initialize device control device.start_control() - action_dict = device.input2action() - - # get key with "delta" in it - action_key = [key for key in action_dict.keys() if "delta" in key] - assert len(action_key) == 1, "Error: Key with 'delta' in it not found!" - action_key = action_key[0] - gripper_key = [key for key in action_dict.keys() if "gripper" in key] - assert len(gripper_key) == 1, "Error: Key with 'gripper' in it not found!" - gripper_key = gripper_key[0] - + all_prev_gripper_actions = [ + { + f"{robot_arm}_gripper": np.repeat([0], robot.gripper[robot_arm].dof) + for robot_arm in robot.arms + if robot.gripper[robot_arm].dof > 0 + } + for robot in env.robots + ] + + # Loop until we get a reset from the input or the task completes while True: # Set active robot - active_robot = env.robots[0] if args.config == "bimanual" else env.robots[args.arm == "left"] + active_robot = env.robots[device.active_robot] # Get the newest action - action_dict = device.input2action() + input_ac_dict = device.input2action() - # If action_dict is none, then this a reset so we should break - if action_dict is None: + # If action is none, then this a reset so we should break + if input_ac_dict is None: break - arm_action = action_dict[action_key] - grasp = action_dict[gripper_key] - action = np.concatenate([arm_action, grasp]) - - # If the current grasp is active (1) and last grasp is not (-1) (i.e.: grasping input just pressed), - # toggle arm control and / or camera viewing angle if requested - if last_grasp < 0 < grasp: - if args.switch_on_grasp: - args.arm = "left" if args.arm == "right" else "right" - if args.toggle_camera_on_grasp: - cam_id = (cam_id + 1) % num_cam - env.viewer.set_camera(camera_id=cam_id) - # Update last grasp - last_grasp = grasp - - # Fill out the rest of the action space if necessary - rem_action_dim = env.action_dim - action.size - if rem_action_dim > 0: - # Initialize remaining action space - rem_action = np.zeros(rem_action_dim) - # This is a multi-arm setting, choose which arm to control and fill the rest with zeros - if args.arm == "right": - action = np.concatenate([action, rem_action]) - elif args.arm == "left": - action = np.concatenate([rem_action, action]) + + from copy import deepcopy + + action_dict = deepcopy(input_ac_dict) # {} + # set arm actions + for arm in active_robot.arms: + if isinstance(active_robot.composite_controller, WholeBody): # input type passed to joint_action_policy + controller_input_type = active_robot.composite_controller.joint_action_policy.input_type + else: + controller_input_type = active_robot.part_controllers[arm].input_type + + if controller_input_type == "delta": + action_dict[arm] = input_ac_dict[f"{arm}_delta"] + elif controller_input_type == "absolute": + action_dict[arm] = input_ac_dict[f"{arm}_abs"] else: - # Only right and left arms supported - print( - "Error: Unsupported arm specified -- " - "must be either 'right' or 'left'! Got: {}".format(args.arm) - ) - elif rem_action_dim < 0: - # We're in an environment with no gripper action space, so trim the action space to be the action dim - action = action[: env.action_dim] - - # Step through the simulation and render - obs, reward, done, info = env.step(action) + raise ValueError + + # Maintain gripper state for each robot but only update the active robot with action + env_action = [robot.create_action_vector(all_prev_gripper_actions[i]) for i, robot in enumerate(env.robots)] + env_action[device.active_robot] = active_robot.create_action_vector(action_dict) + env_action = np.concatenate(env_action) + for gripper_ac in all_prev_gripper_actions[device.active_robot]: + all_prev_gripper_actions[device.active_robot][gripper_ac] = action_dict[gripper_ac] + + env.step(env_action) env.render() From 0e1db5b38fe7c6fbd6a8626dfc37f868087ef933 Mon Sep 17 00:00:00 2001 From: snasiriany Date: Sun, 3 Nov 2024 18:45:49 -0600 Subject: [PATCH 15/17] add max frame rate feature to relevant demo scripts --- .../demos/demo_collect_and_playback_data.py | 17 +++++++++++++++-- robosuite/demos/demo_composite_robot.py | 18 +++++++++++++++++- robosuite/demos/demo_control.py | 17 +++++++++++++++++ robosuite/demos/demo_device_control.py | 13 +++++++++++++ robosuite/demos/demo_gripper_selection.py | 11 +++++++++++ robosuite/demos/demo_random_action.py | 12 ++++++++++++ robosuite/demos/demo_renderers.py | 11 +++++++++++ .../scripts/collect_human_demonstrations.py | 17 +++++++++++++++-- 8 files changed, 111 insertions(+), 5 deletions(-) diff --git a/robosuite/demos/demo_collect_and_playback_data.py b/robosuite/demos/demo_collect_and_playback_data.py index 1bb71c316a..ab94ff6f2c 100644 --- a/robosuite/demos/demo_collect_and_playback_data.py +++ b/robosuite/demos/demo_collect_and_playback_data.py @@ -7,6 +7,7 @@ import argparse import os +import time from glob import glob import numpy as np @@ -15,7 +16,7 @@ from robosuite.wrappers import DataCollectionWrapper -def collect_random_trajectory(env, timesteps=1000): +def collect_random_trajectory(env, timesteps=1000, max_fr=None): """Run a random policy to collect trajectories. The rollout trajectory is saved to files in npz format. @@ -24,18 +25,27 @@ def collect_random_trajectory(env, timesteps=1000): Args: env (MujocoEnv): environment instance to collect trajectories from timesteps(int): how many environment timesteps to run for a given trajectory + max_fr (int): if specified, pause the simulation whenever simulation runs faster than max_fr """ env.reset() dof = env.action_dim for t in range(timesteps): + start = time.time() action = np.random.randn(dof) env.step(action) env.render() if t % 100 == 0: print(t) + # limit frame rate if necessary + if max_fr is not None: + elapsed = time.time() - start + diff = 1 / max_fr - elapsed + if diff > 0: + time.sleep(diff) + def playback_trajectory(env, ep_dir): """Playback data from an episode. @@ -74,6 +84,9 @@ def playback_trajectory(env, ep_dir): parser.add_argument("--robots", nargs="+", type=str, default="Panda", help="Which robot(s) to use in the env") parser.add_argument("--directory", type=str, default="/tmp/") parser.add_argument("--timesteps", type=int, default=1000) + parser.add_argument( + "--max_fr", default=25, type=int, help="sleep when simluation runs faster than specified frame rate" + ) args = parser.parse_args() # create original environment @@ -98,7 +111,7 @@ def playback_trajectory(env, ep_dir): # collect some data print("Collecting some random data...") - collect_random_trajectory(env, timesteps=args.timesteps) + collect_random_trajectory(env, timesteps=args.timesteps, max_fr=args.max_fr) # playback some data _ = input("Press any key to begin the playback...") diff --git a/robosuite/demos/demo_composite_robot.py b/robosuite/demos/demo_composite_robot.py index a178032276..b05ed7337b 100644 --- a/robosuite/demos/demo_composite_robot.py +++ b/robosuite/demos/demo_composite_robot.py @@ -1,4 +1,5 @@ import argparse +import time from typing import Dict, List, Union import numpy as np @@ -14,6 +15,7 @@ def create_and_test_env( robots: Union[str, List[str]], controller_config: Dict, headless: bool = False, + max_fr: int = None, ): config = { @@ -38,9 +40,18 @@ def create_and_test_env( # Runs a few steps of the simulation as a sanity check for i in range(100): + start = time.time() + action = np.random.uniform(low, high) obs, reward, done, _ = env.step(action) + # limit frame rate if necessary + if max_fr is not None: + elapsed = time.time() - start + diff = 1 / max_fr - elapsed + if diff > 0: + time.sleep(diff) + env.close() @@ -53,6 +64,9 @@ def create_and_test_env( parser.add_argument("--grippers", nargs="+", type=str, default=["PandaGripper"]) parser.add_argument("--env", type=str, default="Lift") parser.add_argument("--headless", action="store_true") + parser.add_argument( + "--max_fr", default=25, type=int, help="sleep when simluation runs faster than specified frame rate" + ) args = parser.parse_args() @@ -63,4 +77,6 @@ def create_and_test_env( create_composite_robot(name, base=args.base, robot=args.robot, grippers=args.grippers) controller_config = load_composite_controller_config(controller="BASIC", robot=name) - create_and_test_env(env="Lift", robots=name, controller_config=controller_config, headless=args.headless) + create_and_test_env( + env="Lift", robots=name, controller_config=controller_config, headless=args.headless, max_fr=args.max_fr + ) diff --git a/robosuite/demos/demo_control.py b/robosuite/demos/demo_control.py index 32d0dafd01..8d7fab6cdb 100644 --- a/robosuite/demos/demo_control.py +++ b/robosuite/demos/demo_control.py @@ -44,11 +44,14 @@ """ +import time from typing import Dict import robosuite as suite from robosuite.utils.input_utils import * +MAX_FR = 25 # max frame rate for running simluation + if __name__ == "__main__": # Create dict to hold options that will be passed to env creation call @@ -143,6 +146,7 @@ while count < num_test_steps: action = neutral.copy() for i in range(steps_per_action): + start = time.time() if controller_name in {"IK_POSE", "OSC_POSE"} and count > 2: # Set this value to be the scaled axis angle vector vec = np.zeros(3) @@ -153,10 +157,23 @@ total_action = np.tile(action, n) env.step(total_action) env.render() + + # limit frame rate if necessary + elapsed = time.time() - start + diff = 1 / MAX_FR - elapsed + if diff > 0: + time.sleep(diff) for i in range(steps_per_rest): + start = time.time() total_action = np.tile(neutral, n) env.step(total_action) env.render() + + # limit frame rate if necessary + elapsed = time.time() - start + diff = 1 / MAX_FR - elapsed + if diff > 0: + time.sleep(diff) count += 1 # Shut down this env before starting the next test diff --git a/robosuite/demos/demo_device_control.py b/robosuite/demos/demo_device_control.py index 1788cc2c14..ed4b93852f 100644 --- a/robosuite/demos/demo_device_control.py +++ b/robosuite/demos/demo_device_control.py @@ -89,6 +89,7 @@ """ import argparse +import time import numpy as np @@ -111,6 +112,9 @@ parser.add_argument("--device", type=str, default="keyboard") parser.add_argument("--pos-sensitivity", type=float, default=1.0, help="How much to scale position user inputs") parser.add_argument("--rot-sensitivity", type=float, default=1.0, help="How much to scale rotation user inputs") + parser.add_argument( + "--max_fr", default=25, type=int, help="sleep when simluation runs faster than specified frame rate" + ) args = parser.parse_args() # Get controller config @@ -189,6 +193,8 @@ gripper_key = gripper_key[0] while True: + start = time.time() + # Set active robot active_robot = env.robots[0] if args.config == "bimanual" else env.robots[args.arm == "left"] @@ -236,3 +242,10 @@ # Step through the simulation and render obs, reward, done, info = env.step(action) env.render() + + # limit frame rate if necessary + if args.max_fr is not None: + elapsed = time.time() - start + diff = 1 / args.max_fr - elapsed + if diff > 0: + time.sleep(diff) diff --git a/robosuite/demos/demo_gripper_selection.py b/robosuite/demos/demo_gripper_selection.py index 1f87a800b8..1da85c9ddd 100644 --- a/robosuite/demos/demo_gripper_selection.py +++ b/robosuite/demos/demo_gripper_selection.py @@ -2,11 +2,15 @@ This script shows you how to select gripper for an environment. This is controlled by gripper_type keyword argument. """ +import time + import numpy as np import robosuite as suite from robosuite import ALL_GRIPPERS +MAX_FR = 25 # max frame rate for running simluation + if __name__ == "__main__": for gripper in ALL_GRIPPERS: @@ -34,6 +38,7 @@ # Run random policy for t in range(100): + start = time.time() env.render() action = np.random.uniform(low, high) observation, reward, done, info = env.step(action) @@ -41,5 +46,11 @@ print("Episode finished after {} timesteps".format(t + 1)) break + # limit frame rate if necessary + elapsed = time.time() - start + diff = 1 / MAX_FR - elapsed + if diff > 0: + time.sleep(diff) + # close window env.close() diff --git a/robosuite/demos/demo_random_action.py b/robosuite/demos/demo_random_action.py index 91993bab3e..6ce751c1c9 100644 --- a/robosuite/demos/demo_random_action.py +++ b/robosuite/demos/demo_random_action.py @@ -1,5 +1,9 @@ +import time + from robosuite.utils.input_utils import * +MAX_FR = 25 # max frame rate for running simluation + if __name__ == "__main__": # Create dict to hold options that will be passed to env creation call @@ -53,6 +57,14 @@ # do visualization for i in range(10000): + start = time.time() + action = np.random.uniform(low, high) obs, reward, done, _ = env.step(action) env.render() + + # limit frame rate if necessary + elapsed = time.time() - start + diff = 1 / MAX_FR - elapsed + if diff > 0: + time.sleep(diff) diff --git a/robosuite/demos/demo_renderers.py b/robosuite/demos/demo_renderers.py index dc31a16e94..d4d0d351d4 100644 --- a/robosuite/demos/demo_renderers.py +++ b/robosuite/demos/demo_renderers.py @@ -1,5 +1,6 @@ import argparse import json +import time import numpy as np @@ -7,6 +8,8 @@ import robosuite.utils.transform_utils as T from robosuite.utils.input_utils import * +MAX_FR = 25 # max frame rate for running simluation + def str2bool(v): if v.lower() in ("yes", "true", "t", "y", "1"): @@ -102,9 +105,17 @@ def print_command(char, info): # do visualization for i in range(10000): + start = time.time() + action = np.random.uniform(low, high) obs, reward, done, _ = env.step(action) env.render() + # limit frame rate if necessary + elapsed = time.time() - start + diff = 1 / MAX_FR - elapsed + if diff > 0: + time.sleep(diff) + env.close_renderer() print("Done.") diff --git a/robosuite/scripts/collect_human_demonstrations.py b/robosuite/scripts/collect_human_demonstrations.py index a78ad2d639..379eb14d4e 100644 --- a/robosuite/scripts/collect_human_demonstrations.py +++ b/robosuite/scripts/collect_human_demonstrations.py @@ -20,7 +20,7 @@ from robosuite.wrappers import DataCollectionWrapper, VisualizationWrapper -def collect_human_trajectory(env, device, arm): +def collect_human_trajectory(env, device, arm, max_fr): """ Use the device (keyboard or SpaceNav 3D mouse) to collect a demonstration. The rollout trajectory is saved to files in npz format. @@ -30,6 +30,7 @@ def collect_human_trajectory(env, device, arm): env (MujocoEnv): environment to control device (Device): to receive controls from the device arms (str): which arm to control (eg bimanual) 'right' or 'left' + max_fr (int): if specified, pause the simulation whenever simulation runs faster than max_fr """ env.reset() @@ -53,6 +54,8 @@ def collect_human_trajectory(env, device, arm): # Loop until we get a reset from the input or the task completes while True: + start = time.time() + # Set active robot active_robot = env.robots[device.active_robot] @@ -103,6 +106,13 @@ def collect_human_trajectory(env, device, arm): else: task_completion_hold_count = -1 # null the counter if there's no success + # limit frame rate if necessary + if max_fr is not None: + elapsed = time.time() - start + diff = 1 / max_fr - elapsed + if diff > 0: + time.sleep(diff) + # cleanup for end of data collection episodes env.close() @@ -228,6 +238,9 @@ def gather_demonstrations_as_hdf5(directory, out_dir, env_info): default="mjviewer", help="Use Mujoco's builtin interactive viewer (mjviewer) or OpenCV viewer (mujoco)", ) + parser.add_argument( + "--max_fr", default=25, type=int, help="sleep when simluation runs faster than specified frame rate" + ) args = parser.parse_args() # Get controller config @@ -298,5 +311,5 @@ def gather_demonstrations_as_hdf5(directory, out_dir, env_info): # collect demonstrations while True: - collect_human_trajectory(env, device, args.arm) + collect_human_trajectory(env, device, args.arm, args.max_fr) gather_demonstrations_as_hdf5(tmp_directory, new_dir, env_info) From 885a2a5c4a6d5b64c0b032ff300c17f5233e5360 Mon Sep 17 00:00:00 2001 From: Abhiram824 Date: Tue, 5 Nov 2024 20:59:59 -0600 Subject: [PATCH 16/17] cleanup demo fixes --- .gitignore | 2 +- .../composite/composite_controller_factory.py | 14 +++++++------- .../config/{ => default}/parts/ik_pose.json | 0 .../config/{ => default}/parts/joint_position.json | 0 .../config/{ => default}/parts/joint_torque.json | 0 .../config/{ => default}/parts/joint_velocity.json | 0 .../config/{ => default}/parts/osc_pose.json | 0 .../config/{ => default}/parts/osc_position.json | 0 robosuite/controllers/parts/controller_factory.py | 2 +- robosuite/demos/demo_collect_and_playback_data.py | 11 +++++++++-- robosuite/demos/demo_device_control.py | 2 +- 11 files changed, 19 insertions(+), 12 deletions(-) rename robosuite/controllers/config/{ => default}/parts/ik_pose.json (100%) rename robosuite/controllers/config/{ => default}/parts/joint_position.json (100%) rename robosuite/controllers/config/{ => default}/parts/joint_torque.json (100%) rename robosuite/controllers/config/{ => default}/parts/joint_velocity.json (100%) rename robosuite/controllers/config/{ => default}/parts/osc_pose.json (100%) rename robosuite/controllers/config/{ => default}/parts/osc_position.json (100%) diff --git a/.gitignore b/.gitignore index da7750031b..17b247decf 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,7 @@ eggs/ lib/ lib64/ parts/ -!robosuite/controllers/config/parts +!robosuite/controllers/config/default/parts !robosuite/controllers/parts sdist/ var/ diff --git a/robosuite/controllers/composite/composite_controller_factory.py b/robosuite/controllers/composite/composite_controller_factory.py index 14e5c60b2e..53975a7083 100644 --- a/robosuite/controllers/composite/composite_controller_factory.py +++ b/robosuite/controllers/composite/composite_controller_factory.py @@ -19,21 +19,21 @@ def validate_composite_controller_config(config: dict): raise ValueError -def is_stale_controller_config(config: Dict): +def is_arm_controller_config(config: Dict): """ - Checks if a controller config is in the format from robosuite versions <= 1.4.1. - Does not check for config validity, only the format type. + Checks if a controller config is an arm part config as a opposed to a composite + controller config. Args: config (dict): Controller configuration Returns: - bool: True if the config is in the old format, False otherwise + bool: True if the config is in the for the arm-only, False otherwise """ - OLD_CONTROLLER_TYPES = ["JOINT_VELOCITY", "JOINT_TORQUE", "JOINT_POSITION", "OSC_POSITION", "OSC_POSE", "IK_POSE"] + ARM_CONTROLLER_TYPES = ["JOINT_VELOCITY", "JOINT_TORQUE", "JOINT_POSITION", "OSC_POSITION", "OSC_POSE", "IK_POSE"] if "body_parts_controller_configs" not in config and "type" in config: - return config["type"] in OLD_CONTROLLER_TYPES + return config["type"] in ARM_CONTROLLER_TYPES return False @@ -51,7 +51,7 @@ def refactor_composite_controller_config(controller_config, robot_type, arms): Returns: dict: New controller config """ - if not is_stale_controller_config(controller_config): + if not is_arm_controller_config(controller_config): return controller_config config_dir = pathlib.Path(robosuite.__file__).parent / "controllers/config/robots/" diff --git a/robosuite/controllers/config/parts/ik_pose.json b/robosuite/controllers/config/default/parts/ik_pose.json similarity index 100% rename from robosuite/controllers/config/parts/ik_pose.json rename to robosuite/controllers/config/default/parts/ik_pose.json diff --git a/robosuite/controllers/config/parts/joint_position.json b/robosuite/controllers/config/default/parts/joint_position.json similarity index 100% rename from robosuite/controllers/config/parts/joint_position.json rename to robosuite/controllers/config/default/parts/joint_position.json diff --git a/robosuite/controllers/config/parts/joint_torque.json b/robosuite/controllers/config/default/parts/joint_torque.json similarity index 100% rename from robosuite/controllers/config/parts/joint_torque.json rename to robosuite/controllers/config/default/parts/joint_torque.json diff --git a/robosuite/controllers/config/parts/joint_velocity.json b/robosuite/controllers/config/default/parts/joint_velocity.json similarity index 100% rename from robosuite/controllers/config/parts/joint_velocity.json rename to robosuite/controllers/config/default/parts/joint_velocity.json diff --git a/robosuite/controllers/config/parts/osc_pose.json b/robosuite/controllers/config/default/parts/osc_pose.json similarity index 100% rename from robosuite/controllers/config/parts/osc_pose.json rename to robosuite/controllers/config/default/parts/osc_pose.json diff --git a/robosuite/controllers/config/parts/osc_position.json b/robosuite/controllers/config/default/parts/osc_position.json similarity index 100% rename from robosuite/controllers/config/parts/osc_position.json rename to robosuite/controllers/config/default/parts/osc_position.json diff --git a/robosuite/controllers/parts/controller_factory.py b/robosuite/controllers/parts/controller_factory.py index 48be504e0b..8c780f8d48 100644 --- a/robosuite/controllers/parts/controller_factory.py +++ b/robosuite/controllers/parts/controller_factory.py @@ -52,7 +52,7 @@ def load_part_controller_config(custom_fpath=None, default_controller=None): # Store the default controller config fpath associated with the requested controller custom_fpath = os.path.join( - os.path.dirname(__file__), "..", "config/parts/{}.json".format(default_controller.lower()) + os.path.dirname(__file__), "..", "config/default/parts/{}.json".format(default_controller.lower()) ) # Assert that the fpath to load the controller is not empty diff --git a/robosuite/demos/demo_collect_and_playback_data.py b/robosuite/demos/demo_collect_and_playback_data.py index b7aaaff17a..36a6a998d4 100644 --- a/robosuite/demos/demo_collect_and_playback_data.py +++ b/robosuite/demos/demo_collect_and_playback_data.py @@ -47,7 +47,7 @@ def collect_random_trajectory(env, timesteps=1000, max_fr=None): time.sleep(diff) -def playback_trajectory(env, ep_dir): +def playback_trajectory(env, ep_dir, max_fr=None): """Playback data from an episode. Args: @@ -69,6 +69,7 @@ def playback_trajectory(env, ep_dir): dic = np.load(state_file) states = dic["states"] for state in states: + start = time.time() env.sim.set_state_from_flattened(state) env.sim.forward() env.viewer.update() @@ -76,6 +77,12 @@ def playback_trajectory(env, ep_dir): t += 1 if t % 100 == 0: print(t) + + if max_fr is not None: + elapsed = time.time() - start + diff = 1 / max_fr - elapsed + if diff > 0: + time.sleep(diff) env.close() @@ -119,4 +126,4 @@ def playback_trajectory(env, ep_dir): _ = input("Press any key to begin the playback...") print("Playing back the data...") data_directory = env.ep_directory - playback_trajectory(env, data_directory) + playback_trajectory(env, data_directory, args.max_fr) diff --git a/robosuite/demos/demo_device_control.py b/robosuite/demos/demo_device_control.py index 2629633ad5..2fbd2a7a62 100644 --- a/robosuite/demos/demo_device_control.py +++ b/robosuite/demos/demo_device_control.py @@ -113,7 +113,7 @@ "--controller", type=str, default=None, - help="Choice of controller. Can be generic (eg. 'BASIC' or 'WHOLE_BODY_MINK_IK') or json file (see robosuite/controllers/config for examples)", + help="Choice of controller. Can be generic (eg. 'BASIC' or 'WHOLE_BODY_MINK_IK') or json file (see robosuite/controllers/config for examples) or None to get the robot's default controller if it exists", ) parser.add_argument("--device", type=str, default="keyboard") parser.add_argument("--pos-sensitivity", type=float, default=1.0, help="How much to scale position user inputs") From b35473125d9b1ce28a48531fff6567f7a304f30e Mon Sep 17 00:00:00 2001 From: Abhiram824 Date: Tue, 5 Nov 2024 21:19:25 -0600 Subject: [PATCH 17/17] renaming --- .../composite/composite_controller_factory.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/robosuite/controllers/composite/composite_controller_factory.py b/robosuite/controllers/composite/composite_controller_factory.py index 53975a7083..a531c1e5d2 100644 --- a/robosuite/controllers/composite/composite_controller_factory.py +++ b/robosuite/controllers/composite/composite_controller_factory.py @@ -19,9 +19,9 @@ def validate_composite_controller_config(config: dict): raise ValueError -def is_arm_controller_config(config: Dict): +def is_part_controller_config(config: Dict): """ - Checks if a controller config is an arm part config as a opposed to a composite + Checks if a controller config is a part config as a opposed to a composite controller config. Args: @@ -31,9 +31,9 @@ def is_arm_controller_config(config: Dict): bool: True if the config is in the for the arm-only, False otherwise """ - ARM_CONTROLLER_TYPES = ["JOINT_VELOCITY", "JOINT_TORQUE", "JOINT_POSITION", "OSC_POSITION", "OSC_POSE", "IK_POSE"] + PART_CONTROLLER_TYPES = ["JOINT_VELOCITY", "JOINT_TORQUE", "JOINT_POSITION", "OSC_POSITION", "OSC_POSE", "IK_POSE"] if "body_parts_controller_configs" not in config and "type" in config: - return config["type"] in ARM_CONTROLLER_TYPES + return config["type"] in PART_CONTROLLER_TYPES return False @@ -51,7 +51,7 @@ def refactor_composite_controller_config(controller_config, robot_type, arms): Returns: dict: New controller config """ - if not is_arm_controller_config(controller_config): + if not is_part_controller_config(controller_config): return controller_config config_dir = pathlib.Path(robosuite.__file__).parent / "controllers/config/robots/"