# Kommunikation zwischen Matlab und TwinCAT



## stefanm80 (13 November 2011)

Hallo zusammen,

weiß jemand, ob eine Möglichkeit besteht, mit der man aus Matlab heraus auf Variablen in TwinCAT zuzugreifen kann? 

z.B. Ich schliesse Beckhoff E-Bus Klemmen an einen PC an und möchte diese I/Os in Matlab für eine Reglerentwicklung nutzen. 


mfg
Stefan Moser


----------



## simon86 (13 November 2011)

Hallo Stefan

Ob du die Werte dirket in Matlab einfügen kannst weiss ich nicht. Ich habe das mit dem TwinCat Scope gemacht. Mit diesem Programm kannst du die Variablen für eine bestimmte Zeit aufzeichnen und dann als *.dat Datei speichern. Das dat-File wird dann einfach in Matlab eingefügt und weiterverarbeitet.

Gruss
Simon


----------



## witkatz (15 November 2011)

Hast du schon versucht die TcAdsDll in Matlab einzubinden? 


```
addpath 'C:\TwinCAT\ADS Api\TcAdsDll\Include'
addpath 'C:\TwinCAT\ADS Api\TcAdsDll'
loadlibrary 'TcAdsDll.dll' 'TcAdsAPI.h' addheader 'TcAdsDef.h'
calllib('TcAdsDll', 'AdsPortOpen')
```
Weiter müsste man den C-Quellcode aus den Beispielen ins m-Code portieren. Das könnte funktionieren.

Gruß
witkatz


----------



## stefanm80 (19 November 2011)

Hallo,

an die TcAdsDll habe ich auch gedacht. HAbe damit aber bisher noch nicht gearbeitet, so dass ich mich da erst einmal einlesen muss. Wenn ich nächste Woche mal Zeit habe, werde ich mal einen Versuch starten. 

Gruß
Stefan


----------



## guojun lu (8 Dezember 2012)

hi witkatz：
do you have demo m file about communication with the Twincat using ADS. if have, can you send it to me?  thanks, my mail is luguojun007@gmail.com,
i call the dll, use the read value function, always back the error 1793, i don't know where is the problem.

Best regards,
guojun


----------



## dast (8 Dezember 2012)

