From the PLC state diagnostic OPC item. Or just use a flag that the PLC sets on first scan.
I am assuming the wall clock resets on mode change?
In our case, mode change is not the only thing that indicates a "PLC screw up". So getting an unexpected counter value might have to be the screw up indicator for me.
Use either a counter or a UTC timestamp as a trigger.
If the latter, no need to write to the PLC for screw-ups. Just ignore timestamps that are more than a few minutes old.
@pturmel thank you for your guidance on this issue. Using the counter instead of the Boolean tag worked well for accurately counting and reporting parts.
What do you suggest for machine state monitoring and reporting? We currently have a Boolean tag for that as well, which is ON when machine in running and OFF when machine is down. With the logic we discussed for the part count, we are probably losing at least micro downtime events when the ignition OPC server is not able to see short periods of this RUNNING tag turning OFF.
If you need precision timestamps for on-off events, you almost certainly need to use a PLC ring buffer (array of structures) into which to place event type codes and precision timestamps. Then Ignition can monitor the ring buffer head & tail pointers and use system.opc.readValues() to grab just the new entries.
We have now implemented a PLC ring buffer in each PLC which is an array of 1000 strings. The PLC starts at buffer entry 0 and writes each new event with a signal name, value, and the EPOCH MICRO LINT for precise timestamp to the next buffer entry. Once it reaches the last entry of the buffer it circles back to entry 0 and so on. The format of the string being written to these buffer entries is signalName|value|highDINT|lowDINT. The highDINT and lowDINT come from converting the EPOCH MICROS in the PLC into two DINTs because the PLC does not allow converting a LINT to a STRING. All of this payload string formation is done in the PLC in a temp payload tag and then a CPS instruction is used to copy the payload to the buffer entry. Ignition is subscribed to each buffer entry using its OPC LOGIX DRIVER and as each entry is written to, ignition captures the payload and processes the event, inserts into DB. The PLC goes through the entire buffer in about 5 - 7 minutes.
This strategy is working ~99.999% of the time but we are seeing some payloads that are corrupt when ignition reads them. We sometimes see extra digits in the High and Low DINTs and sometimes leftover characters from previous payloads even though the PLC is absolutely clearing each and every tag that forms the payload before it writes a new payload. We have tried to troubleshoot in many different ways but cannot pinpoint the root cause.
Any feedback on this will be much appreciated.
-
Don't use strings for any of this. Use event code integers, and keep everything else in binary. The ring buffer would be an array of UDTs.
-
Use two DINTs for head and tail pointers (array subscripts).
-
Build your event in a separate instance of the array UDT, then CPS to the array at the head subscript just before updating that head subscript.
-
Do not subscribe to any part of the array of UDTs. Monitor the head subscript for changes. Read from the array using
system.opc.readValues(), with the correct subscripts for unread entries. After injecting to your DB, write the last saved event's subscript to the tail pointer. -
Stop the process if the head pointer equals the tail pointer--Ignition is too far behind.
How do you suggest we read PLC tags that have to be strings? For example, alphanumeric serial numbers and more…
If you have strings as part of the data, that's fine. But keep separate in the UDT. And if possible, define a custom string type that doesn't take so much space.
PS. The reason you shouldn't concat your data into a single long string is due to the performance cost compared to reading the individual DINTs. Same reason to keep any actual STRING tags as short as possible due to the overhead they incur
Excellent feedback @pturmel . I implemented the HEAD and TAIL pointer concept and that solved our problem of random corrupt payloads completely. Zero errors across 3MM datapoints. I suspect that ignition was scanning the tag value MID PLC SCAN when the tag was being written to by the PLC. But now since I am pulling only on demand based on the HEAD pointer, that issue is completely eliminated.
@nminchin Thank you for elaborating that. I do see the impact of reading and processing long strings. We are working towards simplifying our approach so that we only work with DINTs and use lookup tables in the DB as much as possible.