Author Topic: Best way to read and write Tags  (Read 5771 times)

scott.clark

  • Jr. Member
  • **
  • Posts: 96
    • View Profile
Best way to read and write Tags
« on: January 08, 2015, 07:11:18 PM »
using AdvancedHMI 3.97, VS 2013

In this application I am working on I have about 25 tags to display that I could use AdvancedHMI controls on a form.  and I have another 25 to 30 tags that I need to read and write in the background so I can push that data to other devices and routines.  I have tried a number or methods but I can't seem to get an acceptable update rate.  I need to be able to update a few tags in under .5 seconds, operator interface stuff.  Then I have to be able to update, mostly read, about 40 tags some to be displayed and others used to log data.

I used some basic labels and buttons for the operator interface stuff on a EthernetIPforCLXCom_Immediate polling at 250, and then created another EthernetIPforCLXCom_Main (poling at 1000)  for the rest of the tags.  To update the background tags, the ones not to be displayed, I used a DataSubscriber Component being triggered by a tag(plc clock) at a polling rate of 1000.  I used the EthernetIPforCLXCom.read() and EthernetIPforCLXCom().write in the DataSubscriber_changed event.   UPdates are still taking several seconds and appear to be erratic.

I was thinking that the few tags that were on the EthernetIPforCLXCom_Immediate would be able to update, but somehow they are bogged down by the traffic on the EthernetIPforCLXCom_Main .

I am open for suggestions.
Thanks!

I am sure there is a better way.   I can't really group the tags into arrays without a lot of PLC reprogramming, I am trying to interface this with an existing system.  I am open for suggestions.
EthernetIPforCLXCom

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: Best way to read and write Tags
« Reply #1 on: January 08, 2015, 09:56:41 PM »
Is there anything else on the network, such as IO devices? I would run Wireshark to get an idea of how much traffic the application is competing with for bandwidth.

scott.clark

  • Jr. Member
  • **
  • Posts: 96
    • View Profile
Re: Best way to read and write Tags
« Reply #2 on: January 08, 2015, 11:58:28 PM »
The network consist of the HMI PC the compactlogix plc and my laptop that I am debugging the application.  Eventually there will be a sql server connection added and a printer.  I can't imagine that it would be a traffic issue at this point, I will run Wireshark tomorrow and see .

Is reading 30 or 40 tags in a DataSubsciber event a good method?

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: Best way to read and write Tags
« Reply #3 on: January 09, 2015, 04:52:38 AM »
With poll rates of only 1000 and 250, it should be fairly responsive. The typical response time for each read is 5-10ms. So if you are reading 50 tags, in worst case, you should be able to get a response in 500ms.

The driver attempts to divide the poll rate into the number of individual subscribed reads, then space each read accordingly. If the poll rate is faster than it can update all of the subscriptions, then it will send the requests as fast as it can.

With Wireshark you should be able to see a particular tag being read, note the time stamp, then scroll down through the list to find the same tag being read. You can then calculate how long it is taking to update the entire subscription list.

scott.clark

  • Jr. Member
  • **
  • Posts: 96
    • View Profile
Re: Best way to read and write Tags
« Reply #4 on: January 09, 2015, 06:26:17 PM »
When you talk about a individual subscribe reads and update of all subscriptions, I don't fully understand.  I am thinking of subscriptions as applying to all the tags that are specified in the form controls, such as digital panel meters, push buttons, indicators, etc...

How do subscriptions apply to individual read writes inserted into a DataSubscriber data changed handler as in the example below? 

When the DataSubscriber changed event occurs, it severely bogs down the other form controls, event though I have them on separate EthernetIPforCLXCom .NET Components.

Sorry for the long code example, I don't know how to post it in that scrolling window.
thanks!


