15 de marzo de 2011

Accediendo a un PLC Siemens desde Visual Basic: LIBNODAVE

Libnodave es una biblioteca libre de funciones para comunicar con PLC Siemens, utilizando adaptadores MPI/PPI o Ethernet. Está disponible para descarga directa aquí y viene con el código fuente, programas de prueba, bibliotecas para Linux, Windows (32 bits), .NET y ejemplos. Para programar podemos elegir una gran variedad de lenguajes y entornos: C, C++, C#, Delphi, Pascal, Perl, Visual Basic y Visual Basic for Aplications.

Para probarlo voy a partir de la configuración que tengo hecha de las dos entradas anteriores en las que comunicaba un S5-95U con un 315-2DP por Profibus. Ahora lo que pretendo es conectarme desde mi ordenador al S7-300 para visualizar, en una aplicación en Visual Basic, las lecturas que hago de la periferia integrada del S5.

Para comunicar mi PC con el 315-2DP tengo un adaptador serie/MPI de Siemens referencia 6ES7901-2BF00-0AA0. No viene en la lista de adaptadores probados en la página de Libnodave pero ha funcionado bien, incluso a través de un adaptador USB/serie de la marca Prolific.

Para clarificar, en el siguiente esquema represento el conexionado que tengo entre los diferentes elementos:

Lo que voy a hacer en este proyecto es una aplicación en Visual Basic 2010 Express a la que voy a incorporar la biblioteca Libnodave para leer y escribir en el bloque de datos donde interactúo con la periferia del S5-95U: lo único que hará mi aplicación es leer y escribir en el DB10 del 315-2DP.


En los programas de Step5 y Step7 no tengo que modificar nada, el acceso es transparente para los PLC; la aplicación en el PC funcionará como HMI.

Lo primero es crear un nuevo proyecto en el entorno de Visual Basic. Una vez creado vamos a sus propiedades:

En la pestaña Referencias vamos a agregar una referencia nueva:

Vamos al directorio donde hayamos descomprimido Libnodave y dentro del subdirectorio Dot.NET seleccionamos la biblioteca libnodave.net.dll:

Al aceptar, en la lista de referencias ya debería aparecer libnodave.net:

Con esto ya tenemos acceso a las funciones para programar nuestra comunicación. Sin embargo, si ejecutamos la aplicación nos saldrá un error de que falta una biblioteca DLL. La solución la encontré en el foro de libnodave. Resulta que la biblioteca que hemos incorporado al proyecto es un "wrapper", o sea, una adaptación de la biblioteca de Win32 a .NET. Así que es necesario copiar manualmente la biblioteca libnodave.dll que se encuentra en el subdirectorio win en el mismo directorio donde esté el ejecutable de nuestro programa, esto es en los subdirectorios \bin\Debug y \bin\Release del directorio del proyecto en Visual Basic.

Realizado este paso ya estamos listos para iniciar la programación. Con la biblioteca Libnodave vienen un par de ejemplos en Visual Basic, en los que me he basado. He creado la clase NDA_LND para gestionar la conexión con las funciones Conectar y Desconectar y un par de funciones para leer y escribir en un DB. El código de la clase es el siguiente:
Public Class NDA_LND
Dim daveSerie As libnodave.daveOSserialType
Dim daveInter As libnodave.daveInterface
Dim daveConex As libnodave.daveConnection

Public BufferLectura(1000) As Byte
Public BufferEscritura(1000) As Byte

Public Conectado As Boolean = False
Public Mensaje As String

Public Function Conectar(Optional ByVal localMPI As Integer = 0, _
Optional ByVal plcMPI As Integer = 2, _
Optional ByVal portSerial As String = "COM1", _
Optional ByVal baud As String = "19200") As Boolean
If Conectado Then
Mensaje = "Conexión abortada, ya existe una conexión."
Conectar = False
Exit Function
End If

Dim Respuesta As Integer

Mensaje = "Abriendo una conexión serie..."
daveSerie.rfd = libnodave.setPort(portSerial, baud, AscW("O"))
daveSerie.wfd = daveSerie.rfd

If daveSerie.rfd > 0 Then
Mensaje = "Conexión serie OK, creando interface..."