Also ich würd das ganze über MEX-Files (siehe z.B. http://cnx.org/content/m12348/latest/) für Matlab lösen.
Dort kannst du den Zugriff auf die C++ ADS Library kapseln ...

Ich hab das mal so für den Zugriff von Matlab aus auf eine unserer Bildverarbeitungseinheiten per CAN gemacht.
Somit konnte ich von Matlab aus bequem auf die Bildverarbeitungseinheiten zugreifen.


----------



## guojun lu (24 Dezember 2012)

hello witkatz:
my code:
	
	



```
nLocalDllVersion=calllib('TcAdsDll','AdsGetDllVersion');nPort=calllib('TcAdsDll','AdsPortOpen')
```
i call the upper function in MATLAB, back the right Build,Revision and Version number, the nPort number also back OK; but when i used the function of 'AdsSyncReadReq', also back Error number  1793, i guess i write the wrong AMSNETID and port number;
if my AMSNETID is '169.254.158.205.1.1' and port number is '801' could you which is the right way to write the M file;
follow is the code my wrote for NETID 
	
	



```
nPort=calllib('TcAdsDll','AdsPortOpen');

NetId=[169,254,158,205,1,1];
pNetId=Libpointer('voidPtr',NetId);


port=801;
AMSNetID=[pNetId,port]
pAMSNetId=Libpointer('voidPtr',AMSNetID);
```


Really thanks for your coming support!


----------



## witkatz (23 Februar 2013)

*Kommunikation zwischen Matlab/Scilab und TwinCAT*

Error Code 1793 means "Service is not supported by server". The ADS Service is selected by the AdsIndexGroup, so I suppose that a wrong IndexGroup is passed to AdsSyncReadReq. You can lookup the return codes in infosys: "http://infosys.beckhoff.com/content/1033/tcadscommon/html/ads_returncodes.htm?id=11763"
I don't have any Matlab, so I cannot check your code, sorry...
But I have recently compiled a Win32 Dll to access TwinCAT from Scilab by ADS. Here is the Code, maybe also useful for Matlab users:

```
#include <windows.h>
#include <string.h>
#include <tcAdsDef.h>
#include <TcAdsApi.h>

extern "C" _declspec(dllexport) void sciAdsReadDouble(const char* PlcVariableName, double* Value, long* TcErr);
extern "C" _declspec(dllexport) void sciAdsWriteDouble(const char* PlcVariableName, double* Value, long* TcErr);

void sciAdsReadDouble(const char* PlcVariableName, double* Value, long* TcErr)
{
    AmsAddr            TcAddr;
    PAmsAddr        pTcAddr = &TcAddr;
    unsigned long    TcHdl;

    *TcErr = AdsGetLocalAddress(pTcAddr);
    if(*TcErr = 1864)  //Ads Port not opened
    {
        AdsPortOpen();
        *TcErr = AdsGetLocalAddress(pTcAddr);
        if(*TcErr) return;
    }
    else return;
    pTcAddr->port = AMSPORT_R0_PLC_RTS1;

    *TcErr = AdsSyncReadWriteReq(pTcAddr, ADSIGRP_SYM_HNDBYNAME, 0x0, sizeof(TcHdl), &TcHdl, strlen(PlcVariableName), (void *)PlcVariableName);
    if(*TcErr) return;

    *TcErr = AdsSyncReadReq(pTcAddr, ADSIGRP_SYM_VALBYHND, TcHdl, sizeof(*Value), Value);
    if(*TcErr) return; 

    *TcErr = AdsSyncWriteReq(pTcAddr, ADSIGRP_SYM_RELEASEHND, 0, sizeof(TcHdl), &TcHdl); 
    if(*TcErr) return;

}

void sciAdsWriteDouble(const char* PlcVariableName, double* Value, long* TcErr)
{
    AmsAddr            TcAddr;
    PAmsAddr        pTcAddr = &TcAddr;
    unsigned long    TcHdl;

    *TcErr = AdsGetLocalAddress(pTcAddr);
    if(*TcErr = 1864)  //Ads Port not opened
    {
        AdsPortOpen();
        *TcErr = AdsGetLocalAddress(pTcAddr);
        if(*TcErr) return;
    }
    else return;
    pTcAddr->port = AMSPORT_R0_PLC_RTS1;

    *TcErr = AdsSyncReadWriteReq(pTcAddr, ADSIGRP_SYM_HNDBYNAME, 0x0, sizeof(TcHdl), &TcHdl, strlen(PlcVariableName), (void *)PlcVariableName);
    if(*TcErr) return;

    *TcErr = AdsSyncWriteReq(pTcAddr, ADSIGRP_SYM_VALBYHND, TcHdl, sizeof(*Value), Value);
    if(*TcErr) return; 

    *TcErr = AdsSyncWriteReq(pTcAddr, ADSIGRP_SYM_RELEASEHND, 0, sizeof(TcHdl), &TcHdl); 
    if(*TcErr) return;

}
```

In scilab you can wrap the Dll-Calls i simpel scilab functions:

```
[COLOR=#32B9B9]link[/COLOR][COLOR=#4A55DB]([/COLOR][COLOR=#BC8F8F]"your_dll_path[/COLOR][COLOR=#BC8F8F]\TcScilabBridge.dll[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]sciAdsReadDouble[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]c[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#4A55DB])[/COLOR][COLOR=#000000];[/COLOR] 
[COLOR=#32B9B9]link[/COLOR][COLOR=#4A55DB]([/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]your_dll_path[/COLOR][COLOR=#BC8F8F]\TcScilabBridge.dll[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]sciAdsWriteDouble[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]c[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#4A55DB])[/COLOR][COLOR=#000000];[/COLOR] 
[COLOR=#B01813]function[/COLOR] [COLOR=#4A55DB][[/COLOR][COLOR=#834310][B]PlcVal[/B][/COLOR][COLOR=#000000], [/COLOR][COLOR=#834310][B]TcErr[/B][/COLOR][COLOR=#4A55DB]][/COLOR][COLOR=#5C5C5C]=[/COLOR][COLOR=#000000][U]AdsReadDouble[/U][/COLOR][COLOR=#4A55DB]([/COLOR][COLOR=#834310][B]PlcVarName[/B][/COLOR][COLOR=#4A55DB])[/COLOR]     
[COLOR=#4A55DB]    [[/COLOR][COLOR=#834310][B]PlcVal[/B][/COLOR][COLOR=#000000],[/COLOR] [COLOR=#834310][B]TcErr[/B][/COLOR][COLOR=#4A55DB]][/COLOR] [COLOR=#5C5C5C]=[/COLOR] [COLOR=#32B9B9]fort[/COLOR][COLOR=#4A55DB]([/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]sciAdsReadDouble[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#834310][B]PlcVarName[/B][/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]1[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]c[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]out[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#4A55DB][[/COLOR][COLOR=#BC8F8F]1[/COLOR][COLOR=#000000],[/COLOR][COLOR=#BC8F8F]1[/COLOR][COLOR=#4A55DB]][/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]2[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]d[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#4A55DB][[/COLOR][COLOR=#BC8F8F]1[/COLOR][COLOR=#000000],[/COLOR][COLOR=#BC8F8F]1[/COLOR][COLOR=#4A55DB]][/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]3[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]i[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#4A55DB])[/COLOR][COLOR=#000000];[/COLOR] [COLOR=#B01813]
endfunction[/COLOR]  
[COLOR=#B01813]function[/COLOR] [COLOR=#834310][B]TcErr[/B][/COLOR][COLOR=#5C5C5C]=[/COLOR][COLOR=#000000][U]AdsWriteDouble[/U][/COLOR][COLOR=#4A55DB]([/COLOR][COLOR=#834310][B]PlcVarName[/B][/COLOR][COLOR=#000000], [/COLOR][COLOR=#834310][B]PlcVal[/B][/COLOR][COLOR=#4A55DB])[/COLOR]     
    [COLOR=#834310][B]TcErr[/B][/COLOR] [COLOR=#5C5C5C]=[/COLOR] [COLOR=#32B9B9]fort[/COLOR][COLOR=#4A55DB]([/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]sciAdsWriteDouble[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#834310][B]PlcVarName[/B][/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]1[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]c[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#834310][B]PlcVal[/B][/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]2[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]d[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]out[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#4A55DB][[/COLOR][COLOR=#BC8F8F]1[/COLOR][COLOR=#000000],[/COLOR][COLOR=#BC8F8F]1[/COLOR][COLOR=#4A55DB]][/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]3[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]i[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#4A55DB])[/COLOR][COLOR=#000000];[/COLOR] [COLOR=#B01813]
endfunction[/COLOR]
```

Cheers
witkatz


----------



## Thomas_v2.1 (23 Februar 2013)

witzkatz, hast du schonmal versucht das in einen grafischen Xcos Block zu packen?
Ich habe mir das mal angesehen, das scheint leider nicht ganz so einfach zu sein. Auch weil die Dokumentation etwas mau ist.


----------



## witkatz (23 Februar 2013)

Ja, ja, ein grafischer Block oder ein Ads-Modul in ATOMS wäre cool! Vielleicht mach ich dass auch irgendwann wenn ich mehr Zeit habe und vor allem, wenn ich eine brauchbare Anleitung finde...
Momentan mach ich's mir auf die Schnelle recht einfach. Hab in TwinCAT LREAL-ARRAYs als Schnittstellenvariablen deklariet:

```
VAR_GLOBAL
    SciToTCat: ARRAY[0..7] OF LREAL;
    TCatToSci: ARRAY[0..7] OF LREAL;
END_VAR
```

Dann deklariere ich in Scilab Funktionen mit einem Double-Wert und dem Array-Index als Parameter. Die Functions werden aus Xcos mit dem scifunc_block_m aufgerufen. 


```
[COLOR=#32B9B9]link[/COLOR][COLOR=#4A55DB]([/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]your_dll_path[/COLOR][COLOR=#BC8F8F]\TcScilabBridge.dll[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]sciAdsReadDouble[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]c[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#4A55DB])[/COLOR][COLOR=#000000];[/COLOR] 
[COLOR=#32B9B9]link[/COLOR][COLOR=#4A55DB]([/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]your_dll_path[/COLOR][COLOR=#BC8F8F]\TcScilabBridge.dll[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]sciAdsWriteDouble[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#BC8F8F]"[/COLOR][COLOR=#BC8F8F]c[/COLOR][COLOR=#BC8F8F]"[/COLOR][COLOR=#4A55DB])[/COLOR][COLOR=#000000];[/COLOR]  
[COLOR=#B01813]function [PlcVal, TcErr] = AdsReadDouble(PlcVarName)
    [PlcVal, TcErr] = fort("sciAdsReadDouble", PlcVarName, 1, "c", "out", [1,1], 2, "d", [1,1], 3, "i");
endfunction

function TcErr = AdsWriteDouble(PlcVarName, PlcVal)
    TcErr = fort("sciAdsWriteDouble", PlcVarName, 1, "c", PlcVal, 2, "d", "out", [1,1], 3, "i");
endfunction

function y = ReadTCatToSci(idx)
    if idx < 0 or idx > 7 then
        y = 0;
    else
        PlcVarName = strcat([".TCatToSci[", string(floor(idx)), "]"]);
        [y, TcErr] = AdsReadDouble(PlcVarName);
    end
endfunction
function TcErr = WriteSciToTCat(idx, x)
    if idx < 0 or idx > 7 then
        TcErr = -1;
    else
        PlcVarName = strcat([".SciToTCat[", string(floor(idx)), "]"]);
        [TcErr] = AdsWriteDouble(PlcVarName, x);
    end
endfunction
[/COLOR][COLOR=#B01813][/COLOR]
```


In Xcos wähle ich dann scifunc_block_m. Der Block muss richtig parametriert werden, s. Bild.




Wichtig ist noch die "Echt-Zeit" Skalierung = 1 in den Xcos Simulationsparametern für ein brauchbares Echtzeitverhalten und los geht's 

Das ist sicherlich keine komfortable Lösung, doch hoffentlich ein brauchbares Provisorium.
Gruß witkatz


----------



## Thomas_v2.1 (23 Februar 2013)

witkatz schrieb:


> Ja, ja, ein grafischer Block oder ein Ads-Modul in ATOMS wäre cool! Vielleicht mach ich dass auch irgendwann wenn ich mehr Zeit habe und vor allem, wenn ich eine brauchbare Anleitung finde...



Anleitung gibt es leider nicht direkt.
Es gibt aber ein Rumpf-Beispiel welches man sich über Atoms installieren kann, nennt sich "xcos toolbox skeleton".
Die eigentliche C-Funktion ist vielleicht 1% von dem ganzen Drumherum, und das Drumherum ist so gut wie nicht dokumentiert. Wenn man mal eine Beschreibung findet, dann gilt diese auch höchstwahrscheinlich für die alten Scilab Versionen wo es noch kein Xcos gab (bzw. für Scicos).

Die C-Funktionen des Skeletons kann ich zumindest ändern, und bekomme das Ganze auch übersetzt. Man muss nur den MS C-Compiler installiert haben.

Ich habe mir das vor einiger Zeit mal angesehen, aber für eine Ankopplung an eine Siemens S7 bzw. Plcsim.
Wenn du mal vorhast das umzusetzen könnte man sicher Teile gemeinsam verwenden. Erstmal einen Rumpf mit den Funktionen (PlcReadDouble, PlcWriteDouble, PlcReadInt, ...) schaffen, der dann für die verschiedenen Anbindungen mit Leben gefüllt werden.
Wobei man sich dann im Vorfeld nochmal Gedanken um das Timing machen muss...


----------



## domicilio (7 Oktober 2013)

Hallo,
ich nörgel ja ungern herum, aber das Thema lautet Matlab. Ich suche die ganze Zeit im Internet wie man mit der DLL von TwinCat über ADS eine Verbindung zu Matlab herstellt.
Ich verwende GUIDE um eine HMI zu erstellen und würde gern auf Variablen zugreifen und evt. an die SPS über ADS Daten senden...

Hier lese ich mich durch und es wird fast nur über SciLab diskutiert. SciLab ist nicht Matlab. Matlab ist das Thema. 
Gibt es nun eine Lösung wie man eine Verbindung herstellt? Ein Beispielcode so wie ganz oben von witkatz?
Nur etwas ausführlicher und funktionierend? Leider findet man über Google keine richtige Dokumentation und Anleitung.

Kann man die DLL direkt im M-Code einbinden und aufrufen? Oder braucht man diese MEX-Files?

Liebe Grüße


----------

