DavidOtt

Mitsubishi FX5 read/write from PC with nodejs

36 posts in this topic

hi david ott,

i still don't understand what exactly is the problem? or why the SLMP communication should be changed to BINARY?
Are you now concerned about the connection PLC to PC (nodejs) or the connection between robot/HMI to PLC?

You wrote:  "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."

I don't understand how the change from ASCII to BINARY should change anything here, or why this should be necessary. If no other devices than the PC can connect to the PLC, you should check if you have configured enough connections in the network settings. If necessary you have to add more connections here.
(Parameter|FXCPU|Module Parameter|Ethernet Port|External Device Configuration)


devcon.thumb.jpg.8c6dbb2d647569836113098

 

If you still want to use the BINARY variant (although I doubt this is necessary) you have to modify the nodejs program accordingly of course.

 

 

Share this post


Link to post
Share on other sites

@AndreasW I got screenshot of the ethernet configuration. The port 1025 where PC should connect. If PLC is set to binary, the log shows that PC connected to PLC, but PC does not receive string started with 8100, but 3 symbols (no more data). Do you know where is the problem? Thank you for your help.

ethernet conf.png

Share this post


Link to post
Share on other sites

hi david ott,

i think the problem is that you send the wrong request. If you set the data code to BINARY, you have to change the nodejs and the Request you send to the plc.
The request has to be send as Bytre-Array and not as a string. Also the response data from the plc can't be interpreted as string
all you recieve are bytes. The response is no longer the string "8100" (4 bytes) but only 2 bytes with the value 81h and 00h,
and if you use console.log to visualize/show these two bytes are interpreted as utf-8 characters and console.log will show the corresponding symbols

to see the received bytes you can use an Buffer object, so in your nodejs program change the client.on function to show the received bytes.
 

///// nodejs (OLD) works for ASCII ////////////////////////////////////

client.on('data', function(data) {
    console.log('Received: ' + data);    <--- received data are ASCII coded so console.log can show them as STRING
    client.end();
});

///// nodejs (NEW) ////////////////////////////////////

client.on('data', function(data) {
    let buff= Buffer.from(data);
    console.log(buff);                            <--- Buffer object hold the received Bytes, console.log show the received Bytes
    client.end();
});

 


 

 

 

1 person likes this

Share this post


Link to post
Share on other sites

@AndreasW I put the received data into Buffer. I got numbers:  176,91,16.This is frame message in binary code, not the stored data I guess. This is my request string: 01FF000A522000004E200900.

I attached photo of the PLC settings what it should read and you can see what the received data was when PLC was set to ASCII. Now with binary I got above 3 numbers.

Do you know how I can convert the numbers to get the numbers in PLC's current values column? Thank you

4.PNG

Edited by DavidOtt

Share this post


Link to post
Share on other sites

hi David Ott,

the response 91,16 (5Bh, 10h) is an error code, i think this is because the request you send to plc is wrong;
-> could you show me the Request you send to PLC (for binary)?

for your request string "01FF000A522000004E200900" (in ASCII) this should be something like:

