How to Read Tags from Rockweell PLC Fast? Or how do it RSLinx?

i can see where you are sending them in groups. It looks like you are getting the data back from the PLC so I would suspect the application code. Are you unpacking in a different thread? Just a question. Not sure what the issue is. How is the performance if you only send one group? Tags 0-14.

Perfomance of one packet request is ~ 6-10ms (direct ethernet connection to PLC).

My code works in one thread (paralell to my main thread).
Idea of request is look for most old updated tags (dateTimeNow - lastUpdatedTime>= myRequiredUpdateRate) and group it to Multiply Service Request. But by experimental was Found some limits:

const int MAX_BYTES_IN_REQUEST = 248; - It max byte size of MessageRouterRequest
const int MAX_ITEMS_IN_REQUEST = 14; - Items in request

If limits will exceed than PLC not answer.
 
Last edited:
Thank you so much! Just after 10 min I will try it!
But for For clarification, I meant if there are 250 tags, then the packets will be sent.
#1. (tags 0 ... 14).
#2. (tags 15 ... 30).
....
# N. (tags 235 ... 250)
270ms is the time to return the update package # 1.
PLC time reply is ~6ms.
The BeginReadMultiple would require that you figure out what the maximum you can fit into a single read. Basically by trial and error.

If you were to use subscriptions with the AdvancedHMI driver, it becomes more efficient because it will calculate the maximum number of tags it can fit into a single request packet. That is where the driver will give the best performance. If you wanted to see that, simple add a DataSubscriber2 to the form and add tags to the PLCAddressValueItems property. From my experience, I would dare guess that if RSLinx does it in 40ms, the AdvancedHMI subscriptions of the same tags would be in the 20-30ms range.
 
Perfomance of one packet request is ~ 6-10ms (direct ethernet connection to PLC).

My code works in one thread (paralell to my main thread).
Idea of request is look for most old updated tags (dateTimeNow - lastUpdatedTime>= myRequiredUpdateRate) and group it to Multiply Service Request. But by experimental was Found some limits:

const int MAX_BYTES_IN_REQUEST = 248; - It max byte size of MessageRouterRequest
const int MAX_ITEMS_IN_REQUEST = 14; - Items in request

If limits will exceed than PLC not answer.

Thank you for information!
Will it same structure for Forward Open like ServiceCode = 0x54?
Will it works for CompactLogix (v18.11)?
Is it possible to find some documentation?

I would recommend that you strip out any logic and test for read requests and receipt and unpack only. Set it so it runs at a fairly brisk pace. Then do the other stuff. The forward open requests are different array sizes, plus there are other types of forward open requests such as hopping through the backplane onto another enet card or onto a controlnet card and out to another PLC. It requires that cryptic path statement. Tricky stuff.

Also tags that have "[]" characters and dot separators nested down in UDTs can be tricky to group. Sounds like you are far along though. You can find the forward open request stuff around in places. Setting bits within integers. Reconnecting automatically etc, etc, etc.
 
I just looked at your tag list. Is it just 250 consecutive elements of a DINT array? If so, you do not need to read each tag individually. Specify the first element, then the number of elements. Then you will only need as few as 1 request packet, then you will get a partial packet response if the data doesn't all fit

It looks like you get about a 5ms round trip, so the longest this should take is 15-20ms, unless you are reading strings.
 
Last edited:
I did a test to see how long it should really take by using a CompactLogix and reading 256 DINTs from an array. Total Read time is 16.1ms

In the Wireshark capture, the read starts at packet 0 and the final data is returned in packet 9.
 
Since you mentioned C# I assume you already have and use Visual Studio. Here is a test that will take you less than 10 minutes to try. I will be surprised if this tag reading is not faster than RSLinx:

1) Download and extract the latest AdvancedHMI. Get the beta version from here:
https://www.advancedhmi.com/forum/index.php?topic=2058.120

2) Open the AdvancedHMI solution in Visual Studio
3) Build the solution
4) Open the MainForm
5) From the Toolbox, add an EthernetIPforCLXCom to the form
6) Set the IPAddress property
7) Double click the form to get to the Load event handler.
8) Enter this code (modifying the tag list to your tags:
Code:
        Dim Tags(2) As String
        Tags(0) = "Tag1"
        Tags(1) = "Tag2"
        Tags(2) = "Tag3"

        EthernetIPforCLXCom1.BeginReadMultiple(Tags)
9) Then add this code to handle the DataReceived event:
Code:
    Private Sub EthernetIPforCLXCom1_DataReceived(sender As Object, e As Drivers.Common.PlcComEventArgs) Handles EthernetIPforCLXCom1.DataReceived
        Console.WriteLine(e.PlcAddress & "=" & e.Values(0))
    End Sub
10) Run the application and see how fast it reads and returns the data

You may want to add a system clock time stamp before calling the read and at each return of data so you can see the speed in the console window. If you had written your own C# driver, I will not go into details of how to do that.

Thank you so much! I did it! For 3 tags multiply service response is 6,3 ms.
In my application the same response, but it also very useful to see.
 
I did a test to see how long it should really take by using a CompactLogix and reading 256 DINTs from an array. Total Read time is 16.1ms

