T04 - Multiple Protocols

Multiple protocols is a use case to test the communication between an asset and its AAS DT via different communication protocols. The current version supports 11 protocols: HTTP, OPC UA, MQTT, ROS2, WebSocket, Modbus TCP, COAP, Zenoh, UA FX, EtherNetIP, and CANOpen.

Note: UA FX, EtherNetIP and CANOpen are not yet included in this tutorial.

Requirements

The following components are required:

The following knowledge are required:

  • Intermediate about Networking

  • Basic about Java + Eclipse IDE

  • Basic about Docker

Deployment Instructions

In this example, the computer runs a software presenting a digital circle. The computer also hosts a Circle AAS DT to change the color of the digital circle. After downloading the T04 Kit, decompress it to get the two packages: (1) circle_v0.1.tar.gz contains the Docker image for the digital circle software, and (2) T04-Mprotocols.tar.gz contains the AAS model design for the computer.

Circle Object setup

On the computer, install and run the Docker image with the following command:

$ docker load -i circle_v0.1.tar.gz
$ docker run -it --net=host --rm circle:v0.1

Open a web browser and access noVNC page at http://127.0.0.1:6081/vnc.html, click connect to view the circle as in Figure 1. The circle has four colors: white, red, green, blue, corresponding to four values: 0, 1, 2, 3.

Figure 1. Circle object program

Circle DT setup

On the computer, extract T04-Mprotocols.tar.gz with the following command:

$ tar -xzvf T04-Mprotocols.tar.gz

Open Papyrus4Manufacturing and import the project as in Figure 2. The AAS Design Diagram shows the basic elements of the project. Note that users can see operation switch inside submodel Color. This operation aims to change the color of the circle.

Figure 2. Project T04-Mprotocols shown on Papyrus4Manufacturing

In Model Explorer, right click on the AssetAministrationShell Circle, choose AAS, then click Generate Asset Administration Shell Basyx code (AAS). When a new project AAS_UR3e is generated, open the file DynamicElementsWorkspace.java inside the package color and modify function switch( ). Depending on the protocol, the code will be different as follows.

a. HTTP

public void Color_switch() {
  int tmp = Integer.parseInt(connectedDevices.ep_http.readValue("").strip());
  switch (tmp) {
  case 0:
    connectedDevices.ep_http.writeValue("", "1", "PUT");
    break;
  case 1:
    connectedDevices.ep_http.writeValue("", "2", "PUT");
    break;
  case 2:
    connectedDevices.ep_http.writeValue("", "3", "PUT");
    break;
  case 3:
    connectedDevices.ep_http.writeValue("", "0", "PUT");
    break;
  default:
    throw new IllegalArgumentException("Unexpected value: " + tmp);
  }
};

b. OPC UA

public void Color_switch() {
  int tmp = Integer.parseInt(connectedDevices.ep_opcua.readValue(new NodeId(2,2))
      .toString());
  switch (tmp) {
  case 0:
    connectedDevices.ep_opcua.writeValue(new NodeId(2,2), "1");
    break;
  case 1:
    connectedDevices.ep_opcua.writeValue(new NodeId(2,2), "2");
    break;
  case 2:
    connectedDevices.ep_opcua.writeValue(new NodeId(2,2), "3");
    break;
  case 3:
    connectedDevices.ep_opcua.writeValue(new NodeId(2,2), "0");
    break;
  default:
    throw new IllegalArgumentException("Unexpected value: " + tmp);
  }
};

c. MQTT

public void Color_switch() {
  int tmp = Integer.parseInt(connectedDevices.ep_mqtt.readValue("read").toString());
  switch (tmp) {
  case 0:
    connectedDevices.ep_mqtt.writeValue("write", "1");
    break;
  case 1:
    connectedDevices.ep_mqtt.writeValue("write", "2");
    break;
  case 2:
    connectedDevices.ep_mqtt.writeValue("write", "3");
    break;
  case 3:
    connectedDevices.ep_mqtt.writeValue("write", "0");
    break;
  default:
    throw new IllegalArgumentException("Unexpected value: " + tmp);
  }
};

