Ejemplos de uso y aplicación del regulador. Controlador PID: descripción completa, aplicación. Coordinación de dispositivos de salida de reguladores continuos.

Sistemas de control automático (ACS) están diseñados para cambiar automáticamente uno o más parámetros de un objeto de control con el fin de establecer el modo requerido de su funcionamiento. El ACS asegura el mantenimiento de la constancia de los valores especificados de los parámetros regulados o su cambio según una ley determinada, u optimiza determinados criterios de calidad del control. Por ejemplo, tales sistemas incluyen:

  • sistemas de estabilización,
  • sistemas de control de programas,
  • sistemas de seguimiento

Esta es una clase bastante amplia de sistemas que se pueden encontrar en cualquier lugar. Pero, ¿qué tiene esto que ver con Unity3D y probablemente con los juegos en particular? En principio, es sencillo: en cualquier juego que de alguna manera utilice la simulación como elemento del juego, se implementan armas autopropulsadas, tales juegos incluyen, por ejemplo, Kerbal Space Programm, Digital Combat Simulator (anteriormente Lock On), Strike Suit Zero, etc. (quién sabe más ejemplos, escriba en los comentarios). En principio, cualquier juego que simule procesos físicos reales, incluida simplemente la cinemática con dinámica de movimiento, puede implementar una u otra pistola autopropulsada; este enfoque es más simple, más natural y el desarrollador ya tiene un conjunto de herramientas listas para usar proporcionadas por todo tipo de Vyshnegradsky, Lyapunov, Kalman, Chebyshev y otros Kolomogorov, por lo que puedes prescindir de reinventar la rueda, porque ya ha sido inventada, hasta el punto de que se ha convertido en una ciencia independiente: la Teoría del Control Automático. Lo principal aquí es no exagerar. Sólo hay un problema: no se habla de TAU en todas partes ni con todo el mundo, muchas veces poco y no muy claro.

una pequeña teoría

El sistema de control automático clásico se muestra en la siguiente figura:



El elemento clave de cualquier arma autopropulsada es regulador que es un dispositivo que monitorea el estado del objeto de control y proporciona la ley de control requerida. El proceso de control incluye: cálculo del error de control o señal de error mi(t) ¿Cuál es la diferencia entre lo deseado? configuración(punto de ajuste o SP ) y el valor actual del proceso (valor del proceso o fotovoltaica ), después de lo cual el regulador genera señales de control (valor manipulado o VM ).


Un tipo de regulador es Controlador proporcional-integral-derivado (PID), que genera una señal de control, que es la suma de tres términos: proporcional, integral y diferencial.



Donde, el error de desajuste, así como los componentes (términos) - proporcionales, - integrales y - diferenciales de la ley de control, que en su forma final se describe mediante las siguientes fórmulas




Componente proporcional P- es responsable de la llamada Control proporcional, cuyo significado es que la señal de salida del controlador contrarresta la desviación de la variable controlada (error de desajuste o también llamado residual) del valor establecido. Cuanto mayor sea el error de desajuste, mayor será la desviación del comando del controlador. Esta es la ley de control más simple y obvia. Defecto La ley de control proporcional es que el regulador nunca se estabiliza en un valor dado y un aumento en el coeficiente de proporcionalidad siempre conduce a autooscilaciones. Por eso, además de la ley de control proporcional, es necesario utilizar la integral y diferencial.


Componente integral I acumula (integra) el error de control, lo que permite al controlador PID eliminar el error estático (error constante, error residual). O en otras palabras: vínculo integral siempre introduce algún sesgo y si el sistema está sujeto a algunos errores permanentes, entonces los compensa (debido a su sesgo). Pero si no existen tales errores o son insignificantes, entonces el efecto será el contrario: el componente integral en sí introducirá un error de desplazamiento. Es por este motivo que no se utiliza, por ejemplo, en tareas de posicionamiento ultraprecisas. Llave desventaja La ley de control integral es el efecto de saturación del integrador (Integrator windup).


Componente diferencial D es proporcional a la tasa de cambio de la desviación de la variable controlada y está diseñado para contrarrestar las desviaciones del valor objetivo, que se predicen en el futuro. Cabe destacar que el componente diferencial elimina las oscilaciones amortiguadas. El control diferencial es especialmente eficaz para procesos que tienen grandes retrasos. Desventaja La ley de control diferencial es su inestabilidad ante los efectos del ruido (Diferenciación de ruido).


Por lo tanto, dependiendo de la situación, se pueden usar reguladores P, PD, PI y PID, pero la ley de control principal es principalmente proporcional (aunque en algunas tareas específicas solo se pueden usar exclusivamente los elementos de diferenciadores e integradores).


Parecería que el tema de la implementación de controladores PID ha sido trillado durante mucho tiempo y aquí en Habré hay un par de buenos artículos sobre este tema, incluso sobre Unity3D, también hay un buen artículo PID sin doctorado (traducción) y una serie de Artículos en la revista "Modern Automation Technologies" en dos partes: primera y segunda. También hay un artículo en Wikipedia a su servicio (lea el más completo en la versión en inglés). Y en los foros de la comunidad Unity3D no, no, y el controlador PID aparecerá como en gamedev.stackexchange


La cuestión sobre la implementación de controladores PID es algo más profunda de lo que parece. Tanto es así que muchos descubrimientos maravillosos esperan a los jóvenes aficionados al bricolaje que decidan implementar un esquema regulatorio de este tipo, y el tema es relevante. Espero que esta obra sea útil para alguien, así que comencemos.

Intento número uno

Como ejemplo, intentaremos implementar un esquema de control usando el ejemplo del control de giro en un simple juego arcade espacial 2D, paso a paso, comenzando desde el principio (¿has olvidado que esto es un tutorial?).


¿Por qué no 3D? Porque la implementación no cambiará, excepto que tendrá que subir el controlador PID para controlar el cabeceo, la guiñada y el balanceo. Aunque el tema de la correcta aplicación del control PID junto con los cuaterniones es realmente interesante, tal vez lo analice en el futuro, pero incluso la NASA prefiere los ángulos de Euler en lugar de los cuaterniones, por lo que nos conformaremos con un modelo simple en dos dimensiones. avión.


Para empezar, creemos el objeto del juego de la nave espacial en sí, que consistirá en el objeto de la nave real en el nivel superior de la jerarquía, y le adjuntaremos un objeto secundario Motor (solo por efectos especiales). Esto es lo que me parece:



Y en el propio objeto de la nave espacial agregamos inspector todo tipo de componentes. De cara al futuro, daré una captura de pantalla de cómo se verá al final:



Pero eso es para más adelante, y por ahora no contiene scripts, solo el conjunto estándar para caballeros: Sprite Render, RigidBody2D, Polygon Collider, Audio Source (¿por qué?).