Example:
    Private Sub DataSubscriber_PLCFunctions_DataChanged(sender As Object, e As Drivers.Common.PlcComEventArgs) Handles DataSubscriber_PLCFunctions.DataChanged

        Dim n_strMessage As String = String.Empty
        Dim strPLCTagAddress As String
        Dim strWriteValue As String
        Dim strResultsCycleDintValues(10) As String
        Dim strResultsCycleRealValues(10) As String
        Try

                strPLCTagAddress = "PCNotFaulted"
                strWriteValue = g_PLCWriteValues.PC_NotFaulted.ToString
                EthernetIPforCLXCom_MainForm.Write(strPLCTagAddress, strWriteValue)

                strPLCTagAddress = "PCStartManualHipotTest.0"
                strWriteValue = g_PLCWriteValues.StartManualHipotTest.ToString
                EthernetIPforCLXCom_MainForm.Write(strPLCTagAddress, strWriteValue)

                strPLCTagAddress = "DixellDownloadComplete"
                strWriteValue = g_PLCWriteValues.DixellDownloadComplete.ToString
                EthernetIPforCLXCom_MainForm.Write(strPLCTagAddress, strWriteValue)

                g_bPLCFunctions_WritePLCValues = False
                n_longElapsedWrite = tmrElapsedWrite.GetTimeExpiredInMilliseconds

                strPLCTagAddress = "StepNumber"
                g_PLCReadValues.PLCStageCounterValue = EthernetIPforCLXCom_MainForm.Read("StepNumber")

                strPLCTagAddress = "DI_MCRStatus.InDbncd"
                g_PLCReadValues.MCR = EthernetIPforCLXCom_MainForm.Read("DI_MCRStatus.InDbncd")

                strPLCTagAddress = "DI_HiPotPass.InDbncd"
                g_PLCReadValues.HipotPass = EthernetIPforCLXCom_MainForm.Read("DI_HiPotPass.InDbncd")

                strPLCTagAddress = "DI_HiPotFail.InDbncd"
                g_PLCReadValues.HipotFail = EthernetIPforCLXCom_MainForm.Read("DI_HiPotFail.InDbncd")

                strPLCTagAddress = "DI_AirPressureSwitch.InDbncd"
                g_PLCReadValues.AirPressureSwitch = EthernetIPforCLXCom_MainForm.Read("DI_AirPressureSwitch.InDbncd")

                strPLCTagAddress = "DI_RejectResetPB.InDbncd"
                g_PLCReadValues.RejectPB = EthernetIPforCLXCom_MainForm.Read("DI_RejectResetPB.InDbncd")

                strPLCTagAddress = "DI_MotorContinuity_1.InDbncd"
                g_PLCReadValues.SinglePhaseContinuity = EthernetIPforCLXCom_MainForm.Read("DI_MotorContinuity_1.InDbncd")

                strPLCTagAddress = "DI_MotorContinuity_2.InDbncd"
                g_PLCReadValues.ThreePhaseContinuity = EthernetIPforCLXCom_MainForm.Read("DI_MotorContinuity_2.InDbncd")

                strPLCTagAddress = "DI_MOLTripped.InDbncd"
                g_PLCReadValues.MOLTripped = EthernetIPforCLXCom_MainForm.Read("DI_MOLTripped.InDbncd")

                strPLCTagAddress = "AI_Volts.EngineeringValue"
                g_PLCReadValues.VoltsScaled = EthernetIPforCLXCom_MainForm.Read("AI_Volts.EngineeringValue")
                g_PLCReadValues.VoltsScaled = Math.Round(g_PLCReadValues.VoltsScaled, 2)


                strPLCTagAddress = "AI_Amps.EngineeringValue"
                g_PLCReadValues.AmpsScaled = EthernetIPforCLXCom_MainForm.Read("AI_Amps.EngineeringValue")
                g_PLCReadValues.AmpsScaled = Math.Round(g_PLCReadValues.AmpsScaled, 2)

                strPLCTagAddress = "AI_DischargePressure.EngineeringValue"
                g_PLCReadValues.DischargePressureScaled = EthernetIPforCLXCom_MainForm.Read("AI_DischargePressure.EngineeringValue")
                g_PLCReadValues.DischargePressureScaled = Math.Round(g_PLCReadValues.DischargePressureScaled, 2)


                strPLCTagAddress = "DO_GreenDomeLight.Output"
                g_PLCReadValues.GreenDomeLight = EthernetIPforCLXCom_MainForm.Read("DO_GreenDomeLight.Output")

                strPLCTagAddress = "DO_AmberDomeLight.Output"
                g_PLCReadValues.AmberDomeLight = EthernetIPforCLXCom_MainForm.Read("DO_AmberDomeLight.Output")

                strPLCTagAddress = "DO_RedDomeLight.Output"
                g_PLCReadValues.RedDomeLight = EthernetIPforCLXCom_MainForm.Read("DO_RedDomeLight.Output")

                strPLCTagAddress = "DO_DomeLightAlarm.Output"
                g_PLCReadValues.DomeLightAlarm = EthernetIPforCLXCom_MainForm.Read("DO_DomeLightAlarm.Output")

                strPLCTagAddress = "MachineFaults.HiPotTesterFault"
                g_PLCReadValues.HiPotTesterFault = EthernetIPforCLXCom_MainForm.Read("MachineFaults.HiPotTesterFault")

                strPLCTagAddress = "MachineFaults.AirSupplyFault"
                g_PLCReadValues.AirSupplyFault = EthernetIPforCLXCom_MainForm.Read("MachineFaults.AirSupplyFault")

                strPLCTagAddress = "MachineFaults.ParameterFault"
                g_PLCReadValues.ParameterFault = EthernetIPforCLXCom_MainForm.Read("MachineFaults.ParameterFault")

                strPLCTagAddress = "MachineFaults.PCFault"
                g_PLCReadValues.PCFault = EthernetIPforCLXCom_MainForm.Read("MachineFaults.PCFault")

                strPLCTagAddress = "MachineFaults.ContinuityFault"
                g_PLCReadValues.ContinuityFault = EthernetIPforCLXCom_MainForm.Read("MachineFaults.ContinuityFault")

                strPLCTagAddress = "MachineFaults.NoPowerFault"
                g_PLCReadValues.NoPowerFault = EthernetIPforCLXCom_MainForm.Read("MachineFaults.NoPowerFault")

                strPLCTagAddress = "MachineFaults.MOLTripped"
                g_PLCReadValues.MOLTrippedFault = EthernetIPforCLXCom_MainForm.Read("MachineFaults.MOLTripped")

                strPLCTagAddress = "MasterReset"
                g_PLCReadValues.MasterReset = EthernetIPforCLXCom_MainForm.Read("MasterReset")

                strPLCTagAddress = "TestCycleTime.ACC"
                g_PLCReadValues.TestCycleTime = EthernetIPforCLXCom_MainForm.Read("TestCycleTime.ACC")

                strPLCTagAddress = "Results.CycleDintValues[0]"
                strResultsCycleDintValues = EthernetIPforCLXCom_MainForm.Read("Results.CycleDintValues[0]", 10)

                strPLCTagAddress = "Results.CycleRealValues[0]"
                strResultsCycleRealValues = EthernetIPforCLXCom_MainForm.Read("Results.CycleRealValues[0]", 10)

                strPLCTagAddress = "Results.PassFailCode"
                g_PLCReadValues.PassFailValue = EthernetIPforCLXCom_MainForm.Read("Results.PassFailCode")

                strPLCTagAddress = "SolenoidRequirementComplete"
                g_PLCReadValues.SolenoidInstallComplete = EthernetIPforCLXCom_MainForm.Read("SolenoidRequirementComplete")

        Catch ex As Exception
            n_strMessage = "Procedure MainForm: DataSubscriber1_DataChanged failed with error: " & vbCrLf & ex.Message & vbCrLf & strPLCTagAddress

            MsgBox(n_strMessage)

        End Try
    End Sub 

