Comunicación PLC Mitsubishi - Python | protocolo MC
Miguel Gómez | Revisado por Jhon ValenciaSe presenta la comunicación vía ethernet de un computador con un PLC Mitsubishi Electric MELSEC-F Series, modelo FX3GE, usando el módulo socket nativo de Python para enviar las solicitudes y recibir la respuesta del PLC, ya que proporciona una comunicación entre procesos-IPC. Se emplea el protocolo MC con conexión TCP/IP en formato hexadecimal de código ASCII y se usa GX Work2 para cargar la configuración al PLC.
Antes de comenzar con el código, analicemos el problema al que nos enfrentamos: En esencia se requiere enviar un mensaje, para ello se necesita de: un emisor, un receptor, un medio, y un protocolo de comunicación.
┌─────────────────┐ ┌───────────────────┐
│ │ │ │
│ │ │ │
│ ├───────────────────────────► │
│ Computador │ │ PLC │
│ (Emisor) │ Ethernet (Medio) │ (Receptor) │
│ ◄───────────────────────────┤ │
│ │ │ │
│ │ │ │
└─────────────────┘ └───────────────────┘
¿Protocolo de comunicación?
A nivel de hardware se requiere del computador, el cable ethernet y el PLC; la referencia del PLC ya cuenta con un módulo para conexión ethernet, por lo tanto, no es necesario incluir uno.
El rango de protocolos de comunicación se limita a los que maneje el PLC, por lo que el siguiente paso es revisar la documentación disponible por el fabricante:
- Manual de usuario FX3U-ENET-L User's manual. Para conocer el procedimiento de comunicación con el que trabaja.
- Manual de entrenamiento Ethernet course(Q-series). Aunque es de la serie Q, se utilizan los protocolos de comunicación que vamos a revisar, aparte de suministrar conceptos importantes.
Procedimiento de comunicación
En ocasiones no se le suele prestar la debida atención a los manuales, y se comienza por hacer pruebas con librerías en distintos lenguajes y código que se encuentra en internet (lo resalto porque así fue como empecé a realizar pruebas, y de hecho encontré este articulo [1], el cual fue de gran ayuda, por lo que agradezco al autor).
En el capítulo 5 del manual de usuario se identifica que, el módulo de ethernet del PLC soporta:
- Comunicación usando Fixed buffers.
- Comunicación usando el protocolo MC (MELSEC).
- Envío/recepción de email.
- Conexión MELSOFT.
Pero, en una nota aclara, que solo los dos primeros permiten solicitudes de datos desde un dispositivo externo:
The following communication can be performed with an open device on other end.
• Communication using MC protocol
• Sending/receiving in fixed buffer communication (procedure exists)
When receiving communication request data from an external device
— Section 5.1 Overview of the Communication Procedure; FX3U-ENET-L User's manual.
Veamos grosso modo las características de estas dos opciones:
- MC Protocol (MELSEC protocol). Permite a cualquier dispositivo externo (nuestro computador personal por ejemplo) leer o escribir datos desde o hacia el PLC, o ejercer control remoto (RUN/STOP) mediante el módulo ethernet; es un modo de comunicación pasivo, de tal forma que es el dispositivo externo quien da las ordenes de lectura/escritura, y para ello puede usar cualquier lenguaje de programación que proporcione una comunicación entre procesos-IPC.
- Fixed buffer comunication: Permite al PLC comunicarse con otros PLC o con un dispositivo externo usando los búferes fijos en la memoria búfer del módulo de ethernet, por lo que es una comunicación activa y esa es una diferencia con respecto al protocolo MC.
Si desea indagar en cada protocolo, puede revisar la sección 2.2 Types of Data Comunication Functions del manual de entrenamiento.
Para el presente caso, se decide usar el protocolo MC por el control sobre los espacios de memoria y la sencilla configuración del PLC, la cual se va a presentar a continuación, y con ello iniciar el desglose de la estructura de la solicitud que se enviará al PLC.
Protocolo MC
La transmisión de datos en el protocolo MC se realiza en modo semidúplex por lo que cuando se esté enviando un mensaje desde el computador, el PLC estará escuchando, y tendremos que esperar hasta recibir una respuesta del PLC antes de poder enviar el siguiente mensaje; la comunicación se puede usar tanto TCP/IP como UDP y son compatibles tanto en código binario como en formato hexadecimal de código ASCII.
Lado del portátil ┌─────────┐ ┌─────────┐
│ Mensaje │ │ Mensaje │
─────────────────────┴─────────┼───────────┼─────────┼───────────┬──►
│ Respuesta │ │ Respuesta │
Lado del PLC └───────────┘ └───────────┘
Configuración del PLC
Se configura el PLC con GX Work2 para la comunicación mediante TCP/IP con el protocolo MC, empleando formato hexadecimal de código ASCII.
Para el ejemplo le asignaré al PLC la dirección IP 192.168.15.34 y el puerto 5000. En la figura 1 y 2 se ilustra el paso a paso de la configuración que se cargará al PLC luego de iniciar un nuevo proyecto en GX Work2.


Configuración del PC
En el computador se requiere:
- Instalar Python, si está en Windows lo puede descargar la Microsoft Store, o directamente desde la web oficial.
- Habilitar el puerto para entrada y salida de datos. Para Windows, en la configuración avanzada del firewall, agregar 2 REGLAS, una regla de entrada y una de salida con la misma configuración: seleccionar la comunicación TCP en el puerto que elija (
5000para este caso), y seleccionar en permitir la conexión, puede seguir la guía de Microsoft, para el paso a paso.
Estructura de la solicitud (request)
La estructura del mensaje se especifica en la sección 9.1.2 Message format and control procedure del manual de usuario, globalmente consiste en una cabecera seguida de los datos de la aplicación, para el mensaje se ignora la primera ya que en la cabecera se especifican los datos de configuración de la conexión, TCP o UDP, dirección IP, pero, eso no se escribe directamente en el mensaje, desde la configuración del socket se establece.
En la figura 3 se presenta la estructura de la lectura y escritura tanto del mensaje enviado desde el PC, hasta la de la respuesta del PLC.

