├── .gitattributes ├── VERSION.md ├── isaac-zmq-server ├── src │ ├── isaac_zmq_server │ │ ├── __init__.py │ │ ├── fonts │ │ │ ├── Inter-Medium.ttf │ │ │ └── LICENSE.txt │ │ ├── ui.py │ │ └── server.py │ ├── server_control_message_pb2.py │ └── client_stream_message_pb2.py ├── build_server.sh ├── run_server.sh ├── README.md └── Dockerfile ├── exts ├── isaacsim.zmq.bridge.examples │ ├── isaacsim │ │ └── zmq │ │ │ └── bridge │ │ │ └── examples │ │ │ ├── core │ │ │ ├── __init__.py │ │ │ ├── proto_util.py │ │ │ ├── server_control_message_pb2.py │ │ │ ├── client_stream_message_pb2.py │ │ │ ├── rate_limiter.py │ │ │ └── client.py │ │ │ ├── __init__.py │ │ │ ├── example_headless.py │ │ │ ├── ui.py │ │ │ ├── mission.py │ │ │ └── extension.py │ ├── data │ │ ├── arch.png │ │ ├── ext.png │ │ ├── icon.png │ │ ├── multi.png │ │ ├── buttons.png │ │ ├── preview.png │ │ ├── 2d_to_3d.png │ │ ├── create_menu.png │ │ ├── franka_mission.png │ │ ├── play_stream.svg │ │ └── stop_stream.svg │ ├── docs │ │ ├── README.md │ │ └── CHANGELOG.md │ ├── premake5.lua │ └── config │ │ └── extension.toml └── isaacsim.zmq.bridge │ ├── data │ ├── icon.png │ └── preview.png │ ├── docs │ ├── README.md │ └── CHANGELOG.md │ ├── isaacsim │ └── zmq │ │ └── bridge │ │ └── __init__.py │ ├── config │ └── extension.toml │ ├── plugins │ ├── nodes │ │ ├── OgnIsaacBridgeZMQCamera.ogn │ │ ├── OgnIsaacBridgeZMQNode.ogn │ │ ├── OgnIsaacBridgeZMQCamera.cpp │ │ ├── icons │ │ │ └── isaac-sim.svg │ │ └── OgnIsaacBridgeZMQNode.cpp │ └── isaacsim.zmq.bridge │ │ └── OgnIsaacBridgeZMQNodeExtension.cpp │ └── premake5.lua ├── assets ├── props │ ├── looks.usd │ ├── model.usd │ ├── scale.usd │ ├── sensor.usd │ ├── physics.usd │ ├── base_camera.usd │ ├── sensor_camera.usd │ ├── interface_camera.usd │ ├── phyisics_camera.usd │ └── camera.usda ├── franka_world.usda └── franka_multi_cam_world.usda ├── tools ├── repoman │ ├── omni │ │ └── repo │ │ │ └── format │ │ │ └── .gitignore │ ├── repoman.py │ └── repoman_bootstrapper.py └── packman │ ├── config.packman.xml │ ├── python.bat │ ├── python.sh │ ├── bootstrap │ ├── fetch_file_from_packman_bootstrap.cmd │ ├── download_file_from_url.ps1 │ ├── configure.bat │ ├── install_package.py │ ├── generate_temp_file_name.ps1 │ └── generate_temp_folder.ps1 │ ├── packman.cmd │ ├── packmanconf.py │ └── packman ├── deps ├── pip.toml ├── kit-sdk.packman.xml ├── host-deps.packman.xml ├── repo-deps.packman.xml ├── ext-deps.packman.xml └── kit-sdk-deps.packman.xml ├── repo.sh ├── premake5.lua ├── .gitignore ├── .gitlab-ci.yml ├── LICENSE.txt ├── proto ├── server_control_message.proto └── client_stream_message.proto ├── repo.toml └── SECURITY.md /.gitattributes: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /VERSION.md: -------------------------------------------------------------------------------- 1 | 107.3.3 -------------------------------------------------------------------------------- /isaac-zmq-server/src/isaac_zmq_server/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/isaacsim/zmq/bridge/examples/core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /isaac-zmq-server/build_server.sh: -------------------------------------------------------------------------------- 1 | docker build -t isaac-zmq-server -f Dockerfile . -------------------------------------------------------------------------------- /assets/props/looks.usd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/assets/props/looks.usd -------------------------------------------------------------------------------- /assets/props/model.usd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/assets/props/model.usd -------------------------------------------------------------------------------- /assets/props/scale.usd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/assets/props/scale.usd -------------------------------------------------------------------------------- /assets/props/sensor.usd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/assets/props/sensor.usd -------------------------------------------------------------------------------- /assets/props/physics.usd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/assets/props/physics.usd -------------------------------------------------------------------------------- /assets/props/base_camera.usd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/assets/props/base_camera.usd -------------------------------------------------------------------------------- /assets/props/sensor_camera.usd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/assets/props/sensor_camera.usd -------------------------------------------------------------------------------- /assets/props/interface_camera.usd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/assets/props/interface_camera.usd -------------------------------------------------------------------------------- /assets/props/phyisics_camera.usd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/assets/props/phyisics_camera.usd -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge/data/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/exts/isaacsim.zmq.bridge/data/icon.png -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge/data/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/exts/isaacsim.zmq.bridge/data/preview.png -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/data/arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/exts/isaacsim.zmq.bridge.examples/data/arch.png -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/data/ext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/exts/isaacsim.zmq.bridge.examples/data/ext.png -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/data/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/exts/isaacsim.zmq.bridge.examples/data/icon.png -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/data/multi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/exts/isaacsim.zmq.bridge.examples/data/multi.png -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/data/buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/exts/isaacsim.zmq.bridge.examples/data/buttons.png -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/data/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/exts/isaacsim.zmq.bridge.examples/data/preview.png -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/data/2d_to_3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/exts/isaacsim.zmq.bridge.examples/data/2d_to_3d.png -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/data/create_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/exts/isaacsim.zmq.bridge.examples/data/create_menu.png -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/data/franka_mission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/exts/isaacsim.zmq.bridge.examples/data/franka_mission.png -------------------------------------------------------------------------------- /isaac-zmq-server/src/isaac_zmq_server/fonts/Inter-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isaac-sim/IsaacSimZMQ/HEAD/isaac-zmq-server/src/isaac_zmq_server/fonts/Inter-Medium.ttf -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge/docs/README.md: -------------------------------------------------------------------------------- 1 | # Isaac SIM ZMQ Bridge OmniGraph Nodes [isaacsim.zmq.bridge] 2 | 3 | Extention to facilitate communication between Omniverse and External application via ZMQ 4 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/docs/README.md: -------------------------------------------------------------------------------- 1 | # Isaac SIM ZMQ Bridge [isaacsim.zmq.bridge.examples] 2 | 3 | Extention to facilitate communication between Omniverse and External application via ZMQ 4 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge/docs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). 4 | 5 | 6 | ## [1.0.0] - 2025-03-03 7 | - Initial version 8 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/docs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). 4 | 5 | 6 | ## [1.0.0] - 2025-03-03 7 | - Initial version 8 | -------------------------------------------------------------------------------- /tools/repoman/omni/repo/format/.gitignore: -------------------------------------------------------------------------------- 1 | # Dummy omni.repo.format Python module so we don't have to pull down the format package. 2 | 3 | # Ignore everything in this directory, except this file to ensure the folder is created. 4 | * 5 | !.gitignore -------------------------------------------------------------------------------- /deps/pip.toml: -------------------------------------------------------------------------------- 1 | [[dependency]] 2 | python = "../_build/target-deps/python" 3 | packages = [ 4 | "pyzmq==25.1.2", # 26.4.0 no longer works as prebunlde. 5 | "protobuf==5.26.0", 6 | ] 7 | 8 | target = "../_build/target-deps/pip_prebundle" 9 | platforms = ["*-x86_64", "*-aarch64"] 10 | download_only = false 11 | append_to_install_folder = true 12 | -------------------------------------------------------------------------------- /tools/packman/config.packman.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /deps/kit-sdk.packman.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/premake5.lua: -------------------------------------------------------------------------------- 1 | -- Use folder name to build extension name and tag. Version is specified explicitly. 2 | local ext = get_current_extension_info() 3 | 4 | project_ext (ext) 5 | 6 | -- Link only those files and folders into the extension target directory 7 | repo_build.prebuild_link { 8 | { "%{target_deps}/pip_prebundle", ext.target_dir.."/pip_prebundle" }, 9 | } -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/isaacsim/zmq/bridge/examples/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: MIT 3 | 4 | EXT_NAME = "isaacsim.zmq.bridge.examples" 5 | 6 | from .core.proto_util import register_proto_modules 7 | 8 | register_proto_modules() 9 | 10 | from .core.annotators import * 11 | from .core.client import * 12 | from .extension import * 13 | -------------------------------------------------------------------------------- /repo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Set OMNI_REPO_ROOT early so `repo` bootstrapping can target the repository 6 | # root when writing out Python dependencies. 7 | export OMNI_REPO_ROOT="$( cd "$(dirname "$0")" ; pwd -P )" 8 | 9 | SCRIPT_DIR=$(dirname ${BASH_SOURCE}) 10 | cd "$SCRIPT_DIR" 11 | 12 | # Use "exec" to ensure that envrionment variables don't accidentally affect other processes. 13 | exec "tools/packman/python.sh" tools/repoman/repoman.py "$@" 14 | -------------------------------------------------------------------------------- /isaac-zmq-server/run_server.sh: -------------------------------------------------------------------------------- 1 | xhost +local:appuser 2 | docker run --gpus all --network host \ 3 | -e DISPLAY=$DISPLAY \ 4 | -v /tmp/.X11-unix:/tmp/.X11-unix \ 5 | -e XAUTHORITY=$XAUTHORITY \ 6 | -v $XAUTHORITY:$XAUTHORITY \ 7 | -v ./src:/isaac-zmq-server/src \ 8 | --device /dev/input \ 9 | --device /dev/input/event21 \ 10 | --device /dev/input/event22 \ 11 | --device /dev/input/event23 \ 12 | --privileged \ 13 | -it --rm \ 14 | isaac-zmq-server bash 15 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge/isaacsim/zmq/bridge/__init__.py: -------------------------------------------------------------------------------- 1 | ## Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. 2 | ## 3 | ## NVIDIA CORPORATION and its licensors retain all intellectual property 4 | ## and proprietary rights in and to this software, related documentation 5 | ## and any modifications thereto. Any use, reproduction, disclosure or 6 | ## distribution of this software and related documentation without an express 7 | ## license agreement from NVIDIA CORPORATION is strictly prohibited. 8 | ## 9 | 10 | # This file is needed so tests don't fail. 11 | -------------------------------------------------------------------------------- /deps/host-deps.packman.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /premake5.lua: -------------------------------------------------------------------------------- 1 | -- Shared build scripts from repo_build package. 2 | repo_build = require("omni/repo/build") 3 | 4 | -- Repo root 5 | root = repo_build.get_abs_path(".") 6 | 7 | -- Set the desired MSVC, WINSDK, and MSBUILD versions before executing the kit template premake configuration. 8 | MSVC_VERSION = "14.27.29110" 9 | WINSDK_VERSION = "10.0.18362.0" 10 | MSBUILD_VERSION = "Current" 11 | 12 | -- Execute the kit template premake configuration, which creates the solution, finds extensions, etc. 13 | dofile("_repo/deps/repo_kit_tools/kit-template/premake5.lua") 14 | 15 | include("exts/isaacsim.zmq.bridge.examples/premake5.lua") 16 | include("exts/isaacsim.zmq.bridge/premake5.lua") 17 | -------------------------------------------------------------------------------- /tools/repoman/repoman.py: -------------------------------------------------------------------------------- 1 | import contextlib 2 | import io 3 | import os 4 | import sys 5 | 6 | import packmanapi 7 | from repoman_bootstrapper import repoman_bootstrap 8 | 9 | REPO_ROOT = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../..") 10 | REPO_DEPS_FILE = os.path.join(REPO_ROOT, "deps/repo-deps.packman.xml") 11 | 12 | 13 | def bootstrap(): 14 | """ 15 | Bootstrap all omni.repo modules. 16 | 17 | Pull with packman from repo.packman.xml and add them all to python sys.path to enable importing. 18 | """ 19 | # with contextlib.redirect_stdout(io.StringIO()): 20 | deps = packmanapi.pull(REPO_DEPS_FILE) 21 | for dep_path in deps.values(): 22 | if dep_path not in sys.path: 23 | sys.path.append(dep_path) 24 | 25 | 26 | if __name__ == "__main__": 27 | repoman_bootstrap() 28 | bootstrap() 29 | import omni.repo.man 30 | 31 | omni.repo.man.main(REPO_ROOT) 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # all folders starting with _ are local 2 | _*/ 3 | 4 | .DS_Store 5 | **/.vscode/ipch 6 | 7 | # byte-compiled python files 8 | *.py[cod] 9 | 10 | /.vs 11 | 12 | /app 13 | 14 | /assets/.thumbs 15 | /assets/build 16 | /source/apps 17 | /assets/props/.thumbs 18 | 19 | *.cbin 20 | *.cinfo 21 | 22 | # Too big to upload 23 | 24 | exts/isaacsim.zmq.bridge/bin/lib/*.* 25 | exts/isaacsim.zmq.bridge/bin/libisaacsim.zmq.bridge.plugin.so 26 | 27 | /scratch.py 28 | /temp.py 29 | /release 30 | 31 | 32 | /vendor/Video_Codec_SDK_12.2.72 33 | 34 | tests/rtsp/deps 35 | tests/rtsp/src/build 36 | .nvcode 37 | .nvidia-omniverse 38 | _conan 39 | _deps 40 | _repo 41 | _build 42 | _compiler 43 | 44 | .vscode/ 45 | source/ 46 | 47 | exts/isaacsim.zmq.bridge/isaacsim/zmq/bridge/ogn/ 48 | exts/isaacsim.zmq.bridge/PACKAGE-LICENSES/ 49 | exts/isaacsim.zmq.bridge/ogn/ 50 | exts/isaacsim.zmq.bridge/bin/ 51 | 52 | 53 | exts/isaacsim.zmq.bridge.examples/pip_prebundle 54 | exts/isaacsim.zmq.bridge.examples/PACKAGE-LICENSES -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | include: 2 | - project: 'omniverse/devplat/gitlab/templates/common/compliance' 3 | file: 'modules/omniverse-repo-compliance.gitlab-ci.yml' 4 | ref: v1_latest 5 | 6 | variables: 7 | OSEC_NSPECT_ID: NSPECT-9GUM-4H71 8 | OSEC_SONARQUBE_ENABLED: true 9 | OSEC_CHECKMARX_ENABLED: false 10 | OSEC_PULSE_TRUFFLEHOG_ENABLED: true 11 | OSEC_OMNI_PULSE_ENABLED: false 12 | 13 | # overrides for sonarqube job to enable C/C++ analysis 14 | osec:sonarqube: 15 | variables: 16 | SONAR_CFAMILY_COMPILE_COMMANDS: _build/linux-x86_64/release/compile_commands.json 17 | SONAR_EXCLUSIONS: "_build/**,_repo/**,\ 18 | \ 19 | source/tests/**,\ 20 | " 21 | LINBUILD_EMBEDDED: "1" 22 | before_script: 23 | # Additions to enable C/C++ scan via sonar's compile_commands.json, you still need all of the 24 | # packman headers and generated headers in place for this analysis to work. 25 | # So we run repo --generate 26 | - ./repo.sh build --generate --config release 27 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/config/extension.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | version = "1.1.0" 3 | authors = ["Lior Ben Horin "] 4 | title = "isaacsim zmq bridge examples" 5 | description="Extention to facilitate communication between Isaac SIM and External application via ZMQ" 6 | readme = "docs/README.md" 7 | repository="https://github.com/isaac-sim/IsaacSimZMQ" 8 | category = "Sample" 9 | keywords = ["bridge","example", "zmq"] 10 | changelog="docs/CHANGELOG.md" 11 | preview_image = "data/preview.png" 12 | icon = "data/icon.png" 13 | 14 | # Use omni.ui to build simple UI 15 | [dependencies] 16 | "omni.kit.uiapp" = {} 17 | "isaacsim.zmq.bridge" = {} 18 | 19 | 20 | [[python.module]] 21 | path = "pip_prebundle" 22 | 23 | # Main python module this extension provides, it will be publicly available as "import lbenhorin.nvidia.vision_pipeline". 24 | [[python.module]] 25 | name = "isaacsim.zmq.bridge.examples" 26 | 27 | [[test]] 28 | # Extra dependencies only to be used during test run 29 | dependencies = [ 30 | "omni.kit.ui_test" # UI testing extension 31 | ] -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/data/play_stream.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /isaac-zmq-server/README.md: -------------------------------------------------------------------------------- 1 | # Example container to mock as Server for Isaac Sim ZMQ Bridge 2 | 3 | 4 | This example container provides a starting point for building your own server to communicate with Isaac Sim using ZMQ and Protobuf. 5 | You can use it to run and test your CV models, or any other task that will form a closed loop with Isaac Sim. 6 | 7 | The server also provides a GUI to visualize the data sensor messages being recived, using the [DearPyGui](https://github.com/hoffstadt/DearPyGui) library, which is a simple and easy to use and extend. 8 | 9 | --- 10 | 11 | ## Instructions 12 | 13 | #### Server (Python inside a contatiner) 14 | 15 | 1. Build the docker image and run it 16 | ```bash 17 | cd isaac-zmq-server 18 | ./build_server.sh 19 | ./run_server.sh 20 | ``` 21 | 2. Inside the container, run the server 22 | ```bash 23 | python example.py 24 | ``` 25 | 3. Optional - For the Franka RMPFlow (Multi Camera), start two servers 26 | 27 | 28 | ```bash 29 | # Inside the container 30 | python example.py # server 1 for main camera 31 | # in a second container 32 | python example.py --subscribe_only 1 --port 5591 # server 2 for gripper camera 33 | ``` 34 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/data/stop_stream.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /tools/packman/python.bat: -------------------------------------------------------------------------------- 1 | :: Copyright 2019-2020 NVIDIA CORPORATION 2 | :: 3 | :: Licensed under the Apache License, Version 2.0 (the "License"); 4 | :: you may not use this file except in compliance with the License. 5 | :: You may obtain a copy of the License at 6 | :: 7 | :: http://www.apache.org/licenses/LICENSE-2.0 8 | :: 9 | :: Unless required by applicable law or agreed to in writing, software 10 | :: distributed under the License is distributed on an "AS IS" BASIS, 11 | :: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | :: See the License for the specific language governing permissions and 13 | :: limitations under the License. 14 | 15 | @echo off 16 | setlocal enableextensions 17 | 18 | call "%~dp0\packman" init 19 | set "PYTHONPATH=%PM_MODULE_DIR%;%PYTHONPATH%" 20 | 21 | if not defined PYTHONNOUSERSITE ( 22 | set PYTHONNOUSERSITE=1 23 | ) 24 | 25 | REM For performance, default to unbuffered; however, allow overriding via 26 | REM PYTHONUNBUFFERED=0 since PYTHONUNBUFFERED on windows can truncate output 27 | REM when printing long strings 28 | if not defined PYTHONUNBUFFERED ( 29 | set PYTHONUNBUFFERED=1 30 | ) 31 | 32 | "%PM_PYTHON%" %* -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | SPDX-License-Identifier: MIT 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the "Software"), 6 | to deal in the Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge/config/extension.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | version = "1.1.0" 3 | title = "isaac sim zmq bridge omnigraph nodes" 4 | description = "An Omnigraph node to communicate data in/out from Omniverse via zMQ" 5 | category = "Sample" 6 | keywords = ["bridge","example", "zmq", "cpp", "nodes", "omnigraph"] 7 | icon = "data/icon.png" 8 | preview_image = "data/preview.png" 9 | changelog = "docs/CHANGELOG.md" 10 | readme = "docs/README.md" 11 | authors = ["Lior Ben Horin "] 12 | repository="https://github.com/isaac-sim/IsaacSimZMQ" 13 | 14 | [dependencies] 15 | "omni.graph.core" = {} 16 | "omni.graph.tools" = {} 17 | 18 | [[python.module]] 19 | name = "isaacsim.zmq.bridge" 20 | 21 | [[native.plugin]] 22 | path = "bin/*.plugin" 23 | 24 | 25 | # Order of linkins is critical! 26 | # [[native.library]] 27 | # path = "bin/lib/libsodium.so.23" 28 | #[[native.library]] 29 | #path = "bin/lib/libsodium.so.18" 30 | #[[native.library]] 31 | #path = "bin/lib/libpgm-5.2.so.0" 32 | #[[native.library]] 33 | #path = "bin/lib/libnorm.so.1" 34 | [[native.library]] 35 | path = "bin/lib/libzmq.so.5" 36 | [[native.library]] 37 | path = "bin/lib/libzmq.so" 38 | 39 | [documentation] 40 | pages = [ 41 | "docs/CHANGELOG.md", 42 | ] 43 | -------------------------------------------------------------------------------- /proto/server_control_message.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | // Vector3 represents a 3D vector with x, y, z components 4 | message Vector3 { 5 | double x = 1; 6 | double y = 2; 7 | double z = 3; 8 | } 9 | 10 | // CameraControlCommand represents all camera-related controls 11 | message CameraControlCommand { 12 | Vector3 joints_vel = 1; // Velocities for camera mount joints (x, y, z axes) 13 | double focal_length = 2; // The focal length value 14 | } 15 | 16 | // SettingsCommand represents general control parameters 17 | message SettingsCommand { 18 | bool adaptive_rate = 1; // Whether to use adaptive rate 19 | } 20 | 21 | // FrankaCommand represents a command for the Franka robot 22 | message FrankaCommand { 23 | Vector3 effector_pos = 1; // The effector position 24 | bool show_marker = 2; // Whether to show the marker 25 | } 26 | 27 | // ServerControlMessage is the main message that can contain any of the command types 28 | message ServerControlMessage { 29 | // Only one of these fields will be set 30 | oneof command { 31 | CameraControlCommand camera_control_command = 1; 32 | SettingsCommand settings_command = 2; 33 | FrankaCommand franka_command = 3; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /repo.toml: -------------------------------------------------------------------------------- 1 | ######################################################################################################################## 2 | # Repo tool base settings 3 | ######################################################################################################################## 4 | 5 | [repo] 6 | 7 | # Use the Kit Template repo configuration as a base. Only override things specific to the repo. 8 | import_configs = ["${root}/_repo/deps/repo_kit_tools/kit-template/repo.toml"] 9 | 10 | # Repository Name 11 | name = "IsaacSimZMQ" 12 | 13 | [repo_build] 14 | msbuild.vs_version = "vs2019" 15 | post_build.commands = [] 16 | 17 | [repo_build.premake] 18 | linux_x86_64_cxx_abi=true 19 | 20 | [repo_build.docker] 21 | enabled = false 22 | 23 | 24 | [repo_precache_exts] 25 | registries = [ 26 | {name = "kit/default", url = "omniverse://kit-extensions.ov.nvidia.com/exts/kit/default"}, 27 | {name = "kit/sdk", url = "omniverse://kit-extensions.ov.nvidia.com/exts/kit/sdk/${kit_version_short}/${kit_git_hash}"}, 28 | ] 29 | 30 | ext_folders = [ 31 | "${root}/exts", 32 | "${root}/exts/apps", 33 | ] 34 | 35 | [repo_symstore] 36 | enabled = false 37 | 38 | [repo_build.fetch.pip] 39 | ignore_pip_cache_failure = true 40 | licensing_enabled = false 41 | publish_pip_cache = false 42 | 43 | [repo_build.licensing] 44 | enabled = false -------------------------------------------------------------------------------- /deps/repo-deps.packman.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /tools/packman/python.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2019-2020 NVIDIA CORPORATION 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | PACKMAN_CMD="$(dirname "${BASH_SOURCE}")/packman" 20 | if [ ! -f "$PACKMAN_CMD" ]; then 21 | PACKMAN_CMD="${PACKMAN_CMD}.sh" 22 | fi 23 | source "$PACKMAN_CMD" init 24 | export PYTHONPATH="${PM_MODULE_DIR}:${PYTHONPATH}" 25 | 26 | if [ -z "${PYTHONNOUSERSITE:-}" ]; then 27 | export PYTHONNOUSERSITE=1 28 | fi 29 | 30 | # For performance, default to unbuffered; however, allow overriding via 31 | # PYTHONUNBUFFERED=0 since PYTHONUNBUFFERED on windows can truncate output 32 | # when printing long strings 33 | if [ -z "${PYTHONUNBUFFERED:-}" ]; then 34 | export PYTHONUNBUFFERED=1 35 | fi 36 | 37 | # workaround for our python not shipping with certs 38 | if [[ -z ${SSL_CERT_DIR:-} ]]; then 39 | export SSL_CERT_DIR=/etc/ssl/certs/ 40 | fi 41 | 42 | "${PM_PYTHON}" "$@" 43 | -------------------------------------------------------------------------------- /tools/packman/bootstrap/fetch_file_from_packman_bootstrap.cmd: -------------------------------------------------------------------------------- 1 | :: Copyright 2019 NVIDIA CORPORATION 2 | :: 3 | :: Licensed under the Apache License, Version 2.0 (the "License"); 4 | :: you may not use this file except in compliance with the License. 5 | :: You may obtain a copy of the License at 6 | :: 7 | :: http://www.apache.org/licenses/LICENSE-2.0 8 | :: 9 | :: Unless required by applicable law or agreed to in writing, software 10 | :: distributed under the License is distributed on an "AS IS" BASIS, 11 | :: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | :: See the License for the specific language governing permissions and 13 | :: limitations under the License. 14 | 15 | :: You need to specify as input to this command 16 | @setlocal 17 | @set PACKAGE_NAME=%1 18 | @set TARGET_PATH=%2 19 | 20 | @echo Fetching %PACKAGE_NAME% ... 21 | 22 | @powershell -ExecutionPolicy ByPass -NoLogo -NoProfile -File "%~dp0download_file_from_url.ps1" ^ 23 | -source "https://bootstrap.packman.nvidia.com/%PACKAGE_NAME%" -output %TARGET_PATH% 24 | :: A bug in powershell prevents the errorlevel code from being set when using the -File execution option 25 | :: We must therefore do our own failure analysis, basically make sure the file exists: 26 | @if not exist %TARGET_PATH% goto ERROR_DOWNLOAD_FAILED 27 | 28 | @endlocal 29 | @exit /b 0 30 | 31 | :ERROR_DOWNLOAD_FAILED 32 | @echo Failed to download file from S3 33 | @echo Most likely because endpoint cannot be reached or file %PACKAGE_NAME% doesn't exist 34 | @endlocal 35 | @exit /b 1 -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/isaacsim/zmq/bridge/examples/core/proto_util.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: MIT 3 | 4 | import carb 5 | import omni 6 | import importlib 7 | import sys 8 | import types 9 | 10 | 11 | def register_proto_modules(): 12 | """Register Protobuf modules in a persistent namespace to prevent hot-reload issues. 13 | 14 | Problem: Protobuf modules raise exceptions when hot-reloaded during extension reloads. 15 | Solution: Store imported modules in a persistent namespace (omni.__proto__) that survives 16 | extension reloads, preventing the need to reimport the modules. 17 | """ 18 | namespace = "__proto__" 19 | 20 | # Create persistent namespace 21 | if not hasattr(omni, namespace): 22 | omni.__proto__ = types.ModuleType(f"omni.{namespace}") 23 | sys.modules[f"omni.{namespace}"] = omni.__proto__ 24 | 25 | # List of protobuf modules to register 26 | proto_modules = [ 27 | "server_control_message_pb2", 28 | "client_stream_message_pb2", 29 | ] 30 | 31 | # Import each module if not already registered 32 | for module_name in proto_modules: 33 | if not hasattr(omni.__proto__, module_name): 34 | try: 35 | imported_module = importlib.import_module(f".{module_name}", package=__package__) 36 | setattr(omni.__proto__, module_name, imported_module) 37 | except ImportError as e: 38 | carb.log_warn(f"Warning: Failed to import {module_name}: {e}") 39 | -------------------------------------------------------------------------------- /tools/packman/bootstrap/download_file_from_url.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Copyright 2019 NVIDIA CORPORATION 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | #> 16 | 17 | param( 18 | [Parameter(Mandatory=$true)][string]$source=$null, 19 | [string]$output="out.exe" 20 | ) 21 | $filename = $output 22 | 23 | $triesLeft = 4 24 | $delay = 2 25 | do 26 | { 27 | $triesLeft -= 1 28 | 29 | try 30 | { 31 | Write-Host "Downloading from bootstrap.packman.nvidia.com ..." 32 | $wc = New-Object net.webclient 33 | $wc.Downloadfile($source, $fileName) 34 | exit 0 35 | } 36 | catch 37 | { 38 | Write-Host "Error downloading $source!" 39 | Write-Host $_.Exception|format-list -force 40 | if ($triesLeft) 41 | { 42 | Write-Host "Retrying in $delay seconds ..." 43 | Start-Sleep -seconds $delay 44 | } 45 | $delay = $delay * $delay 46 | } 47 | } while ($triesLeft -gt 0) 48 | # We only get here if the retries have been exhausted, remove any left-overs: 49 | if (Test-Path $fileName) 50 | { 51 | Remove-Item $fileName 52 | } 53 | exit 1 -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Security 2 | 3 | NVIDIA is dedicated to the security and trust of our software products and services, including all source code repositories managed through our organization. 4 | 5 | If you need to report a security issue, please use the appropriate contact points outlined below. **Please do not report security vulnerabilities through GitHub/GitLab.** 6 | 7 | ## Reporting Potential Security Vulnerability in an NVIDIA Product 8 | 9 | To report a potential security vulnerability in any NVIDIA product: 10 | - Web: [Security Vulnerability Submission Form](https://www.nvidia.com/object/submit-security-vulnerability.html) 11 | - E-Mail: psirt@nvidia.com 12 | - We encourage you to use the following PGP key for secure email communication: [NVIDIA public PGP Key for communication](https://www.nvidia.com/en-us/security/pgp-key) 13 | - Please include the following information: 14 | - Product/Driver name and version/branch that contains the vulnerability 15 | - Type of vulnerability (code execution, denial of service, buffer overflow, etc.) 16 | - Instructions to reproduce the vulnerability 17 | - Proof-of-concept or exploit code 18 | - Potential impact of the vulnerability, including how an attacker could exploit the vulnerability 19 | 20 | While NVIDIA currently does not have a bug bounty program, we do offer acknowledgement when an externally reported security issue is addressed under our coordinated vulnerability disclosure policy. Please visit our [Product Security Incident Response Team (PSIRT)](https://www.nvidia.com/en-us/security/psirt-policies/) policies page for more information. 21 | 22 | ## NVIDIA Product Security 23 | 24 | For all security-related concerns, please visit NVIDIA's Product Security portal at https://www.nvidia.com/en-us/security 25 | 26 | -------------------------------------------------------------------------------- /deps/ext-deps.packman.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/isaacsim/zmq/bridge/examples/example_headless.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: MIT 3 | 4 | # to run this file: 5 | # ISAACSIM_PYTHON exts/isaacsim.zmq.bridge.examples/isaacsim/zmq/bridge/examples/example_headless.py --ext-folder ./exts 6 | 7 | import isaacsim 8 | from isaacsim.simulation_app import SimulationApp 9 | 10 | # Set headless mode to True for GUI enabled. 11 | simulation_app = SimulationApp({"headless": True}) 12 | 13 | import carb 14 | import omni.kit.app 15 | 16 | # Get the extension manager and enable our extension 17 | manager = omni.kit.app.get_app().get_extension_manager() 18 | manager.set_extension_enabled_immediate("isaacsim.zmq.bridge.examples", True) 19 | 20 | 21 | from isaacsim.zmq.bridge.examples import EXT_NAME 22 | from isaacsim.zmq.bridge.examples.example_missions import ( 23 | FrankaMultiVisionMission, 24 | FrankaVisionMission, 25 | ) 26 | 27 | # select an example mission here 28 | mission = FrankaVisionMission() 29 | # mission = FrankaMultiVisionMission() # Uncomment to use this mission instead 30 | 31 | # Load the mission USD file and set up the scene 32 | mission.load_mission() 33 | mission.reset_world() 34 | 35 | # Warm up the simulation with a few steps 36 | # This helps ensure caputured images wont have artifacts 37 | for i in range(100): 38 | simulation_app.update() 39 | print(f"[{EXT_NAME}] Warm up step {i+1}/20") 40 | 41 | # Start the mission 42 | # This will start the world simulation. 43 | mission.start_mission() 44 | print(f"[{EXT_NAME}] Streaming data...") 45 | 46 | 47 | while True: 48 | simulation_app.update() # run forever 49 | 50 | # This line is never reached, 51 | # Left to demonstrate how to gracefully close the app 52 | simulation_app.close() 53 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge/plugins/nodes/OgnIsaacBridgeZMQCamera.ogn: -------------------------------------------------------------------------------- 1 | { 2 | "OgnIsaacBridgeZMQCamera": { 3 | "version": 1, 4 | "icon": "icons/isaac-sim.svg", 5 | "categories": "function", 6 | "description": ["Node to retrive camera extrinsics/intrinsics params"], 7 | "language": "c++", 8 | "metadata": { 9 | "uiName": "Isaac Bridge ZMQ Camera Params" 10 | }, 11 | "inputs": { 12 | "execIn": { 13 | "type": "execution", 14 | "description": "Signal to the graph that this node is ready to be executed." 15 | }, 16 | "cameraPrimPath": { 17 | "type": "path", 18 | "description": "Path of the camera prim.", 19 | "uiName": "Camera Prim Path" 20 | }, 21 | "width": { 22 | "type": "uint", 23 | "description": "Camera resolution width", 24 | "default": 720 25 | }, 26 | "height": { 27 | "type": "uint", 28 | "description": "Camera resolution height", 29 | "default": 720 30 | } 31 | }, 32 | "outputs": { 33 | "cameraViewTransform" : { 34 | "type" : "frame[4]", 35 | "description" : "", 36 | "uiName" : "Camera View Transform in ROS world" 37 | }, 38 | "cameraIntrinsics" : { 39 | "type" : "matrixd[3]", 40 | "description" : "", 41 | "uiName" : "Camera Intrinsitcs Matrix" 42 | }, 43 | "cameraWorldScale" : { 44 | "type" : "double[3]", 45 | "description" : "", 46 | "uiName" : "Camera World Scale" 47 | } 48 | } 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge/plugins/isaacsim.zmq.bridge/OgnIsaacBridgeZMQNodeExtension.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | #define CARB_EXPORTS 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // Standard plugin definitions required by Carbonite. 14 | const struct carb::PluginImplDesc pluginImplDesc = { "isaacsim.zmq.bridge.plugin", 15 | "IsaacSim ZMQ Bridge C++ Ogn Nodes.", "NVIDIA", 16 | carb::PluginHotReload::eEnabled, "dev" }; 17 | 18 | // These interface dependencies are required by all OmniGraph node types 19 | CARB_PLUGIN_IMPL_DEPS(omni::graph::core::IGraphRegistry, 20 | omni::fabric::IPath, 21 | omni::fabric::IToken) 22 | 23 | // This macro sets up the information required to register your node type definitions with OmniGraph 24 | DECLARE_OGN_NODES() 25 | 26 | namespace isaacsim 27 | { 28 | namespace zmq 29 | { 30 | namespace bridge 31 | { 32 | 33 | class OmniGraphIsaacZMQNodeExtension : public omni::ext::IExt 34 | { 35 | public: 36 | void onStartup(const char* extId) override 37 | { 38 | // This macro walks the list of pending node type definitions and registers them with OmniGraph 39 | INITIALIZE_OGN_NODES() 40 | } 41 | 42 | void onShutdown() override 43 | { 44 | // This macro walks the list of registered node type definitions and deregisters all of them. This is required 45 | // for hot reload to work. 46 | RELEASE_OGN_NODES() 47 | } 48 | 49 | private: 50 | }; 51 | 52 | } 53 | } 54 | } 55 | 56 | 57 | CARB_PLUGIN_IMPL(pluginImplDesc, isaacsim::zmq::bridge::OmniGraphIsaacZMQNodeExtension) 58 | 59 | void fillInterface(isaacsim::zmq::bridge::OmniGraphIsaacZMQNodeExtension& iface) 60 | { 61 | } 62 | -------------------------------------------------------------------------------- /isaac-zmq-server/src/server_control_message_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: server_control_message.proto 4 | # Protobuf Python Version: 5.26.0 5 | """Generated protocol buffer code.""" 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | from google.protobuf.internal import builder as _builder 10 | # @@protoc_insertion_point(imports) 11 | 12 | _sym_db = _symbol_database.Default() 13 | 14 | 15 | 16 | 17 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1cserver_control_message.proto\"*\n\x07Vector3\x12\t\n\x01x\x18\x01 \x01(\x01\x12\t\n\x01y\x18\x02 \x01(\x01\x12\t\n\x01z\x18\x03 \x01(\x01\"J\n\x14\x43\x61meraControlCommand\x12\x1c\n\njoints_vel\x18\x01 \x01(\x0b\x32\x08.Vector3\x12\x14\n\x0c\x66ocal_length\x18\x02 \x01(\x01\"(\n\x0fSettingsCommand\x12\x15\n\radaptive_rate\x18\x01 \x01(\x08\"D\n\rFrankaCommand\x12\x1e\n\x0c\x65\x66\x66\x65\x63tor_pos\x18\x01 \x01(\x0b\x32\x08.Vector3\x12\x13\n\x0bshow_marker\x18\x02 \x01(\x08\"\xb2\x01\n\x14ServerControlMessage\x12\x37\n\x16\x63\x61mera_control_command\x18\x01 \x01(\x0b\x32\x15.CameraControlCommandH\x00\x12,\n\x10settings_command\x18\x02 \x01(\x0b\x32\x10.SettingsCommandH\x00\x12(\n\x0e\x66ranka_command\x18\x03 \x01(\x0b\x32\x0e.FrankaCommandH\x00\x42\t\n\x07\x63ommandb\x06proto3') 18 | 19 | _globals = globals() 20 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 21 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'server_control_message_pb2', _globals) 22 | if not _descriptor._USE_C_DESCRIPTORS: 23 | DESCRIPTOR._loaded_options = None 24 | _globals['_VECTOR3']._serialized_start=32 25 | _globals['_VECTOR3']._serialized_end=74 26 | _globals['_CAMERACONTROLCOMMAND']._serialized_start=76 27 | _globals['_CAMERACONTROLCOMMAND']._serialized_end=150 28 | _globals['_SETTINGSCOMMAND']._serialized_start=152 29 | _globals['_SETTINGSCOMMAND']._serialized_end=192 30 | _globals['_FRANKACOMMAND']._serialized_start=194 31 | _globals['_FRANKACOMMAND']._serialized_end=262 32 | _globals['_SERVERCONTROLMESSAGE']._serialized_start=265 33 | _globals['_SERVERCONTROLMESSAGE']._serialized_end=443 34 | # @@protoc_insertion_point(module_scope) 35 | -------------------------------------------------------------------------------- /proto/client_stream_message.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | // BBox2DType represents a single bounding box with semantic information 4 | message BBox2DType { 5 | uint32 semanticId = 1; // Unique identifier for the semantic class 6 | int32 xMin = 2; // Left coordinate of the bounding box 7 | int32 yMin = 3; // Top coordinate of the bounding box 8 | int32 xMax = 4; // Right coordinate of the bounding box 9 | int32 yMax = 5; // Bottom coordinate of the bounding box 10 | float occlusionRatio = 6; // Ratio indicating how much of the object is occluded (0-1) 11 | } 12 | 13 | // BBox2DInfo contains metadata for a collection of bounding boxes 14 | message BBox2DInfo { 15 | map idToLabels = 1; // Maps semantic IDs to human-readable labels 16 | repeated int32 bboxIds = 2; // List of bounding box identifiers 17 | } 18 | 19 | // BBox2D represents a complete set of bounding boxes with their metadata 20 | message BBox2D { 21 | repeated BBox2DType data = 1; // Collection of bounding boxes 22 | BBox2DInfo info = 2; // Metadata for the bounding boxes 23 | } 24 | 25 | // Clock contains timing information for synchronization 26 | message Clock { 27 | double sim_dt = 1; // Simulation delta time (seconds) 28 | double sys_dt = 2; // System delta time (seconds) 29 | double sim_time = 3; // Current simulation time (seconds) 30 | double sys_time = 4; // Current system time (seconds) 31 | } 32 | 33 | // Camera contains camera parameters and transformation matrices 34 | message Camera { 35 | repeated double view_matrix_ros = 1; // Flattened 4x4 matrix (size 16) for camera pose in ROS format 36 | repeated double camera_scale = 2; // Size 3 vector for camera scaling factors 37 | repeated double intrinsics_matrix = 3; // Flattened 3x3 matrix (size 9) for camera intrinsics 38 | } 39 | 40 | // ClientStreamMessage is the main message containing all data transmitted 41 | message ClientStreamMessage { 42 | BBox2D bbox2d = 1; // Bounding box data 43 | Clock clock = 2; // Timing information 44 | Camera camera = 3; // Camera parameters 45 | bytes color_image = 4; // RGB image data (encoded) 46 | bytes depth_image = 5; // Depth image data (encoded) 47 | } 48 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/isaacsim/zmq/bridge/examples/core/server_control_message_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: server_control_message.proto 4 | # Protobuf Python Version: 5.26.0 5 | """Generated protocol buffer code.""" 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | from google.protobuf.internal import builder as _builder 10 | # @@protoc_insertion_point(imports) 11 | 12 | _sym_db = _symbol_database.Default() 13 | 14 | 15 | 16 | 17 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1cserver_control_message.proto\"*\n\x07Vector3\x12\t\n\x01x\x18\x01 \x01(\x01\x12\t\n\x01y\x18\x02 \x01(\x01\x12\t\n\x01z\x18\x03 \x01(\x01\"J\n\x14\x43\x61meraControlCommand\x12\x1c\n\njoints_vel\x18\x01 \x01(\x0b\x32\x08.Vector3\x12\x14\n\x0c\x66ocal_length\x18\x02 \x01(\x01\"(\n\x0fSettingsCommand\x12\x15\n\radaptive_rate\x18\x01 \x01(\x08\"D\n\rFrankaCommand\x12\x1e\n\x0c\x65\x66\x66\x65\x63tor_pos\x18\x01 \x01(\x0b\x32\x08.Vector3\x12\x13\n\x0bshow_marker\x18\x02 \x01(\x08\"\xb2\x01\n\x14ServerControlMessage\x12\x37\n\x16\x63\x61mera_control_command\x18\x01 \x01(\x0b\x32\x15.CameraControlCommandH\x00\x12,\n\x10settings_command\x18\x02 \x01(\x0b\x32\x10.SettingsCommandH\x00\x12(\n\x0e\x66ranka_command\x18\x03 \x01(\x0b\x32\x0e.FrankaCommandH\x00\x42\t\n\x07\x63ommandb\x06proto3') 18 | 19 | _globals = globals() 20 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 21 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'server_control_message_pb2', _globals) 22 | if not _descriptor._USE_C_DESCRIPTORS: 23 | DESCRIPTOR._loaded_options = None 24 | _globals['_VECTOR3']._serialized_start=32 25 | _globals['_VECTOR3']._serialized_end=74 26 | _globals['_CAMERACONTROLCOMMAND']._serialized_start=76 27 | _globals['_CAMERACONTROLCOMMAND']._serialized_end=150 28 | _globals['_SETTINGSCOMMAND']._serialized_start=152 29 | _globals['_SETTINGSCOMMAND']._serialized_end=192 30 | _globals['_FRANKACOMMAND']._serialized_start=194 31 | _globals['_FRANKACOMMAND']._serialized_end=262 32 | _globals['_SERVERCONTROLMESSAGE']._serialized_start=265 33 | _globals['_SERVERCONTROLMESSAGE']._serialized_end=443 34 | # @@protoc_insertion_point(module_scope) 35 | -------------------------------------------------------------------------------- /deps/kit-sdk-deps.packman.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /isaac-zmq-server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nvidia/cuda:12.8.0-devel-ubuntu22.04 2 | 3 | # Create a non-root user and group for security 4 | RUN addgroup --system appgroup 5 | RUN adduser --system appuser --ingroup appgroup 6 | 7 | # Detect architecture during build time 8 | ARG TARGETARCH 9 | RUN echo "Target architecture: ${TARGETARCH}" 10 | 11 | # Install dependencies based on architecture 12 | RUN apt-get update && \ 13 | if [ "${TARGETARCH}" = "arm64" ]; then \ 14 | # Full dependencies for aarch64 (to build DearPyGui) 15 | apt-get --no-install-recommends install -y \ 16 | python3 \ 17 | python3-pip \ 18 | libgl1-mesa-glx \ 19 | libglib2.0-0 \ 20 | git \ 21 | build-essential \ 22 | cmake \ 23 | libpython3-dev \ 24 | python3-setuptools \ 25 | python3-wheel \ 26 | libgl1-mesa-glx \ 27 | libx11-dev \ 28 | libgl-dev \ 29 | libxrandr-dev \ 30 | libxinerama-dev \ 31 | libxcursor-dev \ 32 | libxi-dev \ 33 | && rm -rf /var/lib/apt/lists/*; \ 34 | else \ 35 | # Minimal dependencies for x86_64 36 | apt-get --no-install-recommends install -y \ 37 | libgl1-mesa-glx \ 38 | libglib2.0-0 \ 39 | python3 \ 40 | python3-pip \ 41 | && rm -rf /var/lib/apt/lists/*; \ 42 | fi 43 | 44 | RUN ln -sf /usr/bin/python3 /usr/bin/python \ 45 | && ln -sf /usr/bin/pip3 /usr/bin/pip 46 | 47 | # Switch to the non-root user for security 48 | USER appuser 49 | 50 | # Install Python dependencies 51 | # - dearpygui: GUI framework for Python 52 | RUN if [ "${TARGETARCH}" = "arm64" ]; then \ 53 | # For aarch64, build dearpygui from source 54 | cd /tmp && \ 55 | git clone https://github.com/hoffstadt/DearPyGui.git && \ 56 | cd DearPyGui && \ 57 | git checkout v2.0.0 && git submodule update --init --recursive && \ 58 | python3 -m setup bdist_wheel --plat-name linux_$(uname -m) --dist-dir ../dist && \ 59 | cd ../dist && \ 60 | pip install *.whl; \ 61 | else \ 62 | # For x86_64, install dearpygui directly 63 | pip install dearpygui==2.0.0; \ 64 | fi 65 | 66 | ENV MESA_GL_VERSION_OVERRIDE=4.5 67 | 68 | # Install Python dependencies 69 | # - pytorch: for CUDA 12.8 70 | # - zmq: ZeroMQ messaging library 71 | # - opencv-python: Computer vision library 72 | # - protobuf: Protocol Buffers library 73 | RUN pip install torch --index-url https://download.pytorch.org/whl/cu128 74 | RUN pip install \ 75 | pyzmq==26.4.0 \ 76 | opencv-python \ 77 | protobuf==5.26.0 78 | 79 | # Set the working directory for the application 80 | WORKDIR /isaac-zmq-server/src 81 | 82 | # Add the source code to the image (We will also mount it for dynamic updates) 83 | ADD ./src /isaac-zmq-server/src -------------------------------------------------------------------------------- /isaac-zmq-server/src/client_stream_message_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: client_stream_message.proto 4 | # Protobuf Python Version: 5.26.0 5 | """Generated protocol buffer code.""" 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | from google.protobuf.internal import builder as _builder 10 | # @@protoc_insertion_point(imports) 11 | 12 | _sym_db = _symbol_database.Default() 13 | 14 | 15 | 16 | 17 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1b\x63lient_stream_message.proto\"p\n\nBBox2DType\x12\x12\n\nsemanticId\x18\x01 \x01(\r\x12\x0c\n\x04xMin\x18\x02 \x01(\x05\x12\x0c\n\x04yMin\x18\x03 \x01(\x05\x12\x0c\n\x04xMax\x18\x04 \x01(\x05\x12\x0c\n\x04yMax\x18\x05 \x01(\x05\x12\x16\n\x0eocclusionRatio\x18\x06 \x01(\x02\"\x81\x01\n\nBBox2DInfo\x12/\n\nidToLabels\x18\x01 \x03(\x0b\x32\x1b.BBox2DInfo.IdToLabelsEntry\x12\x0f\n\x07\x62\x62oxIds\x18\x02 \x03(\x05\x1a\x31\n\x0fIdToLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\">\n\x06\x42\x42ox2D\x12\x19\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x0b.BBox2DType\x12\x19\n\x04info\x18\x02 \x01(\x0b\x32\x0b.BBox2DInfo\"K\n\x05\x43lock\x12\x0e\n\x06sim_dt\x18\x01 \x01(\x01\x12\x0e\n\x06sys_dt\x18\x02 \x01(\x01\x12\x10\n\x08sim_time\x18\x03 \x01(\x01\x12\x10\n\x08sys_time\x18\x04 \x01(\x01\"R\n\x06\x43\x61mera\x12\x17\n\x0fview_matrix_ros\x18\x01 \x03(\x01\x12\x14\n\x0c\x63\x61mera_scale\x18\x02 \x03(\x01\x12\x19\n\x11intrinsics_matrix\x18\x03 \x03(\x01\"\x88\x01\n\x13\x43lientStreamMessage\x12\x17\n\x06\x62\x62ox2d\x18\x01 \x01(\x0b\x32\x07.BBox2D\x12\x15\n\x05\x63lock\x18\x02 \x01(\x0b\x32\x06.Clock\x12\x17\n\x06\x63\x61mera\x18\x03 \x01(\x0b\x32\x07.Camera\x12\x13\n\x0b\x63olor_image\x18\x04 \x01(\x0c\x12\x13\n\x0b\x64\x65pth_image\x18\x05 \x01(\x0c\x62\x06proto3') 18 | 19 | _globals = globals() 20 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 21 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'client_stream_message_pb2', _globals) 22 | if not _descriptor._USE_C_DESCRIPTORS: 23 | DESCRIPTOR._loaded_options = None 24 | _globals['_BBOX2DINFO_IDTOLABELSENTRY']._loaded_options = None 25 | _globals['_BBOX2DINFO_IDTOLABELSENTRY']._serialized_options = b'8\001' 26 | _globals['_BBOX2DTYPE']._serialized_start=31 27 | _globals['_BBOX2DTYPE']._serialized_end=143 28 | _globals['_BBOX2DINFO']._serialized_start=146 29 | _globals['_BBOX2DINFO']._serialized_end=275 30 | _globals['_BBOX2DINFO_IDTOLABELSENTRY']._serialized_start=226 31 | _globals['_BBOX2DINFO_IDTOLABELSENTRY']._serialized_end=275 32 | _globals['_BBOX2D']._serialized_start=277 33 | _globals['_BBOX2D']._serialized_end=339 34 | _globals['_CLOCK']._serialized_start=341 35 | _globals['_CLOCK']._serialized_end=416 36 | _globals['_CAMERA']._serialized_start=418 37 | _globals['_CAMERA']._serialized_end=500 38 | _globals['_CLIENTSTREAMMESSAGE']._serialized_start=503 39 | _globals['_CLIENTSTREAMMESSAGE']._serialized_end=639 40 | # @@protoc_insertion_point(module_scope) 41 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/isaacsim/zmq/bridge/examples/core/client_stream_message_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: client_stream_message.proto 4 | # Protobuf Python Version: 5.26.0 5 | """Generated protocol buffer code.""" 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | from google.protobuf.internal import builder as _builder 10 | # @@protoc_insertion_point(imports) 11 | 12 | _sym_db = _symbol_database.Default() 13 | 14 | 15 | 16 | 17 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1b\x63lient_stream_message.proto\"p\n\nBBox2DType\x12\x12\n\nsemanticId\x18\x01 \x01(\r\x12\x0c\n\x04xMin\x18\x02 \x01(\x05\x12\x0c\n\x04yMin\x18\x03 \x01(\x05\x12\x0c\n\x04xMax\x18\x04 \x01(\x05\x12\x0c\n\x04yMax\x18\x05 \x01(\x05\x12\x16\n\x0eocclusionRatio\x18\x06 \x01(\x02\"\x81\x01\n\nBBox2DInfo\x12/\n\nidToLabels\x18\x01 \x03(\x0b\x32\x1b.BBox2DInfo.IdToLabelsEntry\x12\x0f\n\x07\x62\x62oxIds\x18\x02 \x03(\x05\x1a\x31\n\x0fIdToLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\">\n\x06\x42\x42ox2D\x12\x19\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x0b.BBox2DType\x12\x19\n\x04info\x18\x02 \x01(\x0b\x32\x0b.BBox2DInfo\"K\n\x05\x43lock\x12\x0e\n\x06sim_dt\x18\x01 \x01(\x01\x12\x0e\n\x06sys_dt\x18\x02 \x01(\x01\x12\x10\n\x08sim_time\x18\x03 \x01(\x01\x12\x10\n\x08sys_time\x18\x04 \x01(\x01\"R\n\x06\x43\x61mera\x12\x17\n\x0fview_matrix_ros\x18\x01 \x03(\x01\x12\x14\n\x0c\x63\x61mera_scale\x18\x02 \x03(\x01\x12\x19\n\x11intrinsics_matrix\x18\x03 \x03(\x01\"\x88\x01\n\x13\x43lientStreamMessage\x12\x17\n\x06\x62\x62ox2d\x18\x01 \x01(\x0b\x32\x07.BBox2D\x12\x15\n\x05\x63lock\x18\x02 \x01(\x0b\x32\x06.Clock\x12\x17\n\x06\x63\x61mera\x18\x03 \x01(\x0b\x32\x07.Camera\x12\x13\n\x0b\x63olor_image\x18\x04 \x01(\x0c\x12\x13\n\x0b\x64\x65pth_image\x18\x05 \x01(\x0c\x62\x06proto3') 18 | 19 | _globals = globals() 20 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 21 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'client_stream_message_pb2', _globals) 22 | if not _descriptor._USE_C_DESCRIPTORS: 23 | DESCRIPTOR._loaded_options = None 24 | _globals['_BBOX2DINFO_IDTOLABELSENTRY']._loaded_options = None 25 | _globals['_BBOX2DINFO_IDTOLABELSENTRY']._serialized_options = b'8\001' 26 | _globals['_BBOX2DTYPE']._serialized_start=31 27 | _globals['_BBOX2DTYPE']._serialized_end=143 28 | _globals['_BBOX2DINFO']._serialized_start=146 29 | _globals['_BBOX2DINFO']._serialized_end=275 30 | _globals['_BBOX2DINFO_IDTOLABELSENTRY']._serialized_start=226 31 | _globals['_BBOX2DINFO_IDTOLABELSENTRY']._serialized_end=275 32 | _globals['_BBOX2D']._serialized_start=277 33 | _globals['_BBOX2D']._serialized_end=339 34 | _globals['_CLOCK']._serialized_start=341 35 | _globals['_CLOCK']._serialized_end=416 36 | _globals['_CAMERA']._serialized_start=418 37 | _globals['_CAMERA']._serialized_end=500 38 | _globals['_CLIENTSTREAMMESSAGE']._serialized_start=503 39 | _globals['_CLIENTSTREAMMESSAGE']._serialized_end=639 40 | # @@protoc_insertion_point(module_scope) 41 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/isaacsim/zmq/bridge/examples/ui.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: MIT 3 | 4 | import asyncio 5 | import os 6 | from pathlib import Path 7 | 8 | import carb 9 | import omni.ext 10 | import omni.ui as ui 11 | import omni.usd 12 | from omni.kit.notification_manager import NotificationStatus, post_notification 13 | from omni.kit.widget.toolbar import WidgetGroup 14 | 15 | from . import EXT_NAME 16 | from .mission import Mission 17 | 18 | 19 | def get_data_path() -> Path: 20 | manager = omni.kit.app.get_app().get_extension_manager() 21 | extension_path = manager.get_extension_path_by_module("isaacsim.zmq.bridge.examples") 22 | return Path(extension_path).joinpath("data") 23 | 24 | 25 | class ZMQClientButtonGroup(WidgetGroup): 26 | """ 27 | UI widget group that provides buttons to start/stop streaming and reset the world. 28 | """ 29 | 30 | def __init__(self): 31 | WidgetGroup.__init__(self) 32 | self._is_streaming = False 33 | self.mission = None 34 | 35 | def set_mission(self, mission: Mission) -> None: 36 | """ 37 | Set the active mission for this button group. 38 | 39 | Args: 40 | mission (Mission): The mission to control with this button group 41 | """ 42 | self.mission = mission 43 | 44 | def clean(self) -> None: 45 | """Clean up resources when the widget is destroyed.""" 46 | super().clean() 47 | # self._start_stop_button = None 48 | self._reset_button = None 49 | 50 | def get_style(self) -> dict: 51 | return {} 52 | 53 | def on_reset_click(self) -> None: 54 | """ 55 | Handle click on the reset world button. 56 | 57 | This method resets the world for the current mission. 58 | If no mission is set, it displays a popup notification. 59 | """ 60 | if not self.mission: 61 | post_notification( 62 | f"[{EXT_NAME}] Please load a mission - Menu > Create > Isaac ZMQ Examples", 63 | duration=4, 64 | status=NotificationStatus.WARNING, 65 | ) 66 | return 67 | 68 | self._reset_button.checked = False 69 | self.mission.reset_world_async() 70 | 71 | def create(self, default_size) -> None: 72 | """ 73 | Create the UI buttons for the widget group. 74 | """ 75 | # Create reset world button 76 | self._reset_button = ui.ToolButton( 77 | image_url="${glyphs}/menu_refresh.svg", 78 | name="resert_world", 79 | tooltip=f"Reset World", 80 | width=default_size, 81 | height=default_size, 82 | clicked_fn=self.on_reset_click, 83 | ) 84 | self.set_visiblity(False) 85 | 86 | def set_visiblity(self, visible: bool) -> None: 87 | """ 88 | Set the visibility of the buttons. 89 | 90 | Args: 91 | visible (bool): Whether the buttons should be visible 92 | """ 93 | if hasattr(self, "_reset_button"): 94 | self._reset_button.visible = visible 95 | -------------------------------------------------------------------------------- /tools/packman/packman.cmd: -------------------------------------------------------------------------------- 1 | :: RUN_PM_MODULE must always be at the same spot for packman update to work (batch reloads file during update!) 2 | :: [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx] 3 | :: Reset errorlevel status (don't inherit from caller) 4 | @call :ECHO_AND_RESET_ERROR 5 | 6 | :: You can remove this section if you do your own manual configuration of the dev machines 7 | call :CONFIGURE 8 | if %errorlevel% neq 0 ( exit /b %errorlevel% ) 9 | 10 | :: Everything below is mandatory 11 | if not defined PM_PYTHON goto :PYTHON_ENV_ERROR 12 | if not defined PM_MODULE goto :MODULE_ENV_ERROR 13 | 14 | set PM_VAR_PATH_ARG= 15 | 16 | if "%1"=="pull" goto :SET_VAR_PATH 17 | if "%1"=="install" goto :SET_VAR_PATH 18 | 19 | :RUN_PM_MODULE 20 | "%PM_PYTHON%" -S -s -u -E "%PM_MODULE%" %* %PM_VAR_PATH_ARG% 21 | if %errorlevel% neq 0 ( exit /b %errorlevel% ) 22 | 23 | :: Marshall environment variables into the current environment if they have been generated and remove temporary file 24 | if exist "%PM_VAR_PATH%" ( 25 | for /F "usebackq tokens=*" %%A in ("%PM_VAR_PATH%") do set "%%A" 26 | ) 27 | if %errorlevel% neq 0 ( goto :VAR_ERROR ) 28 | 29 | if exist "%PM_VAR_PATH%" ( 30 | del /F "%PM_VAR_PATH%" 31 | ) 32 | if %errorlevel% neq 0 ( goto :VAR_ERROR ) 33 | 34 | set PM_VAR_PATH= 35 | goto :eof 36 | 37 | :: Subroutines below 38 | :PYTHON_ENV_ERROR 39 | @echo User environment variable PM_PYTHON is not set! Please configure machine for packman or call configure.bat. 40 | exit /b 1 41 | 42 | :MODULE_ENV_ERROR 43 | @echo User environment variable PM_MODULE is not set! Please configure machine for packman or call configure.bat. 44 | exit /b 1 45 | 46 | :VAR_ERROR 47 | @echo Error while processing and setting environment variables! 48 | exit /b 1 49 | 50 | :: pad [xxxx] 51 | :ECHO_AND_RESET_ERROR 52 | @echo off 53 | if /I "%PM_VERBOSITY%"=="debug" ( 54 | @echo on 55 | ) 56 | exit /b 0 57 | 58 | :SET_VAR_PATH 59 | :: Generate temporary path for variable file 60 | for /f "delims=" %%a in ('%PM_PYTHON% -S -s -u -E -c "import tempfile;file = tempfile.NamedTemporaryFile(mode='w+t', delete=False);print(file.name)"') do (set PM_VAR_PATH=%%a) 61 | set PM_VAR_PATH_ARG=--var-path="%PM_VAR_PATH%" 62 | goto :RUN_PM_MODULE 63 | 64 | :CONFIGURE 65 | :: Must capture and set code page to work around issue #279, powershell invocation mutates console font 66 | :: This issue only happens in Windows CMD shell when using 65001 code page. Some Git Bash implementations 67 | :: don't support chcp so this workaround is a bit convoluted. 68 | :: Test for chcp: 69 | chcp > nul 2>&1 70 | if %errorlevel% equ 0 ( 71 | for /f "tokens=2 delims=:" %%a in ('chcp') do (set PM_OLD_CODE_PAGE=%%a) 72 | ) else ( 73 | call :ECHO_AND_RESET_ERROR 74 | ) 75 | :: trim leading space (this is safe even when PM_OLD_CODE_PAGE has not been set) 76 | set PM_OLD_CODE_PAGE=%PM_OLD_CODE_PAGE:~1% 77 | if "%PM_OLD_CODE_PAGE%" equ "65001" ( 78 | chcp 437 > nul 79 | set PM_RESTORE_CODE_PAGE=1 80 | ) 81 | call "%~dp0\bootstrap\configure.bat" 82 | set PM_CONFIG_ERRORLEVEL=%errorlevel% 83 | if defined PM_RESTORE_CODE_PAGE ( 84 | :: Restore code page 85 | chcp %PM_OLD_CODE_PAGE% > nul 86 | ) 87 | set PM_OLD_CODE_PAGE= 88 | set PM_RESTORE_CODE_PAGE= 89 | exit /b %PM_CONFIG_ERRORLEVEL% 90 | -------------------------------------------------------------------------------- /isaac-zmq-server/src/isaac_zmq_server/ui.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: MIT 3 | 4 | import dearpygui.dearpygui as dpg 5 | 6 | 7 | class App: 8 | """ 9 | Base class for creating the GUI with DearPyGUI. 10 | 11 | This class provides the basic structure for creating a window, setting up 12 | the application, and handling the main loop. Derived classes should implement 13 | the create_app_body and create_network_iface methods. 14 | """ 15 | 16 | def __init__(self): 17 | """Initialize the application with default window settings.""" 18 | self.window_name = "DearPyGUI App" 19 | self.window_width = 800 20 | self.window_height = 600 21 | self.resizeable = False 22 | 23 | def create_app_body(self): 24 | """ 25 | Create the body of the application. 26 | 27 | This method should be implemented by derived classes to define the 28 | UI elements of the application. 29 | 30 | Raises: 31 | NotImplementedError: If the derived class does not implement this method. 32 | """ 33 | raise NotImplementedError 34 | 35 | def create_network_iface(self): 36 | """ 37 | Create the network interface for the application. 38 | 39 | This method should be implemented by derived classes to set up 40 | network communication. 41 | 42 | Raises: 43 | NotImplementedError: If the derived class does not implement this method. 44 | """ 45 | raise NotImplementedError 46 | 47 | def _create_app(self) -> None: 48 | """ 49 | Create the application window. 50 | """ 51 | # Initialize DearPyGUI 52 | dpg.create_context() 53 | dpg.create_viewport( 54 | title=self.window_name, 55 | width=self.window_width, 56 | height=self.window_height, 57 | resizable=self.resizeable, 58 | ) 59 | dpg.setup_dearpygui() 60 | 61 | # Set up fonts 62 | self.font_scale = 20 63 | with dpg.font_registry(): 64 | font_medium = dpg.add_font("./isaac_zmq_server/fonts/Inter-Medium.ttf", 16 * self.font_scale) 65 | 66 | dpg.set_global_font_scale(1 / self.font_scale) 67 | dpg.bind_font(font_medium) 68 | 69 | # Create the application body 70 | self.create_app_body() 71 | 72 | # Show the viewport 73 | dpg.show_viewport() 74 | 75 | def _run(self) -> None: 76 | """ 77 | Run the main application loop. 78 | """ 79 | while dpg.is_dearpygui_running(): 80 | dpg.render_dearpygui_frame() 81 | 82 | def _cleanup(self) -> None: 83 | """ 84 | Clean up resources when the application is closed. 85 | 86 | This method cleans up the ZMQ server and destroys the DearPyGUI context. 87 | """ 88 | self.zmq_server.cleanup() 89 | dpg.destroy_context() 90 | 91 | @classmethod 92 | def run_app(cls) -> None: 93 | """ 94 | Static method to run the application. 95 | """ 96 | app = cls() 97 | app._create_app() 98 | app.create_network_iface() 99 | app._run() 100 | app._cleanup() 101 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge/premake5.lua: -------------------------------------------------------------------------------- 1 | -- Setup the basic extension information. 2 | local ext = get_current_extension_info() 3 | project_ext(ext) 4 | 5 | -- -------------------------------------------------------------------------------------------------------------- 6 | -- Helper variable containing standard configuration information for projects containing OGN files. 7 | local ogn = get_ogn_project_information(ext, "isaacsim/zmq/bridge") 8 | 9 | -- -------------------------------------------------------------------------------------------------------------- 10 | -- Link folders that should be packaged with the extension. 11 | repo_build.prebuild_link { 12 | { "data", ext.target_dir.."/data" }, 13 | { "docs", ext.target_dir.."/docs" }, 14 | } 15 | 16 | -- -------------------------------------------------------------------------------------------------------------- 17 | -- Copy the __init__.py to allow building of a non-linked ogn/ import directory. 18 | -- In a mixed extension this would be part of a separate Python-based project but since here it is just the one 19 | -- file it can be copied directly with no build dependencies. 20 | repo_build.prebuild_copy { 21 | { "isaacsim/zmq/bridge/__init__.py", ogn.python_target_path } 22 | } 23 | 24 | -- -------------------------------------------------------------------------------------------------------------- 25 | -- Breaking this out as a separate project ensures the .ogn files are processed before their results are needed. 26 | project_ext_ogn( ext, ogn ) 27 | 28 | -- -------------------------------------------------------------------------------------------------------------- 29 | -- Build the C++ plugin that will be loaded by the extension. 30 | project_ext_plugin(ext, ogn.plugin_project) 31 | -- It is important that you add all subdirectories containing C++ code to this project 32 | add_files("source", "plugins/"..ogn.module) 33 | add_files("nodes", "plugins/nodes") 34 | 35 | -- same as BUILD_SHARED_LIBS=OFF in CMake, for static linking 36 | staticruntime "On" 37 | 38 | includedirs { "%{target_deps}/python/include/python3.10", 39 | "%{target_deps}/usd/release/include", 40 | "%{target_deps}/protobuf/include", 41 | "%{target_deps}/zmq/include", 42 | "%{target_deps}/cppzmq/include", 43 | "%{target_deps}/libsodium/include", 44 | "%{target_deps}/abseil/include", 45 | } 46 | libdirs { "%{target_deps}/usd/release/lib", 47 | "%{target_deps}/protobuf/lib", 48 | "%{target_deps}/zmq/lib", 49 | "%{target_deps}/libsodium/lib", 50 | "%{target_deps}/abseil/lib", 51 | } 52 | buildoptions { "-fexceptions" } 53 | 54 | -- Dynamic linking 55 | links {"zmq"} 56 | 57 | -- Static linking 58 | linkoptions { 59 | "-Wl,--allow-multiple-definition", 60 | "-Wl,--whole-archive", 61 | -- Abseil 62 | "%{target_deps}/abseil/lib/libabsl_*.a", 63 | -- Protobuf 64 | "%{target_deps}/protobuf/lib/lib*.a", 65 | "-Wl,--no-whole-archive" 66 | } 67 | 68 | -- Begin OpenUSD 69 | add_usd("arch", "gf", "sdf", "tf", "usd", "usdGeom", "usdUtils") 70 | -- End OpenUSD 71 | 72 | -- Add the standard dependencies all OGN projects have; includes, libraries to link, and required compiler flags 73 | add_ogn_dependencies(ogn) 74 | 75 | -- -- RPATH linking 76 | -- linkoptions { 77 | -- "-Wl,-rpath,\\$$ORIGIN/lib" 78 | -- } 79 | cppdialect "C++17" 80 | 81 | -- Additional build options for static linking of abseil 82 | defines { "ABSL_BUILD_DLL=0" } 83 | 84 | filter "action:gmake*" 85 | linkoptions { "-static-libgcc", "-static-libstdc++" } 86 | filter {} 87 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge/plugins/nodes/OgnIsaacBridgeZMQNode.ogn: -------------------------------------------------------------------------------- 1 | { 2 | "OgnIsaacBridgeZMQNode": { 3 | "version": 1, 4 | "uiName": "ZMQ Client Node", 5 | "icon": "icons/isaac-sim.svg", 6 | "description": [ 7 | "This is a ZMQ Client responsible for sending out sensory data" 8 | ], 9 | "categories": ["function"], 10 | "language": "c++", 11 | "scheduling": "pure", 12 | "inputs": { 13 | "execIn": { 14 | "type": "execution", 15 | "description": "The input execution port." 16 | }, 17 | "port": { 18 | "type": "uint", 19 | "description": "ZMQ server port", 20 | "default": 5561 21 | }, 22 | "ip": { 23 | "type": "string", 24 | "description": "ZMQ server ip", 25 | "default": "localhost" 26 | }, 27 | "deltaSimulationTime": { 28 | "type": "double", 29 | "description": "simulation delta time" 30 | }, 31 | "deltaSystemTime": { 32 | "type": "double", 33 | "description": "system delta time" 34 | }, 35 | "simulationTime": { 36 | "type": "double", 37 | "description": "simulation time" 38 | }, 39 | "systemTime": { 40 | "type": "double", 41 | "description": "system time" 42 | }, 43 | "bufferSizeColor": { 44 | "type": "uint64", 45 | "description": "Size (in bytes) of the buffer (0 if the input is a texture)" 46 | }, 47 | "dataPtrColor": { 48 | "type": "uint64", 49 | "description": "Pointer to the raw data (cuda device pointer or host pointer)", 50 | "default": 0 51 | }, 52 | "bufferSizeDepth": { 53 | "type": "uint64", 54 | "description": "Size (in bytes) of the buffer (0 if the input is a texture)" 55 | }, 56 | "dataPtrDepth": { 57 | "type": "uint64", 58 | "description": "Pointer to the raw data (cuda device pointer or host pointer)", 59 | "default": 0 60 | }, 61 | "bboxIdsBBox2d" : { 62 | "type": "uint[]", 63 | "description": "." 64 | }, 65 | "bufferSizeBBox2d" : { 66 | "type": "uint", 67 | "description": "" 68 | }, 69 | "dataBBox2d" : { 70 | "type": "uchar[]", 71 | "description": "" 72 | }, 73 | "heightBBox2d" : { 74 | "type": "uint", 75 | "description": "" 76 | }, 77 | "widthBBox2d" : { 78 | "type": "uint", 79 | "description": "" 80 | }, 81 | "primPathsBBox2d" : { 82 | "type": "token[]", 83 | "description": "" 84 | }, 85 | "labelsBBox2d" : { 86 | "type": "token[]", 87 | "description": "" 88 | }, 89 | "idsBBox2d" : { 90 | "type": "uint[]", 91 | "description": "" 92 | }, 93 | "cameraViewTransform" : { 94 | "type" : "frame[4]", 95 | "description" : "", 96 | "uiName" : "Camera View Transform in ROS world" 97 | }, 98 | "cameraIntrinsics" : { 99 | "type" : "matrixd[3]", 100 | "description" : "", 101 | "uiName" : "Camera Intrinsitcs Matrix" 102 | }, 103 | "cameraWorldScale" : { 104 | "type" : "double[3]", 105 | "description" : "", 106 | "uiName" : "Camera World Scale" 107 | } 108 | }, 109 | "outputs": {} 110 | } 111 | } -------------------------------------------------------------------------------- /assets/props/camera.usda: -------------------------------------------------------------------------------- 1 | #usda 1.0 2 | ( 3 | customLayerData = { 4 | dictionary cameraSettings = { 5 | dictionary Front = { 6 | double3 position = (5, 0, 0) 7 | double radius = 5 8 | } 9 | dictionary Perspective = { 10 | double3 position = (-1.4111027697500935, 2.015850069579361, 1.1834364504018025) 11 | double3 target = (-0.16134589688674472, 0.23661424000629805, 0.5193712021654908) 12 | } 13 | dictionary Right = { 14 | double3 position = (0, -5, 0) 15 | double radius = 5 16 | } 17 | dictionary Top = { 18 | double3 position = (0, 0, 5) 19 | double radius = 5 20 | } 21 | string boundCamera = "/OmniverseKit_Persp" 22 | } 23 | dictionary omni_layer = { 24 | string authoring_layer = "./camera.usda" 25 | dictionary locked = { 26 | bool "./looks.usd" = 1 27 | bool "./model.usd" = 1 28 | bool "./physics.usd" = 1 29 | bool "./scale.usd" = 1 30 | bool "./sensor.usd" = 1 31 | } 32 | dictionary muteness = { 33 | } 34 | } 35 | dictionary physicsSettings = { 36 | int "/persistent/simulation/minFrameRate" = 60 37 | } 38 | dictionary renderSettings = { 39 | float3 "rtx:debugView:pixelDebug:textColor" = (0, 1e18, 0) 40 | float3 "rtx:fog:fogColor" = (0.75, 0.75, 0.75) 41 | float3 "rtx:index:backgroundColor" = (0, 0, 0) 42 | float3 "rtx:index:regionOfInterestMax" = (0, 0, 0) 43 | float3 "rtx:index:regionOfInterestMin" = (0, 0, 0) 44 | float3 "rtx:post:backgroundZeroAlpha:backgroundDefaultColor" = (0, 0, 0) 45 | float3 "rtx:post:colorcorr:contrast" = (1, 1, 1) 46 | float3 "rtx:post:colorcorr:gain" = (1, 1, 1) 47 | float3 "rtx:post:colorcorr:gamma" = (1, 1, 1) 48 | float3 "rtx:post:colorcorr:offset" = (0, 0, 0) 49 | float3 "rtx:post:colorcorr:saturation" = (1, 1, 1) 50 | float3 "rtx:post:colorgrad:blackpoint" = (0, 0, 0) 51 | float3 "rtx:post:colorgrad:contrast" = (1, 1, 1) 52 | float3 "rtx:post:colorgrad:gain" = (1, 1, 1) 53 | float3 "rtx:post:colorgrad:gamma" = (1, 1, 1) 54 | float3 "rtx:post:colorgrad:lift" = (0, 0, 0) 55 | float3 "rtx:post:colorgrad:multiply" = (1, 1, 1) 56 | float3 "rtx:post:colorgrad:offset" = (0, 0, 0) 57 | float3 "rtx:post:colorgrad:whitepoint" = (1, 1, 1) 58 | float3 "rtx:post:lensDistortion:lensFocalLengthArray" = (10, 30, 50) 59 | float3 "rtx:post:lensFlares:anisoFlareFalloffX" = (450, 475, 500) 60 | float3 "rtx:post:lensFlares:anisoFlareFalloffY" = (10, 10, 10) 61 | float3 "rtx:post:lensFlares:cutoffPoint" = (2, 2, 2) 62 | float3 "rtx:post:lensFlares:haloFlareFalloff" = (10, 10, 10) 63 | float3 "rtx:post:lensFlares:haloFlareRadius" = (75, 75, 75) 64 | float3 "rtx:post:lensFlares:isotropicFlareFalloff" = (50, 50, 50) 65 | float3 "rtx:post:lensFlares:spectralBlurWavelengthRange" = (380, 550, 770) 66 | float3 "rtx:post:tonemap:whitepoint" = (1, 1, 1) 67 | float3 "rtx:raytracing:indexdirect:svoBrickSize" = (32, 32, 32) 68 | float3 "rtx:raytracing:inscattering:singleScatteringAlbedo" = (0.9, 0.9, 0.9) 69 | float3 "rtx:raytracing:inscattering:transmittanceColor" = (0.5, 0.5, 0.5) 70 | float3 "rtx:sceneDb:ambientLightColor" = (0.1, 0.1, 0.1) 71 | float2 "rtx:viewTile:resolution" = (0, 0) 72 | } 73 | } 74 | defaultPrim = "World" 75 | endTimeCode = 1000000 76 | metersPerUnit = 1 77 | startTimeCode = 0 78 | subLayers = [ 79 | @./sensor.usd@, 80 | @./physics.usd@, 81 | @./looks.usd@, 82 | @./scale.usd@, 83 | @./model.usd@ 84 | ] 85 | timeCodesPerSecond = 60 86 | upAxis = "Z" 87 | ) 88 | 89 | def Xform "World" 90 | { 91 | custom string cmd_path = "" 92 | } 93 | 94 | -------------------------------------------------------------------------------- /tools/repoman/repoman_bootstrapper.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2019-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: MIT 3 | # 4 | 5 | import json 6 | import logging 7 | import os 8 | import platform 9 | from pathlib import Path 10 | 11 | logger = logging.getLogger(__name__) 12 | 13 | REPO_ROOT = os.path.join(os.path.dirname(os.path.normpath(__file__)), "../..") 14 | REPO_CACHE_FILE = os.path.join(REPO_ROOT, "repo-cache.json") 15 | 16 | 17 | def repoman_bootstrap(): 18 | _path_checks() 19 | _prep_cache_paths() 20 | 21 | 22 | def _path_checks(): 23 | """Check for problematic path conditions and warn appropriately.""" 24 | cwd = os.getcwd() 25 | if " " in cwd: 26 | logger.warning( 27 | "Current working directory: %s contains whitespace which may cause issues with some tooling such as premake within repo_build. It is recommended to move your project to a path without spaces.", 28 | cwd, 29 | ) 30 | 31 | # Check if current working directory is within a OneDrive folder 32 | if platform.system() == "Windows": 33 | onedrive_path = os.getenv("OneDrive") # For personal OneDrive 34 | onedrive_business_path = os.getenv("OneDriveCommercial") # For business accounts 35 | 36 | if not onedrive_path and not onedrive_business_path: 37 | # OneDrive is not installed or synced 38 | return 39 | 40 | if (onedrive_path and cwd.startswith(onedrive_path)) or ( 41 | onedrive_business_path and cwd.startswith(onedrive_business_path) 42 | ): 43 | logger.warning( 44 | "Current working directory: %s appears to be within a OneDrive folder. This may cause filesystem issues with Packman linking dependencies. It is recommended to move your project outside of OneDrive.", 45 | cwd, 46 | ) 47 | 48 | 49 | def _prep_cache_paths(): 50 | """ 51 | There are several environment variables that repo_man can optionally set to control where various caches are placed. They will all be relative to the repository root. 52 | - PM_PACKAGES_ROOT: this is where Packman stores its package cache 53 | - PIP_CACHE_DIR: this is where pip stores its wheel cache 54 | - UV_CACHE_DIR: this is where uv stores its wheel and package cache 55 | 56 | There are several gating flags as well to prevent repo_man from using the pip/uv default cache dir envvars unless explicitly set by us. 57 | - OM_PIP_CACHE: gating pip cache dir flag for omni.repo.man.deps.pip_install_requirements 58 | - OM_UV_CACHE: gating uv cache dir flag for omni.repo.man.deps._uv_requirements_load 59 | """ 60 | 61 | repo_cache_file = Path(REPO_CACHE_FILE) 62 | if repo_cache_file.is_file(): 63 | # cache file is present, read it in and set environment variables. 64 | cache_path_data = json.loads(repo_cache_file.read_text()) 65 | # resolve REPO_ROOT rather than relative path to avoid any chdir shenanigans. 66 | resolved_root = Path(REPO_ROOT).resolve() 67 | 68 | for cache, cache_path in cache_path_data.items(): 69 | # Expand $HOME and ~ 70 | resolved_path = Path(os.path.expandvars(os.path.expanduser(cache_path))) 71 | if not resolved_path.is_dir(): 72 | # Relative path to current working directory or absolute path is not present. 73 | # It's possible repo was somehow executed outside of the repository root. 74 | resolved_path = resolved_root / cache_path 75 | 76 | # Fully resolve path to avoid weird dir popping in some workflows. 77 | os.environ[cache] = resolved_path.resolve().as_posix() 78 | resolved_path.mkdir(parents=True, exist_ok=True) 79 | 80 | # Set repo_man breadcrumb to respect PIP_CACHE_DIR and UV_CACHE_DIR. 81 | # Unset OMNI_REPO_ROOT to force the caching of installed Python deps 82 | # in the packman cache dir. 83 | if cache == "PIP_CACHE_DIR": 84 | os.environ["OM_PIP_CACHE"] = "1" 85 | os.environ["OMNI_REPO_ROOT"] = "" 86 | elif cache == "UV_CACHE_DIR": 87 | os.environ["OM_UV_CACHE"] = "1" 88 | os.environ["OMNI_REPO_ROOT"] = "" 89 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/isaacsim/zmq/bridge/examples/core/rate_limiter.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: MIT 3 | 4 | import time 5 | 6 | from isaacsim.core.api.world import World 7 | 8 | 9 | # Concept mechanisim for controling stream rate, only used when not using c++ nodes 10 | class RateLimitedCallback: 11 | """ 12 | Controls the execution rate of callbacks in the physics simulation. 13 | 14 | This class ensures that a callback function is executed at a specified rate, 15 | regardless of the physics simulation step frequency. It also provides an 16 | adaptive rate mechanism that adjusts the execution rate based on the actual 17 | execution time of the callback. 18 | 19 | Note: This class is only used when not using C++ OGN nodes for streaming. 20 | """ 21 | 22 | def __init__( 23 | self, 24 | name: str, 25 | rate: float, 26 | fn: callable, 27 | start_time: float = 0.0, 28 | adeptive_rate: bool = True, 29 | ) -> None: 30 | """ 31 | Initialize a rate-limited callback. 32 | 33 | Args: 34 | name (str): Name of the callback for identification 35 | rate (float): Target execution rate in seconds (1/Hz) 36 | fn (callable): Function to call at the specified rate 37 | start_time (float): Real world time at which the simulation started 38 | adeptive_rate (bool): Whether to adaptively adjust the rate based on execution time 39 | """ 40 | self.world = World.instance() 41 | self.name = name 42 | self.fn = fn # function to call at rate 43 | self.rate = rate # 1/Hz 44 | self.previous_step_time = 0 45 | self.accumulated_time = 0 46 | self.last_exec_time = 0 47 | 48 | self.adeptive_rate = adeptive_rate 49 | self.start_time = start_time # real world time at which the simulation started 50 | self.interval = 3 # seconds between rate adjustments 51 | self.accumulated_interval_time = 0 52 | self.exec_count = 0 53 | self.actual_rate = rate 54 | self.adj_rate = rate 55 | self.rates_diff = 0 56 | 57 | def rate_limit(self, dt: float) -> None: 58 | """ 59 | Execute the callback function at the specified rate. 60 | 61 | This method is called every simulation step, but only executes the callback 62 | function when enough time has accumulated to match the specified rate. 63 | 64 | When adaptive rate is enabled, it measures the actual execution rate and 65 | adjusts the target rate to compensate for execution time of the callback. 66 | 67 | Args: 68 | dt (float): Time step of the physics simulation 69 | """ 70 | # -> Times here are real world times 71 | real_time = time.time() - self.start_time 72 | interval_time = real_time - self.accumulated_interval_time 73 | 74 | # Sample the actual rate each interval, by counting executions 75 | # Find the difference and set new adjusted rate 76 | if interval_time >= self.interval and self.adeptive_rate: 77 | self.accumulated_interval_time = real_time 78 | interval_rate = self.exec_count / interval_time 79 | self.actual_rate = (1 / interval_rate) if interval_rate > 0 else self.rate 80 | self.exec_count = 0 81 | 82 | # Adjust rate to compensate for execution time 83 | self.rates_diff = self.rate - self.actual_rate 84 | if abs(self.rate - self.actual_rate) > 0.001: 85 | self.adj_rate += self.rates_diff 86 | 87 | if not self.adeptive_rate: 88 | self.adj_rate = self.rate 89 | 90 | # -> Times here are simulated physical times 91 | elapsed_time = self.world.current_time - self.previous_step_time 92 | self.previous_step_time = self.world.current_time 93 | 94 | # Accumulate time until we reach the adjusted rate 95 | self.accumulated_time += elapsed_time 96 | 97 | # Execute the callback when enough time has accumulated 98 | if self.accumulated_time >= self.adj_rate: 99 | self.last_exec_time = self.fn(self.rate, self.world.current_time) 100 | self.accumulated_time -= self.adj_rate 101 | self.exec_count += 1 102 | -------------------------------------------------------------------------------- /isaac-zmq-server/src/isaac_zmq_server/fonts/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 The Inter Project Authors (https://github.com/rsms/inter) 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | ----------------------------------------------------------- 8 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 9 | ----------------------------------------------------------- 10 | 11 | PREAMBLE 12 | The goals of the Open Font License (OFL) are to stimulate worldwide 13 | development of collaborative font projects, to support the font creation 14 | efforts of academic and linguistic communities, and to provide a free and 15 | open framework in which fonts may be shared and improved in partnership 16 | with others. 17 | 18 | The OFL allows the licensed fonts to be used, studied, modified and 19 | redistributed freely as long as they are not sold by themselves. The 20 | fonts, including any derivative works, can be bundled, embedded, 21 | redistributed and/or sold with any software provided that any reserved 22 | names are not used by derivative works. The fonts and derivatives, 23 | however, cannot be released under any other type of license. The 24 | requirement for fonts to remain under this license does not apply 25 | to any document created using the fonts or their derivatives. 26 | 27 | DEFINITIONS 28 | "Font Software" refers to the set of files released by the Copyright 29 | Holder(s) under this license and clearly marked as such. This may 30 | include source files, build scripts and documentation. 31 | 32 | "Reserved Font Name" refers to any names specified as such after the 33 | copyright statement(s). 34 | 35 | "Original Version" refers to the collection of Font Software components as 36 | distributed by the Copyright Holder(s). 37 | 38 | "Modified Version" refers to any derivative made by adding to, deleting, 39 | or substituting -- in part or in whole -- any of the components of the 40 | Original Version, by changing formats or by porting the Font Software to a 41 | new environment. 42 | 43 | "Author" refers to any designer, engineer, programmer, technical 44 | writer or other person who contributed to the Font Software. 45 | 46 | PERMISSION AND CONDITIONS 47 | Permission is hereby granted, free of charge, to any person obtaining 48 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 49 | redistribute, and sell modified and unmodified copies of the Font 50 | Software, subject to the following conditions: 51 | 52 | 1) Neither the Font Software nor any of its individual components, 53 | in Original or Modified Versions, may be sold by itself. 54 | 55 | 2) Original or Modified Versions of the Font Software may be bundled, 56 | redistributed and/or sold with any software, provided that each copy 57 | contains the above copyright notice and this license. These can be 58 | included either as stand-alone text files, human-readable headers or 59 | in the appropriate machine-readable metadata fields within text or 60 | binary files as long as those fields can be easily viewed by the user. 61 | 62 | 3) No Modified Version of the Font Software may use the Reserved Font 63 | Name(s) unless explicit written permission is granted by the corresponding 64 | Copyright Holder. This restriction only applies to the primary font name as 65 | presented to the users. 66 | 67 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 68 | Software shall not be used to promote, endorse or advertise any 69 | Modified Version, except to acknowledge the contribution(s) of the 70 | Copyright Holder(s) and the Author(s) or with their explicit written 71 | permission. 72 | 73 | 5) The Font Software, modified or unmodified, in part or in whole, 74 | must be distributed entirely under this license, and must not be 75 | distributed under any other license. The requirement for fonts to 76 | remain under this license does not apply to any document created 77 | using the Font Software. 78 | 79 | TERMINATION 80 | This license becomes null and void if any of the above conditions are 81 | not met. 82 | 83 | DISCLAIMER 84 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 85 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 86 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 87 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 88 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 89 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 90 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 91 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 92 | OTHER DEALINGS IN THE FONT SOFTWARE. -------------------------------------------------------------------------------- /tools/packman/packmanconf.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2024 NVIDIA CORPORATION 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Use this file to bootstrap packman into your Python environment. Simply 16 | # add the path by doing sys.insert to where packmanconf.py is located and then execute: 17 | # 18 | # >>> import packmanconf 19 | # >>> packmanconf.init() 20 | # 21 | # It will use the configured remote(s) and the version of packman in the same folder, 22 | # giving you full access to the packman API via the following module 23 | # 24 | # >> import packmanapi 25 | # >> dir(packmanapi) 26 | 27 | import os 28 | import platform 29 | import sys 30 | 31 | 32 | MIN_PYTHON_VERSION = (3, 10, 0) 33 | MAX_PYTHON_VERSION = (3, 11, 2) 34 | 35 | 36 | def is_valid_python_version(version: tuple[int, int, int] = sys.version_info[:3]): 37 | return MIN_PYTHON_VERSION <= version <= MAX_PYTHON_VERSION 38 | 39 | 40 | def validate_python_version(version: tuple[int, int, int] = sys.version_info[:3]): 41 | if not is_valid_python_version(version): 42 | 43 | def ver_str(pyver): 44 | return ".".join(str(x) for x in pyver) 45 | 46 | raise RuntimeError( 47 | f"This version of packman requires Python {ver_str(MIN_PYTHON_VERSION)} " 48 | f"up to {ver_str(MAX_PYTHON_VERSION)}, but {ver_str(version)} was provided" 49 | ) 50 | 51 | 52 | def init(): 53 | """Call this function to initialize the packman configuration. 54 | 55 | Calls to the packman API will work after successfully calling this function. 56 | 57 | Note: 58 | This function only needs to be called once during the execution of your 59 | program. Calling it repeatedly is harmless but wasteful. 60 | Compatibility with your Python interpreter is checked and upon failure 61 | the function will report what is required. 62 | 63 | Example: 64 | >>> import packmanconf 65 | >>> packmanconf.init() 66 | >>> import packmanapi 67 | >>> packmanapi.set_verbosity_level(packmanapi.VERBOSITY_HIGH) 68 | """ 69 | validate_python_version() 70 | conf_dir = os.path.dirname(os.path.abspath(__file__)) 71 | os.environ["PM_INSTALL_PATH"] = conf_dir 72 | packages_root = get_packages_root(conf_dir) 73 | version = get_version(conf_dir) 74 | module_dir = get_module_dir(conf_dir, packages_root, version) 75 | sys.path.insert(1, module_dir) 76 | 77 | 78 | def get_packages_root(conf_dir: str) -> str: 79 | root = os.getenv("PM_PACKAGES_ROOT") 80 | if not root: 81 | platform_name = platform.system() 82 | if platform_name == "Windows": 83 | drive, _ = os.path.splitdrive(conf_dir) 84 | root = os.path.join(drive, "packman-repo") 85 | elif platform_name == "Darwin": 86 | # macOS 87 | root = os.path.join( 88 | os.path.expanduser("~"), "Library/Application Support/packman-cache" 89 | ) 90 | elif platform_name == "Linux": 91 | try: 92 | cache_root = os.environ["XDG_HOME_CACHE"] 93 | except KeyError: 94 | cache_root = os.path.join(os.path.expanduser("~"), ".cache") 95 | return os.path.join(cache_root, "packman") 96 | else: 97 | raise RuntimeError(f"Unsupported platform '{platform_name}'") 98 | # make sure the path exists: 99 | os.makedirs(root, exist_ok=True) 100 | return root 101 | 102 | 103 | def get_module_dir(conf_dir, packages_root: str, version: str) -> str: 104 | module_dir = os.path.join(packages_root, "packman-common", version) 105 | if not os.path.exists(module_dir): 106 | import tempfile 107 | 108 | tf = tempfile.NamedTemporaryFile(delete=False) 109 | target_name = tf.name 110 | tf.close() 111 | # Forced to change to https because some customers will simply not allow http, 112 | # even when it's used in a safe way (with download checksum verification). 113 | # See issue #367 for more background. 114 | url = f"https://bootstrap.packman.nvidia.com/packman-common@{version}.zip" 115 | print(f"Downloading '{url}' ...") 116 | import urllib.request 117 | 118 | urllib.request.urlretrieve(url, target_name) 119 | from importlib.machinery import SourceFileLoader 120 | 121 | # import module from path provided 122 | script_path = os.path.join(conf_dir, "bootstrap", "install_package.py") 123 | ip = SourceFileLoader("install_package", script_path).load_module() 124 | print("Unpacking ...") 125 | ip.install_common_module(target_name, module_dir) 126 | os.unlink(tf.name) 127 | return module_dir 128 | 129 | 130 | def get_version(conf_dir: str): 131 | path = os.path.join(conf_dir, "packman") 132 | if not os.path.exists(path): # in dev repo fallback 133 | path += ".sh" 134 | with open(path, "rt", encoding="utf8") as launch_file: 135 | for line in launch_file.readlines(): 136 | if "PM_PACKMAN_VERSION" in line: 137 | _, value = line.split("=") 138 | return value.strip() 139 | raise RuntimeError(f"Unable to find 'PM_PACKMAN_VERSION' in '{path}'") 140 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/isaacsim/zmq/bridge/examples/mission.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: MIT 3 | 4 | import asyncio 5 | import time 6 | from pathlib import Path 7 | import zmq.asyncio 8 | 9 | import omni 10 | import carb 11 | 12 | import isaacsim.core.utils.stage as stage_utils 13 | from isaacsim.core.api.world import World 14 | 15 | from . import EXT_NAME, ZMQClient 16 | 17 | 18 | class Mission: 19 | """Base class for all ZMQ bridge missions. 20 | 21 | This class provides the foundation for creating missions that communicate with external 22 | applications via ZeroMQ. Derived classes should implement the mission-specific logic 23 | by overriding methods like before_reset_world, after_reset_world, start_mission, etc. 24 | """ 25 | 26 | name = "Mission" 27 | world_usd_path = None # Should be set by derived classes to point to the USD world file 28 | 29 | def __init__(self, server_ip: str = "localhost"): 30 | self.zmq_client = ZMQClient(server_ip=server_ip) 31 | 32 | self.receive_commands = False 33 | 34 | def before_reset_world(self) -> None: 35 | """ 36 | Prepare the world for reset 37 | """ 38 | carb.log_warn(f"[{EXT_NAME}] before reset world: NOT IMPLEMENTED") 39 | 40 | def after_reset_world(self) -> None: 41 | """ 42 | Execute any operation that requried a clean world. 43 | """ 44 | carb.log_warn(f"[{EXT_NAME}] after reset world: NOT IMPLEMENTED") 45 | 46 | def start_mission(self) -> None: 47 | """ 48 | Starts the mission by initializing the necessary sockets, annotators, and callbacks. 49 | """ 50 | carb.log_warn(f"[{EXT_NAME}] start mission: NOT IMPLEMENTED") 51 | 52 | def reset_world(self) -> None: 53 | self.world = World(physics_dt=1.0 / self.physics_dt) 54 | # Clear only the registry to maintain stage structure 55 | self.world.scene.clear(registry_only=True) 56 | self.before_reset_world() 57 | self.world.reset() 58 | self.after_reset_world() 59 | 60 | def stop_mission(self) -> None: 61 | """ 62 | Stops the current mission by setting the `receive_commands` flag to False and removing all callbacks from the ZMQ client. 63 | It also ensures that all connections are disconnected asynchronously. 64 | 65 | """ 66 | carb.log_warn(f"[{EXT_NAME}] stop mission: NOT IMPLEMENTED") 67 | 68 | def subscribe_to_protobuf_in_loop( 69 | self, socket: zmq.asyncio.Socket, proto_class, fn: callable, *args, **kwargs 70 | ) -> None: 71 | """ 72 | Runs a loop that continuously receives protobuf messages from a ZeroMQ socket and calls a given function for each received message. 73 | 74 | Args: 75 | socket (zmq.asyncio.Socket): The ZeroMQ socket to receive data from. 76 | proto_class: The protobuf message class to parse the received data. 77 | fn (callable): The function to call for each received protobuf message. 78 | """ 79 | 80 | async def _async_executor() -> None: 81 | # Continue receiving data as long as receive_commands flag is True 82 | while self.receive_commands: 83 | proto_msg = await self.zmq_client.receive_protobuf(socket, proto_class) 84 | fn(proto_msg, *args, **kwargs) 85 | carb.log_info(f"[{socket}] Stopped listening for protobuf messages.") 86 | 87 | asyncio.ensure_future(_async_executor()) 88 | 89 | @classmethod 90 | def mission_usd_path(cls) -> str: 91 | """ 92 | For the headless example, we need to import the stage progrematically. 93 | """ 94 | # Get the extension path to locate assets 95 | manager = omni.kit.app.get_app().get_extension_manager() 96 | extension_path = manager.get_extension_path_by_module("isaacsim.zmq.bridge.examples") 97 | data_path = Path(extension_path).joinpath("data") 98 | assets_path = data_path.parent.parent.parent / "assets" 99 | source_usd = str(assets_path / cls.world_usd_path) 100 | 101 | return source_usd 102 | 103 | @classmethod 104 | def load_mission(cls, source_usd: str) -> None: 105 | """ 106 | Loads the mission by opening the stage file. 107 | """ 108 | print(f"[{EXT_NAME}] loading mission") 109 | stage_utils.open_stage(source_usd) 110 | 111 | def reset_world_async(self) -> None: 112 | carb.log_warn(f"[{EXT_NAME}] reset world async: NOT IMPLEMENTED") 113 | 114 | @classmethod 115 | async def _async_load(cls, source_usd: str) -> None: 116 | await stage_utils.open_stage_async(source_usd) 117 | 118 | @classmethod 119 | def load_mission_async(cls) -> None: 120 | print(f"[{EXT_NAME}] loading mission") 121 | asyncio.ensure_future(cls._async_load()) 122 | 123 | async def stop_mission_async(self) -> None: 124 | """ 125 | Stop the mission and clean up resources. 126 | """ 127 | carb.log_warn(f"[{EXT_NAME}] stop mission: NOT IMPLEMENTED") 128 | 129 | async def _reset(self) -> None: 130 | """ 131 | similar to reset_world() but async 132 | """ 133 | await self.stop_mission_async() 134 | self.world = World(physics_dt=1.0 / self.physics_dt) 135 | # Clear only the registry to maintain stage structure 136 | self.world.scene.clear(registry_only=True) 137 | # Initialize simulation context asynchronously 138 | await self.world.initialize_simulation_context_async() 139 | self.before_reset_world() 140 | await self.world.reset_async() 141 | self.after_reset_world() 142 | self.start_mission() 143 | 144 | def reset_world_async(self) -> None: 145 | asyncio.ensure_future(self._reset()) 146 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/isaacsim/zmq/bridge/examples/extension.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: MIT 3 | 4 | 5 | from functools import partial 6 | 7 | import carb 8 | import omni.ext 9 | import omni.ui as ui 10 | import omni.usd 11 | from omni.kit.menu.utils import MenuItemDescription, add_menu_items, remove_menu_items 12 | from omni.kit.notification_manager import post_notification 13 | from omni.kit.widget.toolbar import get_instance 14 | import omni.timeline 15 | 16 | from . import EXT_NAME 17 | from .example_missions import FrankaMultiVisionMission, FrankaVisionMission 18 | from .ui import ZMQClientButtonGroup 19 | 20 | 21 | class IsaacSimZMQBridgeExamples(omni.ext.IExt): 22 | """Extension for demonstrating ZMQ bridge functionality in Isaac Sim. 23 | 24 | This extension provides UI elements and mission management for ZMQ bridge examples, 25 | allowing users to load different example missions and control their execution. 26 | """ 27 | 28 | server_ip = "localhost" 29 | 30 | def on_startup(self, ext_id) -> None: 31 | self.mission = None 32 | 33 | # Append example buttons to the main isaac sim toolbar 34 | self.toolbar = get_instance() 35 | self.button_group = ZMQClientButtonGroup() 36 | self.toolbar.add_widget(self.button_group, 100, self.toolbar.get_context()) 37 | 38 | # Append example menu items to the main isaac sim menu 39 | self._franka_mission_menu = MenuItemDescription( 40 | name="Franka RMPFlow", 41 | glyph="plug.svg", 42 | onclick_fn=FrankaVisionMission.load_mission_async, 43 | ) 44 | self._franka_multi_mission_menu = MenuItemDescription( 45 | name="Franka RMPFlow (Multi Camera)", 46 | glyph="plug.svg", 47 | onclick_fn=FrankaMultiVisionMission.load_mission_async, 48 | ) 49 | 50 | self._menu_items = [ 51 | MenuItemDescription( 52 | name="Isaac ZMQ Examples", 53 | glyph="plug.svg", 54 | sub_menu=[self._franka_mission_menu, self._franka_multi_mission_menu], 55 | ) 56 | ] 57 | add_menu_items(self._menu_items, "Create") 58 | 59 | # Subscribe to stage events to detect when a new stage is loaded / Cleared 60 | self.stage_load_sub = ( 61 | omni.usd.get_context() 62 | .get_stage_event_stream() 63 | .create_subscription_to_pop(self.stage_event, name="event_stage_loaded") 64 | ) 65 | self.check_stage() 66 | 67 | # Subscribe to timeline events to detect when the timeline is stopped 68 | self.timeline = omni.timeline.get_timeline_interface() 69 | self.timeline_sub = ( 70 | self.timeline 71 | .get_timeline_event_stream() 72 | .create_subscription_to_pop(self.timeline_event, 73 | name="timeline_event") 74 | ) 75 | 76 | def timeline_event(self, event) -> None: 77 | if event.type == int(omni.timeline.TimelineEventType.STOP): 78 | if self.mission: 79 | self.mission.stop_mission() 80 | 81 | def stage_event(self, event) -> None: 82 | """Handle stage events. 83 | 84 | When a stage is opened, check if it matches any of our example missions. 85 | """ 86 | if event.type == int(omni.usd.StageEventType.OPENED): 87 | self.check_stage() 88 | 89 | def check_stage(self) -> None: 90 | """Check the current stage and set the appropriate mission. 91 | 92 | This method examines the loaded USD file and sets the corresponding mission 93 | if it matches one of our example missions. 94 | """ 95 | # set the mission based on the loaded stage 96 | stage = omni.usd.get_context().get_stage() 97 | if not stage: 98 | return 99 | usd_path = stage.GetRootLayer().realPath 100 | if usd_path.endswith(FrankaVisionMission.world_usd_path): 101 | self._set_mission(FrankaVisionMission, "FrankaVisionMission") 102 | elif usd_path.endswith(FrankaMultiVisionMission.world_usd_path): 103 | self._set_mission(FrankaMultiVisionMission, "FrankaMultiVisionMission") 104 | else: 105 | self._clear_mission() 106 | return 107 | 108 | def _set_mission(self, mission_class, mission_name) -> None: 109 | """Set the active mission. 110 | 111 | Creates an instance of the specified mission class and assigns it to the button group. 112 | 113 | Args: 114 | mission_class: The mission class to instantiate 115 | mission_name: The name of the mission for logging 116 | """ 117 | print(f"[{EXT_NAME}] Setting {mission_name}.") 118 | post_notification(f"[{EXT_NAME}] Setting {mission_name}.", duration=2) 119 | self.mission = mission_class(server_ip=self.server_ip) 120 | self.button_group.set_mission(self.mission) 121 | self.button_group.set_visiblity(True) 122 | 123 | def _clear_mission(self) -> None: 124 | """Clear the active mission. 125 | 126 | Called when the loaded stage doesn't match any of our example missions. 127 | """ 128 | carb.log_warn(f"[{EXT_NAME}] Stage is empty - Setting mission to None") 129 | post_notification(f"[{EXT_NAME}] Setting mission to None", duration=2) 130 | self.mission = None 131 | self.button_group.set_mission(None) 132 | self.button_group.set_visiblity(False) 133 | 134 | def on_shutdown(self) -> None: 135 | """Clean up resources when the extension is disabled. 136 | 137 | Stops any active mission and removes UI elements. 138 | """ 139 | if self.mission: 140 | self.mission.stop_mission() 141 | 142 | self.toolbar.remove_widget(self.button_group) 143 | self.button_group = None 144 | 145 | remove_menu_items(self._menu_items, "Create") 146 | 147 | self.stage_load_sub = None 148 | self.timeline_sub = None 149 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge/plugins/nodes/OgnIsaacBridgeZMQCamera.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | 23 | using omni::graph::core::Type; 24 | using omni::graph::core::BaseDataType; 25 | 26 | 27 | namespace isaacsim { 28 | namespace zmq { 29 | namespace bridge { 30 | 31 | 32 | class OgnIsaacBridgeZMQCamera 33 | { 34 | // int m_evaluationCount{ 0 }; 35 | 36 | public: 37 | OgnIsaacBridgeZMQCamera() 38 | { 39 | CARB_LOG_INFO("OgnIsaacBridgeZMQCamera::constructor\n"); 40 | } 41 | ~OgnIsaacBridgeZMQCamera() 42 | { 43 | CARB_LOG_INFO("OgnIsaacBridgeZMQCamera::destructor\n"); 44 | } 45 | 46 | 47 | static bool compute(OgnIsaacBridgeZMQCameraDatabase& db); 48 | 49 | static pxr::GfMatrix4d get_view_matrix_ros(const pxr::UsdPrim& cameraPrim); 50 | 51 | static pxr::GfMatrix3d get_intrinsics_matrix(const pxr::UsdPrim& cameraPrim, uint32_t width, uint32_t height); 52 | 53 | }; 54 | 55 | 56 | pxr::GfMatrix4d OgnIsaacBridgeZMQCamera::get_view_matrix_ros(const pxr::UsdPrim& cameraPrim) 57 | { 58 | // c++ implementation omni.isaac.sensor.camera.Camera.get_view_matrix_ros() by ai :) 59 | 60 | // Step 1: Get the world-to-camera transformation matrix 61 | pxr::UsdGeomXformable xformable(cameraPrim); 62 | pxr::GfMatrix4d local_to_world_tf = xformable.ComputeLocalToWorldTransform(pxr::UsdTimeCode::Default()); 63 | 64 | // Convert the matrix type from double to float and transpose 65 | pxr::GfMatrix4d world_w_cam_u_T = local_to_world_tf.GetTranspose(); 66 | 67 | // Step 2: Define R_U_TRANSFORM as a fixed transformation matrix 68 | static const pxr::GfMatrix4d r_u_transform_converted( 69 | 1, 0, 0, 0, 70 | 0, -1, 0, 0, 71 | 0, 0, -1, 0, 72 | 0, 0, 0, 1 73 | ); 74 | 75 | // Step 3: Perform matrix inversion using GfMatrix4f's Inverse() method 76 | pxr::GfMatrix4d inverse_world_w_cam_u_T = world_w_cam_u_T.GetInverse(); 77 | 78 | // Step 4: Perform matrix multiplication of r_u_transform_converted and inverse_world_w_cam_u_T 79 | pxr::GfMatrix4d result_matrix = r_u_transform_converted * inverse_world_w_cam_u_T; 80 | 81 | // Return the final view matrix 82 | return result_matrix; 83 | 84 | 85 | // results from a python call: 86 | // [[ 8.8442159e-01 -4.1348362e-01 -2.1640186e-01 0.0000000e+00] 87 | // [-4.0163556e-01 -9.1051155e-01 9.8272912e-02 0.0000000e+00] 88 | // [-2.3767065e-01 -3.2561711e-09 -9.7134584e-01 0.0000000e+00] 89 | // [ 0.0000000e+00 0.0000000e+00 0.0000000e+00 1.0000000e+00]] 90 | 91 | //results from this call - appear to be 10x smaller... 92 | // 0.884422 -0.413484 -0.216402 0.000000 93 | // -0.401636 -0.910512 0.098273 0.000000 94 | // -0.237671 0.000000 -0.971346 0.000000 95 | // 0.000000 0.000000 0.000000 1.000000 96 | } 97 | 98 | 99 | pxr::GfMatrix3d OgnIsaacBridgeZMQCamera::get_intrinsics_matrix(const pxr::UsdPrim& cameraPrim, uint32_t width, uint32_t height) 100 | { 101 | // c++ implementation omni.isaac.sensor.camera.Camera.get_intrinsics_matrix() by ai :) 102 | 103 | // Get attributes for focal length and horizontal aperture 104 | pxr::UsdGeomCamera camera(cameraPrim); 105 | 106 | pxr::VtValue focal_length_value; 107 | camera.GetFocalLengthAttr().Get(&focal_length_value, pxr::UsdTimeCode::Default()); 108 | 109 | static constexpr float scale_factor = 10.0f; // Used in multiple places 110 | float focal_length = focal_length_value.Get() / scale_factor; 111 | 112 | pxr::VtValue horizontal_aperture_value; 113 | camera.GetHorizontalApertureAttr().Get(&horizontal_aperture_value, pxr::UsdTimeCode::Default()); 114 | float horizontal_aperture = horizontal_aperture_value.Get() / scale_factor; 115 | 116 | float vertical_aperture = horizontal_aperture * (static_cast(height) / width); 117 | 118 | // Calculate intrinsic parameters 119 | float fx = width * focal_length / horizontal_aperture; 120 | float fy = height * focal_length / vertical_aperture; 121 | float cx = width * 0.5f; 122 | float cy = height * 0.5f; 123 | 124 | // Return the intrinsic matrix as pxr::GfMatrix3f 125 | return pxr::GfMatrix3d(fx, 0.0f, cx, 0.0f, fy, cy, 0.0f, 0.0f, 1.0f); 126 | } 127 | 128 | 129 | bool OgnIsaacBridgeZMQCamera::compute(OgnIsaacBridgeZMQCameraDatabase& db) 130 | { 131 | // Get USD Stage 132 | const IPath& iPath = *db.abi_context().iPath; 133 | long stageId = db.abi_context().iContext->getStageId(db.abi_context()); 134 | pxr::UsdStageRefPtr stage = pxr::UsdUtilsStageCache::Get().Find(pxr::UsdStageCache::Id::FromLongInt(stageId)); 135 | 136 | // // // Get Camera Prim 137 | std::string cameraPrimPathStr = db.inputs.cameraPrimPath(); 138 | if (cameraPrimPathStr.empty()) 139 | { 140 | db.logWarning("No target prim path specified"); 141 | return true; 142 | } 143 | pxr::SdfPath cameraPrimPath(cameraPrimPathStr.c_str()); 144 | pxr::UsdPrim cameraPrim = stage->GetPrimAtPath(cameraPrimPath); 145 | 146 | // // Get the local-to-world transform of the camera prim 147 | pxr::UsdGeomXformable xformable(cameraPrim); 148 | pxr::GfMatrix4d prim_tf = xformable.ComputeLocalToWorldTransform(pxr::UsdTimeCode::Default()); 149 | pxr::GfTransform transform; 150 | transform.SetMatrix(prim_tf); 151 | pxr::GfVec3d scale = transform.GetScale(); 152 | db.outputs.cameraWorldScale() = scale; 153 | 154 | uint32_t width = db.inputs.width(); 155 | uint32_t height = db.inputs.height(); 156 | 157 | // // Get the view matrix corrected for ROS conventions 158 | pxr::GfMatrix4d view_matrix_ros = get_view_matrix_ros(cameraPrim); 159 | db.outputs.cameraViewTransform() = view_matrix_ros; 160 | 161 | // // Get the camera intrinsics matrix 162 | pxr::GfMatrix3d intrinsics_matrix = get_intrinsics_matrix(cameraPrim, width, height); 163 | db.outputs.cameraIntrinsics() = intrinsics_matrix; 164 | 165 | // Returning true tells Omnigraph that the compute was successful and the output value is now valid. 166 | return true; 167 | } 168 | 169 | // This macro provides the information necessary to OmniGraph that lets it automatically register and deregister 170 | // your node type definition. 171 | REGISTER_OGN_NODE() 172 | 173 | 174 | } // bridge 175 | } // zmq 176 | } // isaacsim 177 | -------------------------------------------------------------------------------- /tools/packman/bootstrap/configure.bat: -------------------------------------------------------------------------------- 1 | :: Copyright 2019-2023 NVIDIA CORPORATION 2 | :: 3 | :: Licensed under the Apache License, Version 2.0 (the "License"); 4 | :: you may not use this file except in compliance with the License. 5 | :: You may obtain a copy of the License at 6 | :: 7 | :: http://www.apache.org/licenses/LICENSE-2.0 8 | :: 9 | :: Unless required by applicable law or agreed to in writing, software 10 | :: distributed under the License is distributed on an "AS IS" BASIS, 11 | :: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | :: See the License for the specific language governing permissions and 13 | :: limitations under the License. 14 | 15 | set PM_PACKMAN_VERSION=7.28 16 | 17 | :: Specify where packman command is rooted 18 | set PM_INSTALL_PATH=%~dp0.. 19 | 20 | :: The external root may already be configured and we should do minimal work in that case 21 | if defined PM_PACKAGES_ROOT goto ENSURE_DIR 22 | 23 | :: If the folder isn't set we assume that the best place for it is on the drive that we are currently 24 | :: running from 25 | set PM_DRIVE=%CD:~0,2% 26 | 27 | set PM_PACKAGES_ROOT=%PM_DRIVE%\packman-repo 28 | 29 | :: We use *setx* here so that the variable is persisted in the user environment 30 | echo Setting user environment variable PM_PACKAGES_ROOT to %PM_PACKAGES_ROOT% 31 | setx PM_PACKAGES_ROOT %PM_PACKAGES_ROOT% 32 | if %errorlevel% neq 0 ( goto ERROR ) 33 | 34 | :: The above doesn't work properly from a build step in VisualStudio because a separate process is 35 | :: spawned for it so it will be lost for subsequent compilation steps - VisualStudio must 36 | :: be launched from a new process. We catch this odd-ball case here: 37 | if defined PM_DISABLE_VS_WARNING goto ENSURE_DIR 38 | if not defined VSLANG goto ENSURE_DIR 39 | echo The above is a once-per-computer operation. Unfortunately VisualStudio cannot pick up environment change 40 | echo unless *VisualStudio is RELAUNCHED*. 41 | echo If you are launching VisualStudio from command line or command line utility make sure 42 | echo you have a fresh launch environment (relaunch the command line or utility). 43 | echo If you are using 'linkPath' and referring to packages via local folder links you can safely ignore this warning. 44 | echo You can disable this warning by setting the environment variable PM_DISABLE_VS_WARNING. 45 | echo. 46 | 47 | :: Check for the directory that we need. Note that mkdir will create any directories 48 | :: that may be needed in the path 49 | :ENSURE_DIR 50 | if not exist "%PM_PACKAGES_ROOT%" ( 51 | echo Creating packman packages cache at %PM_PACKAGES_ROOT% 52 | mkdir "%PM_PACKAGES_ROOT%" 53 | ) 54 | if %errorlevel% neq 0 ( goto ERROR_MKDIR_PACKAGES_ROOT ) 55 | 56 | :: The Python interpreter may already be externally configured 57 | if defined PM_PYTHON_EXT ( 58 | set PM_PYTHON=%PM_PYTHON_EXT% 59 | goto PACKMAN 60 | ) 61 | 62 | set PM_PYTHON_VERSION=3.10.17-nv1-windows-x86_64 63 | set PM_PYTHON_BASE_DIR=%PM_PACKAGES_ROOT%\python 64 | set PM_PYTHON_DIR=%PM_PYTHON_BASE_DIR%\%PM_PYTHON_VERSION% 65 | set PM_PYTHON=%PM_PYTHON_DIR%\python.exe 66 | 67 | if exist "%PM_PYTHON%" goto PACKMAN 68 | if not exist "%PM_PYTHON_BASE_DIR%" call :CREATE_PYTHON_BASE_DIR 69 | 70 | set PM_PYTHON_PACKAGE=python@%PM_PYTHON_VERSION%.cab 71 | for /f "delims=" %%a in ('powershell -ExecutionPolicy ByPass -NoLogo -NoProfile -File "%~dp0\generate_temp_file_name.ps1"') do set TEMP_FILE_NAME=%%a 72 | set TARGET=%TEMP_FILE_NAME%.zip 73 | call "%~dp0fetch_file_from_packman_bootstrap.cmd" %PM_PYTHON_PACKAGE% "%TARGET%" 74 | if %errorlevel% neq 0 ( 75 | echo !!! Error fetching python from CDN !!! 76 | goto ERROR 77 | ) 78 | 79 | for /f "delims=" %%a in ('powershell -ExecutionPolicy ByPass -NoLogo -NoProfile -File "%~dp0\generate_temp_folder.ps1" -parentPath "%PM_PYTHON_BASE_DIR%"') do set TEMP_FOLDER_NAME=%%a 80 | echo Unpacking Python interpreter ... 81 | "%SystemRoot%\system32\expand.exe" -F:* "%TARGET%" "%TEMP_FOLDER_NAME%" 1> nul 82 | del "%TARGET%" 83 | :: Failure during extraction to temp folder name, need to clean up and abort 84 | if %errorlevel% neq 0 ( 85 | echo !!! Error unpacking python !!! 86 | call :CLEAN_UP_TEMP_FOLDER 87 | goto ERROR 88 | ) 89 | 90 | :: If python has now been installed by a concurrent process we need to clean up and then continue 91 | if exist "%PM_PYTHON%" ( 92 | call :CLEAN_UP_TEMP_FOLDER 93 | goto PACKMAN 94 | ) else ( 95 | if exist "%PM_PYTHON_DIR%" ( rd /s /q "%PM_PYTHON_DIR%" > nul ) 96 | ) 97 | 98 | :: Perform atomic move (allowing overwrite, /y) 99 | move /y "%TEMP_FOLDER_NAME%" "%PM_PYTHON_DIR%" 1> nul 100 | :: Verify that python.exe is now where we expect 101 | if exist "%PM_PYTHON%" goto PACKMAN 102 | 103 | :: Wait a second and try again (can help with access denied weirdness) 104 | timeout /t 1 /nobreak 1> nul 105 | move /y "%TEMP_FOLDER_NAME%" "%PM_PYTHON_DIR%" 1> nul 106 | if %errorlevel% neq 0 ( 107 | echo !!! Error moving python %TEMP_FOLDER_NAME% -> %PM_PYTHON_DIR% !!! 108 | call :CLEAN_UP_TEMP_FOLDER 109 | goto ERROR 110 | ) 111 | 112 | :PACKMAN 113 | :: The packman module may already be externally configured 114 | if defined PM_MODULE_DIR_EXT ( 115 | set PM_MODULE_DIR=%PM_MODULE_DIR_EXT% 116 | ) else ( 117 | set PM_MODULE_DIR=%PM_PACKAGES_ROOT%\packman-common\%PM_PACKMAN_VERSION% 118 | ) 119 | 120 | set PM_MODULE=%PM_MODULE_DIR%\run.py 121 | 122 | if exist "%PM_MODULE%" goto END 123 | 124 | :: Clean out broken PM_MODULE_DIR if it exists 125 | if exist "%PM_MODULE_DIR%" ( rd /s /q "%PM_MODULE_DIR%" > nul ) 126 | 127 | set PM_MODULE_PACKAGE=packman-common@%PM_PACKMAN_VERSION%.zip 128 | for /f "delims=" %%a in ('powershell -ExecutionPolicy ByPass -NoLogo -NoProfile -File "%~dp0\generate_temp_file_name.ps1"') do set TEMP_FILE_NAME=%%a 129 | set TARGET=%TEMP_FILE_NAME% 130 | call "%~dp0fetch_file_from_packman_bootstrap.cmd" %PM_MODULE_PACKAGE% "%TARGET%" 131 | if %errorlevel% neq 0 ( 132 | echo !!! Error fetching packman from CDN !!! 133 | goto ERROR 134 | ) 135 | 136 | echo Unpacking ... 137 | "%PM_PYTHON%" -S -s -u -E "%~dp0\install_package.py" "%TARGET%" "%PM_MODULE_DIR%" 138 | if %errorlevel% neq 0 ( 139 | echo !!! Error unpacking packman !!! 140 | goto ERROR 141 | ) 142 | 143 | del "%TARGET%" 144 | 145 | goto END 146 | 147 | :ERROR_MKDIR_PACKAGES_ROOT 148 | echo Failed to automatically create packman packages repo at %PM_PACKAGES_ROOT%. 149 | echo Please set a location explicitly that packman has permission to write to, by issuing: 150 | echo. 151 | echo setx PM_PACKAGES_ROOT {path-you-choose-for-storing-packman-packages-locally} 152 | echo. 153 | echo Then launch a new command console for the changes to take effect and run packman command again. 154 | exit /B %errorlevel% 155 | 156 | :ERROR 157 | echo !!! Failure while configuring local machine :( !!! 158 | exit /B %errorlevel% 159 | 160 | :CLEAN_UP_TEMP_FOLDER 161 | rd /S /Q "%TEMP_FOLDER_NAME%" 162 | exit /B 163 | 164 | :CREATE_PYTHON_BASE_DIR 165 | :: We ignore errors and clean error state - if two processes create the directory one will fail which is fine 166 | md "%PM_PYTHON_BASE_DIR%" > nul 2>&1 167 | exit /B 0 168 | 169 | :END 170 | -------------------------------------------------------------------------------- /tools/packman/bootstrap/install_package.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019 NVIDIA CORPORATION 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | import zipfile 17 | import tempfile 18 | import sys 19 | import os 20 | import stat 21 | import time 22 | import hashlib 23 | from typing import Any, Callable, Union 24 | 25 | 26 | RENAME_RETRY_COUNT = 100 27 | RENAME_RETRY_DELAY = 0.1 28 | 29 | logging.basicConfig(level=logging.WARNING, format="%(message)s") 30 | logger = logging.getLogger("install_package") 31 | 32 | 33 | def remove_directory_item(path): 34 | if os.path.islink(path) or os.path.isfile(path): 35 | try: 36 | os.remove(path) 37 | except PermissionError: 38 | # make sure we have access and try again: 39 | os.chmod(path, stat.S_IRWXU) 40 | os.remove(path) 41 | else: 42 | # try first to delete the dir because this will work for folder junctions, otherwise we would follow the junctions and cause destruction! 43 | clean_out_folder = False 44 | try: 45 | # make sure we have access preemptively - this is necessary because recursing into a directory without permissions 46 | # will only lead to heart ache 47 | os.chmod(path, stat.S_IRWXU) 48 | os.rmdir(path) 49 | except OSError: 50 | clean_out_folder = True 51 | 52 | if clean_out_folder: 53 | # we should make sure the directory is empty 54 | names = os.listdir(path) 55 | for name in names: 56 | fullname = os.path.join(path, name) 57 | remove_directory_item(fullname) 58 | # now try to again get rid of the folder - and not catch if it raises: 59 | os.rmdir(path) 60 | 61 | 62 | class StagingDirectory: 63 | def __init__(self, staging_path): 64 | self.staging_path = staging_path 65 | self.temp_folder_path = None 66 | os.makedirs(staging_path, exist_ok=True) 67 | 68 | def __enter__(self): 69 | self.temp_folder_path = tempfile.mkdtemp(prefix="ver-", dir=self.staging_path) 70 | return self 71 | 72 | def get_temp_folder_path(self): 73 | return self.temp_folder_path 74 | 75 | # this function renames the temp staging folder to folder_name, it is required that the parent path exists! 76 | def promote_and_rename(self, folder_name): 77 | abs_dst_folder_name = os.path.join(self.staging_path, folder_name) 78 | os.rename(self.temp_folder_path, abs_dst_folder_name) 79 | 80 | def __exit__(self, type, value, traceback): 81 | # Remove temp staging folder if it's still there (something went wrong): 82 | path = self.temp_folder_path 83 | if os.path.isdir(path): 84 | remove_directory_item(path) 85 | 86 | 87 | def rename_folder(staging_dir: StagingDirectory, folder_name: str): 88 | try: 89 | staging_dir.promote_and_rename(folder_name) 90 | except OSError as exc: 91 | # if we failed to rename because the folder now exists we can assume that another packman process 92 | # has managed to update the package before us - in all other cases we re-raise the exception 93 | abs_dst_folder_name = os.path.join(staging_dir.staging_path, folder_name) 94 | if os.path.exists(abs_dst_folder_name): 95 | logger.warning( 96 | f"Directory {abs_dst_folder_name} already present, package installation already completed" 97 | ) 98 | else: 99 | raise 100 | 101 | 102 | def call_with_retry( 103 | op_name: str, func: Callable, retry_count: int = 3, retry_delay: float = 20 104 | ) -> Any: 105 | retries_left = retry_count 106 | while True: 107 | try: 108 | return func() 109 | except (OSError, IOError) as exc: 110 | logger.warning(f"Failure while executing {op_name} [{str(exc)}]") 111 | if retries_left: 112 | retry_str = "retry" if retries_left == 1 else "retries" 113 | logger.warning( 114 | f"Retrying after {retry_delay} seconds" 115 | f" ({retries_left} {retry_str} left) ..." 116 | ) 117 | time.sleep(retry_delay) 118 | else: 119 | logger.error("Maximum retries exceeded, giving up") 120 | raise 121 | retries_left -= 1 122 | 123 | 124 | def rename_folder_with_retry(staging_dir: StagingDirectory, folder_name): 125 | dst_path = os.path.join(staging_dir.staging_path, folder_name) 126 | call_with_retry( 127 | f"rename {staging_dir.get_temp_folder_path()} -> {dst_path}", 128 | lambda: rename_folder(staging_dir, folder_name), 129 | RENAME_RETRY_COUNT, 130 | RENAME_RETRY_DELAY, 131 | ) 132 | 133 | 134 | def generate_sha256_for_file(file_path: Union[str, os.PathLike]) -> str: 135 | """Returns the SHA-256 hex digest for the file at `file_path`""" 136 | hash = hashlib.sha256() 137 | # Read the file in binary mode and update the hash object with data 138 | with open(file_path, "rb") as file: 139 | for chunk in iter(lambda: file.read(4096), b""): 140 | hash.update(chunk) 141 | return hash.hexdigest() 142 | 143 | 144 | def install_common_module(package_path, install_path): 145 | COMMON_SHA256 = "c49ce665f107f44d0d92ebb1e7b62417e94b37399dc3c92584d03b1ac44bb132" 146 | package_sha256 = generate_sha256_for_file(package_path) 147 | if package_sha256 != COMMON_SHA256: 148 | raise RuntimeError( 149 | f"Package at '{package_path}' must have a sha256 of '{COMMON_SHA256}' " 150 | f"but was found to have '{package_sha256}'" 151 | ) 152 | staging_path, version = os.path.split(install_path) 153 | with StagingDirectory(staging_path) as staging_dir: 154 | output_folder = staging_dir.get_temp_folder_path() 155 | with zipfile.ZipFile(package_path, allowZip64=True) as zip_file: 156 | zip_file.extractall(output_folder) 157 | 158 | # attempt the rename operation 159 | rename_folder_with_retry(staging_dir, version) 160 | 161 | print(f"Package successfully installed to {install_path}") 162 | 163 | 164 | if __name__ == "__main__": 165 | executable_paths = os.getenv("PATH") 166 | paths_list = executable_paths.split(os.path.pathsep) if executable_paths else [] 167 | target_path_np = os.path.normpath(sys.argv[2]) 168 | target_path_np_nc = os.path.normcase(target_path_np) 169 | for exec_path in paths_list: 170 | if os.path.normcase(os.path.normpath(exec_path)) == target_path_np_nc: 171 | raise RuntimeError(f"packman will not install to executable path '{exec_path}'") 172 | install_common_module(sys.argv[1], target_path_np) 173 | -------------------------------------------------------------------------------- /isaac-zmq-server/src/isaac_zmq_server/server.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: MIT 3 | 4 | import threading 5 | import time 6 | import traceback 7 | 8 | import zmq 9 | 10 | 11 | class ZMQServer: 12 | """ 13 | Server for handling ZMQ communication. 14 | 15 | This class implements a singleton pattern and provides methods for creating 16 | ZMQ sockets, sending and receiving data in separate threads, and cleaning up 17 | resources when they are no longer needed. 18 | """ 19 | 20 | _instance = None 21 | 22 | def __new__(cls, *args, **kwargs): 23 | """Implement singleton pattern for ZMQServer.""" 24 | if not cls._instance: 25 | cls._instance = super().__new__(cls, *args, **kwargs) 26 | return cls._instance 27 | 28 | def __init__(self): 29 | """Initialize the ZMQServer with empty collections for sockets and threads.""" 30 | # Skip initialization if already initialized (singleton pattern) 31 | if hasattr(self, "push_sockets"): 32 | return 33 | 34 | self.push_sockets = {} 35 | self.pull_sockets = {} 36 | self.reciveing_threads = {} 37 | self.sending_threads = {} 38 | 39 | # ZMQ context 40 | self._context = None 41 | 42 | def context(self) -> zmq.Context: 43 | """ 44 | Returns the ZMQ context instance. 45 | If the context has not been initialized, it creates a new ZMQ context and assigns it to the `_context` attribute. 46 | 47 | Returns: 48 | zmq.Context: The ZMQ context instance. 49 | """ 50 | if not self._context: 51 | self._context = zmq.Context() 52 | return self._context 53 | 54 | def get_pull_socket(self, port: int) -> zmq.Socket: 55 | """ 56 | Creates and returns a new pull socket that is bound to the specified port. 57 | 58 | Args: 59 | port (int): The port number to bind the socket to. 60 | 61 | Returns: 62 | zmq.Socket: The newly created pull socket. 63 | """ 64 | addr = f"tcp://*:{port}" 65 | sock = self.context().socket(zmq.PULL) 66 | sock.set_hwm(1) # High water mark: only buffer 1 message 67 | sock.bind(addr) 68 | sock.setsockopt(zmq.RCVTIMEO, 1000) # 1 second timeout for receiving 69 | poller = zmq.Poller() 70 | poller.register(sock, zmq.POLLIN) 71 | self.pull_sockets[port] = sock 72 | return sock 73 | 74 | def get_push_socket(self, port: int) -> zmq.Socket: 75 | """ 76 | Creates and returns a ZeroMQ PUSH socket bound to the specified port. 77 | 78 | Args: 79 | port (int): The port number to bind the socket to. 80 | 81 | Returns: 82 | zmq.Socket: The created PUSH socket. 83 | """ 84 | addr = f"tcp://*:{port}" 85 | sock = self.context().socket(zmq.PUSH) 86 | sock.setsockopt(zmq.SNDTIMEO, 1000) # 1 second timeout for sending 87 | sock.bind(addr) 88 | self.push_sockets[port] = sock 89 | return sock 90 | 91 | def subscribe_to_socket_in_loop(self, name: str, port: int, fn: callable) -> None: 92 | """ 93 | Receives messages from a socket in a loop and calls a given function for each message. 94 | 95 | This method creates a new thread that continuously receives messages from the specified 96 | port and passes them to the provided callback function. 97 | 98 | Args: 99 | name (str): The name of the receiving thread. 100 | port (int): The port number to receive messages from. 101 | fn (callable): A callable function that takes a message as input. 102 | """ 103 | # Create socket for receiving 104 | sock = self.get_pull_socket(port) 105 | stop_event = threading.Event() 106 | 107 | def loop(): 108 | """Thread function that continuously receives messages.""" 109 | while not stop_event.is_set(): 110 | try: 111 | msg = sock.recv() 112 | fn(msg) 113 | except zmq.Again: 114 | continue 115 | except: 116 | print("[isaac-zmq-server] Unable to unpack from socket...") 117 | print(traceback.format_exc()) 118 | continue 119 | 120 | # Clean up when thread is finsihed 121 | sock.close() 122 | del self.pull_sockets[port] 123 | 124 | # Start the thread 125 | worker = threading.Thread(target=loop) 126 | self.reciveing_threads[name] = (worker, stop_event) 127 | worker.start() 128 | 129 | def publish_protobuf_in_loop(self, name: str, port: int, rate_hz: float, fn: callable) -> None: 130 | """ 131 | Sends protobuf messages from a socket in a loop at a specified rate. 132 | 133 | This method creates a new thread that continuously sends protobuf messages at the specified 134 | rate to the specified port. The protobuf message to send is obtained by calling the provided 135 | callback function. 136 | 137 | Args: 138 | name (str): The name of the sending thread. 139 | port (int): The port number to send data to. 140 | rate_hz (float): The rate at which data is sent in Hz. 141 | fn (callable): A callable function that returns a protobuf message. 142 | """ 143 | # Create socket for sending 144 | sock = self.get_push_socket(port) 145 | stop_event = threading.Event() 146 | 147 | def loop(): 148 | """Thread function that continuously sends protobuf messages at the specified rate.""" 149 | while not stop_event.is_set(): 150 | try: 151 | # Get the protobuf message from the callback function 152 | proto_msg = fn() 153 | # Serialize the protobuf message and send it 154 | sock.send(proto_msg.SerializeToString()) 155 | except zmq.Again: 156 | continue 157 | except Exception as e: 158 | print(f"[isaac-zmq-server] Unable to send protobuf to socket: {e}") 159 | continue 160 | 161 | # Sleep to maintain the desired rate 162 | time.sleep(1 / rate_hz) 163 | 164 | # Clean up when thread is finished 165 | sock.close() 166 | del self.push_sockets[port] 167 | 168 | # Start the sending thread 169 | worker = threading.Thread(target=loop) 170 | self.sending_threads[name] = (worker, stop_event) 171 | worker.start() 172 | 173 | def cleanup(self) -> None: 174 | """ 175 | Stops and joins all receiving and sending threads. 176 | 177 | This function is used to clean up the threads when they are no longer needed. 178 | It sets the stop event for each thread and then joins them to ensure they have finished. 179 | """ 180 | # Stop and join all receiving threads 181 | for name, (worker, stop_event) in self.reciveing_threads.items(): 182 | stop_event.set() 183 | worker.join() 184 | 185 | # Stop and join all sending threads 186 | for name, (worker, stop_event) in self.sending_threads.items(): 187 | stop_event.set() 188 | worker.join() 189 | -------------------------------------------------------------------------------- /tools/packman/packman: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2019-2025 NVIDIA CORPORATION 4 | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | SAVED_SETTINGS=`echo $-` 17 | # Fail on undefined variables 18 | set -u 19 | # Don't exit on errors 20 | set +e 21 | 22 | if echo ${PM_VERBOSITY-} | grep -i "debug" > /dev/null ; then 23 | set -x 24 | PM_CURL_SILENT="" 25 | PM_WGET_QUIET="" 26 | else 27 | PM_CURL_SILENT="-s -S" 28 | PM_WGET_QUIET="--quiet" 29 | fi 30 | export PM_PACKMAN_VERSION=7.28 31 | 32 | 33 | cleanup() { 34 | # Remove temporary variable file if it exists 35 | if [[ -n "${PM_VAR_PATH:-}" && -f "$PM_VAR_PATH" ]]; then 36 | rm -f "$PM_VAR_PATH" 37 | fi 38 | 39 | # Restore the settings we may have altered during our run 40 | if [[ "$SAVED_SETTINGS" == *"e"* ]]; then 41 | set -e 42 | fi 43 | 44 | if [[ "$SAVED_SETTINGS" != *"x"* ]]; then 45 | set +x 46 | fi 47 | 48 | # the e setting is always set in source mode so we remove it here so it 49 | # doesn't leak (in regular ./ execution doesn't matter) 50 | set +u 51 | } 52 | 53 | main() { 54 | # This is necessary for newer macOS 55 | if [ `uname` == 'Darwin' ]; then 56 | export LC_ALL=en_US.UTF-8 57 | export LANG=en_US.UTF-8 58 | fi 59 | 60 | # We cannot rely on realpath, it isn't installed on macOS and some Linux distros 61 | get_abs_filename() { 62 | echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" 63 | } 64 | 65 | # Specify where packman command exists 66 | export PM_INSTALL_PATH="$(get_abs_filename "$(dirname "${BASH_SOURCE}")")" 67 | 68 | # The packages root may already be configured by the user 69 | if [ -z "${PM_PACKAGES_ROOT:-}" ]; then 70 | # Set variable temporarily in this process so that the following execution will work 71 | if [ `uname` == 'Darwin' ]; then 72 | export PM_PACKAGES_ROOT="${HOME}/Library/Application Support/packman-cache" 73 | else 74 | if [ -z "${XDG_CACHE_HOME:-}" ]; then 75 | export PM_PACKAGES_ROOT="${HOME}/.cache/packman" 76 | else 77 | export PM_PACKAGES_ROOT="${XDG_CACHE_HOME}/packman" 78 | fi 79 | fi 80 | fi 81 | 82 | # Ensure the packages root path exists: 83 | if [ ! -d "$PM_PACKAGES_ROOT" ]; then 84 | echo "Creating packman packages cache at $PM_PACKAGES_ROOT" 85 | mkdir -p -m a+rwx "$PM_PACKAGES_ROOT" || return 1 86 | fi 87 | 88 | execute_with_retry() 89 | { 90 | local CMD="$1" 91 | local MAX_TRIES=4 92 | local DELAY=2 93 | local TRIES=0 94 | local exit_code 95 | 96 | while [ $TRIES -lt $MAX_TRIES ] 97 | do 98 | ((TRIES++)) 99 | eval $CMD 100 | exit_code=$? 101 | if [ $exit_code -eq 0 ]; then 102 | return 0 103 | fi 104 | 105 | if [ $TRIES -lt $MAX_TRIES ]; then 106 | echo "Attempt $TRIES failed. Retrying in $DELAY seconds ..." 107 | sleep $DELAY 108 | DELAY=$((DELAY * DELAY)) 109 | echo "Retrying ..." 110 | fi 111 | done 112 | 113 | echo "Command failed after $MAX_TRIES attempts: $CMD" 114 | return $exit_code 115 | } 116 | 117 | fetch_file_from_s3() 118 | { 119 | local SOURCE=$1 120 | local SOURCE_URL=https://bootstrap.packman.nvidia.com/$SOURCE 121 | local TARGET=$2 122 | echo "Fetching $SOURCE from bootstrap.packman.nvidia.com ..." 123 | local CMD="curl -o $TARGET $SOURCE_URL $PM_CURL_SILENT" 124 | if command -v wget >/dev/null 2>&1; then 125 | CMD="wget $PM_WGET_QUIET -O$TARGET $SOURCE_URL" 126 | fi 127 | execute_with_retry "$CMD" 128 | return $? 129 | } 130 | 131 | generate_temp_file_name() 132 | { 133 | if [ `uname` == "Darwin" ]; then 134 | local tmpfile=`mktemp -t packman` 135 | else 136 | local tmpfile=`mktemp -t packman.XXXXXXXX` 137 | fi 138 | echo "$tmpfile" 139 | } 140 | 141 | install_python() 142 | { 143 | PLATFORM=`uname` 144 | PROCESSOR=`uname -m` 145 | PYTHON_VERSION=3.10.17-nv1 146 | 147 | if [ $PLATFORM == 'Darwin' ]; then 148 | PYTHON_PACKAGE=3.10.5-1-macos-x86_64 149 | elif [ $PLATFORM == 'Linux' ] && [ $PROCESSOR == 'x86_64' ]; then 150 | PYTHON_PACKAGE=$PYTHON_VERSION-linux-x86_64 151 | elif [ $PLATFORM == 'Linux' ] && [ $PROCESSOR == 'aarch64' ]; then 152 | PYTHON_PACKAGE=$PYTHON_VERSION-linux-aarch64 153 | else 154 | echo "Operating system not supported" 155 | return 1 156 | fi 157 | 158 | PYTHON_INSTALL_FOLDER="$PM_PACKAGES_ROOT/python/$PYTHON_PACKAGE" 159 | if [ ! -d "$PYTHON_INSTALL_FOLDER" ]; then 160 | mkdir -p "$PYTHON_INSTALL_FOLDER" || return 1 161 | fi 162 | 163 | export PM_PYTHON="$PYTHON_INSTALL_FOLDER/python" 164 | 165 | if [ ! -f "$PM_PYTHON" ]; then 166 | PYTHON_PACKAGE_TMP=$(generate_temp_file_name) 167 | fetch_file_from_s3 "python@$PYTHON_PACKAGE.tar.gz" "$PYTHON_PACKAGE_TMP" || return 1 168 | echo "Unpacking python" 169 | tar -xf "$PYTHON_PACKAGE_TMP" -C "$PYTHON_INSTALL_FOLDER" || return 1 170 | rm "$PYTHON_PACKAGE_TMP" || return 1 171 | fi 172 | } 173 | 174 | # Ensure python is available: 175 | if [ -z "${PM_PYTHON_EXT:-}" ]; then 176 | install_python || return 1 177 | else 178 | PM_PYTHON="$PM_PYTHON_EXT" 179 | fi 180 | 181 | # The packman module may be externally configured 182 | if [ -z "${PM_MODULE_DIR_EXT:-}" ]; then 183 | PM_MODULE_DIR="$PM_PACKAGES_ROOT/packman-common/$PM_PACKMAN_VERSION" 184 | else 185 | PM_MODULE_DIR="$PM_MODULE_DIR_EXT" 186 | fi 187 | export PM_MODULE="$PM_MODULE_DIR/run.py" 188 | 189 | # Ensure the packman package exists: 190 | if [ ! -f "$PM_MODULE" ]; then 191 | # Remove a previously corrupt packman-common if it's there 192 | if [ -d "$PM_MODULE_DIR" ]; then 193 | rm -rf "$PM_MODULE_DIR" || return 1 194 | fi 195 | PM_MODULE_PACKAGE="packman-common@$PM_PACKMAN_VERSION.zip" 196 | TARGET=$(generate_temp_file_name) 197 | # We always fetch packman from S3: 198 | fetch_file_from_s3 "$PM_MODULE_PACKAGE" "$TARGET" || return 1 199 | echo "Unpacking ..." 200 | "$PM_PYTHON" -S -s -u -E "$PM_INSTALL_PATH/bootstrap/install_package.py" "$TARGET" "$PM_MODULE_DIR" || return 1 201 | rm "$TARGET" || return 1 202 | fi 203 | 204 | # Generate temporary file name for environment variables: 205 | PM_VAR_PATH=`mktemp -u -t tmp.$$.pmvars.XXXXXX` 206 | 207 | if [ $# -ne 0 ]; then 208 | PM_VAR_PATH_ARG=--var-path="$PM_VAR_PATH" 209 | else 210 | PM_VAR_PATH_ARG="" 211 | fi 212 | 213 | "$PM_PYTHON" -S -s -u -E "$PM_MODULE" "$@" ${PM_VAR_PATH_ARG:-} || return 1 214 | # Export the variables if the file was used: 215 | if [ -f "$PM_VAR_PATH" ]; then 216 | while read -r line 217 | do 218 | if [ ${#line} -gt 0 ]; then 219 | export "$line" 220 | fi 221 | done < "$PM_VAR_PATH" 222 | fi 223 | 224 | # Return success 225 | return 0 226 | } 227 | 228 | main "$@" 229 | exit_code=$? 230 | cleanup 231 | 232 | # Determine execution context and return accordingly 233 | if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then 234 | # This is direct execution 235 | exit $exit_code 236 | else 237 | # This is sourced execution 238 | return $exit_code 239 | fi 240 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge.examples/isaacsim/zmq/bridge/examples/core/client.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | # SPDX-License-Identifier: MIT 3 | 4 | import asyncio 5 | import traceback 6 | import zmq 7 | import zmq.asyncio 8 | 9 | import carb 10 | import omni 11 | 12 | from isaacsim.core.api.world import World 13 | 14 | from .rate_limiter import RateLimitedCallback 15 | from .. import EXT_NAME 16 | 17 | class ZMQClient: 18 | """ 19 | The ZMQClient class provides a singleton instance which handles the creation and management of ZMQ sockets. 20 | 21 | This class is responsible for: 22 | - Creating and managing ZMQ sockets for communication with external applications 23 | - Handling connection and disconnection of sockets 24 | - Managing physics callbacks for rate-limited data streaming (Python-only mode) 25 | - Providing methods for sending and receiving data through ZMQ 26 | """ 27 | 28 | _instance = None 29 | 30 | def __new__(cls, *args, **kwargs): 31 | # Implement singleton pattern 32 | if not cls._instance: 33 | cls._instance = super().__new__(cls) 34 | return cls._instance 35 | 36 | def __init__(self, server_ip: str = "localhost"): 37 | self.server_ip = server_ip 38 | self.push_sockets = {} 39 | self.pull_sockets = {} 40 | self.phyx_callbacks = {} 41 | self.annotators = {} 42 | 43 | # ZMQ context 44 | self._context = None 45 | 46 | # Timing and rate control 47 | self.start_time = 0 48 | self._adeptive_rate = True 49 | 50 | def context(self) -> zmq.asyncio.Context: 51 | """ 52 | Returns the ZMQ context if it has not been initialized yet. 53 | Initializes and returns the ZMQ context if it has not been initialized. 54 | 55 | Returns: 56 | zmq.asyncio.Context: The ZMQ context. 57 | """ 58 | if not self._context: 59 | self._context = zmq.asyncio.Context() 60 | return self._context 61 | 62 | def get_pull_socket(self, port: int) -> zmq.Socket: 63 | """ 64 | Creates and returns a ZeroMQ PULL socket connected to the specified port. 65 | 66 | This socket type is used to receive data from a remote PUSH socket. 67 | 68 | Args: 69 | port (int): The port number to connect the socket to. 70 | 71 | Returns: 72 | zmq.Socket: The created PULL socket. 73 | """ 74 | addr = f"tcp://{self.server_ip}:{port}" 75 | sock = self.context().socket(zmq.PULL) 76 | sock.set_hwm(1) # High water mark: only buffer 1 message 77 | sock.connect(addr) 78 | self.pull_sockets[addr] = sock 79 | return sock 80 | 81 | async def receive_protobuf(self, sock: zmq.asyncio.Socket, proto_class) -> object: 82 | """ 83 | Asynchronously receives a protobuf message from a ZeroMQ socket. 84 | 85 | Args: 86 | sock (zmq.asyncio.Socket): The ZeroMQ socket to receive data from. 87 | proto_class: The protobuf message class to parse the received data. 88 | 89 | Returns: 90 | object: The received data as a protobuf message. 91 | """ 92 | message_bytes = await sock.recv() 93 | proto_msg = proto_class() 94 | proto_msg.ParseFromString(message_bytes) 95 | return proto_msg 96 | 97 | async def disconnect_all(self) -> None: 98 | """ 99 | Disconnects all ZeroMQ sockets and terminates the ZeroMQ context. 100 | 101 | This method iterates over all push and pull sockets, disconnects them, and closes them. 102 | It then clears the socket dictionaries and terminates the ZeroMQ context. 103 | """ 104 | # Disconnect and close all push sockets 105 | for addr, sock in self.push_sockets.items(): 106 | await asyncio.sleep(0.1) 107 | try: 108 | sock.setsockopt(zmq.LINGER, 0) # Don't wait for pending messages 109 | sock.disconnect(addr) 110 | except asyncio.CancelledError: 111 | pass 112 | except zmq.error.ZMQError: 113 | carb.log_warn(f"[{EXT_NAME}] zmq error - non critical\n {traceback.format_exc()}") 114 | except Exception: 115 | carb.log_error(traceback.format_exc()) 116 | 117 | sock.close() 118 | 119 | # Disconnect and close all pull sockets 120 | for addr, sock in self.pull_sockets.items(): 121 | await asyncio.sleep(0.1) 122 | try: 123 | sock.disconnect(addr) 124 | except asyncio.CancelledError: 125 | pass 126 | except zmq.error.ZMQError: 127 | carb.log_warn(f"[{EXT_NAME}] zmq error - non critical\n {traceback.format_exc()}") 128 | except Exception: 129 | carb.log_error(traceback.format_exc()) 130 | 131 | sock.close() 132 | 133 | # Clear socket dictionaries 134 | self.pull_sockets = {} 135 | self.push_sockets = {} 136 | 137 | # Terminate ZMQ context 138 | if self._context: 139 | self._context.term() 140 | self._context = None 141 | 142 | ###################################################################################### 143 | # The following methods are used only when the C++ node modes is not in use 144 | # They provide Python-based alternatives for streaming data 145 | ###################################################################################### 146 | 147 | def get_push_socket(self, port: int) -> zmq.Socket: 148 | """ 149 | Creates and returns a ZeroMQ PUSH socket connected to the specified port. 150 | 151 | This socket type is used to send data to a remote PULL socket. 152 | 153 | Args: 154 | port (int): The port number to connect the socket to. 155 | 156 | Returns: 157 | zmq.Socket: The created PUSH socket. 158 | """ 159 | addr = f"tcp://{self.server_ip}:{port}" 160 | sock = self.context().socket(zmq.PUSH) 161 | sock.set_hwm(1) # High water mark: only buffer 1 message 162 | sock.setsockopt(zmq.SNDTIMEO, 1000) # 1 sec timeout for sending 163 | sock.connect(addr) 164 | self.push_sockets[addr] = sock 165 | return sock 166 | 167 | def add_physx_step_callback(self, name: str, hz: float, fn: callable) -> None: 168 | """ 169 | Adds a callback function to be executed at a specified simulation steps frequency. 170 | 171 | This method creates a rate-limited callback that will be executed during physics 172 | simulation steps at the specified frequency. 173 | 174 | Args: 175 | name (str): The name of the callback. 176 | hz (float): The frequency at which the callback is executed. 177 | fn (callable): The callback function to be executed. 178 | """ 179 | self.world = World.instance() 180 | rate_limited_callback = RateLimitedCallback(name, hz, fn, self.start_time) 181 | self.world.add_physics_callback(name, rate_limited_callback.rate_limit) 182 | self.phyx_callbacks[name] = rate_limited_callback 183 | return 184 | 185 | def remove_physx_callbacks(self) -> None: 186 | """ 187 | Removes all registered physics callbacks. 188 | 189 | This method iterates over the `phyx_callbacks` dictionary and unsubscribes each callback 190 | from the physics simulation. 191 | """ 192 | for name, cb in self.phyx_callbacks.items(): 193 | self.world.remove_physics_callback(name) 194 | del cb 195 | 196 | @property 197 | def adeptive_rate(self) -> bool: 198 | return self._adeptive_rate 199 | 200 | @adeptive_rate.setter 201 | def adeptive_rate(self, value: bool) -> None: 202 | """ 203 | Set the adaptive rate setting and update all callbacks. 204 | 205 | When adaptive rate is enabled, the system will automatically adjust 206 | the callback frequency to match the desired rate, accounting for 207 | execution time of the callbacks. 208 | 209 | Args: 210 | value (bool): True to enable adaptive rate, False to disable it. 211 | """ 212 | if value != self._adeptive_rate: 213 | self._adeptive_rate = value 214 | for cb in self.phyx_callbacks.values(): 215 | cb.adeptive_rate = value 216 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge/plugins/nodes/icons/isaac-sim.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | 27 | 28 | 29 | 30 | 32 | 57 | 63 | 71 | 77 | 85 | 93 | 102 | 110 | 116 | 122 | 128 | 134 | 140 | 146 | 151 | 152 | -------------------------------------------------------------------------------- /tools/packman/bootstrap/generate_temp_file_name.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Copyright 2019 NVIDIA CORPORATION 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | #> 16 | 17 | $out = [System.IO.Path]::GetTempFileName() 18 | Write-Host $out 19 | # SIG # Begin signature block 20 | # MIIaVwYJKoZIhvcNAQcCoIIaSDCCGkQCAQExDzANBglghkgBZQMEAgEFADB5Bgor 21 | # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG 22 | # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAK+Ewup1N0/mdf 23 | # 1l4R58rxyumHgZvTmEhrYTb2Zf0zd6CCCiIwggTTMIIDu6ADAgECAhBi50XpIWUh 24 | # PJcfXEkK6hKlMA0GCSqGSIb3DQEBCwUAMIGEMQswCQYDVQQGEwJVUzEdMBsGA1UE 25 | # ChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNVBAsTFlN5bWFudGVjIFRydXN0 26 | # IE5ldHdvcmsxNTAzBgNVBAMTLFN5bWFudGVjIENsYXNzIDMgU0hBMjU2IENvZGUg 27 | # U2lnbmluZyBDQSAtIEcyMB4XDTE4MDcwOTAwMDAwMFoXDTIxMDcwOTIzNTk1OVow 28 | # gYMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRQwEgYDVQQHDAtT 29 | # YW50YSBDbGFyYTEbMBkGA1UECgwSTlZJRElBIENvcnBvcmF0aW9uMQ8wDQYDVQQL 30 | # DAZJVC1NSVMxGzAZBgNVBAMMEk5WSURJQSBDb3Jwb3JhdGlvbjCCASIwDQYJKoZI 31 | # hvcNAQEBBQADggEPADCCAQoCggEBALEZN63dA47T4i90jZ84CJ/aWUwVtLff8AyP 32 | # YspFfIZGdZYiMgdb8A5tBh7653y0G/LZL6CVUkgejcpvBU/Dl/52a+gSWy2qJ2bH 33 | # jMFMKCyQDhdpCAKMOUKSC9rfzm4cFeA9ct91LQCAait4LhLlZt/HF7aG+r0FgCZa 34 | # HJjJvE7KNY9G4AZXxjSt8CXS8/8NQMANqjLX1r+F+Hl8PzQ1fVx0mMsbdtaIV4Pj 35 | # 5flAeTUnz6+dCTx3vTUo8MYtkS2UBaQv7t7H2B7iwJDakEQKk1XHswJdeqG0osDU 36 | # z6+NVks7uWE1N8UIhvzbw0FEX/U2kpfyWaB/J3gMl8rVR8idPj8CAwEAAaOCAT4w 37 | # ggE6MAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUF 38 | # BwMDMGEGA1UdIARaMFgwVgYGZ4EMAQQBMEwwIwYIKwYBBQUHAgEWF2h0dHBzOi8v 39 | # ZC5zeW1jYi5jb20vY3BzMCUGCCsGAQUFBwICMBkMF2h0dHBzOi8vZC5zeW1jYi5j 40 | # b20vcnBhMB8GA1UdIwQYMBaAFNTABiJJ6zlL3ZPiXKG4R3YJcgNYMCsGA1UdHwQk 41 | # MCIwIKAeoByGGmh0dHA6Ly9yYi5zeW1jYi5jb20vcmIuY3JsMFcGCCsGAQUFBwEB 42 | # BEswSTAfBggrBgEFBQcwAYYTaHR0cDovL3JiLnN5bWNkLmNvbTAmBggrBgEFBQcw 43 | # AoYaaHR0cDovL3JiLnN5bWNiLmNvbS9yYi5jcnQwDQYJKoZIhvcNAQELBQADggEB 44 | # AIJKh5vKJdhHJtMzATmc1BmXIQ3RaJONOZ5jMHn7HOkYU1JP0OIzb4pXXkH8Xwfr 45 | # K6bnd72IhcteyksvKsGpSvK0PBBwzodERTAu1Os2N+EaakxQwV/xtqDm1E3IhjHk 46 | # fRshyKKzmFk2Ci323J4lHtpWUj5Hz61b8gd72jH7xnihGi+LORJ2uRNZ3YuqMNC3 47 | # SBC8tAyoJqEoTJirULUCXW6wX4XUm5P2sx+htPw7szGblVKbQ+PFinNGnsSEZeKz 48 | # D8jUb++1cvgTKH59Y6lm43nsJjkZU77tNqyq4ABwgQRk6lt8cS2PPwjZvTmvdnla 49 | # ZhR0K4of+pQaUQHXVIBdji8wggVHMIIEL6ADAgECAhB8GzU1SufbdOdBXxFpymuo 50 | # MA0GCSqGSIb3DQEBCwUAMIG9MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNp 51 | # Z24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV 52 | # BAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl 53 | # IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmlj 54 | # YXRpb24gQXV0aG9yaXR5MB4XDTE0MDcyMjAwMDAwMFoXDTI0MDcyMTIzNTk1OVow 55 | # gYQxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEf 56 | # MB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazE1MDMGA1UEAxMsU3ltYW50 57 | # ZWMgQ2xhc3MgMyBTSEEyNTYgQ29kZSBTaWduaW5nIENBIC0gRzIwggEiMA0GCSqG 58 | # SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDXlUPU3N9nrjn7UqS2JjEEcOm3jlsqujdp 59 | # NZWPu8Aw54bYc7vf69F2P4pWjustS/BXGE6xjaUz0wt1I9VqeSfdo9P3Dodltd6t 60 | # HPH1NbQiUa8iocFdS5B/wFlOq515qQLXHkmxO02H/sJ4q7/vUq6crwjZOeWaUT5p 61 | # XzAQTnFjbFjh8CAzGw90vlvLEuHbjMSAlHK79kWansElC/ujHJ7YpglwcezAR0yP 62 | # fcPeGc4+7gRyjhfT//CyBTIZTNOwHJ/+pXggQnBBsCaMbwDIOgARQXpBsKeKkQSg 63 | # mXj0d7TzYCrmbFAEtxRg/w1R9KiLhP4h2lxeffUpeU+wRHRvbXL/AgMBAAGjggF4 64 | # MIIBdDAuBggrBgEFBQcBAQQiMCAwHgYIKwYBBQUHMAGGEmh0dHA6Ly9zLnN5bWNk 65 | # LmNvbTASBgNVHRMBAf8ECDAGAQH/AgEAMGYGA1UdIARfMF0wWwYLYIZIAYb4RQEH 66 | # FwMwTDAjBggrBgEFBQcCARYXaHR0cHM6Ly9kLnN5bWNiLmNvbS9jcHMwJQYIKwYB 67 | # BQUHAgIwGRoXaHR0cHM6Ly9kLnN5bWNiLmNvbS9ycGEwNgYDVR0fBC8wLTAroCmg 68 | # J4YlaHR0cDovL3Muc3ltY2IuY29tL3VuaXZlcnNhbC1yb290LmNybDATBgNVHSUE 69 | # DDAKBggrBgEFBQcDAzAOBgNVHQ8BAf8EBAMCAQYwKQYDVR0RBCIwIKQeMBwxGjAY 70 | # BgNVBAMTEVN5bWFudGVjUEtJLTEtNzI0MB0GA1UdDgQWBBTUwAYiSes5S92T4lyh 71 | # uEd2CXIDWDAfBgNVHSMEGDAWgBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG 72 | # 9w0BAQsFAAOCAQEAf+vKp+qLdkLrPo4gVDDjt7nc+kg+FscPRZUQzSeGo2bzAu1x 73 | # +KrCVZeRcIP5Un5SaTzJ8eCURoAYu6HUpFam8x0AkdWG80iH4MvENGggXrTL+QXt 74 | # nK9wUye56D5+UaBpcYvcUe2AOiUyn0SvbkMo0yF1u5fYi4uM/qkERgSF9xWcSxGN 75 | # xCwX/tVuf5riVpLxlrOtLfn039qJmc6yOETA90d7yiW5+ipoM5tQct6on9TNLAs0 76 | # vYsweEDgjY4nG5BvGr4IFYFd6y/iUedRHsl4KeceZb847wFKAQkkDhbEFHnBQTc0 77 | # 0D2RUpSd4WjvCPDiaZxnbpALGpNx1CYCw8BaIzGCD4swgg+HAgEBMIGZMIGEMQsw 78 | # CQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNV 79 | # BAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxNTAzBgNVBAMTLFN5bWFudGVjIENs 80 | # YXNzIDMgU0hBMjU2IENvZGUgU2lnbmluZyBDQSAtIEcyAhBi50XpIWUhPJcfXEkK 81 | # 6hKlMA0GCWCGSAFlAwQCAQUAoHwwEAYKKwYBBAGCNwIBDDECMAAwGQYJKoZIhvcN 82 | # AQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUw 83 | # LwYJKoZIhvcNAQkEMSIEIPW+EpFrZSdzrjFFo0UT+PzFeYn/GcWNyWFaU/JMrMfR 84 | # MA0GCSqGSIb3DQEBAQUABIIBAA8fmU/RJcF9t60DZZAjf8FB3EZddOaHgI9z40nV 85 | # CnfTGi0OEYU48Pe9jkQQV2fABpACfW74xmNv3QNgP2qP++mkpKBVv28EIAuINsFt 86 | # YAITEljLN/VOVul8lvjxar5GSFFgpE5F6j4xcvI69LuCWbN8cteTVsBGg+eGmjfx 87 | # QZxP252z3FqPN+mihtFegF2wx6Mg6/8jZjkO0xjBOwSdpTL4uyQfHvaPBKXuWxRx 88 | # ioXw4ezGAwkuBoxWK8UG7Qu+7CSfQ3wMOjvyH2+qn30lWEsvRMdbGAp7kvfr3EGZ 89 | # a3WN7zXZ+6KyZeLeEH7yCDzukAjptaY/+iLVjJsuzC6tCSqhgg1EMIINQAYKKwYB 90 | # BAGCNwMDATGCDTAwgg0sBgkqhkiG9w0BBwKggg0dMIINGQIBAzEPMA0GCWCGSAFl 91 | # AwQCAQUAMHcGCyqGSIb3DQEJEAEEoGgEZjBkAgEBBglghkgBhv1sBwEwMTANBglg 92 | # hkgBZQMEAgEFAAQg14BnPazQkW9whhZu1d0bC3lqqScvxb3SSb1QT8e3Xg0CEFhw 93 | # aMBZ2hExXhr79A9+bXEYDzIwMjEwNDA4MDkxMTA5WqCCCjcwggT+MIID5qADAgEC 94 | # AhANQkrgvjqI/2BAIc4UAPDdMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVT 95 | # MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j 96 | # b20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBp 97 | # bmcgQ0EwHhcNMjEwMTAxMDAwMDAwWhcNMzEwMTA2MDAwMDAwWjBIMQswCQYDVQQG 98 | # EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xIDAeBgNVBAMTF0RpZ2lDZXJ0 99 | # IFRpbWVzdGFtcCAyMDIxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA 100 | # wuZhhGfFivUNCKRFymNrUdc6EUK9CnV1TZS0DFC1JhD+HchvkWsMlucaXEjvROW/ 101 | # m2HNFZFiWrj/ZwucY/02aoH6KfjdK3CF3gIY83htvH35x20JPb5qdofpir34hF0e 102 | # dsnkxnZ2OlPR0dNaNo/Go+EvGzq3YdZz7E5tM4p8XUUtS7FQ5kE6N1aG3JMjjfdQ 103 | # Jehk5t3Tjy9XtYcg6w6OLNUj2vRNeEbjA4MxKUpcDDGKSoyIxfcwWvkUrxVfbENJ 104 | # Cf0mI1P2jWPoGqtbsR0wwptpgrTb/FZUvB+hh6u+elsKIC9LCcmVp42y+tZji06l 105 | # chzun3oBc/gZ1v4NSYS9AQIDAQABo4IBuDCCAbQwDgYDVR0PAQH/BAQDAgeAMAwG 106 | # A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwQQYDVR0gBDowODA2 107 | # BglghkgBhv1sBwEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5j 108 | # b20vQ1BTMB8GA1UdIwQYMBaAFPS24SAd/imu0uRhpbKiJbLIFzVuMB0GA1UdDgQW 109 | # BBQ2RIaOpLqwZr68KC0dRDbd42p6vDBxBgNVHR8EajBoMDKgMKAuhixodHRwOi8v 110 | # Y3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLXRzLmNybDAyoDCgLoYsaHR0 111 | # cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC10cy5jcmwwgYUGCCsG 112 | # AQUFBwEBBHkwdzAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t 113 | # ME8GCCsGAQUFBzAChkNodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl 114 | # cnRTSEEyQXNzdXJlZElEVGltZXN0YW1waW5nQ0EuY3J0MA0GCSqGSIb3DQEBCwUA 115 | # A4IBAQBIHNy16ZojvOca5yAOjmdG/UJyUXQKI0ejq5LSJcRwWb4UoOUngaVNFBUZ 116 | # B3nw0QTDhtk7vf5EAmZN7WmkD/a4cM9i6PVRSnh5Nnont/PnUp+Tp+1DnnvntN1B 117 | # Ion7h6JGA0789P63ZHdjXyNSaYOC+hpT7ZDMjaEXcw3082U5cEvznNZ6e9oMvD0y 118 | # 0BvL9WH8dQgAdryBDvjA4VzPxBFy5xtkSdgimnUVQvUtMjiB2vRgorq0Uvtc4GEk 119 | # JU+y38kpqHNDUdq9Y9YfW5v3LhtPEx33Sg1xfpe39D+E68Hjo0mh+s6nv1bPull2 120 | # YYlffqe0jmd4+TaY4cso2luHpoovMIIFMTCCBBmgAwIBAgIQCqEl1tYyG35B5AXa 121 | # NpfCFTANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGln 122 | # aUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtE 123 | # aWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMTYwMTA3MTIwMDAwWhcNMzEw 124 | # MTA3MTIwMDAwWjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j 125 | # MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBT 126 | # SEEyIEFzc3VyZWQgSUQgVGltZXN0YW1waW5nIENBMIIBIjANBgkqhkiG9w0BAQEF 127 | # AAOCAQ8AMIIBCgKCAQEAvdAy7kvNj3/dqbqCmcU5VChXtiNKxA4HRTNREH3Q+X1N 128 | # aH7ntqD0jbOI5Je/YyGQmL8TvFfTw+F+CNZqFAA49y4eO+7MpvYyWf5fZT/gm+vj 129 | # RkcGGlV+Cyd+wKL1oODeIj8O/36V+/OjuiI+GKwR5PCZA207hXwJ0+5dyJoLVOOo 130 | # CXFr4M8iEA91z3FyTgqt30A6XLdR4aF5FMZNJCMwXbzsPGBqrC8HzP3w6kfZiFBe 131 | # /WZuVmEnKYmEUeaC50ZQ/ZQqLKfkdT66mA+Ef58xFNat1fJky3seBdCEGXIX8RcG 132 | # 7z3N1k3vBkL9olMqT4UdxB08r8/arBD13ays6Vb/kwIDAQABo4IBzjCCAcowHQYD 133 | # VR0OBBYEFPS24SAd/imu0uRhpbKiJbLIFzVuMB8GA1UdIwQYMBaAFEXroq/0ksuC 134 | # MS1Ri6enIZ3zbcgPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGG 135 | # MBMGA1UdJQQMMAoGCCsGAQUFBwMIMHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcw 136 | # AYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8v 137 | # Y2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0 138 | # MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGln 139 | # aUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMDqgOKA2hjRodHRwOi8vY3JsMy5kaWdp 140 | # Y2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMFAGA1UdIARJMEcw 141 | # OAYKYIZIAYb9bAACBDAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2Vy 142 | # dC5jb20vQ1BTMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAQEAcZUS6VGH 143 | # VmnN793afKpjerN4zwY3QITvS4S/ys8DAv3Fp8MOIEIsr3fzKx8MIVoqtwU0HWqu 144 | # mfgnoma/Capg33akOpMP+LLR2HwZYuhegiUexLoceywh4tZbLBQ1QwRostt1AuBy 145 | # x5jWPGTlH0gQGF+JOGFNYkYkh2OMkVIsrymJ5Xgf1gsUpYDXEkdws3XVk4WTfraS 146 | # Z/tTYYmo9WuWwPRYaQ18yAGxuSh1t5ljhSKMYcp5lH5Z/IwP42+1ASa2bKXuh1Eh 147 | # 5Fhgm7oMLSttosR+u8QlK0cCCHxJrhO24XxCQijGGFbPQTS2Zl22dHv1VjMiLyI2 148 | # skuiSpXY9aaOUjGCAk0wggJJAgEBMIGGMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK 149 | # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNV 150 | # BAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBpbmcgQ0ECEA1C 151 | # SuC+Ooj/YEAhzhQA8N0wDQYJYIZIAWUDBAIBBQCggZgwGgYJKoZIhvcNAQkDMQ0G 152 | # CyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yMTA0MDgwOTExMDlaMCsGCyqG 153 | # SIb3DQEJEAIMMRwwGjAYMBYEFOHXgqjhkb7va8oWkbWqtJSmJJvzMC8GCSqGSIb3 154 | # DQEJBDEiBCCHEAmNNj2zWjWYRfEi4FgzZvrI16kv/U2b9b3oHw6UVDANBgkqhkiG 155 | # 9w0BAQEFAASCAQCdefEKh6Qmwx7xGCkrYi/A+/Cla6LdnYJp38eMs3fqTTvjhyDw 156 | # HffXrwdqWy5/fgW3o3qJXqa5o7hLxYIoWSULOCpJRGdt+w7XKPAbZqHrN9elAhWJ 157 | # vpBTCEaj7dVxr1Ka4NsoPSYe0eidDBmmvGvp02J4Z1j8+ImQPKN6Hv/L8Ixaxe7V 158 | # mH4VtXIiBK8xXdi4wzO+A+qLtHEJXz3Gw8Bp3BNtlDGIUkIhVTM3Q1xcSEqhOLqo 159 | # PGdwCw9acxdXNWWPjOJkNH656Bvmkml+0p6MTGIeG4JCeRh1Wpqm1ZGSoEcXNaof 160 | # wOgj48YzI+dNqBD9i7RSWCqJr2ygYKRTxnuU 161 | # SIG # End signature block 162 | -------------------------------------------------------------------------------- /tools/packman/bootstrap/generate_temp_folder.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Copyright 2019 NVIDIA CORPORATION 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | #> 16 | 17 | param( 18 | [Parameter(Mandatory=$true)][string]$parentPath=$null 19 | ) 20 | [string] $name = [System.Guid]::NewGuid() 21 | $out = Join-Path $parentPath $name 22 | New-Item -ItemType Directory -Path ($out) | Out-Null 23 | Write-Host $out 24 | 25 | # SIG # Begin signature block 26 | # MIIaVwYJKoZIhvcNAQcCoIIaSDCCGkQCAQExDzANBglghkgBZQMEAgEFADB5Bgor 27 | # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG 28 | # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCB29nsqMEu+VmSF 29 | # 7ckeVTPrEZ6hsXjOgPFlJm9ilgHUB6CCCiIwggTTMIIDu6ADAgECAhBi50XpIWUh 30 | # PJcfXEkK6hKlMA0GCSqGSIb3DQEBCwUAMIGEMQswCQYDVQQGEwJVUzEdMBsGA1UE 31 | # ChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNVBAsTFlN5bWFudGVjIFRydXN0 32 | # IE5ldHdvcmsxNTAzBgNVBAMTLFN5bWFudGVjIENsYXNzIDMgU0hBMjU2IENvZGUg 33 | # U2lnbmluZyBDQSAtIEcyMB4XDTE4MDcwOTAwMDAwMFoXDTIxMDcwOTIzNTk1OVow 34 | # gYMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRQwEgYDVQQHDAtT 35 | # YW50YSBDbGFyYTEbMBkGA1UECgwSTlZJRElBIENvcnBvcmF0aW9uMQ8wDQYDVQQL 36 | # DAZJVC1NSVMxGzAZBgNVBAMMEk5WSURJQSBDb3Jwb3JhdGlvbjCCASIwDQYJKoZI 37 | # hvcNAQEBBQADggEPADCCAQoCggEBALEZN63dA47T4i90jZ84CJ/aWUwVtLff8AyP 38 | # YspFfIZGdZYiMgdb8A5tBh7653y0G/LZL6CVUkgejcpvBU/Dl/52a+gSWy2qJ2bH 39 | # jMFMKCyQDhdpCAKMOUKSC9rfzm4cFeA9ct91LQCAait4LhLlZt/HF7aG+r0FgCZa 40 | # HJjJvE7KNY9G4AZXxjSt8CXS8/8NQMANqjLX1r+F+Hl8PzQ1fVx0mMsbdtaIV4Pj 41 | # 5flAeTUnz6+dCTx3vTUo8MYtkS2UBaQv7t7H2B7iwJDakEQKk1XHswJdeqG0osDU 42 | # z6+NVks7uWE1N8UIhvzbw0FEX/U2kpfyWaB/J3gMl8rVR8idPj8CAwEAAaOCAT4w 43 | # ggE6MAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUF 44 | # BwMDMGEGA1UdIARaMFgwVgYGZ4EMAQQBMEwwIwYIKwYBBQUHAgEWF2h0dHBzOi8v 45 | # ZC5zeW1jYi5jb20vY3BzMCUGCCsGAQUFBwICMBkMF2h0dHBzOi8vZC5zeW1jYi5j 46 | # b20vcnBhMB8GA1UdIwQYMBaAFNTABiJJ6zlL3ZPiXKG4R3YJcgNYMCsGA1UdHwQk 47 | # MCIwIKAeoByGGmh0dHA6Ly9yYi5zeW1jYi5jb20vcmIuY3JsMFcGCCsGAQUFBwEB 48 | # BEswSTAfBggrBgEFBQcwAYYTaHR0cDovL3JiLnN5bWNkLmNvbTAmBggrBgEFBQcw 49 | # AoYaaHR0cDovL3JiLnN5bWNiLmNvbS9yYi5jcnQwDQYJKoZIhvcNAQELBQADggEB 50 | # AIJKh5vKJdhHJtMzATmc1BmXIQ3RaJONOZ5jMHn7HOkYU1JP0OIzb4pXXkH8Xwfr 51 | # K6bnd72IhcteyksvKsGpSvK0PBBwzodERTAu1Os2N+EaakxQwV/xtqDm1E3IhjHk 52 | # fRshyKKzmFk2Ci323J4lHtpWUj5Hz61b8gd72jH7xnihGi+LORJ2uRNZ3YuqMNC3 53 | # SBC8tAyoJqEoTJirULUCXW6wX4XUm5P2sx+htPw7szGblVKbQ+PFinNGnsSEZeKz 54 | # D8jUb++1cvgTKH59Y6lm43nsJjkZU77tNqyq4ABwgQRk6lt8cS2PPwjZvTmvdnla 55 | # ZhR0K4of+pQaUQHXVIBdji8wggVHMIIEL6ADAgECAhB8GzU1SufbdOdBXxFpymuo 56 | # MA0GCSqGSIb3DQEBCwUAMIG9MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNp 57 | # Z24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV 58 | # BAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl 59 | # IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmlj 60 | # YXRpb24gQXV0aG9yaXR5MB4XDTE0MDcyMjAwMDAwMFoXDTI0MDcyMTIzNTk1OVow 61 | # gYQxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEf 62 | # MB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazE1MDMGA1UEAxMsU3ltYW50 63 | # ZWMgQ2xhc3MgMyBTSEEyNTYgQ29kZSBTaWduaW5nIENBIC0gRzIwggEiMA0GCSqG 64 | # SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDXlUPU3N9nrjn7UqS2JjEEcOm3jlsqujdp 65 | # NZWPu8Aw54bYc7vf69F2P4pWjustS/BXGE6xjaUz0wt1I9VqeSfdo9P3Dodltd6t 66 | # HPH1NbQiUa8iocFdS5B/wFlOq515qQLXHkmxO02H/sJ4q7/vUq6crwjZOeWaUT5p 67 | # XzAQTnFjbFjh8CAzGw90vlvLEuHbjMSAlHK79kWansElC/ujHJ7YpglwcezAR0yP 68 | # fcPeGc4+7gRyjhfT//CyBTIZTNOwHJ/+pXggQnBBsCaMbwDIOgARQXpBsKeKkQSg 69 | # mXj0d7TzYCrmbFAEtxRg/w1R9KiLhP4h2lxeffUpeU+wRHRvbXL/AgMBAAGjggF4 70 | # MIIBdDAuBggrBgEFBQcBAQQiMCAwHgYIKwYBBQUHMAGGEmh0dHA6Ly9zLnN5bWNk 71 | # LmNvbTASBgNVHRMBAf8ECDAGAQH/AgEAMGYGA1UdIARfMF0wWwYLYIZIAYb4RQEH 72 | # FwMwTDAjBggrBgEFBQcCARYXaHR0cHM6Ly9kLnN5bWNiLmNvbS9jcHMwJQYIKwYB 73 | # BQUHAgIwGRoXaHR0cHM6Ly9kLnN5bWNiLmNvbS9ycGEwNgYDVR0fBC8wLTAroCmg 74 | # J4YlaHR0cDovL3Muc3ltY2IuY29tL3VuaXZlcnNhbC1yb290LmNybDATBgNVHSUE 75 | # DDAKBggrBgEFBQcDAzAOBgNVHQ8BAf8EBAMCAQYwKQYDVR0RBCIwIKQeMBwxGjAY 76 | # BgNVBAMTEVN5bWFudGVjUEtJLTEtNzI0MB0GA1UdDgQWBBTUwAYiSes5S92T4lyh 77 | # uEd2CXIDWDAfBgNVHSMEGDAWgBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG 78 | # 9w0BAQsFAAOCAQEAf+vKp+qLdkLrPo4gVDDjt7nc+kg+FscPRZUQzSeGo2bzAu1x 79 | # +KrCVZeRcIP5Un5SaTzJ8eCURoAYu6HUpFam8x0AkdWG80iH4MvENGggXrTL+QXt 80 | # nK9wUye56D5+UaBpcYvcUe2AOiUyn0SvbkMo0yF1u5fYi4uM/qkERgSF9xWcSxGN 81 | # xCwX/tVuf5riVpLxlrOtLfn039qJmc6yOETA90d7yiW5+ipoM5tQct6on9TNLAs0 82 | # vYsweEDgjY4nG5BvGr4IFYFd6y/iUedRHsl4KeceZb847wFKAQkkDhbEFHnBQTc0 83 | # 0D2RUpSd4WjvCPDiaZxnbpALGpNx1CYCw8BaIzGCD4swgg+HAgEBMIGZMIGEMQsw 84 | # CQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNV 85 | # BAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxNTAzBgNVBAMTLFN5bWFudGVjIENs 86 | # YXNzIDMgU0hBMjU2IENvZGUgU2lnbmluZyBDQSAtIEcyAhBi50XpIWUhPJcfXEkK 87 | # 6hKlMA0GCWCGSAFlAwQCAQUAoHwwEAYKKwYBBAGCNwIBDDECMAAwGQYJKoZIhvcN 88 | # AQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUw 89 | # LwYJKoZIhvcNAQkEMSIEIG5YDmcpqLxn4SB0H6OnuVkZRPh6OJ77eGW/6Su/uuJg 90 | # MA0GCSqGSIb3DQEBAQUABIIBAA3N2vqfA6WDgqz/7EoAKVIE5Hn7xpYDGhPvFAMV 91 | # BslVpeqE3apTcYFCEcwLtzIEc/zmpULxsX8B0SUT2VXbJN3zzQ80b+gbgpq62Zk+ 92 | # dQLOtLSiPhGW7MXLahgES6Oc2dUFaQ+wDfcelkrQaOVZkM4wwAzSapxuf/13oSIk 93 | # ZX2ewQEwTZrVYXELO02KQIKUR30s/oslGVg77ALnfK9qSS96Iwjd4MyT7PzCkHUi 94 | # ilwyGJi5a4ofiULiPSwUQNynSBqxa+JQALkHP682b5xhjoDfyG8laR234FTPtYgs 95 | # P/FaeviwENU5Pl+812NbbtRD+gKlWBZz+7FKykOT/CG8sZahgg1EMIINQAYKKwYB 96 | # BAGCNwMDATGCDTAwgg0sBgkqhkiG9w0BBwKggg0dMIINGQIBAzEPMA0GCWCGSAFl 97 | # AwQCAQUAMHcGCyqGSIb3DQEJEAEEoGgEZjBkAgEBBglghkgBhv1sBwEwMTANBglg 98 | # hkgBZQMEAgEFAAQgJhABfkDIPbI+nWYnA30FLTyaPK+W3QieT21B/vK+CMICEDF0 99 | # worcGsdd7OxpXLP60xgYDzIwMjEwNDA4MDkxMTA5WqCCCjcwggT+MIID5qADAgEC 100 | # AhANQkrgvjqI/2BAIc4UAPDdMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVT 101 | # MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j 102 | # b20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBp 103 | # bmcgQ0EwHhcNMjEwMTAxMDAwMDAwWhcNMzEwMTA2MDAwMDAwWjBIMQswCQYDVQQG 104 | # EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xIDAeBgNVBAMTF0RpZ2lDZXJ0 105 | # IFRpbWVzdGFtcCAyMDIxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA 106 | # wuZhhGfFivUNCKRFymNrUdc6EUK9CnV1TZS0DFC1JhD+HchvkWsMlucaXEjvROW/ 107 | # m2HNFZFiWrj/ZwucY/02aoH6KfjdK3CF3gIY83htvH35x20JPb5qdofpir34hF0e 108 | # dsnkxnZ2OlPR0dNaNo/Go+EvGzq3YdZz7E5tM4p8XUUtS7FQ5kE6N1aG3JMjjfdQ 109 | # Jehk5t3Tjy9XtYcg6w6OLNUj2vRNeEbjA4MxKUpcDDGKSoyIxfcwWvkUrxVfbENJ 110 | # Cf0mI1P2jWPoGqtbsR0wwptpgrTb/FZUvB+hh6u+elsKIC9LCcmVp42y+tZji06l 111 | # chzun3oBc/gZ1v4NSYS9AQIDAQABo4IBuDCCAbQwDgYDVR0PAQH/BAQDAgeAMAwG 112 | # A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwQQYDVR0gBDowODA2 113 | # BglghkgBhv1sBwEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5j 114 | # b20vQ1BTMB8GA1UdIwQYMBaAFPS24SAd/imu0uRhpbKiJbLIFzVuMB0GA1UdDgQW 115 | # BBQ2RIaOpLqwZr68KC0dRDbd42p6vDBxBgNVHR8EajBoMDKgMKAuhixodHRwOi8v 116 | # Y3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLXRzLmNybDAyoDCgLoYsaHR0 117 | # cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC10cy5jcmwwgYUGCCsG 118 | # AQUFBwEBBHkwdzAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t 119 | # ME8GCCsGAQUFBzAChkNodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl 120 | # cnRTSEEyQXNzdXJlZElEVGltZXN0YW1waW5nQ0EuY3J0MA0GCSqGSIb3DQEBCwUA 121 | # A4IBAQBIHNy16ZojvOca5yAOjmdG/UJyUXQKI0ejq5LSJcRwWb4UoOUngaVNFBUZ 122 | # B3nw0QTDhtk7vf5EAmZN7WmkD/a4cM9i6PVRSnh5Nnont/PnUp+Tp+1DnnvntN1B 123 | # Ion7h6JGA0789P63ZHdjXyNSaYOC+hpT7ZDMjaEXcw3082U5cEvznNZ6e9oMvD0y 124 | # 0BvL9WH8dQgAdryBDvjA4VzPxBFy5xtkSdgimnUVQvUtMjiB2vRgorq0Uvtc4GEk 125 | # JU+y38kpqHNDUdq9Y9YfW5v3LhtPEx33Sg1xfpe39D+E68Hjo0mh+s6nv1bPull2 126 | # YYlffqe0jmd4+TaY4cso2luHpoovMIIFMTCCBBmgAwIBAgIQCqEl1tYyG35B5AXa 127 | # NpfCFTANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGln 128 | # aUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtE 129 | # aWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMTYwMTA3MTIwMDAwWhcNMzEw 130 | # MTA3MTIwMDAwWjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j 131 | # MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBT 132 | # SEEyIEFzc3VyZWQgSUQgVGltZXN0YW1waW5nIENBMIIBIjANBgkqhkiG9w0BAQEF 133 | # AAOCAQ8AMIIBCgKCAQEAvdAy7kvNj3/dqbqCmcU5VChXtiNKxA4HRTNREH3Q+X1N 134 | # aH7ntqD0jbOI5Je/YyGQmL8TvFfTw+F+CNZqFAA49y4eO+7MpvYyWf5fZT/gm+vj 135 | # RkcGGlV+Cyd+wKL1oODeIj8O/36V+/OjuiI+GKwR5PCZA207hXwJ0+5dyJoLVOOo 136 | # CXFr4M8iEA91z3FyTgqt30A6XLdR4aF5FMZNJCMwXbzsPGBqrC8HzP3w6kfZiFBe 137 | # /WZuVmEnKYmEUeaC50ZQ/ZQqLKfkdT66mA+Ef58xFNat1fJky3seBdCEGXIX8RcG 138 | # 7z3N1k3vBkL9olMqT4UdxB08r8/arBD13ays6Vb/kwIDAQABo4IBzjCCAcowHQYD 139 | # VR0OBBYEFPS24SAd/imu0uRhpbKiJbLIFzVuMB8GA1UdIwQYMBaAFEXroq/0ksuC 140 | # MS1Ri6enIZ3zbcgPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGG 141 | # MBMGA1UdJQQMMAoGCCsGAQUFBwMIMHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcw 142 | # AYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8v 143 | # Y2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0 144 | # MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGln 145 | # aUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMDqgOKA2hjRodHRwOi8vY3JsMy5kaWdp 146 | # Y2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMFAGA1UdIARJMEcw 147 | # OAYKYIZIAYb9bAACBDAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2Vy 148 | # dC5jb20vQ1BTMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAQEAcZUS6VGH 149 | # VmnN793afKpjerN4zwY3QITvS4S/ys8DAv3Fp8MOIEIsr3fzKx8MIVoqtwU0HWqu 150 | # mfgnoma/Capg33akOpMP+LLR2HwZYuhegiUexLoceywh4tZbLBQ1QwRostt1AuBy 151 | # x5jWPGTlH0gQGF+JOGFNYkYkh2OMkVIsrymJ5Xgf1gsUpYDXEkdws3XVk4WTfraS 152 | # Z/tTYYmo9WuWwPRYaQ18yAGxuSh1t5ljhSKMYcp5lH5Z/IwP42+1ASa2bKXuh1Eh 153 | # 5Fhgm7oMLSttosR+u8QlK0cCCHxJrhO24XxCQijGGFbPQTS2Zl22dHv1VjMiLyI2 154 | # skuiSpXY9aaOUjGCAk0wggJJAgEBMIGGMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK 155 | # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNV 156 | # BAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBpbmcgQ0ECEA1C 157 | # SuC+Ooj/YEAhzhQA8N0wDQYJYIZIAWUDBAIBBQCggZgwGgYJKoZIhvcNAQkDMQ0G 158 | # CyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yMTA0MDgwOTExMDlaMCsGCyqG 159 | # SIb3DQEJEAIMMRwwGjAYMBYEFOHXgqjhkb7va8oWkbWqtJSmJJvzMC8GCSqGSIb3 160 | # DQEJBDEiBCDvFxQ6lYLr8vB+9czUl19rjCw1pWhhUXw/SqOmvIa/VDANBgkqhkiG 161 | # 9w0BAQEFAASCAQB9ox2UrcUXQsBI4Uycnhl4AMpvhVXJME62tygFMppW1l7QftDy 162 | # LvfPKRYm2YUioak/APxAS6geRKpeMkLvXuQS/Jlv0kY3BjxkeG0eVjvyjF4SvXbZ 163 | # 3JCk9m7wLNE+xqOo0ICjYlIJJgRLudjWkC5Skpb1NpPS8DOaIYwRV+AWaSOUPd9P 164 | # O5yVcnbl7OpK3EAEtwDrybCVBMPn2MGhAXybIHnth3+MFp1b6Blhz3WlReQyarjq 165 | # 1f+zaFB79rg6JswXoOTJhwICBP3hO2Ua3dMAswbfl+QNXF+igKLJPYnaeSVhBbm6 166 | # VCu2io27t4ixqvoD0RuPObNX/P3oVA38afiM 167 | # SIG # End signature block 168 | -------------------------------------------------------------------------------- /exts/isaacsim.zmq.bridge/plugins/nodes/OgnIsaacBridgeZMQNode.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include 20 | #include "client_stream_message.pb.h" 21 | 22 | 23 | using omni::graph::core::Type; 24 | using omni::graph::core::BaseDataType; 25 | 26 | #define CUDA_CHECK(call) \ 27 | do { \ 28 | cudaError_t err = call; \ 29 | if (err != cudaSuccess) { \ 30 | fprintf(stderr, "CUDA error at %s %d: %s\n", __FILE__, __LINE__, \ 31 | cudaGetErrorString(err)); \ 32 | /* Instead of exiting, log the error and continue */ \ 33 | return true; \ 34 | } \ 35 | } while (0) 36 | 37 | namespace zmq_lib = zmq; // assign namespace to zmq library to avoid conflicts with our library 38 | 39 | namespace isaacsim { 40 | namespace zmq { 41 | namespace bridge { 42 | 43 | struct InputDataBBox2d { 44 | uint32_t semanticId; 45 | int xMin; 46 | int yMin; 47 | int xMax; 48 | int yMax; 49 | float occlusionRatio; 50 | }; 51 | 52 | class OgnIsaacBridgeZMQNode { 53 | std::unique_ptr m_zmqContext; 54 | std::unique_ptr m_zmqSocket; 55 | uint32_t m_port; 56 | std::string m_ip; 57 | std::mutex m_mutex; 58 | cudaStream_t m_cudaStream; 59 | bool m_cudaStreamNotCreated{ true }; 60 | uint32_t m_zmqFailCount{ 0 }; 61 | 62 | public: 63 | OgnIsaacBridgeZMQNode() 64 | : m_zmqContext(std::make_unique(1)) { 65 | CARB_LOG_INFO("OgnIsaacBridgeZMQNode::constructor\n"); 66 | } 67 | ~OgnIsaacBridgeZMQNode() { 68 | CARB_LOG_INFO("OgnIsaacBridgeZMQNode::destructor\n"); 69 | if (m_zmqSocket) { 70 | m_zmqSocket->close(); 71 | } 72 | if (m_zmqContext) { 73 | m_zmqContext->close(); 74 | } 75 | 76 | // Clean up CUDA stream if it was created 77 | if (!m_cudaStreamNotCreated) { 78 | cudaError_t err = cudaStreamDestroy(m_cudaStream); 79 | if (err != cudaSuccess) { 80 | // Just log the error instead of using CUDA_CHECK 81 | CARB_LOG_ERROR("Error destroying CUDA stream in destructor: %s", cudaGetErrorString(err)); 82 | } 83 | } 84 | } 85 | 86 | static bool compute(OgnIsaacBridgeZMQNodeDatabase& db); 87 | 88 | bool initializeSocket(uint32_t port, const std::string& ip) { 89 | std::lock_guard lock(m_mutex); 90 | 91 | m_port = port; 92 | m_ip = ip; 93 | m_zmqFailCount = 0; 94 | 95 | try { 96 | m_zmqSocket = std::make_unique(*m_zmqContext, zmq_lib::socket_type::push); 97 | 98 | int linger = 0; 99 | m_zmqSocket->setsockopt(ZMQ_LINGER, &linger, sizeof(linger)); 100 | 101 | int hwm = 1; 102 | m_zmqSocket->setsockopt(ZMQ_SNDHWM, &hwm, sizeof(hwm)); 103 | 104 | std::string address = "tcp://" + m_ip + ":" + std::to_string(m_port); 105 | m_zmqSocket->connect(address); 106 | CARB_LOG_INFO("Connected to %s\n", address.c_str()); 107 | return true; 108 | } catch (const std::exception& e) { 109 | CARB_LOG_WARN("Failed to create socket or connect to %s:%d: %s", m_ip.c_str(), m_port, e.what()); 110 | m_zmqSocket.reset(); 111 | return false; 112 | } 113 | } 114 | }; 115 | 116 | 117 | bool OgnIsaacBridgeZMQNode::compute(OgnIsaacBridgeZMQNodeDatabase& db) { 118 | // Static variable to track the last time an error was logged 119 | // This persists between function calls to limit error message frequency 120 | static double lastErrorLogTime = 0.0; 121 | 122 | // Get the internal state for this node 123 | auto& state = db.internalState(); 124 | 125 | // Get the port and IP address from the inputs 126 | uint32_t port = db.inputs.port(); 127 | const omni::graph::core::ogn::const_string& ip = db.inputs.ip(); 128 | std::string std_ip(ip.data(), ip.size()); 129 | 130 | // If the socket is not initialized, or the port or IP address has changed, initialize the socket 131 | if (!state.m_zmqSocket || port != state.m_port || std_ip != state.m_ip) { 132 | if (!state.initializeSocket(port, std_ip)) { 133 | return true; 134 | } 135 | } 136 | 137 | // Create Protobuf message 138 | ClientStreamMessage message; 139 | 140 | // Bounding boxes 2d 141 | const InputDataBBox2d* bbox_data = reinterpret_cast(db.inputs.dataBBox2d().data()); 142 | size_t num_boxes = db.inputs.dataBBox2d().size() / sizeof(InputDataBBox2d); 143 | auto& bbox_ids = db.inputs.idsBBox2d(); 144 | auto& bbox_bbox_ids = db.inputs.bboxIdsBBox2d(); 145 | auto& bbox_labels = db.inputs.labelsBBox2d(); 146 | 147 | // Populate bbox2d data 148 | for (size_t i = 0; i < num_boxes; ++i) { 149 | const InputDataBBox2d& bbox = bbox_data[i]; 150 | BBox2DType* bbox_proto = message.mutable_bbox2d()->add_data(); 151 | bbox_proto->set_semanticid(bbox.semanticId); 152 | bbox_proto->set_xmin(bbox.xMin); 153 | bbox_proto->set_ymin(bbox.yMin); 154 | bbox_proto->set_xmax(bbox.xMax); 155 | bbox_proto->set_ymax(bbox.yMax); 156 | bbox_proto->set_occlusionratio(bbox.occlusionRatio); 157 | } 158 | 159 | // Populate bboxIds 160 | for (size_t i = 0; i < bbox_bbox_ids.size(); ++i) { 161 | message.mutable_bbox2d()->mutable_info()->add_bboxids(bbox_bbox_ids[i]); 162 | } 163 | 164 | // Populate idToLabels 165 | for (size_t i = 0; i < bbox_ids.size(); ++i) { 166 | int id = bbox_ids[i]; 167 | std::string label = db.tokenToString(bbox_labels[i]); 168 | (*message.mutable_bbox2d()->mutable_info()->mutable_idtolabels())[std::to_string(id)] = label; 169 | } 170 | 171 | // Simulation & System time 172 | double sim_dt = db.inputs.deltaSimulationTime(); 173 | double sys_dt = db.inputs.deltaSystemTime(); 174 | double sim_time = db.inputs.simulationTime(); 175 | double sys_time = db.inputs.systemTime(); 176 | 177 | message.mutable_clock()->set_sim_dt(sim_dt); 178 | message.mutable_clock()->set_sys_dt(sys_dt); 179 | message.mutable_clock()->set_sim_time(sim_time); 180 | message.mutable_clock()->set_sys_time(sys_time); 181 | 182 | // Camera data 183 | const pxr::GfMatrix4d& view_matrix = db.inputs.cameraViewTransform(); 184 | const pxr::GfVec3d& scale = db.inputs.cameraWorldScale(); 185 | const pxr::GfMatrix3d& intrinsics_matrix = db.inputs.cameraIntrinsics(); 186 | 187 | // Flatten and populate view_matrix_ros 188 | for (int row = 0; row < 4; ++row) { 189 | for (int col = 0; col < 4; ++col) { 190 | message.mutable_camera()->add_view_matrix_ros(view_matrix[row][col]); 191 | } 192 | } 193 | 194 | // Populate camera_scale 195 | message.mutable_camera()->add_camera_scale(scale[0]); 196 | message.mutable_camera()->add_camera_scale(scale[1]); 197 | message.mutable_camera()->add_camera_scale(scale[2]); 198 | 199 | // Flatten and populate intrinsics_matrix 200 | for (int row = 0; row < 3; ++row) { 201 | for (int col = 0; col < 3; ++col) { 202 | message.mutable_camera()->add_intrinsics_matrix(intrinsics_matrix[row][col]); 203 | } 204 | } 205 | 206 | // RGB & DEPTH 207 | 208 | // Copy from Device to Host 209 | size_t data_size_color = db.inputs.bufferSizeColor(); 210 | uint64_t raw_ptr_color = db.inputs.dataPtrColor(); 211 | auto data_ptr_color = std::make_unique(data_size_color); 212 | 213 | size_t data_size_depth = db.inputs.bufferSizeDepth(); 214 | uint64_t raw_ptr_depth = db.inputs.dataPtrDepth(); 215 | auto data_ptr_depth = std::make_unique(data_size_depth / sizeof(float)); 216 | 217 | // Create CUDA stream if not already created 218 | if (state.m_cudaStreamNotCreated) { 219 | CUDA_CHECK(cudaStreamCreate(&state.m_cudaStream)); 220 | state.m_cudaStreamNotCreated = false; 221 | } 222 | 223 | // If the stream is not created, warn and return true 224 | if (state.m_cudaStreamNotCreated) { 225 | CARB_LOG_WARN("CUDA stream not created, will not stream images"); 226 | return true; 227 | } 228 | 229 | // Use the stream for memory operations 230 | CUDA_CHECK(cudaMemcpyAsync(data_ptr_color.get(), reinterpret_cast(raw_ptr_color), 231 | data_size_color, cudaMemcpyDeviceToHost, state.m_cudaStream)); 232 | 233 | CUDA_CHECK(cudaMemcpyAsync(data_ptr_depth.get(), reinterpret_cast(raw_ptr_depth), 234 | data_size_depth, cudaMemcpyDeviceToHost, state.m_cudaStream)); 235 | 236 | CUDA_CHECK(cudaStreamSynchronize(state.m_cudaStream)); 237 | 238 | // Add image data to Protobuf message 239 | message.set_color_image(data_ptr_color.get(), data_size_color); 240 | message.set_depth_image(reinterpret_cast(data_ptr_depth.get()), data_size_depth); 241 | 242 | // Serialize Protobuf message 243 | std::string serialized_message; 244 | message.SerializeToString(&serialized_message); 245 | 246 | // ZMQ Data sending 247 | zmq_lib::message_t zmq_message(serialized_message.size()); 248 | memcpy(zmq_message.data(), serialized_message.data(), serialized_message.size()); 249 | auto message_sent = state.m_zmqSocket->send(zmq_message, zmq_lib::send_flags::dontwait); 250 | 251 | if (!message_sent.has_value()) { 252 | state.m_zmqFailCount++; 253 | double currentTime = db.inputs.systemTime(); 254 | // Log the error state every 5 seconds, 255 | // and only if errors are accumulating. 256 | if (state.m_zmqFailCount > 20 && currentTime - lastErrorLogTime >= 5.0) { 257 | CARB_LOG_ERROR("Failed to send message (no server available)"); 258 | lastErrorLogTime = currentTime; 259 | } 260 | } else { 261 | state.m_zmqFailCount = 0; 262 | } 263 | 264 | return true; 265 | } 266 | 267 | // This macro provides the information necessary to OmniGraph that lets it automatically register and deregister 268 | // your node type definition. 269 | REGISTER_OGN_NODE() 270 | 271 | } // bridge 272 | } // zmq 273 | } // isaacsim 274 | -------------------------------------------------------------------------------- /assets/franka_world.usda: -------------------------------------------------------------------------------- 1 | #usda 1.0 2 | ( 3 | customLayerData = { 4 | dictionary cameraSettings = { 5 | dictionary Front = { 6 | double3 position = (5, 0, 0) 7 | double radius = 5 8 | } 9 | dictionary Perspective = { 10 | double3 position = (0.40973424888394017, 1.937909539741277, 0.7595238826797109) 11 | double3 target = (0.5786803092460564, 1.2909837464738065, 0.6568495708366566) 12 | } 13 | dictionary Right = { 14 | double3 position = (0, -5, 0) 15 | double radius = 5 16 | } 17 | dictionary Top = { 18 | double3 position = (0, 0, 5) 19 | double radius = 5 20 | } 21 | string boundCamera = "/OmniverseKit_Persp" 22 | } 23 | dictionary omni_layer = { 24 | string authoring_layer = "./franka_world.usda" 25 | dictionary locked = { 26 | bool "./props/camera.usda" = 1 27 | bool "./props/looks.usd" = 0 28 | bool "./props/model.usd" = 0 29 | bool "./props/physics.usd" = 0 30 | bool "./props/scale.usd" = 0 31 | bool "./props/sensor.usd" = 0 32 | } 33 | } 34 | dictionary physicsSettings = { 35 | int "/persistent/simulation/minFrameRate" = 60 36 | } 37 | dictionary renderSettings = { 38 | } 39 | } 40 | defaultPrim = "World" 41 | endTimeCode = 1000000 42 | metersPerUnit = 1 43 | startTimeCode = 0 44 | timeCodesPerSecond = 60 45 | upAxis = "Z" 46 | ) 47 | 48 | def Xform "World" 49 | { 50 | custom string cmd_path = "" 51 | 52 | def Xform "GroundPlane" 53 | { 54 | quatf xformOp:orient = (1, 0, 0, 0) 55 | float3 xformOp:scale = (1, 1, 1) 56 | double3 xformOp:translate = (0, 0, 0) 57 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 58 | 59 | def Mesh "CollisionMesh" 60 | { 61 | uniform bool doubleSided = 0 62 | int[] faceVertexCounts = [4] 63 | int[] faceVertexIndices = [0, 1, 2, 3] 64 | normal3f[] normals = [(0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1)] 65 | point3f[] points = [(-25, -25, 0), (25, -25, 0), (25, 25, 0), (-25, 25, 0)] 66 | color3f[] primvars:displayColor = [(0.5, 0.5, 0.5)] 67 | bool primvars:isMatteObject = 1 68 | texCoord2f[] primvars:st = [(0, 0), (1, 0), (1, 1), (0, 1)] ( 69 | interpolation = "varying" 70 | ) 71 | } 72 | 73 | def Plane "CollisionPlane" ( 74 | prepend apiSchemas = ["PhysicsCollisionAPI"] 75 | ) 76 | { 77 | uniform token axis = "Z" 78 | bool primvars:isMatteObject = 1 79 | uniform token purpose = "guide" 80 | } 81 | } 82 | 83 | def Mesh "Target" ( 84 | prepend apiSchemas = ["SemanticsAPI:Semantics_1Vc4", "MaterialBindingAPI"] 85 | ) 86 | { 87 | float3[] extent = [(-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)] 88 | int[] faceVertexCounts = [4, 4, 4, 4, 4, 4] 89 | int[] faceVertexIndices = [0, 1, 3, 2, 4, 6, 7, 5, 6, 2, 3, 7, 4, 5, 1, 0, 4, 0, 2, 6, 5, 7, 3, 1] 90 | rel material:binding = ( 91 | bindMaterialAs = "weakerThanDescendants" 92 | ) 93 | normal3f[] normals = [(0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 1, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0), (-1, 0, 0), (-1, 0, 0), (-1, 0, 0), (-1, 0, 0), (1, 0, 0), (1, 0, 0), (1, 0, 0), (1, 0, 0)] ( 94 | interpolation = "faceVarying" 95 | ) 96 | point3f[] points = [(-0.5, -0.5, 0.5), (0.5, -0.5, 0.5), (-0.5, 0.5, 0.5), (0.5, 0.5, 0.5), (-0.5, -0.5, -0.5), (0.5, -0.5, -0.5), (-0.5, 0.5, -0.5), (0.5, 0.5, -0.5)] 97 | texCoord2f[] primvars:st = [(0, 0), (1, 0), (1, 1), (0, 1), (1, 0), (1, 1), (0, 1), (0, 0), (0, 1), (0, 0), (1, 0), (1, 1), (0, 0), (1, 0), (1, 1), (0, 1), (0, 0), (1, 0), (1, 1), (0, 1), (1, 0), (1, 1), (0, 1), (0, 0)] ( 98 | interpolation = "faceVarying" 99 | ) 100 | string semantic:Semantics_1Vc4:params:semanticData = "object" 101 | string semantic:Semantics_1Vc4:params:semanticType = "class" 102 | uniform token subdivisionScheme = "none" 103 | quatd xformOp:orient = (1, 0, 0, 0) 104 | double3 xformOp:scale = (0.05, 0.05, 0.05) 105 | double3 xformOp:translate = (0.4, 0, 0.025) 106 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 107 | } 108 | 109 | def RectLight "RectLight" ( 110 | prepend apiSchemas = ["ShapingAPI"] 111 | ) 112 | { 113 | float3[] extent = [(-50, -50, -0), (50, 50, 0)] 114 | float inputs:exposure = 0 115 | float inputs:height = 100 116 | float inputs:intensity = 8000 117 | bool inputs:normalize = 1 118 | float inputs:shaping:cone:angle = 180 119 | float inputs:shaping:cone:softness 120 | float inputs:shaping:focus 121 | color3f inputs:shaping:focusTint 122 | asset inputs:shaping:ies:file 123 | float inputs:width = 100 124 | bool visibleInPrimaryRay = 0 125 | quatd xformOp:orient = (0.7071067811865476, 0, 0, 0.7071067811865475) 126 | double3 xformOp:scale = (0.0007000000000030127, 0.0007000000000030127, 0.0007000000000030127) 127 | double3 xformOp:translate = (0.9131000543134977, -9.084533137818426e-15, 1.553758659902226) 128 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 129 | } 130 | 131 | def Xform "camera" ( 132 | displayName = "camera" 133 | references = @./props/interface_camera.usd@ 134 | ) 135 | { 136 | quatd xformOp:orient = (0.18301270189221946, -0.18301270189221924, -0.6830127018922193, 0.6830127018922194) 137 | float3 xformOp:rotateXYZ = (0, 0, 0) 138 | double3 xformOp:scale = (0.1, 0.1, 0.1) 139 | double3 xformOp:translate = (0.8, 1.3, 0.7) 140 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 141 | } 142 | } 143 | 144 | def Xform "Environment" 145 | { 146 | quatd xformOp:orient = (1, 0, 0, 0) 147 | double3 xformOp:scale = (1, 1, 1) 148 | double3 xformOp:translate = (0, 0, 0) 149 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 150 | 151 | def DomeLight "sky" ( 152 | prepend apiSchemas = ["ShapingAPI"] 153 | ) 154 | { 155 | float inputs:exposure = -1 156 | float inputs:intensity = 1000 157 | float inputs:shaping:cone:angle = 180 158 | float inputs:shaping:cone:softness 159 | float inputs:shaping:focus 160 | color3f inputs:shaping:focusTint 161 | asset inputs:shaping:ies:file 162 | float inputs:specular = 1 163 | asset inputs:texture:file = @https://omniverse-content-production.s3.us-west-2.amazonaws.com/Environments/2023_1/DomeLights/Indoor/ZetoCGcom_ExhibitionHall_Interior1.hdr@ 164 | token inputs:texture:format = "latlong" 165 | token visibility = "inherited" 166 | bool visibleInPrimaryRay = 1 167 | quatd xformOp:orient = (1, 0, 0, 0) 168 | double3 xformOp:scale = (1, 1, 1) 169 | double3 xformOp:translate = (0, 0, 0) 170 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 171 | } 172 | } 173 | 174 | def PhysicsScene "physicsScene" ( 175 | prepend apiSchemas = ["PhysxSceneAPI"] 176 | ) 177 | { 178 | vector3f physics:gravityDirection = (0, 0, -1) 179 | float physics:gravityMagnitude = 9.81 180 | uniform token physxScene:broadphaseType = "MBP" 181 | bool physxScene:enableCCD = 1 182 | bool physxScene:enableGPUDynamics = 0 183 | bool physxScene:enableStabilization = 1 184 | uniform token physxScene:solverType = "TGS" 185 | uint physxScene:timeStepsPerSecond = 60 186 | } 187 | 188 | def "Render" ( 189 | hide_in_stage_window = true 190 | no_delete = true 191 | ) 192 | { 193 | def "OmniverseKit" 194 | { 195 | def "HydraTextures" ( 196 | hide_in_stage_window = true 197 | no_delete = true 198 | ) 199 | { 200 | def RenderProduct "omni_kit_widget_viewport_ViewportTexture_0" ( 201 | prepend apiSchemas = ["OmniRtxSettingsCommonAdvancedAPI_1", "OmniRtxSettingsRtAdvancedAPI_1", "OmniRtxSettingsPtAdvancedAPI_1", "OmniRtxPostColorGradingAPI_1", "OmniRtxPostChromaticAberrationAPI_1", "OmniRtxPostBloomPhysicalAPI_1", "OmniRtxPostMatteObjectAPI_1", "OmniRtxPostCompositingAPI_1", "OmniRtxPostDofAPI_1", "OmniRtxPostMotionBlurAPI_1", "OmniRtxPostTvNoiseAPI_1", "OmniRtxPostTonemapIrayReinhardAPI_1", "OmniRtxPostDebugSettingsAPI_1", "OmniRtxDebugSettingsAPI_1"] 202 | hide_in_stage_window = true 203 | no_delete = true 204 | ) 205 | { 206 | rel camera = 207 | token omni:rtx:background:source:texture:textureMode = "repeatMirrored" 208 | token omni:rtx:background:source:type = "domeLight" 209 | bool omni:rtx:dlss:frameGeneration = 0 210 | string omni:rtx:material:db:rtSensorNameToIdMap = "DefaultMaterial:0;AsphaltStandardMaterial:1;AsphaltWeatheredMaterial:2;VegetationGrassMaterial:3;WaterStandardMaterial:4;GlassStandardMaterial:5;FiberGlassMaterial:6;MetalAlloyMaterial:7;MetalAluminumMaterial:8;MetalAluminumOxidizedMaterial:9;PlasticStandardMaterial:10;RetroMarkingsMaterial:11;RetroSignMaterial:12;RubberStandardMaterial:13;SoilClayMaterial:14;ConcreteRoughMaterial:15;ConcreteSmoothMaterial:16;OakTreeBarkMaterial:17;FabricStandardMaterial:18;PlexiGlassStandardMaterial:19;MetalSilverMaterial:20" 211 | bool omni:rtx:material:db:syncLoads = 1 212 | bool omni:rtx:post:registeredCompositing:invertColorCorrection = 1 213 | bool omni:rtx:post:registeredCompositing:invertToneMap = 1 214 | bool omni:rtx:pt:lightcache:cached:dontResolveConflicts = 1 215 | int omni:rtx:pt:maxSamplesPerLaunch = 2073600 216 | int omni:rtx:pt:mgpu:maxPixelsPerRegionExponent = 12 217 | color3f omni:rtx:rt:ambientLight:color = (0.1, 0.1, 0.1) 218 | bool omni:rtx:rt:demoire = 0 219 | bool omni:rtx:rt:lightcache:spatialCache:dontResolveConflicts = 1 220 | bool omni:rtx:scene:hydra:materialSyncLoads = 1 221 | bool omni:rtx:scene:hydra:mdlMaterialWarmup = 1 222 | uint omni:rtx:viewTile:limit = 4294967295 223 | rel orderedVars = 224 | custom bool overrideClipRange = 0 225 | uniform int2 resolution = (1280, 720) 226 | } 227 | } 228 | } 229 | 230 | def RenderSettings "OmniverseGlobalRenderSettings" ( 231 | prepend apiSchemas = ["OmniRtxSettingsGlobalRtAdvancedAPI_1", "OmniRtxSettingsGlobalPtAdvancedAPI_1"] 232 | no_delete = true 233 | ) 234 | { 235 | rel products = 236 | } 237 | 238 | def "Vars" 239 | { 240 | def RenderVar "LdrColor" ( 241 | hide_in_stage_window = true 242 | no_delete = true 243 | ) 244 | { 245 | uniform string sourceName = "LdrColor" 246 | } 247 | } 248 | } 249 | 250 | -------------------------------------------------------------------------------- /assets/franka_multi_cam_world.usda: -------------------------------------------------------------------------------- 1 | #usda 1.0 2 | ( 3 | customLayerData = { 4 | dictionary cameraSettings = { 5 | dictionary Front = { 6 | double3 position = (5, 0, 0) 7 | double radius = 5 8 | } 9 | dictionary Perspective = { 10 | double3 position = (0.40973424888394017, 1.937909539741277, 0.7595238826797109) 11 | double3 target = (0.5786803092460564, 1.2909837464738065, 0.6568495708366566) 12 | } 13 | dictionary Right = { 14 | double3 position = (0, -5, 0) 15 | double radius = 5 16 | } 17 | dictionary Top = { 18 | double3 position = (0, 0, 5) 19 | double radius = 5 20 | } 21 | string boundCamera = "/OmniverseKit_Persp" 22 | } 23 | dictionary omni_layer = { 24 | string authoring_layer = "./franka_world.usda" 25 | dictionary locked = { 26 | bool "./props/camera.usda" = 1 27 | bool "./props/looks.usd" = 0 28 | bool "./props/model.usd" = 0 29 | bool "./props/physics.usd" = 0 30 | bool "./props/scale.usd" = 0 31 | bool "./props/sensor.usd" = 0 32 | } 33 | } 34 | dictionary physicsSettings = { 35 | int "/persistent/simulation/minFrameRate" = 60 36 | } 37 | dictionary renderSettings = { 38 | } 39 | } 40 | defaultPrim = "World" 41 | endTimeCode = 1000000 42 | metersPerUnit = 1 43 | startTimeCode = 0 44 | timeCodesPerSecond = 60 45 | upAxis = "Z" 46 | ) 47 | 48 | def Xform "World" 49 | { 50 | custom string cmd_path = "" 51 | 52 | def Xform "GroundPlane" 53 | { 54 | quatf xformOp:orient = (1, 0, 0, 0) 55 | float3 xformOp:scale = (1, 1, 1) 56 | double3 xformOp:translate = (0, 0, 0) 57 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 58 | 59 | def Mesh "CollisionMesh" 60 | { 61 | uniform bool doubleSided = 0 62 | int[] faceVertexCounts = [4] 63 | int[] faceVertexIndices = [0, 1, 2, 3] 64 | normal3f[] normals = [(0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1)] 65 | point3f[] points = [(-25, -25, 0), (25, -25, 0), (25, 25, 0), (-25, 25, 0)] 66 | color3f[] primvars:displayColor = [(0.5, 0.5, 0.5)] 67 | bool primvars:isMatteObject = 1 68 | texCoord2f[] primvars:st = [(0, 0), (1, 0), (1, 1), (0, 1)] ( 69 | interpolation = "varying" 70 | ) 71 | } 72 | 73 | def Plane "CollisionPlane" ( 74 | prepend apiSchemas = ["PhysicsCollisionAPI"] 75 | ) 76 | { 77 | uniform token axis = "Z" 78 | bool primvars:isMatteObject = 1 79 | uniform token purpose = "guide" 80 | } 81 | } 82 | 83 | def Mesh "Target" ( 84 | prepend apiSchemas = ["SemanticsAPI:Semantics_1Vc4", "MaterialBindingAPI"] 85 | ) 86 | { 87 | float3[] extent = [(-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)] 88 | int[] faceVertexCounts = [4, 4, 4, 4, 4, 4] 89 | int[] faceVertexIndices = [0, 1, 3, 2, 4, 6, 7, 5, 6, 2, 3, 7, 4, 5, 1, 0, 4, 0, 2, 6, 5, 7, 3, 1] 90 | rel material:binding = ( 91 | bindMaterialAs = "weakerThanDescendants" 92 | ) 93 | normal3f[] normals = [(0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, 1), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 0, -1), (0, 1, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0), (0, -1, 0), (-1, 0, 0), (-1, 0, 0), (-1, 0, 0), (-1, 0, 0), (1, 0, 0), (1, 0, 0), (1, 0, 0), (1, 0, 0)] ( 94 | interpolation = "faceVarying" 95 | ) 96 | point3f[] points = [(-0.5, -0.5, 0.5), (0.5, -0.5, 0.5), (-0.5, 0.5, 0.5), (0.5, 0.5, 0.5), (-0.5, -0.5, -0.5), (0.5, -0.5, -0.5), (-0.5, 0.5, -0.5), (0.5, 0.5, -0.5)] 97 | texCoord2f[] primvars:st = [(0, 0), (1, 0), (1, 1), (0, 1), (1, 0), (1, 1), (0, 1), (0, 0), (0, 1), (0, 0), (1, 0), (1, 1), (0, 0), (1, 0), (1, 1), (0, 1), (0, 0), (1, 0), (1, 1), (0, 1), (1, 0), (1, 1), (0, 1), (0, 0)] ( 98 | interpolation = "faceVarying" 99 | ) 100 | string semantic:Semantics_1Vc4:params:semanticData = "object" 101 | string semantic:Semantics_1Vc4:params:semanticType = "class" 102 | uniform token subdivisionScheme = "none" 103 | quatd xformOp:orient = (1, 0, 0, 0) 104 | double3 xformOp:scale = (0.05, 0.05, 0.05) 105 | double3 xformOp:translate = (0.4, 0, 0.025) 106 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 107 | } 108 | 109 | def RectLight "RectLight" ( 110 | prepend apiSchemas = ["ShapingAPI"] 111 | ) 112 | { 113 | float3[] extent = [(-50, -50, -0), (50, 50, 0)] 114 | float inputs:exposure = 0 115 | float inputs:height = 100 116 | float inputs:intensity = 8000 117 | bool inputs:normalize = 1 118 | float inputs:shaping:cone:angle = 180 119 | float inputs:shaping:cone:softness 120 | float inputs:shaping:focus 121 | color3f inputs:shaping:focusTint 122 | asset inputs:shaping:ies:file 123 | float inputs:width = 100 124 | bool visibleInPrimaryRay = 0 125 | quatd xformOp:orient = (0.7071067811865476, 0, 0, 0.7071067811865475) 126 | double3 xformOp:scale = (0.0007000000000030127, 0.0007000000000030127, 0.0007000000000030127) 127 | double3 xformOp:translate = (0.9131000543134977, -9.084533137818426e-15, 1.553758659902226) 128 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 129 | } 130 | 131 | def Xform "camera" ( 132 | displayName = "camera" 133 | references = @./props/interface_camera.usd@ 134 | ) 135 | { 136 | quatd xformOp:orient = (0.18301270189221946, -0.18301270189221924, -0.6830127018922193, 0.6830127018922194) 137 | float3 xformOp:rotateXYZ = (0, 0, 0) 138 | double3 xformOp:scale = (0.1, 0.1, 0.1) 139 | double3 xformOp:translate = (0.8, 1.3, 0.7) 140 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 141 | } 142 | } 143 | 144 | def Xform "Environment" 145 | { 146 | quatd xformOp:orient = (1, 0, 0, 0) 147 | double3 xformOp:scale = (1, 1, 1) 148 | double3 xformOp:translate = (0, 0, 0) 149 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 150 | 151 | def DomeLight "sky" ( 152 | prepend apiSchemas = ["ShapingAPI"] 153 | ) 154 | { 155 | float inputs:exposure = -1 156 | float inputs:intensity = 1000 157 | float inputs:shaping:cone:angle = 180 158 | float inputs:shaping:cone:softness 159 | float inputs:shaping:focus 160 | color3f inputs:shaping:focusTint 161 | asset inputs:shaping:ies:file 162 | float inputs:specular = 1 163 | asset inputs:texture:file = @https://omniverse-content-production.s3.us-west-2.amazonaws.com/Environments/2023_1/DomeLights/Indoor/ZetoCGcom_ExhibitionHall_Interior1.hdr@ 164 | token inputs:texture:format = "latlong" 165 | token visibility = "inherited" 166 | bool visibleInPrimaryRay = 1 167 | quatd xformOp:orient = (1, 0, 0, 0) 168 | double3 xformOp:scale = (1, 1, 1) 169 | double3 xformOp:translate = (0, 0, 0) 170 | uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"] 171 | } 172 | } 173 | 174 | def PhysicsScene "physicsScene" ( 175 | prepend apiSchemas = ["PhysxSceneAPI"] 176 | ) 177 | { 178 | vector3f physics:gravityDirection = (0, 0, -1) 179 | float physics:gravityMagnitude = 9.81 180 | uniform token physxScene:broadphaseType = "MBP" 181 | bool physxScene:enableCCD = 1 182 | bool physxScene:enableGPUDynamics = 0 183 | bool physxScene:enableStabilization = 1 184 | uniform token physxScene:solverType = "TGS" 185 | uint physxScene:timeStepsPerSecond = 60 186 | } 187 | 188 | def "Render" ( 189 | hide_in_stage_window = true 190 | no_delete = true 191 | ) 192 | { 193 | def "OmniverseKit" 194 | { 195 | def "HydraTextures" ( 196 | hide_in_stage_window = true 197 | no_delete = true 198 | ) 199 | { 200 | def RenderProduct "omni_kit_widget_viewport_ViewportTexture_0" ( 201 | prepend apiSchemas = ["OmniRtxSettingsCommonAdvancedAPI_1", "OmniRtxSettingsRtAdvancedAPI_1", "OmniRtxSettingsPtAdvancedAPI_1", "OmniRtxPostColorGradingAPI_1", "OmniRtxPostChromaticAberrationAPI_1", "OmniRtxPostBloomPhysicalAPI_1", "OmniRtxPostMatteObjectAPI_1", "OmniRtxPostCompositingAPI_1", "OmniRtxPostDofAPI_1", "OmniRtxPostMotionBlurAPI_1", "OmniRtxPostTvNoiseAPI_1", "OmniRtxPostTonemapIrayReinhardAPI_1", "OmniRtxPostDebugSettingsAPI_1", "OmniRtxDebugSettingsAPI_1"] 202 | hide_in_stage_window = true 203 | no_delete = true 204 | ) 205 | { 206 | rel camera = 207 | token omni:rtx:background:source:texture:textureMode = "repeatMirrored" 208 | token omni:rtx:background:source:type = "domeLight" 209 | bool omni:rtx:dlss:frameGeneration = 0 210 | string omni:rtx:material:db:rtSensorNameToIdMap = "DefaultMaterial:0;AsphaltStandardMaterial:1;AsphaltWeatheredMaterial:2;VegetationGrassMaterial:3;WaterStandardMaterial:4;GlassStandardMaterial:5;FiberGlassMaterial:6;MetalAlloyMaterial:7;MetalAluminumMaterial:8;MetalAluminumOxidizedMaterial:9;PlasticStandardMaterial:10;RetroMarkingsMaterial:11;RetroSignMaterial:12;RubberStandardMaterial:13;SoilClayMaterial:14;ConcreteRoughMaterial:15;ConcreteSmoothMaterial:16;OakTreeBarkMaterial:17;FabricStandardMaterial:18;PlexiGlassStandardMaterial:19;MetalSilverMaterial:20" 211 | bool omni:rtx:material:db:syncLoads = 1 212 | bool omni:rtx:post:registeredCompositing:invertColorCorrection = 1 213 | bool omni:rtx:post:registeredCompositing:invertToneMap = 1 214 | bool omni:rtx:pt:lightcache:cached:dontResolveConflicts = 1 215 | int omni:rtx:pt:maxSamplesPerLaunch = 2073600 216 | int omni:rtx:pt:mgpu:maxPixelsPerRegionExponent = 12 217 | color3f omni:rtx:rt:ambientLight:color = (0.1, 0.1, 0.1) 218 | bool omni:rtx:rt:demoire = 0 219 | bool omni:rtx:rt:lightcache:spatialCache:dontResolveConflicts = 1 220 | bool omni:rtx:scene:hydra:materialSyncLoads = 1 221 | bool omni:rtx:scene:hydra:mdlMaterialWarmup = 1 222 | uint omni:rtx:viewTile:limit = 4294967295 223 | rel orderedVars = 224 | custom bool overrideClipRange = 0 225 | uniform int2 resolution = (1280, 720) 226 | } 227 | } 228 | } 229 | 230 | def RenderSettings "OmniverseGlobalRenderSettings" ( 231 | prepend apiSchemas = ["OmniRtxSettingsGlobalRtAdvancedAPI_1", "OmniRtxSettingsGlobalPtAdvancedAPI_1"] 232 | no_delete = true 233 | ) 234 | { 235 | rel products = 236 | } 237 | 238 | def "Vars" 239 | { 240 | def RenderVar "LdrColor" ( 241 | hide_in_stage_window = true 242 | no_delete = true 243 | ) 244 | { 245 | uniform string sourceName = "LdrColor" 246 | } 247 | } 248 | } 249 | 250 | --------------------------------------------------------------------------------