7 de octubre de 2011

Comunicación OPC con un PLC Logix5000 desde Visual Basic

Ya he hablado en el blog de comunicación OPC, en concreto en esta entrada traté el acceso a un WinAC desde Visual Basic. Ahora, aprovechando la configuración que tengo con SoftLogix sobre una máquina virtual, voy a hacer lo mismo.

Mi prueba consistirá en crear un proyecto para SoftLogix en el que definiré un par de tags, OPC_BIT y OPC_DINT, que me servirán para probar la comunicación. En el SoftLogix no voy a hacer nada más, simplemente le transferiré el proyecto, lo pondre en modo Run y monitorizaré el contenido de los tags. Luego generaré un enlace OPC con el RSLinx y desde un programa en Visual Basic leeré y escribiré en los tags del PLC.


Para establecer una comunicación OPC necesitaré un servidor OPC, y Rockwell nos lo proporciona integrado con el RSLinx, pero ojo, deberemos asegurarnos de que no sea la versión lite. Recomiendo echar un vistazo a este documento Cómo obtener resultados con RSLinx Classic (pdf) donde se especifica para qué sirve cada versión de RSLinx.

En el ordenador donde tengo instalado Visual Basic he instalado RSLinx Classic. Con mi SoftLogix funcionando compruebo que lo detecta.


Para obtener acceso al PLC a través de OPC deberemos configurar un Topic, que es la definición de la ruta de acceso al controlador. Para ello vamos al menú de RSLinx y pulsamos sobre DDE/OPC → Topic Configuration... y aparecerá una ventana donde seleccionaremos nuestro controlador y le asignaremos un Topic, en mi caso PRUEBA_OPC.


Aceptamos y ya podemos cerrar el RSLinx. Para comprobar que nuestro servidor OPC funciona, Rockwell suministra la herramienta OPC Test Client (se instala conjuntamente con el RSLinx). La ejecutamos y vamos al menú Server → Connect...


Selecciono RSLinx OPC Server.


Ahora tenemos que añadir un grupo, vamos al menú Group → Add Group...


Le asignamos un nombre cualquiera y aceptamos.


Ya solo falta añadir Items (que serán nuestros tags), vamos al menú Item → Add Item...


En la ventana que aparece, en la parte inferior izquierda navegamos por el árbol del servidor OPC, seleccionamos dentro de nuestro Topic la opción online y a la derecha deberán mostrarse los tags de nuestro proyecto Logix5000. Selecciono el tag que me interese y pulso el botón Add Item.


Y ya podemos ver el contenido de nuestro tag. Si modificamos su valor desde el RSLogix5000 veremos en el OPC Test Client como varía.


Ya hemos comprobado que tenemos acceso por OPC a nuestro controlador. Ahora lo que voy a hacer es la misma operación pero desde un programa en Visual Basic.

Crearemos un proyecto en Visual Basic y, para tener acceso a las funciones de comunicación OPC, deberemos agregar, en mi caso, la referencia OPC DA Automation Wrapper 2.02 (OPCDAAuto.DLL) que estará disponible en mi ordenador al tener instalado el RSLinx. Esta referencia difiere según sea la versión de RSLinx de que dispongamos; según leo en el foro de control.com  deberemos agregar RsLinxOPCAuto.DLL o incluso RsiOPCAuto.DLL si disponemos de versiones antiguas.


Comprobamos que en Espacios de nombres importados esté marcado RsiOPCAuto.


Con esto ya podemos empezar a programar. Voy a adaptar el código de la clase que programé en la entrada sobre OPC y WinAC:
Imports OPCAutomation

