PLC en Raspberry PI: classicladder

El proyecto «classicladder» consiste en un PLC (en inglés Programmable Logic Controller, autómata programable o solo autómata en español) programable en ladder (diagrama de contactos en español) o en grafcet. También integra un entorno de monitorización y comunicaciones, incluyendo MODBUS para las entradas y salidas. Esta escrito en C y usa el entorno GTK+2, puede compilarse para Windows y para Linux.
El autor de este programa es Marc Le Douarain, yo he hecho pequeñas contribuciones: https://sites.google.com/site/classicladder/
El software interpreta el programa, al contrario que otros PLCs que ejecutan código compilado en un PLC virtual, y es totalmente funcional. Es posible ejecutar el software en una máquina sin entorno gráfico y controlarlo desde otra con entorno gráfico mediante comunicaciones (tcp/ip o serie).
Compilarlo para Raspberry pi no debería ser dificil, corre un linux.

Trabajando en la propia raspberry pi con conexión a internet, primero descargamos los fuentes en C de la última versión a 18/2/2013 classicladder 0.9.6 desde el directorio de usuario PI:
«wget http://sourceforge.net/projects/classicladder/files/classicladder/classicladder-0.9.006.tar.gz»
Y lo descomprimimos con:
«tar -xvzf classicladder-0.9.006.tar.gz»
Esto crea el arbol de diecorios en ~/classicladder, ahora cambiamos los permisos de los ficheros, por seguridad.
Entrar en el directorio:
«cd «~/classicladder/projects_examples»
y hacer
«chmod 644 *»
Salir al directorio «~/classicladder»:
«cd ..»
y hacer:
«chmod 644 *»
«chmod 755 projects_examples»

Ya tenemos todos os fuentes listos.
Ahora podemos compilar el software CON o SIN entorno gráfico. Si lo hacemos sin entorno gráfico no podremos controlar el PLC classicladder si no es comunicándolo con otro classicladder que si tenga entorno gráfico.

Para compilar con entorno gráfico es necesario instalar las librerías del entorno GTK+2:
«sudo apt-get install libgtk2.0-dev»

Ya esta todo listo, compilar simplemente ejecutando make desde el directorio de los fuentes, el makefile que acompaña al royecto ya esta configurado para linux y funcionará perfectamente en la raspberry pi:
«cd «~/classicladder»
«make»
Esto habrá creado un fichero ejecutable «classicladder». Ya podemos probarlo ejecutarlo «./classicladder». Se desplegrán varias ventanas y podremos ver el estado del PLC…:

Escritorio de raspberry con classicladder

Podemos salvar esta versión del ejecutable con entorno gráfico con otro nombre:
«cp classicladder classicladder_gtk»

Para compilarlo SIN entorno gráfico y usarlo como aplicación embebida, mucho mas ligero (la aplicación gráfica con GTK+2 consume bastante CPU de la raspberry), hay que modificar un para de cosas en el fichero «Makefile»:

Comentar la siguiente línea:
«GTK_INTERFACE = 1» -> «#GTK_INTERFACE = 1»
Esto le dice al makefile que compile el proyecto SIN entorno gráfico.
Comentar las siguientes líneas:
«OWN_CFLAGS = -march=i486» -> «#OWN_CFLAGS= -march=i486»
«OWN_LIBS = -march=i486» -> «#OWN_LIBS = -march=i486»
Estas líneas son específicas para entornos intel x86, nosotros vamos a compilarlo para ARM.
Salvar el fichero modificado, hacer:
«make clean»
para limpiar cualquier compilación anterior y compilar de nuevo con:
«make»
Se habrá creado un nuevo ejecutable «classicladder».

Para que funcione correctamente en modo embebido SIN entorno gráfico hay que crear un directorio donde se almacenarán los programas recibidos y donde classicladder buscará para cargar automáticamente el programa en el arranque:
«cd /usr/local»
«md classicladder»
Esto creará un directorio «/usr/local/classicladder»