En realidad, la física es lo más importante para nosotros ahora y el control se realizará exclusivamente a través de ella, de lo contrario, el uso de un controlador PID perdería su sentido. Dejemos también la masa de nuestra nave espacial en 1 kg, y todos los coeficientes de fricción y gravedad sean iguales a cero, en el espacio.


Porque Además de la nave espacial en sí, hay muchos otros objetos espaciales menos inteligentes, por lo que primero describiremos la clase principal. Cuerpo base, que contendrá enlaces a nuestros componentes, métodos de inicialización y destrucción, así como una serie de campos y métodos adicionales, por ejemplo, para implementar la mecánica celeste:


BaseBody.cs

usando UnityEngine; usando System.Collections; usando System.Collections.Generic; espacio de nombres Assets.Scripts.SpaceShooter.Bodies ( clase pública BaseBody: MonoBehaviour ( flotador de solo lectura _deafultTimeDelay = 0.05f; Lista pública estática _bodies = nueva lista (); #región RigidBody public Rigidbody2D _rb2d; Colisionador público2D_c2d; #endregion #region Referencias public Transform _myTransform; GameObject público _myObject; ///

/// Un objeto que aparece cuando se destruye /// público GameObject_explodePrefab; #endregion #region Audio público AudioSource _audioSource; /// /// Sonidos que se reproducen al recibir daño /// público AudioClip_hitSounds; /// /// Sonidos que se reproducen cuando aparece un objeto /// AudioClip público_awakeSounds; /// /// Sonidos que se reproducen antes de la muerte /// AudioClip público_deadSounds; #endregion #region Variables de fuerza externa /// /// Fuerzas externas que actúan sobre un objeto /// Vector2 público _ExternalForces = nuevo Vector2(); /// /// Vector de velocidad actual /// Vector2 público _V = nuevo Vector2(); /// /// Vector actual de gravedad /// Vector2 público _G = nuevo Vector2(); #endregion public virtual void Awake() ( Init(); ) public virtual void Start() ( ) public virtual void Init() ( _myTransform = this.transform; _myObject = gameObject; _rb2d = GetComponent (); _c2d = ObtenerComponentesEnNiños (); _audioSource = ObtenerComponente (); ReproducirSonidoAleatorio(_awakeSounds); BaseBody bb = ObtenerComponente (); _bodies.Add(bb); ) /// /// Destrucción de un personaje /// public virtual void Destroy() ( _bodies.Remove(this); for (int i = 0; i< _c2d.Length; i++) { _c2d[i].enabled = false; } float _t = PlayRandomSound(_deadSounds); StartCoroutine(WaitAndDestroy(_t)); } /// /// Esperamos algún tiempo antes de la destrucción /// /// Tiempo de espera /// public IEnumerator WaitAndDestroy(float waitTime) ( rendimiento return new WaitForSeconds(waitTime); if (_explodePrefab) ( Instantiate(_explodePrefab, transform.position, Quaternion.identity); ) Destroy(gameObject, _deafultTimeDelay); ) /// /// Reproduce un sonido aleatorio /// /// variedad de sonidos /// Duración del sonido reproducido public float PlayRandomSound(AudioClip audioClip) ( float _t = 0; if (audioClip.Length > 0) ( int _i = UnityEngine.Random.Range(0, audioClip.Length - 1); AudioClip _audioClip = audioClip[_i]; _t = _audioClip.length; _audioSource.PlayOneShot(_audioClip); ) return _t; ) /// /// Recibiendo daño /// /// Nivel de daño Daño virtual público vacío (daño flotante) ( PlayRandomSound(_hitSounds); ) ) )


Parece que describimos todo lo que se necesitaba, incluso más de lo necesario (en el marco de este artículo). Ahora heredemos la clase de barco. Barco, que debería poder moverse y girar:


nave espacial.cs

usando UnityEngine; usando System.Collections; usando System.Collections.Generic; espacio de nombres Assets.Scripts.SpaceShooter.Bodies ( clase pública Ship: BaseBody ( público Vector2 _movement = new Vector2(); public Vector2 _target = new Vector2(); public float _rotation = 0f; public void FixedUpdate() ( float torque = ControlRotate( _rotation); Vector2 force = ControlForce(_movement); _rb2d.AddTorque(torque); _rb2d.AddRelativeForce(force); ) public float ControlRotate(Vector2 rotar) ( float resultado = 0f; devolver resultado; ) public Vector2 ControlForce(Vector2 movimiento) (Resultado de Vector2 = nuevo Vector2(); resultado de retorno; ) ) )


Si bien no tiene nada de interesante, por el momento es solo una clase resguardada.


También describiremos la clase base (abstracta) para todos los controladores de entrada BaseInputController:


BaseInputController.cs

usando UnityEngine; usando Assets.Scripts.SpaceShooter.Bodies; espacio de nombres Assets.Scripts.SpaceShooter.InputController (enum público eSpriteRotation (Derecha = 0, Arriba = -90, Izquierda = -180, Abajo = -270) clase abstracta pública BaseInputController: MonoBehaviour (GameObject público _agentObject; Ship público _agentBody; // Enlace al componente lógico del barco public eSpriteRotation _spriteOrientation = eSpriteRotation.Up; //Esto se debe a la // orientación no estándar del sprite "arriba" en lugar de "derecha" public abstract void ControlRotate(float dt); public abstract void ControlForce (float dt); inicio vacío virtual público() ( _agentObject = gameObject; _agentBody = gameObject.GetComponent (); ) public virtual void FixedUpdate() ( float dt = Time.fixedDeltaTime; ControlRotate(dt); ControlForce(dt); ) public virtual void Update() ( //PARA HACER ) ) )


Y finalmente, la clase de controlador del jugador. JugadorLuchaEntrada:


ReproductorInput.cs

usando UnityEngine; usando Assets.Scripts.SpaceShooter.Bodies; espacio de nombres Assets.Scripts.SpaceShooter.InputController ( clase pública PlayerFigtherInput: BaseInputController ( anulación pública void ControlRotate(float dt) ( // Determina la posición del mouse en relación con el jugador Vector3 worldPos = Input.mousePosition; worldPos = Camera.main.ScreenToWorldPoint (worldPos); // Guarda las coordenadas del puntero del mouse float dx = -this.transform.position.x + worldPos.x; float dy = -this.transform.position.y + worldPos.y; //Pasa la dirección Vector2 target = new Vector2(dx, dy); _agentBody._target = target; //Calcula la rotación según las pulsaciones de tecla float targetAngle = Mathf.Atan2(dy, dx) * Mathf.Rad2Deg; _agentBody._targetAngle = targetAngle + (float)_spriteOrientation ; ) anulación pública void ControlForce( float dt) ( //Pasar movimiento _agentBody._movement = Input.GetAxis("Vertical") * Vector2.up + Input.GetAxis("Horizontal") * Vector2.right; ) ) )


Parece que hemos terminado, ahora por fin podemos pasar a aquello para lo que empezó todo esto, es decir. Controladores PID (espero que no lo hayas olvidado). Su implementación parece muy simple:


usando Sistema; usando System.Collections.Generic; usando System.Linq; usando System.Text; espacio de nombres Assets.Scripts.Regulator ( // Este atributo es necesario para que los campos del regulador // se muestren en el inspector y en la clase pública serializada SimplePID ( public float Kp, Ki, Kd; private float lastError; private float P, I, D ; público SimplePID() ( Kp = 1f; Ki = 0; Kd = 0.2f; ) público SimplePID(flotante pFactor, flotante iFactor, flotante dFactor) ( this.Kp = pFactor; this.Ki = iFactor; this.Kd = dFactor ; ) actualización pública flotante (error flotante, dt flotante) ( P = error; I += error * dt; D = (error - últimoError) / dt; últimoError = error; flotante CO = P * Kp + I * Ki + D * Kd ; devolver CO; ) ) )

Tomaremos los valores predeterminados de los coeficientes de la nada: este será un coeficiente único trivial de la ley de control proporcional Kp = 1, un pequeño valor del coeficiente de la ley de control diferencial Kd = 0,2, que debería eliminar las fluctuaciones esperadas y un valor cero para Ki, que se eligió porque en nuestro software el modelo no tiene errores estáticos (pero siempre puedes introducirlos y luego luchar heroicamente con la ayuda del integrador).


Ahora volvamos a nuestra clase SpaceShip e intentemos usar nuestra creación como controlador de rotación de la nave espacial en el método ControlRotate:


public float ControlRotate(Vector2 rotar) ( float MV = 0f; float dt = Time.fixedDeltaTime; //Calcular el error float angleError = Mathf.DeltaAngle(_myTransform.eulerAngles.z, targetAngle); //Obtener la aceleración correctiva MV = _angleController .Actualizar (angleError, dt); devolver MV; )

El controlador PID realizará un posicionamiento angular preciso de la nave espacial utilizando únicamente el torque. Todo es justo, física y armas autopropulsadas, casi como en la vida real.


Y sin estos Quaternion.Lerp tuyo

if (!_rb2d.freezeRotation) rb2d.freezeRotation = verdadero; float deltaAngle = Mathf.DeltaAngle(_myTransform.eulerAngles.z, targetAngle); float T = dt * Mathf.Abs(_rotationSpeed ​​​​/ deltaAngle); // Transforma el ángulo en un vector Quaternion rot = Quaternion.Lerp(_myTransform.rotation, Quaternion.Euler(new Vector3(0, 0, targetAngle)), T); // Cambia la rotación del objeto _myTransform.rotation = rot;


El código fuente resultante de Ship.cs está bajo el spoiler

usando UnityEngine; usando Assets.Scripts.Regulator; espacio de nombres Assets.Scripts.SpaceShooter.Bodies (clase pública Nave: BaseBody (GameObject público _flame; Vector2 público _movement = nuevo Vector2(); Vector2 público _target = nuevo Vector2(); flotante público _targetAngle = 0f; ángulo flotante público = 0f; público SimplePID _angleController = new SimplePID(); public void FixedUpdate() ( float torque = ControlRotate(_targetAngle); Vector2 force = ControlForce(_movement); _rb2d.AddTorque(torque); _rb2d.AddRelativeForce(force); ) public float ControlRotate(float) rotar) ( float MV = 0f; float dt = Time.fixedDeltaTime; _angle = _myTransform.eulerAngles.z; // Calcular el error float angleError = Mathf.DeltaAngle(_angle, rotar); // Obtener la aceleración correctiva MV = _angleController. Actualización (angleError, dt); return MV; ) public Vector2 ControlForce (movimiento Vector2) ( Vector2 MV = new Vector2(); // Un fragmento de código para el efecto especial de un motor en funcionamiento por el bien de if (movimiento! = Vector2.zero) ( if (_flame != null) ( _flame.SetActive(true); ) ) else ( if (_flame != null) ( _flame.SetActive(false); ) ) MV = movimiento; devolver VM; ) ) )


¿Todo? ¿Nos vamos a casa?



¡Qué carajo! ¿Lo que está sucediendo? ¿Por qué el barco gira de forma extraña? ¿Y por qué rebota tan bruscamente en otros objetos? ¿Este estúpido controlador PID no funciona?


¡No entrar en pánico! Intentemos descubrir qué está pasando.


En el momento en que se recibe un nuevo valor de SP, hay un salto brusco (paso a paso) en el error de coincidencia, que, como recordamos, se calcula así: en consecuencia, hay un salto brusco en el error derivado, que calculamos en esta línea de código:


D = (error - últimoError) / dt;

Por supuesto, puedes probar otros esquemas de diferenciación, por ejemplo, de tres puntos, de cinco puntos, o... pero aun así no servirá de nada. Bueno, no les gustan las derivadas de saltos bruscos; en esos puntos la función no es diferenciable. Sin embargo, vale la pena experimentar con diferentes esquemas de diferenciación e integración, pero no en este artículo.


Creo que ha llegado el momento de construir gráficos del proceso de transición: acción gradual desde S(t) = 0 hasta SP(t) = 90 grados para un cuerpo que pesa 1 kg, una longitud de brazo de fuerza de 1 metro y un paso de cuadrícula de diferenciación. de 0,02 s, como en nuestro ejemplo en Unity3D (de hecho, no del todo; al construir estos gráficos, no se tuvo en cuenta que el momento de inercia depende de la geometría del cuerpo sólido, por lo que el proceso transitorio será ligeramente diferentes, pero aún lo suficientemente similares para una demostración). Todos los valores del gráfico se dan en valores absolutos:


Mmmm, ¿qué está pasando aquí? ¿A dónde fue la respuesta del controlador PID?


Felicitaciones, acabamos de encontrarnos con un fenómeno llamado "patada". Evidentemente, en un momento en el que el proceso todavía es PV = 0, y el setpoint ya es SP = 90, entonces con diferenciación numérica obtenemos un valor derivado del orden de 4500, que se multiplicará por Kd=0,2 y sumamos con una temperatura proporcional, de modo que en la salida obtenemos un valor de aceleración angular de 990, y esto ya es un completo escándalo en el modelo físico de Unity3D (las velocidades angulares alcanzarán 18000 grados/s... Creo que esto es el valor límite de la velocidad angular para RigidBody2D).


  • ¿Quizás valga la pena elegir los coeficientes manualmente para que el salto no sea tan fuerte?
  • ¡No! Lo mejor que podemos conseguir de esta forma es una pequeña amplitud del salto derivativo, pero el salto en sí permanecerá como estaba y en este caso el componente diferencial puede volverse completamente ineficaz.

Sin embargo, puedes experimentar.

Intento número dos. Saturación

Es lógico que Unidad de manejo(en nuestro caso, los motores de maniobra virtuales de SpaceShip), no pueden manejar ningún valor grande que nuestro loco regulador pueda producir. Entonces lo primero que haremos será saturar la salida del regulador:


public float ControlRotate(Vector2 rotar, flotar empuje) ( float CO = 0f; float MV = 0f; float dt = Time.fixedDeltaTime; // Calcular el error float angleError = Mathf.DeltaAngle(_myTransform.eulerAngles.z, targetAngle); / / Obtenemos la aceleración correctiva CO = _angleController.Update(angleError, dt); //Saturar MV = CO; si (MV > empuje) MV = empuje; si (MV< -thrust) MV = -thrust; return MV; }

Y una vez más, la clase Ship reescrita se ve así:

espacio de nombres Assets.Scripts.SpaceShooter.Bodies (clase pública Ship: BaseBody (GameObject público _flame; Vector2 público _movement = nuevo Vector2(); Vector2 público _target = nuevo Vector2(); flotador público _targetAngle = 0f; ángulo flotante público = 0f; público float _thrust = 1f; public SimplePID _angleController = new SimplePID(0.1f,0f,0.05f); public void FixedUpdate() ( _torque = ControlRotate(_targetAngle, _thrust); _force = ControlForce(_movement); _rb2d.AddTorque(_torque); _rb2d.AddRelativeForce(_force); ) public float ControlRotate(float targetAngle, float impulse) ( float CO = 0f; float MV = 0f; float dt = Time.fixedDeltaTime; //Calcula el error float angleError = Mathf.DeltaAngle(_myTransform. eulerAngles .z, targetAngle); //Obtener la aceleración correctiva CO = _angleController.Update(angleError, dt); //Saturar MV = CO; if (MV > empuje) MV = empuje; if (MV< -thrust) MV = -thrust; return MV; } public Vector2 ControlForce(Vector2 movement) { Vector2 MV = new Vector2(); if (movement != Vector2.zero) { if (_flame != null) { _flame.SetActive(true); } } else { if (_flame != null) { _flame.SetActive(false); } } MV = movement * _thrust; return MV; } public void Update() { } } }


El esquema final de nuestras armas autopropulsadas se verá así


Al mismo tiempo, queda claro que la salida del controlador Cuna) ligeramente diferente de la variable controlada del proceso VM(t).


En realidad, desde este lugar ya puedes agregar una nueva entidad de juego: Unidad de manejo, a través del cual se controlará el proceso, cuya lógica puede ser más compleja que solo Mathf.Clamp(), por ejemplo, puedes introducir la discretización de valores (para no sobrecargar la física del juego con valores que vienen en sextos después del punto decimal), una zona muerta (nuevamente, no tiene sentido sobrecargar la física con reacciones ultrapequeñas), introducir un retraso en el control y la no linealidad (por ejemplo, un sigmoide) de la unidad, y luego ver lo que resulta de ello.


Habiendo iniciado el juego, encontraremos que la nave espacial finalmente se ha vuelto controlable:



Si construye gráficos, puede ver que la respuesta del controlador se ha vuelto así:


Aquí ya se utilizan valores normalizados, los ángulos se dividen por el valor SP y la salida del controlador se normaliza en relación con el valor máximo en el que ya se produce la saturación.

A continuación se muestra una tabla conocida del efecto de aumentar los parámetros del controlador PID ( ¿Cómo puedo hacer que la fuente sea más pequeña? De lo contrario, la tabla de separación de palabras del merengue no encajará.):



Y el algoritmo general para ajustar manualmente el controlador PID es el siguiente:


  1. Seleccionamos los coeficientes proporcionales con los enlaces diferencial e integral apagados hasta que comiencen las autooscilaciones.
  2. Aumentando gradualmente el componente diferencial nos deshacemos de las autooscilaciones.
  3. Si hay un error de control residual (desplazamiento), lo eliminamos utilizando el componente integral.

No existen valores generales para los parámetros del controlador PID: los valores específicos dependen únicamente de los parámetros del proceso (su característica de transferencia): un controlador PID que funciona perfectamente con un objeto de control no funcionará con otro. Además, los coeficientes de los componentes proporcional, integral y diferencial también son interdependientes.


Intento número tres. Una vez más derivados

Habiendo colocado una muleta en forma de limitación de los valores de salida del controlador, todavía no resolvimos el problema más importante de nuestro controlador: el componente diferencial no funciona bien cuando el error en la entrada del controlador cambia paso a paso. De hecho, existen muchas otras muletas, por ejemplo, en el momento de un cambio brusco de SP, “apagar” el componente diferencial o instalar filtros de paso bajo entre SP(t) y una operación por la cual el error aumentará gradualmente, o puede darse la vuelta por completo y utilizar un filtro de Kalman real para suavizar los datos de entrada. En general, hay muchas muletas, y agrega observador Por supuesto que me gustaría, pero esta vez no.


Por lo tanto, volvamos a la derivada del error de discrepancia y analicémosla detenidamente:



¿Notaste algo? Si observa detenidamente, encontrará que, en general, SP(t) no cambia con el tiempo (excepto en los momentos de cambio de paso cuando el controlador recibe un nuevo comando), es decir su derivada es cero:





En otras palabras, en lugar de un error derivativo que sea diferenciable no en todas partes podemos utilizar la derivada de un proceso, que en el mundo de la mecánica clásica suele ser continuo y diferenciado en todas partes, y el diagrama de nuestro sistema de control automático ya tomará la siguiente forma:




Modifiquemos el código del controlador:


usando Sistema; usando System.Collections.Generic; usando System.Linq; usando System.Text; espacio de nombres Assets.Scripts.Regulator ( clase pública SimplePID ( flotante público Kp, Ki, Kd; flotante privado P, I, D; flotante privado lastPV = 0f; SimplePID público() ( Kp = 1f; Ki = 0f; Kd = 0.2f ; ) público SimplePID(pFactor flotante, iFactor flotante, dFactor flotante) ( this.Kp = pFactor; this.Ki = iFactor; this.Kd = dFactor; ) Actualización pública flotante (error flotante, PV flotante, dt flotante) ( P = error; I += error * dt; D = -(PV - últimoPV) / dt; últimoPV = PV; flotar CO = Kp * P + Ki * I + Kd * D; devolver CO; ) ) )

Y cambiemos un poco el método ControlRotate:


public float ControlRotate(Vector2 rotar, flotar empuje) ( float CO = 0f; float MV = 0f; float dt = Time.fixedDeltaTime; // Calcular el error float angleError = Mathf.DeltaAngle(_myTransform.eulerAngles.z, targetAngle); / / Obtenemos la aceleración correctiva CO = _angleController.Update(angleError, _myTransform.eulerAngles.z, dt); //Saturar MV = CO; if (CO >< -thrust) MV = -thrust; return MV; }

Y-y-y-y... si comienzas el juego, encontrarás que en realidad nada ha cambiado desde el último intento, que es lo que había que demostrar. Sin embargo, si elimina la saturación, el gráfico de respuesta del regulador se verá así:


Saltar Cuna) todavía está presente, pero ya no es tan grande como al principio y, lo más importante, se ha vuelto predecible, porque es proporcionado exclusivamente por el componente proporcional, y está limitado por el máximo error de desajuste posible y la ganancia proporcional del controlador PID (y esto ya sugiere que kp tiene sentido elegir menos de la unidad, por ejemplo, 1/90f), pero no depende del paso de la cuadrícula de diferenciación (es decir, dt). En general, recomiendo encarecidamente utilizar la derivada del proceso en lugar del error.


Creo que ahora no sorprenderá a nadie, pero de la misma manera puedes reemplazarlo por , pero no nos detendremos en esto, puedes experimentar tú mismo y contar en los comentarios qué salió de él (lo más interesante)

Intento número cuatro. Implementaciones alternativas del controlador PID

Además de la representación ideal del controlador PID descrita anteriormente, en la práctica se suele utilizar la forma estándar, sin coeficientes. ki Y kd, en lugar de las cuales se utilizan constantes temporales.


Este enfoque se debe al hecho de que varias técnicas de sintonización del controlador PID se basan en las características de frecuencia del controlador PID y del proceso. En realidad, toda la TAU gira en torno a las características de frecuencia de los procesos, por lo que para aquellos que quieran profundizar más y de repente se encuentren con una nomenclatura alternativa, les daré un ejemplo de la llamada. forma estándar Controlador PID:




donde, es la constante de diferenciación que afecta la predicción del estado del sistema por parte del regulador,
- constante de integración, que afecta el intervalo de promedio de error por el enlace integral.


Los principios básicos para ajustar un controlador PID en forma estándar son similares a los del controlador PID idealizado:

  • aumentar el coeficiente proporcional aumenta el rendimiento y reduce el margen de estabilidad;
  • con una disminución en el componente integral, el error de control disminuye más rápidamente con el tiempo;
  • disminuir la constante de integración reduce el margen de estabilidad;
  • un aumento en el componente diferencial aumenta el margen de estabilidad y el rendimiento

El código fuente del formulario estándar se puede encontrar debajo del spoiler.

espacio de nombres Assets.Scripts.Regulator ( clase pública StandartPID ( flotador público Kp, Ti, Td; error de flotador público, CO; flotador público P, I, D; último PV flotante privado = 0f; StandartPID público() ( Kp = 0.1f; Ti = 10000f; Td = 0.5f; sesgo = 0f; ) PID estándar público (Kp flotante, Ti flotante, Td flotante) ( this.Kp = Kp; this.Ti = Ti; this.Td = Td; ) Actualización pública flotante (flotante error, PV flotante, dt flotante) ( this.error = error; P = error; I += (1 / Ti) * error * dt; D = -Td * (PV - últimoPV) / dt; CO = Kp * ( P + I + D); últimoPV = PV; devolver CO; ) ) )

Los valores predeterminados son Kp = 0,01, Ti = 10000, Td = 0,5; con estos valores el barco gira con bastante rapidez y tiene un cierto margen de estabilidad.


Además de esta forma de controlador PID, el llamado forma recurrente:



No nos detendremos en ello, porque... Es relevante principalmente para programadores de hardware que trabajan con FPGA y microcontroladores, donde dicha implementación es mucho más conveniente y eficiente. En nuestro caso, demos algo a los montones de Unity3D, esta es solo otra implementación de un controlador PID, que no es mejor que otras e incluso menos comprensible, así que una vez más, regocijémonos de lo bueno que es programar en el cómodo C#. , y no en el espeluznante y terrible VHDL, por ejemplo.

En lugar de una conclusión. ¿Dónde más agregaría un controlador PID?

Ahora intentemos complicar un poco el control del barco utilizando el control de doble circuito: un controlador PID, que ya conocemos _angleController, sigue siendo responsable del posicionamiento angular, pero el segundo, nuevo, _angularVelocityController, controla la velocidad de rotación:


public float ControlRotate(float targetAngle, float impulse) ( float CO = 0f; float MV = 0f; float dt = Time.fixedDeltaTime; _angle = _myTransform.eulerAngles.z; // Controlador de ángulo de rotación float angleError = Mathf.DeltaAngle(_angle, targetAngle); float torqueCorrectionForAngle = _angleController.Update(angleError, _angle, dt); // Controlador de estabilización de velocidad float angularVelocityError = -_rb2d.angularVelocity; float torqueCorrectionForAngularVelocity = _angularVelocityController.Update(angularVelocityError, -angularVelocityError, dt); //Total salida del controlador CO = torqueCorrectionForAngle + torqueCorrectionForAngularVelocity; //Muestra en pasos de 100 CO = Mathf.Round(100f * CO) / 100f; //Saturar MV = CO; if (CO > empuje) MV = empuje; if (CO< -thrust) MV = -thrust; return MV; }

El propósito del segundo regulador es amortiguar el exceso de velocidades angulares cambiando el par; esto es similar a la presencia de fricción angular, que desactivamos al crear el objeto del juego. Tal esquema de control [posiblemente] permitirá obtener un comportamiento más estable del barco, e incluso arreglárselas solo con coeficientes de control proporcionales: el segundo regulador amortiguará todas las fluctuaciones, realizando una función similar al componente diferencial del primer regulador. .


Además, agregaremos una nueva clase de entrada del jugador: PlayerInputCorvette, en la que los turnos se realizarán presionando las teclas derecha-izquierda, y dejaremos la designación del objetivo con el mouse para algo más útil, por ejemplo, para controlar una torreta. . Al mismo tiempo, ahora tenemos un parámetro como _turnRate, que es responsable de la velocidad/capacidad de respuesta del giro (no está claro dónde es mejor colocarlo en el InputCOntroller o en el Ship).


clase pública PlayerCorvetteInput: BaseInputController ( public float _turnSpeed ​​​​= 90f; public override void ControlRotate() ( // Encuentra el puntero del mouse Vector3 worldPos = Input.mousePosition; worldPos = Camera.main.ScreenToWorldPoint(worldPos); // Almacena el relativo coordenadas del puntero del mouse float dx = -this.transform.position.x + worldPos.x; float dy = -this.transform.position.y + worldPos.y; //Pase la dirección del puntero del mouse Vector2 target = new Vector2( dx, dy); _agentBody. _target = target; // Calcula la rotación de acuerdo con las pulsaciones de teclas _agentBody._rotation -= Input.GetAxis("Horizontal") * _turnSpeed ​​​​* Time.deltaTime; ) public override void ControlForce() ( //Pasar movimiento _agentBody._movement = Entrada .GetAxis("Vertical") * Vector2.up; ) )

Además, para mayor claridad, pondremos un script sobre nuestras rodillas para mostrar información de depuración.

espacio de nombres Assets.Scripts.SpaceShooter.UI ( clase pública Depurador: MonoBehaviour ( Ship _ship; BaseInputController _controller; Lista _pids = nueva lista (); Lista _names = nueva lista (); Vector2 _orientación = nuevo Vector2(); // Usa esto para la inicialización void Start() ( _ship = GetComponent (); _controller = ObtenerComponente (); _pids.Add(_ship._angleController); _names.Add("Controlador de ángulo"); _pids.Add(_ship._angularVelocityController); _names.Add("Controlador de velocidad angular"); ) // La actualización se llama una vez por cuadro void Update() ( DrawDebug(); ) Vector3 GetDiretion(eSpriteRotation spriteRotation) ( switch (_controller._spriteOrientation) ( case eSpriteRotation.Rigth: return transform.right; case eSpriteRotation.Up: return transform .up; case eSpriteRotation.Left: return -transform.right; case eSpriteRotation.Down: return -transform.up; ) return Vector3.zero; ) void DrawDebug() ( //Dirección de rotación Vector3 vectorToTarget = transform.position + 5f * new Vector3(-Mathf.Sin(_ship._targetAngle * Mathf.Deg2Rad), Mathf.Cos(_ship._targetAngle * Mathf.Deg2Rad), 0f); // Dirección actual Vector3 rumbo = transform.position + 4f * GetDiretion(_controller. _spriteOrientation); //Aceleración angular Vector3 torque = rumbo - transform.right * _ship._Torque; Debug.DrawLine(transform.position, vectorToTarget, Color.white); Debug.DrawLine(transform.position, rumbo, Color.green); Debug.DrawLine(rumbo, torque, Color.red); ) void OnGUI() ( float x0 = 10; flotar y0 = 100; flotador dx = 200; flotador dy = 40; flotador deslizanteKpMax = 1; deslizador flotanteKpMin = 0; flotador SliderKiMax = .5f; flotador SliderKiMin = -.5f; flotador deslizanteKdMax = .5f; deslizador flotanteKdMin = 0; int yo = 0; foreach (SimplePID pid en _pids) ( y0 += 2 * dy; GUI.Box(nuevo Rect(25 + x0, 5 + y0, dx, dy), ""); pid.Kp = GUI.HorizontalSlider(nuevo Rect( 25 + x0, 5 + y0, 200, 10), pid.Kp, SliderKpMin, SliderKpMax); pid.Ki = GUI.HorizontalSlider(nuevo Rect(25 + x0, 20 + y0, 200, 10), pid.Ki, SliderKiMin, SliderKiMax); pid.Kd = GUI.HorizontalSlider(nuevo Rect(25 + x0, 35 + y0, 200, 10), pid.Kd, SliderKdMin, SliderKdMax); GUIStyle estilo1 = nuevo GUIStyle(); estilo1.alignment = TextAnchor.MiddleRight; style1.fontStyle = FontStyle.Bold; style1.normal.textColor = Color.amarillo; style1.fontSize = 9; GUI.Label(new Rect(0 + x0, 5 + y0, 20, 10), "Kp ", estilo1); GUI.Label(nuevo Rect(0 + x0, 20 + y0, 20, 10), "Ki", ​​​​estilo1); GUI.Label(nuevo Rect(0 + x0, 35 + y0, 20 , 10 ), "Kd", estilo1); GUIStyle estilo2 = nuevo GUIStyle(); style2.alignment = TextAnchor.MiddleLeft; style2.fontStyle = FontStyle.Bold; style2.normal.textColor = Color.amarillo; style2.fontSize = 9 ; GUI .TextField(new Rect(235 + x0, 5 + y0, 60, 10), pid.Kp.ToString(), style2); GUI.TextField(nuevo Rect(235 + x0, 20 + y0, 60, 10), pid. Ki.ToString(), estilo2); GUI.TextField(new Rect(235 + x0, 35 + y0, 60, 10), pid.Kd.ToString(), style2); GUI.Label(new Rect(0 + x0, -8 + y0, 200, 10), _names, style2); ) ) ) )


La clase Ship también ha sufrido mutaciones irreversibles y ahora debería verse así:

espacio de nombres Assets.Scripts.SpaceShooter.Bodies (clase pública Ship: BaseBody (GameObject público _flame; Vector2 público _movement = nuevo Vector2(); Vector2 público _target = nuevo Vector2(); flotador público _targetAngle = 0f; ángulo flotante público = 0f; público float _thrust = 1f; público SimplePID _angleController = nuevo SimplePID(0.1f,0f,0.05f); público SimplePID _angularVelocityController = nuevo SimplePID(0f,0f,0f); privado float _torque = 0f; público float _Torque ( get ( return _torque; ) ) privado Vector2 _force = nuevo Vector2(); público Vector2 _Force ( get ( return _force; ) ) public void FixUpdate() ( _torque = ControlRotate(_targetAngle, _thrust); _force = ControlForce(_movement, _thrust); _rb2d.AddTorque( _torque); _rb2d.AddRelativeForce(_force); ) public float ControlRotate(flotador targetAngle, flotador de empuje) ( float CO = 0f; float MV = 0f; float dt = Time.fixedDeltaTime; _angle = _myTransform.eulerAngles.z; //Controlador ángulo de rotación float angleError = Mathf.DeltaAngle(_angle, targetAngle); float torqueCorrectionForAngle = _angleController.Update(angleError, _angle, dt); // Controlador de estabilización de velocidad float angularVelocityError = -_rb2d.angularVelocity; float torqueCorrectionForAngularVelocity = _angularVelocityController.Update(angularVelocityError, -angularVelocityError, dt); //Salida total del controlador CO = torqueCorrectionForAngle + torqueCorrectionForAngularVelocity; //Discretizar en pasos de 100 CO = Mathf.Round(100f * CO) / 100f; //Saturar MV = CO; si (CO > empuje) MV = empuje; si(CO< -thrust) MV = -thrust; return MV; } public Vector2 ControlForce(Vector2 movement, float thrust) { Vector2 MV = new Vector2(); if (movement != Vector2.zero) { if (_flame != null) { _flame.SetActive(true); } } else { if (_flame != null) { _flame.SetActive(false); } } MV = movement * thrust; return MV; } public void Update() { } } }

Algunos enlaces más a otros ejemplos.

La banda de proporcionalidad X p, al igual que la desviación E, se expresa en unidades del parámetro controlado. Cuanto más amplia sea la banda proporcional X p, menor será la señal de salida Y para la misma desviación E.

Fuera de la banda proporcional, la salida Y es 0 o 100%.

Cuando opera la ley P, el controlador produce pulsos en los que solo está presente un componente proporcional del valor de la señal de salida.


Cuando el dispositivo funciona en modo controlador PD, la magnitud de la señal de salida Yi depende no solo de la magnitud de la desviación Ei, sino también de la velocidad de su cambio:

En la figura se muestra el cambio en la señal de salida del controlador con un cambio gradual en la desviación. En el primer período después de un cambio de paso en E i, el controlador emite un pulso de control, en el que, además del componente proporcional causado por el desajuste E i, se agrega un diferencial (parte sombreada) ΔYd, que depende del valor del coeficiente ΔE i y τ l. En los pulsos posteriores solo hay un componente proporcional, ya que no hay cambio en E i.


La figura muestra que en el primer momento del tiempo, cuando no hay desviación (E i =0), no hay señal de salida (Y i =0). Con la aparición de la desviación E i, aparecen pulsos, cuya duración aumenta gradualmente. Los pulsos contienen una componente proporcional, que depende del valor de E (parte no sombreada de los pulsos) y una componente integral (parte sombreada). Se produce un aumento en la duración del pulso debido a un aumento en el componente integral, que depende del desajuste E i y el coeficiente τ i.

Un controlador diferencial proporcional-integral es un dispositivo que se instala en sistemas automatizados para mantener un parámetro determinado que es capaz de cambiar.

A primera vista, todo resulta confuso, pero el control PID se puede explicar para principiantes, es decir, personas que no están del todo familiarizadas con los sistemas y dispositivos electrónicos.

¿Qué es un controlador PID?

El controlador PID es un dispositivo integrado en el circuito de control con retroalimentación obligatoria. Está diseñado para mantener niveles establecidos de valores específicos, por ejemplo, la temperatura del aire.

El dispositivo suministra una señal de control o de salida al dispositivo de control, basándose en los datos recibidos de los sensores o sensores. Los controladores tienen una alta precisión de los procesos transitorios y la calidad del desempeño de la tarea asignada.

Tres coeficientes del controlador PID y principio de funcionamiento.

El trabajo del controlador PID es proporcionar una señal de salida sobre la potencia requerida para mantener el parámetro controlado en un nivel determinado. Para calcular el indicador, se utiliza una fórmula matemática compleja que contiene 3 coeficientes: proporcional, integral y diferencial.

Tomemos como objeto de regulación un recipiente con agua en el que es necesario mantener la temperatura a un nivel determinado ajustando el grado de apertura de la válvula con vapor.

El componente proporcional aparece en el momento de la discrepancia con los datos de entrada. En palabras simples, suena así: se toma la diferencia entre la temperatura real y la deseada, se multiplica por un coeficiente ajustable y se obtiene una señal de salida que debe suministrarse a la válvula. Aquellos. Tan pronto como los grados bajan, comienza el proceso de calentamiento; si suben por encima del nivel deseado, se produce un apagado o incluso un enfriamiento.

Luego viene el componente integral, que está diseñado para compensar la influencia del medio ambiente u otras influencias perturbadoras en el mantenimiento de nuestra temperatura en un nivel determinado. Dado que siempre hay factores adicionales que influyen en los dispositivos controlados, en el momento en que llegan los datos para calcular el componente proporcional, la cifra ya está cambiando. Y cuanto mayor es la influencia externa, más fuertes son las fluctuaciones del indicador. Hay aumentos repentinos en la energía suministrada.

El componente integral intenta, basándose en valores de temperatura pasados, devolver su valor si ha cambiado. El proceso se describe con más detalle en el vídeo a continuación.

La integral se utiliza para eliminar errores calculando el error estático. Lo principal en este proceso es seleccionar el coeficiente correcto; de lo contrario, el error (desajuste) también afectará al componente integral.

El tercer componente del PID es diferenciador. Está diseñado para compensar los efectos de los retrasos que se producen entre el impacto en el sistema y la retroalimentación. El controlador proporcional suministra energía hasta que la temperatura alcanza el nivel deseado, pero siempre ocurren errores cuando la información pasa al dispositivo, especialmente en valores grandes. Esto puede causar sobrecalentamiento. El diferencial predice desviaciones causadas por retrasos o influencias ambientales y reduce de antemano la potencia suministrada.

Configurar el controlador PID

El controlador PID se configura mediante 2 métodos:

  1. La síntesis implica calcular parámetros basados ​​en un modelo de sistema. Esta configuración es precisa, pero requiere un conocimiento profundo de la teoría del control automático. Está sujeto únicamente a ingenieros y científicos. Ya que es necesario tomar las características de consumo y hacer muchos cálculos.
  2. El método manual se basa en prueba y error. Para hacer esto, se toman como base los datos de un sistema listo para usar y se realizan algunos ajustes a uno o más coeficientes reguladores. Después de encender y observar el resultado final, los parámetros se cambian en la dirección deseada. Y así sucesivamente hasta alcanzar el nivel de rendimiento deseado.

El método teórico de análisis y ajuste se utiliza muy raramente en la práctica, lo que se debe al desconocimiento de las características del objeto de control y a una serie de posibles influencias perturbadoras. Más comunes son los métodos experimentales basados ​​en la observación del sistema.

Los procesos automatizados modernos se implementan como módulos especializados controlados por programas para ajustar los coeficientes del controlador.

Propósito del controlador PID

El controlador PID está diseñado para mantener un cierto valor en el nivel requerido: temperatura, presión, nivel en el tanque, caudal en la tubería, concentración de algo, etc., cambiando la acción de control en los actuadores, como las válvulas de control automático. , utilizando para su fijación cantidades proporcionales, integradoras y diferenciadoras.

El propósito de su uso es obtener una señal de control precisa que sea capaz de controlar grandes industrias e incluso reactores de centrales eléctricas.

Ejemplo de circuito de control de temperatura

Los controladores PID se utilizan a menudo para regular la temperatura; veamos este proceso automático usando un ejemplo simple de calentar agua en un recipiente.

El recipiente está lleno de líquido que debe calentarse a la temperatura deseada y mantenerse en un nivel determinado. Un sensor de medición de temperatura está instalado dentro del tanque o está conectado directamente al controlador PID.

Para calentar el líquido suministraremos vapor, como se muestra en la figura siguiente, con una válvula de control automático. La propia válvula recibe una señal del regulador. El operador ingresa el valor de consigna de temperatura en el controlador PID que debe mantenerse en el tanque.

Si la configuración del coeficiente del regulador es incorrecta, la temperatura del agua fluctuará, con la válvula completamente abierta o completamente cerrada. En este caso, es necesario calcular los coeficientes del controlador PID e ingresarlos nuevamente. Si todo se hace correctamente, al cabo de un corto periodo de tiempo el sistema nivelará el proceso y la temperatura en el recipiente se mantendrá en el punto establecido, mientras que el grado de apertura de la válvula de control quedará en la posición media.

El controlador PID es un dispositivo listo para usar que permitirá al usuario implementar un algoritmo de software para controlar ciertos equipos de un sistema automatizado. Construir y configurar sistemas de control se vuelve mucho más fácil si utiliza dispositivos ya preparados como el controlador PID universal TRM148 para 8 canales de la empresa Aries.

Digamos que necesita automatizar el mantenimiento de las condiciones climáticas correctas en un invernadero: tenga en cuenta la temperatura del suelo cerca de las raíces de las plantas, la presión del aire, la humedad del aire y del suelo y mantenga los parámetros establecidos controlando los ventiladores. No hay nada más sencillo, basta con configurar el controlador PID.

Primero recordemos qué es un controlador PID. Un controlador PID es un dispositivo especial que realiza un ajuste continuo y preciso de los parámetros de salida de tres maneras: proporcional, integral y diferencial, y los parámetros iniciales son parámetros de entrada recibidos de los sensores (presión, humedad, temperatura, iluminación, etc.).

El parámetro de entrada se suministra a la entrada del controlador PID desde un sensor, por ejemplo, desde un sensor de humedad. El regulador recibe un valor de voltaje o corriente, lo mide, luego realiza cálculos de acuerdo con su algoritmo y finalmente envía una señal a la salida correspondiente, como resultado de lo cual el sistema automatizado recibe una acción de control. La humedad del suelo disminuyó: el riego se inició durante unos segundos.

El objetivo es alcanzar un valor de humedad especificado por el usuario. O, por ejemplo: la iluminación ha disminuido: encienda las fitolamparas sobre las plantas, etc.

Control PID

De hecho, aunque todo es sencillo en apariencia, dentro del regulador las matemáticas son más complicadas, no todo sucede en un solo paso. Después de encender el riego, el controlador PID vuelve a realizar una medición, midiendo cuánto ha cambiado el valor de entrada; así es como se encuentra el error de control. El siguiente impacto en el órgano ejecutivo se ajustará teniendo en cuenta el error de regulación medido, y así sucesivamente en cada paso de control hasta alcanzar el objetivo, un parámetro especificado por el usuario.

En la regulación intervienen tres componentes: proporcional, integral y diferencial. Cada componente tiene su propio grado de importancia en cada sistema específico, y cuanto mayor sea la contribución de uno u otro componente, más significativamente deberá cambiarse en el proceso regulatorio.

El componente proporcional es el más simple, cuanto mayor es el cambio, mayor es el coeficiente (proporcionalidad en la fórmula), y para reducir el impacto basta simplemente con reducir el coeficiente (multiplicador).

Digamos que la humedad del suelo en el invernadero es mucho menor que la establecida; entonces el tiempo de riego debería ser más largo en la misma cantidad que la humedad actual es menor que la establecida. Éste es un ejemplo aproximado, pero es el principio general.

Componente integral: es necesario aumentar la precisión del control en función de eventos de control anteriores: los errores anteriores se integran y se realizan correcciones para finalmente obtener una desviación cero al regular en el futuro.

Finalmente, el componente diferencial. Aquí se tiene en cuenta la tasa de cambio de la variable controlada. En consecuencia, ya sea que el valor especificado cambie de manera suave o abrupta, la acción regulatoria no debe dar lugar a desviaciones excesivas del valor durante la regulación.

Todo lo que queda es seleccionar un dispositivo para el control PID. Hoy en día existen muchos en el mercado, los hay multicanal que te permiten cambiar varios parámetros a la vez, como en el ejemplo anterior con un invernadero.

Veamos el diseño del controlador usando el ejemplo del controlador PID universal TRM148 de la empresa Aries.

Los ocho sensores de entrada proporcionan señales a las entradas correspondientes. Las señales se escalan, filtran, corrigen y sus valores se pueden ver en la pantalla cambiando con los botones.

Las salidas del dispositivo se fabrican en diferentes modificaciones en las combinaciones requeridas de lo siguiente:

    relé 4 A 220 V;

    optoacopladores de transistores tipo n–p–n 400 mA 60 V;

    optoacopladores triac 50 mA 300 V;

    DAC “parámetro-corriente 4...20 mA”;

    DAC “parámetro-tensión 0...10 V”;

    Salida de 4...6 V 100 mA para controlar un relé de estado sólido.

Así, la acción de control puede ser analógica o digital. - estos son pulsos de ancho variable y analógicos - en forma de voltaje o corriente que varía suavemente en un rango unificado: de 0 a 10 V para voltaje y de 4 a 20 mA para una señal de corriente.

Estas señales de salida se utilizan precisamente para controlar actuadores, por ejemplo, una bomba de sistema de riego o un relé que enciende y apaga un elemento calefactor o un motor de control de válvula. Hay indicadores de señal en el panel regulador.


Para interactuar con una PC, el regulador TRM148 está equipado con una interfaz RS-485, que permite:

    configurar el dispositivo en una PC (los programas de configuración se proporcionan de forma gratuita);

    transmitir a la red los valores actuales de los valores medidos, la potencia de salida del controlador, así como cualquier parámetro programable;

  • recibir datos operativos de la red para generar señales de control.

Se puede argumentar que el mayor rendimiento lo proporciona ley p, - basado en la relación tp / T d .

Sin embargo, si la ganancia del regulador P Kr es pequeña (la mayoría de las veces esto se observa con un retraso), entonces esto no proporciona una alta precisión de control, porque en este caso el valor es grande.

Si Kp > 10, entonces el regulador P es aceptable, y si Kp< 10, то требуется введение в закон управления составляющей.

Ley de regulación de PI

Lo más común en la práctica es controlador PI, que tiene las siguientes ventajas:

  1. Proporciona regulación cero.
  2. Bastante fácil de configurar, porque... Sólo se ajustan dos parámetros, a saber, la ganancia Kp y la constante de tiempo de integración Ti. En un controlador de este tipo es posible optimizar el valor de la relación Kp/Ti-min, lo que garantiza el control con la mínima regulación cuadrática media posible.
  3. Baja sensibilidad al ruido en las medidas (a diferencia del controlador PID).

Ley de control PID

Para los bucles de control más críticos, podemos recomendar el uso , proporcionando el mayor rendimiento en el sistema.

Sin embargo, tenga en cuenta que esto sólo se hace con su configuración óptima (se configuran tres parámetros).

A medida que aumenta el retraso en el sistema, los cambios de fase negativos aumentan considerablemente, lo que reduce el efecto del componente diferencial del controlador. Por lo tanto, la calidad del controlador PID para sistemas con grandes retrasos se vuelve comparable a la calidad del controlador PI.

Además, la presencia de ruido en el canal de medición en un sistema con un controlador PID conduce a fluctuaciones aleatorias significativas en la señal de control del controlador, lo que aumenta la variación del error de control y el desgaste del mecanismo.

Por lo tanto, el controlador PID debe seleccionarse para sistemas de control con un nivel de ruido y un retraso de control relativamente bajos. Ejemplos de tales sistemas son los sistemas de control de temperatura.



Continuando con el tema:
Yeso

Todo el mundo sabe qué son los cereales. Después de todo, el hombre comenzó a cultivar estas plantas hace más de 10 mil años. Por eso hoy en día se le dan nombres a cereales como trigo, centeno, cebada, arroz,...