No consigo que el PID me regule la velocidad del motor

Buenos días a todos,
Le cuento mi problema a ver si damos con la clave. Anticipo que mis conocimientos en programación son los justos para no prender fuego el escritorio.

El caso es que tengo un circuito en el que por un lado puedo hacer lecturas de caudal en un tubo y por otro puedo hacer que una turbina se mueva a un valor de pwm dado.

Todo esto lo comando introduciendo una orden y un valor por el puerto serial.

El problema viene ahora cuando quiero controlar mediante un PID para que, dando una valor de flujo dado, la turbina ponga el valor de PWM necesario para ese flujo.

Con el código que tengo, cuando escribo pid y un valor de flujo deseado, la turbina arranca, pero no hace fluctuar el pwm.

He probado con varias librerias (PID_v1, Pid_v2, ArduPid, PIDController de Luis en llamas) y todas sin resultados.

Les paso el código, yo lo tengo dividido en diferentes pestaña, pero se los pongo aquí todo junto.

#include <Wire.h>
#include <Adafruit_ADS1X15.h>
#include <BME280I2C.h>
#include <BTS7960.h>
#include "PIDController.hpp"

//Entorno motores
#define L_EN 8
#define R_EN 8
#define L_PWM 10                             //pin 5 supports 980hz pwm frequency
#define R_PWM 9                             //pin 6 supports 980hz pwm frequency
int imotor = 0;
int iobjetivo = 0;
BTS7960 motor1(L_EN, R_EN, L_PWM, R_PWM);   //This method will create a object of the class BTS7960

//Entorno sensores de presión
  //Sensores absoluta
  Adafruit_ADS1115 ads;
  const float multiplier = 0.1875F;
  double Q1, Q2;
  //Sensor barométrica
  BME280I2C bme;    
  //Calibración
  bool calibrated = false; // Indica si se ha realizado la calibración
  float pressatm, corr0, corr1, corr2, corr3;

//Entorno PID
PID::PIDParameters<double> parameters(4.0, 0.2, 1);
PID::PIDController<double> pidController(parameters);

//Entorno lectura serial
int accion = 0;
double value;

void setup(void) {
  Serial.begin(9600);
  inisensores();
  calibracionsensores();
  motor1.begin();                           //This method will set the motor driver pins as output
  motor1.enable();
  pidController.Input = caudalimetro(1);
  pidController.Setpoint = 100;
  pidController.SetOutputLimits (30,100);
  pidController.TurnOn();
}

void loop(void) {
  if (Serial.available()) {
    String command = Serial.readStringUntil('\n'); // Leer el comando enviado por el puerto serial

    // Extraer el comando y el valor (si está presente)
    String task = command.substring(0, command.indexOf(' '));
    String valueString = command.substring(command.indexOf(' ') + 1);
    value = valueString.toDouble();

    // Ejecutar la tarea correspondiente al comando recibido
    if (task == "calibrar") {
      Serial.println("calibrando");

    } else if (task == "inimotor") {
      accion = 1;
    } else if (task == "parar") {
      accion = 2;
    } else if ((task == "pid")) {
      accion = 3;        
    }else{
    Serial.println("Comando inválido");
    }
}

switch (accion){
  case (1):
  iobjetivo = value;
  arranquerampa(iobjetivo,10);
  Serial.println("iniciando motor");
  break;

  case (2):
  paradaMotor();
  imotor=0;
  Serial.println("motor parado");
  break;

  case (3):
  pidController.Input = caudalimetro(1);
  pidController.Setpoint = value;
  pidController.Update();
  accionMotor(pidController.Output);
  Serial.print("value: "); Serial.println(value,6);
  Serial.print("PWM: "); Serial.println(pidController.Output);
  Serial.print("caudal: "); Serial.println(caudalimetro(1),6);
  delay (500);

  break;
}


 //Serial.println("Externo");
 //Serial.print("caudal: "); Serial.println(caudalimetro(1),6);
 //Serial.print("value: "); Serial.println(value,6);
 //Serial.print("imotor: "); Serial.println(imotor);
 // Serial.println(caudalimetro(1),6);
  //Serial.println(" ");
  delay (500);
}

void arranquerampa(int iobjetivo, int crecimiento){ 
   if (imotor<iobjetivo){
           motor1.pwm = imotor;                         //Set the speed, by default the speed is set to 255 you can change it 
           motor1.front();                         //front functions should turn the motor in clockwise direction
           imotor=imotor+crecimiento;
           Serial.println(imotor);
           delay(500);
   }else if(imotor>iobjetivo){
           motor1.pwm = imotor;                         //Set the speed, by default the speed is set to 255 you can change it 
           motor1.front();                         //front functions should turn the motor in clockwise direction
           imotor=imotor-crecimiento;
           Serial.println(imotor);
           delay(500);
   }else if(imotor=iobjetivo){
     accion=0;
   }
}

void accionMotor(int imotor){
  motor1.pwm = imotor; //Set the speed, by default the speed is set to 255 you can change it 
  motor1.front();      //front functions should turn the motor in clockwise direction
  delay(500);
}
  
void paradaMotor(){
   if (accion=2){
    motor1.stop();
    accion=0;
  } 
}

