Merge branch 'og-develop' into fix-profiling

This commit is contained in:
Cem Gökmen 2024-10-23 19:48:45 -07:00 committed by GitHub
commit 0c330ba22c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 64 additions and 79 deletions

View File

@ -491,7 +491,7 @@ class StarterSemanticActionPrimitives(BaseActionPrimitiveSet):
action = StarterSemanticActionPrimitiveSet(action_idx)
return self.apply_ref(action, target_obj)
def apply_ref(self, prim, *args, attempts=3):
def apply_ref(self, prim, *args, attempts=5):
"""
Yields action for robot to execute the primitive with the given arguments.

View File

@ -4,6 +4,10 @@ from omnigibson.utils.sim_utils import prim_paths_to_rigid_prims, prims_to_rigid
class ContactBodies(AbsoluteObjectState):
"""
NOTE: This is slow and uncached, but it works even for sleeping objects.
For frequent contact checks, consider using RigidContactAPI for performance.
"""
def _get_value(self, ignore_objs=None):
# Compute bodies in contact, minus the self-owned bodies

View File

@ -2,7 +2,6 @@ from omnigibson.object_states.contact_bodies import ContactBodies
from omnigibson.object_states.kinematics_mixin import KinematicsMixin
from omnigibson.object_states.object_state_base import BooleanStateMixin, RelativeObjectState
from omnigibson.utils.constants import PrimType
from omnigibson.utils.usd_utils import RigidContactAPI
class Touching(KinematicsMixin, RelativeObjectState, BooleanStateMixin):
@ -20,11 +19,5 @@ class Touching(KinematicsMixin, RelativeObjectState, BooleanStateMixin):
return self._check_contact(other, self.obj)
elif other.prim_type == PrimType.CLOTH:
return self._check_contact(self.obj, other)
# elif not self.obj.kinematic_only and not other.kinematic_only:
# # Use optimized check for rigid bodies
# return RigidContactAPI.in_contact(
# prim_paths_a=[link.prim_path for link in self.obj.links.values()],
# prim_paths_b=[link.prim_path for link in other.links.values()],
# )
else:
return self._check_contact(other, self.obj) and self._check_contact(self.obj, other)

View File

@ -21,7 +21,8 @@ from omnigibson.utils.usd_utils import PoseAPI, absolute_prim_path_to_scene_rela
m = create_module_macros(module_path=__file__)
# Default sleep threshold for all objects -- see https://docs.omniverse.nvidia.com/extensions/latest/ext_physics/simulation-control/physics-settings.html?highlight=sleep#sleeping
m.DEFAULT_SLEEP_THRESHOLD = 0.001
# Mass-normalized kinetic energy threshold below which an actor may go to sleep
m.DEFAULT_SLEEP_THRESHOLD = 0.00005
class EntityPrim(XFormPrim):
@ -613,6 +614,8 @@ class EntityPrim(XFormPrim):
def contact_list(self):
"""
Get list of all current contacts with this object prim
NOTE: This method is slow and uncached, but it works even for sleeping objects.
For frequent contact checks, consider using RigidContactAPI for performance.
Returns:
list of CsRawData: raw contact info for this rigid body

View File

