UE4中實現OPC UA Client來控制PLC

緣由與介紹
  OPC Foundation
  OPC (Open Platform Communications)
  OPC UA

實作參考
  Labview控制PLC使用OPC
  商業授權方案 - LabView + LabVIEW OPC UA Toolkit
  Qt OPC UA

open62541實現 (OPC UA C++ Library)
  open62541 - github
  open62541 - documentation

--------------------------------------------------

專案說明
本案硬體需與UE4連動,使用OPC來管理,透過PLC去控制,將open62541 (OPC UA C++  Library) 整理成UE4 plugin,可直接在UE4中直接使用 blueprint function library 呼叫方法來讀取、寫入PLC中的數值。

  硬體端負責工作:硬體與相關感測器整合、PLC串接與控制、建立OPC Server
  軟體端負責工作:建立OPC Client並整合至UE4,可讀取/寫入PLC中的數值

已實現方法
  UA Client Connect
  UA Client ReadValueAttribute
  UA Client WriteValueAttribute
  UA Client Disconnect

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "OpcUaClientBPLibrary.h"
#include "OpcUaClient.h"
#include "open62541.h"
static UA_Client *client;
UOpcUaClientBPLibrary::UOpcUaClientBPLibrary(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
bool UOpcUaClientBPLibrary::UA_Client_connect_open62541(FString endpointUrl)
{
// Create a client and connect
client = UA_Client_new();
UA_ClientConfig_setDefault(UA_Client_getConfig(client));
UA_StatusCode status = UA_Client_connect(client, TCHAR_TO_UTF8(*endpointUrl));
if (status != UA_STATUSCODE_GOOD) {
UA_Client_delete(client);
return false;
}
return true;
}
float UOpcUaClientBPLibrary::UA_Client_readValueAttribute_open62541(FString nodeId)
{
if (!client) return -2;
UA_Variant value; /* Variants can hold scalar values and arrays of any type */
UA_Variant_init(&value);
UA_StatusCode status = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, TCHAR_TO_UTF8(*nodeId)), &value);
if (status == UA_STATUSCODE_GOOD &&
UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_FLOAT])) {
return *(UA_Float*)value.data;
}
return -1;
}
bool UOpcUaClientBPLibrary::UA_Client_writeValueAttribute_open62541(FString nodeId, float newValue)
{
if (!client) return false;
UA_Variant value;
UA_Variant_setScalar(&value, &newValue, &UA_TYPES[UA_TYPES_FLOAT]);
UA_StatusCode status = UA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, TCHAR_TO_UTF8(*nodeId)), &value);
if (status == UA_STATUSCODE_GOOD &&
UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_FLOAT])) {
return true;
}
return false;
}
bool UOpcUaClientBPLibrary::UA_Client_disconnect_open62541()
{
UA_Client_delete(client);
return true;
}
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Kismet/BlueprintFunctionLibrary.h"
#include "OpcUaClientBPLibrary.generated.h"
/*
* Function library class.
* Each function in it is expected to be static and represents blueprint node that can be called in any blueprint.
*
* When declaring function you can define metadata for the node. Key function specifiers will be BlueprintPure and BlueprintCallable.
* BlueprintPure - means the function does not affect the owning object in any way and thus creates a node without Exec pins.
* BlueprintCallable - makes a function which can be executed in Blueprints - Thus it has Exec pins.
* DisplayName - full name of the node, shown when you mouse over the node and in the blueprint drop down menu.
* Its lets you name the node using characters not allowed in C++ function names.
* CompactNodeTitle - the word(s) that appear on the node.
* Keywords - the list of keywords that helps you to find node when you search for it using Blueprint drop-down menu.
* Good example is "Print String" node which you can find also by using keyword "log".
* Category - the category your node will be under in the Blueprint drop-down menu.
*
* For more info on custom blueprint nodes visit documentation:
* https://wiki.unrealengine.com/Custom_Blueprint_Node_Creation
*/
UCLASS()
class UOpcUaClientBPLibrary : public UBlueprintFunctionLibrary
{
GENERATED_UCLASS_BODY()
/**
* Connect to OPC UA Server.
* @param endpointUrl
* @return true if the connect success.
*/
UFUNCTION(BlueprintCallable, meta = (DisplayName = "UA Client Connect", Keywords = "Connect to OPC UA Server"), Category = "OPC UA Client")
static bool UA_Client_connect_open62541(FString endpointUrl);
/**
* Read the value attribute of the node.
* @param nodeId
* @return value attribute of the node
*/
UFUNCTION(BlueprintCallable, meta = (DisplayName = "UA Client ReadValueAttribute", Keywords = "Read the value attribute of the node"), Category = "OPC UA Client")
static float UA_Client_readValueAttribute_open62541(FString nodeId);
/**
* Write the value attribute of the node.
* @param nodeId
* @param newValue
* @return true if the value attribute writes success.
*/
UFUNCTION(BlueprintCallable, meta = (DisplayName = "UA Client WriteValueAttribute", Keywords = "Write the value attribute of the node"), Category = "OPC UA Client")
static bool UA_Client_writeValueAttribute_open62541(FString nodeId, float newValue);
/**
* Disconnects the client.
* @return true if dissconnected.
*/
UFUNCTION(BlueprintCallable, meta = (DisplayName = "UA Client Disconnect", Keywords = "Disconnects the client."), Category = "OPC UA Client")
static bool UA_Client_dissconnect_open62541();
};

這個網誌中的熱門文章

Windows10 版本1607後可啟用支援長路徑檔名 (Maximum Path Length Limitation)

標準使用者如何執行需系統管理者權限的程式