Necesito controlar un balancín con PID

Tengo que agregarle a un circuito de control PID, el funcionamiento de un motor de 9v. Tengo que programar la velocidad de giro y dirección usando un transistor (2n2222, TIP120, o cualquiera que recomienden), potenciómetro y Arduino. Adjunto el código de la primera parte (control PID con 3 potenciómetros).

Gracias por leer, espero respuestas. URGENTE

// Definir pines de entrada
const int potPin1 = A0; // Potenciómetro 1 conectado a A0
const int potPin2 = A1; // Potenciómetro 2 conectado a A1
const int potPin3 = A2; // Potenciómetro 3 conectado a A2

// Definir pines de salida
const int outPin1 = 3; // Salida PWM 1 en el pin 3
const int outPin2 = 5; // Salida PWM 2 en el pin 5
const int outPin3 = 6; // Salida PWM 3 en el pin 6

// Ganancia proporcional
float Kp = 1.0;

//Ganancia derivativa
float Kd = 0.5;

//Ganancia Integral
float Ki = 0.5;

// Tiempo de muestreo
float Tm = 1.0;

// Variable para almacenar el error anterior
float previousError2 = 0.5;

// Error Integral
float previousError3 = 1.0;
float Integral = 0.0;

// Valor constante para el error
void setup() {
  // Inicializar comunicación serie a 9600 baudios
  Serial.begin(9600);

  // Configurar pines de salida
  pinMode(outPin1, OUTPUT);
  pinMode(outPin2, OUTPUT);
  pinMode(outPin3, OUTPUT);
}

void loop() {
  // Leer valores de los potenciómetros (0-1023)
  int potValue1 = analogRead(potPin1);
  int potValue2 = analogRead(potPin2);
  int potValue3 = analogRead(potPin3);

//error del proporcional
  float error1 = map(potValue1,0,1023,0,255); 

// Mapear el valor del potenciómetro 2 (0-1023) a un rango de error deseado
  float error2 = map(potValue2, 0, 1023, 0, 255);

// Mapeo Potenciometro 3 (integral) 
  float error3 = map(potValue3, 0, 1023, 0, 255);

// Calcular la señal de control usando el error constante para outPin1 (proporcional)
  int controlSignal1 = Kp * error1;

// Calcular la derivada del error
  float derivative2 = (error2 - previousError2);

  // Calcular la señal de control derivativa
  float controlSignal2 = Kd / Tm * derivative2;

// calcular señal de control integral
  Integral = (previousError3 + error3) / 2.0;
float controlSignal3 = Ki * Integral * Tm;

  // Asegurarse de que la señal de control para outPin1 esté en el rango 0-255 (Proporcional)
  controlSignal1 = constrain(controlSignal1, 0, 255);

// Asegurarse de que la señal de control para outPin1 esté en el rango 0-255 (Derivativo)
  controlSignal2 = constrain(controlSignal2, 0, 255);

// Asegurarse de q la señal de control para pot3 esté en el rango (Integral)
  controlSignal3 = constrain(controlSignal3, 0, 255);

  // Generar salidas analógicas (PWM)
  analogWrite(outPin1, controlSignal1);
  analogWrite(outPin2, abs(controlSignal2));
  analogWrite(outPin3, abs(controlSignal3));

  // Enviar valores al monitor serie
  Serial.print("\t");
  Serial.print(controlSignal1);
  Serial.print("\t");
  Serial.print(controlSignal2);
  Serial.print("\t");
  Serial.print(potValue3);
  Serial.print("\t");
  Serial.println(controlSignal3);


  previousError2 = error2;
  previousError3 = error3;
  // Esperar 1000 ms antes de la próxima lectura
  delay(Tm * 1000);

}

To make the motor go both directions, you need an H-bridge circuit to reverse the current through the motor.

The PID math in the code does not make sense. For a PID, one would normally compare a measurement of the systems to a Setpoint to get a single +/- error, and use that to create an output to drive the system. Your code has three inputs, three outputs, and a fixed Setpoint. The three input errors are all constrained to be positive, which does not make sense. and the outputs are doubly constrained to be positive.

It makes no sense as a PID. The three constrained inputs make no sense as a single motor's bidirectional speed measurement. The three constrained outputs make no sense as H-bridge control inputs.

He trasladado su tema de una categoría de idioma inglés del foro a la categoría International > Español @tecnico_electronico_emilio.

En adelante por favor usar la categoría apropiada a la lengua en que queráis publicar. Esto es importante para el uso responsable del foro, y esta explicado aquí la guía "How to get the best out of this forum".
Este guía contiene mucha información útil. Por favor leer.