In the Wireshark capture, the read starts at packet 0 and the final data is returned in packet 9.

Very interested! For Fragment Tag Read is clear for me, but not so convenient for me, because target is collect any tags from Controller tags and from different structures.

I saw on your Wireshark capture that at first request to PLC there is request With service 0x4C, but Data at the end of packet is "00 01". Could you explain me what it means? Usually is "01 00" - is "Number of elements to read (1)".
*******************************************
I tried to test two request for tag ARR_S (is SINT array).

1. Data is "01 00" as writed in documentation -> Result: I got just first element of array.
2. Data is "00 01" what is very interested for me -> Result: I got all array in responce... o_O
 
Last edited:
Very interested! For Fragment Tag Read is clear for me, but not so convenient for me, because target is collect any tags from Controller tags and from different structures.

I saw on your Wireshark capture that at first request to PLC there is request With service 0x4C, but Data at the end of packet is "00 01". Could you explain me what it means? Usually is "01 00" - is "Number of elements to read (1)".
00 01 = 0x0100 = 256
The number of elements to read. In my test I read 256 elements of the array.

Dim data() as string = EthernetIPforCLXCom1.Read("ARR_S[0]",256)
 
Reasons why PLC manufacturers would have to think about incorporating OPC UA natively to their products:

- Message size up to 4 MB
- Client and server previously negotiate maximum message size and buffer.
- If the buffer is smaller than the message, the protocol sends it in several chunks
- Encryption
- And the best of all: with full extensive documentation available for free (not as Ethernet/IP and Rockwell)
 
Reasons why PLC manufacturers would have to think about incorporating OPC UA natively to their products:

- Message size up to 4 MB
- Client and server previously negotiate maximum message size and buffer.
- If the buffer is smaller than the message, the protocol sends it in several chunks
- Encryption
- And the best of all: with full extensive documentation available for free (not as Ethernet/IP and Rockwell)

That would be amazing if every major PLC manufacturer would adopt an open standard for an internal data server.
 
Hello everybody! I just study mechanism of RSLinx excange with PLC and tryed to repeate this, something I understand.

I just made comments in my code, I think it would be clear.


// **************************************************************************************************
// [STEP 1]: "CREATION OF CLASS 0xB2".
// *** I suppose that is like a buffer or memory space in PLC.
// **************************************************************************************************
// Request:
request = new MessageRouterRequest();
request.ServiceCode = (byte)CIPCommonServices.Create;
request.RequestPath.Segments.Add(new EPathSegment(EPathSegmentHeader.Local_ClassID, 0xB2));
request.RequestPath.Segments.Add(new EPathSegment(EPathSegmentHeader.Local_InstanceID_16bit, 0x0000));
request.RequestData.Add(0x01); // <- what is it???
request.RequestData.Add(0x00); // <- what is it???
request.RequestData.Add(0x03); // <- what is it???
request.RequestData.Add(0x00); // <- what is it???
request.RequestData.Add(0x03); // <- what is it???
request.RequestData.Add(0x00); // <- what is it???
List<object> objects = eipClient.SendUnitData(request);

// RESPONSE: Success
// PLC Answer by Data: 21 00 f8 d4 0c 00 // <- what is it???


// **************************************************************************************************
// [STEP 2]: "ADD TAG TO CLASS 0xB2, INSTANCE 0x0021".
// **************************************************************************************************
request = new MessageRouterRequest();
request.ServiceCode = 0x4E; // I think is service for add/associate tag in 0xb2 class.
request.RequestPath.Segments.Add(new EPathSegment(EPathSegmentHeader.Local_ClassID, 0xB2));
request.RequestPath.Segments.Add(new EPathSegment(EPathSegmentHeader.Local_InstanceID_16bit, 0x0021));
request.RequestData.Add(0x02); // <- what is it???
request.RequestData.Add(0x00); // <- what is it???
request.RequestData.Add(0x01); // <- what is it???
request.RequestData.Add(0x01); // <- what is it???
request.RequestData.Add(0x01); // <- what is it???
request.RequestData.Add(0x04); // <- what is it???
request.RequestData.Add(0x00); // <- what is it???

// __________________________ Is tag epath:
request.RequestData.Add(0x03); // Segment Length of EPath = 3.
request.RequestData.Add(0x20); // CLASS:
request.RequestData.Add(0x6B); // 0x6B
request.RequestData.Add(0x25); // INSTANCE:
request.RequestData.Add(0x00); //
request.RequestData.Add(0x44); // 0x4644
request.RequestData.Add(0x46); //
eipClient.SendUnitData(request);

// RESPONSE: Success
// PLC Answer by Data: "01 00" - Is number of tag data in area of class 0xB2 (for next tags will be 0x02, 0x03 ...)


// **************************************************************************************************
// [STEP 3]: "TRY TO GET DATA OF TAG FROM CLASS 0xB2, INSTANCE 0x0021".
// **************************************************************************************************

