diff --git a/extensions/omni.new.extension/config/extension.toml b/extensions/omni.new.extension/config/extension.toml new file mode 100644 index 0000000..a7aad1c --- /dev/null +++ b/extensions/omni.new.extension/config/extension.toml @@ -0,0 +1,36 @@ + +[package] +# Semantic Versioning is used: https://semver.org/ +version = "0.1.0" + +# Lists people or organizations that are considered the "authors" of the package. +authors = [] + +# The title and description fields are primarly for displaying extension info in UI +title = "Omniverse Graph Extension Example" +description="Example extension for OmniGraph nodes." + +# Path (relative to the root) or content of readme markdown file for UI. +readme = "docs/README.md" + +# URL of the extension source repository. +repository="https://gitlab-master.nvidia.com/omniverse/kit-extensions/example" + +# Categories for UI. +category = "Example" + +# Keywords for the extension +keywords = ["kit", "omnigraph"] + +# Watch the .ogn files for hot reloading (only works for Python files) +[fswatcher.patterns] +include = ["*.ogn", "*.py"] +exclude = ["Ogn*Database.py"] + +[dependencies] +"omni.kit.test" = {} +"omni.graph" = {} + +# Main python module this extension provides, it will be publicly available as "import omni.new.extension". +[[python.module]] +name = "omni.new.extension" diff --git a/extensions/omni.new.extension/docs/CHANGELOG.md b/extensions/omni.new.extension/docs/CHANGELOG.md new file mode 100644 index 0000000..80e2d56 --- /dev/null +++ b/extensions/omni.new.extension/docs/CHANGELOG.md @@ -0,0 +1,4 @@ +### 0.1.0 + + - Initial release of Omni New Extension + - Added simple steer and move based controller \ No newline at end of file diff --git a/extensions/omni.new.extension/docs/README.md b/extensions/omni.new.extension/docs/README.md new file mode 100644 index 0000000..72439a2 --- /dev/null +++ b/extensions/omni.new.extension/docs/README.md @@ -0,0 +1,3 @@ + +# OmniGraph Extension [omni.new.extension] +Extension with implementation of some OmniGraph nodes diff --git a/extensions/omni.new.extension/omni/new/extension/__init__.py b/extensions/omni.new.extension/omni/new/extension/__init__.py new file mode 100644 index 0000000..fd11976 --- /dev/null +++ b/extensions/omni.new.extension/omni/new/extension/__init__.py @@ -0,0 +1,14 @@ + +import omni.ext + +# Any class derived from `omni.ext.IExt` in a top level module (defined in `python.modules` of `extension.toml`) will be +# instantiated when the extension is enabled and `on_startup(ext_id)` will be called. Later when extension gets disabled +# on_shutdown() will be called. +class OmniNewExtensionExtension(omni.ext.IExt): + # ext_id is the current extension id. It can be used with the extension manager to query additional information, + # such as where this extension is located in the filesystem. + def on_startup(self, ext_id): + print("[omni.new.extension] OmniNewExtensionExtension startup", flush=True) + + def on_shutdown(self): + print("[omni.new.extension] OmniNewExtensionExtension shutdown", flush=True) diff --git a/extensions/omni.new.extension/omni/new/extension/__pycache__/__init__.cpython-310.pyc b/extensions/omni.new.extension/omni/new/extension/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..a2aadcd Binary files /dev/null and b/extensions/omni.new.extension/omni/new/extension/__pycache__/__init__.cpython-310.pyc differ diff --git a/extensions/omni.new.extension/omni/new/extension/ogn/__init__.py b/extensions/omni.new.extension/omni/new/extension/ogn/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/extensions/omni.new.extension/omni/new/extension/ogn/__pycache__/__init__.cpython-310.pyc b/extensions/omni.new.extension/omni/new/extension/ogn/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..f83a565 Binary files /dev/null and b/extensions/omni.new.extension/omni/new/extension/ogn/__pycache__/__init__.cpython-310.pyc differ diff --git a/extensions/omni.new.extension/omni/new/extension/ogn/nodes/NegateNumber.ogn b/extensions/omni.new.extension/omni/new/extension/ogn/nodes/NegateNumber.ogn new file mode 100644 index 0000000..71a3458 --- /dev/null +++ b/extensions/omni.new.extension/omni/new/extension/ogn/nodes/NegateNumber.ogn @@ -0,0 +1,29 @@ +{ + "NegateNumber": { + "version": 1, + "description": "Negates a number", + "language": "Python", + "metadata": { + "uiName": "Negate Number" + }, + "inputs": { + "a": { + "type": "int", + "description": "Input", + "default": 0, + "metadata": { + "uiName": "A" + } + } + }, + "outputs": { + "b": { + "type": "int", + "description": "Ouput", + "metadata": { + "uiName": "B" + } + } + } + } +} \ No newline at end of file diff --git a/extensions/omni.new.extension/omni/new/extension/ogn/nodes/NegateNumber.py b/extensions/omni.new.extension/omni/new/extension/ogn/nodes/NegateNumber.py new file mode 100644 index 0000000..b820161 --- /dev/null +++ b/extensions/omni.new.extension/omni/new/extension/ogn/nodes/NegateNumber.py @@ -0,0 +1,18 @@ +""" +This is the implementation of the OGN node defined in NegateNumber.ogn +""" + +# Array or tuple values are accessed as numpy arrays so you probably need this import +import numpy + + +class NegateNumber: + """ + Negates a number + """ + + @staticmethod + def compute(db) -> bool: + """Compute the outputs from the current input""" + db.outputs.b = -db.inputs.a + return True diff --git a/extensions/omni.new.extension/omni/new/extension/ogn/nodes/__pycache__/NegateNumber.cpython-310.pyc b/extensions/omni.new.extension/omni/new/extension/ogn/nodes/__pycache__/NegateNumber.cpython-310.pyc new file mode 100644 index 0000000..b9829de Binary files /dev/null and b/extensions/omni.new.extension/omni/new/extension/ogn/nodes/__pycache__/NegateNumber.cpython-310.pyc differ diff --git a/extensions/omni.spaceros.roversimplecontroller/config/extension.toml b/extensions/omni.spaceros.roversimplecontroller/config/extension.toml new file mode 100644 index 0000000..e6b32c2 --- /dev/null +++ b/extensions/omni.spaceros.roversimplecontroller/config/extension.toml @@ -0,0 +1,38 @@ + +[package] +# Semantic Versioning is used: https://semver.org/ +version = "0.1.0" + +# Lists people or organizations that are considered the "authors" of the package. +authors = ["https://github.com/franklinselva"] + +# The title and description fields are primarly for displaying extension info in UI +description = "Rover Simple Controller for Space ROS" +title = "Rover Simple Controller" + +# Path (relative to the root) or content of readme markdown file for UI. +changelog = "docs/CHANGELOG.md" +preview_image = "data/node-preview.png" +readme = "docs/README.md" + +# URL of the extension source repository. +repository = "https://github.com/space-ros/simulation" + +# Categories for UI. +category = "Space ROS" + +# Keywords for the extension +keywords = ["ros2", "omnigraph", "space-ros"] + +# Watch the .ogn files for hot reloading (only works for Python files) +[fswatcher.patterns] +exclude = ["Ogn*Database.py"] +include = ["*.ogn", "*.py"] + +[dependencies] +"omni.graph" = {} +"omni.kit.test" = {} + +# Main python module this extension provides, it will be publicly available as "import omni.spaceros.roversimplecontroller". +[[python.module]] +name = "omni.spaceros.roversimplecontroller" diff --git a/extensions/omni.spaceros.roversimplecontroller/data/node-preview.png b/extensions/omni.spaceros.roversimplecontroller/data/node-preview.png new file mode 100644 index 0000000..ffa2ad6 Binary files /dev/null and b/extensions/omni.spaceros.roversimplecontroller/data/node-preview.png differ diff --git a/extensions/omni.spaceros.roversimplecontroller/docs/README.md b/extensions/omni.spaceros.roversimplecontroller/docs/README.md new file mode 100644 index 0000000..6a6a849 --- /dev/null +++ b/extensions/omni.spaceros.roversimplecontroller/docs/README.md @@ -0,0 +1,3 @@ +### Rover Simple Controller + +This extension provides a simple controller for the rover. This is an omnigraph node extension. diff --git a/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/__init__.py b/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/__init__.py new file mode 100644 index 0000000..62118da --- /dev/null +++ b/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/__init__.py @@ -0,0 +1,14 @@ + +import omni.ext + +# Any class derived from `omni.ext.IExt` in a top level module (defined in `python.modules` of `extension.toml`) will be +# instantiated when the extension is enabled and `on_startup(ext_id)` will be called. Later when extension gets disabled +# on_shutdown() will be called. +class OmniSpacerosRoversimplecontrollerExtension(omni.ext.IExt): + # ext_id is the current extension id. It can be used with the extension manager to query additional information, + # such as where this extension is located in the filesystem. + def on_startup(self, ext_id): + print("[omni.spaceros.roversimplecontroller] OmniSpacerosRoversimplecontrollerExtension startup", flush=True) + + def on_shutdown(self): + print("[omni.spaceros.roversimplecontroller] OmniSpacerosRoversimplecontrollerExtension shutdown", flush=True) diff --git a/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/__pycache__/__init__.cpython-310.pyc b/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..96716d0 Binary files /dev/null and b/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/__pycache__/__init__.cpython-310.pyc differ diff --git a/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/ogn/__init__.py b/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/ogn/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/ogn/__pycache__/__init__.cpython-310.pyc b/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/ogn/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..65f291b Binary files /dev/null and b/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/ogn/__pycache__/__init__.cpython-310.pyc differ diff --git a/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/ogn/nodes/RoverSimpleController.ogn b/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/ogn/nodes/RoverSimpleController.ogn new file mode 100644 index 0000000..2656932 --- /dev/null +++ b/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/ogn/nodes/RoverSimpleController.ogn @@ -0,0 +1,82 @@ +{ + "RoverSimpleController": { + "version": 1, + "description": "Receives Linear and Angular Velocity for rover and translates to wheel and steering outputs", + "language": "Python", + "metadata": { + "uiName": "Rover Simple Controller" + }, + "inputs": { + "chassis_length": { + "type": "float", + "description": "Chassis Length in meters (L)", + "default": 0, + "metadata": { + "uiName": "Chassis Length" + } + }, + "chassis_width": { + "type": "float", + "description": "Chassis Width in meters (T)", + "default": 0, + "metadata": { + "uiName": "Chassis Width" + } + }, + "linear_velocity": { + "type": "float[3]", + "description": "Linear Velocity Vector in m/s (x, y, z)", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "metadata": { + "uiName": "Linear Velocity Vector" + } + }, + "angular_velocity": { + "type": "float[3]", + "description": "Angular Velocity Vector in rad/s (x, y, z)", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "metadata": { + "uiName": "Angular Velocity Vector" + } + } + }, + "outputs": { + "wheel_velocity": { + "type": "double[]", + "description": "Wheel Velocity for six wheels of rover", + "metadata": { + "uiName": "Wheel Velocity" + }, + "default": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + }, + "steering_position": { + "type": "double[]", + "description": "Steering angle in radians", + "default": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "metadata": { + "uiName": "Steering Position" + } + } + } + } +} \ No newline at end of file diff --git a/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/ogn/nodes/RoverSimpleController.py b/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/ogn/nodes/RoverSimpleController.py new file mode 100644 index 0000000..e66cea9 --- /dev/null +++ b/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/ogn/nodes/RoverSimpleController.py @@ -0,0 +1,78 @@ +""" +This is the implementation of the OGN node defined in RoverSimpleController.ogn +""" + +# Array or tuple values are accessed as numpy arrays so you probably need this import +import math + + +def map_angular_to_steering(angular_speed) -> float: + """Map angular speed to steering angle.""" + if abs(angular_speed) < 1e-3: + return 0.0 + + # max 0.6 min -0.6 + angular_speed = min(0.6, max(angular_speed, -0.6)) + return (angular_speed / abs(angular_speed)) * (-25 * abs(angular_speed) + 17.5) + + +class RoverSimpleController: + """ + Receives Linear and Angular Velocity for rover and translates to wheel and steering + outputs + """ + + @staticmethod + def compute(db) -> bool: + """Compute the outputs from the current input""" + # Get the inputs + chassis_length = db.inputs.chassis_length + chassis_width = db.inputs.chassis_width + linear_velocity = db.inputs.linear_velocity + angular_velocity = db.inputs.angular_velocity + + # Compute wheel velocity + linear_velocity_x = linear_velocity[0] + wheel_velocity = [ + linear_velocity_x, + linear_velocity_x * 1.5, + linear_velocity_x, + -linear_velocity_x, + -linear_velocity_x * 1.5, + -linear_velocity_x, + ] + + # Compute steering angle + steer_position = [] + turn_rad = map_angular_to_steering(angular_velocity[2]) + + if abs(turn_rad) < 1e-3: + steer_position = [0.0, 0.0, 0.0, 0.0] + else: + turning_radius = abs(turn_rad) # R + + chassis_length = 2.08157 # L + chassis_width = 1.53774 # T + + alpha_i = math.atan(chassis_length / (turning_radius - (chassis_width / 2))) + alpha_o = math.atan(chassis_length / (turning_radius + (chassis_width / 2))) + + if alpha_i > 0.6: + alpha_i = 0.6 + + if alpha_o > 0.6: + alpha_o = 0.6 + + alpha_i = round(alpha_i, 2) + alpha_o = round(alpha_o, 2) + + if turn_rad > 0.0: + steer_position = [alpha_i, -alpha_i, alpha_o, -alpha_o] + else: + steer_position = [-alpha_o, alpha_o, -alpha_i, alpha_i] + + # Assign the outputs + db.outputs.wheel_velocity = wheel_velocity + db.outputs.steering_position = steer_position + + return True diff --git a/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/ogn/nodes/__pycache__/RoverSimpleController.cpython-310.pyc b/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/ogn/nodes/__pycache__/RoverSimpleController.cpython-310.pyc new file mode 100644 index 0000000..64a8aca Binary files /dev/null and b/extensions/omni.spaceros.roversimplecontroller/omni/spaceros/roversimplecontroller/ogn/nodes/__pycache__/RoverSimpleController.cpython-310.pyc differ