PID para motores

Buenos días,

Pido si me pueden ayudar porfavor con un tema de control de motores con PID

Os pongo en antecedentes:

Tengo que realizar un trabajo para la universidad en el cual tengo que regular la fuerza de un motor, el motor elegido es trifásico brushless y se controla mediante un ESC.

(Para dar mas detalles diré que mido la inclinacion de un brazo y el objetivo es que el motor mantenga el brazo en equilibriom, algo asi como un balancín, para no enrrollarme mucho adjunto una imagen: algo parecido a esto:

Tengo realizada la programación para el control de este mediante un sistema proporcional en el que tenía puestas bastantes esperanzas.

Pero el resultado fue muy pobre, pues "funciona" pero trabaja con una reacción super lenta.

Me han hablado del tema de los PID y que funcionan muy bien para este tipo de casos, he leido la teoría y se mas o menos como funcionan, pero la verdad que en cuanto a la programación ando un poco perdido y el tiempo se va echando encima...

¿Podrían por favor ayudarme con este tema?

Lo que pido es una pequeña orientación y si conocen alguna página (preferiblemente en español) que tenga algún ejemplo de uso y de como controlan las señales que me pueda servir de ayuda.
Si es controlando algo parecido a un motor estaría genial.

Yo continúo buscando, pero no he encontrado demasiado, si encuentro algo interesante lo responderé aquí por si a alguien le sirve de ayuda.

Repito, en cuanto a la calibración y teoría de como funciona el PID ya he leído mucho, pero no tanto así como con temas directamente de aplicación que es donde estoy realmente perdido.

Agradezco la atención.

Un saludo a todos.

Hola.
Para comenzar, supongo que sabes que existe una librería PID para arduino, ¿no?
Por lo tanto, lo único que deberás es utilizarla, alimentarla con el dato del sensor que indique en qué inclinación se halla el brazo y qué inclinación buscas; calibrar los parámetros proporcional, integral y derivativo, y enviar el valor resultante al control del motor.
Este vídeo me parece bastante ilustrativo.

Hola Venator, bienvenido al foro arduino.

Muchas consultas estan ampliamente respondidas. Si pones PID en Search o buscas en Google Arduino PID encontraras la guia que estas buscando sea en español o inglés.

Vídeo muy ilustrativo,

Conozco la librería pero no la he usado, me encuentro ahora mismo construyendo el brazo-balancín.

Estoy en fase de informarme y recopilar toda la información posible.

Iré informando de los avances estos próximos días.

Hola VenatorV.
Me gustaría que aportaras alguna información sobre el hardware que estas usando que ayude a clarificar mas las cosas. Que motor datos, valores, corrientes.
Ya has dicho que es un brushless trifasico y tiene un controlador ESC.

Como armas el balancín, etc?
Esto será mas ilustrativo para nosotros y para aquel estudiante de control automático (asi se llamaba la materia en mi Universidad).

Es importante conocer bien la planta, mas alla que luego pongas el PID y lo ajustes manualmente o uses el AUTOTUNE del que dispone el PID.

Vamos por partes. PID: Proporcional Integral Diferential control. No vale la pena la traducción.

Proporcional : es lo que haces siempre con un simple if que establece cuando preder apagar el sistema para estabilizarlo alrededor de una zona sea de temperatura, angulo, velocidad o el parámetro que te interese.

Integral : es un concepto que evalua el error a lo largo del tiempo e intenta minimizarlo.
Con el control proporcional siempre tendras una brecha mas menos algo en el que el sistema se estará moviendo. Ese error es importante.
Si pudieras ajustarlo de modo que en un tiempo determinado el error tiende a 0 entonces logras la estabilidad deseada.

Diferencial: es el parámetro que corrige el error cuando una perturbación, saca al sistema de su zona de control.
Imagina que ya tienes el sistema estabilizado pero de golpe viene alguien o algo y lo toca, entonces ese toque lo sacará de control y esa perturbación debe ser corrigida con algo que nada tiene que ver con P o I.

Bien. Espero se entienda el concepto en líneas generales. Para una mejor y/o mas profunda explicacón ya sabes que Google dispone de lo necesario.

Ahora, configurar el PID puede no ser tarea fácil, para ello existe algo que se llama AUTOTUNNING que ajusta los valores del PID de forma automática. Es un proceso de calibración. Luego el sistema sigue operando con los datos de las constantes alladas para P I o D que se llaman Kp Ki y Kd
K de constante
Kp constante proporcional
Ki constante integral
Kd constante diferencial.

Me encuentro programando el PID

Tengo calculado el angulo que me da el IMU etc...

Mi problema es que no se como funciona el PID y no estoy seguro de si lo estoy entendiendo bien

Corregidme si me equivoco.

Tenemos PID

myPID(&Input, &Output, &Setpoint,kp,ki,kd, DIRECT);

Los datos kp ki kd no me preocupan ya los ajustare por ziegler nichols o algun metodo de tanteo

--> Dato que introduces al arduino (input)

Angulo actual dado por el IMU

---> Dato que recives del arduino

¿?¿? ni idea

---> Setpoint

Puto de referencia al que quiero que se quede el pendulo osea angulo 0º

---> SetOutputLimits()

Esto entiendo que me marca el rango de valores que me puede dar en la salida

Yo tengo el motor al que le doy un valor mediante

motor1.writeMicroseconds(i)

el valor "i" como lo consigo? porque no creo que me lo de directamente el PID

Lo que trato de intentar entender es que te da la salida del PID para así poder jugar con ese valor

PD: si que se que estoy un poco perdido pero en cuanto entienda este concepto avanzaré mucho, tengo mucho programado y llevo mucho tiempo en este proyecto, tengo una aplicacion android y comunicacion BT perfectamente operativa.

Agradezco que me puedan ilustrar un poco.

Saludos

surbyte:
Hola VenatorV.
Me gustaría que aportaras alguna información sobre el hardware que estas usando que ayude a clarificar mas las cosas. Que motor datos, valores, corrientes.
Ya has dicho que es un brushless trifasico y tiene un controlador ESC.

Como armas el balancín, etc?
Esto será mas ilustrativo para nosotros y para aquel estudiante de control automático (asi se llamaba la materia en mi Universidad).

Ahora mismo no tengo el código a mano pero puedo postear esta tarde toda la comunicación por BT y como la elaboro (si lo considerais necesario).

Tengo aplicado un filtro complementario hecho a mano sin ninguna libreria, es el conjunto de un filtro paso alto y un filtro paso bajo.
Consigue hacer una variante del filtro de kalaman pero con un coste de procesamiento mucho mas reducido de todos modos me estoy informando sobre la libreria de filtro kalaman.

El armado del balancín supongo que te refieres a como armo los ESC, estos como sabrás se les envía una señal a modo de pulso en ms.

Mi ESC se activa con un pulso de 1 ms por lo tanto valor 1000

trabajo declaran dolo como servo:

en mi caso:

Servo motor1

y una vez en el loop

motor1.writeMicroseconds(valor que corresponda)

Si necesitáis algún valor o dato mas concreto hacérmelo saber, no tengo ningún problema en facilitarlo

Cuando uses cosas como esta recuerda usar tags o etiquetas, hace mas fácil la lectura que el texto plano.

PID myPID(&Input, &Output, &Setpoint,kp,ki,kd, DIRECT);

INPUT será la entrada de tu sensor
OUTPUT es la salida que enviaras a tu controlador.
SETPOINT es el valor de angulo que deseas.

Asi que el error será siempre la diferencia entre tu Setpoint y la INPUT.

La salida podría ser un valor supongamos 0-255 tal que con eso comandes una PWM y con eso controlar tu ESC. Eso sería lo mas apropiado.
Por eso te pedi mas información porque no has puesto ni siquiera el código de como comandas el motor.

Tienes que modificar algunas cosas.
Mucho filtro complementario o Kalman o lo que sea agrega retardo, asi que si no optimizas las cosas puedes estar tratando con tiempos que dificulten las cosas.

Sería bueno que pongas un código aunque no funcione del todo bien pero para situarnos en el contexto de tu problema.
Luego analizamos tiempos y ver que hay que optimizar o no.

el valor "i" como lo consigo? porque no creo que me lo de directamente el PID

Pues, precisamente... :roll_eyes: :roll_eyes: :roll_eyes: :roll_eyes:

Eso sí, deberá estar sintonizado correctamente en todos los parámetros que decías.

surbyte:
Cuando uses cosas como esta recuerda usar tags o etiquetas, hace mas fácil la lectura que el texto plano.

PID myPID(&Input, &Output, &Setpoint,kp,ki,kd, DIRECT);

INPUT será la entrada de tu sensor
OUTPUT es la salida que enviaras a tu controlador.
SETPOINT es el valor de angulo que deseas.

Asi que el error será siempre la diferencia entre tu Setpoint y la INPUT.

La salida podría ser un valor supongamos 0-255 tal que con eso comandes una PWM y con eso controlar tu ESC. Eso sería lo mas apropiado.
Por eso te pedi mas información porque no has puesto ni siquiera el código de como comandas el motor.

Arreglado lo de introducir el código, intentaré que no se vuelva a repetir, tienes razón que es mucho mas visual.

Esta tarde espero tener tiempo para elaborar el código adaptándolo a como creo que se usa el PID

Adjunto el código que usaba hasta ahora (sin PID y que funcionar "funciona" pero mal y lento)

Espero que esté lo suficientemente claro, tiene varios comentarios para explicar lo que hago.

Me falta introducir en algún momento el PID pues es lo que no tengo claro.

(El código esta adaptado para un cuadricóptero que es lo que quiero realizar en un fin, pero ahora para ir poco a poco probando el PID haré lo del brazo balancín)

el código se encuentra en el mensaje siguiente pues sino este excedía el maximo de caracteres permitidos

MI problema es ese INPUT y OUTPUT que no se lo que me van a dar, ¿podemos hacer un ejemplo teórico rápido?

Input angulo actual (10º)

Setpoint angulo deseado (0º)

Output que es lo que me da?

Codigo del cuadricoptero sin PID :stuck_out_tongue:

//motores

#include<Servo.h>

//acelerometro grioscopio

#include <Wire.h>


#define  BAUD 9600   //velocidad puerto serial   funciona hasta 38400


//Direccion I2C de la IMU

#define MPU 0x68

 


//Ratios de conversion

#define A_R 16384.0

#define G_R 131.0
 


//Conversion de radianes a grados 180/PI

#define RAD_A_DEG = 57.295779



// conexiones bluetooth

//#define TxD 0

//#define RxD 1


#define EN 2

//VCC -->5V



// conexiones giroscopio


//VCC -->5V

//GND -->GND

//(Valores por defecto en la libreria) 

//SCL -->A5

//SDA -->A4 


 


Servo motor1, motor2, motor3, motor4; 
//Crear un objeto de clase servo

int16_t 

AcX, AcY, AcZ, GyX, GyY, GyZ;

int vel = 1000; 

//amplitud del pulso
float 

i,j,k,l=1000;

int a,b=0;

int aceleracion;

int media;


byte recibiendoByte ;

boolean iniciado = false; 

//int vel1;

int dato = 0;

int desconexion = 0;






//Angulos
float Acc[2];

float Gy[2];

float Angle[2];






void setup()


{

	Serial.begin(BAUD);


	Bluetooth.begin(BAUD);
  
  

	Wire.begin();
  Wire.beginTransmission(MPU);

	Wire.write(0x6B);
  
	Wire.write(0);
  
	Wire.endTransmission(true);

  

	//Asignar pines bluetooth
   pinMode(EN ,OUTPUT);
   

   
  
	//Asignar un pin al ESC
  

	motor1.attach(9);
  
	motor2.attach(10);
  
	motor3.attach(6);
  
	motor4.attach(5);

  

	//Preparar Bluetooth
  

	digitalWrite(EN,HIGH);
 
    
   
   
   

	while ( iniciado==false )
	{
          
          
		recibiendoByte = Serial.read(); 

		// Leemos el Byte recibido
          
		if (recibiendoByte == 65) 
          
		{    
              
			iniciado=true;

                                
                                

			//Activar el ESC
                                 
			motor1.writeMicroseconds(1000); 
			//1000 = 1ms
                                 
			motor2.writeMicroseconds(1000);
                                 
			motor3.writeMicroseconds(1000);
                                 
			motor4.writeMicroseconds(1000);
                                  
			//Cambia el 1000 anterior por 2000 si
                                  
			//tu ESC se activa con un pulso de 2ms
                                
                                    
                                  
			delay(5000); 
			//Esperar 5 segundos para hacer la activacion
 
                                           
            
            
           
		}
   
	}
 
  
 
  
 

}

  






void loop()


{

   
	//Leer los valores del Acelerometro de la IMU
   Wire.beginTransmission(MPU);
   
	Wire.write(0x3B); 
	
	//Pedir el registro 0x3B - corresponde al AcX
   Wire.endTransmission(false);
   
	Wire.requestFrom(MPU,6,true); 
	
	//A partir del 0x3B, se piden 6 registros
   AcX=Wire.read()<<8|Wire.read(); 
	//Cada valor ocupa 2 registros
   AcY=Wire.read()<<8|Wire.read();
   AcZ=Wire.read()<<8|Wire.read();
 
    

	//Se calculan los angulos Y, X respectivamente.
   
	Acc[1] = atan(-1*(AcX/A_R)/sqrt(pow((AcY/A_R),2) + pow((AcZ/A_R),2)))*RAD_TO_DEG;
   
	Acc[0] = atan((AcY/A_R)/sqrt(pow((AcX/A_R),2) + pow((AcZ/A_R),2)))*RAD_TO_DEG;
 
   

	//Leer los valores del Giroscopio
   Wire.beginTransmission(MPU);
   
	Wire.write(0x43);
   
	Wire.endTransmission(false);
   
	Wire.requestFrom(MPU,4,true); 
	//A diferencia del Acelerometro, solo se piden 4 registros
   

	GyX=Wire.read()<<8|Wire.read();
   
	GyY=Wire.read()<<8|Wire.read();
 
   

	//Calculo del angulo del Giroscopio
   
	Gy[0] = GyX/G_R;
   
	Gy[1] = GyY/G_R;
 
   
	//Aplicar el Filtro Complementario
   

	Angle[0] = 0.98 *(Angle[0]+Gy[0]*0.010) + 0.02*Acc[0];
   
	Angle[1] = 0.98 *(Angle[1]+Gy[1]*0.010) + 0.02*Acc[1];
 
   


	


// leemos el dato que entre por el bluetooth y lo almacenamos en la variable "dato" para poder clasificarlo


	dato = Serial.read();
 // .read envia un -1 si no lee nada




	//descenso controlado si pierde señal
   

	     if (dato == -1)    

		{
       
		desconexion++; 
      
		iniciado=false; 
     
		recibiendoByte=0;
 

		     if (desconexion>50)
    
			{
       
			  while ((i>1000)||(j>1000)||(k>1000)||(l>1000))
             
				{
            
				i=i-20;
               
				j=j-20;
              
				k=k-20;
              
				l=l-20;
               

				motor1.writeMicroseconds(i);      
              
				motor2.writeMicroseconds(j);
               
				motor3.writeMicroseconds(k);
               
				motor4.writeMicroseconds(l);
      
                
				}
     


			  while ( iniciado==false )             
				{
               

				recibiendoByte = Serial.read(); // Leemos el Byte recibido
                 

				     if (recibiendoByte == 65) 
               
					{                          
					iniciado=true;

					
					//Activar el ESC
//                                         

					motor1.writeMicroseconds(1000); //1000 = 1ms
                                        
					motor2.writeMicroseconds(1000);
                                        
					motor3.writeMicroseconds(1000);
                                        
					motor4.writeMicroseconds(1000);
//Cambia el 1000 anterior por 2000 si
 tu ESC se activa con un pulso de 2ms


					desconexion=0;                                                          
					delay(5000); //Esperar 5 segundos para hacer la activacion
 
					}
				} 
			}
		}
    
    



	if (dato != -1)
    
	{

          

		// eje x
//      

		if (dato<21)
     

		{
        
			a=dato-10;
   
		}
      


		// eje y
//      
	

		if (dato>21 && dato<51)
     

		{
       
			b=dato-40;
      
		}

      




		//velocidad
      
		
		if (dato>99 && dato<151)
       
		{
        
			desconexion=0;
        
			// el dato entra entre 100 y 150, pero nosotros lo queremos entre 1000 y 1500
        
			vel=dato*10;



        
			//marcar un minimo para que los motores no tengan una señal de poca fuerza en la que no pueden ni arrancar ni pararse
          

			if(vel<1070)
            
			{

             			 vel=1000;
            
			}
            

			// calculamos la media de los valores i j k l       
        

			media=(i+j+k+l)/4;
            
			
			// medimos cual es la "aceleracion" para calcular la diferencia entre la velociad deseada y los valores actuales
    
    
			aceleracion=vel-media;
  
      		
			i=i+aceleracion;
        
			j=j+aceleracion;
       
			k=k+aceleracion;
        
			l=l+aceleracion; 
        
      
		}
    
    
  
	}
  



	//  delay(10); //Nuestra dt sera, pues, 0.010, que es el intervalo de tiempo en cada medida








	// Estabilidad angulo X
     

	if( Angle[0]-a>0)
      
	{
        
		i=i+0.01,j=j+0.01,k=k-0.01,l=l-0.01;
 
        
      
	}
    

	if( Angle[0]-a<-0)
      
	{
        
        
		i=i-0.01,j=j-0.01,k=k+0.01,l=l+0.01;
  
      
	}      
   




	// Estabilidad angulo y        
    

	if( Angle[1]-b > 0)
      
	{
        
        
		i=i+0.01,j=j-0.01,k=k+0.01,l=l-0.01;

      
	}
    

	if( Angle[1]-b < -0)
      
	{
     
		i=i-0.01,j=j+0.01,k=k-0.01,l=l+0.01;
   
      
	}





	// marcar maximos y minimos
         


	if( i>1500)

	{
		i=1500;
  
	}


	if (i<1000)

	{
		i=1000;
  
	}



	if( j>1500)

	{
		j=1500;
  
	}


	if (j<1000)

	{
		j=1000;
  
	}



	if( k>1500)

	{
		k=1500;
  
	}


	if (k<1000)
	{
		k=1000;
  
	}
  


	if(l>1500)

	{
		l=1500;
  
	}


	if (l<1000)

	{
		l=1000;
  
	}







	if( Angle[0]-a<3 && Angle[0]-a>-3 &&  Angle[1]-b<3 &&  Angle[1]-b>-3)

	{
  
		i=vel;
 
		j=vel;

		k=vel;
 
		l=vel;
 
	}
  

 





	if (vel>1070)
  

	{
      
		motor1.writeMicroseconds(i);      
     
		motor2.writeMicroseconds(j);
      
		motor3.writeMicroseconds(k);
      
		motor4.writeMicroseconds(l);
 
 	}
  

	else
  
	{
      
		motor1.writeMicroseconds(1000);      
      
		motor2.writeMicroseconds(1000);
      
		motor3.writeMicroseconds(1000);
      
		motor4.writeMicroseconds(1000);
  
	}

}

Bueno, pendulo-brazo construido,

Estoy con el ahora con el código...

Espero poder plantear dudas (si tengo) mañana, os iré informando de los avances.

De momento sigo viendo ejemplos de PID e intentando comprenderlos.

Buenas gente!

Planteo el código que pienso probar:

lo voy comentando para que quede mas claro:

Declaraciones servo y diferentes variables para controlar IMU y obtener un ángulo

//motores

#include<Servo.h>

//acelerometro grioscopio

#include <Wire.h>


#define  BAUD 20000   //velocidad puerto serial   funciona hasta 38400


//Direccion I2C de la IMU

#define MPU 0x68

 


//Ratios de conversion

#define A_R 16384.0

#define G_R 131.0
 


//Conversion de radianes a grados 180/PI

#define RAD_A_DEG = 57.295779



// conexiones bluetooth

//#define TxD 0

//#define RxD 1


#define EN 2

//VCC -->5V



// conexiones giroscopio


//VCC -->5V

//GND -->GND

//(Valores por defecto en la libreria) 

//SCL -->A5

//SDA -->A4 


 


Servo motor1;  //Crear un objeto de clase servo

int16_t 

AcX, AcY, AcZ, GyX, GyY, GyZ;

int vel = 1000; 

//amplitud del pulso
float 

i=1000;

int a,b=0;




byte recibiendoByte ;

boolean iniciado = false; 

//int vel1;

int dato = 0;

int desconexion = 0;






//Angulos
float Acc[2];

float Gy[2];

float Angle[2];

Declaraciones para el PID (esto supongo que esta bien)

// valores kp,ki,kd


float kp=1.5;
float ki=1.5;
float kd=1.5;


/* PID Data */
double Setpoint, Input, Output;    //Definir vaiables del pid
PID myPID(&Input, &Output, &Setpoint,kp,ki,kd, DIRECT);   //crear myPID para ya llamarlo con sus todos sus parametros

Void setup: consta de leer un dato por el bluetooth para comprobar que todo esta listo e iniciar el ESC del motor

Poner PID en automatico y Sample time que no le tengo muy claro y setpoint supongo que hay que poner lo deseado (angulo = 0º)

void setup()


{

	Serial.begin(BAUD);


	Bluetooth.begin(BAUD);
  
  

	Wire.begin();
  Wire.beginTransmission(MPU);

	Wire.write(0x6B);
  
	Wire.write(0);
  
	Wire.endTransmission(true);

  

	//Asignar pines bluetooth
   

	pinMode(EN ,OUTPUT);
  
 

   
  
	//Asignar un pin al ESC
  

	motor1.attach(9);
  


  

	//Preparar Bluetooth
  

	digitalWrite(EN,HIGH);
 
    
   
   
   

	while ( iniciado==false )
	{
          
          
		recibiendoByte = Serial.read(); 

		// Leemos el Byte recibido
          
		if (recibiendoByte == 65) 
          
		{    
              
			iniciado=true;

                                
                                

			//Activar el ESC
                                 
			motor1.writeMicroseconds(1000); //1000 = 1ms
                                 
			                                
			//Cambia el 1000 anterior por 2000 si
                                  
			//tu ESC se activa con un pulso de 2ms
                                
                                    
                                  
			delay(5000); 
			//Esperar 5 segundos para hacer la activacion
 
                                           
            
            
           
		}
   
	}
 
 
//turn the PID on
 myPID.SetMode(AUTOMATIC);
// myPID.SetOutputLimits(**,**);
 myPID.SetSampleTime(10);     // este valor no lo tengo muy claro, pero supongo que cuanto ams pequeño mejor no?
 Setpoint = 0;		//angulo 0º
 
  
 

}

Void loop

Calculos para obtener angulo X e Y del IMU (aunque solo utilizaremos uno de ellos)

void loop()


{

   
	//Leer los valores del Acelerometro de la IMU
   Wire.beginTransmission(MPU);
   
	Wire.write(0x3B); 
	
	//Pedir el registro 0x3B - corresponde al AcX
   Wire.endTransmission(false);
   
	Wire.requestFrom(MPU,6,true); 
	
	//A partir del 0x3B, se piden 6 registros
   

	AcX=Wire.read()<<8|Wire.read(); //Cada valor ocupa 2 registros
   
	AcY=Wire.read()<<8|Wire.read();
   
	AcZ=Wire.read()<<8|Wire.read();
 
    

	//Se calculan los angulos Y, X respectivamente.
   
	Acc[1] = atan(-1*(AcX/A_R)/sqrt(pow((AcY/A_R),2) + pow((AcZ/A_R),2)))*RAD_TO_DEG;
   
	Acc[0] = atan((AcY/A_R)/sqrt(pow((AcX/A_R),2) + pow((AcZ/A_R),2)))*RAD_TO_DEG;
 
   

	//Leer los valores del Giroscopio
   Wire.beginTransmission(MPU);
   
	Wire.write(0x43);
   
	Wire.endTransmission(false);
   
	Wire.requestFrom(MPU,4,true); 
	//A diferencia del Acelerometro, solo se piden 4 registros
   

	GyX=Wire.read()<<8|Wire.read();
   
	GyY=Wire.read()<<8|Wire.read();
 
   

	//Calculo del angulo del Giroscopio
   
	Gy[0] = GyX/G_R;
   
	Gy[1] = GyY/G_R;
 
   

	//Aplicar el Filtro Complementario
   

	Angle[0] = 0.98 *(Angle[0]+Gy[0]*0.010) + 0.02*Acc[0];
   
	Angle[1] = 0.98 *(Angle[1]+Gy[1]*0.010) + 0.02*Acc[1];

Leer datos por el bluetooth para cambiar kp ki kd

// leemos el dato que entre por el bluetooth y lo almacenamos en la variable "dato" para poder clasificarlo


	dato = Serial.read();



	// Ajustar kp ki kd con el Bluetooth

	if (dato != -1)
    
	{

          

		// kp 
//      

		if (dato==1)
     

		{
        
			kp=kp+0.5;
   
		}
      

		if (dato==2)
     

		{
        
			kp=kp-0.5;
   
		}
  
		
		// ki 
//      

		if (dato==3)
     

		{
        
			ki=ki+0.5;
   
		}
      

		if (dato==4)
     

		{
        
			ki=ki-0.5;
   
		}
  


		// kd 
//      

		if (dato==5)
     

		{
        
			kd=kd+0.5;
   
		}
      

		if (dato==6)
     

		{
        
			kd=kd-0.5;
   
		}

Y aquí viene donde tengo mas dudas y espero que me podáis decir si es correcto o no o por donde van los tiros...

Notese que la función map es la primera vez que la uso, creo que me convierte los º a ms segun la relacción que le he dado: -45º 1070ms (motor parado) +45º 2000(motor al maximo), pero tampoco estoy muy seguro si así funcionará (tambien agradeceria un poco de luz en este asunto)

// PID
		Input = Angle[0];
 
  		myPID.Compute(); 
   
		i = map (Output,-45,45,1070,2000);
		
		motor1.writeMicroseconds(i);    
   		
 }

Saludos y gracias por anticipado

Desde mi nula experiencia (si me equivoco que alguien me corrija).

Olvídate del map, que vendría a ser una de las partes de la fórmula del PID (la parte proporcional).
El propio Output asignado al PID debería poder enviarse directamente a motor1.writeMicroseconds. Eso sí, deberás establecer los límites de salida; y sobre todo deberás buscar unos valores de sintonización y de tiempo de muestreo adecuados.
Agrega a tu setup:

myPID.SetOutputLimits(1070,2000);

Quedando la última parte como:

myPID.Compute();
motor1.writeMicroseconds(Output);

Muy recomendable que leas la documentación.

Gracias por contestar.

Entonces, si nadie me dice lo contrario, debería funcionar así:

Input angulo actual

Setpoint angulo deseado

Output (diciendole los limites) salida para meter ya directamente a pelo al motor (esto la verdad que no lo tengo demasiado claro, pero supongo que tengo que confiar en el poder del PID jeje)

tiempo de muestreo unos 10 ms?

Lo probaré a lo largo de este finde y os comento los resultados muchas gracias.

Estaría bien si alguien mas puede confirmar que ese código podría funcionar ajustando bien kp ki kd, pues la verdad que le he cogido un poco de miedo al prueba y error debido a un accidente que tuve.

Saludos.

Ahora creo que estás (estamos) en lo correcto. Hay otro parámetro a tener en cuenta que es Direction, que por defecto es DIRECT, que indica en tu caso si aumentar la salida hará incrementar (DIRECT) o decrementar (REVERSE) el ángulo.
Será mejor que alguien que lo haya experimentado te confirme (máxime si la vida del "artista" está en juego), pero creo que sí debería funcionar ajustando los parámetros. Lo delicado es encontrar la frecuencia y los kp,ki y kd óptimos. Lamentablemente esto requerirá inevitablemente el prueba y error.

Pd. En la documentación que te refería en mi post anterior, también se hacía referencia a una librería para sintonizar un PID. Tal vez te pueda servir de ayuda.

Bueno, simplemente decir que el código con unas pequeñas modificaciones ya funciona.

//Libreria motores

#include<Servo.h>

//Libreria PID

#include <PID_v1.h>

//acelerometro grioscopio

#include <Wire.h>


#define  BAUD 9600   //velocidad puerto serial   funciona hasta 38400


//Direccion I2C de la IMU

#define MPU 0x68

//Ratios de conversion

#define A_R 16384.0
#define G_R 131.0
 


//Conversion de radianes a grados 180/PI

#define RAD_A_DEG = 57.295779



// conexiones bluetooth

//#define TxD 0
//#define RxD 1
#define EN 2
//VCC -->5V



// conexiones giroscopio


//VCC -->5V
//GND -->GND
//(Valores por defecto en la libreria) 
//SCL -->A5
//SDA -->A4 


Servo motor1;  //Crear un objeto de clase servo

int16_t AcX, AcY, AcZ, GyX, GyY, GyZ;

int vel = 1000; 

//amplitud del pulso

int a,b=0;
int Reinicio=0;
byte recibiendoByte ;
boolean iniciado = false; 

int dato = 0;
int desconexion = 0;


//Angulos
float Acc[2];
float Gy[2];
float Angle[2];


// valores kp,ki,kd


float kp=10;
float ki=0;
float kd=0;


/* PID Data */
double Setpoint, Input, Output;    //Definir vaiables del pid
PID myPID(&Input, &Output, &Setpoint,kp,ki,kd, DIRECT);   //crear myPID para ya llamarlo con sus todos sus parametros




 



void setup()


{

  Serial.begin(BAUD);

//  //dar corriente al bluetooth
//  pinMode(8, OUTPUT);
//  digitalWrite(8,HIGH); 

  // Bluetooth.begin(BAUD);
  
  

  Wire.begin();
  Wire.beginTransmission(MPU);
  Wire.write(0x6B);
  Wire.write(0);
  Wire.endTransmission(true);

  

  //Asignar pines bluetooth
   
  pinMode(EN ,OUTPUT);
  
 
  //Asignar un pin al ESC
  
  motor1.attach(10);
  
  //Preparar Bluetooth
  digitalWrite(EN,HIGH);
 
    
   

    while ( iniciado==false ){
          
          recibiendoByte = Serial.read(); // Leemos el Byte recibido
          if (recibiendoByte == 65) 
          {    
              iniciado=true;

                                
                                //Activar el ESC
                                 motor1.writeMicroseconds(1000); //1000 = 1ms
                                
                                  //Cambia el 1000 anterior por 2000 si
                                  //tu ESC se activa con un pulso de 2ms
                                
                                    
                                  delay(5000); //Esperar 5 segundos para hacer la activacion
                                            
            
            
            }
   }
 
 
 
//turn the PID on
 myPID.SetMode(AUTOMATIC);
// myPID.SetOutputLimits(**,**);
 myPID.SetSampleTime(10);     // este valor no lo tengo muy claro, pero supongo que cuanto ams pequeño mejor no?
 myPID.SetOutputLimits(1000,2000); 
Setpoint = 0;   //angulo 0º  



 

 

}

  






void loop()


{

    //Leer los valores del Acelerometro de la IMU
   Wire.beginTransmission(MPU);
   Wire.write(0x3B); //Pedir el registro 0x3B - corresponde al AcX
   Wire.endTransmission(false);
   Wire.requestFrom(MPU,6,true); //A partir del 0x3B, se piden 6 registros
   AcX=Wire.read()<<8|Wire.read(); //Cada valor ocupa 2 registros
   AcY=Wire.read()<<8|Wire.read();
   AcZ=Wire.read()<<8|Wire.read();
 
    //Se calculan los angulos Y, X respectivamente.
   Acc[1] = atan(-1*(AcX/A_R)/sqrt(pow((AcY/A_R),2) + pow((AcZ/A_R),2)))*RAD_TO_DEG;
   Acc[0] = atan((AcY/A_R)/sqrt(pow((AcX/A_R),2) + pow((AcZ/A_R),2)))*RAD_TO_DEG;
 
   //Leer los valores del Giroscopio
   Wire.beginTransmission(MPU);
   Wire.write(0x43);
   Wire.endTransmission(false);
   Wire.requestFrom(MPU,4,true); //A diferencia del Acelerometro, solo se piden 4 registros
   GyX=Wire.read()<<8|Wire.read();
   GyY=Wire.read()<<8|Wire.read();
 
   //Calculo del angulo del Giroscopio
   Gy[0] = GyX/G_R;
   Gy[1] = GyY/G_R;
 
   //Aplicar el Filtro Complementario
   Angle[0] = 0.98 *(Angle[0]+Gy[0]*0.010) + 0.02*Acc[0];
   Angle[1] = 0.98 *(Angle[1]+Gy[1]*0.010) + 0.02*Acc[1];

   

  //Leer los valores del Giroscopio
   Wire.beginTransmission(MPU);
   
  Wire.write(0x43);
   
  Wire.endTransmission(false);
   
  Wire.requestFrom(MPU,4,true); 
  //A diferencia del Acelerometro, solo se piden 4 registros
   

  GyX=Wire.read()<<8|Wire.read();
   
  GyY=Wire.read()<<8|Wire.read();
 
   

  //Calculo del angulo del Giroscopio
   
  Gy[0] = GyX/G_R;
   
  Gy[1] = GyY/G_R;
 
   

  //Aplicar el Filtro Complementario
   

  Angle[0] = 0.98 *(Angle[0]+Gy[0]*0.010) + 0.02*Acc[0];
   
  Angle[1] = 0.98 *(Angle[1]+Gy[1]*0.010) + 0.02*Acc[1];
 
   


  


// leemos el dato que entre por el bluetooth y lo almacenamos en la variable "dato" para poder clasificarlo


//  dato = Serial.read(); // .read envia un -1 si no lee nada
    
 if(Serial.available() >= 1)
  {
    dato = Serial.parseInt(); //Leer un entero por serial
    
  }
  
//
//velocidad // cambiar de 0 a 1000 y PID 0-2000 funcionara?
//      if (dato>99 && dato<151)
//       {
//        desconexion=0;
//        // le dato entra entre 100 y 150, pero nosotros lo queremos entre 1000 y 1500
//        vel=dato*10;
//       }
//
//  // Ajustar kp ki kd con el Bluetooth

         

    // kp 
    // 

    if (dato==151)
     

    {
        
      kp=kp+1;
   Serial.println(" kp = ") ; 
   Serial.println(kp) ;
    }
      

    if (dato==152)
     

    {
        
      kp=kp-1;
   Serial.println(" kp = ") ; 
   Serial.println(kp) ;
    }
  
    
    // ki 
     

    if (dato==153)
     

    {
        
      ki=ki+0.5;
   Serial.println(" ki = ") ; 
   Serial.println(ki) ;
    }
      

    if (dato==154)
     

    {
        
      ki=ki-1;
     Serial.println(" ki = ") ; 
   Serial.println(ki) ;
    }
  


    // kd 
     

    if (dato==155)
     

    {
        
      kd=kd+1;
     Serial.println(" kd = ") ; 
   Serial.println(kd) ;
    }
      

    if (dato==156)
     

    {
        
      kd=kd-1;
     Serial.println(" kd = ") ; 
   Serial.println(kd) ;
    }


  //stop
  
  if (dato==163)
     

    {
     while( Reinicio==0)   
     { 
       motor1.writeMicroseconds(1000);
       dato = 0;
       dato = Serial.read();
       if (dato==163)
       {
        Reinicio = 1;
        }
     }
    }

    // PID
    Input = -Angle[0];
 
    myPID.Compute(); 
      
    motor1.writeMicroseconds(Output);    
      
  }

Solo queda sintonizar los valores kp,ki,kd.

Muchas gracias a los que habéis colaborado.
Por mi parte cierro este post y nos veremos en el futuro en otros.

Un saludo.