Variables Beckhoff Proface

Ya que tenía esta aplicación, he pensado que estaía bien explicar un poco como funciona, aunque no tiene mucha historia.

La aplicación llamada utilidades, es un conjunto de herramientas que nos pueden ayudar a realizar algunos  trabajos.  Hoy hablaré de la conversión de variables globales de beckhoff  BX9000 a proface para Modbus Tcp/ip.  Básicamente los pasos son:

  1. Exportar las variables globales desde PLC Control  a un archivo que llamaremos VARIABLES GLOBALES. Proyecto –> export. En el cuadro de diálogo abrimos la carpeta Global variables y seleccionamos variables globales.
  2. Abrimos utilidades –> Herramientas –> Generar variables globales.
  3. Y pulsamos en generar variables globales.
  4. Seleccionar la carpeta donde guardamos las variables exportadas.
  5. Abrir el proyecto  HMI de Proface,  ajustes comunes –> ajustes de simbolos de variables   –> Utilidades –> Formato de Gx-pro Ex.

Podemos hacer la conversión de una o varias variables directamente. En el combobox convertir variables, ponemos la variable a convertir en el texbox y pulsamos el botón que hay debajo. Esta conversión se puede realizar en los dos sentidos. Si tenemos marcado Sumar, la variable que hay en el textbox aumentará automáticamente, esto es práctico para hacer varias conversiones consecutivas.

 

Midiendo temperatura II

PT100 y PT1000.

La sondas PT100 y PT1000 son termorresistencias PTC. El valor Ohnmico a 0º es de 100 y 1000 Ω, respectivamente. Además tienen la caracteristica de variar el valor ohnmico proporcionalmente a la temperatura en el rango de medición.

Sonda PT100: Rt = [((0.00389) * 100 )*ºC]+100

Sonda PT1000: Rt = [((0.00389) * 1000 )*ºC]+1000

He preparado una hoja de calculo excel. La primera tabla calcula RT (valor en Ω de la sonda) a diferentes temperaturas y tipo de sonda (PT100 y PT1000).  La segunda tabla nos calcula el valor Ω del conductor en función de la longitud y sección. La tercera el cambio por efecto de la temperatura en el conductor. La última tabla calcula el error en grados por la suma del error del conductor más la temperatura. Aquí podeis descargar la hoja de cálculo.  Las celdas en amarillo son para introducir datos. 

Sondas a 3 y 4 hilos o sondas con compensación.

Para evitar los errores producidos por la resistencia del conductor hay sondas con 3 y 4 hilos.

Básicamente de lo que se trata es de saber cuánta resistencia tenemos en el conductor (midiendo entre los dos terminales +R) y restársela a la resistencia de la sonda -R +R.

Como podemos ver en la tabla para un ejemplo de 100 metros de cable con una sección de 0,25 mm2, tenemos unos 3,6 ºC de error.  Utilizando un tipo de sonda compensada este error quedaría anulado. Tambien se anularía el error producido por las variaciones de temperatura en el conductor.

Se pueden utilizar sondas PT100 a dos hilos en lugar de 3, puenteando las entradas pero lo correcto es que este puente se realice lo más cerca posible de la sonda.

La importancia de una correcta instalación.

Como podemos ver en la tabla, para un incremento de 1ºC sólo se produce un cambio de 0,4 Ω en la sonda. Por este motivo es recomendable realizar todos los empalmes con soldadura de estaño.

Si utilizamos sondas PT100 de dos hilos deberemos calibrar la sonda para compensar la distancia del conductor. Siempre tendremos el error producido por los cambios de temperatura en éste. Podemos decir que el error en la sonda PT1000 es diez veces menor que en la PT100.

Error por calentamiento de la sonda.

Para poder medir el valor ohnmico deberemos aplicar una tensión. Esta tensión produce un calentamiento en la propia sonda produciendo a su vez un error en la medida. En el caso de la sonda PT1000, este calentamiento es diez veces superior. A efectos prácticos no sabría decir de cuánto estamos hablando puesto que parte del calor producido en la sonda es disipado al medio. En este punto es importante la transmisión de temperatura de la sonda al medio.

Como calibrar una sonda de temperatura.

