Skip to content

Step 9: Using a custom UANodeSet with open62541

Last updated on September 1, 2020


Compile open62541 with a custom UANodeSet using CMake. This step will use nodeset_compiler.py to convert the UANodeSet2.xml to C99 header and source files and then compile the complete open62541 C99 application into a single executable.

This Post is part of the OPC UA Information Model Tutorial.


Notice

You can use the open62541 Nodeset Compiler directly, or create a CMake project which is using the provided macros.
I strongly recommend to use the CMake approach.


Especially for more complex setups where you have multiple NodeSets based on each other, manually passing the parameters to the Nodeset Compiler is very cumbersome. CMake will do this for you.
Also, the CMake macro also calls the datatype generator (custom datatypes) and nodeid generator (header file with node ID defines) for you.

A more complete example with heavy use of heavy usage of ModelDesign files and dependencies between them is shown in this project:

https://github.com/opcua-skills/plug-and-produce

Building an OPC UA Server with a custom UANodeSet using CMake

The open62541 OPC UA Stack uses a Python Script (Nodeset Compiler) to generate compilable C99 Code out of NodeSet2.xml files.

The complete documentation on the Nodeset Compiler can be found here:
https://open62541.org/doc/current/nodeset_compiler.html

Over the last years the interface and parameters to this Python Script became somewhat complext and not as intuitive as they should be (shame on me (Stefan) as I’m the one who extended it).

Therefore I created a simpler to use CMake Macro which handles all the complex stuff for you, as shown in the following example:

# Generate types and namespace for DI
ua_generate_nodeset_and_datatypes(
    NAME "di"
    FILE_CSV "${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/OpcUaDiModel.csv"
    FILE_BSD "${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/Opc.Ua.Di.Types.bsd"
    NAMESPACE_IDX 2
    FILE_NS "${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/Opc.Ua.Di.NodeSet2.xml"
)

# generate PLCopen namespace which is using DI
ua_generate_nodeset_and_datatypes(
    NAME "plc"
    # PLCopen does not define custom types. Only generate the nodeset
    FILE_NS "${PROJECT_SOURCE_DIR}/deps/ua-nodeset/PLCopen/Opc.Ua.Plc.NodeSet2.xml"
    # PLCopen depends on the di nodeset, which must be generated before
    DEPENDS "di"
)

As you can see, you need the following files of a NodeSet:

  • .csv: Used to generate the NodeID header to provide defines for specific node IDs instead of numbers
  • .bsd: Used to generate custom data types and struct definitions if you define your own Data Types in the nodeset
  • NodeSet2.xml: Contains the whole nodeset definition and is used to generate the initialization code for the open62541 server.

Create a new CMake Project

The first step is to create a new CMake project in a new folder, let’s name it FooServer. In this folder create a CMakeLists.txt file with the following content:

