TwinCAT3-使用Matlab从ADS数据流中读取时,时间戳值错误

问题描述 投票:0回答:1

我正在尝试从TwinCAT3项目中读取ADS数据流。

我编写的函数应该在CycleCount(来自SPS)更改其值时读取数据流-因此CycleCount是回调函数的触发器,并且每毫秒检查一次更改。

要读取的数据流由包含两个值“ nCycleCount”(DWORD-4Bytes)和“ TStamp”(ULINT-8Bytes)的结构组成。因此,整个流包含12个字节的数据。

TwinCAT中的一个周期配置为0.5毫秒,因此变量CycleCount应该每秒更改2次(如果PLC任务的周期时间为一个周期刻度)。当我的程序每毫秒检查一次变量CycleCount是否更改时,应每毫秒调用一次回调函数,并将时间戳记写入Buffer(“ myBuffer”)。但我注意到,在2秒的运行时间中,我仅收到1000个值(而不是预期的2000个值),而我找不到原因?

TwinCAT3中的PLC任务似乎显示了正确的值,但是当用MatLab读取它们时,时间戳值是不正确的,并且并非如前所述是每毫秒:

enter image description here

这些是Matlab的一些输出,其中CycleCounter被写入第1列,时间戳被写入第2列:

enter image description here

我在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

希望您能帮助我解决我的问题-提前致谢!

matlab plc twincat twincat-ads
1个回答
0
投票

据我所知,您的程序运行正常。

1)

您正在检查每个ms的时间戳,并且plc周期为0.5 ms,您将获得1000个2000 plc周期滴答的值。

您假设运行时间为2秒,但实际上只有1秒。

2)

转换错误必须与matlab解释8字节的方式有关。

[在twincat中,您正在使用UNSIGNED long int ..,在matlab中?根据值前面的减号,必须将其解释为8字节有符号整数。

© www.soinside.com 2019 - 2024. All rights reserved.