Intentar contrastar una sonda de temperatura con un patrón puede ser una tarea ardua. Quizás, la forma mas simple es introducir la sonda en agua, junto a la sonda patrón, de esta manera evitaremos los problemas ocasionados por estratificaciones y velocidad de respuesta. Lo que de ninguna manera deberíamos hacer es constractar temperaturas con un patrón situando las sondas en diferentes puntos ya que las diferencias pueden llegar a ser considerables.

 

 

Midiendo temperatura I

Algunos datos interesantes en la medida de temperatura:

Errores según norma en sondas de temperatura PT100.

Errores según caracteristicas de fabricante en modulo de entrada PT100 de beckhoff.

Modulos especiales de Beckhoff . Como vemos, en el recuadro marcado en rojo, la versión 0028 presenta un menor error y un mayor resolución.

 Error según fabricante de modulo ADP para PLC FX·U de Mitsubishi para lectura de sondas PT100.

También podemos leer con módulos de 4-20 mA y convertidores. La siguiente figura presenta el máximo error global para un convertidor de PT100 a 4-20mA.

En el caso de leer a través de convertidor tendremos que sumar errores: error en sonda, error en convertidor, error en módulo 4-20mA. La siguiente figura muestra el error según fabricante del módulo KL3454 de Beckhoff.

Otras tecnologías.

Aunque aún estoy un poco verde en este tema, lo voy a estudiar porque me parece interesante. Se trata de la red 1-wire. Son sensores, entre otras cosas de temperatura y humedad, con comunicación 1-wire. La gran ventaja de esto es que en la misma sonda tenemos el sensor, el convertidor a digital y la comunicación. Según el fabricante habla de un ±0.5 ºC de error. Con resulociones de hasta 12 bit (0.0132 ºC).  Os dejo algunos link para abrir boca. Si saco algo en claro ya contaré.

iButtonLink

Maxim

Wiki 1wire

TwinCat

Para quien esté interesado en probar algunas de las cosas que se ven por aquí, os dejo una pequeña introducción para poner en marcha el PLC o, mejor dicho, el SoftPlc. Para abrir  pinchamos en el icono de la barra de tareas, en system manager. 

 

 

El siguiente paso es añadir un proyecto o, dicho de otra forma, el programa con el que queremos trabajar. 

 

Seleccionamos  y activamos la configuración. 

 

Ahora tenemos nuestro PLC en marcha. 

 

La dirección ADS es la dirección Ip con .1.1 añadidos al final. Esta dirección será la que usaremos para direccionar las peticiones desde Vb.net. En los detalles de las variables podemos ver el puerto, grupo y offset. Estos datos son importantes para leer estas variables desde vb.net. Las aplicaciones en Vb.net, pueden recuperar el valor de las variables con el nemónico, pero yo lo haré con la dirección. En fondo verde podemos ver el estado del plc. 

Ya tenemos el PLC en  marcha. Algo asi como poner en tensión un plc y conectarlo al PC. El siguiente paso es mandar el programa desde PLC control y poner en RUN.

FB Derivada

Continuando con los FB que componen un FB PID,  hoy toca la derivada.

FUNCTION_BLOCK FT_DERIV

VAR_INPUT
in : REAL;
K : REAL := 1;
run : BOOL := 1;
END_VAR

 

VAR_OUTPUT
out : REAL;
END_VAR


VAR
old: REAL;
tx: DWORD;
last: DWORD;
init: BOOL;
MaxValue : REAL;

END_VAR

(* lee system time *)
tx := T_PLC_US();

(* init para inicializar  *)
IF NOT init THEN
init := TRUE;
last := tx;
old := in;
ELSIF run AND tx – last > 0 THEN
out := (in – old) / DWORD_TO_REAL(tx – last) * 1000000.0 * K;
last := tx;
old := in;
ELSE
out := 0;
END_IF;

Init se utiliza para hacer una configuración inicial del FB. En programación leader, probablemente utilizariamos un flanco ascendente.

 

Realmente, este Fb nos recuerda bastante al Fb Integral, con la diferencia de que ahora no sumamos al valor anterior. En esencia lo que hace es calcular un valor proporcional a la desviación entre dos lecturas consecutivas. Cada ciclo de scan se lee el valor PV (por ejemplo la temperatura actual) y la compara con el valor en el anterior ciclo de scan. Pero esto tiene un gran inconveniente y me explico. Si leemos una temperatura, normalmente tendremos un decimal. A efectos prácticos, esto se traduce en que la temperatura parecerá estable hasta el instante en que aumente una décima y será en ese instante en el que la derivada nos de un valor > 0. En realidad esto no es cierto y sabemos que la temperatura está aumentando porque en el trancurso de un tiempo, varios minutos, sí se puede observar un incremento más o menos paulativo.

 