request = new MessageRouterRequest();
request.ServiceCode = 0x4C;
request.RequestPath.Segments.Add(new EPathSegment(EPathSegmentHeader.Local_ClassID, 0xB2));
request.RequestPath.Segments.Add(new EPathSegment(EPathSegmentHeader.Local_InstanceID_16bit, 0x0021));
eipClient.SendUnitData(request);

// RESPONSE: Success
// PLC Answer by Data: "01 00 ee ee ee ee"
// where 01 00 - number of tag in class 0xb2
// ee ee ee ee - is Value of DINT tag.
 
Hello everybody! I just study mechanism of RSLinx excange with PLC and tryed to repeate this, something I understand.

I just made comments in my code, I think it would be clear.


// ************************************************** ************************************************
// [STEP 1]: "CREATION OF CLASS 0xB2".
// *** I suppose that is like a buffer or memory space in PLC.
// ************************************************** ************************************************
// Request:
request = new MessageRouterRequest();
request.ServiceCode = (byte)CIPCommonServices.Create;
request.RequestPath.Segments.Add(new EPathSegment(EPathSegmentHeader.Local_ClassID, 0xB2));
request.RequestPath.Segments.Add(new EPathSegment(EPathSegmentHeader.Local_InstanceID_1 6bit, 0x0000));
request.RequestData.Add(0x01); // <- what is it???
request.RequestData.Add(0x00); // <- what is it???
request.RequestData.Add(0x03); // <- what is it???
request.RequestData.Add(0x00); // <- what is it???
request.RequestData.Add(0x03); // <- what is it???
request.RequestData.Add(0x00); // <- what is it???
List<object> objects = eipClient.SendUnitData(request);

// RESPONSE: Success
// PLC Answer by Data: 21 00 f8 d4 0c 00 // <- what is it???


// ************************************************** ************************************************
// [STEP 2]: "ADD TAG TO CLASS 0xB2, INSTANCE 0x0021".
// ************************************************** ************************************************
request = new MessageRouterRequest();
request.ServiceCode = 0x4E; // I think is service for add/associate tag in 0xb2 class.
request.RequestPath.Segments.Add(new EPathSegment(EPathSegmentHeader.Local_ClassID, 0xB2));
request.RequestPath.Segments.Add(new EPathSegment(EPathSegmentHeader.Local_InstanceID_1 6bit, 0x0021));
request.RequestData.Add(0x02); // <- what is it???
request.RequestData.Add(0x00); // <- what is it???
request.RequestData.Add(0x01); // <- what is it???
request.RequestData.Add(0x01); // <- what is it???
request.RequestData.Add(0x01); // <- what is it???
request.RequestData.Add(0x04); // <- what is it???
request.RequestData.Add(0x00); // <- what is it???

// __________________________ Is tag epath:
request.RequestData.Add(0x03); // Segment Length of EPath = 3.
request.RequestData.Add(0x20); // CLASS:
request.RequestData.Add(0x6B); // 0x6B
request.RequestData.Add(0x25); // INSTANCE:
request.RequestData.Add(0x00); //
request.RequestData.Add(0x44); // 0x4644
request.RequestData.Add(0x46); //
eipClient.SendUnitData(request);

// RESPONSE: Success
// PLC Answer by Data: "01 00" - Is number of tag data in area of class 0xB2 (for next tags will be 0x02, 0x03 ...)


// ************************************************** ************************************************
// [STEP 3]: "TRY TO GET DATA OF TAG FROM CLASS 0xB2, INSTANCE 0x0021".
// ************************************************** ************************************************

request = new MessageRouterRequest();
request.ServiceCode = 0x4C;
request.RequestPath.Segments.Add(new EPathSegment(EPathSegmentHeader.Local_ClassID, 0xB2));
request.RequestPath.Segments.Add(new EPathSegment(EPathSegmentHeader.Local_InstanceID_1 6bit, 0x0021));
eipClient.SendUnitData(request);

// RESPONSE: Success
// PLC Answer by Data: "01 00 ee ee ee ee"
// where 01 00 - number of tag in class 0xb2
// ee ee ee ee - is Value of DINT tag.

Also I added Wireshark capture
 
Hello everybody!

I just wanted to say that I managed to reproduce the tag reading mechanism from class 0xb2, as RSLinx does. The maximum I can get 44 tags from different structures (not an array) for 6ms.

If anyone is interested in how - I can write in more detail.

At the moment, the controller does not send me more information, but in the case of RSLinx it sends more. I will understand how to do more.
 

Similar Topics

Hi everyone. Quick questions. On UnityPro, I want to open and quickly read tags from a .STA files witouth opening the program. I have 30 plc...
Replies
2
Views
103
How to read/write tags using class3 connection with omron Nx/Nj Plc? when i am seeing wireshark packets for my existing connection its shows as...
Replies
0
Views
693
Dear Friends; I am trying to read the Tag Values in excel by using VBA. I write a code but was stuck on the following error: Dim OPC Server1 As...
Replies
21
Views
6,273
Hello, Just wondering if it is possible to make internal CitectSCADA project tags available to an OPC server. (Schneider OFS). There are...
Replies
0
Views
902
Hello Everyone, I've been trying to write a python code to read input and output tags from a PLC using CIP. I found the service...
Replies
25
Views
6,091
Back
Top Bottom