TwinCAT3 - 使用 Matlab 从 ADS 数据流读取时时间戳的错误值
TwinCAT3 - Wrong values for timestamp when reading from ADS datastream with Matlab
我正在尝试从 TwinCAT3 项目读取 ADS 数据流。
每当 CycleCount(来自 SPS)更改其值时,我编写的函数应该读取数据流 - 因此 CycleCount 是回调函数的触发器,并且每毫秒检查一次更改。
要读取的数据流由一个包含两个值 "nCycleCount" (DWORD-4Bytes) 和 "TStamp" (ULINT-8Bytes) 的结构组成。因此整个流包含 12 个字节的数据。
TwinCAT 中的一个周期配置为 0.5ms,因此变量 CycleCount 应该每秒变化 2 次(如果 PLC-tasks 周期时间是一个 cycle-tick)。由于我的程序每毫秒检查一次变量 CycleCount 是否更改,因此应每毫秒调用一次回调函数并将时间戳写入缓冲区 ("myBuffer")。
但我注意到,在 2 秒的运行时间里,我只收到 1000 个值(而不是预期的 2000 个),我找不到原因?
TwinCAT3 中的 PLC 任务似乎显示了正确的值,但是当使用 MatLab 读取它们时,时间戳值不正确并且不是如前所述的每毫秒:
这些是 Matlab 的一些输出,其中 CycleCounter 被写入第 1 列,时间戳被写入第 2 列:
我在 TwinCAT 中使用以下代码来定义结构和主程序:
结构:
TYPE ST_CC :
STRUCT
nCycleCount : DWORD; //4Bytes
TStamp : ULINT; //8Bytes
//Stream with 12Bytes total
END_STRUCT
END_TYPE
MAIN_CC(对于 PlcTask):
PROGRAM MAIN_CC
VAR
CC_struct : ST_CC;
END_VAR;
CC_struct.nCycleCount := _TaskInfo[1].CycleCount;
CC_struct.TStamp := IO_Mapping.ulint_i_TimeStamp;
通知时读取流的 Matlab 代码:
function ReadTwinCAT()
%% Import Ads.dll
AdsAssembly = NET.addAssembly('D:\TwinCat3\AdsApi\.NET\v4.0.30319\TwinCAT.Ads.dll');
import TwinCAT.Ads.*;
%% Create TcAdsClient instance
tcClient = TcAdsClient;
%% Connect to ADS port 851 on the local machine
tcClient.Connect(851);
%% ADS Device Notifications variables
% ADS stream
dataStream = AdsStream(12); %12Bytes necessary
% reader
binRead = AdsBinaryReader(dataStream);
% Variable to trigger notification
CCount = 'MAIN_CC.CC_struct.nCycleCount';
%% Create unique variable handles for structure
try
st_handle = tcClient.CreateVariableHandle('MAIN_CC.CC_struct');
catch err
tcClient.Dispose();
msgbox(err.message,'Fehler beim Erstellen des Variablenhandles','error');
error(err.message);
end
%% Create buffer for values
myBuffer = {};
MAXBUFFLEN = 1000;
%% Register ADS Device
try
% Register callback function
tcClient.addlistener('AdsNotification',@OnNotification);
% Register notifications
% %AddDeviceNotification( variableName As String,
% dataStream As AdsStream,
% offset As Integer,
% length As Integer (in Byte),
% transMode As AdsTransMode,
% cycleTime As Integer,
% maxDelay As Integer,
% userData As Object)
% Notification handle
hConnect = tcClient.AddDeviceNotification(CCount,dataStream,0,4,AdsTransMode.OnChange,1,0,CCount);
% Listen to ADS notifications for x seconds
pause(2);
catch err
msgbox(err.message,'Error reading array via ADS','error');
disp(['Error registering ADS notifications: ' err.message]);
end
%% Delete ADS notifications
for idx=1:length(hConnect)
tcClient.DeleteDeviceNotification(hConnect(idx));
end
%% Dispose ADS client
tcClient.Dispose();
%% MatlabAdsSample_Notification: OnNotification
function OnNotification(sender, e)
e.DataStream.Position = e.Offset; %Startposition = 0
%% load variables from workspace
hConnect = evalin('caller','hConnect');
binRead = evalin('caller','binRead');
%% assign to ADS variable and convert to string
if( e.NotificationHandle == hConnect )
%% Read timestamp and encodervalues & append to Buffer
tcClient.Read(st_handle, dataStream); %Read structure from stream
%nCycleCount
nCycleCount = binRead.ReadInt32;
[bufflen, ~] = size(myBuffer); %Get current buffer length
myBuffer{bufflen+1,1} = nCycleCount;
%Read & Append Timestamp to Buffer
tstamp = binRead.ReadInt64; %Read tstamp from dataStream and shift reading position by 8bytes (int64)
myBuffer{bufflen+1,2} = tstamp;
if bufflen < MAXBUFFLEN-1
return;
else
assignin('base','myBuffer', myBuffer);
disp("buffer assigned in workspace")
myBuffer = {}; %empty Buffer
end
else
%do nothing
end
end
希望你能帮我解决我的问题 - 提前致谢!
据我所知,您的程序运行正常。
1)
由于通知是异步的,它们可能会在您的等待时间 over.At 之后到达,尽管您已经处理了通知。
要测试这个理论是否正确,请在您的 Twincat 程序中添加一个计时器。
声明:
fbTimer : TON;
实施:
fbTimer(IN:=TRUE,PT:=T#2s);
IF NOT fbTimer.Q
THEN
cc_struct.nCycleCount := _TaskInfo[1].CycleCount;
END_IF
在启动plc之前确保你的matlab程序已经启动
并将您在 Matlab 中的暂停时间提高到 120 秒。
如果您得到 2000 个值,那么您就知道问题出在通信的异步性质上。
2)
转换错误源自 ReadInt64 方法,该方法:
Reads an 8-byte signed integer from the current stream and advances
the current position of the stream by eight bytes.
您应该改用 ReadUInt64。
为了查看是否可以重现您的相同行为,我创建了一个小型 C# 测试程序。
测试程序运行正常,我能够收到正确数量的通知。
这里是ST代码:
声明:
PROGRAM MAIN
VAR
fbTimer: TON;
nCycleCount : DWORD;
END_VAR
实施:
fbTimer(IN:=TRUE,PT:=T#2S);
IF NOT fbTimer.Q
THEN
nCycleCount := _TaskInfo[1].CycleCount;
END_IF
这里是 C# 代码:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TwinCAT.Ads;
namespace AdsNotificationTest
{
class Program
{
static TcAdsClient tcClient;
static int hConnect;
static AdsStream dataStream;
static BinaryReader binReader;
static uint uVal, huValHandle;
static int counter = 0;
static void Main(string[] args)
{
tcClient = new TcAdsClient();
dataStream = new AdsStream(31);
binReader = new BinaryReader(dataStream, System.Text.Encoding.ASCII);
tcClient.Connect(851);
try
{
hConnect = tcClient.AddDeviceNotification("MAIN.nCycleCount", dataStream, 0, 4, AdsTransMode.OnChange, 1, 0, huValHandle);
tcClient.AdsNotification += new AdsNotificationEventHandler(OnNotification);
}
catch (Exception err)
{
Console.WriteLine("Exception.");
}
Console.ReadKey();
tcClient.DeleteDeviceNotification(hConnect);
tcClient.Dispose();
}
private static void OnNotification(object sender, AdsNotificationEventArgs e)
{
if (e.NotificationHandle == hConnect)
{
counter += 1;
uVal = binReader.ReadUInt32();
Console.WriteLine(counter + ": " + uVal);
}
}
}
}
我找到了一个似乎有效的解决方案,因为对 4300 万个数据集的 12 小时测试成功了。
我现在的做法是将我的结构(包含要读取的值)附加到大小为 10.000 的结构数组。一旦数组已满,我的通知变量就会触发回调函数来读取整个数组(1.000 * 40 字节)。
但这似乎只适用于大数组。当使用大小为 100 或 1.000 的较小数组时,我注意到由于读取不正确而导致错误值的可能性更高。
结构:
TYPE ST_ENC :
STRUCT
TStamp : ULINT; //8Bytes
EncRAx1 : DINT; //4Bytes
EncRAx2 : DINT; //4Bytes
EncRAx3 : DINT; //4Bytes
EncRAx4 : DINT; //4Bytes
EncRAx5 : DINT; //4Bytes
EncRAx6 : DINT; //4Bytes
EncEAx1 : DINT; //4Bytes
EncEAx2 : DINT; //4Bytes
END_STRUCT
END_TYPE
主线:
PROGRAM MAIN_Array
VAR
encVal : ST_ENC; //Structure of encoder values and timestamp
arr2write : ARRAY [0..9999] OF ST_ENC; //array of structure to write to
arr2read : ARRAY [0..9999] OF ST_ENC; //array of structure to read from
ARR_SIZE : INT := 9999;
counter : INT := 0; //Counter for arraysize
END_VAR;
// --Timestamp & Encoderwerte
encVal.TStamp := IO_Mapping.ulint_i_TimeStamp;
encVal.EncRAx1 := IO_Mapping.dint_i_EncoderValue_RAx1;
encVal.EncRAx2 := IO_Mapping.dint_i_EncoderValue_RAx2;
encVal.EncRAx3 := IO_Mapping.dint_i_EncoderValue_RAx3;
encVal.EncRAx4 := IO_Mapping.dint_i_EncoderValue_RAx4;
encVal.EncRAx5 := IO_Mapping.dint_i_EncoderValue_RAx5;
encVal.EncRAx6 := IO_Mapping.dint_i_EncoderValue_RAx6;
encVal.EncEAx1 := IO_Mapping.dint_i_EncoderValue_EAx1;
encVal.EncEAx2 := IO_Mapping.dint_i_EncoderValue_EAx2;
//Append to array
IF counter < ARR_SIZE
THEN
arr2write[counter] := encVal;
counter := counter + 1;
ELSE
arr2write[ARR_SIZE] := encVal; //Write last Bufferentry - otherwise 1 cycle of struct missing
arr2read := arr2write;
counter := 0;
END_IF
MATLAB
function ReadTwinCAT()
%% Import Ads.dll
AdsAssembly = NET.addAssembly('D:\TwinCat3\AdsApi\.NET\v4.0.30319\TwinCAT.Ads.dll');
import TwinCAT.Ads.*;
%% Initialize POOL
pool = gcp();
disp("Worker pool for parallel computing initalized");
%% Create TcAdsClient instance
tcClient = TcAdsClient;
%% Connect to ADS port 851 on the local machine
tcClient.Connect(851);
%% ADS Device Notifications variables
% ADS stream
ARR_SIZE = 10000; %Groesse des auszulesenden Arrays of Struct
STREAM_SIZE = 40; %in Byte
dataStream = AdsStream(ARR_SIZE * STREAM_SIZE); %40Bytes per entry
% Binary reader
binRead = AdsBinaryReader(dataStream);
% Variable to trigger notification
arr2read = 'MAIN_Array.arr2read[0].TStamp'; %Notification handle = first TStamp entry
%% Create unique variable handles for encoder-array
try
arr_handle = tcClient.CreateVariableHandle('MAIN_Array.arr2read');
catch err
tcClient.Dispose();
msgbox(err.message,'Fehler beim Erstellen des Variablenhandles','error');
error(err.message);
end
%% Create buffer for values
myBuffer = {}; %Creates empty buffer
buffcount = 0; %Nur fuer Workspace-Ausgabe
%% Register ADS Device
try
% Register callback function
tcClient.addlistener('AdsNotification',@OnNotification);
% Notification handle
hConnect = tcClient.AddDeviceNotification(arr2read,dataStream,0,8,AdsTransMode.OnChange,1,0,arr2read);
% Listen to ADS notifications for x seconds
pause(15);
catch err
msgbox(err.message,'Error reading array via ADS','error');
disp(['Error registering ADS notifications: ' err.message]);
end
%% Delete ADS notifications
tcClient.DeleteDeviceNotification(hConnect);
%% Dispose ADS client
tcClient.Dispose();
%% MatlabAdsSample_Notification: OnNotification
function OnNotification(sender, e)
e.DataStream.Position = e.Offset;
%% load variables from workspace
hConnect = evalin('caller','hConnect');
binRead = evalin('caller','binRead');
%% assign to ADS variable and convert to string
if( e.NotificationHandle == hConnect )
%% Read timestamp and encodervalues & append to Buffer
tcClient.Read(arr_handle, dataStream); %Read structure from stream
for idx=1:ARR_SIZE
%Read & Append Timestamp to Buffer
[bufflen, ~] = size(myBuffer); %Get current buffer length
tstamp = binRead.ReadUInt64; %Read tstamp from dataStream and shift reading position by 8bytes (int64)
myBuffer{bufflen+1,1} = tstamp;
%Read & Append Encodervalues to Buffer
for n=1:8
encval = binRead.ReadInt32; %Read tstamp from dataStream and shift reading position by 8bytes (int64)
myBuffer{bufflen+1,n+1} = encval;
end
end
Assign arraybuffer
buffname = 'myBuffer';
buffcount = buffcount+1;
buffcount_str = num2str(buffcount);
assignin('base',strcat(buffname, buffcount_str), myBuffer);
myBuffer = {}; %empty Buffer for next array
disp("buffer assigned")
else
%do nothing
end
end
end
我正在尝试从 TwinCAT3 项目读取 ADS 数据流。
每当 CycleCount(来自 SPS)更改其值时,我编写的函数应该读取数据流 - 因此 CycleCount 是回调函数的触发器,并且每毫秒检查一次更改。
要读取的数据流由一个包含两个值 "nCycleCount" (DWORD-4Bytes) 和 "TStamp" (ULINT-8Bytes) 的结构组成。因此整个流包含 12 个字节的数据。
TwinCAT 中的一个周期配置为 0.5ms,因此变量 CycleCount 应该每秒变化 2 次(如果 PLC-tasks 周期时间是一个 cycle-tick)。由于我的程序每毫秒检查一次变量 CycleCount 是否更改,因此应每毫秒调用一次回调函数并将时间戳写入缓冲区 ("myBuffer")。 但我注意到,在 2 秒的运行时间里,我只收到 1000 个值(而不是预期的 2000 个),我找不到原因?
TwinCAT3 中的 PLC 任务似乎显示了正确的值,但是当使用 MatLab 读取它们时,时间戳值不正确并且不是如前所述的每毫秒:
这些是 Matlab 的一些输出,其中 CycleCounter 被写入第 1 列,时间戳被写入第 2 列:
我在 TwinCAT 中使用以下代码来定义结构和主程序:
结构:
TYPE ST_CC :
STRUCT
nCycleCount : DWORD; //4Bytes
TStamp : ULINT; //8Bytes
//Stream with 12Bytes total
END_STRUCT
END_TYPE
MAIN_CC(对于 PlcTask):
PROGRAM MAIN_CC
VAR
CC_struct : ST_CC;
END_VAR;
CC_struct.nCycleCount := _TaskInfo[1].CycleCount;
CC_struct.TStamp := IO_Mapping.ulint_i_TimeStamp;
通知时读取流的 Matlab 代码:
function ReadTwinCAT()
%% Import Ads.dll
AdsAssembly = NET.addAssembly('D:\TwinCat3\AdsApi\.NET\v4.0.30319\TwinCAT.Ads.dll');
import TwinCAT.Ads.*;
%% Create TcAdsClient instance
tcClient = TcAdsClient;
%% Connect to ADS port 851 on the local machine
tcClient.Connect(851);
%% ADS Device Notifications variables
% ADS stream
dataStream = AdsStream(12); %12Bytes necessary
% reader
binRead = AdsBinaryReader(dataStream);
% Variable to trigger notification
CCount = 'MAIN_CC.CC_struct.nCycleCount';
%% Create unique variable handles for structure
try
st_handle = tcClient.CreateVariableHandle('MAIN_CC.CC_struct');
catch err
tcClient.Dispose();
msgbox(err.message,'Fehler beim Erstellen des Variablenhandles','error');
error(err.message);
end
%% Create buffer for values
myBuffer = {};
MAXBUFFLEN = 1000;
%% Register ADS Device
try
% Register callback function
tcClient.addlistener('AdsNotification',@OnNotification);
% Register notifications
% %AddDeviceNotification( variableName As String,
% dataStream As AdsStream,
% offset As Integer,
% length As Integer (in Byte),
% transMode As AdsTransMode,
% cycleTime As Integer,
% maxDelay As Integer,
% userData As Object)
% Notification handle
hConnect = tcClient.AddDeviceNotification(CCount,dataStream,0,4,AdsTransMode.OnChange,1,0,CCount);
% Listen to ADS notifications for x seconds
pause(2);
catch err
msgbox(err.message,'Error reading array via ADS','error');
disp(['Error registering ADS notifications: ' err.message]);
end
%% Delete ADS notifications
for idx=1:length(hConnect)
tcClient.DeleteDeviceNotification(hConnect(idx));
end
%% Dispose ADS client
tcClient.Dispose();
%% MatlabAdsSample_Notification: OnNotification
function OnNotification(sender, e)
e.DataStream.Position = e.Offset; %Startposition = 0
%% load variables from workspace
hConnect = evalin('caller','hConnect');
binRead = evalin('caller','binRead');
%% assign to ADS variable and convert to string
if( e.NotificationHandle == hConnect )
%% Read timestamp and encodervalues & append to Buffer
tcClient.Read(st_handle, dataStream); %Read structure from stream
%nCycleCount
nCycleCount = binRead.ReadInt32;
[bufflen, ~] = size(myBuffer); %Get current buffer length
myBuffer{bufflen+1,1} = nCycleCount;
%Read & Append Timestamp to Buffer
tstamp = binRead.ReadInt64; %Read tstamp from dataStream and shift reading position by 8bytes (int64)
myBuffer{bufflen+1,2} = tstamp;
if bufflen < MAXBUFFLEN-1
return;
else
assignin('base','myBuffer', myBuffer);
disp("buffer assigned in workspace")
myBuffer = {}; %empty Buffer
end
else
%do nothing
end
end
希望你能帮我解决我的问题 - 提前致谢!
据我所知,您的程序运行正常。
1)
由于通知是异步的,它们可能会在您的等待时间 over.At 之后到达,尽管您已经处理了通知。
要测试这个理论是否正确,请在您的 Twincat 程序中添加一个计时器。
声明:
fbTimer : TON;
实施:
fbTimer(IN:=TRUE,PT:=T#2s);
IF NOT fbTimer.Q
THEN
cc_struct.nCycleCount := _TaskInfo[1].CycleCount;
END_IF
在启动plc之前确保你的matlab程序已经启动 并将您在 Matlab 中的暂停时间提高到 120 秒。
如果您得到 2000 个值,那么您就知道问题出在通信的异步性质上。
2)
转换错误源自 ReadInt64 方法,该方法:
Reads an 8-byte signed integer from the current stream and advances the current position of the stream by eight bytes.
您应该改用 ReadUInt64。
为了查看是否可以重现您的相同行为,我创建了一个小型 C# 测试程序。 测试程序运行正常,我能够收到正确数量的通知。
这里是ST代码:
声明:
PROGRAM MAIN
VAR
fbTimer: TON;
nCycleCount : DWORD;
END_VAR
实施:
fbTimer(IN:=TRUE,PT:=T#2S);
IF NOT fbTimer.Q
THEN
nCycleCount := _TaskInfo[1].CycleCount;
END_IF
这里是 C# 代码:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TwinCAT.Ads;
namespace AdsNotificationTest
{
class Program
{
static TcAdsClient tcClient;
static int hConnect;
static AdsStream dataStream;
static BinaryReader binReader;
static uint uVal, huValHandle;
static int counter = 0;
static void Main(string[] args)
{
tcClient = new TcAdsClient();
dataStream = new AdsStream(31);
binReader = new BinaryReader(dataStream, System.Text.Encoding.ASCII);
tcClient.Connect(851);
try
{
hConnect = tcClient.AddDeviceNotification("MAIN.nCycleCount", dataStream, 0, 4, AdsTransMode.OnChange, 1, 0, huValHandle);
tcClient.AdsNotification += new AdsNotificationEventHandler(OnNotification);
}
catch (Exception err)
{
Console.WriteLine("Exception.");
}
Console.ReadKey();
tcClient.DeleteDeviceNotification(hConnect);
tcClient.Dispose();
}
private static void OnNotification(object sender, AdsNotificationEventArgs e)
{
if (e.NotificationHandle == hConnect)
{
counter += 1;
uVal = binReader.ReadUInt32();
Console.WriteLine(counter + ": " + uVal);
}
}
}
}
我找到了一个似乎有效的解决方案,因为对 4300 万个数据集的 12 小时测试成功了。
我现在的做法是将我的结构(包含要读取的值)附加到大小为 10.000 的结构数组。一旦数组已满,我的通知变量就会触发回调函数来读取整个数组(1.000 * 40 字节)。
但这似乎只适用于大数组。当使用大小为 100 或 1.000 的较小数组时,我注意到由于读取不正确而导致错误值的可能性更高。
结构:
TYPE ST_ENC :
STRUCT
TStamp : ULINT; //8Bytes
EncRAx1 : DINT; //4Bytes
EncRAx2 : DINT; //4Bytes
EncRAx3 : DINT; //4Bytes
EncRAx4 : DINT; //4Bytes
EncRAx5 : DINT; //4Bytes
EncRAx6 : DINT; //4Bytes
EncEAx1 : DINT; //4Bytes
EncEAx2 : DINT; //4Bytes
END_STRUCT
END_TYPE
主线:
PROGRAM MAIN_Array
VAR
encVal : ST_ENC; //Structure of encoder values and timestamp
arr2write : ARRAY [0..9999] OF ST_ENC; //array of structure to write to
arr2read : ARRAY [0..9999] OF ST_ENC; //array of structure to read from
ARR_SIZE : INT := 9999;
counter : INT := 0; //Counter for arraysize
END_VAR;
// --Timestamp & Encoderwerte
encVal.TStamp := IO_Mapping.ulint_i_TimeStamp;
encVal.EncRAx1 := IO_Mapping.dint_i_EncoderValue_RAx1;
encVal.EncRAx2 := IO_Mapping.dint_i_EncoderValue_RAx2;
encVal.EncRAx3 := IO_Mapping.dint_i_EncoderValue_RAx3;
encVal.EncRAx4 := IO_Mapping.dint_i_EncoderValue_RAx4;
encVal.EncRAx5 := IO_Mapping.dint_i_EncoderValue_RAx5;
encVal.EncRAx6 := IO_Mapping.dint_i_EncoderValue_RAx6;
encVal.EncEAx1 := IO_Mapping.dint_i_EncoderValue_EAx1;
encVal.EncEAx2 := IO_Mapping.dint_i_EncoderValue_EAx2;
//Append to array
IF counter < ARR_SIZE
THEN
arr2write[counter] := encVal;
counter := counter + 1;
ELSE
arr2write[ARR_SIZE] := encVal; //Write last Bufferentry - otherwise 1 cycle of struct missing
arr2read := arr2write;
counter := 0;
END_IF
MATLAB
function ReadTwinCAT()
%% Import Ads.dll
AdsAssembly = NET.addAssembly('D:\TwinCat3\AdsApi\.NET\v4.0.30319\TwinCAT.Ads.dll');
import TwinCAT.Ads.*;
%% Initialize POOL
pool = gcp();
disp("Worker pool for parallel computing initalized");
%% Create TcAdsClient instance
tcClient = TcAdsClient;
%% Connect to ADS port 851 on the local machine
tcClient.Connect(851);
%% ADS Device Notifications variables
% ADS stream
ARR_SIZE = 10000; %Groesse des auszulesenden Arrays of Struct
STREAM_SIZE = 40; %in Byte
dataStream = AdsStream(ARR_SIZE * STREAM_SIZE); %40Bytes per entry
% Binary reader
binRead = AdsBinaryReader(dataStream);
% Variable to trigger notification
arr2read = 'MAIN_Array.arr2read[0].TStamp'; %Notification handle = first TStamp entry
%% Create unique variable handles for encoder-array
try
arr_handle = tcClient.CreateVariableHandle('MAIN_Array.arr2read');
catch err
tcClient.Dispose();
msgbox(err.message,'Fehler beim Erstellen des Variablenhandles','error');
error(err.message);
end
%% Create buffer for values
myBuffer = {}; %Creates empty buffer
buffcount = 0; %Nur fuer Workspace-Ausgabe
%% Register ADS Device
try
% Register callback function
tcClient.addlistener('AdsNotification',@OnNotification);
% Notification handle
hConnect = tcClient.AddDeviceNotification(arr2read,dataStream,0,8,AdsTransMode.OnChange,1,0,arr2read);
% Listen to ADS notifications for x seconds
pause(15);
catch err
msgbox(err.message,'Error reading array via ADS','error');
disp(['Error registering ADS notifications: ' err.message]);
end
%% Delete ADS notifications
tcClient.DeleteDeviceNotification(hConnect);
%% Dispose ADS client
tcClient.Dispose();
%% MatlabAdsSample_Notification: OnNotification
function OnNotification(sender, e)
e.DataStream.Position = e.Offset;
%% load variables from workspace
hConnect = evalin('caller','hConnect');
binRead = evalin('caller','binRead');
%% assign to ADS variable and convert to string
if( e.NotificationHandle == hConnect )
%% Read timestamp and encodervalues & append to Buffer
tcClient.Read(arr_handle, dataStream); %Read structure from stream
for idx=1:ARR_SIZE
%Read & Append Timestamp to Buffer
[bufflen, ~] = size(myBuffer); %Get current buffer length
tstamp = binRead.ReadUInt64; %Read tstamp from dataStream and shift reading position by 8bytes (int64)
myBuffer{bufflen+1,1} = tstamp;
%Read & Append Encodervalues to Buffer
for n=1:8
encval = binRead.ReadInt32; %Read tstamp from dataStream and shift reading position by 8bytes (int64)
myBuffer{bufflen+1,n+1} = encval;
end
end
Assign arraybuffer
buffname = 'myBuffer';
buffcount = buffcount+1;
buffcount_str = num2str(buffcount);
assignin('base',strcat(buffname, buffcount_str), myBuffer);
myBuffer = {}; %empty Buffer for next array
disp("buffer assigned")
else
%do nothing
end
end
end