-
Notifications
You must be signed in to change notification settings - Fork 8
Add TurnKnob atomic task #315
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
alexmillane
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great!
Just a few small comments. The only major thing is the (private) non-commercial asset. I think we should try to retieve that through the LightWheel sdk.
| self.min_level_angle = min_level_angle * math.pi / 180.0 | ||
| self.max_level_angle = max_level_angle * math.pi / 180.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion to suffix with unit: self.min_level_angle_rad
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| """ | ||
|
|
||
| def __init__( | ||
| self, turnable_joint_name: str, min_level_angle: float, max_level_angle: float, num_levels: int, **kwargs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion to suffix with units: min_level_angle_deg
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| # Active range: map level [0, num_levels-1] to angle [min_level_angle, max_level_angle] | ||
| step_size = (self.max_level_angle - self.min_level_angle) / (self.num_levels - 1) | ||
| theta = self.min_level_angle + step_size * target_level |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To me it might make more sense to set it in the middle of the level. With this, you could set it to some level, then read it back and get the level below due to a rounding change, or a small motion due to physX.
Perhaps there's a good reason to have it this way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great point of handling 0.5 oscillation. So I changed from round to floor in getter, and set it to mid point in setter.
| def is_at_level( | ||
| self, env: ManagerBasedEnv, asset_cfg: SceneEntityCfg | None = None, target_level: int = -1 | ||
| ) -> torch.Tensor: | ||
| """Check if the object is at the given level (in all the environments).""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider rewriting the docstring slightly. This description makes it sound like you'd get back True if the asset reaches the target level in all envs (simultaneously).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| asset_cfg = SceneEntityCfg(self.name) | ||
| asset_cfg = self._add_joint_name_to_scene_entity_cfg(asset_cfg) | ||
| current_level = self.get_turning_level(env, asset_cfg) | ||
| return torch.abs(current_level - target_level) <= 1e-6 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be an integer comparison? (And if not, should we make the level and integer? We're rounding it anyway.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| @register_asset | ||
| class StandMixer(LibraryObject, Turnable): | ||
| """ | ||
| Encapsulates the pick-up object config for a pick-and-place environment. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update the docstring
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| usd_path = ( | ||
| "omniverse://isaac-dev.ov.nvidia.com/Isaac/IsaacLab/Arena/assets/object_library/StandMixer013/StandMixer013.usd" | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I'm not mistaken, this will fail in CI. Our CI only has access to public assets (which reflects what a public user has access to).
In your description, you say that this asset is from LightWheel. Could we retrieve this asset through the sdk, as we've done for the other LightWheel Assets?
If we plan on hosting ourselves (which I would be in favour of not doing), we need to name the asset lightwheel_stand_mixer (see attribution guide)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thx for the info! I was wondering why CI cannot fetch it. Lemme see if LW is hosted somehwere. If not, then i need to think of some ways.
| class TurnKnobTask(TaskBase): | ||
| def __init__( | ||
| self, | ||
| turnable_object: Turnable, | ||
| target_level: int, | ||
| reset_level: int = -1, | ||
| episode_length_s: float | None = None, | ||
| task_description: str | None = None, | ||
| ): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool!
| torch.tensor([joint_index]).to(env.device), | ||
| env_ids=env_ids.to(env.device) if env_ids is not None else None, | ||
| ) | ||
| set_unnormalized_joint_position(env, asset_cfg, target_joint_position_unnormlized, env_ids) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for modularizing this file!
5581856 to
3e52d43
Compare
Summary
Introduce turning knob into atomic task library, together with a stand mixer asset curated from LW open source repo.
Detailed description
turn_knob_task-2026-01-05_16.26.32.mp4
TODO