OPC questions - differences between opc.readValue and tag.read

I have some specific questions regarding how the OPC server is working behind the scenes and the recommend methods for scripting when reading/writing OPC tags.

  • Is the sample handshake analysis below correct?
  • tag.read/write will read/write values from the OPC server, whereas system.opc.readValue/writeValue will force interaction with the data source (opc server connection) - is this accurate?
  • How can you 100% guarantee data in system.tag.read is accurate - or is the only guarantee system.opc.readValue? Is it normal to see people exclusively using system.opc.* in scripts?
  • Is there a list of OPC best practices that IA has compiled over the years?

Sample Handshake

The OPC server scans for updated information and based on the scans, updates its internal OPC server memory map.

Ignition and the system.tag.read/write commands interface with the block of memory stored on the OPC server - increasing the systems speed - but since actions are async so there is no guarantee that the event actually occurs. So if the handshake shown below was implemented, it would fail some times (or every time). Because at step 6, ACK_Complete is low, getting set to high, IA will write the bit and immediately look for it to be low (step 9). It will start looking for a low bit prior to the PLC doing any action. Sometimes the handshake will work, other times it won’t (probably won’t?).

The tag in Ignition and the node in the OPC server are completely decoupled.

system.tag.read will just give you the current value in memory for the Ignition tag.
system.tag.write will write to the Ignition tag, which in turn causes a write to the OPC server to happen if it’s an OPC tag.

system.opc.read bypasses Ignition’s tags altogether and just sends a read request to the OPC server.
system.opc.write bypasses Ignition’s tags algotether and just sends a write request to the OPC server. If successful and there’s an Ignition OPC tag pointing at any of the nodes in the write, those tags will eventually receive the updated value through the normal OPC subscription mechanism.

Is there a process or procedure to guarantee every read/write has happened on the PLC hardware before moving onto the next step?

This psudo code procedure doesn’t seem reasonable for every write.
write Tag1 = 1
while (read Tag1) != 1:
.... sleep

Using system.opc functions is the best you can do. There’s no such thing as a guarantee. Any PLC can report that the write was successful, and while that’s usually good enough, the only way you can verify the value is to read it. Even if the write didn’t fail, another write or some logic in the PLC could change the value after the value you wrote.

Is there any documentation that IA has compiled over the years that provide best practices for setting up OPC-UA handshakes?

No, but I’m sure some of our forum users can jump in and share what’s worked for them.

(That’s your queue, guys… :wink: @pturmel maybe?)

The only way to know for sure that a specific write to the PLC has occured is to use system.opc.writeValue and examine the status it returns. Even better is to use different addresses in the PLC for reads and writes. I generally prefer to use odometer-style integers as triggers for critical handshakes, in both directions. When a block of data needs to go to the PLC, I have Ignition write all but the trigger via system.opc.writeValues(), and if all succeeded, increment and write a trigger with system.opc.writeValue(). The PLC does the same with another set of variables and a trigger integer. An Ignition tag monitor’s the PLC->Ignition trigger for scripted operations, or a transaction group’s trigger points at it. The remaining PLC->Ignition data is read after the trigger is detected, either with system.opc.readValues(), or by the transaction group (in OPC Read mode).

Depending on how much data is being moved, I have:

  • Concatenated the data into a single string with delimiter of choice (I work a lot with strings, part numbers, serial numbers, etc). Handshake the string back to the PLC then increment the trigger (an integer, like Phil mentioned). The transaction group splits it back out into the individual data points.
    Advantage: only one tag to monitor for matches. Generally adaptable across data types. Relatively short time to implement.
    Disadvantage: Strings are limited to 255 characters (At least on the AB driver. painful discovery, that one.:unamused:)

  • CRC all your values. Start with a seed value, shift to the left one bit, XOR in value, shift, XOR, shift, XOR, rinse, repeat. Handshake on the CRC
    Advantage: only one tag to monitor for handshake. Adaptable for different data types.
    Disadvantage: Long time and more difficult to implement. Especially on the PLC side of things

Been thinking on a simple hash system, but alas, unlike the song by the Stones, time is not on my side.

Masochist, eh? But who am I to talk – my primary laptop runs gentoo. (-:

Traceability is a harsh mistress…