De antemano, muchas gracias por cooperar.

First of all, thank you for taking the time to read and answer my question.

I forgot to explain some details.
This programming is for a school project, it is a see-saw with propeller. We can't use libraries because it's kind of hard to explain afterwards, plus we had considered the h-bridge but we weren't quite sure.

The PID will be to control it later and we have to add things (step by step) to the programming.

The only thing I need is to add a new code (to control the speed) and leave the previous code to continue programming it in the future.

I will give it a try, thank you very much.

**Moderador

**
Supongo que tu respuesta en inglés fue antes de que movieran el hilo a este foro.
Ya esas en el foro en español de modo que DETENTE con las respuestas en inglés en este foro.
Ultima advertencia.
Lee las Normas del foro

Existe un paquete PID que resuelve tu problema

Empieza por ahi, y suma un puente H como te han sugerido en #2.
No necesitas 3 PID.

1 Like

A drawing would help, but if I understand from this sentance, you want to control the angle of the see-saw by the thrust of the motor. And it is possible you measure the see-saw angle by a potentiometer. It might not need an H-bridge if the see-saw naturally falls to one side and the thrust of the motor/fan can push it opposite from the direction of fall.

Of course I could be imagining your project completely wrong.

I like thinking of the PID parameters as converting between measurements of inputs and outputs. Maybe you are trying to convert an error in see-saw angle to into a 0-255 value for analogWrite(value);. With PID, you can then think of Kp as how many PWM counts of fan output per error of see-saw angle.

The Kp term of PID works like:

analogWrite(motorPWMPin,constrain(kP*(seeSawAngle - targetSeeSawAngle),0,255));

Your #1 code looks senseless because it looks like it is trying to control three motors(?) based on some strange transformations of three different types of error, and it is not at all clear how the three different PWM outputs would affect affect motor thrust to change the angle of the see-saw.

=======
traducido mecánicamente:

Un dibujo ayudaría, pero si entiendo por esta frase, deseas controlar el ángulo del balancín mediante el empuje del motor. Y es posible medir el ángulo del balancín con un potenciómetro. Es posible que no necesite un puente en H si el balancín cae naturalmente hacia un lado y el empuje del motor/ventilador puede empujarlo en dirección opuesta a la de caída.

Por supuesto, podría estar imaginando tu proyecto completamente mal.

Me gusta pensar en los parámetros PID como una conversión entre mediciones de entradas y salidas. Tal vez esté intentando convertir un error en el ángulo de balancín en un valor de 0-255 para analogWrite(value);. Con PID, puede pensar en Kp como cuántos recuentos de PWM de salida del ventilador por error del ángulo de balancín.

El término Kp de PID funciona como:

analogWrite(motorPWMPin,constrain(kP*(seeSawAngle - targetSeeSawAngle),0,255));

Su código n.° 1 parece sin sentido porque parece que está tratando de controlar tres motores (?) en función de algunas transformaciones extrañas de tres tipos diferentes de error, y no está del todo claro cómo las tres salidas PWM diferentes afectarían el empuje del motor. para cambiar el ángulo del balancín.

Hola, necesito ayuda con un proyecto escolar. Es un balancín con control PID (cuyas ganancias cambiamos con tres potenciómetros). Yo no sé programar, pero he usado un código para los 3 potenciómetros, y otro para controlar la velocidad del motor con un potenciómetro. Ya tengo la estructura del balancín hecha, y sé que tengo que usar un potenciómetro como sensor para configurar un valor de referencia y que a partir de este, el potenciómetro se equilibre.

Usamos estos materiales:

  • Motor de CC de 9v
  • Fuente externa de 9v
  • Transistor TIP122
  • Un potenciómetro como sensor para medir el valor de referencia
  • Tres potenciómetros para controlar la ganancia de cada control (P; I; D;)
  • Una resistencia de 1k
  • Un diodo 1n4007 para proteger al transistor

El primer código es este:

// Definir pines de entrada
const int potPin1 = A0; // Potenciómetro 1 conectado a A0
const int potPin2 = A1; // Potenciómetro 2 conectado a A1
const int potPin3 = A2; // Potenciómetro 3 conectado a A2

// Definir pines de salida
const int outPin1 = 3; // Salida PWM 1 en el pin 3
const int outPin2 = 5; // Salida PWM 2 en el pin 5
const int outPin3 = 6; // Salida PWM 3 en el pin 6

// Ganancia proporcional
float Kp = 1.0;

//Ganancia derivativa
float Kd = 0.5;

//Ganancia Integral
float Ki = 0.5;

// Tiempo de muestreo
float Tm = 1.0;