Para no extenderme, el ejemplo del post se limita solo a lectura del PLC, en una próxima entrega se hará un proceso de lectura y escritura con mas detalle. Notará que la diferencia radica en agregar los datos a escribir al final de la solicitud del mensaje, y que la respuesta del PLC se limita a indicar si se escribió exitosamente o no.
Solicitud de lectura
Para comprender la lectura y cada parte de los datos del mensaje, voy a partir del ejemplo de la pág. 9-10 del manual de usuario, en el que se leen los registros del relé interno M (el cual son marcas en memoria que se pueden usar durante el programa del PLC) en el rango de M100 hasta el M108.

En la figura 4, se aprecian las partes de los datos de la aplicación, divida según la función que cumple cada sección de bytes que se especifica en el mensaje. Recordemos que de aquí en adelante nos referiremos siempre al formato hex de código ASCII . Pasemos por cada una:
1. Subheader 2 bytes. Indica la función que se requiere realizar, leer, escribir, testear, o controlar el PLC; en algunos casos decidir si los datos son bits o words (2 bytes). En la tabla 1 se encuentra la pareja de bytes correspondientes de acuerdo con la función, que para lectura en bits de nuestro ejemplo es la 00.

2. PC number 2 bytes. Valor por diseño fijo en FF.
3. Monitoring timer 4 bytes. Periodo máximo de tiempo que se configura al módulo ethernet de espera para una solicitud y poder regresar un resultado.
0000 < - - - Esperar indefinidamente hasta que el PLC responda
┌─────────────┬───────────┬────────────────┐
│ Hexadecimal │ Decimal │ Milisegundos │
├─────────────┼───────────┼────────────────┤
│ │ │ │
│ 0001 - FFFF │ 1 - 65535 │ 250 - 16383750 │
│ │ │ │
├─────────────┴───────────┴────────────────┤
│ Recomendación para comunicación de datos │
├─────────────┬───────────┬────────────────┤
│ │ │ │
│ 0001 - 0028 │ 1 - 40 │ 250 - 10000 │
│ │ │ │
└─────────────┴───────────┴────────────────┘
Para el ejemplo se usan 000A equivalente a 2.5 segundos.
4. Device name 4 bytes. Tipo de registro al que vamos a realizar lectura/escritura, para el ejemplo inicial, se usa el 4D20 el cual corresponde al relé interno M.

5. Head device number 8 bytes. Indica el registro de partida para leer/escribir datos. en el ejemplo se requiere iniciar leyendo en el M100, 100decimal son 0x64 en hex, y rellenamos con ceros el resto de los bytes 00000064.
6. Number of device points 2 bytes. Número de registros a leer/escribir desde el punto de partida definido en el Head device number, para el ejemplo, leer entre el 64 al 72, corresponde a 8 registros, por lo que se escribe 08.
Los últimos dos bytes que están en 00 se emplean para completar el último octeto de bytes, y enviar 3 octetos <==> 24 bytes. que para el ejemplo quedaría:
msg:= 00FF000A4D20000000640800
La respuesta, también tiene un subheader de 2 bytes, seguido de un código de 2 bytes que indica si la comunicación fue completa 00 o anormal 5B, si es anormal, aparecerán otros 2 bytes indicando el código del error ocurrido, como se ilustra en la figura 7.

Ya se configuró el PLC y se comprende la estructura del mensaje (eso espero), ¡es hora de probarlo en Python!
¡Código!
Se va a enviar el mensaje escribiendolo directamente con la estructura hexadecimal previa, más adelante se podrá parsear para tener una entrada de datos cómoda.
Revisando la documentación del módulo socket, para la creación del socket, se requiere crear el objeto para el cliente que será nuestro PC con la clase socket.socket() y se ingresaran como argumentos:
- La dirección de la familia, que para el caso es
IPv4por lo que se usa la constante socket.AF_INET. - El tipo de socket, se usa el socket.AF_INET ya que la comunicación es TCP/IP.
Vamos a solicitar leer words con un tiempo máximo de espera de 2.5 segundos el registro de datos D135 del PLC, el mensaje queda estructurado como en la figura 7.

Y para corroborarlo desde el GX work2 vamos a modificar el registro D135, colocando el valor 2328.
import socket # IP y puerto que deben ser iguales a los definidos en el PLC HOST = '192.168.15.34' PORT = 5000 # Crear el cliente con el que se enviarán y recibirán los datos client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Conectar el cliente a la IP en el puerto especificado client.connect((HOST, PORT)) # El mensaje debe usar el tipo de dato bytes # por eso se agrega el prefijo "b" en lugar de almacenarlo como string msg = b'01FF000A4420000000870100' # Se convierte a tipo de dato bytearray to_send = bytearray(msg) # Se usa el método send() del cliente y luego el recv() # para traer la respuesta client.send(to_send) res = client.recv(1024) # Se imprime la respuesta print(res) b'81002328'
¡La respuesta 8100 indica una comunicación exitosa!, y efectivamente el valor de la respuesta es de 2328.
Ya se aprendió a realizar una comunicación de lectura sencilla con el PLC. En el próximo post realizaremos una comunicación más compleja de lectura y escritura.
Referencias
[1] Mitsubishi PLC communication python code
[2] Socket Programming in Python (Guide)
[3] Manual de usuario FX3U-ENET-L User's manual
[4] Manual de entrenamiento Ethernet course(Q-series)