(see also: https://github.com/Pro/opcua-modeling-tutorial-server/blob/master/CMakeLists.txt)

cmake_minimum_required(VERSION 3.2)
project(opcua-modeling-tutorial-server)

# open62541 must be installed.
# If in custom path, then use -DCMAKE_PREFIX_PATH=/home/user/install
find_package(open62541 1.1 REQUIRED COMPONENTS FullNamespace)

# Output directory for Nodeset Compiler
set(GENERATE_OUTPUT_DIR "${CMAKE_BINARY_DIR}/src_generated/")

file(MAKE_DIRECTORY "${GENERATE_OUTPUT_DIR}")
include_directories("${GENERATE_OUTPUT_DIR}")

ua_generate_nodeset_and_datatypes(
        NAME "foo_flt"
        TARGET_PREFIX "${PROJECT_NAME}"
        FILE_CSV "${PROJECT_SOURCE_DIR}/model/Published/FooFlt/FooFltModel.csv"
        FILE_BSD "${PROJECT_SOURCE_DIR}/model/Published/FooFlt/FooFlt.Types.bsd"
        OUTPUT_DIR "${GENERATE_OUTPUT_DIR}"
	# This namespace index must match the order in which you are adding the nodeset in the source code
        NAMESPACE_IDX 2
        FILE_NS "${PROJECT_SOURCE_DIR}/model/Published/FooFlt/FooFlt.NodeSet2.xml"
        INTERNAL
)

# Previous macro automatically sets some variables which hold the generated source code files using the provided NAME
add_executable(opcua-modeling-tutorial-server
               ${UA_NODESET_FOO_FLT_SOURCES}
               ${UA_TYPES_FOO_FLT_SOURCES}
               main.c
               )

# Make sure the nodeset compiler is execute before compiling the main file
add_dependencies(opcua-modeling-tutorial-server
                 ${PROJECT_NAME}-ns-foo_flt
                 )

target_link_libraries(opcua-modeling-tutorial-server open62541::open62541)

And copy the previously generated NodeSet2 files into the model/Published subfolder:

tree ~/FooServer
.
└── CMakeLists.txt
└── model
    ├── FooFltModel.csv
    ├── FooFltModel.xml
    ├── Published
    │   └── FooFlt
    │       ├── FooFlt.Classes.cs
    │       ├── FooFlt.Constants.cs
    │       ├── FooFlt.DataTypes.cs
    │       ├── FooFltModel.csv
    │       ├── FooFltModel.xml
    │       ├── FooFlt.NodeSet2.xml
    │       ├── FooFlt.NodeSet.xml
    │       ├── FooFlt.PredefinedNodes.uanodes
    │       ├── FooFlt.PredefinedNodes.xml
    │       ├── FooFlt.Types.bsd
    │       └── FooFlt.Types.xsd

Create a custom Server Code which uses your Model

After you created a new CMake project in previous section, you now need to define your Source Code which is initializing an OPC UA Server with your model.

Therefore, create a new file called main.c in the FooServer directory with the following content:

(see also https://github.com/Pro/opcua-modeling-tutorial-server/blob/master/main.c)

#include <open62541/plugin/log_stdout.h>
#include <open62541/server.h>
#include <open62541/server_config_default.h>

/* Files namespace_foo_flt_generated.h and namespace_foo_flt_generated.c are created from FooFlt.NodeSet2.xml in the
 * /src_generated directory by CMake */
#include "foo_flt_nodeids.h"
#include "namespace_foo_flt_generated.h"

#include <signal.h>
#include <stdlib.h>

UA_Boolean running = true;

static void stopHandler(int sign) {
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
    running = false;
}

int main(int argc, char** argv) {
    signal(SIGINT, stopHandler);
    signal(SIGTERM, stopHandler);
    
    UA_Server *server = UA_Server_new();
    UA_ServerConfig_setDefault(UA_Server_getConfig(server));

    UA_StatusCode retval;
    /* create nodes from nodeset */
    if(namespace_foo_flt_generated(server) != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Could not add the Foo FLT nodeset. "
        "Check previous output for any error.");
        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    } else {

        // Do some additional stuff with the nodes

        // this will just get the namespace index, since it is already added to the server
        UA_UInt16 nsIdx = UA_Server_addNamespace(server, "https://new.foo.com/zebra-compression/flattening-and-subspacefolding/UA/");

        UA_NodeId testInstanceId = UA_NODEID_NUMERIC(nsIdx, UA_FOO_FLTID_APE);

        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "The Ape has ns=%d;id=%d",
                    testInstanceId.namespaceIndex, testInstanceId.identifier.numeric);

        retval = UA_Server_run(server, &running);
    }

    UA_Server_delete(server);
    return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}

Especially look at line 29 which is is calling the gererated Nodeset initialization. This call will create all the nodes defined in your NodeSet2.xml file inside the open62541 OPC UA server.

To build and run this server just use CMake and make. Note, if you installed open62541 in a custom location, you may need to use the CMAKE_PREFIX_PATH option:

cd ~/FooServer
mkdir build && cd build
cmake -DCMAKE_PREFIX_PATH=/home/user/install ..
make -j
# Then run the server:
./opcua-modeling-tutorial-server

Now you can connect any OPC UA Client to your server and browse it.

Here is an example output:

