DavidOtt

Mitsubishi FX5 read/write from PC with nodejs

36 posts in this topic

I'm new to PLC, I don't know the technical terms either. I'm trying to develop app to read/write from/to Mitsubishi MELSEC iQ-F FX5.

As I read here: https://dl.mitsubishielectric.co.jp/dl/fa/document/catalog/plcf/l08645/l08645-a.pdf that it is possible to write/read from PLC to/from a PC (with Ethernet connection). I'm programming in Nodejs, I don't know if such an application needs any server operation (main.js) or all coding - to do the read/writing operation - are handled in html function. 

The FX5 user manual explains methods for the device that is communicating with CPU module by MC protocol (Is this one? https://github.com/plcpeople/mcprotocol)

I don't know where to store data in PLC and from where to read in PLC. I need to send number sequence and timestamp to PLC and read 3 data (number sequence, timestamp, true/false) from PLC.

This mc protocol states 9 variables (D0, M6990, CN199, R2000, X034, D6000.1, D6001.2, S4, RFLOAT5000). Which variables are good for storing such data?

Do you recommend MC protocol?

 

Edited by DavidOtt

Share this post


Link to post
Share on other sites

FX5U have ModBus TCP (slave/Master). Maybe it will be easier on it? For ModBus TCP (slave) it is not necessary to write a program inside the PLC. In the "Enable" settings and you're done.

Edited by Neverov
2 people like this

Share this post


Link to post
Share on other sites

Hi DavidOtt,

i don't know the mcprotocol library for node.js you referenced, but you can use the mcprotocoll to read/write data from/to mitsubishi plc.
you can't handle it with html only, but with javascript and ethernet communication it shouldn't be a problem. in this case the
plc act as server, you establish a connection and then send the request (read/write, registertype, number of register) and the the plc will respond.
the request is handled at the end of the normal scan cycle of the plc.

the mcprotocoll is described in the melsec communication protocol manual, 
https://dl.mitsubishielectric.com/dl/fa/document/manual/plcf/jy997d60801/jy997d60801f.pdf
there are two types of the mcprotocoll ascii and binary, if you use nodejs/javascript using the ascii version should be easier,
beacuse you you can use ASCII-character to build the REQUEST string you send to the plc and doesn't need to handle byte
values in the senddata.

for a list of possible devices you can read/write have a look at the application manual
chapter 28 devices, https://dl.mitsubishielectric.com/dl/fa/document/manual/plcf/jy997d55401/jy997d55401t.pdf
in short you can use D (Data register) or R (file register) for signed/unsigend 16/32bit data (32bit require two registers)
and M (internal relay) or L (latch relay) for bit-data (true/false). to send an timestamp (js) you have split it into
the different parts (hour, minute, second) and send this in different registers, because the plc doesn't have a datatype
for date/time representation.

whitch register you can use, depends on the program on the plc. be sure that you don't use (write to) registers that are
used by the plc program. If you need read/write synchronisation for the data you also need to implement this on the plc side.


list of manuals https://www.mitsubishielectric.com/app/fa/download/search.do?kisyu=/plcf&mode=manual
If you need a tool to test the communication, you can use the HERCULES Setup utility
https://www.hw-group.com/software/hercules-setup-utility

2 people like this

Share this post


Link to post
Share on other sites

 

On 2021. 09. 24. at 8:02 PM, AndreasW said:

Hi DavidOtt,

i don't know the mcprotocol library for node.js you referenced, but you can use the mcprotocoll to read/write data from/to mitsubishi plc.
you can't handle it with html only, but with javascript and ethernet communication it shouldn't be a problem. in this case the
plc act as server, you establish a connection and then send the request (read/write, registertype, number of register) and the the plc will respond.
the request is handled at the end of the normal scan cycle of the plc.

the mcprotocoll is described in the melsec communication protocol manual, 
https://dl.mitsubishielectric.com/dl/fa/document/manual/plcf/jy997d60801/jy997d60801f.pdf
there are two types of the mcprotocoll ascii and binary, if you use nodejs/javascript using the ascii version should be easier,
beacuse you you can use ASCII-character to build the REQUEST string you send to the plc and doesn't need to handle byte
values in the senddata.

for a list of possible devices you can read/write have a look at the application manual
chapter 28 devices, https://dl.mitsubishielectric.com/dl/fa/document/manual/plcf/jy997d55401/jy997d55401t.pdf
in short you can use D (Data register) or R (file register) for signed/unsigend 16/32bit data (32bit require two registers)
and M (internal relay) or L (latch relay) for bit-data (true/false). to send an timestamp (js) you have split it into
the different parts (hour, minute, second) and send this in different registers, because the plc doesn't have a datatype
for date/time representation.

whitch register you can use, depends on the program on the plc. be sure that you don't use (write to) registers that are
used by the plc program. If you need read/write synchronisation for the data you also need to implement this on the plc side.


list of manuals https://www.mitsubishielectric.com/app/fa/download/search.do?kisyu=/plcf&mode=manual
If you need a tool to test the communication, you can use the HERCULES Setup utility
https://www.hw-group.com/software/hercules-setup-utility

Thank you for the detailed description. I asked these, because the PLC programming is done by my partner, they know how to program PLC, but they don't know how to read/write from/to PC. I would do the PC side. So I need to make app that does this. I need to know the registers(slot, memory id) where the data is or registers where I need to write data.

@Neverov recommended ModBus. I checked it and the syntax is familiar to me. I would go that way.

Share this post


Link to post
Share on other sites
On 2021. 09. 24. at 7:49 PM, Neverov said:

FX5U have ModBus TCP (slave/Master). Maybe it will be easier on it? For ModBus TCP (slave) it is not necessary to write a program inside the PLC. In the "Enable" settings and you're done.

I checked ModBus. I found these 

https://www.npmjs.com/package/jsmodbus

https://www.npmjs.com/package/node-net-reconnect (keep TCP connections alive)  I would write app with this function when reading from PLC. Reading should be continous during operation. 

I don't know if these packages are good for this purpose. 

client.readCoils(0, 13).then(function (resp) {

This line should read the PLC, but I don't know how to set here the PLC's registers and it shows example only for reading.

In this video https://www.youtube.com/watch?v=rcy90W7lDQM&ab_channel=%D0%92%D0%B0%D0%BB%D0%B5%D0%BD%D1%82%D0%B8%D0%BD%D0%9B%D0%BE%D0%B1%D0%B0%D1%82%D0%B5%D0%BD%D0%BA%D0%BE jsmodbus package was used, but not specifically with FX5. 

I need similar coding for FX5.

Share this post


Link to post
Share on other sites

Hi DavidOtt,

if you wan't to use modbus you can setup the modbus register inside the plc ethernet configuration. you first have to add a modbus-tcp-connection
inside the external device configuration (see chapter 12 https://dl.mitsubishielectric.com/dl/fa/document/manual/plcf/jy997d56101/jy997d56101g.pdf)
then you can assign the required devices for the different modbus function (read/write coil, input, input register, holding register,...).

beside this, i still think that using the mcprotocol may be easier, and you don't need a special node library for this, just create a socket
and send the request string (ascii-string) from node js (only 'net'-module is required for the socket)

Share this post


Link to post
Share on other sites
5 hours ago, AndreasW said:

Hi DavidOtt,

if you wan't to use modbus you can setup the modbus register inside the plc ethernet configuration. you first have to add a modbus-tcp-connection
inside the external device configuration (see chapter 12 https://dl.mitsubishielectric.com/dl/fa/document/manual/plcf/jy997d56101/jy997d56101g.pdf)
then you can assign the required devices for the different modbus function (read/write coil, input, input register, holding register,...).

beside this, i still think that using the mcprotocol may be easier, and you don't need a special node library for this, just create a socket
and send the request string (ascii-string) from node js (only 'net'-module is required for the socket)

Can you help me please? The PLC serial number is 2010516. The MC protocol package (https://github.com/plcpeople/mcprotocol) uses 1E frame (I don't know what this means). If I cannot use this package I would write code with socket as you recommended. I can connect to host, but I do not know the syntax for ASCII string. Can you please give some ASCII string example for read and write?

Share this post


Link to post
Share on other sites
15 hours ago, AndreasW said:

Hi DavidOtt,

if you wan't to use modbus you can setup the modbus register inside the plc ethernet configuration. you first have to add a modbus-tcp-connection
inside the external device configuration (see chapter 12 https://dl.mitsubishielectric.com/dl/fa/document/manual/plcf/jy997d56101/jy997d56101g.pdf)
then you can assign the required devices for the different modbus function (read/write coil, input, input register, holding register,...).

beside this, i still think that using the mcprotocol may be easier, and you don't need a special node library for this, just create a socket
and send the request string (ascii-string) from node js (only 'net'-module is required for the socket)

Can you help me please? The PLC serial number is 2010516. The MC protocol package (https://github.com/plcpeople/mcprotocol) uses 1E frame (I don't know what this means). If I cannot use this package I would write code with socket as you recommended. I can connect to host, but I do not know the syntax for ASCII string. Can you please give some ASCII string example for read and write?

I had a test with MC protocol app. Unfortunately, it did not connect. However, my partner said that PLC is in SLMP. My app uses MC protocol. Do you think this can cause connection error?

I found a site https://www.codeproject.com/Articles/616262/PLC-Communication-Using-NET it shows ascii strings like this  500000FF03FF00001C000A14010000D*0095010002  where 1401 and 00950 refer to writing and D is the device code. I don't know if I should use such a string. And I also don't know what is the data in this string?

Share this post


Link to post
Share on other sites

Hi DavidOtt,

first check the required firmwareversion for the fx5, for mc this should be at least v1.240firmware_version.jpg.a700d315f780d6251f5

otherwise mc-protocol won't work; if your version is lower then you have to update the firmware via sd-card
download of firware_update:       https://www.mitsubishielectric.com/fa/download/software/cnt/plc/index.html#cat_melsec-fx_series
fimrware update procedure:        Chapter 5/ (SD-Card required) https://www.mitsubishifa.co.th/files/dl/jy997d55401j_FX5(Application).pdf

if firmwareversion is ok, you can setup the protocol settingsethernet_Settings.thumb.jpg.b26d01bad209

Communication Data code: ASCII (HEX) or ASCII(OCT) if you prefer octal instead of hexadecimal adressing and values;
Add an SLMP connection and setup the port; be sure to write changed ethernet module settings to the plc.

for the built in ethernet port the FX5 cpu uses the 1E-frame, see SLMP Manual, Chapter 3.2 "1E-Frame"
https://dl.mitsubishielectric.com/dl/fa/document/manual/plcf/jy997d56001/jy997d56001j.pdf

the Message Format is
data:  [CMD][PCNR][TIMEOUT][DEVCODE][ADDR][COUNT][ENDCODE]
digits:  2    2      4        4       8      2      2

CMD:    see chapter5/  01..batch read 1 word unit, 03... batch write
PCNR:    FF (fixed)
TIMEOUT: 0000 wait unlimited or timeout in units of 250ms
DEVCODE: see page 123 (device range)
         D-register ... 4420
         M-register...  4D20
COUNT:    2digit HEX/0A... 10Register
END:    00 (fixed)

 

so to read D10...D15 (5 words) command is:
"01FF000A44200000000A0500"   
--> 01 (cmd)... batch read 1 word unit
--> FF (pcnr, fixed)
--> 000A (timeout 10x250ms= 2.5sec)
--> 4420 (devcode for d-register)
--> 0000000A (start adress in hex = 10 decimal)
--> 05 (counter in hex= 5), (to read 10 register it would be 0A)
--> 00 (end, fixed)

response "8100xxxxyyyyzzzz"  (x,y,z = hex value of registers, each 4 digits)

to write D10=255, D11=20, D12= 27
"03FF000A44200000000A030000FF0014001B"
--> 03 (cmd)... batch write 1 word unit
--> FF (pcnr, fixed)
--> 000A (timeout 10x250ms= 2.5sec)
--> 4420 (devcode for d-register)
--> 0000000A (start adress in hex = 10 decimal)
--> 03 (counter in hex= 3)
--> 00 (end, fixed)
--> 00FF (first value in hex, FF=255)
--> 0014 (second value in hex= 20)
--> 001B (third value in hex = 27)
 

for node js you only need the net module
/////////////// TEST.JS ///////////////////////////////////////////////

var net = require('net');

var client = new net.Socket();
client.connect(1000, '172.25.110.7', function() {      //change ip and port
    console.log('Connected');
    client.write('01FF000A44200000000A0200');      // read D10,D11
});

client.on('data', function(data) {
    console.log('Received: ' + data);
    client.end();
});

client.on('close', function() {
    console.log('Connection closed');
});

//////////////////////////////////////////////////////////////////

Edited by AndreasW
2 people like this

Share this post


Link to post
Share on other sites
47 minutes ago, AndreasW said:

Hi DavidOtt,

first check the required firmwareversion for the fx5, for mc this should be at least v1.240firmware_version.jpg.a700d315f780d6251f5

otherwise mc-protocol won't work; if your version is lower then you have to update the firmware via sd-card
download of firware_update:       https://www.mitsubishielectric.com/fa/download/software/cnt/plc/index.html#cat_melsec-fx_series
fimrware update procedure:        Chapter 5/ (SD-Card required) https://www.mitsubishifa.co.th/files/dl/jy997d55401j_FX5(Application).pdf

if firmwareversion is ok, you can setup the protocol settingsethernet_Settings.thumb.jpg.b26d01bad209

Communication Data code: ASCII (HEX) or ASCII(OCT) if you prefer octal instead of hexadecimal adressing and values;
Add an SLMP connection and setup the port; be sure to write changed ethernet module settings to the plc.

for the built in ethernet port the FX5 cpu uses the 1E-frame, see SLMP Manual, Chapter 3.2 "1E-Frame"
https://dl.mitsubishielectric.com/dl/fa/document/manual/plcf/jy997d56001/jy997d56001j.pdf

the Message Format is
data:  [CMD][PCNR][TIMEOUT][DEVCODE][ADDR][COUNT][ENDCODE]
digits:  2    2      4        4       8      2      2

CMD:    see chapter5/  01..batch read 1 word unit, 03... batch write
PCNR:    FF (fixed)
TIMEOUT: 0000 wait unlimited or timeout in units of 250ms
DEVCODE: see page 123 (device range)
         D-register ... 4420
         M-register...  4D20
COUNT:    2digit HEX/0A... 10Register
END:    00 (fixed)

 

so to read D10...D15 (5 words) command is:
"01FF000A44200000000A0500"   
--> 01 (cmd)... batch read 1 word unit
--> FF (pcnr, fixed)
--> 000A (timeout 10x250ms= 2.5sec)
--> 4420 (devcode for d-register)
--> 0000000A (start adress in hex = 10 decimal)
--> 05 (counter in hex= 5), (to read 10 register it would be 0A)
--> 00 (end, fixed)

response "8100xxxxyyyyzzzz"  (x,y,z = hex value of registers, each 4 digits)

to write D10=255, D11=20, D12= 27
"03FF000A44200000000A030000FF0014001B"
--> 03 (cmd)... batch write 1 word unit
--> FF (pcnr, fixed)
--> 000A (timeout 10x250ms= 2.5sec)
--> 4420 (devcode for d-register)
--> 0000000A (start adress in hex = 10 decimal)
--> 03 (counter in hex= 3)
--> 00 (end, fixed)
--> 00FF (first value in hex, FF=255)
--> 0014 (second value in hex= 20)
--> 001B (third value in hex = 27)
 

for node js you only need the net module
/////////////// TEST.JS ///////////////////////////////////////////////

var net = require('net');

var client = new net.Socket();
client.connect(1000, '172.25.110.7', function() {      //change ip and port
    console.log('Connected');
    client.write('01FF000A44200000000A0200');      // read D10,D11
});

client.on('data', function(data) {
    console.log('Received: ' + data);
    client.end();
});

client.on('close', function() {
    console.log('Connection closed');
});

//////////////////////////////////////////////////////////////////

Sounds very promising, I will write the code. However, I have problems with definitions. You wrote check version "otherwise mc-protocol" won't work and at the end you wrote "for nodejs you only need the net module". Why should I check if mc protocol can work based on version? I won't use the mc-protocol module if I need only the net module. You also wrote "Add an SLMP connection". I thought it is a different protocol, other than MC.

In nodejs code you wrote:  client.write('01FF000A44200000000A0200');      // read D10,D11 

Client.write is not a writing command? Because you wrote in comment: // read D10,D11 

Nevertheless, I prepare app with your nodejs codes. Thank you for your help.

Share this post


Link to post
Share on other sites

Hi DavidOtt,

the version to check is the firmware version of the plc, (see Appendix4 in https://dl.mitsubishielectric.com/dl/fa/document/manual/plcf/jy997d56001/jy997d56001j.pdf)
not the version for node module.
 

In nodejs code you wrote:  client.write('01FF000A44200000000A0200');      // read D10,D11 
Client.write is not a writing command? Because you wrote in comment: // read D10,D11
 

in nodejs you have to send a command (WRITE) to the plc. If this command reads/writes depends only of the content of the send string,
sending '01FF...' is a batch read command, that will response with the values of the requested registers;
sending '03FF...' is a batch write command, that will set values of the registers upon the data given in the sendstring

 

 

Share this post


Link to post
Share on other sites
54 minutes ago, AndreasW said:

Hi DavidOtt,

the version to check is the firmware version of the plc, (see Appendix4 in https://dl.mitsubishielectric.com/dl/fa/document/manual/plcf/jy997d56001/jy997d56001j.pdf)
not the version for node module.
 

In nodejs code you wrote:  client.write('01FF000A44200000000A0200');      // read D10,D11 
Client.write is not a writing command? Because you wrote in comment: // read D10,D11
 

in nodejs you have to send a command (WRITE) to the plc. If this command reads/writes depends only of the content of the send string,
sending '01FF...' is a batch read command, that will response with the values of the requested registers;
sending '03FF...' is a batch write command, that will set values of the registers upon the data given in the sendstring

 

 

I understood the same when you wrote PLC version should be checked in order to make mc protocol work. What confused me that MC is a protocol and SLMP is also a protocol.

I found in the link you wrote:

The message format of each SLMP is the same as that of the following MC protocols frames.

• 3E frame: QnA compatible 3E frame of MC protocol

• 1E frame: A compatible 1E frame of MC protocol

The external devices used with the above MC protocols can be connected to SLMP compatible devices.

 

So If I understood well, the nodejs net format (client.write('ASCII format string')) is compatible to MC protocol so with that a communication channel can be established to a PLC that is SLMP compatible.

Edited by DavidOtt

Share this post


Link to post
Share on other sites
1 hour ago, Dave W. said:

Hi DavidOtt
I have made tests with this Node for Node Red.
works find with FX5U.
Maybe you can read the code behind this Node?

node-red-contrib-mcprotocol (node) - Node-RED (nodered.org)

I wish you success
Dave

Thank you for your advise and wishes.

Is Node-RED a programming app? On npm (https://www.npmjs.com/package/node-red-contrib-mcprotocol), it didn't show code snippet. Is it working on PC as a web browser based app that communicates with PLC (I open web browser and connect to PLC with http address)? The PC side coding (html, server) is done in Node-RED? I checked Node-RED before and I saw it has its own ui with palette and flow window.

Share this post


Link to post
Share on other sites
1 hour ago, DavidOtt said:

 understood the same when you wrote PLC version should be checked in order to make mc protocol work. What confused me that MC is a protocol and SLMP is also a protocol.

I found in the link you wrote:

The message format of each SLMP is the same as that of the following MC protocols frames.

• 3E frame: QnA compatible 3E frame of MC protocol

• 1E frame: A compatible 1E frame of MC protocol

The external devices used with the above MC protocols can be connected to SLMP compatible devices.

 

So If I understood well, the nodejs net format (client.write('ASCII format string')) is compatible to MC protocol so with that a communication channel can be established to a PLC that is SLMP compatible.

in short: not exact but in general yes (when using the ASCII version)

some more details, but don't let it confuse you:
the 'original' mc-protocol is primary used with serial connection, using the build in ethernet you can use the SLMP protocol instead,
but the SLMP protocol use the same frame-types (3E/1E) as the mc-protocol. There are two protocol types supported: binary and ascii.
It's easy when you use ASCII-format, because in this case the frame defines the format ( [CMD][PCNR][TIMEOUT][DEVCODE][ADDR][COUNT][ENDCODE] )  and the
number of digits of each part. Every digit is coded as 1 byte using the ASCII code assignment.
And this is what the node-net module does, it takes a an ascii coded string, build an tcp-packet an put each character as 1 byte into the payload of the
tcp-packet. This is why its easy to use, all you have to do is building the 'right' ascii-sendstring following the frame (format/number of digits).

Using the binary version is also be possible, but would be a little bit more complicated, because you can't use the net.Socket.write() function. In this case 
you would have to build the senddata byte by byte and you have to care about endianess so using the ascii version is easier.

 

 

Share this post


Link to post
Share on other sites
On 2021. 09. 28. at 0:12 PM, AndreasW said:

in short: not exact but in general yes (when using the ASCII version)

some more details, but don't let it confuse you:
the 'original' mc-protocol is primary used with serial connection, using the build in ethernet you can use the SLMP protocol instead,
but the SLMP protocol use the same frame-types (3E/1E) as the mc-protocol. There are two protocol types supported: binary and ascii.
It's easy when you use ASCII-format, because in this case the frame defines the format ( [CMD][PCNR][TIMEOUT][DEVCODE][ADDR][COUNT][ENDCODE] )  and the
number of digits of each part. Every digit is coded as 1 byte using the ASCII code assignment.
And this is what the node-net module does, it takes a an ascii coded string, build an tcp-packet an put each character as 1 byte into the payload of the
tcp-packet. This is why its easy to use, all you have to do is building the 'right' ascii-sendstring following the frame (format/number of digits).

Using the binary version is also be possible, but would be a little bit more complicated, because you can't use the net.Socket.write() function. In this case 
you would have to build the senddata byte by byte and you have to care about endianess so using the ascii version is easier.

 

 

Thank you very much for your help. It connected to PLC and I could read data from PLC. I still have issues, but I need to solve it by testing different codes.

FX5U needs different string line, same as here https://www.c-sharpcorner.com/UploadFile/asmabegam/plc-communication-using-net/

Do you have experience with such a connection? If I use your code the sequence is like: 1. it connects to PLC 2. sends the string and 3. closes connection. If PLC register (ie new value in D10) is updated when app is running, then it shows the data ( console.log('Connection closed'); and then console.log('Received: ' + data); ). 

I need to monitor the PLC, hence I need to check its registers if new data is stored there. I should make a while loop for connection and I would break connection if data string (stored data from PLC) ends with 'exit'. Until that it should check every 2-3 seconds for new data (it should send client.write to PLC to read the registers).

 

Share this post


Link to post
Share on other sites

the node.js code was just an example, the connection is closed by the client.end() command set after receiving the response from the plc.

if you wan't to check every 2-3 seconds you can use the setInterval methode, something like this:
but this is also just an example:

 

 

const Net = require('net');         // Include Nodejs' net module.

const port = 8080;                  // The port number and hostname of the plc.
const host = 'localhost';

const requestString= '04010001A8000001000A';    // the RequestString to READ your data from the plc

const client = new Net.Socket();    // create socket
let requestInterval= null;          // request interval
let timeout= null;                  // request timeout

// EndConnection, called to destroy the socket and clear request interval and timeout
function EndConnection()
{
    if (requestInterval != null)
    {
        clearInterval(requestInterval);
        requestInterval= null;
    }
    if (timeout != null)
    {
        clearTimeout(timeout);
        timeout= null;
    }
    console.debug('disconnect from plc, terminate connection');
    client.destroy();
}


// ReadDataFromPLC, send RequestString to plc
function ReadDataFromPLC()
{
    // check if socket is ready
    if (client.readyState != 'open')
    {   // socket not connected,
        console.debug('error: socket/plc not ready for sending ReadRequest');
        EndConnection();
    }
    else
    {   // socket is ready, check if Timeout for last ReadRequest occured
        if (timeout== null)
        {   // socket is open, send 'ReadRequest' to plc and set timeout for the response,
            // timeout will cleared when data received from plc
            // !!!! TimeOut 'time' should be smaller than Interval 'time'
            console.debug('send Request to plc....');
            client.write(requestString, ()=>{
                timeout= setTimeout(()=> {
                    console.debug('error: timeout occured, no data received for last ReadRequest');
                    EndConnection();
                }, 1500);
            });
        }
        else{
            // if there is no response from the plc for the last ReadRequest,
            // don't send a new readRequest
            console.debug('error: no data received for last ReadRequest ');
            EndConnection();
        }
    }
}

// connect to plc, set Interval to 3seconds (3000ms)
client.connect({ port: port, host: host }, function() {
    console.debug('TCP connection established with the plc.');
    requestInterval= setInterval( ReadDataFromPLC, 3000);
});

// handle connection termination, e.g. server/plc close connection
client.on('end', function() {
    console.debug('Requested an end to the TCP connection');
    EndConnection();
});

// handle socket error
client.on('error', function(err) {
    console.log(`socket error occured ${err.toString()}`);
    EndConnection();
});


// handle response from plc
client.on('data', function(chunk) {
    console.debug(`Data received from the plc: ${chunk.toString()}.`);
    // clear TimeOut for ReadRequest
    if (timeout != null)
    {   
        clearTimeout(timeout);
        timeout= null;
    }

    /////////////////////////////////////////////////////
    // TODO: check received data, verify response string,
    /////////////////////////////////////////////////////

});

 

 

 

 

 

Edited by AndreasW

Share this post


Link to post
Share on other sites
16 hours ago, AndreasW said:

the node.js code was just an example, the connection is closed by the client.end() command set after receiving the response from the plc.

if you wan't to check every 2-3 seconds you can use the setInterval methode, something like this:
but this is also just an example:

 

 

const Net = require('net');         // Include Nodejs' net module.

const port = 8080;                  // The port number and hostname of the plc.
const host = 'localhost';

const requestString= '04010001A8000001000A';    // the RequestString to READ your data from the plc

const client = new Net.Socket();    // create socket
let requestInterval= null;          // request interval
let timeout= null;                  // request timeout

// EndConnection, called to destroy the socket and clear request interval and timeout
function EndConnection()
{
    if (requestInterval != null)
    {
        clearInterval(requestInterval);
        requestInterval= null;
    }
    if (timeout != null)
    {
        clearTimeout(timeout);
        timeout= null;
    }
    console.debug('disconnect from plc, terminate connection');
    client.destroy();
}


// ReadDataFromPLC, send RequestString to plc
function ReadDataFromPLC()
{
    // check if socket is ready
    if (client.readyState != 'open')
    {   // socket not connected,
        console.debug('error: socket/plc not ready for sending ReadRequest');
        EndConnection();
    }
    else
    {   // socket is ready, check if Timeout for last ReadRequest occured
        if (timeout== null)
        {   // socket is open, send 'ReadRequest' to plc and set timeout for the response,
            // timeout will cleared when data received from plc
            // !!!! TimeOut 'time' should be smaller than Interval 'time'
            console.debug('send Request to plc....');
            client.write(requestString, ()=>{
                timeout= setTimeout(()=> {
                    console.debug('error: timeout occured, no data received for last ReadRequest');
                    EndConnection();
                }, 1500);
            });
        }
        else{
            // if there is no response from the plc for the last ReadRequest,
            // don't send a new readRequest
            console.debug('error: no data received for last ReadRequest ');
            EndConnection();
        }
    }
}

// connect to plc, set Interval to 3seconds (3000ms)
client.connect({ port: port, host: host }, function() {
    console.debug('TCP connection established with the plc.');
    requestInterval= setInterval( ReadDataFromPLC, 3000);
});

// handle connection termination, e.g. server/plc close connection
client.on('end', function() {
    console.debug('Requested an end to the TCP connection');
    EndConnection();
});

// handle socket error
client.on('error', function(err) {
    console.log(`socket error occured ${err.toString()}`);
    EndConnection();
});


// handle response from plc
client.on('data', function(chunk) {
    console.debug(`Data received from the plc: ${chunk.toString()}.`);
    // clear TimeOut for ReadRequest
    if (timeout != null)
    {   
        clearTimeout(timeout);
        timeout= null;
    }

    /////////////////////////////////////////////////////
    // TODO: check received data, verify response string,
    /////////////////////////////////////////////////////

});

 

 

 

 

 

With your code it gave me this result (D2050 is read its value in PLC is 133, this string is 500000FF03FF000018000004010000D*0020500001):

1. 'disconnect from plc, terminate connection'

2. 'error: timeout occured, no data received for last ReadRequest'

3. 'send Request to plc....'

4. Data received from the plc: D00000FF03FF00000800000085

And then 3 and 4 repeats

Can you please advise what this means? Your request string is different. Shall I try that string? What would be your string to read D2050?

 

 

Share this post


Link to post
Share on other sites

To read D2050 the string should be "01FF000A4420000008020100"

"01 FF 000A 4420 00000802 01 00"   
--> 01 (cmd)... batch read 1 word unit
--> FF (pcnr, fixed)
--> 000A (timeout 10x250ms= 2.5sec)
--> 4420 (devcode for d-register)
--> 00000802 (start adress in hex h802= decimal 2050)
--> 01 (counter in hex= h01= decimal 01 = 1 register)
--> 00 (end, fixed)

 

 

Share this post


Link to post
Share on other sites
On 2021. 10. 13. at 1:35 PM, AndreasW said:

To read D2050 the string should be "01FF000A4420000008020100"

"01 FF 000A 4420 00000802 01 00"   
--> 01 (cmd)... batch read 1 word unit
--> FF (pcnr, fixed)
--> 000A (timeout 10x250ms= 2.5sec)
--> 4420 (devcode for d-register)
--> 00000802 (start adress in hex h802= decimal 2050)
--> 01 (counter in hex= h01= decimal 01 = 1 register)
--> 00 (end, fixed)

 

 

Thank you Thank you Thank you. It's working. I really appreciate your help. 

One more question, is it possible to reach the PLC's sd card through such a connection?

Thank you again!

Share this post


Link to post
Share on other sites

@AndreasW Hello again, I got far with your info. Thank you. However, I stuck again. All went fine with reading string as you recommended in ascii format. Now that more parts are set together in the system, PLC got robot and HMI. With such a setup in ascii format, the robot and HMI cannot communicate with PLC, but only PC can. So system needs to be changed to binary format.

Now that I understand more, your above info gave me new information:  Using the binary version is also be possible, but would be a little bit more complicated, because you can't use the net.Socket.write() function. In this case you would have to build the senddata byte by byte and you have to care about endianess so using the ascii version is easier.

I need to change the reading request to binary. Can you please send information how to form such request?

Edited by DavidOtt

Share this post


Link to post
Share on other sites

hi David Ott,


I don't quite understand what influence a robot or an HMI should have on the communication between PLC and PC?  Or is it about to handle a communication between robot and PLC also over the MC protocol ? Or is it about the fact that only the PC but neither the HMI nor the robot can establish a connection to the PLC?

If it is the latter, you should check if you have enough free Ethernet/SLMP connections in the network configuration of the PLC.
(Parameter|FXCPU|Module Parameter|Ethernet Port|External Device Configuration),if no other connections are configured here, only one client can communicate with the PLC at a time.)


If you want to establish a communication between PLC and robot via the MC protocol, this must be programmed on the robot side, if this is basically supported by the robot, it should then also be the same whether the MC protocol is used as ASCII or BINARY variant and also in this case the ASCII variant should be easier to program, at least for the robots that I know (Mitsubishi, Epson, ABB).

 

The difference between the ASCII and BINARY variant iof the MC-protocoll is basically only in the number of bytes to be sent and the values.
See the SLMP manual (chapter 3.2 1E frame, and chapter 5.2 device access).

https://dl.mitsubishielectric.com/dl/fa/document/manual/plcf/jy997d56001/jy997d56001j.pdf


Maybe again to explain why the ASCII variant is a bit easier to program.
As an example the request string for reading D2050 should serve:

in the ASCII variant the request string is structured as follows:
"01 FF 000A 4420 00000802 01 00"

"01 FF 000A 4420 00000802 01 00"   
--> 01 (cmd)... batch read 1 word unit [2 byte, 30h, 31h] "01"
--> FF (pcnr, fixed) [2 bytes, 46h, 46h] "FF"
--> 000A (timeout 10x250ms= 2.5sec) [4 byte, 30h, 30h, 41h] "000A"
--> 4420 (devcode for d-register) [4 byte, 34h, 34h, 32h, 30h]
--> 00000802 (start address in hex h802= decimal 2050) [8 Byte]
--> 01 (counter in hex= h01= decimal 01 = 1 register) [2 byte]
--> 00 (end, fixed) [2 byte]

Strictly speaking, we do not have to send the STRING, but the byte stream consisting of 24 bytes (hex: 30,31,46,46,30,30,41,34,34,32,30, ....)
This Byte stream corresponds exactly to the ASCII character set, which is why we can simply pass this "byte array" as an ASCII string to the functions such as client.write(...) without having to build the byte array manually for this purpose.

If, for example, the above request is not to be sent as ASCII but as BINARY,
the structure changes (see Chapter 5.2, page 124).
CMD --> 1 byte 01h, instead of string "01" = [30h, 31h]
PCNR --> 1 byte: FFh, instead of string "FF" = [46h,46h]
TIMEOUT --> 2 byte: 00h, 0Ah, instead of string "000A" = [30h,30h,30h,41h]
START ADDRESS --> 4 bytes: 00h, 00h, 08h , 02h instead of string "00000802 " = [30h,30h,30h,30h,30h,38h,30h,32h]
DEVICE-CODE -> 2 Byte: 44h, 20h, instead of string "4420" = [34h,34h,32h,30h]
COUNTER -> 1 byte: 01h, instead of string "01" = [30h, 31h]
END -> 1 byte: 00h, instead of string "00" = [30h, 30h]

the whole request consists then only of 12 bytes instead of 24 bytes,
these 12 bytes must be written within the program first manually into a byte array and can be sent then likewise by client.write.

So in nodejs instead of client.write("01FF000A4420000008020100") would be
would rather result in something like this

testBuff = new Buffer([1, 255, 0, 10, 0,0,8,2, 68, 32, 1, 0]);
client.write(testBuff);

the response data would then also be processed as a byte array. Since only the byte data arrives here and client.write only returns the raw data, the byte order (endianess) must be taken into account.available String functions can't be used to split the received data, and so on....

So in total this would be much more complex and I have never seen a system where the communication can't be solved with the ASCII-Varainte.
The BINARY variant has only the advantage that less data must be transferred, but this should normally not be a problem.


 

 

Share this post


Link to post
Share on other sites

@AndreasW Thank you for your reply. I got screenshot of the PLC settings where communication data code was changed from ascii to binary. Does this tell you where I miss the reading command to work well?

PLCsetting.png

PLCsetting1.png

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now