Understanding OPC Scan Time vs Execution Time

We have logic on the PLC that requires a particular data tag with a unique serial number (USN) to be populated before a separate BOOL tag (DataRequest) will be turned on. When Ignition sees DataRequest turned on, it reads the USN tag and then performs some action. At several stations, we find that when DataRequest is turned on, the USN tag is still 0 even though we know that the PLC populates the USN tag before it populates the DataRequest tag.

I can reduce the occurrence of this issue by setting the scan time for the USN tag to be significantly faster (e.g. 100ms) than the DataRequest tag (e.g. 500ms), but I’m trying to understand exactly how the Ignition OPC scans these tags so I can develop a better architecture to fit our situation.

Can anyone shed any light on the backend logic for the OPC Server and how Gateway Events and other logic responds to changes with these tags? Thanks in advance.

OPC tags are subscribed through a driver. There is no guarantee for ordering of any given update versus any other OPC item. To ensure ordering, you would need to monitor the trigger tag (OPC subscription with tag change event script) then use the system.opc.read*() functions to get values for the rest. Only an OPC read is sure to happen in order.

FWIW, a triggered transaction group set to OPC Read mode does exactly this–it subscribes to the trigger OPC item, and explicitly reads the other items after the trigger fires.

Thanks @pturmel! So if I understand this correctly, system.tag.readBlocking just reads from the OPC server, while systsem.opc.readValue will actually force a read back to the PLC. Is this correct?

Not quite, system.tag.readBlocking just reads the current value of the Ignition tag.

system.opc.readValue goes to the OPC server, and with our server/drivers will read directly from the PLC and report the value.

2 Likes

@Kevin.Herron I think that’s what I meant, but I might not have used the right language. :grinning:

Thanks for the clarification!

@pturmel By “OPC Read Mode” are you referring to the “OPC Data Mode” under options?

2021-05-25 15_55_03-GatewayEvents - EPWM-Ignition - Ignition Designer

1 Like

Yes.

1 Like

Not sure if this could be useful to anyone else in the future, but I have put together a function that we are going to use to pass Ignition tags to, and it will perform the system.opc.readValue on the tag and return the result. It takes into account the fact that UDT tags with parameters have to be processed differently from regular tags with a string for the tag on the PLC.

There may be a way easier way to do this, but it is working for us. :grinning:

I should mention that this only works with UDT tags that have a single (1) parameter.

######################################################
# This function finds all occurences of a character in a string
# It is called from the read() function below
######################################################
def findOccurrences(s, ch):
	return [i for i, letter in enumerate(s) if letter == ch]

######################################################
# This function receives an Ignition tag, looks up the PLC tag, and then reads the value and returns it
# It is called from the Gateway Event 'RobotStackerQuery'
######################################################
def read(tag):
	opcTag = system.tag.getConfiguration(tag)[0]['opcItemPath']
	if type(opcTag) == unicode:
		# This is a regular STRING tag WITHOUT parameters
		result = system.opc.readValue(server, str(opcTag)).getValue()
	else:
		# This is a tag that requires parameters; find the folders in the path
		slashes = findOccurrences(tag, '/')
		# Find out how many folder paths to search; subtract one so it can equal the list length
		i = len(slashes) - 1
		# Go through each folder path to locate the UDT instance
		while i >= 0:
			# Get the folder path by locating the last slash in the tag name
			folder = tag[:slashes[i]]
			# Get the tagType from the foldre
			tagType = system.tag.getConfiguration(folder)[0]['tagType']
			
			# Check the tagType
			if str(tagType) == 'UdtInstance':
				# This is the UDT tag, so it should have the parameters
				# Find the key
				key = system.tag.getConfiguration(folder)[0]['parameters'].keys()
				# Use the key to find tha prameter section
				paramValues = system.tag.getConfiguration(folder)[0]['parameters'][key[0]]
				# Get the parameter value
				param =  paramValues.getValue()
				# Since the UDT folder has been located, exit the loop
				break
			
			# Decrement i by 1
			i -= 1
		
		# Reformat the tag with the parameter
		# Find the binding from the OPC tag; this contains the PLC tag name WITH the parameter
		bindTag = opcTag.binding
		# Locate the start and end of the paremter in the tag name; e.g. {Param}
		lc = bindTag.find('{')
		rc = bindTag.find('}')
		# Replace the {Param} with the actual parameter found in the UDT
		opcTag = bindTag[:lc] + str(param) + bindTag[rc + 1:] 
		# Read the tag from the PLC
		result = system.opc.readValue(server, str(opcTag)).getValue()

	# Return the result
	return result