$ make -j
Scanning dependencies of target opcua-modeling-tutorial-server-ids-foo_flt
Scanning dependencies of target opcua-modeling-tutorial-server-types-foo_flt
[ 22%] Generating src_generated/types_foo_flt_generated.c, src_generated/types_foo_flt_generated.h, src_generated/types_foo_flt_generated_handling.h, src_generated/types_foo_flt_generated_encoding_binary.h
[ 22%] Generating src_generated/foo_flt_nodeids.h
[ 22%] Built target opcua-modeling-tutorial-server-ids-foo_flt
[ 22%] Built target opcua-modeling-tutorial-server-types-foo_flt
Scanning dependencies of target opcua-modeling-tutorial-server-ns-foo_flt
[ 33%] Generating src_generated/namespace_foo_flt_generated.c, src_generated/namespace_foo_flt_generated.h
INFO:__main__:Preprocessing (existing) /home/user/install/open62541/share/open62541/tools/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml
INFO:__main__:Preprocessing /home/user/FooServer/model/Published/FooFlt/FooFlt.NodeSet2.xml
INFO:__main__:Generating Code for Backend: open62541
INFO:__main__:NodeSet generation code successfully printed
[ 33%] Built target opcua-modeling-tutorial-server-ns-foo_flt
Scanning dependencies of target opcua-modeling-tutorial-server
[ 44%] Building C object CMakeFiles/opcua-modeling-tutorial-server.dir/src_generated/namespace_foo_flt_generated.c.o
[ 55%] Building C object CMakeFiles/opcua-modeling-tutorial-server.dir/src_generated/types_foo_flt_generated.c.o
[ 66%] Building C object CMakeFiles/opcua-modeling-tutorial-server.dir/main.c.o
[ 77%] Linking C executable opcua-modeling-tutorial-server
[100%] Built target opcua-modeling-tutorial-server

$ ls
CMakeFiles     CMakeCache.txt       Makefile
src_generated  cmake_install.cmake  opcua-modeling-tutorial-server

$ ./opcua-modeling-tutorial-server
[2020-08-31 14:26:27.897 (UTC+0200)] warn/server	AccessControl: Unconfigured AccessControl. Users have all permissions.
[2020-08-31 14:26:27.897 (UTC+0200)] info/server	AccessControl: Anonymous login is enabled
[2020-08-31 14:26:27.897 (UTC+0200)] warn/server	Username/Password configured, but no encrypting SecurityPolicy. This can leak credentials on the network.
[2020-08-31 14:26:27.897 (UTC+0200)] warn/userland	AcceptAll Certificate Verification. Any remote certificate will be accepted.
[2020-08-31 14:26:27.898 (UTC+0200)] info/server	The Ape has ns=2;id=15111
[2020-08-31 14:26:27.898 (UTC+0200)] info/network	TCP network layer listening on opc.tcp://localhost:4840/
^C[2020-08-31 14:26:32.597 (UTC+0200)] info/server	received ctrl-c
[2020-08-31 14:26:32.597 (UTC+0200)] info/network	Shutting down the TCP network layer
                                                                          

And the view in UaExpert:

Building an example server with a custom UANodeset and gcc (the manual, hard way)

Instead of blindly relying on the pre-existing examples and make files of open62541, a manual build of the custom UANodeSet and open62541 OPC UA server will yield additional insights.

Manual validation and compilation of an UANodeSet

The main reference is: https://open62541.org/doc/current/nodeset_compiler.html

Before compiling an open62541 OPC UA server, the target UANodeSet file must be validated and compiled to C99 source and header files.

A valid FOO UANodeSet file FooFltModel.xml is provided in the Github Repo of this tutorial, including the generated NodeSet2.xml files in the Published folder:

https://github.com/Pro/opcua-modeling-tutorial/tree/master-published/Published/FooFlt

Compile the UANodeSet according to the documentation in the folder created at the beginning of this post:

cd ~/FooServer
python ~/open62541/tools/nodeset_compiler/nodeset_compiler.py --types-array=UA_TYPES --existing ~/open62541/deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml --xml model/Published/FooFlt/FooFlt.NodeSet2.xml FooFlt

# INFO:__main__:Preprocessing (existing) /home/user/open62541/deps/ua-# nodeset/Schema/Opc.Ua.NodeSet2.xml
# INFO:__main__:Preprocessing model/Published/FooFlt/FooFlt.NodeSet2.xml
# INFO:__main__:Generating Code for Backend: open62541
# INFO:__main__:NodeSet generation code successfully printed

This will generate two source files, namely FooFlt.c and FooFlt.h.

At this point the UANodeSet is ready to be compiled into a open62541.

Building an open62541 OPC UA server with a custom UANodeset by hand

After manually creating the .c and .h file from the UANodeset, you need a main file which uses the generated source code.

Use this slightly adapted main.c file. Especially note the changed include files and that the Node IDs are not availalbe:

#include <open62541/plugin/log_stdout.h>
#include <open62541/server.h>
#include <open62541/server_config_default.h>

/* Files namespace_foo_flt_generated.h and namespace_foo_flt_generated.c are created from FooFlt.NodeSet2.xml in the
 * /src_generated directory by CMake */
#include "FooFlt.h"

#include <signal.h>
#include <stdlib.h>

