Skip to content

Commit

Permalink
Merge pull request #4 from loupeteam/release/prep
Browse files Browse the repository at this point in the history
Prepare for official release
  • Loading branch information
AndrewMusser authored May 16, 2024
2 parents 7447284 + bc98ff3 commit 78832b2
Show file tree
Hide file tree
Showing 17 changed files with 542 additions and 137 deletions.
10 changes: 10 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"ms-vscode.cpptools",
"ms-python.python",
"ms-python.vscode-pylance",
"bungcip.better-toml"
],
}
File renamed without changes.
342 changes: 342 additions & 0 deletions .vscode/settings.json

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,26 @@ [email protected]

# Description

Beckhoff Bridge Extension for Isaac Sim. Developed using [pyads](https://github.com/stlehmann/pyads).
This is an extension that connects Beckhoff PLCs into the Omniverse ecosystem. It leverages [pyads](https://github.com/stlehmann/pyads) to set up an ADS client for communicating with PLCs.

# Documentation

Usage can be found in the extension readme file [here](loupe.beckhoff_bridge/docs/README.md).
Detailed documentation can be found in the extension readme file [here](exts/loupe.simulation.beckhoff_bridge/docs/README.md).

# Licensing

This software contains source code provided by NVIDIA Corporation. This code is subject to the terms of the [NVIDIA Omniverse License Agreement](https://docs.omniverse.nvidia.com/isaacsim/latest/common/NVIDIA_Omniverse_License_Agreement.html). Files are licensed as follows:

### Files created entirely by Loupe ([MIT License](LICENSE)):
* `ads_driver.py`
* `BeckhoffBridge.py`
* `__init__.py`

### Files including Nvidia-generated code and modifications by Loupe (Nvidia Omniverse License Agreement AND MIT License; use must comply to whichever is most restrictive for any attribute):
* `__init__.py`
* `extension.py`
* `global_variables.py`
* `ui_builder.py`

This software is intended for use with NVIDIA Isaac Sim, which is subject to the [NVIDIA Omniverse License Agreement](https://docs.omniverse.nvidia.com/isaacsim/latest/common/NVIDIA_Omniverse_License_Agreement.html) for use and distribution.
This software is intended for use with NVIDIA Omniverse apps, which are subject to the [NVIDIA Omniverse License Agreement](https://docs.omniverse.nvidia.com/isaacsim/latest/common/NVIDIA_Omniverse_License_Agreement.html) for use and distribution.

This software also relies on [pyads](https://github.com/stlehmann/pyads), which is licensed under the MIT license.
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ order = 0

[package]
version = "0.1.0"
category = "Connector"
category = "simulation"
title = "Beckhoff Bridge"
description = "A bridge for connecting Omniverse to Beckhoff PLCs over ADS"
authors = ["Loupe"]
repository = "https://github.com/loupeteam/IsaacSim_Beckhoff_Bridge_Extension"
keywords = []
repository = "https://github.com/loupeteam/Omniverse_Beckhoff_Bridge_Extension"
keywords = ["Beckhoff", "Digital Twin", "ADS", "PLC"]
changelog = "docs/CHANGELOG.md"
readme = "docs/README.md"
preview_image = "data/preview.png"
Expand All @@ -18,12 +18,11 @@ icon = "data/icon.png"

[dependencies]
"omni.kit.uiapp" = {}
"omni.isaac.ui" = {}
"omni.isaac.core" = {}

[python.pipapi]
requirements = ['pyads']
use_online_index = true

[[python.module]]
name = "loupe.beckhoff_bridge"
name = "loupe.simulation.beckhoff_bridge"
public = true
File renamed without changes
File renamed without changes
File renamed without changes.
77 changes: 77 additions & 0 deletions exts/loupe.simulation.beckhoff_bridge/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Beckhoff Bridge

The Beckhoff Bridge is an [NVIDIA Omniverse](https://www.nvidia.com/en-us/omniverse/) extension for communicating with [Beckhoff PLCs](https://www.beckhoff.com/en-en/) using the [ADS protocol](https://infosys.beckhoff.com/english.php?content=../content/1033/cx8190_hw/5091854987.html&id=).

# Installation

### Install from registry

This is the preferred method. Open up the extensions manager by navigating to `Window / Extensions`. The extension is available as a "Third Party" extension. Search for `Beckhoff Bridge`, and click the slider to Enable it. Once enabled, the extension will be available as an option in the top menu banner of the Omniverse app.

### Install from source

You can also install from source instead. In order to do so, follow these steps:
- Clone the repo [here](https://github.com/loupeteam/Omniverse_Beckhoff_Bridge_Extension).
- In your Omniverse app, open the extensions manager by navigating to `Window / Extensions`.
- Open the general extension settings, and add a new entry into the `Extension Search Paths` table. This should be the local path to the root of the repo that was just cloned.
- Back in the extensions manager, search for `BECKHOFF BRIDGE`, and enable it.
- Once enabled, the extension will show up as an option in the top menu banner.

# Configuration

You can open the extension by clicking on `Beckhoff Bridge / Open Bridge Settings` from the top menu. The following configuration options are available:

- Enable ADS Client: Enable or disable the ADS client from reading or writing data to the PLC.
- Refresh Rate: The rate at which the ADS client will read data from the PLC in milliseconds.
- PLC AMS Net ID: The AMS Net ID of the PLC to connect to.
- Settings commands: These commands are used to load and save the extension settings as permanent parameters. The Save button backs up the current parameters, and the Load button restores them from the last saved values.

# Usage

Once the extension is enabled, the Beckhoff Bridge will attempt to connect to the PLC.

### Monitoring Extension Status

The status of the extension can be viewed in the `Status` field. Here are the possible messages and their meaning:
- `Disabled`: the enable checkbox is unchecked, and no communication is attempted.
- `Attempting to connect...`: the ADS client is trying to connect to the PLC. Staying in this state for more than a few seconds indicates that there is a problem with the connection.
- `Connected`: the ADS client has successfully established a connection with the PLC.
- `Error writing data to the PLC: [...]`: an error occurred while performing an ADS variable write.
- `Error reading data from the PLC: [...]`: an error occurred while performing an ADS variable read.

### Monitoring Variable Values

Once variable reads are occurring, the `Monitor` pane will show a JSON string with the names and values of the variables being read. This is helpful for troubleshooting.

### Performing read/write operations

The variables on the PLC that should be read or written are specified in a custom user extension or app that uses the API available from the `loupe.simulation.beckhoff_bridge` module.

```python
from loupe.simulation.beckhoff_bridge import BeckhoffBridge

# Instantiate the bridge and register lifecycle subscriptions
beckhoff_bridge = BeckhoffBridge.Manager()
beckhoff_bridge.register_init_callback(on_beckoff_init)
beckhoff_bridge.register_data_callback(on_message)

# This function gets called once on init, and should be used to subscribe to cyclic reads.
def on_beckoff_init( event ):
# Create a list of variable names to be read cyclically, and add to Manager
variables = [ 'MAIN.custom_struct.var1',
'MAIN.custom_struct.var_array[0]',
'MAIN.custom_struct.var_array[1]']

beckhoff_bridge.add_cyclic_read_variables(variables)

# This function is called every time the bridge receives new data
def on_message( event ):
# Read the event data, which includes values for the PLC variables requested
data = event.payload['data']['MAIN']['custom_struct']['var_array']

# In the app's cyclic logic, writes can be performed as follows:
def cyclic():
# Write the value `1` to PLC variable 'MAIN.custom_struct.var1'
beckhoff_bridge.write_variable('MAIN.custom_struct.var1', 1)

```
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
Copyright (c) 2024 Loupe
https://loupe.team
This file is part of IsaacSim_Beckhoff_Bridge_Extension, licensed under the MIT License.
This file is part of Omniverse_Beckhoff_Bridge_Extension, licensed under the MIT License.
'''

from typing import Callable
import carb.events
import omni.kit.app

EVENT_TYPE_DATA_INIT = carb.events.type_from_string("loupe.beckhoff_bridge.DATA_INIT")
EVENT_TYPE_DATA_READ = carb.events.type_from_string("loupe.beckhoff_bridge.DATA_READ")
EVENT_TYPE_DATA_READ_REQ = carb.events.type_from_string("loupe.beckhoff_bridge.DATA_READ_REQ")
EVENT_TYPE_DATA_WRITE_REQ = carb.events.type_from_string("loupe.beckhoff_bridge.DATA_WRITE_REQ")
EVENT_TYPE_DATA_INIT = carb.events.type_from_string("loupe.simulation.beckhoff_bridge.DATA_INIT")
EVENT_TYPE_DATA_READ = carb.events.type_from_string("loupe.simulation.beckhoff_bridge.DATA_READ")
EVENT_TYPE_DATA_READ_REQ = carb.events.type_from_string("loupe.simulation.beckhoff_bridge.DATA_READ_REQ")
EVENT_TYPE_DATA_WRITE_REQ = carb.events.type_from_string("loupe.simulation.beckhoff_bridge.DATA_WRITE_REQ")

class Manager:
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This software contains source code provided by NVIDIA Corporation.
# Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
#
# NVIDIA CORPORATION and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION is strictly prohibited.
#

from .extension import *
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Copyright (c) 2024 Loupe
https://loupe.team
This file is part of IsaacSim_Beckhoff_Bridge_Extension, licensed under the MIT License.
This file is part of Omniverse_Beckhoff_Bridge_Extension, licensed under the MIT License.
'''

Expand Down Expand Up @@ -135,4 +135,25 @@ def connect(self, ams_net_id = None):
self._connection = pyads.Connection(self.ams_net_id, pyads.PORT_TC3PLC1)
self._connection.open()

def disconnect(self):
"""
Disconnects from the target device.
"""
self._connection.close()

def is_connected(self):
"""
Returns the connection state.
Returns:
bool: True if the connection is open, False otherwise.
"""
try:
adsState, deviceState = self._connection.read_state()
return True
except Exception as e:
return False


Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
import omni.usd
import omni.timeline
import omni.kit.commands
from omni.kit.menu.utils import add_menu_items, remove_menu_items
from omni.isaac.ui.menu import make_menu_item_description
from omni.kit.menu.utils import add_menu_items, remove_menu_items, MenuItemDescription
from omni.usd import StageEventType
import omni.physx as _physx

Expand Down Expand Up @@ -59,9 +58,8 @@ def on_startup(self, ext_id: str):
self._models = {}
self._ext_id = ext_id
self._menu_items = [
make_menu_item_description(ext_id, EXTENSION_TITLE, lambda a=weakref.proxy(self): a._menu_callback())
MenuItemDescription(name="Open Bridge Settings", onclick_fn=lambda a=weakref.proxy(self): a._menu_callback())
]

add_menu_items(self._menu_items, EXTENSION_TITLE)

# Filled in with User Functions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#


EXTENSION_TITLE = "beckhoff_bridge"
EXTENSION_NAME = "loupe.beckhoff_bridge"
EXTENSION_DESCRIPTION = "Connector for Beckhoff PLCs"
EXTENSION_TITLE = "Beckhoff Bridge"
EXTENSION_NAME = "loupe.simulation.beckhoff_bridge"
EXTENSION_DESCRIPTION = "Bridge to Beckhoff PLCs"

Loading

0 comments on commit 78832b2

Please sign in to comment.