Como podemos ver en el grafico, la evolución de la temperatura en el tiempo. La temperatura es la Serie1 en ºC x 10 que suele ser la medida en un entrada analógica de 12 bit. Supongamos que el eje x son los sucesivos ciclos de scan. La linea azul muestra la evolución real de la temperatura.

La derivada esta definida como la variación de temperatura (Y1 – Y0) partido la duración del ciclo de scan T.

(Y1 – Y0) / T.

Analizando las derivadas en cada ciclo de scan con un tiempo de ciclo de 200ms.

1º Ciclo de scan. Se guardan los datos pero no se calcula. Momento actual y valor actual. last y old.

2ºCiclo de scan (100 – 100) / 200 = 0.

3ºCiclo de scan (100-100)/200 = 0.

4ºCiclo de scan (100 – 100) / 200 = 0.

5ºCiclo de scan (101 -100) / 200 = 0,005.

6º y sucesivos ciclos de scan (101- 101)/200 = 0.

Como vemos, la derivada, sólo nos devolverá un valor en el momento del cambio. Pero realmente el cambio se produce continuamente, aunque la resolución de la entrada analógica hace que este cambio se realice en escalones. Si nuestra entrada de temperatura tiene algo de ruido, el resultado en la derivada será totalmente erróneo. Por estos motivos la derivada se suele poner  Tv = 0,  para este tipo de procesos.

La derivada devuelve un valor proporcional a la aceleración en PV.

Con el símil de un coche. La aceleración es la derivada de la velocidad = (V- V0)/t.

Posibilidades

Esta entrada la quiero dedicar a comentar un poco por donde me moveré en posteriores post. En la anterior entrada vimos un programa que hacía de simulador y control. Tenemos más posibilidades, claro cientos. Pero yo quiero centrarme en dos ideas principales, a saber: control y visualización. Como es obvio el control esta constituido principalmente por un PLC que actuará sobre los equipos. Para este fin yo he elegido PLC Control de Beckhoff por una serie de razones que iremos viendo. Para la parte de visualización, y cuando hablo de esto me refiero a todas las posibilidades, visualización pura, registro en texto plano, registro en bases de datos, servidores web, etc. Como decía, para esto he elegido vb.net, pero como veremos mas adelante esto es solo el principio puesto que esta será la base para saltar a las bases de datos, etc.  Y todo esto con software gratuito.

¿Por qué Beckhoff?.

La respuesta es sencilla, podemos probar cuánto queramos sin gastar un duro. Lo que hagamos luego, es cuestión de cada uno. Pero esta claro que los conceptos y en muchas ocasiones el código será valido para otras marcas. Aunque el PLC, propiamente dicho, esta limitado a 30 dias, podemos volver a instalarlo y volverá a funcionar sin problemas. El hecho de poder tener un PLC corriendo en el PC es una gran ventaja en cuanto que no necesitamos, ni cables ni equipos. Teniendo este PLC corriendo podremos probar tanto los programas de PLC como aplicaciones en VB.net leyendo y escribiendo variables en éste. Por lo tanto, la filosofía a partir de ahora será que el PLC sea control puro y la parte de simulación y visualización será por parte de vb.net. De esta manera tendremos tres aplicaciones a las que iremos añadiendo funcionalidad. PLC, simulador en vb.net y visualización en vb.net.

¿Por qué en tres partes ?.

Bien, una de las cosas que tenemos que tener muy presentes es la posibilidad de reutilizar el código que generamos. Es una buena forma de ahorrar tiempo, aunque tenga sus inconvenientes. De esta manera el código generado en la parte de PLC podrá ser reutilizado , añadiendo los “seguros” que precise para aplicaciones reales. Los UserControl en vb.net, igualmente. Imaginemos por un momento que generamos un UserControl en vb.net encargado de simular una cámara, otro encargado de simular un compresor. Teniendo esto, nos sera fácil y rápido generar un simulador de 3 cámaras y 4 compresores. Así podemos probar nuestras aplicaciones antes de una puesta en marcha real, probar nuebos Fb de una forma algo mas realista o explicar y probar conceptos en este blog. Para todo lo que exponga aquí dejaré el codigo fuente y el compilado. De esta manera, quien no quiera entrar en los entresijos de vb.net, simplemente podrá utilizar el ejecutable.

