Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DebugVisualizer Update #1775

Merged
merged 5 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 17 additions & 16 deletions habitat-lab/habitat/datasets/rearrange/navmesh_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ def record_robot_nav_debug_image(
robot_navmesh_offsets: List[Tuple[float, float]],
robot_navmesh_radius: float,
in_collision: bool,
vdb: DebugVisualizer,
dbv: DebugVisualizer,
obs_cache: List[Any],
) -> None:
"""
Expand All @@ -277,7 +277,7 @@ def record_robot_nav_debug_image(
:param robot_navmesh_offsets: Robot embodiement approximation. List of 2D points XZ in robot local space.
:param robot_navmesh_radius: The radius of each point approximating the robot embodiement.
:param in_collision: Whether or not the robot is in collision with the environment. If so, embodiement is rendered red.
:param vdb: The DebugVisualizer instance.
:param dbv: The DebugVisualizer instance.
:param obs_cache: The observation cache for later video rendering.
"""

Expand All @@ -291,10 +291,10 @@ def record_robot_nav_debug_image(
mn.Color4.cyan(),
)
)
vdb.render_debug_lines(debug_lines=path_point_render_lines)
dbv.render_debug_lines(debug_lines=path_point_render_lines)

# draw the local coordinate axis ofthe robot
vdb.render_debug_frame(
dbv.render_debug_frame(
axis_length=0.3, transformation=robot_transformation
)

Expand All @@ -307,7 +307,7 @@ def record_robot_nav_debug_image(
np.array([xz[0], robot_transformation.translation[1], xz[2]])
for xz in cur_pos
]
vdb.render_debug_circles(
dbv.render_debug_circles(
[
(
pos,
Expand All @@ -321,12 +321,13 @@ def record_robot_nav_debug_image(

# render 3rd person viewer into the observation cache
robot_position = robot_transformation.translation
vdb.get_observation(
look_at=robot_position,
# 3rd person viewpoint from behind and above the robot
look_from=robot_position
+ robot_transformation.transform_vector(mn.Vector3(0, 1.5, 1.5)),
obs_cache=obs_cache,
obs_cache.append(
dbv.get_observation(
look_at=robot_position,
# 3rd person viewpoint from behind and above the robot
look_from=robot_position
+ robot_transformation.transform_vector(mn.Vector3(0, 1.5, 1.5)),
)
)


Expand All @@ -341,7 +342,7 @@ def path_is_navigable_given_robot(
angular_speed: float = 1.0,
distance_threshold: float = 0.25,
linear_speed: float = 1.0,
vdb: Optional[DebugVisualizer] = None,
dbv: Optional[DebugVisualizer] = None,
render_debug_video: bool = False,
) -> bool:
"""
Expand All @@ -357,7 +358,7 @@ def path_is_navigable_given_robot(
:param angular_speed: The constant angular speed for turning (radians/sec)
:param distance_threshold: The euclidean distance between the robot and the target within which navigation is considered successful and the function returns.
:param linear_speed: The constant linear speed for translation (meters/sec).
:param vdb: An optional DebugVisualizer if rendering and video export are desired.
:param dbv: An optional DebugVisualizer if rendering and video export are desired.
:param render_debug_video: Whether or not to render and export a visualization of the navigation. If True, requires a DebugVisualizer instance.

:return: Whether or not the ratio of time-steps where collisions were detected is within the provided threshold.
Expand All @@ -377,7 +378,7 @@ def path_is_navigable_given_robot(
)

if render_debug_video:
assert vdb is not None, "Need a vdb for visual debugging."
assert dbv is not None, "Need a dbv for visual debugging."
sim.navmesh_visualization = True

# Create a new pathfinder with slightly stricter radius to provide nav buffer from collision
Expand Down Expand Up @@ -489,15 +490,15 @@ def path_is_navigable_given_robot(
robot_navmesh_offsets=robot_navmesh_offsets,
robot_navmesh_radius=robot_navmesh_radius,
in_collision=collision[-1],
vdb=vdb,
dbv=dbv,
obs_cache=debug_video_frames,
)
time_since_debug_frame += 1.0 / vc._integration_frequency

collision_rate = np.average(collision)

if render_debug_video:
vdb.make_debug_video(
dbv.make_debug_video(
output_path="spot_nav_debug",
prefix=f"{collision_rate}",
fps=debug_framerate,
Expand Down
48 changes: 24 additions & 24 deletions habitat-lab/habitat/datasets/rearrange/rearrange_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def __init__(

# debug visualization settings
self._render_debug_obs = self._make_debug_video = debug_visualization
self.vdb: DebugVisualizer = (
self.dbv: DebugVisualizer = (
None # visual debugger initialized with sim
)

Expand Down Expand Up @@ -447,8 +447,8 @@ def visualize_scene_receptacles(self) -> None:
sampled_look_target = receptacle.sample_uniform_global(
self.sim, 1.0
)
self.vdb.look_at(sampled_look_target)
self.vdb.get_observation()
self.dbv.look_at(sampled_look_target)
self.dbv.debug_obs.append(self.dbv.get_observation())

def generate_episodes(
self, num_episodes: int = 1, verbose: bool = False
Expand Down Expand Up @@ -655,7 +655,7 @@ def generate_single_episode(self) -> Optional[RearrangeEpisode]:
# visualize after setting AO states to correctly see scene state
if self._render_debug_obs:
self.visualize_scene_receptacles()
self.vdb.make_debug_video(prefix="receptacles_")
self.dbv.make_debug_video(prefix="receptacles_")

# track a list of target objects to be used for settle culling later
target_object_names: List[str] = []
Expand All @@ -667,7 +667,7 @@ def generate_single_episode(self) -> Optional[RearrangeEpisode]:
recep_tracker,
target_receptacles[sampler_name],
snap_down=True,
vdb=(self.vdb if self._render_debug_obs else None),
dbv=(self.dbv if self._render_debug_obs else None),
)
if len(object_sample_data) == 0:
return None
Expand Down Expand Up @@ -702,8 +702,8 @@ def generate_single_episode(self) -> Optional[RearrangeEpisode]:
f"Generating debug images for {len(new_objects)} objects..."
)
for new_object in new_objects:
self.vdb.look_at(new_object.translation)
self.vdb.get_observation()
self.dbv.look_at(new_object.translation)
self.dbv.debug_obs.append(self.dbv.get_observation())
logger.info(
f"... done generating the debug images for {len(new_objects)} objects."
)
Expand Down Expand Up @@ -742,7 +742,7 @@ def generate_single_episode(self) -> Optional[RearrangeEpisode]:
self.sim,
recep_tracker,
snap_down=True,
vdb=self.vdb,
dbv=self.dbv,
target_receptacles=target_receptacles[obj_sampler_name],
goal_receptacles=goal_receptacles[sampler_name],
object_to_containing_receptacle=self.object_to_containing_receptacle,
Expand Down Expand Up @@ -775,7 +775,7 @@ def generate_single_episode(self) -> Optional[RearrangeEpisode]:
angular_speed=self.cfg.angular_velocity,
distance_threshold=self.cfg.distance_threshold,
linear_speed=self.cfg.linear_velocity,
vdb=self.vdb,
dbv=self.dbv,
render_debug_video=False,
)
if not is_navigable:
Expand Down Expand Up @@ -811,15 +811,15 @@ def generate_single_episode(self) -> Optional[RearrangeEpisode]:
size=target_bb_size / 2.0,
transform=target_transform,
)
self.vdb.look_at(target_transform.translation)
self.vdb.debug_line_render.set_line_width(2.0)
self.vdb.debug_line_render.draw_transformed_line(
self.dbv.look_at(target_transform.translation)
self.dbv.debug_line_render.set_line_width(2.0)
self.dbv.debug_line_render.draw_transformed_line(
target_transform.translation,
rom.get_object_by_handle(instance_handle).translation,
mn.Color4(1.0, 0.0, 0.0, 1.0),
mn.Color4(1.0, 0.0, 0.0, 1.0),
)
self.vdb.get_observation()
self.dbv.debug_obs.append(self.dbv.get_observation())

# collect final object states and serialize the episode
# TODO: creating shortened names should be automated and embedded in the objects to be done in a uniform way
Expand Down Expand Up @@ -949,10 +949,10 @@ def initialize_sim(self, scene_name: str, dataset_path: str) -> None:
# initialize the debug visualizer
output_path = (
"rearrange_ep_gen_output/"
if self.vdb is None
else self.vdb.output_path
if self.dbv is None
else self.dbv.output_path
)
self.vdb = DebugVisualizer(self.sim, output_path=output_path)
self.dbv = DebugVisualizer(self.sim, output_path=output_path)

def settle_sim(
self,
Expand Down Expand Up @@ -981,16 +981,16 @@ def settle_sim(
new_obj_centroid /= len(self.ep_sampled_objects)
settle_db_obs: List[Any] = []
if self._render_debug_obs:
self.vdb.get_observation(
look_at=new_obj_centroid,
look_from=scene_bb.center(),
obs_cache=settle_db_obs,
settle_db_obs.append(
self.dbv.get_observation(
look_at=new_obj_centroid, look_from=scene_bb.center()
)
)

while self.sim.get_world_time() < duration:
self.sim.step_world(1.0 / 30.0)
if self._render_debug_obs:
self.vdb.get_observation(obs_cache=settle_db_obs)
settle_db_obs.append(self.dbv.get_observation())

logger.info(
f" ...done with placement stability analysis in {time.time()-settle_start_time} seconds."
Expand All @@ -1013,7 +1013,7 @@ def settle_sim(
f" Object '{new_object.handle}' unstable. Moved {error} units from placement."
)
if self._render_debug_obs:
self.vdb.peek_rigid_object(
self.dbv.peek_rigid_object(
obj=new_object,
peek_all_axis=True,
additional_savefile_prefix="unstable_",
Expand All @@ -1036,7 +1036,7 @@ def settle_sim(
# TODO: maybe draw/display trajectory tubes for the displacements?

if self._render_debug_obs and make_video:
self.vdb.make_debug_video(
self.dbv.make_debug_video(
prefix="settle_", fps=30, obs_cache=settle_db_obs
)

Expand Down Expand Up @@ -1127,7 +1127,7 @@ def settle_sim(
# generate debug images of all final object placements
if self._render_debug_obs and success:
for obj in self.ep_sampled_objects:
self.vdb.peek_rigid_object(obj, peek_all_axis=True)
self.dbv.peek_rigid_object(obj, peek_all_axis=True)

# return success or failure
return success
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ def get_arg_parser():
) as ep_gen:
if not osp.isdir(args.db_output):
os.makedirs(args.db_output)
ep_gen.vdb.output_path = osp.abspath(args.db_output)
ep_gen.dbv.output_path = osp.abspath(args.db_output)

# Simulator has been initialized and SceneDataset is populated
if args.list:
Expand Down
20 changes: 10 additions & 10 deletions habitat-lab/habitat/datasets/rearrange/samplers/object_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ def sample_placement(
object_handle: str,
receptacle: Receptacle,
snap_down: bool = False,
vdb: Optional[DebugVisualizer] = None,
dbv: Optional[DebugVisualizer] = None,
) -> Optional[habitat_sim.physics.ManagedRigidObject]:
"""
Attempt to sample a valid placement of the object in/on a receptacle given an object handle and receptacle information.
Expand All @@ -239,7 +239,7 @@ def sample_placement(
:param object_handle: The handle of the object template for instantiation and attempted placement.
:param receptacle: The Receptacle instance on which to sample a placement position.
:param snap_down: Whether or not to use the snap_down utility to place the object.
:param vdb: Optionally provide a debug visualizer (vdb)
:param dbv: Optionally provide a DebugVisualizer(dbv)

:return: The newly instanced rigid object or None if placement sampling failed.
"""
Expand Down Expand Up @@ -320,7 +320,7 @@ def sample_placement(
sim,
new_object,
support_object_ids,
vdb=vdb,
dbv=dbv,
)
if snap_success:
logger.info(
Expand Down Expand Up @@ -374,7 +374,7 @@ def single_sample(
sim: habitat_sim.Simulator,
recep_tracker: ReceptacleTracker,
snap_down: bool = False,
vdb: Optional[DebugVisualizer] = None,
dbv: Optional[DebugVisualizer] = None,
fixed_target_receptacle=None,
fixed_obj_handle: Optional[str] = None,
) -> Optional[habitat_sim.physics.ManagedRigidObject]:
Expand All @@ -384,7 +384,7 @@ def single_sample(
:param sim: The active Simulator instance.
:param recep_tracker: The pre-initialized ReceptacleTracker instace containg active ReceptacleSets.
:param snap_down: Whether or not to use the snap_down utility to place the objects.
:param vdb: Optionally provide a debug visualizer (vdb)
:param dbv: Optionally provide a DebugVisualizer (dbv)
:param fixed_target_receptacle: Optionally provide a pre-selected Receptacle instead of sampling. For example, when a target object's receptacle is selected in advance.
:param fixed_obj_handle: Optionally provide a pre-selected object instead of sampling. For example, when sampling the goal position for a known target object.

Expand All @@ -406,7 +406,7 @@ def single_sample(
)

new_object = self.sample_placement(
sim, object_handle, target_receptacle, snap_down, vdb
sim, object_handle, target_receptacle, snap_down, dbv
)

return new_object, target_receptacle
Expand All @@ -428,7 +428,7 @@ def sample(
recep_tracker: ReceptacleTracker,
target_receptacles: List[Receptacle],
snap_down: bool = False,
vdb: Optional[DebugVisualizer] = None,
dbv: Optional[DebugVisualizer] = None,
target_object_handles: Optional[List[str]] = None,
object_idx_to_recep: Optional[Dict[int, Receptacle]] = None,
) -> List[Tuple[habitat_sim.physics.ManagedRigidObject, Receptacle]]:
Expand All @@ -439,7 +439,7 @@ def sample(
:param recep_tracker: The pre-initialized ReceptacleTracker instace containg active ReceptacleSets.
:param target_receptacles: A list of pre-selected Receptacles for target object placement. These will be sampled first.
:param snap_down: Whether or not to use the snap_down utility to place the objects.
:param vdb: Optionally provide a debug visualizer (vdb)
:param dbv: Optionally provide a DebugVisualizer (dbv)

:return: The list of new (object,receptacle) pairs placed by the sampler.
"""
Expand Down Expand Up @@ -475,7 +475,7 @@ def sample(
sim,
recep_tracker,
snap_down,
vdb,
dbv,
target_receptacles[cur_obj_idx],
fixed_obj_handle=fixed_obj_handle,
)
Expand All @@ -486,7 +486,7 @@ def sample(
sim,
recep_tracker,
snap_down,
vdb,
dbv,
fixed_target_receptacle=object_idx_to_recep.get(
cur_obj_idx, None
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def __init__(
"""
Initialize a standard ObjectSampler but construct the object_set to correspond with specific object instances provided.
"""

self.object_instance_set = object_instance_set
object_set = [
x.creation_attributes.handle for x in self.object_instance_set
Expand All @@ -41,7 +42,7 @@ def sample(
sim: habitat_sim.Simulator,
recep_tracker: ReceptacleTracker,
snap_down: bool = False,
vdb: Optional[DebugVisualizer] = None,
dbv: Optional[DebugVisualizer] = None,
target_receptacles=None,
goal_receptacles=None,
object_to_containing_receptacle=None,
Expand All @@ -50,7 +51,16 @@ def sample(
]:
"""
Overridden sampler maps to instances without replacement.
Returns None if failed, or a dict mapping object handles to new object instances in the sampled target location.

:param sim: The Simulator instance.
:param recep_tracker: The ReceptacleTracker containing ReceptacleSet and use information.
:param snap_down: Whether or not to use the snapdown utility for placement.
:param dbv: An optional DebugVisualizer (dbv) to gather placement debug images.
:param target_receptacles: Specify precise Receptacles to use instead of sampling.
:param goal_receptacles: Provide the list of Receptacles pre-selected for goal placement.
:param object_to_containing_receptacle: Dictionary mapping object handles to receptacles containing them.

:return: None if failed. Otherwise a dict mapping object handles to new object instances in the sampled target location.
"""

new_target_objects = {}
Expand All @@ -76,7 +86,7 @@ def sample(
sim,
recep_tracker,
snap_down,
vdb,
dbv,
goal_recep,
use_target.creation_attributes.handle,
)
Expand Down
Loading