Para comandar el cilindro se pueden elegir diversos tipos de electroválvulas, las más habituales son las de dos posiciones (monoestables o biestables) o tres posiciones (centros cerrados o centros a escape).
Su programación casi siempre sigue las mismas pautas, así que he programado un bloque de función (FB) donde está todo el código repetitivo. Aquí cada programador tiene sus propias manías y preferencias, el código que pongo a continuación es el que me resulta más cómodo, pero supongo que para otros no será la mejor solución. Una llamada al FB en cuestión tiene el siguiente aspecto:
Lo primero es indicar qué entradas y salidas digitales están asignadas al cilindro. Si comandamos el cilindro con una electroválvula monoestable solo será necesaria una salida (la que realiza el movimiento de avance). También puede suceder que no tengamos algún detector o ninguno de los dos, en cuyo caso la detección se hará temporizando la activación de la salida digital correspondiente.
Para poder realizar un movimiento este debe ser seguro, para ello están las entradas de permisos PERM_AVANCE y PERM_ORIGEN, que deben estar activadas para poder iniciar los movimientos de avance y retroceso; por ejemplo, en el caso de tener dos cilindros que avanzados simultáneamente colisionarían, uno de ellos solo podrá avanzar si el otro está en origen.
La entrada de SEGURIDAD debe estar a uno para que las salidas puedan activarse. Si esta señal cae, las salidas caerán también. Lo normal sería poner aquí las condiciones de emergencia de la máquina.
La entrada MANTENER sirve para mantener activadas las salidas al acabar el movimiento. Puede ser interesante si tenemos electroválvulas monoestables o de tres posiciones. Recientemente, en una de nuestras máquinas, un cliente nos solicitó sustituir, por motivos de seguridad, las electroválvulas biestables por electroválvulas de tres posiciones con centros a escape. Toda la modificación que habría que hacer en programa sería pasar la entrada MANTENER de cero a uno.
A continuación vienen tres entradas más de configuración: SIN_DET_ORIGEN, SIN_DET_AVANCE y SIN_SAL_ORIGEN, para especificar si tenemos detección de origen, detección de avance y salida de origen respectivamente.
Es habitual que los detectores tengan una temporización para garantizar que los movimientos se completen. Estos tiempos deben ser suficientes para que, si el detector está mal posicionado, el cilindro lo sobrepase sin completarse, para así poder avisar del fallo. Son las entradas T_ORIGEN y T_AVANCE. En el caso de que no exista algún detector, estos tiempos se usarán para temporizar la salida correspondiente, para simular la detección.
No es raro que te llamen por alguna incidencia en una máquina en la que algún detector falla. Si no disponemos de un repuesto y la máquina tiene que ponerse en marcha, como solución provisional se puede temporizar la salida digital del movimiento. Recuerdo un caso en el que un compañero, para probar una máquina, tuvo que temporizar todas las salidas de control de los cilindros.
Como última entrada del FB está el tiempo T_LIMITE, que sirve como timeout para los movimientos. Si un movimiento, de avance o retroceso, no se completa en este tiempo se indica un error.
Una aclaración: este FB no consume temporizadores SIMATIC, gestiona internamente los tiempos. Y el formato de tiempos es TIME, no usar S5TIME.
Como salidas del FB, aparte de especificar las salidas digitales SAL_ORIGEN y SAL_AVANCE, tenemos indicaciones de si el cilindro está en origen o avanzado (EN_ORIGEN, AVANZADO) y de si hay algún error y el código de error correspondiente.
Los códigos de error son los siguientes:
0 - Sin error
1 - Fallo en la vuelta a origen: en un movimiento de vuelta a origen el cilindro no ha activado la detección de origen en el tiempo límite. El cilindro no puede hacer el movimiento o hay algún problema con el detector.
2 - Fallo en el avance: como el fallo de vuelta a origen
3 - Detección simultánea: se dan los dos detectores a la vez.
4 - Activaciones simultáneas: las órdenes de avanzar y de vuelta a origen están activadas a la vez (por tanto no se hace caso a ninguna de ellas).
5 - Detección de origen sobrepasada: en el movimiento de vuelta a origen se ha rebasado la señal del detector de origen (el detector debe tener una temporización suficiente para ser efectiva). Quiere decir que detector está mal colocado.
6 - Detección de avance sobrepasada: como el caso anterior.
El FB está programado en diagrama de contactos (KOP). Para poder importarlo a tu proyecto, incluye el código en la carpeta fuentes de tu proyecto de Step7 y compílalo. Aparecerá en AWL, para pasarlo a KOP asegúrate que tienes la comprobación de tipos de operando desactivada:
Actualización: también tienes el código en este proyecto de Step7.
El código en cuestión es:
FUNCTION_BLOCK FB10
TITLE =CONTROL DE UN CILINDRO NEUMÁTICO DE DOBLE EFECTO
//CONTROLES DE LAS SEÑALES PARA MANEJAR UN CILINDRO NEUMÁTICO DE DOBLE EFECTO
//MEDIANTE UNA ELECTROVÁLVULA MONOESTABLE, BIESTABLE O DE TRES POSICIONES
//
//SE CONTROLAN TIEMPOS SIN CONSUMIR TEMPORIZADORES SIMATIC
//
//http://notasdeautomatizacion.blogspot.com
VERSION : 0.1
VAR_INPUT
DET_ORIGEN : BOOL ; //DETECTOR DE POSICIÓN EN ORIGEN
DET_AVANCE : BOOL ; //DETECTOR DE POSICIÓN AVANZADA
A_ORIGEN : BOOL ; //ORDEN DE CILINDRO A ORIGEN
AVANZAR : BOOL ; //ORDEN DE AVANCE DE CICLINDRO
SEGURIDAD : BOOL ; //SE DAN LAS CONDICIONES PARA UN MOVIMIENTO SEGURO
PERM_ORIGEN : BOOL ; //PERMISO PARA INICIAR EL MOVIMIENTO A ORIGEN
PERM_AVANCE : BOOL ; //PERMISO PARA INICIAR EL MOVIMIENTO DE AVANCE
MANTENER : BOOL ; //MANTENER LAS SALIDAS ACTIVADAS
SIN_DET_ORIGEN : BOOL ; //SIN DETECTOR DE ORIGEN (TEMPORIZADO)
SIN_DET_AVANCE : BOOL ; //SIN DETECTOR DE AVANCE (TEMPORIZADO)
SIN_SAL_ORIGEN : BOOL ; //SIN SALIDA PARA VOLVER A ORIGEN (ELECTROV. MONOESTABLE)
T_ORIGEN : TIME ; //TEMPORIZACIÓN DEL DETECTOR DE ORIGEN
T_AVANCE : TIME ; //TEMPORIZACIÓN DEL DETECTOR DE AVANCE
T_LIMITE : TIME ; //TIEMPO LÍMITE PARA REALIZAR UN AVANCE O RETROCESO
END_VAR
VAR_OUTPUT
SAL_ORIGEN : BOOL ; //SALIDA PARA IR A ORIGEN
SAL_AVANCE : BOOL ; //SALIDA PARA AVANZAR
EN_ORIGEN : BOOL ; //CILINDRO EN ORIGEN
AVANZADO : BOOL ; //CILINDRO AVANZADO
ERROR : BOOL ; //HAY UN ERROR PRESENTE
COD_ERROR : INT ; //CÓDIGO DE ERROR
END_VAR
VAR
T_AUX_ORIGEN : TIME ;
T_AUX_AVANCE : TIME ;
T_AUX_LIM_OR : TIME ;
T_AUX_LIM_AV : TIME ;
FP_DET_ORIGEN : BOOL ;
FP_DET_AVANCE : BOOL ;
FP_SAL_ORIGEN : BOOL ;
FP_SAL_AVANCE : BOOL ;
AUX_ERROR_5 : BOOL ;
AUX_ERROR_6 : BOOL ;
FN_DET_ORIGEN : BOOL ;
FN_DET_AVANCE : BOOL ;
END_VAR
VAR_TEMP
TICKS : TIME ;
DET_ORIGEN_T : BOOL ;
DET_AVANCE_T : BOOL ;
DET_SAL_ORIGEN_T : BOOL ;
DET_SAL_AVANCE_T : BOOL ;
AUX_ERROR_1 : BOOL ;
AUX_ERROR_2 : BOOL ;
AUX_ERROR_3 : BOOL ;
AUX_ERROR_4 : BOOL ;
END_VAR
BEGIN
NETWORK
TITLE =LECTURA DEL TIEMPO ACTUAL
//EN MILISEGUNDOS QUE HAN TRANSCURRIDO DESDE EL ÚLTIMO ARRANQUE DEL PLC.
CALL "TIME_TCK" (
RET_VAL := #TICKS);
NOP 0;
NETWORK
TITLE =TIEMPOS DETECCIÓN ORIGEN CILINDRO
//SI NO HAY DETECCIÓN DE ORIGEN, ESTA SE MARCARÁ POR TEMPORIZACIÓN DE LA SALIDA
//DE VUELTA A ORIGEN.
U( ;
UN #SIN_DET_ORIGEN;
U #DET_ORIGEN;
O ;
U #SIN_DET_ORIGEN;
U #SAL_ORIGEN;
) ;
FP #FP_DET_ORIGEN;
SPBNB _001;
L #TICKS;
L #T_ORIGEN;
+D ;
T #T_AUX_ORIGEN;
_001: NOP 0;
NETWORK
TITLE =TEMPORIZACIÓN DEL DETECTOR DE ORIGEN
//EL DETECTOR DEBE ESTAR ACTIVADO DURANTE UN TIEMPO DADO PARA DAR EL MOVIMIENTO
//POR FINALIZADO.
UN #SIN_DET_ORIGEN;
U #DET_ORIGEN;
U( ;
L #TICKS;
L #T_AUX_ORIGEN;
>=D ;
) ;
= #DET_ORIGEN_T;
NETWORK
TITLE =TEMPORIZACIÓN DE LA SALIDA COMO DETECCIÓN
//LA SALIDA DEBE ESTAR ACTIVADA DURANTE UN TIEMPO DADO PARA DAR EL MOVIMIENTO
//POR FINALIZADO.
U #SIN_DET_ORIGEN;
U #SAL_ORIGEN;
U( ;
L #TICKS;
L #T_AUX_ORIGEN;
>=D ;
) ;
= #DET_SAL_ORIGEN_T;
NETWORK
TITLE =TIEMPOS DETECCIÓN AVANCE CILINDRO
//SI NO HAY DETECCIÓN DE AVANCE, ESTA SE MARCARÁ POR TEMPORIZACIÓN DE LA SALIDA
//DE AVANCE.
U( ;
UN #SIN_DET_AVANCE;
U #DET_AVANCE;
O ;
U #SIN_DET_AVANCE;
U #SAL_AVANCE;
) ;
FP #FP_DET_AVANCE;
SPBNB _002;
L #TICKS;
L #T_AVANCE;
+D ;
T #T_AUX_AVANCE;
_002: NOP 0;
NETWORK
TITLE =TEMPORIZACIÓN DEL DETECTOR DE AVANCE
//EL DETECTOR DEBE ESTAR ACTIVADO DURANTE UN TIEMPO DADO PARA DAR EL MOVIMIENTO
//POR FINALIZADO.
UN #SIN_DET_AVANCE;
U #DET_AVANCE;
U( ;
L #TICKS;
L #T_AUX_AVANCE;
>=D ;
) ;
= #DET_AVANCE_T;
NETWORK
TITLE =TEMPORIZACIÓN DE LA SALIDA COMO DETECCIÓN
//LA SALIDA DEBE ESTAR ACTIVADA DURANTE UN TIEMPO DADO PARA DAR EL MOVIMIENTO
//POR FINALIZADO.
U #SIN_DET_AVANCE;
U #SAL_AVANCE;
U( ;
L #TICKS;
L #T_AUX_AVANCE;
>=D ;
) ;
= #DET_SAL_AVANCE_T;
NETWORK
TITLE =CONDICIONES DE ORIGEN
//SE DEBE DAR EL DETECTOR DE ORIGEN Y NO DAR EL DE AVANCE.
U( ;
UN #SIN_DET_ORIGEN;
U #DET_ORIGEN;
O ;
U #SIN_DET_ORIGEN;
U #DET_SAL_ORIGEN_T;
) ;
U( ;
UN #SIN_DET_AVANCE;
UN #DET_AVANCE;
O ;
U #SIN_DET_AVANCE;
UN #DET_SAL_AVANCE_T;
) ;
= #EN_ORIGEN;
NETWORK
TITLE =MOVIMIENTO AVANZADO
//SE DEBE DAR EL DETECTOR DE AVANCE Y NO DAR EL DE ORIGEN.
U( ;
UN #SIN_DET_ORIGEN;
UN #DET_ORIGEN;
O ;
U #SIN_DET_ORIGEN;
UN #DET_SAL_ORIGEN_T;
) ;
U( ;
UN #SIN_DET_AVANCE;
U #DET_AVANCE;
O ;
U #SIN_DET_AVANCE;
U #DET_SAL_AVANCE_T;
) ;
= #AVANZADO;
NETWORK
TITLE =ACTIVACIÓN DE LA SALIDA VUELTA A ORIGEN
//SI ESTÁ PERMITIDO VOLVER A ORIGEN, SE ACTIVA LA SALIDA CON LA ORDEN DE ORIGEN.
//SE QUITA SI NO HAY SEGURIDAD, SI SE HACE EL MOVIMIENTO CONTRARIO O SI NO HAY
//QUE MANTENER LA SALIDA Y SE HA COMPLETADO O INTERRUMPIDO LA ORDEN.
U #PERM_ORIGEN;
U #A_ORIGEN;
S #SAL_ORIGEN;
U( ;
ON #SEGURIDAD;
O #AVANZAR;
O #SIN_SAL_ORIGEN;
O ;
UN #MANTENER;
U( ;
UN #SIN_DET_ORIGEN;
U #DET_ORIGEN_T;
ON #A_ORIGEN;
) ;
) ;
R #SAL_ORIGEN;
NOP 0;
NETWORK
TITLE =ACTIVACIÓN DE LA SALIDA DE AVANCE
//SI ESTÁ PERMITIDO AVANZAR, SE ACTIVA LA SALIDA CON LA ORDEN DE AVANZAR.
//SE QUITA SI NO HAY SEGURIDAD, SI SE HACE EL MOVIMIENTO CONTRARIO O SI NO HAY
//QUE MANTENER LA SALIDA Y SE HA COMPLETADO O INTERRUMPIDO LA ORDEN.
U #PERM_AVANCE;
U #AVANZAR;
S #SAL_AVANCE;
U( ;
ON #SEGURIDAD;
O #A_ORIGEN;
O ;
UN #MANTENER;
U( ;
UN #SIN_DET_AVANCE;
U #DET_AVANCE_T;
ON #AVANZAR;
) ;
) ;
R #SAL_AVANCE;
NOP 0;
NETWORK
TITLE =CÁLCULO DEL TIEMPO VIGILANCIA DE MOVIMIENTO DE VUELTA A ORIGEN
//TIEMPO MÁXIMO EN EL QUE EL MOVIMIENTO DEBE COMPLETARSE
U( ;
UN #SIN_SAL_ORIGEN;
U #SAL_ORIGEN;
O ;
U #SIN_SAL_ORIGEN;
UN #SAL_AVANCE;
) ;
FP #FP_SAL_ORIGEN;
SPBNB _003;
L #TICKS;
L #T_LIMITE;
+D ;
T #T_AUX_LIM_OR;
_003: NOP 0;
NETWORK
TITLE =ERROR 1
//SE DA LA ORDEN DE VUELTA A ORIGEN Y NO SE COMPLETA EN EL TIEMPO DADO
U( ;
UN #SIN_SAL_ORIGEN;
U #SAL_ORIGEN;
O ;
U #SIN_SAL_ORIGEN;
UN #SAL_AVANCE;
) ;
UN #SIN_DET_ORIGEN;
UN #DET_ORIGEN;
U( ;
L #TICKS;
L #T_AUX_LIM_OR;
>=D ;
) ;
SPBNB _004;
L 1;
T #COD_ERROR;
SET ;
SAVE ;
CLR ;
_004: U BIE;
= #AUX_ERROR_1;
NETWORK
TITLE =CÁLCULO DEL TIEMPO VIGILANCIA DE MOVIMIENTO DE AVANCE
//TIEMPO MÁXIMO EN EL QUE EL MOVIMIENTO DEBE COMPLETARSE
U #SAL_AVANCE;
FP #FP_SAL_AVANCE;
SPBNB _005;
L #TICKS;
L #T_LIMITE;
+D ;
T #T_AUX_LIM_AV;
_005: NOP 0;
NETWORK
TITLE =ERROR 2
//SE DA LA ORDEN DE AVANCE Y NO SE COMPLETA EN EL TIEMPO DADO
U #SAL_AVANCE;
UN #SIN_DET_AVANCE;
UN #DET_AVANCE;
U( ;
L #TICKS;
L #T_AUX_LIM_AV;
>=D ;
) ;
SPBNB _006;
L 2;
T #COD_ERROR;
SET ;
SAVE ;
CLR ;
_006: U BIE;
= #AUX_ERROR_2;
NETWORK
TITLE =ERROR 3
//SE DAN SIMULTÁNEAMENTE LOS DOS DETECTORES
UN #SIN_DET_ORIGEN;
UN #SIN_DET_AVANCE;
U #DET_ORIGEN;
U #DET_AVANCE;
SPBNB _007;
L 3;
T #COD_ERROR;
SET ;
SAVE ;
CLR ;
_007: U BIE;
= #AUX_ERROR_3;
NETWORK
TITLE =ERROR 4
//SE DAN SIMULTÁNEAMENTE LAS ÓRDENES DE VUELTA A ORIGEN Y DE AVANCE
U #A_ORIGEN;
U #AVANZAR;
SPBNB _008;
L 4;
T #COD_ERROR;
SET ;
SAVE ;
CLR ;
_008: U BIE;
= #AUX_ERROR_4;
NETWORK
TITLE =ERROR 5
//SE HA SOBREPASADO EL DETECTOR DE ORIGEN (EL DETECTOR DE ORIGEN DEBE TENER UNA
//TEMPORIZACIÓN SUFICIENTE)
U #DET_ORIGEN;
FN #FN_DET_ORIGEN;
UN #SIN_DET_ORIGEN;
U #SAL_ORIGEN;
S #AUX_ERROR_5;
U( ;
ON #SAL_ORIGEN;
O #DET_ORIGEN_T;
) ;
R #AUX_ERROR_5;
NOP 0;
NETWORK
TITLE =ERROR 6
//SE HA SOBREPASADO EL DETECTOR DE AVANCE (EL DETECTOR DE AVANCE DEBE TENER UNA
//TEMPORIZACIÓN SUFICIENTE)
U #DET_AVANCE;
FN #FN_DET_AVANCE;
UN #SIN_DET_AVANCE;
U #SAL_AVANCE;
S #AUX_ERROR_6;
U( ;
ON #SAL_AVANCE;
O #DET_AVANCE_T;
) ;
R #AUX_ERROR_6;
NOP 0;
NETWORK
TITLE =SEÑAL DE ERROR
//SE INDICA SI EXISTE ALGÚN ERROR
//SI NO HAY ERROR SE INDICA CON EL CÓDIGO CERO
O #AUX_ERROR_1;
O #AUX_ERROR_2;
O #AUX_ERROR_3;
O #AUX_ERROR_4;
O #AUX_ERROR_5;
O #AUX_ERROR_6;
= L 5.0;
U L 5.0;
BLD 102;
= #ERROR;
U L 5.0;
NOT ;
SPBNB _009;
L 0;
T #COD_ERROR;
_009: NOP 0;
END_FUNCTION_BLOCK
Tengo que reconocer que la llamada al FB queda un poco grande, pero personalmente me ahorra trabajo. Está pensado para mis propias necesidades, espero que a alguien más le resulte útil.
Si mejoras el código, encuentras algún error o crees que le falta algo, cuéntamelo en los comentarios.
Hola
ResponderEliminarComo siempre, genial articulo. La pena es que pasa mucho tiempo entre ellos!!!.
Tengo una duda que esta relacionada en parte con el bloque. ¿Es multinstancia?.
Supon que tengo dos cilindros y uso dos bloques de este tipo dentro de otro bloque multinstancia que los incluye.
A la hora de observar online los bloques, Step7 muestra los datos de cada cilindro o solo los del primero?. Por mi experencia, creo que solo visualiza los datos del primero.
Esta es una duda que tengo desde hace tiempo e incluso llame a la Hotline de Siemens a ver si me la aclaraban pero no me supieron contestar.
Creo que este problema es una gran limitacion de Siemens, ya que ellos recomiendan usar multinstancias pero luego a la hora de usarlas te encuentras con sorpresas como esta
Un saludo
Hola Ragundo,
ResponderEliminarDebes declarar un DB de instancia por cada llamada al FB.
Tienes razón en que si el mismo código se llama varias veces en el mismo ciclo de scan, la visualización on-line del FB no es fiable. Ni siquiera estoy seguro que se visualize la primera llamada. En estos casos me suelo ayudar de tablas de variables.
Gracias por tu interés. Ya me gustaría poder escribir más a menudo, pero el tiempo es limitado.
Enhorabuena, muy buen comentario tanto por su desarrollo como por su contenido.
ResponderEliminarEstoy haciendo un repaso por tus entradas y pienso que es impresionante, yo en un cdigo de más de veinte lineas ya entro en shock.
ResponderEliminarGracias por enseñarnos tanto.