{"id":2890,"date":"2026-09-13T20:42:16","date_gmt":"2026-09-13T20:42:16","guid":{"rendered":"https:\/\/garikoitz.info\/blog\/?p=2890"},"modified":"2026-09-13T20:46:05","modified_gmt":"2026-09-13T20:46:05","slug":"librerias-pid-y-herramientas-de-identificacion-para-arduino","status":"publish","type":"post","link":"https:\/\/garikoitz.info\/blog\/2026\/09\/librerias-pid-y-herramientas-de-identificacion-para-arduino\/","title":{"rendered":"Librer\u00edas PID y herramientas de identificaci\u00f3n para Arduino"},"content":{"rendered":"\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_87_1 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\/2026\/09\/librerias-pid-y-herramientas-de-identificacion-para-arduino\/#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\/2026\/09\/librerias-pid-y-herramientas-de-identificacion-para-arduino\/#%C2%BFQue_debe_ofrecer_una_libreria_PID\" >\u00bfQu\u00e9 debe ofrecer una librer\u00eda PID?<\/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\/2026\/09\/librerias-pid-y-herramientas-de-identificacion-para-arduino\/#Arduino_PID_Library_de_Brett_Beauregard\" >Arduino PID Library de Brett Beauregard<\/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\/2026\/09\/librerias-pid-y-herramientas-de-identificacion-para-arduino\/#QuickPID\" >QuickPID<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/garikoitz.info\/blog\/2026\/09\/librerias-pid-y-herramientas-de-identificacion-para-arduino\/#Controlar_no_es_lo_mismo_que_identificar\" >Controlar no es lo mismo que identificar<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/garikoitz.info\/blog\/2026\/09\/librerias-pid-y-herramientas-de-identificacion-para-arduino\/#Arduino_PID_Autotuner\" >Arduino PID Autotuner<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/garikoitz.info\/blog\/2026\/09\/librerias-pid-y-herramientas-de-identificacion-para-arduino\/#%C2%BFY_la_identificacion_en_lazo_abierto\" >\u00bfY la identificaci\u00f3n en lazo abierto?<\/a><\/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\/2026\/09\/librerias-pid-y-herramientas-de-identificacion-para-arduino\/#Comparativa_practica\" >Comparativa pr\u00e1ctica<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/garikoitz.info\/blog\/2026\/09\/librerias-pid-y-herramientas-de-identificacion-para-arduino\/#Control\" >Control<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/garikoitz.info\/blog\/2026\/09\/librerias-pid-y-herramientas-de-identificacion-para-arduino\/#Identificacion_autotuning\" >Identificaci\u00f3n \/ autotuning<\/a><\/li><\/ul><\/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\/2026\/09\/librerias-pid-y-herramientas-de-identificacion-para-arduino\/#Que_comprobar_antes_de_utilizar_una_libreria\" >Qu\u00e9 comprobar antes de utilizar una librer\u00eda<\/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\/2026\/09\/librerias-pid-y-herramientas-de-identificacion-para-arduino\/#Conclusiones\" >Conclusiones<\/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\/2026\/09\/librerias-pid-y-herramientas-de-identificacion-para-arduino\/#Serie_Introduccion_al_PID_y_su_implementacion_en_Arduino\" >Serie Introducci\u00f3n al PID y su implementaci\u00f3n en Arduino<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/garikoitz.info\/blog\/2026\/09\/librerias-pid-y-herramientas-de-identificacion-para-arduino\/#Lectura_recomendada\" >Lectura recomendada<\/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\">A lo largo de los tres art\u00edculos anteriores he implementado el controlador, identificado el proceso y calculado una sinton\u00eda. Llegados a este punto es razonable preguntarse por qu\u00e9 escribir todo ese c\u00f3digo si existen librer\u00edas PID para Arduino. La respuesta es sencilla. Una librer\u00eda puede ahorrarme trabajo, pero no elimina la necesidad de entender qu\u00e9 ecuaci\u00f3n ejecuta, c\u00f3mo interpreta sus par\u00e1metros, c\u00f3mo trata la saturaci\u00f3n o qu\u00e9 prueba realiza cuando ofrece autotuning.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En este \u00faltimo art\u00edculo no voy a buscar una librer\u00eda que me permita olvidarme del PID. Har\u00e9 justo lo contrario y utilizar\u00e9 lo aprendido para saber qu\u00e9 debo comprobar antes de confiar en una implementaci\u00f3n ajena. Tambi\u00e9n separar\u00e9 claramente dos funciones diferentes, controlar el proceso e identificarlo o sintonizarlo autom\u00e1ticamente.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%C2%BFQue_debe_ofrecer_una_libreria_PID\"><\/span>\u00bfQu\u00e9 debe ofrecer una librer\u00eda PID?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">La llamada m\u00e1s visible de una librer\u00eda suele ser Compute(), update() o una funci\u00f3n equivalente, pero para comparar implementaciones necesito mirar bastante m\u00e1s. En el primer art\u00edculo mi ejemplo termin\u00f3 incorporando una estructura seleccionable PID\/PI-D\/I-PD, tiempo de muestreo conocido, l\u00edmites de OP, integraci\u00f3n condicional como anti-windup, acci\u00f3n de control, modo manual\/autom\u00e1tico, inicializaci\u00f3n para reducir los saltos en la transferencia y PV Tracking. Esa implementaci\u00f3n me sirve ahora como lista de requisitos con la que comparar las librer\u00edas.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><td><strong>Aspecto<\/strong><\/td><td><strong>Qu\u00e9 debemos comprobar<\/strong><\/td><\/tr><\/thead><tbody><tr><td>Par\u00e1metros<\/td><td>\u00bfEspera Kc\/Ki\/Kd o Kc\/Ti\/Td? \u00bfC\u00f3mo escala Ki y Kd con Ts?<\/td><\/tr><tr><td>Estructura<\/td><td>\u00bfPID cl\u00e1sico, PI-D, I-PD o ponderaci\u00f3n configurable de P y D?<\/td><\/tr><tr><td>Muestreo<\/td><td>\u00bfUsa un Ts interno fijo, millis(), temporizador o tiempo real entre muestras?<\/td><\/tr><tr><td>Saturaci\u00f3n<\/td><td>\u00bfPermite configurar l\u00edmites f\u00edsicos de OP?<\/td><\/tr><tr><td>Anti-windup<\/td><td>\u00bfClamping, integraci\u00f3n condicional, back-calculation u otra estrategia?<\/td><\/tr><tr><td>Acci\u00f3n \/ direcci\u00f3n<\/td><td>\u00bfQu\u00e9 significan DIRECT y REVERSE exactamente en esa API?<\/td><\/tr><tr><td>Modos<\/td><td>\u00bfGestiona manual y autom\u00e1tico?<\/td><\/tr><tr><td>Bumpless transfer<\/td><td>\u00bfInicializa sus estados internos para evitar un salto de OP?<\/td><\/tr><tr><td>PV Tracking<\/td><td>\u00bfPuede hacer que SP siga a PV en manual o debemos implementarlo fuera?<\/td><\/tr><tr><td>Diagn\u00f3stico<\/td><td>\u00bfPodemos consultar P, I y D por separado y conocer la configuraci\u00f3n activa?<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Una librer\u00eda que no documenta estos puntos puede servir para una demostraci\u00f3n sencilla, pero me dificulta trasladar una sinton\u00eda obtenida con otro m\u00e9todo o diagnosticar por qu\u00e9 el lazo no se comporta como esperaba. Adem\u00e1s, no doy por hecho que nombres como Kc, Ki o Kd representen exactamente la misma parametrizaci\u00f3n que he utilizado en la serie, compruebo siempre c\u00f3mo los define cada librer\u00eda.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Arduino_PID_Library_de_Brett_Beauregard\"><\/span>Arduino PID Library de Brett Beauregard<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">La Arduino PID Library de Brett Beauregard es la referencia cl\u00e1sica dentro del ecosistema Arduino. Su fichero <code>library.properties<\/code> declara actualmente la versi\u00f3n 1.2.1. La librer\u00eda permite configurar las ganancias, los l\u00edmites de salida, el tiempo de muestreo y la acci\u00f3n del controlador. Desde la versi\u00f3n 1.2 tambi\u00e9n permite elegir entre <em>Proportional on Error<\/em> y <em>Proportional on Measurement<\/em>. En su API la ganancia proporcional del controlador se denomina Kp, aunque en esta serie seguir\u00e9 llam\u00e1ndola Kc para no confundirla con Kp, que he utilizado para representar la ganancia del proceso.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Aqu\u00ed aparece una relaci\u00f3n directa con las estructuras que estudi\u00e9 en el primer art\u00edculo. PID_v1 calcula siempre la acci\u00f3n derivativa sobre la medida. Cuando selecciono <code>P_ON_E<\/code>, las acciones P e I trabajan sobre el error mientras D act\u00faa sobre PV. Con la nomenclatura utilizada en esta serie, esto corresponde a una estructura PI-D. Si selecciono <code>P_ON_M<\/code>, la acci\u00f3n proporcional tambi\u00e9n pasa a trabajar sobre la medida mientras I contin\u00faa actuando sobre el error. Desde el punto de vista de las estructuras que hemos estudiado, el comportamiento corresponde entonces a una estructura I-PD.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Me parece importante se\u00f1alar esta diferencia porque <em>Proportional on Measurement<\/em> no significa PI-D. En realidad ocurre justo lo contrario, ya que esta opci\u00f3n desplaza la acci\u00f3n proporcional desde el error hacia la medida. La estructura PI-D es la que obtenemos con <code>P_ON_E<\/code>, puesto que la librer\u00eda ya calcula por defecto la acci\u00f3n derivativa sobre PV.<\/p>\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=\"\">\/\/P_ON_E  + D sobre PV  ->  PI-D\n\/\/P_ON_M  + D sobre PV  ->  I-PD\n#include &lt;PID_v1.h>\n\ndouble SP, PV, OP;\ndouble Kc = 2.0, Ki = 0.2, Kd = 0.0;\n\n\/\/ Para nuestro proceso de calentamiento: PI-D y proceso PV(+) OP(-)\nPID pid(&amp;PV, &amp;OP, &amp;SP, Kc, Ki, Kd, P_ON_E, REVERSE);\n\nvoid setup() {\n    pid.SetOutputLimits(0, 255);\n    pid.SetSampleTime(100);\n    pid.SetMode(AUTOMATIC);\n}\n\nvoid loop() {\n    PV = leerProceso();\n    pid.Compute();\n    aplicarSalida(OP);\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">En cuanto a los cambios entre manual y autom\u00e1tico, PID_v1 incorpora un mecanismo b\u00e1sico de inicializaci\u00f3n destinado a reducir los saltos durante la transferencia. Al pasar a autom\u00e1tico, la librer\u00eda inicializa su suma interna con el valor actual de OP y almacena la medida actual como referencia para el t\u00e9rmino derivativo. Tambi\u00e9n limita esa suma interna a los l\u00edmites configurados para la salida, proporcionando una protecci\u00f3n b\u00e1sica frente al windup.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sin embargo, en mis implementaciones he comprobado que esta inicializaci\u00f3n no garantiza por s\u00ed sola una transferencia completamente sin salto. Con la configuraci\u00f3n habitual, en la que la acci\u00f3n proporcional trabaja sobre el error, en el primer c\u00e1lculo autom\u00e1tico se a\u00f1ade a la salida inicializada el t\u00e9rmino proporcional <math xmlns=\"http:\/\/www.w3.org\/1998\/Math\/MathML\"><semantics><mrow><msub><mi>K<\/mi><mi>c<\/mi><\/msub><mo stretchy=\"false\">(<\/mo><mi>S<\/mi><mi>P<\/mi><mo>\u2212<\/mo><mi>P<\/mi><mi>V<\/mi><mo stretchy=\"false\">)<\/mo><\/mrow><annotation encoding=\"application\/x-tex\">K_c(SP-PV)<\/annotation><\/semantics><\/math>. Si existe una diferencia apreciable entre SP y PV en ese momento, puede producirse un cambio brusco de OP.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Por este motivo, en mis implementaciones sigo realizando expl\u00edcitamente la inicializaci\u00f3n antes de pasar a autom\u00e1tico. Mientras el controlador est\u00e1 en manual aplico PV Tracking, haciendo <math xmlns=\"http:\/\/www.w3.org\/1998\/Math\/MathML\"><semantics><mrow><mi>S<\/mi><mi>P<\/mi><mo>=<\/mo><mi>P<\/mi><mi>V<\/mi><\/mrow><annotation encoding=\"application\/x-tex\">SP=PV<\/annotation><\/semantics><\/math>, y mantengo la variable de salida del PID igualada a la OP que realmente estoy aplicando al proceso. De esta forma, cuando paso a autom\u00e1tico, el controlador parte tanto de un error inicial nulo como de la salida real que estaba utilizando en manual, reduciendo considerablemente la posibilidad de que aparezca un salto.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">PID_v1 gestiona, por tanto, los modos manual y autom\u00e1tico y proporciona una inicializaci\u00f3n interna \u00fatil, pero no incorpora PV Tracking ni una l\u00f3gica de inicializaci\u00f3n tan completa como la que utilizo habitualmente en mis implementaciones. Tampoco permite consultar por separado las contribuciones instant\u00e1neas P, I y D, aunque s\u00ed permite consultar los valores configurados de Kc, Ki y Kd.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"QuickPID\"><\/span>QuickPID<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">QuickPID parte de la Arduino PID Library y ampl\u00eda considerablemente sus posibilidades. En la versi\u00f3n principal mantenida actualmente por Dlloydev puedo seleccionar la proporcional sobre error, medida o una combinaci\u00f3n 50\/50, elegir la derivada sobre error o medida, seleccionar distintos modos de anti-windup, utilizar modo TIMER y consultar individualmente los t\u00e9rminos P, I y D. Tambi\u00e9n dispone de modos manual y autom\u00e1tico y de un mecanismo interno de inicializaci\u00f3n al cambiar de modo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Con pOnError y dOnError obtengo el PID cl\u00e1sico. Con pOnError y dOnMeas obtengo PI-D. Con pOnMeas y dOnMeas obtengo I-PD. La opci\u00f3n pOnErrorMeas reparte la acci\u00f3n proporcional entre error y medida y representa una estructura intermedia. De esta forma puedo seleccionar expl\u00edcitamente d\u00f3nde act\u00faan P y D sin reescribir el algoritmo.<\/p>\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=\"\">QuickPID pid(&amp;PV, &amp;OP, &amp;SP);\n\npid.SetTunings(Kc, Ki, Kd);\npid.SetProportionalMode(QuickPID::pMode::pOnError);\npid.SetDerivativeMode(QuickPID::dMode::dOnMeas);   \/\/ PI-D\npid.SetAntiWindupMode(QuickPID::iAwMode::iAwCondition);\npid.SetControllerDirection(QuickPID::Action::reverse);\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">QuickPID no incorpora PV Tracking como funci\u00f3n espec\u00edfica, por lo que en mis implementaciones mantendr\u00eda fuera de la librer\u00eda la misma estrategia que he utilizado hasta ahora para inicializar el paso de manual a autom\u00e1tico. En cuanto al autotuning, su documentaci\u00f3n remite a sTune, una librer\u00eda independiente que comentar\u00e9 al hablar de identificaci\u00f3n en lazo abierto.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Controlar_no_es_lo_mismo_que_identificar\"><\/span>Controlar no es lo mismo que identificar<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Me parece importante separar dos tipos de librer\u00edas. Una librer\u00eda PID ejecuta el controlador durante el funcionamiento normal. Una librer\u00eda de autotuning sustituye temporalmente ese control o modifica deliberadamente la actuaci\u00f3n para obtener informaci\u00f3n del proceso. Cuando termina la prueba devuelve par\u00e1metros que despu\u00e9s puedo utilizar en el controlador.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Esta distinci\u00f3n me parece especialmente importante por seguridad. Durante el autotuning la salida puede oscilar deliberadamente y PV se apartar\u00e1 de su valor estacionario. Antes de activar cualquier autotuner necesito conocer qu\u00e9 ensayo realiza y comprobar que el proceso puede soportarlo.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Arduino_PID_Autotuner\"><\/span>Arduino PID Autotuner<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Arduino-pid-autotuner<\/strong>, de <strong>jackw01<\/strong>, implementa un autotuning basado en el m\u00e9todo de rel\u00e9 y reglas de Ziegler-Nichols. La propia documentaci\u00f3n indica que debe ejecutarse con el mismo intervalo que utilizar\u00e1 posteriormente el lazo PID, permite configurar el rango de salida y ofrece tres variantes de ajuste, Basic PID, Less Overshoot y No Overshoot. Es, por tanto, un ejemplo claro de identificaci\u00f3n en lazo cerrado mediante oscilaci\u00f3n inducida.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durante la prueba la librer\u00eda sustituye temporalmente al controlador y genera la actuaci\u00f3n necesaria para inducir la oscilaci\u00f3n. Al terminar devuelve Kc, Ki y Kd para transferirlos al controlador que vaya a utilizar. Esto enlaza directamente con el m\u00e9todo de rel\u00e9 de \u00c5str\u00f6m-H\u00e4gglund que expliqu\u00e9 en el segundo art\u00edculo, el autotuner automatiza el ensayo y el c\u00e1lculo de la sinton\u00eda, pero no cambia el principio f\u00edsico del procedimiento ni elimina la necesidad de que compruebe que la oscilaci\u00f3n es segura.<\/p>\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=\"\">PIDAutotuner tuner;\n\ntuner.setTargetInputValue(SP);\ntuner.setLoopInterval(loopInterval);\ntuner.setOutputRange(0, 255);\ntuner.startTuningLoop(micros());\n\n\/\/ Durante el ensayo:\nOP = tuner.tunePID(PV, micros());\n\n\/\/ Al finalizar:\ndouble Kc = tuner.getKp();\ndouble Ki = tuner.getKi();\ndouble Kd = tuner.getKd();\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Presto especial atenci\u00f3n a la nomenclatura. Esta API llama Kp a la ganancia proporcional del controlador. En esta serie he reservado Kp para la ganancia del proceso y Kc para la ganancia del controlador. Por tanto, tuner.getKp() debe interpretarse conceptualmente como el Kc que he utilizado hasta ahora. La librer\u00eda devuelve directamente las ganancias del controlador, no confundir ese resultado con haber obtenido un modelo FOPDT Kp, T0 y Tp del proceso.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"%C2%BFY_la_identificacion_en_lazo_abierto\"><\/span>\u00bfY la identificaci\u00f3n en lazo abierto?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">La identificaci\u00f3n en lazo abierto del segundo art\u00edculo tambi\u00e9n se puede automatizar. Una opci\u00f3n especialmente coherente con el recorrido de esta serie es sTune, de Dlloydev. La librer\u00eda coloca el PID en manual, aplica un escal\u00f3n de salida y analiza la curva de reacci\u00f3n. Su modo de punto de inflexi\u00f3n puede terminar la prueba antes de alcanzar completamente el nuevo estado estacionario y dispone tambi\u00e9n de un ensayo m\u00e1s largo. Entre los resultados accesibles est\u00e1n la ganancia del proceso, el tiempo muerto y la constante de tiempo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Con la nomenclatura utilizada en esta serie, esos tres resultados corresponden conceptualmente a Kp, T<sub>0<\/sub> y Tp. Esto enlaza de forma directa con los art\u00edculos 2 y 3 en que a partir de la respuesta escal\u00f3n obtengo un modelo aproximado del proceso y despu\u00e9s puedo aplicar reglas como Ziegler-Nichols en lazo abierto o Cohen-Coon. sTune ofrece varias reglas de sinton\u00eda y devuelve tambi\u00e9n par\u00e1metros del controlador. Aun as\u00ed, sigue siendo un ensayo en lazo abierto donde antes de utilizarlo necesito poder fijar la OP manualmente y dejar evolucionar la PV dentro de l\u00edmites seguros.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Comparativa_practica\"><\/span>Comparativa pr\u00e1ctica<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Control\"><\/span>Control<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><td><strong>Aspecto<\/strong><\/td><td>Mi implementaci\u00f3n (art. 1)<\/td><td><strong>PID_v1<\/strong><\/td><td><strong>QuickPID<\/strong><\/td><\/tr><\/thead><tbody><tr><td>Par\u00e1metros \/ ecuaci\u00f3n<\/td><td>Kc, Ki, Kd; Ki = Kc\/Ti; Kd = Kc\u00b7Td<\/td><td>API: Kp = Kc de esta serie; Ki y Kd se escalan internamente con Ts<\/td><td>API: Kp = Kc de esta serie; Ki y Kd se escalan internamente con Ts<\/td><\/tr><tr><td>Estructura<\/td><td>PID \/ PI-D \/ I-PD<\/td><td>P_ON_E = PI-D; P_ON_M = I-PD<\/td><td>PID cl\u00e1sico \/ PI-D \/ I-PD + P 50\/50<\/td><\/tr><tr><td>D sobre medida<\/td><td>Seleccionable<\/td><td>S\u00ed, siempre<\/td><td>Seleccionable<\/td><\/tr><tr><td>Ts<\/td><td>Configurable; c\u00e1lculo con tiempo transcurrido<\/td><td>SetSampleTime()<\/td><td>SetSampleTimeUs() \/ TIMER<\/td><\/tr><tr><td>L\u00edmites OP<\/td><td>S\u00ed<\/td><td>S\u00ed<\/td><td>S\u00ed<\/td><\/tr><tr><td>Anti-windup<\/td><td>Integraci\u00f3n condicional<\/td><td>Clamping de la suma interna<\/td><td>Condicional, clamping u off<\/td><\/tr><tr><td>Acci\u00f3n<\/td><td>Seleccionable: directa \/ inversa<\/td><td>DIRECT \/ REVERSE<\/td><td>direct \/ reverse<\/td><\/tr><tr><td>Manual \/ autom\u00e1tico<\/td><td>S\u00ed<\/td><td>S\u00ed<\/td><td>S\u00ed + TIMER<\/td><\/tr><tr><td>Inicializaci\u00f3n MAN\u2192AUTO<\/td><td>Expl\u00edcita: PV Tracking + OP manual sincronizada<\/td><td>B\u00e1sica: inicializa suma interna y medida anterior<\/td><td>Inicializaci\u00f3n interna; la complemento si necesito PV Tracking<\/td><\/tr><tr><td>PV Tracking<\/td><td>S\u00ed, lo implemento en manual<\/td><td>No; lo implemento externamente<\/td><td>No espec\u00edfico; lo implemento externamente<\/td><\/tr><tr><td>P, I y D separados<\/td><td>S\u00ed internamente<\/td><td>No<\/td><td>S\u00ed:<br>GetPterm()<br>GetIterm()<br>GetDterm()<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Identificacion_autotuning\"><\/span><strong>Identificaci\u00f3n \/ autotuning<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><td><strong>Aspecto<\/strong><\/td><td>Mi ensayo<\/td><td><strong>arduino-pid-autotuner<\/strong><\/td><td><strong>sTune<\/strong><\/td><\/tr><\/thead><tbody><tr><td>Tipo de ensayo<\/td><td>Escal\u00f3n en lazo abierto<\/td><td>Rel\u00e9 \/ oscilaci\u00f3n en lazo cerrado<\/td><td>Escal\u00f3n en lazo abierto<\/td><\/tr><tr><td>Qu\u00e9 obtenemos<\/td><td>Kp, T0, Tp<\/td><td>Ganancias Kp, Ki, Kd de su API<\/td><td>Ganancia de proceso, tiempo muerto, Tau + sinton\u00eda<\/td><\/tr><tr><td>Equivalencia<\/td><td>Kp, T0, Tp<\/td><td>Kp devuelto = Kc de esta serie<\/td><td>Process gain = Kp; dead time = T0; Tau = Tp<\/td><\/tr><tr><td>Reglas<\/td><td>Las calculamos despu\u00e9s<\/td><td>Variantes Ziegler-Nichols<\/td><td>ZN, Cohen-Coon y otras<\/td><\/tr><tr><td>Modelo del proceso<\/td><td>S\u00ed, FOPDT aproximado<\/td><td>No directamente<\/td><td>S\u00ed, par\u00e1metros equivalentes al FOPDT<\/td><\/tr><tr><td>Condici\u00f3n<\/td><td>Manual seguro<\/td><td>Oscilaciones seguras<\/td><td>Manual seguro<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">He separado las tablas de control e identificaci\u00f3n. Utilizo el c\u00f3digo que desarroll\u00e9 en el art\u00edculo 1 como referencia porque s\u00e9 exactamente qu\u00e9 ecuaci\u00f3n ejecuta y qu\u00e9 funciones he implementado. PID_v1 me obliga a traducir P_ON_E\/P_ON_M a las estructuras que ya he explicado, mientras que QuickPID a\u00f1ade m\u00e1s flexibilidad de estructura y diagn\u00f3stico. Para identificar, arduino-pid-autotuner automatiza el ensayo de rel\u00e9 en lazo cerrado y sTune automatiza el escal\u00f3n en lazo abierto que conduce a Kp, T<sub>0<\/sub> y Tp.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Que_comprobar_antes_de_utilizar_una_libreria\"><\/span>Qu\u00e9 comprobar antes de utilizar una librer\u00eda<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Antes de integrar una librer\u00eda traduzco primero su nomenclatura a la utilizada en esta serie. Qu\u00e9 llama Kp, c\u00f3mo selecciona la acci\u00f3n del controlador y sobre qu\u00e9 se\u00f1al calcula P y D. Despu\u00e9s compruebo parametrizaci\u00f3n, Ts, l\u00edmites de OP y anti-windup, y pruebo manual\/autom\u00e1tico, la inicializaci\u00f3n al cambiar de modo y, si lo necesito, PV Tracking. Solo entonces traslado una sinton\u00eda o ejecuto una herramienta de identificaci\u00f3n.<\/p>\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\">Cuando encontramos por internet implementaciones de control PID en Arduino, a menudo aparecen en un contexto acad\u00e9mico o como maquetas caseras destinadas a realizar una prueba de concepto. Normalmente no son sistemas dise\u00f1ados para trabajar 24 horas al d\u00eda y 7 d\u00edas a la semana, por lo que en esas situaciones podemos permitirnos ciertas simplificaciones. Puede que no nos preocupe demasiado que el controlador no se inicialice correctamente o que, ante un cambio en el punto de consigna, la OP oscile bruscamente entre el 0 y el 100 % durante unos segundos.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sin embargo, Arduino permite desarrollar sistemas de control mucho m\u00e1s complejos y existen incluso soluciones orientadas al entorno industrial, como los <a href=\"https:\/\/www.arduino.cc\/pro\/hardware-arduino-opta\/\" target=\"_blank\" rel=\"noopener\">Arduino Opta<\/a>. Cuando pasamos de una maqueta de laboratorio a un sistema que debe funcionar de forma continua y fiable, una implementaci\u00f3n correcta deja de ser algo deseable y pasa a ser una necesidad. Aspectos como la inicializaci\u00f3n, la transferencia entre manual y autom\u00e1tico, el tratamiento de la saturaci\u00f3n, el anti-windup o la forma en que se aplican los cambios de consigna pueden marcar una diferencia importante en el comportamiento real del proceso.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Una librer\u00eda me permite escribir menos c\u00f3digo, pero entender el PID me permite saber si realmente hace lo que necesito. Despu\u00e9s de esta serie ya no me interesa preguntar \u00fanicamente \u00ab\u00bfqu\u00e9 valores pongo en Kc, Ki y Kd?\u00bb. Me interesa tambi\u00e9n saber qu\u00e9 significa cada par\u00e1metro, qu\u00e9 estructura utiliza la librer\u00eda, sobre qu\u00e9 se\u00f1ales act\u00faan la parte Proporcional y la Derivativa, c\u00f3mo gestiona la saturaci\u00f3n, qu\u00e9 ocurre al cambiar entre manual y autom\u00e1tico y de d\u00f3nde proceden realmente los par\u00e1metros que devuelve un autotuner.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ese es, para m\u00ed, el principal valor de haber implementado primero el controlador, haber identificado despu\u00e9s el proceso y haber calculado finalmente la sinton\u00eda antes de delegar esas funciones en una librer\u00eda. Una vez entendido todo lo anterior, utilizar una librer\u00eda deja de ser una forma de evitar conocer c\u00f3mo funciona el PID y pasa a ser simplemente una forma m\u00e1s c\u00f3moda de implementar aquello que ya sabemos que necesitamos.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Serie_Introduccion_al_PID_y_su_implementacion_en_Arduino\"><\/span>Serie Introducci\u00f3n al PID y su implementaci\u00f3n en Arduino<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\/2026\/09\/introduccion-al-pid-y-su-implementacion-en-arduino\/#Serie_Introduccion_al_PID_y_su_implementacion_en_Arduino\">Art\u00edculo 1: Entender e implementar antes de sintonizar<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/garikoitz.info\/blog\/2026\/09\/identificacion-de-procesos-para-la-sintonia-de-un-pid\/\">Art\u00edculo 2: Identificaci\u00f3n de procesos para la sinton\u00eda de un PID<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/garikoitz.info\/blog\/2026\/09\/metodos-de-sintonia-pid-a-partir-de-la-identificacion-del-proceso\/\">Art\u00edculo 3: M\u00e9todos de sinton\u00eda PID a partir de la identificaci\u00f3n del proceso<\/a><\/li>\n\n\n\n<li>Art\u00edculo 4: Librer\u00edas PID y herramientas de identificaci\u00f3n para Arduino<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Lectura_recomendada\"><\/span>Lectura recomendada<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">[1] Tore H\u00e4gglund. <em>Process Control in Practice<\/em>. De Gruyter, 2023. eBook ISBN: 978-3-11-110495-9.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">[2] Karl J. \u00c5str\u00f6m, Tore H\u00e4gglund. <em>Control PID avanzado<\/em>. Pearson Educaci\u00f3n, 2009. ISBN: 978-84-8322-511-0.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">[3] Daniel Chuk. <em>Los sistemas de primer orden y los controladores PID<\/em>. 2012. [<a href=\"https:\/\/garikoitz.info\/blog\/descargas\/ControladoresPID.pdf\">Link<\/a>] [<a href=\"http:\/\/dea.unsj.edu.ar\/control2\/ControladoresPID.pdf\">Link2<\/a>]<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">[4] Fernando Morilla Garc\u00eda. <em>\u00bfQu\u00e9 quieres controlar? \u00bfHas probado con controladores PID?<\/em> Dpto. de Inform\u00e1tica y Autom\u00e1tica, UNED, 2015. [<a href=\"https:\/\/www.dia.uned.es\/~fmorilla\/MaterialDidactico\/P2015_Conferencia_PID_FMorilla_19Mayo2015.pdf\">Link<\/a>]<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">[5] Brett Beauregard. <em>Arduino PID Library (PID_v1)<\/em>. Biblioteca PID para Arduino, versi\u00f3n 1.2.1. [<a href=\"https:\/\/github.com\/br3ttb\/Arduino-PID-Library\">GitHub<\/a>]<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">[6] Dlloydev. <em>QuickPID<\/em>. Implementaci\u00f3n PID para Arduino basada en Arduino PID Library, con opciones configurables para las acciones proporcional y derivativa, anti-windup y diagn\u00f3stico de los t\u00e9rminos P, I y D. [<a href=\"https:\/\/github.com\/Dlloydev\/QuickPID\">GitHub<\/a>]<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">[7] Dlloydev. <em>sTune<\/em>. Librer\u00eda de autotuning para Arduino basada en identificaci\u00f3n en lazo abierto mediante respuesta al escal\u00f3n y an\u00e1lisis del punto de inflexi\u00f3n. [<a href=\"https:\/\/github.com\/Dlloydev\/sTune\">GitHub<\/a>]<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">[8] Jack W. <em>arduino-pid-autotuner<\/em>. Librer\u00eda de autotuning PID basada en el m\u00e9todo de rel\u00e9 y reglas de Ziegler-Nichols. [<a href=\"https:\/\/github.com\/jackw01\/arduino-pid-autotuner\">GitHub<\/a>]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introducci&oacute;n A lo largo de los tres art&iacute;culos anteriores he implementado el controlador, identificado el proceso y calculado una sinton&iacute;a. Llegados a este punto es razonable preguntarse por qu&eacute; escribir todo ese c&oacute;digo si existen librer&iacute;as PID para Arduino. La respuesta es sencilla. Una librer&iacute;a puede ahorrarme trabajo, pero no elimina la necesidad de entender qu&eacute; ecuaci&oacute;n ejecuta, c&oacute;mo interpreta sus par&aacute;metros, c&oacute;mo trata la saturaci&oacute;n o qu&eacute; prueba realiza cuando ofrece autotuning. En este &uacute;ltimo art&iacute;culo no voy a&#8230;<\/p>\n<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/garikoitz.info\/blog\/2026\/09\/librerias-pid-y-herramientas-de-identificacion-para-arduino\/\"> Leer m\u00e1s<span class=\"screen-reader-text\">  Leer m\u00e1s<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":2920,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"wpupg_custom_link":[],"wpupg_custom_link_behaviour":[],"wpupg_custom_link_nofollow":[],"wpupg_custom_image":[],"wpupg_custom_image_id":[],"footnotes":""},"categories":[15,213],"tags":[16,274,143,96,120,142,17,101],"class_list":["post-2890","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-arduino","category-pid","tag-arduino","tag-ensayo-escalon","tag-i-pd","tag-identificacion-de-procesos","tag-metodo-del-rele","tag-pi-d","tag-pid","tag-sintonia-pid"],"_links":{"self":[{"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/posts\/2890","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=2890"}],"version-history":[{"count":19,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/posts\/2890\/revisions"}],"predecessor-version":[{"id":2938,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/posts\/2890\/revisions\/2938"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/media\/2920"}],"wp:attachment":[{"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/media?parent=2890"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/categories?post=2890"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/tags?post=2890"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}