Arduino, Motor,IMU6050 y PID

Hola, he estado mirado por internet el control PID para implementarlo en el arduino, he visto este video de un proyecto Brushless Gimbal Controller Test 2 - YouTube y he mirado la libreria PID, pero no entiendo como implementarlo para que lea los valores del imu6050 y usando el pid actue de esa forma, alguien puede ayudarme e indicarme?, como introduzco los valores del imu y que valor devuelve el PID?

otro video similar donde tambien se usa

Un saludo.

De poco o nada sirve ver un vídeo así salvo para saber que alguien lo ha hecho funcionar.

Lo primero es que te documentes y leas mucha información para entender lo que es el IMU, lo que hace, los datos que puede darte y cómo y con qué código te los da. Luego te documentas sobre lo que es un PID, cómo funciona, aprender a usar por ejemplo la librería que hay para tal efecto en Arduino y practicar con ejemplos sencillos. Después de todo eso ya puedes pasar a aplicar todos esos conocimientos elaborando el código necesario para tu aplicación. Y en ese momento puedes seguir preguntando donde te hayas atascado, lo que no te funcione o no sepas depurar apropiadamente.

Hasta ahora tengo el IMU6050 funcionando correctamente y lo tengo con un filtro de Kalman para que los datos sean mas estables, lo que no entiendo bien es como el PID pasandole esos datos del imu sea capaz de mover el motor, por eso pregunto que es lo que da la salida del PID, he visto que tiene un variable setpoint, donde seleccionas un valor y apartir de ese da una salida, pero es esa salida la que tiene que tomar el motor para moverse? y para que se usan los valores Kp, ki, kd? no son siempre iguales o se varian dependiendo de las necesidades?

Entonces te recomiendo que hagas lo que indicaba en la segunda parte de mi mensaje. Lee información sobre lo que es una regulación en bucle cerrado, un PID, el error de control y los parámetros kp, ki y kd. Créeme si te digo que luego avanzarás más rápido.

