NORD: NVIDIA Omniverse Robot Definition
Overview
NVIDIA Omniverse Robot Definition (NORD) represents a comprehensive framework for defining, simulating, and deploying robotic systems within the NVIDIA Omniverse platform. NORD bridges the gap between robot design and simulation, providing a standardized approach to create digital twins of robotic systems that can be used for development, testing, and validation before physical deployment.
Architecture and Components
NORD Framework Structure
NORD is built on several key components that work together to create comprehensive robot definitions:
┌─────────────────────────────────────────┐
│ NORD Framework │
├─────────────────────────────────────────┤
│ ┌───────────────────────────────────┐ │
│ │ Robot Description Format │ │
│ │ (Extended URDF/SDF Integration) │ │
│ └───────────────────────────────────┘ │
├─────────────────────────────────────────┤
│ ┌─────────────────┐ ┌─────────────────┐│
│ │ Physics │ │ Materials ││
│ │ Simulation │ │ Definition ││
│ └─────────────────┘ └─────────────────┘│
├─────────────────────────────────────────┤
│ ┌─────────────────┐ ┌─────────────────┐│
│ │ Sensor │ │ Actuator ││
│ │ Modeling │ │ Integration ││
│ └─────────────────┘ └─────────────────┘│
├─────────────────────────────────────────┤
│ ┌───────────────────────────────────┐ │
│ │ Omniverse Integration Layer │ │
│ └──────────────────── ───────────────┘ │
└─────────────────────────────────────────┘
Core Components
1. Extended Robot Description
NORD extends traditional robot description formats with Omniverse-specific capabilities:
{
"robot": {
"name": "example_robot",
"version": "1.0",
"description": "Example robot for NORD demonstration",
"links": [
{
"name": "base_link",
"visual": {
"mesh": "package://robot_description/meshes/base_link.stl",
"material": "metal_chrome"
},
"collision": {
"mesh": "package://robot_description/meshes/base_link_collision.stl"
},
"inertial": {
"mass": 10.0,
"inertia": {
"ixx": 0.4,
"ixy": 0.0,
"ixz": 0.0,
"iyy": 0.4,
"iyz": 0.0,
"izz": 0.2
}
}
}
],
"joints": [
{
"name": "joint1",
"type": "revolute",
"parent": "base_link",
"child": "link1",
"origin": {
"xyz": [0.0, 0.0, 0.1],
"rpy": [0.0, 0.0, 0.0]
},
"axis": [0, 0, 1],
"limits": {
"lower": -3.14,
"upper": 3.14,
"effort": 100,
"velocity": 1.0
}
}
]
},
"omniverse": {
"articulation": {
"enable_self_collision": true,
"fix_root_link": false
},
"materials": {
"metal_chrome": {
"albedo": [0.8, 0.8, 0.9],
"metallic": 0.9,
"roughness": 0.1,
"specular": 0.5
}
},
"sensors": [
{
"name": "camera_sensor",
"type": "camera",
"parent_link": "sensor_mount",
"position": [0.1, 0.0, 0.05],
"orientation": [0.0, 0.0, 0.0, 1.0],
"parameters": {
"resolution": [640, 480],
"fov": 1.047,
"clipping_range": [0.1, 100.0]
}
}
]
}
}
2. Physics Simulation Integration
NORD provides advanced physics simulation capabilities:
class NORDPhysicsIntegrator:
def __init__(self, robot_config):
self.robot = self.load_robot(robot_config)
self.physics_scene = self.create_physics_scene()
self.contact_manager = self.setup_contact_manager()
def load_robot(self, config):
"""Load robot with NORD extensions"""
# Load base URDF/SDF
robot = self.load_base_description(config['urdf_path'])
# Apply NORD-specific physics properties
for link in robot.links:
self.apply_material_properties(link, config['materials'])
self.setup_collision_properties(link, config['collision'])
return robot
def create_physics_scene(self):
"""Create physics scene with Omniverse integration"""
scene = PhysicsScene(
gravity=[0, 0, -9.81],
solver_type='tgs', # Time-stepping Gauss-Seidel
num_position_iterations=4,
num_velocity_iterations=1
)
# Add NORD-specific constraints
scene.set_contact_offset(0.001)
scene.set_rest_offset(0.0)
return scene
def setup_contact_manager(self):
"""Setup advanced contact handling"""
contact_manager = ContactManager()
# Register contact callbacks for NORD-specific behaviors
contact_manager.register_callback(
'robot_environment',
self.handle_robot_environment_contact
)
contact_manager.register_callback(
'robot_robot',
self.handle_robot_robot_contact
)
return contact_manager
3. Material and Appearance System
NORD includes advanced material definitions for photorealistic rendering:
class NORDMaterialSystem:
def __init__(self):
self.material_library = {}
self.pbr_properties = {}
def define_material(self, name, properties):
"""Define material with Physically Based Rendering properties"""
material = {
'name': name,
'albedo': properties.get('albedo', [0.8, 0.8, 0.8]),
'metallic': properties.get('metallic', 0.0),
'roughness': properties.get('roughness', 0.5),
'normal_map': properties.get('normal_map'),
'occlusion_map': properties.get('occlusion_map'),
'emissive': properties.get('emissive', [0.0, 0.0, 0.0]),
'transmission': properties.get('transmission', 0.0),
'ior': properties.get('ior', 1.5)
}
self.material_library[name] = material
return material
def apply_material_to_link(self, link, material_name):
"""Apply material to robot link"""
if material_name in self.material_library:
material = self.material_library[material_name]
# Apply to visual mesh in Omniverse
self.set_visual_material(link.visual_mesh, material)
return True
return False
NORD Integration with Omniverse
USD (Universal Scene Description)
NORD leverages USD for scene representation:
from pxr import Usd, UsdGeom, Sdf
class NORDUSDExporter:
def __init__(self, stage_path):
self.stage = Usd.Stage.CreateNew(stage_path)
self.root_prim = self.stage.GetPseudoRoot()
def export_robot(self, robot_config):
"""Export robot to USD format"""
robot_prim = UsdGeom.Xform.Define(self.stage, '/Robot')
# Export links as Xform prims
for link_config in robot_config['links']:
link_prim = UsdGeom.Xform.Define(
self.stage,
f'/Robot/{link_config["name"]}'
)
# Set transform
xform_api = UsdGeom.XformCommonAPI(link_prim)
xform_api.SetTranslate(link_config['origin']['xyz'])
# Add mesh
if 'mesh' in link_config['visual']:
mesh_prim = UsdGeom.Mesh.Define(
self.stage,
f'/Robot/{link_config["name"]}/visual'
)
self.set_mesh_properties(mesh_prim, link_config['visual'])
# Export joints as articulation joints
self.export_joints(robot_config['joints'])
self.stage.GetRootLayer().Save()
def export_joints(self, joints):
"""Export joints with articulation properties"""
for joint_config in joints:
joint_prim = UsdGeom.Xform.Define(
self.stage,
f'/Robot/Joints/{joint_config["name"]}'
)
# Apply articulation joint properties
articulation_joint = PhysxSchema.Joint.Define(
self.stage,
joint_prim.GetPath()
)
self.set_joint_properties(articulation_joint, joint_config)
Sensor Integration
NORD provides comprehensive sensor modeling:
class NORDSensorIntegrator:
def __init__(self):
self.sensor_types = {
'camera': self.create_camera_sensor,
'lidar': self.create_lidar_sensor,
'imu': self.create_imu_sensor,
'force_torque': self.create_force_torque_sensor
}
def create_camera_sensor(self, config):
"""Create Omniverse-compatible camera sensor"""
camera = omni.replicator.core.Camera()
camera.set_resolution(config['parameters']['resolution'])
camera.set_fov(config['parameters']['fov'])
camera.set_clipping_range(config['parameters']['clipping_range'])
return {
'sensor': camera,
'config': config,
'data_provider': omni.replicator.core.RandomIntrinsicsCameraProvider()
}
def create_lidar_sensor(self, config):
"""Create Omniverse-compatible LIDAR sensor"""
lidar = omni.isaac.range_sensor.acquire_lidar_sensor_interface()
return {
'sensor': lidar,
'config': config,
'spec': {
'min_range': config['parameters'].get('min_range', 0.1),
'max_range': config['parameters'].get('max_range', 10.0),
'rotation_frequency': config['parameters'].get('rotation_frequency', 10),
'channels': config['parameters'].get('channels', 16)
}
}
def integrate_sensors(self, robot_prim, sensor_configs):
"""Integrate sensors into robot structure"""
for sensor_config in sensor_configs:
sensor_type = sensor_config['type']
if sensor_type in self.sensor_types:
sensor_instance = self.sensor_types[sensor_type](sensor_config)
# Attach sensor to parent link
parent_link_path = f'/Robot/{sensor_config["parent_link"]}'
sensor_prim = self.stage.DefinePrim(
f'{parent_link_path}/{sensor_config["name"]}',
'Xform'
)
# Set sensor transform
transform_api = UsdGeom.XformCommonAPI(sensor_prim)
transform_api.SetTranslate(sensor_config['position'])
transform_api.SetRotate Orient(sensor_config['orientation'])
NORD Replay System
The NORD Replay system enables recording and playback of robot simulation data for analysis and debugging.
Data Recording
class NORDReplayRecorder:
def __init__(self, robot, output_path):
self.robot = robot
self.output_path = output_path
self.recording_data = {
'timestamps': [],
'joint_states': [],
'sensor_data': [],
'environment_state': [],
'control_commands': []
}
self.is_recording = False
def start_recording(self):
"""Start recording robot simulation data"""
self.is_recording = True
self.start_time = time.time()
self.record_initial_state()
def record_frame(self):
"""Record current simulation frame"""
if not self.is_recording:
return
current_time = time.time() - self.start_time
self.recording_data['timestamps'].append(current_time)
# Record joint states
joint_states = {}
for joint in self.robot.joints:
joint_states[joint.name] = {
'position': joint.get_position(),
'velocity': joint.get_velocity(),
'effort': joint.get_effort()
}
self.recording_data['joint_states'].append(joint_states)
# Record sensor data
sensor_data = {}
for sensor_name, sensor in self.robot.sensors.items():
sensor_data[sensor_name] = sensor.get_data()
self.recording_data['sensor_data'].append(sensor_data)
def stop_recording(self):
"""Stop recording and save data"""
self.is_recording = False
# Save recording data to file
with open(self.output_path, 'wb') as f:
pickle.dump(self.recording_data, f)
print(f"Recording saved to {self.output_path}")
Data Playback
class NORDReplayPlayer:
def __init__(self, recording_path):
self.recording_path = recording_path
self.recording_data = self.load_recording()
self.current_frame = 0
self.playback_speed = 1.0
def load_recording(self):
"""Load recording data from file"""
with open(self.recording_path, 'rb') as f:
return pickle.load(f)
def play_frame(self, target_robot):
"""Play back a single frame of recording"""
if self.current_frame >= len(self.recording_data['timestamps']):
return False # End of recording
# Apply joint states
joint_states = self.recording_data['joint_states'][self.current_frame]
for joint_name, state in joint_states.items():
target_robot.set_joint_position(joint_name, state['position'])
target_robot.set_joint_velocity(joint_name, state['velocity'])
# Apply sensor data (for visualization/analysis)
sensor_data = self.recording_data['sensor_data'][self.current_frame]
self.current_frame += 1
return True
def play_sequence(self, target_robot, callback=None):
"""Play back entire sequence"""
self.current_frame = 0
while self.current_frame < len(self.recording_data['timestamps']):
success = self.play_frame(target_robot)
if not success:
break
if callback:
callback(self.current_frame, len(self.recording_data['timestamps']))
time.sleep(0.01 / self.playback_speed) # Simulate real-time playback
Best Practices for NORD Implementation
Performance Optimization
- Use level-of-detail (LOD) models for complex robots
- Optimize mesh resolution based on use case
- Implement efficient collision geometries
- Use instancing for repeated components
Quality Assurance
- Validate robot kinematics before simulation
- Test sensor configurations in isolation
- Verify physics parameters with real-world data
- Perform stress testing with extreme inputs
Integration Guidelines
- Maintain compatibility with standard ROS/ROS2 interfaces
- Use standard coordinate frames and units
- Implement proper error handling and logging
- Document custom extensions clearly
NORD provides a powerful framework for creating detailed robot definitions that integrate seamlessly with NVIDIA Omniverse, enabling sophisticated simulation and digital twin capabilities for physical AI applications.