UA_Boolean running = true;

static void stopHandler(int sign) {
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
    running = false;
}

int main(int argc, char** argv) {
    signal(SIGINT, stopHandler);
    signal(SIGTERM, stopHandler);
    
    UA_Server *server = UA_Server_new();
    UA_ServerConfig_setDefault(UA_Server_getConfig(server));

    UA_StatusCode retval;
    /* create nodes from nodeset */
    if(FooFlt(server) != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Could not add the Foo FLT nodeset. "
        "Check previous output for any error.");
        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    } else {

        // Do some additional stuff with the nodes

        // this will just get the namespace index, since it is already added to the server
        UA_UInt16 nsIdx = UA_Server_addNamespace(server, "https://new.foo.com/zebra-compression/flattening-and-subspacefolding/UA/");

	// UA_FOO_FLTID_APE = 15111 
        UA_NodeId testInstanceId = UA_NODEID_NUMERIC(nsIdx, 15111);

        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "The Ape has ns=%d;id=%d",
                    testInstanceId.namespaceIndex, testInstanceId.identifier.numeric);

        retval = UA_Server_run(server, &running);
    }

    UA_Server_delete(server);
    return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}

Then compile the server:

gcc -std=c99 -I$HOME/install/include -L$HOME/install/lib main_manual.c FooFlt.c -lopen62541 -lmbedtls -lmbedx509 -lmbedcrypto -o myServer

To execute the generated server, make sure to add your custom installation path to the LD_LIBRARY_PATH, otherwise the open62541 library is not found:

LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/install/lib ./myServer

Success!

Troubleshooting

Exception: Reference ns=1;i=15103–[ns=0;i=40]–>ns=0;i=2368 has an unknown target

This exception is thrown because the example server is compiled with Opc.Ua.NodeSet2.Reduced.xml which does not support AnalogItemType .

Compiling the example server with a custom nodeset may fail as follows

[ 78%] Built target tutorial_client_firststeps
[ 78%] Generating ../../src_generated/open62541/namespace_example_generated.c, ../../src_generated/open62541/namespace_example_generated.h
INFO:__main__:Preprocessing (existing) /home/user/open62541/tools/schema/Opc.Ua.NodeSet2.Reduced.xml
INFO:__main__:Preprocessing /home/user/open62541/examples/nodeset/server_nodeset.xml
['http://opcfoundation.org/UA/', u'https://new.foo.com/zebra-compression/flattening-and-subspacefolding/UA/']
Traceback (most recent call last):
  File "/home/user/open62541/tools/nodeset_compiler/nodeset_compiler.py", line 154, in <module>
    ns.sanitize()
  File "/home/user/open62541/tools/nodeset_compiler/nodeset.py", line 131, in sanitize
    raise Exception("Reference " + str(ref) + " has an unknown target")
Exception: Reference ns=1;i=15103--[ns=0;i=40]-->ns=0;i=2368 has an unknown target
make[2]: *** [examples/nodeset/CMakeFiles/server_nodeset.dir/build.make:70: src_generated/open62541/namespace_example_generated.c] Error 1
make[1]: *** [CMakeFiles/Makefile2:2190: examples/nodeset/CMakeFiles/server_nodeset.dir/all] Error 2
make: *** [Makefile:152: all] Error 2

user@debian:~/open62541/build$

The output indicates:

  • calling nodeset_compiler.py is part of the compilation process and breaks it
    • it is called on:
      • open62541/tools/schema/Opc.Ua.NodeSet2.Reduced.xml
      • open62541/examples/nodeset/server_nodeset.xml the example nodeset that is replaced with the custom nodeset before compilation
  • and that Reference ns=1;i=15103--[ns=0;i=40]-->ns=0;i=2368 has an unknown target

The missing 2368 can be located in https://github.com/OPCFoundation/UA-Nodeset (which is a git submodule of https://github.com/OPCFoundation/UA-ModelCompiler)