void inisensores(){
  //Descomentar el que interese
  ads.setGain(GAIN_TWOTHIRDS);  //+/- 6.144V  1 bit = 0.1875mV (default)
  //ads.setGain(GAIN_ONE);       // +/- 4.096V  1 bit = 0.125mV
  // ads.setGain(GAIN_TWO);        +/- 2.048V  1 bit = 0.0625mV
  // ads.setGain(GAIN_FOUR);       +/- 1.024V  1 bit = 0.03125mV
  // ads.setGain(GAIN_EIGHT);      +/- 0.512V  1 bit = 0.015625mV
  // ads.setGain(GAIN_SIXTEEN);    +/- 0.256V  1 bit = 0.0078125mV 
  ads.begin();
}

void calibracionsensores(){
  Wire.begin();
  bme.begin();
  Serial.println("Iniciando calibracion");
    // Leer la presión atmosférica
    printBME280Data(&Serial);
    delay(500);
    
    // Leer la presión de los Venturi
    int16_t adc0 = ads.readADC_SingleEnded(0);
    int16_t adc1 = ads.readADC_SingleEnded(1);
    int16_t adc2 = ads.readADC_SingleEnded(2);
    int16_t adc3 = ads.readADC_SingleEnded(3); 
    float press0 = ((((((adc0) * multiplier/1000)/5.05)+0.00842)/0.002421)*1000)+corr0;
    float press1 = ((((((adc1) * multiplier/1000)/5.05)+0.00842)/0.002421)*1000)+corr1;
    float press2 = ((((((adc2) * multiplier/1000)/5.05)+0.00842)/0.002421)*1000)+corr2;
    float press3 = ((((((adc3) * multiplier/1000)/5.05)+0.00842)/0.002421)*1000)+corr3;
    
    //Calibración de sensores de presión
    corr0 = (press0 - pressatm)*-1;
    corr1 = (press1 - pressatm)*-1;
    corr2 = (press2 - pressatm)*-1;
    corr3 = (press3 - pressatm)*-1;
    calibrated = true; // Marcar que la calibración se ha realizado
    Serial.println("Finalizando calibracion");
}


double caudalimetro(int sensor){ 
  int16_t adcx, adcy;
  double corrx, corry;
  switch (sensor){
    case 1:
      adcx = ads.readADC_SingleEnded(0); //ADS1115 da una señal de -32.768 a 32767
      adcy = ads.readADC_SingleEnded(1);
      corrx = corr0;
      corry = corr1;
    break;
    case 2:
      adcx = ads.readADC_SingleEnded(2); //ADS1115 da una señal de -32.768 a 32767
      adcy = ads.readADC_SingleEnded(3);
      corrx = corr2;
      corry = corr3;
    break;  
  }

  float pressx = ((((((adcx) * multiplier/1000)/5.05)+0.00842)/0.002421)*1000)+corrx;
  float pressy = ((((((adcy) * multiplier/1000)/5.05)+0.00842)/0.002421)*1000)+corry;
  
  double Q = 0.000100655*sqrt(abs(pressx-pressy));
  return Q;
}



void printBME280Data (Stream* client){
   float temp(NAN), hum(NAN), pres(NAN);

   BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
   BME280::PresUnit presUnit(BME280::PresUnit_Pa);

   bme.read(pres, temp, hum, tempUnit, presUnit);
   pressatm = pres;

   //client->print("Temp: ");
   // client->print(temp);
   // client->print("°"+ String(tempUnit == BME280::TempUnit_Celsius ? 'C' :'F'));
   //client->print("\t\tHumidity: ");
   //client->print(hum);
   //client->print("% RH");
   //client->print("\t\tPressure: ");
   //client->print(pres);
   //client->println("Pa");
   //client->print("\t\tATMPressure: ");
   //client->print(pressatm);
   //client->println("Pa");

   delay(1000);
}


Muchas gracias de antemano por la ayuda

Moderador:
Por favor, lee las Normas del foro y edita tu código/error usando etiquetas de código, de modo tal que se pueda leer.
Si subes un archivo como has hecho te aseguro que muy pocos te van a responder.
Ve a edición, luego selecciona todo el código que has publicado, lo cortas y click en (<CODE/>)


Hola Surbyte, como leí en el punto 8 de las normas que si el código estaba en diferentes archivos se podía poner adjuntos, pues eso hice.
No obstante tomo tu consejo y ya está editado, espero que se entienda.

Muchas gracias

El nuevo respositorio soporta grandes archivos.

Esto no te excluye de nada pero empezar sin conocimiento con un PID? Me parece que se te fue la mano.
Lo primero es usa el PID solo como P. Funciona? Luego PI y finalmente si hace falta D de diferencial.
De donde sacaste

PID::PIDParameters<double> parameters(4.0, 0.2, 1);

kp es 4.0
ki = 0.2
kd = 1

Cómo sacaste estos valores?

Esos valores son los del ejemplo de Luis en llamas, aún no lo he calibrado.
Pero mi principal problema es que el valor del pwm no varía, se mantiene siempre constante en 30 (el mínimo)

tienes que sintonizar las variables proporcional, integradora y derivativa, empieza por el kp desde 0.1, con las variable ki y kd en 0; subele de tanto en tanto hasta tener un comportamiento deseado un poco erratico luego sigues con el valor de ki para finalizar con la constante kd en donde ya deberias tener el comportamiento deseado

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.