let sndBuff= new Buffer([1,255,0,10,0,0,78,32,82,32,9,0]);
client.write(sndBuffer, ()=>{
                timeout= setTimeout(()=> {
                    console.debug('error: timeout occured, no data received for last ReadRequest');
                    EndConnection();
                }, 1500);

 

be aware that the position of the device code and the head device are switched in the binary version, see page 124 in the
SLMP manual https://dl.mitsubishielectric.com/dl/fa/document/manual/plcf/jy997d56001/jy997d56001j.pdf

 

 

Edited by AndreasW

Share this post


Link to post
Share on other sites

Hi @AndreasW  If I use your lines above (sndBuff, I changed at client.write(sndBuffer) to sndBuff)  the app receives data from PLC => Buffer.from(data) = 129,86. These 2 numbers are received. Do you know how I can convert to the original data as in PLC? Thank you

Edited by DavidOtt

Share this post


Link to post
Share on other sites

hi david ott,

if you receive 192, 86 (81h, 5Bh) this is the error code, because the send request is wrong,
i forgot that the send buffer also need the data in high order, to receive R20000 and following register use
the following send buffer:

let sndBuff= new Buffer([0x01, 0xFF, 0x0A,0x00, 0x20,0x4E,0x00,0x00,  0x20,0x52,   0x09,0x00]);

0x01 ... command: batch read word units
0xFF ... pc-no
0x0A, 0x00 .... timeout (000Ah)
0x20, 0x4E, 0x00, 0x00 .... start adress (00004E20h .... = 20000)
0x20, 0x52 .... register type (5220h = R-Register)
0x09 .... number of register to read
0x00 ... endcode


inside the receive function you have to convert/combine the received bytes to an 16 bit value (signed/unsigned, depending on the data type used in the plc)
Therefore you can use an Int16 Array or an UInt16 Array.

 

client.on('data', function(data) {
    let buff= Buffer.from(data);
    console.log('Received: ');
    console.log(buff);

    const int16array = new Int16Array(
        buff.buffer,
        buff.byteOffset,
        buff.length / Int16Array.BYTES_PER_ELEMENT);
    console.log(int16array);

    const uint16array = new Uint16Array(
        buff.buffer,
        buff.byteOffset,
        buff.length / Uint16Array.BYTES_PER_ELEMENT);
    console.log(uint16array);

    let value1= (buff[3] << 8 ) | buff[2];
    let value2= (buff[5] << 8 ) | buff[4];
    console.log('value1=' + value1);
    console.log('value2=' + value2);

    client.end();
});

 

Share this post


Link to post
Share on other sites

Hi @AndreasW It's working. Thank you very much.

I'm trying the same way wirting to PLC. So far this is what I have:

I need to write 2-2-2 digits numbers to R19990~R19992, numbers are between 0-99 in decimal.
```var writeBuffer = new Buffer.from([0x03, 0xFF, 0x0A, 0x00, 0x16, 0x4E, 0x00, 0x00, 0x20, 0x52, 0x03, 0x00, input1format, input2format, input3format]);```

Where input1format (2,3 too) are string: '0x0'+input if input length is 1 and if input length is 2: '0x'+input. Input is the hexadecimal conversion of the 2-2-2 digits.

I also need to write to R19999(writeMachineBuffer), I don't know if I can do that together with R19990~R19992 writing. So I would have 2 client.write. One with writeBuffer and another one with writeMachineBuffer. Can I do that or I should write once from R19990~R19999 and having 0x00 for R19993~R19998.

Thank you for all your help.

1215-2.PNG

Share this post


Link to post
Share on other sites

Hello David Ott,

if there are only 10 registers you can of course simply write zero to the other registers (R19993-R19998) if these registers are not used in the PLC.
If you do this, you should mark the registers as used/written in the device comments of the PLC, so that they are not accidentally used later.

Alternatively you can use the function Test(Wrandom Write) to write only the selected registers,
see page 133 in the SLMP manual
https://dl.mitsubishielectric.com/dl/fa/document/manual/plcf/jy997d56001/jy997d56001j.pdf


In both cases the values written are 16 Bit, that mean you have to write two bytes for each value (high byte and low byte, in the order LOW, HIGH).

i.e. if the value to write is <= 255 (decimal) => High-Byte= 0x00,
"var writeBuffer = new Buffer.from([0x03, 0xFF, 0x0A, 0x00, 0x16, 0x4E, 0x00, 0x00, 0x20, 0x52, 0x03, 0x00, input1format, 0x00, input2format, 0x,00, input3format, 0x00]);"

if the value is > 255 the corresponding high byte must be written

e.g. 16.589 (dec) = 40CD(hex) => 0xCD, 0x40


 

1 person likes this

Share this post


Link to post
Share on other sites

Hi @AndreasW 

Thank you for your advice. You wrote if value > 255 it should be in hexa. The buffer starts with 0x01, 0xFF, 0x0A, 0x00. Why 10 is written in hexa as 0x0A? It's less then 255. Also the R19999 register: 0x1F, 0x4E, 0x00, 0x00, 0x20, 0x52, where the R is 5220 which is larger than 255, but it was just split up and swapped. For 19999, hexa is used.

I realized that I have to use Test(Wrandom Write) as you recommended too. I need to use registers R19990~R19999, but I cannot overwrite data in register with 0x00, I should leave data in register if there is data. I need to create 3 different writings: 1. machine 1 is used write to R19990~R19992 and R19999 or 2. machine 2 is used write to R19993~R19995 and R19999 or 3. 1 and 2 machines are used together write to R19996~R19999. If R19990~R19992 and R19999 is written, app should not overwrite data in R19993~R19998

I.e if input1 = 22, input2 = 40, input3 = 04 and machineUsed = 1

I cannot do this:

new Buffer.from([0x03, 0xFF, 0x0A, 0x00, 0x16, 0x4E, 0x00, 0x00, 0x20, 0x52, 0x10, 0x00, 0x22 (input1), 0x40 (input2), 0x04 (input3), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 (machineUsed)]);

On page 133 in FX5 documentation it is not clear for me if R19990~R19992 and R19999 is written:

Number of devices for this example would be (R19990~R19992 and R19999) 2(?) or (R19990 and R19991 and R19992 and R19999) 4(?)

My Test(Wrandom Write) would be as on page 133 and as I thought:

new Buffer.from([0x05(subheader), 0xFF(PC No.), 0x0A, 0x00 (monitoring time in 2 parts), 0x04(number of devices?), 0x00 (fixed value),0x16, 0x4E, 0x00, 0x00 (head dev.# in 4 parts), 0x20, 0x52 (device name in 2 part), 0x00, 0x22 (input1 in 2 parts), 0x17, 0x4E, 0x00, 0x00 (head dev.# in 4 parts), 0x20, 0x52 (device name in 2 parts), 0x00, 0x40 (input2 in 2 parts), 0x18, 0x4E, 0x00, 0x00 (head dev.# in 4 parts), 0x20, 0x52 (device name in 2 parts), 0x00, 0x04(input3 in 2 parts),0x1F, 0x4E, 0x00, 0x00 (head dev.# in 4 parts), 0x20, 0x52 (device name in 2 parts), 0x00, 0x01(machineUsed in 2 parts),]);

 

write.png

Share this post


Link to post
Share on other sites

hi david ott,
 

you wrote:

My Test(Wrandom Write) would be as on page 133 and as I thought:

new Buffer.from([0x05(subheader), 0xFF(PC No.), 0x0A, 0x00 (monitoring time in 2 parts), 0x04(number of devices?), 0x00 (fixed value),0x16, 0x4E, 0x00, 0x00 (head dev.# in 4 parts), 0x20, 0x52 (device name in 2 part), 0x00, 0x22 (input1 in 2 parts), 0x17, 0x4E, 0x00, 0x00 (head dev.# in 4 parts), 0x20, 0x52 (device name in 2 parts), 0x00, 0x40 (input2 in 2 parts), 0x18, 0x4E, 0x00, 0x00 (head dev.# in 4 parts), 0x20, 0x52 (device name in 2 parts), 0x00, 0x04(input3 in 2 parts),0x1F, 0x4E, 0x00, 0x00 (head dev.# in 4 parts), 0x20, 0x52 (device name in 2 parts), 0x00, 0x01(machineUsed in 2 parts),]);

 

this should be Ok except for the data values, but should write R19990- R19992 and R19999.
i think for the inputvalues you have to switch the order of the High and the Low Byte:
e.g.
input1 = 22 (dec) = 16 (hex)  --> 0x16, 0x00 (input1 in 2 parts)
input2 = 40 (dec) = 28 (hex)  --> 0x28, 0x00 (input2 in 2 parts)
input3 = 04 (dec) = 04 (hex) --> 0x04, 0x00 (input3 in 2 parts)
...

new Buffer.from([0x05, 0xFF, 0x0A, 0x00, 0x04, 0x00  ,0x16, 0x4E, 0x00, 0x00 , 0x20, 0x52 , 0x16, 0x00 , 0x17, 0x4E, 0x00, 0x00, 0x20, 0x52, 0x28, 0x00,  0x18, 0x4E, 0x00, 0x00 , ....

 

If your input is a decimal number and if you don't want to convert it to a hex number you also can use the decimal number as input
for the buffer, then just leave out the "0x" at the beginning.
input1 = 22 (dec) =  22, 0 (input1 in 2 parts)
input2 = 40 (dec) = 40, 0 (input2 in 2 parts)
input3 = 04 (dec) = 4, 0 (input3 in 2 parts)

new Buffer.from([0x05, 0xFF, 0x0A, 0x00, 0x04, 0x00  ,0x16, 0x4E, 0x00, 0x00 , 0x20, 0x52 , 22, 0 , 0x17, 0x4E, 0x00, 0x00, 0x20, 0x52, 40, 0,  0x18, 0x4E, 0x00, 0x00 , ....
 

 

regarding the value 255: that was only a hint, which is about the High Byte. If the value is in the range 0-255 (dec) the high byte is 0 and the low byte is equal to the value,
therefore it can be written in the buffer as [VALUE, 0] as above. For values > 255 (dez) it is easier to represent the number hexadecimal, because you can directly see the
high/low byte. e.g. 16589 (dec) = 40CD(hex) => Low-Byte= 0xCD, High-Byte= 0x40

 

 

 

 

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