johndoe@winpc MINGW64 /c/FLT_SW/UA-ModelCompiler/Published/Schema ((5bbf784...))
$ grep -r 2368
NodeIds.csv:AnalogItemType,2368,VariableType
Opc.Ua.Constants.cs:        public const uint AnalogItemType = 2368;
Opc.Ua.NodeSet.xml:            <Identifier>i=2368</Identifier>
Opc.Ua.NodeSet.xml:        <Identifier>i=2368</Identifier>
Opc.Ua.NodeSet.xml:            <Identifier>i=2368</Identifier>
Opc.Ua.NodeSet.xml:            <Identifier>i=2368</Identifier>
Opc.Ua.NodeSet.xml:            <Identifier>i=2368</Identifier>
Opc.Ua.NodeSet2.Part8.xml:  <UAVariableType NodeId="i=2368" BrowseName="AnalogItemType" DataType="Number" ValueRank="-2">
Opc.Ua.NodeSet2.Part8.xml:  <UAVariable NodeId="i=2370" BrowseName="InstrumentRange" ParentNodeId="i=2368" DataType="i=884">
Opc.Ua.NodeSet2.Part8.xml:      <Reference ReferenceType="HasProperty" IsForward="false">i=2368</Reference>
Opc.Ua.NodeSet2.Part8.xml:  <UAVariable NodeId="i=2369" BrowseName="EURange" ParentNodeId="i=2368" DataType="i=884">
Opc.Ua.NodeSet2.Part8.xml:      <Reference ReferenceType="HasProperty" IsForward="false">i=2368</Reference>
Opc.Ua.NodeSet2.Part8.xml:  <UAVariable NodeId="i=2371" BrowseName="EngineeringUnits" ParentNodeId="i=2368" DataType="i=887">
Opc.Ua.NodeSet2.Part8.xml:      <Reference ReferenceType="HasProperty" IsForward="false">i=2368</Reference>
Opc.Ua.NodeSet2.xml:  <UAVariableType NodeId="i=2368" BrowseName="AnalogItemType" DataType="Number" ValueRank="-2">
Opc.Ua.NodeSet2.xml:  <UAVariable NodeId="i=2370" BrowseName="InstrumentRange" ParentNodeId="i=2368" DataType="i=884">
Opc.Ua.NodeSet2.xml:      <Reference ReferenceType="HasProperty" IsForward="false">i=2368</Reference>
Opc.Ua.NodeSet2.xml:  <UAVariable NodeId="i=2369" BrowseName="EURange" ParentNodeId="i=2368" DataType="i=884">
Opc.Ua.NodeSet2.xml:      <Reference ReferenceType="HasProperty" IsForward="false">i=2368</Reference>
Opc.Ua.NodeSet2.xml:  <UAVariable NodeId="i=2371" BrowseName="EngineeringUnits" ParentNodeId="i=2368" DataType="i=887">
Opc.Ua.NodeSet2.xml:      <Reference ReferenceType="HasProperty" IsForward="false">i=2368</Reference>
Opc.Ua.PredefinedNodes.xml:      <uax:Identifier>i=2368</uax:Identifier>

Pay special attention to

Opc.Ua.NodeSet2.Part8.xml:  <UAVariableType NodeId="i=2368" BrowseName="AnalogItemType" DataType="Number" ValueRank="-2">
Opc.Ua.NodeSet2.xml:  <UAVariableType NodeId="i=2368" BrowseName="AnalogItemType" DataType="Number" ValueRank="-2">

This leads to the suspicion, that Opc.Ua.NodeSet2.Reduced.xml does not hold the required node. To verify that, call nodeset_compiler.py with the full Opc.Ua.NodeSet2.xml

user@debian:~/open62541/tools/nodeset_compiler$
python ./nodeset_compiler.py --types-array=UA_TYPES --existing ../../deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml --xml ../../examples/nodeset/server_nodeset.xml temporary_garbage_file
INFO:__main__:Preprocessing (existing) ../../deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml
INFO:__main__:Preprocessing ../../examples/nodeset/server_nodeset.xml
INFO:__main__:Generating Code for Backend: open62541
INFO:__main__:NodeSet generation code successfully printed

Consequently, one of the following solutions must be implemented:

The first solution is implemented by replacing the reduced nodeset with the full nodeset as indicated by the following diff:

