Boss Mode: 100 Millisecond Tag History In Ignition
It seems like Bill has been moving from one top secret project to another! On one really large machine, he encountered a problem a couple of months ago. After some Corso ingenuity, he was able to put together a really elegant solution. Remember to give Bill a round of applause so he continues to share his expertise!!
For a recent project, Corso was tasked with capturing the history of 12 key process values for a high precision machine at a rate of 100ms. Ignition’s built-in Tag Historian was fairly adequate in storing history at this rate but would occasionally miss a scan class execution. Our solution was to leverage the system.tag and system.opc APIs in a Gateway timer script to read the values directly from the PLC and write them to the historian database “manually.”
To illustrate the problem, I’ve put together a simple PLC program that increases the tag values at a constant rate. Tag1 increases by .1 every scan, Tag2 by .2, etc. This should result in a chart with relatively even steps every 100ms when the values are trended.
The traditional approach is to simply create 12 OPC tags, give them 100ms scan classes and enable tag history. As you can see from the chart, there are occasional gaps of more than 100ms between values and we don’t see the even climbing steps that we would expect.
As always, there is more than one way to solve this problem in Ignition. In this case, we found a Gateway timer script running at 100ms to be the best solution. The key functions in the script are system.opc.readValues to read values directly from the PLC over OPC without relying on internal tags and system.tag.storeTagHistory to store tag history on-demand.
if system.tag.read('Process/Run').value: #only collect history while process is active
opcServer = 'Ignition OPC-UA Server'
opcPaths = [
'[S7 Desk]DB1,REAL2.0', #Tag 1
'[S7 Desk]DB1,REAL6.0', #Tag 2
'[S7 Desk]DB1,REAL10.0', #Tag 3
'[S7 Desk]DB1,REAL14.0', #Tag 4
'[S7 Desk]DB1,REAL18.0', #Tag 5
'[S7 Desk]DB1,REAL22.0', #Tag 6
'[S7 Desk]DB1,REAL26.0', #Tag 7
'[S7 Desk]DB1,REAL30.0', #Tag 8
'[S7 Desk]DB1,REAL34.0', #Tag 9
'[S7 Desk]DB1,REAL38.0', #Tag 10
'[S7 Desk]DB1,REAL42.0', #Tag 11
'[S7 Desk]DB1,REAL46.0' #Tag 12
] # "virtual" tag paths, these tags do not exist
tagPaths = [
] historyProvider = 'db'
tagProvider = 'default' #may be a "virtual" provider
historyPaths =  historyTimestamps =  historyQualities =  historyValues =  #using a single timestamp for all tags results in cleaner data when exporting to Excel or .CSV
timestamp = system.date.now()
opcValues = system.opc.readValues(opcServer, opcPaths)
for i in range(len(opcValues)): #collect tag values and qualities
quality = opcValues[i].quality
qualityValue = 192
qualityValue = 0
#write to the historian!
system.tag.storeTagHistory(historyProvider, tagProvider, historyPaths, historyValues, historyQualities, historyTimestamps)
Together, these functions allow us to quickly gather the process values and write them to the historian database. The result is nearly perfectly timed values and the uniform steps that we wanted to see.
A nice feature of storeTagHistory is that it works with “virtual” tags and tag providers, meaning the tags do not need to exist. This means we can delete the OPC tags from the traditional approach or at least disable tag history and put them on a slower scan class.
Enjoy what Bill put together? Check out more Boss Mode Posts!
Ready to take your whole system to the next level? Check out Corso’s Ultimate MES Guide.
Learn more about Inductive Automation’s Ignition.