d. ROS2

public void Color_switch() {
  int tmp = Integer.parseInt(connectedDevices.ep_ros2.readValue("read").toString());
  switch (tmp) {
  case 0:
    connectedDevices.ep_ros2.writeValue("write", "1");
    break;
  case 1:
    connectedDevices.ep_ros2.writeValue("write", "2");
    break;
  case 2:
    connectedDevices.ep_ros2.writeValue("write", "3");
    break;
  case 3:
    connectedDevices.ep_ros2.writeValue("write", "0");
    break;
  default:
    throw new IllegalArgumentException("Unexpected value: " + tmp);
  }
};

e. WebSocket

public void Color_switch() {
  int tmp = Integer.parseInt(connectedDevices.ep_ws.readValue("").toString());
  switch (tmp) {
  case 0:
    connectedDevices.ep_ws.writeValue("", "1");
    break;
  case 1:
    connectedDevices.ep_ws.writeValue("", "2");
    break;
  case 2:
    connectedDevices.ep_ws.writeValue("", "3");
    break;
  case 3:
    connectedDevices.ep_ws.writeValue("", "0");
    break;
  default:
    throw new IllegalArgumentException("Unexpected value: " + tmp);
  }
};

f. Modbus TCP

public void Color_switch() {
  int tmp = Integer.parseInt(connectedDevices.ep_mtcp.readValue(0, EDataTypeMODBUS.REGISTER, 
    0, 1).toString());
  switch (tmp) {
  case 0:
    connectedDevices.ep_mtcp.writeValue(0, EDataTypeMODBUS.REGISTER, 0, 1, 1);
    break;
  case 1:
    connectedDevices.ep_mtcp.writeValue(0, EDataTypeMODBUS.REGISTER, 0, 1, 2);
    break;
  case 2:
    connectedDevices.ep_mtcp.writeValue(0, EDataTypeMODBUS.REGISTER, 0, 1, 3);
    break;
  case 3:
    connectedDevices.ep_mtcp.writeValue(0, EDataTypeMODBUS.REGISTER, 0, 1, 0);
    break;
  default:
    throw new IllegalArgumentException("Unexpected value: " + tmp);
  }
};

g. COAP

public void Color_switch() {
  int tmp = Integer.parseInt(connectedDevices.ep_coap.readValue().toString());
  switch (tmp) {
  case 0:
    connectedDevices.ep_coap.writeValue("1");
    break;
  case 1:
    connectedDevices.ep_coap.writeValue("2");
    break;
  case 2:
    connectedDevices.ep_coap.writeValue("3");
    break;
  case 3:
    connectedDevices.ep_coap.writeValue("0");
    break;
  default:
    throw new IllegalArgumentException("Unexpected value: " + tmp);
  }
};

h. Zenoh

public void Color_switch() {
  int tmp = Integer.parseInt(connectedDevices.ep_zenoh.readValue("read").toString());
  switch (tmp) {
  case 0:
    connectedDevices.ep_zenoh.writeValue("write", "1");
    break;
  case 1:
    connectedDevices.ep_zenoh.writeValue("write", "2");
    break;
  case 2:
    connectedDevices.ep_zenoh.writeValue("write", "3");
    break;
  case 3:
    connectedDevices.ep_zenoh.writeValue("write", "0");
    break;
  default:
    throw new IllegalArgumentException("Unexpected value: " + tmp);
  }
};

UAFX

TODO…

EtherNetIP

TODO…

CANOpen

TODO…

Verification

If all the above setups are correct, then the Circle AAS DT is connecting to the Circle software. The aim is to send command to Circle AAS DT to switch the color of the circle object.

The command requires a body. Create a file named Body and add the following content:

{
 "requestId": "{{$timestamp}}", 
 "inputArguments": [],
 "outputArguments": [],
 "timeout":5000
}

Run the following command to switch color of the circle object:

$ curl -X POST -H 'Content-Type: application/json' -d @Body \
http://127.0.0.1:8001/aas/submodels/Circle/submodel/submodelElements/switch/invoke