Public Class OPC_NdA 'OPC Notas de Automatización
    'Objectos para establecer la comunicación OPC
    Private WithEvents ServidorOPC As OPCServer
    Private WithEvents GrupoOPC As OPCGroup
    Private WithEvents GruposOPC As OPCGroups
    Private ItemOPC() As OPCItem

    Public Conectado As Boolean 'Para saber si la conexión está activada

    'Si hay algún error se indica en estas variables
    Public Mensaje As String
    Public Detalle_Error As String

    'Constructor
    Public Sub New()
        'Al crear el objeto, no estamos conectados
        Conectado = False
    End Sub

    'Función para activar la conexión OPC
    Public Function Conectar() As Boolean

        'Si ya estoy conectado aviso y salgo.
        If Conectado Then
            Mensaje = "Error conexión OPC."
            Detalle_Error = "Se ha intentado crear una conexión OPC cuando ya hay una creada."
            Conectar = False
            Exit Function
        End If

        Try
            Mensaje = "Conectando con el servidor OPC..."
            ServidorOPC = New OPCServer
            ServidorOPC.Connect("RSLinx OPC Server")

            Mensaje = "Añadiendo grupo al servidor OPC..."
            GruposOPC = ServidorOPC.OPCGroups
            GrupoOPC = GruposOPC.Add("Grupo1")

            GrupoOPC.IsActive = True
            GrupoOPC.UpdateRate = 1000
            GrupoOPC.IsSubscribed = True

            Mensaje = "Añadiendo Items al grupo..."
            ReDim ItemOPC(100) 'Dimensionar según las necesidades

            'Introducir un ítem por cada variable del PLC en la que queramos leer o escribir
            'A cada ítem le asignamos un número, que debemos recordar para referirnos a él en el programa
            ItemOPC(0) = GrupoOPC.OPCItems.AddItem("[PRUEBA_OPC]OPC_DINT", 0)
            ItemOPC(1) = GrupoOPC.OPCItems.AddItem("[PRUEBA_OPC]OPC_BIT", 1)

        Catch ex As Exception

            Detalle_Error = "Error: " & ex.ToString
            Conectado = False
            Conectar = False
            Exit Function

        End Try

        Mensaje = "Conexión OPC realizada correctamente."
        Detalle_Error = ""
        Conectado = True
        Conectar = True

    End Function

    'Función para deshacer la conexión OPC
    Public Function Desconectar() As Boolean
        Try
            Mensaje = "Desconectando..."
            ItemOPC = Nothing

            If Not IsNothing(ServidorOPC) Then
                ServidorOPC.OPCGroups.RemoveAll()
                ServidorOPC.Disconnect()
                ServidorOPC = Nothing
            End If
            GrupoOPC = Nothing
            GruposOPC = Nothing

        Catch ex As Exception

            Detalle_Error = "Error: " & ex.ToString
            Desconectar = False
            Exit Function

        End Try

        Mensaje = "Desconexión realizada correctamente."
        Detalle_Error = ""
        Conectado = False
        Desconectar = True

    End Function

    'Función para escribir en un ítem que representa una variable entera
    'Se le pasa el índice del ítem y el valor que vamos a escribir
    'Si todo va bien devuelve True
    Public Function EscribirItemInt(ByVal Indice As Integer, ByVal Entero As Integer) As Boolean
        Dim Dims() As Integer = New Integer() {1}
        Dim Bounds() As Integer = New Integer() {1}
        Dim Serverhandles As Array = Array.CreateInstance(GetType(Integer), Dims, Bounds)
        Dim Errores As Array = Array.CreateInstance(GetType(Integer), Dims, Bounds)
        Dim Valores As Array = Array.CreateInstance(GetType(Object), Dims, Bounds)

        If Not Conectado Then
            Mensaje = "Error conexión OPC."
            Detalle_Error = "No hay establecida una conexión OPC."
            EscribirItemInt = False
            Exit Function
        End If

        Try
            Serverhandles.SetValue(ItemOPC(Indice).ServerHandle, 1)
            Errores.SetValue(0, 1)
            Valores.SetValue(Entero, 1)

            GrupoOPC.SyncWrite(1, Serverhandles, Valores, Errores)

        Catch ex As Exception

            Detalle_Error = ex.ToString
            Mensaje = "¡Error al escribir Item! [Int, Índice " & Indice & "]"
            EscribirItemInt = False
            Exit Function

        End Try

        Mensaje = ""
        Detalle_Error = ""
        EscribirItemInt = True

    End Function

    'Función para escribir en un ítem que representa una variable booleana
    'Se le pasa el índice del ítem y el valor que vamos a escribir
    'Si todo va bien devuelve True
    Public Function EscribirItemBool(ByVal indice As Integer, ByVal Bit As Boolean) As Boolean
        Dim Dims() As Integer = New Integer() {1}
        Dim Bounds() As Integer = New Integer() {1}
        Dim Serverhandles As Array = Array.CreateInstance(GetType(Integer), Dims, Bounds)
        Dim Errores As Array = Array.CreateInstance(GetType(Integer), Dims, Bounds)
        Dim Valores As Array = Array.CreateInstance(GetType(Object), Dims, Bounds)

        If Not Conectado Then
            Mensaje = "Error conexión OPC."
            Detalle_Error = "No hay establecida una conexión OPC."
            EscribirItemBool = False
            Exit Function
        End If

        Try
            Serverhandles.SetValue(ItemOPC(indice).ServerHandle, 1)
            Errores.SetValue(0, 1)
            Valores.SetValue(Bit, 1)

            GrupoOPC.SyncWrite(1, Serverhandles, Valores, Errores)

        Catch ex As Exception

            Detalle_Error = ex.ToString
            Mensaje = "¡Error al escribir Item! [Bool, Índice " & indice & "]"
            EscribirItemBool = False
            Exit Function

        End Try

        Mensaje = ""
        Detalle_Error = ""
        EscribirItemBool = True

    End Function

    'Función para leer un ítem que representa una variable entera
    'Se le pasa el índice del ítem que vamos a leer
    'Si todo va bien devuelve el valor de la variable
    Public Function LeerItemInt(ByVal Indice) As Integer

        Dim Valor As Object = Nothing
        Dim Calidad As Object = Nothing
        Dim TimeStamp As Object = Nothing

        If Not Conectado Then
            Mensaje = "Error conexión OPC."
            Detalle_Error = "No hay establecida una conexión OPC."
            LeerItemInt = 0
            Exit Function
        End If

        Try
            ItemOPC(Indice).Read(OPCDataSource.OPCDevice, Valor, Calidad, TimeStamp)
            LeerItemInt = CInt(Valor.ToString)

        Catch ex As Exception

            Detalle_Error = ex.ToString
            Mensaje = "¡Error al leer Item! [Int, Índice " & Indice & "]"
            LeerItemInt = 0
            Exit Function

        End Try

        Mensaje = ""
        Detalle_Error = ""

    End Function

    'Función para leer un ítem que representa una variable booleana
    'Se le pasa el índice del ítem que vamos a leer
    'Si todo va bien devuelve el valor de la variable
    Public Function LeerItemBool(ByRef Indice) As Boolean

        Dim Valor As Object = Nothing
        Dim Calidad As Object = Nothing
        Dim TimeStamp As Object = Nothing

        If Not Conectado Then
            Mensaje = "Error conexión OPC."
            Detalle_Error = "No hay establecida una conexión OPC."
            LeerItemBool = 0
            Exit Function
        End If

        Try
            ItemOPC(Indice).Read(OPCDataSource.OPCDevice, Valor, Calidad, TimeStamp)
            If StrComp(Valor.ToString, "True") = 0 Or Valor = 1 Then
                LeerItemBool = True
            Else
                LeerItemBool = False
            End If

        Catch ex As Exception

            Detalle_Error = ex.ToString
            Mensaje = "¡Error al leer Item! [Bool, Índice " & Indice & "]"
            LeerItemBool = False
            Exit Function

        End Try

        Mensaje = ""
        Detalle_Error = ""

    End Function