Ejecutar classicladder desde el directorio donde se creó:
«cd ~/classicladder/
«./classicladder»
Podremos ver una serie de mensajes y al final «SOCKET WAITING». Este será el PLC tarjet y ya esta funcionando y esperando órdenes. Ahora podremos comunicarnos con este PLC desde otra máquina con entorno gráfico.
Conectar la red a la raspberry y hacer «ifconfig» para ver su IP, si no la hemos anotado cuando arrancó.
En otro PC o raspberry arrancar el classicladder con entorno gráfico.
Cargar un programa con File->Load
Transferirlo al PLC tarjet con PLC->FileTransfer->Send Current Project To Tarjet y poner la IP del PLC tarjet (la raspberry pi).
Una vez que el PLC tarjet tenga el programa cargado arrancará en RUN cada vez que arranquemos classicladder en la raspberry pi.
Ahora podremos hacer PLC->Connect y poner la IP del PLC tarjet para monitorizar el estado y las variables del PLC. También podemos pararlo etc.

Podrá verse en el PLC tarjet distintos mensajes durante la recepción de datos.
Si todo va bién el programa recibido se grabará en «/usr/local/classicladder/nombredelprograma.clprjz»

CONECTANDOLO CON EL MUNDO REAL
Vale, esto es muy bonito, pero ¿y controlar directamente entradas y salidas reales desde la reaspberry pi y classicladder?. En principio basta con conectar el puerto serie de la raspberry, en el conector P1 pines 6(GND), 8(TXD) y 10(RXD) a cualquier dispositivo que use protocolo MODBUS (con el adaptador de nivel adecuado, la raspberry pi usa TTL a 3,3V).
Se puede usar un módulo IO MODBUS el propio autor del programa Marc Le Douarain: https://sites.google.com/site/classicladder/classicladder_io_module
También se pueden usar módulos ADAM de Advantech: http://www.advantech.es/producto/adquisicion-de-datos/data-acquisition-modules

Los pines tienen dos nombres: uno el original del chip (broadcom) y otro el que da el sistema operativo (raspberry pi):
Pines GPIO

¿Y por que no usar los pines GPIO directamente?. Son pocos, y puede que nos interese usarlos para mas cosas… pero como hace años ya diseñé una placa de ampliación de I/O (SIO) basada en registros de desplazamiento voy a revivirla y usarla aquí!!!!
Esta es el esquema adaptado a la raspberry pi, hay que conectar 8 hilos del conector P1 (6 señales y dos de alimentación) y listo.:

Esquema Shifted Input Output
Esquemas Eagle: https://heli.xbot.es/wp-content/uploads/2014/01/Raspberry_SIO.zip

