Saltar al contenido

Control PID con Raspberry Pi Pico

En esta entrada aprenderemos a programar un control PID con la Raspberry Pi Pico usando MicroPython para controlar el nivel de un tanque de agua. Veremos inicialmente como implementar el sistema de medición de nivel del tanque con la Raspberry Pi Pico empleando un sensor de presión diferencial, para posteriormente programar el controlador PID utilizando como ayuda una pantalla OLED.

Antes de comenzar, te hago la invitación para que le des un vistazo a todo nuestro curso gratuito de MicroPython enfocado en la Raspberry Pi Pico y los módulos ESP.

Y que te suscríbas al canal si te gusta la programación de microcontroladores y la teoría del control.

Lista de Materiales

En esta entrada emplearemos diversos materiales, tu puedes conseguir materiales similares con el objetivo de que puedas realizar este tutorial.

  • Raspberry Pi Pico (o módulo ESP)
  • Bomba de Agua (12v, 2A, 3.5l/min, 0.48MPa)
  • Pantalla OLED
  • Potenciometro
  • Fuente de Voltaje de 12v
  • Mangueras
  • Regla
  • Sensor de Presión Diferencial MPX5010
  • Válvula manual
  • Tanque cilindrico (6500 cm^3)
  • Driver para Motor (BTS7960)

Medidor de Nivel de Agua por Presión Diferencial

En este sitio WEB y en el canal de YouTube, ya hemos hablado de los SENSORES de PRESIÓN y especificamente hemos visto como emplear un sensor de presión diferencial para realizar la medición de nivel con un Arduino y también como realizar la medición de nivel con un microcontroladores PIC.

El nivel y el caudal pueden ser derivados de una medida de presión. Uno de los métodos más populares de hacerlo es empleando sensores de presión diferencial, bien sea si queremos medir el nivel de un tanque abierto, o si queremos medir el nivel de un tanque cerrado.

Para eso, podemos valernos de la ecuación de la presión hidrostática.

\Delta P= P_H - P_L =\rho g h
Medicion del nivel por presión diferencial
Sensor de Nivel con PIC

Sensor de Presión MPX con PIC

Timer

Interrupción por Timer

Sensor de Presión MPX5010DP

En esta práctica usaremos el sensor de presión diferencial MPX5010DP que consigue entregar en su salida una relación lineal y proporcional de voltaje de 0v – 5v, conforme la presión vaya aumentando. Este sensor es ideal para microcontroladores, a diferencia de su hermano el MPX10DP que en su salida entrega solo hasta 50mV lo que requerirá de un amplificador operacional para tratar su señal.

MPX5010DP con Arduino

El MPX5010 puede medir una presión de 10 kPa y su salida lineal puede verse en el siguiente gráfico:

Voltaje vs Presión MPX5010DP

Claro está que las aplicaciones de este sensor NO se limitan únicamente a la medición de Nivel, sino a cualquer aplicación donde se desee conocer la medida de presión o presión diferencial.

Como vemos en el gráfico anterior, la ecuación para obtener la presión del sensor viene dada por:

P=\dfrac{V_{out}-0.04V_s\pm Tol}{0.09V_s}

V_s es el voltaje de alimentación (V_s=5v) y V_{out} es el voltaje que entrega el sensor (o sea, el que leemos con arduino en bytes y lo transformamos a voltaje) y Tol es la tolerancia, un ajuste que debemos hacerle al sensor para calibrar la medida.

Medición de Nivel por Presión Hidrostática

El pinado del sensor de presión MPX5010DP se muestra a continuación:

IMPORTANTE: Según el datasheet, el sensor no puede entrar en contacto directo con el liquido, por lo tanto debemos crear un colchón de aire en el interior del tubo que esta conectado al sensor para evitar que el liquido entre al interior del mismo.

Vamos a valernos de que el sensor de presión presenta una medición lineal, según lo pudimos observar en su datasheet y en la gráfica de arriba donde muestra la relación voltaje – Presión.

Tomando como base la ecuación de presión diferencial que relaciona la altura (recordando que la presión a la atmosfera es cero):

P=\rho g h

donde P es la presión, \rho es la gravedad y h es la altura o nivel del tanque. De la ecuación anterior podemos despejar la altura y de esa manera saber el nivel actual del tanque.

h=\dfrac{P}{\rho g}

Circuito

El siguiente circuito será empleado tanto para realizar la práctica de la medición de nivel de un tanque con la Raspberry pi Pico como para realizar un Controlador PID de Nivel con la Raspberry Pi Pico.

control pid con raspberry pi pico

Medición de Nivel de un Tanque con Raspberry Pi Pico

Una vez ya tenemos claros los conceptos que iremos a emplear para la medición de nivel del tanque empleando el sensor de presión diferencial y que ya hemos montado el circuito, prodederemos a realizar la programación en MicroPython de la medición de nivel con la Raspberry Pi Pico, sin embargo, puedes extender esta práctica por ejemplo con un ESP32.

La idea escencial de la práctica es tener un tanque principal en el cual vamos a realizar la medición de nivel y posteriormente el control de nivel de altura. Este tanque tendrá instalado una válvula manual en la parte inferior, con el cual vamos a simular la demanda de salida de nivel. Y por la parte superior va a recibir el caudal proveniente de una bomba de conrriente directa de 12v.

Tendremos un segundo tanque que va a funcionar como reservatório, este tanque va a recibir el liquido que sale del tanque principal por medio de la válvula manual. Adicionalmente, la bomba va a recircular este caudal hacia la parte superior del tanque principal, esto con el fin de no gastar mucha agua en este experimento, donde el obejtivo principal es mostrar la medición y el control de la variable nivel.

Algunas fotografias del sistema se presentan a continuación:

Aplicando la ecuación lineal del sensor la cual fue presentada anteriormente es posible encontrar cual será la altura del tanque.

P=\dfrac{V_{out}-0.04V_s\pm Tol}{0.09V_s}
h=\dfrac{P}{\rho g}
  • V_{out} es el voltaje de salida del sensor
  • V_s es el voltaje de alimentación del sensor
  • Tol: Es una variable que me permite ajustar la medida

Dado que la ecuación del sensor depende de el voltaje de alimentación, se procede a conectar la entrada analógica ADC1 (Pin 27) para hacer un cálculo más preciso (ver ADC Raspberry Pi Pico) y la salida del sensor a la entrada analógica de la raspberry pi pico ADC0 (Pin 26). La medida la vamos a filtrar con un filtro de promedio movil, de 200 muestras para tener una medición estable.

Raspberry Pi Pico Pines

El potenciometro será conectado al pin 28 correspondeinte al ADC2, el valor del potenciometro va a servir para aumentar las revoluciones de la bomba la cual está conectada al PWM2A (pin 26).

Para realizar la corrección en la medida de nivel, hacemos una regresión como se muestra en el video para tener una medida mucho más acorde a la realidad. Esto es especialmente util cuando el nivel es muy bajo, dado que el sensor no se comporta muy bien cuando lee presiones muy bajas.

Para descargar el código puedes hacerlo a través del siguiente botón:

Control PID de Nivel de un Tanque con Raspberry Pi Pico

Una vez tenemos una medida adecuada de la variable controlada (Nivel), vamos a emplear exactamente el mismo circuito donde vamos a involucrar el algoritmo de un controlador PID digital empleando MicroPython y la Raspberry pi Pico.

Para comenzar a entender como funciona un controlador PID, inicialmente, vamos a ver su representación clásica en el siguiente diagrama de bloques, recordando que en el Canal de YouTube tenemos una lista de reproducción completa de PID:

Malla cerrada controlador

Notemos que las señales del diagrama anterior esta representado en el tiempo por muestras k (lo explicaré más adelante) y las funciones del controlador y el proceso C(z) y P(z) en función de la variable compleja z, eso nos indica que estamos hablando de un control digital que actúa por instantes de muestreo.

donde r(k) es nuestra señal de referencia o set point, e(k) es nuestra señal de error (La resta entre r(k) y y(k)), C(z) es nuestro controlador PID de temperatura discreto, u(k) es nuestra señal de control (Ley de control), P(z) es nuestra planta o proceso en representación discreta que deseamos controlar, y(k) es nuestra variable de salida la cual es leída por el sensor del proceso.

Podrán observar en la literatura que la ley de control PID en el caso continuo es representarse por la siguiente ecuación:

u(t)=k_pe(t)+\dfrac{k_p}{t_i}\int_{0}^{t}e(t)dt+k_pt_d\dfrac{de(t)}{dt}

El control PID posee tres parámetros (k_p,t_i,t_d) correspondientes a la ganancia proporcional, tiempo integral y tiempo derivativo respectivamente.

Existen numerosas técnicas y autores que muestran formas de sintonizar o ajustar los parámetros del controlador, que no es nada trivial. En esta entrada, les voy a enseñar TRES formas diferentes de sintonizar este controlador:

Sin embargo, en este caso como vamos a realizar la implementación del control PID en la Raspberry Pi Pico usando MicroPython vamos a representar la ecuación de la ley de control en su forma discreta o digital, que represente el diagrama visto anteriormente.

Antes de continuar, me gustaría invitarte a alguno de mis cursos premium donde te enseño a implementar varias estrategias de control dentro de un Arduino o incluso dentro de un microcontrolador PIC, todo paso a paso.

  • Curso de Sistemas de Control en Dispositivos Microcontrolados en UDEMY (PIC y ARDUINO)
  • Certificado de Aprobación una vez finalices el Curso
  • DESCUENTO si accedes directamente con los siguientes botones de acceso.
  • NOTA: Si buscas el curso directamente en UDEMY o si lo adquieres en otra plataforma distintas a las mostradas anteriormente NO OBTENDRÁS NINGUN DESCUENTO sobre el valor final del Curso.

Controlador PID Discreto en Raspberry Pi Pico

El control discreto PID se obtiene discretizando la ecuación continua vista anteriormente aproximando el término integral mediante la sumatoria trapezoidal y el término derivativo mediante la diferencia de dos puntos asi:

\int e(t)dt = \sum\left[ \dfrac{e(k)+e(k-1)}{2}\right]T_s
\dfrac{de(t)}{dt}=\dfrac{e(k)-e(k-1)}{T_s}

Donde T_s se conoce como el tiempo de muestreo, que es el tiempo a cada cuanto se va a ejecutar la ley de control discreta.

Note que como estamos trabajando en muestras k, eso quiere decir que nuestro error representado por la variable e significa lo siguiente:

  • e(k) es el error en el instante actual, o tiempo de muestreo actual (presente)
  • e(k-1) es el error en un instante anterior, o en el tiempo de muestreo anterior (pasado)

Suscríbete a este sitio WEB para estar enterado de las nuevas entradas!

Por otro lado, es de vital importancia saber escoger adecuadamente el periodo de muestreo T_s al momento de querer implementar controladores digitales, para esta entrada vamos a utilizar uno de los dos método propuesto por Ziegle-Nichols que son:

  1. T_s<\dfrac{\theta}{4}
  2. \dfrac{\tau}{20}\leq T_s\leq\dfrac{\tau}{10}

Para nuestro caso del control PID de nivel de un tanque con Raspberry Pi Pico escogeremos un T=10s.

Los parámetros de ajuste del controlador PID de temperatura que vamos a implementar en Arduino los vamos a estimar usando tres estrategias diferentes a partir de los parámetros continuos k_p,\tau_i,\tau_d.

Para este caso vamos a tomar el retardo de tiempo de nuestro modelo continuo como:

\theta = L +T_s/2

en donde T_s/2 es una aproximación correspondiente al retardo introducido por el muestreador y el retenedor, recordando que T_s es el período de muestreo.

El control discreto PID se obtiene discretizando la ecuación continua (vista al comienzo de esta entrada) de esa forma obtener la función de transferencia pulso del controlador PID digital:

C(z^{-1})=\dfrac{u(k)}{e(k)}=\dfrac{q_0+q_1z^{-1}+q_2z^{-2}}{1-z^{-1}}

donde:

q_0=k_p\left [ 1+\dfrac{T_s}{2t_i}+\dfrac{t_d}{T_s} \right ]
q_1=-k_p\left [ 1-\dfrac{T_s}{2t_i}+\dfrac{2t_d}{T_s} \right ]
q_2=\dfrac{k_pt_d}{T_s}

Con esto, la ley de control que vamos a ingresar a nuestro PIC sale del control PID discreto en Arduino (Despejando u(k))

u(k)(1-z^{-1})=q_0e(k)+q_1z^{-1}e(k)+q_2z^{-2}e(k)
u(k)-u(k)z^{-1}=q_0e(k)+q_1z^{-1}e(k)+q_2z^{-2}e(k)
u(k)=u(k)z^{-1}+q_0e(k)+q_1z^{-1}e(k)+q_2z^{-2}e(k)

Aplicando transformada inversa Z obtenemos la ecuación en diferencias:

u(k)=u(k-1)+q_0e(k)+q_1e(k-1)+q_2e(k-2)

Así, u(k) quiere decir la ley de control actual, u(k-1) es la ley de control un instante de muestreo atrás,  e(k) es el error actual (Referencia – temperatura), e(k-1) es el error un instante de muestreo atrás,  e(k-2) es el error dos instantes de muestreo atrás.

Planta de Nivel de un Tanque

En una entrada pasada, habias estudiado la ecuación del balance de materia de un tanque de nivel, donde obtuvimos una función de trasferencia de un tanque sobre un punto de operación.

Recordemos que la función de transferencia del tanque viene dado por la siguiente función de transferencia:

\dfrac{\bar{h}}{\bar{a_1}} = \dfrac{k_1/A}{s+\dfrac{k_2a_2\sqrt{2g}}{2A\sqrt{H_o}}}

Donde:

  • A=0.0284 m^2: área del tanque
  • H_{o}=0.13m es la altura en equilibrio
  • k_1 y k_2 son las constantes de las válvulas
  • a_1 y a_2 son las aberturas de las válvulas
  • g=9.8m/s^2 es la fuerza de gravedad.

Sin embargo, dado que en este ejemplo, no tenemos una válvula en la entrada, sino que por el contrario tenemos una bomba electrica, podemos considerar el caudal de entrada como:

q_e=k_1u

Donde k_1 es la constante de la bomba y u es el voltaje medio aplicado a la bomba (0 – 12v), por lo tanto la función de transferencia anterior puedo asumirla como:

\dfrac{\bar{h}}{\bar{u}} = \dfrac{k_1/A}{s+\dfrac{k_2a_2\sqrt{2g}}{2A\sqrt{H_o}}}

Para determinar la constante de la válvula k_2 se colocó el sistema en estado estacionario H_o = 13cm, es decir en el punto donde todo el liquido que entra es igual todo el liquido que sale, Para eso abrimos la válvula de salida media vuelta o 20% (teniendo en consideración que la válvula abre completamente cuando se realizan 2 vueltas y media) y colocando un PWM de 35746 (1.8v).

Por medio de la técnica del aforo y un recipiende con medida volumétrica se determinó el caudal de la válvula bajo estas condiciones:

Tiempo (s)Volumen (l)Cudal (l/s)
240.50.020833333
23.80.50.021008403
230.50.02173913

Heciendo la conversión a m^3/s tenemos que el caudal medio fue q_s = 2.11\times 10^{-5} m^3/s

A partir de la ecuación de la válvula de salida:

Q_s=k_2a_2 \sqrt{2gH}

Consigo determinar quien es k_2:

k_2=\dfrac{Q_s}{a_2 \sqrt{2gH}}=\dfrac{2.11\times 10^{-5}}{0.2\sqrt{2(9.8)(0.13)}}=6.63\times 10^{-5}

Con esto ya conocemos el denominador de la función de transferencia:

\dfrac{\bar{h}}{\bar{u}} = \dfrac{k_1/0.0284}{s+0.003121}= \dfrac{12284k_1}{350s+1}=\dfrac{K}{\tau s+1}

Cuando entró en equilibrio, se modificó un poco el PWM para 35846 (1.805v) y se observo que el nivel subió de 13cm hasta 15.5 cm, con esto podemos ver la ganancia estática del sistema:

K = \dfrac{0.155-0.13}{1.805 - 1.8}=5

Por lo tanto podemos ssaber quien es k_1

12284k_1 = K
k_1=\dfrac{K}{12284}=\dfrac{5}{12284}=4.07\times 10^{-4}

Finalmente, adicionamos un pequeño retardo que puede verse justo cuando inicia la bomba, dado que este retardo es necesario si deseamos usar la sintonia de Ziegler y Nichols, así la función de transferencia empleada en el sistema es:

G(s)= \dfrac{5}{350s+1}e^{-3s}

El script para el cálculo de la función de transferencia en matlab es el siguiente:

clc
clear all
close all

D = 19/100; %m
A = pi*D^2/4;%m2
Ho = 13/100; %m
a2 = 0.2;
k1 = 4.0703e-04;
k2 = 6.63e-05;
g = 9.8;

num = k1/A;
den = [1 (k2*a2*sqrt(2*g)/(2*A*sqrt(Ho)))];


G = tf(num/den(2),den/den(2))

Descargas

Para el control pid del nivel de un tanque con la Raspberry Pi Pico en MicroPython puedes usar el siguiente código:

[cite]

Eso es todo por la entrada del dia de hoy, espero les haya gustado y hayan aprendido algo nuevo. Si te ha servido el contenido de esta entrada, de los videos y los códigos de implementación y deseas apoyar mi trabajo invitandome a un café super barato, puedes hacerlo en el siguiente link:

👉 Invitar a Sergio a un Café ☕️

Que esten muy bien, nos vemos en la siguiente entrada.

Entradas relacionadas

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Comentarios (10)

Hola Sergio, primeramente te felicito por el material tan extenso y descrito de forma tan detallada y entendible, ahora quería realizarte una consulta, que tipo de amplificador operacional tendría que utilizar si estoy manejando como sensor de presión diferencial al MPX10DP

Responder

Hola sergio, tengo un error en el código y se trata de: #OLED
oled = SSD1306_I2C(WIDTH, HEIGHT, i2c)
No deja avanzar ni vincular el código, necesito ayuda ya que estoy implementando el proyecto.

Responder

Tienes que instalar la librería SSD1306_I2C en la Raspberry Pi Pico para que funcione. En el video se muestra todo el proceso.

Responder

Hola Sergio! Intentare hacer una imprementacion PID para controlar el pH de una solucion en un tanque, algo muy usual en la industria quimica, agronomica, sanitaria… Imagino que el approach sera similar a lo que desarrollaste en estos videos. Gracias por compartir (perdon las faltas ortograficas, pero mi teclado esta configurado en otro idioma). Saludos!

Responder

Excelente Gilberto, éxitos en tu implementación. El procedimiento es el mismo, solo cambia el proceso y los parametros de sintonia del controlador. Saludos

Responder

Haz probado protocolos de comunicaion como MODBUS

Responder

Hola Sergio. Por favor dejeme saber si posteriormente tambien habra un video aplicando MPC a esta planta de nivel.

Responder

Hola Eduardo, infortunadamente por ahora no, de hecho ya desmonté la planta pues estoy en una mudanza. Talvez en un futuro vuelva y monte un sistema similar y hagamos controladores más avanzados.

Responder

Sergio, es probable hacer este mismo codigo en Spyder-Python? Me gustaria contactarme contigo de ser posible.

Responder

Hola Eduardo, deseas implementarlo en Spyder de forma de simulación? O quieres usar el computador como controlador? En esta entrada nota que estamos usando la Raspberry Pi Pico como microcontrolador, y no puedes usar directamente Python pues es muy pesado para un microcontrolador, es por eso que empleamos MicroPhython. Existen varios IDEs, pero el que yo uso en el Curso es el Thonny. Habría que consultar si Spyder permite ejecutar y programar en MicroPython, pero creo que no. Cualquier inquietud puedes dejarla en los comentários aqui en el sitio web o en el canal, con algún espacio puedo ir respondiendo. Saludos.

Responder