// Variable para almacenar el error anterior
float previousError2 = 0.5;

// Error Integral
float previousError3 = 1.0;
float Integral = 0.0;

// Valor constante para el error
void setup() {
  // Inicializar comunicación serie a 9600 baudios
  Serial.begin(9600);

  // Configurar pines de salida
  pinMode(outPin1, OUTPUT);
  pinMode(outPin2, OUTPUT);
  pinMode(outPin3, OUTPUT);
}

void loop() {
  // Leer valores de los potenciómetros (0-1023)
  int potValue1 = analogRead(potPin1);
  int potValue2 = analogRead(potPin2);
  int potValue3 = analogRead(potPin3);

//error del proporcional
  float error1 = map(potValue1,0,1023,0,255); 

// Mapear el valor del potenciómetro 2 (0-1023) a un rango de error deseado
  float error2 = map(potValue2, 0, 1023, 0, 255);

// Mapeo Potenciometro 3 (integral) 
  float error3 = map(potValue3, 0, 1023, 0, 255);

// Calcular la señal de control usando el error constante para outPin1 (proporcional)
  int controlSignal1 = Kp * error1;

// Calcular la derivada del error
  float derivative2 = (error2 - previousError2);

  // Calcular la señal de control derivativa
  float controlSignal2 = Kd / Tm * derivative2;

// calcular señal de control integral
  Integral = (previousError3 + error3) / 2.0;
float controlSignal3 = Ki * Integral * Tm;

  // Asegurarse de que la señal de control para outPin1 esté en el rango 0-255 (Proporcional)
  controlSignal1 = constrain(controlSignal1, 0, 255);

// Asegurarse de que la señal de control para outPin1 esté en el rango 0-255 (Derivativo)
  controlSignal2 = constrain(controlSignal2, 0, 255);

// Asegurarse de q la señal de control para pot3 esté en el rango (Integral)
  controlSignal3 = constrain(controlSignal3, 0, 255);

  // Generar salidas analógicas (PWM)
  analogWrite(outPin1, controlSignal1);
  analogWrite(outPin2, abs(controlSignal2));
  analogWrite(outPin3, abs(controlSignal3));

  // Enviar valores al monitor serie
  Serial.print("\t");
  Serial.print(controlSignal1);
  Serial.print("\t");
  Serial.print(controlSignal2);
  Serial.print("\t");
  Serial.print(potValue3);
  Serial.print("\t");
  Serial.println(controlSignal3);


  previousError2 = error2;
  previousError3 = error3;
  // Esperar 1000 ms antes de la próxima lectura
  delay(Tm * 500);

}

El segundo código es este:

#define pinPWM 3
#define pinPot A0

const int umbral = 10; // Umbral mínimo para activar el motor

void setup() {
  pinMode(pinPWM, OUTPUT);    // Configurar el pin PWM como salida
  pinMode(pinPot, INPUT);     // Configurar el pin del potenciómetro como entrada
  Serial.begin(9600);         // Iniciar comunicación serial (opcional)
}

void loop() {
  int valorPot = analogRead(pinPot);  // Leer valor del potenciómetro (0-1023)

  if (valorPot > umbral) {  // Encender motor si el valor del potenciómetro es mayor que el umbral
    int dutyCycle = map(valorPot, 0, 1023, 0, 255);  // Mapear a 0-255
    analogWrite(pinPWM, dutyCycle);  // Generar la señal PWM
    Serial.println(dutyCycle);  // (Opcional) Imprimir el duty cycle en el monitor serial
  } else {
    analogWrite(pinPWM, 0);  // Apagar el motor si el valor es menor o igual al umbral
  }

  delay(10);  // Pequeño retardo para estabilizar el bucle
}

Alguien me podría ayudar diciéndome cómo programar todo esto? Como dije antes, no sé programar y se me dificulta mucho. Cualquier duda la estaré respondiendo. Muchas gracias.

Adjunto foto de la estructura del balancín.

Su publicacion se MUEVE a su ubicacion actual ya que es mas adecuada.

Moderador
Dos post, 2 veces en el Foro en inglés escribiendo en español.
Las dos veces el mismo tema lo que constituye una nueva falta o sea un doble posteo.
Primero) No leíste las normas del foro? Por favor hazlo!!
Segundo) Desactiva para este dominio la traducción al español.
La próxima te baneo por 1 día, por repetición de faltas.

Perdón, es que no sé cerrar este post y es la primera vez que uso el foro. Preferiría que cerraras este y dejaras el anterior abierto. He leído las normas pero hay cosas que aún no entiendo. Mis disculpas

