Skip to main content

example - building a robot

In this example, we are going to create interactively a instance of a Robotic Arm, that is based on the "Robotic" companion specification.

robot

If you haven't explored the "Robotic" Companion specification, I strongly encourage you to have a look at it so we understand how a Robotic device can be modelize and how semantic informations can be added to the model.

MotionDeviceSystem

As we read the Robotic companion spec, we understand that a Robotique system is in fact described in a Object of type "MotionDeviceSystemType". MotionDeviceSystemTable

A MotionDeviceSystemType can have one or more independant Motion Devices. It can also have Controllers and SafetyStates.

The Motion Devices will have to be inserted inside the MotionDevices folder of the MotionDeviceSystem.

This is quite interesting as it allows us to design complex robotics setup made of multiple robotics arms or robotics arms combined with other articulated equipment such as robotized Linear rails or rotary tables.

In our case, we will need to create a MotionDeviceSystem that only contain a single robotic 6 axis arm.

MotionDevice

Let's now focus now on the MotionDeviceType.

You can explore the online documenation of this ObjectType in https://reference.opcfoundation.org/Robotics/v100/docs/7.2.

MotionDeviceType

A MotionDeviceType derives from ComponentType defined in the Device Integration namespace (di).

It contains a collection of axes stored in the Axes folder as well as a collection of power train subsystems stored in the PowerTrains folder. At least one Axis and one PowerTrain are mandatory,

It as a optional Folder named AdditionalComponents that can be used to store addition subsystems that may be required.

As a ComponentType, a MotionDeviceType exposes the property that are defined in the base type and that will be useful to expose information about the Manufacturer , the SerialNumber , the ProductCode etc

Let's go !

let create a file with this initial file named "robot.model.yml"

# yaml-language-server: $schema=https://support.sterfive.com/nodeset2.schema.json
namespaceUri: http://sterfive.com/UA/MyRobot/
version: 1.0.0
publicationDate: 2019-01-01T12:00:00Z

Let now start the opcua-modeler in watch mode with the --serverso we can immediatly see the result of our model appearing in a live demo OPCUA server.

$ opcua-modeler generate -i robot.model.yml --watch --server

You can open the _generated_demoRobot.Nodeset2.xml file

click here to see _generated_demoRobot.Nodeset2.xml
<?xml version="1.0"?>
<UANodeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:uax="http://opcfoundation.org/UA/2008/02/Types.xsd" xmlns="http://opcfoundation.org/UA/2011/03/UANodeSet.xsd" xmlns:ns1="http://sterfive.com/UA/MyRobot/Type.xsd">
<NamespaceUris>
<Uri>http://sterfive.com/UA/MyRobot/</Uri>
</NamespaceUris>
<Models>
<Model ModelUri="http://sterfive.com/UA/MyRobot/" Version="0.0.0" PublicationDate="1900-01-01T00:00:00.000Z">
<RequiredModel ModelUri="http://opcfoundation.org/UA/" Version="1.05.01" PublicationDate="2022-02-24T00:00:00.000Z"/>
</Model>
</Models>
<Aliases/>
<!--ReferenceTypes-->
<!--ObjectTypes-->
<!--VariableTypes-->
<!--Other Nodes-->
</UANodeSet>

We need to import the companion namespaces that our model is relying on.

The standard OPCUA Namespace (namespace=0) is always included and do not need to be specifically added.

We need to install the http://opcfoundation.org/UA/Robotics/ namespace.

Because, the robotic namespace relies on the Device Integration namespace, we will need to install the http://opcfoundation.org/UA/DI/ beforehand.

opcua-modeler already have in stock a list of the most common companion specification.

namespace Urialias
http://opcfoundation.org/UA/ua
http://opcfoundation.org/UA/DI/di
http://opcfoundation.org/UA/IA/ia
http://opcfoundation.org/UA/AutoID/autoId
http://opcfoundation.org/UA/CNCcnc
http://opcfoundation.org/UA/Machinery/machinery
http://opcfoundation.org/UA/Robotics/robotics
http://opcfoundation.org/UA/MachineVisionmachineVision
http://opcfoundation.org/UA/PackML/packML
http://opcfoundation.org/UA/MachineTool/machineTool