Y una vez entendido lo que es una regulacion en bucle cerrado y los puntos kp,ki y kp
He echo un codigo de prueba (Muy malo sinceramente =( ) Y nose como ajustar los parametros
¿Algien me ayuda?

saludos !

Yo llegue a odiar este tema, teníamos 4 preciosas asignaturas en las que se hacía lo que comentas. Fueron un horror de las que no me acuerdo (o no quiero acordarme) de gran cosa. Lo que saque en claro es que por muchos cálculos que hagas, los mejores resultados los conseguía metiendo valores a huevo. Empieza por Kp cuando se acerque a lo que quieres métele un poco de derivativo y cuando se acerque a lo que buscas corrige un poco con el integral. Como puedes ver todo muy profesional y elegante :smiley:

Muy buenas este es el codigo que tengo por el momento, en la base que tengo como balancin se estabiliza bien aunque lo hace lento; ¿Alguna sugerencia para ajustar el PID? Si me recomendais un potenciometro, ir dando valores por teclado o que.
Saludos!!!
PD: Tengo un video del funcionamiento de este codigo aun sin subir

#include <PID_v1.h>
#include <Wire.h>
#include "Kalman.h" // Source: https://github.com/TKJElectronics/KalmanFilter
#include <Servo.h> 

#define PINMOTOR 8      //pin conectado al ESC
#define MAXIMOPWM 160   
#define MINIMOPWM 30    
#define PINMOTOR2 9

Kalman kalmanX; // Create the Kalman instances
Kalman kalmanY;
float inverOutput;
int X;
/* Motor Data */
int pulsoMotor = 30;
int pulsoMotor2 = 30;
Servo myservo;  
Servo myservo2; 
 byte recibiendoByte ;
 boolean iniciado = false;
 boolean carga = false;
 
/* PID Data */
double Setpoint, Input, Output;    //Define Variables we'll be connecting to
PID myPID(&Input, &Output, &Setpoint,1,5,1, DIRECT);   //Specify the links and initial tuning parameters

/* IMU Data */
int16_t accX, accY, accZ;
int16_t gyroX, gyroY, gyroZ;

double accXangle, accYangle; // Angle calculate using the accelerometer
double gyroXangle, gyroYangle; // Angle calculate using the gyro
double compAngleX, compAngleY; // Calculate the angle using a complementary filter
double kalAngleX, kalAngleY; // Calculate the angle using a Kalman filter

uint32_t timer;
uint8_t i2cData[14]; // Buffer for I2C data

void setup() {
  Serial.begin(115200);
  Setpoint = 180;

  myservo.attach(PINMOTOR);  // inicializo el ESC 
  myservo2.attach(PINMOTOR2);
   Serial.println(" Comienzo del test");  //
   Serial.println (" Pulsar 'A' para arrancar  \n Cuando escuche el pitido de confirmación");
   while ( iniciado==false ){
          myservo.write(0);
          myservo2.write(0);   // Armado
          recibiendoByte = Serial.read(); // Leemos el Byte recibido
          if (recibiendoByte == 65 || recibiendoByte ==97) {    // A o a  Mayusculas o minusculas
              iniciado=true;
            }
} 
   Serial.println (" Pulsar 'C' para cargar");

  while ( carga==false ){
          myservo.write(30);   // Armado
          myservo2.write(30);
          recibiendoByte = Serial.read(); // Leemos el Byte recibido
          if (recibiendoByte == 67 || recibiendoByte ==99) {    // A o a  Mayusculas o minusculas
              carga=true;
            }
} 
  //turn the PID on
  myPID.SetMode(AUTOMATIC);
 // myPID.SetOutputLimits(90,179);
  myPID.SetSampleTime(50);
  
  Wire.begin();
  TWBR = ((F_CPU / 400000L) - 16) / 2; // Set I2C frequency to 400kHz

  i2cData[0] = 7; // Set the sample rate to 1000Hz - 8kHz/(7+1) = 1000Hz
  i2cData[1] = 0x00; // Disable FSYNC and set 260 Hz Acc filtering, 256 Hz Gyro filtering, 8 KHz sampling
  i2cData[2] = 0x00; // Set Gyro Full Scale Range to ±250deg/s
  i2cData[3] = 0x00; // Set Accelerometer Full Scale Range to ±2g
  while (i2cWrite(0x19, i2cData, 4, false)); // Write to all four registers at once
  while (i2cWrite(0x6B, 0x01, true)); // PLL with X axis gyroscope reference and disable sleep mode

  while (i2cRead(0x75, i2cData, 1));
  if (i2cData[0] != 0x68) { // Read "WHO_AM_I" register
    Serial.print(F("Error reading sensor"));
    while (1);
  }

  delay(100); // Wait for sensor to stabilize

  /* Set kalman and gyro starting angle */
  while (i2cRead(0x3B, i2cData, 6));
  accX = ((i2cData[0] << 8) | i2cData[1]);
  accY = ((i2cData[2] << 8) | i2cData[3]);
  accZ = ((i2cData[4] << 8) | i2cData[5]);
  // atan2 outputs the value of -? to ? (radians) - see http://en.wikipedia.org/wiki/Atan2
  // We then convert it to 0 to 2? and then from radians to degrees
  accYangle = (atan2(accX, accZ) + PI) * RAD_TO_DEG;
  accXangle = (atan2(accY, accZ) + PI) * RAD_TO_DEG;

  kalmanX.setAngle(accXangle); // Set starting angle
  kalmanY.setAngle(accYangle);
  gyroXangle = accXangle;
  gyroYangle = accYangle;
  compAngleX = accXangle;
  compAngleY = accYangle;

  timer = micros();
}

void loop() {
  /* Update all the values */
  while (i2cRead(0x3B, i2cData, 14));
  accX = ((i2cData[0] << 8) | i2cData[1]);
  accY = ((i2cData[2] << 8) | i2cData[3]);
  accZ = ((i2cData[4] << 8) | i2cData[5]);
  gyroX = ((i2cData[8] << 8) | i2cData[9]);
  gyroY = ((i2cData[10] << 8) | i2cData[11]);
  gyroZ = ((i2cData[12] << 8) | i2cData[13]);

  // atan2 outputs the value of -? to ? (radians) - see http://en.wikipedia.org/wiki/Atan2
  // We then convert it to 0 to 2? and then from radians to degrees
  accXangle = (atan2(accY, accZ) + PI) * RAD_TO_DEG;
  accYangle = (atan2(accX, accZ) + PI) * RAD_TO_DEG;

  double gyroXrate = (double)gyroX / 131.0;
  double gyroYrate = -((double)gyroY / 131.0);
  gyroXangle += gyroXrate * ((double)(micros() - timer) / 1000000); // Calculate gyro angle without any filter
  gyroYangle += gyroYrate * ((double)(micros() - timer) / 1000000);
  //gyroXangle += kalmanX.getRate()*((double)(micros()-timer)/1000000); // Calculate gyro angle using the unbiased rate
  //gyroYangle += kalmanY.getRate()*((double)(micros()-timer)/1000000);

  compAngleX = (0.93 * (compAngleX + (gyroXrate * (double)(micros() - timer) / 1000000))) + (0.07 * accXangle); // Calculate the angle using a Complimentary filter
  compAngleY = (0.93 * (compAngleY + (gyroYrate * (double)(micros() - timer) / 1000000))) + (0.07 * accYangle);

  kalAngleX = kalmanX.getAngle(accXangle, gyroXrate, (double)(micros() - timer) / 1000000); // Calculate the angle using a Kalman filter
  kalAngleY = kalmanY.getAngle(accYangle, gyroYrate, (double)(micros() - timer) / 1000000);
  timer = micros();


  /* Print Data */
#if 0 // Set to 1 to activate
  Serial.print(accX); Serial.print("\t");
  Serial.print(accY); Serial.print("\t");
  Serial.print(accZ); Serial.print("\t");

  Serial.print(gyroX); Serial.print("\t");
  Serial.print(gyroY); Serial.print("\t");
  Serial.print(gyroZ); Serial.print("\t");
#endif
  //Serial.print(accXangle); Serial.print("\t");
  //Serial.print(gyroXangle); Serial.print("\t");
  //Serial.print(compAngleX); Serial.print("\t");
  Serial.print(kalAngleX); Serial.print("\t");

  Serial.print("\t");

  //Serial.print(accYangle); Serial.print("\t");
  //Serial.print(gyroYangle); Serial.print("\t");
  //Serial.print(compAngleY); Serial.print("\t");
  //Serial.print(kalAngleY); Serial.print("\t");


  Serial.print("\r\n");
  delay(1);

  // PID
  Input = kalAngleX; 
    myPID.Compute();    
    pulsoMotor2= map (Output,0,255,90,94);
    pulsoMotor= 184 - pulsoMotor2 ;
    myservo.write(pulsoMotor); 
    myservo2.write(pulsoMotor2); 
    
  delay(250);
  Serial.print("Velocidad del pulso-1->  ");
  Serial.println (pulsoMotor);
  Serial.print("PID 11111 -->  ");
  Serial.println (inverOutput);
  Serial.print("Velocidad del pulso-2->  ");
  Serial.println (pulsoMotor2);
  Serial.print("PID 22222 -->  ");
  Serial.println (Output);
   
}

Si ponle algo porque sino te vas a aburrir de enviar el programa con cada PID. Yo haría con bluetooth. Salu2

Ya lo e variado y la diferencia de estabilizacion es ENORME jeje
lo controlaremos con un modulo RF (Es lo mas ssencillo si nos da tiempo se mejorara)

aqui esta el codigo y una dudilla
http://forum.arduino.cc/index.php?topic=215303.0