daveInter = New libnodave.daveInterface(daveSerie, "My Interface 1", _
localMPI, _
libnodave.daveProtoMPI2, _
libnodave.daveSpeed187k)
daveInter.setTimeout(1000000) 'Make this longer if you have a very long response time

Mensaje = "Inicializando adaptador..."
Respuesta = daveInter.initAdapter()

If Respuesta = 0 Then
Mensaje = "Inicialización del adaptador OK, creando conexión MPI..."
daveConex = New libnodave.daveConnection(daveInter, plcMPI, 0, 0) 'Rack and slot don't matter in case of MPI
Respuesta = daveConex.connectPLC()
If Respuesta = 0 Then
Mensaje = "Conexión MPI correcta, lista para operar."
Conectado = True
Else
daveInter.disconnectAdapter()
libnodave.closePort(daveSerie.rfd)
Mensaje = "Error al abrir la conexión MPI [" & _
libnodave.daveStrerror(Respuesta) & "]"
Conectado = False
End If

Else
libnodave.closePort(daveSerie.rfd)
Mensaje = "Error al inicializar el adaptador [" & _
Respuesta & "] " & libnodave.daveStrerror(Respuesta)
Conectado = False
End If

Else
Mensaje = "Error al abrir el puerto serie " & portSerial
Conectado = False
End If

Conectar = Conectado

End Function

Public Function Desconectar() As Boolean
If Conectado Then
daveConex.disconnectPLC()
daveInter.disconnectAdapter()
libnodave.closePort(daveSerie.rfd)
Conectado = False
Mensaje = "Conexión correctamente terminada."
Desconectar = True
Else
Mensaje = "No existe conexión activa."
Desconectar = False
End If
End Function

Public Function LeerBytesDB(ByVal NumDB As Integer, _
ByVal Dir As Integer, _
ByVal NumBytes As Integer) As Boolean

Dim Respuesta As Integer

Respuesta = daveConex.readBytes(libnodave.daveDB, NumDB, Dir, NumBytes, BufferLectura)

If Respuesta = 0 Then
Mensaje = "Leídos " & NumBytes & " bytes a partir de la dirección " & _
Dir & " en el DB " & NumDB
LeerBytesDB = True
Else
Mensaje = "Error al leer " & NumBytes & " bytes a partir de la dirección " & _
Dir & " en el DB " & NumDB
LeerBytesDB = False
End If

End Function

Public Function EscribirBytesDB(ByVal NumDB As Integer, _
ByVal Dir As Integer, _
ByVal NumBytes As Integer) As Boolean
Dim Respuesta As Integer

Respuesta = daveConex.writeBytes(libnodave.daveDB, NumDB, Dir, NumBytes, BufferEscritura)

If Respuesta = 0 Then
Mensaje = "Escritos " & NumBytes & " bytes a partir de la dirección " & _
Dir & " en el DB " & NumDB
EscribirBytesDB = True
Else
Mensaje = "Error al escribir " & NumBytes & " bytes a partir de la dirección " & _
Dir & " en el DB " & NumDB
EscribirBytesDB = False
End If

End Function