the full table is available at the namespace alias table

To make it easy, we can simply use the "alias" to refer to the corresponding namespace.

We will see later on that the alias is quite convenient to build-up browse name and browse path, without worrying about namespace indexes that are usually hardly predictable.

We have chosen to replace namespace indexes with more readiable in which namepsace context a broxwse name is refering to.

So inserting a reference to the robotics and di is done straigforwardly by populating the namespaces: array in the yaml file with the corresponding aliases. Make sure you add di before robotics.

namespaces:
- di
- robotics

It is now time to create our RoboticSystemType object type by deriving from the MotionDeviceSystemType defined in robotic namespace:

objectTypes:
- browseName: MyRoboticSystemType
subtypeOf: robotics:MotionDeviceSystemType
Your YAML file should now look like this
# yaml-language-server: $schema=https://support.sterfive.com/nodeset2.schema.json
namespaceUri: http://sterfive.com/UA/MyRobot/
version: 1.0.0
publicationDate: 2023-01-01T12:00:00Z
namespaces:
- di
- robotics
objectTypes:
- browseName: MyRoboticSystemType
subtypeOf: robotics:MotionDeviceSystemType
and the generated NodeSet2.Xml File should look like this
<?xml version="1.0"?>
<UANodeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:uax="http://opcfoundation.org/UA/2008/02/Types.xsd" xmlns="http://opcfoundation.org/UA/2011/03/UANodeSet.xsd" xmlns:ns2="http://opcfoundation.org/UA/DI/Type.xsd" xmlns:ns3="http://opcfoundation.org/UA/Robotics/Type.xsd" xmlns:ns1="http://sterfive.com/UA/MyRobot/Type.xsd">
<NamespaceUris>
<Uri>http://sterfive.com/UA/MyRobot/</Uri>
<Uri>http://opcfoundation.org/UA/DI/</Uri>
<Uri>http://opcfoundation.org/UA/Robotics/</Uri>
</NamespaceUris>
<Models>
<Model ModelUri="http://sterfive.com/UA/MyRobot/" Version="0.0.0" PublicationDate="1900-01-01T00:00:00.000Z">
<RequiredModel ModelUri="http://opcfoundation.org/UA/" Version="1.05.01" PublicationDate="2022-02-24T00:00:00.000Z"/>
<RequiredModel ModelUri="http://opcfoundation.org/UA/DI/" Version="1.03.1" PublicationDate="2021-09-07T00:00:00.000Z"/>
<RequiredModel ModelUri="http://opcfoundation.org/UA/Robotics/" Version="1.01.2" PublicationDate="2021-05-20T00:00:00.000Z"/>
</Model>
</Models>
<Aliases>
<Alias Alias="HasSubtype">i=45</Alias>
</Aliases>
<!--ReferenceTypes-->
<!--ObjectTypes-->
<!--ObjectType - 1:MyRoboticSystemType {{{{ -->
<UAObjectType NodeId="ns=1;i=1000" BrowseName="1:MyRoboticSystemType">
<DisplayName>MyRoboticSystemType</DisplayName>
<References>
<Reference ReferenceType="HasSubtype" IsForward="false">ns=3;i=1002</Reference>
</References>
</UAObjectType>
<!--ObjectType - 1:MyRoboticSystemType }}}}-->
<!--VariableTypes-->
<!--Other Nodes-->
</UANodeSet>

Now, if you explore the generate md file, you should see appearing the documentation of our model. THe opcua-modeler has generated for us the class diagram using the OPCUA convention.

hierarchy MyRoboticSystemType

instantiating Robot1 inside the MotionDeviceSystem

we cannot now add a MotionDevive instance inside the MotionDevices folder of the MyRoboticSystemType instance. Note: do not forget to prefix the MotionDevices browseName with the alias of the corresponding namespace. Here we need to specify that the MotionDevices browseName belongs to the robotics namespace : robotics:MotionDevice.

