← Back to list

Implementación del control PID de balancín

En el presente reporte se detalla la implementación del control Proporcional- Integral-Derivativo (PID) en el escenario de un balancín. El…

Eder Larios · 2023-10-14 17:43 · 3 claps · 5.0 min read
#control-automático #balancín #pid-controller #esp32 #programming
Open on Medium ↗
Wiki topics: 💻 · Programming

Implementación del control PID de balancín

En el presente reporte se detalla la implementación del control Proporcional- Integral-Derivativo (PID) en el escenario de un balancín. El control PID es una técnica ampliamente utilizada en el ámbito de la automatización y el control de procesos, debido a su versatilidad y eficacia para mantener y regular variables importantes en diversos sistemas. En la primera parte de este reporte, se describe el desarrollo que se llevo a cabo para el desarrollo del balancín. El control PID (proporcional, integral y derivativo) es un mecanismo de control que a través de un lazo de retroalimentación permite regular la velocidad, temperatura, presión y flujo entre otras variables de un proceso en general. El controlador PID calcula la diferencia entre nuestra variable real contra la variable deseada (Setpoint), pero lo hace teniendo en cuenta los tres parámetros antes mencionados de tal manera que el proporcional depende del error actual, el integral depende de los errores pasados y el derivativo es una predicción de los errores futuros. Esto nos proporciona un ajuste muy fino y estable del valor que queremos (Setpoint).

Implementación de control PID para un balancín

Los componentes a utilizar son los siguientes: • Módulo Esp32 Wrover

Módulo Esp32 Wrover

Módulo Esp32 Wrover

• Kit motores brushless

Kit motor brushless

Kit motor brushless

• Mpu6050

Mpu6050

Mpu6050

• Fuente de alimentación

Fuente de alimentación

Fuente de alimentación

Diseño de balancín

Para desarrollar el diseño del prototipo se uso el software de Solidworks.

Vista frontal

Vista frontal

Vista lateral

Vista lateral

Posteriormente todas las piezas se pasaron al formato DXF para poder man-dar a cortar en la máquina de corte láser.

Recorte de piezas en láser

Recorte de piezas en láser

Piezas terminadas

Piezas terminadas

Después de tener todas las piezas recortadas se armo el balancín y se le coloco los motores.

Pegado de balancín

Pegado de balancín

Colocación de los motores en el Balancín

Colocación de los motores en el Balancín

Para que el balancín pudiera moverse de un lado a otro, se le colocaron rodamientos.

Colocación de rodamientos

Colocación de rodamientos

Código de Control PID

El código para el control PID es el siguiente:

#include <ESP32Servo.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>

Adafruit_MPU6050 mpu;

//Promedio de los grados 
const int numReadings = 10;
int readings[numReadings];      // the readings from the analog input
int readIndex = 0;              // the index of the current reading
int total = 0;                  // the running total
int average = 0;

Servo servo1;
Servo servo2;
int vel1 = 1000; 
int vel2 = 1000; 
double throttle1 = 1150; 
double throttle2 = 1150; 

//Variables de tiempo
float tiempo = 0;
unsigned long currentTime = 0;
unsigned long elapsedTime = 0;
unsigned long prevTime = 0;
const unsigned long samplePeriod = 10000;  // Período de muestreo en microsegundos (10000 = 10milisegundos)

//Variables para el control
float setPoint = 0;
float ek = 0, ek1 = 0;
float ek_1 = 0;
float deltaT = 0.01;

float derivada = 0;
float integral = 0;
float uk = 0;
//10,0.5,0          8,0.957,0.078
float kp = 2;
float ki = 2;//2.85;
float kd = 0;

void setup() {

  Serial.begin(115200);
  setCpuFrequencyMhz(240);

  //MOTOR 1
  servo1.attach(2); 
  servo1.writeMicroseconds(1000);
  //MOTOR 2
  servo2.attach(4); 
  servo2.writeMicroseconds(1000); 
  delay(5000); // Esperar 5 segundos para hacer la activacion


  while (!Serial)
    delay(10);
  // Try to initialize!
  if (!mpu.begin()) {
    while (1) {
      delay(10);
    }
  }

  //Promedio
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }

  prevTime = micros();
}