user@debian:~/open62541$
git diff examples/nodeset/CMakeLists.txt
diff --git a/examples/nodeset/CMakeLists.txt b/examples/nodeset/CMakeLists.txt
index 073db5f0..49d23332 100644
--- a/examples/nodeset/CMakeLists.txt
+++ b/examples/nodeset/CMakeLists.txt
@@ -20,7 +20,7 @@ if(NOT CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
     ua_generate_nodeset_and_datatypes(
         NAME "example"
         FILE_NS "${FILE_NS_DIRPREFIX}/server_nodeset.xml"
-        DEPENDS "${CMAKE_SOURCE_DIR}/tools/schema/Opc.Ua.NodeSet2.Reduced.xml"
+        DEPENDS "${CMAKE_SOURCE_DIR}/deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml"
     )
 else()
     # standalone examples build expects already installed Opc.Ua.NodeSet2.Reduced.xml

This change allows to build the open62541 example server with AnalogItemTypes and EUInformation.

Note: Alternative reduced standard nodesets are available from folder open62541/tools/schema

KeyError: 65535 self.browseName.ns = nsMapping[self.browseName.ns]

Compilation of the UANodeSet may fail as follows:

user@debian:~/open62541/tools/nodeset_compiler$
python ./nodeset_compiler.py --types-array=UA_TYPES --existing ../../deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml --xml ../../examples/nodeset/server_nodeset.xml server_nodeset
INFO:__main__:Preprocessing (existing) ../../deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml
INFO:__main__:Preprocessing ../../examples/nodeset/server_nodeset.xml
Traceback (most recent call last):
  File "./nodeset_compiler.py", line 131, in <module>
    ns.addNodeSet(xmlfile, typesArray=getTypesArray(nsCount))
  File "/home/user/open62541/tools/nodeset_compiler/nodeset.py", line 296, in addNodeSet
    node.replaceNamespaces(namespaceMapping)
  File "/home/user/open62541/tools/nodeset_compiler/nodes.py", line 177, in replaceNamespaces
    self.browseName.ns = nsMapping[self.browseName.ns]
KeyError: 65535

Note: Be aware that in this example deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml is used, while the example servers of open62541 use reduced nodesets! This is relevant when using AnalogItemType or EUInformation types.

This is most likely caused by a missing namespace prefix like in the example below:

Insert the missing prefix to the ModelDesign, regenerate the UANodeSet with UA-ModelCompiler and rerun nodeset_compiler.py

Published inopen62541

9 Comments

  1. Sebastian Sebastian

    First of all thanks a lot for your work on these tutorials.

    I have been looking for a long time instructions to build an OPC UA server from a nodeset2.xml file. In fact, I am trying to implement the Openfuncdation Robotics and automation Companion.

    I followed the instructions from the Step 1 of the “OPC UA Information Model Tutorial”.I tried to implement the FooFlt example, but I got problems using the CMake for building the server:

    CMake Error at /usr/local/lib/cmake/open62541/open62541Macros.cmake:488 (message):
    ua_generate_nodeset_and_datatypes function requires NAMESPACE_MAP argument
    if any of FILE_CSV or FILE_BSD are set
    Call Stack (most recent call first):
    CMakeLists.txt:10 (ua_generate_nodeset_and_datatypes)

    — Configuring incomplete, errors occurred!

    It looks like there was a problem to find the .bsd, and .csv files, but I verified the path and the files many times.

    Then I decided to use the nodeset_compiler.py script:

    python ~/open62541/tools/nodeset_compiler/nodeset_compiler.py –types-array=UA_TYPES –existing ~/open62541/deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml –xml model/Published/FooFlt/FooFlt.NodeSet2.xml FooFlt

    and

    gcc -std=c99 -I$HOME/install/include -L$HOME/install/lib main.c FooFlt.c -lopen62541 -lmbedtls -lmbedx509 -lmbedcrypto -o myServer

    (the manual, hard way)

    Then I launched the executable an I got:

    ~/FooServer$ ./myServer
    [2020-11-03 11:30:29.761 (UTC+0100)] warn/server AccessControl: Unconfigured AccessControl. Users have all permissions.
    [2020-11-03 11:30:29.761 (UTC+0100)] info/server AccessControl: Anonymous login is enabled
    [2020-11-03 11:30:29.761 (UTC+0100)] warn/server Username/Password configured, but no encrypting SecurityPolicy. This can leak credentials on the network.
    [2020-11-03 11:30:29.761 (UTC+0100)] warn/userland AcceptAll Certificate Verification. Any remote certificate will be accepted.
    [2020-11-03 11:30:29.762 (UTC+0100)] error/server Could not add the Foo FLT nodeset. Check previous output for any error.

    if anyone can help me solve the bug or tell me where I can find information related to the error, I would be very grateful.

    • Benedict Simlinger Benedict Simlinger

      Hi Sebastian,

      regarding your first error message:

      CMake Error at /usr/local/lib/cmake/open62541/open62541Macros.cmake:488 (message):
      ua_generate_nodeset_and_datatypes function requires NAMESPACE_MAP argument
      if any of FILE_CSV or FILE_BSD are set

      This is NOT about missing csv or bsd files. They are fine.
      This is about the CMake function ua_generate_nodeset_and_datatypes wich requires NAMESPACE_MAP as argument BECAUSE you are using FILE_CSV and FILE_BSD.

      1) If you google for “NAMESPACE_MAP open62541”, your first result will be the official documentation
      https://open62541.org/doc/current/nodeset_compiler.html
      Look at how they are using it. My first attempt would be to replace NAMESPACE_IDX with NAMESPACE_MAP (and respective values).

      2) What is the console output of
      python ~/open62541/tools/nodeset_compiler/nodeset_compiler.py –types-array=UA_TYPES –existing ~/open62541/deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml –xml model/Published/FooFlt/FooFlt.NodeSet2.xml FooFlt

      3) What is the console output of
      gcc -std=c99 -I$HOME/install/include -L$HOME/install/lib main.c FooFlt.c -lopen62541 -lmbedtls -lmbedx509 -lmbedcrypto -o myServer

  2. audupi audupi

    Hi!

    Thanks for these tutorials. Helped me a lot in my journey on OPCUA.

    I have developed an information model for a Robot and i am building the CMakeLists.txt file for my project. My model consists of multiple namespaces. For example my model built on (NS4) is dependent on OPCUA Robotics namespace (NS2) and another custom namespace (NS3).

    Since there is no official bsd file for OPCUA Robotics, the issue arises when using the (ua_generate_nodeset_and_datatypes) function with NAMESPACE_MAP variable in CMake. ( The error requires both csv and bsd file if NAMESPACE_MAP is used)

    To work around, it I created my own bsd & csv files for OPCUA Robotics, however it resulted in makefile execution issues.

    I am working on this issue concurrently, any suggestions on how to include the Robotics NS as an intermediate NS with ua_generate_nodeset_and_datatypes) function & NAMESPACE_MAP would be helpful.

    Thanks in advance.

    • Benedict Simlinger Benedict Simlinger

      Hi,

      please have look at the notice at the very beginning of this article:

      A more complete example with heavy use of heavy usage of ModelDesign files and dependencies between them is shown in this project:
      https://github.com/opcua-skills/plug-and-produce

      It shows how to manage dependencies between several namespaces. Have a look at the CMakeLists.txt files in the subdirectories as well.

      I recommend you post your error messages when looking for help. Without those, I doubt anyone can or will help you in a meaningful way.

      Kind regards

      PS: The CSV and BSD files are optional. Here is their use case:

      If you compile your model for the first time, the compiler will generate a CSV and BSD file. Those files will document the types and node IDs assigned to the nodes of your model. This ID assignment is somewhat arbitrary. Let us assume that node ‘foo’ received ID ‘123’.

      If you change your model and recompile WITHOUT taking into account the CSV and BSD files, node ‘foo’ may now be assigned a different ID ‘234’.

      If you change your model and recompile WITH taking into account the CSV and BSD files, they make sure that nodes will be assigned the SAME ID they have been assigned initially. That is important, because OPC UA depends on those IDs during runtime. If your node changes its ID with a new release of your model, OPC UA clients will not be able to successfully recognize that node as the same node they used before.

      Hope that helps.

  3. Sebastian Sebastian

    Thank you for your quick answer.

    I applied your suggestion about using the NAMESPACE_MAP flag. It solved my bug.
    I was able to successfully build the FOOFLT server example and running it.

    Then I applied the same procedure with the Opc.Ua.Robotics.NodeSet2.xml, which I recovered from the official site:

    https://opcfoundation.org/developer-tools/specifications-opc-ua-information-models/opc-unified-architecture-for-robotics/#:~:text=The%20OPC%20UA%20Robotics%20Companion,Industrial%20robots

    (Link to the nodeset2.xml and nodels.cvs in the annexe A ).

    For building the server I used the Cmake function:

    ua_generate_nodeset_and_datatypes(
    NAME “Robotics”
    TARGET_PREFIX “${PROJECT_NAME}”
    FILE_NS “${PROJECT_SOURCE_DIR}/Opc.Ua.Robotics.NodeSet2.xml”
    # FILE_CSV “${PROJECT_SOURCE_DIR}/NodeIds.csv”
    # NAMESPACE_MAP “1:http://opcfoundation.org/UA/Robotics/
    OUTPUT_DIR “${GENERATE_OUTPUT_DIR}”
    INTERNAL
    )

    Called by:

    cmake -DCMAKE_PREFIX_PATH=$USER/install ..

    the console output:

    — The C compiler identification is GNU 7.5.0
    — The CXX compiler identification is GNU 7.5.0
    — Check for working C compiler: /usr/bin/cc
    — Check for working C compiler: /usr/bin/cc — works
    — Detecting C compiler ABI info
    — Detecting C compiler ABI info – done
    — Detecting C compile features
    — Detecting C compile features – done
    — Check for working CXX compiler: /usr/bin/c++
    — Check for working CXX compiler: /usr/bin/c++ — works
    — Detecting CXX compiler ABI info
    — Detecting CXX compiler ABI info – done
    — Detecting CXX compile features
    — Detecting CXX compile features – done
    — Found PythonInterp: /usr/bin/python (found version “3.6.9”)
    — Configuring done
    — Generating done
    — Build files have been written to: /home/ubuntu18ros/OPC-UA-Robotics-Model-Server/build

    However, when I ran the Makefile I got:

    Scanning dependencies of target opcua-Robotics-server-ns-Robotics
    [ 20%] Generating src_generated/namespace_Robotics_generated.c, src_generated/namespace_Robotics_generated.h
    INFO:__main__:Preprocessing (existing) /usr/local/share/open62541/tools/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml
    INFO:__main__:Preprocessing /home/ubuntu18ros/OPC-UA-Robotics-Model-Server/Opc.Ua.Robotics.NodeSet2.xml
    [‘http://opcfoundation.org/UA/’, ‘http://opcfoundation.org/UA/Robotics/’, ‘http://opcfoundation.org/UA/DI/’]
    Traceback (most recent call last):
    File “/usr/local/share/open62541/tools/nodeset_compiler/nodeset_compiler.py”, line 154, in
    ns.sanitize()
    File “/usr/local/share/open62541/tools/nodeset_compiler/nodeset.py”, line 131, in sanitize
    raise Exception(“Reference ” + str(ref) + ” has an unknown target”)
    Exception: Reference ns=1;i=1002<–[ns=0;i=45]–ns=2;i=15063 has an unknown target
    CMakeFiles/opcua-Robotics-server-ns-Robotics.dir/build.make:69: recipe for target 'src_generated/namespace_Robotics_generated.c' failed
    make[2]: *** [src_generated/namespace_Robotics_generated.c] Error 1
    CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/opcua-Robotics-server-ns-Robotics.dir/all' failed
    make[1]: *** [CMakeFiles/opcua-Robotics-server-ns-Robotics.dir/all] Error 2
    Makefile:83: recipe for target 'all' failed
    make: *** [all] Error 2

    I didn't use FILE_CSV , nether the NAMESPACE_MAP on the ua_generate_nodeset_and_datatypes() method, car the OPC UA Companion Specification doesn't provides a .BSD file.

    I appreciate a lot the help to solve this problem. I'm beginner on OPC UA.

    My complete project:
    https://github.com/scepedaesp2018/OPC-UA-Robotics-Model-Server

  4. Sebastian Sebastian

    Thanks,

    I also thought it was the error of this post the first time, so I used Opc.Ua.NodeSet2.xml as you can see in the Makefile’s results.

    • Benedict Simlinger Benedict Simlinger

      Hi Sebastian,

      you have different namespaces and indices in your error message. Applying the specific solution from the article (use full nodeset instead of reduced nodeset) to your problem will most likely _not_ help. You have to follow the presented _method_

      That is:
      Research what nodes are represented by the indices in your error message and deduce the adequate solution for your problem.

  5. audupi audupi

    Hi,

    I am trying to compile my Nodeset consisting of 5 Namespaces using CMakeLists.txt. I have been successful in building the files using CMAKE command.

    However, when I run the MAKE command, this is the encountering this error. The error is shown below.

    [ 63%] Linking CXX executable opcua_server
    c++: fatal error: Killed signal terminated program lto1
    compilation terminated.
    lto-wrapper: fatal error: /usr/bin/c++ returned 1 exit status
    compilation terminated.
    /usr/bin/ld: error: lto-wrapper failed
    collect2: error: ld returned 1 exit status
    make[2]: *** [CMakeFiles/opcua_server.dir/build.make:346: opcua_server] Error 1
    make[1]: *** [CMakeFiles/Makefile2:419: CMakeFiles/opcua_server.dir/all] Error 2
    make: *** [Makefile:84: all] Error 2

    I am trying to understand this error. Any suggestions from your end would be helpful.

    Thanks in advance.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.