namespaceUri: http://sterfive.com/UA/MyRobot/
version: 1.0.0
publicationDate: 2023-01-01T12:00:00Z
namespaces:
- di
- robotics
objectTypes:
- browseName: MyRoboticSystemType
subtypeOf: robotics:MotionDeviceSystemType
components:
- browseName: robotics:MotionDevices
components:
- browseName: Robot1
typeDefinition: robotics:MotionDeviceType

We can continue, by starting adding the Axe (Axis1, Axis2, Axis3 etc ... ) of our robot.

objectTypes:
- browseName: MyRoboticSystemType
subtypeOf: robotics:MotionDeviceSystemType
components:
- browseName: robotics:MotionDevices
components:
- browseName: Robot1
typeDefinition: robotics:MotionDeviceType
components:
- browseName: robotics:Axes
components:
- browseName: Axis1
typeDefinition: robotics:Axis
componentOf: MyRoboticSystemType/robotics:Axes

We may want to expose the flangeLoad variable. This variable is marked with a Optional Modeling rule on the MotionDeviceType. Therefore we need to specify that we want to instantate this otptional variable by adding it to the optionals collection of the component instance definition in the yaml file:

  - browseName: Robot1
typeDefinition: robotics:MotionDeviceType
organizedBy: /ua:Objects/di:DeviceSet
optionals:
- FlangeLoad

In the same way, we need to definE the PowerTrain;

objectTypes:
- browseName: MyRoboticSystemType
subtypeOf: robotics:MotionDeviceSystemType
components:
- browseName: robotics:MotionDevices
- browseName: robotics:PowerTrains
components:
- browseName: PowerTrain1
- typeDefinition: robotics:PowerTrainType


then the motors inside the power Trains

```yaml
objectTypes:
- browseName: MyRoboticSystemType
subtypeOf: robotics:MotionDeviceSystemType
components:
- browseName: robotics:MotionDevices
- browseName: robotics:PowerTrains
components:
- browseName: PowerTrain1
- typeDefinition: robotics:PowerTrainType
components:
- browseName: Motor1
typeDefinition: robotics:MotorType

and the associated gear boxes

      components:
- browseName: Motor1
typeDefinition: robotics:MotorType
- browseName: Gear1
typeDefinition: robotics:GearType

specifyin optionals properties and components

If you want to enrich one instance by exposing one of the optional properties or components defined in its type, you can specify this using the optionals yaml entry in the instance definition.

Here is how you would expose the optional ActualSpeed and ActualAcceleration OPCUA Variable for the Axis1 component.

  - browseName: Axis
typeDefinition: robotics:AxisType
optionals:
- ActualSpeed
- ActualAcceleration

The Robotics Companion provide a Move referenceType that can be use to link a power train with the axis that it put in motion.

Similarly, the HasSlave referenceType provides the relationship of power trains which provide torque for a common axis.

Adding additional references is relatively straightfoward.

references:
- referenceType: robotics:Moves
source: PowerTrain1
target: Axis1

- referenceType: robotics:HasSlave
source: PowerTrainA
target: PowerTrainC

- referenceType: robotics:Moves
source: PowerTrainB
target: AxisB
- referenceType: robotics:HasSlave
source: PowerTrainB
target: PowerTrainC

- referenceType: robotics:Moves
source: PowerTrainC
target: AxisC
- referenceType: robotics:HasSlave
source: PowerTrainC
target: PowerTrainD

- referenceType: robotics:Moves
source: PowerTrainD
target: AxisD

Initializing variables

initializers:
- variable: Robot1/di:Manufacturer
value: Sterfive Fake Robot
- variable: Robot1/di:ProductCode
value: Sterfive Fake Robot
- variable: Robot1/di:SerialNumber
value: SN12345
- variable: Robot1/robotics:FlangeLoad/robotics:Mass
value: 1000
engineeringUnits: kg