void loop() {

  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);


  currentTime = micros();
  elapsedTime = currentTime - prevTime;

  // Si ha pasado el período de muestreo
  if (elapsedTime >= samplePeriod) {

  // Verificar si hay datos disponibles en el puerto serial
  if (Serial.available()) {
    String input = Serial.readStringUntil('\n');
    sscanf(input.c_str(), "%f,%f,%f", &kp, &ki, &kd);

    Serial.print("Valores recibidos - Kp: ");
    Serial.print(kp);
    Serial.print(", Ki: ");
    Serial.print(ki);
    Serial.print(", Kd: ");
    Serial.println(kd);
  }


    //Roll es el angulo respecto al suelo. Debé usarse este angulo
    float roll = atan2(a.acceleration.y, a.acceleration.z) * 180.0 / PI;
    //float pitch = atan2(-a.acceleration.x, sqrt(a.acceleration.y * a.acceleration.y + a.acceleration.z * a.acceleration.z)) * 180.0 / PI;

    //Promedio
    total = total - readings[readIndex];
    readings[readIndex] = (roll * -1);
    total = total + readings[readIndex];
    readIndex = readIndex + 1;

    // if we're at the end of the array...
    if (readIndex >= numReadings) {
      readIndex = 0;
    }
    average = total / numReadings;

    Serial.print("Setpoint: ");
    Serial.print(setPoint);
    Serial.print(", angulo: ");
    Serial.println(average);

    //Control PID
    //Error
    ek = setPoint - average;

    //Calculo de la derivada del error
    derivada = (ek - ek1) / deltaT;

    //Calculo de la integral del error
    integral += ((ek + ek1) / 2) * deltaT;
    integral = constrain(integral, -100, 100);  // Saturar la integral entre -100 y 100
    ek1 = ek;

    //Calculo del PID
    uk = kp * ek + ki * integral + kd * derivada;

    //Donde colocará la mayor velocidad
    if (0 < uk) {
      //Salida del PWM del motor
      uk = abs(uk);
      uk = constrain(uk, 0, 100);  // Saturar la uk entre 0 y 100
      vel1 = throttle1 + uk;
      vel2 = throttle2 - uk;

    } else {
      uk = abs(uk);
      uk = constrain(uk, 0, 100);  // Saturar la uk entre 0 y 100
      vel1 = throttle1 - uk;
      vel2 = throttle2 + uk;
    }

    //Velocidad de motores en base a uk
    servo1.writeMicroseconds(vel1);
    servo2.writeMicroseconds(vel2);

    prevTime = micros();
  }

}

Funcionamiento del control

La conexión en físico de el balancín es el siguiente:

Conexión de Esp32 con motores y Mpu

Conexión de Esp32 con motores y Mpu

Conexión de motores y colocación de hélices

Conexión de motores y colocación de hélices

Conexión con la computadora al Esp32.

Conexión con la computadora al Esp32.

Resultado del control PID en el balancín

Después de la sintonización heurística del controlador obtuvimos el resultado deseado. Nuestro SetPoint fue de 0 grados y la planta se mantuvo completamente horizontal como se muestra en la imagen de abajo.

Resultado final.

Resultado final.

Video demostrativo del funcionamiento del control PID

[embed]

Lecturas y envió de datos a LabVIEW.

Como manera de visualización de los datos y valores del control PID en el balancín se realizo el siguiente VI, que permitiera la lectura y envió de datos al Esp32 con el fin de sintonizarlo adecuadamente.

Parte visual del VI.

Parte visual del VI.

Programación del VI para la comunicación con el Esp32.

Programación del VI para la comunicación con el Esp32.


메타데이터
post_id
50d4bcba7221
slug
implementación-del-control-pid-de-balancín-50d4bcba7221
url
https://medium.com/@eder88559/implementaci%C3%B3n-del-control-pid-de-balanc%C3%ADn-50d4bcba7221
canonical_url
https://medium.com/@eder88559/implementaci%C3%B3n-del-control-pid-de-balanc%C3%ADn-50d4bcba7221
author_url
https://medium.com/@eder88559
status
ok
fetched_at
2026-07-07 07:11:48