Modbus UINT16 to decimal?

Hello, I've got a rotation sensor that is returning values via Modbus through a Mitsubishi PLC, and the PLC programming software is calculating and displaying decimal values for a rate in the range 0.2m3/hr to 3 decimal places and stored as FLOAT [Single Precision]. However, when the numbers get to node-red, they're completely different. I'm putting them through buffer parser and have to set that to UINT16 to get the same numbers output.

I'm sure there must be some sort of formula I have to put them through, but I'm not sure what I'm dealing with... unsigned 16-bit integers that are off by orders of magnitude and seem to switch between very specific numbers?

Here's an example of what I'm getting in node-red, along with equivalent (?) numbers that appear in GXWorks 3 PLC programming software. The numbers seem to switch between these very specific values.

64367
63073
57743
49504 = 0.241
46955
41496 = 0.165
36895
32901
32108 = 0.229
28867 = 0.157
18032
15187 = 0.143
13265 = 0.129
455 = 0.149
4700, 7247 = 0.228

Has anyone seen weird numbers like this from Modbus and know what sort of formulae are required? This thread is relevant; the problem is superficially similar to my previous thread about getting garbage from Modbus in node-red, but is probably a different problem.

At least I'm getting numbers (albeit wrong ones) rather than nothing from the buffer parser node.

Your problem could be a number of things.

Typically though, what happens with PLC values is you or reading across the bounds of two different values or the data is byteswapped (little vs big endian).

The easiest way to solve this is to read from a unused area in the PLC. Enter known values directly into the PLC and check the buffer parser outputs what your expect.

More often than not, you need to byte swap or in the case of non IEE 754 compliant data, extract the exponent and whole parts manually.

Lastly, in mitsubishi PLC, the default for values is signed data. So any 16 bit number that goes above 32767 suddenly becomes a negative value, but when read as an unsigned integer, it does not.

If you can capture real data coming from the modbus node (use the debug copy value button) and provide the exact expected value, I'll show you how to use the buffer parser

Seeing the value in the PLC will also help me.

1 Like

Following this :+1:

Thank you for your help!

Slightly frustratingly, I've tested reading several other known-value registers from the PLC, and e.g. 60 is broadcast for temperature, and 60 is received, no conversion/buffer parser needed.

Updated values read:

gfuel_flow_rate, left = node-red, right = GXW3

64367
63073
60645 = 0.240
57743
49504 = 0.241
46955
29258 = 0.166
41496 = 0.165
36895
32901
32108 = 0.229
28867 = 0.157
18032
15187 = 0.143
13265 = 0.129
708, 9444 = 0.232
455 = 0.149
4700, 7247 = 0.228
5287 = 0.166

Trimmed to useful values, sequential by real number:

gfuel_flow_rate

m3/hr

node-red (displayed value before buffer parser, unknown format) GXWorks3 output (expected value, FLOAT [Single Precision])
49504 0.241
60645 0.240
32108 0.229
4700, 7247 0.228
708, 9444 0.232
5287, 29258 0.166
41496 0.165
28867 0.157
455 0.149
15187 0.143
13265 0.129

Exact expected values are those seen in GXW3. Modbus node output is sequential as it is fed with a large data structure of available devices, and is just a single-number array. It looks like the 0. might be throwing node-red off.

Sorry, it is unclear what you are saying.

Is there a problem or not?

PS, tables are supported in markdown, making it much easier to read

e.g...

GXWorks | Node-red | Expected Value / Type | Info
------- | -------- | --------------------- | ----
49504 | 49504 | 0.241 | buffer parser type set to UINT16 & scale of `/1000` - working ok
60645 | 60645 | 0.240 | buffer parser type set to UINT16 & scale of `/1000` - working ok

becomes

GXWorks Node-red Expected Value / Type Info
49504 49504 0.241 buffer parser type set to UINT16 & scale of /1000 - working ok
60645 60645 0.240 buffer parser type set to UINT16 & scale of /1000 - working ok
1 Like

I have reformatted the data. Issue is node-red seems to be reading single precision floats as garbage (albeit consistent sequential garbage), whereas all other modbus output numbers are read as exported from the PLC without any problems or buffer parsing. I was just wondering if there was a known number format that node-red used in such situations or whether the existing numbers looked like a known particular format that I could apply a transformation formula to? I can't see any pattern.

As explained before, the reason they will be garbage will be because of how you address the values.

So if you can provide the right info I can show you how to do this properly.

  • I will need a capture of data coming out of the modbus node (use Copy Value button)
  • I will need you to tell me what the value(s) are supposed to be.

So something like

Value in PLC PLC Data Type Value seen in Modbus Expected value after parsing
65000 UINT16 65000 6.5
1234567.89 Float [46143,18838] 1234567.89

How to copy value

chrome_MD52DtN5Eo

1 Like

That makes sense; apologies for misunderstanding. I will post it here:

gfuel_flow_rate

Double numbers given for some numbers as I have observed both to appear in node-red while the PLC monitoring software GXW3 reports only one value. The numbers are definitely not random/read from the wrong place, as they consistently appear at the same time. I'm not sure if that's all the info required; a colleague who was also helping was saying that the hex values would probably be useful, but the software doesn't have an easy way of monitoring them so I would have to convert the numbers back to hex and hope I didn't mess it up if needed