End Class
Aunque no está comentado, el código creo que es fácil de entender. Con la función Conectar abrimos el puerto serie, inicializamos el adaptador y la conexión MPI, dejándola lista para operar. Comprobando el booleano que devuelve podemos saber si la operación se completó correctamente. Se le pasan por parámetros la dirección MPI del adaptador (por lo general la 0), la dirección MPI del PLC, el puerto serie por el cual comunicará y la velocidad de conexión:
S7MPI = New NDA_LND
S7MPI.Conectar(LocalMPI, PLCMPI, "COM1", "19200")
Los datos se leen con la función LeerBytesDB y se depositan en BufferLectura; por ejemplo, para leer las entradas analógicas se haría así:
S7MPI.LeerBytesDB(10, 26, 16) 'DB10, 16 bytes a partir de la dirección 26
'Entradas analógicas
EW40.Value = libnodave.getU16from(S7MPI.BufferLectura, 0)
EW42.Value = libnodave.getU16from(S7MPI.BufferLectura, 2)
EW44.Value = libnodave.getU16from(S7MPI.BufferLectura, 4)
EW46.Value = libnodave.getU16from(S7MPI.BufferLectura, 6)
EW48.Value = libnodave.getU16from(S7MPI.BufferLectura, 8)
EW50.Value = libnodave.getU16from(S7MPI.BufferLectura, 10)
EW52.Value = libnodave.getU16from(S7MPI.BufferLectura, 12)
EW54.Value = libnodave.getU16from(S7MPI.BufferLectura, 14)
y los que necesitemos escribir en BufferEscritura transfiriéndolo con la función EscribirBytesDB especificando el número de DB, la dirección de byte dentro del DB y el número de bytes a escribir:
S7MPI.BufferEscritura(8) = Valor16bits \ 256 'División entera
S7MPI.BufferEscritura(9) = Valor16bits Mod 256
S7MPI.EscribirBytesDB(10, 42, 10) 'DB10, 10 bytes a partir de la dirección 42
Una vez terminadas la operaciones debemos Desconectar, si no se quedará el puerto serie ocupado.
S7MPI.Desconectar()
El proyecto completo en Visual Basic lo tienes aquí. Si lo ejecutas tendrá el siguiente aspecto:

Con Libnodave viene documentación que deberás leer para adaptar el código a otros adaptadores. En mi caso, al inicializar el adaptador tuve que cambiar el protocolo a daveProtoMPI2 para que funcionase.

Aunque en mi ejemplo solo leo y escribo de bloques de datos se puede acceder a más áreas de memoria, habría que completar las funciones de la clase. Si alguien completa el código me gustaría echarle un vistazo.

La velocidad de comunicación no es muy buena, el adaptador serie/MPI se comunica con el PC a 19200 baudios, lo cual constituye un cuello de botella. Libnodave también permite la comunicación Ethernet, si tengo ocasión la probaré, el incremento de velocidad tiene que ser notable.

Actualización: en esta entrada pruebo Libnodave a través de ethernet.

En resumen, el autor de Libnodave ha hecho un trabajo fantástico, en las pruebas ha tenido un comportamiento impecable. Sin embargo no debemos olvidar que no tiene el soporte de una empresa detrás y que si lo usamos es por nuestra cuenta y riesgo.

Cualquier comentario será bienvenido.