Ya esta, es lo mismo. no puedo volverlo atras.

En el segundo código, ¿ajustas el valorPot con los dedos? ¿O es una medida del ángulo de la palanca?

Usando un ajuste del potenciómetro con los dedos para controlar el segundo código, ¿qué ciclo de trabajo necesitas para equilibrar el brazo? Si puedes ajustar el ciclo de trabajo con los dedos usando el código 2, podría darte una idea de cómo el PID necesitaría ajustar el ciclo de trabajo con el código 1.

Cuando funciona el primer código, el PID en el primer código debería poder producir el mismo ciclo de trabajo.

El problema con el primer código es que produce tres salidas y no está claro qué salida controla el motor. ¿Tienes tres brazos y tres motores que estás intentando controlar?

Si tienes un brazo, deberías tener una entrada (A0?') que controle una salida (¿pin3?) y los términos PI y D deberían combinarse para formar analogWrite(outPin1, controlSignal1);`

Quizás:

    controlSignal1 = Kp * error1 + Kd / Tm * derivative2 + Ki * Integral * Tm ;
    controlSignal1 = constrain(controlSignal1, 0, 255);
    analogWrite(outPin1, controlSignal1);

(Is this thread supposed to be in english or in spanish?)

Primero que nada, gracias por tomarte el tiempo de responder. Creo que este hilo está en español, no estoy muy seguro de cómo funciona el foro todavía pero estoy aprendiendo.

Para el segundo código, varío el valor del potenciómetro con los dedos. Este controla la velocidad del motor, pero solo funciona para eso.

Para equilibrar el brazo tengo que usar un control PID, pero mi profesor me ha pedido que para ajustar las ganancias use esos 3 potenciómetros (es decir, uno para P, uno para I y otro para D).

Para el primer código, la consigna era generar esas 3 salidas, es por eso que puede ser confuso.

El problema es que no sé cómo lograr que el balancín funcione como tal aplicando este PID ya que muchas personas lo solucionan usando librerías y otras cosas que no se me permiten usar en esta práctica.

Últimamente estuve probando varios códigos pero ninguno funcionaba, además de que el potenciómetro que uso como sensor me da problemas a la hora de agregarlo a la programación y me cuesta mucho configurar un valor de referencia.

Perdón si no me explico bien o queda algo inconcluso, es que no se me dan muy bien estas cosas y no tengo mucho tiempo, necesito tener este proyecto funcionando pronto. Estaré atento a cualquier duda que tengas y agradezco mucho tu ayuda.

¿Tienes algo que mida el ángulo del brazo? Si quieres usar PID para controlar el ángulo del brazo, esa es la entrada crítica para el proceso PID. Si no tienes una medida del ángulo, no puedes medir el error en el ángulo. Esperaría algo como:

int potValue0 = analogRead(potPinArmAngle);
const int targetArmAngle=512;// o cualquier 'nivel' que sea

int armError = potValue0 - targetArmError;

Editado por moderador. Aunque sea 1 línea de código usar etiquetas

¿Entiendes cómo funciona PID? Y que ninguno de los códigos hace PID. El primer código tiene algunas partes que parecen elementos de PID, pero como no hay ninguna retroalimentación real del brazo, es una farsa. Y eso puede hacer que PID sea más difícil de entender de lo que debería ser.

Pero si no has aprendido cómo funciona PID, el código con nombre similar en tu código n.° 1 puede ser más confuso que útil.

El diseñador de la biblioteca Arduino PID tiene una excelente descripción de cómo funciona el PID en Improving the Beginner’s PID – Introduction | Project Blog etcétera.

No soy tu profesor, pero si tuviera que mezclar todos esos componentes (más la medición del ángulo del brazo, potValue0 de arriba) en un programa para demostrar/aprender el PID, usaría los tres potenciómetros manuales para variar Kp, Ki y Kd y agregaría tres LED para representar los componentes de salida del PID. Reescribiría los componentes de salida para usar armAngleError en lugar de los tres potenciómetros diferentes del Código n.° 1. Luego, sumaría esos tres componentes de salida y los usaría para controlar el PWM del motor.
Luego, podrías usar los potenciómetros para "ajustar" el PID y observar las contribuciones de los componentes Kp, Ki y Kd en los LED, y ver el resultado de la salida combinada en el motor.

Busque una explicación de PID e intente comprenderla antes de mirar las cosas en su código n.° 1.

No es necesario utilizar la biblioteca, pero la explicación de PID aquí es buena.

http://brettbeauregard.com/blog/wp-content/uploads/2012/07/Guía-de-uso-PID-para-Arduino.pdf