@ -67,7 +67,6 @@ class RigidPrim(XFormPrim):
# Other values that will be filled in at runtime
self._rigid_prim_view_direct = None
self._belongs_to_articulation = None
self._cs = None # Contact sensor interface
self._body_name = None
self._visual_only = None
@ -115,11 +114,12 @@ class RigidPrim(XFormPrim):
# Only create contact report api if we're not visual only
if not self._visual_only:
(
contact_api = (
lazy.pxr.PhysxSchema.PhysxContactReportAPI(self._prim)
if self._prim.HasAPI(lazy.pxr.PhysxSchema.PhysxContactReportAPI)
else lazy.pxr.PhysxSchema.PhysxContactReportAPI.Apply(self._prim)
)
contact_api.GetThresholdAttr().Set(0.0)
# Store references to owned visual / collision meshes
# We iterate over all children of this object's prim,
@ -144,10 +144,6 @@ class RigidPrim(XFormPrim):
else False
)
# Create contact sensor
self._cs = lazy.omni.isaac.sensor._sensor.acquire_contact_sensor_interface()
# self._create_contact_sensor()
def _initialize(self):
# Run super method first
super()._initialize()
@ -159,7 +155,7 @@ class RigidPrim(XFormPrim):
# Get contact info first
if self.contact_reporting_enabled:
self._cs.get_rigid_body_raw_data(self.prim_path)
og.sim.contact_sensor.get_rigid_body_raw_data(self.prim_path)
# Grab handle to this rigid body and get name
self.update_handles()
@ -261,6 +257,8 @@ class RigidPrim(XFormPrim):
def contact_list(self):
"""
Get list of all current contacts with this rigid body
NOTE: This method is slow and uncached, but it works even for sleeping objects.
For frequent contact checks, consider using RigidContactAPI for performance.
Returns:
list of CsRawData: raw contact info for this rigid body
@ -268,12 +266,12 @@ class RigidPrim(XFormPrim):
# Make sure we have the ability to grab contacts for this object
contacts = []
if self.contact_reporting_enabled:
raw_data = self._cs.get_rigid_body_raw_data(self.prim_path)
raw_data = og.sim.contact_sensor.get_rigid_body_raw_data(self.prim_path)
for c in raw_data:
# convert handles to prim paths for comparison
c = [*c] # CsRawData enforces body0 and body1 types to be ints, but we want strings
c[2] = self._cs.decode_body_name(c[2])
c[3] = self._cs.decode_body_name(c[3])
c[2] = og.sim.contact_sensor.decode_body_name(c[2])
c[3] = og.sim.contact_sensor.decode_body_name(c[3])
contacts.append(CsRawData(*c))
return contacts

View File

@ -456,6 +456,7 @@ class Scene(Serializable, Registerable, Recreatable, ABC):
self._pose_inv = th.linalg.inv_ex(self._pose).inverse
if gm.ENABLE_TRANSITION_RULES:
assert gm.ENABLE_OBJECT_STATES, "Transition rules require object states to be enabled!"
self._transition_rule_api = TransitionRuleAPI(scene=self)
# Always stop the sim if we started it internally

View File

@ -403,6 +403,9 @@ def _launch_simulator(*args, **kwargs):
self.viewer_width = viewer_width
self.viewer_height = viewer_height
# Acquire contact sensor interface
self._contact_sensor = lazy.omni.isaac.sensor._sensor.acquire_contact_sensor_interface()
def _set_viewer_camera(self, relative_prim_path="/viewer_camera", viewport_name="Viewport"):
"""
Creates a camera prim dedicated for this viewer at @prim_path if it doesn't exist,
@ -1733,6 +1736,14 @@ def _launch_simulator(*args, **kwargs):
"""
return self._initial_rendering_dt
@property
def contact_sensor(self):
"""
Returns:
ContactSensor: Contact sensor object
"""
return self._contact_sensor
def _dump_state(self):
# Default state is from the scene
return {i: scene.dump_state(serialized=False) for i, scene in enumerate(self.scenes)}

View File

@ -334,6 +334,10 @@ class TouchingAnyCondition(RuleCondition):
"""
Rule condition that prunes object candidates from @filter_1_name, only keeping any that are touching any object
from @filter_2_name
Note that this condition uses the RigidContactAPI for contact checking. This is not a persistent contact check,
meaning that if objects get in contact for some time and both fall asleep, the contact will not be detected.
To get persistent contact checking, please use contact_sensor.
"""
def __init__(self, filter_1_name, filter_2_name):
@ -354,71 +358,39 @@ class TouchingAnyCondition(RuleCondition):
# If optimized, filter_2_idxs will be used, otherwise filter_2_bodies will be used!
# Maps object to the list of rigid body idxs in the global contact matrix corresponding to filter 2
self._filter_2_idxs = None
# Maps object to set of rigid bodies corresponding to filter 2
self._filter_2_bodies = None
# Flag whether optimized call can be used
self._optimized = None
def refresh(self, object_candidates):
# Check whether we can use optimized computation or not -- this is determined by whether or not any objects
# in our collision set are kinematic only
# self._optimized = not th.any(
# th.tensor(
# [
# obj.kinematic_only or obj.prim_type == PrimType.CLOTH
# for f in (self._filter_1_name, self._filter_2_name)
# for obj in object_candidates[f]
# ]
# )
# )
# TODO: RigidContactAPI sometimes has false negatives (returning zero impulses when there are contacts), so we will stick
# with the non-optimized version for now. We will fix this in a future release.
self._optimized = False
if self._optimized:
# Register idx mappings
self._filter_1_idxs = {
obj: [RigidContactAPI.get_body_row_idx(link.prim_path)[1] for link in obj.links.values()]
for obj in object_candidates[self._filter_1_name]
}
self._filter_2_idxs = {
obj: th.tensor(
[RigidContactAPI.get_body_col_idx(link.prim_path)[1] for link in obj.links.values()],
dtype=th.float32,
)
for obj in object_candidates[self._filter_2_name]
}
else:
# Register body mappings
self._filter_2_bodies = {obj: set(obj.links.values()) for obj in object_candidates[self._filter_2_name]}
# Register idx mappings
self._filter_1_idxs = {
obj: [RigidContactAPI.get_body_row_idx(link.prim_path)[1] for link in obj.links.values()]
for obj in object_candidates[self._filter_1_name]
}
self._filter_2_idxs = {
obj: th.tensor(
[RigidContactAPI.get_body_col_idx(link.prim_path)[1] for link in obj.links.values()],
dtype=th.float32,
)
for obj in object_candidates[self._filter_2_name]
}
def __call__(self, object_candidates):
# Keep any object that has non-zero impulses between itself and any of the @filter_2_name's objects
objs = []
if self._optimized:
# Batch check for each object
for obj in object_candidates[self._filter_1_name]:
# Get all impulses between @obj and any object in @filter_2_name that are in the same scene
idxs_to_check = th.cat(
[
self._filter_2_idxs[obj2]
for obj2 in object_candidates[self._filter_2_name]
if obj2.scene == obj.scene
]
)
if th.any(
RigidContactAPI.get_all_impulses(obj.scene.idx)[self._filter_1_idxs[obj]][:, idxs_to_check.tolist()]
):
objs.append(obj)
else:
# Manually check contact
filter_2_bodies = set.union(*(self._filter_2_bodies[obj] for obj in object_candidates[self._filter_2_name]))
for obj in object_candidates[self._filter_1_name]:
if len(obj.states[ContactBodies].get_value().intersection(filter_2_bodies)) > 0:
objs.append(obj)
# Batch check for each object
for obj in object_candidates[self._filter_1_name]:
# Get all impulses between @obj and any object in @filter_2_name that are in the same scene
idxs_to_check = th.cat(
[
self._filter_2_idxs[obj2]
for obj2 in object_candidates[self._filter_2_name]
if obj2.scene == obj.scene
]
)
if th.any(
RigidContactAPI.get_all_impulses(obj.scene.idx)[self._filter_1_idxs[obj]][:, idxs_to_check.tolist()]
):
objs.append(obj)
# Update candidates
object_candidates[self._filter_1_name] = objs

View File

@ -185,6 +185,8 @@ def create_joint(
class RigidContactAPIImpl:
"""
Class containing class methods to aggregate rigid body contacts across all rigid bodies in the simulator
NOTE: The RigidContactAPI only works when the contacting objects are awake. If the objects could be asleep, use ContactBodies instead.
"""
def __init__(self):
@ -230,7 +232,7 @@ class RigidContactAPIImpl:
@classmethod
def get_max_contact_data_count(cls):
return 0
return 256
def initialize_view(self):
"""

View File

@ -40,5 +40,6 @@ def test_object_in_FOV_of_robot():
vision_sensor.set_position_orientation(position=[100, 150, 100])
og.sim.step()
og.sim.step()
assert robot.states[ObjectsInFOVOfRobot].get_value() == [robot]
# Since the sensor is moved away from the robot, the robot should not see itself
assert robot.states[ObjectsInFOVOfRobot].get_value() == []
og.clear()