¿Por dónde empezamos ?.

En las últimas entradas he hecho un avance rápido y ahora toca rebobinar. Así que la respuesta es: desde el principio. La idea es volver a retomar los FB`s PID, y seguir poquito a poco. El tema de TwinCat lo abordaremos un poco por encima,  lo justo para poder poner las aplicaciones en marcha.

Fb PID y simulador

He preparado un simulador con el que poder probar el bloque de función PID y comparar con una función termostato. Ademas he añadido la posibilidad de utilizar el PID mediante una Fb Pwm (Modulación en ancho de pulsos). Esto nos llevará algunos post para explicar como funciona   pero creo que es mejor poder ir haciendo pruebas desde el primer momento. Es importante destacar que muchos de los Fb utilizados en este programa estan extraídos de la libreria libre Oscat. Veamos un vídeo y seguimos con los detalles. 

   

Pantalla de visualización.

El gráfico nos muestra la evolución de la temperatura y lo que he llamado “valor equipo” que sería, en una aplicación real, la potencia suministrada por los equipos de frío y calor. 

  

 

Simulador cámara.

K camara es una constante utilizada para simular el los cambios de temperatura dentro de la cámara. Los valores positivos serán entradas de calor a la cámara, y los negativos cesión de calor por la cámara. Pot equipo se utiliza para simular la potencia del equipo frigorífico o la fuente de calor (resistencias, bomba de calor, etc). Intervalo, mediante este parámetro podemos modificar las condiciones de inercia de la cámara, el valor es en mseg. 

Parametros Pid.

Kp o constante proporcional, TN o tiempo integral y TV o tiempo derivativo. 

Selectores.

Mediante los tres botones podemos activar cualquiera de las posibilidades, Pid directo, termostato o Pid a traves de PWM. Si existen mas de dos botones activados solo se tiene en cuenta el primero en orden de Izq a Drcha. 

Para ponerlo en marcha solo hay que conectar al PLC, poner a RUN. Para que cambia K cámara por ejemplo con 3.0 y activa una de las funciones, PID, termostato o PWM. 

(A) RUN (B) STOP (C) Conectarse a PLC (D) Desconectar de PLC.

 

 Desde aquí podeis descargar el archivo. Y aquí hay teoria del Pid.

Algo más de integrales

En la anterior entrada hicimos un FB para calcular la integral de una matriz de 100 elementos. Dicho de otra forma: la integral de lo que paso en los últimos 50 seg. (la matriz se actualizaba cada 500 mseg.).  En esta entrada voy ha comentar el FB integral que se incluye en la librería OSCAT. Esta libreria podeis descargarla desde aquí. Para ver los FB solo teneis que abrir la librería como library (*.lib).

FUNCTION_BLOCK INTEGRATE
VAR_INPUT
E : BOOL := TRUE;
X : REAL;
K : REAL := 1;
END_VAR
VAR_IN_OUT
Y : REAL;
END_VAR
VAR
X_last : REAL;
init: BOOL;
last: DWORD;
tx: DWORD;
END_VAR
(*read system time *)
tx := T_PLC_MS();
IF NOT init THEN
 init := TRUE;
 X_last := X;
ELSIF E THEN
Y := (X + X_LAST) * 0.5E-3 * DWORD_TO_REAL(tx-last) * K + Y;
X_last := X;
END_IF;
last := tx;
(*
hm  3. nov. 2008 rev 1.0
original version
 
*)

Analizando el FB.


Lo que calcula este FB es la integral de un valor en cada ciclo de scan y lo suma al valor acumulado.  De esta manera Integral = IntegralAnterior + [(Error + ErrorAnterior) * 0.5  * 0.001 * Tiempo trancurrido en ms * Constante proporcional ]
La función T_PLC_MS(), nos devuelve el momento actual en una doble palabra (DWORD) .  El proceso en palabras es el siguiente:

1º Ciclo de SCAN

Leemos el tiempo actual y lo guardamos en Tx.
Como Init = FALSE, guardamos el valor de X en X_Last (Valor del error anterior). Ponemos Init a True para que no vuelva a entrar.
Guardamos tx en last.

2º y posteriores Ciclos de SCAN

Leemos el tiempo actual y lo guardamos en Tx.
Si E = TRUE ( E es la activación del cálculo, como vemos en la declaración de variables esta inicializada a TRUE).
Calcula la integral
Guarda el valor de X en X Last
Guarda tx en Tx-Last.
Aquí os dejo un proyecto con un pequeño programa que simula un cambio en la temperatura y calcula la integral. He añadido la misma función modificada para que sea mas fácil de  entender. En posteriores entradas, me gustaría  mejorar el simulador para que realmente podamos probar una función PID. Por el momento es solo para que se pueda ver la integral en funcionamiento.

User Function block

En esta entrada vamos a realizar un User Function block o bloque de función de usario. Y esto, no es nada más que un poco de codigo, realizado por nosotros, y  encapsulado para poder reutilizarlo. En este caso tambien vamos a utilizar algun Function Block  (en adelante FB)  y Function (en adelante F) de la librería standar de Beckhoff. La diferencia entre éstos es: en el primero el resultado de las salidas, depende de las entradas y del valor de las variables internas. En el segundo caso F, la salida sólo depende del valor de la entrada. Un ejemplo de F es  FDoble = In * 2.

Concretamente vamos a realizar un FB que calcula la integral numérica  por la regla del trapecio. La integral la realizaremos de la función del error (SetPoint – Temperatura). Para saber más sobre integrales numéricas.

La integral definida de una función representa el área limitada por la gráfica de la función, con signo positivo cuando la función toma valores positivos y negativo cuando toma valores negativos.

Fuente : Wikipedia.

Veamos un ejemplo del cálculo:

1.1. Tabla de datos de ejemplo

1.2 Representación grafica de la integral.

El cálculo realizado por el programa de plc:

El programa en cuestión:

FUNCTION_BLOCK Integral

VAR_INPUT
Sp:INT;
Pv:INT;
END_VAR
VAR_OUTPUT

Integral: REAL;
END_VAR
VAR
SpReal:REAL;
PvReal:REAL;
Error: REAL;
Matriz:ARRAY [0..99] OF REAL;
esPulso: TON;
Inicio:INT;
i:INT;
h:INT;
k:INT;

END_VAR

(*FB temporizador TON, en este caso la salida es un pulso cada 500 ms*)
esPulso(IN:= NOT esPulso.Q, PT:= T#500ms);
(*Convertimos las entradas en Var REAL con funciones*)
SpReal:= INT_TO_REAL(Sp)/10;
PvReal:= INT_TO_REAL(Pv)/10;
(* Si hicieramos SpReal := INT_TO_REAL(Sp/10) el resultado seria diferentes puesto que el programa analiza (Sp/10) como un entero *)

Error := PvReal – SpReal;

CASE Inicio OF

0: (*Llenamos la matriz en el primer scan *)
FOR i:=0 TO 99 DO

Matriz[i] := Error;

END_FOR;
Inicio := 1;
1: (* Pasamos los registro en h a h-1, retrasamos la matriz en un registro e introducimos el valor actual en el ultimo registro *)
IF esPulso.Q THEN

FOR h:= 0 TO 98 DO

Matriz[h] := Matriz[h+1];

END_FOR;

Matriz[99]:= Error;
END_IF;

END_CASE;
(* Ponemos a 0 el valor de la integral para volver a calcular *)
Integral := 0;
(* Aqui esta realmente el calculo de la integral a partir de una matriz que contiene los últimos 100 registros *)
FOR k:= 0 TO 98 DO

(* Cálculo integral por la regla del trapecio  Calculamos el valor de cada columna   = (B3-B2)*((C2+C3)/2) y los sumamos*)
Integral:= Integral + (    (  (k+1)  – k)   *  (   (Matriz[k] + Matriz[k + 1]) / 2 )    );

END_FOR;

1.4 Apariencia del FB integrado en el programa.

TEXTO LITERAL EXTRUCTURADO

He pensado que una buena manera de empezar es con unas nociones generales de este lenguaje, puesto que será uno de los idiomas que hablemos aquí. Realmente no es complicado, pese a lo que pueda parecer, en un principio y cuando hablamos de ciertas operaciones con palabras resulta ser la mejor opción.

Hay ciertas diferencias en función de la marca pero los principios son los mismos. En esta primera entrada haré un repaso rápido para ver un poco las posibilidades.  Los ejemplos están realizados con PLC CONTROL de beckhoff. Este software es gratuito y esta basado en CoDeSys. Lo podeis descargar desde aquí. Este software cumple la norma IEC 61131-3 de programación. Para este caso he declarado todas las variables como globales.

VAR_GLOBAL

(* Ejemplos lógica *)
Var1:BOOL;
Var2:BOOL;
OutSerie:BOOL;
OutParalelo:BOOL;
(* Ejemplos marcha paro *)
Pmarcha:BOOL;
Pparo:BOOL;
Motor:BOOL;
(* Ejemplo termostato *)
TempCam1:INT;
SetPoint:INT;
SetPointAlto:INT;
Termostato:BOOL;
(* Ejemplo de media *)
Matriz: ARRAY[0..9] OF INT;
Indice: INT;
i:INT;
Suma:INT;
Valor:INT;
Media:INT;
(* Ejemplo CASE *)
Error := INT;
Resistencia1:BOOL;
Resistencia2:BOOL;
Resistencia3:BOOL;

END_VAR

Red serie:

OutSerie := Var1 AND Var2;

1.1. Ejemplo de red serie en leader

Red paralelo:

OutParalelo := Var1 OR Var2;

1.2. Ejemplo red paralelo en leader

Marcha paro con pulsador:

Motor := Pparo AND (Pmarcha OR Motor);

1.3. Ejemplo de secuencia marcha paro en leader

Comparaciones. Una funcion termostato:

Termostato := TempCam > SetPoint AND (TempCam > SetPoint + 20 OR Termostato);

La misma función con IF THEN ELSE

IF TemCam > SetPoint +20 THEN Termostato := TRUE;

IF TemCam < SetPoint THEN Termostato := FALSE;

1.4. Ejemplo funcion termostato en leader

Media de un valor:

Y aquí empieza a cobrar sentido este lenguaje de programación. Cada ciclo de scan almacenamos el valor actual en una matriz de manera que se mantengan los diez últimos. La media, claro esta, será la suma de todos los elementos de la matriz dividido entre el número de registros.

(* Sumamos 1 al índice para avanzar el registro de la matriz a escribir *)

Indice := Indice +1;

(* es importante poner limites a los índices para evitar un error. Tambien nos sirve para volver al registro 0 de la matriz cundo la recorremos por completo *)

IF Indice < 0 THEN Indice := 0;END_IF;

IF Indice > 9 THEN Indice := 0;END_IF;

(*Asignamos a la matriz el valor actual en el registro actual *)

Matriz[Indice] := Valor;

(* Ponemos a 0 la variable suma para volver a calcular la suma *)

Suma:= 0;

(* Recorremos la matriz para calcular la suma de todos los registros *)

FOR i := 0 TO 9 DO

Suma:= Suma + Matriz[i];

END_FOR;

(* Calculamos la media procurando no dividir nunca el valor 0 *)

IF Suma = 0 THEN Media := 0; ELSE Media:= Suma / 10;END_IF;

Condicional CASE:

(*Ejemplo CASE*)
(* Activar tres resistencias en función de la diferencia entre la temperatura y el setpoint *)

Error := TempCam1 – SetPoint;
IF Error < 0 THEN Error := 0;END_IF;

CASE Error OF
0:  Resistencia1:= FALSE;
Resistencia2:= FALSE;
Resistencia3 :=FALSE;

1..3: Resistencia1:= TRUE;
Resistencia2:= FALSE;
Resistencia3 :=FALSE;

4..6: Resistencia1:= TRUE;
Resistencia2:= TRUE;
Resistencia3 :=FALSE;

ELSE;  Resistencia1:= TRUE;
Resistencia2:= TRUE;
Resistencia3 :=TRUE;
END_CASE;

Aquí podeis descargar  el programa con los ejemplos. Para programar PLC según la norma IEC 61131-3 es importante tener un conocimiento básico de éste.

Un saludo y hasta la próxima. !Ah¡  y espero algún comentario.

Editado 23-Enero.

Aquí dejo una recopilación de manuales.