Unverified Commit 17fc724d authored by jsmith-bdai's avatar jsmith-bdai Committed by GitHub

Adds future annotations and docstring arg updates (#165)

# Description

Adds `from __future__ import annotations`, cleans up old annotations
(`List` -> `list`, `Tuple` -> `tuple`, etc) to conform with formatter,
and removes duplicated type hints in docstrings.

Fixes #140

## Type of change

- Bug fix (non-breaking change which fixes an issue)

## Checklist

- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./orbit.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file

---------
Co-authored-by: 's avatarMayank Mittal <mittalma@leggedrobotics.com>
parent 4686c3da
......@@ -15,3 +15,8 @@ ignore=E402,E501,W503,E203,D401,R504,R505,SIM102,SIM117
max-line-length = 120
max-complexity = 30
exclude=_*,.vscode,.git,docs/**,**/test/**
# docstrings
docstring-convention=google
# annotations
suppress-none-returning=True
allow-star-arg-any=True
......@@ -4,7 +4,8 @@
# SPDX-License-Identifier: BSD-3-Clause
#
"""
"""This script sets up the vs-code settings for the orbit project.
This script merges the python.analysis.extraPaths from the "_isaac_sim/.vscode/settings.json" file into
the ".vscode/settings.json" file.
......@@ -25,14 +26,19 @@ ISAACSIM_DIR = os.path.join(ORBIT_DIR, "_isaac_sim")
def overwrite_python_analysis_extra_paths(orbit_settings: str) -> str:
"""Overwrite the python.analysis.extraPaths in the orbit settings file with the path names
from the isaac-sim settings file.
"""Overwrite the python.analysis.extraPaths in the orbit settings file.
The extraPaths are replaced with the path names from the isaac-sim settings file that exists in the
"_isaac_sim/.vscode/settings.json" file.
Args:
orbit_settings (str): The settings string to use as template.
orbit_settings: The settings string to use as template.
Returns:
The settings string with overwritten python analysis extra paths.
Raises:
FileNotFoundError: If the isaac-sim settings file does not exist.
"""
# isaac-sim settings
isaacsim_vscode_filename = os.path.join(ISAACSIM_DIR, ".vscode", "settings.json")
......@@ -68,11 +74,14 @@ def overwrite_python_analysis_extra_paths(orbit_settings: str) -> str:
def overwrite_default_python_interpreter(orbit_settings: str) -> str:
"""Overwrite the default python interpreter in the orbit settings file with the path to the
python interpreter used.
"""Overwrite the default python interpreter in the orbit settings file.
The default python interpreter is replaced with the path to the python interpreter used by the
isaac-sim project. This is necessary because the default python interpreter is the one shipped with
isaac-sim.
Args:
orbit_settings (str): The settings string to use as template.
orbit_settings: The settings string to use as template.
Returns:
The settings string with overwritten default python interpreter.
......
......@@ -67,6 +67,19 @@ For documentation, we adopt the `Google Style Guide <https://sphinxcontrib-napol
for docstrings. We use `Sphinx <https://www.sphinx-doc.org/en/master/>`__ for generating the documentation.
Please make sure that your code is well-documented and follows the guidelines.
Type-hinting
^^^^^^^^^^^^
To make the code more readable, we use `type hints <https://docs.python.org/3/library/typing.html>`__ for
all the functions and classes. This helps in understanding the code and makes it easier to maintain. Following
this practice also helps in catching bugs early with static type checkers like `mypy <https://mypy.readthedocs.io/en/stable/>`__.
To avoid duplication of efforts, we do not specify type hints for the arguments and return values in the docstrings.
However, if your function or class is not self-explanatory, please add a docstring with the type hints.
Tools
^^^^^
We use the following tools for maintaining code quality:
* `pre-commit <https://pre-commit.com/>`__: Runs a list of formatters and linters over the codebase.
......
......@@ -27,6 +27,7 @@ Usage:
>>> env = gym.make(task_name, cfg=cfg)
"""
from __future__ import annotations
import gym # noqa: F401
import os
......
......@@ -5,6 +5,8 @@
"""Installation script for the 'omni.isaac.contrib_envs' python package."""
from __future__ import annotations
import os
import toml
......
[package]
# Note: Semantic Versioning is used: https://semver.org/
version = "0.9.4"
version = "0.9.5"
# Description
title = "ORBIT framework for Robot Learning"
......
Changelog
---------
0.9.5 (2023-09-25)
~~~~~~~~~~~~~~~~~~
Changed
^^^^^^^
* Added future import of ``annotations`` to have a consistent behavior across Python versions.
* Removed the type-hinting from docstrings to simplify maintenance of the documentation. All type-hints are
now in the code itself.
0.9.4 (2023-08-29)
~~~~~~~~~~~~~~~~~~
......
......@@ -5,6 +5,8 @@
"""Subpackage for handling actuator models."""
from __future__ import annotations
from .actuator_base import ActuatorBase
from .actuator_cfg import (
ActuatorBaseCfg,
......
......@@ -50,11 +50,12 @@ class ActuatorBase(ABC):
"""Initialize the actuator.
Args:
cfg (ActuatorBaseCfg): The configuration of the actuator model.
joint_names (list[str]): The joint names in the articulation.
joint_ids (list[int] | Ellipsis): The joint indices in the articulation.
num_envs (int): Number of articulations in the view.
device (str): Device used for processing.
cfg: The configuration of the actuator model.
joint_names: The joint names in the articulation.
joint_ids: The joint indices in the articulation. If :obj:`Ellipsis`, then all the joints in the
articulation are part of the group.
num_envs: Number of articulations in the view.
device: Device used for processing.
"""
# save parameters
self.cfg = cfg
......@@ -95,7 +96,7 @@ class ActuatorBase(ABC):
self.damping[:, indices] = torch.tensor(values, device=self._device)
def __str__(self) -> str:
"""A string representation of the actuator group."""
"""Returns: A string representation of the actuator group."""
# resolve joint indices for printing
joint_indices = self.joint_indices
if joint_indices is Ellipsis:
......@@ -140,7 +141,7 @@ class ActuatorBase(ABC):
"""Reset the internals within the group.
Args:
env_ids (Sequence[int]): List of environment IDs to reset.
env_ids: List of environment IDs to reset.
"""
raise NotImplementedError
......@@ -153,14 +154,12 @@ class ActuatorBase(ABC):
It computes the articulation actions based on the actuator model type
Args:
control_action (ArticulationActions): The joint action instance comprising of the desired joint
positions, joint velocities and (feed-forward) joint efforts.
joint_pos (torch.Tensor): The current joint positions of the joints in the group.
Shape is ``(num_envs, num_joints)``.
joint_vel (torch.Tensor): The current joint velocities of the joints in the group.
Shape is ``(num_envs, num_joints)``.
control_action: The joint action instance comprising of the desired joint positions, joint velocities
and (feed-forward) joint efforts.
joint_pos: The current joint positions of the joints in the group. Shape is ``(num_envs, num_joints)``.
joint_vel: The current joint velocities of the joints in the group. Shape is ``(num_envs, num_joints)``.
Returns:
ArticulationActions: The computed desired joint positions, joint velocities and joint efforts.
The computed desired joint positions, joint velocities and joint efforts.
"""
raise NotImplementedError
......@@ -122,10 +122,10 @@ class IdealPDActuator(ActuatorBase):
"""Clip the desired torques based on the motor limits.
Args:
desired_torques (torch.Tensor): The desired torques to clip.
desired_torques: The desired torques to clip.
Returns:
torch.Tensor: The clipped torques.
The clipped torques.
"""
return torch.clip(effort, min=-self.effort_limit, max=self.effort_limit)
......
......@@ -72,6 +72,8 @@ Alternatively, one can set the environment variables to the python script direct
"""
from __future__ import annotations
import faulthandler
import os
import re
......
......@@ -37,6 +37,8 @@ specified joint targets are not directly applied to the simulator but are instea
the corresponding actuator torques.
"""
from __future__ import annotations
from .articulation import Articulation, ArticulationCfg, ArticulationData
from .asset_base import AssetBase
from .asset_base_cfg import AssetBaseCfg
......
......@@ -37,8 +37,9 @@ class Articulation(RigidObject):
def __init__(self, cfg: ArticulationCfg):
"""Initialize the articulation.
Args:
cfg (ArticulationCfg): A configuration instance.
cfg: A configuration instance.
"""
super().__init__(cfg)
# container for data access
......@@ -136,13 +137,12 @@ class Articulation(RigidObject):
"""Find joints in the articulation based on the name keys.
Args:
name_keys (Union[str, Sequence[str]]): A regular expression or a list of regular expressions
to match the joint names.
joint_subset (Optional[List[str]], optional): A subset of joints to search for. Defaults to None,
which means all joints in the articulation are searched.
name_keys: A regular expression or a list of regular expressions to match the joint names.
joint_subset: A subset of joints to search for. Defaults to None, which means all joints
in the articulation are searched.
Returns:
Tuple[List[int], List[str]]: A tuple of lists containing the joint indices and names.
A tuple of lists containing the joint indices and names.
"""
if joint_subset is None:
joint_subset = self.joint_names
......@@ -186,12 +186,10 @@ class Articulation(RigidObject):
"""Write joint positions and velocities to the simulation.
Args:
position (torch.Tensor): Joint positions. Shape is ``(len(env_ids), len(joint_ids))``.
velocity (torch.Tensor): Joint velocities. Shape is ``(len(env_ids), len(joint_ids))``.
joint_ids (Optional[Sequence[int]], optional): The joint indices to set the targets for.
Defaults to None (all joints).
env_ids (Optional[Sequence[int]], optional): The environment indices to set the targets for.
Defaults to None (all environments).
position: Joint positions. Shape is ``(len(env_ids), len(joint_ids))``.
velocity: Joint velocities. Shape is ``(len(env_ids), len(joint_ids))``.
joint_ids: The joint indices to set the targets for. Defaults to None (all joints).
env_ids: The environment indices to set the targets for. Defaults to None (all environments).
"""
# resolve indices
if env_ids is None:
......@@ -216,11 +214,9 @@ class Articulation(RigidObject):
"""Write joint stiffness into the simulation.
Args:
stiffness (torch.Tensor): Joint stiffness. Shape is ``(len(env_ids), len(joint_ids))``.
joint_ids (Optional[Sequence[int]], optional): The joint indices to set the stiffness for.
Defaults to None (all joints).
env_ids (Optional[Sequence[int]], optional): The environment indices to set the stiffness for.
Defaults to None (all environments).
stiffness: Joint stiffness. Shape is ``(len(env_ids), len(joint_ids))``.
joint_ids: The joint indices to set the stiffness for. Defaults to None (all joints).
env_ids: The environment indices to set the stiffness for. Defaults to None (all environments).
"""
# note: This function isn't setting the values for actuator models. (#128)
# resolve indices
......@@ -240,10 +236,10 @@ class Articulation(RigidObject):
"""Write joint damping into the simulation.
Args:
damping (torch.Tensor): Joint damping. Shape is ``(len(env_ids), len(joint_ids))``.
joint_ids (Optional[Sequence[int]], optional): The joint indices to set the damping for.
damping: Joint damping. Shape is ``(len(env_ids), len(joint_ids))``.
joint_ids: The joint indices to set the damping for.
Defaults to None (all joints).
env_ids (Optional[Sequence[int]], optional): The environment indices to set the damping for.
env_ids: The environment indices to set the damping for.
Defaults to None (all environments).
"""
# note: This function isn't setting the values for actuator models. (#128)
......@@ -267,11 +263,9 @@ class Articulation(RigidObject):
"""Write joint torque limits into the simulation.
Args:
limits (torch.Tensor): Joint torque limits. Shape is ``(len(env_ids), len(joint_ids))``.
joint_ids (Optional[Sequence[int]], optional): The joint indices to set the joint torque limits for.
Defaults to None (all joints).
env_ids (Optional[Sequence[int]], optional): The environment indices to set the joint torque limits for.
Defaults to None (all environments).
limits: Joint torque limits. Shape is ``(len(env_ids), len(joint_ids))``.
joint_ids: The joint indices to set the joint torque limits for. Defaults to None (all joints).
env_ids: The environment indices to set the joint torque limits for. Defaults to None (all environments).
"""
# note: This function isn't setting the values for actuator models. (#128)
# resolve indices
......@@ -300,11 +294,9 @@ class Articulation(RigidObject):
the desired values. To apply the joint targets, call the :meth:`write_data_to_sim` function.
Args:
target (torch.Tensor): Joint position targets. Shape is ``(len(env_ids), len(joint_ids))``.
joint_ids (Optional[Sequence[int]], optional): The joint indices to set the targets for.
Defaults to None (all joints).
env_ids (Optional[Sequence[int]], optional): The environment indices to set the targets for.
Defaults to None (all environments).
target: Joint position targets. Shape is ``(len(env_ids), len(joint_ids))``.
joint_ids: The joint indices to set the targets for. Defaults to None (all joints).
env_ids: The environment indices to set the targets for. Defaults to None (all environments).
"""
# resolve indices
if env_ids is None:
......@@ -324,11 +316,9 @@ class Articulation(RigidObject):
the desired values. To apply the joint targets, call the :meth:`write_data_to_sim` function.
Args:
target (torch.Tensor): Joint velocity targets. Shape is ``(len(env_ids), len(joint_ids))``.
joint_ids (Optional[Sequence[int]], optional): The joint indices to set the targets for.
Defaults to None (all joints).
env_ids (Optional[Sequence[int]], optional): The environment indices to set the targets for.
Defaults to None (all environments).
target: Joint velocity targets. Shape is ``(len(env_ids), len(joint_ids))``.
joint_ids: The joint indices to set the targets for. Defaults to None (all joints).
env_ids: The environment indices to set the targets for. Defaults to None (all environments).
"""
# resolve indices
if env_ids is None:
......@@ -348,11 +338,9 @@ class Articulation(RigidObject):
the desired values. To apply the joint targets, call the :meth:`write_data_to_sim` function.
Args:
target (torch.Tensor): Joint effort targets. Shape is ``(len(env_ids), len(joint_ids))``.
joint_ids (Optional[Sequence[int]], optional): The joint indices to set the targets for.
Defaults to None (all joints).
env_ids (Optional[Sequence[int]], optional): The environment indices to set the targets for.
Defaults to None (all environments).
target: Joint effort targets. Shape is ``(len(env_ids), len(joint_ids))``.
joint_ids: The joint indices to set the targets for. Defaults to None (all joints).
env_ids: The environment indices to set the targets for. Defaults to None (all environments).
"""
# resolve indices
if env_ids is None:
......
......@@ -23,7 +23,7 @@ class AssetBase(ABC):
"""Initialize the asset base.
Args:
cfg (AssetBaseCfg): The configuration class for the asset.
cfg: The configuration class for the asset.
Raises:
RuntimeError: If no prims found at input prim path or prim path expression.
......@@ -102,7 +102,7 @@ class AssetBase(ABC):
"""Sets whether to visualize the asset data.
Args:
debug_vis (bool): Whether to visualize the asset data.
debug_vis: Whether to visualize the asset data.
Raises:
RuntimeError: If the asset debug visualization is not enabled.
......@@ -115,8 +115,7 @@ class AssetBase(ABC):
"""Resets all internal buffers of selected environments.
Args:
env_ids (Optional[Sequence[int]], optional): The indices of the object to reset.
Defaults to None (all instances).
env_ids: The indices of the object to reset. Defaults to None (all instances).
"""
raise NotImplementedError
......@@ -133,7 +132,7 @@ class AssetBase(ABC):
accelerations which are not provided by the simulator.
Args:
dt (float): The amount of time passed from last ``update`` call.
dt: The amount of time passed from last ``update`` call.
"""
raise NotImplementedError
......
......@@ -3,8 +3,10 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
from dataclasses import MISSING
from typing import ClassVar, Optional, Tuple
from typing import ClassVar
from typing_extensions import Literal
from omni.isaac.orbit.sim import SpawnerCfg
......@@ -20,9 +22,9 @@ class AssetBaseCfg:
"""Initial state of the asset."""
# root position
pos: Tuple[float, float, float] = (0.0, 0.0, 0.0)
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)."""
rot: Tuple[float, float, float, float] = (1.0, 0.0, 0.0, 0.0)
rot: tuple[float, float, float, float] = (1.0, 0.0, 0.0, 0.0)
"""Quaternion rotation ``(w, x, y, z)`` of the root in simulation world frame.
Defaults to (1.0, 0.0, 0.0, 0.0).
"""
......@@ -43,7 +45,7 @@ class AssetBaseCfg:
init_state: InitialStateCfg = InitialStateCfg()
"""Initial state of the rigid object. Defaults to identity pose."""
spawn: Optional[SpawnerCfg] = MISSING
spawn: SpawnerCfg | None = MISSING
"""Spawn configuration for the asset.
If :obj:`None`, then no prims are spawned by the asset class. Instead, it is assumed that the
......
......@@ -7,6 +7,8 @@
Sub-module containing configuration instances for different assets.
"""
from __future__ import annotations
from .anymal import *
from .franka import *
from .ridgeback_franka import *
......
......@@ -14,6 +14,7 @@ Reference:
* https://github.com/ANYbotics/anymal_c_simple_description
"""
from __future__ import annotations
import omni.isaac.orbit.sim as sim_utils
from omni.isaac.orbit.actuators import ActuatorNetLSTMCfg, DCMotorCfg
......
......@@ -12,6 +12,7 @@ The following configurations are available:
Reference: https://github.com/frankaemika/franka_ros
"""
from __future__ import annotations
import omni.isaac.orbit.sim as sim_utils
from omni.isaac.orbit.actuators import ImplicitActuatorCfg
......
......@@ -12,6 +12,7 @@ The following configurations are available:
Reference: https://github.com/ridgeback/ridgeback_manipulation
"""
from __future__ import annotations
import omni.isaac.orbit.sim as sim_utils
from omni.isaac.orbit.actuators import ImplicitActuatorCfg
......
......@@ -12,6 +12,7 @@ The following configurations are available:
Reference: https://github.com/unitreerobotics/unitree_ros
"""
from __future__ import annotations
import omni.isaac.orbit.sim as sim_utils
from omni.isaac.orbit.actuators import DCMotorCfg
......
......@@ -12,6 +12,7 @@ The following configuration parameters are available:
Reference: https://github.com/ros-industrial/universal_robot
"""
from __future__ import annotations
import omni.isaac.orbit.sim as sim_utils
from omni.isaac.orbit.actuators import ImplicitActuatorCfg
......
......@@ -3,6 +3,8 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
from .rigid_object import RigidObject
from .rigid_object_cfg import RigidObjectCfg
from .rigid_object_data import RigidObjectData
......
......@@ -32,7 +32,7 @@ class RigidObject(AssetBase):
"""Initialize the rigid object.
Args:
cfg (RigidObjectCfg): A configuration instance.
cfg: A configuration instance.
"""
super().__init__(cfg)
# container for data access
......@@ -134,11 +134,11 @@ class RigidObject(AssetBase):
"""Find bodies in the articulation based on the name keys.
Args:
name_keys (Union[str, Sequence[str]]): A regular expression or a list of regular expressions
name_keys: A regular expression or a list of regular expressions
to match the body names.
Returns:
Tuple[List[int], List[str]]: A tuple of lists containing the body indices and names.
A tuple of lists containing the body indices and names.
"""
return string_utils.resolve_matching_names(name_keys, self.body_names)
......@@ -153,8 +153,8 @@ class RigidObject(AssetBase):
and angular velocity. All the quantities are in the simulation frame.
Args:
root_state (torch.Tensor): Root state in simulation frame. Shape: ``(len(env_ids), 13)``.
env_ids (Optional[Sequence[int]]): Environment indices. If :obj:`None`, then all indices are used.
root_state: Root state in simulation frame. Shape is ``(len(env_ids), 13)``.
env_ids: Environment indices. If :obj:`None`, then all indices are used.
"""
# set into simulation
self.write_root_pose_to_sim(root_state[:, :7], env_ids=env_ids)
......@@ -166,8 +166,8 @@ class RigidObject(AssetBase):
The root pose comprises of the cartesian position and quaternion orientation in (w, x, y, z).
Args:
root_pose (torch.Tensor): Root poses in simulation frame. Shape: ``(len(env_ids), 7)``.
env_ids (Optional[Sequence[int]]): Environment indices. If :obj:`None`, then all indices are used.
root_pose: Root poses in simulation frame. Shape is ``(len(env_ids), 7)``.
env_ids: Environment indices. If :obj:`None`, then all indices are used.
"""
# resolve all indices
if env_ids is None:
......@@ -185,8 +185,8 @@ class RigidObject(AssetBase):
"""Set the root velocity over selected environment indices into the simulation.
Args:
root_velocity (torch.Tensor): Root velocities in simulation frame. Shape: ``(len(env_ids), 6)``.
env_ids (Optional[Sequence[int]]): Environment indices. If :obj:`None`, then all indices are used.
root_velocity: Root velocities in simulation frame. Shape is ``(len(env_ids), 6)``.
env_ids: Environment indices. If :obj:`None`, then all indices are used.
"""
# resolve all indices
if env_ids is None:
......@@ -227,10 +227,10 @@ class RigidObject(AssetBase):
the desired values. To apply the external wrench, call the :meth:`write_data_to_sim` function.
Args:
forces (torch.Tensor): External forces in bodies' local frame. Shape: ``(len(env_ids), len(body_ids), 3)``.
torques (torch.Tensor): External torques in bodies' local frame. Shape: ``(len(env_ids), len(body_ids), 3)``.
body_ids (Optional[Sequence[int]], optional): Body indices to apply external wrench to. Defaults to None (all bodies).
env_ids (Optional[Sequence[int]], optional): Environment indices to apply external wrench to. Defaults to None (all instances).
forces: External forces in bodies' local frame. Shape is ``(len(env_ids), len(body_ids), 3)``.
torques: External torques in bodies' local frame. Shape is ``(len(env_ids), len(body_ids), 3)``.
body_ids: Body indices to apply external wrench to. Defaults to None (all bodies).
env_ids: Environment indices to apply external wrench to. Defaults to None (all instances).
"""
if forces.any() or torques.any():
self.has_external_force = True
......
......@@ -3,7 +3,7 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from typing import Tuple
from __future__ import annotations
from omni.isaac.orbit.utils import configclass
......@@ -21,9 +21,9 @@ class RigidObjectCfg(AssetBaseCfg):
class InitialStateCfg(AssetBaseCfg.InitialStateCfg):
"""Initial state of the rigid body."""
lin_vel: Tuple[float, float, float] = (0.0, 0.0, 0.0)
lin_vel: tuple[float, float, float] = (0.0, 0.0, 0.0)
"""Linear velocity of the root in simulation world frame. Defaults to (0.0, 0.0, 0.0)."""
ang_vel: Tuple[float, float, float] = (0.0, 0.0, 0.0)
ang_vel: tuple[float, float, float] = (0.0, 0.0, 0.0)
"""Angular velocity of the root in simulation world frame. Defaults to (0.0, 0.0, 0.0)."""
##
......
......@@ -3,9 +3,10 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import torch
from dataclasses import dataclass
from typing import List
@dataclass
......@@ -16,7 +17,7 @@ class RigidObjectData:
# Properties.
##
body_names: List[str] = None
body_names: list[str] = None
"""Body names in the order parsed by the simulation view."""
##
......
......@@ -41,8 +41,8 @@ class CommandGeneratorBase(ABC):
"""Initialize the command generator class.
Args:
cfg (CommandGeneratorBaseCfg): The configuration parameters for the command generator.
env (BaseEnv): The environment object.
cfg: The configuration parameters for the command generator.
env: The environment object.
"""
# store the inputs
self.cfg = cfg
......@@ -97,7 +97,7 @@ class CommandGeneratorBase(ABC):
"""Sets whether to visualize the command data.
Args:
debug_vis (bool): Whether to visualize the command data.
debug_vis: Whether to visualize the command data.
Raises:
RuntimeError: If the command debug visualization is not enabled.
......@@ -112,10 +112,10 @@ class CommandGeneratorBase(ABC):
at the beginning of each episode.
Args:
env_ids (Optional[Sequence[int]], optional): The list of environment IDs to reset. Defaults to None.
env_ids: The list of environment IDs to reset. Defaults to None.
Returns:
Dict[str, float]: A dictionary containing the information to log under the "Metrics/{name}" key.
A dictionary containing the information to log under the "Metrics/{name}" key.
"""
# resolve the environment IDs
if env_ids is None:
......@@ -137,7 +137,7 @@ class CommandGeneratorBase(ABC):
"""Compute the command.
Args:
dt (float): The time step passed since the last call to compute.
dt: The time step passed since the last call to compute.
"""
# update the metrics based on current state
self._update_metrics()
......@@ -161,7 +161,7 @@ class CommandGeneratorBase(ABC):
specified environment indices.
Args:
env_ids (Sequence[int]): The list of environment IDs to resample.
env_ids: The list of environment IDs to resample.
"""
# resample the time left before resampling
self.time_left[env_ids] = self.time_left[env_ids].uniform_(*self.cfg.resampling_time_range)
......
......@@ -38,8 +38,8 @@ class TerrainBasedPositionCommandGenerator(CommandGeneratorBase):
"""Initialize the command generator class.
Args:
cfg (TerrainBasedPositionCommandGeneratorCfg): The configuration parameters for the command generator.
env (BaseEnv): The environment object.
cfg: The configuration parameters for the command generator.
env: The environment object.
"""
super().__init__(cfg, env)
# -- robot
......
......@@ -48,8 +48,8 @@ class UniformVelocityCommandGenerator(CommandGeneratorBase):
"""Initialize the command generator.
Args:
cfg (UniformVelocityCommandGeneratorCfg): The configuration of the command generator.
env (BaseEnv): The environment.
cfg: The configuration of the command generator.
env: The environment.
"""
super().__init__(cfg, env)
# -- robot
......@@ -224,7 +224,7 @@ class NormalVelocityCommandGenerator(UniformVelocityCommandGenerator):
"""Initializes the command generator.
Args:
cfg (NormalVelocityCommandGeneratorCfg): The command generator configuration.
cfg: The command generator configuration.
env: The environment.
"""
super().__init__(self, cfg, env)
......
......@@ -10,3 +10,5 @@ This submodule contains code from previous release of Orbit that is kept for com
This module is not part of the public API and may be removed in future releases.
"""
from __future__ import annotations
......@@ -11,6 +11,8 @@ Module containing different actuator groups.
- **non-holonomic**: Adds a 2D kinematics skid-steering constraint for the actuator group.
"""
from __future__ import annotations
from .actuator_control_cfg import ActuatorControlCfg
from .actuator_group import ActuatorGroup
from .actuator_group_cfg import ActuatorGroupCfg, GripperActuatorGroupCfg, NonHolonomicKinematicsGroupCfg
......
......@@ -3,8 +3,9 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
from dataclasses import MISSING
from typing import Dict, List, Optional
from omni.isaac.orbit.utils import configclass
......@@ -31,7 +32,7 @@ class ActuatorControlCfg:
documentation of the :class:`ActuatorGroup` class.
"""
command_types: List[str] = MISSING
command_types: list[str] = MISSING
"""
Command types applied on the DOF in the group.
......@@ -40,14 +41,14 @@ class ActuatorControlCfg:
"p" (position-controlled), "v" (velocity-controlled), or "t" (torque-controlled).
"""
stiffness: Optional[Dict[str, float]] = None
stiffness: dict[str, float] | None = None
"""
Stiffness gains of the DOFs in the group. Defaults to :obj:`None`.
If :obj:`None`, these are loaded from the articulation prim.
"""
damping: Optional[Dict[str, float]] = None
damping: dict[str, float] | None = None
"""
Damping gains of the DOFs in the group. Defaults to :obj:`None`.
......
......@@ -3,9 +3,11 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import re
import torch
from typing import List, Optional, Sequence
from typing import Sequence
from omni.isaac.core.articulations import ArticulationView
from omni.isaac.core.utils.types import ArticulationActions
......@@ -41,19 +43,19 @@ class ActuatorGroup:
"""Number of articulations in the view."""
device: str
"""Device used for processing."""
dof_names: List[str]
dof_names: list[str]
"""Articulation's DOF names that are part of the group."""
dof_indices: List[int]
dof_indices: list[int]
"""Articulation's DOF indices that are part of the group."""
model: Optional[IdealActuator]
model: IdealActuator | None
"""Actuator model used by the group."""
def __init__(self, cfg: ActuatorGroupCfg, view: ArticulationView):
"""Initialize the actuator group.
Args:
cfg (ActuatorGroupCfg): The configuration of the actuator group.
view (ArticulationView): The simulation articulation view.
cfg: The configuration of the actuator group.
view: The simulation articulation view.
Raises:
ValueError: When no command types are specified in the configuration.
......@@ -154,7 +156,7 @@ class ActuatorGroup:
return self.cfg.model_cfg.model_type
@property
def command_types(self) -> List[str]:
def command_types(self) -> list[str]:
"""Command type applied on the DOF in the group.
It contains a list of strings. Each string has two sub-strings joined by underscore:
......@@ -229,7 +231,7 @@ class ActuatorGroup:
return self._applied_torques
@property
def velocity_limit(self) -> Optional[torch.Tensor]:
def velocity_limit(self) -> torch.Tensor | None:
"""DOF velocity limits from actuator.
Returns :obj:`None` for implicit and ideal actuator.
......@@ -247,7 +249,7 @@ class ActuatorGroup:
"""Reset the internals within the group.
Args:
env_ids (Sequence[int]): List of environment IDs to reset.
env_ids: List of environment IDs to reset.
"""
# actuator
if self.model is not None:
......@@ -264,9 +266,9 @@ class ActuatorGroup:
4. computes the articulation actions based on the actuator model type
Args:
group_actions (torch.Tensor): The actuator group actions of shape (num_articulation, control_dim).
dof_pos (torch.Tensor): The current joint positions of the joints in the group.
dof_vel (torch.Tensor): The current joint velocities of the joints in the group.
group_actions: The actuator group actions of shape (num_articulation, control_dim).
dof_pos: The current joint positions of the joints in the group.
dof_vel: The current joint velocities of the joints in the group.
Raises:
ValueError: When the group actions has the wrong shape. Expected shape: (num_articulation, control_dim).
......@@ -274,7 +276,7 @@ class ActuatorGroup:
ValueError: Invalid actuator model type in group. Expected: 'explicit' or 'implicit'.
Returns:
ArticulationActions: An instance of the articulation actions.
An instance of the articulation actions.
a. for explicit actuator models, it returns the computed joint torques (after clipping)
b. for implicit actuator models, it returns the actions with the processed desired joint
positions, velocities, and efforts (based on the command types)
......@@ -352,7 +354,7 @@ class ActuatorGroup:
commands and the joint commands.
Returns:
torch.Tensor: Desired commands for the DOFs in the group.
Desired commands for the DOFs in the group.
Shape is ``(num_articulation, num_actuators * len(command_types))``.
"""
return command
......
......@@ -14,9 +14,10 @@ Currently, the following configuration classes are supported:
"""
from __future__ import annotations
from dataclasses import MISSING
from typing import ClassVar, Dict, List
from typing import ClassVar
from omni.isaac.orbit.actuators.model.actuator_cfg import BaseActuatorCfg
from omni.isaac.orbit.utils import configclass
......@@ -31,7 +32,7 @@ class ActuatorGroupCfg:
cls_name: ClassVar[str] = "ActuatorGroup"
"""Name of the associated actuator group class. Used to construct the actuator group."""
dof_names: List[str] = MISSING
dof_names: list[str] = MISSING
"""Articulation's DOF names that are part of the group."""
model_cfg: BaseActuatorCfg = MISSING
......@@ -50,7 +51,7 @@ class GripperActuatorGroupCfg(ActuatorGroupCfg):
speed: float = MISSING
"""The speed at which gripper should close. (used with velocity command type.)"""
mimic_multiplier: Dict[str, float] = MISSING
mimic_multiplier: dict[str, float] = MISSING
"""
Mapping of command from DOF names to command axis [-1, 1].
......
......@@ -3,6 +3,8 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import re
import torch
from typing import Sequence
......@@ -44,8 +46,8 @@ class GripperActuatorGroup(ActuatorGroup):
"""Initialize the actuator group.
Args:
cfg (GripperActuatorGroupCfg): The configuration of the actuator group.
view (ArticulationView): The simulation articulation view.
cfg: The configuration of the actuator group.
view: The simulation articulation view.
Raises:
ValueError: When command type is not "p_abs" or "v_abs".
......@@ -115,7 +117,7 @@ class GripperActuatorGroup(ActuatorGroup):
* Negative command: close grippers
Returns:
torch.Tensor: The target joint commands for the gripper.
The target joint commands for the gripper.
"""
# FIXME: mimic joint positions -- Gazebo plugin seems to do this.
# The following is commented out because Isaac Sim doesn't support setting joint positions
......
......@@ -3,6 +3,8 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import torch
from omni.isaac.core.articulations import ArticulationView
......@@ -48,8 +50,8 @@ class NonHolonomicKinematicsGroup(ActuatorGroup):
"""Initialize the actuator group.
Args:
cfg (NonHolonomicKinematicsGroupCfg): The configuration of the actuator group.
view (ArticulationView): The simulation articulation view.
cfg: The configuration of the actuator group.
view: The simulation articulation view.
Raises:
ValueError: When command type is not "v_abs".
......@@ -87,7 +89,7 @@ class NonHolonomicKinematicsGroup(ActuatorGroup):
The input command is the base velocity and turning rate command.
Returns:
torch.Tensor: The target joint commands for the gripper.
The target joint commands for the gripper.
"""
# obtain current heading
quat_w = self.view.get_world_poses(clone=False)[1]
......
......@@ -22,6 +22,8 @@ Currently, the module provides two classes:
"""
from __future__ import annotations
from .point_marker import PointMarker
from .static_marker import StaticMarker
......
......@@ -5,9 +5,11 @@
"""A class to coordinate groups of visual markers (loaded from USD)."""
from __future__ import annotations
import numpy as np
import torch
from typing import List, Optional, Sequence, Union
from typing import Sequence
import omni.isaac.core.utils.prims as prim_utils
import omni.isaac.core.utils.stage as stage_utils
......@@ -54,9 +56,9 @@ class PointMarker:
"""Initialize the class.
Args:
prim_path (str): The prim path where the PointInstancer will be created.
count (int): The number of marker duplicates to create.
radius (float, optional): The radius of the sphere. Defaults to 1.0.
prim_path: The prim path where the PointInstancer will be created.
count: The number of marker duplicates to create.
radius: The radius of the sphere. Defaults to 1.0.
Raises:
ValueError: When a prim already exists at the :obj:`prim_path` and it is not a :class:`UsdGeom.PointInstancer`.
......@@ -117,7 +119,7 @@ class PointMarker:
The method does this through the USD API.
Args:
visible (bool): flag to set the visibility.
visible: flag to set the visibility.
"""
imageable = UsdGeom.Imageable(self._instancer_manager)
if visible:
......@@ -127,20 +129,20 @@ class PointMarker:
def set_world_poses(
self,
positions: Optional[Union[np.ndarray, torch.Tensor]] = None,
orientations: Optional[Union[np.ndarray, torch.Tensor]] = None,
indices: Optional[Sequence[int]] = None,
positions: np.ndarray | torch.Tensor | None = None,
orientations: np.ndarray | torch.Tensor | None = None,
indices: Sequence[int] | None = None,
):
"""Update marker poses in the simulation world frame.
Args:
positions (Optional[Union[np.ndarray, torch.Tensor]], optional):
Positions in the world frame. Shape: (M, 3). Defaults to :obj:`None`, which means left unchanged.
orientations (Optional[Union[np.ndarray, torch.Tensor]], optional):
Quaternion orientations (w, x, y, z) in the world frame of the prims. Shape: (M, 4).
positions:
Positions in the world frame. Shape is (M, 3). Defaults to :obj:`None`, which means left unchanged.
orientations:
Quaternion orientations (w, x, y, z) in the world frame of the prims. Shape is (M, 4).
Defaults to :obj:`None`, which means left unchanged.
indices (Optional[Sequence[int]], optional): Indices to specify which alter poses.
Shape: (M,), where M <= total number of markers. Defaults to :obj:`None` (i.e: all markers).
indices: Indices to specify which alter poses.
Shape is (M,), where M <= total number of markers. Defaults to :obj:`None` (i.e: all markers).
"""
# resolve inputs
if positions is not None:
......@@ -160,13 +162,13 @@ class PointMarker:
self._instancer_manager.GetPositionsAttr().Set(self._gf_positions)
self._instancer_manager.GetOrientationsAttr().Set(self._gf_orientations)
def set_status(self, status: Union[List[int], np.ndarray, torch.Tensor], indices: Optional[Sequence[int]] = None):
def set_status(self, status: list[int] | np.ndarray | torch.Tensor, indices: Sequence[int] | None = None):
"""Updates the marker activated by the instance manager.
Args:
status (Union[List[int], np.ndarray, torch.Tensor]): Decides which prototype marker to visualize. Shape: (M)
indices (Optional[Sequence[int]], optional): Indices to specify which alter poses.
Shape: (M,), where M <= total number of markers. Defaults to :obj:`None` (i.e: all markers).
status: Decides which prototype marker to visualize. Shape is (M)
indices: Indices to specify which alter poses.
Shape is (M,), where M <= total number of markers. Defaults to :obj:`None` (i.e: all markers).
"""
# default values
if indices is None:
......
......@@ -5,9 +5,11 @@
"""A class to coordinate groups of visual markers (loaded from USD)."""
from __future__ import annotations
import numpy as np
import torch
from typing import Optional, Sequence, Tuple, Union
from typing import Sequence
import omni.isaac.core.utils.prims as prim_utils
import omni.isaac.core.utils.stage as stage_utils
......@@ -48,9 +50,9 @@ class StaticMarker:
self,
prim_path: str,
count: int,
usd_path: Optional[str] = None,
scale: Tuple[float, float, float] = (1.0, 1.0, 1.0),
color: Optional[Tuple[float, float, float]] = None,
usd_path: str | None = None,
scale: tuple[float, float, float] = (1.0, 1.0, 1.0),
color: tuple[float, float, float] | None = None,
):
"""Initialize the class.
......@@ -58,17 +60,16 @@ class StaticMarker:
and the marker prim is registered into it.
Args:
prim_path (str): The prim path where the PointInstancer will be created.
count (int): The number of marker duplicates to create.
usd_path (Optional[str], optional): The USD file path to the marker. Defaults to the USD path
for the RGB frame axis marker.
scale (Tuple[float, float, float], optional): The scale of the marker. Defaults to (1.0, 1.0, 1.0).
color (Optional[Tuple[float, float, float]], optional): The color of the marker.
If provided, it overrides the existing color on all the prims of the marker.
Defaults to None.
prim_path: The prim path where the PointInstancer will be created.
count: The number of marker duplicates to create.
usd_path: The USD file path to the marker. Defaults to the USD path for the RGB frame axis marker.
scale: The scale of the marker. Defaults to (1.0, 1.0, 1.0).
color: The color of the marker. If provided, it overrides the existing color on all the
prims of the marker. Defaults to None.
Raises:
ValueError: When a prim already exists at the :obj:`prim_path` and it is not a :class:`UsdGeom.PointInstancer`.
ValueError: When a prim already exists at the :obj:`prim_path` and it is not a
:class:`UsdGeom.PointInstancer`.
FileNotFoundError: When the USD file at :obj:`usd_path` does not exist.
"""
# resolve default markers in the UI elements
......@@ -133,7 +134,7 @@ class StaticMarker:
The method does this through the USD API.
Args:
visible (bool): flag to set the visibility.
visible: flag to set the visibility.
"""
imageable = UsdGeom.Imageable(self._instancer_manager)
if visible:
......@@ -143,20 +144,18 @@ class StaticMarker:
def set_world_poses(
self,
positions: Optional[Union[np.ndarray, torch.Tensor]] = None,
orientations: Optional[Union[np.ndarray, torch.Tensor]] = None,
indices: Optional[Sequence[int]] = None,
positions: np.ndarray | torch.Tensor | None = None,
orientations: np.ndarray | torch.Tensor | None = None,
indices: Sequence[int] | None = None,
):
"""Update marker poses in the simulation world frame.
Args:
positions (Optional[Union[np.ndarray, torch.Tensor]], optional):
Positions in the world frame. Shape: (M, 3). Defaults to :obj:`None`, which means left unchanged.
orientations (Optional[Union[np.ndarray, torch.Tensor]], optional):
Quaternion orientations (w, x, y, z) in the world frame of the prims. Shape: (M, 4).
positions: Positions in the world frame. Shape is (M, 3). Defaults to :obj:`None`, which means left unchanged.
orientations: Quaternion orientations (w, x, y, z) in the world frame of the prims. Shape is (M, 4).
Defaults to :obj:`None`, which means left unchanged.
indices (Optional[Sequence[int]], optional): Indices to specify which alter poses.
Shape: (M,), where M <= total number of markers. Defaults to :obj:`None` (i.e: all markers).
indices: Indices to specify which alter poses. Shape is ``(M,),`` where M <= total number of markers.
Defaults to :obj:`None` (i.e: all markers).
"""
# resolve inputs
if positions is not None:
......@@ -176,13 +175,13 @@ class StaticMarker:
self._instancer_manager.GetPositionsAttr().Set(self._gf_positions)
self._instancer_manager.GetOrientationsAttr().Set(self._gf_orientations)
def set_scales(self, scales: Union[np.ndarray, torch.Tensor], indices: Optional[Sequence[int]] = None):
def set_scales(self, scales: np.ndarray | torch.Tensor, indices: Sequence[int] | None = None):
"""Update marker poses in the simulation world frame.
Args:
scales (Union[np.ndarray, torch.Tensor]): Scale applied before any rotation is applied. Shape: (M, 3).
indices (Optional[Sequence[int]], optional): Indices to specify which alter poses.
Shape: (M,), where M <= total number of markers. Defaults to :obj:`None` (i.e: all markers).
scales: Scale applied before any rotation is applied. Shape is (M, 3).
indices: Indices to specify which alter poses.
Shape is (M,), where M <= total number of markers. Defaults to :obj:`None` (i.e: all markers).
"""
# default arguments
if indices is None:
......
......@@ -2,3 +2,5 @@
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
......@@ -7,6 +7,7 @@
Camera wrapper around USD camera prim to provide an interface that follows the robotics convention.
"""
from __future__ import annotations
from .camera import Camera, CameraData
from .camera_cfg import FisheyeCameraCfg, PinholeCameraCfg
......
......@@ -5,13 +5,14 @@
"""Camera class in Omniverse workflows."""
from __future__ import annotations
import builtins
import math
import numpy as np
import scipy.spatial.transform as tf
from dataclasses import dataclass
from typing import Any, Dict, Sequence, Tuple, Union
from typing import Any, Sequence
import omni.isaac.core.utils.prims as prim_utils
import omni.isaac.core.utils.stage as stage_utils
......@@ -41,9 +42,9 @@ class CameraData:
"""Quaternion orientation `(w, x, y, z)` of the sensor origin in world frame, following ROS convention."""
intrinsic_matrix: np.ndarray = None
"""The intrinsic matrix for the camera."""
image_shape: Tuple[int, int] = None
image_shape: tuple[int, int] = None
"""A tuple containing (height, width) of the camera sensor."""
output: Dict[str, Any] = None
output: dict[str, Any] = None
"""The retrieved sensor data with sensor types as key.
The format of the data is available in the `Replicator Documentation`_.
......@@ -86,15 +87,15 @@ class Camera(SensorBase):
"""
def __init__(self, cfg: Union[PinholeCameraCfg, FisheyeCameraCfg], device: str = "cpu"):
def __init__(self, cfg: PinholeCameraCfg | FisheyeCameraCfg, device: str = "cpu"):
"""Initializes the camera sensor.
If the ``device`` is ``"cpu"``, the output data is returned as a numpy array. If the ``device`` is
``"cuda"``, then a Warp array is returned. Note that only the valid sensor types will be moved to GPU.
Args:
cfg (Union[PinholeCameraCfg, FisheyeCameraCfg]): The configuration parameters.
device (str): The device on which to receive data. Defaults to "cpu".
cfg: The configuration parameters.
device: The device on which to receive data. Defaults to "cpu".
"""
# store inputs
self.cfg = cfg
......@@ -152,7 +153,7 @@ class Camera(SensorBase):
return self._data
@property
def image_shape(self) -> Tuple[int, int]:
def image_shape(self) -> tuple[int, int]:
"""A tuple containing (height, width) of the camera sensor."""
return (self.cfg.height, self.cfg.width)
......@@ -164,7 +165,7 @@ class Camera(SensorBase):
"""Set visibility of the instance in the scene.
Args:
visible (bool): Whether to make instance visible or invisible.
visible: Whether to make instance visible or invisible.
Raises:
RuntimeError: If the camera prim is not set. Need to call :meth:`initialize` first.
......@@ -198,8 +199,8 @@ class Camera(SensorBase):
is not true in the input intrinsic matrix, then the camera will not set up correctly.
Args:
intrinsic_matrix (np.ndarray): The intrinsic matrix for the camera.
focal_length (float, optional): Focal length to use when computing aperture values. Defaults to 1.0.
intrinsic_matrix: The intrinsic matrix for the camera.
focal_length: Focal length to use when computing aperture values. Defaults to 1.0.
"""
# convert to numpy for sanity
intrinsic_matrix = np.asarray(matrix, dtype=float)
......@@ -247,8 +248,8 @@ class Camera(SensorBase):
T_{ROS} = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & -1 & 0 & 0 \\ 0 & 0 & -1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} T_{USD}
Args:
pos (Sequence[float], optional): The cartesian coordinates (in meters). Defaults to None.
quat (Sequence[float], optional): The quaternion orientation in (w, x, y, z). Defaults to None.
pos: The cartesian coordinates (in meters). Defaults to None.
quat: The quaternion orientation in (w, x, y, z). Defaults to None.
Raises:
RuntimeError: If the camera prim is not set. Need to call :meth:`initialize` method first.
......@@ -276,8 +277,8 @@ class Camera(SensorBase):
"""Set the pose of the camera from the eye position and look-at target position.
Args:
eye (Sequence[float]): The position of the camera's eye.
target (Sequence[float], optional): The target location to look at. Defaults to [0, 0, 0].
eye: The position of the camera's eye.
target: The target location to look at. Defaults to [0, 0, 0].
Raises:
RuntimeError: If the camera prim is not set. Need to call :meth:`initialize` method first.
......@@ -332,9 +333,9 @@ class Camera(SensorBase):
translation and orientation.
Args:
parent_prim_path (str): The path of the parent prim to attach sensor to.
translation (Sequence[float], optional): The local position offset w.r.t. parent prim. Defaults to None.
orientation (Sequence[float], optional): The local rotation offset in ``(w, x, y, z)`` w.r.t.
parent_prim_path: The path of the parent prim to attach sensor to.
translation: The local position offset w.r.t. parent prim. Defaults to None.
orientation: The local rotation offset in ``(w, x, y, z)`` w.r.t.
parent prim. Defaults to None.
"""
# Check if sensor is already spawned
......@@ -363,8 +364,8 @@ class Camera(SensorBase):
the camera prim is used instead of the settings passed in the configuration object.
Args:
cam_prim_path (str, optional): The prim path to existing camera. Defaults to None.
has_rig (bool, optional): Whether the passed camera prim path is attached to a rig. Defaults to False.
cam_prim_path: The prim path to existing camera. Defaults to None.
has_rig: Whether the passed camera prim path is attached to a rig. Defaults to False.
Raises:
RuntimeError: When input `cam_prim_path` is :obj:`None`, the method defaults to using the last
......@@ -390,7 +391,7 @@ class Camera(SensorBase):
self.prim_path, resolution=(self.cfg.width, self.cfg.height)
)
# Attach the sensor data types to render node
self._rep_registry: Dict[str, rep.annotators.Annotator] = dict.fromkeys(self.cfg.data_types, None)
self._rep_registry: dict[str, rep.annotators.Annotator] = dict.fromkeys(self.cfg.data_types, None)
# -- iterate over each data type
for name in self.cfg.data_types:
# init params -- Checked from rep.scripts.writes_default.basic_writer.py
......@@ -511,7 +512,7 @@ class Camera(SensorBase):
The coordinates of points on the image plane are in the homogeneous representation.
Returns:
np.ndarray: A 3 x 3 numpy array containing the intrinsic parameters for the camera.
A 3 x 3 numpy array containing the intrinsic parameters for the camera.
Raises:
RuntimeError: If the camera prim is not set. Need to call :meth:`initialize` first.
......@@ -536,14 +537,14 @@ class Camera(SensorBase):
# return the matrix
return np.array([[a, 0, b], [0, c, d], [0, 0, 1]], dtype=float)
def _compute_ros_pose(self) -> Tuple[np.ndarray, np.ndarray]:
def _compute_ros_pose(self) -> tuple[np.ndarray, np.ndarray]:
"""Computes the pose of the camera in the world frame with ROS convention.
This methods uses the ROS convention to resolve the input pose. In this convention,
we assume that the camera front-axis is +Z-axis and up-axis is -Y-axis.
Returns:
Tuple[np.ndarray, np.ndarray]: A tuple of the position (in meters) and quaternion (w, x, y, z).
A tuple of the position (in meters) and quaternion (w, x, y, z).
"""
# get camera's location in world space
prim_tf = self._sensor_prim.ComputeLocalToWorldTransform(Usd.TimeCode.Default())
......
......@@ -5,9 +5,9 @@
"""Configuration for the camera sensor."""
from __future__ import annotations
from dataclasses import MISSING
from typing import List, Tuple
# omni-isaac-orbit
from omni.isaac.orbit.utils import configclass
......@@ -32,7 +32,7 @@ class PinholeCameraCfg:
* https://graphics.pixar.com/usd/docs/api/class_usd_geom_camera.html
"""
clipping_range: Tuple[float, float] = None
clipping_range: tuple[float, float] = None
"""Near and far clipping distances (in stage units)."""
focal_length: float = None
"""Perspective focal length (in mm). Longer lens lengths narrower FOV, shorter lens lengths wider FOV."""
......@@ -55,13 +55,13 @@ class PinholeCameraCfg:
sensor_tick: float = 0.0
"""Simulation seconds between sensor buffers. Defaults to 0.0."""
data_types: List[str] = ["rgb"]
data_types: list[str] = ["rgb"]
"""List of sensor names/types to enable for the camera. Defaults to ["rgb"]."""
width: int = MISSING
"""Width of the image in pixels."""
height: int = MISSING
"""Height of the image in pixels."""
semantic_types: List[str] = ["class"]
semantic_types: list[str] = ["class"]
"""List of allowed semantic types the types. Defaults to ["class"].
For example, if semantic types is [“class”], only the bounding boxes for prims with semantics of
......
......@@ -7,6 +7,8 @@
Height-scanner based on ray-casting operations using PhysX ray-caster.
"""
from __future__ import annotations
from .height_scanner import HeightScanner, HeightScannerData
from .height_scanner_cfg import HeightScannerCfg
......
......@@ -3,11 +3,12 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import numpy as np
import scipy.spatial.transform as tf
from dataclasses import dataclass
from typing import List, Sequence
from typing import Sequence
import omni
import omni.isaac.core.utils.prims as prim_utils
......@@ -73,7 +74,7 @@ class HeightScanner(SensorBase):
"""Initializes the scanner object.
Args:
cfg (HeightScannerCfg): The configuration parameters.
cfg: The configuration parameters.
"""
# TODO: Use generic range sensor from Isaac Sim?
# Reference: https://docs.omniverse.nvidia.com/app_isaacsim/app_isaacsim/ext_omni_isaac_range_sensor.html#isaac-sim-generic-range-sensor-example
......@@ -132,20 +133,20 @@ class HeightScanner(SensorBase):
"""Enables drawing of the scan points in the viewport.
Args:
visible (bool) -- Whether to draw scan points or not.
visible: Whether to draw scan points or not.
"""
# copy argument
self._visualize = visible
# set visibility
self._height_scanner_vis.set_visibility(visible)
def set_filter_prims(self, names: List[str]):
def set_filter_prims(self, names: list[str]):
"""Set the names of prims to ignore ray-casting collisions with.
If None is passed into argument, then no filtering is performed.
Args:
names (List[str]): A list of prim names to ignore ray-cast collisions with.
names: A list of prim names to ignore ray-cast collisions with.
"""
# default
if names is None:
......@@ -200,9 +201,9 @@ class HeightScanner(SensorBase):
"""Updates the buffers at sensor frequency.
Args:
dt (float): The simulation time-step.
pos (Sequence[float]): Position of the frame to which the sensor is attached.
quat (Sequence[float]): Quaternion (w, x, y, z) of the frame to which the sensor is attached.
dt: The simulation time-step.
pos: Position of the frame to which the sensor is attached.
quat: Quaternion (w, x, y, z) of the frame to which the sensor is attached.
"""
super().update(dt, pos, quat)
......@@ -214,8 +215,8 @@ class HeightScanner(SensorBase):
Otherwise, the hit distance is set to the maximum value specified in the configuration.
Args:
pos (Sequence[float]): Position of the frame to which the sensor is attached.
quat (Sequence[float]): Quaternion (w, x, y, z) of the frame to which the sensor is attached.
pos: Position of the frame to which the sensor is attached.
quat: Quaternion (w, x, y, z) of the frame to which the sensor is attached.
"""
# convert to numpy for sanity
pos = np.asarray(pos)
......@@ -266,7 +267,7 @@ class HeightScanner(SensorBase):
"""A PhysX callback to filter out hit-reports that are on the collision bodies.
Returns:
bool: If True, continue casting the ray. Otherwise, stop and report the result.
If True, continue casting the ray. Otherwise, stop and report the result.
"""
# unset the query info
self._query_info = None
......
......@@ -5,9 +5,9 @@
"""Configuration for the height scanner sensor."""
from __future__ import annotations
from dataclasses import MISSING
from typing import List, Tuple
# omni-isaac-orbit
from omni.isaac.orbit.utils import configclass
......@@ -21,11 +21,11 @@ class HeightScannerCfg:
"""Simulation seconds between sensor buffers. Defaults to 0.0."""
points: list = MISSING
"""The 2D scan points to query ray-casting from. Results are reported in this order."""
offset: Tuple[float, float, float] = (0.0, 0.0, 0.0)
offset: tuple[float, float, float] = (0.0, 0.0, 0.0)
"""The offset from the frame the sensor is attached to. Defaults to (0.0, 0.0, 0.0)."""
direction: Tuple[float, float, float] = (0.0, 0.0, -1.0)
direction: tuple[float, float, float] = (0.0, 0.0, -1.0)
"""Unit direction for the scanner ray-casting. Defaults to (0.0, 0.0, -1.0)."""
max_distance: float = 100.0
"""Maximum distance from the sensor to ray cast to. Defaults to 100.0."""
filter_prims: List[str] = list()
filter_prims: list[str] = list()
"""A list of prim names to ignore ray-cast collisions with. Defaults to empty list."""
......@@ -6,9 +6,11 @@
"""Helper class to handle visual sphere markers to show ray-casting of height scanner."""
from __future__ import annotations
import numpy as np
import torch
from typing import List, Optional, Sequence, Union
from typing import Sequence
import omni.isaac.core.utils.prims as prim_utils
import omni.isaac.core.utils.stage as stage_utils
......@@ -34,9 +36,9 @@ class HeightScannerMarker:
"""Initialize the class.
Args:
prim_path (str): The prim path of the point instancer.
count (int): The number of markers to create.
radius (float, optional): The radius of the spherical markers. Defaults to 1.0.
prim_path: The prim path of the point instancer.
count: The number of markers to create.
radius: The radius of the spherical markers. Defaults to 1.0.
Raises:
ValueError: When a prim at the given path exists but is not a valid point instancer.
......@@ -96,7 +98,7 @@ class HeightScannerMarker:
The method does this through the USD API.
Args:
visible (bool): flag to set the visibility.
visible: flag to set the visibility.
"""
imageable = UsdGeom.Imageable(self._instancer_manager)
if visible:
......@@ -106,20 +108,20 @@ class HeightScannerMarker:
def set_world_poses(
self,
positions: Optional[Union[np.ndarray, torch.Tensor]] = None,
orientations: Optional[Union[np.ndarray, torch.Tensor]] = None,
indices: Optional[Sequence[int]] = None,
positions: np.ndarray | torch.Tensor | None = None,
orientations: np.ndarray | torch.Tensor | None = None,
indices: Sequence[int] | None = None,
):
"""Update marker poses in the simulation world frame.
Args:
positions (Optional[Union[np.ndarray, torch.Tensor]], optional):
Positions in the world frame. Shape: (M, 3). Defaults to :obj:`None`, which means left unchanged.
orientations (Optional[Union[np.ndarray, torch.Tensor]], optional):
Quaternion orientations (w, x, y, z) in the world frame of the prims. Shape: (M, 4).
positions:
Positions in the world frame. Shape is (M, 3). Defaults to :obj:`None`, which means left unchanged.
orientations:
Quaternion orientations (w, x, y, z) in the world frame of the prims. Shape is (M, 4).
Defaults to :obj:`None`, which means left unchanged.
indices (Optional[Sequence[int]], optional): Indices to specify which alter poses.
Shape: (M,), where M <= total number of markers. Defaults to :obj:`None` (i.e: all markers).
indices: Indices to specify which alter poses.
Shape is (M,), where M <= total number of markers. Defaults to :obj:`None` (i.e: all markers).
"""
# resolve inputs
if positions is not None:
......@@ -139,13 +141,13 @@ class HeightScannerMarker:
self._instancer_manager.GetPositionsAttr().Set(self._gf_positions)
self._instancer_manager.GetOrientationsAttr().Set(self._gf_orientations)
def set_status(self, status: Union[List[int], np.ndarray, torch.Tensor], indices: Optional[Sequence[int]] = None):
def set_status(self, status: list[int] | np.ndarray | torch.Tensor, indices: Sequence[int] | None = None):
"""Updates the marker activated by the instance manager.
Args:
status (Union[List[int], np.ndarray, torch.Tensor]): Decides which prototype marker to visualize. Shape: (M)
indices (Optional[Sequence[int]], optional): Indices to specify which alter poses.
Shape: (M,), where M <= total number of markers. Defaults to :obj:`None` (i.e: all markers).
status: Decides which prototype marker to visualize. Shape is (M)
indices: Indices to specify which alter poses. Shape is (M,), where M <= total number of markers.
Defaults to :obj:`None` (i.e: all markers).
"""
# default values
if indices is None:
......
......@@ -5,17 +5,17 @@
"""Utilities to create and visualize 2D height-maps."""
from __future__ import annotations
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.axes import Axes
from matplotlib.image import AxesImage
from typing import Tuple
__all__ = ["create_points_from_grid", "plot_height_grid"]
def create_points_from_grid(size: Tuple[float, float], resolution: float) -> np.ndarray:
def create_points_from_grid(size: tuple[float, float], resolution: float) -> np.ndarray:
"""Creates a list of points from 2D mesh-grid.
The terrain scan is approximated with a grid map of the input resolution.
......@@ -36,11 +36,11 @@ def create_points_from_grid(size: Tuple[float, float], resolution: float) -> np.
]
Args:
size (Tuple[float, float]): The 2D scan region along x and y directions (in meters).
resolution (float): The resolution of the scanner (in meters/cell).
size: The 2D scan region along x and y directions (in meters).
resolution: The resolution of the scanner (in meters/cell).
Returns:
np.ndarray: A set of points of shape (N, 2) or (N, 3), where first x is fixed while y changes.
A set of points of shape (N, 2) or (N, 3), where first x is fixed while y changes.
"""
# Compute the scan grid
# Note: np.arange does not include end-point when dealing with floats. That is why we add resolution.
......@@ -52,7 +52,7 @@ def create_points_from_grid(size: Tuple[float, float], resolution: float) -> np.
def plot_height_grid(
hit_distance: np.ndarray, size: Tuple[float, float], resolution: float, ax: Axes = None
hit_distance: np.ndarray, size: tuple[float, float], resolution: float, ax: Axes = None
) -> AxesImage:
"""Plots the sensor height-map distances using matplotlib.
......@@ -63,13 +63,13 @@ def plot_height_grid(
:meth:`create_points_from_grid` method.
Args:
hit_distance (dict): The ray hit distance measured from the sensor.
size (Tuple[float, float]): The 2D scan region along x and y directions (in meters).
resolution (float): The resolution of the scanner (in meters/cell).
ax (Axes, optional): The current matplotlib axes to plot in.. Defaults to None.
hit_distance: The ray hit distance measured from the sensor.
size: The 2D scan region along x and y directions (in meters).
resolution: The resolution of the scanner (in meters/cell).
ax: The current matplotlib axes to plot in.. Defaults to None.
Returns:
AxesImage: Image axes of the created plot.
Image axes of the created plot.
"""
# Check that request of keys has same length as available axes.
if ax is None:
......
......@@ -9,6 +9,7 @@ This class defines an interface for sensors similar to how the :class:`omni.isaa
Each sensor class should inherit from this class and implement the abstract methods.
"""
from __future__ import annotations
from abc import abstractmethod
from typing import Any
......@@ -31,7 +32,7 @@ class SensorBase:
buffers are filled at every simulation step.
Args:
sensor_tick (float, optional): Simulation seconds between sensor buffers. Defaults to 0.0.
sensor_tick: Simulation seconds between sensor buffers. Defaults to 0.0.
"""
# print warning to notify user that the sensor is not vectorized
carb.log_warn("This implementation of the sensor is not vectorized yet. Please use the vectorized version.")
......@@ -85,7 +86,7 @@ class SensorBase:
overriding this method is optional.
Args:
visible (bool) -- Whether to make instance visible or invisible.
visible: Whether to make instance visible or invisible.
"""
pass
......@@ -98,7 +99,7 @@ class SensorBase:
"""Spawns the sensor into the stage.
Args:
parent_prim_path (str): The path of the parent prim to attach sensor to.
parent_prim_path: The path of the parent prim to attach sensor to.
"""
raise NotImplementedError
......@@ -123,9 +124,9 @@ class SensorBase:
not be called directly.
Args:
dt (float): The simulation time-step.
args (tuple): Other positional arguments passed to function :meth:`buffer()`.
kwargs (dict): Other keyword arguments passed to function :meth:`buffer()`.
dt: The simulation time-step.
args: Other positional arguments passed to function :meth:`buffer()`.
kwargs: Other keyword arguments passed to function :meth:`buffer()`.
"""
# Get current time
self._timestamp += dt
......
......@@ -3,6 +3,8 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
from .configclass import configclass
__all__ = [
......
......@@ -5,10 +5,11 @@
"""Wrapper around the Python 3.7 onwards `dataclasses` module."""
from __future__ import annotations
from copy import deepcopy
from dataclasses import Field, dataclass, field
from typing import Any, Callable, ClassVar, Dict
from typing import Any, Callable, ClassVar
from omni.isaac.orbit.utils.dict import class_to_dict, update_class_from_dict
......@@ -88,22 +89,22 @@ These are redefined here to add new docstrings.
"""
def _class_to_dict(obj: object) -> Dict[str, Any]:
def _class_to_dict(obj: object) -> dict[str, Any]:
"""Convert an object into dictionary recursively.
Returns:
Dict[str, Any]: Converted dictionary mapping.
Converted dictionary mapping.
"""
return class_to_dict(obj)
def _update_class_from_dict(obj, data: Dict[str, Any]) -> None:
def _update_class_from_dict(obj, data: dict[str, Any]) -> None:
"""Reads a dictionary and sets object variables recursively.
This function performs in-place update of the class member attributes.
Args:
data (Dict[str, Any]): Input (nested) dictionary to update from.
data: Input (nested) dictionary to update from.
Raises:
TypeError: When input is not a dictionary.
......
......@@ -5,6 +5,8 @@
"""This sub-module introduces the base managers for defining MDPs."""
from __future__ import annotations
from .observation_manager import ObservationManager
from .reward_manager import RewardManager
......
......@@ -6,12 +6,14 @@
"""Observation manager for computing observation signals for a given world."""
from __future__ import annotations
import copy
import functools
import inspect
import torch
from prettytable import PrettyTable
from typing import Any, Callable, Dict, Sequence, Tuple
from typing import Any, Callable, Sequence
class ObservationManager:
......@@ -137,14 +139,14 @@ class ObservationManager:
"""
def __init__(self, cfg: Dict[str, Dict[str, Any]], env, device: str):
def __init__(self, cfg: dict[str, dict[str, Any]], env, device: str):
"""Initialize observation manager.
Args:
cfg (Dict[str, Dict[str, Any]]): A dictionary of configuration settings for each group.
env (_type_): The object instance (typically the environment) from which data is read to
cfg: A dictionary of configuration settings for each group.
env: The object instance (typically the environment) from which data is read to
compute the observation terms.
device (str): The computation device for observations.
device: The computation device for observations.
"""
# store input
self._cfg = copy.deepcopy(cfg)
......@@ -155,7 +157,7 @@ class ObservationManager:
# parse config to create observation terms information
self._prepare_observation_terms()
# compute combined vector for obs group
self._group_obs_dim: Dict[str, Tuple[int, ...]] = dict()
self._group_obs_dim: dict[str, tuple[int, ...]] = dict()
for group_name, group_term_dims in self._group_obs_term_dim.items():
term_dims = [torch.tensor(dims, device="cpu") for dims in group_term_dims]
self._group_obs_dim[group_name] = tuple(torch.sum(torch.stack(term_dims, dim=0), dim=0).tolist())
......@@ -207,12 +209,12 @@ class ObservationManager:
return self._device
@property
def active_terms(self) -> Dict[str, Sequence[str]]:
def active_terms(self) -> dict[str, Sequence[str]]:
"""Name of active observation terms in each group."""
return self._group_obs_term_names
@property
def group_obs_dim(self) -> Dict[str, Tuple[int, ...]]:
def group_obs_dim(self) -> dict[str, tuple[int, ...]]:
"""Shape of observation tensor in each group."""
return self._group_obs_dim
......@@ -224,12 +226,12 @@ class ObservationManager:
"""Reset the terms computation for input environment indices.
Args:
env_ids (torch.Tensor): Indices of environment instances to reset.
env_ids: Indices of environment instances to reset.
"""
# Might need this when dealing with history and delays.
pass
def compute(self) -> Dict[str, torch.Tensor]:
def compute(self) -> dict[str, torch.Tensor]:
"""Compute the observations per group.
The method computes the observations for each group and returns a dictionary with keys as
......@@ -245,7 +247,7 @@ class ObservationManager:
settings. By default, no scaling or clipping is applied.
Returns:
Dict[str, torch.Tensor]: A dictionary with keys as the group names and values as the
A dictionary with keys as the group names and values as the
computed observations.
"""
self._obs_buffer = dict()
......@@ -315,13 +317,13 @@ class ObservationManager:
"""
# create buffers to store information for each observation group
# TODO: Make this more convenient by using data structures.
self._group_obs_term_names: Dict[str, Sequence[str]] = dict()
self._group_obs_term_dim: Dict[str, Sequence[int]] = dict()
self._group_obs_term_params: Dict[str, Sequence[Dict[str, float]]] = dict()
self._group_obs_term_clip_ranges: Dict[str, Sequence[Tuple[float, float]]] = dict()
self._group_obs_term_scales: Dict[str, Sequence[float]] = dict()
self._group_obs_term_corruptors: Dict[str, Sequence[Callable]] = dict()
self._group_obs_term_functions: Dict[str, Sequence[Callable]] = dict()
self._group_obs_term_names: dict[str, Sequence[str]] = dict()
self._group_obs_term_dim: dict[str, Sequence[int]] = dict()
self._group_obs_term_params: dict[str, Sequence[dict[str, float]]] = dict()
self._group_obs_term_clip_ranges: dict[str, Sequence[tuple[float, float]]] = dict()
self._group_obs_term_scales: dict[str, Sequence[float]] = dict()
self._group_obs_term_corruptors: dict[str, Sequence[Callable]] = dict()
self._group_obs_term_functions: dict[str, Sequence[Callable]] = dict()
for group_name, group_cfg in self._cfg.items():
# skip non-group settings (those should be read above)
......
......@@ -6,11 +6,13 @@
"""Reward manager for computing reward signals for a given world."""
from __future__ import annotations
import copy
import inspect
import torch
from prettytable import PrettyTable
from typing import Any, Dict, List, Optional
from typing import Any
class RewardManager:
......@@ -94,15 +96,15 @@ class RewardManager:
"""
def __init__(self, cfg: Dict[str, Dict[str, Any]], env, num_envs: int, dt: float, device: str):
def __init__(self, cfg: dict[str, dict[str, Any]], env, num_envs: int, dt: float, device: str):
"""Construct a list of reward functions which are used to compute the total reward.
Args:
cfg (Dict[str, Dict[str, Any]]): Configuration for reward terms.
env (IsaacEnv): A world instance used for accessing state.
num_envs (int): Number of environment instances.
dt (float): The time-stepping for the environment.
device (int): The device on which create buffers.
cfg: Configuration for reward terms.
env: A world instance used for accessing state.
num_envs: Number of environment instances.
dt: The time-stepping for the environment.
device: The device on which create buffers.
"""
# store input
self._cfg = copy.deepcopy(cfg)
......@@ -154,12 +156,12 @@ class RewardManager:
return self._device
@property
def active_terms(self) -> List[str]:
def active_terms(self) -> list[str]:
"""Name of active reward terms."""
return self._reward_term_names
@property
def episode_sums(self) -> Dict[str, torch.Tensor]:
def episode_sums(self) -> dict[str, torch.Tensor]:
"""Contains the current episodic sum of individual reward terms."""
return self._episode_sums
......@@ -167,15 +169,15 @@ class RewardManager:
Operations.
"""
def reset_idx(self, env_ids: torch.Tensor, episodic_extras: Optional[dict] = None):
def reset_idx(self, env_ids: torch.Tensor, episodic_extras: dict | None = None):
"""Reset the reward terms computation for input environment indices.
If `episodic_extras` is not None, then the collected sum of individual reward terms is stored
in the dictionary. This is useful for logging episodic information.
Args:
env_ids (torch.Tensor): Indices of environment instances to reset.
episodic_extras (Optional[dict], optional): Dictionary to store episodic information.
env_ids: Indices of environment instances to reset.
episodic_extras: Dictionary to store episodic information.
Defaults to None.
"""
if episodic_extras is None:
......@@ -200,7 +202,7 @@ class RewardManager:
reward signal. It also updates the episodic sums corresponding to individual reward terms.
Returns:
torch.Tensor: The net reward signal of shape (num_envs,).
The net reward signal of shape (num_envs,).
"""
# reset computation
self._reward_buf[:] = 0.0
......
......@@ -3,6 +3,8 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
# enable motion generation extension
from omni.isaac.core.utils.extensions import enable_extension
......
......@@ -2,3 +2,5 @@
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
......@@ -3,6 +3,8 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import os
from omni.isaac.core.utils.extensions import get_extension_path_from_name
......
......@@ -3,9 +3,10 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import torch
from dataclasses import MISSING
from typing import Dict, Optional, Tuple
from omni.isaac.orbit.utils import configclass
from omni.isaac.orbit.utils.math import (
......@@ -27,7 +28,7 @@ class DifferentialInverseKinematicsCfg:
ik_method: str = MISSING
"""Method for computing inverse of Jacobian: "pinv", "svd", "trans", "dls"."""
ik_params: Optional[Dict[str, float]] = None
ik_params: dict[str, float] | None = None
"""Parameters for the inverse-kinematics method. (default: obj:`None`).
- Moore-Penrose pseudo-inverse ("pinv"):
......@@ -41,14 +42,14 @@ class DifferentialInverseKinematicsCfg:
- "lambda_val": Damping coefficient (default: 0.1).
"""
position_offset: Tuple[float, float, float] = (0.0, 0.0, 0.0)
position_offset: tuple[float, float, float] = (0.0, 0.0, 0.0)
"""Position offset from parent body to end-effector frame in parent body frame."""
rotation_offset: Tuple[float, float, float, float] = (1.0, 0.0, 0.0, 0.0)
rotation_offset: tuple[float, float, float, float] = (1.0, 0.0, 0.0, 0.0)
"""Rotational offset from parent body to end-effector frame in parent body frame."""
position_command_scale: Tuple[float, float, float] = (1.0, 1.0, 1.0)
position_command_scale: tuple[float, float, float] = (1.0, 1.0, 1.0)
"""Scaling of the position command received. Used only in relative mode."""
rotation_command_scale: Tuple[float, float, float] = (1.0, 1.0, 1.0)
rotation_command_scale: tuple[float, float, float] = (1.0, 1.0, 1.0)
"""Scaling of the rotation command received. Used only in relative mode."""
......@@ -84,9 +85,9 @@ class DifferentialInverseKinematics:
"""Initialize the controller.
Args:
cfg (DifferentialInverseKinematicsCfg): The configuration for the controller.
num_robots (int): The number of robots to control.
device (str): The device to use for computations.
cfg: The configuration for the controller.
num_robots: The number of robots to control.
device: The device to use for computations.
Raises:
ValueError: When configured IK-method is not supported.
......@@ -174,7 +175,7 @@ class DifferentialInverseKinematics:
"""Performs inference with the controller.
Returns:
torch.Tensor: The target joint positions commands.
The target joint positions commands.
"""
# compute the desired end-effector pose
if "position_rel" in self.cfg.command_type:
......@@ -236,11 +237,11 @@ class DifferentialInverseKinematics:
position.
Args:
delta_pose (torch.Tensor): The desired delta pose in shape [N, 3 or 6].
jacobian (torch.Tensor): The geometric jacobian matrix in shape [N, 3 or 6, num-dof]
delta_pose: The desired delta pose in shape (N, 3) or (N, 6).
jacobian: The geometric jacobian matrix in shape (N, 3, num-dof) or (N, 6, num-dof).
Returns:
torch.Tensor: The desired delta in joint space.
The desired delta in joint space.
"""
if self.cfg.ik_method == "pinv": # Jacobian pseudo-inverse
# parameters
......
......@@ -3,9 +3,11 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import torch
from dataclasses import MISSING
from typing import Optional, Sequence, Tuple, Union
from typing import Sequence
from omni.isaac.orbit.utils import configclass
......@@ -17,7 +19,7 @@ class JointImpedanceControllerCfg:
command_type: str = "p_abs"
"""Type of command: p_abs (absolute) or p_rel (relative)."""
dof_pos_offset: Optional[Sequence[float]] = None
dof_pos_offset: Sequence[float] | None = None
"""Offset to DOF position command given to controller. (default: :obj:`None`).
If :obj:`None` then position offsets are set to zero.
......@@ -32,10 +34,10 @@ class JointImpedanceControllerCfg:
gravity_compensation: bool = False
"""Whether to perform gravity compensation."""
stiffness: Union[float, Sequence[float]] = MISSING
stiffness: float | Sequence[float] = MISSING
"""The positional gain for determining desired torques based on joint position error."""
damping_ratio: Optional[Union[float, Sequence[float]]] = None
damping_ratio: float | Sequence[float] | None = None
"""The damping ratio is used in-conjunction with positional gain to compute desired torques
based on joint velocity error.
......@@ -43,13 +45,13 @@ class JointImpedanceControllerCfg:
:math:`d_gains = 2 * sqrt(p_gains) * damping_ratio`.
"""
stiffness_limits: Tuple[float, float] = (0, 300)
stiffness_limits: tuple[float, float] = (0, 300)
"""Minimum and maximum values for positional gains.
Note: Used only when :obj:`impedance_mode` is "variable" or "variable_kp".
"""
damping_ratio_limits: Tuple[float, float] = (0, 100)
damping_ratio_limits: tuple[float, float] = (0, 100)
"""Minimum and maximum values for damping ratios used to compute velocity gains.
Note: Used only when :obj:`impedance_mode` is "variable".
......@@ -67,11 +69,11 @@ class JointImpedanceController:
"""Initialize joint impedance controller.
Args:
cfg (JointImpedanceControllerCfg): The configuration for the controller.
num_robots (int): The number of robots to control.
dof_pos_limits (torch.Tensor): The joint position limits for each robot. This is a tensor of shape
cfg: The configuration for the controller.
num_robots: The number of robots to control.
dof_pos_limits: The joint position limits for each robot. This is a tensor of shape
(num_robots, num_dof, 2) where the last dimension contains the lower and upper limits.
device (str): The device to use for computations.
device: The device to use for computations.
Raises:
ValueError: When the shape of :obj:`dof_pos_limits` is not (num_robots, num_dof, 2).
......@@ -146,7 +148,7 @@ class JointImpedanceController:
"""Set target end-effector pose command.
Args:
command (torch.Tensor): The command to set. This is a tensor of shape (num_robots, num_actions) where
command: The command to set. This is a tensor of shape (num_robots, num_actions) where
:obj:`num_actions` is the dimension of the action space of the controller.
"""
# check input size
......@@ -184,22 +186,22 @@ class JointImpedanceController:
self,
dof_pos: torch.Tensor,
dof_vel: torch.Tensor,
mass_matrix: Optional[torch.Tensor] = None,
gravity: Optional[torch.Tensor] = None,
mass_matrix: torch.Tensor | None = None,
gravity: torch.Tensor | None = None,
) -> torch.Tensor:
"""Performs inference with the controller.
Args:
dof_pos (torch.Tensor): The current joint positions.
dof_vel (torch.Tensor): The current joint velocities.
mass_matrix (Optional[torch.Tensor], optional): The joint-space inertial matrix. Defaults to None.
gravity (Optional[torch.Tensor], optional): The joint-space gravity vector. Defaults to None.
dof_pos: The current joint positions.
dof_vel: The current joint velocities.
mass_matrix: The joint-space inertial matrix. Defaults to None.
gravity: The joint-space gravity vector. Defaults to None.
Raises:
ValueError: When the command type is invalid.
Returns:
torch.Tensor: The target joint torques commands.
The target joint torques commands.
"""
# resolve the command type
if self.cfg.command_type == "p_abs":
......
......@@ -3,9 +3,11 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import torch
from dataclasses import MISSING
from typing import Optional, Sequence, Tuple, Union
from typing import Sequence
from omni.isaac.orbit.utils import configclass
from omni.isaac.orbit.utils.math import apply_delta_pose, compute_pose_error
......@@ -40,10 +42,10 @@ class OperationSpaceControllerCfg:
gravity_compensation: bool = False
"""Whether to perform gravity compensation."""
stiffness: Union[float, Sequence[float]] = MISSING
stiffness: float | Sequence[float] = MISSING
"""The positional gain for determining wrenches based on task-space pose error."""
damping_ratio: Optional[Union[float, Sequence[float]]] = None
damping_ratio: float | Sequence[float] | None = None
"""The damping ratio is used in-conjunction with positional gain to compute wrenches
based on task-space velocity error.
......@@ -51,27 +53,27 @@ class OperationSpaceControllerCfg:
:math:`d_gains = 2 * sqrt(p_gains) * damping_ratio`.
"""
stiffness_limits: Tuple[float, float] = (0, 300)
stiffness_limits: tuple[float, float] = (0, 300)
"""Minimum and maximum values for positional gains.
Note: Used only when :obj:`impedance_mode` is "variable" or "variable_kp".
"""
damping_ratio_limits: Tuple[float, float] = (0, 100)
damping_ratio_limits: tuple[float, float] = (0, 100)
"""Minimum and maximum values for damping ratios used to compute velocity gains.
Note: Used only when :obj:`impedance_mode` is "variable".
"""
force_stiffness: Union[float, Sequence[float]] = None
force_stiffness: float | Sequence[float] = None
"""The positional gain for determining wrenches for closed-loop force control.
If obj:`None`, then open-loop control of desired forces is performed.
"""
position_command_scale: Tuple[float, float, float] = (1.0, 1.0, 1.0)
position_command_scale: tuple[float, float, float] = (1.0, 1.0, 1.0)
"""Scaling of the position command received. Used only in relative mode."""
rotation_command_scale: Tuple[float, float, float] = (1.0, 1.0, 1.0)
rotation_command_scale: tuple[float, float, float] = (1.0, 1.0, 1.0)
"""Scaling of the rotation command received. Used only in relative mode."""
......@@ -86,10 +88,10 @@ class OperationSpaceController:
"""Initialize operation-space controller.
Args:
cfg (OperationSpaceControllerCfg): The configuration for operation-space controller.
num_robots (int): The number of robots to control.
num_dof (int): The number of degrees of freedom of the robot.
device (str): The device to use for computations.
cfg: The configuration for operation-space controller.
num_robots: The number of robots to control.
num_dof: The number of degrees of freedom of the robot.
device: The device to use for computations.
Raises:
ValueError: When invalid control command is provided.
......@@ -189,7 +191,7 @@ class OperationSpaceController:
"""Set target end-effector pose or force command.
Args:
command (torch.Tensor): The target end-effector pose or force command.
command: The target end-effector pose or force command.
"""
# check input size
if command.shape != (self.num_robots, self.num_actions):
......@@ -225,24 +227,24 @@ class OperationSpaceController:
def compute(
self,
jacobian: torch.Tensor,
ee_pose: Optional[torch.Tensor] = None,
ee_vel: Optional[torch.Tensor] = None,
ee_force: Optional[torch.Tensor] = None,
mass_matrix: Optional[torch.Tensor] = None,
gravity: Optional[torch.Tensor] = None,
ee_pose: torch.Tensor | None = None,
ee_vel: torch.Tensor | None = None,
ee_force: torch.Tensor | None = None,
mass_matrix: torch.Tensor | None = None,
gravity: torch.Tensor | None = None,
) -> torch.Tensor:
"""Performs inference with the controller.
Args:
jacobian (torch.Tensor): The Jacobian matrix of the end-effector.
ee_pose (Optional[torch.Tensor], optional): The current end-effector pose. It is a tensor of shape
jacobian: The Jacobian matrix of the end-effector.
ee_pose: The current end-effector pose. It is a tensor of shape
(num_robots, 7), which contains the position and quaternion ``(w, x, y, z)``. Defaults to None.
ee_vel (Optional[torch.Tensor], optional): The current end-effector velocity. It is a tensor of shape
ee_vel: The current end-effector velocity. It is a tensor of shape
(num_robots, 6), which contains the linear and angular velocities. Defaults to None.
ee_force (Optional[torch.Tensor], optional): The current external force on the end-effector.
ee_force: The current external force on the end-effector.
It is a tensor of shape (num_robots, 3), which contains the linear force. Defaults to None.
mass_matrix (Optional[torch.Tensor], optional): The joint-space inertial matrix. Defaults to None.
gravity (Optional[torch.Tensor], optional): The joint-space gravity vector. Defaults to None.
mass_matrix: The joint-space inertial matrix. Defaults to None.
gravity: The joint-space gravity vector. Defaults to None.
Raises:
ValueError: When the end-effector pose is not provided for the 'position_rel' command.
......@@ -255,7 +257,7 @@ class OperationSpaceController:
ValueError: When gravity compensation is enabled but the gravity vector is not provided.
Returns:
torch.Tensor: The target joint torques commands.
The target joint torques commands.
"""
# buffers for motion/force control
desired_ee_pos = None
......
......@@ -3,9 +3,10 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import torch
from dataclasses import MISSING
from typing import Tuple
import omni.isaac.core.utils.prims as prim_utils
from omni.isaac.core.articulations import Articulation
......@@ -43,8 +44,8 @@ class RmpFlowController:
"""Initialize the controller.
Args:
cfg (RmpFlowControllerCfg): The configuration for the controller.
device (str): The device to use for computation.
cfg: The configuration for the controller.
device: The device to use for computation.
"""
# store input
self.cfg = cfg
......@@ -69,7 +70,7 @@ class RmpFlowController:
"""Initialize the controller.
Args:
prim_paths_expr (str): The expression to find the articulation prim paths.
prim_paths_expr: The expression to find the articulation prim paths.
"""
# obtain the simulation time
physics_dt = SimulationContext.instance().get_physics_dt()
......@@ -125,11 +126,11 @@ class RmpFlowController:
# store command
self._command[:] = command
def compute(self) -> Tuple[torch.Tensor, torch.Tensor]:
def compute(self) -> tuple[torch.Tensor, torch.Tensor]:
"""Performs inference with the controller.
Returns:
Tuple[torch.Tensor, torch.Tensor]: The target joint positions and velocity commands.
The target joint positions and velocity commands.
"""
# convert command to numpy
command = self._command.cpu().numpy()
......
......@@ -71,6 +71,8 @@ Example usage showing the keyboard interface:
"""
from __future__ import annotations
from .gamepad import Se2Gamepad, Se3Gamepad
from .keyboard import Se2Keyboard, Se3Keyboard
from .spacemouse import Se2SpaceMouse, Se3SpaceMouse
......
......@@ -5,6 +5,7 @@
"""Base class for teleoperation interface."""
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Any, Callable
......@@ -35,8 +36,8 @@ class DeviceBase(ABC):
"""Add additional functions to bind keyboard.
Args:
key (Any): The button to check against.
func (Callable): The function to call when key is pressed. The callback function should not
key: The button to check against.
func: The function to call when key is pressed. The callback function should not
take any arguments.
"""
raise NotImplementedError
......@@ -46,6 +47,6 @@ class DeviceBase(ABC):
"""Provides the joystick event state.
Returns:
Any: The processed output form the joystick.
The processed output form the joystick.
"""
raise NotImplementedError
......@@ -5,6 +5,8 @@
"""Gamepad device for SE(2) and SE(3) control."""
from __future__ import annotations
from .se2_gamepad import Se2Gamepad
from .se3_gamepad import Se3Gamepad
......
......@@ -5,6 +5,7 @@
"""Gamepad controller for SE(2) control."""
from __future__ import annotations
import numpy as np
from typing import Callable
......@@ -49,10 +50,10 @@ class Se2Gamepad(DeviceBase):
"""Initialize the gamepad layer.
Args:
v_x_sensitivity (float): Magnitude of linear velocity along x-direction scaling. Defaults to 1.0.
v_y_sensitivity (float): Magnitude of linear velocity along y-direction scaling. Defaults to 1.0.
omega_z_sensitivity (float): Magnitude of angular velocity along z-direction scaling. Defaults to 1.0.
dead_zone (float): Magnitude of dead zone for gamepad. An event value from the gamepad less than
v_x_sensitivity: Magnitude of linear velocity along x-direction scaling. Defaults to 1.0.
v_y_sensitivity: Magnitude of linear velocity along y-direction scaling. Defaults to 1.0.
omega_z_sensitivity: Magnitude of angular velocity along z-direction scaling. Defaults to 1.0.
dead_zone: Magnitude of dead zone for gamepad. An event value from the gamepad less than
this value will be ignored. Defaults to 0.01.
"""
# turn off simulator gamepad control
......@@ -110,8 +111,8 @@ class Se2Gamepad(DeviceBase):
`carb documentation <https://docs.omniverse.nvidia.com/kit/docs/carbonite/latest/docs/python/carb.html#carb.input.GamepadInput>`__.
Args:
key (carb.input.GamepadInput): The gamepad button to check against.
func (Callable): The function to call when key is pressed. The callback function should not
key: The gamepad button to check against.
func: The function to call when key is pressed. The callback function should not
take any arguments.
"""
self._additional_callbacks[key] = func
......@@ -120,7 +121,7 @@ class Se2Gamepad(DeviceBase):
"""Provides the result from gamepad event state.
Returns:
np.ndarray: A 3D array containing the linear (x,y) and angular velocity (z).
A 3D array containing the linear (x,y) and angular velocity (z).
"""
return self._resolve_command_buffer(self._base_command_raw)
......@@ -174,13 +175,13 @@ class Se2Gamepad(DeviceBase):
"""Resolves the command buffer.
Args:
raw_command (np.ndarray): The raw command from the gamepad. Shape: (2, 3)
raw_command: The raw command from the gamepad. Shape is (2, 3)
This is a 2D array since gamepad dpad/stick returns two values corresponding to
the positive and negative direction. The first index is the direction (0: positive, 1: negative)
and the second index is value (absolute) of the command.
Returns:
np.ndarray: resolved command. Shape: (3,)
Resolved command. Shape is (3,)
"""
# compare the positive and negative value decide the sign of the value
# if the positive value is larger, the sign is positive (i.e. False, 0)
......
......@@ -51,9 +51,9 @@ class Se3Gamepad(DeviceBase):
"""Initialize the gamepad layer.
Args:
pos_sensitivity (float): Magnitude of input position command scaling. Defaults to 1.0.
rot_sensitivity (float): Magnitude of scale input rotation commands scaling. Defaults to 1.6.
dead_zone (float): Magnitude of dead zone for gamepad. An event value from the gamepad less than
pos_sensitivity: Magnitude of input position command scaling. Defaults to 1.0.
rot_sensitivity: Magnitude of scale input rotation commands scaling. Defaults to 1.6.
dead_zone: Magnitude of dead zone for gamepad. An event value from the gamepad less than
this value will be ignored. Defaults to 0.01.
"""
# turn off simulator gamepad control
......@@ -117,8 +117,8 @@ class Se3Gamepad(DeviceBase):
`carb documentation <https://docs.omniverse.nvidia.com/kit/docs/carbonite/latest/docs/python/carb.html?highlight=gamepadeventtype#carb.input.GamepadInput>`__.
Args:
key (carb.input.GamepadInput): The gamepad button to check against.
func (Callable): The function to call when key is pressed. The callback function should not
key: The gamepad button to check against.
func: The function to call when key is pressed. The callback function should not
take any arguments.
"""
self._additional_callbacks[key] = func
......@@ -127,7 +127,7 @@ class Se3Gamepad(DeviceBase):
"""Provides the result from gamepad event state.
Returns:
Tuple[np.ndarray, bool]: A tuple containing the delta pose command and gripper commands.
A tuple containing the delta pose command and gripper commands.
"""
# -- resolve position command
delta_pos = self._resolve_command_buffer(self._delta_pose_raw[:, :3])
......@@ -218,13 +218,13 @@ class Se3Gamepad(DeviceBase):
"""Resolves the command buffer.
Args:
raw_command (np.ndarray): The raw command from the gamepad. Shape: (2, 3)
raw_command: The raw command from the gamepad. Shape is (2, 3)
This is a 2D array since gamepad dpad/stick returns two values corresponding to
the positive and negative direction. The first index is the direction (0: positive, 1: negative)
and the second index is value (absolute) of the command.
Returns:
np.ndarray: resolved command. Shape: (3,)
Resolved command. Shape is (3,)
"""
# compare the positive and negative value decide the sign of the value
# if the positive value is larger, the sign is positive (i.e. False, 0)
......
......@@ -5,6 +5,8 @@
"""Keyboard device for SE(2) and SE(3) control."""
from __future__ import annotations
from .se2_keyboard import Se2Keyboard
from .se3_keyboard import Se3Keyboard
......
......@@ -5,6 +5,7 @@
"""Keyboard controller for SE(2) control."""
from __future__ import annotations
import numpy as np
from typing import Callable
......@@ -43,9 +44,9 @@ class Se2Keyboard(DeviceBase):
"""Initialize the keyboard layer.
Args:
v_x_sensitivity (float): Magnitude of linear velocity along x-direction scaling. Defaults to 0.8.
v_y_sensitivity (float): Magnitude of linear velocity along y-direction scaling. Defaults to 0.4.
omega_z_sensitivity (float): Magnitude of angular velocity along z-direction scaling. Defaults to 1.0.
v_x_sensitivity: Magnitude of linear velocity along x-direction scaling. Defaults to 0.8.
v_y_sensitivity: Magnitude of linear velocity along y-direction scaling. Defaults to 0.4.
omega_z_sensitivity: Magnitude of angular velocity along z-direction scaling. Defaults to 1.0.
"""
# store inputs
self.v_x_sensitivity = v_x_sensitivity
......@@ -97,8 +98,8 @@ class Se2Keyboard(DeviceBase):
`carb documentation <https://docs.omniverse.nvidia.com/kit/docs/carbonite/latest/docs/python/carb.html?highlight=keyboardeventtype#carb.input.KeyboardInput>`__.
Args:
key (str): The keyboard button to check against.
func (Callable): The function to call when key is pressed. The callback function should not
key: The keyboard button to check against.
func: The function to call when key is pressed. The callback function should not
take any arguments.
"""
self._additional_callbacks[key] = func
......@@ -107,7 +108,7 @@ class Se2Keyboard(DeviceBase):
"""Provides the result from keyboard event state.
Returns:
np.ndarray: A 3D array containing the linear (x,y) and angular velocity (z).
3D array containing the linear (x,y) and angular velocity (z).
"""
return self._base_command
......
......@@ -51,8 +51,8 @@ class Se3Keyboard(DeviceBase):
"""Initialize the keyboard layer.
Args:
pos_sensitivity (float): Magnitude of input position command scaling. Defaults to 0.05.
rot_sensitivity (float): Magnitude of scale input rotation commands scaling. Defaults to 0.5.
pos_sensitivity: Magnitude of input position command scaling. Defaults to 0.05.
rot_sensitivity: Magnitude of scale input rotation commands scaling. Defaults to 0.5.
"""
# store inputs
self.pos_sensitivity = pos_sensitivity
......@@ -107,8 +107,8 @@ class Se3Keyboard(DeviceBase):
`carb documentation <https://docs.omniverse.nvidia.com/kit/docs/carbonite/latest/docs/python/carb.html?highlight=keyboardeventtype#carb.input.KeyboardInput>`__.
Args:
key (str): The keyboard button to check against.
func (Callable): The function to call when key is pressed. The callback function should not
key: The keyboard button to check against.
func: The function to call when key is pressed. The callback function should not
take any arguments.
"""
self._additional_callbacks[key] = func
......@@ -117,7 +117,7 @@ class Se3Keyboard(DeviceBase):
"""Provides the result from keyboard event state.
Returns:
Tuple[np.ndarray, bool]: A tuple containing the delta pose command and gripper commands.
A tuple containing the delta pose command and gripper commands.
"""
# convert to rotation vector
rot_vec = Rotation.from_euler("XYZ", self._delta_rot).as_rotvec()
......
......@@ -5,6 +5,8 @@
"""Spacemouse device for SE(2) and SE(3) control."""
from __future__ import annotations
from .se2_spacemouse import Se2SpaceMouse
from .se3_spacemouse import Se3SpaceMouse
......
......@@ -5,6 +5,8 @@
"""Spacemouse controller for SE(2) control."""
from __future__ import annotations
import hid
import numpy as np
import threading
......@@ -38,9 +40,9 @@ class Se2SpaceMouse(DeviceBase):
"""Initialize the spacemouse layer.
Args:
v_x_sensitivity (float): Magnitude of linear velocity along x-direction scaling. Defaults to 0.8.
v_y_sensitivity (float): Magnitude of linear velocity along y-direction scaling. Defaults to 0.4.
omega_z_sensitivity (float): Magnitude of angular velocity along z-direction scaling. Defaults to 1.0.
v_x_sensitivity: Magnitude of linear velocity along x-direction scaling. Defaults to 0.8.
v_y_sensitivity: Magnitude of linear velocity along y-direction scaling. Defaults to 0.4.
omega_z_sensitivity: Magnitude of angular velocity along z-direction scaling. Defaults to 1.0.
"""
# store inputs
self.v_x_sensitivity = v_x_sensitivity
......@@ -92,7 +94,7 @@ class Se2SpaceMouse(DeviceBase):
"""Provides the result from spacemouse event state.
Returns:
np.ndarray: A 3D array containing the linear (x,y) and angular velocity (z).
A 3D array containing the linear (x,y) and angular velocity (z).
"""
return self._base_command
......
......@@ -5,12 +5,14 @@
"""Spacemouse controller for SE(3) control."""
from __future__ import annotations
import hid
import numpy as np
import threading
import time
from scipy.spatial.transform.rotation import Rotation
from typing import Callable, Tuple
from typing import Callable
from ..device_base import DeviceBase
from .utils import convert_buffer
......@@ -42,8 +44,8 @@ class Se3SpaceMouse(DeviceBase):
"""Initialize the space-mouse layer.
Args:
pos_sensitivity (float): Magnitude of input position command scaling. Defaults to 0.4.
rot_sensitivity (float): Magnitude of scale input rotation commands scaling. Defaults to 0.8.
pos_sensitivity: Magnitude of input position command scaling. Defaults to 0.4.
rot_sensitivity: Magnitude of scale input rotation commands scaling. Defaults to 0.8.
"""
# store inputs
self.pos_sensitivity = pos_sensitivity
......@@ -99,11 +101,11 @@ class Se3SpaceMouse(DeviceBase):
# TODO: Improve this to allow multiple buttons on same key.
self._additional_callbacks[key] = func
def advance(self) -> Tuple[np.ndarray, bool]:
def advance(self) -> tuple[np.ndarray, bool]:
"""Provides the result from spacemouse event state.
Returns:
Tuple[np.ndarray, bool]: A tuple containing the delta pose command and gripper commands.
A tuple containing the delta pose command and gripper commands.
"""
rot_vec = Rotation.from_euler("XYZ", self._delta_rot).as_rotvec()
# if new command received, reset event flag to False until keyboard updated.
......
......@@ -27,6 +27,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from __future__ import annotations
__all__ = ["convert_buffer"]
......@@ -35,10 +36,11 @@ def convert_buffer(b1, b2):
"""Converts raw SpaceMouse readings to commands.
Args:
b1 (int): 8-bit byte
b2 (int): 8-bit byte
b1: 8-bit byte
b2: 8-bit byte
Returns:
float: Scaled value from Space-mouse message
Scaled value from Space-mouse message
"""
return _scale_to_control(_to_int16(b1, b2))
......@@ -52,10 +54,11 @@ def _to_int16(y1, y2):
"""Convert two 8 bit bytes to a signed 16 bit integer.
Args:
y1 (int): 8-bit byte
y2 (int): 8-bit byte
y1: 8-bit byte
y2: 8-bit byte
Returns:
int: 16-bit integer
16-bit integer
"""
x = (y1) | (y2 << 8)
if x >= 32768:
......@@ -67,12 +70,13 @@ def _scale_to_control(x, axis_scale=350.0, min_v=-1.0, max_v=1.0):
"""Normalize raw HID readings to target range.
Args:
x (int): Raw reading from HID
axis_scale (float): (Inverted) scaling factor for mapping raw input value
min_v (float): Minimum limit after scaling
max_v (float): Maximum limit after scaling
x: Raw reading from HID
axis_scale: (Inverted) scaling factor for mapping raw input value
min_v: Minimum limit after scaling
max_v: Maximum limit after scaling
Returns:
float: Clipped, scaled input from HID
Clipped, scaled input from HID
"""
x = x / axis_scale
return min(max(x, min_v), max_v)
......@@ -58,7 +58,7 @@ class BaseEnv:
"""Initialize the environment.
Args:
cfg (BaseEnvCfg): The configuration object for the environment.
cfg: The configuration object for the environment.
Raises:
RuntimeError: If a simulation context already exists. The environment must always create one
......
......@@ -10,6 +10,8 @@ The functions can be provided to different managers that are responsible for the
the observation, reward, termination, actions, randomization and curriculum managers.
"""
from __future__ import annotations
from .actions import * # noqa: F401, F403
from .curriculums import * # noqa: F401, F403
from .observations import * # noqa: F401, F403
......
......@@ -33,7 +33,7 @@ def terrain_levels_vel(env: RLEnv, env_ids: Sequence[int], asset_cfg: SceneEntit
on different terrain types, check the :class:`omni.isaac.orbit.terrains.TerrainImporter` class.
Returns:
torch.Tensor: The mean terrain level for the given environment ids.
The mean terrain level for the given environment ids.
"""
# extract the used quantities (to enable type-hinting)
asset: RigidObject = env.scene[asset_cfg.name]
......
......@@ -108,7 +108,7 @@ def joint_vel_limits(env: RLEnv, asset_cfg: SceneEntityCfg, soft_ratio: float) -
This is computed as a sum of the absolute value of the difference between the joint velocity and the soft limits.
Args:
soft_ratio (float) -> torch.Tensor: The ratio of the soft limits to be used.
soft_ratio: The ratio of the soft limits to be used.
"""
# extract the used quantities (to enable type-hinting)
asset: Articulation = env.scene[asset_cfg.name]
......
......@@ -152,10 +152,10 @@ class RLEnv(BaseEnv, gym.Env):
"""Set the seed for the environment.
Args:
seed (int, optional): The seed for random generator. Defaults to -1.
seed: The seed for random generator. Defaults to -1.
Returns:
int: The seed used for random generator.
The seed used for random generator.
"""
import omni.replicator.core as rep
......@@ -171,7 +171,7 @@ class RLEnv(BaseEnv, gym.Env):
of terminated sub-environments.
Returns:
VecEnvObs: Observations from the environment.
Observations from the environment.
"""
# reset state of scene
indices = torch.arange(self.num_envs, dtype=torch.int64, device=self.device)
......@@ -192,7 +192,7 @@ class RLEnv(BaseEnv, gym.Env):
3. If the simulation is playing, we set the actions and step the simulator.
Args:
action (torch.Tensor): Actions to apply on the simulator.
action: Actions to apply on the simulator.
Returns:
VecEnvStepReturn: A tuple containing:
......@@ -245,10 +245,10 @@ class RLEnv(BaseEnv, gym.Env):
x-by-y pixel image, suitable for turning into a video.
Args:
mode (str, optional): The mode to render with. Defaults to "human".
mode: The mode to render with. Defaults to "human".
Returns:
np.ndarray | None: The rendered image as a numpy array if mode is "rgb_array" and offscreen
The rendered image as a numpy array if mode is "rgb_array" and offscreen
rendering is enabled.
Raises:
......@@ -305,7 +305,7 @@ class RLEnv(BaseEnv, gym.Env):
"""Reset environments based on specified indices.
Args:
env_ids (list[int]): List of environment ids which must be reset
env_ids: List of environment ids which must be reset
"""
# update the curriculum for environments that need a reset
self.curriculum_manager.compute(env_ids=env_ids)
......
......@@ -3,6 +3,8 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
from dataclasses import MISSING
from omni.isaac.orbit.utils import configclass
......
......@@ -33,6 +33,8 @@ Example pseudo-code for a manager:
"""
from __future__ import annotations
from .action_manager import ActionManager, ActionTerm
from .curriculum_manager import CurriculumManager
from .manager_base import ManagerBase
......
......@@ -39,8 +39,8 @@ class ActionTerm(ABC):
"""Initialize the action term.
Args:
cfg (ActionTermCfg): The configuration object.
env (BaseEnv): The environment instance.
cfg: The configuration object.
env: The environment instance.
"""
# store the inputs
self.cfg = cfg
......@@ -92,7 +92,7 @@ class ActionTerm(ABC):
This function is called once per environment step by the manager.
Args:
actions (torch.Tensor): The actions to process.
actions: The actions to process.
"""
raise NotImplementedError
......@@ -125,8 +125,8 @@ class ActionManager(ManagerBase):
"""Initialize the action manager.
Args:
cfg (object): The configuration object or dictionary (``dict[str, ActionTermCfg]``).
env (BaseEnv): The environment instance.
cfg: The configuration object or dictionary (``dict[str, ActionTermCfg]``).
env: The environment instance.
"""
super().__init__(cfg, env)
# create buffers to store actions
......@@ -173,12 +173,12 @@ class ActionManager(ManagerBase):
@property
def action(self) -> torch.Tensor:
"""The actions sent to the environment. Shape: ``(num_envs, total_action_dim)``."""
"""The actions sent to the environment. Shape is ``(num_envs, total_action_dim)``."""
return self._action
@property
def prev_action(self) -> torch.Tensor:
"""The previous actions sent to the environment. Shape: ``(num_envs, total_action_dim)``."""
"""The previous actions sent to the environment. Shape is ``(num_envs, total_action_dim)``."""
return self._prev_action
"""
......@@ -189,11 +189,11 @@ class ActionManager(ManagerBase):
"""Resets the action history.
Args:
env_ids (Optional[Sequence[int]], optional): The environment ids. Defaults to None, in which case
env_ids: The environment ids. Defaults to None, in which case
all environments are considered.
Returns:
Dict[str, torch.Tensor]: An empty dictionary.
An empty dictionary.
"""
# resolve environment ids
if env_ids is None:
......@@ -211,7 +211,7 @@ class ActionManager(ManagerBase):
This function should be called once per environment step.
Args:
action (torch.Tensor): The actions to process.
action: The actions to process.
"""
# check if action dimension is valid
if self.total_action_dim != action.shape[1]:
......
......@@ -37,8 +37,8 @@ class CurriculumManager(ManagerBase):
"""Initialize the manager.
Args:
cfg (object): The configuration object or dictionary (``dict[str, CurriculumTermCfg]``)
env (RLEnv): An environment object.
cfg: The configuration object or dictionary (``dict[str, CurriculumTermCfg]``)
env: An environment object.
Raises:
TypeError: If curriculum term is not of type :class:`CurriculumTermCfg`.
......@@ -90,7 +90,7 @@ class CurriculumManager(ManagerBase):
to maintain consistency with other classes.
Returns:
dict[str, float]: Dictionary of curriculum terms and their states.
Dictionary of curriculum terms and their states.
"""
extras = {}
for term_name, term_state in self._curriculum_state.items():
......@@ -115,7 +115,7 @@ class CurriculumManager(ManagerBase):
This function calls each curriculum term managed by the class.
Args:
env_ids (Optional[Sequence[int]]): The list of environment IDs to update.
env_ids: The list of environment IDs to update.
If None, all the environments are updated. Defaults to None.
"""
# resolve environment indices
......
......@@ -27,8 +27,8 @@ class ManagerBase(ABC):
"""Initialize the manager.
Args:
cfg (object): The configuration object.
env (BaseEnv): The environment instance.
cfg: The configuration object.
env: The environment instance.
"""
# store the inputs
self.cfg = copy.deepcopy(cfg)
......@@ -64,11 +64,11 @@ class ManagerBase(ABC):
"""Resets the manager and returns logging information for the current time-step.
Args:
env_ids (Sequence[int], optional): The environment ids for which to log data. Defaults
:obj:`None`, which logs data for all environments.
env_ids: The environment ids for which to log data.
Defaults :obj:`None`, which logs data for all environments.
Returns:
dict[str, float]: Dictionary containing the logging information.
Dictionary containing the logging information.
"""
return {}
......@@ -98,10 +98,10 @@ class ManagerBase(ABC):
required by the term function to be called correctly by the manager.
Args:
term_name (str): The name of the term.
term_cfg (ManagerBaseTermCfg): The term configuration.
min_argc (int): The minimum number of arguments required by the term function to
be called correctly by the manager.
term_name: The name of the term.
term_cfg: The term configuration.
min_argc: The minimum number of arguments required by the term function to be called correctly
by the manager.
Raises:
TypeError: If the term configuration is not of type :class:`ManagerBaseTermCfg`.
......
......@@ -35,8 +35,8 @@ class ObservationManager(ManagerBase):
"""Initialize observation manager.
Args:
cfg (object): The configuration object or dictionary (``dict[str, ObservationGroupCfg]``).
env (BaseEnv): The environment instance.
cfg: The configuration object or dictionary (``dict[str, ObservationGroupCfg]``).
env: The environment instance.
"""
super().__init__(cfg, env)
# compute combined vector for obs group
......@@ -112,8 +112,7 @@ class ObservationManager(ManagerBase):
settings. By default, no scaling or clipping is applied.
Returns:
Dict[str, torch.Tensor]: A dictionary with keys as the group names and values as the
computed observations.
A dictionary with keys as the group names and values as the computed observations.
"""
self._obs_buffer = dict()
# iterate over all the terms in each group
......
......@@ -5,6 +5,7 @@
"""Randomization manager for randomizing different elements in the scene."""
from __future__ import annotations
import torch
......@@ -56,8 +57,8 @@ class RandomizationManager(ManagerBase):
"""Initialize the randomization manager.
Args:
cfg (object): A configuration object or dictionary (``dict[str, RandomizationTermCfg]``).
env (RLEnv): An environment object.
cfg: A configuration object or dictionary (``dict[str, RandomizationTermCfg]``).
env: An environment object.
"""
super().__init__(cfg, env)
......@@ -108,10 +109,10 @@ class RandomizationManager(ManagerBase):
applied. If the time step is not constant, the user should pass the time step to this function.
Args:
mode (str): The mode of randomization.
env_ids (Optional[Sequence[int]]): The indices of the environments to apply randomization to.
mode: The mode of randomization.
env_ids: The indices of the environments to apply randomization to.
Defaults to None, in which case the randomization is applied to all environments.
dt (Optional[float], optional): The time step of the environment. This is only used for the "interval" mode.
dt: The time step of the environment. This is only used for the "interval" mode.
Defaults to None, in which case the randomization is not applied.
Raises:
......
......@@ -44,8 +44,8 @@ class RewardManager(ManagerBase):
"""Initialize the reward manager.
Args:
cfg (object): The configuration object or dictionary (``dict[str, RewardTermCfg]``).
env (RLEnv): The environment instance.
cfg: The configuration object or dictionary (``dict[str, RewardTermCfg]``).
env: The environment instance.
"""
super().__init__(cfg, env)
# prepare extra info to store individual reward term information
......@@ -91,11 +91,11 @@ class RewardManager(ManagerBase):
"""Returns the episodic sum of individual reward terms.
Args:
env_ids (Sequence[int], optional): The environment ids for which the episodic sum of
env_ids: The environment ids for which the episodic sum of
individual reward terms is to be returned. Defaults to all the environment ids.
Returns:
dict[str, torch.Tensor]: Dictionary of episodic sum of individual reward terms.
Dictionary of episodic sum of individual reward terms.
"""
# resolve environment ids
if env_ids is None:
......@@ -118,10 +118,10 @@ class RewardManager(ManagerBase):
reward signal. It also updates the episodic sums corresponding to individual reward terms.
Args:
dt (float): The time-step interval of the environment.
dt: The time-step interval of the environment.
Returns:
torch.Tensor: The net reward signal of shape (num_envs,).
The net reward signal of shape (num_envs,).
"""
# reset computation
self._reward_buf[:] = 0.0
......
......@@ -38,8 +38,8 @@ class TerminationManager(ManagerBase):
"""Initializes the termination manager.
Args:
cfg (object): The configuration object or dictionary (``dict[str, TerminationTermCfg]``).
env (RLEnv): An environment object.
cfg: The configuration object or dictionary (``dict[str, TerminationTermCfg]``).
env: An environment object.
"""
super().__init__(cfg, env)
# prepare extra info to store individual termination term information
......@@ -95,11 +95,11 @@ class TerminationManager(ManagerBase):
"""Returns the episodic counts of individual termination terms.
Args:
env_ids (Optional[Sequence[int]], optional): The environment ids. Defaults to None, in which case
env_ids: The environment ids. Defaults to None, in which case
all environments are considered.
Returns:
dict[str, torch.Tensor]: Dictionary of episodic sum of individual reward terms.
Dictionary of episodic sum of individual reward terms.
"""
# resolve environment ids
if env_ids is None:
......@@ -120,7 +120,7 @@ class TerminationManager(ManagerBase):
to compute the net termination signal.
Returns:
torch.Tensor: The combined termination signal of shape ``(num_envs,)``.
The combined termination signal of shape ``(num_envs,)``.
"""
# reset computation
self._done_buf[:] = 0.0
......
......@@ -22,6 +22,8 @@ Currently, the module provides the following classes:
"""
from __future__ import annotations
from .visualization_markers import VisualizationMarkers, VisualizationMarkersCfg
__all__ = ["VisualizationMarkersCfg", "VisualizationMarkers"]
from __future__ import annotations
from omni.isaac.orbit.utils.assets import ISAAC_NUCLEUS_DIR
from ..visualization_markers import VisualizationMarkersCfg
......
......@@ -16,10 +16,12 @@ The marker prototypes can be configured with the :class:`VisualizationMarkersCfg
.. _UsdGeom.PointInstancer: https://graphics.pixar.com/usd/dev/api/class_usd_geom_point_instancer.html
"""
from __future__ import annotations
import numpy as np
import torch
from dataclasses import MISSING
from typing import Any, Dict, List, Optional, Union
from typing import Any
import omni.isaac.core.utils.prims as prim_utils
import omni.isaac.core.utils.stage as stage_utils
......@@ -48,16 +50,16 @@ class VisualizationMarkersCfg:
This can be any valid USD prim type, such as "Sphere" or "Cone".
"""
scale: Optional[List[float]] = None
scale: list[float] | None = None
"""The scale of the marker. Defaults to None."""
color: Optional[List[float]] = None
color: list[float] | None = None
"""The RGB color of the marker. Defaults to None.
If not :obj:`None`, the marker will be colored with the given color. The color is
applied to the material of the marker prim with a preview surface shader that has a
precedence over any existing material on the prim.
"""
attributes: Optional[Dict[str, Any]] = None
attributes: dict[str, Any] | None = None
"""The attributes of the marker. Defaults to None."""
@configclass
......@@ -69,7 +71,7 @@ class VisualizationMarkersCfg:
usd_path: str = MISSING
"""The path to the USD file of the marker."""
markers: Dict[str, MarkerCfg] = MISSING
markers: dict[str, MarkerCfg] = MISSING
"""The dictionary of marker configurations.
The key is the name of the marker, and the value is the configuration of the marker.
......@@ -160,8 +162,8 @@ class VisualizationMarkers:
and the marker prims are registered into it.
Args:
prim_path (str): The prim path where the PointInstancer will be created.
cfg (VisualizationMarkersCfg): The configuration for the markers.
prim_path: The prim path where the PointInstancer will be created.
cfg: The configuration for the markers.
Raises:
ValueError: When no markers are provided in the :obj:`cfg`.
......@@ -186,11 +188,11 @@ class VisualizationMarkers:
self._instancer_manager.GetPositionsAttr().Set([Gf.Vec3f()])
self._count = 1
def __str__(self):
def __str__(self) -> str:
"""Return a string representation of the class.
Returns:
str: A string representation of the class.
A string representation of the class.
"""
msg = f"VisualizationMarkers(prim_path={self.prim_path})"
msg += f"\n\tCount: {self.count}"
......@@ -226,7 +228,7 @@ class VisualizationMarkers:
The method does this through the USD API.
Args:
visible (bool): flag to set the visibility.
visible: flag to set the visibility.
"""
imageable = UsdGeom.Imageable(self._instancer_manager)
if visible:
......@@ -238,16 +240,16 @@ class VisualizationMarkers:
"""Checks the visibility of the markers.
Returns:
bool: True if the markers are visible, False otherwise.
True if the markers are visible, False otherwise.
"""
return self._instancer_manager.GetVisibilityAttr().Get() != UsdGeom.Tokens.invisible
def visualize(
self,
translations: Optional[Union[np.ndarray, torch.Tensor]] = None,
orientations: Optional[Union[np.ndarray, torch.Tensor]] = None,
scales: Optional[Union[np.ndarray, torch.Tensor]] = None,
marker_indices: Optional[Union[List[int], np.ndarray, torch.Tensor]] = None,
translations: np.ndarray | torch.Tensor | None = None,
orientations: np.ndarray | torch.Tensor | None = None,
scales: np.ndarray | torch.Tensor | None = None,
marker_indices: list[int] | np.ndarray | torch.Tensor | None = None,
):
"""Update markers in the viewport.
......@@ -281,16 +283,13 @@ class VisualizationMarkers:
yourself and pass the complete arrays to this function.
Args:
translations (Optional[Union[np.ndarray, torch.Tensor]], optional):
translations w.r.t. parent prim frame. Shape: (M, 3).
translations: Translations w.r.t. parent prim frame. Shape is (M, 3).
Defaults to :obj:`None`, which means left unchanged.
orientations (Optional[Union[np.ndarray, torch.Tensor]], optional):
Quaternion orientations (w, x, y, z) w.r.t. parent prim frame. Shape: (M, 4).
orientations: Quaternion orientations (w, x, y, z) w.r.t. parent prim frame. Shape is (M, 4).
Defaults to :obj:`None`, which means left unchanged.
scales (Union[np.ndarray, torch.Tensor]): Scale applied before any rotation is applied. Shape: (M, 3).
scales: Scale applied before any rotation is applied. Shape is (M, 3).
Defaults to :obj:`None`, which means left unchanged.
marker_indices (Optional[Union[np.ndarray, torch.Tensor]], optional):
Decides which marker prototype to visualize. Shape: (M).
marker_indices: Decides which marker prototype to visualize. Shape is (M).
Defaults to :obj:`None`, which means left unchanged provided that the total number of markers
is the same as the previous call. If the number of markers is different, the function
will update the number of markers in the scene.
......@@ -369,7 +368,7 @@ class VisualizationMarkers:
Helper functions.
"""
def _add_markers_prototypes(self, markers_cfg: Dict[str, VisualizationMarkersCfg.MarkerCfg]):
def _add_markers_prototypes(self, markers_cfg: dict[str, VisualizationMarkersCfg.MarkerCfg]):
"""Adds markers prototypes to the scene and sets the markers instancer to use them."""
# add markers based on config
for name, cfg in markers_cfg.items():
......
......@@ -108,7 +108,7 @@ class InteractiveScene:
as we call heterogeneous environments). This limitation is fixed in Isaac Sim 2023.1.
Args:
cfg (InteractiveSceneCfg): The configuration class for the scene.
cfg: The configuration class for the scene.
"""
# store inputs
self.cfg = cfg
......@@ -230,7 +230,7 @@ class InteractiveScene:
"""Resets the scene entities.
Args:
env_ids (Optional[Sequence[int]], optional): The indices of the environments to reset.
env_ids: The indices of the environments to reset.
Defaults to None (all instances).
"""
# -- assets
......@@ -268,7 +268,7 @@ class InteractiveScene:
"""Update the scene entities.
Args:
dt (float): The amount of time passed from last :meth:`update` call.
dt: The amount of time passed from last :meth:`update` call.
"""
# -- assets
for articulation in self.articulations.values():
......@@ -287,7 +287,7 @@ class InteractiveScene:
"""Returns the keys of the scene entities.
Returns:
list[str]: The keys of the scene entities.
The keys of the scene entities.
"""
all_keys = ["terrain"]
for asset_family in [self.articulations, self.rigid_objects, self.sensors, self.extras]:
......@@ -298,10 +298,10 @@ class InteractiveScene:
"""Returns the scene entity with the given key.
Args:
key (str): The key of the scene entity.
key: The key of the scene entity.
Returns:
Any: The scene entity.
The scene entity.
"""
# check if it is a terrain
if key == "terrain":
......
......@@ -11,6 +11,8 @@ require creating a USD prim for them. Custom sensors, on the other hand, are the
implemented in Python and do not require creating a USD prim for them.
"""
from __future__ import annotations
from .camera import * # noqa: F401, F403
from .contact_sensor import * # noqa: F401, F403
from .ray_caster import * # noqa: F401, F403
......
......@@ -71,7 +71,7 @@ class Camera(SensorBase):
"""Initializes the camera sensor.
Args:
cfg (CameraCfg): The configuration parameters.
cfg: The configuration parameters.
Raises:
RuntimeError: If no camera prim is found at the given path.
......@@ -185,9 +185,9 @@ class Camera(SensorBase):
is not true in the input intrinsic matrix, then the camera will not set up correctly.
Args:
matrices (torch.Tensor): The intrinsic matrices for the camera. Shape: :math:`(N, 3, 3)`.
focal_length (float, optional): Focal length to use when computing aperture values. Defaults to 1.0.
indices (Sequence[int], optional): A list of indices of length :obj:`N` to specify the prims to manipulate.
matrices: The intrinsic matrices for the camera. Shape is :math:`(N, 3, 3)`.
focal_length: Focal length to use when computing aperture values. Defaults to 1.0.
indices: A list of indices of length :obj:`N` to specify the prims to manipulate.
Defaults to None, which means all prims will be manipulated.
"""
# resolve indices
......@@ -254,13 +254,13 @@ class Camera(SensorBase):
on the conventions.
Args:
positions (torch.Tensor | None, optional): The cartesian coordinates (in meters).
Shape: :math:`(N, 3)`. Defaults to None, in which case the camera position in not changed.
orientations (torch.Tensor | None, optional): The quaternion orientation in (w, x, y, z).
Shape: :math:`(N, 4)`. Defaults to None, in which case the camera orientation in not changed.
indices (Sequence[int], optional): A list of indices of length :obj:`N` to specify the prims to manipulate.
positions: The cartesian coordinates (in meters). Shape is :math:`(N, 3)`.
Defaults to None, in which case the camera position in not changed.
orientations: The quaternion orientation in (w, x, y, z). Shape is :math:`(N, 4)`.
Defaults to None, in which case the camera orientation in not changed.
indices: A list of indices of length :obj:`N` to specify the prims to manipulate.
Defaults to None, which means all prims will be manipulated.
convention (Literal["opengl", "ros", "world"], optional): The convention in which the poses are fed.
convention: The convention in which the poses are fed.
Defaults to "ros".
Raises:
......@@ -294,9 +294,9 @@ class Camera(SensorBase):
"""Set the poses of the camera from the eye position and look-at target position.
Args:
eyes (torch.Tensor): The positions of the camera's eye. Shape is :math:`(N, 3)`.
targets (torch.Tensor): The target locations to look at. Shape is :math:`(N, 3)`.
indices (Sequence[int], optional): A list of indices of length :math:`N` to specify the prims to manipulate.
eyes: The positions of the camera's eye. Shape is :math:`(N, 3)`.
targets: The target locations to look at. Shape is :math:`(N, 3)`.
indices: A list of indices of length :math:`N` to specify the prims to manipulate.
Defaults to None, which means all prims will be manipulated.
Raises:
......@@ -381,6 +381,9 @@ class Camera(SensorBase):
This function creates handles and registers the provided data types with the replicator registry to
be able to access the data from the sensor. It also initializes the internal buffers to store the data.
Raises:
RuntimeError: If the number of camera prims in the view does not match the number of environments.
"""
import omni.replicator.core as rep
......@@ -534,7 +537,7 @@ class Camera(SensorBase):
we assume that the camera front-axis is +Z-axis and up-axis is -Y-axis.
Returns:
Tuple[np.ndarray, np.ndarray]: A tuple of the position (in meters) and quaternion (w, x, y, z).
A tuple of the position (in meters) and quaternion (w, x, y, z).
"""
# check camera prim exists
if len(self._sensor_prims) == 0:
......
......@@ -31,7 +31,7 @@ class CameraData:
.. note::
ROS convention follows the camera aligned with forward axis +Z and up axis -Y.
Shape: (N, 4) where ``N`` is the number of sensors.
Shape is (N, 4) where ``N`` is the number of sensors.
"""
quat_w_world: torch.Tensor = None
......@@ -40,7 +40,7 @@ class CameraData:
.. note::
World frame convention follows the camera aligned with forward axis +X and up axis +Z.
Shape: (N, 4) where ``N`` is the number of sensors.
Shape is ``(N, 4)`` where ``N`` is the number of sensors.
"""
quat_w_opengl: torch.Tensor = None
......@@ -49,7 +49,7 @@ class CameraData:
.. note::
OpenGL convention follows the camera aligned with forward axis -Z and up axis +Y.
Shape: (N, 4) where ``N`` is the number of sensors.
Shape is ``(N, 4)`` where ``N`` is the number of sensors.
"""
##
......@@ -62,7 +62,7 @@ class CameraData:
intrinsic_matrices: torch.Tensor = None
"""The intrinsic matrices for the camera.
Shape is (N, 3, 3) where ``N`` is the number of sensors.
Shape is ``(N, 3, 3)`` where ``N`` is the number of sensors.
"""
output: TensorDict = None
......
......@@ -47,15 +47,14 @@ def transform_points(
If either the inputs `position` and `orientation` are :obj:`None`, the corresponding transformation is not applied.
Args:
points (Union[np.ndarray, torch.Tensor, wp.array]): A tensor of shape (P, 3) or (N, P, 3) comprising of 3D points in source frame.
position (Optional[Sequence[float]], optional): The position of source frame in target frame. Defaults to None.
orientation (Optional[Sequence[float]], optional): The orientation ``(w, x, y, z)`` of source frame in target frame.
points: a tensor of shape (p, 3) or (n, p, 3) comprising of 3d points in source frame.
position: The position of source frame in target frame. Defaults to None.
orientation: The orientation ``(w, x, y, z)`` of source frame in target frame.
Defaults to None.
device (Optional[Union[torch.device, str]], optional): The device for torch where the computation
device: The device for torch where the computation
should be executed. Defaults to None, i.e. takes the device that matches the depth image.
Returns:
Union[np.ndarray, torch.Tensor]:
A tensor of shape (N, 3) comprising of 3D points in target frame.
If the input is a numpy array, the output is a numpy array. Otherwise, it is a torch tensor.
"""
......@@ -111,25 +110,16 @@ def create_pointcloud_from_depth(
p_{target} = R_{target} \times p_{camera} + t_{target}
Args:
intrinsic_matrix (Union[np.ndarray, torch.Tensor, wp.array]): A (3, 3) array providing camera's calibration
matrix.
depth (Union[np.ndarray, torch.Tensor, wp.array]): An array of shape (H, W) with values encoding the depth
measurement.
keep_invalid (bool, optional): Whether to keep invalid points in the cloud or not. Invalid points
intrinsic_matrix: A (3, 3) array providing camera's calibration matrix.
depth: An array of shape (H, W) with values encoding the depth measurement.
keep_invalid: Whether to keep invalid points in the cloud or not. Invalid points
correspond to pixels with depth values 0.0 or NaN. Defaults to False.
position (Optional[Sequence[float]], optional): The position of the camera in a target frame.
Defaults to None.
orientation (Optional[Sequence[float]], optional): The orientation ``(w, x, y, z)`` of the
camera in a target frame. Defaults to None.
device (Optional[Union[torch.device, str]], optional): The device for torch where the computation
should be executed. Defaults to None, i.e. takes the device that matches the depth image.
Raises:
ValueError: When intrinsic matrix is not of shape (3, 3).
ValueError: When depth image is not of shape (H, W) or (H, W, 1).
position: The position of the camera in a target frame. Defaults to None.
orientation: The orientation ``(w, x, y, z)`` of the camera in a target frame. Defaults to None.
device: The device for torch where the computation should be executed.
Defaults to None, i.e. takes the device that matches the depth image.
Returns:
Union[np.ndarray, torch.Tensor]:
An array/tensor of shape (N, 3) comprising of 3D coordinates of points.
The returned datatype is torch if input depth is of type torch.tensor or wp.array. Otherwise, a np.ndarray
is returned.
......@@ -193,29 +183,23 @@ def create_pointcloud_from_rgbd(
If the input ``normalize_rgb`` is set to :obj:`True`, then the RGB values are normalized to be in the range [0, 1].
Args:
intrinsic_matrix (Union[torch.Tensor, np.ndarray, wp.array]): A (3, 3) array/tensor providing camera's
calibration matrix.
depth (Union[torch.Tensor, np.ndarray, wp.array]): An array/tensor of shape (H, W) with values encoding
the depth measurement.
rgb (Union[np.ndarray, Tuple[float, float, float]], optional): Color for generated point cloud.
Defaults to None.
normalize_rgb (bool, optional): Whether to normalize input rgb. Defaults to False.
position (Optional[Sequence[float]], optional): The position of the camera in a target frame.
Defaults to None.
orientation (Optional[Sequence[float]], optional): The orientation `(w, x, y, z)` of the
camera in a target frame. Defaults to None.
device (Optional[Union[torch.device, str]], optional): The device for torch where the computation
should be executed. Defaults to None, i.e. takes the device that matches the depth image.
num_channels (int, optional): Number of channels in RGB pointcloud. Defaults to 3.
Raises:
ValueError: When rgb image is a numpy array but not of shape (H, W, 3) or (H, W, 4).
intrinsic_matrix: A (3, 3) array/tensor providing camera's calibration matrix.
depth: An array/tensor of shape (H, W) with values encoding the depth measurement.
rgb: Color for generated point cloud. Defaults to None.
normalize_rgb: Whether to normalize input rgb. Defaults to False.
position: The position of the camera in a target frame. Defaults to None.
orientation: The orientation `(w, x, y, z)` of the camera in a target frame. Defaults to None.
device: The device for torch where the computation should be executed. Defaults to None, in which case
it takes the device that matches the depth image.
num_channels: Number of channels in RGB pointcloud. Defaults to 3.
Returns:
Union[Tuple[torch.Tensor, torch.Tensor], Tuple[np.ndarray, np.ndarray]]:
A tuple of (N, 3) arrays or tensors containing the 3D coordinates of points and their RGB color respectively.
The returned datatype is torch if input depth is of type torch.tensor or wp.array. Otherwise, a np.ndarray
is returned.
Raises:
ValueError: When rgb image is a numpy array but not of shape (H, W, 3) or (H, W, 4).
"""
# check valid inputs
if rgb is not None and not isinstance(rgb, tuple):
......@@ -313,12 +297,12 @@ def convert_orientation_convention(
- :obj:"world" - forward axis: +X - up axis +Z - Offset is applied in the World Frame convention
Args:
orientation torch.Tensor: Quaternion of form `(w, x, y, z)` with shape (..., 4) in source convention
origin (Literal["opengl", "ros", "world"], optional): Convention to convert to. Defaults to "ros".
target (Literal["opengl", "ros", "world"], optional): Convention to convert from. Defaults to "opengl".
orientation: Quaternion of form `(w, x, y, z)` with shape (..., 4) in source convention
origin: Convention to convert to. Defaults to "ros".
target: Convention to convert from. Defaults to "opengl".
Returns:
torch.Tensor: Quaternion of form `(w, x, y, z)` with shape (..., 4) in target convention
Quaternion of form `(w, x, y, z)` with shape (..., 4) in target convention
"""
if target == origin:
return orientation.clone()
......
......@@ -7,6 +7,8 @@
Rigid contact sensor based on :class:`omni.isaac.core.prims.RigidContactView`.
"""
from __future__ import annotations
from .contact_sensor import ContactSensor
from .contact_sensor_cfg import ContactSensorCfg
from .contact_sensor_data import ContactSensorData
......
......@@ -50,7 +50,7 @@ class ContactSensor(SensorBase):
"""Initializes the contact sensor object.
Args:
cfg (ContactSensorCfg): The configuration parameters.
cfg: The configuration parameters.
"""
# initialize base class
super().__init__(cfg)
......@@ -149,11 +149,11 @@ class ContactSensor(SensorBase):
"""Find bodies in the articulation based on the name keys.
Args:
name_keys (Union[str, Sequence[str]]): A regular expression or a list of regular expressions
name_keys: A regular expression or a list of regular expressions
to match the body names.
Returns:
Tuple[List[int], List[str]]: A tuple of lists containing the body indices and names.
A tuple of lists containing the body indices and names.
"""
return string_utils.resolve_matching_names(name_keys, self.body_names)
......
......@@ -3,6 +3,8 @@
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import torch
from dataclasses import dataclass
......
......@@ -7,6 +7,7 @@
Ray-caster based on warp.
"""
from __future__ import annotations
from . import patterns
from .ray_caster import RayCaster
......
......@@ -7,6 +7,8 @@
Utility functions for different ray-casting patterns that are used by the ray-caster.
"""
from __future__ import annotations
from .patterns import bpearl_pattern, grid_pattern, pinhole_camera_pattern
from .patterns_cfg import BpearlPatternCfg, GridPatternCfg, PatternBaseCfg, PinholeCameraPatternCfg
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment