{"id":1923,"date":"2023-01-11T11:26:57","date_gmt":"2023-01-11T11:26:57","guid":{"rendered":"https:\/\/garikoitz.info\/blog\/?p=1923"},"modified":"2024-02-29T19:19:30","modified_gmt":"2024-02-29T19:19:30","slug":"sintonizar-pid-con-arduino-laboratorio-de-control-de-temperatura-tclab","status":"publish","type":"post","link":"https:\/\/garikoitz.info\/blog\/2023\/01\/sintonizar-pid-con-arduino-laboratorio-de-control-de-temperatura-tclab\/","title":{"rendered":"SINTONIZAR PID CON ARDUINO \u2013 Laboratorio de Control de Temperatura (TCLab)"},"content":{"rendered":"\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">\u00cdndice<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Alternar tabla de contenidos\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 eztoc-toggle-hide-by-default' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/garikoitz.info\/blog\/2023\/01\/sintonizar-pid-con-arduino-laboratorio-de-control-de-temperatura-tclab\/#Introduccion\" >Introducci\u00f3n<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/garikoitz.info\/blog\/2023\/01\/sintonizar-pid-con-arduino-laboratorio-de-control-de-temperatura-tclab\/#Caracteristicas\" >Caracter\u00edsticas<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/garikoitz.info\/blog\/2023\/01\/sintonizar-pid-con-arduino-laboratorio-de-control-de-temperatura-tclab\/#Identificacion\" >Identificaci\u00f3n<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/garikoitz.info\/blog\/2023\/01\/sintonizar-pid-con-arduino-laboratorio-de-control-de-temperatura-tclab\/#Control_PID_con_una_temperatura\" >Control PID con una temperatura<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/garikoitz.info\/blog\/2023\/01\/sintonizar-pid-con-arduino-laboratorio-de-control-de-temperatura-tclab\/#CC-25_PI\" >CC-25 (PI)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/garikoitz.info\/blog\/2023\/01\/sintonizar-pid-con-arduino-laboratorio-de-control-de-temperatura-tclab\/#ZN-10_PI\" >ZN-10 (PI)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/garikoitz.info\/blog\/2023\/01\/sintonizar-pid-con-arduino-laboratorio-de-control-de-temperatura-tclab\/#LAMBDA_PI\" >LAMBDA (PI)<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/garikoitz.info\/blog\/2023\/01\/sintonizar-pid-con-arduino-laboratorio-de-control-de-temperatura-tclab\/#Control_PID_con_dos_temperaturas\" >Control PID con dos temperaturas<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/garikoitz.info\/blog\/2023\/01\/sintonizar-pid-con-arduino-laboratorio-de-control-de-temperatura-tclab\/#Codigo_Arduino\" >C\u00f3digo Arduino<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/garikoitz.info\/blog\/2023\/01\/sintonizar-pid-con-arduino-laboratorio-de-control-de-temperatura-tclab\/#Conclusiones\" >Conclusiones<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/garikoitz.info\/blog\/2023\/01\/sintonizar-pid-con-arduino-laboratorio-de-control-de-temperatura-tclab\/#Descargas\" >Descargas<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/garikoitz.info\/blog\/2023\/01\/sintonizar-pid-con-arduino-laboratorio-de-control-de-temperatura-tclab\/#Enlaces\" >Enlaces<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/garikoitz.info\/blog\/2023\/01\/sintonizar-pid-con-arduino-laboratorio-de-control-de-temperatura-tclab\/#Libros_y_publicaciones\" >Libros y publicaciones<\/a><\/li><\/ul><\/nav><\/div>\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Introduccion\"><\/span>Introducci\u00f3n<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">El <a rel=\"noreferrer noopener\" href=\"http:\/\/apmonitor.com\/pdc\/index.php\/Main\/ArduinoTemperatureControl\" target=\"_blank\">Laboratorio de Control de Temperatura<\/a> (<a rel=\"noreferrer noopener\" href=\"http:\/\/apmonitor.com\/pdc\/index.php\/Main\/ArduinoTemperatureControl\" target=\"_blank\">TCLab<\/a>) es una peque\u00f1a placa compatible con Arduino creada por <a rel=\"noreferrer noopener\" href=\"https:\/\/apm.byu.edu\/prism\/index.php\/Members\/JohnHedengren\" target=\"_blank\">John D. Hedengren<\/a> y la comunidad APMonitor. Esta placa est\u00e1 dise\u00f1ada para fines did\u00e1cticos y despu\u00e9s de probarla os puedo asegurar que es una virguer\u00eda para los amantes del control. La placa en s\u00ed es muy sencilla, consta de dos sensores de temperatura y dos transistores  usados como calentadores, lo realmente interesante es el software que lo acompa\u00f1a ya que tenemos a nuestra disposici\u00f3n diferentes desarrollos en <a href=\"https:\/\/apmonitor.com\/pdc\/uploads\/Main\/tclab.zip\">Matlab, Simulink y Python<\/a> que van desde un simple PID hasta un controlador MPC no lineal, en definitiva, una maravilla con un potencial did\u00e1ctico enorme.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En esta primera entrada vamos a obviar el software que acompa\u00f1a a la placa usando mis propios desarrollos tanto en el firmware de Arduino como en el software de recolecci\u00f3n de datos.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Caracteristicas\"><\/span>Caracter\u00edsticas<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">La placa est\u00e1 compuesta por dos sensores de temperatura <a rel=\"noreferrer noopener\" href=\"https:\/\/www.analog.com\/media\/en\/technical-documentation\/data-sheets\/TMP35_36_37.pdf\" target=\"_blank\">TMP36<\/a> con un rango de -40 a 150\u00baC y dos transistores <a rel=\"noreferrer noopener\" href=\"https:\/\/www.st.com\/resource\/en\/datasheet\/tip31c.pdf\" target=\"_blank\">TIP31C<\/a> usados como calentadores. La transferencia entre sensor y calentador se da mediante conducci\u00f3n, convecci\u00f3n y radiaci\u00f3n, y como m\u00e1s adelante comprobaremos en la identificaci\u00f3n, al estar tan juntas se afectan mucho entre s\u00ed.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/tclab_schematic_garikoitz-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"723\" src=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/tclab_schematic_garikoitz-1-1024x723.png\" alt=\"\" class=\"wp-image-1932\" style=\"width:512px;height:362px\" srcset=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/tclab_schematic_garikoitz-1-1024x723.png 1024w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/tclab_schematic_garikoitz-1-300x212.png 300w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/tclab_schematic_garikoitz-1-768x542.png 768w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/tclab_schematic_garikoitz-1-382x270.png 382w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/tclab_schematic_garikoitz-1.avif 1385w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Sensor y calentador est\u00e1n unidos por una pintura t\u00e9rmica de color gris que se vuelve rosa a medida que aumenta la temperatura. En la imagen que se puede ver a continuaci\u00f3n T2 estaba aproximadamente a 50\u00baC.<\/p>\n\n\n<div class=\"wp-block-image is-style-default\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/PXL_20230103_161130020-scaled.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/PXL_20230103_161130020-1024x768.jpg\" alt=\"T2 con temperatura\" class=\"wp-image-1933\" style=\"width:512px;height:384px\" srcset=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/PXL_20230103_161130020-1024x768.jpg 1024w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/PXL_20230103_161130020-300x225.jpg 300w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/PXL_20230103_161130020-768x576.jpg 768w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/PXL_20230103_161130020-1536x1152.jpg 1536w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/PXL_20230103_161130020-2048x1536.jpg 2048w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/PXL_20230103_161130020-360x270.jpg 360w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Identificacion\"><\/span>Identificaci\u00f3n<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Con el objetivo de implementar dos PIDs vamos a realizar un StepTest a cada temperatura para empezar a sacar conclusiones. En fucsia vemos la temperatura T1 a la que se est\u00e1 realizando el test (\u00baC), en amarillo la salida PWM del calentador 1 y en azul la  temperatura T2 (\u00baC).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/StepTest_T1T2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"869\" height=\"1024\" src=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/StepTest_T1T2-869x1024.png\" alt=\"\" class=\"wp-image-1949\" style=\"width:435px;height:512px\" srcset=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/StepTest_T1T2-869x1024.png 869w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/StepTest_T1T2-255x300.png 255w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/StepTest_T1T2-768x905.png 768w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/StepTest_T1T2-1304x1536.png 1304w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/StepTest_T1T2-229x270.png 229w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/StepTest_T1T2.avif 1549w\" sizes=\"auto, (max-width: 869px) 100vw, 869px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">La primera conclusi\u00f3n a la que he llegado es que hay que limitar de alguna manera que los calentadores se acerquen a los 100\u00baC. Para ello en Manual limitaremos la salida PWM a 190 y en Autom\u00e1tico el m\u00e1ximo punto de consigna ser\u00e1 de75\u00baC.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La segunda conclusi\u00f3n es que hay mucha interrelaci\u00f3n entre temperaturas de modo que si queremos controlar las dos temperaturas en determinadas situaciones no vamos a poder cumplir con los puntos de consigna.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En cuanto a la identificaci\u00f3n, los resultados son similares tanto en saltos positivos como negativos, qued\u00e1ndonos con las constantes halladas de un salto positivo intermedio.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_12_21_13.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"603\" src=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_12_21_13-1024x603.png\" alt=\"\" class=\"wp-image-1950\" style=\"width:512px;height:302px\" srcset=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_12_21_13-1024x603.png 1024w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_12_21_13-300x177.png 300w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_12_21_13-768x452.png 768w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_12_21_13-1536x904.png 1536w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_12_21_13-459x270.png 459w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_12_21_13.avif 1549w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"lyte-wrapper fourthree\" style=\"width:420px;max-width:100%;margin:5px;\"><div class=\"lyMe\" id=\"WYL_CUju0yjvfOM\"><div id=\"lyte_CUju0yjvfOM\" data-src=\"\/\/i.ytimg.com\/vi\/CUju0yjvfOM\/hqdefault.jpg\" class=\"pL\"><div class=\"tC\"><div class=\"tT\"><\/div><\/div><div class=\"play\"><\/div><div class=\"ctrl\"><div class=\"Lctrl\"><\/div><div class=\"Rctrl\"><\/div><\/div><\/div><noscript><a href=\"https:\/\/youtu.be\/CUju0yjvfOM\" rel=\"nofollow\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i.ytimg.com\/vi\/CUju0yjvfOM\/0.jpg\" alt=\"YouTube video thumbnail\" width=\"420\" height=\"295\" \/><br \/>Ver este v\u00eddeo en YouTube<\/a><\/noscript><\/div><\/div><div class=\"lL\" style=\"max-width:100%;width:420px;margin:5px;\"><\/div><figcaption>Identificaci\u00f3n de T1<\/figcaption><\/figure>\n\n\n<figure class=\"wp-block-table aligncenter is-style-regular\"><table><tbody><tr><td><\/td><td><strong>T1<\/strong><\/td><td><strong>T2<\/strong><\/td><\/tr><tr><td><strong>K(%\/%)<\/strong><\/td><td>0.380<\/td><td>0.405<\/td><\/tr><tr><td><strong>T<sub>0<\/sub>(s)<\/strong><\/td><td>29.5<\/td><td>20<\/td><\/tr><tr><td><strong>T<sub>p<\/sub>(s)<\/strong><\/td><td>100.5<\/td><td>117<\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">Resultado de la identificaci\u00f3n<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Control_PID_con_una_temperatura\"><\/span>Control PID con una temperatura<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">El control de una sola temperatura es muy sencillo. A continuaci\u00f3n se muestra la respuesta de tres sinton\u00edas aunque todas las probadas respondieron adecuadamente.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"CC-25_PI\"><\/span>CC-25 (PI)<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Sinton\u00eda Cohen-Coon con una raz\u00f3n de amortiguamiento del 25%.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_13_18_17.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"311\" src=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_13_18_17-1024x311.png\" alt=\"\" class=\"wp-image-1954\" style=\"width:512px;height:156px\" srcset=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_13_18_17-1024x311.png 1024w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_13_18_17-300x91.png 300w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_13_18_17-768x234.png 768w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_13_18_17-1536x467.png 1536w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_13_18_17-604x184.png 604w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_13_18_17.avif 1549w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Respuesta real<\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">La simulaci\u00f3n se corresponde con el primer cambio de Set Point.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_13_13_46.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"269\" src=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_13_13_46-1024x269.png\" alt=\"\" class=\"wp-image-1955\" style=\"width:512px;height:135px\" srcset=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_13_13_46-1024x269.png 1024w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_13_13_46-300x79.png 300w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_13_13_46-768x202.png 768w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_13_13_46-1536x404.png 1536w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_13_13_46-604x159.png 604w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_13_13_46.avif 1549w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Simulaci\u00f3n en lazo cerrado de un cambio de SP de 7\u00baC<\/figcaption><\/figure>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"ZN-10_PI\"><\/span>ZN-10 (PI)<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Sinton\u00eda Ziegler-Nichols con una raz\u00f3n de amortiguamiento del 10%. La raz\u00f3n de amortiguamiento es muy peque\u00f1a, casi imperceptible (0.1\u00baC).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_14_23_56.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"311\" src=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_14_23_56-1024x311.png\" alt=\"\" class=\"wp-image-1957\" style=\"width:512px;height:156px\" srcset=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_14_23_56-1024x311.png 1024w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_14_23_56-300x91.png 300w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_14_23_56-768x234.png 768w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_14_23_56-1536x467.png 1536w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_14_23_56-604x184.png 604w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_14_23_56.avif 1549w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Respuesta real<\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">La simulaci\u00f3n se corresponde con el primer cambio de Set Point.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_14_23_59.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"269\" src=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_14_23_59-1024x269.png\" alt=\"\" class=\"wp-image-1958\" style=\"width:512px;height:135px\" srcset=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_14_23_59-1024x269.png 1024w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_14_23_59-300x79.png 300w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_14_23_59-768x202.png 768w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_14_23_59-1536x404.png 1536w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_14_23_59-604x159.png 604w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_14_23_59.avif 1549w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Simulaci\u00f3n en lazo cerrado de un cambio de SP de 9\u00baC<\/figcaption><\/figure>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"LAMBDA_PI\"><\/span>LAMBDA (PI)<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_14_33_56.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"311\" src=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_14_33_56-1024x311.png\" alt=\"\" class=\"wp-image-1960\" style=\"width:512px;height:156px\" srcset=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_14_33_56-1024x311.png 1024w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_14_33_56-300x91.png 300w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_14_33_56-768x234.png 768w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_14_33_56-1536x467.png 1536w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_14_33_56-604x184.png 604w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_09_01_2023_14_33_56.avif 1549w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Respuesta real<\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">La simulaci\u00f3n se corresponde con el primer cambio de Set Point.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_14_33_58.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"269\" src=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_14_33_58-1024x269.png\" alt=\"\" class=\"wp-image-1961\" style=\"width:512px;height:135px\" srcset=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_14_33_58-1024x269.png 1024w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_14_33_58-300x79.png 300w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_14_33_58-768x202.png 768w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_14_33_58-1536x404.png 1536w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_14_33_58-604x159.png 604w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_sim_09_01_2023_14_33_58.avif 1549w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Simulaci\u00f3n en lazo cerrado de un cambio de SP de 8\u00baC<\/figcaption><\/figure>\n<\/div>\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"lyte-wrapper fourthree\" style=\"width:420px;max-width:100%;margin:5px;\"><div class=\"lyMe\" id=\"WYL__Hz_rcUjVw0\"><div id=\"lyte__Hz_rcUjVw0\" data-src=\"\/\/i.ytimg.com\/vi\/_Hz_rcUjVw0\/hqdefault.jpg\" class=\"pL\"><div class=\"tC\"><div class=\"tT\"><\/div><\/div><div class=\"play\"><\/div><div class=\"ctrl\"><div class=\"Lctrl\"><\/div><div class=\"Rctrl\"><\/div><\/div><\/div><noscript><a href=\"https:\/\/youtu.be\/_Hz_rcUjVw0\" rel=\"nofollow\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i.ytimg.com\/vi\/_Hz_rcUjVw0\/0.jpg\" alt=\"YouTube video thumbnail\" width=\"420\" height=\"295\" \/><br \/>Ver este v\u00eddeo en YouTube<\/a><\/noscript><\/div><\/div><div class=\"lL\" style=\"max-width:100%;width:420px;margin:5px;\"><\/div><figcaption>Control PID de T1. T2 permanece en manual<\/figcaption><\/figure>\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Control_PID_con_dos_temperaturas\"><\/span>Control PID con dos temperaturas<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Para la prueba se ha sintonizado T1 con ZN-10 (PI) (<a rel=\"noreferrer noopener\" href=\"https:\/\/garikoitz.info\/blog\/descargas\/Z-N.pdf\" target=\"_blank\">Ziegler-Nichols<\/a> con una raz\u00f3n de amortiguamiento del 10%) que est\u00e1 dise\u00f1ada para comportarse mejor ante perturbaciones que ante cambios de Set Point. T2 se ha sintonizado con IAE-SP (PI), dise\u00f1ada para minimizar la integral del valor absoluto del error y comportarse de forma equilibrada ante cambios de Set Point aunque con cierto sobre impulso. Al inicio de la prueba se sit\u00faan las temperaturas T1 y T2 en 40 y 42\u00baC respectivamente y a partir de ah\u00ed se realizan una serie de cambios de Set Point. Como se aprecia en la imagen, las sinton\u00edas se comportan seg\u00fan lo esperado provoc\u00e1ndose perturbaciones entre s\u00ed.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_11_01_2023_00_02_31.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"603\" src=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_11_01_2023_00_02_31-1024x603.png\" alt=\"\" class=\"wp-image-1968\" style=\"width:512px;height:302px\" srcset=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_11_01_2023_00_02_31-1024x603.png 1024w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_11_01_2023_00_02_31-300x177.png 300w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_11_01_2023_00_02_31-768x452.png 768w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_11_01_2023_00_02_31-1536x904.png 1536w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_11_01_2023_00_02_31-459x270.png 459w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2023\/01\/ACP_11_01_2023_00_02_31.avif 1549w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Respuesta real del control de las dos temperaturas<\/figcaption><\/figure>\n<\/div>\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"lyte-wrapper fourthree\" style=\"width:420px;max-width:100%;margin:5px;\"><div class=\"lyMe\" id=\"WYL_QE-M3ht25qA\"><div id=\"lyte_QE-M3ht25qA\" data-src=\"\/\/i.ytimg.com\/vi\/QE-M3ht25qA\/hqdefault.jpg\" class=\"pL\"><div class=\"tC\"><div class=\"tT\"><\/div><\/div><div class=\"play\"><\/div><div class=\"ctrl\"><div class=\"Lctrl\"><\/div><div class=\"Rctrl\"><\/div><\/div><\/div><noscript><a href=\"https:\/\/youtu.be\/QE-M3ht25qA\" rel=\"nofollow\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i.ytimg.com\/vi\/QE-M3ht25qA\/0.jpg\" alt=\"YouTube video thumbnail\" width=\"420\" height=\"295\" \/><br \/>Ver este v\u00eddeo en YouTube<\/a><\/noscript><\/div><\/div><div class=\"lL\" style=\"max-width:100%;width:420px;margin:5px;\"><\/div><figcaption>V\u00eddeo: Respuesta real del control de las dos temperaturas<\/figcaption><\/figure>\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Codigo_Arduino\"><\/span>C\u00f3digo Arduino<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">He aprovechado para actualizar <a href=\"https:\/\/garikoitz.info\/blog\/2020\/05\/arduino-com-plotter\/#Descarga\" target=\"_blank\" rel=\"noreferrer noopener\">Arduino COM Plotter<\/a> para poder visualizar ambas temperaturas de forma separada pero simult\u00e1neamente. Tambi\u00e9n se ha implementado la posibilidad de enviar comandos v\u00eda serial para poder hacer cambios de Set Point entre otras cosas. A continuaci\u00f3n un resumen de los comandos implementados:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>T1M <\/strong>&#8211; Pone el <strong>PID <\/strong>de la temperatura 1 en <strong>Manual<\/strong>. Al hacer esto s\u00f3lo podemos cambiar la OP (salida PWM). Al arrancar Arduino arranca en \u00e9ste modo. En Manual el <em>Set Point y la PV marcan lo mismo<\/em> (PV Tracking) para evitar problemas al pasar a Autom\u00e1tico.<\/li>\n\n\n\n<li><strong>T1A <\/strong>&#8211; Pone el <strong>PID <\/strong>de la temperatura 1 a <strong>Autom\u00e1tico<\/strong>. En \u00e9ste modo s\u00f3lo podemos alterar el Set Point limitado a un m\u00e1ximo de 75\u00baC.<\/li>\n\n\n\n<li><strong>T1OP X<\/strong> &#8211; Permite <strong>cambiar <\/strong>la <strong>salida PWM<\/strong> de la temperatura 1 siendo X un valor entre 0 y 190. S\u00f3lo si el controlador est\u00e1 en Manual.<\/li>\n\n\n\n<li><strong>T1SP X<\/strong> &#8211; Permite <strong>cambiar <\/strong>el <strong>Set Point<\/strong> de la temperatura 1 siendo X un valor entre 0 y 75\u00baC. S\u00f3lo si el controlador est\u00e1 en autom\u00e1tico.<\/li>\n\n\n\n<li><strong>T1KC X<\/strong> &#8211; Permite cambiar la constante proporcional del controlador PID de la temperatura 1.<\/li>\n\n\n\n<li><strong>T1KI X<\/strong> &#8211; Permite cambiar la constante integral del controlador PID de la temperatura 1.<\/li>\n\n\n\n<li><strong>T1KD X<\/strong> &#8211; Permite cambiar la constante derivativa del controlador PID de la temperatura 1.<\/li>\n\n\n\n<li><strong>SST1<\/strong> &#8211; Realiza un <strong>Step Test<\/strong> de la temperatura 1. Para ello pone ambos controladores en Manual, su salida a 0, espera a que la temperatura a la que se va a realizar el test est\u00e9 por debajo de 30\u00baC y a continuaci\u00f3n comienza el test. El test dura unos 30 minutos.<\/li>\n<\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/***************************************************************\n* TCLAB - Control PID v0.2\n* Desarrollado por Garikoitz Mart\u00ednez [garikoitz.info] [01\/2023]\n* https:\/\/garikoitz.info\/blog\/?p=1923\n***************************************************************\/\n\/***************************************************************\n* Librer\u00edas\n***************************************************************\/\n#include &lt;PID_v1.h>\n\/***************************************************************\n* Variables\n***************************************************************\/\nint T1pin = 0;\nint T2pin = 2;\nint H1pin = 3;\nint H2pin = 5;\nfloat T1_PV = 0.0;\nfloat T2_PV = 0.0; \nfloat T1_SP = 0.0;\nfloat T2_SP = 0.0;\nint T1_OP = 0;\nint T2_OP = 0;\nint T1SPMAX = 75;\nint T2SPMAX = 75;\nint T1OPMAX = 190;\nint T2OPMAX = 190;\nconst long baud = 9600;       \/\/ serial baud rate\nunsigned long previousMillis = 0;\nint Ts = 50; \/\/Sample time in ms\nint contador = 0;\nint n = 15; \/\/Promedio lecturas\nboolean newData = false;       \nconst char sp = ' ';           \nconst char nl = '\\n';\n\/\/ global variables\nchar Buffer[64]; \nint buffer_index = 0; \nString cmd;  \nfloat val;\n\/\/PID\ndouble SetpointT1, InputT1, OutputT1, SetpointT2, InputT2, OutputT2;\ndouble KcT1=13.70, KiT1=0.14, KdT1=0.0; \/\/ZN10\ndouble KcT2=21.82, KiT2=0.18, KdT2=0.0; \/\/IAE-SP\nPID PIDT1(&amp;InputT1, &amp;OutputT1, &amp;SetpointT1, KcT1, KiT1, KdT1, P_ON_E, DIRECT);    \/\/PI-D\n\/\/PID PIDT1(&amp;InputT1, &amp;OutputT1, &amp;SetpointT1, KcT1, KiT1, KdT1, P_ON_M, DIRECT);  \/\/I-PD\nPID PIDT2(&amp;InputT2, &amp;OutputT2, &amp;SetpointT2, KcT2, KiT2, KdT2, P_ON_E, DIRECT);    \/\/PI-D\n\/\/PID PIDT2(&amp;InputT2, &amp;OutputT2, &amp;SetpointT2, Kc, Ki, Kd, P_ON_M, DIRECT);        \/\/I-PD\n\/***************************************************************\n* SINTON\u00cdAS\n* T1 -> K:0.380  T0:29.5   TP:100.5\n* CC25      PI KcT1=08.29, KiT1=0.14, KdT1=0.0 \n* CC10      PI KcT1=04.97, KiT1=0.07, KdT1=0.0 \n* ZN25      PI KcT1=08.07, KiT1=0.08, KdT1=0.0  \n* ZN10      PI KcT1=05.37, KiT1=0.05, KdT1=0.0  \n* ITAE-C    PI KcT1=07.49, KiT1=0.12, KdT1=0.0 \n* ITAE-SP   PI KcT1=04.74, KiT1=0.05, KdT1=0.0  \n* IAE-C     PI KcT1=08.67, KiT1=0.12, KdT1=0.0 \n* IAE-SP    PI KcT1=05.73, KiT1=0.05, KdT1=0.0  \n* LAMBDA    PI KcT1=03.81, KiT1=0.04, KdT1=0.0      TF:40\n* IMC       PI KcT1=04.73, KiT1=0.04, KdT1=0.0      TF:60\n* SIMC      PI KcT1=04.44, KiT1=0.04, KdT1=0.0      TF:30\n* IMP.SIMC  PI KcT1=04.18, KiT1=0.04, KdT1=0.0      TF:40\n* ------------------------------------------------------\n* T2 -> K:0.405   T0:20    TP:117 \n* CC25      PI KcT1=12.45, KiT1=0.08, KdT1=0.0 \n* CC10      PI KcT1=07.92, KiT1=0.13, KdT1=0.0 \n* ZN25      PI KcT1=13.00, KiT1=0.19, KdT1=0.0 \n* ZN10      PI KcT1=08.66, KiT1=0.13, KdT1=0.0 \n* ITAE-C    PI KcT1=11.91, KiT1=0.23, KdT1=0.0 \n* ITAE-SP   PI KcT1=07.30, KiT1=0.06, KdT1=0.0  \n* IAE-C     PI KcT1=13.87, KiT1=0.25, KdT1=0.0 \n* IAE-SP    PI KcT1=08.57, KiT1=0.07, KdT1=0.0 \n* LAMBDA    PI KcT1=04.13, KiT1=0.04, KdT1=0.0      TF:50\n* IMC       PI KcT1=06.02, KiT1=0.05, KdT1=0.0      TF:50\n* SIMC      PI KcT1=05.78, KiT1=0.05, KdT1=0.0      TF:30\n* IMP.SIMC  PI KcT1=06.11, KiT1=0.05, KdT1=0.0      TF:30\n***************************************************************\/\n\/***************************************************************\n* SETUP\n***************************************************************\/\nvoid setup() \n{ \n\tanalogReference(EXTERNAL);\n  while (!Serial) {\n    ; \/\/ wait for serial port to connect.\n  }\n  Serial.begin(baud);\n  Serial.flush();\n  \/\/\n  PIDT1.SetOutputLimits(0, 255);\n  PIDT1.SetMode(MANUAL);\n  PIDT2.SetOutputLimits(0, 255);\n  PIDT2.SetMode(MANUAL);\n  if (Ts &lt; 100){\n    PIDT1.SetSampleTime(Ts);\n    PIDT2.SetSampleTime(Ts);\n  }\n    \n}\n\/***************************************************************\n* BUCLE PRINCIPAL\n***************************************************************\/\nvoid loop() \n{\n  if (millis() - previousMillis > Ts)\n  {\n    previousMillis = millis();\n    \/\/Lectura Temperaturas\n    LecturaTTs();\n    LeoCMD();\n    ProcesoCMD();\n    EjecutoCMD();\n    \/\/PID (Par\u00e1metros v\u00eda serial cmds)\n    if (PIDT1.GetMode() == 1){\/\/AUTO\n        InputT1 = T1_PV;\n        SetpointT1 = T1_SP;\n        PIDT1.Compute();\n        T1_OP = map(OutputT1, 0, 255, 0, 100); \/\/PWM -> %\n        analogWrite(H1pin,OutputT1);\n     }else if (PIDT1.GetMode() == 0) {\/\/MANUAL\n        T1_SP = T1_PV;\n     }\n     if (PIDT2.GetMode() == 1){\/\/AUTO\n        InputT2 = T2_PV;\n        SetpointT2 = T2_SP;\n        PIDT2.Compute();\n        T2_OP = map(OutputT2, 0, 255, 0, 100); \/\/PWM -> %\n        analogWrite(H2pin,OutputT2);\n     }else if (PIDT2.GetMode() == 0) {\/\/MANUAL\n        T2_SP = T2_PV;\n     }\n     \/\/Para Arduino COM Plotter\n     Serial.print(\"#\");        \/\/Char inicio\n     Serial.print(T1_SP,1);    \/\/\n     Serial.write(\" \");        \/\/separador\n     Serial.print(T1_PV,1);    \/\/\n     Serial.write(\" \");        \/\/separador\n     Serial.print(T1_OP);      \/\/\n     Serial.write(\" \");        \/\/separador\n     Serial.print(T2_SP,1);    \/\/\n     Serial.write(\" \");        \/\/separador\n     Serial.print(T2_PV,1);    \/\/\n     Serial.write(\" \");        \/\/separador\n     Serial.print(T2_OP);      \/\/\n     Serial.println();\n    \/\/\n  }\/\/millis\n}\/\/loop\n\/***************************************************************\n* FUNCIONES\n***************************************************************\/\ndouble mapf(double val, double in_min, double in_max, double out_min, double out_max) {\n    return (val - in_min) * (out_max - out_min) \/ (in_max - in_min) + out_min;\n}\nvoid LeoCMD() {\n  while (Serial &amp;&amp; (Serial.available() > 0) &amp;&amp; (newData == false)) {\n    int byte = Serial.read();\n    if ((byte != '\\r') &amp;&amp; (byte != nl) &amp;&amp; (buffer_index &lt; 64)) {\n      Buffer[buffer_index] = byte;\n      buffer_index++;\n    }\n    else {\n      newData = true;\n    }\n  }   \n}\nvoid ProcesoCMD(void) {\n  if (newData) {\n    String read_ = String(Buffer);\n    \/\/ separate command from associated data\n    int idx = read_.indexOf(sp);\n    cmd = read_.substring(0, idx);\n    cmd.trim();\n    cmd.toUpperCase();\n\n    \/\/ extract data. toFloat() returns 0 on error\n    String data = read_.substring(idx + 1);\n    data.trim();\n    val = data.toFloat();\n\n    \/\/ reset parameter for next command\n    memset(Buffer, 0, sizeof(Buffer));\n    buffer_index = 0;\n    newData = false;\n  }\n}\nvoid EjecutoCMD(void) {\n  if (cmd == \"T1A\") {\n    PIDT1.SetMode(AUTOMATIC);\n  }\n  else if (cmd == \"T1M\") {\n    PIDT1.SetMode(MANUAL);\n  }\n  else if (cmd == \"T2A\") {\n    PIDT2.SetMode(AUTOMATIC);\n  }\n  else if (cmd == \"T2M\") {\n    PIDT2.SetMode(MANUAL);\n  }\n  else if (cmd == \"T1SP\") {\n    if (PIDT1.GetMode() == 1){\n      if (val > T1SPMAX){\n        T1_SP = T1SPMAX;\n      }else{\n        T1_SP = val;\n      }\n    }\n  }\n  else if (cmd == \"T1OP\") {\n    if (PIDT1.GetMode() == 0){\n      if (val > T1OPMAX){\n        val = T1OPMAX;\n      }\n      T1_OP = val;\n      val = map(val, 0, 100, 0, 255);\n      analogWrite(H1pin,T1_OP);\n    }\n  }\n  else if (cmd == \"T2SP\") {\n    if (PIDT2.GetMode() == 1){\n      if (val > T2SPMAX){\n        T2_SP = T2SPMAX;\n      }else{\n        T2_SP = val;\n      }\n    }\n  }\n  else if (cmd == \"T2OP\") {\n    if (PIDT2.GetMode() == 0){\n      if (val > T2OPMAX){\n        val = T2OPMAX;\n      }\n      T2_OP = val;\n      val = map(val, 0, 100, 0, 255);\n      analogWrite(H2pin,T2_OP);\n    }\n  }\n  else if (cmd == \"T1KC\") {\n    PIDT1.SetTunings(val,KiT1,KdT1);\n  }\n  else if (cmd == \"T1KI\") {\n    PIDT1.SetTunings(KcT1,val,KdT1);\n  }\n  else if (cmd == \"T1KD\") {\n    PIDT1.SetTunings(KcT1,KiT1,val);\n  }\n  else if (cmd == \"T2KC\") {\n    PIDT2.SetTunings(val,KiT2,KdT2);\n  }\n  else if (cmd == \"T2KI\") {\n    PIDT2.SetTunings(KcT2,val,KdT2);\n  }\n  else if (cmd == \"T2KD\") {\n    PIDT2.SetTunings(KcT2,KiT2,val);\n  }\n  else if (cmd == \"STT2\") {\n    StepTestT2();\n  }\n  else if (cmd == \"STT1\") {\n    StepTestT1();\n  }\n  Serial.flush();\n  cmd = \"\";\n}\nvoid LecturaTTs(void) {\n  \/\/Lectura Temperaturas\n  for (int i = 0; i &lt; n; i++) {   \n    T1_PV += (analogRead(T1pin)* 0.322265625 - 50.0); \/\/ 3.3v AREF\n    T2_PV += (analogRead(T2pin)* 0.322265625 - 50.0); \/\/ 3.3v AREF\n    \/\/T1_PV += (analogRead(T1pin)*4.88 - 500) \/ 10; \/\/5v\n    \/\/T2_PV += (analogRead(T2pin)*4.88 - 500) \/ 10; \/\/5v\n  }\n  T1_PV = T1_PV \/ float(n);\n  T2_PV = T2_PV \/ float(n);\n}\nvoid StepTestT1(void) {\n  PIDT2.SetMode(MANUAL);\n  analogWrite(H2pin,0);\n  PIDT1.SetMode(MANUAL);\n  analogWrite(H1pin,0);\n  while (T1_PV > 30){\n    LecturaTTs(); \n    Serial.print(T1_PV,1);\n    Serial.println();\n    Serial.write(\"Esperando a T1_PV &lt;= 30\u00baC\");\n    Serial.println();\n  }\n  for (int contador = 0; contador &lt; 1850; contador++) {\n      LecturaTTs(); \n      if (contador &lt;=50){\n         analogWrite(H1pin,0);\n         T1_OP = 0;\n      }else if (contador >=50 &amp;&amp; contador &lt;350){     \n          analogWrite(H1pin,63);\n          T1_OP = 63; \/\/25%\n      }else if (contador >=350 &amp;&amp; contador &lt;650){     \n          analogWrite(H1pin,127);\n          T1_OP = 127; \/\/50%\n      }else if (contador >=650 &amp;&amp; contador &lt;950){     \n          analogWrite(H1pin,190);\n          T1_OP = 190; \/\/75%\n      }else if (contador >=950 &amp;&amp; contador &lt;1250){     \n          analogWrite(H1pin,127);\n          T1_OP = 127;\n      }else if (contador >=1250 &amp;&amp; contador &lt;1550){     \n          analogWrite(H1pin,63);\n          T1_OP = 63;\n      }else if (contador >=1550 &amp;&amp; contador &lt;1850){     \n          analogWrite(H1pin,0);\n          T1_OP = 0;\n      }\n      if (1){\n        \/\/Debug serial Arduino COM Plotter\n        Serial.print(\"#\");        \/\/Char inicio\n        Serial.print(T2_PV,1);    \/\/\n        Serial.write(\" \");        \/\/separador\n        Serial.print(T1_PV,1);    \/\/\n        Serial.write(\" \");        \/\/separador\n        Serial.print(T1_OP);      \/\/\n        Serial.println();\n      }\n      delay(1000);\n  }\n}\nvoid StepTestT2(void) {\n  PIDT2.SetMode(MANUAL);\n  analogWrite(H2pin,0);\n  PIDT1.SetMode(MANUAL);\n  analogWrite(H1pin,0);\n  while (T2_PV > 30){\n    LecturaTTs(); \n    Serial.print(T2_PV,1);\n    Serial.println();\n    Serial.write(\"Esperando a T2_PV &lt;= 30\u00baC\");\n    Serial.println();\n  }\n  for (int contador = 0; contador &lt; 1850; contador++) {\n      LecturaTTs(); \n      if (contador &lt;=50){\n         analogWrite(H2pin,0);\n         T2_OP = 0;\n      }else if (contador >=50 &amp;&amp; contador &lt;350){     \n          analogWrite(H2pin,63);\n          T2_OP = 63; \/\/25%\n      }else if (contador >=350 &amp;&amp; contador &lt;650){     \n          analogWrite(H2pin,127);\n          T2_OP = 127; \/\/50%\n      }else if (contador >=650 &amp;&amp; contador &lt;950){     \n          analogWrite(H2pin,190);\n          T2_OP = 190; \/\/75%\n      }else if (contador >=950 &amp;&amp; contador &lt;1250){     \n          analogWrite(H2pin,127);\n          T2_OP = 127;\n      }else if (contador >=1250 &amp;&amp; contador &lt;1550){     \n          analogWrite(H2pin,63);\n          T2_OP = 63;\n      }else if (contador >=1550 &amp;&amp; contador &lt;1850){     \n          analogWrite(H2pin,0);\n          T2_OP = 0;\n      }\n      if (1){\n        \/\/Debug serial Arduino COM Plotter\n        Serial.print(\"#\");        \/\/Char inicio\n        Serial.print(T2_PV,1);    \/\/\n        Serial.write(\" \");        \/\/separador\n        Serial.print(T2_PV,1);    \/\/\n        Serial.write(\" \");        \/\/separador\n        Serial.print(T2_OP);      \/\/\n        Serial.println();\n      }\n      delay(1000);\n  }\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Conclusiones\"><\/span>Conclusiones<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">La placa viene acompa\u00f1ada con un Arduino Leonardo que no he sido capaz de hacer comunicar v\u00eda puerto serie con Arduino COM Plotter. En su lugar he utilizado un Arduino UNO y \u00e9ste comunica sin problema.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Me ha sorprendido la sencillez del concepto de la placa con todas las posibilidades que tiene. Desde el punto de vista del control podemos desarrollar un control ON\/OFF, un PID y un MPC (Control Predictivo basado en Modelo). Dependiendo del control elegido podemos conformarnos con realizar una estimaci\u00f3n, obtener un modelo o plantear las ecuaciones de balance para crear simulaciones, es decir, las posibilidades son amplias.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La implementaci\u00f3n del PID es muy sencilla y creo que la interacci\u00f3n con la placa mediante comandos serial ha sido un acierto. Los resultados hablan por s\u00ed mismos, las sinton\u00edas calculadas coinciden plenamente con la simulaci\u00f3n en lazo cerrado sin necesidad de realizar ning\u00fan ajuste adicional. Los disipadores est\u00e1n muy pegados toc\u00e1ndose ligeramente lo que hace que por conducci\u00f3n suframos perturbaciones entre temperaturas y podamos comprobar el comportamiento de nuestras sinton\u00edas tanto ante perturbaciones como ante cambios de Setpoint.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En definitiva, TCLab es sencillo de implementar, testear y sintonizar. Sin duda es un buen punto de partida para quien quiera iniciarse en el mundo del control de procesos. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Descargas\"><\/span>Descargas<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/garikoitz.info\/blog\/descargas\/TCLab\/\" target=\"_blank\" rel=\"noreferrer noopener\">Carpeta del proyecto<\/a> [<a href=\"https:\/\/github.com\/deurus\/PID_TCLAB\" target=\"_blank\" rel=\"noreferrer noopener\">Github<\/a>]<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Enlaces\"><\/span>Enlaces<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Temperature Control Lab [<a href=\"http:\/\/apmonitor.com\/pdc\/index.php\/Main\/ArduinoTemperatureControl\" target=\"_blank\" rel=\"noreferrer noopener\">APMonitor<\/a>] [<a href=\"https:\/\/github.com\/APMonitor\/arduino\" target=\"_blank\" rel=\"noreferrer noopener\">Github<\/a>]<\/li>\n\n\n\n<li>Comprar Temperature Control Lab [<a href=\"https:\/\/apmonitor.com\/pdc\/index.php\/Main\/PurchaseLabKit\" target=\"_blank\" rel=\"noreferrer noopener\">APMonitor<\/a>]<\/li>\n\n\n\n<li>Teaching Dynamics and Control with Arduino-based TCLab [<a rel=\"noreferrer noopener\" href=\"https:\/\/www.youtube.com\/watch?v=zMBeL4HpFVY\" target=\"_blank\">Youtube<\/a>]<\/li>\n\n\n\n<li>Arduino COM Plotter [<a rel=\"noreferrer noopener\" href=\"https:\/\/garikoitz.info\/blog\/2020\/05\/arduino-com-plotter\" target=\"_blank\">garikoitz.info<\/a>] [<a href=\"https:\/\/github.com\/deurus\/ACP\" target=\"_blank\" rel=\"noreferrer noopener\">Github<\/a>]<\/li>\n\n\n\n<li>PIDLab &#8211; C\u00e1lculo de Sinton\u00edas online [<a rel=\"noreferrer noopener\" href=\"https:\/\/garikoitz.info\/pidlab\/\" target=\"_blank\">garikoitz.info<\/a>]<\/li>\n\n\n\n<li>Librer\u00eda PID by Brett Beauregard&nbsp;[<a href=\"https:\/\/github.com\/br3ttb\/Arduino-PID-Library\" target=\"_blank\" rel=\"noreferrer noopener\">Github<\/a>]<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Libros_y_publicaciones\"><\/span>Libros y publicaciones<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">[1] Karl J. Astrom, Tore Hagglund. Control PID avanzado, Pearson, ISBN: 978-84-8322-511-0<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">[2] Daniel Chuck. Los sistemas de primer orden y los controladores PID, edici\u00f3n 2012. [<a rel=\"noreferrer noopener\" href=\"https:\/\/garikoitz.info\/blog\/descargas\/ControladoresPID.pdf\" target=\"_blank\">Link<\/a>] [<a rel=\"noreferrer noopener\" href=\"http:\/\/dea.unsj.edu.ar\/control2\/ControladoresPID.pdf\" target=\"_blank\">Link2<\/a>]<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">[3] J.G. Ziegler, N.B. Nichols. Optimum Settings For Automatic Controllers, 1942 edition, American Society of Mechanical Engineers. [<a rel=\"noreferrer noopener\" href=\"https:\/\/garikoitz.info\/blog\/descargas\/Z-N.pdf\" target=\"_blank\">Link<\/a>]<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">[4] G.H. Cohen, G.A. Coon. Theoretical Consideration of Retarded Control, 1953 edition, American Society of Mechanical Engineers. [<a rel=\"noreferrer noopener\" href=\"https:\/\/garikoitz.info\/blog\/descargas\/Cohen_Coon.pdf\" target=\"_blank\">Link<\/a>] [<a rel=\"noreferrer noopener\" href=\"http:\/\/folk.ntnu.no\/skoge\/puublications_others\/Cohen%20and%20Coon%20(1953)%20-%20Theoretical%20Consideration%20of%20Retarded%20Control.pdf\" target=\"_blank\">Link2<\/a>]<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">[5] Daniel E. Rivera. Internal Model Control: A Comprehensive View, 1999 edition, College of Engineering and Applied Sciences. [<a rel=\"noreferrer noopener\" href=\"https:\/\/garikoitz.info\/blog\/descargas\/IMC_(Rivera).pdf\" target=\"_blank\">Link<\/a>]<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">[6] R. Vilanova, A. Visioli. PID Control in the Third Millennium. Chapter 5, The SIMC Method for smooth PID Controller Tuning, Springer. ISBN: 978-1-4471-2424-5.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">[7] Chriss Grimholt, Sigurd Skogestad. The improved SIMC method for PI controller tuning, IFAC-conference PID\u201912, Brescia, Italy, March 2012. [<a rel=\"noreferrer noopener\" href=\"http:\/\/npcw17.imm.dtu.dk\/Proceedings\/Session%207%20Control%20Theory\/The%20improved%20SIMC%20method%20for%20PI%20controller%20tuning.pdf\" target=\"_blank\">Link<\/a>]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introducci&oacute;n El Laboratorio de Control de Temperatura (TCLab) es una peque&ntilde;a placa compatible con Arduino creada por John D. Hedengren y la comunidad APMonitor. Esta placa est&aacute; dise&ntilde;ada para fines did&aacute;cticos y despu&eacute;s de probarla os puedo asegurar que es una virguer&iacute;a para los amantes del control. La placa en s&iacute; es muy sencilla, consta de dos sensores de temperatura y dos transistores usados como calentadores, lo realmente interesante es el software que lo acompa&ntilde;a ya que tenemos a nuestra&#8230;<\/p>\n<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/garikoitz.info\/blog\/2023\/01\/sintonizar-pid-con-arduino-laboratorio-de-control-de-temperatura-tclab\/\"> Leer m\u00e1s<span class=\"screen-reader-text\">  Leer m\u00e1s<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":1978,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_crdt_document":"","wpupg_custom_link":[],"wpupg_custom_link_behaviour":[],"wpupg_custom_link_nofollow":[],"wpupg_custom_image":[],"wpupg_custom_image_id":[],"footnotes":""},"categories":[15],"tags":[94,175,16,143,176,17,101,173,174],"class_list":["post-1923","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-arduino","tag-acp","tag-apmonitor","tag-arduino","tag-i-pd","tag-john-hedengren","tag-pid","tag-sintonia-pid","tag-tclab","tag-temperature-control-lab"],"_links":{"self":[{"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/posts\/1923","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/comments?post=1923"}],"version-history":[{"count":42,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/posts\/1923\/revisions"}],"predecessor-version":[{"id":2211,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/posts\/1923\/revisions\/2211"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/media\/1978"}],"wp:attachment":[{"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/media?parent=1923"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/categories?post=1923"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/tags?post=1923"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}