La placa de registros de desplazamiento queda alimentada desde la raspberry pi. Ahora hay que modificar classicladder para que use este hardware. Hay varias formas de usar los GPIOs de la raspberry pi:
Mediante el sistema de archivos virtual «/sys/class/gpio»
Usando una librería como: http://www.open.com.au/mikem/bcm2835.
Accediendo directamente al hardware, esta es la que yo usaré: http://elinux.org/RPi_Low-level_peripherals#GPIO_Driving_Example_.28C.29
Despues de escribir el código mostrado y hacer unas pruebas veo que puedo escribir en los puertos sin problemas. Pero ¿y leer?. No hay ninguna función para leer los puertos en el ejemplo… Busco la datasheet del chip bcm2835 y busco el periférico GPIO. Perfecto en el apartado 6.1 (página 90), describe las direcciones de memoria donde estan mapeados los GPIOs, los pines se pueden en el offset 34h desde el inicio del mapa de GPIO. Como los accesos a memoria a 32 bit, para acceder a la dirección 34h usaré (gpio+13) porque (13*4) = 53d = 34h
Por lo tanto para leer los 32 GPIOs sería (g es el número de GPIO 0-53, gpio es la dirección base del periférico):
PINS_READ(g) *(gpio+(13+(g*3)) // Lee los 32 bits donde esta incluido el GPIO g
y para leer un pin individual:
PIN_READ(g) (((*(gpio+13)) & 1<< g)==1<< g) // Retorna el estado del GPIO g: 0 or 1 Me ha costado mucho que esto funcione, aunque hay mucha información acerca de la raspberry pi es dificil reunirla de forma consistente. Un problema que me ha hecho perder varias horas picando código y mirando con el osciloscopio es que el pin 13 de P1 (GPIO21 según Broadcom, o GPIO2 según Raspberry pi) en la versión V2 esta conectado a GPIO27 (según broadcom). El sistema operativo de la raspberry lo mapea a GPIO2 igual que en las V1, pero si se accede al hardware y no se usa el sistema operativo hay que tenerlo en cuenta!!! Ahora solo hay que incluir todo lo probado en el fichero "hardware.c" de classicladder y modificar "Makefile" para que se pueda compilar con o sin este hardware experiemental. Mis versiones de Makefile y hardware.c: https://heli.xbot.es/wp-content/uploads/2014/01/Makefile_y_hardware.zip
En Makeile ahora hay dos nuevos switches:
RASPBERRY_PI = 1
Si no se comenta con # al principio compila para raspberry pi.
MAKE_SIO_ACCESS = 1
Si no se comenta con # al principio compila con el hardware experimental SIO, esta opción puede usarse también para windows y para linux en entorno PC usando el puerto paralelo. Es similar a MAKE_IO_ACCESS.
Descargarse mi version desde la raspberry pi en el directorio «~/classicladder»:
«wget https://heli.xbot.es/wp-content/uploads/2014/01/Makefile_y_hardware.zip»
descomprimirla:
«unzip Makefile_y_hardware.zip»
Contestar «yes» cuando nos pregunte que si sobreescribe los ficheros existentes.
Compilarla:
«make»
Ahora para ejecutarla hay que hacerlo como superusuario. Esto es así porque necesita acceder a la menoria física del sistema (para leer y escribir en los GPIOs). Supongo que también funcionaría si el usuario tiene permisos de lectura y escritura sobre el dispositivo «/dev/mem».
«sudo ./classicladder»
Si alguien esta interesado en inspeccionar el código, las modificaciones hechas en «hardware.c» estan entre las directivas
#if defined (MAKE_SIO_ACCESS) – #endif

Asi se ve la placa SIO con la raspberry pi funcionando:
Esquema Shifted Input Output

CLASSICLADDER CON SIO EN PC
También podemos compilarlo para PC, si comentamos:
#RASPBERRY_PI = 1
en makefile. Si vamos a compilar bajo windows descomentamos:
WINDOWS = 1
Si lo hacemos bajo linux es necesario dejarlo comentado:
#WINDOWS = 1
Para usar el la placa SIO conectada al puerto paralelo hay que poner en «hardware.c» la dirección física del puerto LPT del PC:
#define SIO_PORT 0x378 // Base port for PC hardware LPT1, LPT2=0x278, LPT3=0x3BC
Y usamos este cable para conectar el PC con la placa SIO:

Esquema Shifted Input Output
Esquemas Eagle: https://heli.xbot.es/wp-content/uploads/2014/01/Raspberry_SIO.zip (El fichero contiene los dos esquemas, placa SIO para raspberry pi y cable PC).

El software es experimental, los parámetros de configuración deberían poder modificarse a través de los menús de «config_gtk.c», y estar definidos en «classicladder.h» en la estructura «infos_gene», por ejemplo. Pero para comenzar sirve…

He comprobado que con la raspberry pi es muy estable, sin embargo bajo windows se producen glitches periódicos que desactivan las salidas… Bajo linux (suse 12) también, pero en menor medida.
En windows con mas de un procesador va francamente mal, he tenido que incluir código para forzar el proceso en una sola CPU:
SetProcessAffinityMask(GetCurrentProcess(), 1); // Ejecutar solo en la CPU #1
Supongo que estos problemas son debidos al entorno multitarea, este mismo hardware con un micro PIC, atmel o similar y las mismas rutinas funciona perfectamente.

Yo no he usado una placa completa de 32 salidas y 32 entradas, sino una mas pequeña pero con entradas optoaisladas y con relés en las salidas (16 entradas y 8 salidas).