End Class

Con respecto al código que hice para Siemens simplemente he cambiado en la función Conectar el servidor OPC a RSLinx OPC Server y he adaptado la lista de items.

Para introducir los items deberemos especificar el nombre del Topic que hayamos configurado en el RSLinx entre corchetes seguido del nombre del tag, por ejemplo:

ItemOPC(0) = GrupoOPC.OPCItems.AddItem("[PRUEBA_OPC]OPC_DINT", 0)

Las funciones para leer y escribir booleanos y enteros son las mismas que las programadas en el OPC de Siemens.

Ya solo nos queda crear una interfaz sencilla para probar la conexión:


Pulsando el botón Conectar se establecerá la conexión OPC y si todo va correctamente podremos escribir y leer valores en el tag OPC_DINT y cambiar el estado del booleano OPC_BIT.

El código de este sencillo programa lo tienes en este proyecto de Visual Basic.

Y hasta aquí esta toma de contacto con la tecnología OPC en Rockwell. No es un ejemplo elaborado, pero espero que pueda servir de punto de partida para aplicaciones más complejas.

Como siempre, agradeceré cualquier comentario.

25 comentarios:

  1. WinLC RTX es un controlador en tiempo real basado en el entorno PC, se comunica de forma remota con STEP 7 y SIMATIC Computing a través
    de redes PROFIBUS, MPI o Ethernet.
    WinLC RTX es compatible con las herramientas de automatización de la gama de productos SIMATIC, p.ej. con el software de programación STEP 7 y WinCC de SIEMENS.
    ¿PODRIAS HACER UN EJEMPLO DE WinLC RTX + STEP 7 + WinCC de SIEMENS con Ethernet?
    GRACIAS, JG.

    ResponderEliminar
  2. Hola JG. Supongo que ya has visto en el blog las entradas sobre WinAC.

    No creo que dedique ninguna entrada a WinCC, ya que es un software que nunca he visto y no lo tengo disponible.

    Lo que sí tengo es un runtime de WinCC Flexible, que tengo pensado intalar en una máquina virtual y en un futuro lo usaré para alguna entrada del blog.

    Un saludo y gracias por el interés.

    ResponderEliminar
  3. un runtime de WinCC Flexible ???
    GR, puedes detallar mas el concepto?
    GRACIAS, JG.

    ResponderEliminar
  4. Hola JG.

    El WinCC Flexible Runtime es un software que, instalado en un ordenador normal, te permite usarlo como un panel Simatic, programable con WinCC Flexible.

    Más información aquí: https://www.automation.siemens.com/mcms/human-machine-interface/en/visualization-software/wincc-flexible/wincc-flexible-runtime/Pages/Default.aspx

    Un saludo.

    ResponderEliminar
  5. Hola podrias enviarme un ejemplo o un documento en el cual saques datos del controlador..como los direcciono?...al convertir el PLC en un servidor OPC este ya me muestra todos los TAGS?..
    felipe_medinasw@yahoo.com

    ResponderEliminar
    Respuestas
    1. El servidor OPC está en el RSLinx, no en el PLC. Desde el OPC Test Client puedes ver que tienes acceso a todos los tags.

      Un saludo.

      Eliminar
  6. Hola, estoy utilizando el visual basic 6.0 pero para agregar la referencia no aparece como en las imagenes que muestras y lo cheque y no tengo el raiopcauto.dll sabes donde lo puedo descargar??

    ResponderEliminar
    Respuestas
    1. Las bibliotecas se instalan con el RSLinx. Desconozco si se pueden conseguir por separado.

      Prueba a buscar RsLinxOPCAuto.DLL o incluso RsiOPCAuto.DLL

      Un saludo.

      Eliminar
  7. hola tengo problemas en leer un tag de tipo String desde el PLC no se si el metodo READ puede hacerlo podrias ponerme un ejemplo del metodo.

    un saludo :)

    ResponderEliminar
  8. estoy utilizando un OPC server de un Micrologix 1400

    ResponderEliminar
  9. Excelente lo estoy provando con Visual Basic 2010 express y RSLogix y softlogix rev 19 y todo excelente gracias por la ayuda estaba buscando esto para poder hacer mas cosas... Sigue asi te felicito

    ResponderEliminar
    Respuestas
    1. Hola amigo , necesito un poco de ayuda , podria usted ayudarme ?

      Eliminar
  10. Hey amigo, excelente contribucion, de verdad, mucho mejor documentado que en el mismo sitio de OPC foundation o Rockwell.

    Gracias. de mucha ayuda para resolver el principio basico de conexion al PLC. Por cierto, tu codigo funciona bien en VS2010.

    ResponderEliminar
  11. GR, gracias por tu aportación, me esta siendo de mucha ayuda para un proyecto que estoy desarrollando. Podrías pasarme tu correo?

    ResponderEliminar
    Respuestas
    1. Igual te dejo mi correo por si se te hace mejor escribirme.

      Eliminar
    2. Hola AR, puedes escribirme a notasdeautomatizacion@gmail.com

      Un saludo.

      Eliminar
  12. Hola GR, tu código es lo que estaba buscando, nada más alguna idea que pudieras compartir de como puedo manipular datos Strings, intente cambiando el código de EscribirItemInt para adaptarlo pero al momento de agregar la etiqueta me marca un error, alguna idea? Gracias

    ResponderEliminar
  13. Estimado ami no me aparece en el visual studio la opción de agregar RsLinxOPCAuto.DLL. ademas en el opc test cliente me da error de conexion con rslinx opc sever. Lastima no puedo subir una foto de la falla en el comentario para que tu la veas

    ResponderEliminar
  14. Hola , muy buena explicacion del funcionamiento y configuracion . gracias por su aporte!!. quisiera preguntarle si hay alguna forma de usar los datos obtenidos en el opc dentro de la logica de un programa del Step 7 . osea poder tomar esos valores y usarlo como contactos NA, NO, o variables de valor entero o doble entero.
    desde ya muchas gracias

    ResponderEliminar
  15. Respuestas
    1. Grazas amigo!!! unha vez mais salvachesme o pelexo! recordame que que se volto de novo a Galicia che invite a tomar algo. Unha Aperta desde a Arxentina

      Eliminar
  16. con esto pudo hacer una aplicacion como de panelview para adquisicion de datos, aparte me gustaria saber si puedo manejar datos flotantes de lectura desde el plc, me pudieran ayudar por favor. y cual seria el total de datos que puedo manejar desde el plc estaria limitado a tags o todos los que yo quiera

    saludos

    ResponderEliminar
  17. Buenas tardes

    En realidad me parecio muy interesante este tema, mas porque estoy desarrollando un programa similar, donde interactuo visual basic y un plc allen bradley 1400

    Realmente aun no puedo comunicarme exitosamente con el plc a traves de vb...
    Por eso es que escribo aqui por ayuda ya que soy nuevo es esto de la programacion con plc

    Tengo algunas dudas espero y me pueda ayudar, una de ellas seria...
    Problema:
    Tengo ya una aplicacion de Visual Basic, tengo Rs logix500 y RsLinxs Classic Gateway... Ya estableci la comunicacion Rslinks y Rslogix con el PLC, ya agrege el topic a Rslinx, en el OPC test client ya agrege un grupo, junto con un item supongamos que es la variable B3:75... Y cuando la activo en Rslogix ya la puedo monitorear en OPC test client...Ademas de que la veo visualmente cuando se enciende en el PLC... Pero cuando copio el codigo fuente y ademas agrego la libraria OPC Automation junto con el parametro RsiOPCAuto, no puedo activar ese bit desde visual basic... Me falta algo? Algun paso que me haya brincado? Algo que no este bien?
    Como nota:
    * Se tarda mucho en el mensaje Conectando con el servirdor OPC... No se que pasa la verdad
    * Para activar ese bit lo tengo mediante un boton

    Espero sus respuestas, ojala que me ayuden

    Este es mi correo: Javier.lunag@novatechnologiesmx.com
    Por si tienen alguna opinion o algo que me pueda ayudar...

    Muchas gracias

    ResponderEliminar
  18. Hola GR buen probama sencillo y bueno te comento el problema que tengo ya logre entablar comunicacion ente visual y el plc pro me falta lo siguiente intento hacer una funcion que lea en automaticosin necesidad del boton leer y lootro esque deseo activar un bit del plc desde visual para poder resetear un contador quisiera que me ayudes con eso gracias.

    ResponderEliminar

Por favor, no pidas copias de programas comerciales, licencias o números de serie.