Hacer que un robot vaya directo utilizando motores de encoder y microcontrolador (Arduino)

3

Ahora tengo un chasis simple con dos ruedas que funcionan con motores de encoder. Conecté Arduino Uno con el chasis e hice un programa simple para simplemente contar el número de señales (en términos simples) de cada uno de los motores del codificador.

Ahora, teóricamente, cuando el chasis se mueve en línea recta, ambas lecturas deberían ser exactamente iguales (lo he comprobado, ¡lo son!). Y cuando un motor es más rápido, cierta lectura debería ser más.

Así que hice un programa simple que mantiene un control de estas lecturas del codificador y cuando la diferencia excede un cierto valor, apaga un motor hasta que los valores no se vuelven iguales y luego lo encienden.

En teoría, el chasis debe ir en línea recta, pero no lo hace y realiza cosas raras. (El código se adjunta a continuación).

Ahora, a veces, el código se atasca en uno de los bucles while. También he jugado mucho con mi código. Por ejemplo, en lugar de while(left_counter != right_counter) , incluso he hecho while ((left_counter - right_counter) > Certain_Range

El único problema que se me ocurre es que los motores tardan en apagarse y en ese momento las interrupciones están causando estragos. (Soy nuevo en la programación de microcontroladores y demás, aunque tengo mucha experiencia en C ++, etc.)

Por favor, ¿alguien puede explicar por qué este enfoque no funciona para mantener el motor en orden?

Código (Arduino UNO):

int motor_vcc_left = 12; //LEFT TIRE - BLUE
int pull_up_left = 3; //LEFT TIRE - GREEN

int motor_vcc_right = 11; //RIGHT TIRE - ORANGE
int pull_up_right = 2; //RIGHT TIRE - BLUE

int encoder_vcc_pin = 7;

volatile int left_counter = 0;
volatile int right_counter = 0;

void setup() {
  pinMode(motor_vcc_left, OUTPUT);
  pinMode(motor_vcc_right, OUTPUT);

  pinMode(encoder_vcc_pin, OUTPUT);
  digitalWrite(encoder_vcc_pin, HIGH);

  pinMode(3, INPUT_PULLUP); //LEFT TIRE
  attachInterrupt(1, blinkleft, CHANGE); //LEFT TIRE

  pinMode(2, INPUT_PULLUP); //RIGHT TIRE
  attachInterrupt(0, blinkright, CHANGE); //RIGHT TIRE

  digitalWrite(motor_vcc_left, HIGH);
  digitalWrite(motor_vcc_right, HIGH);
}

void loop() {
  if ((left_counter - right_counter) > 10) {
    while (left_counter != right_counter) {
      digitalWrite(motor_vcc_left, LOW);
    }
    digitalWrite(motor_vcc_left, HIGH);
  } else if ((right_counter - left_counter) > 10) {
    while (right_counter != left_counter) {
      digitalWrite(motor_vcc_right, LOW);
    }
    digitalWrite(motor_vcc_right, HIGH);
  }
}

void blinkleft() {
  left_counter++;
}

void blinkright() {
  right_counter++;
}
    
pregunta Saim Salman

2 respuestas

2

Simplemente encender y apagar los motores no lo llevará muy lejos cuando se trata de conducir en línea recta. Los motores y el propio robot tienen cierta inercia, por lo que no se detendrán cuando los apague. Un enfoque mucho mejor sería implementar un controlador PID , o al menos una parte proporcional de él.

¿Cómo funciona el controlador proporcional?

  • Primero mide la cantidad de tics que obtienes en un cierto período constante, es decir, 10 ms, para cada una de las ruedas.
  • Comparas el resultado con el valor objetivo deseado, digamos 40 ticks.
  • Cuando el valor medido es mayor que el objetivo, ralentiza un poco el motor, cuando es más pequeño, lo acelera.

En Arduino, donde controlas la velocidad de un motor mediante PWM, se ve así:

void loop() {
  if(micros() - t > PERIOD) {
    error = target - ticks;
    newPWM = error * proportionalGain;
    runMotor(newPWM);
    t = micros();
  }
}

Este ejemplo es solo para un motor, pero espero que se haga una idea general. Deberá ajustar PERIOD y proprtionalGain usted mismo. Recuerde que el rango de PWM válido para Arduino es 0-255.

Problemas que probablemente encontrará Incluso cuando tienes tu motor funcionando exactamente a la misma velocidad, puedes observar que tu robot girará. Aquí hay algunas razones posibles:  - Diámetros de ruedas desiguales.  - Distribución desigual de la masa en el robot (más masa en una rueda que en otra)  - Desalineación de ruedas. Aquí hay un gran artículo sobre un método llamado UMBmark desarrollado por Johann Borenstein que ayuda a contrarrestar estos errores: enlace

    
respondido por el mactro
1

El uso de la retroalimentación del codificador ofrecerá una ligera mejora con solo encender los motores, pero no logrará un seguimiento perfecto de una línea recta en una larga distancia. Eso requeriría algún otro tipo de mecanismo de retroalimentación. Lo siguiente asume que solo está buscando mejoras menores.

En cuanto a su código, perdería los estados adicionales introducidos por los bucles while y haría algo como:

#define DEAD_BAND 10

void loop() {
  if ((left_counter - right_counter) > DEAD_BAND) {
    // We are pointing too far to the right. Turn right motor on, left motor off.
    digitalWrite(motor_vcc_right, HIGH);
    digitalWrite(motor_vcc_left, LOW);
  } 
  else if ((right_counter - left_counter) > DEAD_BAND) {
    // We are pointing too far to the left. Turn left motor on, right motor off.
    digitalWrite(motor_vcc_right, LOW);
    digitalWrite(motor_vcc_left, HIGH);
  }
  else {
    // Everything seems cool. Continue psuedo-straight.
    digitalWrite(motor_vcc_right, HIGH);
    digitalWrite(motor_vcc_left, HIGH);
  }
}

Mejora adicional: Lo anterior tiene algunas debilidades. Una vez que acumulamos un error y estamos apuntando a la derecha, corregimos el conteo inclinándolo un poco más hacia la izquierda. Sin embargo, es posible que aún nos hayamos movido lateralmente y / o que hayamos corregido a un radio de giro diferente al de la fuente de error.

    
respondido por el Houston Fortney

Lea otras preguntas en las etiquetas