Hello Developers!
I’m trying to create a custom user extension in Isaac Sim 4.2 to log some simulation properties while the simulation is running. I’m really new to these topics and am trying to learn how to create an user extension. I was able to create the .csv
files at runtime, but I’m struggling to get the current simulation properties, such as:
get_physical_dt()
current_time()
- World objects’ aliases and poses
My goal is to create an isaac_logger
extension to log the simulation time, simulation time step, render FPS, and total frames as shown below:
import os
import csv
import carb
import time
import omni.ext
import omni.physx
import omni.timeline
from datetime import datetime
from omni.isaac.core import SimulationContext
class IsaacLogger():
def __init__(self):
root_folder = "/..../..../.."
self.sep = ';'
logs_dir = os.path.join(root_folder, "isaac")
os.makedirs(logs_dir, exist_ok=True)
self.log_file = os.path.join(logs_dir, file_name)
self.simulation_context = SimulationContext.instance()
# Variables to control
self.frame_count = 0
self.total_frames = 0
self.last_time = time.time()
self.initial_time = time.time()
self.fps = 0.0
# CSV file
self.csv_file = open(self.log_file, 'w', newline='')
self.csv_writer = csv.writer(self.csv_file, delimiter=self.sep)
# Headers
self.csv_writer.writerow([
"Timestamp (%Y-%m-%d_%H-%M-%S)",
"Frame",
"IsaacSim - Step Size (ms)",
"IsaacSim - Simulation Time (ms)",
"IsaacSim - Real Time (ms)",
"OS - System Time (ms)",
"IsaacSim - RTF",
"OS - RTF",
"IsaacSim - Render FPS (Hz)",
"OS - Plugin FPS (Hz)",
"Active Objects"
])
def collect_metrics(self, event):
# Get simulation step size (in ms)
if self.simulation_context is not None:
step_size = self.simulation_context.get_physics_dt() * 1000 # Convert to milliseconds
else:
step_size = 0
class IsaacLoggerExtension(omni.ext.IExt):
def on_startup(self, ext_id):
print("[isaac.logger] Isaac Logger startup")
# Get the timeline interface
self.timeline = omni.timeline.get_timeline_interface()
if not self.timeline:
carb.log_error("Timeline interface not found")
return
# Initialize the logger
self.logger = None
# Register the update callback to check the simulation time continuously
self._update_sub = omni.kit.app.get_app().get_update_event_stream().create_subscription_to_pop(self._on_update)
def _on_update(self, event):
# Check if the simulation is playing
if self.timeline.is_playing() and self.logger is None:
self.logger = IsaacLogger()
elif self.timeline.is_playing() and self.logger is not None:
self.logger.collect_metrics(event)
elif not self.timeline.is_playing() and self.logger is not None:
self.logger.stop_logging()
self.logger = None
def on_shutdown(self):
if self.logger is not None:
self.logger.stop_logging()
self.logger = None
print("[isaac.logger] Isaac Logger shutdown")
However, I’m encountering an issue where physics_context
is None
, and I’m unable to retrieve all the properties I need. Could someone help me properly structure this code?
Thank you!