Value in PLC (read from GXW3, m3/hr) PLC Data Type Value seen in Modbus Expected value
0.241 Float [Single Precision] 49504 0.241
0.240 Float [Single Precision] 60645, 16420 0.240
0.229 Float [Single Precision] 32108 0.229
0.228 Float [Single Precision] 4700, 7247 0.228
0.232 Float [Single Precision] 708, 9444 0.232
0.166 Float [Single Precision] 5287, 29258 0.166
0.165 Float [Single Precision] 41496 0.165
0.158 Float [Single Precision] 35228 0.158
0.157 Float [Single Precision] 28867 0.157
0.149 Float [Single Precision] 455 0.149
0.143 Float [Single Precision] 15187 0.143
0.129 Float [Single Precision] 13265 0.129

Screenshots




1 Like

I found this thread: Modbus 16 bit registers to Float value that sounds quite like my issue, but haven't had much luck copying the measures from that thread.

I'm currently experimenting with reading the hex buffer from the Modbus node.

This thread is also similar to my issue: How to Decode 16 Bit signed Integer

If you dont provide REAL SAMPLE data I cannot assist you.

1 Like

I must apologise if I have misunderstood, the sample data is real, directly from running systems. Not simulated.

Do you mean like this?

screen recording GIF on Imgur
Or are you asking for the HEX output of the Modbus buffer?

What I have done so far is this:

screen recording GIF on Imgur

(Imgur seems to have flagged engineering software as 18+ NSFW, not sure why)

In order to develop a solution for you, I need actual data captured using the copy value button and for it to be posted into a reply as text (JSON) (not a screenshot).

The reason for this is I will simulate your device (something I do not have access to) by taking the ACTUAL data that you post and injecting it into a demo flow.

1 Like

The screenshots were not data, only illustrative of my data acquisition process(es), as I'm not sure if we're talking about getting it from the same place.
My Modbus-flex-getter node is outputting numbers like I previously posted (though if I remember rightly the previous data went through buffer parser set to UINT16), just with square brackets around them. I'm not sure how I can make the data any more real than that. As it is multiplexing across many different devices, I have to use a switch to select individual data streams, all of which are configured the same and all of which, bar one, work perfectly. e.g. like the following, from the malfunctioning gfuel_flow_rate data stream:

[41496]
[65061]
[41496]

The buffer output from the Modbus-flex-getter is different, but I'm not sure if that is what you're asking for, hence the screen recordings :cry:

{"data":[41496],"buffer":[162,24]}
{"data":[65061],"buffer":[254,37]}
{"data":[65061],"buffer":[254,37]}

Screen recording

NB. data not copied directly from Modbus node debug because there are 6 simultaneous data streams and I can't pause the node-red debug log or move fast enough to copy the relevant part...
Screenshot_23-08-17-162648

Well slow it down then, and/or run it on just one stream initially.

1 Like

Or send it through a Delay node set to Rate Limit to 1 every 20 seconds, with Drop Intermediate messages, then feed that into the debug node.

1 Like

@Darren, no need for the apologies. And don't worry, this will all fall into place very soon (you are getting close - and you will learn lots in the process - so its all good)

This :point_up: is what I need - BUT - what are they supposed to be parsed to? Are these the first 2 from your list?

Value in PLC (read from GXW3, m3/hr) PLC Data Type Value seen in Modbus Expected value
0.241 Float [Single Precision] 49504 0.241
0.240 Float [Single Precision] 60645, 16420 0.240


One more thing: Single precision floats are typically 32bit values. Can you confirm if the PLC occupies uses 2 16 bit WORDS to hold the float values?

If they are 32 Bit, you need to request a length of 2 in the ModBus data.
In case you are not aware, ModBus always delivers 16 bit data. Thats why floats can be a pain. It doesnt help when the PLC or interface swaps bytes and doesnt adhere to IEE floats.
That isnt really a worry but it is important to know what size the data is in the PLC.

If you dont know, identify the function in the PLC writing to the address & I will tell you.



Back to the data for parsing:

Let me try to make this clearer :crossed_fingers: .

I need:

  1. The ACTUAL ModBus payload (you did this when you copied the full payload value - great!)
  2. At the EXACT SAME TIME - I need the ACTUAL equivalent matching value from the PLC - so that I have both the source (ModBus) data AND a target value to achieve - so I can check my work and ensure you get accurate data.

Does that make sense?

1 Like

Understood now! Thank you! I will enter the data here:

Expected value Modbus
0.165 {"data":[41496],"buffer":[162,24]}
0.229 {"data":[32108],"buffer":[125,108]}
0.201 {"data":[56615],"buffer":[221,39]}
0.235 {"data":[11439],"buffer":[44,175]}
0.228 {"data":[52312],"buffer":[204,88]}
0.164 {"data":[65061],"buffer":[254,37]}
0.228 {"data":[7247],"buffer":[28,79]}
0.165 {"data":[65061],"buffer":[254,37]}
0.164 {"data":[60204],"buffer":[235,44]}

That is the data from the monitoring software with the concurrent Modbus reading. Strangely, for the same expected value, there are multiple (but consistent) Modbus readings.


I must admit, it skipped my mind to remove the other data streams; however, I believe the switch implemented serves much the same purpose to separate them out. I didn't think to use a delay note to rate limit things. I think I've got it working now, though. Thank you for the advice

A colleague did mention Modbus output only 16bit, wheras I have read on StackOverflow that JS only uses 32bit by default. I'm looking through the PLC documentation, though in the "Data Type Selection" there are Double Word [Unsigned]/Bit String [32-bit], Word [Unsigned]/Bit String [16-bit], Word [Signed], Double-Word [Signed] as well as FLOAT [Single Precision]

Before I do this, please clarify the size of data in PLC:

Its just that you have provided 1 WD (2 byte) data for each "Expected value" and typically, single precision floats are 32bit (2 WDs / 4 bytes) and this will be key (critical) to getting this right.

1 Like