39 comentarios:

  1. Muy buen Tutorial, y de lo poquito que hay en Castellano sobre libnodave, un muy buen recurso. Muchas gracias

    ResponderEliminar
  2. hola soy martin de uruguay,
    debo hacer un proyecto de una aeronave programada para que ralize determinado vuelo, puedo aplicar esta tecnologia para dicho proyecto?
    saludos, y valoro tu ayuda

    ResponderEliminar
  3. Hola Martín,

    No das muchos detalles de tu proyecto, pero si lo que ves en este blog te sirve adelante.

    Un saludo y suerte.

    ResponderEliminar
  4. Hola GR,

    Buen tutorial!
    Yo estoy programando una aplicacion con C# y necesito conectarme via S7ONLINE y no lo he conseguido. Con los otros protocolos si que me ha ido pero con el runtime este no.¿Has provado de usarlo?

    Yo por este tema al final he tenido que usar las PRODAVE de Siemens :(

    Saludos

    ResponderEliminar
  5. Buen tutorial para empezar,
    Yo estoy intentado hacer lectura de DB's por ethernet y con java, he intentado aclararme con el libnodave (no veas que curro) y intentar implementarlo en java, pero estoy llegando al punto de que no se como he de enviar la o las PDU.
    Alguien puede aclararme un poco el uso de las PDU y su estructura para S7/300.

    Saludos y gracias por anticipado

    ResponderEliminar
  6. Estimado, muy buen tutorial, queria consultarle si con estas librerias se puede acceder a un S7-1200. Muchas gracias. Saludos.

    ResponderEliminar
    Respuestas
    1. Este comentario ha sido eliminado por el autor.

      Eliminar
    2. Hola quizás sea un poco tarde para contestar a tu cuestión: si, es posible. Al menos yo he conseguido acceder para leer/escribir las entradas y salidas del 1200 empleando una configuración idéntica a la que se usaría para un S7300. (Programando en VB.Net)

      Si estás interesado, visita la página de nuestro proyecto: Automatizaciones Reales de Máquinas Virtuales. (www.armv.es)

      Un saludo

      Eliminar
    3. Hola necesito obtener datos de un S7-1200 para almacenarlos en una base de datos, soy relativamente nuevo podrías asesorarme???

      Eliminar
  7. Pues no lo sé, en la página de LibNoDave no pone nada y no tengo ningún 1200 para hacer pruebas.

    Un saludo.

    ResponderEliminar
  8. Yo sigo con mis pruebas en java y queria preguntar si con el libnodave hay que configurar algo en el PLC.
    Yo por el momento he conseguido conectar el socket pero no leo ningún byte.

    Si alguien me puede responder estaría muy agradecido.
    Saludos.

    ResponderEliminar
  9. Perdonar, la conexión es via TCP/IP

    ResponderEliminar
  10. Hola. respondo a akyra:

    Yo tengo ya desarrollado un servidor en Java que utiliza libnodave y permite leer y escribir datos en un plc S7-300 desde un cliente remoto, a travñes de este servidor.
    El componente es ya operativo, si bien tengo un problema a la hora de visualizar los valores leídos con getFloat (REAL en plc), dado que no consigo ver los valores en otro formato que no sea representación científica (0.8345E5, por ejemplo). Salvo este inconveniente, el resto tengo muy claro cómo debe hacerse y ya lo tengo implementado (servidor y cliente de prueba).

    Si estás interesado, podemos intercambiar experiencias. Mi intención es desarrollar un SCADA GNU que pueda correr de manera remota en diferentes plataformas.

    Saludos.

    A. Sancho

    alfredo_sancho@telefonica.net

    ResponderEliminar
    Respuestas
    1. Hola Alfredo. Tengo la misma idea que tu, pero mis conocimientos en Java son mas bien escasos, lo que no me impide que quiera intentarlo. Te deseo buena suerte y espero que puedas ayudarme con mi proyecto.

      Saludos.

      Eliminar
  11. Hola Alfredo,
    Me parece interesante tu idea, yo hace años estuve haciendo uno con VB6 y no es fàcil.

    Yo actualmente no estoy trabajando habitualmente con PLC's, profesionalmente estoy más metido en temas de scada de Wonderware (Archestra IAS), pero si te puedo ayudar, encantado.

    Saludos

    ResponderEliminar
  12. Bueno, la verdad es que estoy asombrado de esta entrada. Muy buen tutorial, aunque a mi me cuesta un poquito entender algunas cosas. Al final todo se consigue.

    Mi objetivo en conseguir enlazar un scada basado en Delphi 7 con un plc de siemens a traves del protocolo MPI.

    Una pregunta, ¿sabes de algun drive que no sea libnodave y que tenga respaldo tecnico, pero que sea de libre distribucion?

    Me reconozco ya un tanto mayor y me cuesta entender algunos terminos y necesitaria ayuda.

    Un saludo y muchos animos para que continues publicando todos tu trabajos.

    ResponderEliminar
  13. Hola Paco, comercialmente Siemens tiene disponible Prodave http://support.automation.siemens.com/WW/llisapi.dll?func=cslib.csinfo&lang=es&objid=6ES78074BA020YA0&caller=view

    Espero que te sirva, un saludo.

    ResponderEliminar
  14. Buenas, soy nuevo en todo esto, lo mío es la programación en .net pero me interesa mucho el tema de los PLCs.
    Mi pregunta es la siguiente ¿se podría aplicar esta biblioteca o librería, y por consiguiente este tutorial, para un PLC Twido?

    Gracias, un saludo.

    ResponderEliminar
  15. Esta biblioteca está diseñada para PLC Simatic y no te serviría. Desconozco los Twido, pero imagino que podrás usar tecnología OPC para acceder a sus datos.

    Un saludo.

    ResponderEliminar
  16. Saludos.
    Una pregunta al foro. ¿Hay alguna forma de conetarse usando un cable MPI-USB?

    Gracias

    ResponderEliminar
  17. Hola muy buenas tardes...me parecio muy bueno el tutorial..mi consulta es la siguiente. ¿con esta libreria puedo conectarme,desde un plc s7-200 a visual 2010?..

    ResponderEliminar
    Respuestas
    1. Pues sí, según pone el la web de libnodave: also supports S7-200 family via PPI-cable

      Un saludo.

      Eliminar
    2. hola buenas tardes, mi pregunta es la siguiente ¿ CON un plc s7200 puedo acceder directamente a una de base de datos como sql server 2008 o mysql server, de esta forma insertando y leyendo datos ?

      Eliminar
    3. No, el plc no accede a ningun lado es al contrario. Para acceder a los datos del plc necesitas un programa como el opc server o como este libnodave y de estos obtienes los datos para llenar la base de datos

      Eliminar
  18. tengo un problema con un panel siemens de una maquina y me da error 700000 dice que no tiene configurado el plc y me gustaria saber que se debe hacer

    ResponderEliminar
  19. que bienn le exare mano a estaaa solo por curiosidad

    ResponderEliminar
  20. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  21. consulta el cable mpi es el mispo que ppi?

    ResponderEliminar
  22. ciao funziona perfettamente, mi potresti indicare come leggere una Dword ?
    esempio :

    DB80.DBD 10

    Grazie pel l ' aiuto
    Marco , from italy

    ResponderEliminar
  23. hola funciona perfectamente, podría indicar cómo leer un DWORD?
    ejemplo:

    DB80.DBD 10

    Gracias por la ayuda "
    Marco de italia

    ResponderEliminar
  24. Hola, estuve intentando correr el programa que subes, y no obedece a ningún puierto COM
    Sale el mensaje de "error al abrir la conexión MPI (y salen unos cuadritos)

    Estoy trabajando desde una máquina virtual con XP

    Tengo un adaptador MPI/USB

    ¿Por qué puede pasar esto?


    Necesito ayuda urgente.

    ResponderEliminar
    Respuestas
    1. Que yo sepa no se pueden usar adaptadores USB/MPI. Deben ser Serie/MPI o usar una conexión ethernet.

      Un saludo.

      Eliminar
  25. Hola, muchas gracias por compartir tu conocimiento para ayudarnos a entender a otros.
    Tengo una duda: he implementado un sistema de control completo para automatizar una planta de mezcla de hormigón a través de visual c# y libnodave en un S7-1200, ahora estoy tratando de comunicar unos indicadores de peso por RS485, en la DB3 en la posición 554.0 tengo la variable tipo string que recibe la trama RS485, sabes como leer un string con libnodave?
    Muchas gracias si me puedes ayudar en algo.

    ResponderEliminar
  26. Hola, muchas gracias por compartir tu conocimiento para ayudarnos a entender a otros.
    Tengo una duda: he implementado un sistema de control completo para automatizar una planta de mezcla de hormigón a través de visual c# y libnodave en un S7-1200, ahora estoy tratando de comunicar unos indicadores de peso por RS485, en la DB3 en la posición 554.0 tengo la variable tipo string que recibe la trama RS485, sabes como leer un string con libnodave?
    Muchas gracias si me puedes ayudar en algo.

    ResponderEliminar
  27. Buenos días, GR.

    Te cuento que en un grupo de estudio en la universidad logramos conectar via OPC con un Siemens S7-200 y lo logramos, pero fue usando el programa PC-Access de Siemens que trabaja con el S7-200. En el momento queremos conectar via OPC con PLC Siemens S7-300 pero no tenemos un programa como el PC-Access de Siemens que funcione con éste y queremos usar una alternativa que sea libre y/o gratuita.

    ¿Crees que podríamos usar esta librería de alguna forma para lograr dicho objetivo?

    ResponderEliminar
  28. http://s7net.codeplex.com/ hay teneis..

    ResponderEliminar
  29. Desde una virtual corriendo plcsim no conecta el programa en vb...que puede ser?

    ResponderEliminar
  30. Hola. una pregunta: tengo que hacer un escada en visual basic, un escada donde tengo que leer un archivo CAD y transfierirlo al un NJ, Omron. la pregunta es: hay que darle una extension al proiecto de visual basic o solamente con lo que le pones el IP y las variables ya comunica?

    ResponderEliminar

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