Sensor Rig#

MobilityGenSensorRig is a Python Module container that groups all sensors on a robot so that cascade operations — update_state(), enable_rgb_rendering(), state_dict_rgb() — propagate to all sensors automatically without manual loops.

Each sensor is attached as a named attribute on the rig (e.g. rig.front_hawk_left). The sensor name comes from the robot YAML and becomes the key in output data (e.g. "sensor_rig.front_hawk_left.rgb_image").

Currently supported: type: camera — full support via MobilityGenCamera. Logged and skipped: type: lidar, imu, radar.

Sensor attachment#

sensor_prim_path in the YAML is relative to the robot root prim. At build time it is joined with robot_root_path to form an absolute stage path. For cameras, rep.create.render_product(abs_path, resolution) attaches Replicator to the existing UsdGeom.Camera prim. If the prim is missing, the sensor is skipped with a carb.log_error.

Intrinsics (cameras)#

USD is the source of truth. focal_length, aperture, and other optical parameters live in the UsdGeom.Camera prim baked into the robot asset. They are intentionally absent from the YAML — duplicating them would create a divergence risk with no benefit. The YAML only carries sensor_prim_path and pixel resolution.

YAML format#

sensor_rig:
  sensors:
    - name: front_hawk_left
      type: camera
      sensor_prim_path: chassis_link/sensors/front_hawk/left/camera_left
      width_px: 960
      height_px: 600

    - name: front_hawk_right
      type: camera
      sensor_prim_path: chassis_link/sensors/front_hawk/right/camera_right
      width_px: 960
      height_px: 600

    - name: chassis_imu        # unsupported — logged and skipped
      type: imu
      sensor_prim_path: chassis_link/sensors/chassis_imu/Imu_Sensor

Scaffolding the YAML#

scripts/generate_sensor_rigs.py opens a robot USD, discovers all sensor prims, and writes sensor_prim_path entries with # TODO comments on fields requiring human review (name, resolution). Unsupported sensor types are included as comments for inventory. Run once per robot, edit the output, then commit.

BUILD=./_build/linux-x86_64/release
SCRIPT=source/extensions/isaacsim.replicator.mobility_gen.examples/scripts/generate_sensor_rigs.py
DATA=source/extensions/isaacsim.replicator.mobility_gen.examples/isaacsim/replicator/mobility_gen/examples/data/robots

"$BUILD/python.sh" "$SCRIPT" --list "$DATA/carter.yaml"   # inspect only
"$BUILD/python.sh" "$SCRIPT" "$DATA/carter.yaml"          # write in-place

Robot integration#

MobilityGenRobot.__init_subclass__ reads the YAML at class-definition time and stores cls.sensor_configs. build() calls cls.build_sensor_rig(prim_path) after spawning the articulation; build_sensor_rig calls MobilityGenSensorRig.build_mounted. Robots with no sensor_configs (e.g. H1Robot) get sensor_rig = None.

robot = CarterRobot.build("/World/carter")
robot.sensor_rig.enable_rgb_rendering()
robot.sensor_rig.finalize_rendering()   # re-enables Hydra — must be called after all enable_*

# each simulation step
robot.update_state()
images = robot.state_dict_rgb()
# → {"sensor_rig.front_hawk_left.rgb_image": np.ndarray,
#    "sensor_rig.front_hawk_right.rgb_image": np.ndarray}

Footgun: enable_rgb_rendering() disables Hydra texture updates while annotators are attached to avoid OmniGraph crashes on partially-constructed nodes. finalize_rendering() re-enables Hydra. Omitting it causes cameras to silently produce no frames.

Recording and replay#

The UI recording callback writes pose/state only — no sensor readings. Sensor data is generated at replay time by replay_scenario() in build.py, which restores recorded poses to the stage, steps the renderer, and writes annotator outputs. Render modalities (RGB, depth, semantic and instance ID segmentation, and normals) are selected at replay time via ReplayConfig.

Multi-sensor output is automatic: state_dict_rgb() traverses the Module tree recursively, keying each sensor buffer by its full dotted path. The writer uses the key as a folder name; the reader discovers folders via glob. Adding sensors to the YAML requires no changes to writer, reader, or scenario code.