scott.clark

  • Jr. Member
  • **
  • Posts: 96
    • View Profile
Re: Best way to read and write Tags
« Reply #5 on: January 12, 2015, 02:39:01 PM »
Is it better to put each of these Tag reads in as a DataSubscriber component than to group them in one DataSubscriber?
Thanks!

Noe

  • Full Member
  • ***
  • Posts: 205
    • View Profile
Re: Best way to read and write Tags
« Reply #6 on: January 12, 2015, 06:00:50 PM »
How would you group them? I saw Archies response about using a bit to update more tags, do you mean that type of grouping?

scott.clark

  • Jr. Member
  • **
  • Posts: 96
    • View Profile
Re: Best way to read and write Tags
« Reply #7 on: January 13, 2015, 10:26:06 AM »
By grouping, I mean to do consecutive reads of various tag addresses in one DataSubscriber.  Again, I don't know if this is the best method for performance, but it does work.

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: Best way to read and write Tags
« Reply #8 on: January 13, 2015, 10:44:07 AM »
By grouping, I mean to do consecutive reads of various tag addresses in one DataSubscriber.  Again, I don't know if this is the best method for performance, but it does work.
A slightly better method that will help keep the HMI responsive would be to use Asynchronous reads within the DataChangedEvent. To do this you would use BeginRead in place of Read. Then add an event Handler for DataReceived event of the driver such as this:

    Private MyValue As String
    Private Sub EthernetIPforPLCSLCMicroCom1_DataReceived(sender As Object, e As Drivers.Common.PlcComEventArgs) Handles EthernetIPforPLCSLCMicroCom1.DataReceived
        If e.PlcAddress = "MyTagAddress" Then
            MyValue = e.Values(0)
        End If
    End Sub